@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
@@ -0,0 +1,63 @@
1
+ import type { StructuredPatchHunk } from "diff";
2
+ import type { DiffHunk, DiffLine } from "./types";
3
+
4
+ /**
5
+ * Maps the `diff` library's structured-patch hunks into our presentation
6
+ * {@link DiffHunk} shape, assigning running old/new line numbers per line.
7
+ *
8
+ * This is the single source of truth for the hunk mapping, shared by
9
+ * {@link computeDiff} (which feeds it `structuredPatch` output computed from
10
+ * before/after text) and `parseUnifiedDiff` (which feeds it `parsePatch` output
11
+ * parsed from a unified-diff string). Both functions in the `diff` library emit
12
+ * the identical {@link StructuredPatchHunk} shape, so one mapper serves both and
13
+ * the two diff sources can never drift in how a `+`/`-`/context line becomes a
14
+ * {@link DiffLine}.
15
+ *
16
+ * `` markers are skipped: they are diff metadata, not
17
+ * content, and would otherwise be mis-rendered as a spurious context line.
18
+ *
19
+ * Pure function — no side effects, safe to call outside React.
20
+ */
21
+ export function mapPatchHunks(
22
+ hunks: readonly StructuredPatchHunk[],
23
+ ): readonly DiffHunk[] {
24
+ return hunks.map((hunk) => {
25
+ const lines: DiffLine[] = [];
26
+ let oldLine = hunk.oldStart;
27
+ let newLine = hunk.newStart;
28
+
29
+ for (const raw of hunk.lines) {
30
+ // "" is a metadata marker, not a real line.
31
+ if (raw.startsWith("\\")) continue;
32
+
33
+ const prefix = raw[0];
34
+ const content = raw.slice(1);
35
+
36
+ if (prefix === "+") {
37
+ lines.push({ type: "added", content, newLineNumber: newLine });
38
+ newLine++;
39
+ } else if (prefix === "-") {
40
+ lines.push({ type: "removed", content, oldLineNumber: oldLine });
41
+ oldLine++;
42
+ } else {
43
+ // A context line (leading space) or an empty raw line.
44
+ lines.push({
45
+ type: "context",
46
+ content,
47
+ oldLineNumber: oldLine,
48
+ newLineNumber: newLine,
49
+ });
50
+ oldLine++;
51
+ newLine++;
52
+ }
53
+ }
54
+
55
+ return {
56
+ oldStart: hunk.oldStart,
57
+ oldLines: hunk.oldLines,
58
+ newStart: hunk.newStart,
59
+ newLines: hunk.newLines,
60
+ lines,
61
+ };
62
+ });
63
+ }
@@ -9,6 +9,7 @@ export type { DiffSummaryProps } from "./DiffSummary";
9
9
  export { MultiFileDiffView } from "./MultiFileDiffView";
10
10
  export type { MultiFileDiffViewProps } from "./MultiFileDiffView";
11
11
  export { computeDiff } from "./computeDiff";
12
+ export { parseUnifiedDiff } from "./parseUnifiedDiff";
12
13
  export { computeMultiFileDiff } from "./computeMultiFileDiff";
