@stigmer/react 3.1.1 → 3.1.3

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 (483) hide show
  1. package/composer/SessionComposer.d.ts +25 -1
  2. package/composer/SessionComposer.d.ts.map +1 -1
  3. package/composer/SessionComposer.js +19 -8
  4. package/composer/SessionComposer.js.map +1 -1
  5. package/execution/ArtifactContentRenderer.d.ts +11 -1
  6. package/execution/ArtifactContentRenderer.d.ts.map +1 -1
  7. package/execution/ArtifactContentRenderer.js +39 -15
  8. package/execution/ArtifactContentRenderer.js.map +1 -1
  9. package/execution/ArtifactPreviewModal.d.ts +5 -5
  10. package/execution/ArtifactPreviewModal.js +4 -4
  11. package/execution/ArtifactPreviewModal.js.map +1 -1
  12. package/execution/FileChangeProgressBar.d.ts +47 -0
  13. package/execution/FileChangeProgressBar.d.ts.map +1 -0
  14. package/execution/FileChangeProgressBar.js +49 -0
  15. package/execution/FileChangeProgressBar.js.map +1 -0
  16. package/execution/FileChangesView.d.ts.map +1 -1
  17. package/execution/FileChangesView.js +19 -4
  18. package/execution/FileChangesView.js.map +1 -1
  19. package/execution/FilePathContext.d.ts +8 -1
  20. package/execution/FilePathContext.d.ts.map +1 -1
  21. package/execution/FilePathContext.js.map +1 -1
  22. package/execution/FilePathLink.d.ts.map +1 -1
  23. package/execution/FilePathLink.js +21 -6
  24. package/execution/FilePathLink.js.map +1 -1
  25. package/execution/FileReviewAtoms.d.ts +27 -0
  26. package/execution/FileReviewAtoms.d.ts.map +1 -0
  27. package/execution/FileReviewAtoms.js +64 -0
  28. package/execution/FileReviewAtoms.js.map +1 -0
  29. package/execution/FileReviewCard.d.ts +2 -2
  30. package/execution/FileReviewCard.d.ts.map +1 -1
  31. package/execution/FileReviewCard.js +32 -62
  32. package/execution/FileReviewCard.js.map +1 -1
  33. package/execution/MessageEntry.d.ts +20 -0
  34. package/execution/MessageEntry.d.ts.map +1 -1
  35. package/execution/MessageEntry.js +19 -5
  36. package/execution/MessageEntry.js.map +1 -1
  37. package/execution/MessageThread.d.ts +75 -13
  38. package/execution/MessageThread.d.ts.map +1 -1
  39. package/execution/MessageThread.js +195 -27
  40. package/execution/MessageThread.js.map +1 -1
  41. package/execution/PlanArtifactCard.d.ts +36 -21
  42. package/execution/PlanArtifactCard.d.ts.map +1 -1
  43. package/execution/PlanArtifactCard.js +39 -25
  44. package/execution/PlanArtifactCard.js.map +1 -1
  45. package/execution/PlanCompletionCard.d.ts +4 -4
  46. package/execution/PlanCompletionCard.d.ts.map +1 -1
  47. package/execution/PlanCompletionCard.js +4 -4
  48. package/execution/PlanCompletionCard.js.map +1 -1
  49. package/execution/PlanDocumentMessage.d.ts +32 -0
  50. package/execution/PlanDocumentMessage.d.ts.map +1 -0
  51. package/execution/PlanDocumentMessage.js +37 -0
  52. package/execution/PlanDocumentMessage.js.map +1 -0
  53. package/execution/PlanStreamingCard.d.ts +50 -0
  54. package/execution/PlanStreamingCard.d.ts.map +1 -0
  55. package/execution/PlanStreamingCard.js +40 -0
  56. package/execution/PlanStreamingCard.js.map +1 -0
  57. package/execution/index.d.ts +9 -1
  58. package/execution/index.d.ts.map +1 -1
  59. package/execution/index.js +4 -0
  60. package/execution/index.js.map +1 -1
  61. package/execution/use-build-from-plan-hotkey.d.ts +1 -1
  62. package/execution/use-build-from-plan-hotkey.js +1 -1
  63. package/execution/useArtifactCopy.d.ts +51 -0
  64. package/execution/useArtifactCopy.d.ts.map +1 -0
  65. package/execution/useArtifactCopy.js +75 -0
  66. package/execution/useArtifactCopy.js.map +1 -0
  67. package/execution/useArtifactDownload.d.ts.map +1 -1
  68. package/execution/useArtifactDownload.js +17 -5
  69. package/execution/useArtifactDownload.js.map +1 -1
  70. package/execution/useCreateAgentExecution.d.ts +12 -0
  71. package/execution/useCreateAgentExecution.d.ts.map +1 -1
  72. package/execution/useCreateAgentExecution.js +5 -1
  73. package/execution/useCreateAgentExecution.js.map +1 -1
  74. package/github/decodeGitHubContent.d.ts +29 -0
  75. package/github/decodeGitHubContent.d.ts.map +1 -0
  76. package/github/decodeGitHubContent.js +72 -0
  77. package/github/decodeGitHubContent.js.map +1 -0
  78. package/github/index.d.ts +1 -0
  79. package/github/index.d.ts.map +1 -1
  80. package/github/index.js +1 -0
  81. package/github/index.js.map +1 -1
  82. package/github/useGitHubFileReader.d.ts +26 -0
  83. package/github/useGitHubFileReader.d.ts.map +1 -0
  84. package/github/useGitHubFileReader.js +106 -0
  85. package/github/useGitHubFileReader.js.map +1 -0
  86. package/github/useGitHubTreeLister.d.ts.map +1 -1
  87. package/github/useGitHubTreeLister.js +6 -2
  88. package/github/useGitHubTreeLister.js.map +1 -1
  89. package/index.d.ts +9 -9
  90. package/index.d.ts.map +1 -1
  91. package/index.js +5 -5
  92. package/index.js.map +1 -1
  93. package/internal/ResizableSplit.d.ts +72 -22
  94. package/internal/ResizableSplit.d.ts.map +1 -1
  95. package/internal/ResizableSplit.js +96 -38
  96. package/internal/ResizableSplit.js.map +1 -1
  97. package/internal/VirtualizedThread.d.ts +5 -3
  98. package/internal/VirtualizedThread.d.ts.map +1 -1
  99. package/internal/VirtualizedThread.js +6 -4
  100. package/internal/VirtualizedThread.js.map +1 -1
  101. package/internal/file-icons/index.d.ts +17 -0
  102. package/internal/file-icons/index.d.ts.map +1 -0
  103. package/internal/file-icons/index.js +60 -0
  104. package/internal/file-icons/index.js.map +1 -0
  105. package/internal/file-tree/FileTreeNode.d.ts +18 -1
  106. package/internal/file-tree/FileTreeNode.d.ts.map +1 -1
  107. package/internal/file-tree/FileTreeNode.js +11 -2
  108. package/internal/file-tree/FileTreeNode.js.map +1 -1
  109. package/internal/markdown-components.d.ts +38 -1
  110. package/internal/markdown-components.d.ts.map +1 -1
  111. package/internal/markdown-components.js +86 -11
  112. package/internal/markdown-components.js.map +1 -1
  113. package/{workflow → internal}/motion-preference.d.ts +7 -4
  114. package/internal/motion-preference.d.ts.map +1 -0
  115. package/{workflow → internal}/motion-preference.js +7 -4
  116. package/internal/motion-preference.js.map +1 -0
  117. package/internal/store/index.d.ts +33 -0
  118. package/internal/store/index.d.ts.map +1 -1
  119. package/internal/store/index.js +59 -0
  120. package/internal/store/index.js.map +1 -1
  121. package/internal/store/workspace-editors-store.d.ts +145 -0
  122. package/internal/store/workspace-editors-store.d.ts.map +1 -0
  123. package/internal/store/workspace-editors-store.js +208 -0
  124. package/internal/store/workspace-editors-store.js.map +1 -0
  125. package/internal/store/workspace-file-selection-store.d.ts +38 -0
  126. package/internal/store/workspace-file-selection-store.d.ts.map +1 -0
  127. package/internal/store/workspace-file-selection-store.js +62 -0
  128. package/internal/store/workspace-file-selection-store.js.map +1 -0
  129. package/internal/useRevealLine.d.ts +49 -0
  130. package/internal/useRevealLine.d.ts.map +1 -0
  131. package/internal/useRevealLine.js +43 -0
  132. package/internal/useRevealLine.js.map +1 -0
  133. package/library/detect-plan-artifact.d.ts +43 -4
  134. package/library/detect-plan-artifact.d.ts.map +1 -1
  135. package/library/detect-plan-artifact.js +45 -5
  136. package/library/detect-plan-artifact.js.map +1 -1
  137. package/library/detect-streaming-plan.d.ts +45 -0
  138. package/library/detect-streaming-plan.d.ts.map +1 -0
  139. package/library/detect-streaming-plan.js +83 -0
  140. package/library/detect-streaming-plan.js.map +1 -0
  141. package/library/index.d.ts +4 -1
  142. package/library/index.d.ts.map +1 -1
  143. package/library/index.js +2 -1
  144. package/library/index.js.map +1 -1
  145. package/package.json +4 -4
  146. package/session/NewSessionViewer.d.ts +19 -4
  147. package/session/NewSessionViewer.d.ts.map +1 -1
  148. package/session/NewSessionViewer.js +52 -25
  149. package/session/NewSessionViewer.js.map +1 -1
  150. package/session/PlanEditor.d.ts +55 -0
  151. package/session/PlanEditor.d.ts.map +1 -0
  152. package/session/PlanEditor.js +88 -0
  153. package/session/PlanEditor.js.map +1 -0
  154. package/session/PlanStreamingDocument.d.ts +30 -0
  155. package/session/PlanStreamingDocument.d.ts.map +1 -0
  156. package/session/PlanStreamingDocument.js +37 -0
  157. package/session/PlanStreamingDocument.js.map +1 -0
  158. package/session/SessionPanelChip.d.ts +26 -0
  159. package/session/SessionPanelChip.d.ts.map +1 -0
  160. package/session/SessionPanelChip.js +40 -0
  161. package/session/SessionPanelChip.js.map +1 -0
  162. package/session/SessionViewer.d.ts +34 -7
  163. package/session/SessionViewer.d.ts.map +1 -1
  164. package/session/SessionViewer.js +334 -33
  165. package/session/SessionViewer.js.map +1 -1
  166. package/session/{inspector → facets}/ArtifactsTab.d.ts +10 -2
  167. package/session/facets/ArtifactsTab.d.ts.map +1 -0
  168. package/session/{inspector → facets}/ArtifactsTab.js +8 -3
  169. package/session/facets/ArtifactsTab.js.map +1 -0
  170. package/session/{inspector → facets}/ChangesTab.d.ts +3 -3
  171. package/session/facets/ChangesTab.d.ts.map +1 -0
  172. package/session/{inspector → facets}/ChangesTab.js +3 -3
  173. package/session/facets/ChangesTab.js.map +1 -0
  174. package/session/facets/InspectTab.d.ts.map +1 -0
  175. package/session/facets/InspectTab.js.map +1 -0
  176. package/session/{inspector → facets}/SetupTab.d.ts +11 -2
  177. package/session/facets/SetupTab.d.ts.map +1 -0
  178. package/session/{inspector → facets}/SetupTab.js +4 -3
  179. package/session/facets/SetupTab.js.map +1 -0
  180. package/session/{inspector → facets}/UsageTab.d.ts +1 -1
  181. package/session/facets/UsageTab.d.ts.map +1 -0
  182. package/session/{inspector → facets}/UsageTab.js +1 -1
  183. package/session/facets/UsageTab.js.map +1 -0
  184. package/session/{inspector → facets}/index.d.ts +0 -6
  185. package/session/facets/index.d.ts.map +1 -0
  186. package/session/{inspector → facets}/index.js +0 -3
  187. package/session/facets/index.js.map +1 -0
  188. package/session/index.d.ts +11 -2
  189. package/session/index.d.ts.map +1 -1
  190. package/session/index.js +15 -2
  191. package/session/index.js.map +1 -1
  192. package/session/plan-document.d.ts +21 -0
  193. package/session/plan-document.d.ts.map +1 -0
  194. package/session/plan-document.js +28 -0
  195. package/session/plan-document.js.map +1 -0
  196. package/session/useOpenFileChange.d.ts +20 -0
  197. package/session/useOpenFileChange.d.ts.map +1 -0
  198. package/session/useOpenFileChange.js +31 -0
  199. package/session/useOpenFileChange.js.map +1 -0
  200. package/session/usePlanDraft.d.ts +52 -0
  201. package/session/usePlanDraft.d.ts.map +1 -0
  202. package/session/usePlanDraft.js +63 -0
  203. package/session/usePlanDraft.js.map +1 -0
  204. package/session/useSessionConversation.d.ts +14 -1
  205. package/session/useSessionConversation.d.ts.map +1 -1
  206. package/session/useSessionConversation.js +20 -2
  207. package/session/useSessionConversation.js.map +1 -1
  208. package/session/useSessionPageFlow.d.ts.map +1 -1
  209. package/session/useSessionPageFlow.js +1 -0
  210. package/session/useSessionPageFlow.js.map +1 -1
  211. package/session/useSessionPanel.d.ts +120 -0
  212. package/session/useSessionPanel.d.ts.map +1 -0
  213. package/session/useSessionPanel.js +130 -0
  214. package/session/useSessionPanel.js.map +1 -0
  215. package/session/useSessionRailViews.d.ts +45 -0
  216. package/session/useSessionRailViews.d.ts.map +1 -0
  217. package/session/useSessionRailViews.js +105 -0
  218. package/session/useSessionRailViews.js.map +1 -0
  219. package/src/composer/SessionComposer.tsx +53 -10
  220. package/src/composer/__tests__/SessionComposer-contract.test.tsx +58 -4
  221. package/src/execution/ArtifactContentRenderer.tsx +101 -24
  222. package/src/execution/ArtifactPreviewModal.tsx +9 -9
  223. package/src/execution/FileChangeProgressBar.tsx +121 -0
  224. package/src/execution/FileChangesView.tsx +18 -4
  225. package/src/execution/FilePathContext.tsx +8 -1
  226. package/src/execution/FilePathLink.tsx +22 -6
  227. package/src/execution/FileReviewAtoms.tsx +89 -0
  228. package/src/execution/FileReviewCard.tsx +57 -90
  229. package/src/execution/MessageEntry.tsx +49 -1
  230. package/src/execution/MessageThread.tsx +308 -39
  231. package/src/execution/PlanArtifactCard.tsx +174 -64
  232. package/src/execution/PlanCompletionCard.tsx +5 -5
  233. package/src/execution/PlanDocumentMessage.tsx +96 -0
  234. package/src/execution/PlanStreamingCard.tsx +141 -0
  235. package/src/execution/__tests__/ArtifactContentRenderer.test.tsx +80 -1
  236. package/src/execution/__tests__/ArtifactPreviewModal.test.tsx +6 -6
  237. package/src/execution/__tests__/FileChangeProgressBar.test.tsx +125 -0
  238. package/src/execution/__tests__/FilePathLink.test.tsx +87 -0
  239. package/src/execution/__tests__/FileReviewCard.test.tsx +66 -7
  240. package/src/execution/__tests__/MessageThread.test.tsx +102 -1
  241. package/src/execution/__tests__/PlanArtifactCard.test.tsx +114 -26
  242. package/src/execution/__tests__/PlanCompletionCard.test.tsx +2 -2
  243. package/src/execution/__tests__/PlanDocumentMessage.test.tsx +55 -0
  244. package/src/execution/__tests__/PlanStreamingCard.test.tsx +56 -0
  245. package/src/execution/__tests__/buildThreadItems-plan-completion.test.ts +600 -22
  246. package/src/execution/__tests__/message-entry.test.tsx +17 -0
  247. package/src/execution/__tests__/useArtifactCopy.test.tsx +90 -0
  248. package/src/execution/__tests__/useArtifactDownload.test.tsx +2 -0
  249. package/src/execution/__tests__/useCreateAgentExecution.test.tsx +85 -0
  250. package/src/execution/index.ts +13 -1
  251. package/src/execution/use-build-from-plan-hotkey.ts +1 -1
  252. package/src/execution/useArtifactCopy.ts +109 -0
  253. package/src/execution/useArtifactDownload.ts +17 -5
  254. package/src/execution/useCreateAgentExecution.ts +18 -1
  255. package/src/github/__tests__/decodeGitHubContent.test.ts +102 -0
  256. package/src/github/__tests__/useGitHubFileReader.test.ts +183 -0
  257. package/src/github/decodeGitHubContent.ts +83 -0
  258. package/src/github/index.ts +1 -0
  259. package/src/github/useGitHubFileReader.ts +152 -0
  260. package/src/github/useGitHubTreeLister.ts +6 -2
  261. package/src/index.ts +69 -9
  262. package/src/internal/ResizableSplit.tsx +184 -51
  263. package/src/internal/VirtualizedThread.tsx +12 -4
  264. package/src/internal/__tests__/ResizableSplit.test.tsx +125 -3
  265. package/src/internal/__tests__/markdown-components.test.tsx +68 -0
  266. package/src/internal/__tests__/useRevealLine.test.tsx +97 -0
  267. package/src/internal/file-icons/__tests__/file-icons.test.tsx +35 -0
  268. package/src/internal/file-icons/index.tsx +137 -0
  269. package/src/internal/file-tree/FileTreeNode.tsx +56 -5
  270. package/src/internal/file-tree/__tests__/FileTreeNode-explorer.test.tsx +86 -0
  271. package/src/internal/markdown-components.tsx +116 -11
  272. package/src/{workflow → internal}/motion-preference.ts +7 -4
  273. package/src/internal/store/__tests__/workspace-editors-store.test.ts +216 -0
  274. package/src/internal/store/__tests__/workspace-file-selection-store.test.ts +118 -0
  275. package/src/internal/store/index.ts +94 -0
  276. package/src/internal/store/workspace-editors-store.ts +315 -0
  277. package/src/internal/store/workspace-file-selection-store.ts +88 -0
  278. package/src/internal/useRevealLine.ts +81 -0
  279. package/src/library/__tests__/detect-plan-artifact.test.ts +69 -0
  280. package/src/library/__tests__/detect-streaming-plan.test.ts +234 -0
  281. package/src/library/detect-plan-artifact.ts +62 -5
  282. package/src/library/detect-streaming-plan.ts +108 -0
  283. package/src/library/index.ts +7 -0
  284. package/src/session/NewSessionViewer.tsx +123 -55
  285. package/src/session/PlanEditor.tsx +361 -0
  286. package/src/session/PlanStreamingDocument.tsx +97 -0
  287. package/src/session/SessionPanelChip.tsx +103 -0
  288. package/src/session/SessionViewer.tsx +655 -96
  289. package/src/session/__tests__/NewSessionViewer.test.tsx +148 -0
  290. package/src/session/__tests__/PlanEditor.test.tsx +217 -0
  291. package/src/session/__tests__/PlanStreamingDocument.test.tsx +50 -0
  292. package/src/session/__tests__/SessionPanelChip.test.tsx +42 -0
  293. package/src/session/__tests__/SessionViewer-fileReviewDock.test.tsx +66 -4
  294. package/src/session/__tests__/SessionViewer-transcriptFileOpen.test.tsx +205 -0
  295. package/src/session/__tests__/audienceWiring.test.tsx +55 -19
  296. package/src/session/__tests__/useOpenFileChange.test.tsx +82 -0
  297. package/src/session/__tests__/usePlanDraft.test.ts +102 -0
  298. package/src/session/__tests__/useSessionConversation.test.tsx +44 -0
  299. package/src/session/__tests__/useSessionPanel.test.ts +298 -0
  300. package/src/session/__tests__/useSessionRailViews.test.tsx +124 -0
  301. package/src/session/{inspector → facets}/ArtifactsTab.tsx +27 -5
  302. package/src/session/{inspector → facets}/ChangesTab.tsx +3 -3
  303. package/src/session/{inspector → facets}/SetupTab.tsx +13 -1
  304. package/src/session/{inspector → facets}/UsageTab.tsx +1 -1
  305. package/src/session/{inspector → facets}/__tests__/ArtifactsTab.test.tsx +42 -8
  306. package/src/session/facets/__tests__/SetupTab.test.tsx +44 -0
  307. package/src/session/{inspector → facets}/index.ts +0 -16
  308. package/src/session/index.ts +30 -13
  309. package/src/session/plan-document.ts +30 -0
  310. package/src/session/useOpenFileChange.ts +53 -0
  311. package/src/session/usePlanDraft.ts +109 -0
  312. package/src/session/useSessionConversation.ts +38 -3
  313. package/src/session/useSessionPageFlow.ts +1 -0
  314. package/src/session/useSessionPanel.ts +288 -0
  315. package/src/session/useSessionRailViews.tsx +200 -0
  316. package/src/workflow/WorkflowExecutionGraph.tsx +1 -1
  317. package/src/workflow/index.ts +1 -1
  318. package/src/workflow/useFollowExecution.ts +1 -1
  319. package/src/workspace/EditorTabs.tsx +174 -0
  320. package/src/workspace/ExplorerTree.tsx +253 -0
  321. package/src/workspace/FileViewer.tsx +537 -0
  322. package/src/workspace/WorkspaceContentSearch.tsx +502 -0
  323. package/src/workspace/WorkspaceContentSearcher.ts +70 -0
  324. package/src/workspace/WorkspaceEditor.tsx +19 -16
  325. package/src/workspace/WorkspaceFileLister.ts +11 -0
  326. package/src/workspace/WorkspaceFileReader.ts +57 -0
  327. package/src/workspace/WorkspaceFileSearch.tsx +452 -0
  328. package/src/workspace/WorkspaceSurface.tsx +839 -0
  329. package/src/workspace/__tests__/EditorTabs.test.tsx +102 -0
  330. package/src/workspace/__tests__/ExplorerTree.test.tsx +204 -0
  331. package/src/workspace/__tests__/FileViewer.test.tsx +439 -0
  332. package/src/workspace/__tests__/WorkspaceContentSearch.test.tsx +229 -0
  333. package/src/workspace/__tests__/WorkspaceEditor-initialPanel.test.tsx +19 -0
  334. package/src/workspace/__tests__/WorkspaceFileSearch.test.tsx +227 -0
  335. package/src/workspace/__tests__/WorkspaceSurface.test.tsx +418 -0
  336. package/src/workspace/__tests__/a11y/harness.tsx +140 -0
  337. package/src/workspace/__tests__/a11y/mock-capabilities.ts +138 -0
  338. package/src/workspace/__tests__/a11y/workspace-editor.a11y.test.tsx +65 -0
  339. package/src/workspace/__tests__/a11y/workspace-explorer-search.a11y.test.tsx +112 -0
  340. package/src/workspace/__tests__/a11y/workspace-viewer-tabs.a11y.test.tsx +69 -0
  341. package/src/workspace/__tests__/findChangeForSelection.test.ts +132 -0
  342. package/src/workspace/__tests__/matchContentPreview.test.ts +55 -0
  343. package/src/workspace/__tests__/matchWorkspaceFiles.test.ts +104 -0
  344. package/src/workspace/__tests__/resolveWorkspaceFileSelection.test.ts +135 -0
  345. package/src/workspace/__tests__/useWorkspaceContentSearch.test.tsx +196 -0
  346. package/src/workspace/__tests__/useWorkspaceFileContent.test.tsx +190 -0
  347. package/src/workspace/__tests__/useWorkspaceFileSearch.test.tsx +162 -0
  348. package/src/workspace/findChangeForSelection.ts +61 -0
  349. package/src/workspace/index.ts +56 -2
  350. package/src/workspace/matchContentPreview.ts +51 -0
  351. package/src/workspace/matchWorkspaceFiles.ts +86 -0
  352. package/src/workspace/resolveWorkspaceFileSelection.ts +119 -0
  353. package/src/workspace/useWorkspaceContentSearch.ts +228 -0
  354. package/src/workspace/useWorkspaceFileContent.ts +129 -0
  355. package/src/workspace/useWorkspaceFileSearch.ts +184 -0
  356. package/src/workspace/useWorkspaceFiles.ts +27 -27
  357. package/src/workspace/workspaceListingCache.ts +93 -0
  358. package/styles.css +1 -1
  359. package/workflow/WorkflowExecutionGraph.js +1 -1
  360. package/workflow/WorkflowExecutionGraph.js.map +1 -1
  361. package/workflow/index.d.ts +1 -1
  362. package/workflow/index.d.ts.map +1 -1
  363. package/workflow/index.js +1 -1
  364. package/workflow/index.js.map +1 -1
  365. package/workflow/useFollowExecution.js +1 -1
  366. package/workflow/useFollowExecution.js.map +1 -1
  367. package/workspace/EditorTabs.d.ts +47 -0
  368. package/workspace/EditorTabs.d.ts.map +1 -0
  369. package/workspace/EditorTabs.js +78 -0
  370. package/workspace/EditorTabs.js.map +1 -0
  371. package/workspace/ExplorerTree.d.ts +32 -0
  372. package/workspace/ExplorerTree.d.ts.map +1 -0
  373. package/workspace/ExplorerTree.js +49 -0
  374. package/workspace/ExplorerTree.js.map +1 -0
  375. package/workspace/FileViewer.d.ts +93 -0
  376. package/workspace/FileViewer.d.ts.map +1 -0
  377. package/workspace/FileViewer.js +193 -0
  378. package/workspace/FileViewer.js.map +1 -0
  379. package/workspace/WorkspaceContentSearch.d.ts +41 -0
  380. package/workspace/WorkspaceContentSearch.d.ts.map +1 -0
  381. package/workspace/WorkspaceContentSearch.js +216 -0
  382. package/workspace/WorkspaceContentSearch.js.map +1 -0
  383. package/workspace/WorkspaceContentSearcher.d.ts +59 -0
  384. package/workspace/WorkspaceContentSearcher.d.ts.map +1 -0
  385. package/workspace/WorkspaceContentSearcher.js +7 -0
  386. package/workspace/WorkspaceContentSearcher.js.map +1 -0
  387. package/workspace/WorkspaceEditor.d.ts.map +1 -1
  388. package/workspace/WorkspaceEditor.js +8 -10
  389. package/workspace/WorkspaceEditor.js.map +1 -1
  390. package/workspace/WorkspaceFileLister.d.ts +11 -0
  391. package/workspace/WorkspaceFileLister.d.ts.map +1 -1
  392. package/workspace/WorkspaceFileReader.d.ts +48 -0
  393. package/workspace/WorkspaceFileReader.d.ts.map +1 -0
  394. package/workspace/WorkspaceFileReader.js +11 -0
  395. package/workspace/WorkspaceFileReader.js.map +1 -0
  396. package/workspace/WorkspaceFileSearch.d.ts +32 -0
  397. package/workspace/WorkspaceFileSearch.d.ts.map +1 -0
  398. package/workspace/WorkspaceFileSearch.js +175 -0
  399. package/workspace/WorkspaceFileSearch.js.map +1 -0
  400. package/workspace/WorkspaceSurface.d.ts +151 -0
  401. package/workspace/WorkspaceSurface.d.ts.map +1 -0
  402. package/workspace/WorkspaceSurface.js +220 -0
  403. package/workspace/WorkspaceSurface.js.map +1 -0
  404. package/workspace/findChangeForSelection.d.ts +19 -0
  405. package/workspace/findChangeForSelection.d.ts.map +1 -0
  406. package/workspace/findChangeForSelection.js +46 -0
  407. package/workspace/findChangeForSelection.js.map +1 -0
  408. package/workspace/index.d.ts +24 -2
  409. package/workspace/index.d.ts.map +1 -1
  410. package/workspace/index.js +13 -1
  411. package/workspace/index.js.map +1 -1
  412. package/workspace/matchContentPreview.d.ts +21 -0
  413. package/workspace/matchContentPreview.d.ts.map +1 -0
  414. package/workspace/matchContentPreview.js +36 -0
  415. package/workspace/matchContentPreview.js.map +1 -0
  416. package/workspace/matchWorkspaceFiles.d.ts +30 -0
  417. package/workspace/matchWorkspaceFiles.d.ts.map +1 -0
  418. package/workspace/matchWorkspaceFiles.js +58 -0
  419. package/workspace/matchWorkspaceFiles.js.map +1 -0
  420. package/workspace/resolveWorkspaceFileSelection.d.ts +19 -0
  421. package/workspace/resolveWorkspaceFileSelection.d.ts.map +1 -0
  422. package/workspace/resolveWorkspaceFileSelection.js +115 -0
  423. package/workspace/resolveWorkspaceFileSelection.js.map +1 -0
  424. package/workspace/useWorkspaceContentSearch.d.ts +69 -0
  425. package/workspace/useWorkspaceContentSearch.d.ts.map +1 -0
  426. package/workspace/useWorkspaceContentSearch.js +154 -0
  427. package/workspace/useWorkspaceContentSearch.js.map +1 -0
  428. package/workspace/useWorkspaceFileContent.d.ts +73 -0
  429. package/workspace/useWorkspaceFileContent.d.ts.map +1 -0
  430. package/workspace/useWorkspaceFileContent.js +57 -0
  431. package/workspace/useWorkspaceFileContent.js.map +1 -0
  432. package/workspace/useWorkspaceFileSearch.d.ts +61 -0
  433. package/workspace/useWorkspaceFileSearch.d.ts.map +1 -0
  434. package/workspace/useWorkspaceFileSearch.js +119 -0
  435. package/workspace/useWorkspaceFileSearch.js.map +1 -0
  436. package/workspace/useWorkspaceFiles.d.ts +13 -5
  437. package/workspace/useWorkspaceFiles.d.ts.map +1 -1
  438. package/workspace/useWorkspaceFiles.js +18 -19
  439. package/workspace/useWorkspaceFiles.js.map +1 -1
  440. package/workspace/workspaceListingCache.d.ts +47 -0
  441. package/workspace/workspaceListingCache.d.ts.map +1 -0
  442. package/workspace/workspaceListingCache.js +55 -0
  443. package/workspace/workspaceListingCache.js.map +1 -0
  444. package/session/inspector/ArtifactsTab.d.ts.map +0 -1
  445. package/session/inspector/ArtifactsTab.js.map +0 -1
  446. package/session/inspector/ChangesTab.d.ts.map +0 -1
  447. package/session/inspector/ChangesTab.js.map +0 -1
  448. package/session/inspector/InspectTab.d.ts.map +0 -1
  449. package/session/inspector/InspectTab.js.map +0 -1
  450. package/session/inspector/SessionInspector.d.ts +0 -64
  451. package/session/inspector/SessionInspector.d.ts.map +0 -1
  452. package/session/inspector/SessionInspector.js +0 -53
  453. package/session/inspector/SessionInspector.js.map +0 -1
  454. package/session/inspector/SetupTab.d.ts.map +0 -1
  455. package/session/inspector/SetupTab.js.map +0 -1
  456. package/session/inspector/UsageTab.d.ts.map +0 -1
  457. package/session/inspector/UsageTab.js.map +0 -1
  458. package/session/inspector/WorkspaceTab.d.ts +0 -35
  459. package/session/inspector/WorkspaceTab.d.ts.map +0 -1
  460. package/session/inspector/WorkspaceTab.js +0 -75
  461. package/session/inspector/WorkspaceTab.js.map +0 -1
  462. package/session/inspector/index.d.ts.map +0 -1
  463. package/session/inspector/index.js.map +0 -1
  464. package/session/inspector/useSessionInspector.d.ts +0 -49
  465. package/session/inspector/useSessionInspector.d.ts.map +0 -1
  466. package/session/inspector/useSessionInspector.js +0 -122
  467. package/session/inspector/useSessionInspector.js.map +0 -1
  468. package/src/session/inspector/SessionInspector.tsx +0 -162
  469. package/src/session/inspector/WorkspaceTab.tsx +0 -245
  470. package/src/session/inspector/__tests__/useSessionInspector.test.ts +0 -251
  471. package/src/session/inspector/useSessionInspector.ts +0 -178
  472. package/src/workspace/WorkspaceEntryFiles.tsx +0 -196
  473. package/workflow/motion-preference.d.ts.map +0 -1
  474. package/workflow/motion-preference.js.map +0 -1
  475. package/workspace/WorkspaceEntryFiles.d.ts +0 -22
  476. package/workspace/WorkspaceEntryFiles.d.ts.map +0 -1
  477. package/workspace/WorkspaceEntryFiles.js +0 -58
  478. package/workspace/WorkspaceEntryFiles.js.map +0 -1
  479. /package/session/{inspector → facets}/InspectTab.d.ts +0 -0
  480. /package/session/{inspector → facets}/InspectTab.js +0 -0
  481. /package/src/{workflow → internal}/__tests__/motion-preference.test.ts +0 -0
  482. /package/src/session/{inspector → facets}/InspectTab.tsx +0 -0
  483. /package/src/session/{inspector → facets}/__tests__/ChangesTab.test.tsx +0 -0
