@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
@@ -9,7 +9,6 @@ import type { SelectedThreadItem } from "../../internal/store/selection-store";
9
9
  export type SessionInspectorTabId =
10
10
  | "workspace"
11
11
  | "configure"
12
- | "plan"
13
12
  | "changes"
14
13
  | "artifacts"
15
14
  | "usage"
@@ -32,29 +31,34 @@ export interface UseSessionInspectorReturn {
32
31
  }
33
32
 
34
33
  /**
35
- * Compute the system-suggested tab from execution phase and selection.
34
+ * Compute the system-suggested tab from selection.
36
35
  *
37
36
  * Priority:
38
37
  * 1. Thread item selected -> "inspect"
39
- * 2. No execution or terminal phase (idle / ready for follow-up) -> "workspace"
40
- * 3. Actively running -> "plan"
38
+ * 2. Otherwise -> "workspace"
39
+ *
40
+ * Live execution progress (the agent's plan and todos) now renders inline in
41
+ * the message thread as a {@link TodoCard}, not in a sidebar tab — so a running
42
+ * execution no longer steers the inspector to a dedicated facet.
41
43
  */
42
44
  function deriveAutoTab(
43
- phase: ExecutionPhase | null,
44
45
  selectedItem: SelectedThreadItem | null,
45
46
  ): SessionInspectorTabId {
46
47
  if (selectedItem) return "inspect";
47
- if (phase === null || isTerminalPhase(phase)) return "workspace";
48
- return "plan";
48
+ return "workspace";
49
49
  }
50
50
 
51
51
  /**
52
52
  * Build the contextual tab list with badges.
53
53
  *
54
54
  * Tab order follows the user's mental model — context before output:
55
- * Workspace → Config → Plan → Usage. Changes and Artifacts appear
56
- * after Plan when data exists; Inspect appears last when a thread item
57
- * is selected.
55
+ * Workspace → Config → Usage. Changes and Artifacts appear after Config
56
+ * when data exists; Inspect appears last when a thread item is selected.
57
+ *
58
+ * The Changes tab surfaces only when git write-backs (PRs) exist, badged
59
+ * with their count. Local-workspace file edits never surface a tab: they
60
+ * render in the transcript (stamped edit rows + the per-turn decision bar),
61
+ * which is their single review surface.
58
62
  */
