@kortix/ui 0.14.8 → 0.14.9

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 (528) hide show
  1. package/README.md +2 -2
  2. package/dist/_vendor/kortix-shared.js +63 -3
  3. package/dist/_vendor/shared/app-config.d.ts +175 -0
  4. package/dist/_vendor/shared/channel-message.d.ts +34 -5
  5. package/dist/_vendor/shared/index.d.ts +1 -0
  6. package/dist/_vendor/shared/space-slug.d.ts +37 -0
  7. package/dist/access/access/access-detail-shell.js +1 -1
  8. package/dist/access/access/principal-picker.d.ts +11 -0
  9. package/dist/access/access/principal-picker.js +3 -2
  10. package/dist/apps/app-preview-pool.d.ts +7 -2
  11. package/dist/apps/app-preview-pool.js +11 -5
  12. package/dist/apps/app-shared.d.ts +22 -15
  13. package/dist/apps/app-shared.js +37 -19
  14. package/dist/apps/index.d.ts +2 -2
  15. package/dist/apps/index.js +2 -2
  16. package/dist/artifacts/artifact-frame.d.ts +16 -0
  17. package/dist/artifacts/artifact-frame.js +51 -0
  18. package/dist/artifacts/artifact-session.d.ts +18 -0
  19. package/dist/artifacts/artifact-session.js +101 -0
  20. package/dist/artifacts/frame-policy.d.ts +30 -0
  21. package/dist/artifacts/frame-policy.js +61 -0
  22. package/dist/artifacts/index.d.ts +3 -0
  23. package/dist/artifacts/index.js +5 -0
  24. package/dist/browser/sandbox-browser-chrome.d.ts +4 -1
  25. package/dist/browser/sandbox-browser-chrome.js +2 -2
  26. package/dist/customize/agents/agent-grant-pages.d.ts +5 -1
  27. package/dist/customize/agents/agent-grant-pages.js +30 -4
  28. package/dist/customize/agents/agent-page.js +3 -1
  29. package/dist/customize/agents/agent-policy-sets.d.ts +43 -0
  30. package/dist/customize/agents/agent-policy-sets.js +72 -0
  31. package/dist/customize/agents/agent-triggers-section.js +2 -1
  32. package/dist/customize/connectors/add-mcp/add-mcp-server-dialog.d.ts +6 -1
  33. package/dist/customize/connectors/add-mcp/add-mcp-server-dialog.js +10 -4
  34. package/dist/customize/connectors/agent-access.d.ts +35 -0
  35. package/dist/customize/connectors/agent-access.js +77 -0
  36. package/dist/customize/connectors/catalog/browse-sections.d.ts +2 -29
  37. package/dist/customize/connectors/catalog/browse-sections.js +7 -74
  38. package/dist/customize/connectors/catalog/catalog-entry.d.ts +18 -37
  39. package/dist/customize/connectors/catalog/catalog-entry.js +28 -40
  40. package/dist/customize/connectors/catalog/connector-browse.d.ts +3 -32
  41. package/dist/customize/connectors/catalog/connector-browse.js +19 -50
  42. package/dist/customize/connectors/catalog/use-catalog.d.ts +20 -59
  43. package/dist/customize/connectors/catalog/use-catalog.js +48 -175
  44. package/dist/customize/connectors/connector-identity.d.ts +9 -11
  45. package/dist/customize/connectors/connector-identity.js +13 -42
  46. package/dist/customize/connectors/connector-moves-banner.d.ts +2 -1
  47. package/dist/customize/connectors/connector-moves-banner.js +4 -6
  48. package/dist/customize/connectors/connector-routes.d.ts +21 -9
  49. package/dist/customize/connectors/connector-routes.js +29 -20
  50. package/dist/customize/connectors/connectors-page.js +53 -82
  51. package/dist/customize/connectors/detail/app-page.js +226 -98
  52. package/dist/customize/connectors/detail/computer-app-page.d.ts +16 -0
  53. package/dist/customize/connectors/detail/computer-app-page.js +39 -0
  54. package/dist/customize/connectors/detail/connector-accounts.js +3 -1
  55. package/dist/customize/connectors/detail/connector-advanced-tools.d.ts +4 -1
  56. package/dist/customize/connectors/detail/connector-advanced-tools.js +2 -2
  57. package/dist/customize/connectors/detail/connector-agents.d.ts +14 -0
  58. package/dist/customize/connectors/detail/connector-agents.js +69 -0
  59. package/dist/customize/connectors/detail/connector-detail-tabs.js +2 -1
  60. package/dist/customize/connectors/detail/connector-move-row.d.ts +8 -5
  61. package/dist/customize/connectors/detail/connector-move-row.js +23 -14
  62. package/dist/customize/connectors/detail/connector-page.d.ts +4 -1
  63. package/dist/customize/connectors/detail/connector-page.js +14 -10
  64. package/dist/customize/connectors/detail/connector-policy-sets.d.ts +28 -0
  65. package/dist/customize/connectors/detail/connector-policy-sets.js +203 -0
  66. package/dist/customize/connectors/detail/connector-settings.d.ts +4 -1
  67. package/dist/customize/connectors/detail/connector-settings.js +7 -3
  68. package/dist/customize/connectors/detail/connector-status.d.ts +19 -6
  69. package/dist/customize/connectors/detail/connector-status.js +34 -10
  70. package/dist/customize/connectors/detail/connector-tabs.d.ts +4 -1
  71. package/dist/customize/connectors/detail/connector-tabs.js +8 -2
  72. package/dist/customize/connectors/detail/connector-tools.d.ts +3 -3
  73. package/dist/customize/connectors/detail/connector-tools.js +105 -48
  74. package/dist/customize/connectors/detail/email-inboxes.d.ts +43 -0
  75. package/dist/customize/connectors/detail/email-inboxes.js +184 -0
  76. package/dist/customize/connectors/detail/provider-info.d.ts +1 -1
  77. package/dist/customize/connectors/detail/provider-info.js +2 -2
  78. package/dist/customize/connectors/detail/status-badge.d.ts +1 -1
  79. package/dist/customize/connectors/detail/status-badge.js +4 -5
  80. package/dist/customize/connectors/detail/use-connector-detail.d.ts +6 -0
  81. package/dist/customize/connectors/detail/use-connector-detail.js +14 -4
  82. package/dist/customize/connectors/install/install-dialog.d.ts +23 -0
  83. package/dist/customize/connectors/install/install-dialog.js +40 -0
  84. package/dist/customize/connectors/install/install.d.ts +13 -2
  85. package/dist/customize/connectors/install/install.js +9 -4
  86. package/dist/customize/connectors/install/use-install.d.ts +19 -2
  87. package/dist/customize/connectors/install/use-install.js +65 -37
  88. package/dist/customize/connectors/install/way-kind.d.ts +5 -0
  89. package/dist/customize/connectors/install/way-kind.js +16 -0
  90. package/dist/customize/connectors/provider-label.d.ts +2 -1
  91. package/dist/customize/connectors/provider-label.js +13 -3
  92. package/dist/customize/connectors/tools/pattern-rule-draft.d.ts +4 -0
  93. package/dist/customize/connectors/tools/pattern-rule-draft.js +12 -3
  94. package/dist/customize/connectors/tools/policy-sets.d.ts +27 -0
  95. package/dist/customize/connectors/tools/policy-sets.js +41 -0
  96. package/dist/customize/connectors/tools/tool-groups.d.ts +32 -9
  97. package/dist/customize/connectors/tools/tool-groups.js +78 -16
  98. package/dist/customize/connectors/tools/tool-policy-control.d.ts +11 -10
  99. package/dist/customize/connectors/tools/tool-policy-control.js +15 -16
  100. package/dist/customize/connectors/tools/tool-policy-labels.d.ts +6 -5
  101. package/dist/customize/connectors/tools/tool-policy-labels.js +17 -16
  102. package/dist/customize/connectors/tools/tool-policy.d.ts +50 -4
  103. package/dist/customize/connectors/tools/tool-policy.js +74 -8
  104. package/dist/customize/connectors/use-agent-access.d.ts +85 -0
  105. package/dist/customize/connectors/use-agent-access.js +72 -0
  106. package/dist/customize/migrate-to-v2/index.d.ts +1 -2
  107. package/dist/customize/migrate-to-v2/index.js +1 -2
  108. package/dist/customize/migrate-to-v2/migration-prompt.d.ts +12 -25
  109. package/dist/customize/migrate-to-v2/migration-prompt.js +34 -236
  110. package/dist/customize/migrate-to-v2/upgrade-defs.d.ts +1 -1
  111. package/dist/customize/migrate-to-v2/upgrade-defs.js +7 -6
  112. package/dist/customize/migrate-to-v2/upgrade-view.js +7 -7
  113. package/dist/customize/migrate-to-v2/use-run-upgrade.d.ts +3 -3
  114. package/dist/customize/providers/provider-accordion.js +17 -2
  115. package/dist/customize/sections/component/channel-access-panel.d.ts +16 -0
  116. package/dist/customize/sections/component/channel-access-panel.js +146 -0
  117. package/dist/customize/sections/component/channel-connect-hero.d.ts +3 -2
  118. package/dist/customize/sections/component/channel-connect-hero.js +3 -2
  119. package/dist/customize/sections/component/channel-hero-frame.d.ts +31 -0
  120. package/dist/customize/sections/component/channel-hero-frame.js +40 -0
  121. package/dist/customize/sections/component/channel-mocks.d.ts +6 -0
  122. package/dist/customize/sections/component/channel-mocks.js +46 -0
  123. package/dist/customize/sections/component/channel-row.d.ts +13 -3
  124. package/dist/customize/sections/component/channel-row.js +10 -4
  125. package/dist/customize/sections/component/email-connect-form.d.ts +27 -0
  126. package/dist/customize/sections/component/email-connect-form.js +183 -0
  127. package/dist/customize/sections/component/slack-connect-card.d.ts +7 -0
  128. package/dist/customize/sections/component/slack-connect-card.js +2 -3
  129. package/dist/customize/sections/component/teams-connect-card.d.ts +7 -0
  130. package/dist/customize/sections/component/teams-connect-card.js +2 -3
  131. package/dist/customize/sections/component/telegram-channel-row.js +16 -25
  132. package/dist/customize/sections/connectors-view.d.ts +1 -15
  133. package/dist/customize/sections/connectors-view.js +81 -314
  134. package/dist/customize/sections/view/agent-editor-catalog.js +5 -0
  135. package/dist/customize/sections/view/channels-view.d.ts +5 -1
  136. package/dist/customize/sections/view/channels-view.js +61 -75
  137. package/dist/customize/sections/view/gateway/gateway-overview.js +10 -2
  138. package/dist/customize/settings/tabs/experimental-tab.js +35 -16
  139. package/dist/customize/shared/catalog/catalog-empty-state.d.ts +1 -12
  140. package/dist/customize/shared/catalog/catalog-empty-state.js +3 -3
  141. package/dist/customize/shared/channels-switch-dialog.d.ts +18 -0
  142. package/dist/customize/shared/channels-switch-dialog.js +30 -0
  143. package/dist/customize/shared/feature-gate-screen.js +27 -9
  144. package/dist/customize/shared/use-customize-prefetch.d.ts +2 -3
  145. package/dist/customize/shared/use-customize-prefetch.js +9 -27
  146. package/dist/customize/triggers/schedule/post-to-field.d.ts +18 -0
  147. package/dist/customize/triggers/schedule/post-to-field.js +49 -0
  148. package/dist/customize/triggers/schedule/schedule-copy.d.ts +10 -6
  149. package/dist/customize/triggers/schedule/schedule-copy.js +42 -11
  150. package/dist/customize/triggers/schedule/schedule-detail-sheet.js +2 -1
  151. package/dist/customize/triggers/schedule/trigger-composer-logic.d.ts +22 -0
  152. package/dist/customize/triggers/schedule/trigger-composer-logic.js +25 -0
  153. package/dist/customize/triggers/schedule/trigger-composer.d.ts +5 -0
  154. package/dist/customize/triggers/schedule/trigger-composer.js +23 -14
  155. package/dist/customize/triggers/schedule/trigger-edit-logic.js +3 -0
  156. package/dist/customize/triggers/schedule/trigger-filter.js +1 -1
  157. package/dist/customize/triggers/schedule/trigger-runs-logic.d.ts +2 -2
  158. package/dist/customize/triggers/schedule/trigger-runs-panel.js +1 -0
  159. package/dist/customize/triggers/schedule/trigger-toast.js +2 -1
  160. package/dist/customize/triggers/schedule-view.js +5 -2
  161. package/dist/files/index.d.ts +1 -0
  162. package/dist/files/index.js +1 -0
  163. package/dist/files/project/change-request-recovery.d.ts +1 -26
  164. package/dist/files/project/change-request-recovery.js +1 -59
  165. package/dist/files/project/components/change-request-detail-dialog.js +13 -3
  166. package/dist/files/project/components/drive-explorer.js +15 -15
  167. package/dist/files/project/components/drive-toolbar.d.ts +16 -2
  168. package/dist/files/project/components/drive-toolbar.js +14 -5
  169. package/dist/files/project/hooks/use-change-request-recovery.js +3 -19
  170. package/dist/files/project/hooks/use-change-requests.d.ts +1 -0
  171. package/dist/files/project/hooks/use-change-requests.js +11 -2
  172. package/dist/files/renderers/image-frame.d.ts +46 -0
  173. package/dist/files/renderers/image-frame.js +59 -0
  174. package/dist/files/renderers/image-renderer.d.ts +11 -1
  175. package/dist/files/renderers/image-renderer.js +13 -3
  176. package/dist/files/renderers/pdf/pdf-clipboard.d.ts +2 -0
  177. package/dist/files/renderers/pdf/pdf-clipboard.js +21 -0
  178. package/dist/files/renderers/pdf/pdf-viewer.js +4 -2
  179. package/dist/files/renderers/show-content-renderer.d.ts +9 -1
  180. package/dist/files/renderers/show-content-renderer.js +56 -14
  181. package/dist/files/runtime/file-source.js +2 -0
  182. package/dist/files/runtime/hooks/use-binary-blob.d.ts +10 -1
  183. package/dist/files/runtime/hooks/use-binary-blob.js +10 -4
  184. package/dist/files/runtime/hooks/use-shared-image.d.ts +41 -0
  185. package/dist/files/runtime/hooks/use-shared-image.js +177 -0
  186. package/dist/files/viewer/file-content-renderer.d.ts +22 -1
  187. package/dist/files/viewer/file-content-renderer.js +50 -7
  188. package/dist/files/viewer/file-header.d.ts +7 -3
  189. package/dist/files/viewer/file-header.js +20 -11
  190. package/dist/files/viewer/file-preview-modal.d.ts +1 -1
  191. package/dist/files/viewer/file-preview-modal.js +10 -22
  192. package/dist/files/viewer/file-source.d.ts +13 -0
  193. package/dist/files/viewer/use-file-content-state.d.ts +2 -0
  194. package/dist/files/viewer/use-file-content-state.js +28 -10
  195. package/dist/files/viewer/viewer-actions.d.ts +3 -1
  196. package/dist/files/viewer/viewer-actions.js +2 -2
  197. package/dist/hooks/use-media-query.d.ts +1 -0
  198. package/dist/hooks/use-mobile.d.ts +5 -0
  199. package/dist/hooks/use-mobile.js +8 -0
  200. package/dist/i18n/en.d.ts +873 -85
  201. package/dist/i18n/en.js +888 -100
  202. package/dist/i18n/ui-catalog/localize-ui-catalog.js +4 -0
  203. package/dist/i18n/ui-catalog/remaining-ui-translation-keys.generated.js +15 -3
  204. package/dist/index.d.ts +2 -2
  205. package/dist/index.js +2 -2
  206. package/dist/internal/account-hub/account-settings-sidebar.js +1 -1
  207. package/dist/internal/account-hub/hub-sheet.d.ts +9 -1
  208. package/dist/internal/account-hub/hub-sheet.js +21 -5
  209. package/dist/internal/account-hub/sections.d.ts +1 -1
  210. package/dist/internal/account-hub/sections.js +2 -1
  211. package/dist/internal/auth/auth-card-shell.js +3 -3
  212. package/dist/internal/components/agent-mark.js +5 -2
  213. package/dist/internal/connector-logo/connector-logo-source.d.ts +63 -0
  214. package/dist/internal/connector-logo/connector-logo-source.js +48 -0
  215. package/dist/internal/connector-logo/connector-logo.d.ts +39 -0
  216. package/dist/internal/connector-logo/connector-logo.js +56 -0
  217. package/dist/internal/connector-logo/connector-mark-files.d.ts +11 -0
  218. package/dist/internal/connector-logo/connector-mark-files.js +35 -0
  219. package/dist/internal/files/file-read-retry.d.ts +13 -0
  220. package/dist/internal/files/file-read-retry.js +23 -3
  221. package/dist/internal/files/session-drive-files.d.ts +5 -1
  222. package/dist/internal/files/session-drive-files.js +7 -2
  223. package/dist/internal/hooks/channels/use-channels-installations.d.ts +32 -5
  224. package/dist/internal/hooks/channels/use-channels-installations.js +55 -7
  225. package/dist/internal/hooks/channels/use-email-inboxes.d.ts +19 -0
  226. package/dist/internal/hooks/channels/use-email-inboxes.js +48 -0
  227. package/dist/internal/hooks/connectors/use-add-account.js +1 -1
  228. package/dist/internal/hooks/index.d.ts +1 -1
  229. package/dist/internal/hooks/index.js +1 -1
  230. package/dist/internal/hooks/projects/use-new-project-session.d.ts +9 -0
  231. package/dist/internal/hooks/projects/use-new-project-session.js +28 -12
  232. package/dist/internal/hooks/use-auto-scroll.d.ts +8 -1
  233. package/dist/internal/hooks/use-auto-scroll.js +4 -4
  234. package/dist/internal/icons/telegram.d.ts +5 -0
  235. package/dist/internal/icons/telegram.js +6 -1
  236. package/dist/internal/layout/nav-hover-card.d.ts +35 -0
  237. package/dist/internal/layout/nav-hover-card.js +84 -0
  238. package/dist/internal/layout/project-nav-row.d.ts +3 -1
  239. package/dist/internal/layout/project-nav-row.js +3 -2
  240. package/dist/internal/layout/project-page-header.d.ts +4 -2
  241. package/dist/internal/layout/project-page-header.js +4 -3
  242. package/dist/internal/layout/project-settings-nav.js +59 -2
  243. package/dist/internal/lib/browser-error-noise.d.ts +1 -1
  244. package/dist/internal/lib/browser-error-noise.js +1 -1
  245. package/dist/internal/lib/browser-noise/rules/injected-scripts.d.ts +7 -0
  246. package/dist/internal/lib/browser-noise/rules/injected-scripts.js +15 -0
  247. package/dist/internal/lib/manifest-version.d.ts +1 -1
  248. package/dist/internal/lib/manifest-version.js +2 -2
  249. package/dist/internal/lib/memory-href.d.ts +16 -0
  250. package/dist/internal/lib/memory-href.js +46 -0
  251. package/dist/internal/lib/use-project-feature-flags.js +9 -9
  252. package/dist/internal/lib/utils/heic-convert.d.ts +1 -1
  253. package/dist/internal/lib/utils/heic-convert.js +3 -4
  254. package/dist/internal/lib/web-notifications.d.ts +20 -0
  255. package/dist/internal/lib/web-notifications.js +48 -4
  256. package/dist/internal/notifications/notification-bell.d.ts +4 -1
  257. package/dist/internal/notifications/notification-bell.js +2 -2
  258. package/dist/internal/selection/selection-bar.d.ts +2 -1
  259. package/dist/internal/selection/selection-bar.js +1 -1
  260. package/dist/internal/stores/file-preview-store.d.ts +29 -2
  261. package/dist/internal/stores/file-preview-store.js +19 -1
  262. package/dist/internal/stores/kortix-computer-store.js +3 -0
  263. package/dist/internal/stores/sidebar-nav-store.d.ts +1 -1
  264. package/dist/internal/stores/sidebar-nav-store.js +3 -1
  265. package/dist/lib/routes.d.ts +13 -1
  266. package/dist/lib/routes.js +13 -0
  267. package/dist/markdown/index.d.ts +2 -1
  268. package/dist/markdown/index.js +2 -1
  269. package/dist/markdown/setup-links/approval-decision.d.ts +1 -0
  270. package/dist/markdown/setup-links/approval-decision.js +6 -2
  271. package/dist/markdown/setup-links/connector-handshake.d.ts +3 -1
  272. package/dist/markdown/setup-links/connector-handshake.js +12 -10
  273. package/dist/markdown/setup-links/secret-intake-form.d.ts +0 -10
  274. package/dist/markdown/setup-links/secret-intake-form.js +1 -1
  275. package/dist/markdown/setup-links/show-connect-hero.d.ts +28 -0
  276. package/dist/markdown/setup-links/show-connect-hero.js +91 -0
  277. package/dist/markdown/unified-markdown.js +5 -5
  278. package/dist/primitives/badge.d.ts +1 -1
  279. package/dist/primitives/badge.js +2 -0
  280. package/dist/primitives/disclosure.js +14 -2
  281. package/dist/primitives/empty-art.d.ts +12 -0
  282. package/dist/primitives/empty-art.js +11 -0
  283. package/dist/primitives/mermaid-renderer.d.ts +2 -0
  284. package/dist/primitives/mermaid-renderer.js +21 -15
  285. package/dist/primitives/resizable.js +6 -1
  286. package/dist/primitives/resize-seam.d.ts +11 -0
  287. package/dist/primitives/resize-seam.js +12 -0
  288. package/dist/primitives/sidebar-panel.js +4 -7
  289. package/dist/primitives/tabs.d.ts +14 -1
  290. package/dist/primitives/tabs.js +1 -1
  291. package/dist/providers/ui-provider.d.ts +9 -0
  292. package/dist/session/composer/ComposerAboveCard.d.ts +1 -1
  293. package/dist/session/composer/ComposerAboveCard.js +2 -2
  294. package/dist/session/composer/ComposerCard.d.ts +1 -1
  295. package/dist/session/composer/ComposerCard.js +3 -3
  296. package/dist/session/composer/agent-selector.d.ts +13 -1
  297. package/dist/session/composer/agent-selector.js +25 -5
  298. package/dist/session/composer/composer-agent-access.d.ts +15 -0
  299. package/dist/session/composer/composer-agent-access.js +27 -0
  300. package/dist/session/composer/composer-chat-input.d.ts +8 -2
  301. package/dist/session/composer/composer-chat-input.js +8 -6
  302. package/dist/session/composer/composer-logic.d.ts +16 -0
  303. package/dist/session/composer/composer-logic.js +12 -0
  304. package/dist/session/composer/composer-underbar.d.ts +3 -1
  305. package/dist/session/composer/composer-underbar.js +4 -3
  306. package/dist/session/composer/composer.d.ts +15 -1
  307. package/dist/session/composer/composer.js +19 -1
  308. package/dist/session/composer/draft/composer-draft.d.ts +6 -2
  309. package/dist/session/composer/draft/composer-draft.js +5 -1
  310. package/dist/session/composer/reasoning-effort-selector.js +1 -1
  311. package/dist/session/models/chatgpt-connection-button.d.ts +11 -0
  312. package/dist/session/models/chatgpt-connection-button.js +54 -0
  313. package/dist/session/models/model-selector.js +5 -2
  314. package/dist/session/models/use-model-connection-gate.d.ts +5 -5
  315. package/dist/session/models/use-model-connection-gate.js +5 -5
  316. package/dist/session/outcomes/jump-to-outcome.d.ts +10 -0
  317. package/dist/session/outcomes/jump-to-outcome.js +11 -0
  318. package/dist/session/outcomes/session-outcomes-bridge.d.ts +14 -0
  319. package/dist/session/outcomes/session-outcomes-bridge.js +12 -0
  320. package/dist/session/outcomes/session-outcomes-provider.d.ts +3 -1
  321. package/dist/session/outcomes/session-outcomes-provider.js +33 -3
  322. package/dist/session/panel/easy/app-preview.d.ts +10 -0
  323. package/dist/session/panel/easy/app-preview.js +31 -12
  324. package/dist/session/panel/easy/change-requests-card.d.ts +7 -0
  325. package/dist/session/panel/easy/change-requests-card.js +17 -0
  326. package/dist/session/panel/easy/easy-panel-logic.js +7 -1
  327. package/dist/session/panel/easy/easy-panel.js +5 -2
  328. package/dist/session/panel/easy/file-preview.js +1 -1
  329. package/dist/session/panel/easy/outputs-card.d.ts +2 -1
  330. package/dist/session/panel/easy/outputs-card.js +3 -2
  331. package/dist/session/panel/mobile-tool-drawer.js +7 -1
  332. package/dist/session/panel/session-audit-panel.js +9 -2
  333. package/dist/session/panel/session-detail-panel.js +9 -3
  334. package/dist/session/panel/session-files-explorer.d.ts +9 -0
  335. package/dist/session/panel/session-files-explorer.js +12 -3
  336. package/dist/session/panel/session-panel-provider.d.ts +15 -1
  337. package/dist/session/panel/session-panel-provider.js +32 -7
  338. package/dist/session/panel/shared/derive-panels.d.ts +8 -1
  339. package/dist/session/panel/shared/derive-panels.js +12 -2
  340. package/dist/session/panel/shared/output-priority.js +2 -0
  341. package/dist/session/participants/session-participants.d.ts +5 -1
  342. package/dist/session/participants/session-participants.js +9 -2
  343. package/dist/session/prompts/approval-request.d.ts +5 -0
  344. package/dist/session/prompts/approval-request.js +7 -1
  345. package/dist/session/prompts/session-approval-review.d.ts +9 -0
  346. package/dist/session/prompts/session-approval-review.js +18 -0
  347. package/dist/session/status/session-error-banner.js +2 -49
  348. package/dist/session/status/session-starting-loader.d.ts +14 -2
  349. package/dist/session/status/session-starting-loader.js +16 -4
  350. package/dist/session/thread/after-first-prompt.d.ts +7 -0
  351. package/dist/session/thread/after-first-prompt.js +8 -0
  352. package/dist/session/thread/detect-command.d.ts +12 -0
  353. package/dist/session/thread/detect-command.js +20 -0
  354. package/dist/session/thread/session-chat.d.ts +3 -1
  355. package/dist/session/thread/session-chat.js +377 -252
  356. package/dist/session/thread/session-thread.d.ts +3 -1
  357. package/dist/session/thread/session-thread.js +9 -2
  358. package/dist/session/thread/thread-boot-rows.d.ts +36 -0
  359. package/dist/session/thread/thread-boot-rows.js +89 -0
  360. package/dist/session/thread/transcript-rows.d.ts +31 -0
  361. package/dist/session/thread/transcript-rows.js +3 -0
  362. package/dist/session/thread/transcript.d.ts +0 -9
  363. package/dist/session/thread/transcript.js +104 -19
  364. package/dist/session/tool/shared/infrastructure-contexts.d.ts +28 -0
  365. package/dist/session/tool/shared/infrastructure-contexts.js +31 -3
  366. package/dist/session/tool/tool-part-renderer.d.ts +5 -4
  367. package/dist/session/tool/tool-part-renderer.js +8 -3
  368. package/dist/session/tool/tools/bash-tool.js +7 -6
  369. package/dist/session/tool/tools/channel-send-card.d.ts +1 -2
  370. package/dist/session/tool/tools/channel-send.d.ts +2 -1
  371. package/dist/session/tool/tools/codemode-tool.js +1 -1
  372. package/dist/session/tool/tools/connector-tools.js +1 -1
  373. package/dist/session/tool/tools/image-gen-tool.d.ts +1 -1
  374. package/dist/session/tool/tools/image-gen-tool.js +240 -53
  375. package/dist/session/tool/tools/show-tool.js +19 -8
  376. package/dist/session/turn/channel-brand.d.ts +8 -3
  377. package/dist/session/turn/channel-brand.js +20 -4
  378. package/dist/session/turn/message-author.d.ts +8 -0
  379. package/dist/session/turn/message-author.js +24 -0
  380. package/dist/session/turn/message-row.d.ts +52 -0
  381. package/dist/session/turn/message-row.js +44 -0
  382. package/dist/session/turn/plan-anchor.d.ts +1 -1
  383. package/dist/session/turn/plan-anchor.js +1 -1
  384. package/dist/session/turn/user-message.d.ts +7 -1
  385. package/dist/session/turn/user-message.js +21 -7
  386. package/dist/styles.css +1 -1
  387. package/dist/workspace/home/access-requests-bell.d.ts +9 -2
  388. package/dist/workspace/home/access-requests-bell.js +20 -6
  389. package/dist/workspace/home/first-chat.d.ts +8 -21
  390. package/dist/workspace/home/first-chat.js +22 -72
  391. package/dist/workspace/index.d.ts +6 -0
  392. package/dist/workspace/index.js +6 -0
  393. package/dist/workspace/layout/project-home.d.ts +14 -2
  394. package/dist/workspace/layout/project-home.js +60 -21
  395. package/dist/workspace/layout/use-project-home-send.d.ts +9 -1
  396. package/dist/workspace/layout/use-project-home-send.js +82 -3
  397. package/dist/workspace/memory/body-doc.d.ts +17 -0
  398. package/dist/workspace/memory/body-doc.js +208 -0
  399. package/dist/workspace/memory/body-extensions.d.ts +38 -0
  400. package/dist/workspace/memory/body-extensions.js +103 -0
  401. package/dist/workspace/memory/company-memory-page.d.ts +8 -0
  402. package/dist/workspace/memory/company-memory-page.js +16 -0
  403. package/dist/workspace/memory/memory-all.d.ts +20 -0
  404. package/dist/workspace/memory/memory-all.js +27 -0
  405. package/dist/workspace/memory/memory-body.d.ts +19 -0
  406. package/dist/workspace/memory/memory-body.js +139 -0
  407. package/dist/workspace/memory/memory-empty.d.ts +13 -0
  408. package/dist/workspace/memory/memory-empty.js +28 -0
  409. package/dist/workspace/memory/memory-history.d.ts +27 -0
  410. package/dist/workspace/memory/memory-history.js +108 -0
  411. package/dist/workspace/memory/memory-labels.d.ts +16 -0
  412. package/dist/workspace/memory/memory-labels.js +47 -0
  413. package/dist/workspace/memory/memory-page-list.d.ts +34 -0
  414. package/dist/workspace/memory/memory-page-list.js +156 -0
  415. package/dist/workspace/memory/memory-reader.d.ts +58 -0
  416. package/dist/workspace/memory/memory-reader.js +123 -0
  417. package/dist/workspace/memory/memory-view.d.ts +21 -0
  418. package/dist/workspace/memory/memory-view.js +124 -0
  419. package/dist/workspace/memory/remember-popover.d.ts +19 -0
  420. package/dist/workspace/memory/remember-popover.js +61 -0
  421. package/dist/workspace/memory/remember-this.d.ts +12 -0
  422. package/dist/workspace/memory/remember-this.js +89 -0
  423. package/dist/workspace/memory/source-mark.d.ts +18 -0
  424. package/dist/workspace/memory/source-mark.js +79 -0
  425. package/dist/workspace/memory/used-memory-chip.d.ts +14 -0
  426. package/dist/workspace/memory/used-memory-chip.js +61 -0
  427. package/dist/workspace/new/advanced-fields.d.ts +2 -1
  428. package/dist/workspace/new/advanced-fields.js +2 -2
  429. package/dist/workspace/new/source-param.d.ts +1 -1
  430. package/dist/workspace/new/source-param.js +3 -1
  431. package/dist/workspace/new/use-create-workspace.d.ts +8 -10
  432. package/dist/workspace/new/use-create-workspace.js +3 -3
  433. package/dist/workspace/projects/onboarding/app-logo.d.ts +7 -2
  434. package/dist/workspace/projects/onboarding/app-logo.js +6 -13
  435. package/dist/workspace/projects/policies-panel.js +5 -3
  436. package/dist/workspace/review/review-actions.d.ts +4 -2
  437. package/dist/workspace/review/review-actions.js +8 -2
  438. package/dist/workspace/review/review-center.js +11 -7
  439. package/dist/workspace/review/review-detail.d.ts +10 -0
  440. package/dist/workspace/review/review-detail.js +101 -13
  441. package/dist/workspace/saved-session-skeleton.d.ts +2 -2
  442. package/dist/workspace/saved-session-skeleton.js +3 -3
  443. package/dist/workspace/session-workspace.js +15 -13
  444. package/dist/workspace/sessions/project-sessions-view.js +3 -2
  445. package/dist/workspace/sessions/sessions-toolbar.d.ts +3 -1
  446. package/dist/workspace/sessions/sessions-toolbar.js +2 -2
  447. package/dist/workspace/sidebar/footer/project-apps-nav.d.ts +5 -0
  448. package/dist/workspace/sidebar/footer/project-apps-nav.js +41 -2
  449. package/dist/workspace/sidebar/footer/project-artifacts-nav.d.ts +6 -0
  450. package/dist/workspace/sidebar/footer/project-artifacts-nav.js +22 -0
  451. package/dist/workspace/sidebar/footer/project-manifest-upgrade-alert.js +13 -13
  452. package/dist/workspace/sidebar/footer/project-memory-nav.d.ts +7 -0
  453. package/dist/workspace/sidebar/footer/project-memory-nav.js +19 -0
  454. package/dist/workspace/sidebar/nav-row-meta.js +14 -2
  455. package/dist/workspace/sidebar/project-nav-items.js +3 -0
  456. package/dist/workspace/sidebar/project-session-list.js +68 -56
  457. package/dist/workspace/sidebar/project-sidebar.js +9 -2
  458. package/dist/workspace/sidebar/project-spaces-nav.d.ts +8 -0
  459. package/dist/workspace/sidebar/project-spaces-nav.js +69 -0
  460. package/dist/workspace/sidebar/session-group-order.d.ts +9 -0
  461. package/dist/workspace/sidebar/session-group-order.js +25 -0
  462. package/dist/workspace/sidebar/session-group-sections.d.ts +62 -0
  463. package/dist/workspace/sidebar/session-group-sections.js +267 -0
  464. package/dist/workspace/sidebar/session-list-chrome.d.ts +28 -0
  465. package/dist/workspace/sidebar/session-list-chrome.js +50 -0
  466. package/dist/workspace/spaces/channel-glyph.d.ts +5 -0
  467. package/dist/workspace/spaces/channel-glyph.js +6 -0
  468. package/dist/workspace/spaces/channel-setup.d.ts +16 -0
  469. package/dist/workspace/spaces/channel-setup.js +105 -0
  470. package/dist/workspace/spaces/channels-onboarding.d.ts +13 -0
  471. package/dist/workspace/spaces/channels-onboarding.js +37 -0
  472. package/dist/workspace/spaces/create-channel-dialog.d.ts +16 -0
  473. package/dist/workspace/spaces/create-channel-dialog.js +158 -0
  474. package/dist/workspace/spaces/private-channels-not-in.d.ts +9 -0
  475. package/dist/workspace/spaces/private-channels-not-in.js +69 -0
  476. package/dist/workspace/spaces/space-agents.d.ts +10 -0
  477. package/dist/workspace/spaces/space-agents.js +10 -0
  478. package/dist/workspace/spaces/space-details-dialog.d.ts +20 -0
  479. package/dist/workspace/spaces/space-details-dialog.js +176 -0
  480. package/dist/workspace/spaces/space-link-label.d.ts +49 -0
  481. package/dist/workspace/spaces/space-link-label.js +73 -0
  482. package/dist/workspace/spaces/space-links.d.ts +19 -0
  483. package/dist/workspace/spaces/space-links.js +230 -0
  484. package/dist/workspace/spaces/space-members.d.ts +46 -0
  485. package/dist/workspace/spaces/space-members.js +182 -0
  486. package/dist/workspace/spaces/space-roster.d.ts +15 -0
  487. package/dist/workspace/spaces/space-roster.js +44 -0
  488. package/dist/workspace/spaces/space-threads-tab.d.ts +56 -0
  489. package/dist/workspace/spaces/space-threads-tab.js +156 -0
  490. package/dist/workspace/spaces/space-timeline-view.d.ts +254 -0
  491. package/dist/workspace/spaces/space-timeline-view.js +235 -0
  492. package/dist/workspace/spaces/space-timeline.d.ts +106 -0
  493. package/dist/workspace/spaces/space-timeline.js +183 -0
  494. package/dist/workspace/spaces/space-triggers.d.ts +13 -0
  495. package/dist/workspace/spaces/space-triggers.js +78 -0
  496. package/dist/workspace/spaces/space-view.d.ts +37 -0
  497. package/dist/workspace/spaces/space-view.js +436 -0
  498. package/package.json +27 -36
  499. package/skills/kortix-ui/SKILL.md +3 -3
  500. package/skills/kortix-ui/references/custom-dashboard.md +3 -3
  501. package/skills/kortix-ui/references/modules.md +28 -4
  502. package/skills/kortix-ui/references/theming.md +1 -1
  503. package/dist/customize/connectors/catalog/merge-search.d.ts +0 -10
  504. package/dist/customize/connectors/catalog/merge-search.js +0 -26
  505. package/dist/customize/connectors/detail/find-easy-connect-app.d.ts +0 -29
  506. package/dist/customize/connectors/detail/find-easy-connect-app.js +0 -22
  507. package/dist/customize/migrate-to-v2/use-migrate-to-v2.d.ts +0 -9
  508. package/dist/customize/migrate-to-v2/use-migrate-to-v2.js +0 -24
  509. package/dist/customize/sections/connector-connection-header.d.ts +0 -36
  510. package/dist/customize/sections/connector-connection-header.js +0 -33
  511. package/dist/customize/sections/connector-connection-modal.d.ts +0 -34
  512. package/dist/customize/sections/connector-connection-modal.js +0 -72
  513. package/dist/customize/sections/discover-catalogue-card.d.ts +0 -19
  514. package/dist/customize/sections/discover-catalogue-card.js +0 -26
  515. package/dist/customize/sections/discover-catalogue-detail.d.ts +0 -15
  516. package/dist/customize/sections/discover-catalogue-detail.js +0 -24
  517. package/dist/customize/sections/discover-catalogue.d.ts +0 -17
  518. package/dist/customize/sections/discover-catalogue.js +0 -132
  519. package/dist/customize/sections/llm-provider/provider-access-menu.d.ts +0 -10
  520. package/dist/customize/sections/llm-provider/provider-access-menu.js +0 -23
  521. package/dist/files/project/components/drive-empty-art.d.ts +0 -2
  522. package/dist/files/project/components/drive-empty-art.js +0 -5
  523. package/dist/internal/hooks/use-media-query.d.ts +0 -2
  524. package/dist/internal/share/public-share-link-button.d.ts +0 -14
  525. package/dist/internal/share/public-share-link-button.js +0 -17
  526. package/dist/markdown/setup-links/app-credentials-form.d.ts +0 -12
  527. package/dist/markdown/setup-links/app-credentials-form.js +0 -115
  528. /package/dist/{internal/hooks → hooks}/use-media-query.js +0 -0