@@ -31,8 +31,10 @@ import { FileReviewCard } from "./FileReviewCard.js";
31
31
  import { SummarizationCard } from "./SummarizationCard.js";
32
32
  import { PlanCompletionCard } from "./PlanCompletionCard.js";
33
33
  import { PlanArtifactCard } from "./PlanArtifactCard.js";
34
+ import { PlanStreamingCard } from "./PlanStreamingCard.js";
34
35
  import { TodoCard } from "./TodoCard.js";
35
36
  import { findPlanArtifact } from "../library/detect-plan-artifact.js";
37
+ import { findStreamingPlan } from "../library/detect-streaming-plan.js";
36
38
  import type { SummarizationEventView } from "./useContextWindow.js";
37
39
  import { isInternalTool, isCollapsedToolCall } from "./tool-categories.js";
38
40
  import { FilePathContext, type FilePathContextValue } from "./FilePathContext.js";
@@ -40,6 +42,10 @@ import type { ResolvedPathAction } from "./file-path-resolver.js";
40
42
  import { SandboxContext, type SandboxContextValue } from "./SandboxContext.js";
41
43
  import { ApprovalContext, type ApprovalContextValue } from "./ApprovalContext.js";
42
44
  import { FileReviewContext, type FileReviewContextValue } from "./FileReviewContext.js";
