@stigmer/react 3.0.9-dev.20260615153829 → 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 (439) 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/code-highlight.d.ts +24 -0
  178. package/internal/code-highlight.d.ts.map +1 -0
  179. package/internal/code-highlight.js +115 -0
  180. package/internal/code-highlight.js.map +1 -0
  181. package/internal/markdown-components.d.ts.map +1 -1
  182. package/internal/markdown-components.js +13 -2
  183. package/internal/markdown-components.js.map +1 -1
  184. package/internal/useAutoDisclosure.d.ts +34 -0
  185. package/internal/useAutoDisclosure.d.ts.map +1 -0
  186. package/internal/useAutoDisclosure.js +53 -0
  187. package/internal/useAutoDisclosure.js.map +1 -0
  188. package/internal/useElapsedSince.d.ts +30 -0
  189. package/internal/useElapsedSince.d.ts.map +1 -0
  190. package/internal/useElapsedSince.js +70 -0
  191. package/internal/useElapsedSince.js.map +1 -0
  192. package/internal/useIsOverflowing.d.ts +30 -0
  193. package/internal/useIsOverflowing.d.ts.map +1 -0
  194. package/internal/useIsOverflowing.js +47 -0
  195. package/internal/useIsOverflowing.js.map +1 -0
  196. package/internal/useIsTextTruncated.d.ts +24 -0
  197. package/internal/useIsTextTruncated.d.ts.map +1 -0
  198. package/internal/useIsTextTruncated.js +41 -0
  199. package/internal/useIsTextTruncated.js.map +1 -0
  200. package/internal/useKeyedSubmission.d.ts +49 -0
  201. package/internal/useKeyedSubmission.d.ts.map +1 -0
  202. package/internal/useKeyedSubmission.js +67 -0
  203. package/internal/useKeyedSubmission.js.map +1 -0
  204. package/package.json +7 -4
  205. package/session/SessionViewer.d.ts +2 -2
  206. package/session/SessionViewer.d.ts.map +1 -1
  207. package/session/SessionViewer.js +10 -4
  208. package/session/SessionViewer.js.map +1 -1
  209. package/session/index.d.ts +2 -0
  210. package/session/index.d.ts.map +1 -1
  211. package/session/index.js +1 -0
  212. package/session/index.js.map +1 -1
  213. package/session/inspector/ChangesTab.d.ts +8 -5
  214. package/session/inspector/ChangesTab.d.ts.map +1 -1
  215. package/session/inspector/ChangesTab.js +11 -8
  216. package/session/inspector/ChangesTab.js.map +1 -1
  217. package/session/inspector/SessionInspector.d.ts +4 -4
  218. package/session/inspector/SessionInspector.d.ts.map +1 -1
  219. package/session/inspector/SessionInspector.js +4 -4
  220. package/session/inspector/SessionInspector.js.map +1 -1
  221. package/session/inspector/index.d.ts +0 -2
  222. package/session/inspector/index.d.ts.map +1 -1
  223. package/session/inspector/index.js +0 -1
  224. package/session/inspector/index.js.map +1 -1
  225. package/session/inspector/useSessionInspector.d.ts +8 -4
  226. package/session/inspector/useSessionInspector.d.ts.map +1 -1
  227. package/session/inspector/useSessionInspector.js +27 -20
  228. package/session/inspector/useSessionInspector.js.map +1 -1
  229. package/session/useSessionConversation.d.ts +37 -3
  230. package/session/useSessionConversation.d.ts.map +1 -1
  231. package/session/useSessionConversation.js +18 -2
  232. package/session/useSessionConversation.js.map +1 -1
  233. package/session/useSessionFileChanges.d.ts +74 -0
  234. package/session/useSessionFileChanges.d.ts.map +1 -0
  235. package/session/useSessionFileChanges.js +178 -0
  236. package/session/useSessionFileChanges.js.map +1 -0
  237. package/src/__tests__/styles-border-layer-invariant.test.ts +105 -0
  238. package/src/execution/ApprovalCard.tsx +368 -230
  239. package/src/execution/ApprovalContext.ts +109 -0
  240. package/src/execution/ArtifactCard.tsx +10 -6
  241. package/src/execution/ArtifactPreviewModal.tsx +12 -6
  242. package/src/execution/EmptyChangeNotice.tsx +62 -0
  243. package/src/execution/FileChangesView.tsx +383 -0
  244. package/src/execution/FilePathLink.tsx +65 -12
  245. package/src/execution/FileReviewCard.tsx +1118 -0
  246. package/src/execution/FileReviewContext.ts +53 -0
  247. package/src/execution/FileReviewDock.tsx +157 -0
  248. package/src/execution/McpToolDetail.tsx +98 -32
  249. package/src/execution/MessageThread.tsx +374 -9
  250. package/src/execution/PlanArtifactCard.tsx +9 -6
  251. package/src/execution/PlanCompletionCard.tsx +1 -1
  252. package/src/execution/ResultView.tsx +333 -162
  253. package/src/execution/SubAgentSection.tsx +58 -11
  254. package/src/execution/TerminalSession.tsx +91 -0
  255. package/src/execution/TodoCard.tsx +186 -0
  256. package/src/execution/ToolArgsView.tsx +28 -17
  257. package/src/execution/ToolCallDetail.tsx +137 -26
  258. package/src/execution/ToolCallGroup.tsx +68 -296
  259. package/src/execution/ToolCallItem.tsx +265 -67
  260. package/src/execution/ToolRunGroup.tsx +302 -0
  261. package/src/execution/__tests__/ApprovalCard.test.tsx +395 -5
  262. package/src/execution/__tests__/ArtifactContentRenderer.test.tsx +15 -0
  263. package/src/execution/__tests__/ArtifactPreviewModal.test.tsx +0 -1
  264. package/src/execution/__tests__/EmptyChangeNotice.test.tsx +24 -0
  265. package/src/execution/__tests__/FileChangesView.test.tsx +296 -0
  266. package/src/execution/__tests__/FilePathLink.test.tsx +92 -0
  267. package/src/execution/__tests__/FileReviewCard.test.tsx +1044 -0
  268. package/src/execution/__tests__/FileReviewDock.test.tsx +134 -0
  269. package/src/execution/__tests__/McpToolDetail.test.tsx +79 -0
  270. package/src/execution/__tests__/MessageThread.test.tsx +324 -0
  271. package/src/execution/__tests__/PlanArtifactCard.test.tsx +37 -16
  272. package/src/execution/__tests__/ResultView.test.tsx +280 -2
  273. package/src/execution/__tests__/SubAgentSection.test.tsx +180 -0
  274. package/src/execution/__tests__/TerminalSession.test.tsx +72 -0
  275. package/src/execution/__tests__/TodoCard.test.tsx +102 -0
  276. package/src/execution/__tests__/ToolArgsView.test.tsx +48 -0
  277. package/src/execution/__tests__/ToolCallDetail.test.tsx +195 -0
  278. package/src/execution/__tests__/ToolCallGroup.test.tsx +132 -0
  279. package/src/execution/__tests__/ToolCallItem.test.tsx +521 -0
  280. package/src/execution/__tests__/ToolRunGroup.test.tsx +137 -0
  281. package/src/execution/__tests__/blanked-narration.test.tsx +149 -0
  282. package/src/execution/__tests__/buildThreadItems-approvals.test.ts +304 -0
  283. package/src/execution/__tests__/buildThreadItems-file-review.test.ts +331 -0
  284. package/src/execution/__tests__/file-path-resolver.test.ts +44 -0
  285. package/src/execution/__tests__/file-review-status.test.ts +343 -0
  286. package/src/execution/__tests__/message-entry.test.tsx +16 -0
  287. package/src/execution/__tests__/segment-tool-calls.test.ts +124 -0
  288. package/src/execution/__tests__/subagent-file-review-badge.test.tsx +273 -0
  289. package/src/execution/__tests__/thread-keys.test.ts +195 -0
  290. package/src/execution/__tests__/tool-presenter.test.tsx +95 -0
  291. package/src/execution/__tests__/useArtifactDownload.test.tsx +67 -0
  292. package/src/execution/__tests__/useArtifactDownloadUrl.test.tsx +51 -0
  293. package/src/execution/__tests__/useFileChangeContent.test.tsx +240 -0
  294. package/src/execution/__tests__/useFileReview.test.tsx +236 -0
  295. package/src/execution/__tests__/useSubmitApproval.test.tsx +165 -0
  296. package/src/execution/__tests__/useToolOutputContent.test.tsx +82 -0
  297. package/src/execution/approval-provenance.ts +8 -0
  298. package/src/execution/artifact-utils.ts +0 -18
  299. package/src/execution/execution-phases.ts +4 -16
  300. package/src/execution/file-path-resolver.ts +38 -0
  301. package/src/execution/file-review-status.ts +219 -0
  302. package/src/execution/index.ts +84 -4
  303. package/src/execution/segment-tool-calls.ts +101 -0
  304. package/src/execution/tool-categories.ts +128 -1
  305. package/src/execution/tool-presenter.ts +58 -3
  306. package/src/execution/tool-rendering-primitives.tsx +11 -14
  307. package/src/execution/useArtifactDownload.ts +109 -0
  308. package/src/execution/useArtifactDownloadUrl.ts +116 -0
  309. package/src/execution/useFileChangeContent.ts +149 -0
  310. package/src/execution/useFileReview.ts +197 -0
  311. package/src/execution/useSubmitApproval.ts +49 -27
  312. package/src/execution/useToolOutputContent.ts +70 -0
  313. package/src/index.ts +60 -1
  314. package/src/internal/ApprovalPeekBar.tsx +73 -0
  315. package/src/internal/BoundedContent.tsx +97 -0
  316. package/src/internal/DecisionButton.tsx +127 -0
  317. package/src/internal/InCardDecisionError.tsx +47 -0
  318. package/src/internal/RevealToggle.tsx +91 -0
  319. package/src/internal/VirtualizedThread.tsx +28 -2
  320. package/src/internal/__tests__/ApprovalPeekBar.test.tsx +34 -0
  321. package/src/internal/__tests__/BoundedContent.test.tsx +92 -0
  322. package/src/internal/__tests__/DecisionButton.test.tsx +107 -0
  323. package/src/internal/__tests__/RevealToggle.test.tsx +61 -0
  324. package/src/internal/__tests__/code-highlight.test.tsx +59 -0
  325. package/src/internal/__tests__/markdown-components.test.tsx +68 -2
  326. package/src/internal/__tests__/useAutoDisclosure.test.ts +74 -0
  327. package/src/internal/__tests__/useElapsedSince.test.tsx +68 -0
  328. package/src/internal/__tests__/useIsOverflowing.test.ts +36 -0
  329. package/src/internal/__tests__/useKeyedSubmission.test.tsx +126 -0
  330. package/src/internal/code-highlight.tsx +120 -0
  331. package/src/internal/markdown-components.tsx +20 -3
  332. package/src/internal/useAutoDisclosure.ts +58 -0
  333. package/src/internal/useElapsedSince.ts +72 -0
  334. package/src/internal/useIsOverflowing.ts +61 -0
  335. package/src/internal/useIsTextTruncated.ts +55 -0
  336. package/src/internal/useKeyedSubmission.ts +101 -0
  337. package/src/session/SessionViewer.tsx +21 -4
  338. package/src/session/__tests__/SessionViewer-fileReviewDock.test.tsx +198 -0
  339. package/src/session/__tests__/audienceWiring.test.tsx +4 -0
  340. package/src/session/__tests__/useSessionFileChanges.test.ts +303 -0
  341. package/src/session/index.ts +3 -0
  342. package/src/session/inspector/ChangesTab.tsx +20 -17
  343. package/src/session/inspector/SessionInspector.tsx +12 -10
  344. package/src/session/inspector/__tests__/ArtifactsTab.test.tsx +0 -1
  345. package/src/session/inspector/__tests__/ChangesTab.test.tsx +38 -0
  346. package/src/session/inspector/__tests__/useSessionInspector.test.ts +46 -61
  347. package/src/session/inspector/index.ts +0 -3
  348. package/src/session/inspector/useSessionInspector.ts +27 -20
  349. package/src/session/useSessionConversation.ts +80 -3
  350. package/src/session/useSessionFileChanges.ts +207 -0
  351. package/src/styles.css +123 -10
  352. package/src/version-history/DiffViewer.tsx +10 -7
  353. package/src/version-history/UnifiedDiffView.tsx +66 -0
  354. package/src/version-history/__tests__/DiffViewer.test.tsx +57 -0
  355. package/src/version-history/__tests__/UnifiedDiffView.test.tsx +50 -0
  356. package/src/version-history/__tests__/computeDiff.test.ts +35 -0
  357. package/src/version-history/__tests__/parseUnifiedDiff.test.ts +82 -0
  358. package/src/version-history/computeDiff.ts +6 -37
  359. package/src/version-history/diff-hunks.ts +63 -0
  360. package/src/version-history/index.ts +1 -0
  361. package/src/version-history/parseUnifiedDiff.ts +34 -0
  362. package/src/workflow/WorkflowExecutionApprovalCard.tsx +49 -24
  363. package/src/workflow/WorkflowExecutionTimeline.tsx +15 -4
  364. package/src/workflow/WorkflowExecutionTimelineEvent.tsx +8 -3
  365. package/src/workflow/WorkflowExecutionViewer.tsx +72 -28
  366. package/src/workflow/WorkflowFileReviewList.tsx +152 -0
  367. package/src/workflow/WorkflowTaskApprovalCard.tsx +37 -85
  368. package/src/workflow/__tests__/ExecutionInspector.test.tsx +30 -2
  369. package/src/workflow/__tests__/WorkflowExecutionApprovalCard.test.tsx +129 -0
  370. package/src/workflow/__tests__/WorkflowFileReviewList.test.tsx +129 -0
  371. package/src/workflow/__tests__/WorkflowTaskApprovalCard.test.tsx +43 -11
  372. package/src/workflow/__tests__/useWorkflowExecutionActions.test.tsx +276 -0
  373. package/src/workflow/execution-inspector/ExecutionInspector.tsx +42 -18
  374. package/src/workflow/index.ts +5 -0
  375. package/src/workflow/useWorkflowExecutionActions.ts +177 -29
  376. package/styles.css +1 -1
  377. package/version-history/DiffViewer.d.ts.map +1 -1
  378. package/version-history/DiffViewer.js +9 -3
  379. package/version-history/DiffViewer.js.map +1 -1
  380. package/version-history/UnifiedDiffView.d.ts +29 -0
  381. package/version-history/UnifiedDiffView.d.ts.map +1 -0
  382. package/version-history/UnifiedDiffView.js +36 -0
  383. package/version-history/UnifiedDiffView.js.map +1 -0
  384. package/version-history/computeDiff.d.ts +3 -1
  385. package/version-history/computeDiff.d.ts.map +1 -1
  386. package/version-history/computeDiff.js +5 -35
  387. package/version-history/computeDiff.js.map +1 -1
  388. package/version-history/diff-hunks.d.ts +21 -0
  389. package/version-history/diff-hunks.d.ts.map +1 -0
  390. package/version-history/diff-hunks.js +58 -0
  391. package/version-history/diff-hunks.js.map +1 -0
  392. package/version-history/index.d.ts +1 -0
  393. package/version-history/index.d.ts.map +1 -1
  394. package/version-history/index.js +1 -0
  395. package/version-history/index.js.map +1 -1
  396. package/version-history/parseUnifiedDiff.d.ts +22 -0
  397. package/version-history/parseUnifiedDiff.d.ts.map +1 -0
  398. package/version-history/parseUnifiedDiff.js +34 -0
  399. package/version-history/parseUnifiedDiff.js.map +1 -0
  400. package/workflow/WorkflowExecutionApprovalCard.d.ts +8 -1
  401. package/workflow/WorkflowExecutionApprovalCard.d.ts.map +1 -1
  402. package/workflow/WorkflowExecutionApprovalCard.js +17 -3
  403. package/workflow/WorkflowExecutionApprovalCard.js.map +1 -1
  404. package/workflow/WorkflowExecutionTimeline.d.ts +11 -2
  405. package/workflow/WorkflowExecutionTimeline.d.ts.map +1 -1
  406. package/workflow/WorkflowExecutionTimeline.js +2 -2
  407. package/workflow/WorkflowExecutionTimeline.js.map +1 -1
  408. package/workflow/WorkflowExecutionTimelineEvent.d.ts +4 -1
  409. package/workflow/WorkflowExecutionTimelineEvent.d.ts.map +1 -1
  410. package/workflow/WorkflowExecutionTimelineEvent.js +2 -2
  411. package/workflow/WorkflowExecutionTimelineEvent.js.map +1 -1
  412. package/workflow/WorkflowExecutionViewer.d.ts.map +1 -1
  413. package/workflow/WorkflowExecutionViewer.js +18 -10
  414. package/workflow/WorkflowExecutionViewer.js.map +1 -1
  415. package/workflow/WorkflowFileReviewList.d.ts +46 -0
  416. package/workflow/WorkflowFileReviewList.d.ts.map +1 -0
  417. package/workflow/WorkflowFileReviewList.js +48 -0
  418. package/workflow/WorkflowFileReviewList.js.map +1 -0
  419. package/workflow/WorkflowTaskApprovalCard.d.ts +8 -1
  420. package/workflow/WorkflowTaskApprovalCard.d.ts.map +1 -1
  421. package/workflow/WorkflowTaskApprovalCard.js +12 -19
  422. package/workflow/WorkflowTaskApprovalCard.js.map +1 -1
  423. package/workflow/execution-inspector/ExecutionInspector.d.ts +21 -4
  424. package/workflow/execution-inspector/ExecutionInspector.d.ts.map +1 -1
  425. package/workflow/execution-inspector/ExecutionInspector.js +6 -3
  426. package/workflow/execution-inspector/ExecutionInspector.js.map +1 -1
  427. package/workflow/index.d.ts +1 -0
  428. package/workflow/index.d.ts.map +1 -1
  429. package/workflow/index.js +1 -0
  430. package/workflow/index.js.map +1 -1
  431. package/workflow/useWorkflowExecutionActions.d.ts +62 -4
  432. package/workflow/useWorkflowExecutionActions.d.ts.map +1 -1
  433. package/workflow/useWorkflowExecutionActions.js +94 -18
  434. package/workflow/useWorkflowExecutionActions.js.map +1 -1
  435. package/session/inspector/PlanTab.d.ts +0 -15
  436. package/session/inspector/PlanTab.d.ts.map +0 -1
  437. package/session/inspector/PlanTab.js +0 -19
  438. package/session/inspector/PlanTab.js.map +0 -1
  439. package/src/session/inspector/PlanTab.tsx +0 -31
