@stigmer/react 3.0.9-dev.20260616060535 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (426) hide show
  1. package/execution/ApprovalCard.d.ts +47 -3
  2. package/execution/ApprovalCard.d.ts.map +1 -1
  3. package/execution/ApprovalCard.js +138 -70
  4. package/execution/ApprovalCard.js.map +1 -1
  5. package/execution/ApprovalContext.d.ts +72 -0
  6. package/execution/ApprovalContext.d.ts.map +1 -0
  7. package/execution/ApprovalContext.js +41 -0
  8. package/execution/ApprovalContext.js.map +1 -0
  9. package/execution/ArtifactCard.d.ts.map +1 -1
  10. package/execution/ArtifactCard.js +3 -1
  11. package/execution/ArtifactCard.js.map +1 -1
  12. package/execution/ArtifactPreviewModal.d.ts.map +1 -1
  13. package/execution/ArtifactPreviewModal.js +5 -3
  14. package/execution/ArtifactPreviewModal.js.map +1 -1
  15. package/execution/EmptyChangeNotice.d.ts +38 -0
  16. package/execution/EmptyChangeNotice.d.ts.map +1 -0
  17. package/execution/EmptyChangeNotice.js +27 -0
  18. package/execution/EmptyChangeNotice.js.map +1 -0
  19. package/execution/FileChangesView.d.ts +81 -0
  20. package/execution/FileChangesView.d.ts.map +1 -0
  21. package/execution/FileChangesView.js +164 -0
  22. package/execution/FileChangesView.js.map +1 -0
  23. package/execution/FilePathLink.d.ts +24 -4
  24. package/execution/FilePathLink.d.ts.map +1 -1
  25. package/execution/FilePathLink.js +31 -9
  26. package/execution/FilePathLink.js.map +1 -1
  27. package/execution/FileReviewCard.d.ts +111 -0
  28. package/execution/FileReviewCard.d.ts.map +1 -0
  29. package/execution/FileReviewCard.js +558 -0
  30. package/execution/FileReviewCard.js.map +1 -0
  31. package/execution/FileReviewContext.d.ts +35 -0
  32. package/execution/FileReviewContext.d.ts.map +1 -0
  33. package/execution/FileReviewContext.js +23 -0
  34. package/execution/FileReviewContext.js.map +1 -0
  35. package/execution/FileReviewDock.d.ts +73 -0
  36. package/execution/FileReviewDock.d.ts.map +1 -0
  37. package/execution/FileReviewDock.js +65 -0
  38. package/execution/FileReviewDock.js.map +1 -0
  39. package/execution/McpToolDetail.d.ts.map +1 -1
  40. package/execution/McpToolDetail.js +38 -5
  41. package/execution/McpToolDetail.js.map +1 -1
  42. package/execution/MessageThread.d.ts +42 -3
  43. package/execution/MessageThread.d.ts.map +1 -1
  44. package/execution/MessageThread.js +263 -18
  45. package/execution/MessageThread.js.map +1 -1
  46. package/execution/PlanArtifactCard.d.ts.map +1 -1
  47. package/execution/PlanArtifactCard.js +3 -1
  48. package/execution/PlanArtifactCard.js.map +1 -1
  49. package/execution/PlanCompletionCard.d.ts +1 -1
  50. package/execution/PlanCompletionCard.js +1 -1
  51. package/execution/ResultView.d.ts +19 -1
  52. package/execution/ResultView.d.ts.map +1 -1
  53. package/execution/ResultView.js +141 -40
  54. package/execution/ResultView.js.map +1 -1
  55. package/execution/SubAgentSection.d.ts.map +1 -1
  56. package/execution/SubAgentSection.js +45 -6
  57. package/execution/SubAgentSection.js.map +1 -1
  58. package/execution/TerminalSession.d.ts +34 -0
  59. package/execution/TerminalSession.d.ts.map +1 -0
  60. package/execution/TerminalSession.js +34 -0
  61. package/execution/TerminalSession.js.map +1 -0
  62. package/execution/TodoCard.d.ts +53 -0
  63. package/execution/TodoCard.d.ts.map +1 -0
  64. package/execution/TodoCard.js +77 -0
  65. package/execution/TodoCard.js.map +1 -0
  66. package/execution/ToolArgsView.d.ts +7 -1
  67. package/execution/ToolArgsView.d.ts.map +1 -1
  68. package/execution/ToolArgsView.js +10 -9
  69. package/execution/ToolArgsView.js.map +1 -1
  70. package/execution/ToolCallDetail.d.ts +10 -1
  71. package/execution/ToolCallDetail.d.ts.map +1 -1
  72. package/execution/ToolCallDetail.js +66 -19
  73. package/execution/ToolCallDetail.js.map +1 -1
  74. package/execution/ToolCallGroup.d.ts +28 -18
  75. package/execution/ToolCallGroup.d.ts.map +1 -1
  76. package/execution/ToolCallGroup.js +39 -148
  77. package/execution/ToolCallGroup.js.map +1 -1
  78. package/execution/ToolCallItem.d.ts +36 -8
  79. package/execution/ToolCallItem.d.ts.map +1 -1
  80. package/execution/ToolCallItem.js +140 -21
  81. package/execution/ToolCallItem.js.map +1 -1
  82. package/execution/ToolRunGroup.d.ts +48 -0
  83. package/execution/ToolRunGroup.d.ts.map +1 -0
  84. package/execution/ToolRunGroup.js +168 -0
  85. package/execution/ToolRunGroup.js.map +1 -0
  86. package/execution/approval-provenance.d.ts +2 -0
  87. package/execution/approval-provenance.d.ts.map +1 -0
  88. package/execution/approval-provenance.js +6 -0
  89. package/execution/approval-provenance.js.map +1 -0
  90. package/execution/artifact-utils.d.ts +0 -10
  91. package/execution/artifact-utils.d.ts.map +1 -1
  92. package/execution/artifact-utils.js +0 -17
  93. package/execution/artifact-utils.js.map +1 -1
  94. package/execution/execution-phases.d.ts +1 -6
  95. package/execution/execution-phases.d.ts.map +1 -1
  96. package/execution/execution-phases.js +4 -14
  97. package/execution/execution-phases.js.map +1 -1
  98. package/execution/file-path-resolver.d.ts +28 -0
  99. package/execution/file-path-resolver.d.ts.map +1 -1
  100. package/execution/file-path-resolver.js +24 -0
  101. package/execution/file-path-resolver.js.map +1 -1
  102. package/execution/file-review-status.d.ts +127 -0
  103. package/execution/file-review-status.d.ts.map +1 -0
  104. package/execution/file-review-status.js +135 -0
  105. package/execution/file-review-status.js.map +1 -0
  106. package/execution/index.d.ts +39 -5
  107. package/execution/index.d.ts.map +1 -1
  108. package/execution/index.js +23 -3
  109. package/execution/index.js.map +1 -1
  110. package/execution/segment-tool-calls.d.ts +46 -0
  111. package/execution/segment-tool-calls.d.ts.map +1 -0
  112. package/execution/segment-tool-calls.js +71 -0
  113. package/execution/segment-tool-calls.js.map +1 -0
  114. package/execution/tool-categories.d.ts +62 -1
  115. package/execution/tool-categories.d.ts.map +1 -1
  116. package/execution/tool-categories.js +96 -2
  117. package/execution/tool-categories.js.map +1 -1
  118. package/execution/tool-presenter.d.ts +38 -2
  119. package/execution/tool-presenter.d.ts.map +1 -1
  120. package/execution/tool-presenter.js +23 -1
  121. package/execution/tool-presenter.js.map +1 -1
  122. package/execution/tool-rendering-primitives.d.ts.map +1 -1
  123. package/execution/tool-rendering-primitives.js +3 -2
  124. package/execution/tool-rendering-primitives.js.map +1 -1
  125. package/execution/useArtifactDownload.d.ts +44 -0
  126. package/execution/useArtifactDownload.d.ts.map +1 -0
  127. package/execution/useArtifactDownload.js +80 -0
  128. package/execution/useArtifactDownload.js.map +1 -0
  129. package/execution/useArtifactDownloadUrl.d.ts +67 -0
  130. package/execution/useArtifactDownloadUrl.d.ts.map +1 -0
  131. package/execution/useArtifactDownloadUrl.js +59 -0
  132. package/execution/useArtifactDownloadUrl.js.map +1 -0
  133. package/execution/useFileChangeContent.d.ts +61 -0
  134. package/execution/useFileChangeContent.d.ts.map +1 -0
  135. package/execution/useFileChangeContent.js +89 -0
  136. package/execution/useFileChangeContent.js.map +1 -0
  137. package/execution/useFileReview.d.ts +89 -0
  138. package/execution/useFileReview.d.ts.map +1 -0
  139. package/execution/useFileReview.js +106 -0
  140. package/execution/useFileReview.js.map +1 -0
  141. package/execution/useSubmitApproval.d.ts +17 -2
  142. package/execution/useSubmitApproval.d.ts.map +1 -1
  143. package/execution/useSubmitApproval.js +27 -23
  144. package/execution/useSubmitApproval.js.map +1 -1
  145. package/execution/useToolOutputContent.d.ts +44 -0
  146. package/execution/useToolOutputContent.d.ts.map +1 -0
  147. package/execution/useToolOutputContent.js +31 -0
  148. package/execution/useToolOutputContent.js.map +1 -0
  149. package/index.d.ts +6 -6
  150. package/index.d.ts.map +1 -1
  151. package/index.js +3 -3
  152. package/index.js.map +1 -1
  153. package/internal/ApprovalPeekBar.d.ts +23 -0
  154. package/internal/ApprovalPeekBar.d.ts.map +1 -0
  155. package/internal/ApprovalPeekBar.js +25 -0
  156. package/internal/ApprovalPeekBar.js.map +1 -0
  157. package/internal/BoundedContent.d.ts +49 -0
  158. package/internal/BoundedContent.d.ts.map +1 -0
  159. package/internal/BoundedContent.js +50 -0
  160. package/internal/BoundedContent.js.map +1 -0
  161. package/internal/DecisionButton.d.ts +47 -0
  162. package/internal/DecisionButton.d.ts.map +1 -0
  163. package/internal/DecisionButton.js +42 -0
  164. package/internal/DecisionButton.js.map +1 -0
  165. package/internal/InCardDecisionError.d.ts +31 -0
  166. package/internal/InCardDecisionError.d.ts.map +1 -0
  167. package/internal/InCardDecisionError.js +23 -0
  168. package/internal/InCardDecisionError.js.map +1 -0
  169. package/internal/RevealToggle.d.ts +36 -0
  170. package/internal/RevealToggle.d.ts.map +1 -0
  171. package/internal/RevealToggle.js +32 -0
  172. package/internal/RevealToggle.js.map +1 -0
  173. package/internal/VirtualizedThread.d.ts +7 -1
  174. package/internal/VirtualizedThread.d.ts.map +1 -1
  175. package/internal/VirtualizedThread.js +7 -3
  176. package/internal/VirtualizedThread.js.map +1 -1
  177. package/internal/useAutoDisclosure.d.ts +34 -0
  178. package/internal/useAutoDisclosure.d.ts.map +1 -0
  179. package/internal/useAutoDisclosure.js +53 -0
  180. package/internal/useAutoDisclosure.js.map +1 -0
  181. package/internal/useElapsedSince.d.ts +30 -0
  182. package/internal/useElapsedSince.d.ts.map +1 -0
  183. package/internal/useElapsedSince.js +70 -0
  184. package/internal/useElapsedSince.js.map +1 -0
  185. package/internal/useIsOverflowing.d.ts +30 -0
  186. package/internal/useIsOverflowing.d.ts.map +1 -0
  187. package/internal/useIsOverflowing.js +47 -0
  188. package/internal/useIsOverflowing.js.map +1 -0
  189. package/internal/useIsTextTruncated.d.ts +24 -0
  190. package/internal/useIsTextTruncated.d.ts.map +1 -0
  191. package/internal/useIsTextTruncated.js +41 -0
  192. package/internal/useIsTextTruncated.js.map +1 -0
  193. package/internal/useKeyedSubmission.d.ts +49 -0
  194. package/internal/useKeyedSubmission.d.ts.map +1 -0
  195. package/internal/useKeyedSubmission.js +67 -0
  196. package/internal/useKeyedSubmission.js.map +1 -0
  197. package/package.json +4 -4
  198. package/session/SessionViewer.d.ts +2 -2
  199. package/session/SessionViewer.d.ts.map +1 -1
  200. package/session/SessionViewer.js +10 -4
  201. package/session/SessionViewer.js.map +1 -1
  202. package/session/index.d.ts +2 -0
  203. package/session/index.d.ts.map +1 -1
  204. package/session/index.js +1 -0
  205. package/session/index.js.map +1 -1
  206. package/session/inspector/ChangesTab.d.ts +8 -5
  207. package/session/inspector/ChangesTab.d.ts.map +1 -1
  208. package/session/inspector/ChangesTab.js +11 -8
  209. package/session/inspector/ChangesTab.js.map +1 -1
  210. package/session/inspector/SessionInspector.d.ts +4 -4
  211. package/session/inspector/SessionInspector.d.ts.map +1 -1
  212. package/session/inspector/SessionInspector.js +4 -4
  213. package/session/inspector/SessionInspector.js.map +1 -1
  214. package/session/inspector/index.d.ts +0 -2
  215. package/session/inspector/index.d.ts.map +1 -1
  216. package/session/inspector/index.js +0 -1
  217. package/session/inspector/index.js.map +1 -1
  218. package/session/inspector/useSessionInspector.d.ts +8 -4
  219. package/session/inspector/useSessionInspector.d.ts.map +1 -1
  220. package/session/inspector/useSessionInspector.js +27 -20
  221. package/session/inspector/useSessionInspector.js.map +1 -1
  222. package/session/useSessionConversation.d.ts +37 -3
  223. package/session/useSessionConversation.d.ts.map +1 -1
  224. package/session/useSessionConversation.js +18 -2
  225. package/session/useSessionConversation.js.map +1 -1
  226. package/session/useSessionFileChanges.d.ts +74 -0
  227. package/session/useSessionFileChanges.d.ts.map +1 -0
  228. package/session/useSessionFileChanges.js +178 -0
  229. package/session/useSessionFileChanges.js.map +1 -0
  230. package/src/__tests__/styles-border-layer-invariant.test.ts +105 -0
  231. package/src/execution/ApprovalCard.tsx +368 -230
  232. package/src/execution/ApprovalContext.ts +109 -0
  233. package/src/execution/ArtifactCard.tsx +10 -6
  234. package/src/execution/ArtifactPreviewModal.tsx +12 -6
  235. package/src/execution/EmptyChangeNotice.tsx +62 -0
  236. package/src/execution/FileChangesView.tsx +383 -0
  237. package/src/execution/FilePathLink.tsx +65 -12
  238. package/src/execution/FileReviewCard.tsx +1118 -0
  239. package/src/execution/FileReviewContext.ts +53 -0
  240. package/src/execution/FileReviewDock.tsx +157 -0
  241. package/src/execution/McpToolDetail.tsx +98 -32
  242. package/src/execution/MessageThread.tsx +374 -9
  243. package/src/execution/PlanArtifactCard.tsx +9 -6
  244. package/src/execution/PlanCompletionCard.tsx +1 -1
  245. package/src/execution/ResultView.tsx +333 -162
  246. package/src/execution/SubAgentSection.tsx +58 -11
  247. package/src/execution/TerminalSession.tsx +91 -0
  248. package/src/execution/TodoCard.tsx +186 -0
  249. package/src/execution/ToolArgsView.tsx +28 -17
  250. package/src/execution/ToolCallDetail.tsx +137 -26
  251. package/src/execution/ToolCallGroup.tsx +68 -296
  252. package/src/execution/ToolCallItem.tsx +265 -67
  253. package/src/execution/ToolRunGroup.tsx +302 -0
  254. package/src/execution/__tests__/ApprovalCard.test.tsx +395 -5
  255. package/src/execution/__tests__/ArtifactPreviewModal.test.tsx +0 -1
  256. package/src/execution/__tests__/EmptyChangeNotice.test.tsx +24 -0
  257. package/src/execution/__tests__/FileChangesView.test.tsx +296 -0
  258. package/src/execution/__tests__/FilePathLink.test.tsx +92 -0
  259. package/src/execution/__tests__/FileReviewCard.test.tsx +1044 -0
  260. package/src/execution/__tests__/FileReviewDock.test.tsx +134 -0
  261. package/src/execution/__tests__/McpToolDetail.test.tsx +79 -0
  262. package/src/execution/__tests__/MessageThread.test.tsx +324 -0
  263. package/src/execution/__tests__/PlanArtifactCard.test.tsx +37 -16
  264. package/src/execution/__tests__/ResultView.test.tsx +280 -2
  265. package/src/execution/__tests__/SubAgentSection.test.tsx +180 -0
  266. package/src/execution/__tests__/TerminalSession.test.tsx +72 -0
  267. package/src/execution/__tests__/TodoCard.test.tsx +102 -0
  268. package/src/execution/__tests__/ToolArgsView.test.tsx +48 -0
  269. package/src/execution/__tests__/ToolCallDetail.test.tsx +195 -0
  270. package/src/execution/__tests__/ToolCallGroup.test.tsx +132 -0
  271. package/src/execution/__tests__/ToolCallItem.test.tsx +521 -0
  272. package/src/execution/__tests__/ToolRunGroup.test.tsx +137 -0
  273. package/src/execution/__tests__/blanked-narration.test.tsx +149 -0
  274. package/src/execution/__tests__/buildThreadItems-approvals.test.ts +304 -0
  275. package/src/execution/__tests__/buildThreadItems-file-review.test.ts +331 -0
  276. package/src/execution/__tests__/file-path-resolver.test.ts +44 -0
  277. package/src/execution/__tests__/file-review-status.test.ts +343 -0
  278. package/src/execution/__tests__/segment-tool-calls.test.ts +124 -0
  279. package/src/execution/__tests__/subagent-file-review-badge.test.tsx +273 -0
  280. package/src/execution/__tests__/thread-keys.test.ts +195 -0
  281. package/src/execution/__tests__/tool-presenter.test.tsx +95 -0
  282. package/src/execution/__tests__/useArtifactDownload.test.tsx +67 -0
  283. package/src/execution/__tests__/useArtifactDownloadUrl.test.tsx +51 -0
  284. package/src/execution/__tests__/useFileChangeContent.test.tsx +240 -0
  285. package/src/execution/__tests__/useFileReview.test.tsx +236 -0
  286. package/src/execution/__tests__/useSubmitApproval.test.tsx +165 -0
  287. package/src/execution/__tests__/useToolOutputContent.test.tsx +82 -0
  288. package/src/execution/approval-provenance.ts +8 -0
  289. package/src/execution/artifact-utils.ts +0 -18
  290. package/src/execution/execution-phases.ts +4 -16
  291. package/src/execution/file-path-resolver.ts +38 -0
  292. package/src/execution/file-review-status.ts +219 -0
  293. package/src/execution/index.ts +84 -4
  294. package/src/execution/segment-tool-calls.ts +101 -0
  295. package/src/execution/tool-categories.ts +128 -1
  296. package/src/execution/tool-presenter.ts +58 -3
  297. package/src/execution/tool-rendering-primitives.tsx +11 -14
  298. package/src/execution/useArtifactDownload.ts +109 -0
  299. package/src/execution/useArtifactDownloadUrl.ts +116 -0
  300. package/src/execution/useFileChangeContent.ts +149 -0
  301. package/src/execution/useFileReview.ts +197 -0
  302. package/src/execution/useSubmitApproval.ts +49 -27
  303. package/src/execution/useToolOutputContent.ts +70 -0
  304. package/src/index.ts +60 -1
  305. package/src/internal/ApprovalPeekBar.tsx +73 -0
  306. package/src/internal/BoundedContent.tsx +97 -0
  307. package/src/internal/DecisionButton.tsx +127 -0
  308. package/src/internal/InCardDecisionError.tsx +47 -0
  309. package/src/internal/RevealToggle.tsx +91 -0
  310. package/src/internal/VirtualizedThread.tsx +28 -2
  311. package/src/internal/__tests__/ApprovalPeekBar.test.tsx +34 -0
  312. package/src/internal/__tests__/BoundedContent.test.tsx +92 -0
  313. package/src/internal/__tests__/DecisionButton.test.tsx +107 -0
  314. package/src/internal/__tests__/RevealToggle.test.tsx +61 -0
  315. package/src/internal/__tests__/useAutoDisclosure.test.ts +74 -0
  316. package/src/internal/__tests__/useElapsedSince.test.tsx +68 -0
  317. package/src/internal/__tests__/useIsOverflowing.test.ts +36 -0
  318. package/src/internal/__tests__/useKeyedSubmission.test.tsx +126 -0
  319. package/src/internal/useAutoDisclosure.ts +58 -0
  320. package/src/internal/useElapsedSince.ts +72 -0
  321. package/src/internal/useIsOverflowing.ts +61 -0
  322. package/src/internal/useIsTextTruncated.ts +55 -0
  323. package/src/internal/useKeyedSubmission.ts +101 -0
  324. package/src/session/SessionViewer.tsx +21 -4
  325. package/src/session/__tests__/SessionViewer-fileReviewDock.test.tsx +198 -0
  326. package/src/session/__tests__/audienceWiring.test.tsx +4 -0
  327. package/src/session/__tests__/useSessionFileChanges.test.ts +303 -0
  328. package/src/session/index.ts +3 -0
  329. package/src/session/inspector/ChangesTab.tsx +20 -17
  330. package/src/session/inspector/SessionInspector.tsx +12 -10
  331. package/src/session/inspector/__tests__/ArtifactsTab.test.tsx +0 -1
  332. package/src/session/inspector/__tests__/ChangesTab.test.tsx +38 -0
  333. package/src/session/inspector/__tests__/useSessionInspector.test.ts +46 -61
  334. package/src/session/inspector/index.ts +0 -3
  335. package/src/session/inspector/useSessionInspector.ts +27 -20
  336. package/src/session/useSessionConversation.ts +80 -3
  337. package/src/session/useSessionFileChanges.ts +207 -0
  338. package/src/styles.css +35 -10
  339. package/src/version-history/DiffViewer.tsx +10 -7
  340. package/src/version-history/UnifiedDiffView.tsx +66 -0
  341. package/src/version-history/__tests__/DiffViewer.test.tsx +57 -0
  342. package/src/version-history/__tests__/UnifiedDiffView.test.tsx +50 -0
  343. package/src/version-history/__tests__/computeDiff.test.ts +35 -0
  344. package/src/version-history/__tests__/parseUnifiedDiff.test.ts +82 -0
  345. package/src/version-history/computeDiff.ts +6 -37
  346. package/src/version-history/diff-hunks.ts +63 -0
  347. package/src/version-history/index.ts +1 -0
  348. package/src/version-history/parseUnifiedDiff.ts +34 -0
  349. package/src/workflow/WorkflowExecutionApprovalCard.tsx +49 -24
  350. package/src/workflow/WorkflowExecutionTimeline.tsx +15 -4
  351. package/src/workflow/WorkflowExecutionTimelineEvent.tsx +8 -3
  352. package/src/workflow/WorkflowExecutionViewer.tsx +72 -28
  353. package/src/workflow/WorkflowFileReviewList.tsx +152 -0
  354. package/src/workflow/WorkflowTaskApprovalCard.tsx +37 -85
  355. package/src/workflow/__tests__/ExecutionInspector.test.tsx +30 -2
  356. package/src/workflow/__tests__/WorkflowExecutionApprovalCard.test.tsx +129 -0
  357. package/src/workflow/__tests__/WorkflowFileReviewList.test.tsx +129 -0
  358. package/src/workflow/__tests__/WorkflowTaskApprovalCard.test.tsx +43 -11
  359. package/src/workflow/__tests__/useWorkflowExecutionActions.test.tsx +276 -0
  360. package/src/workflow/execution-inspector/ExecutionInspector.tsx +42 -18
  361. package/src/workflow/index.ts +5 -0
  362. package/src/workflow/useWorkflowExecutionActions.ts +177 -29
  363. package/styles.css +1 -1
  364. package/version-history/DiffViewer.d.ts.map +1 -1
  365. package/version-history/DiffViewer.js +9 -3
  366. package/version-history/DiffViewer.js.map +1 -1
  367. package/version-history/UnifiedDiffView.d.ts +29 -0
  368. package/version-history/UnifiedDiffView.d.ts.map +1 -0
  369. package/version-history/UnifiedDiffView.js +36 -0
  370. package/version-history/UnifiedDiffView.js.map +1 -0
  371. package/version-history/computeDiff.d.ts +3 -1
  372. package/version-history/computeDiff.d.ts.map +1 -1
  373. package/version-history/computeDiff.js +5 -35
  374. package/version-history/computeDiff.js.map +1 -1
  375. package/version-history/diff-hunks.d.ts +21 -0
  376. package/version-history/diff-hunks.d.ts.map +1 -0
  377. package/version-history/diff-hunks.js +58 -0
  378. package/version-history/diff-hunks.js.map +1 -0
  379. package/version-history/index.d.ts +1 -0
  380. package/version-history/index.d.ts.map +1 -1
  381. package/version-history/index.js +1 -0
  382. package/version-history/index.js.map +1 -1
  383. package/version-history/parseUnifiedDiff.d.ts +22 -0
  384. package/version-history/parseUnifiedDiff.d.ts.map +1 -0
  385. package/version-history/parseUnifiedDiff.js +34 -0
  386. package/version-history/parseUnifiedDiff.js.map +1 -0
  387. package/workflow/WorkflowExecutionApprovalCard.d.ts +8 -1
  388. package/workflow/WorkflowExecutionApprovalCard.d.ts.map +1 -1
  389. package/workflow/WorkflowExecutionApprovalCard.js +17 -3
  390. package/workflow/WorkflowExecutionApprovalCard.js.map +1 -1
  391. package/workflow/WorkflowExecutionTimeline.d.ts +11 -2
  392. package/workflow/WorkflowExecutionTimeline.d.ts.map +1 -1
  393. package/workflow/WorkflowExecutionTimeline.js +2 -2
  394. package/workflow/WorkflowExecutionTimeline.js.map +1 -1
  395. package/workflow/WorkflowExecutionTimelineEvent.d.ts +4 -1
  396. package/workflow/WorkflowExecutionTimelineEvent.d.ts.map +1 -1
  397. package/workflow/WorkflowExecutionTimelineEvent.js +2 -2
  398. package/workflow/WorkflowExecutionTimelineEvent.js.map +1 -1
  399. package/workflow/WorkflowExecutionViewer.d.ts.map +1 -1
  400. package/workflow/WorkflowExecutionViewer.js +18 -10
  401. package/workflow/WorkflowExecutionViewer.js.map +1 -1
  402. package/workflow/WorkflowFileReviewList.d.ts +46 -0
  403. package/workflow/WorkflowFileReviewList.d.ts.map +1 -0
  404. package/workflow/WorkflowFileReviewList.js +48 -0
  405. package/workflow/WorkflowFileReviewList.js.map +1 -0
  406. package/workflow/WorkflowTaskApprovalCard.d.ts +8 -1
  407. package/workflow/WorkflowTaskApprovalCard.d.ts.map +1 -1
  408. package/workflow/WorkflowTaskApprovalCard.js +12 -19
  409. package/workflow/WorkflowTaskApprovalCard.js.map +1 -1
  410. package/workflow/execution-inspector/ExecutionInspector.d.ts +21 -4
  411. package/workflow/execution-inspector/ExecutionInspector.d.ts.map +1 -1
  412. package/workflow/execution-inspector/ExecutionInspector.js +6 -3
  413. package/workflow/execution-inspector/ExecutionInspector.js.map +1 -1
  414. package/workflow/index.d.ts +1 -0
  415. package/workflow/index.d.ts.map +1 -1
  416. package/workflow/index.js +1 -0
  417. package/workflow/index.js.map +1 -1
  418. package/workflow/useWorkflowExecutionActions.d.ts +62 -4
  419. package/workflow/useWorkflowExecutionActions.d.ts.map +1 -1
  420. package/workflow/useWorkflowExecutionActions.js +94 -18
  421. package/workflow/useWorkflowExecutionActions.js.map +1 -1
  422. package/session/inspector/PlanTab.d.ts +0 -15
  423. package/session/inspector/PlanTab.d.ts.map +0 -1
  424. package/session/inspector/PlanTab.js +0 -19
  425. package/session/inspector/PlanTab.js.map +0 -1
  426. package/src/session/inspector/PlanTab.tsx +0 -31
