@opengeni/react 3.3.2 → 3.4.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 (855) hide show
  1. package/README.md +769 -22
  2. package/dist/accounts.js +2 -0
  3. package/dist/accounts.js.map +1 -1
  4. package/dist/approvals.d.ts +2 -1
  5. package/dist/artifacts-document.js +5 -3
  6. package/dist/artifacts-presentation.js +5 -3
  7. package/dist/artifacts-spreadsheet.d.ts +1 -1
  8. package/dist/artifacts-spreadsheet.js +5 -3
  9. package/dist/artifacts.d.ts +5 -1
  10. package/dist/artifacts.js +536 -42
  11. package/dist/artifacts.js.map +1 -1
  12. package/dist/browser-viewer-ZWR6MWJ7.js +19 -0
  13. package/dist/capability-catalog-row.d.ts +20 -0
  14. package/dist/capability-logo-fallback.d.ts +3 -0
  15. package/dist/chat-interactive-block-4EUKJXUO.js +14 -0
  16. package/dist/chunk-2DDJ6YH6.js +41 -0
  17. package/dist/chunk-2DDJ6YH6.js.map +1 -0
  18. package/dist/chunk-2HVLQ26H.js +183 -0
  19. package/dist/chunk-2HVLQ26H.js.map +1 -0
  20. package/dist/{chunk-XYRDDSXF.js → chunk-2I6R3GCZ.js} +4285 -3980
  21. package/dist/chunk-2I6R3GCZ.js.map +1 -0
  22. package/dist/{chunk-JAQ5K7W6.js → chunk-2SFFYIH3.js} +1178 -166
  23. package/dist/chunk-2SFFYIH3.js.map +1 -0
  24. package/dist/chunk-3PVDYTTB.js +24 -0
  25. package/dist/chunk-3PVDYTTB.js.map +1 -0
  26. package/dist/chunk-3RJKUVCA.js +14068 -0
  27. package/dist/chunk-3RJKUVCA.js.map +1 -0
  28. package/dist/chunk-3UZCWK46.js +298 -0
  29. package/dist/chunk-3UZCWK46.js.map +1 -0
  30. package/dist/chunk-47CKUXTW.js +293 -0
  31. package/dist/chunk-47CKUXTW.js.map +1 -0
  32. package/dist/chunk-4QYP6QUI.js +109 -0
  33. package/dist/chunk-4QYP6QUI.js.map +1 -0
  34. package/dist/chunk-5EY26VZ7.js +1053 -0
  35. package/dist/chunk-5EY26VZ7.js.map +1 -0
  36. package/dist/chunk-5I4VRWBB.js +56 -0
  37. package/dist/chunk-5I4VRWBB.js.map +1 -0
  38. package/dist/chunk-5WOR7UCL.js +191 -0
  39. package/dist/chunk-5WOR7UCL.js.map +1 -0
  40. package/dist/chunk-5YJLGOM5.js +51 -0
  41. package/dist/chunk-5YJLGOM5.js.map +1 -0
  42. package/dist/chunk-6JFN3OWG.js +386 -0
  43. package/dist/chunk-6JFN3OWG.js.map +1 -0
  44. package/dist/chunk-7QJT5O4S.js +35 -0
  45. package/dist/chunk-7QJT5O4S.js.map +1 -0
  46. package/dist/chunk-A55KV72M.js +402 -0
  47. package/dist/chunk-A55KV72M.js.map +1 -0
  48. package/dist/chunk-ADWCLI4G.js +2028 -0
  49. package/dist/chunk-ADWCLI4G.js.map +1 -0
  50. package/dist/chunk-B27E3V37.js +29 -0
  51. package/dist/chunk-B27E3V37.js.map +1 -0
  52. package/dist/chunk-B7TC2A33.js +83 -0
  53. package/dist/chunk-B7TC2A33.js.map +1 -0
  54. package/dist/chunk-BLL56F7R.js +385 -0
  55. package/dist/chunk-BLL56F7R.js.map +1 -0
  56. package/dist/chunk-BOFEQC6K.js +162 -0
  57. package/dist/chunk-BOFEQC6K.js.map +1 -0
  58. package/dist/chunk-CM7LVUKC.js +35 -0
  59. package/dist/chunk-CM7LVUKC.js.map +1 -0
  60. package/dist/chunk-CORUP6JB.js +122 -0
  61. package/dist/chunk-CORUP6JB.js.map +1 -0
  62. package/dist/chunk-CSX5FFKZ.js +35 -0
  63. package/dist/chunk-CSX5FFKZ.js.map +1 -0
  64. package/dist/chunk-EGVHJKGJ.js +3125 -0
  65. package/dist/chunk-EGVHJKGJ.js.map +1 -0
  66. package/dist/{chunk-NEXLLTP4.js → chunk-G76LSA76.js} +6 -5
  67. package/dist/chunk-G76LSA76.js.map +1 -0
  68. package/dist/{chunk-PEI6RANI.js → chunk-GQMRL52F.js} +311 -75
  69. package/dist/chunk-GQMRL52F.js.map +1 -0
  70. package/dist/{chunk-ELIYWBZR.js → chunk-GUUXOISA.js} +1113 -457
  71. package/dist/chunk-GUUXOISA.js.map +1 -0
  72. package/dist/{chunk-HUIKIDM5.js → chunk-I7X2P4FU.js} +225 -116
  73. package/dist/chunk-I7X2P4FU.js.map +1 -0
  74. package/dist/chunk-IGFZFLI2.js +1390 -0
  75. package/dist/chunk-IGFZFLI2.js.map +1 -0
  76. package/dist/{chunk-4MDLEHXL.js → chunk-IMSUVYQB.js} +26 -13
  77. package/dist/chunk-IMSUVYQB.js.map +1 -0
  78. package/dist/chunk-IOYHDEP3.js +38 -0
  79. package/dist/chunk-IOYHDEP3.js.map +1 -0
  80. package/dist/chunk-IZV5FTJC.js +55 -0
  81. package/dist/chunk-IZV5FTJC.js.map +1 -0
  82. package/dist/chunk-KF33GTWN.js +343 -0
  83. package/dist/chunk-KF33GTWN.js.map +1 -0
  84. package/dist/chunk-KSGQ5ODA.js +457 -0
  85. package/dist/chunk-KSGQ5ODA.js.map +1 -0
  86. package/dist/{chunk-ZPBTI3TE.js → chunk-KZC6QRNR.js} +1513 -697
  87. package/dist/chunk-KZC6QRNR.js.map +1 -0
  88. package/dist/chunk-LJUMYUBO.js +218 -0
  89. package/dist/chunk-LJUMYUBO.js.map +1 -0
  90. package/dist/chunk-LSW2OJVV.js +380 -0
  91. package/dist/chunk-LSW2OJVV.js.map +1 -0
  92. package/dist/chunk-M357MHH3.js +2 -0
  93. package/dist/chunk-M357MHH3.js.map +1 -0
  94. package/dist/chunk-MK2TQO4Y.js +24 -0
  95. package/dist/chunk-MK2TQO4Y.js.map +1 -0
  96. package/dist/chunk-N7S72EXK.js +25 -0
  97. package/dist/chunk-N7S72EXK.js.map +1 -0
  98. package/dist/{chunk-YVCHAQZY.js → chunk-NKMYZFHA.js} +616 -621
  99. package/dist/chunk-NKMYZFHA.js.map +1 -0
  100. package/dist/chunk-NX4ADH73.js +14 -0
  101. package/dist/chunk-NX4ADH73.js.map +1 -0
  102. package/dist/chunk-O7F6UJO4.js +71 -0
  103. package/dist/chunk-O7F6UJO4.js.map +1 -0
  104. package/dist/chunk-OYQQJL3J.js +16 -0
  105. package/dist/chunk-OYQQJL3J.js.map +1 -0
  106. package/dist/{chunk-H5YGYNXS.js → chunk-P4BNUO57.js} +60 -17
  107. package/dist/chunk-P4BNUO57.js.map +1 -0
  108. package/dist/{chunk-JVYQRRC4.js → chunk-PEHTX3V7.js} +21 -1
  109. package/dist/chunk-PEHTX3V7.js.map +1 -0
  110. package/dist/chunk-PMV53IMM.js +26 -0
  111. package/dist/chunk-PMV53IMM.js.map +1 -0
  112. package/dist/{chunk-KCGXPP5V.js → chunk-PYEOPA4M.js} +13 -7
  113. package/dist/chunk-PYEOPA4M.js.map +1 -0
  114. package/dist/{chunk-KZ73RL76.js → chunk-QHUE7E4N.js} +8 -3
  115. package/dist/chunk-QHUE7E4N.js.map +1 -0
  116. package/dist/chunk-QV3DJVRZ.js +11 -0
  117. package/dist/chunk-QV3DJVRZ.js.map +1 -0
  118. package/dist/chunk-R5SBNG7S.js +810 -0
  119. package/dist/chunk-R5SBNG7S.js.map +1 -0
  120. package/dist/chunk-RI42H5IU.js +326 -0
  121. package/dist/chunk-RI42H5IU.js.map +1 -0
  122. package/dist/chunk-S2QH6EZ5.js +211 -0
  123. package/dist/chunk-S2QH6EZ5.js.map +1 -0
  124. package/dist/chunk-SHLZMAJN.js +304 -0
  125. package/dist/chunk-SHLZMAJN.js.map +1 -0
  126. package/dist/chunk-TGXK4BAZ.js +293 -0
  127. package/dist/chunk-TGXK4BAZ.js.map +1 -0
  128. package/dist/{chunk-5YK2ZDIG.js → chunk-TNEZNMSN.js} +4 -10
  129. package/dist/chunk-TNEZNMSN.js.map +1 -0
  130. package/dist/{chunk-22KP6LR5.js → chunk-TXS65BB2.js} +3 -1
  131. package/dist/{chunk-22KP6LR5.js.map → chunk-TXS65BB2.js.map} +1 -1
  132. package/dist/chunk-UNJPZGNK.js +63 -0
  133. package/dist/chunk-UNJPZGNK.js.map +1 -0
  134. package/dist/{chunk-IOLVN74D.js → chunk-V5ZUJT2T.js} +175 -42
  135. package/dist/chunk-V5ZUJT2T.js.map +1 -0
  136. package/dist/chunk-WBJY57A3.js +402 -0
  137. package/dist/chunk-WBJY57A3.js.map +1 -0
  138. package/dist/chunk-WIUKB3LD.js +1911 -0
  139. package/dist/chunk-WIUKB3LD.js.map +1 -0
  140. package/dist/{chunk-ICA6R6TW.js → chunk-WNN7NO2N.js} +1451 -355
  141. package/dist/chunk-WNN7NO2N.js.map +1 -0
  142. package/dist/{chunk-3AGBGTRT.js → chunk-X5UVUIMF.js} +1712 -1174
  143. package/dist/chunk-X5UVUIMF.js.map +1 -0
  144. package/dist/chunk-XDA5QJE7.js +402 -0
  145. package/dist/chunk-XDA5QJE7.js.map +1 -0
  146. package/dist/{chunk-VZTQ73XT.js → chunk-XEA5BCMA.js} +3 -1
  147. package/dist/{chunk-VZTQ73XT.js.map → chunk-XEA5BCMA.js.map} +1 -1
  148. package/dist/chunk-XHF7OYAN.js +1150 -0
  149. package/dist/chunk-XHF7OYAN.js.map +1 -0
  150. package/dist/chunk-YSRBFJMQ.js +43 -0
  151. package/dist/chunk-YSRBFJMQ.js.map +1 -0
  152. package/dist/chunk-ZOZAPAUO.js +174 -0
  153. package/dist/chunk-ZOZAPAUO.js.map +1 -0
  154. package/dist/chunk-ZQV5W7YC.js +809 -0
  155. package/dist/chunk-ZQV5W7YC.js.map +1 -0
  156. package/dist/chunk-ZUWF4NF7.js +13 -0
  157. package/dist/chunk-ZUWF4NF7.js.map +1 -0
  158. package/dist/client.d.ts +16 -7
  159. package/dist/clipboard.js +3 -1
  160. package/dist/commands/types.d.ts +2 -0
  161. package/dist/components/anthropic-mark.d.ts +3 -0
  162. package/dist/components/approval-surface.d.ts +19 -6
  163. package/dist/components/artifacts/artifact-chrome.d.ts +120 -0
  164. package/dist/components/artifacts/artifact-sandbox.d.ts +30 -0
  165. package/dist/components/artifacts/artifact-surface.d.ts +4 -2
  166. package/dist/components/artifacts/chat-interactive-block.d.ts +29 -0
  167. package/dist/components/artifacts/deferred-chat-media.d.ts +15 -0
  168. package/dist/components/artifacts/document-editor.d.ts +4 -2
  169. package/dist/components/artifacts/editable-artifact-ui.d.ts +2 -1
  170. package/dist/components/artifacts/editable-artifact-view.d.ts +48 -0
  171. package/dist/components/artifacts/editable-document.d.ts +1 -1
  172. package/dist/components/artifacts/editable-presentation.d.ts +2 -2
  173. package/dist/components/artifacts/editable-spreadsheet.d.ts +8 -3
  174. package/dist/components/artifacts/index.d.ts +9 -2
  175. package/dist/components/artifacts/inline-html-document.d.ts +2 -0
  176. package/dist/components/artifacts/latest-task-runner.d.ts +15 -0
  177. package/dist/components/artifacts/presentation-editor.d.ts +6 -2
  178. package/dist/components/artifacts/published-html-artifact-frame.d.ts +23 -3
  179. package/dist/components/artifacts/session-artifact-viewer.d.ts +39 -0
  180. package/dist/components/artifacts/site-view.d.ts +26 -0
  181. package/dist/components/artifacts/spreadsheet-command-queue.d.ts +20 -0
  182. package/dist/components/artifacts/spreadsheet-download.d.ts +7 -0
  183. package/dist/components/artifacts/spreadsheet-general-display.d.ts +24 -0
  184. package/dist/components/artifacts/spreadsheet-grid.d.ts +10 -3
  185. package/dist/components/artifacts/spreadsheet-resize.d.ts +50 -0
  186. package/dist/components/artifacts/spreadsheet-submissions.d.ts +9 -0
  187. package/dist/components/artifacts/visualization-assets.gen.d.ts +2 -0
  188. package/dist/components/browser-select-control.d.ts +16 -0
  189. package/dist/components/browser-viewer.d.ts +11 -2
  190. package/dist/components/chat-composer.d.ts +21 -3
  191. package/dist/components/child-session-link.d.ts +9 -0
  192. package/dist/components/claude-mark.d.ts +3 -0
  193. package/dist/components/code-editor.d.ts +1 -4
  194. package/dist/components/composer-transcription-control.d.ts +7 -0
  195. package/dist/components/composer.d.ts +34 -67
  196. package/dist/components/computer-viewer.d.ts +1 -1
  197. package/dist/components/copy-button.d.ts +3 -1
  198. package/dist/components/desktop-viewer.d.ts +1 -1
  199. package/dist/components/grok-mark.d.ts +26 -0
  200. package/dist/components/human-input-form.d.ts +28 -32
  201. package/dist/components/human-input-surface.d.ts +7 -2
  202. package/dist/components/linkified-text.d.ts +18 -0
  203. package/dist/components/machine-input-display.d.ts +22 -1
  204. package/dist/components/machines/agent-status-icon.d.ts +6 -0
  205. package/dist/components/machines/machine-detail.d.ts +7 -1
  206. package/dist/components/machines/machine-status.d.ts +48 -0
  207. package/dist/components/markdown-table-layout.d.ts +18 -0
  208. package/dist/components/markdown.d.ts +37 -4
  209. package/dist/components/message-timeline.d.ts +86 -7
  210. package/dist/components/model-mark.d.ts +29 -0
  211. package/dist/components/model-policy-picker-menu.d.ts +9 -0
  212. package/dist/components/model-policy-picker.d.ts +35 -28
  213. package/dist/components/new-conversation.d.ts +32 -0
  214. package/dist/components/open-geni-chat.d.ts +73 -0
  215. package/dist/components/open-geni-links.d.ts +68 -0
  216. package/dist/components/openrouter-mark.d.ts +6 -0
  217. package/dist/components/opper-mark.d.ts +7 -0
  218. package/dist/components/preview-loading.d.ts +2 -0
  219. package/dist/components/provider-recovery-notice.d.ts +16 -0
  220. package/dist/components/queue-item-content.d.ts +9 -0
  221. package/dist/components/rehype-secret-refs.d.ts +23 -0
  222. package/dist/components/remark-soft-line-breaks.d.ts +38 -0
  223. package/dist/components/sandbox-files.d.ts +3 -1
  224. package/dist/components/sandbox-workspace.d.ts +18 -0
  225. package/dist/components/secret-question-field.d.ts +31 -0
  226. package/dist/components/secret-ref-chip.d.ts +35 -0
  227. package/dist/components/session-capability-frame.d.ts +37 -0
  228. package/dist/components/session-chrome.d.ts +57 -8
  229. package/dist/components/session-commands-panel.d.ts +6 -0
  230. package/dist/components/session-commands.d.ts +6 -0
  231. package/dist/components/session-connection-request.d.ts +8 -0
  232. package/dist/components/session-conversation.d.ts +157 -0
  233. package/dist/components/session-list.d.ts +39 -0
  234. package/dist/components/session-mcp-capability-card.d.ts +41 -0
  235. package/dist/components/session-proxy-scope.d.ts +35 -0
  236. package/dist/components/session-status.d.ts +4 -1
  237. package/dist/components/session-usage-limit-notice.d.ts +39 -0
  238. package/dist/components/timeline-anchor.d.ts +24 -0
  239. package/dist/components/timeline-annotation-chrome.d.ts +25 -0
  240. package/dist/components/timeline-annotation-layout.d.ts +42 -0
  241. package/dist/components/timeline-annotation-markers.d.ts +8 -0
  242. package/dist/components/timeline-annotation-reveal-context.d.ts +4 -0
  243. package/dist/components/timeline-annotation-shared.d.ts +31 -0
  244. package/dist/components/timeline-annotations-dialog.d.ts +3 -2
  245. package/dist/components/timeline-annotations.d.ts +13 -3
  246. package/dist/components/timeline-reading-progress.d.ts +11 -0
  247. package/dist/components/timeline-search.d.ts +34 -0
  248. package/dist/components/timeline-settlement.d.ts +16 -0
  249. package/dist/components/tool-action-review.d.ts +47 -0
  250. package/dist/components/tool-review-history.d.ts +25 -0
  251. package/dist/components/usage-limit-notice.d.ts +49 -0
  252. package/dist/components/usage-member-list.d.ts +91 -0
  253. package/dist/components/usage-meter.d.ts +73 -0
  254. package/dist/components/use-viewer-menu-dismiss.d.ts +2 -0
  255. package/dist/components/user-message-body.d.ts +10 -1
  256. package/dist/composer-messages.d.ts +74 -0
  257. package/dist/composer-messages.js +9 -0
  258. package/dist/composer-messages.js.map +1 -0
  259. package/dist/composer-voice-events.d.ts +8 -0
  260. package/dist/composer.d.ts +5 -4
  261. package/dist/composer.js +26 -13
  262. package/dist/computer-viewer-GMLDXPON.js +20 -0
  263. package/dist/computer-viewer-GMLDXPON.js.map +1 -0
  264. package/dist/connect-account-identity.d.ts +8 -0
  265. package/dist/connect-accounts.d.ts +15 -0
  266. package/dist/connect-chooser.d.ts +18 -0
  267. package/dist/connect-panel.d.ts +18 -0
  268. package/dist/connect-setup.d.ts +18 -0
  269. package/dist/connect.d.ts +21 -0
  270. package/dist/connect.js +2149 -0
  271. package/dist/connect.js.map +1 -0
  272. package/dist/connection-catalog.d.ts +38 -0
  273. package/dist/connection-discovery.d.ts +12 -0
  274. package/dist/connection-installed.d.ts +17 -0
  275. package/dist/connection-logo.d.ts +9 -0
  276. package/dist/connection-service-logo.d.ts +8 -0
  277. package/dist/connection-service-presentation.d.ts +13 -0
  278. package/dist/connection-skeleton.d.ts +5 -0
  279. package/dist/connection-type-picker.d.ts +6 -0
  280. package/dist/conversation-timeline.d.ts +5 -0
  281. package/dist/desktop.d.ts +7 -0
  282. package/dist/desktop.js +27 -0
  283. package/dist/desktop.js.map +1 -0
  284. package/dist/device-authorization.d.ts +23 -0
  285. package/dist/diffs.d.ts +8 -0
  286. package/dist/diffs.js +15 -0
  287. package/dist/diffs.js.map +1 -0
  288. package/dist/discovery-cache.d.ts +5 -0
  289. package/dist/editor.d.ts +7 -0
  290. package/dist/editor.js +22 -0
  291. package/dist/editor.js.map +1 -0
  292. package/dist/embedded-new-voice-OCRNT6U5.js +18 -0
  293. package/dist/embedded-new-voice-OCRNT6U5.js.map +1 -0
  294. package/dist/embedded-voice-RPHPYVBT.js +18 -0
  295. package/dist/embedded-voice-RPHPYVBT.js.map +1 -0
  296. package/dist/{fleet-decision-row-GGCAT4E4.js → fleet-decision-row-SI63O5V4.js} +4 -1
  297. package/dist/fleet-decision-row-SI63O5V4.js.map +1 -0
  298. package/dist/hooks/latest-question.d.ts +25 -0
  299. package/dist/hooks/shared-machines-list.d.ts +4 -0
  300. package/dist/hooks/shared-query.d.ts +113 -0
  301. package/dist/hooks/use-attached-browsers.d.ts +1 -1
  302. package/dist/hooks/use-auth-runs.d.ts +1 -4
  303. package/dist/hooks/use-available-models.d.ts +1 -1
  304. package/dist/hooks/use-browser-frame-stream.d.ts +1 -1
  305. package/dist/hooks/use-browser-session.d.ts +12 -1
  306. package/dist/hooks/use-client-config-flags.d.ts +49 -0
  307. package/dist/hooks/use-codex-accounts.d.ts +59 -10
  308. package/dist/hooks/use-composer.d.ts +24 -2
  309. package/dist/hooks/use-computer-frame-stream.d.ts +1 -1
  310. package/dist/hooks/use-computer-input-posture.d.ts +13 -0
  311. package/dist/hooks/use-computer-session.d.ts +4 -0
  312. package/dist/hooks/use-connect.d.ts +23 -0
  313. package/dist/hooks/use-desktop-stream.d.ts +1 -1
  314. package/dist/hooks/use-file-attachments.d.ts +12 -0
  315. package/dist/hooks/use-goal.d.ts +2 -1
  316. package/dist/hooks/use-last-started-turn-policy.d.ts +5 -1
  317. package/dist/hooks/use-new-conversation.d.ts +56 -0
  318. package/dist/hooks/use-new-session-draft.d.ts +74 -0
  319. package/dist/hooks/use-realtime-voice-models.d.ts +7 -0
  320. package/dist/hooks/use-sandbox-files.d.ts +4 -1
  321. package/dist/hooks/use-session-conversation.d.ts +49 -0
  322. package/dist/hooks/use-session-events.d.ts +26 -5
  323. package/dist/hooks/use-session-mcp-approval-policy.d.ts +2 -2
  324. package/dist/hooks/use-session-model-account.d.ts +48 -0
  325. package/dist/hooks/use-supergrok-accounts.d.ts +7 -1
  326. package/dist/hooks/use-terminal-stream.d.ts +11 -5
  327. package/dist/hooks/use-usage.d.ts +40 -0
  328. package/dist/hooks/use-vaults.d.ts +53 -0
  329. package/dist/hooks/use-voice-input.d.ts +8 -1
  330. package/dist/hooks/use-workspace-edit.d.ts +4 -0
  331. package/dist/hooks/use-workspace-sessions.d.ts +24 -5
  332. package/dist/human-input-model.d.ts +122 -0
  333. package/dist/identity-link-accounts.d.ts +11 -0
  334. package/dist/identity-link-consent.d.ts +18 -0
  335. package/dist/index.d.ts +82 -20
  336. package/dist/index.js +2340 -6603
  337. package/dist/index.js.map +1 -1
  338. package/dist/interaction.d.ts +1 -1
  339. package/dist/interaction.js +14 -24
  340. package/dist/interaction.js.map +1 -1
  341. package/dist/latest-question-R77KWSUP.js +118 -0
  342. package/dist/latest-question-R77KWSUP.js.map +1 -0
  343. package/dist/lib/clipboard.d.ts +7 -0
  344. package/dist/lib/error-message.d.ts +7 -0
  345. package/dist/lib/format.d.ts +58 -4
  346. package/dist/lib/host-theme.d.ts +77 -0
  347. package/dist/lib/interaction-errors.d.ts +3 -0
  348. package/dist/lib/menu-styles.d.ts +22 -0
  349. package/dist/lib/notify-observer.d.ts +2 -0
  350. package/dist/lib/pierre-diffs-loader.d.ts +20 -0
  351. package/dist/lib/provider-recovery.d.ts +55 -0
  352. package/dist/lib/scrollbars.d.ts +11 -0
  353. package/dist/lib/terminal-input-readiness.d.ts +11 -0
  354. package/dist/lib/transient-retry.d.ts +25 -0
  355. package/dist/lib/workbench-peers.d.ts +36 -0
  356. package/dist/lib/xterm-theme.d.ts +7 -5
  357. package/dist/machines.js +9 -5
  358. package/dist/markdown-table-layout-3PV2UAAH.js +113 -0
  359. package/dist/markdown-table-layout-3PV2UAAH.js.map +1 -0
  360. package/dist/mcp-connection-status.d.ts +14 -0
  361. package/dist/model-mark-paths.d.ts +34 -0
  362. package/dist/model-mark-paths.js +16 -0
  363. package/dist/model-mark-paths.js.map +1 -0
  364. package/dist/model-picker-model.d.ts +111 -0
  365. package/dist/model-picker-model.js +25 -0
  366. package/dist/model-picker-model.js.map +1 -0
  367. package/dist/model-policy-picker-menu-7GJ5URPR.js +17 -0
  368. package/dist/model-policy-picker-menu-7GJ5URPR.js.map +1 -0
  369. package/dist/model-policy.d.ts +30 -3
  370. package/dist/model-policy.js +14 -1
  371. package/dist/native-previews.d.ts +28 -0
  372. package/dist/native-previews.js +82 -0
  373. package/dist/native-previews.js.map +1 -0
  374. package/dist/new-session-draft.d.ts +7 -0
  375. package/dist/new-session-draft.js +639 -0
  376. package/dist/new-session-draft.js.map +1 -0
  377. package/dist/notification-text.d.ts +27 -0
  378. package/dist/{noto-sans-arabic-loader-IA2T4X2A.js → noto-sans-arabic-loader-XSH2KYWJ.js} +3 -1
  379. package/dist/{noto-sans-arabic-loader-IA2T4X2A.js.map → noto-sans-arabic-loader-XSH2KYWJ.js.map} +1 -1
  380. package/dist/{noto-sans-jp-loader.generated-HFGLYBR3.js → noto-sans-jp-loader.generated-MR5L6V7K.js} +3 -1
  381. package/dist/{noto-sans-jp-loader.generated-HFGLYBR3.js.map → noto-sans-jp-loader.generated-MR5L6V7K.js.map} +1 -1
  382. package/dist/older-history.d.ts +3 -2
  383. package/dist/organization-model.d.ts +32 -0
  384. package/dist/organization-model.js +65 -0
  385. package/dist/organization-model.js.map +1 -0
  386. package/dist/{platform-activity-row-BJHUHXAT.js → platform-activity-row-5OCKOQWZ.js} +16 -78
  387. package/dist/platform-activity-row-5OCKOQWZ.js.map +1 -0
  388. package/dist/plugin-details.d.ts +14 -0
  389. package/dist/plugin-discovery.d.ts +25 -0
  390. package/dist/preview-loading-paint.d.ts +20 -0
  391. package/dist/provider.d.ts +25 -2
  392. package/dist/queue-presentation-model.d.ts +72 -0
  393. package/dist/queue-presentation-model.js +38 -0
  394. package/dist/queue-presentation-model.js.map +1 -0
  395. package/dist/{queue-surface-implementation-BSKUWHRI.js → queue-surface-implementation-GJBH7NKO.js} +65 -265
  396. package/dist/queue-surface-implementation-GJBH7NKO.js.map +1 -0
  397. package/dist/realtime/embedded-new-voice.d.ts +1 -0
  398. package/dist/realtime/embedded-voice.d.ts +1 -0
  399. package/dist/realtime/realtime-control.d.ts +4 -65
  400. package/dist/realtime/session-realtime.d.ts +78 -0
  401. package/dist/realtime.js +25 -1333
  402. package/dist/realtime.js.map +1 -1
  403. package/dist/sandbox-files-O27IPOZW.js +21 -0
  404. package/dist/sandbox-files-O27IPOZW.js.map +1 -0
  405. package/dist/sandbox-label-model.d.ts +30 -0
  406. package/dist/sandbox-label-model.js +20 -0
  407. package/dist/sandbox-label-model.js.map +1 -0
  408. package/dist/scrollbars.d.ts +1 -0
  409. package/dist/scrollbars.js +10 -0
  410. package/dist/scrollbars.js.map +1 -0
  411. package/dist/secret-reference-label.d.ts +14 -0
  412. package/dist/secrets-ui.d.ts +57 -0
  413. package/dist/session-agents-model.d.ts +10 -0
  414. package/dist/session-agents-model.js +25 -0
  415. package/dist/session-agents-model.js.map +1 -0
  416. package/dist/session-attention-model.d.ts +8 -0
  417. package/dist/session-attention-model.js +47 -0
  418. package/dist/session-attention-model.js.map +1 -0
  419. package/dist/session-auth-recommendation.d.ts +5 -0
  420. package/dist/session-capability-policy.d.ts +31 -0
  421. package/dist/session-feedback-model.d.ts +20 -0
  422. package/dist/session-feedback-model.js +56 -0
  423. package/dist/session-feedback-model.js.map +1 -0
  424. package/dist/session-list-model.d.ts +138 -0
  425. package/dist/session-list-model.js +274 -0
  426. package/dist/session-list-model.js.map +1 -0
  427. package/dist/session-realtime-7DJOIHQW.js +21 -0
  428. package/dist/session-realtime-7DJOIHQW.js.map +1 -0
  429. package/dist/session-realtime.d.ts +7 -0
  430. package/dist/session-realtime.js +19 -0
  431. package/dist/session-realtime.js.map +1 -0
  432. package/dist/session-status-model.d.ts +36 -0
  433. package/dist/session-ui.d.ts +39 -1
  434. package/dist/session-ui.js +126 -12
  435. package/dist/session-ui.js.map +1 -1
  436. package/dist/session.d.ts +8 -2
  437. package/dist/session.js +35 -20
  438. package/dist/site-snapshot.d.ts +14 -0
  439. package/dist/sites-ui.d.ts +24 -0
  440. package/dist/sites.d.ts +3 -0
  441. package/dist/sites.js +14 -0
  442. package/dist/sites.js.map +1 -0
  443. package/dist/skill-discovery.d.ts +47 -0
  444. package/dist/terminal.d.ts +8 -0
  445. package/dist/terminal.js +32 -0
  446. package/dist/terminal.js.map +1 -0
  447. package/dist/testing/session-scenarios.d.ts +10 -0
  448. package/dist/testing/session-scenarios.js +367 -0
  449. package/dist/testing/session-scenarios.js.map +1 -0
  450. package/dist/timeline/activity-rail.d.ts +11 -2
  451. package/dist/timeline/agent-identity.d.ts +30 -0
  452. package/dist/timeline/agent-row.d.ts +31 -0
  453. package/dist/timeline/allowance-exhausted-row.d.ts +24 -0
  454. package/dist/timeline/compaction-copy.d.ts +46 -0
  455. package/dist/timeline/focus-sequence.d.ts +9 -0
  456. package/dist/timeline/genie-copy.d.ts +3 -0
  457. package/dist/timeline/genie-loading.d.ts +47 -0
  458. package/dist/timeline/index.d.ts +10 -5
  459. package/dist/timeline/knowledge-receipt.d.ts +17 -0
  460. package/dist/timeline/message-sender.d.ts +19 -0
  461. package/dist/timeline/notice-presentation.d.ts +13 -0
  462. package/dist/timeline/parsers.d.ts +11 -0
  463. package/dist/timeline/patch-apply-command.d.ts +18 -0
  464. package/dist/timeline/platform-activity-presentation.d.ts +21 -0
  465. package/dist/timeline/platform-activity-row.d.ts +1 -2
  466. package/dist/timeline/presented-image.d.ts +11 -0
  467. package/dist/timeline/projection.d.ts +31 -2
  468. package/dist/timeline/provider-logo.d.ts +15 -0
  469. package/dist/timeline/question-nav-model.d.ts +23 -0
  470. package/dist/timeline/registry.d.ts +12 -1
  471. package/dist/timeline/retained-image.d.ts +18 -0
  472. package/dist/timeline/retained-loaders.d.ts +27 -0
  473. package/dist/timeline/rolling-activity.d.ts +11 -0
  474. package/dist/timeline/screenshot-lightbox.d.ts +23 -1
  475. package/dist/timeline/session-usage-limit-row.d.ts +11 -0
  476. package/dist/timeline/shared.d.ts +4 -1
  477. package/dist/timeline/startup-dispatch-details.d.ts +5 -0
  478. package/dist/timeline/startup-preference.d.ts +3 -0
  479. package/dist/timeline/startup-timings.d.ts +4 -0
  480. package/dist/timeline/tool-display-name.d.ts +5 -2
  481. package/dist/timeline/tool-presentation.d.ts +172 -0
  482. package/dist/timeline/turn-summary-model.d.ts +95 -0
  483. package/dist/timeline/turn-summary.d.ts +20 -54
  484. package/dist/timeline/types.d.ts +179 -7
  485. package/dist/timeline/work-presentation.d.ts +60 -0
  486. package/dist/timeline-annotation-markers-U3G66KUD.js +166 -0
  487. package/dist/timeline-annotation-markers-U3G66KUD.js.map +1 -0
  488. package/dist/timeline-annotation-selection-BI7QTPTZ.js +242 -0
  489. package/dist/timeline-annotation-selection-BI7QTPTZ.js.map +1 -0
  490. package/dist/timeline-annotations-dialog-FOMHSDTE.js +274 -0
  491. package/dist/timeline-annotations-dialog-FOMHSDTE.js.map +1 -0
  492. package/dist/timeline-model.d.ts +29 -0
  493. package/dist/timeline-model.js +254 -0
  494. package/dist/timeline-model.js.map +1 -0
  495. package/dist/usage/allowance-copy.d.ts +25 -0
  496. package/dist/usage/session-usage-limit.d.ts +88 -0
  497. package/dist/usage/summary.d.ts +35 -0
  498. package/dist/usage.d.ts +17 -0
  499. package/dist/usage.js +1187 -0
  500. package/dist/usage.js.map +1 -0
  501. package/dist/voice-recording-owner.d.ts +7 -0
  502. package/package.json +106 -7
  503. package/src/approvals.ts +8 -1
  504. package/src/artifacts-spreadsheet.ts +1 -0
  505. package/src/artifacts.ts +44 -0
  506. package/src/assets/README.md +8 -0
  507. package/src/assets/gmail.ico +0 -0
  508. package/src/assets/outlook.ico +0 -0
  509. package/src/capability-catalog-row.tsx +94 -0
  510. package/src/capability-logo-fallback.ts +22 -0
  511. package/src/client.ts +20 -31
  512. package/src/commands/registry.ts +18 -15
  513. package/src/commands/types.ts +2 -0
  514. package/src/components/anthropic-mark.tsx +10 -0
  515. package/src/components/approval-surface.tsx +401 -138
  516. package/src/components/artifacts/artifact-chrome.tsx +413 -0
  517. package/src/components/artifacts/artifact-sandbox.tsx +193 -0
  518. package/src/components/artifacts/artifact-surface.tsx +40 -20
  519. package/src/components/artifacts/chat-interactive-block.tsx +260 -0
  520. package/src/components/artifacts/deferred-chat-media.tsx +67 -0
  521. package/src/components/artifacts/document-editor.tsx +141 -16
  522. package/src/components/artifacts/editable-artifact-ui.tsx +4 -2
  523. package/src/components/artifacts/editable-artifact-view.tsx +197 -0
  524. package/src/components/artifacts/editable-artifact-workbench.tsx +5 -2
  525. package/src/components/artifacts/editable-document.tsx +37 -36
  526. package/src/components/artifacts/editable-presentation.tsx +36 -18
  527. package/src/components/artifacts/editable-spreadsheet.tsx +543 -103
  528. package/src/components/artifacts/index.ts +45 -0
  529. package/src/components/artifacts/inline-html-document.ts +24 -0
  530. package/src/components/artifacts/latest-task-runner.ts +49 -0
  531. package/src/components/artifacts/presentation-editor.tsx +323 -67
  532. package/src/components/artifacts/published-html-artifact-frame.tsx +122 -5
  533. package/src/components/artifacts/session-artifact-viewer.tsx +378 -0
  534. package/src/components/artifacts/site-view.tsx +121 -0
  535. package/src/components/artifacts/spreadsheet-canvas.ts +5 -10
  536. package/src/components/artifacts/spreadsheet-command-queue.ts +184 -0
  537. package/src/components/artifacts/spreadsheet-download.tsx +109 -0
  538. package/src/components/artifacts/spreadsheet-general-display.ts +43 -0
  539. package/src/components/artifacts/spreadsheet-grid.tsx +344 -144
  540. package/src/components/artifacts/spreadsheet-resize.tsx +421 -0
  541. package/src/components/artifacts/spreadsheet-submissions.tsx +46 -0
  542. package/src/components/artifacts/visualization-assets/base.css +1015 -0
  543. package/src/components/artifacts/visualization-assets/helpers.html +349 -0
  544. package/src/components/artifacts/visualization-assets.gen.ts +3 -0
  545. package/src/components/browser-select-control.tsx +312 -0
  546. package/src/components/browser-viewer.tsx +778 -318
  547. package/src/components/chat-composer.tsx +47 -5
  548. package/src/components/child-session-link.tsx +36 -0
  549. package/src/components/claude-mark.tsx +11 -0
  550. package/src/components/code-editor.tsx +13 -16
  551. package/src/components/composer-transcription-control.tsx +128 -30
  552. package/src/components/composer.tsx +404 -195
  553. package/src/components/computer-viewer.tsx +880 -253
  554. package/src/components/copy-button.tsx +13 -5
  555. package/src/components/desktop-viewer.tsx +1 -1
  556. package/src/components/enrollment-consent.tsx +1 -1
  557. package/src/components/enrollment-device-flow.tsx +1 -1
  558. package/src/components/file-browser.tsx +10 -14
  559. package/src/components/fleet-tile.tsx +5 -3
  560. package/src/components/generated-video-player.tsx +4 -2
  561. package/src/components/grok-mark.tsx +34 -0
  562. package/src/components/human-input-form.tsx +590 -283
  563. package/src/components/human-input-surface.tsx +11 -0
  564. package/src/components/interaction-intervention-banner.tsx +2 -2
  565. package/src/components/linkified-text.tsx +79 -0
  566. package/src/components/machine-card.tsx +35 -78
  567. package/src/components/machine-dock-bar.tsx +1 -1
  568. package/src/components/machine-input-display.ts +197 -3
  569. package/src/components/machines/agent-status-icon.tsx +31 -0
  570. package/src/components/machines/machine-detail.tsx +200 -31
  571. package/src/components/machines/machine-operation-policy.tsx +1 -1
  572. package/src/components/machines/machine-status.ts +241 -0
  573. package/src/components/machines-dashboard.tsx +2 -17
  574. package/src/components/markdown-table-layout.ts +143 -0
  575. package/src/components/markdown.tsx +466 -129
  576. package/src/components/message-timeline.tsx +2370 -667
  577. package/src/components/model-mark.tsx +102 -0
  578. package/src/components/model-picker.tsx +15 -4
  579. package/src/components/model-policy-picker-menu.tsx +371 -0
  580. package/src/components/model-policy-picker.tsx +252 -429
  581. package/src/components/new-conversation.tsx +221 -0
  582. package/src/components/open-geni-chat.tsx +309 -0
  583. package/src/components/open-geni-links.tsx +179 -0
  584. package/src/components/openrouter-mark.tsx +13 -0
  585. package/src/components/opper-mark.tsx +18 -0
  586. package/src/components/pierre-diff.tsx +41 -16
  587. package/src/components/pierre-file.tsx +35 -10
  588. package/src/components/preview-loading.tsx +109 -0
  589. package/src/components/provider-recovery-notice.tsx +49 -0
  590. package/src/components/queue-item-content.ts +14 -0
  591. package/src/components/queue-surface-implementation.tsx +51 -356
  592. package/src/components/queue-surface-state.tsx +3 -1
  593. package/src/components/rehype-secret-refs.ts +98 -0
  594. package/src/components/remark-soft-line-breaks.ts +166 -0
  595. package/src/components/sandbox-files.tsx +91 -15
  596. package/src/components/sandbox-terminal.tsx +84 -13
  597. package/src/components/sandbox-workspace.tsx +147 -51
  598. package/src/components/secret-question-field.tsx +324 -0
  599. package/src/components/secret-ref-chip.tsx +185 -0
  600. package/src/components/session-capability-frame.tsx +197 -0
  601. package/src/components/session-chrome.tsx +842 -251
  602. package/src/components/session-commands-panel.tsx +126 -0
  603. package/src/components/session-commands.tsx +18 -0
  604. package/src/components/session-connection-request.tsx +97 -0
  605. package/src/components/session-conversation.tsx +876 -0
  606. package/src/components/session-list.tsx +257 -0
  607. package/src/components/session-mcp-capability-card.tsx +680 -0
  608. package/src/components/session-proxy-scope.tsx +153 -0
  609. package/src/components/session-status.tsx +26 -17
  610. package/src/components/session-usage-limit-notice.tsx +174 -0
  611. package/src/components/timeline-anchor.tsx +119 -0
  612. package/src/components/timeline-annotation-chrome.tsx +196 -0
  613. package/src/components/timeline-annotation-layout.ts +268 -0
  614. package/src/components/timeline-annotation-markers.tsx +185 -0
  615. package/src/components/timeline-annotation-reveal-context.ts +9 -0
  616. package/src/components/timeline-annotation-selection.tsx +106 -54
  617. package/src/components/timeline-annotation-shared.ts +245 -0
  618. package/src/components/timeline-annotations-dialog.tsx +185 -128
  619. package/src/components/timeline-annotations.tsx +189 -45
  620. package/src/components/timeline-reading-progress.ts +80 -0
  621. package/src/components/timeline-search.tsx +168 -0
  622. package/src/components/timeline-settlement.ts +60 -0
  623. package/src/components/tool-action-review.tsx +650 -0
  624. package/src/components/tool-review-history.tsx +88 -0
  625. package/src/components/usage-limit-notice.tsx +179 -0
  626. package/src/components/usage-member-list.tsx +792 -0
  627. package/src/components/usage-meter.tsx +382 -0
  628. package/src/components/use-viewer-menu-dismiss.ts +33 -0
  629. package/src/components/user-message-body.tsx +27 -2
  630. package/src/components/workspace-dock.tsx +18 -1
  631. package/src/composer-messages.ts +150 -0
  632. package/src/composer-voice-events.ts +12 -0
  633. package/src/composer.ts +6 -1
  634. package/src/connect-account-identity.tsx +34 -0
  635. package/src/connect-accounts.tsx +233 -0
  636. package/src/connect-chooser.tsx +336 -0
  637. package/src/connect-panel.tsx +99 -0
  638. package/src/connect-setup.tsx +355 -0
  639. package/src/connect.ts +60 -0
  640. package/src/connection-assets.d.ts +4 -0
  641. package/src/connection-catalog.tsx +162 -0
  642. package/src/connection-discovery.tsx +238 -0
  643. package/src/connection-installed.tsx +51 -0
  644. package/src/connection-logo.tsx +37 -0
  645. package/src/connection-service-logo.tsx +55 -0
  646. package/src/connection-service-presentation.ts +46 -0
  647. package/src/connection-skeleton.tsx +16 -0
  648. package/src/connection-type-picker.tsx +36 -0
  649. package/src/conversation-timeline.ts +92 -0
  650. package/src/desktop.ts +24 -0
  651. package/src/device-authorization.tsx +98 -0
  652. package/src/diffs.ts +16 -0
  653. package/src/discovery-cache.ts +42 -0
  654. package/src/editor.ts +13 -0
  655. package/src/hooks/internal.ts +3 -2
  656. package/src/hooks/latest-question.ts +164 -0
  657. package/src/hooks/shared-machines-list.ts +34 -1
  658. package/src/hooks/shared-query.ts +721 -0
  659. package/src/hooks/use-attached-browsers.ts +1 -1
  660. package/src/hooks/use-auth-runs.ts +0 -27
  661. package/src/hooks/use-available-models.ts +2 -2
  662. package/src/hooks/use-browser-frame-stream.ts +19 -2
  663. package/src/hooks/use-browser-session.ts +680 -205
  664. package/src/hooks/use-browser-sessions.ts +32 -1
  665. package/src/hooks/use-client-config-flags.ts +118 -0
  666. package/src/hooks/use-codex-accounts.ts +247 -47
  667. package/src/hooks/use-composer.ts +227 -44
  668. package/src/hooks/use-computer-frame-stream.ts +25 -7
  669. package/src/hooks/use-computer-input-posture.ts +94 -0
  670. package/src/hooks/use-computer-session.ts +409 -95
  671. package/src/hooks/use-connect.ts +23 -0
  672. package/src/hooks/use-desktop-stream.ts +19 -28
  673. package/src/hooks/use-file-attachments.ts +80 -4
  674. package/src/hooks/use-goal.ts +79 -9
  675. package/src/hooks/use-last-started-turn-policy.ts +37 -11
  676. package/src/hooks/use-machines.ts +4 -0
  677. package/src/hooks/use-new-conversation.ts +374 -0
  678. package/src/hooks/use-new-session-draft.ts +813 -0
  679. package/src/hooks/use-realtime-voice-models.ts +46 -0
  680. package/src/hooks/use-sandbox-files.ts +68 -20
  681. package/src/hooks/use-session-background-commands.ts +22 -11
  682. package/src/hooks/use-session-capabilities.ts +3 -2
  683. package/src/hooks/use-session-conversation.ts +150 -0
  684. package/src/hooks/use-session-events.ts +531 -335
  685. package/src/hooks/use-session-mcp-approval-policy.ts +13 -5
  686. package/src/hooks/use-session-model-account.ts +174 -0
  687. package/src/hooks/use-session.ts +30 -2
  688. package/src/hooks/use-slash-commands.ts +6 -11
  689. package/src/hooks/use-supergrok-accounts.ts +22 -8
  690. package/src/hooks/use-terminal-stream.ts +153 -27
  691. package/src/hooks/use-transcription.ts +6 -0
  692. package/src/hooks/use-turn-queue.ts +2 -1
  693. package/src/hooks/use-usage.ts +100 -0
  694. package/src/hooks/use-vaults.ts +153 -0
  695. package/src/hooks/use-video-artifact-playback.ts +1 -1
  696. package/src/hooks/use-voice-input.ts +127 -19
  697. package/src/hooks/use-workspace-capture.ts +3 -2
  698. package/src/hooks/use-workspace-edit.ts +23 -5
  699. package/src/hooks/use-workspace-sessions.ts +74 -7
  700. package/src/human-input-model.ts +359 -0
  701. package/src/identity-link-accounts.tsx +148 -0
  702. package/src/identity-link-consent.tsx +192 -0
  703. package/src/index.ts +262 -16
  704. package/src/interaction.ts +1 -0
  705. package/src/lib/clipboard.ts +29 -0
  706. package/src/lib/error-message.ts +37 -0
  707. package/src/lib/format.ts +205 -10
  708. package/src/lib/host-theme.ts +529 -0
  709. package/src/lib/interaction-errors.ts +15 -0
  710. package/src/lib/menu-styles.ts +44 -0
  711. package/src/lib/notify-observer.ts +15 -0
  712. package/src/lib/pierre-diffs-loader.ts +53 -0
  713. package/src/lib/provider-recovery.ts +243 -0
  714. package/src/lib/scrollbars.ts +30 -0
  715. package/src/lib/terminal-input-readiness.ts +51 -0
  716. package/src/lib/transient-retry.ts +99 -0
  717. package/src/lib/workbench-peers.ts +62 -0
  718. package/src/lib/xterm-theme.ts +23 -21
  719. package/src/mcp-connection-status.ts +35 -0
  720. package/src/model-mark-paths.ts +53 -0
  721. package/src/model-picker-model.ts +330 -0
  722. package/src/model-policy.ts +299 -74
  723. package/src/native-previews.ts +100 -0
  724. package/src/new-session-draft.ts +22 -0
  725. package/src/notification-text.ts +81 -0
  726. package/src/older-history.ts +22 -4
  727. package/src/organization-model.ts +118 -0
  728. package/src/plugin-details.tsx +185 -0
  729. package/src/plugin-discovery.tsx +196 -0
  730. package/src/preview-loading-paint.ts +68 -0
  731. package/src/provider.tsx +74 -15
  732. package/src/queue-presentation-model.ts +464 -0
  733. package/src/realtime/dropdown-menu.tsx +19 -12
  734. package/src/realtime/embedded-new-voice.tsx +1 -0
  735. package/src/realtime/embedded-voice.tsx +3 -0
  736. package/src/realtime/realtime-control.tsx +138 -550
  737. package/src/realtime/session-realtime.ts +566 -0
  738. package/src/sandbox-label-model.ts +53 -0
  739. package/src/scrollbars.ts +3 -0
  740. package/src/secret-reference-label.ts +43 -0
  741. package/src/secrets-ui.tsx +59 -0
  742. package/src/session-agents-model.ts +33 -0
  743. package/src/session-attention-model.ts +62 -0
  744. package/src/session-auth-recommendation.ts +48 -0
  745. package/src/session-capability-policy.ts +196 -0
  746. package/src/session-context.ts +3 -4
  747. package/src/session-feedback-model.ts +95 -0
  748. package/src/session-list-model.ts +434 -0
  749. package/src/session-realtime.ts +18 -0
  750. package/src/session-status-model.ts +99 -0
  751. package/src/session-ui.ts +98 -1
  752. package/src/session.ts +17 -1
  753. package/src/site-snapshot.ts +74 -0
  754. package/src/sites-ui.tsx +348 -0
  755. package/src/sites.ts +3 -0
  756. package/src/skill-discovery.tsx +208 -0
  757. package/src/terminal.ts +26 -0
  758. package/src/testing/session-scenarios.ts +404 -0
  759. package/src/timeline/activity-rail.tsx +242 -101
  760. package/src/timeline/agent-identity.tsx +84 -0
  761. package/src/timeline/agent-row.tsx +231 -0
  762. package/src/timeline/allowance-exhausted-row.tsx +86 -0
  763. package/src/timeline/compaction-copy.ts +115 -0
  764. package/src/timeline/fleet-decision-projection.ts +2 -1
  765. package/src/timeline/fleet-decision-row.tsx +1 -0
  766. package/src/timeline/focus-sequence.ts +44 -0
  767. package/src/timeline/genie-copy.ts +19 -0
  768. package/src/timeline/genie-loading.tsx +143 -0
  769. package/src/timeline/index.ts +30 -2
  770. package/src/timeline/knowledge-receipt.tsx +100 -0
  771. package/src/timeline/message-sender.tsx +71 -0
  772. package/src/timeline/notice-presentation.ts +48 -0
  773. package/src/timeline/parsers.ts +42 -2
  774. package/src/timeline/patch-apply-command.tsx +135 -0
  775. package/src/timeline/platform-activity-presentation.ts +166 -0
  776. package/src/timeline/platform-activity-row.tsx +15 -90
  777. package/src/timeline/presented-image.ts +63 -0
  778. package/src/timeline/projection.ts +1742 -76
  779. package/src/timeline/provider-logo.tsx +53 -0
  780. package/src/timeline/question-nav-model.ts +28 -0
  781. package/src/timeline/registry.ts +26 -4
  782. package/src/timeline/retained-image.ts +97 -0
  783. package/src/timeline/retained-loaders.ts +91 -0
  784. package/src/timeline/rolling-activity.tsx +80 -0
  785. package/src/timeline/screenshot-lightbox.tsx +228 -5
  786. package/src/timeline/session-usage-limit-row.tsx +42 -0
  787. package/src/timeline/shared.tsx +42 -15
  788. package/src/timeline/startup-dispatch-details.tsx +36 -0
  789. package/src/timeline/startup-preference.ts +33 -0
  790. package/src/timeline/startup-timings.tsx +145 -0
  791. package/src/timeline/tool-display-name.ts +19 -7
  792. package/src/timeline/tool-presentation.ts +1316 -0
  793. package/src/timeline/tool-renderers.tsx +835 -1138
  794. package/src/timeline/turn-summary-model.ts +343 -0
  795. package/src/timeline/turn-summary.tsx +272 -365
  796. package/src/timeline/types.ts +189 -6
  797. package/src/timeline/work-presentation.ts +189 -0
  798. package/src/timeline-model.ts +143 -0
  799. package/src/usage/allowance-copy.ts +64 -0
  800. package/src/usage/session-usage-limit.ts +266 -0
  801. package/src/usage/summary.ts +93 -0
  802. package/src/usage.ts +70 -0
  803. package/src/voice-recording-owner.ts +22 -0
  804. package/styles/compiled.css +2319 -748
  805. package/styles/connect.css +290 -0
  806. package/styles/connect.d.ts +1 -0
  807. package/styles/effective-tokens.css +1 -0
  808. package/styles/index.css +309 -9
  809. package/styles/responsive.css +99 -7
  810. package/styles/session-capability.css +44 -0
  811. package/styles/tokens.css +134 -66
  812. package/dist/browser-viewer-MKKFRRRV.js +0 -14
  813. package/dist/chunk-2DZVYHVO.js +0 -470
  814. package/dist/chunk-2DZVYHVO.js.map +0 -1
  815. package/dist/chunk-3AGBGTRT.js.map +0 -1
  816. package/dist/chunk-4MDLEHXL.js.map +0 -1
  817. package/dist/chunk-5YK2ZDIG.js.map +0 -1
  818. package/dist/chunk-7EAFGICR.js +0 -302
  819. package/dist/chunk-7EAFGICR.js.map +0 -1
  820. package/dist/chunk-ELIYWBZR.js.map +0 -1
  821. package/dist/chunk-H5YGYNXS.js.map +0 -1
  822. package/dist/chunk-HUIKIDM5.js.map +0 -1
  823. package/dist/chunk-ICA6R6TW.js.map +0 -1
  824. package/dist/chunk-IOLVN74D.js.map +0 -1
  825. package/dist/chunk-JAQ5K7W6.js.map +0 -1
  826. package/dist/chunk-JVYQRRC4.js.map +0 -1
  827. package/dist/chunk-KCGXPP5V.js.map +0 -1
  828. package/dist/chunk-KZ73RL76.js.map +0 -1
  829. package/dist/chunk-NEXLLTP4.js.map +0 -1
  830. package/dist/chunk-PEI6RANI.js.map +0 -1
  831. package/dist/chunk-VTOREEXF.js +0 -142
  832. package/dist/chunk-VTOREEXF.js.map +0 -1
  833. package/dist/chunk-WSK7G5LE.js +0 -170
  834. package/dist/chunk-WSK7G5LE.js.map +0 -1
  835. package/dist/chunk-X4A66EWZ.js +0 -223
  836. package/dist/chunk-X4A66EWZ.js.map +0 -1
  837. package/dist/chunk-XYRDDSXF.js.map +0 -1
  838. package/dist/chunk-YG4QEQF5.js +0 -9557
  839. package/dist/chunk-YG4QEQF5.js.map +0 -1
  840. package/dist/chunk-YVCHAQZY.js.map +0 -1
  841. package/dist/chunk-ZPBTI3TE.js.map +0 -1
  842. package/dist/computer-viewer-FWEZISW4.js +0 -16
  843. package/dist/fleet-decision-row-GGCAT4E4.js.map +0 -1
  844. package/dist/hooks/use-environments.d.ts +0 -41
  845. package/dist/hooks/use-packs.d.ts +0 -32
  846. package/dist/platform-activity-row-BJHUHXAT.js.map +0 -1
  847. package/dist/queue-surface-implementation-BSKUWHRI.js.map +0 -1
  848. package/dist/timeline-annotation-selection-3L7LHGG2.js +0 -187
  849. package/dist/timeline-annotation-selection-3L7LHGG2.js.map +0 -1
  850. package/dist/timeline-annotations-dialog-U7EVLR75.js +0 -196
  851. package/dist/timeline-annotations-dialog-U7EVLR75.js.map +0 -1
  852. package/src/hooks/use-environments.ts +0 -182
  853. package/src/hooks/use-packs.ts +0 -157
  854. /package/dist/{browser-viewer-MKKFRRRV.js.map → browser-viewer-ZWR6MWJ7.js.map} +0 -0
  855. /package/dist/{computer-viewer-FWEZISW4.js.map → chat-interactive-block-4EUKJXUO.js.map} +0 -0