13
14
  export type {
14
15
  VersionEntry,
@@ -0,0 +1,34 @@
1
+ import { parsePatch } from "diff";
2
+ import { mapPatchHunks } from "./diff-hunks";
3
+ import type { DiffHunk } from "./types";
4
+
5
+ /**
6
+ * Parses a unified-diff patch *string* into presentation {@link DiffHunk}s.
7
+ *
8
+ * This is the bridge that lets a harness which only emits a ready unified diff
9
+ * (the Cursor harness's `diffString` -> `view.unifiedDiff` / `FileChange.
10
+ * unifiedDiff`) render through the same accessible {@link DiffViewer} table as a
11
+ * computed before/after diff — instead of being dumped as a raw `<pre>` with the
12
+ * `--- /dev/null`, `+++ b/...`, `@@` preamble and inline `+`/`-` prefixes.
13
+ *
14
+ * The `---`/`+++` file headers parse into metadata and are discarded; only the
15
+ * hunks survive, mapped through the shared {@link mapPatchHunks}. A diff input is
16
+ * a single file's patch, but `parsePatch` can return multiple file entries, so
17
+ * their hunks are flattened defensively.
18
+ *
19
+ * Returns `[]` for an empty or unparseable patch, so callers can fall back to a
20
+ * truthful raw rendering rather than showing a misleading "No changes".
21
+ *
22
+ * Pure function — no side effects, safe to call outside React.
23
+ */
24
+ export function parseUnifiedDiff(patch: string): readonly DiffHunk[] {
25
+ if (!patch) return [];
26
+
27
+ try {
28
+ return parsePatch(patch).flatMap((file) => mapPatchHunks(file.hunks));
29
+ } catch {
30
+ // parsePatch can throw on a badly malformed patch; degrade to "no hunks" so
31
+ // the caller renders its raw fallback instead of crashing the thread.
32
+ return [];
33
+ }
34
+ }
@@ -1,8 +1,10 @@
1
1
  "use client";
2
2
 
3
- import { memo, useCallback, useState } from "react";
3
+ import { memo, useCallback, useEffect, useState } from "react";
4
4
  import type { ApprovalAction } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
5
5
  import { cn } from "@stigmer/theme";
6
+ import { DecisionButton } from "../internal/DecisionButton";
7
+ import { InCardDecisionError } from "../internal/InCardDecisionError";
6
8
 
7
9
  /** Props for {@link WorkflowExecutionApprovalCard}. */
8
10
  export interface WorkflowExecutionApprovalCardProps {
@@ -20,8 +22,15 @@ export interface WorkflowExecutionApprovalCardProps {
20
22
  action: ApprovalAction,
21
23
  comment?: string,
22
24
  ) => Promise<unknown>;
23
- /** `true` while a submission is in flight. */
25
+ /** `true` while this gate's submission is in flight. */
24
26
  readonly isSubmitting: boolean;
27
+ /**
28
+ * This gate's last failed decision, or `null`. Surfaced in-card beside the
29
+ * actions (via the shared {@link InCardDecisionError}) — supply
30
+ * {@link useWorkflowExecutionActions}'s `approvalErrorsByToolCallId` for this
31
+ * `toolCallId`.
32
+ */
33
+ readonly error?: Error | null;
25
34
  /** Additional CSS class names. */
26
35
  readonly className?: string;
27
36
  }
@@ -40,16 +49,26 @@ export const WorkflowExecutionApprovalCard = memo(function WorkflowExecutionAppr
40
49
  timeoutSeconds,
41
50
  onSubmitApproval,
42
51
  isSubmitting,
52
+ error,
43
53
  className,
44
54
  }: WorkflowExecutionApprovalCardProps) {
45
55
  const [comment, setComment] = useState("");
56
+ // Which action is in flight, so the spinner lands on the clicked button —
57
+ // matching ApprovalCard / WorkflowTaskApprovalCard. Reset once the RPC settles.
58
+ const [active, setActive] = useState<"approve" | "reject" | null>(null);
59
+
60
+ useEffect(() => {
61
+ if (!isSubmitting) setActive(null);
62
+ }, [isSubmitting]);
46
63
 
47
64
  // ApprovalAction enum values: 0=UNSPECIFIED, 1=APPROVE, 2=SKIP, 3=REJECT
48
65
  const handleApprove = useCallback(() => {
66
+ setActive("approve");
49
67
  onSubmitApproval(toolCallId, 1 as ApprovalAction, comment || undefined);
50
68
  }, [toolCallId, comment, onSubmitApproval]);
51
69
 
52
70
  const handleReject = useCallback(() => {
71
+ setActive("reject");
53
72
  onSubmitApproval(toolCallId, 3 as ApprovalAction, comment || undefined);
54
73
  }, [toolCallId, comment, onSubmitApproval]);
55
74
 
@@ -57,8 +76,10 @@ export const WorkflowExecutionApprovalCard = memo(function WorkflowExecutionAppr
57
76
  <div
58
77
  role="alert"
59
78
  aria-label="Approval required"
79
+ // Neutral card + 2px warning left accent — the quiet Cursor-grade chrome
80
+ // shared with ApprovalCard. (Replaces the old amber `bg-warning/5` fill.)
60
81
  className={cn(
61
- "my-1 rounded-lg border border-warning/30 bg-warning/5 p-3",
82
+ "my-1 rounded-lg border border-border-prominent border-l-2 border-l-warning p-3",
62
83
  className,
63
84
  )}
64
85
  >
@@ -92,30 +113,34 @@ export const WorkflowExecutionApprovalCard = memo(function WorkflowExecutionAppr
92
113
  </div>
93
114
 
94
115
  <div className="mt-2 flex gap-2">
95
- <button
96
- type="button"
116
+ <DecisionButton
117
+ label="Approve"
118
+ variant="primary"
97
119
  onClick={handleApprove}
98
- disabled={isSubmitting}
99
- className={cn(
100
- "rounded px-3 py-1 text-xs font-medium",
101
- "bg-success text-success-foreground",
102
- "hover:bg-success/90 disabled:pointer-events-none disabled:opacity-50",
103
- )}
104
- >
105
- Approve
106
- </button>
107
- <button
108
- type="button"
120
+ isActive={active === "approve"}
121
+ isSubmitting={isSubmitting}
122
+ />
123
+ <DecisionButton
124
+ label="Reject"
125
+ variant="danger"
109
126
  onClick={handleReject}
110
- disabled={isSubmitting}
111
- className={cn(
112
- "rounded border border-destructive/30 px-3 py-1 text-xs font-medium text-destructive",
113
- "hover:bg-destructive/10 disabled:pointer-events-none disabled:opacity-50",
114
- )}
115
- >
116
- Reject
117
- </button>
127
+ isActive={active === "reject"}
128
+ isSubmitting={isSubmitting}
129
+ />
118
130
  </div>
131
+
132
+ {/* A failed decision surfaces HERE, beside this gate's actions — not in the
133
+ viewer's lifecycle banner. A workflow can hold many gates at once, so a
134
+ failure must name the one it belongs to; the optimistic spinner has
135
+ already reverted, and this explains the snap-back. Shared with the
136
+ agent ApprovalCard / FileReviewCard via InCardDecisionError. */}
137
+ {error && (
138
+ <InCardDecisionError
139
+ error={error}
140
+ leadIn="submit decision"
141
+ cursorTarget="wf-approval-error"
142
+ />
143
+ )}
119
144
  </div>
120
145
  );
121
146
  });
