@usetheo/ui 0.13.0 → 0.13.1

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 (1235) hide show
  1. package/CHANGELOG.md +541 -69
  2. package/DESIGN.md +18 -18
  3. package/NOTICE +2 -2
  4. package/README.md +54 -52
  5. package/dist/chunk-23YEYNDS.js +89 -0
  6. package/dist/chunk-23YEYNDS.js.map +1 -0
  7. package/dist/chunk-25KBUQEQ.js +95 -0
  8. package/dist/chunk-25KBUQEQ.js.map +1 -0
  9. package/dist/chunk-2A3E5Y72.js +165 -0
  10. package/dist/chunk-2A3E5Y72.js.map +1 -0
  11. package/dist/chunk-2EUKYGH5.js +98 -0
  12. package/dist/chunk-2EUKYGH5.js.map +1 -0
  13. package/dist/chunk-2NZYMQKT.js +56 -0
  14. package/dist/chunk-2NZYMQKT.js.map +1 -0
  15. package/dist/chunk-2OVFVPSZ.js +26 -0
  16. package/dist/chunk-2OVFVPSZ.js.map +1 -0
  17. package/dist/chunk-2UP7SECE.js +78 -0
  18. package/dist/chunk-2UP7SECE.js.map +1 -0
  19. package/dist/chunk-33ETHPT7.js +112 -0
  20. package/dist/chunk-33ETHPT7.js.map +1 -0
  21. package/dist/chunk-33IIDFSM.js +43 -0
  22. package/dist/chunk-33IIDFSM.js.map +1 -0
  23. package/dist/chunk-345HYADQ.js +88 -0
  24. package/dist/chunk-345HYADQ.js.map +1 -0
  25. package/dist/chunk-3ZXZGZOX.js +57 -0
  26. package/dist/chunk-3ZXZGZOX.js.map +1 -0
  27. package/dist/chunk-45FWKR23.js +62 -0
  28. package/dist/chunk-45FWKR23.js.map +1 -0
  29. package/dist/chunk-4DTLUBRW.js +122 -0
  30. package/dist/chunk-4DTLUBRW.js.map +1 -0
  31. package/dist/chunk-4EH6F54D.js +69 -0
  32. package/dist/chunk-4EH6F54D.js.map +1 -0
  33. package/dist/chunk-4EKF4EIE.js +140 -0
  34. package/dist/chunk-4EKF4EIE.js.map +1 -0
  35. package/dist/chunk-4SMYNLTA.js +83 -0
  36. package/dist/chunk-4SMYNLTA.js.map +1 -0
  37. package/dist/chunk-4UBFLXS3.js +35 -0
  38. package/dist/chunk-4UBFLXS3.js.map +1 -0
  39. package/dist/chunk-52J7SDYH.js +48 -0
  40. package/dist/chunk-52J7SDYH.js.map +1 -0
  41. package/dist/chunk-5XCTTXC3.js +180 -0
  42. package/dist/chunk-5XCTTXC3.js.map +1 -0
  43. package/dist/chunk-624AATQZ.js +77 -0
  44. package/dist/chunk-624AATQZ.js.map +1 -0
  45. package/dist/chunk-6IODJQWC.js +47 -0
  46. package/dist/chunk-6IODJQWC.js.map +1 -0
  47. package/dist/chunk-75IDWFYX.js +134 -0
  48. package/dist/chunk-75IDWFYX.js.map +1 -0
  49. package/dist/chunk-7BGCWJQR.js +113 -0
  50. package/dist/chunk-7BGCWJQR.js.map +1 -0
  51. package/dist/chunk-7BQXMG2A.js +93 -0
  52. package/dist/chunk-7BQXMG2A.js.map +1 -0
  53. package/dist/chunk-7RFWVNQA.js +47 -0
  54. package/dist/chunk-7RFWVNQA.js.map +1 -0
  55. package/dist/chunk-7T4NK6W6.js +192 -0
  56. package/dist/chunk-7T4NK6W6.js.map +1 -0
  57. package/dist/chunk-A3OU6ICP.js +91 -0
  58. package/dist/chunk-A3OU6ICP.js.map +1 -0
  59. package/dist/chunk-ABBXLAJW.js +74 -0
  60. package/dist/chunk-ABBXLAJW.js.map +1 -0
  61. package/dist/chunk-AENNHS3S.js +83 -0
  62. package/dist/chunk-AENNHS3S.js.map +1 -0
  63. package/dist/chunk-AXNJFBYX.js +136 -0
  64. package/dist/chunk-AXNJFBYX.js.map +1 -0
  65. package/dist/chunk-AXUAQM45.js +154 -0
  66. package/dist/chunk-AXUAQM45.js.map +1 -0
  67. package/dist/chunk-B2FL7KBJ.js +65 -0
  68. package/dist/chunk-B2FL7KBJ.js.map +1 -0
  69. package/dist/chunk-BE232OKN.js +42 -0
  70. package/dist/chunk-BE232OKN.js.map +1 -0
  71. package/dist/chunk-BP4RQSX7.js +200 -0
  72. package/dist/chunk-BP4RQSX7.js.map +1 -0
  73. package/dist/chunk-BPJ3RN3U.js +112 -0
  74. package/dist/chunk-BPJ3RN3U.js.map +1 -0
  75. package/dist/chunk-BSF4Y4UT.js +77 -0
  76. package/dist/chunk-BSF4Y4UT.js.map +1 -0
  77. package/dist/chunk-BWIDDAR7.js +86 -0
  78. package/dist/chunk-BWIDDAR7.js.map +1 -0
  79. package/dist/chunk-BYUWQ6OP.js +45 -0
  80. package/dist/chunk-BYUWQ6OP.js.map +1 -0
  81. package/dist/chunk-C5ULP2P5.js +140 -0
  82. package/dist/chunk-C5ULP2P5.js.map +1 -0
  83. package/dist/chunk-CCG7PXLX.js +24 -0
  84. package/dist/chunk-CCG7PXLX.js.map +1 -0
  85. package/dist/chunk-CED2LKHI.js +117 -0
  86. package/dist/chunk-CED2LKHI.js.map +1 -0
  87. package/dist/chunk-CGWIOIEO.js +27 -0
  88. package/dist/chunk-CGWIOIEO.js.map +1 -0
  89. package/dist/chunk-CSEGVTKO.js +110 -0
  90. package/dist/chunk-CSEGVTKO.js.map +1 -0
  91. package/dist/chunk-CVFSNA4K.js +716 -0
  92. package/dist/chunk-CVFSNA4K.js.map +1 -0
  93. package/dist/chunk-E26M7ATD.js +61 -0
  94. package/dist/chunk-E26M7ATD.js.map +1 -0
  95. package/dist/chunk-E63IRXZZ.js +78 -0
  96. package/dist/chunk-E63IRXZZ.js.map +1 -0
  97. package/dist/chunk-ESJUISWY.js +45 -0
  98. package/dist/chunk-ESJUISWY.js.map +1 -0
  99. package/dist/chunk-ET7A3TQZ.js +158 -0
  100. package/dist/chunk-ET7A3TQZ.js.map +1 -0
  101. package/dist/chunk-ETTL6XGU.js +139 -0
  102. package/dist/chunk-ETTL6XGU.js.map +1 -0
  103. package/dist/chunk-EWDN56AS.js +24 -0
  104. package/dist/chunk-EWDN56AS.js.map +1 -0
  105. package/dist/chunk-FJZKA2LV.js +165 -0
  106. package/dist/chunk-FJZKA2LV.js.map +1 -0
  107. package/dist/chunk-G2WCT6PJ.js +69 -0
  108. package/dist/chunk-G2WCT6PJ.js.map +1 -0
  109. package/dist/chunk-GC52HWIL.js +41 -0
  110. package/dist/chunk-GC52HWIL.js.map +1 -0
  111. package/dist/chunk-GCKFA7X7.js +83 -0
  112. package/dist/chunk-GCKFA7X7.js.map +1 -0
  113. package/dist/chunk-GDMCDW66.js +19 -0
  114. package/dist/chunk-GDMCDW66.js.map +1 -0
  115. package/dist/chunk-GIXHBTHH.js +59 -0
  116. package/dist/chunk-GIXHBTHH.js.map +1 -0
  117. package/dist/chunk-GLEOUWPN.js +108 -0
  118. package/dist/chunk-GLEOUWPN.js.map +1 -0
  119. package/dist/chunk-GLRUM43F.js +121 -0
  120. package/dist/chunk-GLRUM43F.js.map +1 -0
  121. package/dist/chunk-H3L7WZDZ.js +74 -0
  122. package/dist/chunk-H3L7WZDZ.js.map +1 -0
  123. package/dist/chunk-H55WXDME.js +45 -0
  124. package/dist/chunk-H55WXDME.js.map +1 -0
  125. package/dist/chunk-H5QPJNVD.js +98 -0
  126. package/dist/chunk-H5QPJNVD.js.map +1 -0
  127. package/dist/chunk-HB45JHMM.js +43 -0
  128. package/dist/chunk-HB45JHMM.js.map +1 -0
  129. package/dist/chunk-HETHTYEZ.js +80 -0
  130. package/dist/chunk-HETHTYEZ.js.map +1 -0
  131. package/dist/chunk-HHSKNB32.js +55 -0
  132. package/dist/chunk-HHSKNB32.js.map +1 -0
  133. package/dist/chunk-HILOUYES.js +151 -0
  134. package/dist/chunk-HILOUYES.js.map +1 -0
  135. package/dist/chunk-HTJVHFNW.js +178 -0
  136. package/dist/chunk-HTJVHFNW.js.map +1 -0
  137. package/dist/chunk-HZ7Z22VW.js +130 -0
  138. package/dist/chunk-HZ7Z22VW.js.map +1 -0
  139. package/dist/chunk-JFKBFQA5.js +129 -0
  140. package/dist/chunk-JFKBFQA5.js.map +1 -0
  141. package/dist/chunk-JIZKW3WC.js +74 -0
  142. package/dist/chunk-JIZKW3WC.js.map +1 -0
  143. package/dist/chunk-JQTCCKZA.js +154 -0
  144. package/dist/chunk-JQTCCKZA.js.map +1 -0
  145. package/dist/chunk-JR4H3FJ2.js +74 -0
  146. package/dist/chunk-JR4H3FJ2.js.map +1 -0
  147. package/dist/chunk-JRW53TVG.js +53 -0
  148. package/dist/chunk-JRW53TVG.js.map +1 -0
  149. package/dist/chunk-JXOCE27Z.js +82 -0
  150. package/dist/chunk-JXOCE27Z.js.map +1 -0
  151. package/dist/chunk-JYW5YNF7.js +188 -0
  152. package/dist/chunk-JYW5YNF7.js.map +1 -0
  153. package/dist/chunk-K72DJOXR.js +81 -0
  154. package/dist/chunk-K72DJOXR.js.map +1 -0
  155. package/dist/chunk-KDE3NYTI.js +144 -0
  156. package/dist/chunk-KDE3NYTI.js.map +1 -0
  157. package/dist/chunk-KFUFTZLS.js +111 -0
  158. package/dist/chunk-KFUFTZLS.js.map +1 -0
  159. package/dist/chunk-KHBXI6AV.js +149 -0
  160. package/dist/chunk-KHBXI6AV.js.map +1 -0
  161. package/dist/chunk-M74ZYBOK.js +93 -0
  162. package/dist/chunk-M74ZYBOK.js.map +1 -0
  163. package/dist/chunk-ML7WLNIK.js +11 -0
  164. package/dist/chunk-ML7WLNIK.js.map +1 -0
  165. package/dist/chunk-MXB2GVEQ.js +57 -0
  166. package/dist/chunk-MXB2GVEQ.js.map +1 -0
  167. package/dist/chunk-NEMXW2LB.js +102 -0
  168. package/dist/chunk-NEMXW2LB.js.map +1 -0
  169. package/dist/chunk-OJPPSJMF.js +65 -0
  170. package/dist/chunk-OJPPSJMF.js.map +1 -0
  171. package/dist/chunk-OMR6ZGME.js +63 -0
  172. package/dist/chunk-OMR6ZGME.js.map +1 -0
  173. package/dist/chunk-ORVYP73T.js +223 -0
  174. package/dist/chunk-ORVYP73T.js.map +1 -0
  175. package/dist/chunk-OZFUUO2Q.js +50 -0
  176. package/dist/chunk-OZFUUO2Q.js.map +1 -0
  177. package/dist/chunk-P44UAK45.js +115 -0
  178. package/dist/chunk-P44UAK45.js.map +1 -0
  179. package/dist/chunk-PJUP4BJD.js +116 -0
  180. package/dist/chunk-PJUP4BJD.js.map +1 -0
  181. package/dist/chunk-PJWYIOY4.js +3 -0
  182. package/dist/chunk-PJWYIOY4.js.map +1 -0
  183. package/dist/chunk-PVCW4O37.js +147 -0
  184. package/dist/chunk-PVCW4O37.js.map +1 -0
  185. package/dist/chunk-PXT47DRZ.js +59 -0
  186. package/dist/chunk-PXT47DRZ.js.map +1 -0
  187. package/dist/chunk-PZGUZHI7.js +142 -0
  188. package/dist/chunk-PZGUZHI7.js.map +1 -0
  189. package/dist/chunk-Q2BAL2PF.js +965 -0
  190. package/dist/chunk-Q2BAL2PF.js.map +1 -0
  191. package/dist/chunk-QBUTRD2M.js +58 -0
  192. package/dist/chunk-QBUTRD2M.js.map +1 -0
  193. package/dist/chunk-QCQTTOMD.js +236 -0
  194. package/dist/chunk-QCQTTOMD.js.map +1 -0
  195. package/dist/chunk-QNYOIVQ4.js +36 -0
  196. package/dist/chunk-QNYOIVQ4.js.map +1 -0
  197. package/dist/chunk-QPURZJJM.js +88 -0
  198. package/dist/chunk-QPURZJJM.js.map +1 -0
  199. package/dist/chunk-QRXIYPWP.js +121 -0
  200. package/dist/chunk-QRXIYPWP.js.map +1 -0
  201. package/dist/chunk-QV4BQRNH.js +29 -0
  202. package/dist/chunk-QV4BQRNH.js.map +1 -0
  203. package/dist/chunk-REFY5MLN.js +212 -0
  204. package/dist/chunk-REFY5MLN.js.map +1 -0
  205. package/dist/chunk-RJ6RAMKH.js +89 -0
  206. package/dist/chunk-RJ6RAMKH.js.map +1 -0
  207. package/dist/chunk-RJBCTMVW.js +59 -0
  208. package/dist/chunk-RJBCTMVW.js.map +1 -0
  209. package/dist/chunk-RLWULF5B.js +113 -0
  210. package/dist/chunk-RLWULF5B.js.map +1 -0
  211. package/dist/chunk-RPZMFGYI.js +31 -0
  212. package/dist/chunk-RPZMFGYI.js.map +1 -0
  213. package/dist/chunk-RQT5DWGG.js +34 -0
  214. package/dist/chunk-RQT5DWGG.js.map +1 -0
  215. package/dist/chunk-SBKVVVYY.js +89 -0
  216. package/dist/chunk-SBKVVVYY.js.map +1 -0
  217. package/dist/chunk-SOJW47EZ.js +70 -0
  218. package/dist/chunk-SOJW47EZ.js.map +1 -0
  219. package/dist/chunk-SQ66DCXY.js +35 -0
  220. package/dist/chunk-SQ66DCXY.js.map +1 -0
  221. package/dist/chunk-SXKGWHAM.js +179 -0
  222. package/dist/chunk-SXKGWHAM.js.map +1 -0
  223. package/dist/chunk-T2OKGV6M.js +13 -0
  224. package/dist/chunk-T2OKGV6M.js.map +1 -0
  225. package/dist/chunk-TJLULCZW.js +108 -0
  226. package/dist/chunk-TJLULCZW.js.map +1 -0
  227. package/dist/chunk-TY6NTWN5.js +29 -0
  228. package/dist/chunk-TY6NTWN5.js.map +1 -0
  229. package/dist/chunk-U3AEEFVB.js +152 -0
  230. package/dist/chunk-U3AEEFVB.js.map +1 -0
  231. package/dist/chunk-V3HFDVZ3.js +102 -0
  232. package/dist/chunk-V3HFDVZ3.js.map +1 -0
  233. package/dist/chunk-V6H2RUVP.js +77 -0
  234. package/dist/chunk-V6H2RUVP.js.map +1 -0
  235. package/dist/chunk-VB53UMAL.js +106 -0
  236. package/dist/chunk-VB53UMAL.js.map +1 -0
  237. package/dist/chunk-VBEMLZGX.js +86 -0
  238. package/dist/chunk-VBEMLZGX.js.map +1 -0
  239. package/dist/chunk-VBQFE5RV.js +92 -0
  240. package/dist/chunk-VBQFE5RV.js.map +1 -0
  241. package/dist/chunk-VHK2OUCW.js +38 -0
  242. package/dist/chunk-VHK2OUCW.js.map +1 -0
  243. package/dist/chunk-VHTAVROO.js +53 -0
  244. package/dist/chunk-VHTAVROO.js.map +1 -0
  245. package/dist/chunk-VZX4HLBM.js +84 -0
  246. package/dist/chunk-VZX4HLBM.js.map +1 -0
  247. package/dist/chunk-W47V2F3Q.js +115 -0
  248. package/dist/chunk-W47V2F3Q.js.map +1 -0
  249. package/dist/chunk-W7I3ZX66.js +76 -0
  250. package/dist/chunk-W7I3ZX66.js.map +1 -0
  251. package/dist/chunk-WD42UBGR.js +64 -0
  252. package/dist/chunk-WD42UBGR.js.map +1 -0
  253. package/dist/chunk-XC7SYZYR.js +86 -0
  254. package/dist/chunk-XC7SYZYR.js.map +1 -0
  255. package/dist/chunk-XJA4B3F5.js +68 -0
  256. package/dist/chunk-XJA4B3F5.js.map +1 -0
  257. package/dist/chunk-XSENM65D.js +128 -0
  258. package/dist/chunk-XSENM65D.js.map +1 -0
  259. package/dist/chunk-YD2QEVHO.js +68 -0
  260. package/dist/chunk-YD2QEVHO.js.map +1 -0
  261. package/dist/chunk-YDKRUSB5.js +35 -0
  262. package/dist/chunk-YDKRUSB5.js.map +1 -0
  263. package/dist/chunk-YES6SPDT.js +55 -0
  264. package/dist/chunk-YES6SPDT.js.map +1 -0
  265. package/dist/chunk-YNDHYMPI.js +46 -0
  266. package/dist/chunk-YNDHYMPI.js.map +1 -0
  267. package/dist/chunk-YO3WEMOH.js +130 -0
  268. package/dist/chunk-YO3WEMOH.js.map +1 -0
  269. package/dist/chunk-YUFFAWNB.js +90 -0
  270. package/dist/chunk-YUFFAWNB.js.map +1 -0
  271. package/dist/chunk-YVXMWUWD.js +118 -0
  272. package/dist/chunk-YVXMWUWD.js.map +1 -0
  273. package/dist/chunk-Z6HZMGO2.js +106 -0
  274. package/dist/chunk-Z6HZMGO2.js.map +1 -0
  275. package/dist/chunk-ZAMPCRFJ.js +121 -0
  276. package/dist/chunk-ZAMPCRFJ.js.map +1 -0
  277. package/dist/chunk-ZEFOXF2I.js +87 -0
  278. package/dist/chunk-ZEFOXF2I.js.map +1 -0
  279. package/dist/chunk-ZJXOHLQE.js +66 -0
  280. package/dist/chunk-ZJXOHLQE.js.map +1 -0
  281. package/dist/chunk-ZPURFK4C.js +203 -0
  282. package/dist/chunk-ZPURFK4C.js.map +1 -0
  283. package/dist/chunk-ZZZIOTLC.js +89 -0
  284. package/dist/chunk-ZZZIOTLC.js.map +1 -0
  285. package/dist/components/composites/account-menu/account-menu.d.ts +43 -0
  286. package/dist/components/composites/account-menu/index.d.ts +1 -0
  287. package/dist/components/composites/agent-composer/agent-composer.d.ts +41 -0
  288. package/dist/components/composites/agent-composer/index.d.ts +1 -0
  289. package/dist/components/composites/agent-editor/agent-editor.d.ts +31 -0
  290. package/dist/components/composites/agent-editor/index.d.ts +1 -0
  291. package/dist/components/composites/agent-stream/agent-stream.d.ts +72 -0
  292. package/dist/components/composites/agent-stream/index.d.ts +2 -0
  293. package/dist/components/composites/agent-stream/to-agent-stream-items.d.ts +32 -0
  294. package/dist/components/composites/agent-timeline/agent-timeline.d.ts +22 -0
  295. package/dist/components/composites/agent-timeline/index.d.ts +1 -0
  296. package/dist/components/composites/agent-tool-renderer/agent-tool-renderer.d.ts +60 -0
  297. package/dist/components/composites/agent-tool-renderer/index.d.ts +1 -0
  298. package/dist/components/composites/agent-tool-renderer/tool-call-part.d.ts +5 -0
  299. package/dist/components/composites/approval-card/approval-card.d.ts +35 -0
  300. package/dist/components/composites/approval-card/index.d.ts +1 -0
  301. package/dist/components/composites/chat-composer/chat-composer.d.ts +68 -0
  302. package/dist/components/composites/chat-composer/index.d.ts +1 -0
  303. package/dist/components/composites/chat-message/chat-message-actions.d.ts +22 -0
  304. package/dist/components/composites/chat-message/chat-message-branch.d.ts +17 -0
  305. package/dist/components/composites/chat-message/chat-message-response.d.ts +15 -0
  306. package/dist/components/composites/chat-message/chat-message-toolbar.d.ts +7 -0
  307. package/dist/components/composites/chat-message/chat-message.d.ts +94 -0
  308. package/dist/components/composites/chat-message/index.d.ts +23 -0
  309. package/dist/components/composites/chat-message/parts/data-part.d.ts +9 -0
  310. package/dist/components/composites/chat-message/parts/file-part.d.ts +5 -0
  311. package/dist/components/composites/chat-message/parts/reasoning-part.d.ts +7 -0
  312. package/dist/components/composites/chat-message/parts/source-part.d.ts +9 -0
  313. package/dist/components/composites/chat-message/parts/text-part.d.ts +11 -0
  314. package/dist/components/composites/choice-prompt/choice-prompt.d.ts +65 -0
  315. package/dist/components/composites/choice-prompt/index.d.ts +2 -0
  316. package/dist/components/composites/code-block/code-block.d.ts +29 -0
  317. package/dist/components/composites/code-block/index.d.ts +1 -0
  318. package/dist/components/composites/command-palette/command-palette.d.ts +41 -0
  319. package/dist/components/composites/command-palette/index.d.ts +1 -0
  320. package/dist/components/composites/confirm-dialog/confirm-dialog.d.ts +41 -0
  321. package/dist/components/composites/confirm-dialog/index.d.ts +1 -0
  322. package/dist/components/composites/confirm-prompt/confirm-prompt.d.ts +31 -0
  323. package/dist/components/composites/confirm-prompt/index.d.ts +1 -0
  324. package/dist/components/composites/cron-jobs-list/cron-jobs-list.d.ts +15 -0
  325. package/dist/components/composites/cron-jobs-list/index.d.ts +1 -0
  326. package/dist/components/composites/data-table/data-table.d.ts +63 -0
  327. package/dist/components/composites/data-table/index.d.ts +1 -0
  328. package/dist/components/composites/deployment-row/deployment-row.d.ts +28 -0
  329. package/dist/components/composites/deployment-row/index.d.ts +1 -0
  330. package/dist/components/composites/domain-config/domain-config.d.ts +34 -0
  331. package/dist/components/composites/domain-config/index.d.ts +1 -0
  332. package/dist/components/composites/env-var-editor/env-var-editor.d.ts +35 -0
  333. package/dist/components/composites/env-var-editor/index.d.ts +1 -0
  334. package/dist/components/composites/mcp-server-list/index.d.ts +1 -0
  335. package/dist/components/composites/mcp-server-list/mcp-server-list.d.ts +15 -0
  336. package/dist/components/composites/metric-card/index.d.ts +2 -0
  337. package/dist/components/composites/metric-card/metric-card.d.ts +46 -0
  338. package/dist/components/composites/multi-select-prompt/index.d.ts +1 -0
  339. package/dist/components/composites/multi-select-prompt/multi-select-prompt.d.ts +61 -0
  340. package/dist/components/composites/page-shell/index.d.ts +1 -0
  341. package/dist/components/composites/page-shell/page-shell.d.ts +68 -0
  342. package/dist/components/composites/permission-modal/index.d.ts +1 -0
  343. package/dist/components/composites/permission-modal/permission-modal.d.ts +48 -0
  344. package/dist/components/composites/preview-env-card/index.d.ts +1 -0
  345. package/dist/components/composites/preview-env-card/preview-env-card.d.ts +36 -0
  346. package/dist/components/composites/preview-panel/index.d.ts +1 -0
  347. package/dist/components/composites/preview-panel/preview-panel.d.ts +24 -0
  348. package/dist/components/composites/project-card/index.d.ts +1 -0
  349. package/dist/components/composites/project-card/project-card.d.ts +32 -0
  350. package/dist/components/composites/rollback-ui/index.d.ts +1 -0
  351. package/dist/components/composites/rollback-ui/rollback-ui.d.ts +32 -0
  352. package/dist/components/composites/rule-editor/index.d.ts +1 -0
  353. package/dist/components/composites/rule-editor/rule-editor.d.ts +18 -0
  354. package/dist/components/composites/skill-editor/index.d.ts +1 -0
  355. package/dist/components/composites/skill-editor/skill-editor.d.ts +19 -0
  356. package/dist/components/composites/skills-list/index.d.ts +1 -0
  357. package/dist/components/composites/skills-list/skills-list.d.ts +15 -0
  358. package/dist/components/composites/slide-deck/context.d.ts +23 -0
  359. package/dist/components/composites/slide-deck/controls.d.ts +8 -0
  360. package/dist/components/composites/slide-deck/fragments.d.ts +20 -0
  361. package/dist/components/composites/slide-deck/index.d.ts +21 -0
  362. package/dist/components/composites/slide-deck/notes.d.ts +14 -0
  363. package/dist/components/composites/slide-deck/presenter-view.d.ts +15 -0
  364. package/dist/components/composites/slide-deck/print-styles.d.ts +21 -0
  365. package/dist/components/composites/slide-deck/progress-bar.d.ts +8 -0
  366. package/dist/components/composites/slide-deck/schema.d.ts +31 -0
  367. package/dist/components/composites/slide-deck/slide-deck.d.ts +78 -0
  368. package/dist/components/composites/slide-deck/slide-number.d.ts +11 -0
  369. package/dist/components/composites/slide-deck/split-deck.d.ts +2 -0
  370. package/dist/components/composites/slide-deck/thumbnails.d.ts +19 -0
  371. package/dist/components/composites/slide-deck/use-deck-hash-routing.d.ts +23 -0
  372. package/dist/components/composites/slide-deck/use-deck-keyboard.d.ts +25 -0
  373. package/dist/components/composites/slide-deck/use-deck-state.d.ts +57 -0
  374. package/dist/components/composites/slide-deck/use-deck-swipe.d.ts +20 -0
  375. package/dist/components/composites/slide-deck/use-fullscreen.d.ts +18 -0
  376. package/dist/components/composites/stability-bundle-viewer/index.d.ts +1 -0
  377. package/dist/components/composites/stability-bundle-viewer/stability-bundle-viewer.d.ts +28 -0
  378. package/dist/components/composites/status-indicator/index.d.ts +2 -0
  379. package/dist/components/composites/status-indicator/status-indicator.d.ts +31 -0
  380. package/dist/components/composites/task-header/index.d.ts +1 -0
  381. package/dist/components/composites/task-header/task-header.d.ts +20 -0
  382. package/dist/components/composites/text-prompt/index.d.ts +1 -0
  383. package/dist/components/composites/text-prompt/text-prompt.d.ts +48 -0
  384. package/dist/components/composites/usage-meter/index.d.ts +1 -0
  385. package/dist/components/composites/usage-meter/usage-meter.d.ts +56 -0
  386. package/dist/components/primitives/action-bar/action-bar.d.ts +34 -0
  387. package/dist/components/primitives/action-bar/index.d.ts +1 -0
  388. package/dist/components/primitives/agent-error-card/agent-error-card.d.ts +47 -0
  389. package/dist/components/primitives/agent-error-card/index.d.ts +1 -0
  390. package/dist/components/primitives/agent-event/agent-event.d.ts +25 -0
  391. package/dist/components/primitives/agent-event/index.d.ts +1 -0
  392. package/dist/components/primitives/agent-handoff/agent-handoff.d.ts +24 -0
  393. package/dist/components/primitives/agent-handoff/index.d.ts +1 -0
  394. package/dist/components/primitives/agent-profile/agent-profile.d.ts +28 -0
  395. package/dist/components/primitives/agent-profile/index.d.ts +1 -0
  396. package/dist/components/primitives/agent-starting-state/agent-starting-state.d.ts +15 -0
  397. package/dist/components/primitives/agent-starting-state/index.d.ts +1 -0
  398. package/dist/components/primitives/agent-streaming/agent-streaming.d.ts +16 -0
  399. package/dist/components/primitives/agent-streaming/index.d.ts +1 -0
  400. package/dist/components/primitives/alert/alert.d.ts +31 -0
  401. package/dist/components/primitives/alert/index.d.ts +1 -0
  402. package/dist/components/primitives/artifact-preview/artifact-preview.d.ts +25 -0
  403. package/dist/components/primitives/artifact-preview/index.d.ts +1 -0
  404. package/dist/components/primitives/attachment-chip/attachment-chip.d.ts +14 -0
  405. package/dist/components/primitives/attachment-chip/index.d.ts +1 -0
  406. package/dist/components/primitives/audit-log-entry/audit-log-entry.d.ts +29 -0
  407. package/dist/components/primitives/audit-log-entry/index.d.ts +1 -0
  408. package/dist/components/primitives/auto-compact-notice/auto-compact-notice.d.ts +24 -0
  409. package/dist/components/primitives/auto-compact-notice/index.d.ts +1 -0
  410. package/dist/components/primitives/avatar/avatar.d.ts +26 -0
  411. package/dist/components/primitives/avatar/index.d.ts +1 -0
  412. package/dist/components/primitives/badge/badge.d.ts +33 -0
  413. package/dist/components/primitives/badge/index.d.ts +1 -0
  414. package/dist/components/primitives/branch-indicator/branch-indicator.d.ts +13 -0
  415. package/dist/components/primitives/branch-indicator/index.d.ts +1 -0
  416. package/dist/components/primitives/browser-controls/browser-controls.d.ts +19 -0
  417. package/dist/components/primitives/browser-controls/index.d.ts +1 -0
  418. package/dist/components/primitives/build-log-stream/build-log-stream.d.ts +51 -0
  419. package/dist/components/primitives/build-log-stream/index.d.ts +1 -0
  420. package/dist/components/primitives/button/button.d.ts +26 -0
  421. package/dist/components/primitives/button/index.d.ts +1 -0
  422. package/dist/components/primitives/capability-indicator/capability-indicator.d.ts +57 -0
  423. package/dist/components/primitives/capability-indicator/index.d.ts +1 -0
  424. package/dist/components/primitives/card/card.d.ts +40 -0
  425. package/dist/components/primitives/card/index.d.ts +1 -0
  426. package/dist/components/primitives/channel-card/channel-card.d.ts +28 -0
  427. package/dist/components/primitives/channel-card/index.d.ts +1 -0
  428. package/dist/components/primitives/chat-thread/chat-thread.d.ts +12 -0
  429. package/dist/components/primitives/chat-thread/index.d.ts +1 -0
  430. package/dist/components/primitives/checkbox/checkbox.d.ts +20 -0
  431. package/dist/components/primitives/checkbox/index.d.ts +1 -0
  432. package/dist/components/primitives/context-card/context-card.d.ts +18 -0
  433. package/dist/components/primitives/context-card/index.d.ts +1 -0
  434. package/dist/components/primitives/context-window-bar/context-window-bar.d.ts +27 -0
  435. package/dist/components/primitives/context-window-bar/index.d.ts +1 -0
  436. package/dist/components/primitives/copy-button/copy-button.d.ts +17 -0
  437. package/dist/components/primitives/copy-button/index.d.ts +1 -0
  438. package/dist/components/primitives/cost-meter/cost-meter.d.ts +23 -0
  439. package/dist/components/primitives/cost-meter/index.d.ts +1 -0
  440. package/dist/components/primitives/created-files-card/created-files-card.d.ts +30 -0
  441. package/dist/components/primitives/created-files-card/index.d.ts +1 -0
  442. package/dist/components/primitives/cron-job-card/cron-job-card.d.ts +30 -0
  443. package/dist/components/primitives/cron-job-card/index.d.ts +1 -0
  444. package/dist/components/primitives/danger-zone/danger-zone.d.ts +40 -0
  445. package/dist/components/primitives/danger-zone/index.d.ts +1 -0
  446. package/dist/components/primitives/dialog/dialog.d.ts +26 -0
  447. package/dist/components/primitives/dialog/index.d.ts +1 -0
  448. package/dist/components/primitives/diff-viewer/diff-viewer.d.ts +45 -0
  449. package/dist/components/primitives/diff-viewer/index.d.ts +1 -0
  450. package/dist/components/primitives/dropdown-menu/dropdown-menu.d.ts +68 -0
  451. package/dist/components/primitives/dropdown-menu/index.d.ts +1 -0
  452. package/dist/components/primitives/empty-state/empty-state.d.ts +22 -0
  453. package/dist/components/primitives/empty-state/index.d.ts +1 -0
  454. package/dist/components/primitives/export-chat-dialog/export-chat-dialog.d.ts +18 -0
  455. package/dist/components/primitives/export-chat-dialog/index.d.ts +1 -0
  456. package/dist/components/primitives/folder-context-card/folder-context-card.d.ts +40 -0
  457. package/dist/components/primitives/folder-context-card/index.d.ts +1 -0
  458. package/dist/components/primitives/folder-selector/folder-selector.d.ts +18 -0
  459. package/dist/components/primitives/folder-selector/index.d.ts +1 -0
  460. package/dist/components/primitives/form-field/form-field.d.ts +44 -0
  461. package/dist/components/primitives/form-field/index.d.ts +1 -0
  462. package/dist/components/primitives/gateway-status-indicator/gateway-status-indicator.d.ts +19 -0
  463. package/dist/components/primitives/gateway-status-indicator/index.d.ts +1 -0
  464. package/dist/components/primitives/hook-config/hook-config.d.ts +27 -0
  465. package/dist/components/primitives/hook-config/index.d.ts +1 -0
  466. package/dist/components/primitives/hook-event-log/hook-event-log.d.ts +27 -0
  467. package/dist/components/primitives/hook-event-log/index.d.ts +1 -0
  468. package/dist/components/primitives/input/index.d.ts +1 -0
  469. package/dist/components/primitives/input/input.d.ts +24 -0
  470. package/dist/components/primitives/intent-selector/index.d.ts +1 -0
  471. package/dist/components/primitives/intent-selector/intent-selector.d.ts +22 -0
  472. package/dist/components/primitives/label/index.d.ts +1 -0
  473. package/dist/components/primitives/label/label.d.ts +15 -0
  474. package/dist/components/primitives/lane-board/index.d.ts +1 -0
  475. package/dist/components/primitives/lane-board/lane-board.d.ts +26 -0
  476. package/dist/components/primitives/login-split/index.d.ts +1 -0
  477. package/dist/components/primitives/login-split/login-split.d.ts +24 -0
  478. package/dist/components/primitives/mcp-server-card/index.d.ts +1 -0
  479. package/dist/components/primitives/mcp-server-card/mcp-server-card.d.ts +32 -0
  480. package/dist/components/primitives/memory-editor/index.d.ts +1 -0
  481. package/dist/components/primitives/memory-editor/memory-editor.d.ts +29 -0
  482. package/dist/components/primitives/mention-menu/index.d.ts +1 -0
  483. package/dist/components/primitives/mention-menu/mention-menu.d.ts +44 -0
  484. package/dist/components/primitives/metrics-panel/index.d.ts +1 -0
  485. package/dist/components/primitives/metrics-panel/metrics-panel.d.ts +62 -0
  486. package/dist/components/primitives/model-card/index.d.ts +1 -0
  487. package/dist/components/primitives/model-card/model-card.d.ts +72 -0
  488. package/dist/components/primitives/model-selector/index.d.ts +1 -0
  489. package/dist/components/primitives/model-selector/model-selector.d.ts +21 -0
  490. package/dist/components/primitives/pagination/index.d.ts +1 -0
  491. package/dist/components/primitives/pagination/pagination.d.ts +44 -0
  492. package/dist/components/primitives/permission-matrix/index.d.ts +1 -0
  493. package/dist/components/primitives/permission-matrix/permission-matrix.d.ts +43 -0
  494. package/dist/components/primitives/pin-input/index.d.ts +1 -0
  495. package/dist/components/primitives/pin-input/pin-input.d.ts +41 -0
  496. package/dist/components/primitives/plan-badge/index.d.ts +1 -0
  497. package/dist/components/primitives/plan-badge/plan-badge.d.ts +35 -0
  498. package/dist/components/primitives/progress/index.d.ts +1 -0
  499. package/dist/components/primitives/progress/progress.d.ts +44 -0
  500. package/dist/components/primitives/progress-checklist/index.d.ts +1 -0
  501. package/dist/components/primitives/progress-checklist/progress-checklist.d.ts +18 -0
  502. package/dist/components/primitives/project-switcher/index.d.ts +1 -0
  503. package/dist/components/primitives/project-switcher/project-switcher.d.ts +32 -0
  504. package/dist/components/primitives/quick-action-chips/index.d.ts +1 -0
  505. package/dist/components/primitives/quick-action-chips/quick-action-chips.d.ts +22 -0
  506. package/dist/components/primitives/radio-group/index.d.ts +1 -0
  507. package/dist/components/primitives/radio-group/radio-group.d.ts +5 -0
  508. package/dist/components/primitives/recent-folders-list/index.d.ts +1 -0
  509. package/dist/components/primitives/recent-folders-list/recent-folders-list.d.ts +21 -0
  510. package/dist/components/primitives/rule-card/index.d.ts +1 -0
  511. package/dist/components/primitives/rule-card/rule-card.d.ts +15 -0
  512. package/dist/components/primitives/run-stats/index.d.ts +1 -0
  513. package/dist/components/primitives/run-stats/run-stats.d.ts +16 -0
  514. package/dist/components/primitives/run-status-pill/index.d.ts +1 -0
  515. package/dist/components/primitives/run-status-pill/run-status-pill.d.ts +13 -0
  516. package/dist/components/primitives/running-tasks-panel/index.d.ts +1 -0
  517. package/dist/components/primitives/running-tasks-panel/running-tasks-panel.d.ts +20 -0
  518. package/dist/components/primitives/scroll-area/index.d.ts +2 -0
  519. package/dist/components/primitives/scroll-area/scroll-area.d.ts +40 -0
  520. package/dist/components/primitives/scroll-area/use-stick-to-bottom.d.ts +20 -0
  521. package/dist/components/primitives/select/index.d.ts +1 -0
  522. package/dist/components/primitives/select/select.d.ts +50 -0
  523. package/dist/components/primitives/session-list-item/index.d.ts +1 -0
  524. package/dist/components/primitives/session-list-item/session-list-item.d.ts +35 -0
  525. package/dist/components/primitives/session-timeline/index.d.ts +1 -0
  526. package/dist/components/primitives/session-timeline/session-timeline.d.ts +32 -0
  527. package/dist/components/primitives/sheet/index.d.ts +1 -0
  528. package/dist/components/primitives/sheet/sheet.d.ts +57 -0
  529. package/dist/components/primitives/sidebar/index.d.ts +1 -0
  530. package/dist/components/primitives/sidebar/sidebar.d.ts +18 -0
  531. package/dist/components/primitives/skeleton/index.d.ts +1 -0
  532. package/dist/components/primitives/skeleton/skeleton.d.ts +21 -0
  533. package/dist/components/primitives/skill-card/index.d.ts +1 -0
  534. package/dist/components/primitives/skill-card/skill-card.d.ts +28 -0
  535. package/dist/components/primitives/slide/alerts.d.ts +31 -0
  536. package/dist/components/primitives/slide/frontmatter.d.ts +23 -0
  537. package/dist/components/primitives/slide/index.d.ts +16 -0
  538. package/dist/components/primitives/slide/json-schema.d.ts +9 -0
  539. package/dist/components/primitives/slide/marpit-bg.d.ts +36 -0
  540. package/dist/components/primitives/slide/parse.d.ts +59 -0
  541. package/dist/components/primitives/slide/plugin.d.ts +79 -0
  542. package/dist/components/primitives/slide/plugins/emoji/index.d.ts +8 -0
  543. package/dist/components/primitives/slide/plugins/emoji/map.d.ts +15 -0
  544. package/dist/components/primitives/slide/plugins/math/index.d.ts +6 -0
  545. package/dist/components/primitives/slide/plugins/mermaid/index.d.ts +48 -0
  546. package/dist/components/primitives/slide/plugins/shiki/index.d.ts +11 -0
  547. package/dist/components/primitives/slide/sanitize.d.ts +33 -0
  548. package/dist/components/primitives/slide/schema.d.ts +109 -0
  549. package/dist/components/primitives/slide/slide.d.ts +53 -0
  550. package/dist/components/primitives/slide/themes/index.d.ts +9 -0
  551. package/dist/components/primitives/slide/use-slide-fit.d.ts +21 -0
  552. package/dist/components/primitives/slide/validate.d.ts +33 -0
  553. package/dist/components/primitives/social-auth-row/index.d.ts +1 -0
  554. package/dist/components/primitives/social-auth-row/social-auth-row.d.ts +24 -0
  555. package/dist/components/primitives/stat-tile/index.d.ts +1 -0
  556. package/dist/components/primitives/stat-tile/stat-tile.d.ts +28 -0
  557. package/dist/components/primitives/status-dot/index.d.ts +1 -0
  558. package/dist/components/primitives/status-dot/status-dot.d.ts +31 -0
  559. package/dist/components/primitives/steps-rail/index.d.ts +1 -0
  560. package/dist/components/primitives/steps-rail/steps-rail.d.ts +24 -0
  561. package/dist/components/primitives/sub-agent-dispatch/index.d.ts +1 -0
  562. package/dist/components/primitives/sub-agent-dispatch/sub-agent-dispatch.d.ts +30 -0
  563. package/dist/components/primitives/switch/index.d.ts +1 -0
  564. package/dist/components/primitives/switch/switch.d.ts +20 -0
  565. package/dist/components/primitives/system-prompt-editor/index.d.ts +1 -0
  566. package/dist/components/primitives/system-prompt-editor/system-prompt-editor.d.ts +25 -0
  567. package/dist/components/primitives/table/index.d.ts +1 -0
  568. package/dist/components/primitives/table/table.d.ts +61 -0
  569. package/dist/components/primitives/tabs/index.d.ts +1 -0
  570. package/dist/components/primitives/tabs/tabs.d.ts +7 -0
  571. package/dist/components/primitives/task-plan/index.d.ts +1 -0
  572. package/dist/components/primitives/task-plan/task-plan.d.ts +36 -0
  573. package/dist/components/primitives/terminal-panel/index.d.ts +1 -0
  574. package/dist/components/primitives/terminal-panel/terminal-panel.d.ts +32 -0
  575. package/dist/components/primitives/textarea/index.d.ts +1 -0
  576. package/dist/components/primitives/textarea/textarea.d.ts +20 -0
  577. package/dist/components/primitives/thinking-level-selector/index.d.ts +1 -0
  578. package/dist/components/primitives/thinking-level-selector/thinking-level-selector.d.ts +24 -0
  579. package/dist/components/primitives/timestamp/index.d.ts +1 -0
  580. package/dist/components/primitives/timestamp/timestamp.d.ts +34 -0
  581. package/dist/components/primitives/toast/index.d.ts +2 -0
  582. package/dist/components/primitives/toast/toast.d.ts +34 -0
  583. package/dist/components/primitives/toast/toaster.d.ts +38 -0
  584. package/dist/components/primitives/token-usage-chart/index.d.ts +2 -0
  585. package/dist/components/primitives/token-usage-chart/token-usage-chart.d.ts +44 -0
  586. package/dist/components/primitives/token-usage-chart/usage-metrics.d.ts +23 -0
  587. package/dist/components/primitives/tool-call/index.d.ts +1 -0
  588. package/dist/components/primitives/tool-call/tool-call.d.ts +30 -0
  589. package/dist/components/primitives/tool-call-card/index.d.ts +1 -0
  590. package/dist/components/primitives/tool-call-card/tool-call-card.d.ts +30 -0
  591. package/dist/components/primitives/tool-result/index.d.ts +1 -0
  592. package/dist/components/primitives/tool-result/tool-result.d.ts +19 -0
  593. package/dist/components/primitives/tools-list/index.d.ts +1 -0
  594. package/dist/components/primitives/tools-list/tools-list.d.ts +32 -0
  595. package/dist/components/primitives/tooltip/index.d.ts +1 -0
  596. package/dist/components/primitives/tooltip/tooltip.d.ts +33 -0
  597. package/dist/components/primitives/topnav/index.d.ts +1 -0
  598. package/dist/components/primitives/topnav/topnav.d.ts +29 -0
  599. package/dist/components/primitives/update-banner/index.d.ts +1 -0
  600. package/dist/components/primitives/update-banner/update-banner.d.ts +16 -0
  601. package/dist/components/primitives/whiteboard/index.d.ts +2 -0
  602. package/dist/components/primitives/whiteboard/render/freedraw.d.ts +2 -0
  603. package/dist/components/primitives/whiteboard/render/line.d.ts +4 -0
  604. package/dist/components/primitives/whiteboard/render/rough-paths.d.ts +16 -0
  605. package/dist/components/primitives/whiteboard/render/scene.d.ts +3 -0
  606. package/dist/components/primitives/whiteboard/render/shape.d.ts +5 -0
  607. package/dist/components/primitives/whiteboard/render/style.d.ts +24 -0
  608. package/dist/components/primitives/whiteboard/render/text.d.ts +2 -0
  609. package/dist/components/primitives/whiteboard/schema.d.ts +596 -0
  610. package/dist/components/primitives/whiteboard/seed.d.ts +22 -0
  611. package/dist/components/primitives/whiteboard/validate.d.ts +26 -0
  612. package/dist/components/primitives/whiteboard/viewport/use-pointer-pan.d.ts +11 -0
  613. package/dist/components/primitives/whiteboard/viewport/use-viewport.d.ts +33 -0
  614. package/dist/components/primitives/whiteboard/whiteboard.d.ts +21 -0
  615. package/dist/components.css +1 -1
  616. package/dist/composites/account-menu/index.js +4 -4
  617. package/dist/composites/agent-composer/index.js +6 -5
  618. package/dist/composites/agent-editor/index.js +8 -7
  619. package/dist/composites/agent-stream/index.js +21 -9
  620. package/dist/composites/agent-timeline/index.js +3 -3
  621. package/dist/composites/agent-tool-renderer/index.js +17 -0
  622. package/dist/composites/agent-tool-renderer/index.js.map +1 -0
  623. package/dist/composites/approval-card/index.js +3 -3
  624. package/dist/composites/chat-composer/index.js +3 -3
  625. package/dist/composites/chat-message/index.js +18 -4
  626. package/dist/composites/choice-prompt/index.js +11 -0
  627. package/dist/composites/choice-prompt/index.js.map +1 -0
  628. package/dist/composites/code-block/index.js +3 -3
  629. package/dist/composites/command-palette/index.js +4 -3
  630. package/dist/composites/confirm-dialog/index.js +6 -5
  631. package/dist/composites/confirm-prompt/index.js +7 -0
  632. package/dist/composites/confirm-prompt/index.js.map +1 -0
  633. package/dist/composites/cron-jobs-list/index.js +3 -3
  634. package/dist/composites/data-table/index.js +8 -7
  635. package/dist/composites/deployment-row/index.js +3 -3
  636. package/dist/composites/domain-config/index.js +6 -5
  637. package/dist/composites/env-var-editor/index.js +7 -5
  638. package/dist/composites/mcp-server-list/index.js +4 -3
  639. package/dist/composites/metric-card/index.js +5 -0
  640. package/dist/composites/metric-card/index.js.map +1 -0
  641. package/dist/composites/multi-select-prompt/index.js +11 -0
  642. package/dist/composites/multi-select-prompt/index.js.map +1 -0
  643. package/dist/composites/page-shell/index.js +6 -5
  644. package/dist/composites/permission-modal/index.js +5 -4
  645. package/dist/composites/preview-env-card/index.js +4 -4
  646. package/dist/composites/preview-panel/index.js +3 -3
  647. package/dist/composites/project-card/index.js +4 -4
  648. package/dist/composites/rollback-ui/index.js +5 -4
  649. package/dist/composites/rule-editor/index.js +9 -8
  650. package/dist/composites/skill-editor/index.js +9 -8
  651. package/dist/composites/skills-list/index.js +4 -3
  652. package/dist/composites/stability-bundle-viewer/index.js +3 -2
  653. package/dist/composites/status-indicator/index.js +4 -0
  654. package/dist/composites/status-indicator/index.js.map +1 -0
  655. package/dist/composites/task-header/index.js +3 -3
  656. package/dist/composites/text-prompt/index.js +10 -0
  657. package/dist/composites/text-prompt/index.js.map +1 -0
  658. package/dist/composites/usage-meter/index.js +3 -3
  659. package/dist/fonts-cdn.css +4 -4
  660. package/dist/fonts.css +2 -2
  661. package/dist/index.d.ts +144 -4622
  662. package/dist/index.js +999 -739
  663. package/dist/index.js.map +1 -1
  664. package/dist/lib/cn.d.ts +6 -0
  665. package/dist/lib/env.d.ts +55 -0
  666. package/dist/lib/live-region-context.d.ts +2 -0
  667. package/dist/lib/markdown/code-block.d.ts +14 -0
  668. package/dist/lib/markdown/inline-code.d.ts +10 -0
  669. package/dist/lib/markdown/math.d.ts +12 -0
  670. package/dist/lib/markdown/mermaid.d.ts +6 -0
  671. package/dist/lib/markdown/parser.d.ts +47 -0
  672. package/dist/lib/markdown/streaming-preprocess.d.ts +39 -0
  673. package/dist/lib/prompt.d.ts +40 -0
  674. package/dist/lib/safe-href.d.ts +27 -0
  675. package/dist/lib/sdk-tools-adapters/index.d.ts +1 -0
  676. package/dist/lib/sdk-tools-adapters/index.js +3 -0
  677. package/dist/lib/sdk-tools-adapters/index.js.map +1 -0
  678. package/dist/lib/sdk-tools-adapters/sdk-tools-adapters.d.ts +60 -0
  679. package/dist/lib/types.d.ts +10 -0
  680. package/dist/preset-v3-legacy.d.ts +7 -10
  681. package/dist/preset-v3-legacy.js +23 -3
  682. package/dist/preset-v3-legacy.js.map +1 -1
  683. package/dist/preset.css +2 -2
  684. package/dist/primitives/action-bar/index.js +2 -2
  685. package/dist/primitives/agent-error-card/index.js +2 -2
  686. package/dist/primitives/agent-event/index.js +3 -2
  687. package/dist/primitives/agent-handoff/index.js +2 -2
  688. package/dist/primitives/agent-profile/index.js +2 -2
  689. package/dist/primitives/agent-starting-state/index.js +2 -2
  690. package/dist/primitives/agent-streaming/index.js +2 -2
  691. package/dist/primitives/alert/index.js +2 -2
  692. package/dist/primitives/artifact-preview/index.js +2 -2
  693. package/dist/primitives/attachment-chip/index.js +2 -2
  694. package/dist/primitives/audit-log-entry/index.js +2 -2
  695. package/dist/primitives/auto-compact-notice/index.js +2 -2
  696. package/dist/primitives/avatar/index.js +2 -2
  697. package/dist/primitives/badge/index.js +2 -2
  698. package/dist/primitives/branch-indicator/index.js +2 -2
  699. package/dist/primitives/browser-controls/index.js +2 -2
  700. package/dist/primitives/build-log-stream/index.js +4 -2
  701. package/dist/primitives/button/index.js +2 -2
  702. package/dist/primitives/capability-indicator/index.js +2 -2
  703. package/dist/primitives/card/index.js +3 -2
  704. package/dist/primitives/channel-card/index.js +2 -2
  705. package/dist/primitives/chat-thread/index.js +2 -2
  706. package/dist/primitives/checkbox/index.js +2 -2
  707. package/dist/primitives/context-card/index.js +2 -2
  708. package/dist/primitives/context-window-bar/index.js +2 -2
  709. package/dist/primitives/copy-button/index.js +3 -2
  710. package/dist/primitives/cost-meter/index.js +2 -2
  711. package/dist/primitives/created-files-card/index.js +2 -2
  712. package/dist/primitives/cron-job-card/index.js +2 -2
  713. package/dist/primitives/danger-zone/index.js +2 -2
  714. package/dist/primitives/dialog/index.js +2 -2
  715. package/dist/primitives/diff-viewer/index.js +2 -2
  716. package/dist/primitives/dropdown-menu/index.js +2 -2
  717. package/dist/primitives/empty-state/index.js +2 -2
  718. package/dist/primitives/export-chat-dialog/index.js +3 -2
  719. package/dist/primitives/folder-context-card/index.js +2 -2
  720. package/dist/primitives/folder-selector/index.js +2 -2
  721. package/dist/primitives/form-field/index.js +3 -2
  722. package/dist/primitives/gateway-status-indicator/index.js +2 -2
  723. package/dist/primitives/hook-config/index.js +3 -2
  724. package/dist/primitives/hook-event-log/index.js +2 -2
  725. package/dist/primitives/input/index.js +2 -2
  726. package/dist/primitives/intent-selector/index.js +2 -2
  727. package/dist/primitives/label/index.js +2 -2
  728. package/dist/primitives/lane-board/index.js +2 -2
  729. package/dist/primitives/login-split/index.js +2 -2
  730. package/dist/primitives/mcp-server-card/index.js +2 -2
  731. package/dist/primitives/memory-editor/index.js +2 -2
  732. package/dist/primitives/mention-menu/index.js +3 -2
  733. package/dist/primitives/metrics-panel/index.js +2 -2
  734. package/dist/primitives/model-card/index.js +2 -2
  735. package/dist/primitives/model-selector/index.js +2 -2
  736. package/dist/primitives/pagination/index.js +2 -2
  737. package/dist/primitives/permission-matrix/index.js +3 -2
  738. package/dist/primitives/pin-input/index.js +3 -2
  739. package/dist/primitives/plan-badge/index.js +2 -2
  740. package/dist/primitives/progress/index.js +2 -2
  741. package/dist/primitives/progress-checklist/index.js +2 -2
  742. package/dist/primitives/project-switcher/index.js +2 -2
  743. package/dist/primitives/quick-action-chips/index.js +2 -2
  744. package/dist/primitives/radio-group/index.js +2 -2
  745. package/dist/primitives/recent-folders-list/index.js +2 -2
  746. package/dist/primitives/rule-card/index.js +2 -2
  747. package/dist/primitives/run-stats/index.js +2 -2
  748. package/dist/primitives/run-status-pill/index.js +2 -2
  749. package/dist/primitives/running-tasks-panel/index.js +2 -2
  750. package/dist/primitives/scroll-area/index.js +3 -2
  751. package/dist/primitives/select/index.js +2 -2
  752. package/dist/primitives/session-list-item/index.js +2 -2
  753. package/dist/primitives/session-timeline/index.js +2 -2
  754. package/dist/primitives/sheet/index.js +2 -2
  755. package/dist/primitives/sidebar/index.js +2 -2
  756. package/dist/primitives/skeleton/index.js +2 -2
  757. package/dist/primitives/skill-card/index.js +2 -2
  758. package/dist/primitives/social-auth-row/index.js +2 -2
  759. package/dist/primitives/stat-tile/index.js +2 -2
  760. package/dist/primitives/status-dot/index.js +4 -2
  761. package/dist/primitives/steps-rail/index.js +2 -2
  762. package/dist/primitives/sub-agent-dispatch/index.js +2 -2
  763. package/dist/primitives/switch/index.js +2 -2
  764. package/dist/primitives/system-prompt-editor/index.js +3 -2
  765. package/dist/primitives/table/index.js +3 -2
  766. package/dist/primitives/tabs/index.js +2 -2
  767. package/dist/primitives/task-plan/index.js +2 -2
  768. package/dist/primitives/terminal-panel/index.js +2 -2
  769. package/dist/primitives/textarea/index.js +2 -2
  770. package/dist/primitives/thinking-level-selector/index.js +3 -2
  771. package/dist/primitives/timestamp/index.js +4 -2
  772. package/dist/primitives/toast/index.js +3 -2
  773. package/dist/primitives/token-usage-chart/index.js +2 -2
  774. package/dist/primitives/tool-call/index.js +3 -2
  775. package/dist/primitives/tool-call-card/index.js +3 -2
  776. package/dist/primitives/tool-result/index.js +2 -2
  777. package/dist/primitives/tools-list/index.js +2 -2
  778. package/dist/primitives/tooltip/index.js +2 -2
  779. package/dist/primitives/topnav/index.js +2 -2
  780. package/dist/primitives/update-banner/index.js +2 -2
  781. package/dist/screens/theo-code-shell.d.ts +9 -0
  782. package/dist/screens/theo-code-shell.data.d.ts +147 -0
  783. package/dist/slide/index.js +2 -1
  784. package/dist/slide/plugins/mermaid/index.js +1 -1
  785. package/dist/slide/plugins/mermaid/index.js.map +1 -1
  786. package/dist/slide/plugins/shiki/index.js.map +1 -1
  787. package/dist/slide/themes/violet-forge.css +1 -1
  788. package/dist/slide-deck/index.js +13 -2
  789. package/dist/slide-deck/index.js.map +1 -1
  790. package/dist/styles/tailwind-preset.d.ts +29 -0
  791. package/dist/styles.css +3 -3
  792. package/dist/test/a11y.d.ts +13 -0
  793. package/dist/test/setup.d.ts +1 -0
  794. package/dist/themes/anthropic-style.d.ts +11 -0
  795. package/dist/themes/aurora-terminal.d.ts +9 -0
  796. package/dist/themes/classic-paper.d.ts +17 -0
  797. package/dist/themes/color-value-pattern.d.ts +22 -0
  798. package/dist/themes/color.d.ts +62 -0
  799. package/dist/themes/define.d.ts +65 -0
  800. package/dist/themes/density.d.ts +17 -0
  801. package/dist/themes/dracula.d.ts +14 -0
  802. package/dist/themes/github-dark.d.ts +11 -0
  803. package/dist/themes/index.d.ts +26 -0
  804. package/dist/themes/linear-glass.d.ts +11 -0
  805. package/dist/themes/one-dark.d.ts +11 -0
  806. package/dist/themes/openai-style.d.ts +10 -0
  807. package/dist/themes/schema.d.ts +112 -0
  808. package/dist/themes/theme-provider.d.ts +82 -0
  809. package/dist/themes/theme-script.d.ts +48 -0
  810. package/dist/themes/theme-switcher.d.ts +17 -0
  811. package/dist/themes/types.d.ts +88 -0
  812. package/dist/themes/vercel-mono.d.ts +11 -0
  813. package/dist/themes/violet-forge.d.ts +12 -0
  814. package/dist/theo-ui-provider.d.ts +50 -0
  815. package/dist/tokens-v4.css +77 -41
  816. package/dist/tokens.css +159 -74
  817. package/dist/types/agent.d.ts +19 -0
  818. package/dist/types/chat.d.ts +173 -0
  819. package/dist/types/mode.d.ts +16 -0
  820. package/dist/types/permission.d.ts +8 -0
  821. package/dist/types/rule.d.ts +28 -0
  822. package/dist/types/task.d.ts +9 -0
  823. package/dist/vite-plugin.d.ts +7 -11
  824. package/dist/vite-plugin.js +4 -4
  825. package/dist/vite-plugin.js.map +1 -1
  826. package/dist/whiteboard/index.js +3 -0
  827. package/dist/whiteboard/index.js.map +1 -1
  828. package/llms.txt +39 -39
  829. package/package.json +236 -188
  830. package/registry/index.json +58 -4
  831. package/registry/r/account-menu.json +1 -1
  832. package/registry/r/action-bar.json +1 -1
  833. package/registry/r/agent-composer.json +1 -1
  834. package/registry/r/agent-editor.json +1 -1
  835. package/registry/r/agent-error-card.json +1 -1
  836. package/registry/r/agent-event.json +1 -1
  837. package/registry/r/agent-handoff.json +1 -1
  838. package/registry/r/agent-profile.json +1 -1
  839. package/registry/r/agent-starting-state.json +1 -1
  840. package/registry/r/agent-stream.json +1 -1
  841. package/registry/r/agent-streaming.json +1 -1
  842. package/registry/r/agent-timeline.json +1 -1
  843. package/registry/r/agent-tool-renderer.json +40 -0
  844. package/registry/r/alert.json +1 -1
  845. package/registry/r/approval-card.json +1 -1
  846. package/registry/r/artifact-preview.json +1 -1
  847. package/registry/r/attachment-chip.json +1 -1
  848. package/registry/r/audit-log-entry.json +1 -1
  849. package/registry/r/auto-compact-notice.json +1 -1
  850. package/registry/r/avatar.json +1 -1
  851. package/registry/r/badge.json +1 -1
  852. package/registry/r/browser-controls.json +1 -1
  853. package/registry/r/build-log-stream.json +2 -1
  854. package/registry/r/button.json +1 -1
  855. package/registry/r/capability-indicator.json +1 -1
  856. package/registry/r/card.json +1 -1
  857. package/registry/r/chat-composer.json +1 -1
  858. package/registry/r/chat-message.json +11 -16
  859. package/registry/r/chat-thread.json +1 -1
  860. package/registry/r/chat-types.json +1 -1
  861. package/registry/r/checkbox.json +1 -1
  862. package/registry/r/choice-prompt.json +25 -0
  863. package/registry/r/cn.json +1 -1
  864. package/registry/r/code-block.json +1 -1
  865. package/registry/r/command-palette.json +1 -1
  866. package/registry/r/confirm-dialog.json +1 -1
  867. package/registry/r/confirm-prompt.json +21 -0
  868. package/registry/r/context-card.json +1 -1
  869. package/registry/r/context-window-bar.json +1 -1
  870. package/registry/r/copy-button.json +1 -1
  871. package/registry/r/cost-meter.json +1 -1
  872. package/registry/r/created-files-card.json +1 -1
  873. package/registry/r/cron-job-card.json +1 -1
  874. package/registry/r/cron-jobs-list.json +1 -1
  875. package/registry/r/danger-zone.json +1 -1
  876. package/registry/r/data-table.json +1 -1
  877. package/registry/r/deployment-row.json +1 -1
  878. package/registry/r/dialog.json +1 -1
  879. package/registry/r/diff-viewer.json +1 -1
  880. package/registry/r/domain-config.json +1 -1
  881. package/registry/r/dropdown-menu.json +2 -2
  882. package/registry/r/empty-state.json +1 -1
  883. package/registry/r/env-var-editor.json +2 -1
  884. package/registry/r/env.json +15 -0
  885. package/registry/r/folder-context-card.json +1 -1
  886. package/registry/r/folder-selector.json +1 -1
  887. package/registry/r/form-field.json +1 -1
  888. package/registry/r/hook-config.json +1 -1
  889. package/registry/r/hook-event-log.json +1 -1
  890. package/registry/r/input.json +1 -1
  891. package/registry/r/intent-selector.json +1 -1
  892. package/registry/r/label.json +1 -1
  893. package/registry/r/lane-board.json +1 -1
  894. package/registry/r/login-split.json +1 -1
  895. package/registry/r/mcp-server-card.json +1 -1
  896. package/registry/r/mcp-server-list.json +1 -1
  897. package/registry/r/memory-editor.json +1 -1
  898. package/registry/r/mention-menu.json +1 -1
  899. package/registry/r/metric-card.json +23 -0
  900. package/registry/r/metrics-panel.json +1 -1
  901. package/registry/r/model-card.json +1 -1
  902. package/registry/r/model-selector.json +1 -1
  903. package/registry/r/multi-select-prompt.json +25 -0
  904. package/registry/r/page-shell.json +1 -1
  905. package/registry/r/pagination.json +1 -1
  906. package/registry/r/permission-matrix.json +1 -1
  907. package/registry/r/permission-modal.json +1 -1
  908. package/registry/r/pin-input.json +1 -1
  909. package/registry/r/plan-badge.json +1 -1
  910. package/registry/r/preview-env-card.json +1 -1
  911. package/registry/r/preview-panel.json +1 -1
  912. package/registry/r/progress-checklist.json +1 -1
  913. package/registry/r/progress.json +1 -1
  914. package/registry/r/project-card.json +1 -1
  915. package/registry/r/project-switcher.json +1 -1
  916. package/registry/r/prompt.json +15 -0
  917. package/registry/r/quick-action-chips.json +1 -1
  918. package/registry/r/radio-group.json +1 -1
  919. package/registry/r/recent-folders-list.json +1 -1
  920. package/registry/r/rollback-ui.json +1 -1
  921. package/registry/r/rule-card.json +1 -1
  922. package/registry/r/rule-editor.json +1 -1
  923. package/registry/r/run-stats.json +1 -1
  924. package/registry/r/running-tasks-panel.json +1 -1
  925. package/registry/r/safe-href.json +1 -1
  926. package/registry/r/scroll-area.json +1 -1
  927. package/registry/r/select.json +1 -1
  928. package/registry/r/session-list-item.json +1 -1
  929. package/registry/r/session-timeline.json +1 -1
  930. package/registry/r/sheet.json +1 -1
  931. package/registry/r/sidebar.json +1 -1
  932. package/registry/r/skeleton.json +1 -1
  933. package/registry/r/skill-card.json +1 -1
  934. package/registry/r/skill-editor.json +1 -1
  935. package/registry/r/skills-list.json +1 -1
  936. package/registry/r/slide-deck.json +8 -8
  937. package/registry/r/slide-plugin-mermaid.json +1 -1
  938. package/registry/r/slide-plugin-shiki.json +1 -1
  939. package/registry/r/slide.json +6 -6
  940. package/registry/r/social-auth-row.json +1 -1
  941. package/registry/r/stat-tile.json +1 -1
  942. package/registry/r/status-dot.json +2 -1
  943. package/registry/r/status-indicator.json +20 -0
  944. package/registry/r/steps-rail.json +1 -1
  945. package/registry/r/sub-agent-dispatch.json +1 -1
  946. package/registry/r/switch.json +1 -1
  947. package/registry/r/system-prompt-editor.json +1 -1
  948. package/registry/r/table.json +1 -1
  949. package/registry/r/tabs.json +1 -1
  950. package/registry/r/tailwind-preset.json +1 -1
  951. package/registry/r/task-header.json +1 -1
  952. package/registry/r/task-plan.json +1 -1
  953. package/registry/r/terminal-panel.json +1 -1
  954. package/registry/r/text-prompt.json +24 -0
  955. package/registry/r/textarea.json +1 -1
  956. package/registry/r/theme-provider.json +7 -6
  957. package/registry/r/theo-ui-provider.json +1 -1
  958. package/registry/r/timestamp.json +2 -1
  959. package/registry/r/toast.json +2 -2
  960. package/registry/r/token-usage-chart.json +1 -1
  961. package/registry/r/tokens.json +2 -2
  962. package/registry/r/tool-call-card.json +1 -1
  963. package/registry/r/tool-call.json +1 -1
  964. package/registry/r/tool-result.json +1 -1
  965. package/registry/r/tools-list.json +1 -1
  966. package/registry/r/tooltip.json +1 -1
  967. package/registry/r/topnav.json +1 -1
  968. package/registry/r/usage-meter.json +1 -1
  969. package/registry/r/whiteboard.json +3 -3
  970. package/dist/chunk-2UJROWAG.js +0 -106
  971. package/dist/chunk-2UJROWAG.js.map +0 -1
  972. package/dist/chunk-2XPWOUEH.js +0 -68
  973. package/dist/chunk-2XPWOUEH.js.map +0 -1
  974. package/dist/chunk-3GHLNCM3.js +0 -42
  975. package/dist/chunk-3GHLNCM3.js.map +0 -1
  976. package/dist/chunk-3HOXC25T.js +0 -48
  977. package/dist/chunk-3HOXC25T.js.map +0 -1
  978. package/dist/chunk-3QGO5SB3.js +0 -46
  979. package/dist/chunk-3QGO5SB3.js.map +0 -1
  980. package/dist/chunk-47QJVWW2.js +0 -85
  981. package/dist/chunk-47QJVWW2.js.map +0 -1
  982. package/dist/chunk-4L63UW3I.js +0 -35
  983. package/dist/chunk-4L63UW3I.js.map +0 -1
  984. package/dist/chunk-4UUSJJFZ.js +0 -25
  985. package/dist/chunk-4UUSJJFZ.js.map +0 -1
  986. package/dist/chunk-4ZBZBRG5.js +0 -127
  987. package/dist/chunk-4ZBZBRG5.js.map +0 -1
  988. package/dist/chunk-57NXT3OX.js +0 -92
  989. package/dist/chunk-57NXT3OX.js.map +0 -1
  990. package/dist/chunk-5FF5EUZP.js +0 -44
  991. package/dist/chunk-5FF5EUZP.js.map +0 -1
  992. package/dist/chunk-5UGQXB2P.js +0 -714
  993. package/dist/chunk-5UGQXB2P.js.map +0 -1
  994. package/dist/chunk-62FT22CI.js +0 -85
  995. package/dist/chunk-62FT22CI.js.map +0 -1
  996. package/dist/chunk-673R3GSK.js +0 -19
  997. package/dist/chunk-673R3GSK.js.map +0 -1
  998. package/dist/chunk-6VINZJBV.js +0 -128
  999. package/dist/chunk-6VINZJBV.js.map +0 -1
  1000. package/dist/chunk-6ZQKEY54.js +0 -149
  1001. package/dist/chunk-6ZQKEY54.js.map +0 -1
  1002. package/dist/chunk-74NZ5U3E.js +0 -145
  1003. package/dist/chunk-74NZ5U3E.js.map +0 -1
  1004. package/dist/chunk-755NWSNW.js +0 -36
  1005. package/dist/chunk-755NWSNW.js.map +0 -1
  1006. package/dist/chunk-7GLBWWMW.js +0 -70
  1007. package/dist/chunk-7GLBWWMW.js.map +0 -1
  1008. package/dist/chunk-7RXYW5VM.js +0 -88
  1009. package/dist/chunk-7RXYW5VM.js.map +0 -1
  1010. package/dist/chunk-AC4MGCXI.js +0 -92
  1011. package/dist/chunk-AC4MGCXI.js.map +0 -1
  1012. package/dist/chunk-AEVSVDT6.js +0 -67
  1013. package/dist/chunk-AEVSVDT6.js.map +0 -1
  1014. package/dist/chunk-AODIMN2N.js +0 -68
  1015. package/dist/chunk-AODIMN2N.js.map +0 -1
  1016. package/dist/chunk-ATHOPBCA.js +0 -61
  1017. package/dist/chunk-ATHOPBCA.js.map +0 -1
  1018. package/dist/chunk-AVPHVQZS.js +0 -73
  1019. package/dist/chunk-AVPHVQZS.js.map +0 -1
  1020. package/dist/chunk-AXKBNRZW.js +0 -173
  1021. package/dist/chunk-AXKBNRZW.js.map +0 -1
  1022. package/dist/chunk-B75MEYNR.js +0 -106
  1023. package/dist/chunk-B75MEYNR.js.map +0 -1
  1024. package/dist/chunk-BGKA6DI6.js +0 -34
  1025. package/dist/chunk-BGKA6DI6.js.map +0 -1
  1026. package/dist/chunk-BNQAJGEN.js +0 -88
  1027. package/dist/chunk-BNQAJGEN.js.map +0 -1
  1028. package/dist/chunk-BP2SETUC.js +0 -101
  1029. package/dist/chunk-BP2SETUC.js.map +0 -1
  1030. package/dist/chunk-BPUQWMBD.js +0 -79
  1031. package/dist/chunk-BPUQWMBD.js.map +0 -1
  1032. package/dist/chunk-BVDASR3Y.js +0 -74
  1033. package/dist/chunk-BVDASR3Y.js.map +0 -1
  1034. package/dist/chunk-BX7A5GUV.js +0 -78
  1035. package/dist/chunk-BX7A5GUV.js.map +0 -1
  1036. package/dist/chunk-CDA6RYOX.js +0 -115
  1037. package/dist/chunk-CDA6RYOX.js.map +0 -1
  1038. package/dist/chunk-CG7O3A42.js +0 -80
  1039. package/dist/chunk-CG7O3A42.js.map +0 -1
  1040. package/dist/chunk-CIYGNPKT.js +0 -76
  1041. package/dist/chunk-CIYGNPKT.js.map +0 -1
  1042. package/dist/chunk-CKXY4FTV.js +0 -59
  1043. package/dist/chunk-CKXY4FTV.js.map +0 -1
  1044. package/dist/chunk-CVOKZITR.js +0 -82
  1045. package/dist/chunk-CVOKZITR.js.map +0 -1
  1046. package/dist/chunk-CWFMFKDI.js +0 -82
  1047. package/dist/chunk-CWFMFKDI.js.map +0 -1
  1048. package/dist/chunk-CWVKSV7S.js +0 -124
  1049. package/dist/chunk-CWVKSV7S.js.map +0 -1
  1050. package/dist/chunk-CYOLRWOX.js +0 -63
  1051. package/dist/chunk-CYOLRWOX.js.map +0 -1
  1052. package/dist/chunk-D23LRJT6.js +0 -116
  1053. package/dist/chunk-D23LRJT6.js.map +0 -1
  1054. package/dist/chunk-DFADMEJK.js +0 -127
  1055. package/dist/chunk-DFADMEJK.js.map +0 -1
  1056. package/dist/chunk-DKQAHZG2.js +0 -83
  1057. package/dist/chunk-DKQAHZG2.js.map +0 -1
  1058. package/dist/chunk-DW247T3Q.js +0 -199
  1059. package/dist/chunk-DW247T3Q.js.map +0 -1
  1060. package/dist/chunk-E5A7HN6H.js +0 -32
  1061. package/dist/chunk-E5A7HN6H.js.map +0 -1
  1062. package/dist/chunk-EI63GTN7.js +0 -57
  1063. package/dist/chunk-EI63GTN7.js.map +0 -1
  1064. package/dist/chunk-EP25QJ4N.js +0 -146
  1065. package/dist/chunk-EP25QJ4N.js.map +0 -1
  1066. package/dist/chunk-ET44426Q.js +0 -80
  1067. package/dist/chunk-ET44426Q.js.map +0 -1
  1068. package/dist/chunk-ETEIDY34.js +0 -67
  1069. package/dist/chunk-ETEIDY34.js.map +0 -1
  1070. package/dist/chunk-EU55O4P7.js +0 -76
  1071. package/dist/chunk-EU55O4P7.js.map +0 -1
  1072. package/dist/chunk-F436537E.js +0 -104
  1073. package/dist/chunk-F436537E.js.map +0 -1
  1074. package/dist/chunk-FLBTGNQI.js +0 -86
  1075. package/dist/chunk-FLBTGNQI.js.map +0 -1
  1076. package/dist/chunk-FUT45NFW.js +0 -46
  1077. package/dist/chunk-FUT45NFW.js.map +0 -1
  1078. package/dist/chunk-G3LWNTVZ.js +0 -51
  1079. package/dist/chunk-G3LWNTVZ.js.map +0 -1
  1080. package/dist/chunk-GBJB5WLT.js +0 -58
  1081. package/dist/chunk-GBJB5WLT.js.map +0 -1
  1082. package/dist/chunk-GIEPEFRX.js +0 -110
  1083. package/dist/chunk-GIEPEFRX.js.map +0 -1
  1084. package/dist/chunk-GSO7MISR.js +0 -58
  1085. package/dist/chunk-GSO7MISR.js.map +0 -1
  1086. package/dist/chunk-GUQFYUIC.js +0 -61
  1087. package/dist/chunk-GUQFYUIC.js.map +0 -1
  1088. package/dist/chunk-GXBFGWQN.js +0 -81
  1089. package/dist/chunk-GXBFGWQN.js.map +0 -1
  1090. package/dist/chunk-H3VJMFJQ.js +0 -35
  1091. package/dist/chunk-H3VJMFJQ.js.map +0 -1
  1092. package/dist/chunk-HG4WEERE.js +0 -26
  1093. package/dist/chunk-HG4WEERE.js.map +0 -1
  1094. package/dist/chunk-HGPBGLNP.js +0 -51
  1095. package/dist/chunk-HGPBGLNP.js.map +0 -1
  1096. package/dist/chunk-HQFTW7SF.js +0 -141
  1097. package/dist/chunk-HQFTW7SF.js.map +0 -1
  1098. package/dist/chunk-I32I36LW.js +0 -113
  1099. package/dist/chunk-I32I36LW.js.map +0 -1
  1100. package/dist/chunk-I7WYM63C.js +0 -170
  1101. package/dist/chunk-I7WYM63C.js.map +0 -1
  1102. package/dist/chunk-JPTPIZ5V.js +0 -120
  1103. package/dist/chunk-JPTPIZ5V.js.map +0 -1
  1104. package/dist/chunk-JQXLPVWP.js +0 -74
  1105. package/dist/chunk-JQXLPVWP.js.map +0 -1
  1106. package/dist/chunk-K5ARID4S.js +0 -26
  1107. package/dist/chunk-K5ARID4S.js.map +0 -1
  1108. package/dist/chunk-K6RTLPIJ.js +0 -41
  1109. package/dist/chunk-K6RTLPIJ.js.map +0 -1
  1110. package/dist/chunk-K7PYLTMP.js +0 -221
  1111. package/dist/chunk-K7PYLTMP.js.map +0 -1
  1112. package/dist/chunk-KQNKKV2C.js +0 -56
  1113. package/dist/chunk-KQNKKV2C.js.map +0 -1
  1114. package/dist/chunk-KRN4NE4U.js +0 -155
  1115. package/dist/chunk-KRN4NE4U.js.map +0 -1
  1116. package/dist/chunk-L2BI762I.js +0 -82
  1117. package/dist/chunk-L2BI762I.js.map +0 -1
  1118. package/dist/chunk-LEEH63B2.js +0 -56
  1119. package/dist/chunk-LEEH63B2.js.map +0 -1
  1120. package/dist/chunk-LHRWVM3G.js +0 -42
  1121. package/dist/chunk-LHRWVM3G.js.map +0 -1
  1122. package/dist/chunk-LIGWMGXM.js +0 -117
  1123. package/dist/chunk-LIGWMGXM.js.map +0 -1
  1124. package/dist/chunk-LKYSX3QF.js +0 -104
  1125. package/dist/chunk-LKYSX3QF.js.map +0 -1
  1126. package/dist/chunk-MCIFB6VS.js +0 -54
  1127. package/dist/chunk-MCIFB6VS.js.map +0 -1
  1128. package/dist/chunk-MI5CXMZU.js +0 -171
  1129. package/dist/chunk-MI5CXMZU.js.map +0 -1
  1130. package/dist/chunk-MYEHGDC2.js +0 -152
  1131. package/dist/chunk-MYEHGDC2.js.map +0 -1
  1132. package/dist/chunk-NQZYY4LR.js +0 -84
  1133. package/dist/chunk-NQZYY4LR.js.map +0 -1
  1134. package/dist/chunk-O23LKHUR.js +0 -66
  1135. package/dist/chunk-O23LKHUR.js.map +0 -1
  1136. package/dist/chunk-PASI2U2R.js +0 -23
  1137. package/dist/chunk-PASI2U2R.js.map +0 -1
  1138. package/dist/chunk-PPH5NTHV.js +0 -34
  1139. package/dist/chunk-PPH5NTHV.js.map +0 -1
  1140. package/dist/chunk-PR6OZF6D.js +0 -28
  1141. package/dist/chunk-PR6OZF6D.js.map +0 -1
  1142. package/dist/chunk-PTHRL242.js +0 -186
  1143. package/dist/chunk-PTHRL242.js.map +0 -1
  1144. package/dist/chunk-PWXOXPFT.js +0 -142
  1145. package/dist/chunk-PWXOXPFT.js.map +0 -1
  1146. package/dist/chunk-QB6BNHO3.js +0 -112
  1147. package/dist/chunk-QB6BNHO3.js.map +0 -1
  1148. package/dist/chunk-QJGGTIUN.js +0 -110
  1149. package/dist/chunk-QJGGTIUN.js.map +0 -1
  1150. package/dist/chunk-QSOIJ6J3.js +0 -91
  1151. package/dist/chunk-QSOIJ6J3.js.map +0 -1
  1152. package/dist/chunk-R63ZKLQM.js +0 -45
  1153. package/dist/chunk-R63ZKLQM.js.map +0 -1
  1154. package/dist/chunk-RC5XME4T.js +0 -33
  1155. package/dist/chunk-RC5XME4T.js.map +0 -1
  1156. package/dist/chunk-RTYYJPPE.js +0 -77
  1157. package/dist/chunk-RTYYJPPE.js.map +0 -1
  1158. package/dist/chunk-RVOBP7PO.js +0 -116
  1159. package/dist/chunk-RVOBP7PO.js.map +0 -1
  1160. package/dist/chunk-SF6R5VMQ.js +0 -97
  1161. package/dist/chunk-SF6R5VMQ.js.map +0 -1
  1162. package/dist/chunk-SP4CP5HY.js +0 -57
  1163. package/dist/chunk-SP4CP5HY.js.map +0 -1
  1164. package/dist/chunk-SWJ4EUOI.js +0 -30
  1165. package/dist/chunk-SWJ4EUOI.js.map +0 -1
  1166. package/dist/chunk-TK24HQJJ.js +0 -128
  1167. package/dist/chunk-TK24HQJJ.js.map +0 -1
  1168. package/dist/chunk-UAYOOTRR.js +0 -77
  1169. package/dist/chunk-UAYOOTRR.js.map +0 -1
  1170. package/dist/chunk-UDTAMHXW.js +0 -55
  1171. package/dist/chunk-UDTAMHXW.js.map +0 -1
  1172. package/dist/chunk-UK27KR35.js +0 -73
  1173. package/dist/chunk-UK27KR35.js.map +0 -1
  1174. package/dist/chunk-UOMQPIB4.js +0 -48
  1175. package/dist/chunk-UOMQPIB4.js.map +0 -1
  1176. package/dist/chunk-UOXU7NDY.js +0 -120
  1177. package/dist/chunk-UOXU7NDY.js.map +0 -1
  1178. package/dist/chunk-V7OOTVK3.js +0 -106
  1179. package/dist/chunk-V7OOTVK3.js.map +0 -1
  1180. package/dist/chunk-VI5M7KJ2.js +0 -1022
  1181. package/dist/chunk-VI5M7KJ2.js.map +0 -1
  1182. package/dist/chunk-VMMATOPE.js +0 -64
  1183. package/dist/chunk-VMMATOPE.js.map +0 -1
  1184. package/dist/chunk-W2PVSIW3.js +0 -89
  1185. package/dist/chunk-W2PVSIW3.js.map +0 -1
  1186. package/dist/chunk-W3DUDZDU.js +0 -88
  1187. package/dist/chunk-W3DUDZDU.js.map +0 -1
  1188. package/dist/chunk-WKEUU2FU.js +0 -114
  1189. package/dist/chunk-WKEUU2FU.js.map +0 -1
  1190. package/dist/chunk-WKLW7RC6.js +0 -28
  1191. package/dist/chunk-WKLW7RC6.js.map +0 -1
  1192. package/dist/chunk-WSJGZNUH.js +0 -111
  1193. package/dist/chunk-WSJGZNUH.js.map +0 -1
  1194. package/dist/chunk-WVPDQMC2.js +0 -144
  1195. package/dist/chunk-WVPDQMC2.js.map +0 -1
  1196. package/dist/chunk-WWNH5ENT.js +0 -43
  1197. package/dist/chunk-WWNH5ENT.js.map +0 -1
  1198. package/dist/chunk-X5L62PXY.js +0 -112
  1199. package/dist/chunk-X5L62PXY.js.map +0 -1
  1200. package/dist/chunk-XGCV5E6W.js +0 -133
  1201. package/dist/chunk-XGCV5E6W.js.map +0 -1
  1202. package/dist/chunk-XRKIEL5M.js +0 -72
  1203. package/dist/chunk-XRKIEL5M.js.map +0 -1
  1204. package/dist/chunk-XUJYEADU.js +0 -80
  1205. package/dist/chunk-XUJYEADU.js.map +0 -1
  1206. package/dist/chunk-XVYNSIQC.js +0 -116
  1207. package/dist/chunk-XVYNSIQC.js.map +0 -1
  1208. package/dist/chunk-XWTISHXO.js +0 -54
  1209. package/dist/chunk-XWTISHXO.js.map +0 -1
  1210. package/dist/chunk-XZKEGEPT.js +0 -156
  1211. package/dist/chunk-XZKEGEPT.js.map +0 -1
  1212. package/dist/chunk-YOGHS4UU.js +0 -202
  1213. package/dist/chunk-YOGHS4UU.js.map +0 -1
  1214. package/dist/chunk-YRSKXEOD.js +0 -135
  1215. package/dist/chunk-YRSKXEOD.js.map +0 -1
  1216. package/dist/chunk-ZALLCR7X.js +0 -108
  1217. package/dist/chunk-ZALLCR7X.js.map +0 -1
  1218. package/dist/chunk-ZDAOHMCW.js +0 -46
  1219. package/dist/chunk-ZDAOHMCW.js.map +0 -1
  1220. package/dist/chunk-ZESICCKK.js +0 -37
  1221. package/dist/chunk-ZESICCKK.js.map +0 -1
  1222. package/dist/chunk-ZIKFOD6N.js +0 -87
  1223. package/dist/chunk-ZIKFOD6N.js.map +0 -1
  1224. package/dist/chunk-ZJRWCQEN.js +0 -76
  1225. package/dist/chunk-ZJRWCQEN.js.map +0 -1
  1226. package/dist/chunk-ZSRJCIWF.js +0 -24
  1227. package/dist/chunk-ZSRJCIWF.js.map +0 -1
  1228. package/dist/plugin-Atb0VKtr.d.ts +0 -172
  1229. package/dist/slide/index.d.ts +0 -212
  1230. package/dist/slide/plugins/emoji/index.d.ts +0 -29
  1231. package/dist/slide/plugins/math/index.d.ts +0 -13
  1232. package/dist/slide/plugins/mermaid/index.d.ts +0 -55
  1233. package/dist/slide/plugins/shiki/index.d.ts +0 -18
  1234. package/dist/slide-deck/index.d.ts +0 -377
  1235. package/dist/whiteboard/index.d.ts +0 -258