59
63
  export function buildVisibleTabs(opts: {
60
64
  hasWriteBacks: boolean;
@@ -67,7 +71,6 @@ export function buildVisibleTabs(opts: {
67
71
  const tabs: TabItem[] = [
68
72
  { id: "workspace", label: "Workspace" },
69
73
  { id: "configure", label: "Config" },
70
- { id: "plan", label: "Plan" },
71
74
  ];
72
75
 
73
76
  if (opts.hasWriteBacks) {
@@ -111,12 +114,16 @@ export function useSessionInspector(
111
114
 
112
115
  const tabs = buildVisibleTabs({ hasWriteBacks, writeBackCount, hasArtifacts, artifactCount, hasUsage, selectedItem });
113
116
 
117
+ // A write-back (the session's only tab-worthy change source) surfaces and
118
+ // auto-selects the Changes tab on first arrival.
119
+ const hasChanges = hasWriteBacks;
120
+
114
121
  const [activeTab, setActiveTab] = useState<SessionInspectorTabId>(
115
- () => deriveAutoTab(phase, selectedItem),
122
+ () => deriveAutoTab(selectedItem),
116
123
  );
117
124
  const [prevPhase, setPrevPhase] = useState(phase);
118
125
  const [prevSelected, setPrevSelected] = useState(selectedItem);
119
- const [prevHasWriteBacks, setPrevHasWriteBacks] = useState(hasWriteBacks);
126
+ const [prevHasChanges, setPrevHasChanges] = useState(hasChanges);
120
127
  const userPickedTabRef = useRef(false);
121
128
 
122
129
  // Selection changed → auto-switch to inspect (unless user picked)
@@ -126,7 +133,7 @@ export function useSessionInspector(
126
133
  setActiveTab("inspect");
127
134
  }
128
135
  if (!selectedItem && activeTab === "inspect") {
129
- setActiveTab(deriveAutoTab(phase, null));
136
+ setActiveTab(deriveAutoTab(null));
130
137
  userPickedTabRef.current = false;
131
138
  }
132
139
  }
@@ -138,25 +145,25 @@ export function useSessionInspector(
138
145
  setPrevPhase(phase);
139
146
  if (wasTerminal !== isNowTerminal) {
140
147
  userPickedTabRef.current = false;
141
- setActiveTab(deriveAutoTab(phase, selectedItem));
148
+ setActiveTab(deriveAutoTab(selectedItem));
142
149
  }
143
150
  }
144
151
 
145
152
  // First write-back arrived → auto-switch to changes
146
- if (hasWriteBacks && !prevHasWriteBacks) {
147
- setPrevHasWriteBacks(hasWriteBacks);
153
+ if (hasChanges && !prevHasChanges) {
154
+ setPrevHasChanges(hasChanges);
148
155
  if (!userPickedTabRef.current) {
149
156
  setActiveTab("changes");
150
157
  }
151
158
  }
152
- if (hasWriteBacks !== prevHasWriteBacks) {
153
- setPrevHasWriteBacks(hasWriteBacks);
159
+ if (hasChanges !== prevHasChanges) {
160
+ setPrevHasChanges(hasChanges);
154
161
  }
155
162
 
156
163
  // Ensure active tab is valid (the selected tab may have been removed)
157
164
  const effectiveTab = tabs.some((t) => t.id === activeTab)
158
165
  ? activeTab
159
- : deriveAutoTab(phase, selectedItem);
166
+ : deriveAutoTab(selectedItem);
160
167
 
161
168
  const onTabChange = useCallback((tabId: string) => {
162
169
  userPickedTabRef.current = true;
@@ -3,7 +3,8 @@
3
3
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
4
  import type { AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
5
5
  import type { PendingApproval } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/approval_pb";
6
- import { ApprovalAction, ExecutionPhase } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
6
+ import type { FileChangeSet } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/filereview_pb";
7
+ import { ApprovalAction, ExecutionPhase, FileChangeSetStatus, FileDecisionAction } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
7
8
  import type { Session } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_pb";
8
9
  import type { McpServerUsage as ProtoMcpServerUsage } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
9
10
  import type { WorkspaceEntry as ProtoWorkspaceEntry } from "@stigmer/protos/ai/stigmer/agentic/session/v1/workspace_pb";
@@ -23,6 +24,7 @@ import { useCreateAgentExecution } from "../execution/useCreateAgentExecution";
23
24
  import { useExecutionStream } from "../execution/useExecutionStream";
24
25
  import { useAgentExecutionActions } from "../execution/useAgentExecutionActions";
25
26
  import { useSubmitApproval } from "../execution/useSubmitApproval";
27
+ import { useFileReview, type FileDecisionOptions } from "../execution/useFileReview";
26
28
  import { useSession } from "./useSession";
27
29
  import { useSessionExecutions } from "./useSessionExecutions";
28
30
  import { useUpdateSession } from "./useUpdateSession";
@@ -196,11 +198,48 @@ export interface UseSessionConversationReturn {
196
198
  ) => Promise<void>;
197
199
  /** Set of tool call IDs currently being submitted for approval. */
198
200
  readonly submittingApprovalIds: ReadonlySet<string>;
199
- /** Error from the last approval submission, or `null` when healthy. */
201
+ /**
202
+ * Per-tool-call approval failures, keyed by `toolCallId` — surfaced in-card by
203
+ * {@link MessageThread}/{@link ApprovalCard} beside the gate that failed
204
+ * (inline row or bottom backstop). The keyed parallel of
205
+ * {@link submittingApprovalIds}.
206
+ */
207
+ readonly approvalErrors: ReadonlyMap<string, Error>;
208
+ /**
209
+ * Error from the last approval submission, or `null` when healthy — the scalar
210
+ * mirror of {@link approvalErrors} (symmetric with `fileReviewError`), for a
211
+ * headless consumer wanting a single error value (e.g. the `ink` surface).
212
+ */
200
213
  readonly approvalError: Error | null;
201
- /** Reset `approvalError` to `null`. */
214
+ /** Reset every approval error (both {@link approvalErrors} and `approvalError`). */
202
215
  readonly clearApprovalError: () => void;
203
216
 
217
+ /** Captured change sets awaiting file review on the active execution, empty when none. */
218
+ readonly fileChangeSets: readonly FileChangeSet[];
219
+ /** Submit a file-review decision for a change set. The executionId is managed internally. */
220
+ readonly submitFileDecision: (
221
+ changeSetId: string,
222
+ action: FileDecisionAction,
223
+ options?: FileDecisionOptions,
224
+ ) => Promise<void>;
225
+ /** Decision keys ({@link fileDecisionKey}) currently being submitted. */
226
+ readonly submittingFileDecisionKeys: ReadonlySet<string>;
227
+ /**
228
+ * Per-decision failures, keyed by {@link fileDecisionKey} — surfaced in-card
229
+ * by {@link MessageThread}/{@link FileReviewCard} beside the failed control.
230
+ */
231
+ readonly fileDecisionErrors: ReadonlyMap<string, Error>;
232
+ /** Clear the error for one decision key (e.g. before a retry of that target). */
233
+ readonly clearFileDecisionError: (key: string) => void;
234
+ /**
235
+ * The most-recent file-review failure, or `null` when healthy — the scalar
236
+ * mirror of {@link fileDecisionErrors} (symmetric with `approvalError`), for a
237
+ * headless consumer wanting a single error value.
238
+ */
239
+ readonly fileReviewError: Error | null;
240
+ /** Reset every file-review error (both {@link fileDecisionErrors} and `fileReviewError`). */
241
+ readonly clearFileReviewError: () => void;
242
+
204
243
  /**
205
244
  * `true` when the active execution can be stopped — i.e. it is in a phase
206
245
  * the backend accepts a cancel/terminate from (`PENDING` or `IN_PROGRESS`).
@@ -337,9 +376,18 @@ export function useSessionConversation(
337
376
  const {
338
377
  submitApproval: rawSubmitApproval,
339
378
  submittingToolCallIds,
379
+ errorsByToolCallId: approvalErrors,
340
380
  error: approvalError,
341
381
  clearError: clearApprovalError,
342
382
  } = useSubmitApproval();
383
+ const {
384
+ submitFileDecision: rawSubmitFileDecision,
385
+ submittingDecisionKeys,
386
+ decisionErrors: fileDecisionErrors,
387
+ clearDecisionError: clearFileDecisionError,
388
+ error: fileReviewError,
389
+ clearError: clearFileReviewError,
390
+ } = useFileReview();
343
391
 
344
392
  // Local execution: attach the session's runner worker while it is open and
345
393
  // detach it on close. No-op for cloud sessions or when no adapter is set.
@@ -578,6 +626,26 @@ export function useSessionConversation(
578
626
  [activeExecutionId, rawSubmitApproval],
579
627
  );
580
628
 
629
+ const fileChangeSets = useMemo<readonly FileChangeSet[]>(
630
+ () =>
631
+ (activeStreamExecution?.status?.fileChangeSets ?? []).filter(
632
+ (cs) => cs.status === FileChangeSetStatus.AWAITING_REVIEW,
633
+ ),
634
+ [activeStreamExecution],
635
+ );
636
+
637
+ const submitFileDecision = useCallback(
638
+ async (
639
+ changeSetId: string,
640
+ action: FileDecisionAction,
641
+ options?: FileDecisionOptions,
642
+ ): Promise<void> => {
643
+ if (!activeExecutionId) return;
644
+ await rawSubmitFileDecision(activeExecutionId, changeSetId, action, options);
645
+ },
646
+ [activeExecutionId, rawSubmitFileDecision],
647
+ );
648
+
581
649
  const isLoading = sessionLoading || executionsLoading;
582
650
  const loadError = sessionError || executionsError;
583
651
 
@@ -605,9 +673,18 @@ export function useSessionConversation(
605
673
  pendingApprovals,
606
674
  submitApproval,
607
675
  submittingApprovalIds: submittingToolCallIds,
676
+ approvalErrors,
608
677
  approvalError,
609
678
  clearApprovalError,
610
679
 
680
+ fileChangeSets,
681
+ submitFileDecision,
682
+ submittingFileDecisionKeys: submittingDecisionKeys,
683
+ fileDecisionErrors,
684
+ clearFileDecisionError,
685
+ fileReviewError,
686
+ clearFileReviewError,
687
+
611
688
  isStoppable,
612
689
  stop,
613
690
  isStopping: stopActions.isSubmitting,
@@ -0,0 +1,207 @@
1
+ "use client";
2
+
3
+ import { useMemo } from "react";
4
+ import { create } from "@bufbuild/protobuf";
5
+ import type { AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
6
+ import type { FileChange } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
7
+ import { FileChangeSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
8
+ import {
9
+ FileChangeCaptureLevel,
10
+ FileChangeType,
11
+ } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
12
+ import { displayFileChangeSets, toDisplayFileChange } from "@stigmer/sdk";
13
+
14
+ /** Return value of {@link useSessionFileChanges}. */
15
+ export interface UseSessionFileChangesReturn {
16
+ /**
17
+ * One {@link FileChange} per file touched in the session — the *net*
18
+ * change for that path (see the net-diff note below) — ordered for a
19
+ * file-list (modified, then created/renamed, then deleted; alphabetical
20
+ * within each group).
21
+ */
22
+ readonly fileChanges: readonly FileChange[];
23
+ /** `true` when at least one file was changed across all executions. */
24
+ readonly hasFileChanges: boolean;
25
+ /** Number of distinct files changed. */
26
+ readonly fileChangeCount: number;
27
+ }
28
+
29
+ /**
30
+ * Pure derivation hook that aggregates an agent's file changes across every
31
+ * execution in a session into one net change per file. A headless building
32
+ * block for platform builders composing a consolidated session-changes surface
33
+ * (typically paired with {@link FileChangesView}); the Console itself renders
34
+ * file changes in the transcript (stamped edit rows + the per-turn decision
35
+ * bar) and does not consume this hook.
36
+ *
37
+ * **Source (ledger-first).** Under apply-then-review the changes live in the
38
+ * file-review ledger; {@link displayFileChangeSets} reads the server's live
39
+ * projection or folds the durable ledger for a terminal execution (whose
40
+ * projection is nil), and each captured change is projected onto the display
41
+ * {@link FileChange} via {@link toDisplayFileChange}. A pre-capture
42
+ * (legacy) execution has no ledger, so it falls back to the tool-call-coupled
43
+ * `ToolCall.file_changes` (#186; removed in a later slice with that field). The
44
+ * two sources are mutually exclusive per execution, so there is no double count.
45
+ *
46
+ * **Traversal.** The ledger is execution-scoped and already includes sub-agent
47
+ * captures (DD-19), so the primary path is one pass per execution. The legacy
48
+ * fallback walks the same surfaces the server-side approval recompute and
49
+ * `MessageThread` walk: `status.messages[].toolCalls` **and**
50
+ * `status.subAgentExecutions[].messages[].toolCalls`. Executions are visited in
51
+ * chronological order, so each path's change list is chronological.
52
+ *
53
+ * **Net-diff (not latest-wins).** `useSessionWriteBacks`/`useSessionArtifacts`
54
+ * dedup by "latest wins" because each entry is a *snapshot* (a PR; a file's
55
+ * final bytes). A {@link FileChange} is a *delta* — an agent often rewrites the
56
+ * same file several times in a turn, and showing only the last edit's diff
57
+ * would misrepresent what changed. So changes to the same path are reduced to a
58
+ * single net change: `before` from the first change, `after` from the last.
59
+ * Because a WHOLE_FILE `after` is a complete file snapshot, `first.before →
60
+ * last.after` is exactly the net change. A group with one change (the common
61
+ * case) is passed through untouched; multi-edit groups synthesize a net
62
+ * {@link FileChange} so every consumer speaks one proto type (DD-007).
63
+ *
64
+ * Counts and unified diffs for whole-file captures stay derivable by the
65
+ * presentation layer (the runner emits 0/"" sentinels), matching the contract
66
+ * the SDK `tool-view` established.
67
+ *
68
+ * @param executions - All executions for a session, in chronological order.
69
+ * Pass both completed and active-stream executions.
70
+ *
71
+ * @example
72
+ * ```tsx
73
+ * const allExecutions = [
74
+ * ...conv.completedExecutions,
75
+ * ...(conv.activeStreamExecution ? [conv.activeStreamExecution] : []),
76
+ * ];
77
+ * const { fileChanges, hasFileChanges } = useSessionFileChanges(allExecutions);
78
+ * ```
79
+ *
80
+ * @see useSessionWriteBacks — git-mode (PR) counterpart, which does drive the
81
+ * inspector's Changes tab
82
+ * @see useFileChangeContent — resolves a change's before/after text for diffing
83
+ * @see FileChangesView — component that renders this data
84
+ */
85
+ export function useSessionFileChanges(
86
+ executions: readonly AgentExecution[],
87
+ ): UseSessionFileChangesReturn {
88
+ return useMemo(() => {
89
+ // Path -> chronological list of raw changes to that path.
90
+ const groups = new Map<string, FileChange[]>();
91
+ // Preserve first-seen path order as a stable tiebreaker before sorting.
92
+ const collect = (change: FileChange) => {
93
+ const key = change.path || change.absolutePath;
94
+ if (!key) return;
95
+ const list = groups.get(key);
96
+ if (list) list.push(change);
97
+ else groups.set(key, [change]);
98
+ };
99
+
100
+ for (const execution of executions) {
101
+ // The file-review ledger is the single source under apply-then-review: the
102
+ // display seam reads the live projection or folds the durable ledger for a
103
+ // terminal execution, and the execution-scoped ledger already covers
104
+ // sub-agent captures (DD-19), so one pass suffices. Each CapturedFileChange
105
+ // is projected onto the display FileChange the net-collapse + renderer speak.
106
+ const capturedChanges = displayFileChangeSets(execution.status).flatMap(
107
+ (set) => set.changes,
108
+ );
109
+ for (const captured of capturedChanges) collect(toDisplayFileChange(captured));
110
+ }
111
+
112
+ const fileChanges = Array.from(groups.values(), netChange);
113
+ fileChanges.sort(fileChangeComparator);
114
+
115
+ return {
116
+ fileChanges,
117
+ hasFileChanges: fileChanges.length > 0,
118
+ fileChangeCount: fileChanges.length,
119
+ };
120
+ }, [executions]);
121
+ }
122
+
123
+ /**
124
+ * Reduces a path's chronological change list to a single net change.
125
+ * A one-change group is returned as-is (the common path, no allocation);
126
+ * multi-edit groups synthesize a net {@link FileChange}.
127
+ */
128
+ function netChange(changes: FileChange[]): FileChange {
129
+ if (changes.length === 1) return changes[0];
130
+
131
+ const first = changes[0];
132
+ const last = changes[changes.length - 1];
133
+ const changeType = netChangeType(first, last);
134
+
135
+ // Whole-file only when both chosen sides come from whole-file captures;
136
+ // otherwise fall back to the last change's hunk diff. A path edited by a
137
+ // single harness won't mix levels — this just stays honest if it ever does.
138
+ const wholeFile =
139
+ first.captureLevel === FileChangeCaptureLevel.WHOLE_FILE &&
140
+ last.captureLevel === FileChangeCaptureLevel.WHOLE_FILE;
141
+
142
+ if (wholeFile) {
143
+ return create(FileChangeSchema, {
144
+ path: last.path,
145
+ absolutePath: last.absolutePath,
146
+ changeType,
147
+ captureLevel: FileChangeCaptureLevel.WHOLE_FILE,
148
+ before: first.before,
149
+ after: last.after,
150
+ renameFrom: changeType === FileChangeType.RENAME ? first.renameFrom : "",
151
+ });
152
+ }
153
+
154
+ return create(FileChangeSchema, {
155
+ path: last.path,
156
+ absolutePath: last.absolutePath,
157
+ changeType,
158
+ captureLevel: FileChangeCaptureLevel.HUNK_ONLY,
159
+ unifiedDiff: last.unifiedDiff,
160
+ linesAdded: last.linesAdded,
161
+ linesRemoved: last.linesRemoved,
162
+ renameFrom: changeType === FileChangeType.RENAME ? first.renameFrom : "",
163
+ });
164
+ }
165
+
166
+ /**
167
+ * Reconciles the net `change_type` of a path from its first and last change.
168
+ *
169
+ * Intent: the badge should describe the file's journey across the *whole*
170
+ * session, anchored on its two endpoints, in this precedence:
171
+ *
172
+ * 1. Ends deleted (`last` is DELETE) → DELETE. The file is gone, regardless of
173
+ * how it got there — this includes create-then-delete, which we deliberately
174
+ * surface as DELETE rather than hiding the path. (`before` then comes from
175
+ * the first change, which for a created-then-deleted file is empty, so the
176
+ * diff reads as the removal of whatever briefly existed.)
177
+ * 2. Started created (`first` is CREATE) and still exists → CREATE. A file born
178
+ * this session and later modified is, on net, a new file.
179
+ * 3. Started renamed (`first` is RENAME) and still exists → RENAME, carrying the
180
+ * original `rename_from` so the move is preserved across later edits.
181
+ * 4. Otherwise → MODIFY (the common multi-edit case).
182
+ */
183
+ function netChangeType(first: FileChange, last: FileChange): FileChangeType {
184
+ if (last.changeType === FileChangeType.DELETE) return FileChangeType.DELETE;
185
+ if (first.changeType === FileChangeType.CREATE) return FileChangeType.CREATE;
186
+ if (first.changeType === FileChangeType.RENAME) return FileChangeType.RENAME;
187
+ return FileChangeType.MODIFY;
188
+ }
189
+
190
+ // Most-actionable first (modified), then additions (create/rename), then
191
+ // deletions — mirroring GitHub's file-list convention — alphabetical within
192
+ // each group so the list is stable and scannable.
193
+ const CHANGE_TYPE_ORDER: Readonly<Record<FileChangeType, number>> = {
194
+ [FileChangeType.MODIFY]: 0,
195
+ [FileChangeType.CREATE]: 1,
196
+ [FileChangeType.RENAME]: 1,
197
+ [FileChangeType.DELETE]: 2,
198
+ [FileChangeType.UNSPECIFIED]: 3,
199
+ };
200
+
201
+ function fileChangeComparator(a: FileChange, b: FileChange): number {
202
+ const order =
203
+ (CHANGE_TYPE_ORDER[a.changeType] ?? 3) -
204
+ (CHANGE_TYPE_ORDER[b.changeType] ?? 3);
205
+ if (order !== 0) return order;
206
+ return a.path.localeCompare(b.path, undefined, { sensitivity: "base" });
207
+ }
package/src/styles.css CHANGED
@@ -1,7 +1,21 @@
1
1
  @source "./**/*.{ts,tsx}";
2
2
  @source "../node_modules/streamdown/dist/*.js";
3
3
 
4
- @layer stgm;
4
+ /* Declare the standard Tailwind layer order plus our `stgm` utilities layer
5
+ LAST. In a host app the host's `@import "tailwindcss"` already declares
6
+ `theme, base, components, utilities` first, so re-stating them here is a
7
+ harmless no-op that simply pins `stgm` after them; in the standalone SDK build
8
+ it establishes the full order explicitly.
9
+
10
+ Why this matters: the preflight-style reset below (which zeroes `border-width`)
11
+ MUST live in `base`, not in a layer above `utilities`. When this stylesheet is
12
+ recompiled by a host's Tailwind v4, the SDK's `border-*` utilities are emitted
13
+ into the host's `utilities` layer (Tailwind v4 emits each utility once) — NOT
14
+ into `stgm`. A reset placed in any layer after `utilities` therefore wins and
15
+ silently zeroes every `border` inside `.stgm`. Keeping the reset in `base`
16
+ (exactly where stock Tailwind keeps preflight) guarantees the utilities win in
17
+ the host build, the standalone build, and a third-party embed alike. */
18
+ @layer theme, base, components, utilities, stgm;
5
19
 
6
20
  @import "tailwindcss/theme.css" layer(stgm);
7
21
  @import "tailwindcss/utilities.css" layer(stgm);
@@ -66,6 +80,7 @@
66
80
  --color-muted-foreground-subtle: var(--stgm-muted-foreground-subtle);
67
81
  --color-muted-foreground-faint: var(--stgm-muted-foreground-faint);
68
82
  --color-border-muted: var(--stgm-border-muted);
83
+ --color-border-prominent: var(--stgm-border-prominent);
69
84
  --color-backdrop: var(--stgm-backdrop);
70
85
  --color-sidebar: var(--stgm-sidebar);
71
86
  --color-sidebar-foreground: var(--stgm-sidebar-foreground);
@@ -115,15 +130,15 @@
115
130
  z-index: var(--stgm-z-popover);
116
131
  }
117
132
 
118
- @layer stgm {
119
- .stgm {
120
- --stgm-motion-duration: 150ms;
121
- --stgm-motion-easing: var(--stgm-transition-timing, ease-out);
122
- line-height: 1.5;
123
- -webkit-font-smoothing: antialiased;
124
- -moz-osx-font-smoothing: grayscale;
125
- }
126
-
133
+ /* Preflight-style reset, scoped to `.stgm`. Lives in the standard `base` layer —
134
+ exactly where stock Tailwind keeps its preflight — so it ranks BELOW the
135
+ `utilities` layer where `border-*` utilities are emitted (see the layer
136
+ declaration at the top of this file). It supplies only the DEFAULTS
137
+ (`border-style: solid`, width 0, themed color) that a `border` utility then
138
+ builds on; because `utilities` outranks `base`, the utility's width always
139
+ wins. Putting this in a layer after `utilities` (the previous `stgm-base`) is
140
+ what silently zeroed every border inside `.stgm`. */
141
+ @layer base {
127
142
  .stgm *,
128
143
  .stgm *::before,
129
144
  .stgm *::after {
@@ -132,6 +147,16 @@
132
147
  border-style: solid;
133
148
  border-color: var(--stgm-border, currentColor);
134
149
  }
150
+ }
151
+
152
+ @layer stgm {
153
+ .stgm {
154
+ --stgm-motion-duration: 150ms;
155
+ --stgm-motion-easing: var(--stgm-transition-timing, ease-out);
156
+ line-height: 1.5;
157
+ -webkit-font-smoothing: antialiased;
158
+ -moz-osx-font-smoothing: grayscale;
159
+ }
135
160
 
136
161
  @keyframes stgm-fade-in-up {
137
162
  from {
@@ -186,3 +211,91 @@
186
211
  }
187
212
  }
188
213
  }
214
+
215
+ @layer stgm {
216
+ /* Syntax highlighting for fenced code blocks (issue #183).
217
+ lowlight (highlight.js) emits these `hljs-*` token classes; we map each
218
+ onto a shared `--stgm-syntax-*` theme token so highlighted code tracks the
219
+ host's preset and color-mode with zero hardcoded colors — the same token
220
+ contract the CodeMirror YAML editor uses. Scoped to `.stgm` so nothing
221
+ leaks into the host application. */
222
+ .stgm .hljs {
223
+ color: var(--stgm-foreground);
224
+ }
225
+
226
+ .stgm .hljs-comment,
227
+ .stgm .hljs-quote {
228
+ color: var(--stgm-syntax-comment);
229
+ font-style: italic;
230
+ }
231
+
232
+ .stgm .hljs-keyword,
233
+ .stgm .hljs-selector-tag,
234
+ .stgm .hljs-subst {
235
+ color: var(--stgm-syntax-keyword);
236
+ }
237
+
238
+ .stgm .hljs-literal,
239
+ .stgm .hljs-symbol,
240
+ .stgm .hljs-bullet {
241
+ color: var(--stgm-syntax-bool);
242
+ }
243
+
244
+ .stgm .hljs-string,
245
+ .stgm .hljs-regexp,
246
+ .stgm .hljs-addition,
247
+ .stgm .hljs-template-tag,
248
+ .stgm .hljs-template-variable,
249
+ .stgm .hljs-meta .hljs-string {
250
+ color: var(--stgm-syntax-string);
251
+ }
252
+
253
+ .stgm .hljs-number {
254
+ color: var(--stgm-syntax-number);
255
+ }
256
+
257
+ .stgm .hljs-title,
258
+ .stgm .hljs-title.function_,
259
+ .stgm .hljs-title.class_,
260
+ .stgm .hljs-section,
261
+ .stgm .hljs-built_in,
262
+ .stgm .hljs-type {
263
+ color: var(--stgm-syntax-property);
264
+ }
265
+
266
+ .stgm .hljs-attr,
267
+ .stgm .hljs-attribute,
268
+ .stgm .hljs-property,
269
+ .stgm .hljs-variable,
270
+ .stgm .hljs-params,
271
+ .stgm .hljs-selector-attr,
272
+ .stgm .hljs-selector-pseudo,
273
+ .stgm .hljs-selector-class,
274
+ .stgm .hljs-selector-id {
275
+ color: var(--stgm-syntax-property);
276
+ }
277
+
278
+ .stgm .hljs-tag,
279
+ .stgm .hljs-name {
280
+ color: var(--stgm-syntax-tag);
281
+ }
282
+
283
+ .stgm .hljs-meta,
284
+ .stgm .hljs-meta .hljs-keyword,
285
+ .stgm .hljs-doctag {
286
+ color: var(--stgm-syntax-meta);
287
+ }
288
+
289
+ .stgm .hljs-link,
290
+ .stgm .hljs-deletion {
291
+ color: var(--stgm-syntax-atom);
292
+ }
293
+
294
+ .stgm .hljs-emphasis {
295
+ font-style: italic;
296
+ }
297
+
298
+ .stgm .hljs-strong {
299
+ font-weight: 600;
300
+ }
301
+ }
@@ -63,8 +63,7 @@ export function DiffViewer({ hunks, filePath, className }: DiffViewerProps) {
63
63
  <table className="w-full border-collapse" role="table">
64
64
  <thead className="sr-only">
65
65
  <tr>
66
- <th scope="col">Old line</th>
67
- <th scope="col">New line</th>
66
+ <th scope="col">Line</th>
68
67
  <th scope="col">Change</th>
69
68
  <th scope="col">Content</th>
70
69
  </tr>
@@ -97,7 +96,7 @@ function HunkRows({
97
96
  {!isFirst && (
98
97
  <tr>
99
98
  <td
100
- colSpan={4}
99
+ colSpan={3}
101
100
  className="select-none bg-diff-hunk-header-bg px-3 py-1 text-[11px] text-diff-hunk-header-fg"
102
101
  aria-label={`Hunk: ${header}`}
103
102
  >
@@ -144,13 +143,17 @@ function DiffLineRow({ line }: { readonly line: DiffLine }) {
144
143
  ? `Removed line ${line.oldLineNumber}: ${line.content}`
145
144
  : undefined;
146
145
 
146
+ // A single line-number gutter — the Cursor/VS Code inline-diff convention,
147
+ // more compact than GitHub's old+new pair. Each line shows the number from the
148
+ // side it belongs to: the new-file number for added/context lines, the
149
+ // old-file number for a removed line (which has no new-side number). The
150
+ // marker (+/-) and row color carry the change type.
151
+ const lineNumber = line.newLineNumber ?? line.oldLineNumber;
152
+
147
153
  return (
148
154
  <tr className={rowClass} aria-label={ariaLabel}>
149
155
  <td className={LINE_NUM_CLASSES}>
150
- {line.oldLineNumber ?? ""}
151
- </td>
152
- <td className={LINE_NUM_CLASSES}>
153
- {line.newLineNumber ?? ""}
156
+ {lineNumber ?? ""}
154
157
  </td>
155
158
  <td className={cn(MARKER_CLASSES, markerColor)} aria-hidden="true">
156
159
  {marker}