45
+ import {
46
+ extractLeadingH1,
47
+ unwrapEnclosingMarkdownFence,
48
+ } from "../internal/markdown-components.js";
43
49
  import { useRenderTracer, useKeyStability, useDomNodeCount, DevProfiler } from "../internal/dev/index.js";
44
50
  import { useAutoScroll } from "../internal/useAutoScroll.js";
45
51
  import { JumpToLatestButton } from "../internal/JumpToLatestButton.js";
@@ -172,7 +178,7 @@ export interface MessageThreadProps {
172
178
  readonly onFilePathClick?: (
173
179
  path: string,
174
180
  resolved: ResolvedPathAction,
175
- ) => void;
181
+ ) => boolean | void;
176
182
  /**
177
183
  * Absolute sandbox workspace root (e.g. `/home/daytona/workspace`).
178
184
  * When provided, shell commands and tool output normalize absolute
@@ -212,6 +218,21 @@ export interface MessageThreadProps {
212
218
  * compatible — existing consumers see no change.
213
219
  */
214
220
  readonly onBuildFromPlan?: () => void;
221
+ /**
222
+ * Opens a plan in the session panel's plan document tab — the side-by-side
223
+ * review/refine surface. Wired to EVERY plan card: the latest opens
224
+ * editable/buildable, a superseded plan opens read-only (the host decides
225
+ * from the execution id). When omitted, cards fall back to the "Open full"
226
+ * preview modal (hosts without a panel).
227
+ *
228
+ * Providing this also opts the thread into LIVE plan collapse: while a
229
+ * Plan-mode turn streams its plan (detected via `findStreamingPlan`), the
230
+ * plan message is suppressed behind a compact {@link PlanStreamingCard}
231
+ * whose "Open plan" routes here — the host is expected to render the
232
+ * streaming document in its plan surface. Hosts without one (this prop
233
+ * omitted) keep the plan streaming inline, where it stays readable.
234
+ */
235
+ readonly onOpenPlan?: (executionId: string) => void;
215
236
  /**
216
237
  * Organization slug. Required for the plan completion card's
217
238
  * "Review plan" action, which opens the shared artifact preview
@@ -225,18 +246,37 @@ export interface MessageThreadProps {
225
246
  * disabled submit.
226
247
  */
