@tai42/studio-sdk 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (422) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +15 -0
  3. package/README.md +318 -0
  4. package/SECURITY.md +51 -0
  5. package/dist/components/badge.d.ts +13 -0
  6. package/dist/components/badge.d.ts.map +1 -0
  7. package/dist/components/badge.js +14 -0
  8. package/dist/components/badge.js.map +1 -0
  9. package/dist/components/checkbox.d.ts +24 -0
  10. package/dist/components/checkbox.d.ts.map +1 -0
  11. package/dist/components/checkbox.js +31 -0
  12. package/dist/components/checkbox.js.map +1 -0
  13. package/dist/components/code-block.d.ts +7 -0
  14. package/dist/components/code-block.d.ts.map +1 -0
  15. package/dist/components/code-block.js +23 -0
  16. package/dist/components/code-block.js.map +1 -0
  17. package/dist/components/completion-input.d.ts +31 -0
  18. package/dist/components/completion-input.d.ts.map +1 -0
  19. package/dist/components/completion-input.js +61 -0
  20. package/dist/components/completion-input.js.map +1 -0
  21. package/dist/components/components.css +2212 -0
  22. package/dist/components/confirm-dialog.d.ts +40 -0
  23. package/dist/components/confirm-dialog.d.ts.map +1 -0
  24. package/dist/components/confirm-dialog.js +11 -0
  25. package/dist/components/confirm-dialog.js.map +1 -0
  26. package/dist/components/control-styles.d.ts +12 -0
  27. package/dist/components/control-styles.d.ts.map +1 -0
  28. package/dist/components/control-styles.js +14 -0
  29. package/dist/components/control-styles.js.map +1 -0
  30. package/dist/components/copy-field.d.ts +8 -0
  31. package/dist/components/copy-field.d.ts.map +1 -0
  32. package/dist/components/copy-field.js +106 -0
  33. package/dist/components/copy-field.js.map +1 -0
  34. package/dist/components/dialog.d.ts +21 -0
  35. package/dist/components/dialog.d.ts.map +1 -0
  36. package/dist/components/dialog.js +25 -0
  37. package/dist/components/dialog.js.map +1 -0
  38. package/dist/components/drawer.d.ts +22 -0
  39. package/dist/components/drawer.d.ts.map +1 -0
  40. package/dist/components/drawer.js +32 -0
  41. package/dist/components/drawer.js.map +1 -0
  42. package/dist/components/error-boundary.d.ts +33 -0
  43. package/dist/components/error-boundary.d.ts.map +1 -0
  44. package/dist/components/error-boundary.js +36 -0
  45. package/dist/components/error-boundary.js.map +1 -0
  46. package/dist/components/extension-combo-builder.d.ts +70 -0
  47. package/dist/components/extension-combo-builder.d.ts.map +1 -0
  48. package/dist/components/extension-combo-builder.js +154 -0
  49. package/dist/components/extension-combo-builder.js.map +1 -0
  50. package/dist/components/extension-grouping.d.ts +65 -0
  51. package/dist/components/extension-grouping.d.ts.map +1 -0
  52. package/dist/components/extension-grouping.js +78 -0
  53. package/dist/components/extension-grouping.js.map +1 -0
  54. package/dist/components/extension-picker.d.ts +35 -0
  55. package/dist/components/extension-picker.d.ts.map +1 -0
  56. package/dist/components/extension-picker.js +31 -0
  57. package/dist/components/extension-picker.js.map +1 -0
  58. package/dist/components/external-link.d.ts +19 -0
  59. package/dist/components/external-link.d.ts.map +1 -0
  60. package/dist/components/external-link.js +12 -0
  61. package/dist/components/external-link.js.map +1 -0
  62. package/dist/components/field.d.ts +64 -0
  63. package/dist/components/field.d.ts.map +1 -0
  64. package/dist/components/field.js +56 -0
  65. package/dist/components/field.js.map +1 -0
  66. package/dist/components/fleet-report.d.ts +39 -0
  67. package/dist/components/fleet-report.d.ts.map +1 -0
  68. package/dist/components/fleet-report.js +50 -0
  69. package/dist/components/fleet-report.js.map +1 -0
  70. package/dist/components/fonts.css +22 -0
  71. package/dist/components/icons.d.ts +142 -0
  72. package/dist/components/icons.d.ts.map +1 -0
  73. package/dist/components/icons.js +139 -0
  74. package/dist/components/icons.js.map +1 -0
  75. package/dist/components/inputs.d.ts +52 -0
  76. package/dist/components/inputs.d.ts.map +1 -0
  77. package/dist/components/inputs.js +35 -0
  78. package/dist/components/inputs.js.map +1 -0
  79. package/dist/components/json-diff.d.ts +40 -0
  80. package/dist/components/json-diff.d.ts.map +1 -0
  81. package/dist/components/json-diff.js +119 -0
  82. package/dist/components/json-diff.js.map +1 -0
  83. package/dist/components/json-tree.d.ts +8 -0
  84. package/dist/components/json-tree.d.ts.map +1 -0
  85. package/dist/components/json-tree.js +70 -0
  86. package/dist/components/json-tree.js.map +1 -0
  87. package/dist/components/modal-focus.d.ts +15 -0
  88. package/dist/components/modal-focus.d.ts.map +1 -0
  89. package/dist/components/modal-focus.js +136 -0
  90. package/dist/components/modal-focus.js.map +1 -0
  91. package/dist/components/page-header.d.ts +56 -0
  92. package/dist/components/page-header.d.ts.map +1 -0
  93. package/dist/components/page-header.js +24 -0
  94. package/dist/components/page-header.js.map +1 -0
  95. package/dist/components/primitives.d.ts +186 -0
  96. package/dist/components/primitives.d.ts.map +1 -0
  97. package/dist/components/primitives.js +204 -0
  98. package/dist/components/primitives.js.map +1 -0
  99. package/dist/components/progress-bar.d.ts +29 -0
  100. package/dist/components/progress-bar.d.ts.map +1 -0
  101. package/dist/components/progress-bar.js +48 -0
  102. package/dist/components/progress-bar.js.map +1 -0
  103. package/dist/components/radio-group.d.ts +37 -0
  104. package/dist/components/radio-group.d.ts.map +1 -0
  105. package/dist/components/radio-group.js +56 -0
  106. package/dist/components/radio-group.js.map +1 -0
  107. package/dist/components/reveal-input.d.ts +13 -0
  108. package/dist/components/reveal-input.d.ts.map +1 -0
  109. package/dist/components/reveal-input.js +31 -0
  110. package/dist/components/reveal-input.js.map +1 -0
  111. package/dist/components/scroll-region.d.ts +85 -0
  112. package/dist/components/scroll-region.d.ts.map +1 -0
  113. package/dist/components/scroll-region.js +574 -0
  114. package/dist/components/scroll-region.js.map +1 -0
  115. package/dist/components/select.d.ts +53 -0
  116. package/dist/components/select.d.ts.map +1 -0
  117. package/dist/components/select.js +33 -0
  118. package/dist/components/select.js.map +1 -0
  119. package/dist/components/table.d.ts +59 -0
  120. package/dist/components/table.d.ts.map +1 -0
  121. package/dist/components/table.js +20 -0
  122. package/dist/components/table.js.map +1 -0
  123. package/dist/components/tabs.d.ts +15 -0
  124. package/dist/components/tabs.d.ts.map +1 -0
  125. package/dist/components/tabs.js +13 -0
  126. package/dist/components/tabs.js.map +1 -0
  127. package/dist/components/tags.d.ts +46 -0
  128. package/dist/components/tags.d.ts.map +1 -0
  129. package/dist/components/tags.js +68 -0
  130. package/dist/components/tags.js.map +1 -0
  131. package/dist/components/tokens.css +392 -0
  132. package/dist/components/tokens.d.ts +15 -0
  133. package/dist/components/tokens.d.ts.map +1 -0
  134. package/dist/components/tokens.js +101 -0
  135. package/dist/components/tokens.js.map +1 -0
  136. package/dist/components/tool-picker.d.ts +24 -0
  137. package/dist/components/tool-picker.d.ts.map +1 -0
  138. package/dist/components/tool-picker.js +97 -0
  139. package/dist/components/tool-picker.js.map +1 -0
  140. package/dist/components/tooltip.d.ts +17 -0
  141. package/dist/components/tooltip.d.ts.map +1 -0
  142. package/dist/components/tooltip.js +18 -0
  143. package/dist/components/tooltip.js.map +1 -0
  144. package/dist/components/version-history-panel.d.ts +71 -0
  145. package/dist/components/version-history-panel.d.ts.map +1 -0
  146. package/dist/components/version-history-panel.js +148 -0
  147. package/dist/components/version-history-panel.js.map +1 -0
  148. package/dist/download.d.ts +7 -0
  149. package/dist/download.d.ts.map +1 -0
  150. package/dist/download.js +18 -0
  151. package/dist/download.js.map +1 -0
  152. package/dist/element-slot.d.ts +4 -0
  153. package/dist/element-slot.d.ts.map +1 -0
  154. package/dist/element-slot.js +20 -0
  155. package/dist/element-slot.js.map +1 -0
  156. package/dist/elicitation/ElicitationForm.d.ts +34 -0
  157. package/dist/elicitation/ElicitationForm.d.ts.map +1 -0
  158. package/dist/elicitation/ElicitationForm.js +24 -0
  159. package/dist/elicitation/ElicitationForm.js.map +1 -0
  160. package/dist/errors.d.ts +9 -0
  161. package/dist/errors.d.ts.map +1 -0
  162. package/dist/errors.js +15 -0
  163. package/dist/errors.js.map +1 -0
  164. package/dist/extension-combos.d.ts +13 -0
  165. package/dist/extension-combos.d.ts.map +1 -0
  166. package/dist/extension-combos.js +9 -0
  167. package/dist/extension-combos.js.map +1 -0
  168. package/dist/hooks/useApi.d.ts +1222 -0
  169. package/dist/hooks/useApi.d.ts.map +1 -0
  170. package/dist/hooks/useApi.js +22 -0
  171. package/dist/hooks/useApi.js.map +1 -0
  172. package/dist/hooks/useAuth.d.ts +13 -0
  173. package/dist/hooks/useAuth.d.ts.map +1 -0
  174. package/dist/hooks/useAuth.js +53 -0
  175. package/dist/hooks/useAuth.js.map +1 -0
  176. package/dist/hooks/useBreakpoint.d.ts +10 -0
  177. package/dist/hooks/useBreakpoint.d.ts.map +1 -0
  178. package/dist/hooks/useBreakpoint.js +66 -0
  179. package/dist/hooks/useBreakpoint.js.map +1 -0
  180. package/dist/hooks/useCapabilities.d.ts +88 -0
  181. package/dist/hooks/useCapabilities.d.ts.map +1 -0
  182. package/dist/hooks/useCapabilities.js +203 -0
  183. package/dist/hooks/useCapabilities.js.map +1 -0
  184. package/dist/hooks/useSse.d.ts +13 -0
  185. package/dist/hooks/useSse.d.ts.map +1 -0
  186. package/dist/hooks/useSse.js +298 -0
  187. package/dist/hooks/useSse.js.map +1 -0
  188. package/dist/hooks/useTheme.d.ts +20 -0
  189. package/dist/hooks/useTheme.d.ts.map +1 -0
  190. package/dist/hooks/useTheme.js +97 -0
  191. package/dist/hooks/useTheme.js.map +1 -0
  192. package/dist/hooks/useUnauthorized.d.ts +3 -0
  193. package/dist/hooks/useUnauthorized.d.ts.map +1 -0
  194. package/dist/hooks/useUnauthorized.js +18 -0
  195. package/dist/hooks/useUnauthorized.js.map +1 -0
  196. package/dist/host.d.ts +11 -0
  197. package/dist/host.d.ts.map +1 -0
  198. package/dist/host.js +10 -0
  199. package/dist/host.js.map +1 -0
  200. package/dist/index.d.ts +118 -0
  201. package/dist/index.d.ts.map +1 -0
  202. package/dist/index.js +91 -0
  203. package/dist/index.js.map +1 -0
  204. package/dist/navigation/context.d.ts +25 -0
  205. package/dist/navigation/context.d.ts.map +1 -0
  206. package/dist/navigation/context.js +45 -0
  207. package/dist/navigation/context.js.map +1 -0
  208. package/dist/navigation/index.d.ts +4 -0
  209. package/dist/navigation/index.d.ts.map +1 -0
  210. package/dist/navigation/index.js +2 -0
  211. package/dist/navigation/index.js.map +1 -0
  212. package/dist/navigation/types.d.ts +97 -0
  213. package/dist/navigation/types.d.ts.map +1 -0
  214. package/dist/navigation/types.js +16 -0
  215. package/dist/navigation/types.js.map +1 -0
  216. package/dist/plugin/host-state.d.ts +45 -0
  217. package/dist/plugin/host-state.d.ts.map +1 -0
  218. package/dist/plugin/host-state.js +62 -0
  219. package/dist/plugin/host-state.js.map +1 -0
  220. package/dist/plugin/registry.d.ts +35 -0
  221. package/dist/plugin/registry.d.ts.map +1 -0
  222. package/dist/plugin/registry.js +129 -0
  223. package/dist/plugin/registry.js.map +1 -0
  224. package/dist/plugin/types.d.ts +165 -0
  225. package/dist/plugin/types.d.ts.map +1 -0
  226. package/dist/plugin/types.js +2 -0
  227. package/dist/plugin/types.js.map +1 -0
  228. package/dist/plugin/version.d.ts +34 -0
  229. package/dist/plugin/version.d.ts.map +1 -0
  230. package/dist/plugin/version.js +37 -0
  231. package/dist/plugin/version.js.map +1 -0
  232. package/dist/query-keys.d.ts +31 -0
  233. package/dist/query-keys.d.ts.map +1 -0
  234. package/dist/query-keys.js +31 -0
  235. package/dist/query-keys.js.map +1 -0
  236. package/dist/schema-editor/SchemaEditor.d.ts +43 -0
  237. package/dist/schema-editor/SchemaEditor.d.ts.map +1 -0
  238. package/dist/schema-editor/SchemaEditor.js +106 -0
  239. package/dist/schema-editor/SchemaEditor.js.map +1 -0
  240. package/dist/schema-editor/index.d.ts +10 -0
  241. package/dist/schema-editor/index.d.ts.map +1 -0
  242. package/dist/schema-editor/index.js +8 -0
  243. package/dist/schema-editor/index.js.map +1 -0
  244. package/dist/schema-editor/lint.d.ts +37 -0
  245. package/dist/schema-editor/lint.d.ts.map +1 -0
  246. package/dist/schema-editor/lint.js +49 -0
  247. package/dist/schema-editor/lint.js.map +1 -0
  248. package/dist/schema-form/SchemaForm.d.ts +70 -0
  249. package/dist/schema-form/SchemaForm.d.ts.map +1 -0
  250. package/dist/schema-form/SchemaForm.js +13 -0
  251. package/dist/schema-form/SchemaForm.js.map +1 -0
  252. package/dist/schema-form/array-field.d.ts +20 -0
  253. package/dist/schema-form/array-field.d.ts.map +1 -0
  254. package/dist/schema-form/array-field.js +39 -0
  255. package/dist/schema-form/array-field.js.map +1 -0
  256. package/dist/schema-form/classify.d.ts +87 -0
  257. package/dist/schema-form/classify.d.ts.map +1 -0
  258. package/dist/schema-form/classify.js +199 -0
  259. package/dist/schema-form/classify.js.map +1 -0
  260. package/dist/schema-form/context.d.ts +4 -0
  261. package/dist/schema-form/context.d.ts.map +1 -0
  262. package/dist/schema-form/context.js +14 -0
  263. package/dist/schema-form/context.js.map +1 -0
  264. package/dist/schema-form/default-value.d.ts +8 -0
  265. package/dist/schema-form/default-value.d.ts.map +1 -0
  266. package/dist/schema-form/default-value.js +64 -0
  267. package/dist/schema-form/default-value.js.map +1 -0
  268. package/dist/schema-form/enum-field.d.ts +19 -0
  269. package/dist/schema-form/enum-field.d.ts.map +1 -0
  270. package/dist/schema-form/enum-field.js +26 -0
  271. package/dist/schema-form/enum-field.js.map +1 -0
  272. package/dist/schema-form/field-group.d.ts +9 -0
  273. package/dist/schema-form/field-group.d.ts.map +1 -0
  274. package/dist/schema-form/field-group.js +32 -0
  275. package/dist/schema-form/field-group.js.map +1 -0
  276. package/dist/schema-form/field-node.d.ts +24 -0
  277. package/dist/schema-form/field-node.d.ts.map +1 -0
  278. package/dist/schema-form/field-node.js +51 -0
  279. package/dist/schema-form/field-node.js.map +1 -0
  280. package/dist/schema-form/index.d.ts +13 -0
  281. package/dist/schema-form/index.d.ts.map +1 -0
  282. package/dist/schema-form/index.js +11 -0
  283. package/dist/schema-form/index.js.map +1 -0
  284. package/dist/schema-form/media-field.d.ts +24 -0
  285. package/dist/schema-form/media-field.d.ts.map +1 -0
  286. package/dist/schema-form/media-field.js +169 -0
  287. package/dist/schema-form/media-field.js.map +1 -0
  288. package/dist/schema-form/media.d.ts +40 -0
  289. package/dist/schema-form/media.d.ts.map +1 -0
  290. package/dist/schema-form/media.js +65 -0
  291. package/dist/schema-form/media.js.map +1 -0
  292. package/dist/schema-form/object-fields.d.ts +20 -0
  293. package/dist/schema-form/object-fields.d.ts.map +1 -0
  294. package/dist/schema-form/object-fields.js +24 -0
  295. package/dist/schema-form/object-fields.js.map +1 -0
  296. package/dist/schema-form/resolve.d.ts +41 -0
  297. package/dist/schema-form/resolve.d.ts.map +1 -0
  298. package/dist/schema-form/resolve.js +102 -0
  299. package/dist/schema-form/resolve.js.map +1 -0
  300. package/dist/schema-form/string-field.d.ts +20 -0
  301. package/dist/schema-form/string-field.d.ts.map +1 -0
  302. package/dist/schema-form/string-field.js +68 -0
  303. package/dist/schema-form/string-field.js.map +1 -0
  304. package/dist/schema-form/styles.d.ts +18 -0
  305. package/dist/schema-form/styles.d.ts.map +1 -0
  306. package/dist/schema-form/styles.js +18 -0
  307. package/dist/schema-form/styles.js.map +1 -0
  308. package/dist/schema-form/types.d.ts +67 -0
  309. package/dist/schema-form/types.d.ts.map +1 -0
  310. package/dist/schema-form/types.js +10 -0
  311. package/dist/schema-form/types.js.map +1 -0
  312. package/dist/schema-form/union-field.d.ts +24 -0
  313. package/dist/schema-form/union-field.d.ts.map +1 -0
  314. package/dist/schema-form/union-field.js +55 -0
  315. package/dist/schema-form/union-field.js.map +1 -0
  316. package/dist/schema-form/union.d.ts +4 -0
  317. package/dist/schema-form/union.d.ts.map +1 -0
  318. package/dist/schema-form/union.js +68 -0
  319. package/dist/schema-form/union.js.map +1 -0
  320. package/dist/schema-form/unsupported-notice.d.ts +18 -0
  321. package/dist/schema-form/unsupported-notice.d.ts.map +1 -0
  322. package/dist/schema-form/unsupported-notice.js +8 -0
  323. package/dist/schema-form/unsupported-notice.js.map +1 -0
  324. package/dist/schema-form/validate.d.ts +18 -0
  325. package/dist/schema-form/validate.d.ts.map +1 -0
  326. package/dist/schema-form/validate.js +162 -0
  327. package/dist/schema-form/validate.js.map +1 -0
  328. package/dist/structured-output/StructuredOutput.d.ts +27 -0
  329. package/dist/structured-output/StructuredOutput.d.ts.map +1 -0
  330. package/dist/structured-output/StructuredOutput.js +41 -0
  331. package/dist/structured-output/StructuredOutput.js.map +1 -0
  332. package/dist/testing.d.ts +80 -0
  333. package/dist/testing.d.ts.map +1 -0
  334. package/dist/testing.js +207 -0
  335. package/dist/testing.js.map +1 -0
  336. package/package.json +101 -0
  337. package/src/components/badge.tsx +31 -0
  338. package/src/components/checkbox.tsx +93 -0
  339. package/src/components/code-block.tsx +37 -0
  340. package/src/components/completion-input.tsx +137 -0
  341. package/src/components/components.css +2212 -0
  342. package/src/components/confirm-dialog.tsx +77 -0
  343. package/src/components/control-styles.ts +14 -0
  344. package/src/components/copy-field.tsx +178 -0
  345. package/src/components/dialog.tsx +76 -0
  346. package/src/components/drawer.tsx +83 -0
  347. package/src/components/error-boundary.tsx +56 -0
  348. package/src/components/extension-combo-builder.tsx +305 -0
  349. package/src/components/extension-grouping.ts +116 -0
  350. package/src/components/extension-picker.tsx +97 -0
  351. package/src/components/external-link.tsx +40 -0
  352. package/src/components/field.tsx +169 -0
  353. package/src/components/fleet-report.tsx +136 -0
  354. package/src/components/fonts.css +22 -0
  355. package/src/components/icons.tsx +504 -0
  356. package/src/components/inputs.tsx +125 -0
  357. package/src/components/json-diff.tsx +192 -0
  358. package/src/components/json-tree.tsx +129 -0
  359. package/src/components/modal-focus.ts +150 -0
  360. package/src/components/page-header.tsx +107 -0
  361. package/src/components/primitives.tsx +489 -0
  362. package/src/components/progress-bar.tsx +100 -0
  363. package/src/components/radio-group.tsx +160 -0
  364. package/src/components/reveal-input.tsx +87 -0
  365. package/src/components/scroll-region.tsx +703 -0
  366. package/src/components/select.tsx +149 -0
  367. package/src/components/table.tsx +94 -0
  368. package/src/components/tabs.tsx +51 -0
  369. package/src/components/tags.tsx +137 -0
  370. package/src/components/tokens.css +392 -0
  371. package/src/components/tokens.ts +102 -0
  372. package/src/components/tool-picker.tsx +175 -0
  373. package/src/components/tooltip.tsx +46 -0
  374. package/src/components/version-history-panel.tsx +407 -0
  375. package/src/css.d.ts +2 -0
  376. package/src/download.ts +17 -0
  377. package/src/element-slot.ts +22 -0
  378. package/src/elicitation/ElicitationForm.tsx +87 -0
  379. package/src/errors.ts +12 -0
  380. package/src/extension-combos.ts +18 -0
  381. package/src/hooks/useApi.ts +27 -0
  382. package/src/hooks/useAuth.ts +67 -0
  383. package/src/hooks/useBreakpoint.ts +78 -0
  384. package/src/hooks/useCapabilities.ts +242 -0
  385. package/src/hooks/useSse.ts +314 -0
  386. package/src/hooks/useTheme.ts +133 -0
  387. package/src/hooks/useUnauthorized.ts +20 -0
  388. package/src/host.ts +15 -0
  389. package/src/index.ts +267 -0
  390. package/src/navigation/context.tsx +90 -0
  391. package/src/navigation/index.ts +9 -0
  392. package/src/navigation/types.ts +90 -0
  393. package/src/plugin/host-state.ts +93 -0
  394. package/src/plugin/registry.ts +174 -0
  395. package/src/plugin/types.ts +178 -0
  396. package/src/plugin/version.ts +44 -0
  397. package/src/query-keys.ts +34 -0
  398. package/src/schema-editor/SchemaEditor.tsx +186 -0
  399. package/src/schema-editor/index.ts +9 -0
  400. package/src/schema-editor/lint.ts +70 -0
  401. package/src/schema-form/SchemaForm.tsx +107 -0
  402. package/src/schema-form/array-field.tsx +110 -0
  403. package/src/schema-form/classify.ts +302 -0
  404. package/src/schema-form/context.ts +17 -0
  405. package/src/schema-form/default-value.ts +65 -0
  406. package/src/schema-form/enum-field.tsx +65 -0
  407. package/src/schema-form/field-group.tsx +71 -0
  408. package/src/schema-form/field-node.tsx +161 -0
  409. package/src/schema-form/index.ts +12 -0
  410. package/src/schema-form/media-field.tsx +281 -0
  411. package/src/schema-form/media.ts +69 -0
  412. package/src/schema-form/object-fields.tsx +74 -0
  413. package/src/schema-form/resolve.ts +114 -0
  414. package/src/schema-form/string-field.tsx +161 -0
  415. package/src/schema-form/styles.ts +20 -0
  416. package/src/schema-form/types.ts +71 -0
  417. package/src/schema-form/union-field.tsx +122 -0
  418. package/src/schema-form/union.ts +78 -0
  419. package/src/schema-form/unsupported-notice.tsx +39 -0
  420. package/src/schema-form/validate.ts +183 -0
  421. package/src/structured-output/StructuredOutput.tsx +81 -0
  422. package/src/testing.ts +235 -0