@@ -23,8 +23,17 @@ export interface WorkflowExecutionTimelineProps {
23
23
  formData?: Record<string, unknown>,
24
24
  comment?: string,
25
25
  ) => Promise<unknown>;
26
- /** True while a task approval submission is in flight. */
27
- readonly isSubmittingApproval?: boolean;
26
+ /**
27
+ * Task names whose human_input approval is currently in flight, keyed by
28
+ * `taskName` so deciding one gate never spins another. Supply
29
+ * {@link useWorkflowExecutionActions}'s `taskApprovalSubmittingTaskNames`.
30
+ */
31
+ readonly taskApprovalSubmittingTaskNames?: ReadonlySet<string>;
32
+ /**
33
+ * Per-gate human_input approval failures, keyed by `taskName`. Supply
34
+ * {@link useWorkflowExecutionActions}'s `taskApprovalErrorsByTaskName`.
35
+ */
36
+ readonly taskApprovalErrorsByTaskName?: ReadonlyMap<string, Error>;
28
37
  /** Additional CSS class names. */
29
38
  readonly className?: string;
30
39
  }
@@ -47,7 +56,8 @@ export const WorkflowExecutionTimeline = memo(function WorkflowExecutionTimeline
47
56
  onNavigateToAgentExecution,
48
57
  taskStates,
49
58
  onSubmitTaskApproval,
50
- isSubmittingApproval,
59
+ taskApprovalSubmittingTaskNames,
60
+ taskApprovalErrorsByTaskName,
51
61
  className,
52
62
  }: WorkflowExecutionTimelineProps) {
53
63
  const scrollRef = useRef<HTMLDivElement>(null);
@@ -112,7 +122,8 @@ export const WorkflowExecutionTimeline = memo(function WorkflowExecutionTimeline
112
122
  onNavigateToAgentExecution={onNavigateToAgentExecution}
113
123
  taskStates={taskStates}
114
124
  onSubmitTaskApproval={onSubmitTaskApproval}
115
- isSubmittingApproval={isSubmittingApproval}
125
+ taskApprovalSubmittingTaskNames={taskApprovalSubmittingTaskNames}
126
+ taskApprovalErrorsByTaskName={taskApprovalErrorsByTaskName}
116
127
  />
117
128
  ))}