@@ -3,17 +3,31 @@
3
3
  import type { ToolCall } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
4
4
  import type { ToolResultView } from "@stigmer/sdk";
5
5
  import { cn } from "@stigmer/theme";
6
+ import { BoundedContent } from "../internal/BoundedContent";
6
7
  import { McpToolDetail } from "./McpToolDetail";
7
8
  import { ToolArgsView } from "./ToolArgsView";
8
9
  import { ResultView } from "./ResultView";
9
10
  import { useToolPresentation } from "./tool-presenter";
10
11
  import type { ToolCategory } from "./tool-categories";
11
12
  import { CollapsiblePre } from "./tool-rendering-primitives";
13
+ import {
14
+ describeApprovalPolicySource,
15
+ isInformativePolicySource,
16
+ } from "./approval-provenance";
12
17
 
13
18
  /** Props for {@link ToolCallDetail}. */
14
19
  export interface ToolCallDetailProps {
15
20
  /** The tool call to render in detail. */
16
21
  readonly toolCall: ToolCall;
22
+ /**
23
+ * Whether the owning row's header truncated the primary argument (the search
24
+ * query / list path). A header-owned layout fact: when `true`, the search/list
25
+ * body restates the full, wrapping value so a long query is reachable without
26
+ * relying on the hover tooltip; when `false` (the default) the header already
27
+ * shows the value in full, so the body does not repeat it. Only the
28
+ * search/list branch consumes it.
29
+ */
30
+ readonly primaryArgTruncated?: boolean;
17
31
  /** Additional CSS class names for the root container. */
18
32
  readonly className?: string;
19
33
  }