227
248
  readonly planActionsDisabled?: boolean;
249
+ /** True while the approved plan is being uploaded ahead of the build turn. */
250
+ readonly planBuildPending?: boolean;
228
251
  /**
229
- * Center thread content within a max-width reading column.
230
- *
231
- * When `true`, items are constrained to `max-w-3xl` (768 px) and
232
- * horizontally centered. The scroll container stays full-width so
233
- * the scrollbar remains at the viewport edge.
252
+ * Constrain thread content to a max-width reading column
253
+ * (`max-w-3xl`, 768 px) inside the full-width scroll container —
254
+ * the scrollbar stays at the viewport edge.
234
255
  *
235
- * Opt-in per DD-011 existing consumers see no layout change.
256
+ * - `"center"`column horizontally centered (classic chat reading view).
257
+ * - `"start"` — column anchored to the left edge, so the thread's left
258
+ * edge stays put when a sibling panel opens/closes beside it.
236
259
  *
237
- * @default false
260
+ * When omitted, content spans the full width. Opt-in per DD-011 —
261
+ * existing consumers see no layout change.
238
262
  */
239
- readonly centerContent?: boolean;
263
+ readonly contentColumn?: ThreadContentColumn;
264
+ }
265
+
266
+ /** Reading-column alignment for {@link MessageThread} content. */
267
+ export type ThreadContentColumn = "center" | "start";
268
+
269
+ /**
270
+ * Class set for the optional reading column — one definition shared by both
271
+ * render paths (non-virtualized and virtualized) so their geometry can never
272
+ * drift.
273
+ *
274
+ * @internal
275
+ */
276
+ export function threadContentColumnClass(
277
+ column: ThreadContentColumn | undefined,
278
+ ): string | false {
279
+ return column != null && cn("w-full max-w-3xl px-4", column === "center" && "mx-auto");
240
280
  }