@@ -0,0 +1,15 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "env",
4
+ "type": "registry:lib",
5
+ "title": "Environment helpers",
6
+ "description": "Typed environment helpers (isDev / isProd) reading NODE_ENV through a single accessor that works in browser bundlers, Node/SSR, and unbundled browsers.",
7
+ "files": [
8
+ {
9
+ "path": "lib/env.ts",
10
+ "type": "registry:lib",
11
+ "target": "lib/env.ts",
12
+ "content": "/**\n * Environment helpers — type-safe, browser- and SSR-safe.\n *\n * Why this exists\n * ---------------\n * Component source files in this package need to gate development-only\n * diagnostics (a11y warnings, dev-only `console.warn`, defensive validation\n * messages) on `process.env.NODE_ENV`. Reading `process.env.NODE_ENV`\n * directly in TypeScript triggers `TS2591: Cannot find name 'process'`\n * unless `@types/node` is included in `tsconfig.json#compilerOptions.types`.\n *\n * Adding `node` to that array would work — but it pollutes the ambient\n * global namespace with Node-only APIs (`Buffer`, `fs`, `path`, `Stream`)\n * that have no place in a UI library targeting the browser. Authors would\n * receive autocomplete for `import { readFileSync } from \"node:fs\"` while\n * writing a React component. That is the wrong trade.\n *\n * The conventional pattern (React, Radix, Stripe Elements, MUI) is to\n * funnel every `NODE_ENV` read through a single typed accessor. Bundlers\n * (Vite, Webpack, esbuild, Rollup, tsup) replace the literal\n * `process.env.NODE_ENV` reference at build time via their `define`\n * mechanism, so this incurs zero runtime cost in the consumer's\n * production build — the dead branch is dead-code-eliminated.\n *\n * Read access is funneled through `globalThis.process?.env?.NODE_ENV`\n * so the helpers work in three environments without ambient types:\n *\n * - Browser via bundler with `define` (Vite/Webpack): the literal\n * `process.env.NODE_ENV` is substituted; `globalThis.process` is the\n * synthesized stub the bundler injects.\n * - Node (SSR, tests, scripts): `globalThis.process` is the real `process`.\n * - Browser without bundler injection: `globalThis.process` is undefined\n * and {@link isDev} returns `true` so developers see warnings during\n * hand-testing rather than silent failure.\n */\n\ninterface NodeEnvCarrier {\n process?: {\n env?: {\n NODE_ENV?: string;\n };\n };\n}\n\nfunction readNodeEnv(): string | undefined {\n return (globalThis as NodeEnvCarrier).process?.env?.NODE_ENV;\n}\n\n/**\n * Returns `true` unless `process.env.NODE_ENV === \"production\"`.\n *\n * Use this to gate development-only branches: a11y warnings, dev-mode\n * `console.warn`, defensive runtime validation. In a consumer's production\n * build the bundler replaces the substituted reference and tree-shakes the\n * dev branch entirely.\n *\n * Defensive default: when `process` is absent (browser without bundler\n * injection), returns `true` to err on the side of more diagnostics.\n */\nexport function isDev(): boolean {\n return readNodeEnv() !== \"production\";\n}\n\n/**\n * Returns `true` only when `process.env.NODE_ENV === \"production\"`.\n *\n * Strict inverse of {@link isDev}: when `process` is absent, returns\n * `false`. Use this when you specifically need to confirm a production\n * build (e.g. enabling minified-only optimizations).\n */\nexport function isProd(): boolean {\n return readNodeEnv() === \"production\";\n}\n"
13
+ }
14
+ ]
15
+ }
@@ -17,7 +17,7 @@
17
17
  "path": "components/primitives/folder-context-card/folder-context-card.tsx",