@@ -39,12 +53,22 @@ export interface ToolCallDetailProps {
39
53
  * <ToolCallDetail toolCall={toolCall} />
40
54
  * ```
41
55
  */
42
- export function ToolCallDetail({ toolCall, className }: ToolCallDetailProps) {
43
- const { category, result } = useToolPresentation(toolCall);
56
+ export function ToolCallDetail({
57
+ toolCall,
58
+ primaryArgTruncated = false,
59
+ className,
60
+ }: ToolCallDetailProps) {
61
+ const { category, result, primaryArg } = useToolPresentation(toolCall);
44
62
 
45
63
  return (
46
64
  <div className={cn("space-y-2 text-xs", className)}>
47
- <CategoryDetail toolCall={toolCall} category={category} result={result} />
65
+ <CategoryDetail
66
+ toolCall={toolCall}
67
+ category={category}
68
+ result={result}
69
+ primaryArg={primaryArg}
70
+ primaryArgTruncated={primaryArgTruncated}
71
+ />
48
72
  </div>
49
73
  );
50
74
  }
@@ -52,19 +76,26 @@ export function ToolCallDetail({ toolCall, className }: ToolCallDetailProps) {
52
76
  // ---------------------------------------------------------------------------
53
77
  // Category composition
54
78
  //
55
- // Each category composes from three parts: MetadataRow (duration, slug),
56
- // ToolArgsView (the input), and ResultView (the effect). The combination is
57
- // chosen to be informative without duplication.
79
+ // Invariant: the owning row header owns the METADATA (icon, label, file name,
80
+ // ± stats, MCP slug, status, duration); the detail body owns the CONTENT — the
81
+ // ToolArgsView input and the ResultView effect — plus, at most, a
82
+ // ProvenanceNote when the authorization provenance is genuinely informative.
83
+ // The body never restates header metadata. Each category picks the input/effect
84
+ // combination that is informative without duplication.
58
85
  // ---------------------------------------------------------------------------
59
86
 
60
87
  function CategoryDetail({
61
88
  toolCall,
62
89
  category,
63
90
  result,
91
+ primaryArg,
92
+ primaryArgTruncated,
64
93
  }: {
65
94
  toolCall: ToolCall;
66
95
  category: ToolCategory;
67
96
  result: ToolResultView;
97
+ primaryArg: string | null;
98
+ primaryArgTruncated: boolean;
68
99
  }) {
69
100
  const args = <ArgsSection toolCall={toolCall} />;
70
101
 
@@ -75,34 +106,87 @@ function CategoryDetail({
75
106
  case "mcp":
76
107
  return <McpToolDetail toolCall={toolCall} />;
77
108
 
109
+ case "search":
110
+ case "list":
111
+ // The query/path is the input; the matches are the effect. The owning row
112
+ // header already shows the query (truncated, with a hover tooltip), so the
113
+ // body does NOT restate it as a redundant "Pattern:" row — it shows the
114
+ // full, wrapping value only when the header truncated it (a long query),
115
+ // then the result. This is the search/list analog of the edit branch's
116
+ // "the diff already names the file" de-duplication.
117
+ return (
118
+ <>
119
+ <ProvenanceNote toolCall={toolCall} />
120
+ {primaryArgTruncated && primaryArg && (
121
+ <SearchQueryBlock category={category} value={primaryArg} />
122
+ )}
123
+ {/* The owning row header shows the count (summarizeResultView), so the
124
+ body suppresses it (showStats={false}) and shows only the matches
125
+ plus, when capped, a truncation note. */}
126
+ <ResultView view={result} showStats={false} />
127
+ </>
128
+ );
129
+
78
130
  case "edit":
131
+ case "write":
79
132
  // The diff already names the file and quantifies the change, so it stands
80
- // alone — showing the new content as an argument would duplicate it.
133
+ // alone — showing the written content as an argument would duplicate it. A
134
+ // write whose capture is unavailable degrades to a `file` result here
135
+ // (ResultView shows the content), so the input is never lost. The owning
136
+ // row already names the file, so the body suppresses the path.
137
+ //
138
+ // The diff is the one tool body with no internal truncation of its own, so
139
+ // it is bounded by the shared BoundedContent budget (the same clamp the
140
+ // approval gate diff uses) — a large or still-streaming edit shows a
141
+ // consistent, scannable window with one in-place reveal, never the whole
142
+ // file. Every other category's body self-truncates (terminal / text via
143
+ // CollapsiblePre), so only edit/write wrap here — never double-bound.
81
144
  return (
82
145
  <>
83
- <MetadataRow toolCall={toolCall} />
84
- <ResultView view={result} />
146
+ <ProvenanceNote toolCall={toolCall} />
147
+ <BoundedContent cursorTarget="tool-detail-expand">
148
+ <ResultView view={result} showFileName={false} showStats={false} />
149
+ </BoundedContent>
85
150
  </>
86
151
  );
87
152
 
88
153
  case "read":
89
- case "write":
90
154
  case "delete":
91
- // The input is the point (path, or path + written content). Only surface a
155
+ // The input is the point (path, or path for a delete). Only surface a
92
156
  // result body when it carries new information — i.e. an error.
93
157
  return (
94
158
  <>
95
- <MetadataRow toolCall={toolCall} />
159
+ <ProvenanceNote toolCall={toolCall} />
96
160
  {args}
97
161
  {result.type === "error" && <ResultView view={result} />}
98
162
  </>
99
163
  );
100
164
 
165
+ case "shell":
166
+ // The result IS a terminal session (command + output in one block via
167
+ // ResultView's terminal view), so a separate args box would just restate
168
+ // the command line the session already leads with. The exception is a
169
+ // hard tool failure (TOOL_CALL_FAILED → error view, which has no command):
170
+ // show the command (args) alongside the error so it is never lost.
171
+ return (
172
+ <>
173
+ <ProvenanceNote toolCall={toolCall} />
174
+ {result.type === "error" ? (
175
+ <>
176
+ {args}
177
+ <ResultView view={result} />
178
+ </>
179
+ ) : (
180
+ <ResultView view={result} />
181
+ )}
182
+ </>
183
+ );
184
+
101
185
  default:
102
- // shell, search, list, fetch, web-search, unknown: input + effect.
186
+ // fetch, web-search, unknown: input + effect.
103
187
  return (
104
188
  <>
105
- <MetadataRow toolCall={toolCall} />
189
+ <ProvenanceNote toolCall={toolCall} />
106
190
  {args}
107
191
  <ResultView view={result} />
108
192
  </>
@@ -110,6 +194,27 @@ function CategoryDetail({
110
194
  }
111
195
  }
112
196
 
197
+ // The full, wrapping query (search) or path (list), shown in the body only when
198
+ // the owning row's header truncated it — so a long value is reachable without
199
+ // hovering, without restating a short value the header already shows in full.
200
+ function SearchQueryBlock({
201
+ category,
202
+ value,
203
+ }: {
204
+ category: ToolCategory;
205
+ value: string;
206
+ }) {
207
+ const label = category === "list" ? "Path" : "Query";
208
+ return (
209
+ <div className="space-y-1">
210
+ <span className="font-medium text-muted-foreground">{label}</span>
211
+ <code className="block whitespace-pre-wrap break-words rounded bg-muted px-1.5 py-0.5 font-mono text-foreground">
212
+ {value}
213
+ </code>
214
+ </div>
215
+ );
216
+ }
217
+
113
218
  function ArgsSection({ toolCall }: { toolCall: ToolCall }) {
114
219
  return (
115
220
  <ToolArgsView
@@ -140,20 +245,26 @@ function ThinkToolDetail({ toolCall }: { toolCall: ToolCall }) {
140
245
  // Shared sub-components
141
246
  // ---------------------------------------------------------------------------
142
247
 
143
- function MetadataRow({ toolCall }: { toolCall: ToolCall }) {
144
- const duration = formatDuration(toolCall.startedAt, toolCall.completedAt);
145
- const hasMetadata = toolCall.mcpServerSlug || duration;
146
- if (!hasMetadata) return null;
248
+ // The detail body's only metadata. Duration and the MCP slug live in the owning
249
+ // row header (ToolCallItem / ApprovalCardHeader), so the body never restates
250
+ // them; it surfaces the authorization provenance the runner stamped onto the
251
+ // call (approval_policy_source) ONLY when it is genuinely informative — an
252
+ // explicit override, a server-marked destructive tighten, or a post-hoc
253
+ // lease/bypass that cleared it. The everyday "this category just needs approval"
254
+ // default and legacy UNSPECIFIED are noise, so they render nothing, mirroring
255
+ // the approval gate's smart-suppress (isInformativePolicySource).
256
+ function ProvenanceNote({ toolCall }: { toolCall: ToolCall }) {
257
+ if (!isInformativePolicySource(toolCall.approvalPolicySource)) return null;
258
+ const provenance = describeApprovalPolicySource(toolCall.approvalPolicySource);
259
+ if (!provenance) return null;
147
260
 
148
261
  return (
149
- <div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-muted-foreground">
150
- {toolCall.mcpServerSlug && (
151
- <span className="rounded bg-muted px-1.5 py-0.5 font-mono">
152
- {toolCall.mcpServerSlug}
153
- </span>
154
- )}
155
- {duration && <span>{duration}</span>}
156
- </div>
262
+ <p
263
+ className="text-[11px] italic text-muted-foreground"
264
+ title={provenance}
265
+ >
266
+ {provenance}
267
+ </p>
157
268
  );
158
269
  }
159
270
 
@@ -1,16 +1,14 @@
1
1
  "use client";
2
2
 
3
- import { memo, useEffect, useMemo, useRef, useState } from "react";
3
+ import { memo, useMemo } from "react";
4
4
  import type { ToolCall } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
5
5
  import type { SubAgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/subagent_pb";
6
- import {
7
- ApprovalAction,
8
- ToolCallStatus,
9
- } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
10
6
  import { cn } from "@stigmer/theme";
11
7
  import { useRenderTracer } from "../internal/dev";
12
8
  import { ToolCallItem } from "./ToolCallItem";
13
- import { resolveToolCategoryFromCall, extractPrimaryArg } from "./tool-categories";
9
+ import { ToolRunGroup } from "./ToolRunGroup";
10
+ import { segmentToolCalls } from "./segment-tool-calls";
11
+ import { isCollapsedToolCall } from "./tool-categories";
14
12
 
15
13
  /** Props for {@link ToolCallGroup}. */
16
14
  export interface ToolCallGroupProps {
@@ -24,114 +22,24 @@ export interface ToolCallGroupProps {
24
22
  */
25
23
  readonly subAgentExecutions?: readonly SubAgentExecution[];
26
24
  /**
27
- * Custom summary formatter. Receives the tool calls and returns a
28
- * display string. When omitted, the component uses a default that
29
- * shows the tool name for single calls and a count for multiple.
25
+ * Custom label formatter for a folded run chip (e.g. a run of reads).
26
+ * Receives the run's tool calls and returns the chip's collapsed label.
27
+ *
28
+ * NOTE: the unit of summary moved from the *turn* to the *run*. This used to
29
+ * label the whole turn ("Ran 3 tools"); since the turn no longer collapses,
30
+ * it now labels each {@link ToolRunGroup} chip. The signature is unchanged.
30
31
  */
31
32
  readonly formatSummary?: (toolCalls: readonly ToolCall[]) => string;
32
33
  /**
33
- * Initial expansion state. Defaults to `false`.
34
+ * @deprecated No-op. The turn no longer collapses as a unit — rows persist
35
+ * and only repetitive runs fold (see {@link ToolRunGroup}). Kept for
36
+ * back-compat so existing call sites keep type-checking.
34
37
  */
35
38
  readonly defaultExpanded?: boolean;
36
39
  /** Additional CSS class names for the root container. */
37
40
  readonly className?: string;
38
41
  }
39
42
 
40
- type AggregateStatus = "running" | "waiting" | "failed" | "completed" | "pending";
41
-
42
- function isResolvedApproval(tc: ToolCall): boolean {
43
- return (
44
- tc.approvalAction === ApprovalAction.APPROVE ||
45
- tc.approvalAction === ApprovalAction.SKIP ||
46
- tc.approvalAction === ApprovalAction.REJECT
47
- );
48
- }
49
-
50
- function deriveAggregateStatus(toolCalls: readonly ToolCall[]): AggregateStatus {
51
- let hasRunning = false;
52
- let hasWaiting = false;
53
- let hasFailed = false;
54
- let allTerminal = true;
55
-
56
- for (const tc of toolCalls) {
57
- switch (tc.status) {
58
- case ToolCallStatus.TOOL_CALL_RUNNING:
59
- hasRunning = true;
60
- allTerminal = false;
61
- break;
62
- case ToolCallStatus.TOOL_CALL_WAITING_APPROVAL:
63
- if (isResolvedApproval(tc)) {
64
- break;
65
- }
66
- hasWaiting = true;
67
- allTerminal = false;
68
- break;
69
- case ToolCallStatus.TOOL_CALL_FAILED:
70
- hasFailed = true;
71
- break;
72
- case ToolCallStatus.TOOL_CALL_COMPLETED:
73
- case ToolCallStatus.TOOL_CALL_SKIPPED:
74
- break;
75
- default:
76
- allTerminal = false;
77
- break;
78
- }
79
- }
80
-
81
- if (hasRunning) return "running";
82
- if (hasWaiting) return "waiting";
83
- if (hasFailed) return "failed";
84
- if (allTerminal) return "completed";
85
- return "pending";
86
- }
87
-
88
- function defaultFormatSummary(
89
- toolCalls: readonly ToolCall[],
90
- status: AggregateStatus,
91
- ): string {
92
- if (toolCalls.length === 1) {
93
- const tc = toolCalls[0];
94
- const cat = resolveToolCategoryFromCall(tc);
95
- const primary = extractPrimaryArg(tc);
96
- if (primary) {
97
- const truncated =
98
- primary.length > 60 ? primary.slice(0, 57) + "\u2026" : primary;
99
- return `${cat.label}: ${truncated}`;
100
- }
101
- return cat.label;
102
- }
103
-
104
- const noun = toolCalls.length === 1 ? "tool" : "tools";
105
- switch (status) {
106
- case "running":
107
- return `Running ${toolCalls.length} ${noun}`;
108
- case "waiting":
109
- return "Waiting for approval";
110
- case "failed":
111
- return `Ran ${toolCalls.length} ${noun} (with errors)`;
112
- case "completed":
113
- return `Ran ${toolCalls.length} ${noun}`;
114
- case "pending":
115
- return `${toolCalls.length} ${noun} pending`;
116
- }
117
- }
118
-
119
- const STATUS_ICON: Record<AggregateStatus, () => React.JSX.Element> = {
120
- running: SpinnerIcon,
121
- waiting: ClockIcon,
122
- failed: XCircleIcon,
123
- completed: CheckCircleIcon,
124
- pending: DotIcon,
125
- };
126
-
127
- const STATUS_COLOR: Record<AggregateStatus, string> = {
128
- running: "text-foreground",
129
- waiting: "text-warning",
130
- failed: "text-destructive",
131
- completed: "text-success",
132
- pending: "text-muted-foreground",
133
- };
134
-
135
43
  /**
136
44
  * Shallow comparison for `ToolCallGroupProps`.
137
45
  *
@@ -159,23 +67,28 @@ export function toolCallGroupPropsEqual(
159
67
  }
160
68
 
161
69
  /**
162
- * Renders a summary line for a group of tool calls from a single
163
- * AI turn. Click to expand and see individual tool calls.
70
+ * Renders one AI turn's tool activity as a **persistent-row timeline** rather
71
+ * than a collapsible "Ran N tools" box. Each call stays visible after it
72
+ * settles, so completed work is never hidden behind a pill — the thread reads
73
+ * like a virtual human at work.
164
74
  *
165
- * Two-level progressive disclosure:
166
- * 1. **Collapsed** aggregate status icon + summary label.
167
- * 2. **Expanded** — list of {@link ToolCallItem} rows, each
168
- * expandable to show detail (args, result, error, timing) or
169
- * a nested sub-agent thread.
75
+ * The turn is segmented by {@link segmentToolCalls}:
76
+ * - high-signal calls (edits, shell, MCP, sub-agents, …) render as persistent
77
+ * {@link ToolCallItem} rows; a content-bearing call shows its body inline
78
+ * (no card chevron), bounded by a single in-place reveal;
79
+ * - runs of consecutive low-signal same-category calls (read / list / search)
80
+ * fold into one collapsible {@link ToolRunGroup} chip — the *only* collapse,
81
+ * because that is the only genuine noise.
170
82
  *
171
- * Default summaries use active-voice phrasing ("Ran 3 tools",
172
- * "Running 2 tools") with category-aware labels for single tools
173
- * (e.g., "Shell: ls -la /tmp"). Platform builders can override
174
- * via the `formatSummary` prop.
83
+ * The rows are clustered under a light left rail (the neutral counterpart to
84
+ * {@link SubAgentSection}'s primary-tinted rail for delegated work), keeping a
85
+ * turn's tools visually associated with their AI message without a tab that
86
+ * hides things.
175
87
  *
176
- * Wrapped in `React.memo` with a custom comparator that checks
177
- * `toolCalls` elements by reference (structural sharing keeps
178
- * individual `ToolCall` objects stable for unchanged calls).
88
+ * Wrapped in `React.memo` with a custom comparator that checks `toolCalls`
89
+ * elements by reference (structural sharing keeps individual `ToolCall` objects
90
+ * stable for unchanged calls), so settled rows skip re-renders while siblings
91
+ * stream (DD-009/010).
179
92
  *
180
93
  * @example
181
94
  * ```tsx
@@ -186,30 +99,23 @@ export const ToolCallGroup = memo(function ToolCallGroup({
186
99
  toolCalls,
187
100
  subAgentExecutions,
188
101
  formatSummary,
189
- defaultExpanded = false,
190
102
  className,
191
103
  }: ToolCallGroupProps) {
192
104
  useRenderTracer("ToolCallGroup", { toolCallCount: toolCalls.length });
193
105
 
194
- const status = deriveAggregateStatus(toolCalls);
195
- const isActive = status === "running" || status === "pending" || status === "waiting";
196
-
197
- const [expanded, setExpanded] = useState(defaultExpanded || isActive);
198
- const userToggledRef = useRef(false);
199
-
200
- useEffect(() => {
201
- if (userToggledRef.current) return;
202
- if (isActive) {
203
- setExpanded(true);
204
- } else {
205
- setExpanded(false);
206
- }
207
- }, [isActive]);
106
+ // Drop runner-collapsed duplicates (a superseded same-turn denial twin of an
107
+ // approval gate) so one gated resource renders one card, not two. The blanked
108
+ // twin is kept in the persisted transcript (the backend's append-only guard
109
+ // forbids dropping it); it is simply not drawn.
110
+ const visibleToolCalls = useMemo(
111
+ () => toolCalls.filter((tc) => !isCollapsedToolCall(tc)),
112
+ [toolCalls],
113
+ );
208
114
 
209
- const handleToggle = () => {
210
- userToggledRef.current = true;
211
- setExpanded((v) => !v);
212
- };
115
+ const segments = useMemo(
116
+ () => segmentToolCalls(visibleToolCalls),
117
+ [visibleToolCalls],
118
+ );
213
119
 
214
120
  const subAgentMap = useMemo(() => {
215
121
  if (!subAgentExecutions || subAgentExecutions.length === 0) return null;
@@ -220,174 +126,40 @@ export const ToolCallGroup = memo(function ToolCallGroup({
220
126
  return map;
221
127
  }, [subAgentExecutions]);
222
128
 
223
- if (toolCalls.length === 0) return null;
129
+ if (visibleToolCalls.length === 0) return null;
224
130
 
225
- const summary = formatSummary
226
- ? formatSummary(toolCalls)
227
- : defaultFormatSummary(toolCalls, status);
228
- const Icon = STATUS_ICON[status];
229
- const ariaLabel = `${summary}, ${status}`;
131
+ const ariaLabel = `${visibleToolCalls.length} tool ${visibleToolCalls.length === 1 ? "call" : "calls"}`;
230
132
 
231
133
  return (
232
134
  <div
233
135
  role="group"
234
136
  aria-label={ariaLabel}
137
+ data-cursor-target="tool-call-group"
235
138
  className={cn(
236
- "rounded-md border border-border bg-muted-faint",
139
+ // Cursor-style: each tool call (and folded run chip) is its own
140
+ // self-contained card; the turn's tools stack with a small gap between
141
+ // them rather than sharing a left rail, so the thread reads as a column
142
+ // of discrete cards.
143
+ "flex flex-col gap-2",
237
144
  className,
238
145
  )}
239
146
  >
240
- {/* Summary trigger */}
241
- <button
242
- type="button"
243
- aria-expanded={expanded}
244
- onClick={handleToggle}
245
- className={cn(
246
- "flex w-full items-center gap-2 px-2.5 py-1.5 text-left text-xs text-muted-foreground transition-colors",
247
- "hover:bg-muted-subtle",
248
- "cursor-pointer",
249
- )}
250
- >
251
- <span className={cn("shrink-0", STATUS_COLOR[status])} aria-hidden="true">
252
- <Icon />
253
- </span>
254
- <span className="min-w-0 flex-1 truncate">{summary}</span>
255
- <ChevronIcon expanded={expanded} />
256
- </button>
257
-
258
- {/* Expanded tool call list — CSS grid-rows animation */}
259
- <div
260
- className={cn(
261
- "grid transition-[grid-template-rows] duration-150 ease-out",
262
- expanded ? "grid-rows-[1fr]" : "grid-rows-[0fr]",
263
- )}
264
- >
265
- <div className="overflow-hidden">
266
- {expanded && (
267
- <div className="border-t border-border-muted">
268
- {toolCalls.map((tc) => (
269
- <ToolCallItem
270
- key={tc.id || tc.name}
271
- toolCall={tc}
272
- subAgentExecution={subAgentMap?.get(tc.id) ?? null}
273
- />
274
- ))}
275
- </div>
276
- )}
277
- </div>
278
- </div>
147
+ {segments.map((segment) =>
148
+ segment.kind === "run" ? (
149
+ <ToolRunGroup
150
+ key={segment.key}
151
+ category={segment.category}
152
+ toolCalls={segment.toolCalls}
153
+ formatLabel={formatSummary}
154
+ />
155
+ ) : (
156
+ <ToolCallItem
157
+ key={segment.key}
158
+ toolCall={segment.toolCall}
159
+ subAgentExecution={subAgentMap?.get(segment.toolCall.id) ?? null}
160
+ />
161
+ ),
162
+ )}
279
163
  </div>
280
164
  );
281
165
  }, toolCallGroupPropsEqual);
282
-
283
- // ---------------------------------------------------------------------------
284
- // Inline SVG icons — same as SP1, kept inline for SDK independence
285
- // ---------------------------------------------------------------------------
286
-
287
- function SpinnerIcon() {
288
- return (
289
- <svg
290
- width="12"
291
- height="12"
292
- viewBox="0 0 12 12"
293
- fill="none"
294
- stroke="currentColor"
295
- strokeWidth="1.5"
296
- className="animate-spin"
297
- >
298
- <path
299
- d="M6 1.5A4.5 4.5 0 1 1 1.5 6"
300
- strokeLinecap="round"
301
- />
302
- </svg>
303
- );
304
- }
305
-
306
- function ClockIcon() {
307
- return (
308
- <svg
309
- width="12"
310
- height="12"
311
- viewBox="0 0 12 12"
312
- fill="none"
313
- stroke="currentColor"
314
- strokeWidth="1.5"
315
- strokeLinecap="round"
316
- strokeLinejoin="round"
317
- >
318
- <circle cx="6" cy="6" r="4.5" />
319
- <path d="M6 3.5V6L7.5 7.5" />
320
- </svg>
321
- );
322
- }
323
-
324
- function CheckCircleIcon() {
325
- return (
326
- <svg
327
- width="12"
328
- height="12"
329
- viewBox="0 0 12 12"
330
- fill="none"
331
- stroke="currentColor"
332
- strokeWidth="1.5"
333
- strokeLinecap="round"
334
- strokeLinejoin="round"
335
- >
336
- <circle cx="6" cy="6" r="4.5" />
337
- <path d="M4 6L5.5 7.5L8 4.5" />
338
- </svg>
339
- );
340
- }
341
-
342
- function XCircleIcon() {
343
- return (
344
- <svg
345
- width="12"
346
- height="12"
347
- viewBox="0 0 12 12"
348
- fill="none"
349
- stroke="currentColor"
350
- strokeWidth="1.5"
351
- strokeLinecap="round"
352
- strokeLinejoin="round"
353
- >
354
- <circle cx="6" cy="6" r="4.5" />
355
- <path d="M4.5 4.5L7.5 7.5M7.5 4.5L4.5 7.5" />
356
- </svg>
357
- );
358
- }
359
-
360
- function DotIcon() {
361
- return (
362
- <svg
363
- width="8"
364
- height="8"
365
- viewBox="0 0 8 8"
366
- fill="currentColor"
367
- >
368
- <circle cx="4" cy="4" r="3" />
369
- </svg>
370
- );
371
- }
372
-
373
- function ChevronIcon({ expanded }: { expanded: boolean }) {
374
- return (
375
- <svg
376
- width="12"
377
- height="12"
378
- viewBox="0 0 12 12"
379
- fill="none"
380
- stroke="currentColor"
381
- strokeWidth="1.5"
382
- strokeLinecap="round"
383
- strokeLinejoin="round"
384
- className={cn(
385
- "shrink-0 text-muted-foreground transition-transform duration-150",
386
- expanded && "rotate-90",
387
- )}
388
- aria-hidden="true"
389
- >
390
- <path d="M4.5 2.5L7.5 6L4.5 9.5" />
391
- </svg>
392
- );
393
- }