@stigmer/react 3.1.1 → 3.1.2

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 (426) hide show
  1. package/composer/SessionComposer.d.ts +24 -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/FilePathContext.d.ts +8 -1
  10. package/execution/FilePathContext.d.ts.map +1 -1
  11. package/execution/FilePathContext.js.map +1 -1
  12. package/execution/FilePathLink.d.ts.map +1 -1
  13. package/execution/FilePathLink.js +21 -6
  14. package/execution/FilePathLink.js.map +1 -1
  15. package/execution/MessageEntry.d.ts +29 -0
  16. package/execution/MessageEntry.d.ts.map +1 -1
  17. package/execution/MessageEntry.js +29 -5
  18. package/execution/MessageEntry.js.map +1 -1
  19. package/execution/MessageThread.d.ts +76 -13
  20. package/execution/MessageThread.d.ts.map +1 -1
  21. package/execution/MessageThread.js +178 -24
  22. package/execution/MessageThread.js.map +1 -1
  23. package/execution/PlanArtifactCard.d.ts +27 -18
  24. package/execution/PlanArtifactCard.d.ts.map +1 -1
  25. package/execution/PlanArtifactCard.js +13 -23
  26. package/execution/PlanArtifactCard.js.map +1 -1
  27. package/execution/PlanDocumentMessage.d.ts +32 -0
  28. package/execution/PlanDocumentMessage.d.ts.map +1 -0
  29. package/execution/PlanDocumentMessage.js +37 -0
  30. package/execution/PlanDocumentMessage.js.map +1 -0
  31. package/execution/PlanStreamingCard.d.ts +45 -0
  32. package/execution/PlanStreamingCard.d.ts.map +1 -0
  33. package/execution/PlanStreamingCard.js +35 -0
  34. package/execution/PlanStreamingCard.js.map +1 -0
  35. package/execution/index.d.ts +5 -1
  36. package/execution/index.d.ts.map +1 -1
  37. package/execution/index.js +2 -0
  38. package/execution/index.js.map +1 -1
  39. package/execution/useCreateAgentExecution.d.ts +10 -0
  40. package/execution/useCreateAgentExecution.d.ts.map +1 -1
  41. package/execution/useCreateAgentExecution.js +5 -1
  42. package/execution/useCreateAgentExecution.js.map +1 -1
  43. package/github/decodeGitHubContent.d.ts +29 -0
  44. package/github/decodeGitHubContent.d.ts.map +1 -0
  45. package/github/decodeGitHubContent.js +72 -0
  46. package/github/decodeGitHubContent.js.map +1 -0
  47. package/github/index.d.ts +1 -0
  48. package/github/index.d.ts.map +1 -1
  49. package/github/index.js +1 -0
  50. package/github/index.js.map +1 -1
  51. package/github/useGitHubFileReader.d.ts +26 -0
  52. package/github/useGitHubFileReader.d.ts.map +1 -0
  53. package/github/useGitHubFileReader.js +106 -0
  54. package/github/useGitHubFileReader.js.map +1 -0
  55. package/github/useGitHubTreeLister.d.ts.map +1 -1
  56. package/github/useGitHubTreeLister.js +6 -2
  57. package/github/useGitHubTreeLister.js.map +1 -1
  58. package/index.d.ts +9 -9
  59. package/index.d.ts.map +1 -1
  60. package/index.js +5 -5
  61. package/index.js.map +1 -1
  62. package/internal/ResizableSplit.d.ts +72 -22
  63. package/internal/ResizableSplit.d.ts.map +1 -1
  64. package/internal/ResizableSplit.js +96 -38
  65. package/internal/ResizableSplit.js.map +1 -1
  66. package/internal/VirtualizedThread.d.ts +5 -3
  67. package/internal/VirtualizedThread.d.ts.map +1 -1
  68. package/internal/VirtualizedThread.js +6 -4
  69. package/internal/VirtualizedThread.js.map +1 -1
  70. package/internal/file-icons/index.d.ts +17 -0
  71. package/internal/file-icons/index.d.ts.map +1 -0
  72. package/internal/file-icons/index.js +60 -0
  73. package/internal/file-icons/index.js.map +1 -0
  74. package/internal/file-tree/FileTreeNode.d.ts +18 -1
  75. package/internal/file-tree/FileTreeNode.d.ts.map +1 -1
  76. package/internal/file-tree/FileTreeNode.js +11 -2
  77. package/internal/file-tree/FileTreeNode.js.map +1 -1
  78. package/internal/markdown-components.d.ts +38 -1
  79. package/internal/markdown-components.d.ts.map +1 -1
  80. package/internal/markdown-components.js +86 -11
  81. package/internal/markdown-components.js.map +1 -1
  82. package/{workflow → internal}/motion-preference.d.ts +7 -4
  83. package/internal/motion-preference.d.ts.map +1 -0
  84. package/{workflow → internal}/motion-preference.js +7 -4
  85. package/internal/motion-preference.js.map +1 -0
  86. package/internal/store/index.d.ts +33 -0
  87. package/internal/store/index.d.ts.map +1 -1
  88. package/internal/store/index.js +59 -0
  89. package/internal/store/index.js.map +1 -1
  90. package/internal/store/workspace-editors-store.d.ts +145 -0
  91. package/internal/store/workspace-editors-store.d.ts.map +1 -0
  92. package/internal/store/workspace-editors-store.js +208 -0
  93. package/internal/store/workspace-editors-store.js.map +1 -0
  94. package/internal/store/workspace-file-selection-store.d.ts +38 -0
  95. package/internal/store/workspace-file-selection-store.d.ts.map +1 -0
  96. package/internal/store/workspace-file-selection-store.js +62 -0
  97. package/internal/store/workspace-file-selection-store.js.map +1 -0
  98. package/internal/useRevealLine.d.ts +49 -0
  99. package/internal/useRevealLine.d.ts.map +1 -0
  100. package/internal/useRevealLine.js +43 -0
  101. package/internal/useRevealLine.js.map +1 -0
  102. package/library/detect-plan-artifact.d.ts +21 -0
  103. package/library/detect-plan-artifact.d.ts.map +1 -1
  104. package/library/detect-plan-artifact.js +20 -0
  105. package/library/detect-plan-artifact.js.map +1 -1
  106. package/library/detect-streaming-plan.d.ts +45 -0
  107. package/library/detect-streaming-plan.d.ts.map +1 -0
  108. package/library/detect-streaming-plan.js +83 -0
  109. package/library/detect-streaming-plan.js.map +1 -0
  110. package/library/index.d.ts +4 -1
  111. package/library/index.d.ts.map +1 -1
  112. package/library/index.js +2 -1
  113. package/library/index.js.map +1 -1
  114. package/package.json +4 -4
  115. package/session/NewSessionViewer.d.ts +19 -4
  116. package/session/NewSessionViewer.d.ts.map +1 -1
  117. package/session/NewSessionViewer.js +52 -25
  118. package/session/NewSessionViewer.js.map +1 -1
  119. package/session/PlanEditor.d.ts +55 -0
  120. package/session/PlanEditor.d.ts.map +1 -0
  121. package/session/PlanEditor.js +88 -0
  122. package/session/PlanEditor.js.map +1 -0
  123. package/session/PlanStreamingDocument.d.ts +30 -0
  124. package/session/PlanStreamingDocument.d.ts.map +1 -0
  125. package/session/PlanStreamingDocument.js +37 -0
  126. package/session/PlanStreamingDocument.js.map +1 -0
  127. package/session/SessionPanelChip.d.ts +26 -0
  128. package/session/SessionPanelChip.d.ts.map +1 -0
  129. package/session/SessionPanelChip.js +40 -0
  130. package/session/SessionPanelChip.js.map +1 -0
  131. package/session/SessionViewer.d.ts +34 -7
  132. package/session/SessionViewer.d.ts.map +1 -1
  133. package/session/SessionViewer.js +315 -33
  134. package/session/SessionViewer.js.map +1 -1
  135. package/session/{inspector → facets}/ArtifactsTab.d.ts +10 -2
  136. package/session/facets/ArtifactsTab.d.ts.map +1 -0
  137. package/session/{inspector → facets}/ArtifactsTab.js +8 -3
  138. package/session/facets/ArtifactsTab.js.map +1 -0
  139. package/session/{inspector → facets}/ChangesTab.d.ts +3 -3
  140. package/session/facets/ChangesTab.d.ts.map +1 -0
  141. package/session/{inspector → facets}/ChangesTab.js +3 -3
  142. package/session/facets/ChangesTab.js.map +1 -0
  143. package/session/facets/InspectTab.d.ts.map +1 -0
  144. package/session/facets/InspectTab.js.map +1 -0
  145. package/session/{inspector → facets}/SetupTab.d.ts +11 -2
  146. package/session/facets/SetupTab.d.ts.map +1 -0
  147. package/session/{inspector → facets}/SetupTab.js +4 -3
  148. package/session/facets/SetupTab.js.map +1 -0
  149. package/session/{inspector → facets}/UsageTab.d.ts +1 -1
  150. package/session/facets/UsageTab.d.ts.map +1 -0
  151. package/session/{inspector → facets}/UsageTab.js +1 -1
  152. package/session/facets/UsageTab.js.map +1 -0
  153. package/session/{inspector → facets}/index.d.ts +0 -6
  154. package/session/facets/index.d.ts.map +1 -0
  155. package/session/{inspector → facets}/index.js +0 -3
  156. package/session/facets/index.js.map +1 -0
  157. package/session/index.d.ts +11 -2
  158. package/session/index.d.ts.map +1 -1
  159. package/session/index.js +15 -2
  160. package/session/index.js.map +1 -1
  161. package/session/plan-document.d.ts +9 -0
  162. package/session/plan-document.d.ts.map +1 -0
  163. package/session/plan-document.js +17 -0
  164. package/session/plan-document.js.map +1 -0
  165. package/session/useOpenFileChange.d.ts +20 -0
  166. package/session/useOpenFileChange.d.ts.map +1 -0
  167. package/session/useOpenFileChange.js +31 -0
  168. package/session/useOpenFileChange.js.map +1 -0
  169. package/session/usePlanDraft.d.ts +52 -0
  170. package/session/usePlanDraft.d.ts.map +1 -0
  171. package/session/usePlanDraft.js +63 -0
  172. package/session/usePlanDraft.js.map +1 -0
  173. package/session/useSessionConversation.d.ts +6 -0
  174. package/session/useSessionConversation.d.ts.map +1 -1
  175. package/session/useSessionConversation.js +1 -0
  176. package/session/useSessionConversation.js.map +1 -1
  177. package/session/useSessionPageFlow.d.ts.map +1 -1
  178. package/session/useSessionPageFlow.js +1 -0
  179. package/session/useSessionPageFlow.js.map +1 -1
  180. package/session/useSessionPanel.d.ts +120 -0
  181. package/session/useSessionPanel.d.ts.map +1 -0
  182. package/session/useSessionPanel.js +130 -0
  183. package/session/useSessionPanel.js.map +1 -0
  184. package/session/useSessionRailViews.d.ts +45 -0
  185. package/session/useSessionRailViews.d.ts.map +1 -0
  186. package/session/useSessionRailViews.js +105 -0
  187. package/session/useSessionRailViews.js.map +1 -0
  188. package/src/composer/SessionComposer.tsx +52 -10
  189. package/src/composer/__tests__/SessionComposer-contract.test.tsx +58 -4
  190. package/src/execution/ArtifactContentRenderer.tsx +101 -24
  191. package/src/execution/FilePathContext.tsx +8 -1
  192. package/src/execution/FilePathLink.tsx +22 -6
  193. package/src/execution/MessageEntry.tsx +111 -1
  194. package/src/execution/MessageThread.tsx +291 -36
  195. package/src/execution/PlanArtifactCard.tsx +63 -31
  196. package/src/execution/PlanDocumentMessage.tsx +96 -0
  197. package/src/execution/PlanStreamingCard.tsx +137 -0
  198. package/src/execution/__tests__/ArtifactContentRenderer.test.tsx +80 -1
  199. package/src/execution/__tests__/FilePathLink.test.tsx +87 -0
  200. package/src/execution/__tests__/MessageThread.test.tsx +101 -0
  201. package/src/execution/__tests__/PlanArtifactCard.test.tsx +66 -12
  202. package/src/execution/__tests__/PlanDocumentMessage.test.tsx +55 -0
  203. package/src/execution/__tests__/PlanStreamingCard.test.tsx +49 -0
  204. package/src/execution/__tests__/buildThreadItems-plan-completion.test.ts +504 -22
  205. package/src/execution/__tests__/message-entry.test.tsx +48 -0
  206. package/src/execution/__tests__/useCreateAgentExecution.test.tsx +85 -0
  207. package/src/execution/index.ts +7 -1
  208. package/src/execution/useCreateAgentExecution.ts +16 -1
  209. package/src/github/__tests__/decodeGitHubContent.test.ts +102 -0
  210. package/src/github/__tests__/useGitHubFileReader.test.ts +183 -0
  211. package/src/github/decodeGitHubContent.ts +83 -0
  212. package/src/github/index.ts +1 -0
  213. package/src/github/useGitHubFileReader.ts +152 -0
  214. package/src/github/useGitHubTreeLister.ts +6 -2
  215. package/src/index.ts +63 -9
  216. package/src/internal/ResizableSplit.tsx +184 -51
  217. package/src/internal/VirtualizedThread.tsx +12 -4
  218. package/src/internal/__tests__/ResizableSplit.test.tsx +125 -3
  219. package/src/internal/__tests__/markdown-components.test.tsx +68 -0
  220. package/src/internal/__tests__/useRevealLine.test.tsx +97 -0
  221. package/src/internal/file-icons/__tests__/file-icons.test.tsx +35 -0
  222. package/src/internal/file-icons/index.tsx +137 -0
  223. package/src/internal/file-tree/FileTreeNode.tsx +43 -3
  224. package/src/internal/file-tree/__tests__/FileTreeNode-explorer.test.tsx +86 -0
  225. package/src/internal/markdown-components.tsx +116 -11
  226. package/src/{workflow → internal}/motion-preference.ts +7 -4
  227. package/src/internal/store/__tests__/workspace-editors-store.test.ts +216 -0
  228. package/src/internal/store/__tests__/workspace-file-selection-store.test.ts +118 -0
  229. package/src/internal/store/index.ts +94 -0
  230. package/src/internal/store/workspace-editors-store.ts +315 -0
  231. package/src/internal/store/workspace-file-selection-store.ts +88 -0
  232. package/src/internal/useRevealLine.ts +81 -0
  233. package/src/library/__tests__/detect-plan-artifact.test.ts +48 -0
  234. package/src/library/__tests__/detect-streaming-plan.test.ts +234 -0
  235. package/src/library/detect-plan-artifact.ts +35 -0
  236. package/src/library/detect-streaming-plan.ts +108 -0
  237. package/src/library/index.ts +5 -0
  238. package/src/session/NewSessionViewer.tsx +123 -55
  239. package/src/session/PlanEditor.tsx +361 -0
  240. package/src/session/PlanStreamingDocument.tsx +97 -0
  241. package/src/session/SessionPanelChip.tsx +103 -0
  242. package/src/session/SessionViewer.tsx +617 -90
  243. package/src/session/__tests__/NewSessionViewer.test.tsx +148 -0
  244. package/src/session/__tests__/PlanEditor.test.tsx +217 -0
  245. package/src/session/__tests__/PlanStreamingDocument.test.tsx +50 -0
  246. package/src/session/__tests__/SessionPanelChip.test.tsx +42 -0
  247. package/src/session/__tests__/SessionViewer-fileReviewDock.test.tsx +9 -4
  248. package/src/session/__tests__/SessionViewer-transcriptFileOpen.test.tsx +205 -0
  249. package/src/session/__tests__/audienceWiring.test.tsx +55 -19
  250. package/src/session/__tests__/useOpenFileChange.test.tsx +82 -0
  251. package/src/session/__tests__/usePlanDraft.test.ts +102 -0
  252. package/src/session/__tests__/useSessionPanel.test.ts +298 -0
  253. package/src/session/__tests__/useSessionRailViews.test.tsx +124 -0
  254. package/src/session/{inspector → facets}/ArtifactsTab.tsx +27 -5
  255. package/src/session/{inspector → facets}/ChangesTab.tsx +3 -3
  256. package/src/session/{inspector → facets}/SetupTab.tsx +13 -1
  257. package/src/session/{inspector → facets}/UsageTab.tsx +1 -1
  258. package/src/session/{inspector → facets}/__tests__/ArtifactsTab.test.tsx +35 -1
  259. package/src/session/facets/__tests__/SetupTab.test.tsx +44 -0
  260. package/src/session/{inspector → facets}/index.ts +0 -16
  261. package/src/session/index.ts +30 -13
  262. package/src/session/plan-document.ts +19 -0
  263. package/src/session/useOpenFileChange.ts +53 -0
  264. package/src/session/usePlanDraft.ts +109 -0
  265. package/src/session/useSessionConversation.ts +7 -0
  266. package/src/session/useSessionPageFlow.ts +1 -0
  267. package/src/session/useSessionPanel.ts +288 -0
  268. package/src/session/useSessionRailViews.tsx +200 -0
  269. package/src/workflow/WorkflowExecutionGraph.tsx +1 -1
  270. package/src/workflow/index.ts +1 -1
  271. package/src/workflow/useFollowExecution.ts +1 -1
  272. package/src/workspace/EditorTabs.tsx +145 -0
  273. package/src/workspace/ExplorerTree.tsx +247 -0
  274. package/src/workspace/FileViewer.tsx +516 -0
  275. package/src/workspace/WorkspaceContentSearch.tsx +478 -0
  276. package/src/workspace/WorkspaceContentSearcher.ts +70 -0
  277. package/src/workspace/WorkspaceFileLister.ts +11 -0
  278. package/src/workspace/WorkspaceFileReader.ts +57 -0
  279. package/src/workspace/WorkspaceFileSearch.tsx +429 -0
  280. package/src/workspace/WorkspaceSurface.tsx +781 -0
  281. package/src/workspace/__tests__/EditorTabs.test.tsx +100 -0
  282. package/src/workspace/__tests__/ExplorerTree.test.tsx +152 -0
  283. package/src/workspace/__tests__/FileViewer.test.tsx +421 -0
  284. package/src/workspace/__tests__/WorkspaceContentSearch.test.tsx +196 -0
  285. package/src/workspace/__tests__/WorkspaceFileSearch.test.tsx +206 -0
  286. package/src/workspace/__tests__/WorkspaceSurface.test.tsx +348 -0
  287. package/src/workspace/__tests__/findChangeForSelection.test.ts +132 -0
  288. package/src/workspace/__tests__/matchContentPreview.test.ts +55 -0
  289. package/src/workspace/__tests__/matchWorkspaceFiles.test.ts +104 -0
  290. package/src/workspace/__tests__/resolveWorkspaceFileSelection.test.ts +135 -0
  291. package/src/workspace/__tests__/useWorkspaceContentSearch.test.tsx +196 -0
  292. package/src/workspace/__tests__/useWorkspaceFileContent.test.tsx +190 -0
  293. package/src/workspace/__tests__/useWorkspaceFileSearch.test.tsx +162 -0
  294. package/src/workspace/findChangeForSelection.ts +61 -0
  295. package/src/workspace/index.ts +56 -2
  296. package/src/workspace/matchContentPreview.ts +51 -0
  297. package/src/workspace/matchWorkspaceFiles.ts +86 -0
  298. package/src/workspace/resolveWorkspaceFileSelection.ts +119 -0
  299. package/src/workspace/useWorkspaceContentSearch.ts +228 -0
  300. package/src/workspace/useWorkspaceFileContent.ts +129 -0
  301. package/src/workspace/useWorkspaceFileSearch.ts +184 -0
  302. package/src/workspace/useWorkspaceFiles.ts +27 -27
  303. package/src/workspace/workspaceListingCache.ts +93 -0
  304. package/styles.css +1 -1
  305. package/workflow/WorkflowExecutionGraph.js +1 -1
  306. package/workflow/WorkflowExecutionGraph.js.map +1 -1
  307. package/workflow/index.d.ts +1 -1
  308. package/workflow/index.d.ts.map +1 -1
  309. package/workflow/index.js +1 -1
  310. package/workflow/index.js.map +1 -1
  311. package/workflow/useFollowExecution.js +1 -1
  312. package/workflow/useFollowExecution.js.map +1 -1
  313. package/workspace/EditorTabs.d.ts +29 -0
  314. package/workspace/EditorTabs.d.ts.map +1 -0
  315. package/workspace/EditorTabs.js +66 -0
  316. package/workspace/EditorTabs.js.map +1 -0
  317. package/workspace/ExplorerTree.d.ts +32 -0
  318. package/workspace/ExplorerTree.d.ts.map +1 -0
  319. package/workspace/ExplorerTree.js +45 -0
  320. package/workspace/ExplorerTree.js.map +1 -0
  321. package/workspace/FileViewer.d.ts +93 -0
  322. package/workspace/FileViewer.d.ts.map +1 -0
  323. package/workspace/FileViewer.js +182 -0
  324. package/workspace/FileViewer.js.map +1 -0
  325. package/workspace/WorkspaceContentSearch.d.ts +41 -0
  326. package/workspace/WorkspaceContentSearch.d.ts.map +1 -0
  327. package/workspace/WorkspaceContentSearch.js +195 -0
  328. package/workspace/WorkspaceContentSearch.js.map +1 -0
  329. package/workspace/WorkspaceContentSearcher.d.ts +59 -0
  330. package/workspace/WorkspaceContentSearcher.d.ts.map +1 -0
  331. package/workspace/WorkspaceContentSearcher.js +7 -0
  332. package/workspace/WorkspaceContentSearcher.js.map +1 -0
  333. package/workspace/WorkspaceFileLister.d.ts +11 -0
  334. package/workspace/WorkspaceFileLister.d.ts.map +1 -1
  335. package/workspace/WorkspaceFileReader.d.ts +48 -0
  336. package/workspace/WorkspaceFileReader.d.ts.map +1 -0
  337. package/workspace/WorkspaceFileReader.js +11 -0
  338. package/workspace/WorkspaceFileReader.js.map +1 -0
  339. package/workspace/WorkspaceFileSearch.d.ts +32 -0
  340. package/workspace/WorkspaceFileSearch.d.ts.map +1 -0
  341. package/workspace/WorkspaceFileSearch.js +155 -0
  342. package/workspace/WorkspaceFileSearch.js.map +1 -0
  343. package/workspace/WorkspaceSurface.d.ts +151 -0
  344. package/workspace/WorkspaceSurface.d.ts.map +1 -0
  345. package/workspace/WorkspaceSurface.js +184 -0
  346. package/workspace/WorkspaceSurface.js.map +1 -0
  347. package/workspace/findChangeForSelection.d.ts +19 -0
  348. package/workspace/findChangeForSelection.d.ts.map +1 -0
  349. package/workspace/findChangeForSelection.js +46 -0
  350. package/workspace/findChangeForSelection.js.map +1 -0
  351. package/workspace/index.d.ts +24 -2
  352. package/workspace/index.d.ts.map +1 -1
  353. package/workspace/index.js +13 -1
  354. package/workspace/index.js.map +1 -1
  355. package/workspace/matchContentPreview.d.ts +21 -0
  356. package/workspace/matchContentPreview.d.ts.map +1 -0
  357. package/workspace/matchContentPreview.js +36 -0
  358. package/workspace/matchContentPreview.js.map +1 -0
  359. package/workspace/matchWorkspaceFiles.d.ts +30 -0
  360. package/workspace/matchWorkspaceFiles.d.ts.map +1 -0
  361. package/workspace/matchWorkspaceFiles.js +58 -0
  362. package/workspace/matchWorkspaceFiles.js.map +1 -0
  363. package/workspace/resolveWorkspaceFileSelection.d.ts +19 -0
  364. package/workspace/resolveWorkspaceFileSelection.d.ts.map +1 -0
  365. package/workspace/resolveWorkspaceFileSelection.js +115 -0
  366. package/workspace/resolveWorkspaceFileSelection.js.map +1 -0
  367. package/workspace/useWorkspaceContentSearch.d.ts +69 -0
  368. package/workspace/useWorkspaceContentSearch.d.ts.map +1 -0
  369. package/workspace/useWorkspaceContentSearch.js +154 -0
  370. package/workspace/useWorkspaceContentSearch.js.map +1 -0
  371. package/workspace/useWorkspaceFileContent.d.ts +73 -0
  372. package/workspace/useWorkspaceFileContent.d.ts.map +1 -0
  373. package/workspace/useWorkspaceFileContent.js +57 -0
  374. package/workspace/useWorkspaceFileContent.js.map +1 -0
  375. package/workspace/useWorkspaceFileSearch.d.ts +61 -0
  376. package/workspace/useWorkspaceFileSearch.d.ts.map +1 -0
  377. package/workspace/useWorkspaceFileSearch.js +119 -0
  378. package/workspace/useWorkspaceFileSearch.js.map +1 -0
  379. package/workspace/useWorkspaceFiles.d.ts +13 -5
  380. package/workspace/useWorkspaceFiles.d.ts.map +1 -1
  381. package/workspace/useWorkspaceFiles.js +18 -19
  382. package/workspace/useWorkspaceFiles.js.map +1 -1
  383. package/workspace/workspaceListingCache.d.ts +47 -0
  384. package/workspace/workspaceListingCache.d.ts.map +1 -0
  385. package/workspace/workspaceListingCache.js +55 -0
  386. package/workspace/workspaceListingCache.js.map +1 -0
  387. package/session/inspector/ArtifactsTab.d.ts.map +0 -1
  388. package/session/inspector/ArtifactsTab.js.map +0 -1
  389. package/session/inspector/ChangesTab.d.ts.map +0 -1
  390. package/session/inspector/ChangesTab.js.map +0 -1
  391. package/session/inspector/InspectTab.d.ts.map +0 -1
  392. package/session/inspector/InspectTab.js.map +0 -1
  393. package/session/inspector/SessionInspector.d.ts +0 -64
  394. package/session/inspector/SessionInspector.d.ts.map +0 -1
  395. package/session/inspector/SessionInspector.js +0 -53
  396. package/session/inspector/SessionInspector.js.map +0 -1
  397. package/session/inspector/SetupTab.d.ts.map +0 -1
  398. package/session/inspector/SetupTab.js.map +0 -1
  399. package/session/inspector/UsageTab.d.ts.map +0 -1
  400. package/session/inspector/UsageTab.js.map +0 -1
  401. package/session/inspector/WorkspaceTab.d.ts +0 -35
  402. package/session/inspector/WorkspaceTab.d.ts.map +0 -1
  403. package/session/inspector/WorkspaceTab.js +0 -75
  404. package/session/inspector/WorkspaceTab.js.map +0 -1
  405. package/session/inspector/index.d.ts.map +0 -1
  406. package/session/inspector/index.js.map +0 -1
  407. package/session/inspector/useSessionInspector.d.ts +0 -49
  408. package/session/inspector/useSessionInspector.d.ts.map +0 -1
  409. package/session/inspector/useSessionInspector.js +0 -122
  410. package/session/inspector/useSessionInspector.js.map +0 -1
  411. package/src/session/inspector/SessionInspector.tsx +0 -162
  412. package/src/session/inspector/WorkspaceTab.tsx +0 -245
  413. package/src/session/inspector/__tests__/useSessionInspector.test.ts +0 -251
  414. package/src/session/inspector/useSessionInspector.ts +0 -178
  415. package/src/workspace/WorkspaceEntryFiles.tsx +0 -196
  416. package/workflow/motion-preference.d.ts.map +0 -1
  417. package/workflow/motion-preference.js.map +0 -1
  418. package/workspace/WorkspaceEntryFiles.d.ts +0 -22
  419. package/workspace/WorkspaceEntryFiles.d.ts.map +0 -1
  420. package/workspace/WorkspaceEntryFiles.js +0 -58
  421. package/workspace/WorkspaceEntryFiles.js.map +0 -1
  422. /package/session/{inspector → facets}/InspectTab.d.ts +0 -0
  423. /package/session/{inspector → facets}/InspectTab.js +0 -0
  424. /package/src/{workflow → internal}/__tests__/motion-preference.test.ts +0 -0
  425. /package/src/session/{inspector → facets}/InspectTab.tsx +0 -0
  426. /package/src/session/{inspector → facets}/__tests__/ChangesTab.test.tsx +0 -0