@@ -14,7 +14,7 @@ import { TokenProgress } from './token-progress.js';
14
14
  const NO_AGENT_SELECT = () => { };
15
15
  /** Stable identity so the empty roster doesn't remount the picker per render. */
16
16
  const EMPTY_AGENTS = [];
17
- export function ComposerUnderbar({ onAttachClick, agents, selectedAgent, agentMenuOpen, onAgentMenuOpenChange, onAgentChange, noAccessibleAgents = false, messages, models, selectedModel, onContextClick, variant = 'row', toolbarSlot, }) {
17
+ export function ComposerUnderbar({ onAttachClick, agents, selectedAgent, agentMenuOpen, onAgentMenuOpenChange, onAgentChange, noAccessibleAgents = false, messages, models, selectedModel, onContextClick, variant = 'row', agentPickerCompact = false, toolbarSlot, }) {
18
18
  const t = useTranslations('threads');
19
19
  const { contextMeterEnabled } = useUiHostConfig();
20
20
  /*
@@ -50,9 +50,10 @@ export function ComposerUnderbar({ onAttachClick, agents, selectedAgent, agentMe
50
50
  // buttons stayed 32px on touch while the identical controls inside
51
51
  // `.kortix-composer-toolbar` were 40px.
52
52
  _jsxs("div", { className: inline
53
- ? 'kortix-composer-underbar flex min-w-0 items-center gap-1'
53
+ ? // `shrink-0`: the model name truncates first (`ModelSelector`), never the agent.
54
+ 'kortix-composer-underbar flex shrink-0 items-center gap-1'
54
55
  : 'kortix-composer-underbar flex items-center justify-between gap-2 px-px pt-1.5 pb-2', children: [_jsxs("div", { className: "flex min-w-0 items-center gap-1", children: [_jsx(Hint, { side: "top", label: t('attachFiles'), children: _jsx(Button, { type: "button", variant: "ghost", size: "icon-base", onClick: onAttachClick, "aria-label": t('attachFiles'),
55
56
  // `hit-area-3` — the ≈29px ghost chip clears the 44px mobile tap
56
57
  // floor only with the shared pseudo-element extension.
57
- className: "text-muted-foreground hit-area-3 rounded-lg", children: _jsx(Paperclip, { className: "size-4 shrink-0" }) }) }), _jsx(AgentSelector, { agents: noAccessibleAgents ? EMPTY_AGENTS : agents, selectedAgent: selectedAgent, open: agentMenuOpen, onOpenChange: onAgentMenuOpenChange, onSelect: onAgentChange ?? NO_AGENT_SELECT, triggerLabelClassName: "max-w-[7rem]", unavailableHint: noAccessibleAgents ? NO_AGENT_ACCESS_MESSAGE : undefined })] }), _jsxs("div", { className: "flex items-center gap-1", children: [(inline && !messages) || !contextMeterEnabled ? null : (_jsx(TokenProgress, { messages: messages, models: models, selectedModel: selectedModel, onContextClick: onContextClick })), toolbarSlot] })] }));
58
+ className: "text-muted-foreground hit-area-3 rounded-lg", children: _jsx(Paperclip, { className: "size-4 shrink-0" }) }) }), _jsx(AgentSelector, { compact: agentPickerCompact, agents: noAccessibleAgents ? EMPTY_AGENTS : agents, selectedAgent: selectedAgent, open: agentMenuOpen, onOpenChange: onAgentMenuOpenChange, onSelect: onAgentChange ?? NO_AGENT_SELECT, triggerLabelClassName: "max-w-[7rem]", unavailableHint: noAccessibleAgents ? NO_AGENT_ACCESS_MESSAGE : undefined })] }), _jsxs("div", { className: "flex items-center gap-1", children: [(inline && !messages) || !contextMeterEnabled ? null : (_jsx(TokenProgress, { messages: messages, models: models, selectedModel: selectedModel, onContextClick: onContextClick })), toolbarSlot] })] }));
58
59
  }
@@ -153,6 +153,11 @@ export interface SessionChatInputProps {
153
153
  * a spinner with no explanation, which was indistinguishable from broken.
154
154
  */
155
155
  notice?: string | null;
156
+ /**
157
+ * The notice reports a sleeping computer: a moon, not a spinner. Default:
158
+ * `notice` is `SESSION_NOTICE.idle`. A host that rewords the notice says it.
159
+ */
160
+ noticeAsleep?: boolean;
156
161
  /**
157
162
  * Renders a "Retry" action inline in the notice bar when set. Wired to
158
163
  * `requestRuntimeReconnect()` for a confirmed-unreachable runtime, or a
@@ -190,8 +195,11 @@ export interface SessionChatInputProps {
190
195
  * Enter. For one-click starters (the first chat's "Update memory"): the
191
196
  * send still carries the composer's agent and model and still hits every
192
197
  * refusal (no agent, no model, blocked images) a typed message would.
198
+ *
199
+ * `'when-ready'` holds the text until a send is possible, then submits once:
200
+ * the onboarding chat's "Onboard me" waits for a model to be connected.
193
201
  */
194
- submit?: boolean;
202
+ submit?: boolean | 'when-ready';
195
203
  } | null;
196
204
  /**
197
205
  * Called with `prefill.id` the moment that prefill has actually landed in the
@@ -240,6 +248,12 @@ export interface SessionChatInputProps {
240
248
  * reads as a detached strip, so there the controls belong on the one bar.
241
249
  */
242
250
  underbarPlacement?: 'below' | 'inline';
251
+ /**
252
+ * The agent picker shows the agent's tile alone, its name in the tooltip
253
+ * and the menu. A narrow inline toolbar (a channel's thread panel) gives
254
+ * the model name the width instead.
255
+ */
256
+ agentPickerCompact?: boolean;
243
257
  /**
244
258
  * Where the `/` menu docks relative to the card. `'above'` (default) keeps
245
259
  * it in flow above the composer — on the session page the card sits at the
@@ -25,7 +25,7 @@ import { ComposerCard } from './ComposerCard.js';
25
25
  import { handleBillingError } from '../../internal/lib/error-handler.js';
26
26
  import { attachedFileUploadId, attachmentsBlockSend, captureAttachmentSubmission, dispatchLatched, planAttachmentReplacement, refusedFilesToast, runComposerSend, heldTraySizes, splitComposerFiles, stageComposerFiles, takeNewBillingRefusals, } from './attachment-submission.js';
27
27
  import { draftWillRunCommand, planCommandAttachments, planUnresolvedCommandChip, readCommandChipLabel, } from './command-attachments.js';
28
- import { appendComposerQuote, classifyPaste, isUndoKey, popPasteUndo, extractReplyQuotes, nextPastedTextFileName, planDraftSubmission, planFailedSendRecovery, planPrefillMerge, planQuoteRequests, removeComposerQuote, resolveEditorPlaceholder, restoreComposerQuotes, shouldApplyPrefill, shouldSubmitPrefill, textToDocument, } from './composer-logic.js';
28
+ import { appendComposerQuote, classifyPaste, isUndoKey, popPasteUndo, extractReplyQuotes, nextPastedTextFileName, planDraftSubmission, planFailedSendRecovery, planPrefillMerge, planQuoteRequests, removeComposerQuote, resolveEditorPlaceholder, restoreComposerQuotes, shouldApplyPrefill, shouldSubmitPrefill, shouldSubmitWhenReady, textToDocument, } from './composer-logic.js';
29
29
  import { getContextUsage } from './context-ring.js';
30
30
  import { useComposerFocus } from './hooks/use-composer-focus.js';
31
31
  import { useMenuRevalidation } from './hooks/use-file-search.js';
@@ -722,6 +722,8 @@ function ComposerImpl(props) {
722
722
  // through this ref, bound in an effect right after that declaration.
723
723
  const handleSubmitRef = useRef(() => undefined);
724
724
  const submittedPrefillIdRef = useRef(null);
725
+ // The prefill id that landed in the editor: `'when-ready'` submits only after it.
726
+ const [landedPrefillId, setLandedPrefillId] = useState(null);
725
727
  const onPrefillAppliedRef = useRef(onPrefillApplied);
726
728
  useEffect(() => {
727
729
  onPrefillAppliedRef.current = onPrefillApplied;
@@ -806,6 +808,7 @@ function ComposerImpl(props) {
806
808
  // re-run the effect whenever the caller re-created it, and a `merge` prefill
807
809
  // applied twice appends its text twice.
808
810
  onPrefillAppliedRef.current?.(prefillId);
811
+ setLandedPrefillId(prefillId);
809
812
  // Last, so the prefill is fully applied and reported before the submit
810
813
  // takes the draft out of the editor.
811
814
  if (shouldSubmitPrefill({
@@ -1361,6 +1364,21 @@ function ComposerImpl(props) {
1361
1364
  useEffect(() => {
1362
1365
  handleSubmitRef.current = () => void handleSubmit();
1363
1366
  }, [handleSubmit]);
1367
+ const submitWhenReady = prefill?.submit === 'when-ready';
1368
+ useEffect(() => {
1369
+ if (!submitWhenReady ||
1370
+ !shouldSubmitWhenReady({
1371
+ prefillId,
1372
+ landedPrefillId,
1373
+ submittedPrefillId: submittedPrefillIdRef.current,
1374
+ submitDisabled,
1375
+ loading: modelsLoading || entitlementsPending,
1376
+ })) {
1377
+ return;
1378
+ }
1379
+ submittedPrefillIdRef.current = prefillId;
1380
+ handleSubmitRef.current();
1381
+ }, [submitWhenReady, prefillId, landedPrefillId, submitDisabled, modelsLoading, entitlementsPending]);
1364
1382
  // A question lock owns the editor: Up there is a caret move, never a take-back.
1365
1383
  const handleArrowUpAtStart = useCallback(() => (lockForQuestion ? false : (onArrowUpAtStart?.() ?? false)), [lockForQuestion, onArrowUpAtStart]);
1366
1384
  const editorPlaceholder = resolveEditorPlaceholder({
@@ -15,12 +15,16 @@ export type StoredUpload = PromptAttachment & {
15
15
  * What a persisted composer draft is keyed by.
16
16
  *
17
17
  * Project scope is the home hero composer — one draft per project, because
18
- * that composer has no session yet. Session scope is every in-thread composer.
19
- * Both ids are UUIDs, so the two families can never collide.
18
+ * that composer has no session yet. Space scope is a channel or DM composer.
19
+ * Session scope is every in-thread composer. Every id is a UUID, and each
20
+ * family has its own prefix, so they can never collide.
20
21
  */
21
22
  export type DraftScope = {
22
23
  kind: 'project';
23
24
  projectId: string;
25
+ } | {
26
+ kind: 'space';
27
+ spaceId: string;
24
28
  } | {
25
29
  kind: 'session';
26
30
  sessionId: string;
@@ -9,7 +9,11 @@ export const DRAFT_ENVELOPE_VERSION = 1;
9
9
  export const MAX_DRAFT_BYTES = 131072;
10
10
  /** The `<kind>:<id>` half of the storage key. The family prefix is the store's. */
11
11
  export function draftScopeKey(scope) {
12
- return scope.kind === 'project' ? `project:${scope.projectId}` : `session:${scope.sessionId}`;
12
+ if (scope.kind === 'project')
13
+ return `project:${scope.projectId}`;
14
+ if (scope.kind === 'space')
15
+ return `space:${scope.spaceId}`;
16
+ return `session:${scope.sessionId}`;
13
17
  }
14
18
  const isRemote = (file) => file.kind === 'remote';
15
19
  /**
@@ -117,5 +117,5 @@ export function ReasoningEffortSelector({ variants, selectedVariant, onVariantCh
117
117
  // reads as Auto rather than an unlabeled value; the next explicit choice
118
118
  // replaces it.
119
119
  const current = selectedVariant && choices.includes(selectedVariant) ? selectedVariant : null;
120
- return (_jsxs(DropdownMenu, { open: open, onOpenChange: setOpen, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { type: "button", variant: "ghost", size: "sm", "aria-label": t('thinkingEffort'), className: "text-foreground/70 gap-1.5 rounded-lg hit-area-y-3", children: [_jsx(EffortIcon, { value: current, className: "size-4 shrink-0" }), _jsx("span", { className: "max-w-[7rem] truncate", children: current ? label(current) : t('auto') }), _jsx(CaretDownIcon, { className: cn('size-3 opacity-50 transition-transform duration-200 ease-out', open && 'rotate-180') })] }) }), _jsx(DropdownMenuContent, { side: "top", align: "start", className: "min-w-[10rem]", children: _jsxs(DropdownMenuRadioGroup, { value: current ?? AUTO, onValueChange: onValueChange, children: [_jsxs(DropdownMenuRadioItem, { value: AUTO, children: [_jsx(EffortIcon, { value: null, className: "size-4 shrink-0" }), t('auto')] }), choices.map((value) => (_jsxs(DropdownMenuRadioItem, { value: value, children: [_jsx(EffortIcon, { value: value, className: "size-4 shrink-0" }), label(value)] }, value)))] }) })] }));
120
+ return (_jsxs(DropdownMenu, { open: open, onOpenChange: setOpen, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { type: "button", variant: "ghost", size: "sm", "aria-label": t('thinkingEffort'), className: "text-muted-foreground gap-1.5 rounded-lg hit-area-y-3", children: [_jsx(EffortIcon, { value: current, className: "size-4 shrink-0" }), _jsx("span", { className: "max-w-[7rem] truncate", children: current ? label(current) : t('auto') }), _jsx(CaretDownIcon, { className: cn('size-3 opacity-50 transition-transform duration-200 ease-out', open && 'rotate-180') })] }) }), _jsx(DropdownMenuContent, { side: "top", align: "start", className: "min-w-[10rem]", children: _jsxs(DropdownMenuRadioGroup, { value: current ?? AUTO, onValueChange: onValueChange, children: [_jsxs(DropdownMenuRadioItem, { value: AUTO, children: [_jsx(EffortIcon, { value: null, className: "size-4 shrink-0" }), t('auto')] }), choices.map((value) => (_jsxs(DropdownMenuRadioItem, { value: value, children: [_jsx(EffortIcon, { value: value, className: "size-4 shrink-0" }), label(value)] }, value)))] }) })] }));
121
121
  }
@@ -0,0 +1,11 @@
1
+ import { type ChatGptConnectionAction } from './chatgpt-connection-action.js';
2
+ /**
3
+ * The ChatGPT fix for a failed turn or tool call (the session error row, the
4
+ * image card). It needs the session the call belongs to, so it renders only on
5
+ * a session route; elsewhere the row stays informational.
6
+ */
7
+ export declare function ChatGptConnectionSlot({ action, className, }: {
8
+ action: ChatGptConnectionAction;
9
+ /** The wrapper's placement in the host row. */
10
+ className?: string;
11
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,54 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useTranslations } from '../../i18n/index.js';
4
+ import { Button } from '../../primitives/button.js';
5
+ import { cn } from '../../lib/utils.js';
6
+ import { useSessionIds } from '../../providers/session-ids.js';
7
+ import { useUiComponents, useUiViewerId } from '../../providers/ui-provider.js';
8
+ import { useFeatureFlag, useModelAccess, useProjectSession, useSessionProviderSecretPools, } from '@kortix/sdk/react';
9
+ import { useState } from 'react';
10
+ import { chatGptActionApplies } from './chatgpt-connection-action.js';
11
+ import { sessionPersonalUser } from '../overrides/provider-pool-draft.js';
12
+ /**
13
+ * The ChatGPT fix for a failed turn or tool call (the session error row, the
14
+ * image card). It needs the session the call belongs to, so it renders only on
15
+ * a session route; elsewhere the row stays informational.
16
+ */
17
+ export function ChatGptConnectionSlot({ action, className = 'mt-2 pl-7', }) {
18
+ const ids = useSessionIds();
19
+ const projectId = ids.projectId ?? null;
20
+ const sessionId = ids.sessionId ?? null;
21
+ if (!projectId || !sessionId)
22
+ return null;
23
+ return _jsx(ChatGptConnectionButton, { action: action, projectId: projectId, sessionId: sessionId, className: className });
24
+ }
25
+ /**
26
+ * Opens the ChatGPT accounts dialog, which exists only with pooled provider
27
+ * secrets and the LLM gateway on. Shown only where connecting or
28
+ * reconnecting an account can fix this session (`chatGptActionApplies`).
29
+ */
30
+ function ChatGptConnectionButton({ action, projectId, sessionId, className, }) {
31
+ const t = useTranslations('pooledSecrets');
32
+ const viewerId = useUiViewerId();
33
+ const pooled = useFeatureFlag(projectId, 'pooled_provider_secrets');
34
+ const enabled = pooled.enabled;
35
+ const access = useModelAccess(enabled ? projectId : null);
36
+ const session = useProjectSession(projectId, sessionId, { enabled });
37
+ const pools = useSessionProviderSecretPools(enabled ? projectId : null, sessionId);
38
+ const [open, setOpen] = useState(false);
39
+ const { ProviderAccountsModal } = useUiComponents();
40
+ const applies = !!ProviderAccountsModal &&
41
+ enabled &&
42
+ !(access.data?.disabledProviders ?? []).includes('codex') &&
43
+ chatGptActionApplies({
44
+ action,
45
+ personalUser: sessionPersonalUser(session.data),
46
+ viewerId: viewerId,
47
+ explicitSelection: pools.isSuccess
48
+ ? pools.data.pools.some((pool) => pool.provider_id === 'codex')
49
+ : undefined,
50
+ });
51
+ if (!applies || !ProviderAccountsModal)
52
+ return null;
53
+ return (_jsxs("div", { className: cn(className), children: [_jsx(Button, { size: "sm", className: "active:scale-[0.96]", onClick: () => setOpen(true), children: t(action === 'reconnect' ? 'reconnectChatGpt' : 'connectChatGpt') }), _jsx(ProviderAccountsModal, { projectId: projectId, providerId: "codex", open: open, onOpenChange: setOpen })] }));
54
+ }
@@ -106,7 +106,7 @@ function ModelRow({ model, groupProviderID, groupProviderName, isSelected, isAcc
106
106
  providerID: model.providerID,
107
107
  modelID: model.modelID,
108
108
  });
109
- }, className: cn('absolute inset-0 flex cursor-pointer items-center justify-center rounded-md', 'text-muted-foreground/70 hover:text-foreground hover:bg-foreground/10',
109
+ }, className: cn('absolute inset-0 flex cursor-pointer items-center justify-center rounded-md', 'text-muted-foreground hover:text-foreground hover:bg-foreground/10',
110
110
  /* `opacity` is NOT in this list, on purpose — see above. These
111
111
  only ever run on the one row the cursor is on, so they cannot
112
112
  leave a trail. */
@@ -304,7 +304,10 @@ export function ModelSelector({ models, selectedModel, onSelect, defaultControls
304
304
  setOpen(false);
305
305
  openUpgrade();
306
306
  }, [openUpgrade, setOpen]);
307
- return (_jsxs(_Fragment, { children: [connectionModal, projectId && chatGptPossible && ProviderAccountsModal && (_jsx(ProviderAccountsModal, { projectId: projectId, providerId: "codex", open: chatGptOpen, onOpenChange: setChatGptOpen })), _jsxs(CommandPopover, { open: disabled ? false : open, onOpenChange: (next) => !disabled && setOpen(next), children: [_jsx(CommandPopoverTrigger, { children: appearance === 'field' ? (_jsxs("button", { type: "button", disabled: disabled, className: cn(triggerVariants(), 'h-9 w-full'), children: [_jsx("span", { className: "truncate", children: displayName }), disabled ? null : _jsx(ChevronDown, { className: cn(TRIGGER_CARET_CLASS, 'size-4') })] })) : (_jsxs(Button, { type: "button", variant: triggerVariant, size: "sm", className: cn('rounded-lg hit-area-y-3', triggerVariant === 'ghost' && 'text-muted-foreground'), children: [_jsx("span", { className: cn('max-w-30 truncate', triggerLabelClassName), children: displayName }), _jsx(ChevronDown, { className: cn('duration-moderate size-3 transition-transform ease-out', open && 'rotate-180') })] })) }), _jsx(CommandPopoverContent, { side: "top", align: "start", sideOffset: 8, className: "w-[min(300px,calc(100vw-1.5rem))]", children: _jsxs(_Fragment, { children: [_jsx(CommandInput, { compact: true, placeholder: tModel('search'), value: search, onValueChange: setSearch, rightElement: canManageModels && canConnectProvider ? (_jsxs("div", { className: "-mr-0.5 flex shrink-0 items-center gap-0.5", children: [_jsx(Hint, { label: tModel('connectProvider'), side: "top", className: "z-50", children: _jsx("button", { type: "button", "aria-label": tModel('addProvider'), onClick: () => handleOpenProviderModal('providers'), className: "text-muted-foreground hover:text-foreground hover:bg-muted flex size-8 cursor-pointer items-center justify-center rounded-md transition-colors", children: _jsx(Plus, { className: "size-4" }) }) }), _jsx(Hint, { label: tModel('manageModels'), side: "top", className: "z-50", children: _jsx("button", { type: "button", "aria-label": tModel('manageModels'), onClick: () => handleOpenProviderModal('models'), className: "text-muted-foreground hover:text-foreground hover:bg-muted flex size-8 cursor-pointer items-center justify-center rounded-md transition-colors", children: _jsx(SlidersHorizontal, { className: "size-4" }) }) })] })) : undefined }), grouped.length > 1 && _jsx(CommandSeparator, { className: "bg-border/60" }), _jsx(CommandList, { className: "max-h-[380px]", children: modelsLoading || entitlementsPending ? (_jsx("div", { className: "flex min-h-32 items-center justify-center", role: "status", "aria-label": tModel('loading'), children: _jsx(Loading, { className: "text-muted-foreground size-4 shrink-0" }) })) : grouped.length > 0 ? (_jsxs(_Fragment, { children: [pinnedDefault && (_jsxs(_Fragment, { children: [_jsx(CommandGroup, { heading: _jsx(GroupHeading, { children: tModel('yourDefault') }), forceMount: true, children: _jsx(ModelRow, { model: pinnedDefault.model, groupProviderID: pinnedDefault.providerID, groupProviderName: pinnedDefault.providerName, isSelected: availableSelectedModel?.providerID === pinnedDefault.model.providerID &&
307
+ return (_jsxs(_Fragment, { children: [connectionModal, projectId && chatGptPossible && ProviderAccountsModal && (_jsx(ProviderAccountsModal, { projectId: projectId, providerId: "codex", open: chatGptOpen, onOpenChange: setChatGptOpen })), _jsxs(CommandPopover, { open: disabled ? false : open, onOpenChange: (next) => !disabled && setOpen(next), children: [_jsx(CommandPopoverTrigger, { children: appearance === 'field' ? (_jsxs("button", { type: "button", disabled: disabled, className: cn(triggerVariants(), 'h-9 w-full'), children: [_jsx("span", { className: "truncate", children: displayName }), disabled ? null : _jsx(ChevronDown, { className: cn(TRIGGER_CARET_CLASS, 'size-4') })] })) : (_jsxs(Button, { type: "button", variant: triggerVariant, size: "sm",
308
+ // `min-w-0 shrink`: in a narrow toolbar (a channel's thread panel) the
309
+ // model name truncates; the controls beside it keep their width.
310
+ className: cn('min-w-0 shrink rounded-lg hit-area-y-3', triggerVariant === 'ghost' && 'text-muted-foreground'), children: [_jsx("span", { className: cn('max-w-30 truncate', triggerLabelClassName), children: displayName }), _jsx(ChevronDown, { className: cn('duration-moderate size-3 transition-transform ease-out', open && 'rotate-180') })] })) }), _jsx(CommandPopoverContent, { side: "top", align: "start", sideOffset: 8, className: "w-[min(300px,calc(100vw-1.5rem))]", children: _jsxs(_Fragment, { children: [_jsx(CommandInput, { compact: true, placeholder: tModel('search'), value: search, onValueChange: setSearch, rightElement: canManageModels && canConnectProvider ? (_jsxs("div", { className: "-mr-0.5 flex shrink-0 items-center gap-0.5", children: [_jsx(Hint, { label: tModel('connectProvider'), side: "top", className: "z-50", children: _jsx("button", { type: "button", "aria-label": tModel('addProvider'), onClick: () => handleOpenProviderModal('providers'), className: "text-muted-foreground hover:text-foreground hover:bg-muted flex size-8 cursor-pointer items-center justify-center rounded-md transition-colors", children: _jsx(Plus, { className: "size-4" }) }) }), _jsx(Hint, { label: tModel('manageModels'), side: "top", className: "z-50", children: _jsx("button", { type: "button", "aria-label": tModel('manageModels'), onClick: () => handleOpenProviderModal('models'), className: "text-muted-foreground hover:text-foreground hover:bg-muted flex size-8 cursor-pointer items-center justify-center rounded-md transition-colors", children: _jsx(SlidersHorizontal, { className: "size-4" }) }) })] })) : undefined }), grouped.length > 1 && _jsx(CommandSeparator, { className: "bg-border/60" }), _jsx(CommandList, { className: "max-h-[380px]", children: modelsLoading || entitlementsPending ? (_jsx("div", { className: "flex min-h-32 items-center justify-center", role: "status", "aria-label": tModel('loading'), children: _jsx(Loading, { className: "text-muted-foreground size-4 shrink-0" }) })) : grouped.length > 0 ? (_jsxs(_Fragment, { children: [pinnedDefault && (_jsxs(_Fragment, { children: [_jsx(CommandGroup, { heading: _jsx(GroupHeading, { children: tModel('yourDefault') }), forceMount: true, children: _jsx(ModelRow, { model: pinnedDefault.model, groupProviderID: pinnedDefault.providerID, groupProviderName: pinnedDefault.providerName, isSelected: availableSelectedModel?.providerID === pinnedDefault.model.providerID &&
308
311
  availableSelectedModel?.modelID === pinnedDefault.model.modelID, isAccountDefault: true, defaultControls: rowDefaultControls, onSelect: handleSelect, connectLabel: tPooled('connect'), scope: "pinned" }) }), _jsx(CommandSeparator, {})] })), sections.map((section, sectionIndex) => {
309
312
  const selectedInSection = section.models.find((m) => availableSelectedModel?.providerID === m.providerID &&
310
313
  availableSelectedModel?.modelID === m.modelID);
@@ -12,11 +12,9 @@ export declare function projectProviderModalTab(tab: ProviderModalTab): 'provide
12
12
  * route segment is the fallback.
13
13
  *
14
14
  * The fallback is what every original caller relies on — they all render under
15
- * `/projects/[id]`. The explicit id exists because the onboarding wizard's plan
16
- * step now also runs on `/new` (`app/(app)/new`), which has NO `[id]` segment:
17
- * there the route yields `null`, `modal` is therefore `null`, and
18
- * `openConnectProvider` renders nothing while the step's only control never
19
- * advances the wizard.
15
+ * `/projects/[id]`. The explicit id serves callers outside that route, such as
16
+ * Customize's provider list: there the route may yield `null`, `modal` is
17
+ * then `null`, and `openConnectProvider` renders nothing.
20
18
  *
21
19
  * `!== undefined`, never `??`: a caller that deliberately passes `null` means
22
20
  * "act on no project", and must not silently inherit whatever route it happens
@@ -47,6 +45,8 @@ export declare function useModelConnectionGate(models?: FlatModel[], options?: {
47
45
  projectId?: string | null;
48
46
  }): {
49
47
  canConnectProvider: boolean;
48
+ /** The viewer holds `project.model.write`: the provider modal can change the project's models. */
49
+ canWriteProviders: boolean;
50
50
  openConnectProvider: (tab?: ProviderModalTab) => void;
51
51
  openUpgrade: () => void;
52
52
  modal: import("react").JSX.Element | null;
@@ -27,11 +27,9 @@ export function projectProviderModalTab(tab) {
27
27
  * route segment is the fallback.
28
28
  *
29
29
  * The fallback is what every original caller relies on — they all render under
30
- * `/projects/[id]`. The explicit id exists because the onboarding wizard's plan
31
- * step now also runs on `/new` (`app/(app)/new`), which has NO `[id]` segment:
32
- * there the route yields `null`, `modal` is therefore `null`, and
33
- * `openConnectProvider` renders nothing while the step's only control never
34
- * advances the wizard.
30
+ * `/projects/[id]`. The explicit id serves callers outside that route, such as
31
+ * Customize's provider list: there the route may yield `null`, `modal` is
32
+ * then `null`, and `openConnectProvider` renders nothing.
35
33
  *
36
34
  * `!== undefined`, never `??`: a caller that deliberately passes `null` means
37
35
  * "act on no project", and must not silently inherit whatever route it happens
@@ -154,6 +152,8 @@ export function useModelConnectionGate(models = [], options) {
154
152
  const showUpgradeOption = !!platformConfig().billingEnabled;
155
153
  return {
156
154
  canConnectProvider,
155
+ /** The viewer holds `project.model.write`: the provider modal can change the project's models. */
156
+ canWriteProviders,
157
157
  openConnectProvider,
158
158
  openUpgrade,
159
159
  modal,
@@ -0,0 +1,10 @@
1
+ import { type LoadEntireHistoryOptions } from '../print/load-entire-history.js';
2
+ /** Resolve again after paging: older pages can change the first loaded turn's anchor. */
3
+ export declare function jumpToOutcome({ needsHistory, history, resolve, scroll, unavailable, loadError }: {
4
+ needsHistory: boolean;
5
+ history: LoadEntireHistoryOptions;
6
+ resolve: () => string | undefined;
7
+ scroll: (key: string) => Promise<boolean>;
8
+ unavailable: () => void;
9
+ loadError: () => void;
10
+ }): Promise<void>;
@@ -0,0 +1,11 @@
1
+ import { loadEntireHistory } from '../print/load-entire-history.js';
2
+ /** Resolve again after paging: older pages can change the first loaded turn's anchor. */
3
+ export async function jumpToOutcome({ needsHistory, history, resolve, scroll, unavailable, loadError }) {
4
+ if (needsHistory && !(await loadEntireHistory(history)).exhausted) {
5
+ loadError();
6
+ return;
7
+ }
8
+ const key = resolve();
9
+ if (!key || !await scroll(key))
10
+ unavailable();
11
+ }
@@ -0,0 +1,14 @@
1
+ import { type Dispatch, type ReactNode, type SetStateAction } from 'react';
2
+ import type { ChangeRequest } from '@kortix/sdk';
3
+ export interface SessionChangeRequests {
4
+ requests: ChangeRequest[];
5
+ onOpen: (crId: string) => void;
6
+ onJump: (crId: string) => Promise<void>;
7
+ jumping: boolean;
8
+ }
9
+ /** Chat and the mobile panel are siblings. Share the existing read, never a second query. */
10
+ export declare function SessionOutcomesBridge({ children }: {
11
+ children: ReactNode;
12
+ }): import("react").JSX.Element;
13
+ export declare const useSessionChangeRequestsPanel: () => SessionChangeRequests | null;
14
+ export declare const usePublishSessionChangeRequests: () => Dispatch<SetStateAction<SessionChangeRequests | null>> | null;
@@ -0,0 +1,12 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext, useState } from 'react';
4
+ const ReadContext = createContext(null);
5
+ const WriteContext = createContext(null);
6
+ /** Chat and the mobile panel are siblings. Share the existing read, never a second query. */
7
+ export function SessionOutcomesBridge({ children }) {
8
+ const [value, setValue] = useState(null);
9
+ return (_jsx(WriteContext.Provider, { value: setValue, children: _jsx(ReadContext.Provider, { value: value, children: children }) }));
10
+ }
11
+ export const useSessionChangeRequestsPanel = () => useContext(ReadContext);
12
+ export const usePublishSessionChangeRequests = () => useContext(WriteContext);
@@ -1,7 +1,7 @@
1
1
  import { type ReactNode } from 'react';
2
2
  import { type TurnSpan } from './anchor-outcomes.js';
3
3
  import type { Outcome } from '../../internal/outcomes/outcome-types.js';
4
- export declare function SessionOutcomesProvider({ projectSessionId, turnSpans, busy, onOpen, children, }: {
4
+ export declare function SessionOutcomesProvider({ projectSessionId, turnSpans, busy, onOpen, children, onJump, jumping, }: {
5
5
  /** The git session id a change request records as `origin_session_id`. */
6
6
  projectSessionId: string | undefined;
7
7
  turnSpans: TurnSpan[];
@@ -9,6 +9,8 @@ export declare function SessionOutcomesProvider({ projectSessionId, turnSpans, b
9
9
  busy: boolean;
10
10
  onOpen: (outcome: Outcome) => void;
11
11
  children: ReactNode;
12
+ onJump: (resolveTurn: () => string | undefined, createdAt: number) => Promise<void>;
13
+ jumping: boolean;
12
14
  }): import("react").JSX.Element;
13
15
  /** A turn's outcomes, oldest first. `EMPTY` is a module constant so a turn with
14
16
  * no outcomes gets the SAME array every render and never re-renders for it. */
@@ -45,6 +45,9 @@ import { useProjectContext } from '../../files/project/context.js';
45
45
  // NOT `@kortix/sdk/react`'s change-request hook. See the note above — this is
46
46
  // a cache-coherence requirement, not a style preference.
47
47
  import { invalidateChangeRequestReads, useSessionChangeRequests, } from '../../files/project/hooks/use-change-requests.js';
48
+ import { usePublishSessionChangeRequests } from './session-outcomes-bridge.js';
49
+ import { useProjectCan } from '../../internal/lib/use-project-can.js';
50
+ import { PROJECT_ACTIONS } from '../../internal/lib/project-actions.js';
48
51
  import { anchorOutcomes } from './anchor-outcomes.js';
49
52
  import { changeRequestOutcomes } from './change-request-outcomes.js';
50
53
  const EMPTY = [];
@@ -52,7 +55,7 @@ const OutcomesContext = createContext(null);
52
55
  /** A change request the agent opens as its turn closes can land after the
53
56
  * turn-end read: read once more after this delay. */
54
57
  const CHANGE_REQUEST_SETTLE_MS = 2_500;
55
- export function SessionOutcomesProvider({ projectSessionId, turnSpans, busy, onOpen, children, }) {
58
+ export function SessionOutcomesProvider({ projectSessionId, turnSpans, busy, onOpen, children, onJump, jumping, }) {
56
59
  const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
57
60
  // No `projectId` argument: this hook reads it from `ProjectFilesProvider`,
58
61
  // which is what keeps it on the same cache entry the dialog invalidates.
@@ -60,15 +63,42 @@ export function SessionOutcomesProvider({ projectSessionId, turnSpans, busy, onO
60
63
  // the turn that produced it — it just reads "Applied" or "Closed".
61
64
  // Only THIS session's change requests, filtered by the server; the key sits
62
65
  // under the project-files list scope the dialog's mutations invalidate.
63
- const { data } = useSessionChangeRequests(projectSessionId, { refetchInterval: 60_000 });
66
+ const projectId = useProjectContext()?.projectId;
67
+ const { allowed } = useProjectCan(projectId, PROJECT_ACTIONS.PROJECT_GITOPS_READ);
68
+ const { data } = useSessionChangeRequests(projectSessionId, { refetchInterval: busy ? 5_000 : 60_000, enabled: allowed });
69
+ const requests = useMemo(() => allowed ? (data?.change_requests ?? []) : [], [allowed, data?.change_requests]);
64
70
  useRefreshChangeRequestsOnTurnEnd(busy);
65
71
  const all = useMemo(
66
72
  // Change requests are the only outcome a turn produces. The derived
67
73
  // pipeline (files, schedules, background tasks, connector links) was built
68
74
  // and removed — see `OutcomeKind` for why each one could not be tied to the
69
75
  // turn that showed it.
70
- () => changeRequestOutcomes(data?.change_requests ?? [], projectSessionId, tI18nComplete), [data?.change_requests, projectSessionId, tI18nComplete]);
76
+ () => changeRequestOutcomes(requests, projectSessionId, tI18nComplete), [requests, projectSessionId, tI18nComplete]);
71
77
  const byTurn = useMemo(() => anchorOutcomes(all, turnSpans), [all, turnSpans]);
78
+ const anchorsRef = useRef(byTurn);
79
+ useEffect(() => { anchorsRef.current = byTurn; }, [byTurn]);
80
+ const publish = usePublishSessionChangeRequests();
81
+ const panelValue = useMemo(() => ({
82
+ requests,
83
+ onOpen: (crId) => {
84
+ const outcome = all.find((item) => item.id === `cr:${crId}`);
85
+ // Rows open this request, not a superseding request's detail.
86
+ if (outcome)
87
+ onOpen({ ...outcome, action: { ...outcome.action, target: crId } });
88
+ },
89
+ onJump: (crId) => onJump(() => {
90
+ for (const [key, outcomes] of anchorsRef.current) {
91
+ if (outcomes.some((item) => item.id === `cr:${crId}`))
92
+ return key;
93
+ }
94
+ return undefined;
95
+ }, Date.parse(requests.find((cr) => cr.cr_id === crId)?.created_at ?? '')),
96
+ jumping,
97
+ }), [requests, all, onOpen, onJump, jumping]);
98
+ useEffect(() => {
99
+ publish?.(panelValue);
100
+ return () => publish?.(null);
101
+ }, [publish, panelValue]);
72
102
  const value = useMemo(() => ({ byTurn, onOpen }), [byTurn, onOpen]);
73
103
  return _jsx(OutcomesContext.Provider, { value: value, children: children });
74
104
  }
@@ -1,3 +1,4 @@
1
+ import { type ReactNode } from 'react';
1
2
  import { type ShareContext } from '../../../files/viewer/viewer-actions.js';
2
3
  export declare function AppPreview({ url, name, projectId, shareContext, onClose, onSendToAgent, }: {
3
4
  /** The internal sandbox URL the agent handed over, e.g. http://localhost:3000. */
@@ -17,3 +18,12 @@ export declare function AppPreview({ url, name, projectId, shareContext, onClose
17
18
  * shows only Retry, exactly as before. */
18
19
  onSendToAgent?: () => void;
19
20
  }): import("react").JSX.Element;
21
+ /**
22
+ * The Browser card while the session's computer boots: the real toolbar, every
23
+ * control that needs the computer disabled, over `children` (the boot status).
24
+ * Mounts nothing that reaches the sandbox: no proxy, no app list, no frame.
25
+ */
26
+ export declare function AppPreviewBooting({ onClose, children, }: {
27
+ onClose: () => void;
28
+ children: ReactNode;
29
+ }): import("react").JSX.Element;
@@ -36,7 +36,7 @@ import { useBrowserRecentsStore } from '../../../internal/stores/browser-recents
36
36
  import { probePreviewPort } from '@kortix/sdk';
37
37
  import { useRuntimeConnectionStore } from '@kortix/sdk/react';
38
38
  import { ArrowSquareOutIcon, GlobeIcon as Globe, SparkleIcon as SparklesSolid, WarningIcon, } from '@phosphor-icons/react';
39
- import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';
39
+ import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore, } from 'react';
40
40
  import { PreviewLoadingOverlay, SandboxAddressBar, } from '../../../browser/sandbox-browser-chrome.js';
41
41
  import { BrowserLanding } from '../../../browser/browser-landing.js';
42
42
  import { CloseButton, DetailSidebarToggle } from './detail-view.js';
@@ -97,7 +97,6 @@ export function AppPreview({ url, name, projectId, shareContext, onClose, onSend
97
97
  // Still loading past PREVIEW_SLOW_MS: the overlay says so and offers Reload.
98
98
  const [slow, setSlow] = useState(false);
99
99
  const addressRef = useRef(null);
100
- const isMobile = useIsMobile();
101
100
  // Copy link mints a PUBLIC share and copies `/share/session/{token}`.
102
101
  // It used to copy `previewUrl` — the authenticated `/v1/p/{sandbox}/{port}/…`
103
102
  // proxy URL — which only ever worked in the tab that had the
@@ -235,16 +234,11 @@ export function AppPreview({ url, name, projectId, shareContext, onClose, onSend
235
234
  setIndex((i) => i + 1);
236
235
  reload();
237
236
  }, [canGoForward, reload]);
238
- return (_jsxs("div", { className: "bg-background flex h-full min-h-0 min-w-0 flex-col", children: [_jsxs("div", { className: "border-border flex shrink-0 items-center gap-0.5 border-b px-2 py-1", children: [_jsx(DetailSidebarToggle, {}), _jsx(SandboxAddressBar, { displayValue: current, hasPreview: hasPreview, isLoading: isLoading, canGoBack: canGoBack, canGoForward: canGoForward, onBack: goBack, onForward: goForward, onReload: reload, onHome: () => navigateTo(''), onNavigate: navigateTo, suggestions: suggestions, placeholder: tI18nComplete.raw('text878abd024f27'), inputRef: addressRef, trailing:
239
- // An app has no file to save and no text to put on a clipboard, so
240
- // `Copy link` is the one copy action — the thing you can hand
241
- // someone for a running port.
242
- _jsx(ViewerActions, { copy: appCopy, shareContext: shareContext, shareInput: shareInput }) }), _jsxs(ButtonGroup, { className: "shrink-0", children: [_jsx(Hint, { label: tI18nComplete.raw('text306ef19c8ac3'), side: "bottom", children: _jsx(Button, { variant: "secondary", size: "icon", disabled: !hasPreview, "aria-label": tI18nComplete.raw('text306ef19c8ac3'), onClick: () => {
243
- if (!previewUrl)
244
- return;
245
- track('app_opened_new_tab');
246
- window.open(previewUrl, '_blank', 'noopener,noreferrer');
247
- }, className: "size-7 shrink-0 active:scale-[0.96]", children: _jsx(ArrowSquareOutIcon, { className: "size-3.5" }) }) }), _jsx(PanelWidthButton, { isMobile: isMobile }), _jsx(CloseButton, { onClose: onClose })] })] }), _jsxs("div", { className: "relative min-h-0 flex-1 overflow-hidden", children: [isLoading && hasPreview && !noApp && (_jsx(PreviewLoadingOverlay, { label: tI18nComplete.raw('textc4cf2b2ccb5d'), detail: slow ? previewSlowReason({ port }) : undefined, action: slow ? (_jsx(Button, { variant: "outline", size: "sm", className: "gap-1.5", onClick: reload, children: tI18nComplete.raw('textbdc090ec61e3') })) : undefined })), (hasError || hostPreview.failed) && !noApp && (_jsx(ErrorState, { icon: WarningIcon, size: "sm", className: "bg-background absolute inset-0 z-10", title: tI18nComplete('textba601cdb484b', { value0: title }),
237
+ return (_jsxs("div", { className: "bg-background flex h-full min-h-0 min-w-0 flex-col", children: [_jsx(AppPreviewToolbar, { previewUrl: previewUrl, onClose: onClose, displayValue: current, isLoading: isLoading, canGoBack: canGoBack, canGoForward: canGoForward, onBack: goBack, onForward: goForward, onReload: reload, onHome: () => navigateTo(''), onNavigate: navigateTo, suggestions: suggestions, inputRef: addressRef, trailing:
238
+ // An app has no file to save and no text to put on a clipboard, so
239
+ // `Copy link` is the one copy action — the thing you can hand
240
+ // someone for a running port.
241
+ _jsx(ViewerActions, { copy: appCopy, shareContext: shareContext, shareInput: shareInput }) }), _jsxs("div", { className: "relative min-h-0 flex-1 overflow-hidden", children: [isLoading && hasPreview && !noApp && (_jsx(PreviewLoadingOverlay, { label: tI18nComplete.raw('textc4cf2b2ccb5d'), detail: slow ? previewSlowReason({ port }) : undefined, action: slow ? (_jsx(Button, { variant: "outline", size: "sm", className: "gap-1.5", onClick: reload, children: tI18nComplete.raw('textbdc090ec61e3') })) : undefined })), (hasError || hostPreview.failed) && !noApp && (_jsx(ErrorState, { icon: WarningIcon, size: "sm", className: "bg-background absolute inset-0 z-10", title: tI18nComplete('textba601cdb484b', { value0: title }),
248
242
  /* The single most common cause, said plainly: the agent started the
249
243
  server a moment ago and it isn't listening yet. Only a SETTLED
250
244
  `dead` verdict earns the stopped-workspace wording — see
@@ -274,6 +268,31 @@ export function AppPreview({ url, name, projectId, shareContext, onClose, onSend
274
268
  // frame reads as "your app is broken".
275
269
  _jsx("div", { className: "flex h-full items-center justify-center", children: _jsx(Loading, { className: "size-4" }) }))] })] }));
276
270
  }
271
+ /**
272
+ * The Browser card's toolbar: sidebar toggle, address bar, open in a new tab,
273
+ * width, close. Shared by the live preview and the booting card, so the two
274
+ * cannot drift.
275
+ */
276
+ function AppPreviewToolbar({ previewUrl, onClose, ...address }) {
277
+ const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
278
+ const isMobile = useIsMobile();
279
+ return (_jsxs("div", { className: "border-border flex shrink-0 items-center gap-0.5 border-b px-2 py-1", children: [_jsx(DetailSidebarToggle, {}), _jsx(SandboxAddressBar, { ...address, hasPreview: !!previewUrl, placeholder: tI18nComplete.raw('text878abd024f27') }), _jsxs(ButtonGroup, { className: "shrink-0", children: [_jsx(Hint, { label: tI18nComplete.raw('text306ef19c8ac3'), side: "bottom", children: _jsx(Button, { variant: "secondary", size: "icon", disabled: !previewUrl, "aria-label": tI18nComplete.raw('text306ef19c8ac3'), onClick: () => {
280
+ if (!previewUrl)
281
+ return;
282
+ track('app_opened_new_tab');
283
+ window.open(previewUrl, '_blank', 'noopener,noreferrer');
284
+ }, className: "size-7 shrink-0 active:scale-[0.96]", children: _jsx(ArrowSquareOutIcon, { className: "size-3.5" }) }) }), _jsx(PanelWidthButton, { isMobile: isMobile }), _jsx(CloseButton, { onClose: onClose })] })] }));
285
+ }
286
+ const noop = () => { };
287
+ /**
288
+ * The Browser card while the session's computer boots: the real toolbar, every
289
+ * control that needs the computer disabled, over `children` (the boot status).
290
+ * Mounts nothing that reaches the sandbox: no proxy, no app list, no frame.
291
+ */
292
+ export function AppPreviewBooting({ onClose, children, }) {
293
+ const addressRef = useRef(null);
294
+ return (_jsxs("div", { className: "bg-background flex h-full min-h-0 min-w-0 flex-col", children: [_jsx(AppPreviewToolbar, { onClose: onClose, displayValue: "", isLoading: false, canGoBack: false, canGoForward: false, onBack: noop, onForward: noop, onReload: noop, onHome: noop, onNavigate: noop, inputRef: addressRef, disabled: true }), _jsx("div", { className: "relative min-h-0 flex-1 overflow-hidden", children: children })] }));
295
+ }
277
296
  function SearchHint() {
278
297
  const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
279
298
  return (_jsx("div", { className: "flex flex-1 items-center justify-center", children: _jsxs("div", { className: "text-muted-foreground flex flex-col items-center gap-4 px-4 text-center", children: [_jsx(Globe, { className: "size-12 opacity-20" }), _jsx("p", { className: "text-sm", children: tI18nComplete.raw('text2f883b75cd2d') })] }) }));
@@ -0,0 +1,7 @@
1
+ import type { ChangeRequest } from '@kortix/sdk';
2
+ export declare function ChangeRequestsCard({ requests, onOpen, onJump, jumping }: {
3
+ requests: ChangeRequest[];
4
+ onOpen: (crId: string) => void;
5
+ onJump: (crId: string) => Promise<void>;
6
+ jumping?: boolean;
7
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,17 @@
1
+ 'use client';
2
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
3
+ import { ArrowBendUpLeftIcon } from '@phosphor-icons/react';
4
+ import { useLocale, useTranslations } from '../../../i18n/index.js';
5
+ import { relativeTime } from '../../../internal/lib/relative-time.js';
6
+ import { ChangeRequestStatusBadge } from '../../../files/project/components/change-request-status-badge.js';
7
+ import { Badge } from '../../../primitives/badge.js';
8
+ import { Button } from '../../../primitives/button.js';
9
+ import Hint from '../../../primitives/hint.js';
10
+ import { PanelCard } from './panel-card.js';
11
+ export function ChangeRequestsCard({ requests, onOpen, onJump, jumping = false }) {
12
+ const t = useTranslations('sessionChangeRequests');
13
+ const locale = useLocale();
14
+ if (requests.length === 0)
15
+ return null;
16
+ return (_jsx(PanelCard, { title: t('title'), count: requests.length, isEmpty: false, defaultExpanded: true, fill: true, contentClassName: "min-h-0 overflow-y-auto px-2 py-2", children: _jsx("ul", { children: [...requests].sort((a, b) => Date.parse(b.created_at) - Date.parse(a.created_at)).map((cr) => (_jsxs("li", { className: "flex items-center gap-1", children: [_jsxs("button", { type: "button", "data-cr-id": cr.cr_id, onClick: () => onOpen(cr.cr_id), className: "hover:bg-accent flex min-w-0 flex-1 flex-col gap-1 rounded-sm px-2 py-2 text-left", children: [_jsxs("span", { className: "flex w-full min-w-0 items-baseline gap-2", children: [_jsxs("span", { className: "text-muted-foreground shrink-0 text-xs tabular-nums", children: ["#", cr.number] }), _jsx("span", { className: "text-foreground truncate text-sm", children: cr.title })] }), _jsxs("span", { className: "flex flex-wrap items-center gap-2", children: [cr.status === 'open' ? _jsx(Badge, { variant: "secondary", size: "sm", children: t('open') }) : _jsx(ChangeRequestStatusBadge, { cr: cr }), _jsx("time", { dateTime: cr.created_at, className: "text-muted-foreground text-xs", children: relativeTime(cr.created_at, locale) })] })] }), _jsx(Hint, { label: t('jump', { number: cr.number }), children: _jsx(Button, { variant: "ghost", size: "icon", disabled: jumping, "aria-label": t('jump', { number: cr.number }), onClick: () => onJump(cr.cr_id), children: _jsx(ArrowBendUpLeftIcon, { className: "size-3.5 shrink-0" }) }) })] }, cr.cr_id))) }) }));
17
+ }
@@ -2,6 +2,7 @@
2
2
  * Pure logic for `EasyPanel`, split out from the client component purely so
3
3
  * it is unit-testable without a DOM.
4
4
  */
5
+ import { parseArtifactUrl } from '../../../artifacts/frame-policy.js';
5
6
  import { isKortixAppUrl } from '../../../apps/kortix-app-url.js';
6
7
  import { parseLocalhostUrl } from '@kortix/sdk';
7
8
  /**
@@ -43,6 +44,10 @@ export function quickBrowserOutput(apps,
43
44
  * wrong page.
44
45
  */
45
46
  target) {
47
+ // An artifact's app link opens as the artifact (the browser cannot frame the Kortix app).
48
+ if (target?.url && parseArtifactUrl(target.url)) {
49
+ return { callID: 'quick-browser', name: target.title || 'Artifact', kind: 'artifact', url: target.url };
50
+ }
46
51
  return {
47
52
  callID: 'quick-browser',
48
53
  name: target?.title || 'Browser',
@@ -98,7 +103,7 @@ export function sandboxRecents(recents) {
98
103
  * - web pages (`.html/.htm` — same viewport assumption as apps).
99
104
  */
100
105
  export function isWideDeliverable(output) {
101
- if (output.kind === 'presentation' || output.kind === 'app')
106
+ if (output.kind === 'presentation' || output.kind === 'app' || output.kind === 'artifact')
102
107
  return true;
103
108
  return /\.(pptx?|key|xlsx?|csv|tsv|html?)$/i.test(output.name);
104
109
  }
@@ -168,6 +173,7 @@ export function deriveIsRunning(stepsRunning, sessionBusy) {
168
173
  * "Apps"). */
169
174
  const KIND_GROUP_LABEL = {
170
175
  app: 'Apps',
176
+ artifact: 'Artifacts',
171
177
  presentation: 'Presentations',
172
178
  image: 'Images',
173
179
  video: 'Videos',