@kortix/ui 0.14.12 → 0.14.14

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 (438) hide show
  1. package/README.md +1 -1
  2. package/dist/_vendor/kortix-shared.js +521 -7045
  3. package/dist/_vendor/shared/app-config.d.ts +8 -0
  4. package/dist/_vendor/shared/artifact-annotations.d.ts +708 -0
  5. package/dist/_vendor/shared/artifact-comments.d.ts +327 -0
  6. package/dist/_vendor/shared/index.d.ts +3 -1
  7. package/dist/_vendor/shared/my-kortix-agent.d.ts +40 -0
  8. package/dist/_vendor/shared/peer-message-prompt.d.ts +35 -0
  9. package/dist/_vendor/shared/pixel-mark.d.ts +11 -0
  10. package/dist/_vendor/shared/prompt-attachments.d.ts +1 -0
  11. package/dist/_vendor/shared/reminder-prompt.d.ts +8 -2
  12. package/dist/_vendor/shared/runtime-versions.d.ts +8 -0
  13. package/dist/artifacts/artifact-frame.d.ts +1 -0
  14. package/dist/artifacts/artifact-frame.js +18 -5
  15. package/dist/artifacts/frame-policy.d.ts +1 -1
  16. package/dist/artifacts/frame-policy.js +10 -5
  17. package/dist/customize/agents/agent-access-text.d.ts +16 -0
  18. package/dist/customize/agents/agent-access-text.js +54 -0
  19. package/dist/customize/agents/agent-approval-rules.d.ts +8 -0
  20. package/dist/customize/agents/agent-approval-rules.js +26 -0
  21. package/dist/customize/agents/agent-authority-card.js +4 -1
  22. package/dist/customize/agents/agent-cover-card.d.ts +4 -1
  23. package/dist/customize/agents/agent-cover-card.js +2 -2
  24. package/dist/customize/agents/agent-detail-aside.d.ts +1 -2
  25. package/dist/customize/agents/agent-detail-aside.js +8 -11
  26. package/dist/customize/agents/agent-drives-section.d.ts +23 -7
  27. package/dist/customize/agents/agent-drives-section.js +107 -41
  28. package/dist/customize/agents/agent-instructions.d.ts +11 -0
  29. package/dist/customize/agents/agent-instructions.js +114 -0
  30. package/dist/customize/agents/agent-model-view.d.ts +17 -0
  31. package/dist/customize/agents/agent-model-view.js +67 -0
  32. package/dist/customize/agents/agent-overview.d.ts +53 -0
  33. package/dist/customize/agents/agent-overview.js +242 -0
  34. package/dist/customize/agents/agent-page-chrome.d.ts +128 -0
  35. package/dist/customize/agents/agent-page-chrome.js +145 -0
  36. package/dist/customize/agents/agent-page.d.ts +13 -1
  37. package/dist/customize/agents/agent-page.js +478 -367
  38. package/dist/customize/agents/agent-pin-button.d.ts +10 -0
  39. package/dist/customize/agents/agent-pin-button.js +20 -0
  40. package/dist/customize/agents/agent-policy-sets-section.d.ts +16 -0
  41. package/dist/customize/agents/agent-policy-sets-section.js +80 -0
  42. package/dist/customize/agents/agent-policy-sets.js +1 -1
  43. package/dist/customize/agents/agent-section-rail.d.ts +21 -0
  44. package/dist/customize/agents/agent-section-rail.js +23 -0
  45. package/dist/customize/agents/agent-share-control.d.ts +4 -3
  46. package/dist/customize/agents/agent-share-control.js +15 -16
  47. package/dist/customize/agents/{agent-people-section.d.ts → agent-share-dialog.d.ts} +3 -1
  48. package/dist/customize/agents/{agent-people-section.js → agent-share-dialog.js} +21 -21
  49. package/dist/customize/agents/agent-tabs.d.ts +95 -0
  50. package/dist/customize/agents/agent-tabs.js +199 -0
  51. package/dist/customize/agents/agents-page.d.ts +0 -21
  52. package/dist/customize/agents/agents-page.js +104 -118
  53. package/dist/customize/agents/connectors-required.d.ts +16 -0
  54. package/dist/customize/agents/connectors-required.js +19 -0
  55. package/dist/customize/agents/create-agent-modal.d.ts +19 -0
  56. package/dist/customize/agents/create-agent-modal.js +94 -0
  57. package/dist/customize/connectors/agent-access.d.ts +4 -4
  58. package/dist/customize/connectors/agent-access.js +7 -10
  59. package/dist/customize/connectors/connector-identity.d.ts +12 -0
  60. package/dist/customize/connectors/connector-identity.js +15 -2
  61. package/dist/customize/connectors/connector-routes.js +2 -2
  62. package/dist/customize/connectors/connectors-page.d.ts +14 -1
  63. package/dist/customize/connectors/connectors-page.js +101 -32
  64. package/dist/customize/connectors/detail/app-page.js +1 -1
  65. package/dist/customize/connectors/detail/connector-agents.js +0 -3
  66. package/dist/customize/connectors/detail/connector-page.d.ts +1 -1
  67. package/dist/customize/connectors/detail/connector-page.js +5 -2
  68. package/dist/customize/connectors/detail/connector-policy-sets.js +1 -1
  69. package/dist/customize/connectors/detail/connector-triggers.js +2 -2
  70. package/dist/customize/connectors/use-agent-access.d.ts +7 -5
  71. package/dist/customize/connectors/use-agent-access.js +2 -6
  72. package/dist/customize/models/models-page.d.ts +7 -1
  73. package/dist/customize/models/models-page.js +2 -2
  74. package/dist/customize/project-settings/project-admin-sections.d.ts +63 -0
  75. package/dist/customize/project-settings/project-admin-sections.js +80 -0
  76. package/dist/customize/project-settings/project-settings-page.d.ts +1 -1
  77. package/dist/customize/project-settings/project-settings-page.js +4 -13
  78. package/dist/customize/project-settings/project-settings-sections.d.ts +5 -5
  79. package/dist/customize/project-settings/project-settings-sections.js +6 -20
  80. package/dist/customize/providers/provider-accordion.js +29 -17
  81. package/dist/customize/providers/provider-connect.js +1 -1
  82. package/dist/customize/providers/provider-sheet.d.ts +4 -1
  83. package/dist/customize/providers/provider-sheet.js +15 -5
  84. package/dist/customize/secrets/secrets-page.d.ts +5 -1
  85. package/dist/customize/secrets/secrets-page.js +2 -2
  86. package/dist/customize/sections/gateway-view.d.ts +10 -2
  87. package/dist/customize/sections/gateway-view.js +16 -4
  88. package/dist/customize/sections/llm-provider/chatgpt-subscription-connect.d.ts +12 -5
  89. package/dist/customize/sections/llm-provider/chatgpt-subscription-connect.js +131 -8
  90. package/dist/customize/sections/llm-provider/claude-code-step.d.ts +10 -0
  91. package/dist/customize/sections/llm-provider/claude-code-step.js +32 -0
  92. package/dist/customize/sections/llm-provider/models-tab.js +5 -1
  93. package/dist/customize/sections/view/account-secret-resources-panel.d.ts +5 -3
  94. package/dist/customize/sections/view/account-secret-resources-panel.js +122 -19
  95. package/dist/customize/sections/view/agent-editor-access-fields.d.ts +1 -1
  96. package/dist/customize/sections/view/agent-editor-access-fields.js +8 -4
  97. package/dist/customize/sections/view/agent-editor-basics-fields.d.ts +4 -1
  98. package/dist/customize/sections/view/agent-editor-basics-fields.js +33 -4
  99. package/dist/customize/sections/view/agent-editor-catalog.d.ts +2 -2
  100. package/dist/customize/sections/view/agent-editor-catalog.js +10 -12
  101. package/dist/customize/sections/view/agent-editor-primitives.d.ts +1 -1
  102. package/dist/customize/sections/view/agent-editor-primitives.js +4 -4
  103. package/dist/customize/sections/view/agent-editor.d.ts +37 -26
  104. package/dist/customize/sections/view/agent-editor.js +19 -19
  105. package/dist/customize/sections/view/grant-mode-field.d.ts +8 -20
  106. package/dist/customize/sections/view/grant-mode-field.js +31 -57
  107. package/dist/customize/sections/view/permission-editor.d.ts +3 -1
  108. package/dist/customize/sections/view/permission-editor.js +19 -10
  109. package/dist/customize/sections/view/review-view.d.ts +8 -0
  110. package/dist/customize/sections/view/review-view.js +12 -1
  111. package/dist/customize/sections/view/secret-delivery.js +1 -4
  112. package/dist/customize/sections/view/secrets-view.d.ts +7 -1
  113. package/dist/customize/sections/view/secrets-view.js +42 -6
  114. package/dist/customize/settings/rail.js +2 -8
  115. package/dist/customize/settings/settings-tabs.d.ts +2 -2
  116. package/dist/customize/settings/settings-tabs.js +17 -19
  117. package/dist/customize/settings/tabs/experimental-tab.d.ts +3 -0
  118. package/dist/customize/settings/tabs/experimental-tab.js +6 -1
  119. package/dist/customize/settings/tabs/sandbox-tab.d.ts +4 -6
  120. package/dist/customize/settings/tabs/sandbox-tab.js +9 -9
  121. package/dist/customize/shared/access-list.d.ts +39 -0
  122. package/dist/customize/shared/access-list.js +62 -0
  123. package/dist/customize/shared/agent-resource-scope.d.ts +87 -0
  124. package/dist/customize/shared/agent-resource-scope.js +123 -0
  125. package/dist/customize/shared/capability-library.d.ts +41 -0
  126. package/dist/customize/shared/capability-library.js +271 -0
  127. package/dist/customize/shared/capability-page-shell.d.ts +18 -1
  128. package/dist/customize/shared/capability-page-shell.js +21 -1
  129. package/dist/customize/shared/catalog/catalog-space-tabs.d.ts +14 -0
  130. package/dist/customize/shared/catalog/catalog-space-tabs.js +20 -0
  131. package/dist/customize/shared/customize-tab-bar.d.ts +13 -0
  132. package/dist/customize/shared/customize-tab-bar.js +95 -0
  133. package/dist/customize/shared/entity/entity-modal.d.ts +17 -1
  134. package/dist/customize/shared/entity/entity-modal.js +10 -9
  135. package/dist/customize/shared/leave-guard.d.ts +23 -0
  136. package/dist/customize/shared/leave-guard.js +87 -0
  137. package/dist/customize/shared/standalone-settings-nav.js +4 -1
  138. package/dist/customize/shared/tool-rules.d.ts +11 -0
  139. package/dist/customize/shared/tool-rules.js +29 -0
  140. package/dist/customize/skills/builtin-skill-modal.d.ts +6 -0
  141. package/dist/customize/skills/builtin-skill-modal.js +41 -0
  142. package/dist/customize/skills/skills-page.d.ts +21 -18
  143. package/dist/customize/skills/skills-page.js +16 -110
  144. package/dist/customize/triggers/runtime-triggers.d.ts +17 -0
  145. package/dist/customize/triggers/runtime-triggers.js +57 -0
  146. package/dist/customize/triggers/schedule/event-trigger-copy.js +2 -2
  147. package/dist/customize/triggers/schedule/post-to-field.js +2 -2
  148. package/dist/customize/triggers/schedule/schedule-copy.d.ts +11 -6
  149. package/dist/customize/triggers/schedule/schedule-copy.js +29 -8
  150. package/dist/customize/triggers/schedule/schedule-detail-sheet.js +7 -3
  151. package/dist/customize/triggers/schedule/trigger-composer-logic.d.ts +26 -1
  152. package/dist/customize/triggers/schedule/trigger-composer-logic.js +64 -3
  153. package/dist/customize/triggers/schedule/trigger-composer.js +57 -20
  154. package/dist/customize/triggers/schedule/trigger-edit-logic.js +18 -5
  155. package/dist/customize/triggers/schedule/trigger-filter.d.ts +10 -0
  156. package/dist/customize/triggers/schedule/trigger-filter.js +16 -0
  157. package/dist/customize/triggers/schedule/trigger-runs-panel.js +1 -0
  158. package/dist/customize/triggers/schedule/trigger-toast.js +2 -1
  159. package/dist/customize/triggers/schedule/use-trigger-mutations.d.ts +1 -1
  160. package/dist/customize/triggers/schedule/use-trigger-mutations.js +1 -1
  161. package/dist/customize/triggers/schedule/when-app.d.ts +15 -0
  162. package/dist/customize/triggers/schedule/when-app.js +21 -0
  163. package/dist/customize/triggers/schedule/when-change-request.d.ts +10 -0
  164. package/dist/customize/triggers/schedule/when-change-request.js +15 -0
  165. package/dist/customize/triggers/schedule-view.d.ts +17 -3
  166. package/dist/customize/triggers/schedule-view.js +46 -16
  167. package/dist/customize/triggers/triggers-page.d.ts +3 -3
  168. package/dist/customize/triggers/triggers-page.js +2 -2
  169. package/dist/customize/use-configure-thread.d.ts +8 -2
  170. package/dist/customize/use-configure-thread.js +30 -18
  171. package/dist/files/project/components/change-request-detail-dialog.js +2 -3
  172. package/dist/files/project/components/drive-explorer.js +6 -5
  173. package/dist/files/project/explorer-source.d.ts +3 -0
  174. package/dist/files/project/upload-batch.d.ts +3 -3
  175. package/dist/files/project/upload-batch.js +7 -6
  176. package/dist/files/runtime/sandbox-explorer-source.js +3 -3
  177. package/dist/i18n/en.d.ts +1330 -53
  178. package/dist/i18n/en.js +1422 -145
  179. package/dist/i18n/ui-catalog/remaining-ui-translation-keys.generated.js +16 -7
  180. package/dist/internal/auth/auth-primitives.d.ts +1 -3
  181. package/dist/internal/auth/auth-primitives.js +2 -2
  182. package/dist/internal/billing/session-cost-format.d.ts +1 -0
  183. package/dist/internal/billing/session-cost-format.js +11 -0
  184. package/dist/internal/components/agent-mark.d.ts +12 -1
  185. package/dist/internal/components/agent-mark.js +34 -11
  186. package/dist/internal/components/nav-rail.d.ts +22 -0
  187. package/dist/internal/components/nav-rail.js +16 -0
  188. package/dist/internal/components/repository-disconnected.js +2 -2
  189. package/dist/internal/goals/goal-meta.d.ts +15 -1
  190. package/dist/internal/goals/goal-meta.js +42 -2
  191. package/dist/internal/hooks/projects/use-agent-config.d.ts +11 -7
  192. package/dist/internal/hooks/projects/use-agent-config.js +28 -11
  193. package/dist/internal/hooks/use-slash-focus.d.ts +7 -1
  194. package/dist/internal/hooks/use-slash-focus.js +9 -3
  195. package/dist/internal/layout/project-capability-nav.d.ts +24 -0
  196. package/dist/internal/layout/project-capability-nav.js +86 -0
  197. package/dist/internal/layout/project-page-header.d.ts +1 -1
  198. package/dist/internal/layout/project-page-header.js +1 -1
  199. package/dist/internal/layout/project-settings-nav.d.ts +3 -2
  200. package/dist/internal/layout/project-settings-nav.js +5 -3
  201. package/dist/internal/lib/browser-noise/rules/old-browsers.js +1 -1
  202. package/dist/internal/lib/capability-tab-routes.d.ts +34 -3
  203. package/dist/internal/lib/capability-tab-routes.js +76 -8
  204. package/dist/internal/lib/manifest-health.d.ts +10 -0
  205. package/dist/internal/lib/manifest-health.js +20 -0
  206. package/dist/internal/lib/pixel-mark.d.ts +4 -1
  207. package/dist/internal/lib/pixel-mark.js +33 -6
  208. package/dist/internal/lib/project-actions.d.ts +1 -1
  209. package/dist/internal/lib/project-actions.js +0 -4
  210. package/dist/internal/lib/provider-branding.js +2 -0
  211. package/dist/internal/lib/space-scope.d.ts +29 -0
  212. package/dist/internal/lib/space-scope.js +28 -0
  213. package/dist/internal/lib/use-project-feature-flags.js +3 -3
  214. package/dist/internal/lib/web-notifications.d.ts +74 -8
  215. package/dist/internal/lib/web-notifications.js +243 -117
  216. package/dist/internal/notifications/notification-rows.d.ts +14 -7
  217. package/dist/internal/notifications/notification-rows.js +21 -14
  218. package/dist/internal/notifications/session-toast-cards.d.ts +2 -2
  219. package/dist/internal/reminders/reminder-format.d.ts +6 -2
  220. package/dist/internal/reminders/reminder-format.js +7 -1
  221. package/dist/internal/stores/active-space-store.d.ts +35 -0
  222. package/dist/internal/stores/active-space-store.js +29 -0
  223. package/dist/internal/stores/kortix-computer-store.js +13 -4
  224. package/dist/internal/stores/pinned-agents-store.d.ts +26 -0
  225. package/dist/internal/stores/pinned-agents-store.js +20 -0
  226. package/dist/internal/stores/session-panel-memory-store.js +3 -0
  227. package/dist/internal/stores/turn-attention-store.d.ts +5 -4
  228. package/dist/lib/routes.d.ts +16 -1
  229. package/dist/lib/routes.js +15 -3
  230. package/dist/markdown/doc-editor/doc-embed.d.ts +31 -0
  231. package/dist/markdown/doc-editor/doc-embed.js +168 -0
  232. package/dist/markdown/doc-editor/doc-extensions.d.ts +26 -0
  233. package/dist/markdown/doc-editor/doc-extensions.js +149 -0
  234. package/dist/markdown/doc-editor/doc-menus.d.ts +9 -0
  235. package/dist/markdown/doc-editor/doc-menus.js +56 -0
  236. package/dist/markdown/doc-editor/markdown.d.ts +12 -0
  237. package/dist/markdown/doc-editor/markdown.js +140 -0
  238. package/dist/markdown/genui/components/inline.d.ts +1 -1
  239. package/dist/primitives/badge.d.ts +1 -1
  240. package/dist/primitives/button.d.ts +1 -1
  241. package/dist/primitives/pixel-kortix-mark.d.ts +5 -4
  242. package/dist/primitives/pixel-kortix-mark.js +5 -15
  243. package/dist/primitives/tag.d.ts +1 -1
  244. package/dist/primitives/textarea.js +14 -0
  245. package/dist/primitives/toast.d.ts +2 -0
  246. package/dist/primitives/toast.js +4 -2
  247. package/dist/providers/ui-provider.d.ts +16 -0
  248. package/dist/session/actions/session-label.d.ts +1 -1
  249. package/dist/session/actions/session-label.js +3 -3
  250. package/dist/session/agents/agent-model.d.ts +92 -0
  251. package/dist/session/agents/agent-model.js +123 -0
  252. package/dist/session/agents/agent-state-mark.d.ts +10 -0
  253. package/dist/session/agents/agent-state-mark.js +22 -0
  254. package/dist/session/agents/agent-strip.d.ts +58 -0
  255. package/dist/session/agents/agent-strip.js +259 -0
  256. package/dist/session/agents/held-messages.d.ts +33 -0
  257. package/dist/session/agents/held-messages.js +50 -0
  258. package/dist/session/agents/legacy-subagent-chat.d.ts +11 -0
  259. package/dist/session/agents/legacy-subagent-chat.js +19 -0
  260. package/dist/session/agents/session-peek.d.ts +20 -0
  261. package/dist/session/agents/session-peek.js +67 -0
  262. package/dist/session/agents/session-prompt.d.ts +13 -0
  263. package/dist/session/agents/session-prompt.js +18 -0
  264. package/dist/session/agents/steer-session.d.ts +13 -0
  265. package/dist/session/agents/steer-session.js +29 -0
  266. package/dist/session/agents/subagent-dialog-content.d.ts +11 -0
  267. package/dist/session/agents/subagent-dialog-content.js +115 -0
  268. package/dist/session/agents/subagent-view.d.ts +8 -0
  269. package/dist/session/agents/subagent-view.js +18 -0
  270. package/dist/session/agents/tasks-panel.d.ts +13 -0
  271. package/dist/session/agents/tasks-panel.js +41 -0
  272. package/dist/session/agents/workflow-run-controls.d.ts +43 -0
  273. package/dist/session/agents/workflow-run-controls.js +141 -0
  274. package/dist/session/composer/ComposerCard.d.ts +1 -1
  275. package/dist/session/composer/ComposerCard.js +3 -3
  276. package/dist/session/composer/agent-selector.js +13 -19
  277. package/dist/session/composer/composer-underbar.d.ts +3 -1
  278. package/dist/session/composer/composer-underbar.js +2 -2
  279. package/dist/session/composer/composer.d.ts +5 -0
  280. package/dist/session/composer/composer.js +16 -10
  281. package/dist/session/composer/editor/composer-editor.js +19 -8
  282. package/dist/session/composer/editor/ultracode.d.ts +34 -0
  283. package/dist/session/composer/editor/ultracode.js +127 -0
  284. package/dist/session/composer/send-blockers.d.ts +1 -11
  285. package/dist/session/composer/send-blockers.js +1 -11
  286. package/dist/session/composer/session-composer-readiness.d.ts +1 -28
  287. package/dist/session/composer/session-composer-readiness.js +5 -16
  288. package/dist/session/header/reminder-parts.d.ts +1 -1
  289. package/dist/session/header/session-site-header.js +6 -3
  290. package/dist/session/header/subagent-hover-card.d.ts +0 -2
  291. package/dist/session/header/subagent-hover-card.js +1 -4
  292. package/dist/session/models/claude-connection-slot.d.ts +11 -0
  293. package/dist/session/models/claude-connection-slot.js +30 -0
  294. package/dist/session/models/model-availability.d.ts +3 -1
  295. package/dist/session/models/model-availability.js +3 -0
  296. package/dist/session/models/model-selector.js +11 -12
  297. package/dist/session/models/model-tags.d.ts +9 -0
  298. package/dist/session/models/model-tags.js +8 -0
  299. package/dist/session/panel/easy/easy-panel.js +1 -1
  300. package/dist/session/panel/easy/step-icon.js +5 -1
  301. package/dist/session/panel/mobile-tool-drawer.js +1 -1
  302. package/dist/session/panel/session-action-panel-column.js +1 -1
  303. package/dist/session/panel/session-desktop.js +41 -14
  304. package/dist/session/panel/session-panel-provider.d.ts +1 -1
  305. package/dist/session/panel/session-panel-provider.js +7 -11
  306. package/dist/session/prompts/question-prompt.js +3 -1
  307. package/dist/session/status/session-error-banner.js +4 -1
  308. package/dist/session/thread/session-chat.js +286 -296
  309. package/dist/session/thread/session-context-modal.js +29 -10
  310. package/dist/session/thread/session-context-spawned-sessions.d.ts +13 -0
  311. package/dist/session/thread/session-context-spawned-sessions.js +44 -0
  312. package/dist/session/thread/session-context-sub-sessions.js +3 -8
  313. package/dist/session/thread/transcript.d.ts +3 -0
  314. package/dist/session/thread/transcript.js +32 -8
  315. package/dist/session/tool/shared/full-view-action.d.ts +29 -0
  316. package/dist/session/tool/shared/full-view-action.js +43 -0
  317. package/dist/session/tool/tool-part-renderer.js +10 -2
  318. package/dist/session/tool/tools/agent-message-tool.js +2 -2
  319. package/dist/session/tool/tools/agent-spawn-tool.js +2 -2
  320. package/dist/session/tool/tools/agent-status-tool.js +2 -2
  321. package/dist/session/tool/tools/kortix-action-tool.d.ts +2 -0
  322. package/dist/session/tool/tools/kortix-action-tool.js +148 -0
  323. package/dist/session/tool/tools/kortix-tool-card.d.ts +83 -0
  324. package/dist/session/tool/tools/kortix-tool-card.js +186 -0
  325. package/dist/session/tool/tools/multi-agent-tool-bodies.d.ts +11 -0
  326. package/dist/session/tool/tools/multi-agent-tool-bodies.js +141 -0
  327. package/dist/session/tool/tools/multi-agent-tool-data.d.ts +63 -0
  328. package/dist/session/tool/tools/multi-agent-tool-data.js +118 -0
  329. package/dist/session/tool/tools/multi-agent-tools.d.ts +9 -0
  330. package/dist/session/tool/tools/multi-agent-tools.js +38 -0
  331. package/dist/session/tool/tools/question-tool.js +1 -1
  332. package/dist/session/tool/tools/register.d.ts +3 -0
  333. package/dist/session/tool/tools/register.js +3 -0
  334. package/dist/session/tool/tools/session-spawn-tool.js +2 -2
  335. package/dist/session/tool/tools/task-tool.d.ts +1 -1
  336. package/dist/session/tool/tools/task-tool.js +29 -41
  337. package/dist/session/tool/tools/workflow-progress.d.ts +34 -0
  338. package/dist/session/tool/tools/workflow-progress.js +186 -0
  339. package/dist/session/tool/tools/workflow-run.d.ts +128 -0
  340. package/dist/session/tool/tools/workflow-run.js +251 -0
  341. package/dist/session/tool/tools/workflow-tool.d.ts +9 -0
  342. package/dist/session/tool/tools/workflow-tool.js +253 -0
  343. package/dist/session/turn/notice-batch-group.d.ts +12 -0
  344. package/dist/session/turn/notice-batch-group.js +17 -0
  345. package/dist/session/turn/peer-message-row.d.ts +14 -0
  346. package/dist/session/turn/peer-message-row.js +57 -0
  347. package/dist/session/turn/subagent-notice-row.d.ts +4 -0
  348. package/dist/session/turn/subagent-notice-row.js +50 -0
  349. package/dist/session/turn/subagent-notice.d.ts +58 -0
  350. package/dist/session/turn/subagent-notice.js +111 -0
  351. package/dist/session/turn/user-message.js +24 -5
  352. package/dist/styles/tokens.css +2 -0
  353. package/dist/styles.css +1 -1
  354. package/dist/terminal/session-terminal-connect-bar.js +1 -1
  355. package/dist/workspace/admin/project-admin-dashboard.d.ts +53 -0
  356. package/dist/workspace/admin/project-admin-dashboard.js +252 -0
  357. package/dist/workspace/admin/project-admin-nav.d.ts +20 -0
  358. package/dist/workspace/admin/project-admin-nav.js +41 -0
  359. package/dist/workspace/home/welcome-body.js +25 -3
  360. package/dist/workspace/index.d.ts +6 -2
  361. package/dist/workspace/index.js +12 -2
  362. package/dist/workspace/layout/new-session-create.js +3 -3
  363. package/dist/workspace/layout/project-home.js +3 -3
  364. package/dist/workspace/memory/memory-labels.js +5 -0
  365. package/dist/workspace/repository-disconnected.js +2 -2
  366. package/dist/workspace/sessions/board-dispatch.d.ts +52 -0
  367. package/dist/workspace/sessions/board-dispatch.js +110 -0
  368. package/dist/workspace/sessions/board-grouping.d.ts +63 -0
  369. package/dist/workspace/sessions/board-grouping.js +141 -0
  370. package/dist/workspace/sessions/board-peek.d.ts +15 -0
  371. package/dist/workspace/sessions/board-peek.js +54 -0
  372. package/dist/workspace/sessions/board-state-mark.d.ts +15 -0
  373. package/dist/workspace/sessions/board-state-mark.js +24 -0
  374. package/dist/workspace/sessions/project-sessions-view.js +42 -31
  375. package/dist/workspace/sessions/sessions-board.d.ts +12 -0
  376. package/dist/workspace/sessions/sessions-board.js +214 -0
  377. package/dist/workspace/sidebar/footer/project-manifest-issues-alert.d.ts +46 -0
  378. package/dist/workspace/sidebar/footer/project-manifest-issues-alert.js +85 -0
  379. package/dist/workspace/sidebar/footer/sidebar-alert.js +1 -1
  380. package/dist/workspace/sidebar/new-agent-modal-provider.d.ts +12 -0
  381. package/dist/workspace/sidebar/new-agent-modal-provider.js +19 -0
  382. package/dist/workspace/sidebar/project-nav-items.d.ts +3 -1
  383. package/dist/workspace/sidebar/project-nav-items.js +53 -5
  384. package/dist/workspace/sidebar/project-session-list.js +35 -12
  385. package/dist/workspace/sidebar/project-sidebar.js +6 -3
  386. package/dist/workspace/sidebar/session-filter-menu.js +2 -1
  387. package/dist/workspace/space/space-blocks.d.ts +25 -0
  388. package/dist/workspace/space/space-blocks.js +124 -0
  389. package/dist/workspace/space/space-filter-tabs.d.ts +17 -0
  390. package/dist/workspace/space/space-filter-tabs.js +31 -0
  391. package/dist/workspace/space/space-page.d.ts +24 -0
  392. package/dist/workspace/space/space-page.js +157 -0
  393. package/dist/workspace/space/space-room.d.ts +20 -0
  394. package/dist/workspace/space/space-room.js +27 -0
  395. package/dist/workspace/space/space-tab-menu.d.ts +14 -0
  396. package/dist/workspace/space/space-tab-menu.js +127 -0
  397. package/dist/workspace/space/space-tab-panels.d.ts +9 -0
  398. package/dist/workspace/space/space-tab-panels.js +203 -0
  399. package/dist/workspace/space/space-templates.d.ts +34 -0
  400. package/dist/workspace/space/space-templates.js +71 -0
  401. package/dist/workspace/space/use-space-filter.d.ts +10 -0
  402. package/dist/workspace/space/use-space-filter.js +40 -0
  403. package/dist/workspace/space/use-space-manifest.d.ts +8 -0
  404. package/dist/workspace/space/use-space-manifest.js +27 -0
  405. package/dist/workspace/spaces/space-timeline.js +2 -2
  406. package/package.json +56 -53
  407. package/skills/kortix-ui/SKILL.md +1 -1
  408. package/skills/kortix-ui/references/custom-dashboard.md +10 -4
  409. package/skills/kortix-ui/references/modules.md +10 -8
  410. package/dist/_vendor/shared/meta-agent.d.ts +0 -7
  411. package/dist/customize/agents/agent-grant-pages.d.ts +0 -37
  412. package/dist/customize/agents/agent-grant-pages.js +0 -226
  413. package/dist/customize/agents/agent-triggers-section.d.ts +0 -17
  414. package/dist/customize/agents/agent-triggers-section.js +0 -109
  415. package/dist/customize/migrate-to-v2/index.d.ts +0 -5
  416. package/dist/customize/migrate-to-v2/index.js +0 -5
  417. package/dist/customize/migrate-to-v2/migration-prompt.d.ts +0 -16
  418. package/dist/customize/migrate-to-v2/migration-prompt.js +0 -59
  419. package/dist/customize/migrate-to-v2/upgrade-defs.d.ts +0 -30
  420. package/dist/customize/migrate-to-v2/upgrade-defs.js +0 -43
  421. package/dist/customize/migrate-to-v2/upgrade-view.d.ts +0 -32
  422. package/dist/customize/migrate-to-v2/upgrade-view.js +0 -152
  423. package/dist/customize/migrate-to-v2/use-run-upgrade.d.ts +0 -18
  424. package/dist/customize/migrate-to-v2/use-run-upgrade.js +0 -16
  425. package/dist/customize/shared/capability-tabs.d.ts +0 -3
  426. package/dist/customize/shared/capability-tabs.js +0 -137
  427. package/dist/customize/skills/skill-scope.d.ts +0 -14
  428. package/dist/customize/skills/skill-scope.js +0 -18
  429. package/dist/internal/lib/manifest-version.d.ts +0 -21
  430. package/dist/internal/lib/manifest-version.js +0 -55
  431. package/dist/session/composer/hooks/use-composer-escape-stop.d.ts +0 -6
  432. package/dist/session/composer/hooks/use-composer-escape-stop.js +0 -28
  433. package/dist/session/thread/sub-session-modal-content.d.ts +0 -8
  434. package/dist/session/thread/sub-session-modal-content.js +0 -23
  435. package/dist/session/thread/sub-session-modal.d.ts +0 -2
  436. package/dist/session/thread/sub-session-modal.js +0 -14
  437. package/dist/workspace/sidebar/footer/project-manifest-upgrade-alert.d.ts +0 -13
  438. package/dist/workspace/sidebar/footer/project-manifest-upgrade-alert.js +0 -48