18
18
  "type": "registry:ui",
19
19
  "target": "components/ui/folder-context-card.tsx",
20
- "content": "import { ChevronRight, File, Folder } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport type { IconComponent } from \"@/lib/types\";\n\nexport interface FolderEntry {\n id: string;\n name: string;\n kind: \"folder\" | \"file\";\n /**\n * If true, the entry is expanded (icons + nested children).\n * Pure visual flag; toggling is the caller's job.\n */\n open?: boolean;\n /**\n * Optional nested entries when this is a folder.\n */\n children?: FolderEntry[];\n /** Optional adornment after the name (badge, modified indicator). */\n trailing?: ReactNode;\n /** Override the icon. */\n icon?: IconComponent;\n}\n\ninterface FolderContextCardProps extends Omit<HTMLAttributes<HTMLElement>, \"title\"> {\n title?: ReactNode;\n /**\n * Root entries shown directly in the card.\n */\n entries: FolderEntry[];\n /**\n * Fires when an entry row is clicked.\n */\n onEntryClick?: (id: string) => void;\n}\n\n/**\n * FolderContextCard — file/folder tree fragment for the right inspector.\n *\n * Visual: 1-level tree with chevron indicating expanded state. Renders nested\n * children recursively, but does not manage open state — caller controls\n * `entry.open` and reacts to `onEntryClick`.\n */\nconst FolderContextCard = forwardRef<HTMLElement, FolderContextCardProps>(\n ({ className, title, entries, onEntryClick, ...props }, ref) => (\n <section ref={ref} className={cn(\"rounded-xl border bg-card p-4\", className)} {...props}>\n {title ? (\n <header className=\"mb-3 flex items-center justify-between\">\n <h3 className=\"font-display text-title-md tracking-tight\">{title}</h3>\n </header>\n ) : null}\n <Tree entries={entries} {...(onEntryClick ? { onEntryClick } : {})} depth={0} />\n </section>\n ),\n);\nFolderContextCard.displayName = \"FolderContextCard\";\n\nfunction Tree({\n entries,\n onEntryClick,\n depth,\n}: {\n entries: FolderEntry[];\n onEntryClick?: (id: string) => void;\n depth: number;\n}) {\n return (\n <ul className={cn(\"grid\", depth === 0 ? \"gap-0.5\" : \"gap-0\")}>\n {entries.map((entry) => {\n const IconComp = entry.icon ?? (entry.kind === \"folder\" ? Folder : File);\n const hasChildren = entry.kind === \"folder\" && entry.children && entry.children.length > 0;\n return (\n <li key={entry.id}>\n <button\n type=\"button\"\n onClick={() => onEntryClick?.(entry.id)}\n className={cn(\n \"flex w-full items-center gap-2 rounded-md px-2 py-1.5\",\n \"font-sans text-body-sm text-foreground\",\n \"transition-colors hover:bg-muted\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n )}\n style={{ paddingLeft: `${0.5 + depth * 0.9}rem` }}\n >\n {hasChildren ? (\n <ChevronRight\n className={cn(\n \"size-3 shrink-0 text-muted-foreground transition-transform\",\n entry.open && \"rotate-90\",\n )}\n aria-hidden=\"true\"\n />\n ) : (\n <span className=\"w-3\" aria-hidden=\"true\" />\n )}\n <IconComp\n className={cn(\n \"size-4 shrink-0\",\n entry.kind === \"folder\" ? \"text-primary\" : \"text-muted-foreground\",\n )}\n aria-hidden=\"true\"\n />\n <span className=\"flex-1 truncate text-left\">{entry.name}</span>\n {entry.trailing}\n </button>\n {hasChildren && entry.open ? (\n <Tree\n entries={entry.children as FolderEntry[]}\n {...(onEntryClick ? { onEntryClick } : {})}\n depth={depth + 1}\n />\n ) : null}\n </li>\n );\n })}\n </ul>\n );\n}\n\nexport { FolderContextCard };\n"
20
+ "content": "import { ChevronRight, File, Folder } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport type { IconComponent } from \"@/lib/types\";\n\nexport interface FolderEntry {\n id: string;\n name: string;\n kind: \"folder\" | \"file\";\n /**\n * If true, the entry is expanded (icons + nested children).\n * Pure visual flag; toggling is the caller's job.\n */\n open?: boolean;\n /**\n * Optional nested entries when this is a folder.\n */\n children?: FolderEntry[];\n /** Optional adornment after the name (badge, modified indicator). */\n trailing?: ReactNode;\n /** Override the icon. */\n icon?: IconComponent;\n}\n\ninterface FolderContextCardProps extends Omit<HTMLAttributes<HTMLElement>, \"title\"> {\n title?: ReactNode;\n /**\n * Root entries shown directly in the card.\n */\n entries: FolderEntry[];\n /**\n * Fires when an entry row is clicked.\n */\n onEntryClick?: (id: string) => void;\n}\n\n/**\n * FolderContextCard — file/folder tree fragment for the right inspector.\n *\n * Visual: 1-level tree with chevron indicating expanded state. Renders nested\n * children recursively, but does not manage open state — caller controls\n * `entry.open` and reacts to `onEntryClick`.\n */\nconst FolderContextCard = forwardRef<HTMLElement, FolderContextCardProps>(\n ({ className, title, entries, onEntryClick, ...props }, ref) => (\n <section\n data-slot=\"folder-context-card\"\n ref={ref}\n className={cn(\"rounded-xl border bg-card p-4\", className)}\n {...props}\n >\n {title ? (\n <header className=\"mb-3 flex items-center justify-between\">\n <h3 className=\"font-display text-title-md tracking-tight\">{title}</h3>\n </header>\n ) : null}\n <Tree entries={entries} {...(onEntryClick ? { onEntryClick } : {})} depth={0} />\n </section>\n ),\n);\nFolderContextCard.displayName = \"FolderContextCard\";\n\nfunction Tree({\n entries,\n onEntryClick,\n depth,\n}: {\n entries: FolderEntry[];\n onEntryClick?: (id: string) => void;\n depth: number;\n}) {\n return (\n <ul className={cn(\"grid\", depth === 0 ? \"gap-0.5\" : \"gap-0\")}>\n {entries.map((entry) => {\n const IconComp = entry.icon ?? (entry.kind === \"folder\" ? Folder : File);\n const hasChildren = entry.kind === \"folder\" && entry.children && entry.children.length > 0;\n return (\n <li key={entry.id}>\n <button\n type=\"button\"\n onClick={() => onEntryClick?.(entry.id)}\n className={cn(\n \"flex w-full items-center gap-2 rounded-md px-2 py-1.5\",\n \"font-sans text-body-sm text-foreground\",\n \"transition-colors hover:bg-muted\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n )}\n style={{ paddingLeft: `${0.5 + depth * 0.9}rem` }}\n >\n {hasChildren ? (\n <ChevronRight\n className={cn(\n \"size-3 shrink-0 text-muted-foreground transition-transform\",\n entry.open && \"rotate-90\",\n )}\n aria-hidden=\"true\"\n />\n ) : (\n <span className=\"w-3\" aria-hidden=\"true\" />\n )}\n <IconComp\n className={cn(\n \"size-4 shrink-0\",\n entry.kind === \"folder\" ? \"text-primary\" : \"text-muted-foreground\",\n )}\n aria-hidden=\"true\"\n />\n <span className=\"flex-1 truncate text-left\">{entry.name}</span>\n {entry.trailing}\n </button>\n {hasChildren && entry.open ? (\n <Tree\n entries={entry.children as FolderEntry[]}\n {...(onEntryClick ? { onEntryClick } : {})}\n depth={depth + 1}\n />\n ) : null}\n </li>\n );\n })}\n </ul>\n );\n}\n\nexport { FolderContextCard };\n"
21
21
  }