241
281
 
242
282
  /**
@@ -249,7 +289,7 @@ export interface MessageThreadProps {
249
289
  * part of the public API.
250
290
  */
251
291
  export type ThreadItem =
252
- | { readonly kind: "message"; readonly message: AgentMessage; readonly key: string; readonly isPending?: boolean; readonly isFailed?: boolean; readonly isEditable?: boolean }
292
+ | { readonly kind: "message"; readonly message: AgentMessage; readonly key: string; readonly isPending?: boolean; readonly isFailed?: boolean; readonly isEditable?: boolean; readonly isPlanDocument?: boolean; readonly interactionMode?: InteractionMode }
253
293
  | { readonly kind: "tool-group"; readonly toolCalls: readonly ToolCall[]; readonly subAgentExecutions: readonly SubAgentExecution[]; readonly key: string }
254
294
  | { readonly kind: "sub-agent"; readonly subAgentExecution: SubAgentExecution; readonly key: string }
255
295
  | { readonly kind: "phase-badge"; readonly phase: ExecutionPhase; readonly key: string }
@@ -269,6 +309,36 @@ export type ThreadItem =
269
309
  readonly key: string;
270
310
  readonly executionId: string;
271
311
  readonly planArtifact?: ExecutionArtifact;
312
+ /**
313
+ * The plan's title (its leading `# H1`), lifted from the plan message at
314
+ * build time — no fetch. Present only when the turn published an
315
+ * artifact (the collapsed-card path); the card falls back to "Plan".
316
+ */
317
+ readonly planTitle?: string;
318
+ /**
319
+ * True for the most recent completed Plan execution in the thread — the
320
+ * only plan whose card carries the primary "Build" action. Superseded
321
+ * plans keep their review actions (open/download) but never a build
322
+ * CTA, so a stale plan can't be implemented by accident.
323
+ */
324
+ readonly isLatestPlan: boolean;
325
+ }
326
+ | {
327
+ /**
328
+ * A plan the active Plan-mode execution is writing RIGHT NOW: the
329
+ * streaming plan message is suppressed and this compact card stands in
330
+ * while the document renders live in the panel's plan tab. On
331
+ * completion the item becomes `plan-completion` — a different kind
332
+ * under the SAME key, so the card holds one thread position and the
333
+ * swap reads as the card settling.
334
+ */
335
+ readonly kind: "plan-writing";
336
+ readonly key: string;
337
+ readonly executionId: string;
338
+ /** Live title (the plan's leading `# H1`), growing as it streams. */
339
+ readonly planTitle?: string;
340
+ /** Length of the plan text streamed so far (drives the live size). */
341
+ readonly planSize: number;
272
342
  };