118
129
 
@@ -19,7 +19,10 @@ interface TimelineEventProps {
19
19
  formData?: Record<string, unknown>,
20
20
  comment?: string,
21
21
  ) => Promise<unknown>;
22
- readonly isSubmittingApproval?: boolean;
22
+ /** Task names whose human_input approval is in flight, keyed by `taskName`. */
23
+ readonly taskApprovalSubmittingTaskNames?: ReadonlySet<string>;
24
+ /** Per-gate human_input approval failures, keyed by `taskName`. */
25
+ readonly taskApprovalErrorsByTaskName?: ReadonlyMap<string, Error>;
23
26
  }
24
27
 
25
28
  /**
@@ -37,7 +40,8 @@ export const WorkflowExecutionTimelineEvent = memo(function WorkflowExecutionTim
37
40
  onNavigateToAgentExecution,
38
41
  taskStates,
39
42
  onSubmitTaskApproval,
40
- isSubmittingApproval,
43
+ taskApprovalSubmittingTaskNames,
44
+ taskApprovalErrorsByTaskName,
41
45
  }: TimelineEventProps) {
42
46
  const timestamp = formatTimestamp(event.occurredAt);
43
47
  const p = event.payload;
@@ -277,7 +281,8 @@ export const WorkflowExecutionTimelineEvent = memo(function WorkflowExecutionTim
277
281
  ? (p.value.formSchema as unknown as Record<string, unknown>)
278
282
  : undefined}
279
283
  onSubmit={onSubmitTaskApproval}
280
- isSubmitting={isSubmittingApproval ?? false}
284
+ isSubmitting={taskApprovalSubmittingTaskNames?.has(event.taskName) ?? false}
285
+ error={taskApprovalErrorsByTaskName?.get(event.taskName) ?? null}
281
286
  />
282
287
  )}
283
288
  </EventRow>
@@ -20,7 +20,8 @@ import { ExecutionInspector } from "./execution-inspector";
20
20
  import { ExecutionComparisonPicker } from "./execution-comparison/ExecutionComparisonPicker";
21
21
  import { ExecutionComparisonView } from "./execution-comparison/ExecutionComparisonView";
22
22
  import { WorkflowExecutionApprovalCard } from "./WorkflowExecutionApprovalCard";
23
- import type { WorkflowPendingApproval } from "@stigmer/protos/ai/stigmer/agentic/workflowexecution/v1/api_pb";
23
+ import { WorkflowFileReviewList, type WorkflowFileDecisionSubmit } from "./WorkflowFileReviewList";
24
+ import type { WorkflowPendingApproval, WorkflowPendingFileReview } from "@stigmer/protos/ai/stigmer/agentic/workflowexecution/v1/api_pb";
24
25
  import type { ApprovalAction } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
25
26
  import { ResizableSplit } from "../internal/ResizableSplit";
26
27
 
@@ -287,7 +288,9 @@ export const WorkflowExecutionViewer = memo(function WorkflowExecutionViewer({
287
288
  onClose={handleCloseComparePicker}
288
289
  />
289
290
 
290
- {/* Action error banner (lifecycle actions: cancel, pause, recover, etc.) */}
291
+ {/* Action error banner lifecycle actions only (cancel/terminate/pause/
292
+ resume/recover). Approval failures are per-gate and surface in-card on
293
+ the failing approval card, never here. */}
291
294
  {actions.error && (
292
295
  <div className="flex items-center gap-2 border-b border-destructive/20 bg-destructive/5 px-4 py-2">
293
296
  <p className="flex-1 text-xs text-destructive">{actions.error.message}</p>
@@ -365,9 +368,11 @@ export const WorkflowExecutionViewer = memo(function WorkflowExecutionViewer({
365
368
  onNavigateToAgentExecution={onNavigateToAgentExecution}
366
369
  pendingApprovals={execution?.status?.pendingApprovals}
367
370
  onSubmitApproval={actions.submitApproval}
368
- isSubmittingApproval={actions.isSubmitting}
371
+ approvalSubmittingToolCallIds={actions.approvalSubmittingToolCallIds}
372
+ approvalErrorsByToolCallId={actions.approvalErrorsByToolCallId}
369
373
  onSubmitTaskApproval={actions.submitTaskApproval}
370
- isSubmittingTaskApproval={actions.isSubmitting}
374
+ taskApprovalSubmittingTaskNames={actions.taskApprovalSubmittingTaskNames}
375
+ taskApprovalErrorsByTaskName={actions.taskApprovalErrorsByTaskName}
371
376
  className="min-h-0 flex-1"
372
377
  />
373
378
 
@@ -403,9 +408,16 @@ export const WorkflowExecutionViewer = memo(function WorkflowExecutionViewer({
403
408
  onNavigateToAgentExecution={onNavigateToAgentExecution}
404
409
  taskStates={effectiveTaskStates}
405
410
  onSubmitTaskApproval={actions.submitTaskApproval}
406
- isSubmittingApproval={actions.isSubmitting}
411
+ taskApprovalSubmittingTaskNames={actions.taskApprovalSubmittingTaskNames}
412
+ taskApprovalErrorsByTaskName={actions.taskApprovalErrorsByTaskName}
407
413
  pendingApprovals={execution?.status?.pendingApprovals}
408
414
  onSubmitApproval={actions.submitApproval}
415
+ approvalSubmittingToolCallIds={actions.approvalSubmittingToolCallIds}
416
+ approvalErrorsByToolCallId={actions.approvalErrorsByToolCallId}
417
+ pendingFileReviews={execution?.status?.pendingFileReviews}
418
+ onSubmitFileDecision={actions.submitFileDecision}
419
+ fileDecisionSubmittingKeys={actions.fileDecisionSubmittingKeys}
420
+ fileDecisionErrorsByKey={actions.fileDecisionErrorsByKey}
409
421
  />
410
422
  </div>
411
423
  </>
@@ -449,9 +461,16 @@ function ExecutionBottomPanel({
449
461
  onNavigateToAgentExecution,
450
462
  taskStates,
451
463
  onSubmitTaskApproval,
452
- isSubmittingApproval,
464
+ taskApprovalSubmittingTaskNames,
465
+ taskApprovalErrorsByTaskName,
453
466
  pendingApprovals,
454
467
  onSubmitApproval,
468
+ approvalSubmittingToolCallIds,
469
+ approvalErrorsByToolCallId,
470
+ pendingFileReviews,
471
+ onSubmitFileDecision,
472
+ fileDecisionSubmittingKeys,
473
+ fileDecisionErrorsByKey,
455
474
  }: {
456
475
  events: WorkflowExecutionTimelineProps["events"];
457
476
  streamState: WorkflowExecutionTimelineProps["streamState"];
@@ -462,28 +481,39 @@ function ExecutionBottomPanel({
462
481
  onNavigateToAgentExecution?: (id: string) => void;
463
482
  taskStates: ReadonlyMap<string, DerivedTaskState>;
464
483
  onSubmitTaskApproval: WorkflowExecutionTimelineProps["onSubmitTaskApproval"];
465
- isSubmittingApproval: boolean;
484
+ taskApprovalSubmittingTaskNames: ReadonlySet<string>;
485
+ taskApprovalErrorsByTaskName: ReadonlyMap<string, Error>;
466
486
  pendingApprovals?: readonly WorkflowPendingApproval[];
467
487
  onSubmitApproval?: (toolCallId: string, action: ApprovalAction, comment?: string) => Promise<unknown>;
488
+ approvalSubmittingToolCallIds: ReadonlySet<string>;
489
+ approvalErrorsByToolCallId: ReadonlyMap<string, Error>;
490
+ pendingFileReviews?: readonly WorkflowPendingFileReview[];
491
+ onSubmitFileDecision: WorkflowFileDecisionSubmit;
492
+ fileDecisionSubmittingKeys: ReadonlySet<string>;
493
+ fileDecisionErrorsByKey: ReadonlyMap<string, Error>;
468
494
  }) {
469
495
  const [collapsed, setCollapsed] = useState(false);
470
496
  const [activeTab, setActiveTab] = useState<BottomTab>("waterfall");
471
- const prevApprovalCountRef = useRef(0);
497
+ const prevHitlCountRef = useRef(0);
472
498
 
473
499
  const approvalCount = pendingApprovals?.length ?? 0;
474
- const hasApprovals = approvalCount > 0;
500
+ const fileReviewCount = pendingFileReviews?.length ?? 0;
501
+ // Both HITL kinds (tool approvals + file reviews) share the one "Approvals" tab.
502
+ const hitlCount = approvalCount + fileReviewCount;
503
+ const hasHitl = hitlCount > 0;
475
504
 
476
- // Auto-switch to Approvals tab when new approvals arrive
505
+ // Auto-switch to the Approvals tab when a new HITL gate (approval or file
506
+ // review) arrives; leave it when everything is resolved.
477
507
  useEffect(() => {
478
- if (approvalCount > prevApprovalCountRef.current && approvalCount > 0) {
508
+ if (hitlCount > prevHitlCountRef.current && hitlCount > 0) {
479
509
  setActiveTab("approvals");
480
510
  setCollapsed(false);
481
511
  }
482
- if (approvalCount === 0 && activeTab === "approvals") {
512
+ if (hitlCount === 0 && activeTab === "approvals") {
483
513
  setActiveTab("waterfall");
484
514
  }
485
- prevApprovalCountRef.current = approvalCount;
486
- }, [approvalCount, activeTab]);
515
+ prevHitlCountRef.current = hitlCount;
516
+ }, [hitlCount, activeTab]);
487
517
 
488
518
  return (
489
519
  <div className="border-t border-[var(--stgm-border,#e5e5e5)]">
@@ -516,9 +546,9 @@ function ExecutionBottomPanel({
516
546
  isActive={activeTab === "events"}
517
547
  onClick={() => { setActiveTab("events"); setCollapsed(false); }}
518
548
  />
519
- {hasApprovals && (
549
+ {hasHitl && (
520
550
  <TabButton
521
- label={`Approvals (${approvalCount})`}
551
+ label={`Approvals (${hitlCount})`}
522
552
  isActive={activeTab === "approvals"}
523
553
  onClick={() => { setActiveTab("approvals"); setCollapsed(false); }}
524
554
  />
@@ -546,24 +576,38 @@ function ExecutionBottomPanel({
546
576
  onNavigateToAgentExecution={onNavigateToAgentExecution}
547
577
  taskStates={taskStates}
548
578
  onSubmitTaskApproval={onSubmitTaskApproval}
549
- isSubmittingApproval={isSubmittingApproval}
579
+ taskApprovalSubmittingTaskNames={taskApprovalSubmittingTaskNames}
580
+ taskApprovalErrorsByTaskName={taskApprovalErrorsByTaskName}
550
581
  className="h-full"
551
582
  />
552
583
  )}
553
- {activeTab === "approvals" && pendingApprovals && onSubmitApproval && (
584
+ {activeTab === "approvals" && (
554
585
  <div className="h-full overflow-y-auto px-4 py-3">
555
586
  <div className="space-y-3">
556
- {pendingApprovals.map((pa) => (
557
- <WorkflowExecutionApprovalCard
558
- key={pa.approval?.toolCallId ?? pa.childAgentExecutionId}
559
- prompt={pa.approval?.message || `Tool "${pa.approval?.toolName}" requires approval`}
560
- toolCallId={pa.approval?.toolCallId ?? ""}
561
- approvers={[]}
562
- timeoutSeconds={0}
563
- onSubmitApproval={onSubmitApproval}
564
- isSubmitting={isSubmittingApproval}
587
+ {pendingApprovals && onSubmitApproval && pendingApprovals.map((pa) => {
588
+ const toolCallId = pa.approval?.toolCallId ?? "";
589
+ return (
590
+ <WorkflowExecutionApprovalCard
591
+ key={toolCallId || pa.childAgentExecutionId}
592
+ prompt={pa.approval?.message || `Tool "${pa.approval?.toolName}" requires approval`}
593
+ toolCallId={toolCallId}
594
+ approvers={[]}
595
+ timeoutSeconds={0}
596
+ onSubmitApproval={onSubmitApproval}
597
+ isSubmitting={approvalSubmittingToolCallIds.has(toolCallId)}
598
+ error={approvalErrorsByToolCallId.get(toolCallId) ?? null}
599
+ />
600
+ );
601
+ })}
602
+ {pendingFileReviews && pendingFileReviews.length > 0 && (
603
+ <WorkflowFileReviewList
604
+ pendingFileReviews={pendingFileReviews}
605
+ onSubmitFileDecision={onSubmitFileDecision}
606
+ submittingDecisionKeys={fileDecisionSubmittingKeys}
607
+ decisionErrors={fileDecisionErrorsByKey}
608
+ onNavigateToAgentExecution={onNavigateToAgentExecution}
565
609
  />
566
- ))}
610
+ )}
567
611
  </div>
568
612
  </div>
569
613
  )}
@@ -0,0 +1,152 @@
1
+ "use client";
2
+
3
+ import { useMemo } from "react";
4
+ import {
5
+ FileChangeSetStatus,
6
+ type FileDecisionAction,
7
+ } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
8
+ import type { WorkflowPendingFileReview } from "@stigmer/protos/ai/stigmer/agentic/workflowexecution/v1/api_pb";
9
+ import { displayFileChangeSets } from "@stigmer/sdk";
10
+ import { cn } from "@stigmer/theme";
11
+ import { FileReviewCard } from "../execution/FileReviewCard";
12
+ import type { FileDecisionOptions } from "../execution/useFileReview";
13
+ import { useExecutionStream } from "../execution/useExecutionStream";
14
+
15
+ /**
16
+ * Submit handler for a workflow-level file decision, matching
17
+ * `useWorkflowExecutionActions().submitFileDecision`. The child id is bound per
18
+ * card so the surface only needs the card-level `(action, options)`.
19
+ */
20
+ export type WorkflowFileDecisionSubmit = (
21
+ childAgentExecutionId: string,
22
+ changeSetId: string,
23
+ action: FileDecisionAction,
24
+ options?: FileDecisionOptions,
25
+ ) => void;
26
+
27
+ /** Props for {@link WorkflowFileReviewList}. */
28
+ export interface WorkflowFileReviewListProps {
29
+ /**
30
+ * The parent workflow's surfaced file-review references
31
+ * (`status.pending_file_reviews`) — one entry per child agent execution.
32
+ */
33
+ readonly pendingFileReviews: readonly WorkflowPendingFileReview[];
34
+ /** Forwards a decision to the child (see {@link WorkflowFileDecisionSubmit}). */
35
+ readonly onSubmitFileDecision: WorkflowFileDecisionSubmit;
36
+ /** In-flight decision keys (pass `fileDecisionSubmittingKeys` straight through). */
37
+ readonly submittingDecisionKeys?: ReadonlySet<string>;
38
+ /** Per-decision failures (pass `fileDecisionErrorsByKey` straight through). */
39
+ readonly decisionErrors?: ReadonlyMap<string, Error>;
40
+ /**
41
+ * Optional deep-link to open the child agent execution in its own view. When
42
+ * provided, each child's review renders a "View agent execution" affordance.
43
+ * Routing is the host's responsibility (DD-004).
44
+ */
45
+ readonly onNavigateToAgentExecution?: (agentExecutionId: string) => void;
46
+ /** Additional CSS class names for the root container. */
47
+ readonly className?: string;
48
+ }
49
+
50
+ /**
51
+ * Renders the child agent file reviews surfaced on a parent WorkflowExecution.
52
+ *
53
+ * Reference-only, derive-from-child: the parent status carries only
54
+ * {@link WorkflowPendingFileReview} references (child id + change set ids). This
55
+ * list mounts one {@link WorkflowChildFileReview} per referenced child, which
56
+ * streams that child's execution and reuses the agent-level {@link FileReviewCard}
57
+ * to render the actual diff — the heavy content stays single-sourced on the child.
58
+ * A decision is forwarded to the child via `WorkflowExecution.submitFileDecision`.
59
+ *
60
+ * This is the file-review sibling of the workflow tool-approval surface
61
+ * (`WorkflowExecutionApprovalCard`). Empty `pendingFileReviews` renders nothing.
62
+ */
63
+ export function WorkflowFileReviewList({
64
+ pendingFileReviews,
65
+ onSubmitFileDecision,
66
+ submittingDecisionKeys,
67
+ decisionErrors,
68
+ onNavigateToAgentExecution,
69
+ className,
70
+ }: WorkflowFileReviewListProps): React.ReactElement | null {
71
+ if (pendingFileReviews.length === 0) return null;
72
+
73
+ return (
74
+ <div className={cn("stgm space-y-3", className)}>
75
+ {pendingFileReviews.map((ref) => (
76
+ <WorkflowChildFileReview
77
+ key={ref.childAgentExecutionId}
78
+ reference={ref}
79
+ onSubmitFileDecision={onSubmitFileDecision}
80
+ submittingDecisionKeys={submittingDecisionKeys}
81
+ decisionErrors={decisionErrors}
82
+ onNavigateToAgentExecution={onNavigateToAgentExecution}
83
+ />
84
+ ))}
85
+ </div>
86
+ );
87
+ }
88
+
89
+ interface WorkflowChildFileReviewProps {
90
+ readonly reference: WorkflowPendingFileReview;
91
+ readonly onSubmitFileDecision: WorkflowFileDecisionSubmit;
92
+ readonly submittingDecisionKeys?: ReadonlySet<string>;
93
+ readonly decisionErrors?: ReadonlyMap<string, Error>;
94
+ readonly onNavigateToAgentExecution?: (agentExecutionId: string) => void;
95
+ }
96
+
97
+ /**
98
+ * Streams a single referenced child agent execution and renders its
99
+ * AWAITING_REVIEW change sets (intersected with the parent's surfaced reference,
100
+ * so a decision always targets a gate the workflow has actually surfaced).
101
+ */
102
+ function WorkflowChildFileReview({
103
+ reference,
104
+ onSubmitFileDecision,
105
+ submittingDecisionKeys,
106
+ decisionErrors,
107
+ onNavigateToAgentExecution,
108
+ }: WorkflowChildFileReviewProps): React.ReactElement | null {
109
+ const childId = reference.childAgentExecutionId;
110
+ const { execution } = useExecutionStream(childId);
111
+
112
+ const changeSets = useMemo(() => {
113
+ const referenced = new Set(reference.changeSetId);
114
+ return displayFileChangeSets(execution?.status).filter(
115
+ (cs) =>
116
+ cs.status === FileChangeSetStatus.AWAITING_REVIEW &&
117
+ referenced.has(cs.id) &&
118
+ cs.changes.length > 0,
119
+ );
120
+ }, [execution?.status, reference.changeSetId]);
121
+
122
+ // Nothing to show yet (child still loading, or its projection has not caught up
123
+ // to the reference). The parent list already signals "review pending" for this
124
+ // child by virtue of the reference existing.
125
+ if (changeSets.length === 0) return null;
126
+
127
+ return (
128
+ <div className="space-y-2">
129
+ {onNavigateToAgentExecution && (
130
+ <button
131
+ type="button"
132
+ onClick={() => onNavigateToAgentExecution(childId)}
133
+ className="text-xs text-muted-foreground hover:text-foreground underline underline-offset-2"
134
+ >
135
+ View agent execution
136
+ </button>
137
+ )}
138
+ {changeSets.map((changeSet) => (
139
+ <FileReviewCard
140
+ key={changeSet.id}
141
+ fileChangeSet={changeSet}
142
+ interactive
143
+ submittingDecisionKeys={submittingDecisionKeys}
144
+ decisionErrors={decisionErrors}
145
+ onSubmit={(action, options) =>
146
+ onSubmitFileDecision(childId, changeSet.id, action, options)
147
+ }
148
+ />
149
+ ))}
150
+ </div>
151
+ );
152
+ }