22
22
  ]
23
23
  }
@@ -16,7 +16,7 @@
16
16
  "path": "components/primitives/folder-selector/folder-selector.tsx",
17
17
  "type": "registry:ui",
18
18
  "target": "components/ui/folder-selector.tsx",
19
- "content": "import { ChevronDown, Folder } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { ButtonHTMLAttributes } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\ninterface FolderSelectorProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** Currently selected absolute path. */\n path: string;\n /**\n * Render in compact mode (smaller height, no chevron padding).\n * Default is the full-width composer variant used in the Files panel.\n */\n compact?: boolean;\n}\n\n/**\n * FolderSelector — chip showing the active working directory.\n *\n * Visual: folder icon + monospaced path (truncated middle) + chevron.\n * Stateless: caller handles the actual folder-picker dialog.\n */\nconst FolderSelector = forwardRef<HTMLButtonElement, FolderSelectorProps>(\n ({ className, path, compact, ...props }, ref) => (\n <button\n ref={ref}\n type=\"button\"\n className={cn(\n \"inline-flex items-center gap-2 rounded-lg border border-border/60 bg-card\",\n \"font-mono text-code-sm text-foreground\",\n \"transition-colors duration-base ease-out-soft\",\n \"hover:border-primary/40 hover:bg-muted\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n compact ? \"h-8 px-2.5\" : \"h-10 px-3\",\n className,\n )}\n {...props}\n >\n <Folder className=\"size-4 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n <span className=\"min-w-0 flex-1 truncate text-left\">{path}</span>\n <ChevronDown className=\"size-3 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n </button>\n ),\n);\nFolderSelector.displayName = \"FolderSelector\";\n\nexport { FolderSelector };\n"
19
+ "content": "import { ChevronDown, Folder } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { ButtonHTMLAttributes } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\ninterface FolderSelectorProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** Currently selected absolute path. */\n path: string;\n /**\n * Render in compact mode (smaller height, no chevron padding).\n * Default is the full-width composer variant used in the Files panel.\n */\n compact?: boolean;\n}\n\n/**\n * FolderSelector — chip showing the active working directory.\n *\n * Visual: folder icon + monospaced path (truncated middle) + chevron.\n * Stateless: caller handles the actual folder-picker dialog.\n */\nconst FolderSelector = forwardRef<HTMLButtonElement, FolderSelectorProps>(\n ({ className, path, compact, ...props }, ref) => (\n <button\n data-slot=\"folder-selector\"\n ref={ref}\n type=\"button\"\n className={cn(\n \"inline-flex items-center gap-2 rounded-lg border border-border/60 bg-card\",\n \"font-mono text-code-sm text-foreground\",\n \"transition-colors duration-base ease-out-soft\",\n \"hover:border-primary/40 hover:bg-muted\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n compact ? \"h-8 px-2.5\" : \"h-10 px-3\",\n className,\n )}\n {...props}\n >\n <Folder className=\"size-4 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n <span className=\"min-w-0 flex-1 truncate text-left\">{path}</span>\n <ChevronDown className=\"size-3 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n </button>\n ),\n);\nFolderSelector.displayName = \"FolderSelector\";\n\nexport { FolderSelector };\n"
20
20
  }
21
21
  ]
22
22
  }
@@ -17,7 +17,7 @@
17
17
  "path": "components/primitives/form-field/form-field.tsx",
18
18
  "type": "registry:ui",
19
19
  "target": "components/ui/form-field.tsx",