@@ -1,69 +1,52 @@
1
1
  import type {
2
2
  HumanInputAnswer,
3
3
  HumanInputQuestion,
4
+ HumanInputSecretAnswer,
5
+ HumanInputSecretSaveTo,
6
+ HumanInputSecretSpec,
7
+ SkillRecord,
4
8
  SessionHumanInputRequest,
5
9
  SubmitHumanInputResponseRequest,
6
10
  } from "@opengeni/sdk";
7
11
  import { ChevronDownIcon, ChevronUpIcon, MessageCircleQuestionIcon } from "lucide-react";
8
- import { useEffect, useId, useRef, useState, type FormEvent, type ReactNode } from "react";
12
+ import {
13
+ useCallback,
14
+ useEffect,
15
+ useId,
16
+ useMemo,
17
+ useRef,
18
+ useState,
19
+ type FormEvent,
20
+ type ReactNode,
21
+ } from "react";
9
22
  import { cn } from "../lib/cn";
23
+ import { useErrorMessage } from "../lib/error-message";
24
+ import {
25
+ answersFromDrafts,
26
+ defaultHumanInputFormMessages,
27
+ emptyDraft,
28
+ initialDrafts,
29
+ secretAnswerFromReading,
30
+ type HumanInputAnswerDraft,
31
+ type HumanInputFormMessages,
32
+ } from "../human-input-model";
33
+ import { SecretQuestionField, type SecretFieldHandle } from "./secret-question-field";
34
+ import { linkifyText } from "./linkified-text";
10
35
 