273
343
 
274
344
  /**
@@ -295,6 +365,45 @@ function hasStartedResponding(execution: AgentExecution): boolean {
295
365
  });
296
366
  }
297
367
 
368
+ /**
369
+ * True for an execution that ran in Plan mode and completed — the only kind of
370
+ * execution that has a reviewable plan (streaming/failed/terminated Plan turns
371
+ * have nothing final to review or build from).
372
+ */
373
+ function isCompletedPlanExecution(execution: AgentExecution): boolean {
374
+ return (
375
+ execution.status?.phase === ExecutionPhase.EXECUTION_COMPLETED &&
376
+ execution.spec?.executionConfig?.interactionMode === InteractionMode.PLAN
377
+ );
378
+ }
379
+
380
+ /**
381
+ * Index of the message that IS the plan in a completed Plan execution: the
382
+ * last AI message with content — the SAME selection rule the runner's
383
+ * `extractFinalPlanText` uses to publish `plan.md`, so the message promoted to
384
+ * a document in the thread is byte-identical to the published artifact.
385
+ * Returns -1 when no such message exists.
386
+ */
387
+ function findPlanMessageIndex(messages: readonly AgentMessage[]): number {
388
+ for (let i = messages.length - 1; i >= 0; i--) {
389
+ const msg = messages[i];
390
+ if (msg.type === MessageType.MESSAGE_AI && msg.content.trim().length > 0) {
391
+ return i;
392
+ }
393
+ }
394
+ return -1;
395
+ }
396
+
397
+ /**
398
+ * The plan's title for its compact card: the leading `# H1` of the plan
399
+ * message, after the same plan-scoped bare-fence unwrap the document renderers
400
+ * apply — so the card and the plan tab always agree on the title. `undefined`
401
+ * when the plan has no H1 (the card falls back to "Plan").
402
+ */
403
+ function extractPlanTitle(content: string): string | undefined {
404
+ return extractLeadingH1(unwrapEnclosingMarkdownFence(content, true)).title ?? undefined;
405
+ }
406
+
298
407
  /**
299
408
  * Adds the tool-call ids that a sub-agent renders as nested rows (the same
300
409
  * non-internal AI tool calls {@link SubAgentSection} surfaces) to `target`,
@@ -397,6 +506,7 @@ export function buildThreadItems(
397
506
  pendingMessageFailed = false,
398
507
  editableActiveTurn = false,
399
508
  includeFileReviewRecords = false,
509
+ collapseStreamingPlan = false,
400
510
  ): ThreadItem[] {
401
511
  const items: ThreadItem[] = [];
402
512
  // Tool-call ids that render as an inline-approval-capable ToolCallItem (a
@@ -427,6 +537,17 @@ export function buildThreadItems(
427
537
  ? allExecutions.length - 1
428
538
  : -1;
429
539
 
540
+ // The most recent completed Plan execution owns the primary "Build" action;
541
+ // every earlier plan renders as a review-only record. Resolved up front so
542
+ // each segment can stamp its own card with the right authority.
543
+ let latestPlanExecutionId: string | null = null;
544
+ for (let i = allExecutions.length - 1; i >= 0; i--) {
545
+ if (isCompletedPlanExecution(allExecutions[i])) {
546
+ latestPlanExecutionId = allExecutions[i].metadata?.id ?? `_e${i}`;
547
+ break;
548
+ }
549
+ }
550
+
430
551
  // Build a queue of summarization events to interleave by timestamp.
431
552
  // Events are consumed as messages pass their timestamp.
432
553
  const pendingEvents = summarizationEvents?.length
@@ -458,6 +579,44 @@ export function buildThreadItems(
458
579
  const messages = exec.status?.messages ?? [];
459
580
  const subAgents = exec.status?.subAgentExecutions ?? [];
460
581
 
582
+ // A completed Plan turn collapses its plan message into the compact plan
583
+ // card (the plan-completion item): the document lives in the panel's plan
584
+ // tab, not the thread. While the plan is still streaming, the same
585
+ // treatment applies live when the host has a plan surface (streamingPlan
586
+ // below): the in-flight plan message is suppressed behind a plan-writing
587
+ // card while the panel's plan tab renders it as it streams — the content
588
+ // moves, it doesn't disappear. Completion swaps the live card for the
589
+ // settled one (same key), and the paired auto-open (useSessionPanel's
590
+ // planKey trigger) keeps the document side-by-side. Collapse of a
591
+ // COMPLETED plan is gated on the ARTIFACT existing: a plan that never
592
+ // published (older executions, failed upload) exists only in the message,
593
+ // so that path keeps the inline document promotion (isPlanDocument) —
594
+ // collapsing it would orphan the plan behind a card with nothing to open.
595
+ const isCompletedPlanExec = isCompletedPlanExecution(exec);
596
+ const planMessageIndex = isCompletedPlanExec
597
+ ? findPlanMessageIndex(messages)
598
+ : -1;
599
+ const planArtifact = isCompletedPlanExec
600
+ ? findPlanArtifact(exec)
601
+ : undefined;
602
+ const collapsePlanMessage =
603
+ planMessageIndex >= 0 && planArtifact !== undefined;
604
+
605
+ // The plan the active Plan-mode turn is writing RIGHT NOW (detected by
606
+ // the H1 convention — see findStreamingPlan). Its message is suppressed
607
+ // in favor of a live plan-writing card, mirroring the completed-turn
608
+ // collapse above, while the panel's plan tab renders the document live.
609
+ // Two gates: collapseStreamingPlan (the host wired onOpenPlan — without a
610
+ // document surface the plan must keep streaming inline, DD-011) and
611
+ // isActiveStreamExec (a stale non-terminal execution left in the
612
+ // completed list by the transient skew documented above must never
613
+ // sprout a live card). Mutually exclusive with collapsePlanMessage by
614
+ // construction: one requires a terminal phase, the other forbids it.
615
+ const streamingPlan =
616
+ collapseStreamingPlan && isActiveStreamExec
617
+ ? findStreamingPlan(exec)
618
+ : undefined;
619
+
461
620
  // This execution's settled change sets render as read-only records inside
462
621
  // its own segment, anchored to the last stamped edit row of each set. The
463
622
  // display seam reads the server's live projection when present and folds
@@ -489,7 +648,13 @@ export function buildThreadItems(
489
648
  }
490
649
 
491
650
  const specMessage = exec.spec?.message;
492
- if (specMessage && specMessage !== "execute") {
651
+ // A Build-from-plan turn synthesizes NO prompt item: its message is a
652
+ // machine-written label ("Build from plan"), not user prose — the real
653
+ // instruction is runner-injected from the same flag. The plan card
654
+ // directly above the turn is the visible cause; rendering the label as a
655
+ // user bubble would attribute words to the user they never typed.
656
+ const isBuildTurn = exec.spec?.executionConfig?.buildFromPlan === true;
657
+ if (specMessage && specMessage !== "execute" && !isBuildTurn) {
493
658
  const syntheticHumanMsg = create(AgentMessageSchema);
494
659
  syntheticHumanMsg.type = MessageType.MESSAGE_HUMAN;
495
660
  syntheticHumanMsg.content = specMessage;
@@ -509,6 +674,9 @@ export function buildThreadItems(
509
674
  // The active execution's prompt is the one a user can edit-and-resubmit
510
675
  // (stop + rephrase). Only mark it when the consumer enabled editing.
511
676
  isEditable: isActiveStreamExec && editableActiveTurn,
677
+ // The turn's mode marks the prompt bubble (a "Plan" pill on Plan
678
+ // turns) so the transcript reads unambiguously after mode switches.
679
+ interactionMode: exec.spec?.executionConfig?.interactionMode,
512
680
  });
513
681
  }
514
682
 
@@ -525,11 +693,23 @@ export function buildThreadItems(
525
693
  msg.type === MessageType.MESSAGE_AI && !msg.content.trim();
526
694
 
527
695
  if (!isEmptyAi) {
528
- items.push({
529
- kind: "message",
530
- message: msg,
531
- key: `${execId}-m${mi}`,
532
- });
696
+ // The collapsed plan message is not rendered — the plan-completion
697
+ // card at the segment's end is the turn's sole plan representation.
698
+ // Its tool calls (below) and the todo anchor still process normally.
699
+ // A STREAMING plan message is suppressed the same way: its stand-in
700
+ // is the plan-writing card at the segment's end, and the document
701
+ // renders live in the panel's plan tab.
702
+ const suppressAsPlan =
703
+ (collapsePlanMessage && mi === planMessageIndex) ||
704
+ mi === streamingPlan?.messageIndex;
705
+ if (!suppressAsPlan) {
706
+ items.push({
707
+ kind: "message",
708
+ message: msg,
709
+ key: `${execId}-m${mi}`,
710
+ isPlanDocument: !collapsePlanMessage && mi === planMessageIndex,
711
+ });
712
+ }
533
713
  // Anchor (1): the plan sits right under the agent's opening narration.
534
714
  if (
535
715
  msg.type === MessageType.MESSAGE_AI ||
@@ -609,6 +789,42 @@ export function buildThreadItems(
609
789
  }
610
790
  }
611
791
 
792
+ // A completed Plan turn closes its segment with the plan card — the
793
+ // compact stand-in for the collapsed plan message, carrying the title the
794
+ // message would have shown. Every plan stays reviewable forever; only the
795
+ // latest carries the build authority (isLatestPlan). A superseded plan
796
+ // that never published an artifact is skipped — with no artifact and no
797
+ // build CTA it would render an empty shell.
798
+ if (isCompletedPlanExec) {
799
+ const isLatestPlan = execId === latestPlanExecutionId;
800
+ if (planArtifact || isLatestPlan) {
801
+ items.push({
802
+ kind: "plan-completion",
803
+ key: `${execId}-plan-completion`,
804
+ executionId: exec.metadata?.id ?? "",
805
+ planArtifact,
806
+ planTitle: collapsePlanMessage
807
+ ? extractPlanTitle(messages[planMessageIndex].content)
808
+ : undefined,
809
+ isLatestPlan,
810
+ });
811
+ }
812
+ } else if (streamingPlan) {
813
+ // The live stand-in for the suppressed streaming plan message. It
814
+ // deliberately SHARES the completion item's key: on completion this
815
+ // item becomes the plan-completion item above (a kind change under a
816
+ // stable key), so the card holds one thread position and the handoff
817
+ // reads as the card settling rather than a new element appearing.
818
+ items.push({
819
+ kind: "plan-writing",
820
+ key: `${execId}-plan-completion`,
821
+ executionId: exec.metadata?.id ?? "",
822
+ planTitle:
823
+ extractLeadingH1(streamingPlan.displayText).title ?? undefined,
824
+ planSize: streamingPlan.displayText.length,
825
+ });
826
+ }
827
+
612
828
  // Anchor (3): a plan that produced no rendered narration or work item still
613
829
  // surfaces — never silently dropped.
614
830
  emitTodos();
@@ -682,27 +898,27 @@ export function buildThreadItems(
682
898
  const reason = lastExec?.status?.error;
683
899
  if (reason) {
684
900
  const specMessage = lastExec?.spec?.message;
901
+ // A failed build turn offers no inline Retry: resending its label as an
902
+ // ordinary message would drop the buildFromPlan flag (no runner
903
+ // directive, no plan attachment). The plan card above the error is the
904
+ // fully-wired retry — its Build button re-runs the whole pipeline.
905
+ const isBuildTurn =
906
+ lastExec?.spec?.executionConfig?.buildFromPlan === true;
685
907
  items.push({
686
908
  kind: "execution-error",
687
909
  error: reason,
688
910
  retryMessage:
689
- specMessage && specMessage !== "execute" ? specMessage : undefined,
911
+ specMessage && specMessage !== "execute" && !isBuildTurn
912
+ ? specMessage
913
+ : undefined,
690
914
  key: `execution-error-${lastExec?.metadata?.id ?? lastPhase}`,
691
915
  });
692
916
  }
693
917
  }
694
918
 
695
- if (
696
- lastPhase === ExecutionPhase.EXECUTION_COMPLETED &&
697
- lastExec?.spec?.executionConfig?.interactionMode === InteractionMode.PLAN
698
- ) {
699
- items.push({
700
- kind: "plan-completion",
701
- key: "plan-completion",
702
- executionId: lastExec?.metadata?.id ?? "",
703
- planArtifact: findPlanArtifact(lastExec),
704
- });
705
- }
919
+ // Plan cards are emitted inside each execution's segment (see the
920
+ // isCompletedPlanExec block in the loop above) — attached to their plan
921
+ // document, persistent across later turns, never appended at the tail.
706
922
 
707
923
  if (includeApprovals) {
708
924
  // Backstop only: an approval whose tool call renders inline shows its gate
@@ -730,8 +946,13 @@ export function buildThreadItems(
730
946
  // not thread items at all: they live in the composer-docked FileReviewDock.
731
947
 
732
948
  if (pendingUserMessage) {
949
+ // A FAILED send never created an execution, so an existing execution with
950
+ // identical text (e.g. two build attempts of the same plan — both
951
+ // "Build from plan") must never swallow the failed bubble. Suppression
952
+ // only applies to the succeeded-send window where the stream has
953
+ // delivered the same turn but the pending state hasn't cleared yet.
733
954
  const alreadySynthesized =
734
- lastExec?.spec?.message === pendingUserMessage;
955
+ !pendingMessageFailed && lastExec?.spec?.message === pendingUserMessage;
735
956
  if (!alreadySynthesized) {
736
957
  const syntheticPending = create(AgentMessageSchema);
737
958
  syntheticPending.type = MessageType.MESSAGE_HUMAN;
@@ -794,17 +1015,23 @@ export function MessageThread({
794
1015
  summarizationEvents,
795
1016
  virtualized = false,
796
1017
  onBuildFromPlan,
1018
+ onOpenPlan,
797
1019
  org,
798
1020
  planActionsDisabled,
799
- centerContent = false,
1021
+ planBuildPending,
1022
+ contentColumn,
800
1023
  }: MessageThreadProps) {
801
1024
  useRenderTracer("MessageThread", { executions, activeStreamExecution });
802
1025
 
803
1026
  const includeApprovals = onApprovalSubmit != null;
804
1027
  const editableActiveTurn = onEditMessage != null;
1028
+ // A streaming plan is collapsed behind its live card only when the host can
1029
+ // open the plan document surface — a panel-less host (no onOpenPlan) keeps
1030
+ // the plan streaming inline, where it remains readable (DD-011).
1031
+ const collapseStreamingPlan = onOpenPlan != null;
805
1032
  const items = useMemo(
806
- () => buildThreadItems(executions, activeStreamExecution, pendingUserMessage, includeApprovals, workspaceEntries, summarizationEvents, pendingMessageFailed, editableActiveTurn, showFileReviewRecords),
807
- [executions, activeStreamExecution, pendingUserMessage, includeApprovals, workspaceEntries, summarizationEvents, pendingMessageFailed, editableActiveTurn, showFileReviewRecords],
1033
+ () => buildThreadItems(executions, activeStreamExecution, pendingUserMessage, includeApprovals, workspaceEntries, summarizationEvents, pendingMessageFailed, editableActiveTurn, showFileReviewRecords, collapseStreamingPlan),
1034
+ [executions, activeStreamExecution, pendingUserMessage, includeApprovals, workspaceEntries, summarizationEvents, pendingMessageFailed, editableActiveTurn, showFileReviewRecords, collapseStreamingPlan],
808
1035
  );
809
1036
 
810
1037
  useKeyStability(items);
@@ -889,9 +1116,11 @@ export function MessageThread({
889
1116
  fileReviewCtx={fileReviewCtx}
890
1117
  unresolvedApprovalCount={unresolvedApprovalCount}
891
1118
  onBuildFromPlan={onBuildFromPlan}
1119
+ onOpenPlan={onOpenPlan}
892
1120
  org={org}
893
1121
  planActionsDisabled={planActionsDisabled}
894
- centerContent={centerContent}
1122
+ planBuildPending={planBuildPending}
1123
+ contentColumn={contentColumn}
895
1124
  onRetrySend={onRetrySend}
896
1125
  onRetryExecution={onRetryExecution}
897
1126
  onEditMessage={onEditMessage}
@@ -905,7 +1134,7 @@ export function MessageThread({
905
1134
  <NonVirtualizedThread
906
1135
  items={items}
907
1136
  className={className}
908
- centerContent={centerContent}
1137
+ contentColumn={contentColumn}
909
1138
  formatToolCallSummary={formatToolCallSummary}
910
1139
  onApprovalSubmit={onApprovalSubmit}
911
1140
  submittingApprovalIds={submittingApprovalIds}
@@ -916,8 +1145,10 @@ export function MessageThread({
916
1145
  fileReviewCtx={fileReviewCtx}
917
1146
  unresolvedApprovalCount={unresolvedApprovalCount}
918
1147
  onBuildFromPlan={onBuildFromPlan}
1148
+ onOpenPlan={onOpenPlan}
919
1149
  org={org}
920
1150
  planActionsDisabled={planActionsDisabled}
1151
+ planBuildPending={planBuildPending}
921
1152
  onRetrySend={onRetrySend}
922
1153
  onRetryExecution={onRetryExecution}
923
1154
  onEditMessage={onEditMessage}
@@ -932,7 +1163,7 @@ export function MessageThread({
932
1163
  interface NonVirtualizedThreadProps {
933
1164
  readonly items: readonly ThreadItem[];
934
1165
  readonly className?: string;
935
- readonly centerContent?: boolean;
1166
+ readonly contentColumn?: ThreadContentColumn;
936
1167
  readonly formatToolCallSummary?: (toolCalls: readonly ToolCall[]) => string;
937
1168
  readonly onApprovalSubmit?: (
938
1169
  toolCallId: string,
@@ -947,8 +1178,11 @@ interface NonVirtualizedThreadProps {
947
1178
  readonly fileReviewCtx: FileReviewContextValue;
948
1179
  readonly unresolvedApprovalCount: number;
949
1180
  readonly onBuildFromPlan?: () => void;
1181
+ readonly onOpenPlan?: (executionId: string) => void;
950
1182
  readonly org?: string;
951
1183
  readonly planActionsDisabled?: boolean;
1184
+ /** True while the approved plan is being uploaded ahead of the build turn. */
1185
+ readonly planBuildPending?: boolean;
952
1186
  readonly onRetrySend?: () => void;