20
- "content": "import * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { AlertCircle } from \"lucide-react\";\nimport {\n Children,\n cloneElement,\n createContext,\n forwardRef,\n isValidElement,\n useContext,\n useId,\n} from \"react\";\nimport type {\n ComponentPropsWithoutRef,\n ElementRef,\n HTMLAttributes,\n ReactElement,\n ReactNode,\n} from \"react\";\nimport { cn } from \"@/lib/cn\";\n\n/**\n * FormField — composition wrapper for accessible form rows.\n *\n * Provides context with a generated `id`, so children (Label, Input, Hint,\n * Error) wire themselves via `htmlFor` / `id` / `aria-describedby` without\n * the consumer having to thread IDs manually.\n *\n * Composition:\n * <FormField>\n * <FormField.Label required>Email</FormField.Label>\n * <FormField.Control>\n * <Input type=\"email\" placeholder=\"…\" />\n * </FormField.Control>\n * <FormField.Hint>We never share your email.</FormField.Hint>\n * <FormField.Error>{error}</FormField.Error>\n * </FormField>\n *\n * Errors take precedence over hints (only one of them shows at once).\n */\n\ntype FormFieldSize = \"sm\" | \"md\" | \"lg\";\n\ninterface FormFieldContextValue {\n fieldId: string;\n hintId: string;\n errorId: string;\n hasError: boolean;\n size: FormFieldSize;\n}\n\nconst FormFieldContext = createContext<FormFieldContextValue | null>(null);\n\nfunction useFormField(): FormFieldContextValue {\n const ctx = useContext(FormFieldContext);\n if (!ctx) throw new Error(\"FormField subcomponents must be inside <FormField>.\");\n return ctx;\n}\n\ninterface FormFieldProps extends HTMLAttributes<HTMLDivElement> {\n /** Optional explicit id override. */\n id?: string;\n /** Marks the field as invalid; switches Hint → Error and toggles aria. */\n invalid?: boolean;\n /**\n * Size scale propagated to Label / Hint / Error subparts via Context.\n * Default `md` preserves prior behavior. Subparts do NOT accept a `size`\n * prop of their own — use `className` for granular tweaks (EC-8).\n */\n size?: FormFieldSize;\n}\n\nconst rootGapBySize: Record<FormFieldSize, string> = {\n sm: \"gap-1\",\n md: \"gap-1.5\",\n lg: \"gap-2\",\n};\n\nconst FormFieldRoot = forwardRef<HTMLDivElement, FormFieldProps>(\n ({ className, id: idProp, invalid, size = \"md\", ...props }, ref) => {\n const auto = useId();\n const fieldId = idProp ?? `field-${auto}`;\n const ctx: FormFieldContextValue = {\n fieldId,\n hintId: `${fieldId}-hint`,\n errorId: `${fieldId}-error`,\n hasError: !!invalid,\n size,\n };\n return (\n <FormFieldContext.Provider value={ctx}>\n <div ref={ref} className={cn(\"grid\", rootGapBySize[size], className)} {...props} />\n </FormFieldContext.Provider>\n );\n },\n);\nFormFieldRoot.displayName = \"FormField\";\n\nconst labelFontBySize: Record<FormFieldSize, string> = {\n sm: \"text-label-caps\",\n md: \"text-body-sm\",\n lg: \"text-body-md\",\n};\n\nconst hintFontBySize: Record<FormFieldSize, string> = {\n sm: \"text-label-caps\",\n md: \"text-body-sm\",\n lg: \"text-body-md\",\n};\n\ninterface FormFieldLabelProps extends ComponentPropsWithoutRef<typeof LabelPrimitive.Root> {\n required?: boolean;\n}\n\n// Inlined label markup (was importing `<Label>` from sibling primitive).\n// BLOCKER-001 / D2: form-field stays in primitives/ but cannot cross-import.\n// Uses the same Radix LabelPrimitive primitive that the standalone `<Label>`\n// uses, with identical Tailwind tokens — visual parity is preserved.\nconst FormFieldLabel = forwardRef<ElementRef<typeof LabelPrimitive.Root>, FormFieldLabelProps>(\n ({ className, required, children, ...props }, ref) => {\n const { fieldId, size } = useFormField();\n return (\n <LabelPrimitive.Root\n ref={ref}\n htmlFor={fieldId}\n className={cn(\n \"inline-flex items-center gap-1 font-medium font-sans text-foreground\",\n labelFontBySize[size],\n \"peer-disabled:cursor-not-allowed peer-disabled:opacity-60\",\n className,\n )}\n {...props}\n >\n {children}\n {required ? (\n <span className=\"text-destructive\" aria-hidden=\"true\">\n *\n </span>\n ) : null}\n </LabelPrimitive.Root>\n );\n },\n);\nFormFieldLabel.displayName = \"FormField.Label\";\n\nconst FormFieldControl = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(\n ({ children, ...props }, ref) => {\n const { fieldId, hintId, errorId, hasError } = useFormField();\n const described = hasError ? errorId : hintId;\n // Children.only enforces exactly one child element (the form control) so we\n // can safely clone it with the wiring props (id + aria-describedby + aria-invalid).\n // The previous implementation spread the element object directly which relied\n // on React's internal `$$typeof` invariant and silently dropped `ref` — the\n // cloneElement path preserves both `ref` and `key`.\n const only = Children.only(children) as ReactElement;\n const cloned = isValidElement(only)\n ? cloneElement(only, {\n id: fieldId,\n \"aria-describedby\": described,\n \"aria-invalid\": hasError || undefined,\n } as Partial<typeof only.props>)\n : only;\n return (\n <div ref={ref} {...props}>\n {cloned}\n </div>\n );\n },\n);\nFormFieldControl.displayName = \"FormField.Control\";\n\nconst FormFieldHint = forwardRef<HTMLParagraphElement, HTMLAttributes<HTMLParagraphElement>>(\n ({ className, children, ...props }, ref) => {\n const { hintId, hasError, size } = useFormField();\n if (hasError) return null;\n return (\n <p\n ref={ref}\n id={hintId}\n className={cn(\"text-muted-foreground\", hintFontBySize[size], className)}\n {...props}\n >\n {children}\n </p>\n );\n },\n);\nFormFieldHint.displayName = \"FormField.Hint\";\n\nconst FormFieldError = forwardRef<HTMLParagraphElement, HTMLAttributes<HTMLParagraphElement>>(\n ({ className, children, ...props }, ref) => {\n const { errorId, hasError, size } = useFormField();\n if (!hasError) return null;\n return (\n <p\n ref={ref}\n id={errorId}\n role=\"alert\"\n className={cn(\"flex items-center gap-1 text-destructive\", hintFontBySize[size], className)}\n {...props}\n >\n <AlertCircle className=\"size-3.5 shrink-0\" aria-hidden=\"true\" />\n {children as ReactNode}\n </p>\n );\n },\n);\nFormFieldError.displayName = \"FormField.Error\";\n\nconst FormField = /*#__PURE__*/ Object.assign(FormFieldRoot, {\n Label: FormFieldLabel,\n Control: FormFieldControl,\n Hint: FormFieldHint,\n Error: FormFieldError,\n});\n\nexport { FormField };\n"
20
+ "content": "\"use client\";\n\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { AlertCircle } from \"lucide-react\";\nimport {\n Children,\n cloneElement,\n createContext,\n forwardRef,\n isValidElement,\n useContext,\n useId,\n} from \"react\";\nimport type {\n ComponentPropsWithoutRef,\n ElementRef,\n HTMLAttributes,\n ReactElement,\n ReactNode,\n} from \"react\";\nimport { cn } from \"@/lib/cn\";\n\n/**\n * FormField — composition wrapper for accessible form rows.\n *\n * Provides context with a generated `id`, so children (Label, Input, Hint,\n * Error) wire themselves via `htmlFor` / `id` / `aria-describedby` without\n * the consumer having to thread IDs manually.\n *\n * Composition:\n * <FormField>\n * <FormField.Label required>Email</FormField.Label>\n * <FormField.Control>\n * <Input type=\"email\" placeholder=\"…\" />\n * </FormField.Control>\n * <FormField.Hint>We never share your email.</FormField.Hint>\n * <FormField.Error>{error}</FormField.Error>\n * </FormField>\n *\n * Errors take precedence over hints (only one of them shows at once).\n */\n\ntype FormFieldSize = \"sm\" | \"md\" | \"lg\";\n\ninterface FormFieldContextValue {\n fieldId: string;\n hintId: string;\n errorId: string;\n hasError: boolean;\n size: FormFieldSize;\n}\n\nconst FormFieldContext = createContext<FormFieldContextValue | null>(null);\n\nfunction useFormField(): FormFieldContextValue {\n const ctx = useContext(FormFieldContext);\n if (!ctx) throw new Error(\"FormField subcomponents must be inside <FormField>.\");\n return ctx;\n}\n\ninterface FormFieldProps extends HTMLAttributes<HTMLDivElement> {\n /** Optional explicit id override. */\n id?: string;\n /** Marks the field as invalid; switches Hint → Error and toggles aria. */\n invalid?: boolean;\n /**\n * Size scale propagated to Label / Hint / Error subparts via Context.\n * Default `md` preserves prior behavior. Subparts do NOT accept a `size`\n * prop of their own — use `className` for granular tweaks (EC-8).\n */\n size?: FormFieldSize;\n}\n\nconst rootGapBySize: Record<FormFieldSize, string> = {\n sm: \"gap-1\",\n md: \"gap-1.5\",\n lg: \"gap-2\",\n};\n\nconst FormFieldRoot = forwardRef<HTMLDivElement, FormFieldProps>(\n ({ className, id: idProp, invalid, size = \"md\", ...props }, ref) => {\n const auto = useId();\n const fieldId = idProp ?? `field-${auto}`;\n const ctx: FormFieldContextValue = {\n fieldId,\n hintId: `${fieldId}-hint`,\n errorId: `${fieldId}-error`,\n hasError: !!invalid,\n size,\n };\n return (\n <FormFieldContext.Provider value={ctx}>\n <div\n data-slot=\"form-field\"\n ref={ref}\n className={cn(\"grid\", rootGapBySize[size], className)}\n {...props}\n />\n </FormFieldContext.Provider>\n );\n },\n);\nFormFieldRoot.displayName = \"FormField\";\n\nconst labelFontBySize: Record<FormFieldSize, string> = {\n sm: \"text-label-caps\",\n md: \"text-body-sm\",\n lg: \"text-body-md\",\n};\n\nconst hintFontBySize: Record<FormFieldSize, string> = {\n sm: \"text-label-caps\",\n md: \"text-body-sm\",\n lg: \"text-body-md\",\n};\n\ninterface FormFieldLabelProps extends ComponentPropsWithoutRef<typeof LabelPrimitive.Root> {\n required?: boolean;\n}\n\n// Inlined label markup (was importing `<Label>` from sibling primitive).\n// BLOCKER-001 / D2: form-field stays in primitives/ but cannot cross-import.\n// Uses the same Radix LabelPrimitive primitive that the standalone `<Label>`\n// uses, with identical Tailwind tokens — visual parity is preserved.\nconst FormFieldLabel = forwardRef<ElementRef<typeof LabelPrimitive.Root>, FormFieldLabelProps>(\n ({ className, required, children, ...props }, ref) => {\n const { fieldId, size } = useFormField();\n return (\n <LabelPrimitive.Root\n data-slot=\"form-field-label\"\n ref={ref}\n htmlFor={fieldId}\n className={cn(\n \"inline-flex items-center gap-1 font-medium font-sans text-foreground\",\n labelFontBySize[size],\n \"peer-disabled:cursor-not-allowed peer-disabled:opacity-60\",\n className,\n )}\n {...props}\n >\n {children}\n {required ? (\n <span className=\"text-destructive\" aria-hidden=\"true\">\n *\n </span>\n ) : null}\n </LabelPrimitive.Root>\n );\n },\n);\nFormFieldLabel.displayName = \"FormField.Label\";\n\nconst FormFieldControl = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(\n ({ children, ...props }, ref) => {\n const { fieldId, hintId, errorId, hasError } = useFormField();\n const described = hasError ? errorId : hintId;\n // Children.only enforces exactly one child element (the form control) so we\n // can safely clone it with the wiring props (id + aria-describedby + aria-invalid).\n // The previous implementation spread the element object directly which relied\n // on React's internal `$$typeof` invariant and silently dropped `ref` — the\n // cloneElement path preserves both `ref` and `key`.\n const only = Children.only(children) as ReactElement;\n const cloned = isValidElement(only)\n ? cloneElement(only, {\n id: fieldId,\n \"aria-describedby\": described,\n \"aria-invalid\": hasError || undefined,\n } as Partial<typeof only.props>)\n : only;\n return (\n <div data-slot=\"form-field-control\" ref={ref} {...props}>\n {cloned}\n </div>\n );\n },\n);\nFormFieldControl.displayName = \"FormField.Control\";\n\nconst FormFieldHint = forwardRef<HTMLParagraphElement, HTMLAttributes<HTMLParagraphElement>>(\n ({ className, children, ...props }, ref) => {\n const { hintId, hasError, size } = useFormField();\n if (hasError) return null;\n return (\n <p\n data-slot=\"form-field-hint\"\n ref={ref}\n id={hintId}\n className={cn(\"text-muted-foreground\", hintFontBySize[size], className)}\n {...props}\n >\n {children}\n </p>\n );\n },\n);\nFormFieldHint.displayName = \"FormField.Hint\";\n\nconst FormFieldError = forwardRef<HTMLParagraphElement, HTMLAttributes<HTMLParagraphElement>>(\n ({ className, children, ...props }, ref) => {\n const { errorId, hasError, size } = useFormField();\n if (!hasError) return null;\n return (\n <p\n data-slot=\"form-field-error\"\n ref={ref}\n id={errorId}\n role=\"alert\"\n className={cn(\"flex items-center gap-1 text-destructive\", hintFontBySize[size], className)}\n {...props}\n >\n <AlertCircle className=\"size-3.5 shrink-0\" aria-hidden=\"true\" />\n {children as ReactNode}\n </p>\n );\n },\n);\nFormFieldError.displayName = \"FormField.Error\";\n\nconst FormField = /*#__PURE__*/ Object.assign(FormFieldRoot, {\n Label: FormFieldLabel,\n Control: FormFieldControl,\n Hint: FormFieldHint,\n Error: FormFieldError,\n});\n\nexport { FormField };\n"
21
21
  }
22
22
  ]
23
23
  }
@@ -16,7 +16,7 @@
16
16
  "path": "components/primitives/hook-config/hook-config.tsx",
17
17
  "type": "registry:ui",
18
18
  "target": "components/ui/hook-config.tsx",
19
- "content": "import { Plus, Trash2, Zap } from \"lucide-react\";\nimport { forwardRef, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\nexport type HookEvent =\n | \"PreToolUse\"\n | \"PostToolUse\"\n | \"UserPromptSubmit\"\n | \"Stop\"\n | \"SessionStart\"\n | \"SessionEnd\";\n\nexport interface HookEntry {\n id: string;\n event: HookEvent;\n /** Tool matcher (e.g. \"Bash\", \"Write\", \"*\"). */\n matcher: string;\n /** Shell command to run. */\n command: string;\n enabled?: boolean;\n}\n\nconst HOOK_EVENTS: HookEvent[] = [\n \"PreToolUse\",\n \"PostToolUse\",\n \"UserPromptSubmit\",\n \"Stop\",\n \"SessionStart\",\n \"SessionEnd\",\n];\n\ninterface HookConfigProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\" | \"onToggle\"> {\n hooks: HookEntry[];\n onAdd?: (hook: Omit<HookEntry, \"id\">) => void;\n onRemove?: (id: string) => void;\n onToggle?: (id: string, enabled: boolean) => void;\n title?: ReactNode;\n}\n\n/**\n * HookConfig — editor for lifecycle hooks (PreToolUse, PostToolUse, Stop…).\n *\n * Mirrors Claude Code's settings.json hooks but visual. Each row is an\n * { event × matcher × command } triple with on/off toggle.\n */\nconst HookConfig = forwardRef<HTMLDivElement, HookConfigProps>(\n ({ className, hooks, onAdd, onRemove, onToggle, title = \"Hooks\", ...props }, ref) => {\n const [event, setEvent] = useState<HookEvent>(\"PreToolUse\");\n const [matcher, setMatcher] = useState(\"*\");\n const [command, setCommand] = useState(\"\");\n\n const submit = () => {\n if (!command.trim()) return;\n onAdd?.({ event, matcher: matcher.trim() || \"*\", command: command.trim() });\n setCommand(\"\");\n };\n\n return (\n <section ref={ref} className={cn(\"rounded-xl border bg-card\", className)} {...props}>\n <header className=\"flex items-baseline justify-between border-border/40 border-b px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n <Zap className=\"size-4 text-primary\" aria-hidden=\"true\" />\n <h3 className=\"font-display text-title-md tracking-tight\">{title}</h3>\n </div>\n <span className=\"font-mono text-label text-muted-foreground\">\n {hooks.length} {hooks.length === 1 ? \"hook\" : \"hooks\"}\n </span>\n </header>\n\n {onAdd ? (\n <form\n className=\"grid grid-cols-[140px_140px_1fr_auto] items-center gap-2 border-border/40 border-b p-3\"\n onSubmit={(e) => {\n e.preventDefault();\n submit();\n }}\n >\n <select\n value={event}\n onChange={(e) => setEvent(e.target.value as HookEvent)}\n aria-label=\"Event\"\n className=\"h-9 rounded-md border border-input bg-card px-2 font-mono text-code-sm\"\n >\n {HOOK_EVENTS.map((evt) => (\n <option key={evt} value={evt}>\n {evt}\n </option>\n ))}\n </select>\n <input\n type=\"text\"\n value={matcher}\n onChange={(e) => setMatcher(e.target.value)}\n placeholder=\"matcher (Bash, Write, *)\"\n aria-label=\"Matcher\"\n className=\"h-9 rounded-md border border-input bg-card px-2 font-mono text-code-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n />\n <input\n type=\"text\"\n value={command}\n onChange={(e) => setCommand(e.target.value)}\n placeholder='command (e.g. \"./scripts/audit.sh\")'\n aria-label=\"Command\"\n className=\"h-9 rounded-md border border-input bg-card px-2 font-mono text-code-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n />\n <button\n type=\"submit\"\n className=\"inline-flex h-9 items-center gap-1 rounded-md bg-primary px-3 font-sans text-label text-primary-foreground hover:shadow-glow focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Plus className=\"size-3.5\" /> Add\n </button>\n </form>\n ) : null}\n\n <ul className=\"divide-y divide-border/30\">\n {hooks.map((hook) => {\n const enabled = hook.enabled ?? true;\n return (\n <li\n key={hook.id}\n className={cn(\n \"grid grid-cols-[140px_140px_1fr_auto_auto] items-center gap-3 px-4 py-2.5\",\n !enabled && \"opacity-50\",\n )}\n >\n <span className=\"font-mono text-code-sm text-primary\">{hook.event}</span>\n <span className=\"font-mono text-code-sm text-muted-foreground\">{hook.matcher}</span>\n <span className=\"truncate font-mono text-code-sm text-foreground\">\n {hook.command}\n </span>\n {onToggle ? (\n <button\n type=\"button\"\n onClick={() => onToggle(hook.id, !enabled)}\n aria-pressed={enabled}\n className={cn(\n \"rounded-full border px-2.5 py-0.5 font-mono text-label uppercase\",\n enabled\n ? \"border-success/40 bg-success/15 text-success\"\n : \"border-border/40 bg-muted text-muted-foreground\",\n )}\n >\n {enabled ? \"On\" : \"Off\"}\n </button>\n ) : (\n <span />\n )}\n {onRemove ? (\n <button\n type=\"button\"\n onClick={() => onRemove(hook.id)}\n aria-label={`Remove hook ${hook.event} ${hook.matcher}`}\n className=\"rounded-md p-1.5 text-muted-foreground hover:bg-muted hover:text-destructive focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Trash2 className=\"size-3.5\" />\n </button>\n ) : (\n <span />\n )}\n </li>\n );\n })}\n {hooks.length === 0 ? (\n <li className=\"px-4 py-8 text-center font-sans text-body-sm text-muted-foreground\">\n No hooks configured.\n </li>\n ) : null}\n </ul>\n </section>\n );\n },\n);\nHookConfig.displayName = \"HookConfig\";\n\nexport { HookConfig, HOOK_EVENTS };\n"
19
+ "content": "\"use client\";\n\nimport { Plus, Trash2, Zap } from \"lucide-react\";\nimport { forwardRef, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\nexport type HookEvent =\n | \"PreToolUse\"\n | \"PostToolUse\"\n | \"UserPromptSubmit\"\n | \"Stop\"\n | \"SessionStart\"\n | \"SessionEnd\";\n\nexport interface HookEntry {\n id: string;\n event: HookEvent;\n /** Tool matcher (e.g. \"Bash\", \"Write\", \"*\"). */\n matcher: string;\n /** Shell command to run. */\n command: string;\n enabled?: boolean;\n}\n\nconst HOOK_EVENTS: HookEvent[] = [\n \"PreToolUse\",\n \"PostToolUse\",\n \"UserPromptSubmit\",\n \"Stop\",\n \"SessionStart\",\n \"SessionEnd\",\n];\n\ninterface HookConfigProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\" | \"onToggle\"> {\n hooks: HookEntry[];\n onAdd?: (hook: Omit<HookEntry, \"id\">) => void;\n onRemove?: (id: string) => void;\n onToggle?: (id: string, enabled: boolean) => void;\n title?: ReactNode;\n}\n\n/**\n * HookConfig — editor for lifecycle hooks (PreToolUse, PostToolUse, Stop…).\n *\n * Mirrors Claude Code's settings.json hooks but visual. Each row is an\n * { event × matcher × command } triple with on/off toggle.\n */\nconst HookConfig = forwardRef<HTMLDivElement, HookConfigProps>(\n ({ className, hooks, onAdd, onRemove, onToggle, title = \"Hooks\", ...props }, ref) => {\n const [event, setEvent] = useState<HookEvent>(\"PreToolUse\");\n const [matcher, setMatcher] = useState(\"*\");\n const [command, setCommand] = useState(\"\");\n\n const submit = () => {\n if (!command.trim()) return;\n onAdd?.({ event, matcher: matcher.trim() || \"*\", command: command.trim() });\n setCommand(\"\");\n };\n\n return (\n <section\n data-slot=\"hook-config\"\n ref={ref}\n className={cn(\"rounded-xl border bg-card\", className)}\n {...props}\n >\n <header className=\"flex items-baseline justify-between border-border/40 border-b px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n <Zap className=\"size-4 text-primary\" aria-hidden=\"true\" />\n <h3 className=\"font-display text-title-md tracking-tight\">{title}</h3>\n </div>\n <span className=\"font-mono text-label text-muted-foreground\">\n {hooks.length} {hooks.length === 1 ? \"hook\" : \"hooks\"}\n </span>\n </header>\n\n {onAdd ? (\n <form\n className=\"grid grid-cols-[140px_140px_1fr_auto] items-center gap-2 border-border/40 border-b p-3\"\n onSubmit={(e) => {\n e.preventDefault();\n submit();\n }}\n >\n <select\n value={event}\n onChange={(e) => setEvent(e.target.value as HookEvent)}\n aria-label=\"Event\"\n className=\"h-9 rounded-md border border-input bg-card px-2 font-mono text-code-sm\"\n >\n {HOOK_EVENTS.map((evt) => (\n <option key={evt} value={evt}>\n {evt}\n </option>\n ))}\n </select>\n <input\n type=\"text\"\n value={matcher}\n onChange={(e) => setMatcher(e.target.value)}\n placeholder=\"matcher (Bash, Write, *)\"\n aria-label=\"Matcher\"\n className=\"h-9 rounded-md border border-input bg-card px-2 font-mono text-code-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n />\n <input\n type=\"text\"\n value={command}\n onChange={(e) => setCommand(e.target.value)}\n placeholder='command (e.g. \"./scripts/audit.sh\")'\n aria-label=\"Command\"\n className=\"h-9 rounded-md border border-input bg-card px-2 font-mono text-code-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n />\n <button\n type=\"submit\"\n className=\"inline-flex h-9 items-center gap-1 rounded-md bg-primary px-3 font-sans text-label text-primary-foreground hover:shadow-glow focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Plus className=\"size-3.5\" /> Add\n </button>\n </form>\n ) : null}\n\n <ul className=\"divide-y divide-border/30\">\n {hooks.map((hook) => {\n const enabled = hook.enabled ?? true;\n return (\n <li\n key={hook.id}\n className={cn(\n \"grid grid-cols-[140px_140px_1fr_auto_auto] items-center gap-3 px-4 py-2.5\",\n !enabled && \"opacity-50\",\n )}\n >\n <span className=\"font-mono text-code-sm text-primary\">{hook.event}</span>\n <span className=\"font-mono text-code-sm text-muted-foreground\">{hook.matcher}</span>\n <span className=\"truncate font-mono text-code-sm text-foreground\">\n {hook.command}\n </span>\n {onToggle ? (\n <button\n type=\"button\"\n onClick={() => onToggle(hook.id, !enabled)}\n aria-pressed={enabled}\n className={cn(\n \"rounded-full border px-2.5 py-0.5 font-mono text-label uppercase\",\n enabled\n ? \"border-success/40 bg-success/15 text-success\"\n : \"border-border/40 bg-muted text-muted-foreground\",\n )}\n >\n {enabled ? \"On\" : \"Off\"}\n </button>\n ) : (\n <span />\n )}\n {onRemove ? (\n <button\n type=\"button\"\n onClick={() => onRemove(hook.id)}\n aria-label={`Remove hook ${hook.event} ${hook.matcher}`}\n className=\"rounded-md p-1.5 text-muted-foreground hover:bg-muted hover:text-destructive focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Trash2 className=\"size-3.5\" />\n </button>\n ) : (\n <span />\n )}\n </li>\n );\n })}\n {hooks.length === 0 ? (\n <li className=\"px-4 py-8 text-center font-sans text-body-sm text-muted-foreground\">\n No hooks configured.\n </li>\n ) : null}\n </ul>\n </section>\n );\n },\n);\nHookConfig.displayName = \"HookConfig\";\n\nexport { HookConfig, HOOK_EVENTS };\n"
20
20
  }
21
21
  ]
22
22
  }
@@ -16,7 +16,7 @@
16
16
  "path": "components/primitives/hook-event-log/hook-event-log.tsx",
17
17
  "type": "registry:ui",
18
18
  "target": "components/ui/hook-event-log.tsx",
19
- "content": "import { CheckCircle2, CircleX, ShieldAlert } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\nexport type HookEventResult = \"ok\" | \"blocked\" | \"error\";\n\nexport interface HookEventEntry {\n id: string;\n /** Hook event (e.g. PreToolUse). */\n event: string;\n /** Hook matcher (e.g. Bash). */\n matcher: string;\n /** What the hook command was. */\n command: string;\n result: HookEventResult;\n timestamp: string;\n /** Optional stderr/stdout snippet. */\n output?: string;\n /** Optional duration label, e.g. \"120ms\". */\n duration?: string;\n}\n\ninterface HookEventLogProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n events: HookEventEntry[];\n title?: ReactNode;\n}\n\nconst RESULT_CONFIG = {\n ok: { icon: CheckCircle2, color: \"text-success\" },\n blocked: { icon: ShieldAlert, color: \"text-warning\" },\n error: { icon: CircleX, color: \"text-destructive\" },\n} as const;\n\n/**\n * HookEventLog — chronological list of hook firings, with result tone, the\n * command that ran, and an optional output preview.\n */\nconst HookEventLog = forwardRef<HTMLDivElement, HookEventLogProps>(\n ({ className, events, title = \"Hook log\", ...props }, ref) => (\n <section ref={ref} className={cn(\"rounded-xl border bg-card\", className)} {...props}>\n <header className=\"flex items-baseline justify-between border-border/40 border-b px-4 py-3\">\n <h3 className=\"font-display text-title-md tracking-tight\">{title}</h3>\n <span className=\"font-mono text-label text-muted-foreground\">\n {events.length} {events.length === 1 ? \"event\" : \"events\"}\n </span>\n </header>\n <ol className=\"divide-y divide-border/30\">\n {events.map((evt) => {\n const cfg = RESULT_CONFIG[evt.result];\n const Icon = cfg.icon;\n return (\n <li\n key={evt.id}\n className=\"grid grid-cols-[auto_1fr_auto] items-start gap-3 px-4 py-2.5\"\n >\n <Icon aria-hidden=\"true\" className={cn(\"mt-0.5 size-3.5 shrink-0\", cfg.color)} />\n <div className=\"min-w-0\">\n <p className=\"flex flex-wrap items-baseline gap-2\">\n <span className=\"font-mono text-code-sm text-primary\">{evt.event}</span>\n <span className=\"font-mono text-code-sm text-muted-foreground\">\n matcher={evt.matcher}\n </span>\n {evt.duration ? (\n <span className=\"font-mono text-label text-muted-foreground tabular-nums\">\n {evt.duration}\n </span>\n ) : null}\n </p>\n <p className=\"truncate font-mono text-code-sm text-foreground\">{evt.command}</p>\n {evt.output ? (\n <pre className=\"mt-1 max-h-24 overflow-auto rounded-md bg-muted/60 px-2 py-1 font-mono text-code-sm text-muted-foreground\">\n {evt.output}\n </pre>\n ) : null}\n </div>\n <span className=\"font-mono text-label text-muted-foreground tabular-nums\">\n {evt.timestamp}\n </span>\n </li>\n );\n })}\n {events.length === 0 ? (\n <li className=\"px-4 py-8 text-center font-sans text-body-sm text-muted-foreground\">\n No hooks have fired yet.\n </li>\n ) : null}\n </ol>\n </section>\n ),\n);\nHookEventLog.displayName = \"HookEventLog\";\n\nexport { HookEventLog };\n"
19
+ "content": "import { CheckCircle2, CircleX, ShieldAlert } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\nexport type HookEventResult = \"ok\" | \"blocked\" | \"error\";\n\nexport interface HookEventEntry {\n id: string;\n /** Hook event (e.g. PreToolUse). */\n event: string;\n /** Hook matcher (e.g. Bash). */\n matcher: string;\n /** What the hook command was. */\n command: string;\n result: HookEventResult;\n timestamp: string;\n /** Optional stderr/stdout snippet. */\n output?: string;\n /** Optional duration label, e.g. \"120ms\". */\n duration?: string;\n}\n\ninterface HookEventLogProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n events: HookEventEntry[];\n title?: ReactNode;\n}\n\nconst RESULT_CONFIG = {\n ok: { icon: CheckCircle2, color: \"text-success\" },\n blocked: { icon: ShieldAlert, color: \"text-warning\" },\n error: { icon: CircleX, color: \"text-destructive\" },\n} as const;\n\n/**\n * HookEventLog — chronological list of hook firings, with result tone, the\n * command that ran, and an optional output preview.\n */\nconst HookEventLog = forwardRef<HTMLDivElement, HookEventLogProps>(\n ({ className, events, title = \"Hook log\", ...props }, ref) => (\n <section\n data-slot=\"hook-event-log\"\n ref={ref}\n className={cn(\"rounded-xl border bg-card\", className)}\n {...props}\n >\n <header className=\"flex items-baseline justify-between border-border/40 border-b px-4 py-3\">\n <h3 className=\"font-display text-title-md tracking-tight\">{title}</h3>\n <span className=\"font-mono text-label text-muted-foreground\">\n {events.length} {events.length === 1 ? \"event\" : \"events\"}\n </span>\n </header>\n <ol className=\"divide-y divide-border/30\">\n {events.map((evt) => {\n const cfg = RESULT_CONFIG[evt.result];\n const Icon = cfg.icon;\n return (\n <li\n key={evt.id}\n className=\"grid grid-cols-[auto_1fr_auto] items-start gap-3 px-4 py-2.5\"\n >\n <Icon aria-hidden=\"true\" className={cn(\"mt-0.5 size-3.5 shrink-0\", cfg.color)} />\n <div className=\"min-w-0\">\n <p className=\"flex flex-wrap items-baseline gap-2\">\n <span className=\"font-mono text-code-sm text-primary\">{evt.event}</span>\n <span className=\"font-mono text-code-sm text-muted-foreground\">\n matcher={evt.matcher}\n </span>\n {evt.duration ? (\n <span className=\"font-mono text-label text-muted-foreground tabular-nums\">\n {evt.duration}\n </span>\n ) : null}\n </p>\n <p className=\"truncate font-mono text-code-sm text-foreground\">{evt.command}</p>\n {evt.output ? (\n <pre className=\"mt-1 max-h-24 overflow-auto rounded-md bg-muted/60 px-2 py-1 font-mono text-code-sm text-muted-foreground\">\n {evt.output}\n </pre>\n ) : null}\n </div>\n <span className=\"font-mono text-label text-muted-foreground tabular-nums\">\n {evt.timestamp}\n </span>\n </li>\n );\n })}\n {events.length === 0 ? (\n <li className=\"px-4 py-8 text-center font-sans text-body-sm text-muted-foreground\">\n No hooks have fired yet.\n </li>\n ) : null}\n </ol>\n </section>\n ),\n);\nHookEventLog.displayName = \"HookEventLog\";\n\nexport { HookEventLog };\n"
20
20
  }
21
21
  ]
22
22
  }