11
- export type HumanInputAnswerDraft = {
12
- values: string[];
13
- other: string;
14
- otherSelected: boolean;
36
+ export {
37
+ answersFromDrafts,
38
+ defaultHumanInputFormMessages,
39
+ type HumanInputAnswerDraft,
40
+ type HumanInputFormMessages,
15
41
  };
16
42
 
17
- export type HumanInputFormMessages = {
18
- title: string;
19
- description: string;
20
- submit: string;
21
- skip: string;
22
- submitting: string;
23
- other: string;
24
- deadlineLabel: string;
25
- formatDeadline: (value: string) => string;
26
- required: string;
27
- otherRequired: string;
28
- minSelections: (count: number) => string;
29
- maxSelections: (count: number) => string;
30
- optional: string;
31
- /** Shown when the question list overflows the card and more content is below. */
32
- moreBelow: string;
33
- questionCount: (count: number) => string;
34
- collapse: string;
35
- expand: string;
36
- selectionHint: (min: number | null | undefined, max: number | null | undefined) => string | null;
37
- };
38
-
39
- export const defaultHumanInputFormMessages: HumanInputFormMessages = {
40
- title: "Input required",
41
- /** Multi-question chrome has no default subtitle; hosts may still override. */
42
- description: "",
43
- submit: "Send answers",
44
- skip: "Skip",
45
- submitting: "Submitting…",
46
- other: "Other",
47
- deadlineLabel: "Expires",
48
- formatDeadline,
49
- required: "This question is required.",
50
- otherRequired: "Enter a value for Other.",
51
- minSelections: (count) => `Choose at least ${count} option${count === 1 ? "" : "s"}.`,
52
- maxSelections: (count) => `Choose no more than ${count} option${count === 1 ? "" : "s"}.`,
53
- optional: "Optional",
54
- moreBelow: "More below",
55
- questionCount: (count) => `${count} questions`,
56
- collapse: "Collapse",
57
- expand: "Expand",
58
- selectionHint: (min, max) => {
59
- if (min != null && max != null) return `Choose ${min}–${max}.`;
60
- if (min != null) return `Choose at least ${min}.`;
61
- if (max != null) return `Choose up to ${max}.`;
62
- return null;
63
- },
64
- };
43
+ class SkillReviewVerificationError extends Error {}
65
44
 
66
45
  export type HumanInputFormProps = {
46
+ /** Scoped immutable revision reader. Saving a Skill fails closed without its full preview. */
47
+ loadSkillReview?:
48
+ | ((reference: NonNullable<HumanInputQuestion["skillReview"]>) => Promise<SkillRecord>)
49
+ | undefined;
67
50
  request: Pick<SessionHumanInputRequest, "id" | "questions" | "allowSkip" | "expiresAt">;
68
51
  onSubmit: (response: SubmitHumanInputResponseRequest) => void | Promise<void>;
69
52
  submitting?: boolean | undefined;
@@ -78,6 +61,18 @@ export type HumanInputFormProps = {
78
61
  autoFocus?: boolean | undefined;
79
62
  /** Start collapsed to a compact bar (drafts still retained). */
80
63
  defaultCollapsed?: boolean | undefined;
64
+ /**
65
+ * Answer a yes/no decision (one required choice between an accept and a
66
+ * decline option, without Other) with two buttons instead of a radio list.
67
+ * Off by default; embedded conversations turn it on.
68
+ */
69
+ decisionButtons?: boolean | undefined;
70
+ /**
71
+ * Where this person may save an answer to a secret question. A request for
72
+ * a target outside this list falls back to the most private allowed one,
73
+ * with a note. Defaults to Only me, This task and This workspace.
74
+ */
75
+ allowedSaveTo?: readonly HumanInputSecretSaveTo[] | undefined;
81
76
  className?: string | undefined;
82
77
  };
83
78
 
@@ -98,6 +93,7 @@ export function HumanInputForm(props: HumanInputFormProps) {
98
93
  function HumanInputRequestForm({
99
94
  request,
100
95
  onSubmit,
96
+ loadSkillReview,
101
97
  submitting = false,
102
98
  error,
103
99
  title,
@@ -108,10 +104,15 @@ function HumanInputRequestForm({
108
104
  messages: messageOverrides,
109
105
  autoFocus = true,
110
106
  defaultCollapsed = false,
107
+ decisionButtons = false,
108
+ allowedSaveTo,
111
109
  className,
112
110
  }: HumanInputFormProps) {
111
+ const formatError = useErrorMessage();
113
112
  const messages = { ...defaultHumanInputFormMessages, ...messageOverrides };
114
113
  const singleQuestion = request.questions.length === 1 ? request.questions[0]! : null;
114
+ const decision = decisionButtons ? binaryDecision(request.questions) : null;
115
+ const [decisionChoice, setDecisionChoice] = useState<string | null>(null);
115
116
  const resolvedTitle =
116
117
  title === undefined
117
118
  ? singleQuestion
@@ -141,7 +142,152 @@ function HumanInputRequestForm({
141
142
  const [collapsed, setCollapsed] = useState(defaultCollapsed);
142
143
  const submissionInFlight = useRef(false);
143
144
  const submissionGeneration = useRef(0);
145
+ // Secret answers stay in their uncontrolled inputs until submit.
146
+ const secretHandles = useRef(new Map<string, SecretFieldHandle>());
147
+ const secretRegistrars = useMemo(
148
+ () => new Map<string, (handle: SecretFieldHandle | null) => void>(),
149
+ [],
150
+ );
151
+ const registerSecret = useCallback(
152
+ (questionId: string) => {
153
+ let registrar = secretRegistrars.get(questionId);
154
+ if (!registrar) {
155
+ registrar = (handle) => {
156
+ if (handle) secretHandles.current.set(questionId, handle);
157
+ else secretHandles.current.delete(questionId);
158
+ };
159
+ secretRegistrars.set(questionId, registrar);
160
+ }
161
+ return registrar;
162
+ },
163
+ [secretRegistrars],
164
+ );
144
165
  const busy = submitting || submittingInternally;
166
+ const reviewIdentity = JSON.stringify(
167
+ request.questions
168
+ .filter((question) => question.skillReview)
169
+ .map((question) => ({
170
+ id: question.id,
171
+ reference: {
172
+ sourceOperationId: question.skillReview!.sourceOperationId,
173
+ skillId: question.skillReview!.skillId,
174
+ revisionId: question.skillReview!.revisionId,
175
+ expectedRevisionId: question.skillReview!.expectedRevisionId,
176
+ expectedScopeVersion: question.skillReview!.expectedScopeVersion,
177
+ ...(question.skillReview!.removalOperationId
178
+ ? { removalOperationId: question.skillReview!.removalOperationId }
179
+ : {}),
180
+ },
181
+ })),
182
+ );
183
+ const [reviewReload, setReviewReload] = useState(0);
184
+ const [reviews, setReviews] = useState<{
185
+ loader: typeof loadSkillReview;
186
+ identity: string;
187
+ records: Record<string, SkillRecord>;
188
+ error: string | null;
189
+ } | null>(null);
190
+ useEffect(() => {
191
+ let current = true;
192
+ const questions = JSON.parse(reviewIdentity) as Array<{
193
+ id: string;
194
+ reference: NonNullable<HumanInputQuestion["skillReview"]>;
195
+ }>;
196
+ if (!questions.length) return;
197
+ setReviews(null);
198
+ void Promise.all(
199
+ questions.map(async (question) => {
200
+ if (!loadSkillReview)
201
+ throw new Error(
202
+ "This client cannot preview Skill files. Ask your administrator for a review-capable client.",
203
+ );
204
+ const reference = question.reference;
205
+ const record = await loadSkillReview(reference);
206
+ if (
207
+ record.id !== reference.skillId ||
208
+ record.revisionId !== reference.revisionId ||
209
+ (record.removalOperationId ?? undefined) !== reference.removalOperationId ||
210
+ !record.files.some((file) => file.path === "SKILL.md")
211
+ ) {
212
+ throw new SkillReviewVerificationError(
213
+ "The requested Skill revision could not be verified.",
214
+ );
215
+ }
216
+ return [question.id, record] as const;
217
+ }),
218
+ )
219
+ .then((records) => {
220
+ if (current)
221
+ setReviews({
222
+ loader: loadSkillReview,
223
+ identity: reviewIdentity,
224
+ records: Object.fromEntries(records),
225
+ error: null,
226
+ });
227
+ })
228
+ .catch((cause) => {
229
+ if (current)
230
+ setReviews({
231
+ loader: loadSkillReview,
232
+ identity: reviewIdentity,
233
+ records: {},
234
+ error: formatError(
235
+ cause,
236
+ cause instanceof SkillReviewVerificationError
237
+ ? cause.message
238
+ : !loadSkillReview
239
+ ? "This client cannot preview Skill files. Ask your administrator for a review-capable client."
240
+ : undefined,
241
+ ),
242
+ });
243
+ });
244
+ return () => {
245
+ current = false;
246
+ };
247
+ }, [loadSkillReview, reviewIdentity, reviewReload, formatError]);
248
+ const visibleReviews =
249
+ reviews?.loader === loadSkillReview && reviews?.identity === reviewIdentity ? reviews : null;
250
+ const preview = (question: HumanInputQuestion) => {
251
+ if (!question.skillReview) return null;
252
+ const record = visibleReviews?.records[question.id];
253
+ return (
254
+ <div className="mb-3 min-w-0 space-y-2" data-skill-review="">
255
+ {record ? (
256
+ <>
257
+ <p className="text-og-sm">
258
+ {record.title ?? "Skill"} · {record.scope} · {record.files.length} files
259
+ </p>
260
+ <p className="text-og-xs text-og-fg-muted">
261
+ {question.skillReview.removalOperationId
262
+ ? "Permanently deletes this Skill and all stored revisions. This cannot be undone; conversations remain unchanged."
263
+ : "Saving activates these exact files. No additional review is required."}
264
+ </p>
265
+ {record.files.map((file) => (
266
+ <details key={file.path} open={file.path === "SKILL.md"}>
267
+ <summary className="cursor-pointer break-all text-og-sm">{file.path}</summary>
268
+ <pre className="max-h-64 overflow-auto whitespace-pre-wrap break-words rounded-og-md bg-og-surface-1 p-2 text-og-xs">
269
+ {file.content}
270
+ </pre>
271
+ </details>
272
+ ))}
273
+ </>
274
+ ) : visibleReviews?.error ? (
275
+ <>
276
+ <p role="alert" className="text-og-sm">
277
+ {visibleReviews.error}
278
+ </p>
279
+ <button type="button" onClick={() => setReviewReload((value) => value + 1)}>
280
+ Retry preview
281
+ </button>
282
+ </>
283
+ ) : (
284
+ <p role="status" className="text-og-sm">
285
+ Loading the exact Skill files…
286
+ </p>
287
+ )}
288
+ </div>
289
+ );
290
+ };
145
291
 
146
292
  useEffect(() => {
147
293
  if (collapsed) {
@@ -187,18 +333,29 @@ function HumanInputRequestForm({
187
333
  });
188
334
  };
189
335
 
190
- const submitResponse = async (response: SubmitHumanInputResponseRequest): Promise<void> => {
191
- if (busy || submissionInFlight.current) return;
336
+ const clearValidationError = (questionId: string): void =>
337
+ setValidationErrors((current) => {
338
+ if (!(questionId in current)) return current;
339
+ const next = { ...current };
340
+ delete next[questionId];
341
+ return next;
342
+ });
343
+
344
+ /** Resolves true when the host accepted the response. */
345
+ const submitResponse = async (response: SubmitHumanInputResponseRequest): Promise<boolean> => {
346
+ if (busy || submissionInFlight.current) return false;
192
347
  const generation = submissionGeneration.current;
193
348
  submissionInFlight.current = true;
194
349
  setSubmissionError(null);
195
350
  setSubmittingInternally(true);
196
351
  try {
197
352
  await onSubmit(response);
353
+ return true;
198
354
  } catch (cause) {
199
355
  if (generation === submissionGeneration.current) {
200
- setSubmissionError(cause instanceof Error ? cause.message : String(cause));
356
+ setSubmissionError(formatError(cause));
201
357
  }
358
+ return false;
202
359
  } finally {
203
360
  if (generation === submissionGeneration.current) {
204
361
  submissionInFlight.current = false;
@@ -223,6 +380,21 @@ function HumanInputRequestForm({
223
380
  const submit = async (event: FormEvent<HTMLFormElement>): Promise<void> => {
224
381
  event.preventDefault();
225
382
  const result = answersFromDrafts(request.questions, drafts, messages);
383
+ const secretAnswers: HumanInputSecretAnswer[] = [];
384
+ const secretPublicAnswers = new Map<string, HumanInputAnswer>();
385
+ for (const question of request.questions) {
386
+ if (question.kind !== "secret") continue;
387
+ const handle = secretHandles.current.get(question.id);
388
+ if (!handle) continue;
389
+ const secret = secretAnswerFromReading(question, handle.read(), messages);
390
+ if (!secret) continue;
391
+ if ("error" in secret) {
392
+ result.errors[question.id] = secret.error;
393
+ continue;
394
+ }
395
+ secretAnswers.push(secret.secretAnswer);
396
+ secretPublicAnswers.set(question.id, secret.answer);
397
+ }
226
398
  if (Object.keys(result.errors).length > 0) {
227
399
  setValidationErrors(result.errors);
228
400
  const firstInvalid = request.questions.find((question) => question.id in result.errors);
@@ -232,7 +404,34 @@ function HumanInputRequestForm({
232
404
  }
233
405
  return;
234
406
  }
235
- await submitResponse({ outcome: "answered", answers: result.answers });
407
+ const unreviewedSave = request.questions.find(
408
+ (question) =>
409
+ question.skillReview &&
410
+ !visibleReviews?.records[question.id] &&
411
+ result.answers.some(
412
+ (answer) => answer.questionId === question.id && answer.values.includes("save"),
413
+ ),
414
+ );
415
+ if (unreviewedSave) {
416
+ setValidationErrors({
417
+ [unreviewedSave.id]: unreviewedSave.skillReview?.removalOperationId
418
+ ? "Load the exact Skill proposal before approving permanent deletion."
419
+ : "Load the exact Skill files before saving.",
420
+ });
421
+ return;
422
+ }
423
+ // Keep the request's question order across drafted and secret answers.
424
+ const drafted = new Map(result.answers.map((answer) => [answer.questionId, answer]));
425
+ const answers = request.questions.flatMap((question) => {
426
+ const answer = drafted.get(question.id) ?? secretPublicAnswers.get(question.id);
427
+ return answer ? [answer] : [];
428
+ });
429
+ const accepted = await submitResponse({
430
+ outcome: "answered",
431
+ answers,
432
+ ...(secretAnswers.length > 0 ? { secretAnswers } : {}),
433
+ });
434
+ if (accepted) for (const handle of secretHandles.current.values()) handle.clear();
236
435
  };
237
436
 
238
437
  const metaBits = [
@@ -305,9 +504,12 @@ function HumanInputRequestForm({
305
504
  </span>
306
505
  <div className="min-w-0 flex-1">
307
506
  <div className="flex flex-wrap items-baseline gap-x-2 gap-y-0.5">
308
- <h2 id={titleId} className="text-og-md font-semibold text-og-fg">
309
- {resolvedTitle}
310
- {singleQuestion?.required && !request.allowSkip ? (
507
+ <h2
508
+ id={titleId}
509
+ className="min-w-0 text-og-md font-semibold text-og-fg [overflow-wrap:anywhere]"
510
+ >
511
+ {linkifyText(resolvedTitle)}
512
+ {singleQuestion?.required && !request.allowSkip && !decision ? (
311
513
  <span aria-hidden className="ml-1 text-og-status-failed">
312
514
  *
313
515
  </span>
@@ -325,7 +527,9 @@ function HumanInputRequestForm({
325
527
  ) : null}
326
528
  </div>
327
529
  {resolvedDescription ? (
328
- <div className="mt-0.5 text-og-sm text-og-fg-muted">{resolvedDescription}</div>
530
+ <div className="mt-0.5 text-og-sm text-og-fg-muted [overflow-wrap:anywhere]">
531
+ {linkifyText(resolvedDescription)}
532
+ </div>
329
533
  ) : null}
330
534
  {request.expiresAt ? (
331
535
  <p className="mt-1 text-og-xs text-og-fg-subtle">
@@ -354,106 +558,247 @@ function HumanInputRequestForm({
354
558
  </div>
355
559
  </header>
356
560
 
357
- <div className="relative flex min-h-0 flex-1 flex-col overflow-hidden">
358
- <div
359
- ref={scrollRef}
360
- className="min-h-0 flex-1 overflow-y-auto overscroll-contain [scrollbar-gutter:stable]"
361
- >
362
- <fieldset disabled={busy} className="min-w-0 space-y-4 px-4 py-3">
363
- {request.questions.map((question, index) => {
364
- if (singleQuestion) {
365
- // Title already carries the question; only render the control + help extras.
366
- return (
367
- <div key={question.id} data-human-input-question={question.id}>
368
- <QuestionControls
369
- question={question}
370
- questionNumber={null}
371
- labelledBy={titleId}
372
- draft={drafts[question.id] ?? emptyDraft()}
373
- fieldId={`${formId}-${index}`}
374
- error={validationErrors[question.id]}
375
- messages={messages}
376
- autoFocus={autoFocus}
377
- firstOption
378
- showPromptChrome={false}
379
- allowSkip={request.allowSkip}
380
- busy={busy}
381
- onUpdate={(apply) => update(question.id, apply)}
382
- />
383
- </div>
384
- );
385
- }
561
+ {decision ? (
562
+ <>
563
+ {decision.question.helpText ||
564
+ decision.accept.description ||
565
+ decision.decline.description ? (
566
+ <div className="shrink-0 space-y-1 px-4 pt-3 text-og-sm text-og-fg-muted [overflow-wrap:anywhere]">
567
+ {decision.question.label && decision.question.helpText ? (
568
+ <p>{linkifyText(decision.question.helpText)}</p>
569
+ ) : null}
570
+ {[decision.accept, decision.decline].map((option) =>
571
+ option.description ? (
572
+ <p key={option.id}>
573
+ <span className="font-medium text-og-fg">{option.label}</span>
574
+ {" · "}
575
+ {option.description}
576
+ </p>
577
+ ) : null,
578
+ )}
579
+ </div>
580
+ ) : null}
581
+ {(error ?? submissionError) ? (
582
+ <p role="alert" className="shrink-0 px-4 pt-3 text-og-sm text-og-status-failed">
583
+ {error ?? submissionError}
584
+ </p>
585
+ ) : null}
586
+ <footer
587
+ className="flex shrink-0 flex-wrap items-center justify-end gap-2 px-4 py-3"
588
+ data-human-input-decision=""
589
+ >
590
+ {request.allowSkip ? (
591
+ <button
592
+ type="button"
593
+ disabled={busy}
594
+ onClick={() => void submitResponse({ outcome: "skipped" })}
595
+ className="mr-auto inline-flex min-h-9 items-center rounded-og-md px-2 py-1.5 text-og-sm font-medium text-og-fg-muted transition-colors hover:bg-og-hover hover:text-og-fg disabled:opacity-50 pointer-coarse:min-h-11"
596
+ >
597
+ {resolvedSkipLabel}
598
+ </button>
599
+ ) : null}
600
+ {[decision.decline, decision.accept].map((option) => {
601
+ const primary = option === decision.accept;
386
602
  return (
387
- <div
388
- key={question.id}
389
- data-human-input-question={question.id}
390
- className="flex flex-col gap-1.5"
603
+ <button
604
+ key={option.id}
605
+ type="button"
606
+ disabled={busy}
607
+ ref={
608
+ !primary && autoFocus
609
+ ? (node) => {
610
+ if (node && !node.dataset.ogFocused) {
611
+ node.dataset.ogFocused = "";
612
+ node.focus({ preventScroll: true });
613
+ }
614
+ }
615
+ : undefined
616
+ }
617
+ data-human-input-choice={option.id}
618
+ onClick={() => {
619
+ setDecisionChoice(option.id);
620
+ void submitResponse({
621
+ outcome: "answered",
622
+ answers: [{ questionId: decision.question.id, values: [option.id] }],
623
+ });
624
+ }}
625
+ className={cn(
626
+ "inline-flex min-h-9 items-center rounded-og-md border px-3.5 py-1.5 text-og-sm font-medium transition disabled:opacity-50 pointer-coarse:min-h-11",
627
+ primary
628
+ ? "border-og-primary-border bg-og-primary text-og-primary-fg hover:bg-og-primary-hover"
629
+ : "border-og-border bg-og-surface-1 text-og-fg hover:bg-og-surface-2",
630
+ )}
391
631
  >
392
- <QuestionControls
393
- question={question}
394
- questionNumber={index + 1}
395
- labelledBy={undefined}
396
- draft={drafts[question.id] ?? emptyDraft()}
397
- fieldId={`${formId}-${index}`}
398
- error={validationErrors[question.id]}
399
- messages={messages}
400
- autoFocus={autoFocus && index === 0}
401
- firstOption={index === 0}
402
- showPromptChrome
403
- allowSkip={request.allowSkip}
404
- busy={busy}
405
- onUpdate={(apply) => update(question.id, apply)}
406
- />
407
- </div>
632
+ {busy && decisionChoice === option.id ? messages.submitting : option.label}
633
+ </button>
408
634
  );
409
635
  })}
410
- </fieldset>
411
- </div>
412
- {overflowBelow ? (
413
- <div
414
- className="pointer-events-none absolute inset-x-0 bottom-0 z-[1] flex flex-col items-center"
415
- aria-hidden="true"
416
- >
417
- <div className="h-10 w-full bg-gradient-to-t from-og-surface-1 via-og-surface-1/85 to-transparent" />
418
- <span className="-mt-5 mb-1 rounded-og-full bg-og-surface-1 px-2.5 py-0.5 text-og-xs font-medium text-og-fg-muted shadow-og-sm ring-1 ring-og-border/60">
419
- {messages.moreBelow}
420
- </span>
636
+ </footer>
637
+ </>
638
+ ) : (
639
+ <>
640
+ <div className="relative flex min-h-0 flex-1 flex-col overflow-hidden">
641
+ <div
642
+ ref={scrollRef}
643
+ className="min-h-0 flex-1 overflow-y-auto overscroll-contain [scrollbar-gutter:stable]"
644
+ >
645
+ <fieldset disabled={busy} className="min-w-0 space-y-4 px-4 py-3">
646
+ {request.questions.map((question, index) => {
647
+ if (singleQuestion) {
648
+ // Title already carries the question; only render the control + help extras.
649
+ return (
650
+ <div key={question.id} data-human-input-question={question.id}>
651
+ {preview(question)}
652
+ <QuestionControls
653
+ question={question}
654
+ questionNumber={null}
655
+ labelledBy={titleId}
656
+ draft={drafts[question.id] ?? emptyDraft()}
657
+ fieldId={`${formId}-${index}`}
658
+ error={validationErrors[question.id]}
659
+ messages={messages}
660
+ autoFocus={autoFocus}
661
+ firstOption
662
+ showPromptChrome={false}
663
+ allowSkip={request.allowSkip}
664
+ busy={busy}
665
+ allowedSaveTo={allowedSaveTo}
666
+ registerSecret={registerSecret(question.id)}
667
+ onSecretEdited={() => clearValidationError(question.id)}
668
+ onUpdate={(apply) => update(question.id, apply)}
669
+ />
670
+ </div>
671
+ );
672
+ }
673
+ return (
674
+ <div
675
+ key={question.id}
676
+ data-human-input-question={question.id}
677
+ className="flex flex-col gap-1.5"
678
+ >
679
+ {preview(question)}
680
+ <QuestionControls
681
+ question={question}
682
+ questionNumber={index + 1}
683
+ labelledBy={undefined}
684
+ draft={drafts[question.id] ?? emptyDraft()}
685
+ fieldId={`${formId}-${index}`}
686
+ error={validationErrors[question.id]}
687
+ messages={messages}
688
+ autoFocus={autoFocus && index === 0}
689
+ firstOption={index === 0}
690
+ showPromptChrome
691
+ allowSkip={request.allowSkip}
692
+ busy={busy}
693
+ allowedSaveTo={allowedSaveTo}
694
+ registerSecret={registerSecret(question.id)}
695
+ onSecretEdited={() => clearValidationError(question.id)}
696
+ onUpdate={(apply) => update(question.id, apply)}
697
+ />
698
+ </div>
699
+ );
700
+ })}
701
+ </fieldset>
702
+ </div>
703
+ {overflowBelow ? (
704
+ <div
705
+ className="pointer-events-none absolute inset-x-0 bottom-0 z-[1] flex flex-col items-center"
706
+ aria-hidden="true"
707
+ >
708
+ <div className="h-10 w-full bg-gradient-to-t from-og-surface-1 via-og-surface-1/85 to-transparent" />
709
+ <span className="-mt-5 mb-1 rounded-og-full bg-og-surface-1 px-2.5 py-0.5 text-og-xs font-medium text-og-fg-muted shadow-og-sm ring-1 ring-og-border/60">
710
+ {messages.moreBelow}
711
+ </span>
712
+ </div>
713
+ ) : null}
421
714
  </div>
422
- ) : null}
423
- </div>
424
715
 
425
- {(error ?? submissionError) ? (
426
- <p
427
- role="alert"
428
- className="relative z-10 shrink-0 px-4 pb-1 text-og-sm text-og-status-failed"
429
- >
430
- {error ?? submissionError}
431
- </p>
432
- ) : null}
716
+ {(error ?? submissionError) ? (
717
+ <p
718
+ role="alert"
719
+ className="relative z-10 shrink-0 px-4 pb-1 text-og-sm text-og-status-failed"
720
+ >
721
+ {error ?? submissionError}
722
+ </p>
723
+ ) : null}
433
724
 
434
- <footer className="relative z-10 flex shrink-0 items-center justify-end gap-2 border-t border-og-status-waiting/20 bg-og-surface-1/95 px-4 py-3 backdrop-blur-[2px]">
435
- {request.allowSkip ? (
436
- <button
437
- type="button"
438
- disabled={busy}
439
- onClick={() => void submitResponse({ outcome: "skipped" })}
440
- className="inline-flex min-h-9 items-center rounded-og-md border border-og-border px-3 py-1.5 text-og-sm font-medium text-og-fg-muted transition-colors hover:bg-og-surface-1 hover:text-og-fg disabled:opacity-50"
441
- >
442
- {resolvedSkipLabel}
443
- </button>
444
- ) : null}
445
- <button
446
- type="submit"
447
- disabled={busy}
448
- className="inline-flex min-h-9 items-center rounded-og-md bg-og-accent-deep px-3 py-1.5 text-og-sm font-medium text-og-accent-fg transition hover:brightness-110 disabled:opacity-50"
449
- >
450
- {busy ? messages.submitting : resolvedSubmitLabel}
451
- </button>
452
- </footer>
725
+ <footer className="relative z-10 flex shrink-0 items-center justify-end gap-2 border-t border-og-status-waiting/20 bg-og-surface-1/95 px-4 py-3 backdrop-blur-[2px]">
726
+ {request.allowSkip ? (
727
+ <button
728
+ type="button"
729
+ disabled={busy}
730
+ onClick={() => void submitResponse({ outcome: "skipped" })}
731
+ className="inline-flex min-h-9 items-center rounded-og-md border border-og-border px-3 py-1.5 text-og-sm font-medium text-og-fg-muted transition-colors hover:bg-og-surface-1 hover:text-og-fg disabled:opacity-50"
732
+ >
733
+ {resolvedSkipLabel}
734
+ </button>
735
+ ) : null}
736
+ <button
737
+ type="submit"
738
+ disabled={busy}
739
+ className="inline-flex min-h-9 items-center rounded-og-md border border-og-primary-border bg-og-primary text-og-primary-fg px-3 py-1.5 text-og-sm font-medium transition hover:bg-og-primary-hover disabled:opacity-50"
740
+ >
741
+ {busy ? messages.submitting : resolvedSubmitLabel}
742
+ </button>
743
+ </footer>
744
+ </>
745
+ )}
453
746
  </form>
454
747
  );
455
748
  }
456
749
 
750
+ // Unambiguous approve/decline verbs only: "Continue with A" vs "Keep B" is a
751
+ // real choice between two options, not a yes/no decision.
752
+ const ACCEPT_WORDS = new Set(["approve", "approved", "yes", "confirm", "allow", "accept"]);
753
+ const DECLINE_WORDS = new Set(["cancel", "decline", "reject", "deny", "no", "don't", "dont"]);
754
+
755
+ function firstWord(label: string): string {
756
+ return (
757
+ label
758
+ .trim()
759
+ .toLowerCase()
760
+ .replace(/[’]/g, "'")
761
+ .split(/[\s,.:;!?()]+/)[0] ?? ""
762
+ );
763
+ }
764
+
765
+ /**
766
+ * A yes/no decision (an approval asked as a question): one required
767
+ * single-choice question with exactly an accept and a decline option. It is
768
+ * answered with two buttons; an "Other" free-text answer has no meaning for it,
769
+ * and the composer still accepts a different instruction.
770
+ */
771
+ export function binaryDecision(questions: readonly HumanInputQuestion[]): {
772
+ question: HumanInputQuestion;
773
+ accept: HumanInputQuestion["options"][number];
774
+ decline: HumanInputQuestion["options"][number];
775
+ } | null {
776
+ if (questions.length !== 1) return null;
777
+ const question = questions[0]!;
778
+ if (
779
+ question.kind !== "single_select" ||
780
+ question.skillReview ||
781
+ // The runtime marks every choice question `allowOther`, so it is not a
782
+ // signal here; a different answer goes through the composer instead.
783
+ !question.required ||
784
+ question.options.length !== 2
785
+ )
786
+ return null;
787
+ const [first, second] = question.options as [
788
+ HumanInputQuestion["options"][number],
789
+ HumanInputQuestion["options"][number],
790
+ ];
791
+ const kind = (option: HumanInputQuestion["options"][number]) => {
792
+ const word = firstWord(option.label);
793
+ return ACCEPT_WORDS.has(word) ? "accept" : DECLINE_WORDS.has(word) ? "decline" : null;
794
+ };
795
+ const a = kind(first);
796
+ const b = kind(second);
797
+ if (a === "accept" && b === "decline") return { question, accept: first, decline: second };
798
+ if (a === "decline" && b === "accept") return { question, accept: second, decline: first };
799
+ return null;
800
+ }
801
+
457
802
  function QuestionControls({
458
803
  question,
459
804
  questionNumber,
@@ -467,6 +812,9 @@ function QuestionControls({
467
812
  showPromptChrome,
468
813
  allowSkip,
469
814
  busy,
815
+ allowedSaveTo,
816
+ registerSecret,
817
+ onSecretEdited,
470
818
  onUpdate,
471
819
  }: {
472
820
  question: HumanInputQuestion;
@@ -481,6 +829,9 @@ function QuestionControls({
481
829
  showPromptChrome: boolean;
482
830
  allowSkip: boolean;
483
831
  busy: boolean;
832
+ allowedSaveTo: readonly HumanInputSecretSaveTo[] | undefined;
833
+ registerSecret: (handle: SecretFieldHandle | null) => void;
834
+ onSecretEdited: () => void;
484
835
  onUpdate: (apply: (draft: HumanInputAnswerDraft) => HumanInputAnswerDraft) => void;
485
836
  }) {
486
837
  const errorId = `${fieldId}-error`;
@@ -521,13 +872,13 @@ function QuestionControls({
521
872
  <label
522
873
  id={labelId}
523
874
  htmlFor={question.kind === "text" ? fieldId : undefined}
524
- className="text-og-sm font-medium text-og-fg"
875
+ className="min-w-0 text-og-sm font-medium text-og-fg [overflow-wrap:anywhere]"
525
876
  >
526
877
  {questionNumber === null ? null : (
527
878
  <span className="mr-1.5 tabular-nums text-og-fg-muted">{questionNumber}.</span>
528
879
  )}
529
880
  {questionNumber === null ? null : " "}
530
- {visibleLabel}
881
+ {linkifyText(visibleLabel)}
531
882
  {question.required && !allowSkip ? (
532
883
  <span aria-hidden className="ml-1 text-og-status-failed">
533
884
  *
@@ -540,13 +891,13 @@ function QuestionControls({
540
891
  </label>
541
892
  </div>
542
893
  {question.label ? (
543
- <p id={promptId} className="text-og-sm text-og-fg-muted">
544
- {question.prompt}
894
+ <p id={promptId} className="text-og-sm text-og-fg-muted [overflow-wrap:anywhere]">
895
+ {linkifyText(question.prompt)}
545
896
  </p>
546
897
  ) : null}
547
898
  {question.helpText ? (
548
- <p id={helpId} className="text-og-xs text-og-fg-subtle">
549
- {question.helpText}
899
+ <p id={helpId} className="text-og-xs text-og-fg-subtle [overflow-wrap:anywhere]">
900
+ {linkifyText(question.helpText)}
550
901
  </p>
551
902
  ) : null}
552
903
  {hint ? (
@@ -561,8 +912,8 @@ function QuestionControls({
561
912
  <p className="text-og-xs text-og-fg-subtle">{messages.optional}</p>
562
913
  ) : null}
563
914
  {question.helpText && question.label ? (
564
- <p id={helpId} className="mb-1.5 text-og-xs text-og-fg-subtle">
565
- {question.helpText}
915
+ <p id={helpId} className="mb-1.5 text-og-xs text-og-fg-subtle [overflow-wrap:anywhere]">
916
+ {linkifyText(question.helpText)}
566
917
  </p>
567
918
  ) : null}
568
919
  {hint ? (
@@ -573,7 +924,30 @@ function QuestionControls({
573
924
  </>
574
925
  )}
575
926
 
576
- {question.kind === "text" ? (
927
+ {question.kind === "secret" ? (
928
+ question.secret ? (
929
+ <SecretQuestionField
930
+ question={question as HumanInputQuestion & { secret: HumanInputSecretSpec }}
931
+ fieldId={fieldId}
932
+ messages={messages}
933
+ autoFocus={autoFocus}
934
+ allowedSaveTo={allowedSaveTo}
935
+ error={error}
936
+ describedBy={
937
+ [
938
+ question.label && showPromptChrome ? promptId : null,
939
+ question.helpText && showPromptChrome ? helpId : null,
940
+ ]
941
+ .filter(Boolean)
942
+ .join(" ") || undefined
943
+ }
944
+ register={registerSecret}
945
+ onEdited={onSecretEdited}
946
+ />
947
+ ) : (
948
+ <p className="text-og-sm text-og-fg-muted">This question can't be answered here.</p>
949
+ )
950
+ ) : question.kind === "text" ? (
577
951
  <textarea
578
952
  id={fieldId}
579
953
  value={draft.values[0] ?? ""}
@@ -643,65 +1017,68 @@ function QuestionControls({
643
1017
  </label>
644
1018
  );
645
1019
  })}
646
- <div
647
- className={cn(
648
- "flex items-start gap-2.5 rounded-og-md px-2.5 py-2 transition-colors",
649
- draft.otherSelected
650
- ? "bg-og-status-waiting/12 text-og-fg"
651
- : "text-og-fg hover:bg-og-surface-1/80",
652
- )}
653
- >
654
- <input
655
- id={otherChoiceId}
656
- type={question.kind === "single_select" ? "radio" : "checkbox"}
657
- name={question.kind === "single_select" ? fieldId : undefined}
658
- aria-labelledby={otherLabelId}
659
- checked={draft.otherSelected}
660
- autoFocus={autoFocus && firstOption && question.options.length === 0}
661
- onChange={(event) =>
662
- onUpdate((current) => ({
663
- ...current,
664
- otherSelected: event.target.checked,
665
- ...(question.kind === "single_select" && event.target.checked
666
- ? { values: [] }
667
- : {}),
668
- }))
669
- }
670
- className="mt-2 accent-og-accent"
671
- />
672
- <span className="min-w-0 flex-1">
673
- <label
674
- id={otherLabelId}
675
- htmlFor={otherChoiceId}
676
- className="block text-og-sm font-medium"
677
- >
678
- {messages.other}
679
- </label>
680
- <label htmlFor={otherTextId} className="sr-only">
681
- {messages.other} answer for {visibleLabel}
682
- </label>
1020
+ {!question.skillReview ? (
1021
+ <div
1022
+ className={cn(
1023
+ "flex items-start gap-2.5 rounded-og-md px-2.5 py-2 transition-colors",
1024
+ draft.otherSelected
1025
+ ? "bg-og-status-waiting/12 text-og-fg"
1026
+ : "text-og-fg hover:bg-og-surface-1/80",
1027
+ )}
1028
+ >
683
1029
  <input
684
- id={otherTextId}
685
- type="text"
686
- value={draft.other}
687
- disabled={busy}
688
- placeholder="Type a value…"
689
- onClick={() => onUpdate(selectOtherDraft)}
690
- onFocus={() => onUpdate(selectOtherDraft)}
691
- onChange={(event) => {
692
- const other = event.target.value;
1030
+ id={otherChoiceId}
1031
+ type={question.kind === "single_select" ? "radio" : "checkbox"}
1032
+ name={question.kind === "single_select" ? fieldId : undefined}
1033
+ aria-labelledby={otherLabelId}
1034
+ checked={draft.otherSelected}
1035
+ autoFocus={autoFocus && firstOption && question.options.length === 0}
1036
+ onChange={(event) =>
693
1037
  onUpdate((current) => ({
694
- ...selectOtherDraft(current),
695
- other,
696
- }));
697
- }}
698
- className="mt-1.5 w-full rounded-og-sm border border-og-border bg-og-surface-1 px-2 py-1.5 text-og-sm text-og-fg outline-hidden focus:border-og-accent disabled:opacity-50"
1038
+ ...current,
1039
+ otherSelected: event.target.checked,
1040
+ ...(question.kind === "single_select" && event.target.checked
1041
+ ? { values: [] }
1042
+ : {}),
1043
+ }))
1044
+ }
1045
+ className="mt-2 accent-og-accent"
699
1046
  />
700
- </span>
701
- </div>
1047
+ <span className="min-w-0 flex-1">
1048
+ <label
1049
+ id={otherLabelId}
1050
+ htmlFor={otherChoiceId}
1051
+ className="block text-og-sm font-medium"
1052
+ >
1053
+ {messages.other}
1054
+ </label>
1055
+ <label htmlFor={otherTextId} className="sr-only">
1056
+ {messages.other} answer for {visibleLabel}
1057
+ </label>
1058
+ <input
1059
+ id={otherTextId}
1060
+ type="text"
1061
+ value={draft.other}
1062
+ disabled={busy}
1063
+ placeholder="Type a value…"
1064
+ onClick={() => onUpdate(selectOtherDraft)}
1065
+ onFocus={() => onUpdate(selectOtherDraft)}
1066
+ onChange={(event) => {
1067
+ const other = event.target.value;
1068
+ onUpdate((current) => ({
1069
+ ...selectOtherDraft(current),
1070
+ other,
1071
+ }));
1072
+ }}
1073
+ className="mt-1.5 w-full rounded-og-sm border border-og-border bg-og-surface-1 px-2 py-1.5 text-og-sm text-og-fg outline-hidden focus:border-og-accent disabled:opacity-50"
1074
+ />
1075
+ </span>
1076
+ </div>
1077
+ ) : null}
702
1078
  </div>
703
1079
  )}
704
- {error ? (
1080
+ {/* A secret field shows its error under the input, above Save to. */}
1081
+ {error && !(question.kind === "secret" && question.secret) ? (
705
1082
  <p id={errorId} role="alert" className="text-og-xs text-og-status-failed">
706
1083
  {error}
707
1084
  </p>
@@ -709,73 +1086,3 @@ function QuestionControls({
709
1086
  </>
710
1087
  );
711
1088
  }
712
-
713
- export function answersFromDrafts(
714
- questions: HumanInputQuestion[],
715
- drafts: Record<string, HumanInputAnswerDraft>,
716
- messageOverrides: Partial<HumanInputFormMessages> = {},
717
- ): { answers: HumanInputAnswer[]; errors: Record<string, string> } {
718
- const messages = { ...defaultHumanInputFormMessages, ...messageOverrides };
719
- const answers: HumanInputAnswer[] = [];
720
- const errors: Record<string, string> = {};
721
- for (const question of questions) {
722
- const draft = drafts[question.id] ?? emptyDraft();
723
- const values = question.kind === "text" ? draft.values.filter(Boolean) : draft.values;
724
- const other = draft.otherSelected ? draft.other : "";
725
- const hasOther = Boolean(other.trim());
726
- const supplied = values.length + (hasOther ? 1 : 0);
727
-
728
- // Other-selected-but-empty must win over generic "required" — otherwise the
729
- // user sees the wrong diagnosis next to a clearly selected control.
730
- if (question.kind !== "text" && draft.otherSelected && !hasOther) {
731
- errors[question.id] = messages.otherRequired;
732
- continue;
733
- }
734
-
735
- if (question.required && supplied === 0) {
736
- errors[question.id] = messages.required;
737
- continue;
738
- }
739
- if (question.kind !== "text") {
740
- const min = question.validation?.minSelections;
741
- const max = question.kind === "single_select" ? 1 : question.validation?.maxSelections;
742
- if (min != null && supplied < min) {
743
- errors[question.id] = messages.minSelections(min);
744
- continue;
745
- }
746
- if (max != null && supplied > max) {
747
- errors[question.id] = messages.maxSelections(max);
748
- continue;
749
- }
750
- }
751
- if (supplied > 0) {
752
- answers.push({
753
- questionId: question.id,
754
- values,
755
- ...(hasOther ? { other } : {}),
756
- });
757
- }
758
- }
759
- return { answers, errors };
760
- }
761
-
762
- function initialDrafts(questions: HumanInputQuestion[]): Record<string, HumanInputAnswerDraft> {
763
- return Object.fromEntries(questions.map((question) => [question.id, emptyDraft()]));
764
- }
765
-
766
- function emptyDraft(): HumanInputAnswerDraft {
767
- return { values: [], other: "", otherSelected: false };
768
- }
769
-
770
- function formatDeadline(value: string): string {
771
- const date = new Date(value);
772
- if (Number.isNaN(date.getTime())) return value;
773
- const ms = date.getTime() - Date.now();
774
- if (ms <= 0) return "deadline passed";
775
- const minutes = Math.round(ms / 60_000);
776
- if (minutes < 1) return "in under a minute";
777
- if (minutes < 60) return `in ${minutes}m`;
778
- const hours = Math.round(minutes / 60);
779
- if (hours < 48) return `in ${hours}h`;
780
- return date.toLocaleString();
781
- }