@@ -9,7 +9,7 @@ import { useSessionWallpaperLayer } from '../panel/session-wallpaper-layer.js';
9
9
  import { useTranslations } from '../../i18n/index.js';
10
10
  import { errorMessageOf, isDeliveredButDisconnected } from '../../internal/lib/delivered-but-disconnected.js';
11
11
  import { useQueuedDraftStore, useQueuedDrafts } from '../composer/stores/queued-draft-store.js';
12
- import { SESSION_LOG_MINOR, SESSION_LOG_SCHEMA, listSessionPrompts, projectSessionConnection, sessionLogOfV1Rows, sessionLogPromptMessage, sessionLogRetrying, sessionLogTurns, fetchSessionAttachment, sessionLogFullTextPlan, sessionLogHarnessSwitches, sessionLogRestoreNotice, sessionLogWithFullTexts, } from '@kortix/sdk';
12
+ import { SESSION_LOG_MINOR, SESSION_LOG_SCHEMA, listSessionPrompts, sessionLogOfV1Rows, sessionLogPromptMessage, sessionLogRetrying, sessionLogTurns, fetchSessionAttachment, sessionLogFullTextPlan, sessionLogHarnessSwitches, sessionLogRestoreNotice, sessionLogWithFullTexts, } from '@kortix/sdk';
13
13
  import { useProjectSession, useSessionLogOlder, useSessionLogRecord, useSessionLogThread, useSessionMessageAuthors, useSessionModelUsage, useSessionParticipants, } from '@kortix/sdk/react';