@@ -13,7 +13,7 @@
13
13
  "path": "components/primitives/input/input.tsx",
14
14
  "type": "registry:ui",
15
15
  "target": "components/ui/input.tsx",
16
- "content": "import { type VariantProps, cva } from \"class-variance-authority\";\nimport { forwardRef } from \"react\";\nimport type { InputHTMLAttributes } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\nconst inputVariants = cva(\n [\n \"flex w-full rounded-md border border-input bg-card\",\n \"text-foreground placeholder:text-muted-foreground\",\n \"transition-[box-shadow,border-color] duration-base ease-out-soft\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n \"focus-visible:border-primary\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n \"file:border-0 file:bg-transparent file:font-medium file:text-body-sm\",\n ],\n {\n variants: {\n size: {\n sm: \"h-8 px-2.5 py-1 text-body-sm\",\n // md: density-tunable via CSS var. Comfortable (default) = 36px.\n md: \"h-[var(--theo-control-h,2.25rem)] px-[var(--theo-control-px,0.875rem)] py-1.5 text-body-sm\",\n lg: \"h-11 px-4 py-2.5 text-body-md\",\n },\n },\n defaultVariants: { size: \"md\" },\n },\n);\n\n/**\n * Input — text input primitive.\n *\n * Violet Forge specifics:\n * - height 40px (h-10) matching default Button md.\n * - rounded-md (6px) — slightly less than buttons to differentiate.\n * - focus uses violet ring (--ring).\n * - placeholder uses --muted-foreground.\n *\n * The `size` prop accepts `\"sm\" | \"md\" | \"lg\"`. Default `md` preserves the\n * 40px tall input from before this prop existed. EC-1 (edge-case review):\n * this overrides the native HTML `size` attribute (text-input columns) —\n * use `{...{ size: 20 } as any}` if you genuinely need the HTML attribute,\n * which is exceedingly rare.\n */\nexport interface InputProps\n extends Omit<InputHTMLAttributes<HTMLInputElement>, \"size\">,\n VariantProps<typeof inputVariants> {}\n\nconst Input = forwardRef<HTMLInputElement, InputProps>(\n ({ className, type = \"text\", size, ...props }, ref) => (\n <input ref={ref} type={type} className={cn(inputVariants({ size }), className)} {...props} />\n ),\n);\nInput.displayName = \"Input\";\n\nexport { Input, inputVariants };\n"
16
+ "content": "import { type VariantProps, cva } from \"class-variance-authority\";\nimport { forwardRef } from \"react\";\nimport type { InputHTMLAttributes } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\nconst inputVariants = cva(\n [\n \"flex w-full rounded-md border border-input bg-card\",\n \"text-foreground placeholder:text-muted-foreground\",\n \"transition-[box-shadow,border-color] duration-base ease-out-soft\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n \"focus-visible:border-primary\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n \"file:border-0 file:bg-transparent file:font-medium file:text-body-sm\",\n ],\n {\n variants: {\n size: {\n sm: \"h-8 px-2.5 py-1 text-body-sm\",\n // md: density-tunable via CSS var. Comfortable (default) = 36px.\n md: \"h-[var(--theo-control-h,2.25rem)] px-[var(--theo-control-px,0.875rem)] py-1.5 text-body-sm\",\n lg: \"h-11 px-4 py-2.5 text-body-md\",\n },\n },\n defaultVariants: { size: \"md\" },\n },\n);\n\n/**\n * Input — text input primitive.\n *\n * Violet Forge specifics:\n * - height 40px (h-10) matching default Button md.\n * - rounded-md (6px) — slightly less than buttons to differentiate.\n * - focus uses violet ring (--ring).\n * - placeholder uses --muted-foreground.\n *\n * The `size` prop accepts `\"sm\" | \"md\" | \"lg\"`. Default `md` preserves the\n * 40px tall input from before this prop existed. EC-1 (edge-case review):\n * this overrides the native HTML `size` attribute (text-input columns) —\n * use `{...{ size: 20 } as any}` if you genuinely need the HTML attribute,\n * which is exceedingly rare.\n */\nexport interface InputProps\n extends Omit<InputHTMLAttributes<HTMLInputElement>, \"size\">,\n VariantProps<typeof inputVariants> {}\n\nconst Input = forwardRef<HTMLInputElement, InputProps>(\n ({ className, type = \"text\", size, ...props }, ref) => (\n <input\n data-slot=\"input\"\n data-size={size}\n ref={ref}\n type={type}\n className={cn(inputVariants({ size }), className)}\n {...props}\n />\n ),\n);\nInput.displayName = \"Input\";\n\nexport { Input, inputVariants };\n"
17
17
  }
18
18
  ],
19
19
  "dependencies": [
@@ -18,7 +18,7 @@
18
18
  "path": "components/primitives/intent-selector/intent-selector.tsx",
19
19
  "type": "registry:ui",
20
20
  "target": "components/ui/intent-selector.tsx",
21
- "content": "import * as DropdownMenu from \"@radix-ui/react-dropdown-menu\";\nimport { Check, ChevronDown, Pencil } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { ButtonHTMLAttributes } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport type { IconComponent } from \"@/lib/types\";\n\nexport interface IntentOption {\n id: string;\n label: string;\n /** Optional one-liner shown below the label in the menu. */\n description?: string;\n /** Optional icon — defaults to a pencil for the trigger if none. */\n icon?: IconComponent;\n}\n\ninterface IntentSelectorProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, \"onChange\"> {\n value: string;\n options: IntentOption[];\n onChange?: (id: string) => void;\n}\n\n/**\n * IntentSelector — chip dropdown for picking the agent's intent for the next\n * turn (e.g. edit / plan / review). Mirrors ModelSelector: pill trigger +\n * Radix DropdownMenu of options with description and a check on the active.\n */\nconst IntentSelector = forwardRef<HTMLButtonElement, IntentSelectorProps>(\n ({ className, value, options, onChange, ...props }, ref) => {\n const current = options.find((o) => o.id === value) ?? options[0];\n const Icon = current?.icon ?? Pencil;\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n ref={ref}\n type=\"button\"\n className={cn(\n \"inline-flex h-8 items-center gap-2 rounded-full border border-border/60 bg-card px-3\",\n \"font-medium font-sans text-body-sm text-foreground\",\n \"transition-colors duration-base ease-out-soft\",\n \"hover:bg-muted\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n className,\n )}\n {...props}\n >\n <Icon className=\"size-3.5 text-primary\" aria-hidden=\"true\" />\n {current?.label ?? \"Select intent\"}\n <ChevronDown className=\"size-3 text-muted-foreground\" aria-hidden=\"true\" />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n sideOffset={6}\n align=\"start\"\n className={cn(\n \"z-50 min-w-[16rem] overflow-hidden rounded-lg border bg-popover p-1 text-popover-foreground shadow-md\",\n \"data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=closed]:animate-out\",\n )}\n >\n {options.map((opt) => {\n const OptIcon = opt.icon ?? Pencil;\n return (\n <DropdownMenu.Item\n key={opt.id}\n onSelect={() => onChange?.(opt.id)}\n className={cn(\n \"flex cursor-pointer items-start gap-3 rounded-md px-2 py-2\",\n \"text-body-sm\",\n \"focus:bg-muted focus:outline-none\",\n \"data-[highlighted]:bg-muted\",\n )}\n >\n <OptIcon className=\"mt-0.5 size-4 shrink-0 text-primary\" aria-hidden=\"true\" />\n <span className=\"flex flex-1 flex-col\">\n <span className=\"font-medium\">{opt.label}</span>\n {opt.description ? (\n <span className=\"text-label text-muted-foreground\">{opt.description}</span>\n ) : null}\n </span>\n {opt.id === value ? (\n <Check className=\"mt-0.5 size-3.5 shrink-0 text-primary\" />\n ) : null}\n </DropdownMenu.Item>\n );\n })}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n );\n },\n);\nIntentSelector.displayName = \"IntentSelector\";\n\nexport { IntentSelector };\n"
21
+ "content": "import * as DropdownMenu from \"@radix-ui/react-dropdown-menu\";\nimport { Check, ChevronDown, Pencil } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { ButtonHTMLAttributes } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport type { IconComponent } from \"@/lib/types\";\n\nexport interface IntentOption {\n id: string;\n label: string;\n /** Optional one-liner shown below the label in the menu. */\n description?: string;\n /** Optional icon — defaults to a pencil for the trigger if none. */\n icon?: IconComponent;\n}\n\ninterface IntentSelectorProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, \"onChange\"> {\n value: string;\n options: IntentOption[];\n onChange?: (id: string) => void;\n}\n\n/**\n * IntentSelector — chip dropdown for picking the agent's intent for the next\n * turn (e.g. edit / plan / review). Mirrors ModelSelector: pill trigger +\n * Radix DropdownMenu of options with description and a check on the active.\n */\nconst IntentSelector = forwardRef<HTMLButtonElement, IntentSelectorProps>(\n ({ className, value, options, onChange, ...props }, ref) => {\n const current = options.find((o) => o.id === value) ?? options[0];\n const Icon = current?.icon ?? Pencil;\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n data-slot=\"intent-selector\"\n ref={ref}\n type=\"button\"\n className={cn(\n \"inline-flex h-8 items-center gap-2 rounded-full border border-border/60 bg-card px-3\",\n \"font-medium font-sans text-body-sm text-foreground\",\n \"transition-colors duration-base ease-out-soft\",\n \"hover:bg-muted\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n className,\n )}\n {...props}\n >\n <Icon className=\"size-3.5 text-primary\" aria-hidden=\"true\" />\n {current?.label ?? \"Select intent\"}\n <ChevronDown className=\"size-3 text-muted-foreground\" aria-hidden=\"true\" />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n sideOffset={6}\n align=\"start\"\n className={cn(\n \"z-50 min-w-[16rem] overflow-hidden rounded-lg border bg-popover p-1 text-popover-foreground shadow-md\",\n \"data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=closed]:animate-out\",\n )}\n >\n {options.map((opt) => {\n const OptIcon = opt.icon ?? Pencil;\n return (\n <DropdownMenu.Item\n key={opt.id}\n onSelect={() => onChange?.(opt.id)}\n className={cn(\n \"flex cursor-pointer items-start gap-3 rounded-md px-2 py-2\",\n \"text-body-sm\",\n \"focus:bg-muted focus:outline-none\",\n \"data-[highlighted]:bg-muted\",\n )}\n >\n <OptIcon className=\"mt-0.5 size-4 shrink-0 text-primary\" aria-hidden=\"true\" />\n <span className=\"flex flex-1 flex-col\">\n <span className=\"font-medium\">{opt.label}</span>\n {opt.description ? (\n <span className=\"text-label text-muted-foreground\">{opt.description}</span>\n ) : null}\n </span>\n {opt.id === value ? (\n <Check className=\"mt-0.5 size-3.5 shrink-0 text-primary\" />\n ) : null}\n </DropdownMenu.Item>\n );\n })}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n );\n },\n);\nIntentSelector.displayName = \"IntentSelector\";\n\nexport { IntentSelector };\n"
22
22
  }
23
23
  ]
24
24
  }
@@ -16,7 +16,7 @@
16
16
  "path": "components/primitives/label/label.tsx",
17
17
  "type": "registry:ui",
18
18
  "target": "components/ui/label.tsx",
19
- "content": "import * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { forwardRef } from \"react\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\n/**\n * Label — form field label built on Radix Label.\n *\n * Behaviors:\n * - Clicking the label focuses the associated `htmlFor` input.\n * - Adds a small red asterisk when `required` is set.\n * - Inherits disabled visuals from the wrapper (`peer-disabled`).\n */\ninterface LabelProps extends ComponentPropsWithoutRef<typeof LabelPrimitive.Root> {\n required?: boolean;\n}\n\nconst Label = forwardRef<ElementRef<typeof LabelPrimitive.Root>, LabelProps>(\n ({ className, required, children, ...props }, ref) => (\n <LabelPrimitive.Root\n ref={ref}\n className={cn(\n \"inline-flex items-center gap-1 font-medium font-sans text-body-sm text-foreground\",\n \"peer-disabled:cursor-not-allowed peer-disabled:opacity-60\",\n className,\n )}\n {...props}\n >\n {children}\n {required ? (\n <span className=\"text-destructive\" aria-hidden=\"true\">\n *\n </span>\n ) : null}\n </LabelPrimitive.Root>\n ),\n);\nLabel.displayName = \"Label\";\n\nexport { Label };\n"
19
+ "content": "import * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { forwardRef } from \"react\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\n/**\n * Label — form field label built on Radix Label.\n *\n * Behaviors:\n * - Clicking the label focuses the associated `htmlFor` input.\n * - Adds a small red asterisk when `required` is set.\n * - Inherits disabled visuals from the wrapper (`peer-disabled`).\n */\ninterface LabelProps extends ComponentPropsWithoutRef<typeof LabelPrimitive.Root> {\n required?: boolean;\n}\n\nconst Label = forwardRef<ElementRef<typeof LabelPrimitive.Root>, LabelProps>(\n ({ className, required, children, ...props }, ref) => (\n <LabelPrimitive.Root\n data-slot=\"label\"\n ref={ref}\n className={cn(\n \"inline-flex items-center gap-1 font-medium font-sans text-body-sm text-foreground\",\n \"peer-disabled:cursor-not-allowed peer-disabled:opacity-60\",\n className,\n )}\n {...props}\n >\n {children}\n {required ? (\n <span className=\"text-destructive\" aria-hidden=\"true\">\n *\n </span>\n ) : null}\n </LabelPrimitive.Root>\n ),\n);\nLabel.displayName = \"Label\";\n\nexport { Label };\n"
20
20
  }
21
21
  ]
22
22
  }
@@ -14,7 +14,7 @@
14
14
  "path": "components/primitives/lane-board/lane-board.tsx",
15
15
  "type": "registry:ui",
16
16
  "target": "components/ui/lane-board.tsx",
17
- "content": "import { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\nexport type LaneState = \"started\" | \"blocked\" | \"failed\" | \"finished\";\n\nexport interface LaneCard {\n id: string;\n /** Card title (e.g. task name). */\n title: ReactNode;\n /** Optional description / preview. */\n description?: ReactNode;\n /** Optional footer / metadata row. */\n footer?: ReactNode;\n}\n\nexport interface Lane {\n state: LaneState;\n cards: LaneCard[];\n}\n\ninterface LaneBoardProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n lanes: Lane[];\n title?: ReactNode;\n}\n\nconst LANE_META: Record<LaneState, { label: string; headerClass: string; cardClass: string }> = {\n started: {\n label: \"Started\",\n headerClass: \"text-primary\",\n cardClass: \"border-primary/30 bg-primary/5\",\n },\n blocked: {\n label: \"Blocked\",\n headerClass: \"text-warning\",\n cardClass: \"border-warning/40 bg-warning/5\",\n },\n failed: {\n label: \"Failed\",\n headerClass: \"text-destructive\",\n cardClass: \"border-destructive/40 bg-destructive/5\",\n },\n finished: {\n label: \"Finished\",\n headerClass: \"text-success\",\n cardClass: \"border-success/40 bg-success/5\",\n },\n};\n\n/**\n * LaneBoard — kanban-style task board with 4 lanes matching the claw-code\n * lane event schema (started/blocked/failed/finished). Each card is a\n * machine-readable task snapshot the agent emits.\n */\nconst LaneBoard = forwardRef<HTMLDivElement, LaneBoardProps>(\n ({ className, lanes, title, ...props }, ref) => (\n <section\n ref={ref}\n className={cn(\"grid gap-3\", className)}\n aria-label=\"Agent lane board\"\n {...props}\n >\n {title ? <h3 className=\"font-display text-title-md tracking-tight\">{title}</h3> : null}\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-4\">\n {lanes.map((lane) => {\n const meta = LANE_META[lane.state];\n return (\n <div\n key={lane.state}\n className=\"grid auto-rows-max gap-2 rounded-xl border border-border/40 bg-card p-3\"\n >\n <header className=\"flex items-center justify-between px-1\">\n <span\n className={cn(\n \"font-mono text-label-caps uppercase tracking-wider\",\n meta.headerClass,\n )}\n >\n {meta.label}\n </span>\n <span className=\"font-mono text-label text-muted-foreground tabular-nums\">\n {lane.cards.length}\n </span>\n </header>\n {lane.cards.length === 0 ? (\n <p className=\"rounded-md border border-border/40 border-dashed px-3 py-4 text-center font-sans text-body-sm text-muted-foreground\">\n empty\n </p>\n ) : (\n <ul className=\"grid gap-2\">\n {lane.cards.map((card) => (\n <li\n key={card.id}\n className={cn(\"grid gap-1 rounded-md border p-3\", meta.cardClass)}\n >\n <p className=\"font-medium text-body-sm text-foreground\">{card.title}</p>\n {card.description ? (\n <p className=\"text-body-sm text-muted-foreground\">{card.description}</p>\n ) : null}\n {card.footer ? (\n <p className=\"font-mono text-label text-muted-foreground\">{card.footer}</p>\n ) : null}\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n })}\n </div>\n </section>\n ),\n);\nLaneBoard.displayName = \"LaneBoard\";\n\nexport { LaneBoard };\n"
17
+ "content": "import { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\nexport type LaneState = \"started\" | \"blocked\" | \"failed\" | \"finished\";\n\nexport interface LaneCard {\n id: string;\n /** Card title (e.g. task name). */\n title: ReactNode;\n /** Optional description / preview. */\n description?: ReactNode;\n /** Optional footer / metadata row. */\n footer?: ReactNode;\n}\n\nexport interface Lane {\n state: LaneState;\n cards: LaneCard[];\n}\n\ninterface LaneBoardProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n lanes: Lane[];\n title?: ReactNode;\n}\n\nconst LANE_META: Record<LaneState, { label: string; headerClass: string; cardClass: string }> = {\n started: {\n label: \"Started\",\n headerClass: \"text-primary\",\n cardClass: \"border-primary/30 bg-primary/5\",\n },\n blocked: {\n label: \"Blocked\",\n headerClass: \"text-warning\",\n cardClass: \"border-warning/40 bg-warning/5\",\n },\n failed: {\n label: \"Failed\",\n headerClass: \"text-destructive\",\n cardClass: \"border-destructive/40 bg-destructive/5\",\n },\n finished: {\n label: \"Finished\",\n headerClass: \"text-success\",\n cardClass: \"border-success/40 bg-success/5\",\n },\n};\n\n/**\n * LaneBoard — kanban-style task board with 4 lanes matching the claw-code\n * lane event schema (started/blocked/failed/finished). Each card is a\n * machine-readable task snapshot the agent emits.\n */\nconst LaneBoard = forwardRef<HTMLDivElement, LaneBoardProps>(\n ({ className, lanes, title, ...props }, ref) => (\n <section\n data-slot=\"lane-board\"\n ref={ref}\n className={cn(\"grid gap-3\", className)}\n aria-label=\"Agent lane board\"\n {...props}\n >\n {title ? <h3 className=\"font-display text-title-md tracking-tight\">{title}</h3> : null}\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-4\">\n {lanes.map((lane) => {\n const meta = LANE_META[lane.state];\n return (\n <div\n key={lane.state}\n className=\"grid auto-rows-max gap-2 rounded-xl border border-border/40 bg-card p-3\"\n >\n <header className=\"flex items-center justify-between px-1\">\n <span\n className={cn(\n \"font-mono text-label-caps uppercase tracking-wider\",\n meta.headerClass,\n )}\n >\n {meta.label}\n </span>\n <span className=\"font-mono text-label text-muted-foreground tabular-nums\">\n {lane.cards.length}\n </span>\n </header>\n {lane.cards.length === 0 ? (\n <p className=\"rounded-md border border-border/40 border-dashed px-3 py-4 text-center font-sans text-body-sm text-muted-foreground\">\n empty\n </p>\n ) : (\n <ul className=\"grid gap-2\">\n {lane.cards.map((card) => (\n <li\n key={card.id}\n className={cn(\"grid gap-1 rounded-md border p-3\", meta.cardClass)}\n >\n <p className=\"font-medium text-body-sm text-foreground\">{card.title}</p>\n {card.description ? (\n <p className=\"text-body-sm text-muted-foreground\">{card.description}</p>\n ) : null}\n {card.footer ? (\n <p className=\"font-mono text-label text-muted-foreground\">{card.footer}</p>\n ) : null}\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n })}\n </div>\n </section>\n ),\n);\nLaneBoard.displayName = \"LaneBoard\";\n\nexport { LaneBoard };\n"
18
18
  }
19
19
  ]
20
20
  }
@@ -14,7 +14,7 @@
14
14
  "path": "components/primitives/login-split/login-split.tsx",
15
15
  "type": "registry:ui",
16
16
  "target": "components/ui/login-split.tsx",
17
- "content": "import { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\ninterface LoginSplitProps extends HTMLAttributes<HTMLDivElement> {\n /** Left pane content — form, brand, etc. */\n left: ReactNode;\n /** Right pane content — illustration, marketing, social proof. */\n right: ReactNode;\n /**\n * Optional footer rendered below both panes.\n */\n footer?: ReactNode;\n /**\n * Reverse the split (form on the right). Default = form left.\n */\n reverse?: boolean;\n}\n\n/**\n * LoginSplit — 50/50 split layout shell.\n *\n * Used for the auth flow. Two slots (`left`, `right`); the right pane has a\n * subtle violet wash so the illustration sits inside Theo identity. Mobile\n * collapses to single column.\n */\nconst LoginSplit = forwardRef<HTMLDivElement, LoginSplitProps>(\n ({ className, left, right, footer, reverse, ...props }, ref) => (\n <div ref={ref} className={cn(\"flex min-h-screen flex-col bg-background\", className)} {...props}>\n <div\n className={cn(\n \"grid flex-1 grid-cols-1 lg:grid-cols-2\",\n reverse && \"lg:[&>*:first-child]:order-2\",\n )}\n >\n <div className=\"flex items-center justify-center px-6 py-12 lg:px-12\">\n <div className=\"w-full max-w-md\">{left}</div>\n </div>\n <div\n className={cn(\n \"relative flex items-center justify-center px-6 py-12 lg:px-12\",\n \"bg-dotted-violet bg-muted/60\",\n )}\n >\n <div className=\"w-full max-w-lg\">{right}</div>\n </div>\n </div>\n {footer ? (\n <footer className=\"border-border/40 border-t px-6 py-3 text-center text-body-sm text-muted-foreground\">\n {footer}\n </footer>\n ) : null}\n </div>\n ),\n);\nLoginSplit.displayName = \"LoginSplit\";\n\nexport { LoginSplit };\n"
17
+ "content": "import { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\ninterface LoginSplitProps extends HTMLAttributes<HTMLDivElement> {\n /** Left pane content — form, brand, etc. */\n left: ReactNode;\n /** Right pane content — illustration, marketing, social proof. */\n right: ReactNode;\n /**\n * Optional footer rendered below both panes.\n */\n footer?: ReactNode;\n /**\n * Reverse the split (form on the right). Default = form left.\n */\n reverse?: boolean;\n}\n\n/**\n * LoginSplit — 50/50 split layout shell.\n *\n * Used for the auth flow. Two slots (`left`, `right`); the right pane has a\n * subtle violet wash so the illustration sits inside Theo identity. Mobile\n * collapses to single column.\n */\nconst LoginSplit = forwardRef<HTMLDivElement, LoginSplitProps>(\n ({ className, left, right, footer, reverse, ...props }, ref) => (\n <div\n data-slot=\"login-split\"\n ref={ref}\n className={cn(\"flex min-h-screen flex-col bg-background\", className)}\n {...props}\n >\n <div\n className={cn(\n \"grid flex-1 grid-cols-1 lg:grid-cols-2\",\n reverse && \"lg:[&>*:first-child]:order-2\",\n )}\n >\n <div className=\"flex items-center justify-center px-6 py-12 lg:px-12\">\n <div className=\"w-full max-w-md\">{left}</div>\n </div>\n <div\n className={cn(\n \"relative flex items-center justify-center px-6 py-12 lg:px-12\",\n \"bg-dotted-violet bg-muted/60\",\n )}\n >\n <div className=\"w-full max-w-lg\">{right}</div>\n </div>\n </div>\n {footer ? (\n <footer className=\"border-border/40 border-t px-6 py-3 text-center text-body-sm text-muted-foreground\">\n {footer}\n </footer>\n ) : null}\n </div>\n ),\n);\nLoginSplit.displayName = \"LoginSplit\";\n\nexport { LoginSplit };\n"
18
18
  }
19
19
  ]
20
20
  }
@@ -16,7 +16,7 @@
16
16
  "path": "components/primitives/mcp-server-card/mcp-server-card.tsx",
17
17
  "type": "registry:ui",
18
18
  "target": "components/ui/mcp-server-card.tsx",