@@ -125,7 +125,7 @@ describe("SessionComposer — public contract", () => {
125
125
  });
126
126
  });
127
127
 
128
- describe("SessionComposer — imperative submit (Implement plan)", () => {
128
+ describe("SessionComposer — imperative submit (Build from plan)", () => {
129
129
  it("submits a message with the interactionMode override, even when the picker is 'plan'", async () => {
130
130
  const ref = createRef<SessionComposerHandle>();
131
131
  const { onSubmit } = renderComposer({
@@ -134,13 +134,13 @@ describe("SessionComposer — imperative submit (Implement plan)", () => {
134
134
  interactionMode: "plan",
135
135
  });
136
136
 
137
- ref.current!.submit("Implement the plan above", { interactionMode: "agent" });
137
+ ref.current!.submit("Build from plan", { interactionMode: "agent" });
138
138
 
139
139
  await waitFor(() => {
140
140
  expect(onSubmit).toHaveBeenCalledOnce();
141
141
  });
142
142
  const [message, , context] = onSubmit.mock.calls[0];
143
- expect(message).toBe("Implement the plan above");
143
+ expect(message).toBe("Build from plan");
144
144
  // The override must win over the current picker value ("plan") so the
145
145
  // implement run executes in Agent mode regardless of render timing.
146
146
  expect(context?.interactionMode).toBe("agent");
@@ -150,7 +150,7 @@ describe("SessionComposer — imperative submit (Implement plan)", () => {
150
150
  const ref = createRef<SessionComposerHandle>();
151
151
  const { onSubmit } = renderComposer({ ref, disabled: true });
152
152
 
153
- ref.current!.submit("Implement the plan above", { interactionMode: "agent" });
153
+ ref.current!.submit("Build from plan", { interactionMode: "agent" });
154
154
 
155
155
  expect(onSubmit).not.toHaveBeenCalled();
156
156
  });
@@ -163,4 +163,58 @@ describe("SessionComposer — imperative submit (Implement plan)", () => {
163
163
 
164
164
  expect(onSubmit).not.toHaveBeenCalled();
165
165
  });
166
+
167
+ it("carries caller-supplied attachments into the submit context (approved plan.md)", async () => {
168
+ const ref = createRef<SessionComposerHandle>();
169
+ const { onSubmit } = renderComposer({ ref });
170
+
171
+ const planAttachment = {
172
+ filename: "plan.md",
173
+ storageKey: "attachments/01ABC/plan.md",
174
+ mountPath: ".stigmer/inputs/plan.md",
175
+ contentType: "text/markdown",
176
+ };
177
+ ref.current!.submit("Build from plan", {
178
+ interactionMode: "agent",
179
+ attachments: [planAttachment],
180
+ });
181
+
182
+ await waitFor(() => {
183
+ expect(onSubmit).toHaveBeenCalledOnce();
184
+ });
185
+ const [, , context] = onSubmit.mock.calls[0];
186
+ expect(context?.attachments).toEqual([planAttachment]);
187
+ expect(context?.interactionMode).toBe("agent");
188
+ });
189
+
190
+ it("carries the buildFromPlan flag into the submit context", async () => {
191
+ const ref = createRef<SessionComposerHandle>();
192
+ const { onSubmit } = renderComposer({ ref });
193
+
194
+ ref.current!.submit("Build from plan", {
195
+ interactionMode: "agent",
196
+ buildFromPlan: true,
197
+ });
198
+
199
+ await waitFor(() => {
200
+ expect(onSubmit).toHaveBeenCalledOnce();
201
+ });
202
+ const [, , context] = onSubmit.mock.calls[0];
203
+ expect(context?.buildFromPlan).toBe(true);
204
+ expect(context?.interactionMode).toBe("agent");
205
+ });
206
+
207
+ it("leaves buildFromPlan unset for ordinary submissions", async () => {
208
+ const { onSubmit } = renderComposer();
209
+
210
+ const textarea = screen.getByRole("textbox");
211
+ fireEvent.change(textarea, { target: { value: "Hello world" } });
212
+ fireEvent.keyDown(textarea, { key: "Enter", shiftKey: false });
213
+
214
+ await waitFor(() => {
215
+ expect(onSubmit).toHaveBeenCalledOnce();
216
+ });
217
+ const [, , context] = onSubmit.mock.calls[0];
218
+ expect(context?.buildFromPlan).toBeUndefined();
219
+ });
166
220
  });
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { useMemo, useState, type ReactNode } from "react";
3
+ import { useEffect, useMemo, useState, type ReactNode } from "react";
4
4
  import Markdown from "react-markdown";
5
5
  import { cn } from "@stigmer/theme";
6
6
  import {
@@ -8,6 +8,7 @@ import {
8
8
  REMARK_PLUGINS,
9
9
  unwrapEnclosingMarkdownFence,
10
10
  } from "../internal/markdown-components.js";
11
+ import { useRevealLine, type RevealTarget } from "../internal/useRevealLine.js";
11
12
  import {
12
13
  getArtifactRenderMode,
13
14
  type ArtifactRenderMode,
@@ -29,6 +30,15 @@ export interface ArtifactContentRendererProps {
29
30
  readonly contentType?: string | null;
30
31
  /** When `true`, shows a truncation warning below the content. */
31
32
  readonly isTruncated?: boolean;
33
+ /**
34
+ * Optional jump-to-line request. When set, the content is rendered
35
+ * **line-faithfully** so the line number maps to the file's real rows —
36
+ * Markdown defaults to its Source view (a line only exists in source) and
37
+ * JSON renders raw rather than pretty-printed (reformatting would shift line
38
+ * numbers) — and the target line is scrolled into view and highlighted. Absent
39
+ * (the default), rendering is unchanged. See {@link RevealTarget}.
40
+ */
41
+ readonly reveal?: RevealTarget;
32
42
  /** Additional CSS classes for the root element. */
33
43
  readonly className?: string;
34
44
  }
@@ -76,6 +86,7 @@ export function ArtifactContentRenderer({
76
86
  fileName,
77
87
  contentType,
78
88
  isTruncated = false,
89
+ reveal,
79
90
  className,
80
91
  }: ArtifactContentRendererProps) {
81
92
  const mode = getArtifactRenderMode(fileName, contentType);
@@ -83,13 +94,19 @@ export function ArtifactContentRenderer({
83
94
  return (
84
95
  <div className={cn(className)}>
85
96
  {mode === "markdown" ? (
86
- <MarkdownView content={content} />
97
+ <MarkdownView content={content} reveal={reveal} />
87
98
  ) : mode === "yaml" ? (
88
- <YamlView content={content} />
99
+ <YamlView content={content} reveal={reveal} />
89
100
  ) : mode === "json" ? (
90
- <JsonView content={content} />
101
+ // A reveal needs raw, line-faithful JSON: pretty-printing reformats the
102
+ // file and would shift the target line off its real row.
103
+ reveal ? (
104
+ <LineNumberedPre content={content} reveal={reveal} />
105
+ ) : (
106
+ <JsonView content={content} />
107
+ )
91
108
  ) : (
92
- <PlainTextView content={content} />
109
+ <PlainTextView content={content} reveal={reveal} />
93
110
  )}
94
111
 
95
112
  {isTruncated && <TruncationWarning />}
@@ -103,8 +120,21 @@ export function ArtifactContentRenderer({
103
120
 
104
121
  type MarkdownTab = "rendered" | "source";
105
122
 
106
- function MarkdownView({ content }: { readonly content: string }) {
107
- const [tab, setTab] = useState<MarkdownTab>("rendered");
123
+ function MarkdownView({
124
+ content,
125
+ reveal,
126
+ }: {
127
+ readonly content: string;
128
+ readonly reveal?: RevealTarget;
129
+ }) {
130
+ // A reveal targets a source line (the rendered HTML has no line concept), so
131
+ // default to — and, on every new reveal, return to — the Source view.
132
+ const [tab, setTab] = useState<MarkdownTab>(reveal ? "source" : "rendered");
133
+ // Keyed on the reveal nonce: each fresh jump-to-line returns to Source (where
134
+ // the line exists); switching to Rendered afterward sticks until the next hit.
135
+ useEffect(() => {
136
+ if (reveal) setTab("source");
137
+ }, [reveal?.nonce]);
108
138
 
109
139
  // A `.md` whose entire body is one ```markdown fence (e.g. a model-wrapped
110
140
  // plan) would render flat. Unwrap for the Rendered view only — Source stays
@@ -145,7 +175,7 @@ function MarkdownView({ content }: { readonly content: string }) {
145
175
  </Markdown>
146
176
  </div>
147
177
  ) : (
148
- <LineNumberedPre content={content} />
178
+ <LineNumberedPre content={content} reveal={reveal} />
149
179
  )}
150
180
  </div>
151
181
  );
@@ -197,15 +227,6 @@ function TabButton({
197
227
  *
198
228
  * Values and block scalar content render in the default `text-foreground`.
199
229
  */
200
- function highlightYaml(content: string): ReactNode {
201
- return content.split("\n").map((line, i) => (
202
- <span key={i}>
203
- {i > 0 && "\n"}
204
- {highlightYamlLine(line)}
205
- </span>
206
- ));
207
- }
208
-
209
230
  function highlightYamlLine(line: string): ReactNode {
210
231
  if (!line.trim()) return line;
211
232
 
@@ -253,10 +274,38 @@ function highlightYamlValue(value: string): ReactNode {
253
274
  return <>{value}</>;
254
275
  }
255
276
 
256
- function YamlView({ content }: { readonly content: string }) {
277
+ function YamlView({
278
+ content,
279
+ reveal,
280
+ }: {
281
+ readonly content: string;
282
+ readonly reveal?: RevealTarget;
283
+ }) {
284
+ const { containerRef, isRevealed } = useRevealLine(reveal);
285
+ const lines = content.split("\n");
286
+
257
287
  return (
258
288
  <pre className="overflow-x-auto p-4 font-mono text-xs leading-relaxed text-foreground">
259
- <code>{highlightYaml(content)}</code>
289
+ <code ref={containerRef}>
290
+ {lines.map((line, i) => (
291
+ <span
292
+ key={i}
293
+ data-line={i + 1}
294
+ className={cn(
295
+ // Transparent left border by default so revealing a line only
296
+ // changes its color — never shifts the text (no layout jump).
297
+ "block border-l-2 border-transparent",
298
+ isRevealed(i + 1) && "border-primary bg-primary-subtle",
299
+ )}
300
+ >
301
+ {/* whitespace-pre inner + `\n` fallback preserves indentation and
302
+ the height of blank lines, mirroring LineNumberedPre. */}
303
+ <span className="whitespace-pre">
304
+ {line.trim() ? highlightYamlLine(line) : "\n"}
305
+ </span>
306
+ </span>
307
+ ))}
308
+ </code>
260
309
  </pre>
261
310
  );
262
311
  }
@@ -345,19 +394,47 @@ function JsonView({ content }: { readonly content: string }) {
345
394
  // Plain text view (monospace + line numbers)
346
395
  // ---------------------------------------------------------------------------
347
396
 
348
- function PlainTextView({ content }: { readonly content: string }) {
349
- return <LineNumberedPre content={content} />;
397
+ function PlainTextView({
398
+ content,
399
+ reveal,
400
+ }: {
401
+ readonly content: string;
402
+ readonly reveal?: RevealTarget;
403
+ }) {
404
+ return <LineNumberedPre content={content} reveal={reveal} />;
350
405
  }
351
406
 
352
- function LineNumberedPre({ content }: { readonly content: string }) {
407
+ /**
408
+ * Line-numbered monospace view. The single line-faithful primitive behind plain
409
+ * text, Markdown Source, and reveal-mode JSON: every row is addressable
410
+ * (`data-line`), so a {@link RevealTarget} can scroll to and highlight a line
411
+ * (via {@link useRevealLine}). Absent a reveal it renders exactly as before.
412
+ */
413
+ function LineNumberedPre({
414
+ content,
415
+ reveal,
416
+ }: {
417
+ readonly content: string;
418
+ readonly reveal?: RevealTarget;
419
+ }) {
420
+ const { containerRef, isRevealed } = useRevealLine(reveal);
353
421
  const lines = content.split("\n");
354
422
  const gutterWidth = String(lines.length).length;
355
423
 
356
424
  return (
357
425
  <pre className="overflow-x-auto font-mono text-xs leading-relaxed text-foreground">
358
- <code>
426
+ <code ref={containerRef}>
359
427
  {lines.map((line, i) => (
360
- <span key={i} className="flex">
428
+ <span
429
+ key={i}
430
+ data-line={i + 1}
431
+ className={cn(
432
+ // Transparent left border by default so a reveal only recolors the
433
+ // row — never shifts its text (no layout jump).
434
+ "flex border-l-2 border-transparent",
435
+ isRevealed(i + 1) && "border-primary bg-primary-subtle",
436
+ )}
437
+ >
361
438
  <span
362
439
  className="sticky left-0 select-none bg-background pr-4 text-right text-muted-foreground"
363
440
  style={{ minWidth: `${gutterWidth + 2}ch` }}
@@ -18,11 +18,18 @@ export interface FilePathContextValue {
18
18
  * `FilePathLink` delegates to this callback instead of opening
19
19
  * a URL or copying to clipboard. Platform builders use this to
20
20
  * integrate their own file viewer or navigation.
21
+ *
22
+ * Return `false` to **decline** a specific path — `FilePathLink` then falls
23
+ * back to its default action (open the GitHub link / copy the path), so a
24
+ * handler that can only open *some* paths (e.g. resolvable workspace files)
25
+ * leaves the rest behaving as before. Returning `true` or `void` means the
26
+ * click was fully handled and the default is suppressed — preserving the
27
+ * behavior of existing `void`-returning handlers.
21
28
  */
22
29
  readonly onFilePathClick?: (
23
30
  path: string,
24
31
  resolved: ResolvedPathAction,
25
- ) => void;
32
+ ) => boolean | void;
26
33
  }
27
34
 
28
35
  const DEFAULT_VALUE: FilePathContextValue = {
@@ -92,15 +92,26 @@ export function FilePathLink({
92
92
  // (ToolCallItem's role=button header); copying/opening a path must not
93
93
  // also expand the row.
94
94
  e.stopPropagation();
95
+
96
+ // Offer the click to the injected handler first. It returns `false` to
97
+ // DECLINE (e.g. an in-app viewer that can't open this particular path),
98
+ // in which case we fall through to the default action below. A `true`/
99
+ // `void` return means it fully handled the click.
95
100
  if (onFilePathClick) {
96
- e.preventDefault();
97
- onFilePathClick(path, resolved);
98
- return;
101
+ const handled = onFilePathClick(path, resolved);
102
+ if (handled !== false) {
103
+ // For a link, also stop the browser from navigating (the file opened
104
+ // in-app instead). A modifier/middle-click bypasses this onClick, so
105
+ // the real <a href> still opens the target in a new tab.
106
+ if (resolved.action === "link") e.preventDefault();
107
+ return;
108
+ }
99
109
  }
110
+
100
111
  if (resolved.action === "copy") {
101
112
  handleCopy();
102
113
  }
103
- // For "link" action the <a> default navigation handles it.
114
+ // For a declined/un-handled "link", the <a>'s native navigation runs.
104
115
  },
105
116
  [onFilePathClick, path, resolved, handleCopy],
106
117
  );
@@ -125,13 +136,18 @@ export function FilePathLink({
125
136
  </>
126
137
  );
127
138
 
128
- if (resolved.action === "link" && !onFilePathClick) {
139
+ // A link-action path always renders a real anchor — even when an
140
+ // `onFilePathClick` handler is present — so native link affordances
141
+ // (middle-click, open-in-new-tab, copy-link-address) survive. `handleClick`
142
+ // intercepts a plain left-click to route it through the handler (e.g. into an
143
+ // in-app viewer) and only calls `preventDefault` when the handler took it.
144
+ if (resolved.action === "link") {
129
145
  return (
130
146
  <a
131
147
  href={resolved.url}
132
148
  target="_blank"
133
149
  rel="noopener noreferrer"
134
- onClick={(e) => e.stopPropagation()}
150
+ onClick={handleClick}
135
151
  aria-label={ariaLabel}
136
152
  title={title}
137
153
  className={cn(sharedClasses, "group/fpl")}
@@ -3,12 +3,17 @@
3
3
  import { memo, useMemo, useState } from "react";
4
4
  import { Streamdown } from "streamdown";
5
5
  import type { AgentMessage } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
6
- import { MessageType } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
6
+ import {
7
+ MessageType,
8
+ type InteractionMode,
9
+ } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
7
10
  import { cn } from "@stigmer/theme";
8
11
  import {
9
12
  MARKDOWN_COMPONENTS,
10
13
  unwrapEnclosingMarkdownFence,
11
14
  } from "../internal/markdown-components.js";
15
+ import { InteractionModeBadge } from "./InteractionModeBadge.js";
16
+ import { PlanDocumentMessage } from "./PlanDocumentMessage.js";
12
17
  import { useRenderTracer } from "../internal/dev/index.js";
13
18
 
14
19
  /** Props for {@link MessageEntry}. */
@@ -24,6 +29,34 @@ export interface MessageEntryProps {
24
29
  * this message for editing. Ignored for non-human messages.
25
30
  */
26
31
  readonly onEdit?: () => void;
32
+ /**
33
+ * Renders a `MESSAGE_AI` entry as a first-class plan document
34
+ * ({@link PlanDocumentMessage}) instead of a chat bubble. Set by the thread
35
+ * builder only on the NO-ARTIFACT fallback path: a completed Plan turn that
36
+ * never published `plan.md` (older executions, failed upload) keeps its
37
+ * plan inline — the message is the only copy of the plan. A turn that
38
+ * published the artifact collapses the message into the compact plan card
39
+ * instead (the document lives in the panel's plan tab). Ignored for non-AI
40
+ * messages.
41
+ */
42
+ readonly isPlanDocument?: boolean;
43
+ /**
44
+ * The turn's interaction mode, stamped by the thread builder on the
45
+ * synthetic prompt bubble (`MESSAGE_HUMAN`). Renders the
46
+ * {@link InteractionModeBadge} for non-default modes (a "Plan" pill), so
47
+ * the transcript reads unambiguously after mode switches. Ignored for
48
+ * non-human messages.
49
+ */
50
+ readonly interactionMode?: InteractionMode;
51
+ /**
52
+ * Renders a `MESSAGE_HUMAN` entry as a compact "Build from plan" chip
53
+ * instead of a prompt bubble. Stamped by the thread builder from
54
+ * `execution_config.build_from_plan`: the turn's message is a short label
55
+ * (the implement instruction is runner-injected), so a full-width bubble
56
+ * would dignify machine plumbing as user prose. Ignored for non-human
57
+ * messages.
58
+ */
59
+ readonly isBuildFromPlan?: boolean;
27
60
  }
28
61
 
29
62
  /**
@@ -54,6 +87,9 @@ export const MessageEntry = memo(function MessageEntry({
54
87
  message,
55
88
  className,
56
89
  onEdit,
90
+ isPlanDocument,
91
+ interactionMode,
92
+ isBuildFromPlan,
57
93
  }: MessageEntryProps) {
58
94
  useRenderTracer("MessageEntry", {
59
95
  messageType: message.type,
@@ -63,14 +99,27 @@ export const MessageEntry = memo(function MessageEntry({
63
99
 
64
100
  switch (message.type) {
65
101
  case MessageType.MESSAGE_HUMAN:
102
+ if (isBuildFromPlan) {
103
+ return (
104
+ <BuildFromPlanChip content={message.content} className={className} />
105
+ );
106
+ }
66
107
  return (
67
108
  <HumanMessage
68
109
  content={message.content}
69
110
  className={className}
70
111
  onEdit={onEdit}
112
+ interactionMode={interactionMode}
71
113
  />
72
114
  );
73
115
  case MessageType.MESSAGE_AI:
116
+ // A completed Plan turn's plan is a document, not a bubble. The flag is
117
+ // only ever set on a settled message, so the streaming path is untouched.
118
+ if (isPlanDocument) {
119
+ return (
120
+ <PlanDocumentMessage content={message.content} className={className} />
121
+ );
122
+ }
74
123
  return (
75
124
  <AiMessage
76
125
  content={message.content}
@@ -97,10 +146,12 @@ function HumanMessage({
97
146
  content,
98
147
  className,
99
148
  onEdit,
149
+ interactionMode,
100
150
  }: {
101
151
  content: string;
102
152
  className?: string;
103
153
  onEdit?: () => void;
154
+ interactionMode?: InteractionMode;
104
155
  }) {
105
156
  return (
106
157
  <div
@@ -111,6 +162,11 @@ function HumanMessage({
111
162
  className,
112
163
  )}
113
164
  >
165
+ {/* The badge renders only for non-default modes (a "Plan" pill), so
166
+ ordinary Agent turns carry no extra chrome. */}
167
+ {interactionMode !== undefined && (
168
+ <InteractionModeBadge mode={interactionMode} className="mb-1.5" />
169
+ )}
114
170
  <p className="text-sm text-foreground whitespace-pre-wrap">{content}</p>
115
171
  {onEdit && (
116
172
  <button
@@ -133,6 +189,60 @@ function HumanMessage({
133
189
  );
134
190
  }
135
191
 
192
+ /**
193
+ * The Build-from-plan turn's user entry: a compact pill in the user-turn
194
+ * position (right-aligned, like the prompt bubble it replaces) carrying the
195
+ * plan glyph and the turn's short label. Deliberately not editable — the
196
+ * label is not user prose to rephrase; refining the plan happens in the plan
197
+ * document, and the build is re-triggered from its card.
198
+ */
199
+ function BuildFromPlanChip({
200
+ content,
201
+ className,
202
+ }: {
203
+ content: string;
204
+ className?: string;
205
+ }) {
206
+ return (
207
+ <div
208
+ role="article"
209
+ aria-label="Build from plan"
210
+ className={cn("flex justify-end", className)}
211
+ >
212
+ <span
213
+ className={cn(
214
+ "inline-flex items-center gap-1.5 rounded-full border border-border",
215
+ "bg-muted-subtle px-3 py-1.5 text-xs font-medium text-foreground",
216
+ )}
217
+ >
218
+ <BuildFromPlanIcon />
219
+ {content}
220
+ </span>
221
+ </div>
222
+ );
223
+ }
224
+
225
+ /** The plan-card glyph (document lines + implement arrow) at chip scale. */
226
+ function BuildFromPlanIcon() {
227
+ return (
228
+ <svg
229
+ width="13"
230
+ height="13"
231
+ viewBox="0 0 16 16"
232
+ fill="none"
233
+ stroke="currentColor"
234
+ strokeWidth="1.5"
235
+ strokeLinecap="round"
236
+ strokeLinejoin="round"
237
+ className="shrink-0 text-muted-foreground"
238
+ aria-hidden="true"
239
+ >
240
+ <path d="M3 4h10M3 8h7M3 12h8" />
241
+ <path d="M12.5 10.5l1.5 1.5-1.5 1.5" />
242
+ </svg>
243
+ );
244
+ }
245
+
136
246
  function EditIcon() {
137
247
  return (
138
248
  <svg