@@ -0,0 +1,303 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { renderHook } from "@testing-library/react";
3
+ import { create } from "@bufbuild/protobuf";
4
+ import {
5
+ AgentExecutionSchema,
6
+ AgentExecutionStatusSchema,
7
+ type AgentExecution,
8
+ } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
9
+ import { ApiResourceMetadataSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
10
+ import { FileContentSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
11
+ import {
12
+ CapturedFileChangeSchema,
13
+ FileChangeSetSchema,
14
+ FileReviewBaselineCapturedSchema,
15
+ FileReviewCandidateCapturedSchema,
16
+ FileReviewEventSchema,
17
+ FileReviewEventStreamSchema,
18
+ type CapturedFileChange,
19
+ } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/filereview_pb";
20
+ import {
21
+ ExecutionPhase,
22
+ FileChangeCaptureLevel,
23
+ FileChangeKind,
24
+ FileChangeSetStatus,
25
+ FileChangeType,
26
+ FileReviewEventType,
27
+ } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
28
+ import { useSessionFileChanges } from "../useSessionFileChanges";
29
+
30
+ // ---------------------------------------------------------------------------
31
+ // Fixtures
32
+ //
33
+ // Under apply-then-review the hook sources exclusively from the file-review
34
+ // ledger (the live `file_change_sets` projection, or the folded
35
+ // `file_review_event_stream` for a terminal execution). The tool-call-coupled
36
+ // `ToolCall.file_changes` (message.proto field 22) was removed in Phase 5
37
+ // Slice 4, so every fixture here is a CapturedFileChange.
38
+ // ---------------------------------------------------------------------------
39
+
40
+ function inlineSide(value: string) {
41
+ return create(FileContentSchema, { body: { case: "inline", value } });
42
+ }
43
+
44
+ function captured(opts: {
45
+ id: string;
46
+ pathBefore?: string;
47
+ pathAfter?: string;
48
+ before?: string;
49
+ after?: string;
50
+ kind?: FileChangeKind;
51
+ }): CapturedFileChange {
52
+ const pathBefore = opts.pathBefore ?? opts.pathAfter ?? "";
53
+ const pathAfter = opts.pathAfter ?? opts.pathBefore ?? "";
54
+ return create(CapturedFileChangeSchema, {
55
+ id: opts.id,
56
+ pathBefore,
57
+ pathAfter,
58
+ kind: opts.kind ?? FileChangeKind.MODIFY,
59
+ before: opts.before !== undefined ? inlineSide(opts.before) : undefined,
60
+ after: opts.after !== undefined ? inlineSide(opts.after) : undefined,
61
+ diffComplete: true,
62
+ });
63
+ }
64
+
65
+ function execWith(id: string): AgentExecution {
66
+ const exec = create(AgentExecutionSchema);
67
+ exec.metadata = create(ApiResourceMetadataSchema, { id });
68
+ exec.status = create(AgentExecutionStatusSchema);
69
+ return exec;
70
+ }
71
+
72
+ /** An execution carrying a live server projection of one change set. */
73
+ function execWithProjection(id: string, changes: CapturedFileChange[]): AgentExecution {
74
+ const exec = execWith(id);
75
+ exec.status!.fileChangeSets = [
76
+ create(FileChangeSetSchema, {
77
+ id: `${id}:0`,
78
+ status: FileChangeSetStatus.AWAITING_REVIEW,
79
+ changes,
80
+ }),
81
+ ];
82
+ return exec;
83
+ }
84
+
85
+ /** A terminal execution: empty projection, changes only in the durable ledger. */
86
+ function execWithLedger(id: string, changes: CapturedFileChange[]): AgentExecution {
87
+ const exec = execWith(id);
88
+ exec.status!.phase = ExecutionPhase.EXECUTION_COMPLETED;
89
+ exec.status!.fileChangeSets = [];
90
+ const changeSetId = `${id}:0`;
91
+ exec.status!.fileReviewEventStream = create(FileReviewEventStreamSchema, {
92
+ executionId: id,
93
+ events: [
94
+ create(FileReviewEventSchema, {
95
+ changeSetId,
96
+ eventType: FileReviewEventType.BASELINE_CAPTURED,
97
+ payload: {
98
+ case: "baselineCaptured",
99
+ value: create(FileReviewBaselineCapturedSchema, { changeSetId }),
100
+ },
101
+ }),
102
+ create(FileReviewEventSchema, {
103
+ changeSetId,
104
+ eventType: FileReviewEventType.CANDIDATE_CAPTURED,
105
+ payload: {
106
+ case: "candidateCaptured",
107
+ value: create(FileReviewCandidateCapturedSchema, { changeSetId, changes }),
108
+ },
109
+ }),
110
+ ],
111
+ });
112
+ return exec;
113
+ }
114
+
115
+ function run(executions: readonly AgentExecution[]) {
116
+ return renderHook(() => useSessionFileChanges(executions)).result.current;
117
+ }
118
+
119
+ // ---------------------------------------------------------------------------
120
+ // Tests
121
+ // ---------------------------------------------------------------------------
122
+
123
+ describe("useSessionFileChanges", () => {
124
+ it("returns empty for no executions", () => {
125
+ const r = run([]);
126
+ expect(r.hasFileChanges).toBe(false);
127
+ expect(r.fileChangeCount).toBe(0);
128
+ expect(r.fileChanges).toEqual([]);
129
+ });
130
+
131
+ it("returns empty when an execution has no file-review changes", () => {
132
+ const r = run([execWith("e1")]);
133
+ expect(r.hasFileChanges).toBe(false);
134
+ });
135
+
136
+ it("collects a single change from the live projection", () => {
137
+ const r = run([
138
+ execWithProjection("e1", [
139
+ captured({ id: "fc1", pathAfter: "src/a.ts", before: "a", after: "b" }),
140
+ ]),
141
+ ]);
142
+ expect(r.fileChangeCount).toBe(1);
143
+ expect(r.fileChanges[0].path).toBe("src/a.ts");
144
+ expect(r.fileChanges[0].captureLevel).toBe(FileChangeCaptureLevel.WHOLE_FILE);
145
+ });
146
+
147
+ it("collects changes from the durable ledger for a terminal execution", () => {
148
+ const r = run([
149
+ execWithLedger("e1", [
150
+ captured({ id: "fc1", pathAfter: "src/term.ts", before: "a", after: "b" }),
151
+ ]),
152
+ ]);
153
+ expect(r.fileChangeCount).toBe(1);
154
+ expect(r.fileChanges[0].path).toBe("src/term.ts");
155
+ });
156
+
157
+ it("net-diffs multiple edits to the same path: first.before -> last.after", () => {
158
+ const r = run([
159
+ execWithProjection("e1", [
160
+ captured({ id: "fc1", pathAfter: "src/a.ts", before: "v0", after: "v1" }),
161
+ captured({ id: "fc2", pathAfter: "src/a.ts", before: "v1", after: "v2" }),
162
+ ]),
163
+ ]);
164
+ expect(r.fileChangeCount).toBe(1);
165
+ const net = r.fileChanges[0];
166
+ expect(net.before?.body.case === "inline" && net.before.body.value).toBe("v0");
167
+ expect(net.after?.body.case === "inline" && net.after.body.value).toBe("v2");
168
+ });
169
+
170
+ it("reconciles create-then-modify on the same path to CREATE", () => {
171
+ const r = run([
172
+ execWithProjection("e1", [
173
+ captured({ id: "fc1", pathAfter: "src/new.ts", after: "first", kind: FileChangeKind.ADD }),
174
+ captured({ id: "fc2", pathAfter: "src/new.ts", before: "first", after: "second", kind: FileChangeKind.MODIFY }),
175
+ ]),
176
+ ]);
177
+ expect(r.fileChanges[0].changeType).toBe(FileChangeType.CREATE);
178
+ expect(r.fileChanges[0].after?.body.case === "inline" && r.fileChanges[0].after.body.value).toBe("second");
179
+ });
180
+
181
+ it("reconciles modify-then-delete on the same path to DELETE", () => {
182
+ const r = run([
183
+ execWithProjection("e1", [
184
+ captured({ id: "fc1", pathAfter: "src/x.ts", before: "a", after: "b" }),
185
+ captured({ id: "fc2", pathBefore: "src/x.ts", pathAfter: "src/x.ts", before: "b", kind: FileChangeKind.DELETE }),
186
+ ]),
187
+ ]);
188
+ expect(r.fileChanges[0].changeType).toBe(FileChangeType.DELETE);
189
+ });
190
+
191
+ it("reconciles create-then-delete on the same path to DELETE (path is not hidden)", () => {
192
+ const r = run([
193
+ execWithProjection("e1", [
194
+ captured({ id: "fc1", pathAfter: "src/tmp.ts", after: "scratch", kind: FileChangeKind.ADD }),
195
+ captured({ id: "fc2", pathBefore: "src/tmp.ts", pathAfter: "src/tmp.ts", before: "scratch", kind: FileChangeKind.DELETE }),
196
+ ]),
197
+ ]);
198
+ // A file created and removed within one session still surfaces, as a DELETE
199
+ // anchored on the first change's (empty) before — it is not silently dropped.
200
+ expect(r.fileChangeCount).toBe(1);
201
+ expect(r.fileChanges[0].changeType).toBe(FileChangeType.DELETE);
202
+ });
203
+
204
+ it("reconciles rename-then-modify on the same path to RENAME, preserving rename_from", () => {
205
+ const r = run([
206
+ execWithProjection("e1", [
207
+ captured({ id: "fc1", pathBefore: "src/old-name.ts", pathAfter: "src/new-name.ts", before: "a", after: "a", kind: FileChangeKind.RENAME }),
208
+ captured({ id: "fc2", pathAfter: "src/new-name.ts", before: "a", after: "b", kind: FileChangeKind.MODIFY }),
209
+ ]),
210
+ ]);
211
+ expect(r.fileChanges[0].changeType).toBe(FileChangeType.RENAME);
212
+ expect(r.fileChanges[0].renameFrom).toBe("src/old-name.ts");
213
+ expect(r.fileChanges[0].after?.body.case === "inline" && r.fileChanges[0].after.body.value).toBe("b");
214
+ });
215
+
216
+ it("groups changes across change sets by path (the execution-scoped ledger covers sub-agents)", () => {
217
+ const exec = execWith("e1");
218
+ exec.status!.fileChangeSets = [
219
+ create(FileChangeSetSchema, {
220
+ id: "e1:0",
221
+ status: FileChangeSetStatus.RECONCILED,
222
+ changes: [captured({ id: "fc1", pathAfter: "src/shared.ts", before: "v0", after: "v1" })],
223
+ }),
224
+ create(FileChangeSetSchema, {
225
+ id: "e1:1",
226
+ status: FileChangeSetStatus.AWAITING_REVIEW,
227
+ changes: [captured({ id: "fc2", pathAfter: "src/shared.ts", before: "v1", after: "v2" })],
228
+ }),
229
+ ];
230
+ const r = run([exec]);
231
+ expect(r.fileChangeCount).toBe(1);
232
+ const net = r.fileChanges[0];
233
+ expect(net.before?.body.case === "inline" && net.before.body.value).toBe("v0");
234
+ expect(net.after?.body.case === "inline" && net.after.body.value).toBe("v2");
235
+ });
236
+
237
+ it("passes a single change through with its bytes intact (no synthesis)", () => {
238
+ const r = run([
239
+ execWithProjection("e1", [
240
+ captured({ id: "fc1", pathAfter: "src/a.ts", before: "a", after: "b" }),
241
+ ]),
242
+ ]);
243
+ expect(r.fileChangeCount).toBe(1);
244
+ const only = r.fileChanges[0];
245
+ expect(only.path).toBe("src/a.ts");
246
+ expect(only.before?.body.case === "inline" && only.before.body.value).toBe("a");
247
+ expect(only.after?.body.case === "inline" && only.after.body.value).toBe("b");
248
+ });
249
+
250
+ it("sorts modified before created/renamed before deleted, then alpha", () => {
251
+ const r = run([
252
+ execWithProjection("e1", [
253
+ captured({ id: "fc1", pathBefore: "z-del.ts", pathAfter: "z-del.ts", before: "x", kind: FileChangeKind.DELETE }),
254
+ captured({ id: "fc2", pathAfter: "a-new.ts", after: "x", kind: FileChangeKind.ADD }),
255
+ captured({ id: "fc3", pathAfter: "m-mod.ts", before: "x", after: "y", kind: FileChangeKind.MODIFY }),
256
+ captured({ id: "fc4", pathAfter: "b-mod.ts", before: "x", after: "y", kind: FileChangeKind.MODIFY }),
257
+ ]),
258
+ ]);
259
+ expect(r.fileChanges.map((c) => c.path)).toEqual([
260
+ "b-mod.ts",
261
+ "m-mod.ts",
262
+ "a-new.ts",
263
+ "z-del.ts",
264
+ ]);
265
+ });
266
+
267
+ it("net-diffs captures across turns from the ledger", () => {
268
+ // Two change sets touching the same path: first.before -> last.after.
269
+ const exec = execWith("e1");
270
+ exec.status!.fileChangeSets = [
271
+ create(FileChangeSetSchema, {
272
+ id: "e1:0",
273
+ status: FileChangeSetStatus.RECONCILED,
274
+ changes: [captured({ id: "fc1", pathAfter: "src/a.ts", before: "v0", after: "v1" })],
275
+ }),
276
+ create(FileChangeSetSchema, {
277
+ id: "e1:1",
278
+ status: FileChangeSetStatus.AWAITING_REVIEW,
279
+ changes: [captured({ id: "fc2", pathAfter: "src/a.ts", before: "v1", after: "v2" })],
280
+ }),
281
+ ];
282
+ const r = run([exec]);
283
+ expect(r.fileChangeCount).toBe(1);
284
+ const net = r.fileChanges[0];
285
+ expect(net.before?.body.case === "inline" && net.before.body.value).toBe("v0");
286
+ expect(net.after?.body.case === "inline" && net.after.body.value).toBe("v2");
287
+ });
288
+
289
+ it("preserves referential stability across re-renders for the same executions", () => {
290
+ const executions = [
291
+ execWithProjection("e1", [
292
+ captured({ id: "fc1", pathAfter: "src/a.ts", before: "a", after: "b" }),
293
+ ]),
294
+ ];
295
+ const { result, rerender } = renderHook(
296
+ (e: readonly AgentExecution[]) => useSessionFileChanges(e),
297
+ { initialProps: executions },
298
+ );
299
+ const first = result.current;
300
+ rerender(executions);
301
+ expect(result.current).toBe(first);
302
+ });
303
+ });
@@ -45,6 +45,9 @@ export type {
45
45
  UseSessionWriteBacksReturn,
46
46
  } from "./useSessionWriteBacks";
47
47
 
48
+ export { useSessionFileChanges } from "./useSessionFileChanges";
49
+ export type { UseSessionFileChangesReturn } from "./useSessionFileChanges";
50
+
48
51
  export { useSessionUsage } from "./useSessionUsage";
49
52
  export type {
50
53
  ModelCostEntry,
@@ -9,34 +9,37 @@ export interface ChangesTabProps {
9
9
  }
10
10
 
11
11
  /**
12
- * Changes facet for the SessionInspector.
12
+ * Changes facet for the SessionInspector — the session's git write-backs
13
+ * (branch/commit/PR), one `WriteBackCard` per entry.
13
14
  *
14
- * Wraps the existing `useSessionWriteBacks` hook and renders
15
- * `WriteBackCard` per write-back entry the same content as
16
- * `WriteBacksWidget` but without its section heading (the tab
17
- * label provides that context).
15
+ * Local file changes deliberately do NOT render here: they live in the
16
+ * transcript, where each stamped edit row shows its diff in place and the
17
+ * per-turn decision bar carries the review controls and file list
18
+ * (`FileReviewCard`). Duplicating them in a side panel gave the same change a
19
+ * third rendering with no added authority. The tab therefore only surfaces
20
+ * once a write-back exists (see `buildVisibleTabs`).
18
21
  */
19
22
  export function ChangesTab({ executions }: ChangesTabProps) {
20
23
  const { writeBacks, hasWriteBacks } = useSessionWriteBacks(executions);
21
24
 
22
- if (!hasWriteBacks) {
25
+ if (hasWriteBacks) {
23
26
  return (
24
- <div className="flex flex-col items-center justify-center px-4 py-8 text-center">
25
- <p className="text-xs text-muted-foreground">
26
- No pull requests yet. Changes will appear here when the agent
27
- writes back to a workspace.
28
- </p>
27
+ <div role="list" className="space-y-2">
28
+ {writeBacks.map((entry) => (
29
+ <div key={entry.writeBack.workspaceEntryName} role="listitem">
30
+ <WriteBackCard writeBack={entry.writeBack} />
31
+ </div>
32
+ ))}
29
33
  </div>
30
34
  );
31
35
  }
32
36
 
33
37
  return (
34
- <div role="list" className="space-y-2">
35
- {writeBacks.map((entry) => (
36
- <div key={entry.writeBack.workspaceEntryName} role="listitem">
37
- <WriteBackCard writeBack={entry.writeBack} />
38
- </div>
39
- ))}
38
+ <div className="flex flex-col items-center justify-center px-4 py-8 text-center">
39
+ <p className="text-xs text-muted-foreground">
40
+ No changes yet. Pull requests will appear here once the agent pushes
41
+ its work back to your repository.
42
+ </p>
40
43
  </div>
41
44
  );
42
45
  }
@@ -10,7 +10,6 @@ import { useSessionArtifacts } from "../useSessionArtifacts";
10
10
  import { useSessionWriteBacks } from "../useSessionWriteBacks";
11
11
  import { useSessionUsage } from "../useSessionUsage";
12
12
  import { useSessionInspector } from "./useSessionInspector";
13
- import { PlanTab } from "./PlanTab";
14
13
  import { ChangesTab } from "./ChangesTab";
15
14
  import { ArtifactsTab } from "./ArtifactsTab";
16
15
  import { UsageTab } from "./UsageTab";
@@ -24,8 +23,7 @@ import type { ApplyResourceResult } from "../../library/useApplyResource";
24
23
  export interface SessionInspectorProps {
25
24
  /**
26
25
  * The most relevant execution — the active streaming execution,
27
- * or the last completed one. Drives the run-status header and
28
- * the Plan facet.
26
+ * or the last completed one. Drives the run-status header (phase badge).
29
27
  */
30
28
  readonly displayExecution: AgentExecution | null;
31
29
  /**
@@ -65,8 +63,9 @@ export interface SessionInspectorProps {
65
63
  * Tabbed right-side inspector panel for agent sessions.
66
64
  *
67
65
  * Displays an always-visible run-status header (phase badge) above
68
- * contextual tabs: Plan, Changes, Artifacts, Usage, and Inspect
69
- * (when a thread item is selected).
66
+ * contextual tabs: Workspace, Config, Changes, Artifacts, Usage, and
67
+ * Inspect (when a thread item is selected). The agent's plan/todos render
68
+ * inline in the message thread (see {@link TodoCard}), not as a tab here.
70
69
  *
71
70
  * Mirrors the `ExecutionInspector` architecture from the workflow
72
71
  * view — same `Tabs` primitive, same tab-FSM behavior hook, same
@@ -109,8 +108,14 @@ export const SessionInspector = memo(function SessionInspector({
109
108
 
110
109
  return (
111
110
  <div className={cn("flex h-full flex-col", className)}>
112
- {/* Always-visible run-status header */}
113
- <div className="flex items-center gap-2 border-b border-border px-3 py-2.5">
111
+ {/* Always-visible run-status header. Labeled as a region so the phase
112
+ badge is reachable as "Execution progress" by assistive tech and
113
+ E2E selectors, independent of which tab is active. */}
114
+ <div
115
+ role="region"
116
+ aria-label="Execution progress"
117
+ className="flex items-center gap-2 border-b border-border px-3 py-2.5"
118
+ >
114
119
  {phase !== ExecutionPhase.EXECUTION_PHASE_UNSPECIFIED ? (
115
120
  <ExecutionPhaseBadge phase={phase} />
116
121
  ) : (
@@ -133,9 +138,6 @@ export const SessionInspector = memo(function SessionInspector({
133
138
  {activeTab === "configure" && sessionConfig && (
134
139
  <SetupTab {...sessionConfig} />
135
140
  )}
136
- {activeTab === "plan" && (
137
- <PlanTab execution={displayExecution} />
138
- )}
139
141
  {activeTab === "changes" && (
140
142
  <ChangesTab executions={allExecutions} />
141
143
  )}
@@ -18,7 +18,6 @@ function artifact(name: string) {
18
18
  sizeBytes: 1024n,
19
19
  sandboxPath: `.stigmer/${name}`,
20
20
  storageKey: `artifacts/aex_1/${name}`,
21
- downloadUrl: `https://example.test/${name}`,
22
21
  });
23
22
  }
24
23
 
@@ -0,0 +1,38 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { render, screen, cleanup } from "@testing-library/react";
3
+
4
+ const writeBacksReturn = { writeBacks: [] as Array<{ writeBack: { workspaceEntryName: string } }>, hasWriteBacks: false };
5
+
6
+ vi.mock("../../useSessionWriteBacks", () => ({
7
+ useSessionWriteBacks: () => writeBacksReturn,
8
+ }));
9
+ vi.mock("../../../execution/WriteBackCard", () => ({
10
+ WriteBackCard: () => <div data-testid="write-back-card" />,
11
+ }));
12
+
13
+ const { ChangesTab } = await import("../ChangesTab");
14
+
15
+ beforeEach(() => {
16
+ writeBacksReturn.writeBacks = [];
17
+ writeBacksReturn.hasWriteBacks = false;
18
+ });
19
+
20
+ afterEach(() => cleanup());
21
+
22
+ describe("ChangesTab", () => {
23
+ it("renders write-back (PR) cards", () => {
24
+ writeBacksReturn.writeBacks = [{ writeBack: { workspaceEntryName: "w1" } }];
25
+ writeBacksReturn.hasWriteBacks = true;
26
+
27
+ render(<ChangesTab executions={[]} />);
28
+ expect(screen.getByTestId("write-back-card")).toBeTruthy();
29
+ });
30
+
31
+ // Local file changes render in the transcript (edit rows + decision bar),
32
+ // never here — the tab is exclusively the write-back (PR) surface.
33
+ it("renders the PR-oriented empty state when no write-back exists", () => {
34
+ render(<ChangesTab executions={[]} />);
35
+ expect(screen.getByText(/no changes yet/i)).toBeTruthy();
36
+ expect(screen.getByText(/pull requests/i)).toBeTruthy();
37
+ });
38
+ });
@@ -20,25 +20,32 @@ function defaultOpts(overrides?: Partial<UseSessionInspectorOptions>): UseSessio
20
20
  };
21
21
  }
22
22
 
23
+ function tabOpts(
24
+ overrides?: Partial<Parameters<typeof buildVisibleTabs>[0]>,
25
+ ): Parameters<typeof buildVisibleTabs>[0] {
26
+ return {
27
+ hasWriteBacks: false,
28
+ writeBackCount: 0,
29
+ hasArtifacts: false,
30
+ artifactCount: 0,
31
+ hasUsage: false,
32
+ selectedItem: null,
33
+ ...overrides,
34
+ };
35
+ }
36
+
23
37
  // ---------------------------------------------------------------------------
24
38
  // buildVisibleTabs
25
39
  // ---------------------------------------------------------------------------
26
40
 
27
41
  describe("buildVisibleTabs", () => {
28
- it("always includes Workspace, Config, Plan, and Usage", () => {
29
- const tabs = buildVisibleTabs({
30
- hasWriteBacks: false,
31
- writeBackCount: 0,
32
- hasArtifacts: false,
33
- artifactCount: 0,
34
- hasUsage: false,
35
- selectedItem: null,
36
- });
42
+ it("always includes Workspace, Config, and Usage (Plan is gone — todos render inline)", () => {
43
+ const tabs = buildVisibleTabs(tabOpts());
37
44
  const ids = tabs.map((t) => t.id);
38
45
  expect(ids).toContain("workspace");
39
46
  expect(ids).toContain("configure");
40
- expect(ids).toContain("plan");
41
47
  expect(ids).toContain("usage");
48
+ expect(ids).not.toContain("plan");
42
49
  expect(ids).not.toContain("changes");
43
50
  expect(ids).not.toContain("artifacts");
44
51
  expect(ids).not.toContain("inspect");
@@ -47,74 +54,52 @@ describe("buildVisibleTabs", () => {
47
54
  expect(configTab?.label).toBe("Config");
48
55
  });
49
56
 
50
- it("includes Changes with badge when write-backs exist", () => {
51
- const tabs = buildVisibleTabs({
52
- hasWriteBacks: true,
53
- writeBackCount: 3,
54
- hasArtifacts: false,
55
- artifactCount: 0,
56
- hasUsage: false,
57
- selectedItem: null,
58
- });
57
+ // The Changes tab is exclusively the write-back (PR) surface: local file
58
+ // changes render in the transcript (edit rows + decision bar) and no longer
59
+ // surface — or badge — a tab.
60
+ it("includes Changes with badge only when write-backs exist", () => {
61
+ const tabs = buildVisibleTabs(tabOpts({ hasWriteBacks: true, writeBackCount: 3 }));
59
62
  const changesTab = tabs.find((t) => t.id === "changes");
60
63
  expect(changesTab).toBeDefined();
61
64
  expect(changesTab?.badge).toBe(3);
62
65
  });
63
66
 
64
67
  it("includes Artifacts with badge when artifacts exist", () => {
65
- const tabs = buildVisibleTabs({
66
- hasWriteBacks: false,
67
- writeBackCount: 0,
68
- hasArtifacts: true,
69
- artifactCount: 7,
70
- hasUsage: false,
71
- selectedItem: null,
72
- });
68
+ const tabs = buildVisibleTabs(tabOpts({ hasArtifacts: true, artifactCount: 7 }));
73
69
  const artifactsTab = tabs.find((t) => t.id === "artifacts");
74
70
  expect(artifactsTab).toBeDefined();
75
71
  expect(artifactsTab?.badge).toBe(7);
76
72
  });
77
73
 
78
74
  it("includes Inspect when a thread item is selected", () => {
79
- const tabs = buildVisibleTabs({
80
- hasWriteBacks: false,
81
- writeBackCount: 0,
82
- hasArtifacts: false,
83
- artifactCount: 0,
84
- hasUsage: false,
85
- selectedItem: { kind: "tool-call", toolCallId: "tc-1" },
86
- });
75
+ const tabs = buildVisibleTabs(
76
+ tabOpts({ selectedItem: { kind: "tool-call", toolCallId: "tc-1" } }),
77
+ );
87
78
  const inspectTab = tabs.find((t) => t.id === "inspect");
88
79
  expect(inspectTab).toBeDefined();
89
80
  });
90
81
 
91
- it("orders tabs as Workspace, Config, Plan, then Usage with Inspect last", () => {
92
- const tabs = buildVisibleTabs({
93
- hasWriteBacks: true,
94
- writeBackCount: 2,
95
- hasArtifacts: true,
96
- artifactCount: 1,
97
- hasUsage: true,
98
- selectedItem: { kind: "tool-call", toolCallId: "tc-1" },
99
- });
82
+ it("orders tabs as Workspace, Config, then Usage with Inspect last", () => {
83
+ const tabs = buildVisibleTabs(
84
+ tabOpts({
85
+ hasWriteBacks: true,
86
+ writeBackCount: 2,
87
+ hasArtifacts: true,
88
+ artifactCount: 1,
89
+ hasUsage: true,
90
+ selectedItem: { kind: "tool-call", toolCallId: "tc-1" },
91
+ }),
92
+ );
100
93
  const ids = tabs.map((t) => t.id);
101
94
  expect(ids.indexOf("workspace")).toBeLessThan(ids.indexOf("configure"));
102
- expect(ids.indexOf("configure")).toBeLessThan(ids.indexOf("plan"));
103
- expect(ids.indexOf("plan")).toBeLessThan(ids.indexOf("usage"));
95
+ expect(ids.indexOf("configure")).toBeLessThan(ids.indexOf("usage"));
104
96
  expect(ids.indexOf("usage")).toBeLessThan(ids.indexOf("inspect"));
105
97
  });
106
98
 
107
99
  it("base tabs are present even when no optional tabs exist", () => {
108
- const tabs = buildVisibleTabs({
109
- hasWriteBacks: false,
110
- writeBackCount: 0,
111
- hasArtifacts: false,
112
- artifactCount: 0,
113
- hasUsage: false,
114
- selectedItem: null,
115
- });
100
+ const tabs = buildVisibleTabs(tabOpts());
116
101
  const ids = tabs.map((t) => t.id);
117
- expect(ids).toEqual(["workspace", "configure", "plan", "usage"]);
102
+ expect(ids).toEqual(["workspace", "configure", "usage"]);
118
103
  });
119
104
  });
120
105
 
@@ -137,13 +122,13 @@ describe("useSessionInspector", () => {
137
122
  expect(result.current.activeTab).toBe("workspace");
138
123
  });
139
124
 
140
- it("defaults to plan while execution is running", () => {
125
+ it("defaults to workspace while execution is running (todos render inline, not in a tab)", () => {
141
126
  const { result } = renderHook(() =>
142
127
  useSessionInspector(
143
128
  defaultOpts({ phase: ExecutionPhase.EXECUTION_IN_PROGRESS }),
144
129
  ),
145
130
  );
146
- expect(result.current.activeTab).toBe("plan");
131
+ expect(result.current.activeTab).toBe("workspace");
147
132
  });
148
133
 
149
134
  it("auto-switches to inspect when a thread item is selected", () => {
@@ -174,7 +159,7 @@ describe("useSessionInspector", () => {
174
159
  expect(result.current.activeTab).toBe("workspace");
175
160
  });
176
161
 
177
- it("reverts to plan when selection is cleared while execution is running", () => {
162
+ it("reverts to workspace when selection is cleared while execution is running", () => {
178
163
  const { result, rerender } = renderHook(
179
164
  (props: UseSessionInspectorOptions) => useSessionInspector(props),
180
165
  {
@@ -192,7 +177,7 @@ describe("useSessionInspector", () => {
192
177
  selectedItem: null,
193
178
  }),
194
179
  );
195
- expect(result.current.activeTab).toBe("plan");
180
+ expect(result.current.activeTab).toBe("workspace");
196
181
  });
197
182
 
198
183
  it("keeps user-picked tab sticky", () => {
@@ -247,7 +232,7 @@ describe("useSessionInspector", () => {
247
232
  expect(result.current.activeTab).toBe("workspace");
248
233
  });
249
234
 
250
- it("switches to workspace when execution transitions to terminal phase", () => {
235
+ it("stays on workspace across the running terminal transition", () => {
251
236
  const { result, rerender } = renderHook(
252
237
  (props: UseSessionInspectorOptions) => useSessionInspector(props),
253
238
  {
@@ -256,7 +241,7 @@ describe("useSessionInspector", () => {
256
241
  }),
257
242
  },
258
243
  );
259
- expect(result.current.activeTab).toBe("plan");
244
+ expect(result.current.activeTab).toBe("workspace");
260
245
 
261
246
  rerender(
262
247
  defaultOpts({ phase: ExecutionPhase.EXECUTION_COMPLETED }),
@@ -8,9 +8,6 @@ export type {
8
8
  UseSessionInspectorReturn,
9
9
  } from "./useSessionInspector";
10
10
 
11
- export { PlanTab } from "./PlanTab";
12
- export type { PlanTabProps } from "./PlanTab";
13
-
14
11
  export { ChangesTab } from "./ChangesTab";
15
12
  export type { ChangesTabProps } from "./ChangesTab";
16
13