19
- "content": "import { Plug, RotateCcw, Server } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\nexport type MCPServerStatus = \"connected\" | \"degraded\" | \"disconnected\" | \"starting\";\n\nexport interface MCPServer {\n id: string;\n /** Friendly name, e.g. \"postgres\". */\n name: string;\n /** Transport endpoint (stdio command or URL). */\n endpoint: string;\n status: MCPServerStatus;\n /** Tools exposed by the server. */\n tools: string[];\n /** Optional resources exposed. */\n resources?: string[];\n /** Diagnostic message when degraded/disconnected. */\n message?: ReactNode;\n /** Auto-restart toggle hint. */\n autoRestart?: boolean;\n}\n\nconst STATUS_CONFIG: Record<MCPServerStatus, { label: string; class: string }> = {\n connected: { label: \"Connected\", class: \"border-success/40 bg-success/15 text-success\" },\n starting: {\n label: \"Starting\",\n class: \"border-primary/40 bg-primary/15 text-primary animate-pulse\",\n },\n degraded: { label: \"Degraded\", class: \"border-warning/40 bg-warning/15 text-warning\" },\n disconnected: {\n label: \"Disconnected\",\n class: \"border-destructive/40 bg-destructive/15 text-destructive\",\n },\n};\n\ninterface MCPServerCardProps extends HTMLAttributes<HTMLElement> {\n server: MCPServer;\n onRestart?: (id: string) => void;\n onDisconnect?: (id: string) => void;\n}\n\n/**\n * MCPServerCard — one MCP server entry showing connection status, the tools\n * it exposes, and inline controls (restart, disconnect).\n *\n * Pairs with claw-code's \"degraded startup reporting\" — failed servers can\n * still appear here with a recovery message.\n */\nconst MCPServerCard = forwardRef<HTMLElement, MCPServerCardProps>(\n ({ className, server, onRestart, onDisconnect, ...props }, ref) => {\n const cfg = STATUS_CONFIG[server.status];\n return (\n <article\n ref={ref}\n className={cn(\"grid gap-3 rounded-xl border bg-card p-4\", className)}\n {...props}\n >\n <header className=\"flex items-start justify-between gap-3\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <Server className=\"size-4 shrink-0 text-primary\" aria-hidden=\"true\" />\n <div className=\"min-w-0\">\n <h4 className=\"font-medium font-mono text-body-sm text-foreground\">{server.name}</h4>\n <p className=\"truncate font-mono text-label text-muted-foreground\">\n {server.endpoint}\n </p>\n </div>\n </div>\n <span\n className={cn(\n \"inline-flex shrink-0 items-center rounded-full border px-2.5 py-0.5\",\n \"font-mono text-label uppercase tracking-wider\",\n cfg.class,\n )}\n >\n {cfg.label}\n </span>\n </header>\n\n {server.message ? (\n <p className=\"rounded-md border border-warning/30 bg-warning/10 px-3 py-2 font-mono text-code-sm text-warning\">\n {server.message}\n </p>\n ) : null}\n\n {server.tools.length > 0 ? (\n <div className=\"grid gap-1.5\">\n <span className=\"font-mono text-label-caps text-muted-foreground uppercase tracking-wider\">\n {server.tools.length} tools\n </span>\n <div className=\"flex flex-wrap gap-1.5\">\n {server.tools.map((tool) => (\n <span\n key={tool}\n className=\"inline-flex items-center rounded-md bg-muted px-2 py-0.5 font-mono text-foreground text-label\"\n >\n {tool}\n </span>\n ))}\n </div>\n </div>\n ) : null}\n\n {server.resources && server.resources.length > 0 ? (\n <div className=\"grid gap-1.5\">\n <span className=\"font-mono text-label-caps text-muted-foreground uppercase tracking-wider\">\n {server.resources.length} resources\n </span>\n <div className=\"flex flex-wrap gap-1.5\">\n {server.resources.map((r) => (\n <span\n key={r}\n className=\"inline-flex items-center rounded-md bg-accent/10 px-2 py-0.5 font-mono text-accent text-label\"\n >\n {r}\n </span>\n ))}\n </div>\n </div>\n ) : null}\n\n <footer className=\"flex items-center justify-end gap-1.5\">\n {onRestart ? (\n <button\n type=\"button\"\n onClick={() => onRestart(server.id)}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border/60 bg-card px-2.5 py-1 font-mono text-label hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <RotateCcw className=\"size-3\" /> Restart\n </button>\n ) : null}\n {onDisconnect ? (\n <button\n type=\"button\"\n onClick={() => onDisconnect(server.id)}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border/60 bg-card px-2.5 py-1 font-mono text-label hover:bg-muted hover:text-destructive focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Plug className=\"size-3\" /> Disconnect\n </button>\n ) : null}\n </footer>\n </article>\n );\n },\n);\nMCPServerCard.displayName = \"MCPServerCard\";\n\nexport { MCPServerCard };\n"
19
+ "content": "import { Plug, RotateCcw, Server } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\nexport type MCPServerStatus = \"connected\" | \"degraded\" | \"disconnected\" | \"starting\";\n\nexport interface MCPServer {\n id: string;\n /** Friendly name, e.g. \"postgres\". */\n name: string;\n /** Transport endpoint (stdio command or URL). */\n endpoint: string;\n status: MCPServerStatus;\n /** Tools exposed by the server. */\n tools: string[];\n /** Optional resources exposed. */\n resources?: string[];\n /** Diagnostic message when degraded/disconnected. */\n message?: ReactNode;\n /** Auto-restart toggle hint. */\n autoRestart?: boolean;\n}\n\nconst STATUS_CONFIG: Record<MCPServerStatus, { label: string; class: string }> = {\n connected: { label: \"Connected\", class: \"border-success/40 bg-success/15 text-success\" },\n starting: {\n label: \"Starting\",\n class: \"border-primary/40 bg-primary/15 text-primary animate-pulse\",\n },\n degraded: { label: \"Degraded\", class: \"border-warning/40 bg-warning/15 text-warning\" },\n disconnected: {\n label: \"Disconnected\",\n class: \"border-destructive/40 bg-destructive/15 text-destructive\",\n },\n};\n\ninterface MCPServerCardProps extends HTMLAttributes<HTMLElement> {\n server: MCPServer;\n onRestart?: (id: string) => void;\n onDisconnect?: (id: string) => void;\n}\n\n/**\n * MCPServerCard — one MCP server entry showing connection status, the tools\n * it exposes, and inline controls (restart, disconnect).\n *\n * Pairs with claw-code's \"degraded startup reporting\" — failed servers can\n * still appear here with a recovery message.\n */\nconst MCPServerCard = forwardRef<HTMLElement, MCPServerCardProps>(\n ({ className, server, onRestart, onDisconnect, ...props }, ref) => {\n const cfg = STATUS_CONFIG[server.status];\n return (\n <article\n data-slot=\"mcp-server-card\"\n ref={ref}\n className={cn(\"grid gap-3 rounded-xl border bg-card p-4\", className)}\n {...props}\n >\n <header className=\"flex items-start justify-between gap-3\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <Server className=\"size-4 shrink-0 text-primary\" aria-hidden=\"true\" />\n <div className=\"min-w-0\">\n <h4 className=\"font-medium font-mono text-body-sm text-foreground\">{server.name}</h4>\n <p className=\"truncate font-mono text-label text-muted-foreground\">\n {server.endpoint}\n </p>\n </div>\n </div>\n <span\n className={cn(\n \"inline-flex shrink-0 items-center rounded-full border px-2.5 py-0.5\",\n \"font-mono text-label uppercase tracking-wider\",\n cfg.class,\n )}\n >\n {cfg.label}\n </span>\n </header>\n\n {server.message ? (\n <p className=\"rounded-md border border-warning/30 bg-warning/10 px-3 py-2 font-mono text-code-sm text-warning\">\n {server.message}\n </p>\n ) : null}\n\n {server.tools.length > 0 ? (\n <div className=\"grid gap-1.5\">\n <span className=\"font-mono text-label-caps text-muted-foreground uppercase tracking-wider\">\n {server.tools.length} tools\n </span>\n <div className=\"flex flex-wrap gap-1.5\">\n {server.tools.map((tool) => (\n <span\n key={tool}\n className=\"inline-flex items-center rounded-md bg-muted px-2 py-0.5 font-mono text-foreground text-label\"\n >\n {tool}\n </span>\n ))}\n </div>\n </div>\n ) : null}\n\n {server.resources && server.resources.length > 0 ? (\n <div className=\"grid gap-1.5\">\n <span className=\"font-mono text-label-caps text-muted-foreground uppercase tracking-wider\">\n {server.resources.length} resources\n </span>\n <div className=\"flex flex-wrap gap-1.5\">\n {server.resources.map((r) => (\n <span\n key={r}\n className=\"inline-flex items-center rounded-md bg-accent/10 px-2 py-0.5 font-mono text-accent text-label\"\n >\n {r}\n </span>\n ))}\n </div>\n </div>\n ) : null}\n\n <footer className=\"flex items-center justify-end gap-1.5\">\n {onRestart ? (\n <button\n type=\"button\"\n onClick={() => onRestart(server.id)}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border/60 bg-card px-2.5 py-1 font-mono text-label hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <RotateCcw className=\"size-3\" /> Restart\n </button>\n ) : null}\n {onDisconnect ? (\n <button\n type=\"button\"\n onClick={() => onDisconnect(server.id)}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border/60 bg-card px-2.5 py-1 font-mono text-label hover:bg-muted hover:text-destructive focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Plug className=\"size-3\" /> Disconnect\n </button>\n ) : null}\n </footer>\n </article>\n );\n },\n);\nMCPServerCard.displayName = \"MCPServerCard\";\n\nexport { MCPServerCard };\n"
20
20
  }
21
21
  ]
22
22
  }
@@ -17,7 +17,7 @@
17
17
  "path": "components/composites/mcp-server-list/mcp-server-list.tsx",
18
18
  "type": "registry:block",
19
19
  "target": "components/blocks/mcp-server-list.tsx",
20
- "content": "import { Plus } from \"lucide-react\";\nimport { forwardRef, useMemo, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport {\n type MCPServer,\n MCPServerCard,\n type MCPServerStatus,\n} from \"@/components/ui/mcp-server-card\";\n\ninterface MCPServerListProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n servers: MCPServer[];\n title?: ReactNode;\n onAdd?: () => void;\n onRestart?: (id: string) => void;\n onDisconnect?: (id: string) => void;\n}\n\nconst STATUS_ORDER: MCPServerStatus[] = [\"connected\", \"starting\", \"degraded\", \"disconnected\"];\n\n/**\n * MCPServerList — grouped MCP server inventory with status filter chips.\n * Surfaces degraded/disconnected servers prominently so the user can act.\n */\nconst MCPServerList = forwardRef<HTMLDivElement, MCPServerListProps>(\n (\n { className, servers, title = \"MCP servers\", onAdd, onRestart, onDisconnect, ...props },\n ref,\n ) => {\n const [filter, setFilter] = useState<MCPServerStatus | null>(null);\n\n const counts = useMemo(() => {\n const result: Record<MCPServerStatus, number> = {\n connected: 0,\n starting: 0,\n degraded: 0,\n disconnected: 0,\n };\n for (const s of servers) result[s.status]++;\n return result;\n }, [servers]);\n\n const filtered = useMemo(\n () => (filter ? servers.filter((s) => s.status === filter) : servers),\n [servers, filter],\n );\n\n return (\n <section\n ref={ref}\n className={cn(\"grid gap-3\", className)}\n aria-label=\"MCP servers\"\n {...props}\n >\n <header className=\"flex flex-wrap items-center justify-between gap-3\">\n {title ? (\n <h3 className=\"font-display text-title-md tracking-tight\">{title}</h3>\n ) : (\n <span />\n )}\n <div className=\"flex items-center gap-2\">\n <div className=\"inline-flex rounded-lg border border-border/60 bg-muted p-0.5\">\n <button\n type=\"button\"\n onClick={() => setFilter(null)}\n aria-pressed={filter === null}\n className={cn(\n \"rounded-md px-2.5 py-1 font-mono text-label\",\n filter === null ? \"bg-card text-foreground shadow-sm\" : \"text-muted-foreground\",\n )}\n >\n All · {servers.length}\n </button>\n {STATUS_ORDER.map((status) => (\n <button\n key={status}\n type=\"button\"\n onClick={() => setFilter(status)}\n aria-pressed={filter === status}\n disabled={counts[status] === 0}\n className={cn(\n \"rounded-md px-2.5 py-1 font-mono text-label uppercase\",\n filter === status\n ? \"bg-card text-foreground shadow-sm\"\n : \"text-muted-foreground\",\n \"disabled:opacity-40\",\n )}\n >\n {status} · {counts[status]}\n </button>\n ))}\n </div>\n {onAdd ? (\n <button\n type=\"button\"\n onClick={onAdd}\n className=\"inline-flex items-center gap-1 rounded-md bg-primary px-2.5 py-1 font-sans text-label text-primary-foreground hover:shadow-glow focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Plus className=\"size-3.5\" /> Add server\n </button>\n ) : null}\n </div>\n </header>\n\n {filtered.length === 0 ? (\n <p className=\"rounded-xl border border-border/60 border-dashed bg-muted/30 px-4 py-8 text-center font-sans text-body-sm text-muted-foreground\">\n No servers in this state.\n </p>\n ) : (\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2\">\n {filtered.map((server) => (\n <MCPServerCard\n key={server.id}\n server={server}\n {...(onRestart ? { onRestart } : {})}\n {...(onDisconnect ? { onDisconnect } : {})}\n />\n ))}\n </div>\n )}\n </section>\n );\n },\n);\nMCPServerList.displayName = \"MCPServerList\";\n\nexport { MCPServerList };\n"
20
+ "content": "\"use client\";\n\nimport { Plus } from \"lucide-react\";\nimport { forwardRef, useMemo, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport {\n type MCPServer,\n MCPServerCard,\n type MCPServerStatus,\n} from \"@/components/ui/mcp-server-card\";\n\ninterface MCPServerListProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n servers: MCPServer[];\n title?: ReactNode;\n onAdd?: () => void;\n onRestart?: (id: string) => void;\n onDisconnect?: (id: string) => void;\n}\n\nconst STATUS_ORDER: MCPServerStatus[] = [\"connected\", \"starting\", \"degraded\", \"disconnected\"];\n\n/**\n * MCPServerList — grouped MCP server inventory with status filter chips.\n * Surfaces degraded/disconnected servers prominently so the user can act.\n */\nconst MCPServerList = forwardRef<HTMLDivElement, MCPServerListProps>(\n (\n { className, servers, title = \"MCP servers\", onAdd, onRestart, onDisconnect, ...props },\n ref,\n ) => {\n const [filter, setFilter] = useState<MCPServerStatus | null>(null);\n\n const counts = useMemo(() => {\n const result: Record<MCPServerStatus, number> = {\n connected: 0,\n starting: 0,\n degraded: 0,\n disconnected: 0,\n };\n for (const s of servers) result[s.status]++;\n return result;\n }, [servers]);\n\n const filtered = useMemo(\n () => (filter ? servers.filter((s) => s.status === filter) : servers),\n [servers, filter],\n );\n\n return (\n <section\n data-slot=\"mcp-server-list\"\n ref={ref}\n className={cn(\"grid gap-3\", className)}\n aria-label=\"MCP servers\"\n {...props}\n >\n <header className=\"flex flex-wrap items-center justify-between gap-3\">\n {title ? (\n <h3 className=\"font-display text-title-md tracking-tight\">{title}</h3>\n ) : (\n <span />\n )}\n <div className=\"flex items-center gap-2\">\n <div className=\"inline-flex rounded-lg border border-border/60 bg-muted p-0.5\">\n <button\n type=\"button\"\n onClick={() => setFilter(null)}\n aria-pressed={filter === null}\n className={cn(\n \"rounded-md px-2.5 py-1 font-mono text-label\",\n filter === null ? \"bg-card text-foreground shadow-sm\" : \"text-muted-foreground\",\n )}\n >\n All · {servers.length}\n </button>\n {STATUS_ORDER.map((status) => (\n <button\n key={status}\n type=\"button\"\n onClick={() => setFilter(status)}\n aria-pressed={filter === status}\n disabled={counts[status] === 0}\n className={cn(\n \"rounded-md px-2.5 py-1 font-mono text-label uppercase\",\n filter === status\n ? \"bg-card text-foreground shadow-sm\"\n : \"text-muted-foreground\",\n \"disabled:opacity-40\",\n )}\n >\n {status} · {counts[status]}\n </button>\n ))}\n </div>\n {onAdd ? (\n <button\n type=\"button\"\n onClick={onAdd}\n className=\"inline-flex items-center gap-1 rounded-md bg-primary px-2.5 py-1 font-sans text-label text-primary-foreground hover:shadow-glow focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Plus className=\"size-3.5\" /> Add server\n </button>\n ) : null}\n </div>\n </header>\n\n {filtered.length === 0 ? (\n <p className=\"rounded-xl border border-border/60 border-dashed bg-muted/30 px-4 py-8 text-center font-sans text-body-sm text-muted-foreground\">\n No servers in this state.\n </p>\n ) : (\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2\">\n {filtered.map((server) => (\n <MCPServerCard\n key={server.id}\n server={server}\n {...(onRestart ? { onRestart } : {})}\n {...(onDisconnect ? { onDisconnect } : {})}\n />\n ))}\n </div>\n )}\n </section>\n );\n },\n);\nMCPServerList.displayName = \"MCPServerList\";\n\nexport { MCPServerList };\n"
21
21
  }
22
22
  ]
23
23
  }
@@ -17,7 +17,7 @@
17
17
  "path": "components/primitives/memory-editor/memory-editor.tsx",
18
18
  "type": "registry:ui",
19
19
  "target": "components/ui/memory-editor.tsx",
20
- "content": "import { Brain, Folder, FolderOpen, User } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport type { IconComponent } from \"@/lib/types\";\n\nexport type MemoryScope = \"global\" | \"project\" | \"session\";\n\nexport interface MemoryLayer {\n scope: MemoryScope;\n /** File path on disk for transparency. */\n path: string;\n /** Markdown content. */\n content: string;\n /** Last modified label, e.g. \"2m ago\". */\n modifiedAt?: string;\n}\n\ninterface MemoryEditorProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n layers: MemoryLayer[];\n /** Currently active layer for editing. */\n activeScope: MemoryScope;\n onScopeChange: (scope: MemoryScope) => void;\n onContentChange: (scope: MemoryScope, next: string) => void;\n title?: ReactNode;\n}\n\nconst SCOPE_META: Record<MemoryScope, { label: string; icon: IconComponent; hint: string }> = {\n global: { label: \"Global\", icon: User, hint: \"Applies to every project for this user.\" },\n project: {\n label: \"Project\",\n icon: FolderOpen,\n hint: \"Versioned with the project. Shared by team.\",\n },\n session: { label: \"Session\", icon: Folder, hint: \"This session only. Wiped on exit.\" },\n};\n\n/**\n * MemoryEditor — three-layer Markdown memory editor (global / project /\n * session) mirroring Claude Code's CLAUDE.md hierarchy.\n *\n * Each scope keeps its own file. Switching scopes via tab updates which\n * layer is being edited. Path is shown explicitly so users know where the\n * content lives on disk.\n */\nconst MemoryEditor = forwardRef<HTMLDivElement, MemoryEditorProps>(\n (\n { className, layers, activeScope, onScopeChange, onContentChange, title = \"Memory\", ...props },\n ref,\n ) => {\n const active = layers.find((l) => l.scope === activeScope);\n const ActiveIcon = active ? SCOPE_META[active.scope].icon : Brain;\n return (\n <section ref={ref} className={cn(\"rounded-xl border bg-card\", className)} {...props}>\n <header className=\"flex items-center justify-between gap-3 border-border/40 border-b px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n <Brain className=\"size-4 text-primary\" aria-hidden=\"true\" />\n <h3 className=\"font-display text-title-md tracking-tight\">{title}</h3>\n </div>\n <div className=\"inline-flex items-center rounded-lg border border-border/60 bg-muted p-0.5\">\n {([\"global\", \"project\", \"session\"] as const).map((scope) => {\n const meta = SCOPE_META[scope];\n const Icon = meta.icon;\n const isActive = scope === activeScope;\n return (\n <button\n key={scope}\n type=\"button\"\n onClick={() => onScopeChange(scope)}\n aria-pressed={isActive}\n className={cn(\n \"inline-flex items-center gap-1.5 rounded-md px-2.5 py-1\",\n \"font-sans text-label transition-colors\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n isActive\n ? \"bg-card text-foreground shadow-sm\"\n : \"text-muted-foreground hover:text-foreground\",\n )}\n >\n <Icon className=\"size-3\" />\n {meta.label}\n </button>\n );\n })}\n </div>\n </header>\n\n {active ? (\n <>\n <div className=\"flex items-center justify-between gap-3 border-border/40 border-b bg-muted/30 px-4 py-2\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <ActiveIcon className=\"size-3 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n <span className=\"truncate font-mono text-code-sm text-foreground\">\n {active.path}\n </span>\n {active.modifiedAt ? (\n <span className=\"shrink-0 font-mono text-label text-muted-foreground\">\n · {active.modifiedAt}\n </span>\n ) : null}\n </div>\n <span className=\"font-sans text-label text-muted-foreground italic\">\n {SCOPE_META[active.scope].hint}\n </span>\n </div>\n <textarea\n value={active.content}\n onChange={(e) => onContentChange(active.scope, e.target.value)}\n rows={12}\n className=\"w-full resize-y bg-transparent px-4 py-3 font-mono text-code-md text-foreground placeholder:text-muted-foreground focus:outline-none\"\n placeholder={`# ${SCOPE_META[active.scope].label} notes\\n\\nWrite Markdown the agent should keep in context.`}\n />\n </>\n ) : null}\n </section>\n );\n },\n);\nMemoryEditor.displayName = \"MemoryEditor\";\n\nexport { MemoryEditor };\n"
20
+ "content": "import { Brain, Folder, FolderOpen, User } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport type { IconComponent } from \"@/lib/types\";\n\nexport type MemoryScope = \"global\" | \"project\" | \"session\";\n\nexport interface MemoryLayer {\n scope: MemoryScope;\n /** File path on disk for transparency. */\n path: string;\n /** Markdown content. */\n content: string;\n /** Last modified label, e.g. \"2m ago\". */\n modifiedAt?: string;\n}\n\ninterface MemoryEditorProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n layers: MemoryLayer[];\n /** Currently active layer for editing. */\n activeScope: MemoryScope;\n onScopeChange: (scope: MemoryScope) => void;\n onContentChange: (scope: MemoryScope, next: string) => void;\n title?: ReactNode;\n}\n\nconst SCOPE_META: Record<MemoryScope, { label: string; icon: IconComponent; hint: string }> = {\n global: { label: \"Global\", icon: User, hint: \"Applies to every project for this user.\" },\n project: {\n label: \"Project\",\n icon: FolderOpen,\n hint: \"Versioned with the project. Shared by team.\",\n },\n session: { label: \"Session\", icon: Folder, hint: \"This session only. Wiped on exit.\" },\n};\n\n/**\n * MemoryEditor — three-layer Markdown memory editor (global / project /\n * session) mirroring Claude Code's CLAUDE.md hierarchy.\n *\n * Each scope keeps its own file. Switching scopes via tab updates which\n * layer is being edited. Path is shown explicitly so users know where the\n * content lives on disk.\n */\nconst MemoryEditor = forwardRef<HTMLDivElement, MemoryEditorProps>(\n (\n { className, layers, activeScope, onScopeChange, onContentChange, title = \"Memory\", ...props },\n ref,\n ) => {\n const active = layers.find((l) => l.scope === activeScope);\n const ActiveIcon = active ? SCOPE_META[active.scope].icon : Brain;\n return (\n <section\n data-slot=\"memory-editor\"\n ref={ref}\n className={cn(\"rounded-xl border bg-card\", className)}\n {...props}\n >\n <header className=\"flex items-center justify-between gap-3 border-border/40 border-b px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n <Brain className=\"size-4 text-primary\" aria-hidden=\"true\" />\n <h3 className=\"font-display text-title-md tracking-tight\">{title}</h3>\n </div>\n <div className=\"inline-flex items-center rounded-lg border border-border/60 bg-muted p-0.5\">\n {([\"global\", \"project\", \"session\"] as const).map((scope) => {\n const meta = SCOPE_META[scope];\n const Icon = meta.icon;\n const isActive = scope === activeScope;\n return (\n <button\n key={scope}\n type=\"button\"\n onClick={() => onScopeChange(scope)}\n aria-pressed={isActive}\n className={cn(\n \"inline-flex items-center gap-1.5 rounded-md px-2.5 py-1\",\n \"font-sans text-label transition-colors\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n isActive\n ? \"bg-card text-foreground shadow-sm\"\n : \"text-muted-foreground hover:text-foreground\",\n )}\n >\n <Icon className=\"size-3\" />\n {meta.label}\n </button>\n );\n })}\n </div>\n </header>\n\n {active ? (\n <>\n <div className=\"flex items-center justify-between gap-3 border-border/40 border-b bg-muted/30 px-4 py-2\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <ActiveIcon className=\"size-3 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n <span className=\"truncate font-mono text-code-sm text-foreground\">\n {active.path}\n </span>\n {active.modifiedAt ? (\n <span className=\"shrink-0 font-mono text-label text-muted-foreground\">\n · {active.modifiedAt}\n </span>\n ) : null}\n </div>\n <span className=\"font-sans text-label text-muted-foreground italic\">\n {SCOPE_META[active.scope].hint}\n </span>\n </div>\n <textarea\n value={active.content}\n onChange={(e) => onContentChange(active.scope, e.target.value)}\n rows={12}\n className=\"w-full resize-y bg-transparent px-4 py-3 font-mono text-code-md text-foreground placeholder:text-muted-foreground focus:outline-none\"\n placeholder={`# ${SCOPE_META[active.scope].label} notes\\n\\nWrite Markdown the agent should keep in context.`}\n />\n </>\n ) : null}\n </section>\n );\n },\n);\nMemoryEditor.displayName = \"MemoryEditor\";\n\nexport { MemoryEditor };\n"
21
21
  }
22
22
  ]
23
23
  }
@@ -17,7 +17,7 @@
17
17
  "path": "components/primitives/mention-menu/mention-menu.tsx",
18
18
  "type": "registry:ui",
19
19
  "target": "components/ui/mention-menu.tsx",