@@ -0,0 +1,154 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * `ExtensionComboBuilder` — a controlled editor for a preset/tool's LIST OF
4
+ * extension combos. A combo is an ordered list of extension ELEMENTS, each a bare
5
+ * extension NAME or a `{ name, config }` mapping carrying author config; the value
6
+ * is the list of combos (`PresetExtensionElement[][]`), the SAME shape the
7
+ * preset/tool extensions wire carries. It is PRESENTATIONAL: the caller fetches the
8
+ * extension catalog (`available`) and owns the `value`; this component fetches nothing.
9
+ *
10
+ * The surface has two parts:
11
+ * - the current combos, each an ordered row of name `Badge`s with a per-combo Edit
12
+ * (pull it back into the draft) and Remove;
13
+ * - a combo UNDER CONSTRUCTION, authored with the shared `ExtensionPicker` (grouped
14
+ * by kind, single-select for the non-stackable `backend` kind). When the draft
15
+ * includes the `output_schema` extension, its config is authored inline with a
16
+ * `SchemaEditor` (no title required); an "Add combo" / "Update combo" action
17
+ * composes the elements — `output_schema` as `{ name, config: { schema } }`, every
18
+ * other extension as a bare name — and writes it into the value.
19
+ *
20
+ * The builder only blocks the client-trivial invalids: an EMPTY combo (Add is
21
+ * disabled until the draft has ≥1 member), a DUPLICATE of a combo already in the
22
+ * value (by name sequence; flagged inline, Add blocked), an INVALID `output_schema`
23
+ * config (the `SchemaEditor` shows the parse/lint error and Add is blocked), and an
24
+ * UNKNOWN extension name in an existing combo (a name absent from `available`, which
25
+ * happens when a plugin is removed after a preset was authored) — flagged inline on
26
+ * that combo row and reported through `onValidityChange` so the caller can block
27
+ * submit. Every deeper rule — the registry's one-per-non-stackable-kind constraint,
28
+ * meta-schema validity, kind/ordering — is SERVER-AUTHORITATIVE: the write route
29
+ * validates each combo and its 400 message is surfaced verbatim by the caller.
30
+ *
31
+ * Loading is signaled by `availableReady`: while the catalog is still loading the
32
+ * builder reports VALID and suppresses the unknown-name notes (no danger-note flash
33
+ * while submit stays enabled — the server backstops), so a stale-seeded combo does
34
+ * not flicker invalid before the catalog resolves.
35
+ *
36
+ * SAFETY: an extension name is server-supplied, so every name renders as TEXT through
37
+ * the DS `Badge`/`Checkbox` (React escapes it) — never an HTML sink.
38
+ *
39
+ * Geometry and ink come from the design-system classes: each committed combo is a
40
+ * `tai-card` row, the invalid notes are `tai-field-error` (icon + message, never
41
+ * color alone), and Remove is a labelled `Button` carrying `CloseIcon` beside the
42
+ * word, under an accessible name that names the combo it removes.
43
+ */
44
+ import { Fragment, useEffect, useState } from 'react';
45
+ import { comboElementNames, extensionElementName } from '../extension-combos';
46
+ import { SchemaEditor } from '../schema-editor';
47
+ import { Badge } from './badge';
48
+ import { ExtensionPicker } from './extension-picker';
49
+ import { CloseIcon, XCircleIcon } from './icons';
50
+ import { Button } from './primitives';
51
+ /** The one config-taking extension this builder authors inline. */
52
+ const OUTPUT_SCHEMA = 'output_schema';
53
+ /** Two combos are equal when their NAME sequences match (config is not part of identity). */
54
+ function sameNames(a, b) {
55
+ return a.length === b.length && a.every((name, index) => name === b[index]);
56
+ }
57
+ /** The stored `output_schema` config schema for a combo, if it carries one. */
58
+ function outputSchemaConfig(combo) {
59
+ for (const element of combo) {
60
+ if (typeof element !== 'string' && element.name === OUTPUT_SCHEMA) {
61
+ const schema = element.config.schema;
62
+ return typeof schema === 'object' && schema !== null && !Array.isArray(schema)
63
+ ? schema
64
+ : {};
65
+ }
66
+ }
67
+ return null;
68
+ }
69
+ /** The element names in a combo that are absent from the known catalog. */
70
+ function unknownNames(combo, availableNames) {
71
+ return comboElementNames(combo).filter((name) => !availableNames.has(name));
72
+ }
73
+ export function ExtensionComboBuilder({ available, value, onChange, disabled, idPrefix = 'extension-combo-builder', onValidityChange, availableReady = true, }) {
74
+ const [draft, setDraft] = useState([]);
75
+ const [draftConfig, setDraftConfig] = useState({ schema: null, valid: true });
76
+ // The index of the combo being edited (pulled into the draft), or `null` for a new one.
77
+ const [editing, setEditing] = useState(null);
78
+ const draftHasOutputSchema = draft.includes(OUTPUT_SCHEMA);
79
+ const isDuplicate = draft.length > 0 &&
80
+ value.some((combo, index) => index !== editing && sameNames(comboElementNames(combo), draft));
81
+ const configInvalid = draftHasOutputSchema && !draftConfig.valid;
82
+ const canAdd = !disabled && draft.length > 0 && !isDuplicate && !configInvalid;
83
+ // Unknown-name validation over the EXISTING combos. Until the catalog is ready the
84
+ // builder reports VALID and suppresses the notes (no flash on a stale-seeded combo).
85
+ const availableNames = new Set(available.map((extension) => extension.name));
86
+ const hasUnknownName = availableReady && value.some((combo) => unknownNames(combo, availableNames).length > 0);
87
+ const valid = !hasUnknownName;
88
+ useEffect(() => {
89
+ onValidityChange?.(valid);
90
+ }, [onValidityChange, valid]);
91
+ const resetDraft = () => {
92
+ setDraft([]);
93
+ setDraftConfig({ schema: null, valid: true });
94
+ setEditing(null);
95
+ };
96
+ /**
97
+ * Compose the draft names into config-bearing elements. `output_schema` takes the
98
+ * inline-authored config; every other name keeps the edited combo's existing
99
+ * element verbatim when it survives — preserving any author `config` (e.g. an
100
+ * `ask_external` verifier) the builder does not itself author — and a newly-added
101
+ * name becomes a bare-name element.
102
+ */
103
+ const composeCombo = () => {
104
+ const source = editing === null ? undefined : value[editing];
105
+ const byName = new Map();
106
+ if (source !== undefined) {
107
+ for (const element of source)
108
+ byName.set(extensionElementName(element), element);
109
+ }
110
+ return draft.map((name) => name === OUTPUT_SCHEMA
111
+ ? { name, config: { schema: draftConfig.schema ?? {} } }
112
+ : (byName.get(name) ?? name));
113
+ };
114
+ const commitCombo = () => {
115
+ if (!canAdd)
116
+ return;
117
+ const composed = composeCombo();
118
+ if (editing === null) {
119
+ onChange([...value.map((combo) => [...combo]), composed]);
120
+ }
121
+ else {
122
+ onChange(value.map((combo, index) => (index === editing ? composed : [...combo])));
123
+ }
124
+ resetDraft();
125
+ };
126
+ const startEdit = (index) => {
127
+ const combo = value[index];
128
+ if (combo === undefined)
129
+ return;
130
+ setDraft(comboElementNames(combo));
131
+ setDraftConfig({ schema: outputSchemaConfig(combo), valid: true });
132
+ setEditing(index);
133
+ };
134
+ const removeCombo = (index) => {
135
+ onChange(value.filter((_, i) => i !== index).map((combo) => [...combo]));
136
+ // Removing the row under edit (or one before it) invalidates the draft target.
137
+ if (editing !== null && (editing === index || editing > index))
138
+ resetDraft();
139
+ };
140
+ return (_jsxs("div", { "data-testid": idPrefix, className: "tai-stack", children: [value.length > 0 ? (_jsx("ul", { className: "tai-stack tai-stack-2", children: value.map((combo, index) => {
141
+ const names = comboElementNames(combo);
142
+ const unknown = availableReady ? unknownNames(combo, availableNames) : [];
143
+ return (
144
+ // The index IS the identity here: the list mutates by append, in-place
145
+ // update, and remove-by-index (no reorder), and a combo has no stable id
146
+ // of its own — so an index key is stable and cannot collide.
147
+ _jsxs("li", { className: "tai-card tai-stack tai-stack-2", children: [_jsxs("div", { className: "tai-row", children: [_jsx("span", { className: "tai-row", children: names.map((name, position) => (_jsxs(Fragment, { children: [position > 0 ? (_jsx("span", { "aria-hidden": true, className: "tai-muted", children: "+" })) : null, _jsx(Badge, { variant: unknown.includes(name) ? 'danger' : 'primary', children: name })] }, `${name}-${String(position)}`))) }), _jsx(Button, { type: "button", "aria-label": `${editing === index ? 'Editing' : 'Edit'} combo ${names.join('+')}`, disabled: disabled === true || editing === index, onClick: () => {
148
+ startEdit(index);
149
+ }, children: editing === index ? 'Editing' : 'Edit' }), _jsxs(Button, { type: "button", "aria-label": `Remove combo ${names.join('+')}`, disabled: disabled, onClick: () => {
150
+ removeCombo(index);
151
+ }, children: [_jsx(CloseIcon, {}), "Remove"] })] }), unknown.length > 0 ? (_jsxs("p", { role: "alert", className: "tai-field-error", children: [_jsx(XCircleIcon, {}), unknown.length === 1 ? 'Unknown extension: ' : 'Unknown extensions: ', unknown.join(', '), "."] })) : null] }, index));
152
+ }) })) : (_jsx("p", { className: "tai-muted", children: "No extension combos." })), _jsxs("div", { className: "tai-stack tai-stack-2", children: [_jsx(ExtensionPicker, { available: available, value: draft, onChange: setDraft, disabled: disabled, idPrefix: `${idPrefix}-draft` }), draftHasOutputSchema ? (_jsx(SchemaEditor, { value: draftConfig.schema, onChange: setDraftConfig, requireTitle: false, label: "Output schema", description: "The JSON Schema the output_schema extension enforces on this combo's result.", disabled: disabled, idPrefix: `${idPrefix}-output-schema` }, editing === null ? 'new' : `edit-${String(editing)}`)) : null, isDuplicate ? (_jsxs("p", { role: "alert", className: "tai-field-error", children: [_jsx(XCircleIcon, {}), "This combo is already added."] })) : null, _jsxs("div", { className: "tai-row", children: [_jsx(Button, { type: "button", variant: "primary", onClick: commitCombo, disabled: !canAdd, children: editing === null ? 'Add combo' : 'Update combo' }), editing !== null ? (_jsx(Button, { type: "button", onClick: resetDraft, disabled: disabled, children: "Cancel edit" })) : null] })] })] }));
153
+ }
154
+ //# sourceMappingURL=extension-combo-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension-combo-builder.js","sourceRoot":"","sources":["../../src/components/extension-combo-builder.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Pure catalog-shaping helpers for the extensions surface — the SHARED grouping
3
+ * source for both the read-only extensions catalog (`features/extensions`) and the
4
+ * `ExtensionPicker`. Kept free of React so the grouping logic is unit-tested
5
+ * directly.
6
+ *
7
+ * The `/api/extensions` catalog is a flat list of `{ name, kind }` entries. Two
8
+ * independent groupings live here:
9
+ * - `groupIntoFamilies` groups a tool's composed branch VARIANTS (which share a
10
+ * base tool name and append underscore suffixes — `tool`, `tool_a`, `tool_a_b`)
11
+ * back into one FAMILY keyed by that base name (the catalog view);
12
+ * - `groupByKind` groups the catalog by extension KIND (the picker view), where
13
+ * the `backend` kind is the single non-stackable one.
14
+ * `kindVariant` maps each serialized `kind` value to a design-system Badge variant.
15
+ */
16
+ import type { Extension } from '@tai42/api-client';
17
+ import type { BadgeProps } from './badge';
18
+ /**
19
+ * The single non-stackable extension kind: at most one `backend` extension may
20
+ * appear in a combo (the `backend` kind is declared non-stackable, `multiple=False`).
21
+ * The `ExtensionPicker` enforces single-select for this kind.
22
+ */
23
+ export declare const NON_STACKABLE_KIND = "backend";
24
+ /** One base tool and every extension entry that branches from it. */
25
+ export interface ExtensionFamily {
26
+ /** The base tool name (the segment before the first underscore). */
27
+ readonly base: string;
28
+ /** The family's entries, ordered by full name. */
29
+ readonly members: readonly Extension[];
30
+ }
31
+ /** One extension `kind` and every catalog entry of that kind. */
32
+ export interface ExtensionKindGroup {
33
+ /** The serialized kind value (`wrapper` / `transformer` / `backend`). */
34
+ readonly kind: string;
35
+ /** Whether this kind is non-stackable (single-select in the picker). */
36
+ readonly nonStackable: boolean;
37
+ /** The kind's entries, ordered by name. */
38
+ readonly members: readonly Extension[];
39
+ }
40
+ /**
41
+ * The base tool name a variant belongs to: the substring before the first
42
+ * underscore, or the whole name when it has none. `tool`, `tool_a`, `tool_a_b`
43
+ * all resolve to `tool`; `x_chain` and `x_batch` both resolve to `x`.
44
+ */
45
+ export declare function baseNameOf(name: string): string;
46
+ /**
47
+ * Group a flat extension list into families keyed by base tool name. Families
48
+ * are ordered by base name and each family's members by full name, so the render
49
+ * order is stable regardless of the server's list order.
50
+ */
51
+ export declare function groupIntoFamilies(extensions: readonly Extension[]): ExtensionFamily[];
52
+ /**
53
+ * Group a flat extension list by `kind`, for the picker. Groups are ordered by
54
+ * kind and each group's members by name, so the render order is stable regardless
55
+ * of the server's list order. The `backend` group is flagged non-stackable.
56
+ */
57
+ export declare function groupByKind(extensions: readonly Extension[]): ExtensionKindGroup[];
58
+ /**
59
+ * Map a serialized extension `kind` to a Badge variant. Known skeleton kinds get
60
+ * a themed color; any unrecognized kind falls back to the neutral variant (the
61
+ * Badge itself also neutral-fallbacks, but choosing here keeps the mapping
62
+ * explicit and testable).
63
+ */
64
+ export declare function kindVariant(kind: string): NonNullable<BadgeProps['variant']>;
65
+ //# sourceMappingURL=extension-grouping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension-grouping.d.ts","sourceRoot":"","sources":["../../src/components/extension-grouping.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,YAAY,CAAC;AAE5C,qEAAqE;AACrE,MAAM,WAAW,eAAe;IAC9B,oEAAoE;IACpE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,QAAQ,CAAC,OAAO,EAAE,SAAS,SAAS,EAAE,CAAC;CACxC;AAED,iEAAiE;AACjE,MAAM,WAAW,kBAAkB;IACjC,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,2CAA2C;IAC3C,QAAQ,CAAC,OAAO,EAAE,SAAS,SAAS,EAAE,CAAC;CACxC;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG/C;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,GAAG,eAAe,EAAE,CAiBrF;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,GAAG,kBAAkB,EAAE,CAiBlF;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAO5E"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * The single non-stackable extension kind: at most one `backend` extension may
3
+ * appear in a combo (the `backend` kind is declared non-stackable, `multiple=False`).
4
+ * The `ExtensionPicker` enforces single-select for this kind.
5
+ */
6
+ export const NON_STACKABLE_KIND = 'backend';
7
+ /**
8
+ * The base tool name a variant belongs to: the substring before the first
9
+ * underscore, or the whole name when it has none. `tool`, `tool_a`, `tool_a_b`
10
+ * all resolve to `tool`; `x_chain` and `x_batch` both resolve to `x`.
11
+ */
12
+ export function baseNameOf(name) {
13
+ const separator = name.indexOf('_');
14
+ return separator === -1 ? name : name.slice(0, separator);
15
+ }
16
+ /**
17
+ * Group a flat extension list into families keyed by base tool name. Families
18
+ * are ordered by base name and each family's members by full name, so the render
19
+ * order is stable regardless of the server's list order.
20
+ */
21
+ export function groupIntoFamilies(extensions) {
22
+ const byBase = new Map();
23
+ for (const extension of extensions) {
24
+ const base = baseNameOf(extension.name);
25
+ const members = byBase.get(base);
26
+ if (members) {
27
+ members.push(extension);
28
+ }
29
+ else {
30
+ byBase.set(base, [extension]);
31
+ }
32
+ }
33
+ return [...byBase.entries()]
34
+ .map(([base, members]) => ({
35
+ base,
36
+ members: [...members].sort((a, b) => a.name.localeCompare(b.name)),
37
+ }))
38
+ .sort((a, b) => a.base.localeCompare(b.base));
39
+ }
40
+ /**
41
+ * Group a flat extension list by `kind`, for the picker. Groups are ordered by
42
+ * kind and each group's members by name, so the render order is stable regardless
43
+ * of the server's list order. The `backend` group is flagged non-stackable.
44
+ */
45
+ export function groupByKind(extensions) {
46
+ const byKind = new Map();
47
+ for (const extension of extensions) {
48
+ const members = byKind.get(extension.kind);
49
+ if (members) {
50
+ members.push(extension);
51
+ }
52
+ else {
53
+ byKind.set(extension.kind, [extension]);
54
+ }
55
+ }
56
+ return [...byKind.entries()]
57
+ .map(([kind, members]) => ({
58
+ kind,
59
+ nonStackable: kind === NON_STACKABLE_KIND,
60
+ members: [...members].sort((a, b) => a.name.localeCompare(b.name)),
61
+ }))
62
+ .sort((a, b) => a.kind.localeCompare(b.kind));
63
+ }
64
+ /**
65
+ * Map a serialized extension `kind` to a Badge variant. Known skeleton kinds get
66
+ * a themed color; any unrecognized kind falls back to the neutral variant (the
67
+ * Badge itself also neutral-fallbacks, but choosing here keeps the mapping
68
+ * explicit and testable).
69
+ */
70
+ export function kindVariant(kind) {
71
+ const known = {
72
+ wrapper: 'primary',
73
+ transformer: 'success',
74
+ backend: 'warning',
75
+ };
76
+ return known[kind] ?? 'neutral';
77
+ }
78
+ //# sourceMappingURL=extension-grouping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension-grouping.js","sourceRoot":"","sources":["../../src/components/extension-grouping.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * `ExtensionPicker` — a controlled multi-select over the extension catalog
3
+ * (`GET /api/extensions`), authoring ONE extension combo (an ordered list of
4
+ * extension names). Built on the DS `Checkbox` so features share one picker
5
+ * instead of re-implementing a checklist (the same reason `SchemaForm`/`ToolPicker`
6
+ * live in the SDK). It is PRESENTATIONAL: the caller fetches `available` and owns
7
+ * the selected `value`; this component fetches nothing.
8
+ *
9
+ * The catalog is GROUPED by `kind`. The `backend` kind is the single NON-STACKABLE
10
+ * one (`multiple=False`), so it is SINGLE-SELECT — checking a backend
11
+ * extension replaces any other backend already in the combo; every other kind is
12
+ * freely multi-select. Selection order is preserved (the combo is ordered — the
13
+ * stacking order that produces the branch tool name), so a newly-checked extension
14
+ * appends to the end and unchecking removes in place.
15
+ *
16
+ * SAFETY: an extension name AND its kind are server-supplied, so every name/kind
17
+ * renders as TEXT through the DS `Checkbox`/`Badge` (React escapes it) — never an
18
+ * HTML sink. Pinned by a test.
19
+ *
20
+ * Geometry and ink come from the design-system layout classes (`tai-stack`,
21
+ * `tai-row`, `tai-muted`); the component carries no palette of its own.
22
+ */
23
+ import type { Extension } from '@tai42/api-client';
24
+ export interface ExtensionPickerProps {
25
+ /** The extension catalog (`GET /api/extensions`) the checklist is drawn from. */
26
+ readonly available: readonly Extension[];
27
+ /** The currently-selected extension names, in combo (stacking) order. */
28
+ readonly value: readonly string[];
29
+ /** Fired with the next ordered selection whenever a box toggles. */
30
+ readonly onChange: (names: string[]) => void;
31
+ readonly disabled?: boolean;
32
+ readonly idPrefix?: string;
33
+ }
34
+ export declare function ExtensionPicker({ available, value, onChange, disabled, idPrefix, }: ExtensionPickerProps): import("react").JSX.Element;
35
+ //# sourceMappingURL=extension-picker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension-picker.d.ts","sourceRoot":"","sources":["../../src/components/extension-picker.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAMnD,MAAM,WAAW,oBAAoB;IACnC,iFAAiF;IACjF,QAAQ,CAAC,SAAS,EAAE,SAAS,SAAS,EAAE,CAAC;IACzC,yEAAyE;IACzE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAgB,eAAe,CAAC,EAC9B,SAAS,EACT,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,QAA6B,GAC9B,EAAE,oBAAoB,+BAmDtB"}
@@ -0,0 +1,31 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Badge } from './badge';
3
+ import { Checkbox } from './checkbox';
4
+ import { groupByKind, kindVariant } from './extension-grouping';
5
+ export function ExtensionPicker({ available, value, onChange, disabled, idPrefix = 'extension-picker', }) {
6
+ const groups = groupByKind(available);
7
+ const selected = new Set(value);
8
+ /**
9
+ * Toggle a single extension. For a NON-STACKABLE kind (`backend`), checking one
10
+ * first strips any other selected member of that kind before appending, so the
11
+ * combo carries at most one backend; unchecking just removes it. Order is
12
+ * preserved: a newly-checked name lands at the end.
13
+ */
14
+ const toggle = (extension, nonStackable, checked) => {
15
+ if (!checked) {
16
+ onChange(value.filter((name) => name !== extension.name));
17
+ return;
18
+ }
19
+ if (selected.has(extension.name))
20
+ return;
21
+ const siblingNames = nonStackable
22
+ ? new Set(available.filter((e) => e.kind === extension.kind).map((e) => e.name))
23
+ : undefined;
24
+ const kept = siblingNames === undefined ? [...value] : value.filter((name) => !siblingNames.has(name));
25
+ onChange([...kept, extension.name]);
26
+ };
27
+ return (_jsx("div", { "data-testid": idPrefix, className: "tai-stack", children: groups.map((group) => (_jsxs("div", { className: "tai-stack tai-stack-2", children: [_jsxs("div", { className: "tai-row", children: [_jsx(Badge, { variant: kindVariant(group.kind), children: group.kind }), group.nonStackable ? _jsx("span", { className: "tai-muted", children: "(single-select)" }) : null] }), _jsx("div", { className: "tai-row", children: group.members.map((extension) => (_jsx(Checkbox, { label: extension.name, checked: selected.has(extension.name), disabled: disabled, onCheckedChange: (checked) => {
28
+ toggle(extension, group.nonStackable, checked);
29
+ } }, extension.name))) })] }, group.kind))) }));
30
+ }
31
+ //# sourceMappingURL=extension-picker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension-picker.js","sourceRoot":"","sources":["../../src/components/extension-picker.tsx"],"names":[],"mappings":";AAwBA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAahE,MAAM,UAAU,eAAe,CAAC,EAC9B,SAAS,EACT,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,QAAQ,GAAG,kBAAkB,GACR;IACrB,MAAM,MAAM,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IAEhC;;;;;OAKG;IACH,MAAM,MAAM,GAAG,CAAC,SAAoB,EAAE,YAAqB,EAAE,OAAgB,EAAQ,EAAE;QACrF,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YAC1D,OAAO;QACT,CAAC;QACD,IAAI,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC;YAAE,OAAO;QACzC,MAAM,YAAY,GAAG,YAAY;YAC/B,CAAC,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAChF,CAAC,CAAC,SAAS,CAAC;QACd,MAAM,IAAI,GACR,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5F,QAAQ,CAAC,CAAC,GAAG,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IACtC,CAAC,CAAC;IAEF,OAAO,CACL,6BAAkB,QAAQ,EAAE,SAAS,EAAC,WAAW,YAC9C,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACrB,eAAsB,SAAS,EAAC,uBAAuB,aAGrD,eAAK,SAAS,EAAC,SAAS,aACtB,KAAC,KAAK,IAAC,OAAO,EAAE,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,YAAG,KAAK,CAAC,IAAI,GAAS,EAC5D,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,eAAM,SAAS,EAAC,WAAW,gCAAuB,CAAC,CAAC,CAAC,IAAI,IAC3E,EACN,cAAK,SAAS,EAAC,SAAS,YACrB,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAChC,KAAC,QAAQ,IAEP,KAAK,EAAE,SAAS,CAAC,IAAI,EACrB,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EACrC,QAAQ,EAAE,QAAQ,EAClB,eAAe,EAAE,CAAC,OAAO,EAAE,EAAE;4BAC3B,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;wBACjD,CAAC,IANI,SAAS,CAAC,IAAI,CAOnB,CACH,CAAC,GACE,KAnBE,KAAK,CAAC,IAAI,CAoBd,CACP,CAAC,GACE,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * `ExternalLinkButton` — an open-link action for a URL the Studio did not author
3
+ * (a registry homepage, an interaction payload's link). Only an ABSOLUTE
4
+ * `http(s)` URL is navigable here: every other spelling — another scheme, and a
5
+ * relative reference, which would be a same-origin in-app navigation the caller
6
+ * never intended — is NEUTRALIZED into plain text with no anchor and no href.
7
+ * This is an XSS pin.
8
+ *
9
+ * The check and the neutralized rendering are `Button`'s; this module chooses the
10
+ * stricter of the two link policies rather than re-implementing either.
11
+ */
12
+ import type { ReactNode } from 'react';
13
+ export { isSafeHttpUrl } from './primitives';
14
+ export interface ExternalLinkButtonProps {
15
+ readonly url: string;
16
+ readonly children?: ReactNode;
17
+ }
18
+ export declare function ExternalLinkButton({ url, children }: ExternalLinkButtonProps): import("react").JSX.Element;
19
+ //# sourceMappingURL=external-link.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-link.d.ts","sourceRoot":"","sources":["../../src/components/external-link.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAUvC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;CAC/B;AAED,wBAAgB,kBAAkB,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,uBAAuB,+BAW5E"}
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Button, buttonClass, DEFAULT_BUTTON_VARIANT, isSafeHttpUrl, NeutralizedLink, } from './primitives';
3
+ export { isSafeHttpUrl } from './primitives';
4
+ export function ExternalLinkButton({ url, children }) {
5
+ const label = children ?? url;
6
+ if (!isSafeHttpUrl(url)) {
7
+ // The same classes the navigable form wears, so the two never drift apart.
8
+ return (_jsx(NeutralizedLink, { className: buttonClass(DEFAULT_BUTTON_VARIANT, undefined), children: label }));
9
+ }
10
+ return _jsx(Button, { href: url, children: label });
11
+ }
12
+ //# sourceMappingURL=external-link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-link.js","sourceRoot":"","sources":["../../src/components/external-link.tsx"],"names":[],"mappings":";AAaA,OAAO,EACL,MAAM,EACN,WAAW,EACX,sBAAsB,EACtB,aAAa,EACb,eAAe,GAChB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAO7C,MAAM,UAAU,kBAAkB,CAAC,EAAE,GAAG,EAAE,QAAQ,EAA2B;IAC3E,MAAM,KAAK,GAAG,QAAQ,IAAI,GAAG,CAAC;IAC9B,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,2EAA2E;QAC3E,OAAO,CACL,KAAC,eAAe,IAAC,SAAS,EAAE,WAAW,CAAC,sBAAsB,EAAE,SAAS,CAAC,YACvE,KAAK,GACU,CACnB,CAAC;IACJ,CAAC;IACD,OAAO,KAAC,MAAM,IAAC,IAAI,EAAE,GAAG,YAAG,KAAK,GAAU,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,64 @@
1
+ import type { CSSProperties, ReactNode } from 'react';
2
+ /** The a11y wiring a form control spreads onto its element. */
3
+ export interface FieldControlProps {
4
+ readonly id: string | undefined;
5
+ readonly 'aria-describedby': string | undefined;
6
+ readonly 'aria-invalid': true | undefined;
7
+ }
8
+ /**
9
+ * Read the enclosing Field's wiring.
10
+ *
11
+ * `id` and `aria-describedby` are `undefined` both when there is no Field AND
12
+ * inside a group `Field`: a group has no single element to carry them, and the
13
+ * group container itself already carries the name and the description. Only
14
+ * `aria-invalid` still crosses that boundary, because `role="group"` does not
15
+ * support it (ARIA 1.2), so the control is the sole place an errored group can
16
+ * expose its invalid state.
17
+ */
18
+ export declare function useFieldControl(): FieldControlProps;
19
+ export interface FieldProps {
20
+ readonly label: string;
21
+ readonly description?: string;
22
+ readonly error?: string;
23
+ readonly children: ReactNode;
24
+ readonly style?: CSSProperties;
25
+ /** APPENDED to `tai-field` rather than replacing it, so the field keeps its paint. */
26
+ readonly className?: string;
27
+ /**
28
+ * Set when the wrapped control is a GROUP rather than one labelable element —
29
+ * a `RadioGroup`, a set of checkboxes, any `role="radiogroup"`/`role="group"`
30
+ * panel.
31
+ *
32
+ * `<label for>` can only name a labelable element: pointed at a group it
33
+ * either dangles at an id no element carries or names an element the browser
34
+ * refuses to label, and it is inert either way. So a group Field wraps
35
+ * `children` in the group CONTAINER itself — a `<div role="group">` carrying
36
+ * `aria-labelledby` at the label and `aria-describedby` at the description and
37
+ * error — and the label becomes a `<span>`, because a `<label>` associated
38
+ * with nothing is a semantics lie.
39
+ *
40
+ * IT ALSO CHANGES WHAT A CHILD READS FROM {@link useFieldControl}. The
41
+ * container is what carries the name and the description, so the group Field
42
+ * publishes NEITHER `id` NOR `aria-describedby` — both are `undefined`, and a
43
+ * control that spread them would take the group's own name and description for
44
+ * itself. `aria-invalid` still crosses: `role="group"` does not support it
45
+ * (ARIA 1.2), so the control is the only place an errored group can expose its
46
+ * invalid state.
47
+ *
48
+ * Naming therefore happens BY CONSTRUCTION rather than by the call site
49
+ * remembering to read a hook. The cost is one extra container announcement
50
+ * where the child has a group role of its own; that is accepted deliberately,
51
+ * because the two failure directions are asymmetric — a redundant container is
52
+ * audible, an unnamed group is silent.
53
+ *
54
+ * A group child left UNMARKED is a build failure, not a runtime surprise:
55
+ * `components/field-group.test.ts` ("Field group contract" → "marks every
56
+ * Field whose child does not claim its control id") scans every Field call
57
+ * site in the repository, and a child outside its list of control-id-claiming
58
+ * components — `RadioGroup` among them — reddens until the site passes
59
+ * `group`.
60
+ */
61
+ readonly group?: boolean;
62
+ }
63
+ export declare function Field({ label, description, error, children, style, className, group, }: FieldProps): import("react").JSX.Element;
64
+ //# sourceMappingURL=field.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../../src/components/field.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAYtD,+DAA+D;AAC/D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;IAChD,QAAQ,CAAC,cAAc,EAAE,IAAI,GAAG,SAAS,CAAC;CAC3C;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,IAAI,iBAAiB,CAUnD;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC;IAC/B,sFAAsF;IACtF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,KAAK,CAAC,EACpB,KAAK,EACL,WAAW,EACX,KAAK,EACL,QAAQ,EACR,KAAK,EACL,SAAS,EACT,KAAa,GACd,EAAE,UAAU,+BAiEZ"}
@@ -0,0 +1,56 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * `Field` — the label + description + error wrapper every form control sits in.
4
+ * It owns one generated id and publishes it (plus the description/error ids and
5
+ * the invalid flag) through a context; a nested control reads them via
6
+ * `useFieldControl` and spreads them, so the label's `htmlFor`, the control's
7
+ * `aria-describedby`, and its `aria-invalid` stay wired without the caller
8
+ * threading ids by hand.
9
+ */
10
+ import { createContext, useContext, useId } from 'react';
11
+ import { XCircleIcon } from './icons';
12
+ const FieldContext = createContext(null);
13
+ /**
14
+ * Read the enclosing Field's wiring.
15
+ *
16
+ * `id` and `aria-describedby` are `undefined` both when there is no Field AND
17
+ * inside a group `Field`: a group has no single element to carry them, and the
18
+ * group container itself already carries the name and the description. Only
19
+ * `aria-invalid` still crosses that boundary, because `role="group"` does not
20
+ * support it (ARIA 1.2), so the control is the sole place an errored group can
21
+ * expose its invalid state.
22
+ */
23
+ export function useFieldControl() {
24
+ const ctx = useContext(FieldContext);
25
+ if (ctx === null) {
26
+ return { id: undefined, 'aria-describedby': undefined, 'aria-invalid': undefined };
27
+ }
28
+ return {
29
+ id: ctx.controlId,
30
+ 'aria-describedby': ctx.describedBy,
31
+ 'aria-invalid': ctx.invalid ? true : undefined,
32
+ };
33
+ }
34
+ export function Field({ label, description, error, children, style, className, group = false, }) {
35
+ const controlId = useId();
36
+ const labelId = `${controlId}-label`;
37
+ const descriptionId = `${controlId}-desc`;
38
+ const errorId = `${controlId}-err`;
39
+ const describedByIds = [];
40
+ if (description !== undefined)
41
+ describedByIds.push(descriptionId);
42
+ if (error !== undefined)
43
+ describedByIds.push(errorId);
44
+ const describedBy = describedByIds.length > 0 ? describedByIds.join(' ') : undefined;
45
+ // A group withholds the ID and the DESCRIPTION — there is no single element to
46
+ // carry them, and a control that spread them inside a group would take the
47
+ // group's own name and description for itself — but it still publishes
48
+ // `invalid`. `aria-invalid` is not supported on `role="group"` (ARIA 1.2), so
49
+ // if the group Field withheld it too, a group Field carrying an `error` would
50
+ // expose its invalid state NOWHERE in the accessibility tree.
51
+ const value = group
52
+ ? { controlId: undefined, describedBy: undefined, invalid: error !== undefined }
53
+ : { controlId, describedBy, invalid: error !== undefined };
54
+ return (_jsx(FieldContext.Provider, { value: value, children: _jsxs("div", { className: className === undefined ? 'tai-field' : `tai-field ${className}`, style: style, children: [group ? (_jsx("span", { id: labelId, className: "tai-field-label", children: label })) : (_jsx("label", { id: labelId, htmlFor: controlId, className: "tai-field-label", children: label })), group ? (_jsx("div", { role: "group", "aria-labelledby": labelId, "aria-describedby": describedBy, className: "tai-field-group", children: children })) : (children), description !== undefined ? (_jsx("p", { id: descriptionId, className: "tai-field-hint", style: { margin: 0 }, children: description })) : null, error !== undefined ? (_jsxs("p", { id: errorId, role: "alert", className: "tai-field-error", style: { margin: 0 }, children: [_jsx(XCircleIcon, {}), error] })) : null] }) }));
55
+ }
56
+ //# sourceMappingURL=field.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field.js","sourceRoot":"","sources":["../../src/components/field.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * `FleetReport` — the shared, loud rendering of a config mutation's fleet broadcast.
3
+ * Every mutation surface (connector, backup, mcp-config, env, extensions, single-MCP
4
+ * reload, fleet reload) computes a `FleetReportSummary` from its response through the
5
+ * api-client's shared handler and hands it here, so a FAILED propagation is never
6
+ * invisible.
7
+ *
8
+ * The `action` prop tunes the copy to the caller's framing: `'save'` (the default,
9
+ * used by every config-mutation surface) reports a saved change that did not fully
10
+ * propagate and points the operator at the System page to reload; `'reload'` (the
11
+ * System page's own fleet-reload action) drops the "Change saved" framing — nothing
12
+ * was saved, a reload was dispatched — and the self-referential System-page pointer.
13
+ *
14
+ * A `converged` summary (every origin applied, or a lone-worker local-only change)
15
+ * renders NOTHING — the calling surface shows its own success. A `degraded` summary
16
+ * (the bus was reached but a sibling did not confirm) or an `unreachable` summary (the
17
+ * bus itself failed) renders a loud `role="alert"` panel naming the honest per-origin
18
+ * outcomes: `failed` / `missing` / `departed` / `timed_out`, or the bus error. It
19
+ * never fakes success on a stranded origin. Every server-supplied string (an origin
20
+ * name, an error/detail message) renders as escaped React text, never an HTML sink.
21
+ *
22
+ * Every state — the headline and each origin's outcome — is a `tai-status` line: an
23
+ * icon MARK plus a word LABEL, with the tone color only reinforcing them, so the
24
+ * report is readable without color perception.
25
+ */
26
+ import type { ReactNode } from 'react';
27
+ import type { FleetReportSummary } from '@tai42/api-client';
28
+ /**
29
+ * Render a fleet broadcast's failure state. Returns `null` for a converged/absent
30
+ * report (nothing to warn about) so callers can always mount it unconditionally
31
+ * beside their own success line.
32
+ */
33
+ export interface FleetReportProps {
34
+ readonly summary: FleetReportSummary | null;
35
+ /** Whose framing the copy takes: a saved config change, or a dispatched reload. */
36
+ readonly action?: 'save' | 'reload';
37
+ }
38
+ export declare function FleetReport({ summary, action }: FleetReportProps): ReactNode;
39
+ //# sourceMappingURL=fleet-report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fleet-report.d.ts","sourceRoot":"","sources":["../../src/components/fleet-report.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,kBAAkB,EAAuB,MAAM,mBAAmB,CAAC;AAgCjF;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC5C,mFAAmF;IACnF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;CACrC;AAED,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,MAAe,EAAE,EAAE,gBAAgB,GAAG,SAAS,CAkErF"}