953
1187
  readonly onRetryExecution?: (message: string) => void;
954
1188
  readonly onEditMessage?: (text: string) => void;
@@ -957,7 +1191,7 @@ interface NonVirtualizedThreadProps {
957
1191
  function NonVirtualizedThread({
958
1192
  items,
959
1193
  className,
960
- centerContent,
1194
+ contentColumn,
961
1195
  formatToolCallSummary,
962
1196
  onApprovalSubmit,
963
1197
  submittingApprovalIds,
@@ -968,8 +1202,10 @@ function NonVirtualizedThread({
968
1202
  fileReviewCtx,
969
1203
  unresolvedApprovalCount,
970
1204
  onBuildFromPlan,
1205
+ onOpenPlan,
971
1206
  org,
972
1207
  planActionsDisabled,
1208
+ planBuildPending,
973
1209
  onRetrySend,
974
1210
  onRetryExecution,
975
1211
  onEditMessage,
@@ -999,7 +1235,7 @@ function NonVirtualizedThread({
999
1235
  <ApprovalContext.Provider value={approvalCtx}>
1000
1236
  <FileReviewContext.Provider value={fileReviewCtx}>
1001
1237
  <DevProfiler id="MessageThread">
1002
- <div ref={contentRef} className={cn("flex flex-col gap-4", centerContent && "mx-auto w-full max-w-3xl px-4")}>
1238
+ <div ref={contentRef} className={cn("flex flex-col gap-4", threadContentColumnClass(contentColumn))}>
1003
1239
  {items.map((item) => (
1004
1240
  <ThreadItemWrapper key={item.key} animate>
1005
1241
  <ThreadItemRenderer
@@ -1009,8 +1245,10 @@ function NonVirtualizedThread({
1009
1245
  submittingApprovalIds={submittingApprovalIds}
1010
1246
  approvalErrors={approvalErrors}
1011
1247
  onBuildFromPlan={onBuildFromPlan}
1248
+ onOpenPlan={onOpenPlan}
1012
1249
  org={org}
1013
1250
  planActionsDisabled={planActionsDisabled}
1251
+ planBuildPending={planBuildPending}
1014
1252
  onRetrySend={onRetrySend}
1015
1253
  onRetryExecution={onRetryExecution}
1016
1254
  onEditMessage={onEditMessage}
@@ -1061,8 +1299,11 @@ export interface ThreadItemRendererProps {
1061
1299
  readonly submittingApprovalIds?: ReadonlySet<string>;
1062
1300
  readonly approvalErrors?: ReadonlyMap<string, Error>;
1063
1301
  readonly onBuildFromPlan?: () => void;
1302
+ readonly onOpenPlan?: (executionId: string) => void;
1064
1303
  readonly org?: string;
1065
1304
  readonly planActionsDisabled?: boolean;
1305
+ /** True while the approved plan is being uploaded ahead of the build turn. */
1306
+ readonly planBuildPending?: boolean;
1066
1307
  readonly onRetrySend?: () => void;
1067
1308
  readonly onRetryExecution?: (message: string) => void;
1068
1309
  readonly onEditMessage?: (text: string) => void;
@@ -1086,8 +1327,10 @@ export function ThreadItemRenderer({
1086
1327
  submittingApprovalIds,
1087
1328
  approvalErrors,
1088
1329
  onBuildFromPlan,
1330
+ onOpenPlan,
1089
1331
  org,
1090
1332
  planActionsDisabled,
1333
+ planBuildPending,
1091
1334
  onRetrySend,
1092
1335
  onRetryExecution,
1093
1336
  onEditMessage,
@@ -1103,6 +1346,8 @@ export function ThreadItemRenderer({
1103
1346
  <MessageEntry
1104
1347
  message={item.message}
1105
1348
  className={item.isPending ? "opacity-70" : undefined}
1349
+ isPlanDocument={item.isPlanDocument}
1350
+ interactionMode={item.interactionMode}
1106
1351
  onEdit={
1107
1352
  item.isEditable && onEditMessage
1108
1353
  ? () => onEditMessage(item.message.content)
@@ -1167,20 +1412,44 @@ export function ThreadItemRenderer({
1167
1412
  // When the plan was published as an artifact, show the richer reviewable
1168
1413
  // card (preview / copy / download / implement). Otherwise fall back to the
1169
1414
  // bare Implement CTA (older executions, or a plan that failed to publish).
1415
+ // Only the latest plan receives the build action — a superseded plan's
1416
+ // card is review-only, so a stale plan can never be implemented from it.
1170
1417
  return item.planArtifact && item.executionId ? (
1171
1418
  <PlanArtifactCard
1172
1419
  executionId={item.executionId}
1173
1420
  artifact={item.planArtifact}
1421
+ title={item.planTitle}
1174
1422
  org={org}
1175
- onImplement={onBuildFromPlan}
1423
+ onImplement={item.isLatestPlan ? onBuildFromPlan : undefined}
1424
+ // Every card routes to the plan document tab — the host renders a
1425
+ // superseded plan read-only there (it receives the execution id).
1426
+ onOpenPlan={
1427
+ onOpenPlan
1428
+ ? () => onOpenPlan(item.executionId)
1429
+ : undefined
1430
+ }
1176
1431
  disabled={planActionsDisabled}
1432
+ buildPending={planBuildPending}
1177
1433
  />
1178
1434
  ) : (
1179
1435
  <PlanCompletionCard
1180
- onImplement={onBuildFromPlan}
1436
+ onImplement={item.isLatestPlan ? onBuildFromPlan : undefined}
1181
1437
  disabled={planActionsDisabled}
1182
1438
  />
1183
1439
  );
1440
+ case "plan-writing":
1441
+ // The live stand-in for a plan the active turn is writing. Emitted only
1442
+ // when onOpenPlan is wired (see buildThreadItems' collapseStreamingPlan
1443
+ // gate), so the action is always available in practice.
1444
+ return (
1445
+ <PlanStreamingCard
1446
+ title={item.planTitle}
1447
+ sizeBytes={item.planSize}
1448
+ onOpenPlan={
1449
+ onOpenPlan ? () => onOpenPlan(item.executionId) : undefined
1450
+ }
1451
+ />
1452
+ );
1184
1453
  }
1185
1454
  }
1186
1455