20
- "content": "import { Hash, type LucideIcon, Slash } from \"lucide-react\";\nimport { useEffect, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport type { IconComponent } from \"@/lib/types\";\n\nexport interface MentionItem {\n id: string;\n /** Primary label shown on the row. */\n label: ReactNode;\n /** Secondary one-line description (optional). */\n description?: ReactNode;\n /** Optional per-row icon override. */\n icon?: IconComponent;\n}\n\n/** Trigger character — drives the default header + icon if not overridden. */\nexport type MentionTrigger = \"/\" | \"@\" | \"#\";\n\ninterface MentionMenuProps {\n /** Whether the panel is open. The consumer (composer) controls this. */\n open: boolean;\n /** Trigger character that opened the menu — used for default title + icon. */\n trigger: MentionTrigger;\n /** Items to display (already filtered by the consumer). */\n items: MentionItem[];\n /** Fires when the user selects an item via click or Enter. */\n onSelect: (item: MentionItem) => void;\n /** Fires when the user dismisses (Esc, click outside). */\n onClose: () => void;\n /** Title above the list. Defaults to the trigger's domain (\"Commands\", \"Files\", \"Memories\"). */\n title?: ReactNode;\n /** Empty-state message when items is empty. */\n emptyLabel?: ReactNode;\n /** Override the alignment relative to its anchor. Default: above-left. */\n className?: string;\n}\n\nconst DEFAULT_TITLE: Record<MentionTrigger, string> = {\n \"/\": \"Commands\",\n \"@\": \"Files\",\n \"#\": \"Memories\",\n};\n\nconst DEFAULT_ICON: Record<MentionTrigger, LucideIcon> = {\n \"/\": Slash,\n \"@\": Slash,\n \"#\": Hash,\n};\n\n/**\n * MentionMenu — keyboard-navigable popover for slash-command / @file / #memory\n * triggers inside an agent composer.\n *\n * Generic by design: the consumer decides what items appear for each trigger\n * (commands list, file search, memory lookup, …). MentionMenu owns the visual\n * presentation, selection highlight, Esc/Enter/Arrow keys.\n *\n * Position: absolute, anchored to the closest positioned ancestor — usually\n * the composer wrapper. Default `bottom-full left-0` (above the composer).\n */\nexport function MentionMenu({\n open,\n trigger,\n items,\n onSelect,\n onClose,\n title,\n emptyLabel = \"No matches\",\n className,\n}: MentionMenuProps) {\n const [activeIndex, setActiveIndex] = useState(0);\n const listRef = useRef<HTMLUListElement>(null);\n\n const resolvedTitle = title ?? DEFAULT_TITLE[trigger];\n const TriggerIcon = DEFAULT_ICON[trigger];\n\n // Clamp the highlighted index whenever items change.\n useEffect(() => {\n if (activeIndex >= items.length) setActiveIndex(Math.max(0, items.length - 1));\n }, [items.length, activeIndex]);\n\n // Reset highlight when the menu opens / trigger changes.\n // biome-ignore lint/correctness/useExhaustiveDependencies: intentional reset on open/trigger\n useEffect(() => {\n if (open) setActiveIndex(0);\n }, [open, trigger]);\n\n // Global keyboard handler — Arrows / Enter / Esc. Captures while open.\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setActiveIndex((i) => Math.min(items.length - 1, i + 1));\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActiveIndex((i) => Math.max(0, i - 1));\n } else if (e.key === \"Enter\") {\n if (items.length === 0) return;\n e.preventDefault();\n const item = items[activeIndex];\n if (item) onSelect(item);\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n onClose();\n }\n };\n window.addEventListener(\"keydown\", onKey, true);\n return () => window.removeEventListener(\"keydown\", onKey, true);\n }, [open, items, activeIndex, onSelect, onClose]);\n\n if (!open) return null;\n\n return (\n <div\n role=\"menu\"\n aria-orientation=\"vertical\"\n aria-label={typeof resolvedTitle === \"string\" ? resolvedTitle : \"Mention menu\"}\n tabIndex={-1}\n className={cn(\n \"absolute bottom-full left-0 z-40 mb-2 w-[22rem] max-w-full\",\n \"overflow-hidden rounded-lg border bg-popover text-popover-foreground shadow-md\",\n \"data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=open]:animate-in\",\n className,\n )}\n data-state=\"open\"\n >\n <div\n role=\"presentation\"\n className=\"flex items-center justify-between gap-2 border-border/40 border-b bg-muted/30 px-3 py-2\"\n >\n <span className=\"inline-flex items-center gap-1.5 font-mono text-label text-muted-foreground uppercase tracking-wider\">\n <TriggerIcon className=\"size-3\" aria-hidden=\"true\" />\n {resolvedTitle}\n </span>\n <span className=\"font-mono text-label text-muted-foreground tabular-nums\">\n {items.length}\n </span>\n </div>\n {items.length === 0 ? (\n <div role=\"presentation\" className=\"px-3 py-4 text-body-sm text-muted-foreground\">\n {emptyLabel}\n </div>\n ) : (\n <ul ref={listRef} role=\"presentation\" className=\"max-h-[18rem] overflow-y-auto py-1\">\n {items.map((item, idx) => {\n const Icon = item.icon;\n const active = idx === activeIndex;\n return (\n <li key={item.id} role=\"presentation\">\n <button\n type=\"button\"\n role=\"menuitem\"\n onMouseEnter={() => setActiveIndex(idx)}\n // Prevent textarea from losing focus on click so the caret stays put.\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => onSelect(item)}\n className={cn(\n \"flex w-full items-start gap-3 px-3 py-2 text-left\",\n \"transition-colors duration-base ease-out-soft\",\n active ? \"bg-muted\" : \"hover:bg-muted/60\",\n )}\n data-active={active || undefined}\n >\n {Icon ? (\n <Icon\n className=\"mt-0.5 size-4 shrink-0 text-muted-foreground\"\n aria-hidden=\"true\"\n />\n ) : null}\n <span className=\"grid min-w-0 flex-1 gap-0.5\">\n <span className=\"truncate font-medium font-mono text-code-md\">\n {item.label}\n </span>\n {item.description ? (\n <span className=\"truncate font-sans text-label text-muted-foreground\">\n {item.description}\n </span>\n ) : null}\n </span>\n </button>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n );\n}\n"
20
+ "content": "\"use client\";\n\nimport { Hash, type LucideIcon, Slash } from \"lucide-react\";\nimport { useEffect, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport type { IconComponent } from \"@/lib/types\";\n\nexport interface MentionItem {\n id: string;\n /** Primary label shown on the row. */\n label: ReactNode;\n /** Secondary one-line description (optional). */\n description?: ReactNode;\n /** Optional per-row icon override. */\n icon?: IconComponent;\n}\n\n/** Trigger character — drives the default header + icon if not overridden. */\nexport type MentionTrigger = \"/\" | \"@\" | \"#\";\n\ninterface MentionMenuProps {\n /** Whether the panel is open. The consumer (composer) controls this. */\n open: boolean;\n /** Trigger character that opened the menu — used for default title + icon. */\n trigger: MentionTrigger;\n /** Items to display (already filtered by the consumer). */\n items: MentionItem[];\n /** Fires when the user selects an item via click or Enter. */\n onSelect: (item: MentionItem) => void;\n /** Fires when the user dismisses (Esc, click outside). */\n onClose: () => void;\n /** Title above the list. Defaults to the trigger's domain (\"Commands\", \"Files\", \"Memories\"). */\n title?: ReactNode;\n /** Empty-state message when items is empty. */\n emptyLabel?: ReactNode;\n /** Override the alignment relative to its anchor. Default: above-left. */\n className?: string;\n}\n\nconst DEFAULT_TITLE: Record<MentionTrigger, string> = {\n \"/\": \"Commands\",\n \"@\": \"Files\",\n \"#\": \"Memories\",\n};\n\nconst DEFAULT_ICON: Record<MentionTrigger, LucideIcon> = {\n \"/\": Slash,\n \"@\": Slash,\n \"#\": Hash,\n};\n\n/**\n * MentionMenu — keyboard-navigable popover for slash-command / @file / #memory\n * triggers inside an agent composer.\n *\n * Generic by design: the consumer decides what items appear for each trigger\n * (commands list, file search, memory lookup, …). MentionMenu owns the visual\n * presentation, selection highlight, Esc/Enter/Arrow keys.\n *\n * Position: absolute, anchored to the closest positioned ancestor — usually\n * the composer wrapper. Default `bottom-full left-0` (above the composer).\n */\nexport function MentionMenu({\n open,\n trigger,\n items,\n onSelect,\n onClose,\n title,\n emptyLabel = \"No matches\",\n className,\n}: MentionMenuProps) {\n const [activeIndex, setActiveIndex] = useState(0);\n const listRef = useRef<HTMLUListElement>(null);\n\n const resolvedTitle = title ?? DEFAULT_TITLE[trigger];\n const TriggerIcon = DEFAULT_ICON[trigger];\n\n // Clamp the highlighted index whenever items change.\n useEffect(() => {\n if (activeIndex >= items.length) setActiveIndex(Math.max(0, items.length - 1));\n }, [items.length, activeIndex]);\n\n // Reset highlight when the menu opens / trigger changes.\n // biome-ignore lint/correctness/useExhaustiveDependencies: intentional reset on open/trigger\n useEffect(() => {\n if (open) setActiveIndex(0);\n }, [open, trigger]);\n\n // Global keyboard handler — Arrows / Enter / Esc. Captures while open.\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setActiveIndex((i) => Math.min(items.length - 1, i + 1));\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActiveIndex((i) => Math.max(0, i - 1));\n } else if (e.key === \"Enter\") {\n if (items.length === 0) return;\n e.preventDefault();\n const item = items[activeIndex];\n if (item) onSelect(item);\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n onClose();\n }\n };\n window.addEventListener(\"keydown\", onKey, true);\n return () => window.removeEventListener(\"keydown\", onKey, true);\n }, [open, items, activeIndex, onSelect, onClose]);\n\n if (!open) return null;\n\n return (\n <div\n data-slot=\"mention-menu\"\n role=\"menu\"\n aria-orientation=\"vertical\"\n aria-label={typeof resolvedTitle === \"string\" ? resolvedTitle : \"Mention menu\"}\n tabIndex={-1}\n className={cn(\n \"absolute bottom-full left-0 z-40 mb-2 w-[22rem] max-w-full\",\n \"overflow-hidden rounded-lg border bg-popover text-popover-foreground shadow-md\",\n \"data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=open]:animate-in\",\n className,\n )}\n data-state=\"open\"\n >\n <div\n role=\"presentation\"\n className=\"flex items-center justify-between gap-2 border-border/40 border-b bg-muted/30 px-3 py-2\"\n >\n <span className=\"inline-flex items-center gap-1.5 font-mono text-label text-muted-foreground uppercase tracking-wider\">\n <TriggerIcon className=\"size-3\" aria-hidden=\"true\" />\n {resolvedTitle}\n </span>\n <span className=\"font-mono text-label text-muted-foreground tabular-nums\">\n {items.length}\n </span>\n </div>\n {items.length === 0 ? (\n <div role=\"presentation\" className=\"px-3 py-4 text-body-sm text-muted-foreground\">\n {emptyLabel}\n </div>\n ) : (\n <ul ref={listRef} role=\"presentation\" className=\"max-h-[18rem] overflow-y-auto py-1\">\n {items.map((item, idx) => {\n const Icon = item.icon;\n const active = idx === activeIndex;\n return (\n <li key={item.id} role=\"presentation\">\n <button\n type=\"button\"\n role=\"menuitem\"\n onMouseEnter={() => setActiveIndex(idx)}\n // Prevent textarea from losing focus on click so the caret stays put.\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => onSelect(item)}\n className={cn(\n \"flex w-full items-start gap-3 px-3 py-2 text-left\",\n \"transition-colors duration-base ease-out-soft\",\n active ? \"bg-muted\" : \"hover:bg-muted/60\",\n )}\n data-active={active || undefined}\n >\n {Icon ? (\n <Icon\n className=\"mt-0.5 size-4 shrink-0 text-muted-foreground\"\n aria-hidden=\"true\"\n />\n ) : null}\n <span className=\"grid min-w-0 flex-1 gap-0.5\">\n <span className=\"truncate font-medium font-mono text-code-md\">\n {item.label}\n </span>\n {item.description ? (\n <span className=\"truncate font-sans text-label text-muted-foreground\">\n {item.description}\n </span>\n ) : null}\n </span>\n </button>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n );\n}\n"
21
21
  }
22
22
  ]
23
23
  }
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "metric-card",
4
+ "type": "registry:ui",
5
+ "title": "MetricCard",
6
+ "description": "Dashboard metric tile composite — title + value + delta with trend semantics. Supports invertTrend for cost/churn metrics (EC-17).",
7
+ "dependencies": [
8
+ "lucide-react"
9
+ ],
10
+ "registryDependencies": [
11
+ "https://usetheodev.github.io/theo-ui/r/card.json",
12
+ "https://usetheodev.github.io/theo-ui/r/cn.json",
13
+ "https://usetheodev.github.io/theo-ui/r/tailwind-preset.json"
14
+ ],
15
+ "files": [
16
+ {
17
+ "path": "components/composites/metric-card/metric-card.tsx",
18
+ "type": "registry:ui",
19
+ "target": "components/ui/metric-card.tsx",
20
+ "content": "import { Minus, TrendingDown, TrendingUp } from \"lucide-react\";\nimport { type HTMLAttributes, type ReactNode, forwardRef } from \"react\";\n\nimport { cn } from \"@/lib/cn\";\nimport { Card } from \"@/components/ui/card\";\n\n/**\n * MetricCard — dashboard metric tile (composite).\n *\n * Pattern recurrente \"Card + CardHeader + value + delta + trend icon\" promoted\n * to a first-class composite per ADR-0007 community-best-practices plan.\n *\n * Trend → token mapping (default `invertTrend=false`):\n * up → text-success (positive growth)\n * down → text-destructive (negative growth)\n * neutral → text-muted-foreground\n *\n * EC-17 absorbed: pass `invertTrend` for metrics where \"up is bad\" (cost,\n * churn, latency). The mapping inverts cleanly:\n * up → text-destructive (cost growing = bad)\n * down → text-success (cost dropping = good)\n *\n * @example\n * <MetricCard title=\"Revenue\" value=\"$12,345\" delta={{ value: \"+12%\", trend: \"up\" }} />\n * <MetricCard title=\"Monthly Cost\" value=\"$3,200\" delta={{ value: \"+18%\", trend: \"up\" }} invertTrend />\n */\n\nexport type MetricCardTrend = \"up\" | \"down\" | \"neutral\";\n\nexport interface MetricCardDelta {\n /** Display text (e.g., `\"+12%\"`, `\"-3.4 pp\"`, `\"unchanged\"`). */\n value: string;\n /** Trend direction — drives icon and color (subject to `invertTrend`). */\n trend: MetricCardTrend;\n}\n\nexport interface MetricCardProps extends HTMLAttributes<HTMLDivElement> {\n /** Metric label (e.g., \"Revenue\", \"Active Users\"). */\n title: string;\n /** Headline value (e.g., \"$12,345\", \"1,234\"). */\n value: ReactNode;\n /** Optional delta with trend direction. */\n delta?: MetricCardDelta;\n /** Optional subtle context line below the value (e.g., \"vs last month\"). */\n hint?: ReactNode;\n /** Optional icon rendered top-right (e.g., `<DollarSign />`). */\n icon?: ReactNode;\n /**\n * EC-17: invert default trend semantics. Use for Cost / Churn / Latency\n * metrics where \"up\" is bad. Default `false` (Revenue / Users / Conversions).\n */\n invertTrend?: boolean;\n}\n\nfunction trendColor(trend: MetricCardTrend, invert: boolean): string {\n if (trend === \"neutral\") return \"text-muted-foreground\";\n const isPositive = invert ? trend === \"down\" : trend === \"up\";\n return isPositive ? \"text-success\" : \"text-destructive\";\n}\n\nfunction TrendIcon({ trend, className }: { trend: MetricCardTrend; className?: string }) {\n if (trend === \"up\") return <TrendingUp className={cn(\"size-3.5\", className)} aria-hidden />;\n if (trend === \"down\") return <TrendingDown className={cn(\"size-3.5\", className)} aria-hidden />;\n return <Minus className={cn(\"size-3.5\", className)} aria-hidden />;\n}\n\nexport const MetricCard = forwardRef<HTMLDivElement, MetricCardProps>(\n ({ title, value, delta, hint, icon, invertTrend = false, className, ...rest }, ref) => {\n return (\n <Card\n data-slot=\"metric-card\"\n ref={ref}\n // T5.5: `@container/metric-card` makes the tile responsive to its PARENT\n // width, not the viewport. Consumers can drop multiple cards into any\n // grid and child elements scale via `@sm:`, `@md:`, `@lg:` variants.\n // `w-full` is the right default for a tile: consumers always wrap in a\n // grid/flex parent (grid-cols-N, flex). Without it, the flex-col card\n // collapses to min-content (~150px) when used in isolation — a real\n // regression observed in the docs site preview pane.\n className={cn(\"@container/metric-card flex w-full flex-col gap-2 p-4\", className)}\n data-testid=\"metric-card\"\n {...rest}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <span className=\"font-medium text-muted-foreground text-xs uppercase tracking-wide\">\n {title}\n </span>\n {icon !== undefined && (\n <span className=\"text-muted-foreground\" aria-hidden>\n {icon}\n </span>\n )}\n </div>\n {/* Value scales 2xl → 3xl when the card container exceeds 18rem. */}\n <div className=\"font-semibold @sm/metric-card:text-3xl text-2xl text-foreground tracking-tight\">\n {value}\n </div>\n {(delta !== undefined || hint !== undefined) && (\n <div className=\"flex items-center gap-2 text-xs\">\n {delta !== undefined && (\n <span\n className={cn(\n \"inline-flex items-center gap-1 font-medium\",\n trendColor(delta.trend, invertTrend),\n )}\n data-trend={delta.trend}\n >\n <TrendIcon trend={delta.trend} />\n {delta.value}\n </span>\n )}\n {hint !== undefined && <span className=\"text-muted-foreground\">{hint}</span>}\n </div>\n )}\n </Card>\n );\n },\n);\nMetricCard.displayName = \"MetricCard\";\n"
21
+ }
22
+ ]
23
+ }
@@ -16,7 +16,7 @@
16
16
  "path": "components/primitives/metrics-panel/metrics-panel.tsx",
17
17
  "type": "registry:block",
18
18
  "target": "components/blocks/metrics-panel.tsx",
19
- "content": "import { TrendingDown, TrendingUp } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\nexport interface Metric {\n /**\n * Short label, e.g. \"Requests/s\", \"p95 latency\", \"Error rate\".\n */\n label: string;\n /**\n * Pre-formatted value string, e.g. \"1.2k\", \"182ms\", \"0.03%\".\n * Consumer formats; the component does not parse.\n */\n value: string;\n /**\n * Optional unit suffix appended after value with .9 opacity.\n */\n unit?: string;\n /**\n * Optional change vs comparison period, e.g. \"+12%\", \"-4ms\", \"+0.01pp\".\n */\n delta?: string;\n /**\n * If true, delta is \"good\" (success color); if false, \"bad\" (destructive).\n * If omitted, delta is rendered in muted (neutral).\n *\n * Caller decides semantics — \"more requests\" is good but \"more errors\" is bad.\n */\n deltaGood?: boolean;\n /**\n * Optional sparkline data, 0..1 normalized. Consumer is responsible for normalization.\n */\n sparkline?: number[];\n /**\n * Optional onClick to drill into the metric.\n */\n onClick?: () => void;\n /**\n * Optional override for the clickable tile's accessible name. When the\n * tile is interactive (`onClick` set), defaults to `View <label> details`.\n * Has no effect when `onClick` is absent (tile is rendered as a non-link\n * `<div>` with no button semantics). T4.3.\n */\n actionLabel?: string;\n}\n\ninterface MetricsPanelProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n title?: ReactNode;\n description?: ReactNode;\n metrics: Metric[];\n /**\n * Grid columns. Defaults to auto-fit ~180px min.\n */\n columns?: number;\n}\n\n/**\n * MetricsPanel — grid of metric tiles for observability dashboards.\n *\n * Visual: each tile is a soft surface with a big value (font-display),\n * label uppercase muted, optional delta with arrow icon + tone color,\n * optional CSS-only sparkline drawn as flexed bars.\n *\n * No external chart lib — keeps the registry copy-pasteable.\n */\nconst MetricsPanel = forwardRef<HTMLDivElement, MetricsPanelProps>(\n ({ className, title, description, metrics, columns, ...props }, ref) => (\n <div ref={ref} className={cn(\"rounded-xl border bg-card p-5 shadow-sm\", className)} {...props}>\n {title || description ? (\n <header className=\"mb-4 grid gap-0.5\">\n {title ? <h3 className=\"font-display text-title-md tracking-tight\">{title}</h3> : null}\n {description ? <p className=\"text-body-sm text-muted-foreground\">{description}</p> : null}\n </header>\n ) : null}\n <div\n className=\"grid gap-4\"\n style={{\n gridTemplateColumns: columns\n ? `repeat(${columns}, minmax(0, 1fr))`\n : \"repeat(auto-fit, minmax(180px, 1fr))\",\n }}\n >\n {metrics.map((m) => (\n <Tile key={m.label} metric={m} />\n ))}\n </div>\n </div>\n ),\n);\nMetricsPanel.displayName = \"MetricsPanel\";\n\nfunction Tile({ metric }: { metric: Metric }) {\n const interactive = metric.onClick !== undefined;\n const Tag = interactive ? \"button\" : \"div\";\n // T4.3 (Code Issue 3): clickable tiles need an explicit accessible name\n // so AT users hear \"View Requests/s details, button\" instead of just\n // the spoken value cluster. Falls back to metric.actionLabel when the\n // caller wants custom text (e.g., \"Drill into requests\").\n const ariaLabel = interactive\n ? (metric.actionLabel ?? `View ${metric.label} details`)\n : undefined;\n return (\n <Tag\n type={interactive ? \"button\" : undefined}\n onClick={metric.onClick}\n aria-label={ariaLabel}\n className={cn(\n \"flex flex-col gap-2 rounded-lg border border-border/30 bg-muted/30 p-4 text-left\",\n \"transition-colors duration-base ease-out-soft\",\n interactive &&\n \"hover:border-primary/40 hover:bg-muted/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card\",\n )}\n >\n <span className=\"font-sans text-label-caps text-muted-foreground uppercase\">\n {metric.label}\n </span>\n <div className=\"flex items-baseline gap-1.5\">\n <span className=\"font-bold font-display text-display-md tabular-nums leading-none\">\n {metric.value}\n </span>\n {metric.unit ? (\n <span className=\"font-mono text-body-sm text-muted-foreground\">{metric.unit}</span>\n ) : null}\n </div>\n <div className=\"flex items-center gap-2\">\n {metric.delta ? <Delta metric={metric} /> : null}\n {metric.sparkline && metric.sparkline.length > 0 ? (\n <Sparkline values={metric.sparkline} />\n ) : null}\n </div>\n </Tag>\n );\n}\n\nfunction Delta({ metric }: { metric: Metric }) {\n const tone =\n metric.deltaGood === undefined\n ? \"text-muted-foreground\"\n : metric.deltaGood\n ? \"text-success\"\n : \"text-destructive\";\n const Icon = metric.deltaGood === false ? TrendingDown : TrendingUp;\n return (\n <span className={cn(\"inline-flex items-center gap-1 font-mono text-body-sm\", tone)}>\n <Icon className=\"size-3\" /> {metric.delta}\n </span>\n );\n}\n\nfunction Sparkline({ values }: { values: number[] }) {\n const clamped = values.map((v) => Math.max(0, Math.min(1, v)));\n return (\n <span className=\"ml-auto flex h-6 items-end gap-[2px]\" aria-hidden=\"true\">\n {clamped.map((v, idx) => (\n <span\n // biome-ignore lint/suspicious/noArrayIndexKey: positional, values are not stable identifiers\n key={idx}\n className=\"w-[3px] rounded-sm bg-primary/60\"\n style={{ height: `${Math.max(8, v * 100)}%` }}\n />\n ))}\n </span>\n );\n}\n\nexport { MetricsPanel };\n"
19
+ "content": "import { TrendingDown, TrendingUp } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\nexport interface Metric {\n /**\n * Short label, e.g. \"Requests/s\", \"p95 latency\", \"Error rate\".\n */\n label: string;\n /**\n * Pre-formatted value string, e.g. \"1.2k\", \"182ms\", \"0.03%\".\n * Consumer formats; the component does not parse.\n */\n value: string;\n /**\n * Optional unit suffix appended after value with .9 opacity.\n */\n unit?: string;\n /**\n * Optional change vs comparison period, e.g. \"+12%\", \"-4ms\", \"+0.01pp\".\n */\n delta?: string;\n /**\n * If true, delta is \"good\" (success color); if false, \"bad\" (destructive).\n * If omitted, delta is rendered in muted (neutral).\n *\n * Caller decides semantics — \"more requests\" is good but \"more errors\" is bad.\n */\n deltaGood?: boolean;\n /**\n * Optional sparkline data, 0..1 normalized. Consumer is responsible for normalization.\n */\n sparkline?: number[];\n /**\n * Optional onClick to drill into the metric.\n */\n onClick?: () => void;\n /**\n * Optional override for the clickable tile's accessible name. When the\n * tile is interactive (`onClick` set), defaults to `View <label> details`.\n * Has no effect when `onClick` is absent (tile is rendered as a non-link\n * `<div>` with no button semantics). T4.3.\n */\n actionLabel?: string;\n}\n\ninterface MetricsPanelProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n title?: ReactNode;\n description?: ReactNode;\n metrics: Metric[];\n /**\n * Grid columns. Defaults to auto-fit ~180px min.\n */\n columns?: number;\n}\n\n/**\n * MetricsPanel — grid of metric tiles for observability dashboards.\n *\n * Visual: each tile is a soft surface with a big value (font-display),\n * label uppercase muted, optional delta with arrow icon + tone color,\n * optional CSS-only sparkline drawn as flexed bars.\n *\n * No external chart lib — keeps the registry copy-pasteable.\n */\nconst MetricsPanel = forwardRef<HTMLDivElement, MetricsPanelProps>(\n ({ className, title, description, metrics, columns, ...props }, ref) => (\n <div\n data-slot=\"metrics-panel\"\n ref={ref}\n className={cn(\"rounded-xl border bg-card p-5 shadow-sm\", className)}\n {...props}\n >\n {title || description ? (\n <header className=\"mb-4 grid gap-0.5\">\n {title ? <h3 className=\"font-display text-title-md tracking-tight\">{title}</h3> : null}\n {description ? <p className=\"text-body-sm text-muted-foreground\">{description}</p> : null}\n </header>\n ) : null}\n <div\n className=\"grid gap-4\"\n style={{\n gridTemplateColumns: columns\n ? `repeat(${columns}, minmax(0, 1fr))`\n : \"repeat(auto-fit, minmax(180px, 1fr))\",\n }}\n >\n {metrics.map((m) => (\n <Tile key={m.label} metric={m} />\n ))}\n </div>\n </div>\n ),\n);\nMetricsPanel.displayName = \"MetricsPanel\";\n\nfunction Tile({ metric }: { metric: Metric }) {\n const interactive = metric.onClick !== undefined;\n const Tag = interactive ? \"button\" : \"div\";\n // T4.3 (Code Issue 3): clickable tiles need an explicit accessible name\n // so AT users hear \"View Requests/s details, button\" instead of just\n // the spoken value cluster. Falls back to metric.actionLabel when the\n // caller wants custom text (e.g., \"Drill into requests\").\n const ariaLabel = interactive\n ? (metric.actionLabel ?? `View ${metric.label} details`)\n : undefined;\n return (\n <Tag\n type={interactive ? \"button\" : undefined}\n onClick={metric.onClick}\n aria-label={ariaLabel}\n className={cn(\n \"flex flex-col gap-2 rounded-lg border border-border/30 bg-muted/30 p-4 text-left\",\n \"transition-colors duration-base ease-out-soft\",\n interactive &&\n \"hover:border-primary/40 hover:bg-muted/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card\",\n )}\n >\n <span className=\"font-sans text-label-caps text-muted-foreground uppercase\">\n {metric.label}\n </span>\n <div className=\"flex items-baseline gap-1.5\">\n <span className=\"font-bold font-display text-display-md tabular-nums leading-none\">\n {metric.value}\n </span>\n {metric.unit ? (\n <span className=\"font-mono text-body-sm text-muted-foreground\">{metric.unit}</span>\n ) : null}\n </div>\n <div className=\"flex items-center gap-2\">\n {metric.delta ? <Delta metric={metric} /> : null}\n {metric.sparkline && metric.sparkline.length > 0 ? (\n <Sparkline values={metric.sparkline} />\n ) : null}\n </div>\n </Tag>\n );\n}\n\nfunction Delta({ metric }: { metric: Metric }) {\n const tone =\n metric.deltaGood === undefined\n ? \"text-muted-foreground\"\n : metric.deltaGood\n ? \"text-success\"\n : \"text-destructive\";\n const Icon = metric.deltaGood === false ? TrendingDown : TrendingUp;\n return (\n <span className={cn(\"inline-flex items-center gap-1 font-mono text-body-sm\", tone)}>\n <Icon className=\"size-3\" /> {metric.delta}\n </span>\n );\n}\n\nfunction Sparkline({ values }: { values: number[] }) {\n const clamped = values.map((v) => Math.max(0, Math.min(1, v)));\n return (\n <span className=\"ml-auto flex h-6 items-end gap-[2px]\" aria-hidden=\"true\">\n {clamped.map((v, idx) => (\n <span\n // biome-ignore lint/suspicious/noArrayIndexKey: positional, values are not stable identifiers\n key={idx}\n className=\"w-[3px] rounded-sm bg-primary/60\"\n style={{ height: `${Math.max(8, v * 100)}%` }}\n />\n ))}\n </span>\n );\n}\n\nexport { MetricsPanel };\n"
20
20
  }
21
21
  ]
22
22
  }