14
14
  import { ArrowBendUpLeftIcon, CaretDownIcon, StackIcon as Layers, } from '@phosphor-icons/react';
15
15
  import { jumpToOutcome } from '../outcomes/jump-to-outcome.js';
@@ -39,6 +39,9 @@ import { ProjectFilesProvider } from '../../files/project/context.js';
39
39
  import { useOptionalSessionPanel } from '../panel/session-panel-provider.js';
40
40
  import { COMPOSER_SHELL_CLASS, Composer as SessionChatInput, } from '../composer/composer.js';
41
41
  import { ComposerDropZone } from '../composer/composer-drop-zone.js';
42
+ import { AgentsLine } from '../agents/agent-strip.js';
43
+ import { HeldMessages } from '../agents/held-messages.js';
44
+ import { SessionPromptContext } from '../agents/session-prompt.js';
42
45
  import { channelRunnableAgents, resolveComposerAgent, withChannelAgents } from '../composer/composer-agent-access.js';
43
46
  import { acknowledgeQuoteRequests, } from '../composer/composer-logic.js';
44
47
  import { sessionSlashFiles } from '../composer/menus/slash-files.js';
@@ -349,7 +352,7 @@ export function SessionChat({ sessionId, projectSessionId, sessionState, project
349
352
  // useSessionSync is the SINGLE source of truth for messages (matches OpenCode SolidJS).
350
353
  // It fetches on first access, then SSE events keep it up to date.
351
354
  // No React Query fallback — prevents stale refetches from overwriting live data.
352
- // A chat with no `useSession` (a sub-agent's: `sub-session-modal`, the `?rs=` route) runs
355
+ // A chat with no `useSession` (a sub-agent's: `legacy-subagent-chat`, the `?rs=` route) runs
353
356
  // inside the route's session. While that session reads its log (v2: the store holds it),
354
357
  // the sub-agent's thread and its older pages are the log's, and no saved copy is read.
355
358
  const [scopeProjectId = '', scopeSessionId = ''] = savedHistoryScope?.split('/') ?? [];
@@ -370,7 +373,7 @@ export function SessionChat({ sessionId, projectSessionId, sessionState, project
370
373
  // failure that needs a retry affordance. Neither is an empty session: a
371
374
  // swallowed 503 used to render exactly that, blank and "complete".
372
375
  freshness: transcriptFreshness, retryTranscript, } = sessionState ?? localSync;
373
- // A chat with no `useSession` (a sub-agent's, `sub-session-modal`) reads its
376
+ // A chat with no `useSession` (a sub-agent's, `legacy-subagent-chat`) reads its
374
377
  // runtime session's rows through `useSessionSync`: the same `fromV1` view.
375
378
  // On v2 that is the fallback while the log does not hold the sub-agent's thread yet.
376
379
  const detachedThread = useMemo(() => sessionState || hookMessages.length === 0
@@ -785,7 +788,7 @@ export function SessionChat({ sessionId, projectSessionId, sessionState, project
785
788
  * turn authority first (`GET .../turn`), the stream second, and this tab's
786
789
  * own send receipt only until either of them answers.
787
790
  */
788
- // A child-session mount (`sub-session-modal.tsx` passes no project ids) has
791
+ // A child-session mount (`legacy-subagent-chat.tsx` passes no project ids) has
789
792
  // no Kortix session row for `/turn` to answer about, so the projection below
790
793
  // is disabled and every working read falls back to the raw stream slot —
791
794
  // the same split `session-layout.tsx` makes for its busy indicator.
@@ -3289,6 +3292,10 @@ export function SessionChat({ sessionId, projectSessionId, sessionState, project
3289
3292
  }), [panelOutputs, panelContextFiles]);
3290
3293
  const sessionScopeAgentName = composerAgentName ?? undefined;
3291
3294
  const chatToolbarSlot = useMemo(() => projectId && projectSessionId ? (_jsx(SessionOverridesComposer, { projectId: projectId, sessionId: projectSessionId, selectedAgent: sessionScopeAgentName ?? null })) : undefined, [projectId, projectSessionId, sessionScopeAgentName]);
3295
+ // The agents this session started, as one line in the composer's under-row
3296
+ // (Claude Code's agent panel). It reads its own lists and never holds the composer.
3297
+ const agentsLineCompact = !!transcriptRows && !isPhone;
3298
+ const chatUnderbarSlot = useMemo(() => _jsx(AgentsLine, { projectId: projectId, sessionId: projectSessionId, compact: agentsLineCompact }), [projectId, projectSessionId, agentsLineCompact]);
3292
3299
  // The queued messages and the one Resume while a Stop holds the queue: their
3293
3300
  // own full-width card above the composer stack, not inside the strip.
3294
3301
  const chatAboveSlot = useMemo(() => (_jsx(QueuedPromptList, { rows: heldCommands.length > 0 ? [...queueRows.rows, ...heldCommandRows(heldCommands)] : queueRows.rows, heldCount: queueRows.heldCount, resumePending: resumePending, onResume: () => void handleResumeQueue(), onEdit: (id) => {
@@ -3385,22 +3392,8 @@ export function SessionChat({ sessionId, projectSessionId, sessionState, project
3385
3392
  // its cause attached instead of a shrug. An actionable cause reports to
3386
3393
  // Sentry; a routine browser tab discard only leaves a breadcrumb.
3387
3394
  useReloadForensics(projectSessionId);
3388
- // ONE answer for every surface that draws this session's runtime, and the
3389
- // reason the composer no longer guesses: `unknown` and `connecting` are
3390
- // waits, and a wait is not a fault. A routine wake says nothing either; only
3391
- // a parked box with no wake under way earns the asleep notice.
3392
- const sessionConnection = projectSessionConnection({
3393
- sandbox: projectSessionRow?.status ?? null,
3394
- runtimeReady,
3395
- unreachable: runtimePhase === 'unreachable' || runtimeUnreachable,
3396
- stalled: runtimeStalled,
3397
- activityFresh: working.state === 'working' && working.source === 'stream',
3398
- });
3399
3395
  const composerReadiness = sessionComposerReadiness({
3400
3396
  runtimeReady,
3401
- pendingPrompt: allowSendBeforeReady && working.state === 'working',
3402
- pendingDelivery: working.pendingDelivery,
3403
- connection: sessionConnection,
3404
3397
  // Only an OPEN TURN the control plane is holding counts here. This tab's
3405
3398
  // optimistic receipt and a stream frame both survive a box that died
3406
3399
  // mid-turn, and a durable inbox row (which the projection also sources to
@@ -3409,12 +3402,6 @@ export function SessionChat({ sessionId, projectSessionId, sessionState, project
3409
3402
  serverTurnLive: serverHoldsOpenTurn(working),
3410
3403
  unreachable: runtimePhase === 'unreachable' || runtimeUnreachable,
3411
3404
  stalled: runtimeStalled,
3412
- // The route's `/start` is bringing the computer up (or has not answered):
3413
- // the same fact the boot pill above the thread shows.
3414
- starting: !!sessionState &&
3415
- (sessionState.stage == null ||
3416
- sessionState.stage === 'provisioning' ||
3417
- sessionState.stage === 'starting'),
3418
3405
  });
3419
3406
  // #6509's `promptLikelyDropped` notice is deliberately NOT carried over: it
3420
3407
  // instrumented the deleted prompt-observation stall machinery to warn about
@@ -3480,7 +3467,7 @@ export function SessionChat({ sessionId, projectSessionId, sessionState, project
3480
3467
  // about which ref backs a change request.
3481
3468
  const outcomesBaseRef = useSessionBaseRef(projectId, projectSessionId);
3482
3469
  const searchParams = useUiSearchParams();
3483
- // `readOnly` is the nested sub-session modal (`sub-session-modal.tsx`) — it
3470
+ // `readOnly` is the nested sub-session modal (`legacy-subagent-chat.tsx`) — it
3484
3471
  // shares this component but must not rewrite the parent route's URL.
3485
3472
  const [openCrId, setOpenCrIdState] = useState(() => readOnly ? null : (searchParams?.get('cr') ?? null));
3486
3473
  const setOpenCrId = useCallback((id) => {
@@ -3523,6 +3510,9 @@ export function SessionChat({ sessionId, projectSessionId, sessionState, project
3523
3510
  // the loader exists to avoid). The connection keeps running in the parent
3524
3511
  // ProjectSessionRuntimeConnection, so as soon as the runtime is ready
3525
3512
  // isDataLoading flips and the full shell renders in one shot.
3513
+ // A control outside the composer ("Save as workflow" on a workflow card) sends through the
3514
+ // same path as a typed prompt: a running turn is steered, an idle session starts a turn.
3515
+ const sendSessionPrompt = useCallback((text) => handleSend(text, undefined, undefined, undefined, composerSendDelivery('transcript', isBusyRef.current)), [handleSend]);
3526
3516
  if (isDataLoading) {
3527
3517
  // A transcript read that genuinely FAILED (not a waking box — the SDK keeps
3528
3518
  // those on `loading` and retries them itself) gets an explicit retry, not
@@ -3535,275 +3525,275 @@ export function SessionChat({ sessionId, projectSessionId, sessionState, project
3535
3525
  }
3536
3526
  return (
3537
3527
  // A read-only view (the sub-session modal) offers no fix inside a tool card.
3538
- _jsx(ReadOnlySessionContext.Provider, { value: !!readOnly, children: _jsx(ProjectFilesProvider, { value: { projectId: projectId ?? '', ref: outcomesBaseRef, defaultBranch: outcomesBaseRef }, children: _jsxs(ComposerDropZone, { className: cn('relative flex h-full flex-col',
3539
- // Transparent in the welcome state so the root-level full-bleed wallpaper
3540
- // (portaled into SessionLayout) reads through; solid once real content
3541
- // takes over. Same base color either way, so non-welcome is unchanged.
3542
- shouldShowWelcomeOverlay ? 'bg-transparent' : 'bg-background'), "data-testid": "session-chat", children: [isPreparingPrint && (_jsxs("div", { "data-print-hide": true, role: "status", className: "bg-popover text-muted-foreground fixed bottom-6 left-1/2 z-50 flex -translate-x-1/2 items-center gap-2 rounded-lg border px-4 py-2 text-xs shadow-lg", children: [_jsx(Loading, { className: "size-3.5 shrink-0" }), tHardcodedUi.raw('i18nComplete.text7dac2ca010fe')] })), wallpaperLayer
3543
- ? welcomeWallpaper && createPortal(welcomeWallpaper, wallpaperLayer)
3544
- : welcomeWallpaper, !hideHeader && (_jsx(SessionSiteHeader, { sessionId: sessionId, sessionTitle: session?.title || 'Untitled', leadingAction: headerLeadingAction, parent: parentCrumb })), _jsx(SessionContextModal, { open: contextModalOpen, onOpenChange: setContextModalOpen,
3545
- // A chat with no `useSession` source: the raw explorer lists the
3546
- // rows `useSessionSync` read for it.
3547
- detachedRows: sessionState ? undefined : hookMessages, source: sessionState ?? DETACHED_SESSION_MESSAGES, session: session, sessionRow: projectSessionRow, providers: providers, allSessions: allSessions, servedModel: sessionServedModel, billedCost: sessionBilledCost(modelUsage) }), _jsx(CompactModal, { sessionId: sessionId, open: compactModalOpen, onOpenChange: setCompactModalOpen }), _jsx(ChangeRequestDetailDialog, { crId: openCrId, onClose: () => setOpenCrId(null), onOpenChangeRequest: setOpenCrId }), _jsxs(SessionBodyRow, { actionPanel: !hideHeader && !readOnly, children: [isNotFound ? (_jsxs("div", { className: "flex min-h-0 flex-1 flex-col items-center justify-center gap-3 px-6 text-center", children: [_jsx("div", { className: "text-muted-foreground text-sm", children: tHardcodedUi.raw('componentsSessionSessionChat.line5821JsxTextThisSessionIsNotAccessibleRightNow') }), _jsx(Button, { asChild: true, variant: "outline", size: "sm", children: _jsx(Link, { href: "/", prefetch: true, onClick: () => {
3548
- try {
3549
- if (sessionId)
3550
- useTabStore.getState().closeTab?.(sessionId);
3551
- }
3552
- catch { }
3553
- }, children: tHardcodedUi.raw('componentsSessionSessionChat.line5833JsxTextGoToHome') }) })] })) : (_jsxs("div", { ref: chatAreaRef, className: "relative z-10 min-h-0 flex-1", children: [_jsx("div", { ref: scrollContainerCallbackRef, className: cn(
3554
- // overflow-anchor:none — this scroll area does ALL of its own
3555
- // anchoring (useAutoScroll's spacer + RAF follow, the send-path
3556
- // turn anchor, and the history-prepend content-space restore in
3557
- // session-history-scroll.ts). The browser's native scroll
3558
- // anchoring (default `overflow-anchor: auto`) tries to
3559
- // compensate for the SAME prepends independently, and the two
3560
- // corrections stacking is the other half of the scroll-up
3561
- // teleport: ours restores the reader's position, then the
3562
- // native one nudges it again.
3563
- 'scrollbar-hide relative z-10 h-full flex-1 overflow-y-auto [scroll-behavior:auto] [overflow-anchor:none]', shouldShowWelcomeOverlay ? 'bg-transparent' : 'bg-background'), onMouseUp: handleChatMouseUp, onMouseDown: handleChatMouseDown, onScroll: handleChatScroll, children: _jsxs("div", { ref: contentRef, role: "log",
3564
- // Width and gutters live in `SESSION_TRANSCRIPT_CLASS`: the
3565
- // instant shell draws this same column and the two crossfade
3566
- // into each other, so a difference here is a sideways jump on
3567
- // screen, not a style opinion. See session-body.tsx.
3568
- //
3569
- // No bottom padding, there or here: the space under the last
3570
- // message is the auto-scroll spacer's job alone. The `pb-32`
3571
- // that used to sit here stacked 128px of dead space on top of
3572
- // it — the "extra inset at the bottom of the session".
3573
- // Rows run edge to edge: each row owns its gutters and its hover fill.
3574
- className: transcriptRows ? 'w-full min-w-0 pt-4' : SESSION_TRANSCRIPT_CLASS, children: [_jsxs("div", { className: "flex min-w-0 flex-col", children: [_jsx(SessionPrintHeader, { title: session?.title || 'Untitled', agentName: composerAgentName }), (hasOlder || showOlderLoading) && (_jsxs("div", { className: "mb-6 flex flex-col items-center gap-2", children: [hasOlder && (_jsx("div", { ref: olderSentinelRef, "aria-hidden": true, className: "h-px w-full" })), showOlderLoading && (_jsxs("div", { role: "status", className: "text-muted-foreground flex items-center gap-2 py-1 text-xs", children: [_jsx(Loading, { className: "size-3.5 shrink-0" }), tHardcodedUi.raw('i18nComplete.text85bf890776a7')] })), !showOlderLoading &&
3575
- !olderPullFailed &&
3576
- olderAutoloadExhausted({ hasOlder, autoLoadedPages }) && (_jsx(Button, { type: "button", variant: "outline-ghost", size: "sm", onClick: () => void handleLoadOlder(), children: tHardcodedUi.raw('i18nComplete.textf17671d83db0') })), olderPullFailed && !showOlderLoading && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-muted-foreground text-xs", children: tHardcodedUi.raw('i18nComplete.textb03a0041ce33') }), _jsx(Button, { type: "button", variant: "outline-ghost", size: "sm", onClick: () => void handleLoadOlder(), children: tHardcodedUi.raw('i18nComplete.text942087cc2d41') })] }))] })), restoreNotice && !restoreDismissed && (_jsx(RestoreNotice, { notice: restoreNotice, onDismiss: () => dismissRestore(historyKey, restoreNotice.generation) })), _jsx(SessionOutcomesProvider, { projectSessionId: projectSessionId, turnSpans: turnSpans, busy: effectiveBusy, onOpen: handleOpenOutcome, onJump: handleJumpToOutcome, jumping: jumpingToOutcome, children: _jsxs(ToolActivateContext.Provider, { value: toolActivate, children: [showFirstPromptPreview &&
3577
- firstPromptSource &&
3578
- queuedSyntheticMessages.length === 0 &&
3579
- rowsContext && (
3580
- // A channel thread draws the stand-in as rows, the same
3581
- // rows its boot body drew (`ThreadBootRows`).
3582
- _jsx(PendingPromptRows, { text: buildOptimisticPromptTextWithUploads(firstPromptSource.text, firstPromptSource.files), author: rowsContext.owner, sessionId: sessionId, busy: turns.length === 0 && (lastTurnWorking || promptInbox.prompts.some(isFirstPromptRow)) })), showFirstPromptPreview &&
3583
- firstPromptSource &&
3584
- queuedSyntheticMessages.length === 0 &&
3585
- !rowsContext && (_jsx(OptimisticTurn, { text: buildOptimisticPromptTextWithUploads(firstPromptSource.text, firstPromptSource.files),
3586
- // Preserve a real failed-send status through the
3587
- // boot-shell handover without inventing upload progress.
3588
- // A first prompt held on its uploads carries its own.
3589
- uploadStatus: firstPromptSource.uploadStatus ?? firstPromptUploadStatus, agentNames: agentNames, onFileClick: openFileInComputer, sessionId: sessionId,
3590
- // The first item of the conversation, like turn 0, which has no
3591
- // top margin. `first:mt-0` misses here: the list opens with a
3592
- // zero-height <header>, so the stand-in sat 44px lower than turn 0
3593
- // and every swap between the two jumped the bubble (KRTX-2931).
3594
- className: "mt-0",
3595
- // An undelivered first prompt is a turn about to start, as the
3596
- // shell above this chat shows it: busy from the first frame,
3597
- // before the working projection has read the inbox (KRTX-2931).
3598
- busy: turns.length === 0 && (lastTurnWorking || promptInbox.prompts.some(isFirstPromptRow)) })), turns.map((turn, turnIndex) => {
3599
- // Check if this turn is a compaction summary — and
3600
- // whether it actually PRODUCED one. A failed/aborted
3601
- // attempt (compaction-flagged, no content, not the
3602
- // working turn) renders as one slim row, draws no
3603
- // divider, and stacks tight against a neighbouring
3604
- // failed attempt.
3605
- const compaction = turn.compaction;
3606
- const hasCompaction = compaction !== null;
3607
- const isTurnWorking = turn.live;
3608
- // `inFlight` (message state) alongside the projection:
3609
- // classifying by projection alone flipped a streaming
3610
- // compaction to "failed" for the frames where the two
3611
- // disagree, popping the divider in and out — a layout
3612
- // bounce right where the reader is looking.
3613
- const isFailedCompaction = compaction !== null &&
3614
- !compaction.hasContent &&
3615
- !compaction.inFlight &&
3616
- !isTurnWorking;
3617
- // Retries collapse to ONE visible row, GLOBALLY: a
3618
- // failed attempt with ANY later compaction turn (a
3619
- // retry, or the one that finally landed) is history —
3620
- // it keeps its TurnViewport (stable keys, scroll
3621
- // anchors) but renders no content, and an empty
3622
- // TurnViewport costs 0px (turn-viewport.tsx RULE 2).
3623
- // Adjacency was not enough: attempts whose error landed
3624
- // on a plain assistant message used to interleave as
3625
- // unclassified turns, breaking every consecutive run.
3626
- const suppressedFailedCompaction = isFailedCompaction && turnIndex < lastCompactionTurnIndex;
3627
- // Notification-only early-return removed: it rendered the
3628
- // user's pty_* card but skipped the turn's replies,
3629
- // hiding every subsequent assistant response in that turn.
3630
- // Fall through to the normal turn renderer instead.
3631
- const confirmedActive = turnIsConfirmedActive({
3632
- isTurnWorking,
3633
- turnId: turn.id,
3634
- activeTurnId,
3635
- pendingDelivery: !!working.pendingDelivery,
3636
- });
3637
- const pendingPrompt = !confirmedActive && turn.assistant.length === 0
3638
- ? pendingPromptsByMessageId.get(turn.id)
3639
- : undefined;
3640
- // A queued prompt is not in the runtime transcript yet;
3641
- // its author still shows (`authorForTurn`).
3642
- const turnAuthor = authorForTurn(transcriptAuthors, messageAuthors, turn.id, pendingPrompt?.wire_message_id);
3643
- return (_jsx(TranscriptTurnRow
3644
- // ONE element per prompt: keyed by the id the
3645
- // bubble was FIRST painted under, so the swap to a
3646
- // re-minted echo id re-renders this node instead
3647
- // of mounting a new one (opacity keeps animating,
3648
- // hover state survives, nothing jumps).
3649
- , { turnId: turn.id, modelOptions: modelOptions, suppressed: suppressedFailedCompaction, continuedWith: harnessSwitches.get(turn.id)?.harness, fullTextState: loaded.state[turn.id] ?? 'idle', onLoadFullText: loadFullTexts, showBusyRow: showFallbackBusyRow &&
3650
- fallbackBusyRowTurnId === turn.id,
3651
- // Queued bubbles STACK: a pending turn right after
3652
- // another pending turn sits close to it, like a
3653
- // list of what is waiting — not a turn's width
3654
- // apart as if each had been answered in between.
3655
- // (Failed compaction rows need no stacking rule any
3656
- // more — at most one is visible at a time.)
3657
- viewportClassName: turnIndex === 0 || transcriptRows
3658
- ? ''
3659
- : // A compaction and the work after it continue the turn above.
3660
- turn.compaction || turn.continues
3661
- ? 'mt-6'
3662
- : lastTurnWorking &&
3663
- pendingTurnIds.has(turn.id) &&
3664
- pendingTurnIds.has(turns[turnIndex - 1].id)
3665
- ? 'mt-3'
3666
- : 'mt-12', turn: turn, author: turnAuthor, showAuthor: showAuthorName(turnAuthor, groupChat, viewerId), stoppedBy: stoppedByName(messageAuthors, turn.id, viewerId), servedModel: servedModelOfTurn(modelUsage, turn.id, turns[turnIndex - 1]?.id), turnOutcome: turnOutcome, isLast: turn.id === lastUserMessageId, ownsPlan: turn.id === planAnchorId, sessionId: sessionId, projectId: projectId, projectSessionId: projectSessionId, sessionStatus: sessionStatus, permissions: pendingPermissions, questions: pendingQuestions, agentNames: agentNames, isFirstTurn: turnIndex === 0,
3667
- // Handed over only once the stand-in has stepped
3668
- // aside — while it is up it draws these itself.
3669
- pendingText: turnIndex === 0 ? firstTurnHandover?.text : undefined, pendingAttachments: sentAttachmentsForTurn({
3670
- sentByMessage: sentAttachmentsByMessage,
3671
- messageId: turn.id,
3672
- originId: optimisticOriginOf(sessionId, turn.id),
3673
- isFirstTurn: turnIndex === 0,
3674
- firstTurnHandover: firstTurnHandover?.attachments,
3675
- firstTurnSent: firstPromptAttachments(projectSessionId),
3676
- queuedRowAttachments: inboxRowsByMessageId.get(turn.id)?.attachments,
3677
- }), uploadStatus: heldSendFailures?.[turn.id]
3678
- ? {
3679
- state: 'failed',
3680
- message: heldSendFailures[turn.id].message,
3681
- onRetry: () => retryHeldSend(sessionId, turn.id, resendHeldSend, (error) => classifySessionError(error).message),
3682
- }
3683
- : turnIndex === 0 && firstTurnHandover?.attachments.length
3684
- ? firstPromptUploadStatus
3685
- : undefined, sessionWorking: lastTurnWorking, isWorkingTurn: turn.live, suppressBusyIndicator: suppressWorkingTurnBusy, awaitingUser: awaitingUserInput,
3686
- // An idle send stays in the inbox until delivery,
3687
- // but nothing runs ahead of it: queued only while
3688
- // it waits behind a turn (`turnRendersQueued`).
3689
- // The first turn, with no turn working, has
3690
- // nothing ahead of it: a session's first prompt is
3691
- // starting, not queued, while the computer comes up
3692
- // and before the turn layer marks it queued or live.
3693
- pending: turnIndex === 0 && workingTurn.workingTurnId === null && !confirmedActive
3694
- ? pendingPrompt?.state === 'waiting' || pendingPrompt?.state === 'failed'
3695
- : turnRendersQueued({
3696
- turnId: turn.id,
3697
- resolution: workingTurn,
3698
- sessionWorking: lastTurnWorking,
3699
- confirmedActive,
3700
- inboxPrompt: pendingPrompt,
3701
- }), pendingPrompt: pendingPrompt, onRetryQueued: stableRetryQueued, onRemoveQueued: stableRemoveQueued, queuedPromptViewer: queuedPromptViewer, interruptedBeforeRun: interruptedTurnIds.has(turn.id), isCompaction: hasCompaction, onOpenCompactionSummary: panel ? stableOpenCompactionSummary : undefined, onOpenPastedContent: panel ? stableOpenPastedContent : undefined, providers: providers, commandMessages: commandMessagesRef.current, commands: commands, disableToolNavigation: disableToolNavigation, onPermissionReply: stablePermissionReply, onRewind: stableRewind, editingText: rewindTarget?.messageId === turn.id
3702
- ? rewindTarget.text
3703
- : null, editPending: editSendPending || !!sessionState?.rewindPending, onEditCancel: stableEditCancel, onEditSend: stableEditSend, rewindDisabled: !!readOnly ||
3704
- (rewindable !== null && !rewindable.has(turn.id)) ||
3705
- !runtimeCanRewind ||
3706
- !sessionState ||
3707
- isBusy ||
3708
- sessionState.rewindPending ||
3709
- // The runtime is not idle while queued prompts
3710
- // are still on their way to it — a rewind mid-
3711
- // delivery fails downstream with "Session is
3712
- // busy" (measured); refuse it up front instead.
3713
- promptInbox.prompts.length > 0 }, turnRenderKeys.get(turn.id)));
3714
- })] }) }), isOptimisticCompacting && !hasCompactionTurn && (_jsx("div", { className: turns.length > 0 ? 'mt-12' : 'mt-2', children: _jsx(CompactionMarker, { running: true }) })), [
3715
- ...(turnOutcome.recent_failures ?? []),
3716
- ...(turnOutcome.last_ended?.end_reason === 'failed' &&
3717
- !turnOutcome.recent_failures?.some((failure) => failure.message_id === turnOutcome.last_ended?.message_id)
3718
- ? [turnOutcome.last_ended]
3719
- : []),
3720
- ].filter((failure) => !isAbortError(failure.error) &&
3721
- !failureShownByTurn(failure, turns) &&
3722
- !failureSupersededByTurn(failure, turns) &&
3723
- (!failure.error?.message || failure.error.message !== commandError?.message)).map((failure) => {
3724
- const messageId = failure.message_id ?? 'persisted-turn-failure';
3725
- // Use the SDK's settle window for a cause that may arrive
3726
- // one frame later, including an unnamed failed last turn.
3727
- const notice = turnEndNotice({
3728
- ...turnOutcome,
3729
- recent_failures: [{ ...failure, message_id: messageId, error: failure.error ?? null }],
3730
- }, messageId, { hasError: false, isAbort: false });
3731
- return notice ? (_jsx(TurnErrorDisplay, { errorText: notice.kind === 'unexplained'
3732
- ? tHardcodedUi.raw('i18nComplete.text73112526c03a')
3733
- : persistedFailureText(failure.error), className: "mt-2" }, messageId)) : null;
3734
- }), commandError && (_jsx(TurnErrorDisplay, { error: commandError, isAbort: isAbortError(commandError.cause), modelOptions: modelOptions, className: "mt-2" })), showFallbackBusyRow && fallbackBusyRowTurnId === null && (rowsContext ? (
3735
- // A channel thread waits in the agent's answer row.
3736
- _jsx(AgentBusyRow, { sessionId: sessionId })) : (_jsx(SessionBusyIndicator, { sessionId: sessionId,
3737
- // Matches the stand-in's row spacing under a bubble
3738
- // (`OptimisticTurn`), so the crossfade into the real
3739
- // transcript does not move it. Nothing above it when
3740
- // the transcript is empty, so no margin there.
3741
- className: turns.length === 0 ? undefined : 'mt-6' })))] }), _jsx("div", { ref: spacerElRef, "data-scroll-spacer": true })] }) }), selectionPopup && (_jsx("div", { "data-reply-popup": true, className: "absolute z-50", style: {
3742
- left: `${selectionPopup.x}px`,
3743
- top: `${selectionPopup.y}px`,
3744
- transform: 'translate(-50%, -100%)',
3745
- }, children: _jsxs(Button, { onClick: handleSelectionReply, size: "sm", className: "animate-in fade-in-0 zoom-in-95 duration-normal origin-bottom px-3 text-xs ease-out has-[>svg]:px-3", children: [tHardcodedUi.raw('i18nComplete.textc253f451bdd5'), _jsx(ArrowBendUpLeftIcon, { className: "size-4 shrink-0" })] }) })), transcriptRows ? null : (_jsx(ChatMinimap, { turns: turns, scrollRef: scrollRef, contentRef: contentRef })), _jsx("div", { className: cn('absolute inset-x-0 bottom-4 z-20 flex justify-center', !showScrollButton && 'pointer-events-none'), children: _jsx(Button, { variant: "outline", size: "icon-md", "aria-hidden": !showScrollButton, tabIndex: showScrollButton ? undefined : -1, className: cn('hit-area-2 bg-background hover:bg-muted rounded-full', 'transition-[opacity,scale] ease-[cubic-bezier(0.23,1,0.32,1)] active:scale-[0.96] motion-reduce:scale-100 motion-reduce:transition-opacity', showScrollButton
3746
- ? 'duration-normal scale-100 opacity-100'
3747
- : 'duration-fast scale-[0.97] opacity-0'), onClick: smoothScrollToAbsoluteBottom, children: _jsx(CaretDownIcon, { className: "size-4" }) }) })] })), readOnly && inputReplacement ? (_jsx("div", { className: cn(COMPOSER_SHELL_CLASS, 'pb-4'), children: inputReplacement })) : null, !readOnly && (_jsx(_Fragment, { children: _jsx(SessionChatInput
3748
- // `undefined`, not `true`, once released: the composer's own
3749
- // viewport rule (>= 640px) still decides, so this never forces
3750
- // focus onto a phone keyboard.
3751
- , {
3752
- // `undefined`, not `true`, once released: the composer's own
3753
- // viewport rule (>= 640px) still decides, so this never forces
3754
- // focus onto a phone keyboard.
3755
- autoFocus: deferComposerFocus ? false : undefined, onSend: async (text, files, mentions, attachments, placement) => {
3756
- if (await queueEdit.save(text))
3757
- return;
3758
- // Enter while a turn runs steers it (D9.1); Cmd/Ctrl+Enter is Queue List.
3759
- await handleSend(text, files, mentions, attachments, composerSendDelivery(placement ?? 'transcript', isBusyRef.current));
3760
- }, prefill: composerPrefill, onPrefillApplied: (id) => {
3761
- useSessionComposerPrefillStore.getState().clearPrefill(sessionId, id);
3762
- },
3763
- // Up from the first row takes the queue back; the placeholder
3764
- // says so while there is something to take.
3765
- onArrowUpAtStart: () => queueEdit.takeBack(),
3766
- // A host placeholder ("Reply…") is static: the rotating tips would replace it.
3767
- hint: canTakeBackQueue ? tHardcodedUi.raw('i18nComplete.text03a01dd53ffa') : composerPlaceholder,
3768
- // Editing a queued message: the send saves it back into the
3769
- // queue, so the control says Submit, never Stop.
3770
- submitLabel: queueEdit.editing ? tQueue('submitEdit') : null, draftScope: composerDraftScope, draftActive: !deferComposerFocus, attachRequestId: attachRequestId, isBusy: isBusy,
3771
- // The ONE projection, not the 300 ms busy fade: it is what
3772
- // decides whether a `/` command may be dispatched, and a fade
3773
- // timer that has already lapsed would let one abort a live turn.
3774
- // `effectiveBusy` folds in optimistic compaction (not a turn, so
3775
- // not in `working`) and the retrying-turn predicate, so this
3776
- // site reads one value instead of re-OR-ing a term onto it.
3777
- sessionWorking: effectiveBusy,
3778
- // Gates `/` COMMANDS only. A prompt typed at a sleeping box is
3779
- // an inbox row and goes out when the box answers; a command has
3780
- // no row, and `runCommand` swallows it silently until the
3781
- // runtime is switched.
3782
- runtimeReady: runtimeReady, rewind: composerRewind, onStop: handleStop, canStop: canStop, escCount: escCount, agents: local.agent.list, selectedAgent: composerAgentName, onAgentChange: handleAgentChange, noAccessibleAgents: noAccessibleAgents, commands: chatCommands, commandsResolved: agentCommands !== undefined, slashFiles: chatSlashFiles, onOpenPastedContent: panel ? stableOpenPastedContent : undefined, onCommand: handleCommand, onHoldCommand: handleHoldCommand, models: local.model.list, selectedModel: local.model.currentKey ?? null, onModelChange: handleModelChange, modelDefaultControls: chatModelDefaultControls, variants: local.model.variant.list, selectedVariant: local.model.variant.current ?? null, onVariantChange: handleVariantChange, messages: messages, sessionId: sessionId, projectId: projectId, providers: providers, modelRequired: true, modelsLoading: providersLoading, onContextClick: handleContextClick, onCompactClick: runtimeCanCompact ? handleCompactClick : undefined, quoteRequests: quoteRequests, onQuoteRequestsApplied: handleQuoteRequestsApplied,
3783
- // Only lock the input into question-answer mode while the session is
3784
- // actually busy (a live question keeps the run busy). If a question
3785
- // chip is ever showing while the session is idle — e.g. a dead /
3786
- // abandoned question the agent left behind — the input stays unlocked
3787
- // so a typed message is sent to the agent instead of being swallowed
3788
- // as a custom answer.
3789
- lockForQuestion: !!renderedQuestion && isBusy,
3790
- // Same dead-prompt guard as questions: only lock while the agent is
3791
- // actually paused on the decision (isBusy), so a stale card can't
3792
- // swallow the composer on an idle session.
3793
- lockForApproval: runtimePermissionLocksComposer(pendingPermissions.length, isBusy), onCustomAnswer: handleCustomAnswer, questionButtonLabel: renderedQuestion ? questionAction.label : null, questionActive: !!renderedQuestion || approvalDocked, questionCanAct: questionAction.canAct, onQuestionAction: handleQuestionAction, aboveSlot: chatAboveSlot, inputSlot: chatInputSlot, toolbarSlot: chatToolbarSlot,
3794
- // The shell can now render on a cached transcript alone, i.e. before
3795
- // the sandbox answers — so sending has to be gated separately from
3796
- // reading. See sessionComposerReadiness.
3797
- notice: hostNotice(composerReadiness.notice, rowsContext?.notices), noticeAsleep: composerReadiness.notice === SESSION_NOTICE.idle,
3798
- // Inside the thread panel's bordered box, as the channel composer.
3799
- // A phone keeps the row under the card; a 720px desktop window does not.
3800
- underbarPlacement: transcriptRows && !isPhone ? 'inline' : undefined,
3801
- // The panel's toolbar is narrow: the agent is its tile, the model keeps its name.
3802
- agentPickerCompact: transcriptRows && !isPhone,
3803
- // A thread panel's rows run `px-5`, and the channel composer
3804
- // beside it sits `pb-4` off the window's bottom edge: the same
3805
- // margins, so the two boxes line up.
3806
- parentClassName: transcriptRows ? 'max-w-none px-5 pb-4' : undefined, onNoticeRetry: composerReadiness.notice && composerReadiness.retryable
3807
- ? requestRuntimeReconnect
3808
- : undefined }) }))] })] }) }) }));
3528
+ _jsx(ReadOnlySessionContext.Provider, { value: !!readOnly, children: _jsx(SessionPromptContext.Provider, { value: readOnly ? null : sendSessionPrompt, children: _jsx(ProjectFilesProvider, { value: { projectId: projectId ?? '', ref: outcomesBaseRef, defaultBranch: outcomesBaseRef }, children: _jsxs(ComposerDropZone, { className: cn('relative flex h-full flex-col',
3529
+ // Transparent in the welcome state so the root-level full-bleed wallpaper
3530
+ // (portaled into SessionLayout) reads through; solid once real content
3531
+ // takes over. Same base color either way, so non-welcome is unchanged.
3532
+ shouldShowWelcomeOverlay ? 'bg-transparent' : 'bg-background'), "data-testid": "session-chat", children: [isPreparingPrint && (_jsxs("div", { "data-print-hide": true, role: "status", className: "bg-popover text-muted-foreground fixed bottom-6 left-1/2 z-50 flex -translate-x-1/2 items-center gap-2 rounded-lg border px-4 py-2 text-xs shadow-lg", children: [_jsx(Loading, { className: "size-3.5 shrink-0" }), tHardcodedUi.raw('i18nComplete.text7dac2ca010fe')] })), wallpaperLayer
3533
+ ? welcomeWallpaper && createPortal(welcomeWallpaper, wallpaperLayer)
3534
+ : welcomeWallpaper, !hideHeader && (_jsx(SessionSiteHeader, { sessionId: sessionId, sessionTitle: session?.title || 'Untitled', leadingAction: headerLeadingAction, parent: parentCrumb })), _jsx(SessionContextModal, { open: contextModalOpen, onOpenChange: setContextModalOpen,
3535
+ // A chat with no `useSession` source: the raw explorer lists the
3536
+ // rows `useSessionSync` read for it.
3537
+ detachedRows: sessionState ? undefined : hookMessages, source: sessionState ?? DETACHED_SESSION_MESSAGES, session: session, sessionRow: projectSessionRow, providers: providers, allSessions: allSessions, servedModel: sessionServedModel, billedCost: sessionBilledCost(modelUsage) }), _jsx(CompactModal, { sessionId: sessionId, open: compactModalOpen, onOpenChange: setCompactModalOpen }), _jsx(ChangeRequestDetailDialog, { crId: openCrId, onClose: () => setOpenCrId(null), onOpenChangeRequest: setOpenCrId }), _jsxs(SessionBodyRow, { actionPanel: !hideHeader && !readOnly, children: [isNotFound ? (_jsxs("div", { className: "flex min-h-0 flex-1 flex-col items-center justify-center gap-3 px-6 text-center", children: [_jsx("div", { className: "text-muted-foreground text-sm", children: tHardcodedUi.raw('componentsSessionSessionChat.line5821JsxTextThisSessionIsNotAccessibleRightNow') }), _jsx(Button, { asChild: true, variant: "outline", size: "sm", children: _jsx(Link, { href: "/", prefetch: true, onClick: () => {
3538
+ try {
3539
+ if (sessionId)
3540
+ useTabStore.getState().closeTab?.(sessionId);
3541
+ }
3542
+ catch { }
3543
+ }, children: tHardcodedUi.raw('componentsSessionSessionChat.line5833JsxTextGoToHome') }) })] })) : (_jsxs("div", { ref: chatAreaRef, className: "relative z-10 min-h-0 flex-1", children: [_jsx("div", { ref: scrollContainerCallbackRef, className: cn(
3544
+ // overflow-anchor:none — this scroll area does ALL of its own
3545
+ // anchoring (useAutoScroll's spacer + RAF follow, the send-path
3546
+ // turn anchor, and the history-prepend content-space restore in
3547
+ // session-history-scroll.ts). The browser's native scroll
3548
+ // anchoring (default `overflow-anchor: auto`) tries to
3549
+ // compensate for the SAME prepends independently, and the two
3550
+ // corrections stacking is the other half of the scroll-up
3551
+ // teleport: ours restores the reader's position, then the
3552
+ // native one nudges it again.
3553
+ 'scrollbar-hide relative z-10 h-full flex-1 overflow-y-auto [scroll-behavior:auto] [overflow-anchor:none]', shouldShowWelcomeOverlay ? 'bg-transparent' : 'bg-background'), onMouseUp: handleChatMouseUp, onMouseDown: handleChatMouseDown, onScroll: handleChatScroll, children: _jsxs("div", { ref: contentRef, role: "log",
3554
+ // Width and gutters live in `SESSION_TRANSCRIPT_CLASS`: the
3555
+ // instant shell draws this same column and the two crossfade
3556
+ // into each other, so a difference here is a sideways jump on
3557
+ // screen, not a style opinion. See session-body.tsx.
3558
+ //
3559
+ // No bottom padding, there or here: the space under the last
3560
+ // message is the auto-scroll spacer's job alone. The `pb-32`
3561
+ // that used to sit here stacked 128px of dead space on top of
3562
+ // it — the "extra inset at the bottom of the session".
3563
+ // Rows run edge to edge: each row owns its gutters and its hover fill.
3564
+ className: transcriptRows ? 'w-full min-w-0 pt-4' : SESSION_TRANSCRIPT_CLASS, children: [_jsxs("div", { className: "flex min-w-0 flex-col", children: [_jsx(SessionPrintHeader, { title: session?.title || 'Untitled', agentName: composerAgentName }), (hasOlder || showOlderLoading) && (_jsxs("div", { className: "mb-6 flex flex-col items-center gap-2", children: [hasOlder && (_jsx("div", { ref: olderSentinelRef, "aria-hidden": true, className: "h-px w-full" })), showOlderLoading && (_jsxs("div", { role: "status", className: "text-muted-foreground flex items-center gap-2 py-1 text-xs", children: [_jsx(Loading, { className: "size-3.5 shrink-0" }), tHardcodedUi.raw('i18nComplete.text85bf890776a7')] })), !showOlderLoading &&
3565
+ !olderPullFailed &&
3566
+ olderAutoloadExhausted({ hasOlder, autoLoadedPages }) && (_jsx(Button, { type: "button", variant: "outline-ghost", size: "sm", onClick: () => void handleLoadOlder(), children: tHardcodedUi.raw('i18nComplete.textf17671d83db0') })), olderPullFailed && !showOlderLoading && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-muted-foreground text-xs", children: tHardcodedUi.raw('i18nComplete.textb03a0041ce33') }), _jsx(Button, { type: "button", variant: "outline-ghost", size: "sm", onClick: () => void handleLoadOlder(), children: tHardcodedUi.raw('i18nComplete.text942087cc2d41') })] }))] })), restoreNotice && !restoreDismissed && (_jsx(RestoreNotice, { notice: restoreNotice, onDismiss: () => dismissRestore(historyKey, restoreNotice.generation) })), _jsx(SessionOutcomesProvider, { projectSessionId: projectSessionId, turnSpans: turnSpans, busy: effectiveBusy, onOpen: handleOpenOutcome, onJump: handleJumpToOutcome, jumping: jumpingToOutcome, children: _jsxs(ToolActivateContext.Provider, { value: toolActivate, children: [showFirstPromptPreview &&
3567
+ firstPromptSource &&
3568
+ queuedSyntheticMessages.length === 0 &&
3569
+ rowsContext && (
3570
+ // A channel thread draws the stand-in as rows, the same
3571
+ // rows its boot body drew (`ThreadBootRows`).
3572
+ _jsx(PendingPromptRows, { text: buildOptimisticPromptTextWithUploads(firstPromptSource.text, firstPromptSource.files), author: rowsContext.owner, sessionId: sessionId, busy: turns.length === 0 && (lastTurnWorking || promptInbox.prompts.some(isFirstPromptRow)) })), showFirstPromptPreview &&
3573
+ firstPromptSource &&
3574
+ queuedSyntheticMessages.length === 0 &&
3575
+ !rowsContext && (_jsx(OptimisticTurn, { text: buildOptimisticPromptTextWithUploads(firstPromptSource.text, firstPromptSource.files),
3576
+ // Preserve a real failed-send status through the
3577
+ // boot-shell handover without inventing upload progress.
3578
+ // A first prompt held on its uploads carries its own.
3579
+ uploadStatus: firstPromptSource.uploadStatus ?? firstPromptUploadStatus, agentNames: agentNames, onFileClick: openFileInComputer, sessionId: sessionId,
3580
+ // The first item of the conversation, like turn 0, which has no
3581
+ // top margin. `first:mt-0` misses here: the list opens with a
3582
+ // zero-height <header>, so the stand-in sat 44px lower than turn 0
3583
+ // and every swap between the two jumped the bubble (KRTX-2931).
3584
+ className: "mt-0",
3585
+ // An undelivered first prompt is a turn about to start, as the
3586
+ // shell above this chat shows it: busy from the first frame,
3587
+ // before the working projection has read the inbox (KRTX-2931).
3588
+ busy: turns.length === 0 && (lastTurnWorking || promptInbox.prompts.some(isFirstPromptRow)) })), turns.map((turn, turnIndex) => {
3589
+ // Check if this turn is a compaction summary — and
3590
+ // whether it actually PRODUCED one. A failed/aborted
3591
+ // attempt (compaction-flagged, no content, not the
3592
+ // working turn) renders as one slim row, draws no
3593
+ // divider, and stacks tight against a neighbouring
3594
+ // failed attempt.
3595
+ const compaction = turn.compaction;
3596
+ const hasCompaction = compaction !== null;
3597
+ const isTurnWorking = turn.live;
3598
+ // `inFlight` (message state) alongside the projection:
3599
+ // classifying by projection alone flipped a streaming
3600
+ // compaction to "failed" for the frames where the two
3601
+ // disagree, popping the divider in and out — a layout
3602
+ // bounce right where the reader is looking.
3603
+ const isFailedCompaction = compaction !== null &&
3604
+ !compaction.hasContent &&
3605
+ !compaction.inFlight &&
3606
+ !isTurnWorking;
3607
+ // Retries collapse to ONE visible row, GLOBALLY: a
3608
+ // failed attempt with ANY later compaction turn (a
3609
+ // retry, or the one that finally landed) is history —
3610
+ // it keeps its TurnViewport (stable keys, scroll
3611
+ // anchors) but renders no content, and an empty
3612
+ // TurnViewport costs 0px (turn-viewport.tsx RULE 2).
3613
+ // Adjacency was not enough: attempts whose error landed
3614
+ // on a plain assistant message used to interleave as
3615
+ // unclassified turns, breaking every consecutive run.
3616
+ const suppressedFailedCompaction = isFailedCompaction && turnIndex < lastCompactionTurnIndex;
3617
+ // Notification-only early-return removed: it rendered the
3618
+ // user's pty_* card but skipped the turn's replies,
3619
+ // hiding every subsequent assistant response in that turn.
3620
+ // Fall through to the normal turn renderer instead.
3621
+ const confirmedActive = turnIsConfirmedActive({
3622
+ isTurnWorking,
3623
+ turnId: turn.id,
3624
+ activeTurnId,
3625
+ pendingDelivery: !!working.pendingDelivery,
3626
+ });
3627
+ const pendingPrompt = !confirmedActive && turn.assistant.length === 0
3628
+ ? pendingPromptsByMessageId.get(turn.id)
3629
+ : undefined;
3630
+ // A queued prompt is not in the runtime transcript yet;
3631
+ // its author still shows (`authorForTurn`).
3632
+ const turnAuthor = authorForTurn(transcriptAuthors, messageAuthors, turn.id, pendingPrompt?.wire_message_id);
3633
+ return (_jsx(TranscriptTurnRow
3634
+ // ONE element per prompt: keyed by the id the
3635
+ // bubble was FIRST painted under, so the swap to a
3636
+ // re-minted echo id re-renders this node instead
3637
+ // of mounting a new one (opacity keeps animating,
3638
+ // hover state survives, nothing jumps).
3639
+ , { turnId: turn.id, modelOptions: modelOptions, suppressed: suppressedFailedCompaction, continuedWith: harnessSwitches.get(turn.id)?.harness, fullTextState: loaded.state[turn.id] ?? 'idle', onLoadFullText: loadFullTexts, showBusyRow: showFallbackBusyRow &&
3640
+ fallbackBusyRowTurnId === turn.id,
3641
+ // Queued bubbles STACK: a pending turn right after
3642
+ // another pending turn sits close to it, like a
3643
+ // list of what is waiting — not a turn's width
3644
+ // apart as if each had been answered in between.
3645
+ // (Failed compaction rows need no stacking rule any
3646
+ // more — at most one is visible at a time.)
3647
+ viewportClassName: turnIndex === 0 || transcriptRows
3648
+ ? ''
3649
+ : // A compaction and the work after it continue the turn above.
3650
+ turn.compaction || turn.continues
3651
+ ? 'mt-6'
3652
+ : lastTurnWorking &&
3653
+ pendingTurnIds.has(turn.id) &&
3654
+ pendingTurnIds.has(turns[turnIndex - 1].id)
3655
+ ? 'mt-3'
3656
+ : 'mt-12', turn: turn, author: turnAuthor, showAuthor: showAuthorName(turnAuthor, groupChat, viewerId), stoppedBy: stoppedByName(messageAuthors, turn.id, viewerId), servedModel: servedModelOfTurn(modelUsage, turn.id, turns[turnIndex - 1]?.id), turnOutcome: turnOutcome, isLast: turn.id === lastUserMessageId, ownsPlan: turn.id === planAnchorId, sessionId: sessionId, projectId: projectId, projectSessionId: projectSessionId, sessionStatus: sessionStatus, permissions: pendingPermissions, questions: pendingQuestions, agentNames: agentNames, isFirstTurn: turnIndex === 0,
3657
+ // Handed over only once the stand-in has stepped
3658
+ // aside — while it is up it draws these itself.
3659
+ pendingText: turnIndex === 0 ? firstTurnHandover?.text : undefined, pendingAttachments: sentAttachmentsForTurn({
3660
+ sentByMessage: sentAttachmentsByMessage,
3661
+ messageId: turn.id,
3662
+ originId: optimisticOriginOf(sessionId, turn.id),
3663
+ isFirstTurn: turnIndex === 0,
3664
+ firstTurnHandover: firstTurnHandover?.attachments,
3665
+ firstTurnSent: firstPromptAttachments(projectSessionId),
3666
+ queuedRowAttachments: inboxRowsByMessageId.get(turn.id)?.attachments,
3667
+ }), uploadStatus: heldSendFailures?.[turn.id]
3668
+ ? {
3669
+ state: 'failed',
3670
+ message: heldSendFailures[turn.id].message,
3671
+ onRetry: () => retryHeldSend(sessionId, turn.id, resendHeldSend, (error) => classifySessionError(error).message),
3672
+ }
3673
+ : turnIndex === 0 && firstTurnHandover?.attachments.length
3674
+ ? firstPromptUploadStatus
3675
+ : undefined, sessionWorking: lastTurnWorking, isWorkingTurn: turn.live, suppressBusyIndicator: suppressWorkingTurnBusy, awaitingUser: awaitingUserInput,
3676
+ // An idle send stays in the inbox until delivery,
3677
+ // but nothing runs ahead of it: queued only while
3678
+ // it waits behind a turn (`turnRendersQueued`).
3679
+ // The first turn, with no turn working, has
3680
+ // nothing ahead of it: a session's first prompt is
3681
+ // starting, not queued, while the computer comes up
3682
+ // and before the turn layer marks it queued or live.
3683
+ pending: turnIndex === 0 && workingTurn.workingTurnId === null && !confirmedActive
3684
+ ? pendingPrompt?.state === 'waiting' || pendingPrompt?.state === 'failed'
3685
+ : turnRendersQueued({
3686
+ turnId: turn.id,
3687
+ resolution: workingTurn,
3688
+ sessionWorking: lastTurnWorking,
3689
+ confirmedActive,
3690
+ inboxPrompt: pendingPrompt,
3691
+ }), pendingPrompt: pendingPrompt, onRetryQueued: stableRetryQueued, onRemoveQueued: stableRemoveQueued, queuedPromptViewer: queuedPromptViewer, interruptedBeforeRun: interruptedTurnIds.has(turn.id), isCompaction: hasCompaction, onOpenCompactionSummary: panel ? stableOpenCompactionSummary : undefined, onOpenPastedContent: panel ? stableOpenPastedContent : undefined, providers: providers, commandMessages: commandMessagesRef.current, commands: commands, disableToolNavigation: disableToolNavigation, onPermissionReply: stablePermissionReply, onRewind: stableRewind, editingText: rewindTarget?.messageId === turn.id
3692
+ ? rewindTarget.text
3693
+ : null, editPending: editSendPending || !!sessionState?.rewindPending, onEditCancel: stableEditCancel, onEditSend: stableEditSend, rewindDisabled: !!readOnly ||
3694
+ (rewindable !== null && !rewindable.has(turn.id)) ||
3695
+ !runtimeCanRewind ||
3696
+ !sessionState ||
3697
+ isBusy ||
3698
+ sessionState.rewindPending ||
3699
+ // The runtime is not idle while queued prompts
3700
+ // are still on their way to it — a rewind mid-
3701
+ // delivery fails downstream with "Session is
3702
+ // busy" (measured); refuse it up front instead.
3703
+ promptInbox.prompts.length > 0 }, turnRenderKeys.get(turn.id)));
3704
+ })] }) }), isOptimisticCompacting && !hasCompactionTurn && (_jsx("div", { className: turns.length > 0 ? 'mt-12' : 'mt-2', children: _jsx(CompactionMarker, { running: true }) })), [
3705
+ ...(turnOutcome.recent_failures ?? []),
3706
+ ...(turnOutcome.last_ended?.end_reason === 'failed' &&
3707
+ !turnOutcome.recent_failures?.some((failure) => failure.message_id === turnOutcome.last_ended?.message_id)
3708
+ ? [turnOutcome.last_ended]
3709
+ : []),
3710
+ ].filter((failure) => !isAbortError(failure.error) &&
3711
+ !failureShownByTurn(failure, turns) &&
3712
+ !failureSupersededByTurn(failure, turns) &&
3713
+ (!failure.error?.message || failure.error.message !== commandError?.message)).map((failure) => {
3714
+ const messageId = failure.message_id ?? 'persisted-turn-failure';
3715
+ // Use the SDK's settle window for a cause that may arrive
3716
+ // one frame later, including an unnamed failed last turn.
3717
+ const notice = turnEndNotice({
3718
+ ...turnOutcome,
3719
+ recent_failures: [{ ...failure, message_id: messageId, error: failure.error ?? null }],
3720
+ }, messageId, { hasError: false, isAbort: false });
3721
+ return notice ? (_jsx(TurnErrorDisplay, { errorText: notice.kind === 'unexplained'
3722
+ ? tHardcodedUi.raw('i18nComplete.text73112526c03a')
3723
+ : persistedFailureText(failure.error), className: "mt-2" }, messageId)) : null;
3724
+ }), commandError && (_jsx(TurnErrorDisplay, { error: commandError, isAbort: isAbortError(commandError.cause), modelOptions: modelOptions, className: "mt-2" })), showFallbackBusyRow && fallbackBusyRowTurnId === null && (rowsContext ? (
3725
+ // A channel thread waits in the agent's answer row.
3726
+ _jsx(AgentBusyRow, { sessionId: sessionId })) : (_jsx(SessionBusyIndicator, { sessionId: sessionId,
3727
+ // Matches the stand-in's row spacing under a bubble
3728
+ // (`OptimisticTurn`), so the crossfade into the real
3729
+ // transcript does not move it. Nothing above it when
3730
+ // the transcript is empty, so no margin there.
3731
+ className: turns.length === 0 ? undefined : 'mt-6' })))] }), _jsx("div", { ref: spacerElRef, "data-scroll-spacer": true })] }) }), selectionPopup && (_jsx("div", { "data-reply-popup": true, className: "absolute z-50", style: {
3732
+ left: `${selectionPopup.x}px`,
3733
+ top: `${selectionPopup.y}px`,
3734
+ transform: 'translate(-50%, -100%)',
3735
+ }, children: _jsxs(Button, { onClick: handleSelectionReply, size: "sm", className: "animate-in fade-in-0 zoom-in-95 duration-normal origin-bottom px-3 text-xs ease-out has-[>svg]:px-3", children: [tHardcodedUi.raw('i18nComplete.textc253f451bdd5'), _jsx(ArrowBendUpLeftIcon, { className: "size-4 shrink-0" })] }) })), transcriptRows ? null : (_jsx(ChatMinimap, { turns: turns, scrollRef: scrollRef, contentRef: contentRef })), _jsx("div", { className: cn('absolute inset-x-0 bottom-4 z-20 flex justify-center', !showScrollButton && 'pointer-events-none'), children: _jsx(Button, { variant: "outline", size: "icon-md", "aria-hidden": !showScrollButton, tabIndex: showScrollButton ? undefined : -1, className: cn('hit-area-2 bg-background hover:bg-muted rounded-full', 'transition-[opacity,scale] ease-[cubic-bezier(0.23,1,0.32,1)] active:scale-[0.96] motion-reduce:scale-100 motion-reduce:transition-opacity', showScrollButton
3736
+ ? 'duration-normal scale-100 opacity-100'
3737
+ : 'duration-fast scale-[0.97] opacity-0'), onClick: smoothScrollToAbsoluteBottom, children: _jsx(CaretDownIcon, { className: "size-4" }) }) })] })), readOnly && inputReplacement ? (_jsx("div", { className: cn(COMPOSER_SHELL_CLASS, 'pb-4'), children: inputReplacement })) : null, !readOnly && (_jsxs(_Fragment, { children: [_jsx(SessionChatInput
3738
+ // `undefined`, not `true`, once released: the composer's own
3739
+ // viewport rule (>= 640px) still decides, so this never forces
3740
+ // focus onto a phone keyboard.
3741
+ , {
3742
+ // `undefined`, not `true`, once released: the composer's own
3743
+ // viewport rule (>= 640px) still decides, so this never forces
3744
+ // focus onto a phone keyboard.
3745
+ autoFocus: deferComposerFocus ? false : undefined, onSend: async (text, files, mentions, attachments, placement) => {
3746
+ if (await queueEdit.save(text))
3747
+ return;
3748
+ // Enter while a turn runs steers it (D9.1); Cmd/Ctrl+Enter is Queue List.
3749
+ await handleSend(text, files, mentions, attachments, composerSendDelivery(placement ?? 'transcript', isBusyRef.current));
3750
+ }, prefill: composerPrefill, onPrefillApplied: (id) => {
3751
+ useSessionComposerPrefillStore.getState().clearPrefill(sessionId, id);
3752
+ },
3753
+ // Up from the first row takes the queue back; the placeholder
3754
+ // says so while there is something to take.
3755
+ onArrowUpAtStart: () => queueEdit.takeBack(),
3756
+ // A host placeholder ("Reply…") is static: the rotating tips would replace it.
3757
+ hint: canTakeBackQueue ? tHardcodedUi.raw('i18nComplete.text03a01dd53ffa') : composerPlaceholder,
3758
+ // Editing a queued message: the send saves it back into the
3759
+ // queue, so the control says Submit, never Stop.
3760
+ submitLabel: queueEdit.editing ? tQueue('submitEdit') : null, draftScope: composerDraftScope, draftActive: !deferComposerFocus, attachRequestId: attachRequestId, isBusy: isBusy,
3761
+ // The ONE projection, not the 300 ms busy fade: it is what
3762
+ // decides whether a `/` command may be dispatched, and a fade
3763
+ // timer that has already lapsed would let one abort a live turn.
3764
+ // `effectiveBusy` folds in optimistic compaction (not a turn, so
3765
+ // not in `working`) and the retrying-turn predicate, so this
3766
+ // site reads one value instead of re-OR-ing a term onto it.
3767
+ sessionWorking: effectiveBusy,
3768
+ // Gates `/` COMMANDS only. A prompt typed at a sleeping box is
3769
+ // an inbox row and goes out when the box answers; a command has
3770
+ // no row, and `runCommand` swallows it silently until the
3771
+ // runtime is switched.
3772
+ runtimeReady: runtimeReady, rewind: composerRewind, onStop: handleStop, canStop: canStop, escCount: escCount, agents: local.agent.list, selectedAgent: composerAgentName, onAgentChange: handleAgentChange, noAccessibleAgents: noAccessibleAgents, commands: chatCommands, commandsResolved: agentCommands !== undefined, slashFiles: chatSlashFiles, onOpenPastedContent: panel ? stableOpenPastedContent : undefined, onCommand: handleCommand, onHoldCommand: handleHoldCommand, models: local.model.list, selectedModel: local.model.currentKey ?? null, onModelChange: handleModelChange, modelDefaultControls: chatModelDefaultControls, variants: local.model.variant.list, selectedVariant: local.model.variant.current ?? null, onVariantChange: handleVariantChange, messages: messages, sessionId: sessionId, projectId: projectId, providers: providers, modelRequired: true, modelsLoading: providersLoading, onContextClick: handleContextClick, onCompactClick: runtimeCanCompact ? handleCompactClick : undefined, quoteRequests: quoteRequests, onQuoteRequestsApplied: handleQuoteRequestsApplied,
3773
+ // Only lock the input into question-answer mode while the session is
3774
+ // actually busy (a live question keeps the run busy). If a question
3775
+ // chip is ever showing while the session is idle — e.g. a dead /
3776
+ // abandoned question the agent left behind — the input stays unlocked
3777
+ // so a typed message is sent to the agent instead of being swallowed
3778
+ // as a custom answer.
3779
+ lockForQuestion: !!renderedQuestion && isBusy,
3780
+ // Same dead-prompt guard as questions: only lock while the agent is
3781
+ // actually paused on the decision (isBusy), so a stale card can't
3782
+ // swallow the composer on an idle session.
3783
+ lockForApproval: runtimePermissionLocksComposer(pendingPermissions.length, isBusy), onCustomAnswer: handleCustomAnswer, questionButtonLabel: renderedQuestion ? questionAction.label : null, questionActive: !!renderedQuestion || approvalDocked, questionCanAct: questionAction.canAct, onQuestionAction: handleQuestionAction, aboveSlot: chatAboveSlot, inputSlot: chatInputSlot, toolbarSlot: chatToolbarSlot, underbarSlot: chatUnderbarSlot,
3784
+ // The shell can now render on a cached transcript alone, i.e. before
3785
+ // the sandbox answers — so sending has to be gated separately from
3786
+ // reading. See sessionComposerReadiness.
3787
+ notice: hostNotice(composerReadiness.notice, rowsContext?.notices),
3788
+ // Inside the thread panel's bordered box, as the channel composer.
3789
+ // A phone keeps the row under the card; a 720px desktop window does not.
3790
+ underbarPlacement: transcriptRows && !isPhone ? 'inline' : undefined,
3791
+ // The panel's toolbar is narrow: the agent is its tile, the model keeps its name.
3792
+ agentPickerCompact: transcriptRows && !isPhone,
3793
+ // A thread panel's rows run `px-5`, and the channel composer
3794
+ // beside it sits `pb-4` off the window's bottom edge: the same
3795
+ // margins, so the two boxes line up.
3796
+ parentClassName: transcriptRows ? 'max-w-none px-5 pb-4' : undefined, onNoticeRetry: composerReadiness.notice && composerReadiness.retryable
3797
+ ? requestRuntimeReconnect
3798
+ : undefined }), _jsx("div", { className: cn(COMPOSER_SHELL_CLASS, 'pb-3 empty:hidden', transcriptRows && 'max-w-none px-5'), children: _jsx(HeldMessages, { projectId: projectId, sessionId: projectSessionId }) })] }))] })] }) }) }) }));
3809
3799
  }