@stigmer/react 3.1.1 → 3.1.3

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 (483) hide show
  1. package/composer/SessionComposer.d.ts +25 -1
  2. package/composer/SessionComposer.d.ts.map +1 -1
  3. package/composer/SessionComposer.js +19 -8
  4. package/composer/SessionComposer.js.map +1 -1
  5. package/execution/ArtifactContentRenderer.d.ts +11 -1
  6. package/execution/ArtifactContentRenderer.d.ts.map +1 -1
  7. package/execution/ArtifactContentRenderer.js +39 -15
  8. package/execution/ArtifactContentRenderer.js.map +1 -1
  9. package/execution/ArtifactPreviewModal.d.ts +5 -5
  10. package/execution/ArtifactPreviewModal.js +4 -4
  11. package/execution/ArtifactPreviewModal.js.map +1 -1
  12. package/execution/FileChangeProgressBar.d.ts +47 -0
  13. package/execution/FileChangeProgressBar.d.ts.map +1 -0
  14. package/execution/FileChangeProgressBar.js +49 -0
  15. package/execution/FileChangeProgressBar.js.map +1 -0
  16. package/execution/FileChangesView.d.ts.map +1 -1
  17. package/execution/FileChangesView.js +19 -4
  18. package/execution/FileChangesView.js.map +1 -1
  19. package/execution/FilePathContext.d.ts +8 -1
  20. package/execution/FilePathContext.d.ts.map +1 -1
  21. package/execution/FilePathContext.js.map +1 -1
  22. package/execution/FilePathLink.d.ts.map +1 -1
  23. package/execution/FilePathLink.js +21 -6
  24. package/execution/FilePathLink.js.map +1 -1
  25. package/execution/FileReviewAtoms.d.ts +27 -0
  26. package/execution/FileReviewAtoms.d.ts.map +1 -0
  27. package/execution/FileReviewAtoms.js +64 -0
  28. package/execution/FileReviewAtoms.js.map +1 -0
  29. package/execution/FileReviewCard.d.ts +2 -2
  30. package/execution/FileReviewCard.d.ts.map +1 -1
  31. package/execution/FileReviewCard.js +32 -62
  32. package/execution/FileReviewCard.js.map +1 -1
  33. package/execution/MessageEntry.d.ts +20 -0
  34. package/execution/MessageEntry.d.ts.map +1 -1
  35. package/execution/MessageEntry.js +19 -5
  36. package/execution/MessageEntry.js.map +1 -1
  37. package/execution/MessageThread.d.ts +75 -13
  38. package/execution/MessageThread.d.ts.map +1 -1
  39. package/execution/MessageThread.js +195 -27
  40. package/execution/MessageThread.js.map +1 -1
  41. package/execution/PlanArtifactCard.d.ts +36 -21
  42. package/execution/PlanArtifactCard.d.ts.map +1 -1
  43. package/execution/PlanArtifactCard.js +39 -25
  44. package/execution/PlanArtifactCard.js.map +1 -1
  45. package/execution/PlanCompletionCard.d.ts +4 -4
  46. package/execution/PlanCompletionCard.d.ts.map +1 -1
  47. package/execution/PlanCompletionCard.js +4 -4
  48. package/execution/PlanCompletionCard.js.map +1 -1
  49. package/execution/PlanDocumentMessage.d.ts +32 -0
  50. package/execution/PlanDocumentMessage.d.ts.map +1 -0
  51. package/execution/PlanDocumentMessage.js +37 -0
  52. package/execution/PlanDocumentMessage.js.map +1 -0
  53. package/execution/PlanStreamingCard.d.ts +50 -0
  54. package/execution/PlanStreamingCard.d.ts.map +1 -0
  55. package/execution/PlanStreamingCard.js +40 -0
  56. package/execution/PlanStreamingCard.js.map +1 -0
  57. package/execution/index.d.ts +9 -1
  58. package/execution/index.d.ts.map +1 -1
  59. package/execution/index.js +4 -0
  60. package/execution/index.js.map +1 -1
  61. package/execution/use-build-from-plan-hotkey.d.ts +1 -1
  62. package/execution/use-build-from-plan-hotkey.js +1 -1
  63. package/execution/useArtifactCopy.d.ts +51 -0
  64. package/execution/useArtifactCopy.d.ts.map +1 -0
  65. package/execution/useArtifactCopy.js +75 -0
  66. package/execution/useArtifactCopy.js.map +1 -0
  67. package/execution/useArtifactDownload.d.ts.map +1 -1
  68. package/execution/useArtifactDownload.js +17 -5
  69. package/execution/useArtifactDownload.js.map +1 -1
  70. package/execution/useCreateAgentExecution.d.ts +12 -0
  71. package/execution/useCreateAgentExecution.d.ts.map +1 -1
  72. package/execution/useCreateAgentExecution.js +5 -1
  73. package/execution/useCreateAgentExecution.js.map +1 -1
  74. package/github/decodeGitHubContent.d.ts +29 -0
  75. package/github/decodeGitHubContent.d.ts.map +1 -0
  76. package/github/decodeGitHubContent.js +72 -0
  77. package/github/decodeGitHubContent.js.map +1 -0
  78. package/github/index.d.ts +1 -0
  79. package/github/index.d.ts.map +1 -1
  80. package/github/index.js +1 -0
  81. package/github/index.js.map +1 -1
  82. package/github/useGitHubFileReader.d.ts +26 -0
  83. package/github/useGitHubFileReader.d.ts.map +1 -0
  84. package/github/useGitHubFileReader.js +106 -0
  85. package/github/useGitHubFileReader.js.map +1 -0
  86. package/github/useGitHubTreeLister.d.ts.map +1 -1
  87. package/github/useGitHubTreeLister.js +6 -2
  88. package/github/useGitHubTreeLister.js.map +1 -1
  89. package/index.d.ts +9 -9
  90. package/index.d.ts.map +1 -1
  91. package/index.js +5 -5
  92. package/index.js.map +1 -1
  93. package/internal/ResizableSplit.d.ts +72 -22
  94. package/internal/ResizableSplit.d.ts.map +1 -1
  95. package/internal/ResizableSplit.js +96 -38
  96. package/internal/ResizableSplit.js.map +1 -1
  97. package/internal/VirtualizedThread.d.ts +5 -3
  98. package/internal/VirtualizedThread.d.ts.map +1 -1
  99. package/internal/VirtualizedThread.js +6 -4
  100. package/internal/VirtualizedThread.js.map +1 -1
  101. package/internal/file-icons/index.d.ts +17 -0
  102. package/internal/file-icons/index.d.ts.map +1 -0
  103. package/internal/file-icons/index.js +60 -0
  104. package/internal/file-icons/index.js.map +1 -0
  105. package/internal/file-tree/FileTreeNode.d.ts +18 -1
  106. package/internal/file-tree/FileTreeNode.d.ts.map +1 -1
  107. package/internal/file-tree/FileTreeNode.js +11 -2
  108. package/internal/file-tree/FileTreeNode.js.map +1 -1
  109. package/internal/markdown-components.d.ts +38 -1
  110. package/internal/markdown-components.d.ts.map +1 -1
  111. package/internal/markdown-components.js +86 -11
  112. package/internal/markdown-components.js.map +1 -1
  113. package/{workflow → internal}/motion-preference.d.ts +7 -4
  114. package/internal/motion-preference.d.ts.map +1 -0
  115. package/{workflow → internal}/motion-preference.js +7 -4
  116. package/internal/motion-preference.js.map +1 -0
  117. package/internal/store/index.d.ts +33 -0
  118. package/internal/store/index.d.ts.map +1 -1
  119. package/internal/store/index.js +59 -0
  120. package/internal/store/index.js.map +1 -1
  121. package/internal/store/workspace-editors-store.d.ts +145 -0
  122. package/internal/store/workspace-editors-store.d.ts.map +1 -0
  123. package/internal/store/workspace-editors-store.js +208 -0
  124. package/internal/store/workspace-editors-store.js.map +1 -0
  125. package/internal/store/workspace-file-selection-store.d.ts +38 -0
  126. package/internal/store/workspace-file-selection-store.d.ts.map +1 -0
  127. package/internal/store/workspace-file-selection-store.js +62 -0
  128. package/internal/store/workspace-file-selection-store.js.map +1 -0
  129. package/internal/useRevealLine.d.ts +49 -0
  130. package/internal/useRevealLine.d.ts.map +1 -0
  131. package/internal/useRevealLine.js +43 -0
  132. package/internal/useRevealLine.js.map +1 -0
  133. package/library/detect-plan-artifact.d.ts +43 -4
  134. package/library/detect-plan-artifact.d.ts.map +1 -1
  135. package/library/detect-plan-artifact.js +45 -5
  136. package/library/detect-plan-artifact.js.map +1 -1
  137. package/library/detect-streaming-plan.d.ts +45 -0
  138. package/library/detect-streaming-plan.d.ts.map +1 -0
  139. package/library/detect-streaming-plan.js +83 -0
  140. package/library/detect-streaming-plan.js.map +1 -0
  141. package/library/index.d.ts +4 -1
  142. package/library/index.d.ts.map +1 -1
  143. package/library/index.js +2 -1
  144. package/library/index.js.map +1 -1
  145. package/package.json +4 -4
  146. package/session/NewSessionViewer.d.ts +19 -4
  147. package/session/NewSessionViewer.d.ts.map +1 -1
  148. package/session/NewSessionViewer.js +52 -25
  149. package/session/NewSessionViewer.js.map +1 -1
  150. package/session/PlanEditor.d.ts +55 -0
  151. package/session/PlanEditor.d.ts.map +1 -0
  152. package/session/PlanEditor.js +88 -0
  153. package/session/PlanEditor.js.map +1 -0
  154. package/session/PlanStreamingDocument.d.ts +30 -0
  155. package/session/PlanStreamingDocument.d.ts.map +1 -0
  156. package/session/PlanStreamingDocument.js +37 -0
  157. package/session/PlanStreamingDocument.js.map +1 -0
  158. package/session/SessionPanelChip.d.ts +26 -0
  159. package/session/SessionPanelChip.d.ts.map +1 -0
  160. package/session/SessionPanelChip.js +40 -0
  161. package/session/SessionPanelChip.js.map +1 -0
  162. package/session/SessionViewer.d.ts +34 -7
  163. package/session/SessionViewer.d.ts.map +1 -1
  164. package/session/SessionViewer.js +334 -33
  165. package/session/SessionViewer.js.map +1 -1
  166. package/session/{inspector → facets}/ArtifactsTab.d.ts +10 -2
  167. package/session/facets/ArtifactsTab.d.ts.map +1 -0
  168. package/session/{inspector → facets}/ArtifactsTab.js +8 -3
  169. package/session/facets/ArtifactsTab.js.map +1 -0
  170. package/session/{inspector → facets}/ChangesTab.d.ts +3 -3
  171. package/session/facets/ChangesTab.d.ts.map +1 -0
  172. package/session/{inspector → facets}/ChangesTab.js +3 -3
  173. package/session/facets/ChangesTab.js.map +1 -0
  174. package/session/facets/InspectTab.d.ts.map +1 -0
  175. package/session/facets/InspectTab.js.map +1 -0
  176. package/session/{inspector → facets}/SetupTab.d.ts +11 -2
  177. package/session/facets/SetupTab.d.ts.map +1 -0
  178. package/session/{inspector → facets}/SetupTab.js +4 -3
  179. package/session/facets/SetupTab.js.map +1 -0
  180. package/session/{inspector → facets}/UsageTab.d.ts +1 -1
  181. package/session/facets/UsageTab.d.ts.map +1 -0
  182. package/session/{inspector → facets}/UsageTab.js +1 -1
  183. package/session/facets/UsageTab.js.map +1 -0
  184. package/session/{inspector → facets}/index.d.ts +0 -6
  185. package/session/facets/index.d.ts.map +1 -0
  186. package/session/{inspector → facets}/index.js +0 -3
  187. package/session/facets/index.js.map +1 -0
  188. package/session/index.d.ts +11 -2
  189. package/session/index.d.ts.map +1 -1
  190. package/session/index.js +15 -2
  191. package/session/index.js.map +1 -1
  192. package/session/plan-document.d.ts +21 -0
  193. package/session/plan-document.d.ts.map +1 -0
  194. package/session/plan-document.js +28 -0
  195. package/session/plan-document.js.map +1 -0
  196. package/session/useOpenFileChange.d.ts +20 -0
  197. package/session/useOpenFileChange.d.ts.map +1 -0
  198. package/session/useOpenFileChange.js +31 -0
  199. package/session/useOpenFileChange.js.map +1 -0
  200. package/session/usePlanDraft.d.ts +52 -0
  201. package/session/usePlanDraft.d.ts.map +1 -0
  202. package/session/usePlanDraft.js +63 -0
  203. package/session/usePlanDraft.js.map +1 -0
  204. package/session/useSessionConversation.d.ts +14 -1
  205. package/session/useSessionConversation.d.ts.map +1 -1
  206. package/session/useSessionConversation.js +20 -2
  207. package/session/useSessionConversation.js.map +1 -1
  208. package/session/useSessionPageFlow.d.ts.map +1 -1
  209. package/session/useSessionPageFlow.js +1 -0
  210. package/session/useSessionPageFlow.js.map +1 -1
  211. package/session/useSessionPanel.d.ts +120 -0
  212. package/session/useSessionPanel.d.ts.map +1 -0
  213. package/session/useSessionPanel.js +130 -0
  214. package/session/useSessionPanel.js.map +1 -0
  215. package/session/useSessionRailViews.d.ts +45 -0
  216. package/session/useSessionRailViews.d.ts.map +1 -0
  217. package/session/useSessionRailViews.js +105 -0
  218. package/session/useSessionRailViews.js.map +1 -0
  219. package/src/composer/SessionComposer.tsx +53 -10
  220. package/src/composer/__tests__/SessionComposer-contract.test.tsx +58 -4
  221. package/src/execution/ArtifactContentRenderer.tsx +101 -24
  222. package/src/execution/ArtifactPreviewModal.tsx +9 -9
  223. package/src/execution/FileChangeProgressBar.tsx +121 -0
  224. package/src/execution/FileChangesView.tsx +18 -4
  225. package/src/execution/FilePathContext.tsx +8 -1
  226. package/src/execution/FilePathLink.tsx +22 -6
  227. package/src/execution/FileReviewAtoms.tsx +89 -0
  228. package/src/execution/FileReviewCard.tsx +57 -90
  229. package/src/execution/MessageEntry.tsx +49 -1
  230. package/src/execution/MessageThread.tsx +308 -39
  231. package/src/execution/PlanArtifactCard.tsx +174 -64
  232. package/src/execution/PlanCompletionCard.tsx +5 -5
  233. package/src/execution/PlanDocumentMessage.tsx +96 -0
  234. package/src/execution/PlanStreamingCard.tsx +141 -0
  235. package/src/execution/__tests__/ArtifactContentRenderer.test.tsx +80 -1
  236. package/src/execution/__tests__/ArtifactPreviewModal.test.tsx +6 -6
  237. package/src/execution/__tests__/FileChangeProgressBar.test.tsx +125 -0
  238. package/src/execution/__tests__/FilePathLink.test.tsx +87 -0
  239. package/src/execution/__tests__/FileReviewCard.test.tsx +66 -7
  240. package/src/execution/__tests__/MessageThread.test.tsx +102 -1
  241. package/src/execution/__tests__/PlanArtifactCard.test.tsx +114 -26
  242. package/src/execution/__tests__/PlanCompletionCard.test.tsx +2 -2
  243. package/src/execution/__tests__/PlanDocumentMessage.test.tsx +55 -0
  244. package/src/execution/__tests__/PlanStreamingCard.test.tsx +56 -0
  245. package/src/execution/__tests__/buildThreadItems-plan-completion.test.ts +600 -22
  246. package/src/execution/__tests__/message-entry.test.tsx +17 -0
  247. package/src/execution/__tests__/useArtifactCopy.test.tsx +90 -0
  248. package/src/execution/__tests__/useArtifactDownload.test.tsx +2 -0
  249. package/src/execution/__tests__/useCreateAgentExecution.test.tsx +85 -0
  250. package/src/execution/index.ts +13 -1
  251. package/src/execution/use-build-from-plan-hotkey.ts +1 -1
  252. package/src/execution/useArtifactCopy.ts +109 -0
  253. package/src/execution/useArtifactDownload.ts +17 -5
  254. package/src/execution/useCreateAgentExecution.ts +18 -1
  255. package/src/github/__tests__/decodeGitHubContent.test.ts +102 -0
  256. package/src/github/__tests__/useGitHubFileReader.test.ts +183 -0
  257. package/src/github/decodeGitHubContent.ts +83 -0
  258. package/src/github/index.ts +1 -0
  259. package/src/github/useGitHubFileReader.ts +152 -0
  260. package/src/github/useGitHubTreeLister.ts +6 -2
  261. package/src/index.ts +69 -9
  262. package/src/internal/ResizableSplit.tsx +184 -51
  263. package/src/internal/VirtualizedThread.tsx +12 -4
  264. package/src/internal/__tests__/ResizableSplit.test.tsx +125 -3
  265. package/src/internal/__tests__/markdown-components.test.tsx +68 -0
  266. package/src/internal/__tests__/useRevealLine.test.tsx +97 -0
  267. package/src/internal/file-icons/__tests__/file-icons.test.tsx +35 -0
  268. package/src/internal/file-icons/index.tsx +137 -0
  269. package/src/internal/file-tree/FileTreeNode.tsx +56 -5
  270. package/src/internal/file-tree/__tests__/FileTreeNode-explorer.test.tsx +86 -0
  271. package/src/internal/markdown-components.tsx +116 -11
  272. package/src/{workflow → internal}/motion-preference.ts +7 -4
  273. package/src/internal/store/__tests__/workspace-editors-store.test.ts +216 -0
  274. package/src/internal/store/__tests__/workspace-file-selection-store.test.ts +118 -0
  275. package/src/internal/store/index.ts +94 -0
  276. package/src/internal/store/workspace-editors-store.ts +315 -0
  277. package/src/internal/store/workspace-file-selection-store.ts +88 -0
  278. package/src/internal/useRevealLine.ts +81 -0
  279. package/src/library/__tests__/detect-plan-artifact.test.ts +69 -0
  280. package/src/library/__tests__/detect-streaming-plan.test.ts +234 -0
  281. package/src/library/detect-plan-artifact.ts +62 -5
  282. package/src/library/detect-streaming-plan.ts +108 -0
  283. package/src/library/index.ts +7 -0
  284. package/src/session/NewSessionViewer.tsx +123 -55
  285. package/src/session/PlanEditor.tsx +361 -0
  286. package/src/session/PlanStreamingDocument.tsx +97 -0
  287. package/src/session/SessionPanelChip.tsx +103 -0
  288. package/src/session/SessionViewer.tsx +655 -96
  289. package/src/session/__tests__/NewSessionViewer.test.tsx +148 -0
  290. package/src/session/__tests__/PlanEditor.test.tsx +217 -0
  291. package/src/session/__tests__/PlanStreamingDocument.test.tsx +50 -0
  292. package/src/session/__tests__/SessionPanelChip.test.tsx +42 -0
  293. package/src/session/__tests__/SessionViewer-fileReviewDock.test.tsx +66 -4
  294. package/src/session/__tests__/SessionViewer-transcriptFileOpen.test.tsx +205 -0
  295. package/src/session/__tests__/audienceWiring.test.tsx +55 -19
  296. package/src/session/__tests__/useOpenFileChange.test.tsx +82 -0
  297. package/src/session/__tests__/usePlanDraft.test.ts +102 -0
  298. package/src/session/__tests__/useSessionConversation.test.tsx +44 -0
  299. package/src/session/__tests__/useSessionPanel.test.ts +298 -0
  300. package/src/session/__tests__/useSessionRailViews.test.tsx +124 -0
  301. package/src/session/{inspector → facets}/ArtifactsTab.tsx +27 -5
  302. package/src/session/{inspector → facets}/ChangesTab.tsx +3 -3
  303. package/src/session/{inspector → facets}/SetupTab.tsx +13 -1
  304. package/src/session/{inspector → facets}/UsageTab.tsx +1 -1
  305. package/src/session/{inspector → facets}/__tests__/ArtifactsTab.test.tsx +42 -8
  306. package/src/session/facets/__tests__/SetupTab.test.tsx +44 -0
  307. package/src/session/{inspector → facets}/index.ts +0 -16
  308. package/src/session/index.ts +30 -13
  309. package/src/session/plan-document.ts +30 -0
  310. package/src/session/useOpenFileChange.ts +53 -0
  311. package/src/session/usePlanDraft.ts +109 -0
  312. package/src/session/useSessionConversation.ts +38 -3
  313. package/src/session/useSessionPageFlow.ts +1 -0
  314. package/src/session/useSessionPanel.ts +288 -0
  315. package/src/session/useSessionRailViews.tsx +200 -0
  316. package/src/workflow/WorkflowExecutionGraph.tsx +1 -1
  317. package/src/workflow/index.ts +1 -1
  318. package/src/workflow/useFollowExecution.ts +1 -1
  319. package/src/workspace/EditorTabs.tsx +174 -0
  320. package/src/workspace/ExplorerTree.tsx +253 -0
  321. package/src/workspace/FileViewer.tsx +537 -0
  322. package/src/workspace/WorkspaceContentSearch.tsx +502 -0
  323. package/src/workspace/WorkspaceContentSearcher.ts +70 -0
  324. package/src/workspace/WorkspaceEditor.tsx +19 -16
  325. package/src/workspace/WorkspaceFileLister.ts +11 -0
  326. package/src/workspace/WorkspaceFileReader.ts +57 -0
  327. package/src/workspace/WorkspaceFileSearch.tsx +452 -0
  328. package/src/workspace/WorkspaceSurface.tsx +839 -0
  329. package/src/workspace/__tests__/EditorTabs.test.tsx +102 -0
  330. package/src/workspace/__tests__/ExplorerTree.test.tsx +204 -0
  331. package/src/workspace/__tests__/FileViewer.test.tsx +439 -0
  332. package/src/workspace/__tests__/WorkspaceContentSearch.test.tsx +229 -0
  333. package/src/workspace/__tests__/WorkspaceEditor-initialPanel.test.tsx +19 -0
  334. package/src/workspace/__tests__/WorkspaceFileSearch.test.tsx +227 -0
  335. package/src/workspace/__tests__/WorkspaceSurface.test.tsx +418 -0
  336. package/src/workspace/__tests__/a11y/harness.tsx +140 -0
  337. package/src/workspace/__tests__/a11y/mock-capabilities.ts +138 -0
  338. package/src/workspace/__tests__/a11y/workspace-editor.a11y.test.tsx +65 -0
  339. package/src/workspace/__tests__/a11y/workspace-explorer-search.a11y.test.tsx +112 -0
  340. package/src/workspace/__tests__/a11y/workspace-viewer-tabs.a11y.test.tsx +69 -0
  341. package/src/workspace/__tests__/findChangeForSelection.test.ts +132 -0
  342. package/src/workspace/__tests__/matchContentPreview.test.ts +55 -0
  343. package/src/workspace/__tests__/matchWorkspaceFiles.test.ts +104 -0
  344. package/src/workspace/__tests__/resolveWorkspaceFileSelection.test.ts +135 -0
  345. package/src/workspace/__tests__/useWorkspaceContentSearch.test.tsx +196 -0
  346. package/src/workspace/__tests__/useWorkspaceFileContent.test.tsx +190 -0
  347. package/src/workspace/__tests__/useWorkspaceFileSearch.test.tsx +162 -0
  348. package/src/workspace/findChangeForSelection.ts +61 -0
  349. package/src/workspace/index.ts +56 -2
  350. package/src/workspace/matchContentPreview.ts +51 -0
  351. package/src/workspace/matchWorkspaceFiles.ts +86 -0
  352. package/src/workspace/resolveWorkspaceFileSelection.ts +119 -0
  353. package/src/workspace/useWorkspaceContentSearch.ts +228 -0
  354. package/src/workspace/useWorkspaceFileContent.ts +129 -0
  355. package/src/workspace/useWorkspaceFileSearch.ts +184 -0
  356. package/src/workspace/useWorkspaceFiles.ts +27 -27
  357. package/src/workspace/workspaceListingCache.ts +93 -0
  358. package/styles.css +1 -1
  359. package/workflow/WorkflowExecutionGraph.js +1 -1
  360. package/workflow/WorkflowExecutionGraph.js.map +1 -1
  361. package/workflow/index.d.ts +1 -1
  362. package/workflow/index.d.ts.map +1 -1
  363. package/workflow/index.js +1 -1
  364. package/workflow/index.js.map +1 -1
  365. package/workflow/useFollowExecution.js +1 -1
  366. package/workflow/useFollowExecution.js.map +1 -1
  367. package/workspace/EditorTabs.d.ts +47 -0
  368. package/workspace/EditorTabs.d.ts.map +1 -0
  369. package/workspace/EditorTabs.js +78 -0
  370. package/workspace/EditorTabs.js.map +1 -0
  371. package/workspace/ExplorerTree.d.ts +32 -0
  372. package/workspace/ExplorerTree.d.ts.map +1 -0
  373. package/workspace/ExplorerTree.js +49 -0
  374. package/workspace/ExplorerTree.js.map +1 -0
  375. package/workspace/FileViewer.d.ts +93 -0
  376. package/workspace/FileViewer.d.ts.map +1 -0
  377. package/workspace/FileViewer.js +193 -0
  378. package/workspace/FileViewer.js.map +1 -0
  379. package/workspace/WorkspaceContentSearch.d.ts +41 -0
  380. package/workspace/WorkspaceContentSearch.d.ts.map +1 -0
  381. package/workspace/WorkspaceContentSearch.js +216 -0
  382. package/workspace/WorkspaceContentSearch.js.map +1 -0
  383. package/workspace/WorkspaceContentSearcher.d.ts +59 -0
  384. package/workspace/WorkspaceContentSearcher.d.ts.map +1 -0
  385. package/workspace/WorkspaceContentSearcher.js +7 -0
  386. package/workspace/WorkspaceContentSearcher.js.map +1 -0
  387. package/workspace/WorkspaceEditor.d.ts.map +1 -1
  388. package/workspace/WorkspaceEditor.js +8 -10
  389. package/workspace/WorkspaceEditor.js.map +1 -1
  390. package/workspace/WorkspaceFileLister.d.ts +11 -0
  391. package/workspace/WorkspaceFileLister.d.ts.map +1 -1
  392. package/workspace/WorkspaceFileReader.d.ts +48 -0
  393. package/workspace/WorkspaceFileReader.d.ts.map +1 -0
  394. package/workspace/WorkspaceFileReader.js +11 -0
  395. package/workspace/WorkspaceFileReader.js.map +1 -0
  396. package/workspace/WorkspaceFileSearch.d.ts +32 -0
  397. package/workspace/WorkspaceFileSearch.d.ts.map +1 -0
  398. package/workspace/WorkspaceFileSearch.js +175 -0
  399. package/workspace/WorkspaceFileSearch.js.map +1 -0
  400. package/workspace/WorkspaceSurface.d.ts +151 -0
  401. package/workspace/WorkspaceSurface.d.ts.map +1 -0
  402. package/workspace/WorkspaceSurface.js +220 -0
  403. package/workspace/WorkspaceSurface.js.map +1 -0
  404. package/workspace/findChangeForSelection.d.ts +19 -0
  405. package/workspace/findChangeForSelection.d.ts.map +1 -0
  406. package/workspace/findChangeForSelection.js +46 -0
  407. package/workspace/findChangeForSelection.js.map +1 -0
  408. package/workspace/index.d.ts +24 -2
  409. package/workspace/index.d.ts.map +1 -1
  410. package/workspace/index.js +13 -1
  411. package/workspace/index.js.map +1 -1
  412. package/workspace/matchContentPreview.d.ts +21 -0
  413. package/workspace/matchContentPreview.d.ts.map +1 -0
  414. package/workspace/matchContentPreview.js +36 -0
  415. package/workspace/matchContentPreview.js.map +1 -0
  416. package/workspace/matchWorkspaceFiles.d.ts +30 -0
  417. package/workspace/matchWorkspaceFiles.d.ts.map +1 -0
  418. package/workspace/matchWorkspaceFiles.js +58 -0
  419. package/workspace/matchWorkspaceFiles.js.map +1 -0
  420. package/workspace/resolveWorkspaceFileSelection.d.ts +19 -0
  421. package/workspace/resolveWorkspaceFileSelection.d.ts.map +1 -0
  422. package/workspace/resolveWorkspaceFileSelection.js +115 -0
  423. package/workspace/resolveWorkspaceFileSelection.js.map +1 -0
  424. package/workspace/useWorkspaceContentSearch.d.ts +69 -0
  425. package/workspace/useWorkspaceContentSearch.d.ts.map +1 -0
  426. package/workspace/useWorkspaceContentSearch.js +154 -0
  427. package/workspace/useWorkspaceContentSearch.js.map +1 -0
  428. package/workspace/useWorkspaceFileContent.d.ts +73 -0
  429. package/workspace/useWorkspaceFileContent.d.ts.map +1 -0
  430. package/workspace/useWorkspaceFileContent.js +57 -0
  431. package/workspace/useWorkspaceFileContent.js.map +1 -0
  432. package/workspace/useWorkspaceFileSearch.d.ts +61 -0
  433. package/workspace/useWorkspaceFileSearch.d.ts.map +1 -0
  434. package/workspace/useWorkspaceFileSearch.js +119 -0
  435. package/workspace/useWorkspaceFileSearch.js.map +1 -0
  436. package/workspace/useWorkspaceFiles.d.ts +13 -5
  437. package/workspace/useWorkspaceFiles.d.ts.map +1 -1
  438. package/workspace/useWorkspaceFiles.js +18 -19
  439. package/workspace/useWorkspaceFiles.js.map +1 -1
  440. package/workspace/workspaceListingCache.d.ts +47 -0
  441. package/workspace/workspaceListingCache.d.ts.map +1 -0
  442. package/workspace/workspaceListingCache.js +55 -0
  443. package/workspace/workspaceListingCache.js.map +1 -0
  444. package/session/inspector/ArtifactsTab.d.ts.map +0 -1
  445. package/session/inspector/ArtifactsTab.js.map +0 -1
  446. package/session/inspector/ChangesTab.d.ts.map +0 -1
  447. package/session/inspector/ChangesTab.js.map +0 -1
  448. package/session/inspector/InspectTab.d.ts.map +0 -1
  449. package/session/inspector/InspectTab.js.map +0 -1
  450. package/session/inspector/SessionInspector.d.ts +0 -64
  451. package/session/inspector/SessionInspector.d.ts.map +0 -1
  452. package/session/inspector/SessionInspector.js +0 -53
  453. package/session/inspector/SessionInspector.js.map +0 -1
  454. package/session/inspector/SetupTab.d.ts.map +0 -1
  455. package/session/inspector/SetupTab.js.map +0 -1
  456. package/session/inspector/UsageTab.d.ts.map +0 -1
  457. package/session/inspector/UsageTab.js.map +0 -1
  458. package/session/inspector/WorkspaceTab.d.ts +0 -35
  459. package/session/inspector/WorkspaceTab.d.ts.map +0 -1
  460. package/session/inspector/WorkspaceTab.js +0 -75
  461. package/session/inspector/WorkspaceTab.js.map +0 -1
  462. package/session/inspector/index.d.ts.map +0 -1
  463. package/session/inspector/index.js.map +0 -1
  464. package/session/inspector/useSessionInspector.d.ts +0 -49
  465. package/session/inspector/useSessionInspector.d.ts.map +0 -1
  466. package/session/inspector/useSessionInspector.js +0 -122
  467. package/session/inspector/useSessionInspector.js.map +0 -1
  468. package/src/session/inspector/SessionInspector.tsx +0 -162
  469. package/src/session/inspector/WorkspaceTab.tsx +0 -245
  470. package/src/session/inspector/__tests__/useSessionInspector.test.ts +0 -251
  471. package/src/session/inspector/useSessionInspector.ts +0 -178
  472. package/src/workspace/WorkspaceEntryFiles.tsx +0 -196
  473. package/workflow/motion-preference.d.ts.map +0 -1
  474. package/workflow/motion-preference.js.map +0 -1
  475. package/workspace/WorkspaceEntryFiles.d.ts +0 -22
  476. package/workspace/WorkspaceEntryFiles.d.ts.map +0 -1
  477. package/workspace/WorkspaceEntryFiles.js +0 -58
  478. package/workspace/WorkspaceEntryFiles.js.map +0 -1
  479. /package/session/{inspector → facets}/InspectTab.d.ts +0 -0
  480. /package/session/{inspector → facets}/InspectTab.js +0 -0
  481. /package/src/{workflow → internal}/__tests__/motion-preference.test.ts +0 -0
  482. /package/src/session/{inspector → facets}/InspectTab.tsx +0 -0
  483. /package/src/session/{inspector → facets}/__tests__/ChangesTab.test.tsx +0 -0
@@ -0,0 +1,148 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { render, screen, cleanup, fireEvent } from "@testing-library/react";
3
+
4
+ // ---------------------------------------------------------------------------
5
+ // Launcher panel behavior: the session panel chip is PERSISTENT chrome (always
6
+ // mounted, not gated on attached context), and opening the panel homes on the
7
+ // Config facet — the pre-session view that carries the run defaults, since the
8
+ // Explorer has no workspace yet.
9
+ //
10
+ // The composer is replaced with a prop-capturing probe so these tests exercise
11
+ // only the panel chrome (chip + WorkspaceSurface rail) without pulling in the
12
+ // full composer's provider requirements. The Config facet (SetupTab) renders
13
+ // for real so "homes on Config" is asserted through the live rail.
14
+ // ---------------------------------------------------------------------------
15
+
16
+ vi.mock("../../composer", async (importOriginal) => {
17
+ const actual = await importOriginal<typeof import("../../composer")>();
18
+ return {
19
+ ...actual,
20
+ SessionComposer: () => <div data-testid="composer-probe" />,
21
+ };
22
+ });
23
+
24
+ // A launcher flow with ZERO attached context — no agent, no workspace, no
25
+ // MCP/skills/vars. This is the case the old `hasContext` gate hid the chip for.
26
+ const emptyWorkspace = {
27
+ entries: [],
28
+ hasEntries: false,
29
+ toInput: vi.fn().mockReturnValue([]),
30
+ addGitRepo: vi.fn(),
31
+ addLocalPath: vi.fn(),
32
+ remove: vi.fn(),
33
+ clear: vi.fn(),
34
+ };
35
+
36
+ const stubEmptyFlow = {
37
+ harness: "native" as const,
38
+ setHarness: vi.fn(),
39
+ modelId: undefined,
40
+ setModelId: vi.fn(),
41
+ agentRef: null,
42
+ setAgentRef: vi.fn(),
43
+ resolution: null,
44
+ setResolution: vi.fn(),
45
+ mcpServerUsages: [],
46
+ setMcpServerUsages: vi.fn(),
47
+ skillRefs: [],
48
+ setSkillRefs: vi.fn(),
49
+ workspace: emptyWorkspace,
50
+ sessionVariables: { entries: [], isEmpty: true, clear: vi.fn() },
51
+ isSubmitting: false,
52
+ submitError: null,
53
+ submit: vi.fn(),
54
+ };
55
+
56
+ // A launcher flow WITH attached context (a git workspace entry). Used to prove
57
+ // the composer stays centered regardless of context — the invariant that
58
+ // replaced the old `hasContext` position flip (DD-16 layout stability).
59
+ const stubPopulatedFlow = {
60
+ ...stubEmptyFlow,
61
+ workspace: {
62
+ ...emptyWorkspace,
63
+ hasEntries: true,
64
+ entries: [
65
+ {
66
+ id: "e1",
67
+ name: "acme/app",
68
+ type: "git" as const,
69
+ gitUrl: "https://github.com/acme/app.git",
70
+ gitBranch: "main",
71
+ },
72
+ ],
73
+ },
74
+ };
75
+
76
+ // Swappable flow so individual tests can substitute the context-attached
77
+ // variant. The mock factory reads `mockFlow` at call time (the `mock` prefix
78
+ // is why Vitest permits referencing it inside the hoisted factory); tests
79
+ // reassign it before render and `beforeEach` resets it to the empty flow.
80
+ let mockFlow: typeof stubEmptyFlow | typeof stubPopulatedFlow = stubEmptyFlow;
81
+
82
+ vi.mock("../useNewSessionFlow", () => ({
83
+ useNewSessionFlow: () => mockFlow,
84
+ }));
85
+
86
+ import { NewSessionViewer } from "../NewSessionViewer";
87
+
88
+ beforeEach(() => {
89
+ cleanup();
90
+ mockFlow = stubEmptyFlow;
91
+ });
92
+
93
+ afterEach(() => {
94
+ cleanup();
95
+ vi.clearAllMocks();
96
+ });
97
+
98
+ describe("NewSessionViewer — persistent panel chip", () => {
99
+ it("renders the chip with zero attached context (not gated on hasContext)", () => {
100
+ render(<NewSessionViewer org="acme" onSessionCreated={vi.fn()} />);
101
+ expect(screen.getByRole("button", { name: "Show panel" })).toBeTruthy();
102
+ });
103
+
104
+ it("homes on the Config facet when the panel opens", () => {
105
+ render(<NewSessionViewer org="acme" onSessionCreated={vi.fn()} />);
106
+
107
+ fireEvent.click(screen.getByRole("button", { name: "Show panel" }));
108
+
109
+ // The Config rail view is the active (checked) one; Explorer is not — the
110
+ // launcher's `defaultView: "configure"` home view.
111
+ const config = screen.getByRole("radio", { name: "Config" });
112
+ const explorer = screen.getByRole("radio", { name: "Explorer" });
113
+ expect(config.getAttribute("aria-checked")).toBe("true");
114
+ expect(explorer.getAttribute("aria-checked")).toBe("false");
115
+ });
116
+
117
+ it("keeps the chip mounted as the collapse control once the panel is open", () => {
118
+ render(<NewSessionViewer org="acme" onSessionCreated={vi.fn()} />);
119
+
120
+ fireEvent.click(screen.getByRole("button", { name: "Show panel" }));
121
+ // Chip is still present with zero context — now as the hide affordance, so
122
+ // an open panel always has its toggle (the vanishing-toggle defect the old
123
+ // context gate could produce is impossible by construction).
124
+ expect(screen.getByRole("button", { name: "Hide panel" })).toBeTruthy();
125
+ });
126
+ });
127
+
128
+ describe("NewSessionViewer — composer stays centered", () => {
129
+ // The composer's wrapper is the probe's parent (wrapper > h1 + composer +
130
+ // footer). `my-auto` is unconditional safe-centering; the old `my-6`
131
+ // top-anchor that appeared once context was attached is gone (DD-16).
132
+ const composerWrapper = () => screen.getByTestId("composer-probe").parentElement;
133
+
134
+ it("centers the composer with zero attached context", () => {
135
+ render(<NewSessionViewer org="acme" onSessionCreated={vi.fn()} />);
136
+ expect(composerWrapper()?.className).toContain("my-auto");
137
+ expect(composerWrapper()?.className).not.toContain("my-6");
138
+ });
139
+
140
+ it("keeps the composer centered when context is attached (no position flip)", () => {
141
+ mockFlow = stubPopulatedFlow;
142
+ render(<NewSessionViewer org="acme" onSessionCreated={vi.fn()} />);
143
+ // Regression guard: attaching a workspace previously top-anchored the
144
+ // composer. Centering must now hold irrespective of attached context.
145
+ expect(composerWrapper()?.className).toContain("my-auto");
146
+ expect(composerWrapper()?.className).not.toContain("my-6");
147
+ });
148
+ });
@@ -0,0 +1,217 @@
1
+ import { describe, it, expect, vi, afterEach } from "vitest";
2
+ import { render, screen, fireEvent, cleanup, waitFor } from "@testing-library/react";
3
+ import { create } from "@bufbuild/protobuf";
4
+ import type { Stigmer } from "@stigmer/sdk";
5
+ import { ExecutionArtifactSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/artifact_pb";
6
+ import { ExecutionArtifactKind } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
7
+ import { StigmerContext } from "../../context";
8
+ import type { SessionPlan } from "../../library/detect-plan-artifact";
9
+ import type { PlanDraftController } from "../usePlanDraft";
10
+ import { PlanEditor } from "../PlanEditor";
11
+
12
+ afterEach(cleanup);
13
+
14
+ const PLAN_TEXT = "# Rollout Plan\n\n## Phase 1\n\nDo the first thing.";
15
+
16
+ const plan: SessionPlan = {
17
+ executionId: "aex_1",
18
+ artifact: create(ExecutionArtifactSchema, {
19
+ name: "plan.md",
20
+ kind: ExecutionArtifactKind.FILE,
21
+ sizeBytes: 128n,
22
+ storageKey: "artifacts/aex_1/plan.md",
23
+ contentHash: "hash-a",
24
+ }),
25
+ };
26
+
27
+ function stigmerMock(opts?: { text?: string; truncated?: boolean }): Stigmer {
28
+ return {
29
+ agentExecution: {
30
+ getArtifactContent: vi.fn().mockResolvedValue({
31
+ content: new TextEncoder().encode(opts?.text ?? PLAN_TEXT),
32
+ contentType: "text/markdown",
33
+ truncated: opts?.truncated ?? false,
34
+ }),
35
+ },
36
+ } as unknown as Stigmer;
37
+ }
38
+
39
+ function draftMock(overrides?: Partial<PlanDraftController>): PlanDraftController {
40
+ return {
41
+ draftText: null,
42
+ isEdited: false,
43
+ setDraft: vi.fn(),
44
+ readDraft: () => null,
45
+ ...overrides,
46
+ };
47
+ }
48
+
49
+ function renderEditor(opts?: {
50
+ stigmer?: Stigmer;
51
+ draft?: PlanDraftController;
52
+ onBuildFromPlan?: () => void;
53
+ buildDisabled?: boolean;
54
+ readOnly?: boolean;
55
+ }) {
56
+ return render(
57
+ <StigmerContext.Provider value={opts?.stigmer ?? stigmerMock()}>
58
+ <PlanEditor
59
+ plan={plan}
60
+ draft={opts?.draft ?? draftMock()}
61
+ onBuildFromPlan={opts?.onBuildFromPlan}
62
+ buildDisabled={opts?.buildDisabled}
63
+ readOnly={opts?.readOnly}
64
+ />
65
+ </StigmerContext.Provider>,
66
+ );
67
+ }
68
+
69
+ describe("PlanEditor", () => {
70
+ it("renders the plan as a document with the H1 lifted into the header", async () => {
71
+ renderEditor();
72
+
73
+ await waitFor(() =>
74
+ expect(screen.getByText("Rollout Plan")).toBeTruthy(),
75
+ );
76
+ expect(screen.getByText("Do the first thing.")).toBeTruthy();
77
+ });
78
+
79
+ it("fires onBuildFromPlan from the primary action", async () => {
80
+ const onBuildFromPlan = vi.fn();
81
+ renderEditor({ onBuildFromPlan });
82
+
83
+ await waitFor(() =>
84
+ expect(screen.getByText("Build")).toBeTruthy(),
85
+ );
86
+ fireEvent.click(screen.getByText("Build"));
87
+ expect(onBuildFromPlan).toHaveBeenCalledTimes(1);
88
+ });
89
+
90
+ it("degrades gracefully at narrow widths: truncating title and shrinkable toolbar", async () => {
91
+ // The document must reflow to whatever width the panel gives it — the
92
+ // toolbar wraps and its labels truncate rather than forcing a sideways
93
+ // scrollbar on the editor pane (the overflow-x-hidden body above clips,
94
+ // so anything that cannot shrink would be cut off, not scrollable).
95
+ renderEditor({ onBuildFromPlan: vi.fn() });
96
+
97
+ await waitFor(() =>
98
+ expect(screen.getByText("Rollout Plan")).toBeTruthy(),
99
+ );
100
+ expect(screen.getByText("Rollout Plan").className).toContain("truncate");
101
+
102
+ const buildLabel = screen.getByText("Build");
103
+ expect(buildLabel.className).toContain("truncate");
104
+ const toolbar = screen.getByRole("tablist", { name: "Plan view" })
105
+ .parentElement!;
106
+ expect(toolbar.className).toContain("flex-wrap");
107
+ expect(toolbar.className).toContain("min-w-0");
108
+ });
109
+
110
+ it("shows a pending label and disables the primary while the build starts", async () => {
111
+ renderEditor({ onBuildFromPlan: vi.fn(), buildDisabled: true });
112
+
113
+ await waitFor(() =>
114
+ expect(screen.getByText("Starting build…")).toBeTruthy(),
115
+ );
116
+ expect(
117
+ (screen.getByText("Starting build…").closest("button") as HTMLButtonElement)
118
+ .disabled,
119
+ ).toBe(true);
120
+ });
121
+
122
+ it("edits into the viewer-owned draft and shows the Edited indicator", async () => {
123
+ const setDraft = vi.fn();
124
+ const stigmer = stigmerMock();
125
+ const { rerender } = render(
126
+ <StigmerContext.Provider value={stigmer}>
127
+ <PlanEditor plan={plan} draft={draftMock({ setDraft })} />
128
+ </StigmerContext.Provider>,
129
+ );
130
+
131
+ await waitFor(() => expect(screen.getByText("Edit")).toBeTruthy());
132
+ fireEvent.click(screen.getByText("Edit"));
133
+
134
+ const editor = screen.getByRole("textbox", { name: "Edit plan" });
135
+ fireEvent.change(editor, { target: { value: "# Edited" } });
136
+ expect(setDraft).toHaveBeenCalledWith("# Edited");
137
+
138
+ // Draft active → indicator + revert, and the editor shows the draft.
139
+ // Same client instance, so the content fetch is not re-triggered.
140
+ rerender(
141
+ <StigmerContext.Provider value={stigmer}>
142
+ <PlanEditor
143
+ plan={plan}
144
+ draft={draftMock({ draftText: "# Edited", isEdited: true, setDraft })}
145
+ />
146
+ </StigmerContext.Provider>,
147
+ );
148
+ await waitFor(() => expect(screen.getByText("Edited")).toBeTruthy());
149
+
150
+ fireEvent.click(screen.getByText("Revert"));
151
+ expect(setDraft).toHaveBeenCalledWith(null);
152
+ });
153
+
154
+ it("disables editing for truncated content", async () => {
155
+ renderEditor({ stigmer: stigmerMock({ truncated: true }) });
156
+
157
+ await waitFor(() => expect(screen.getByText("Edit")).toBeTruthy());
158
+ expect((screen.getByText("Edit") as HTMLButtonElement).disabled).toBe(true);
159
+ expect(screen.getByText(/Preview truncated/)).toBeTruthy();
160
+ });
161
+
162
+ it("renders an error state with retry when the content fetch fails", async () => {
163
+ const failing = {
164
+ agentExecution: {
165
+ getArtifactContent: vi.fn().mockRejectedValue(new Error("boom")),
166
+ },
167
+ } as unknown as Stigmer;
168
+
169
+ renderEditor({ stigmer: failing });
170
+
171
+ await waitFor(() =>
172
+ expect(screen.getByText(/Couldn’t load the plan/)).toBeTruthy(),
173
+ );
174
+ expect(screen.getByText("Retry")).toBeTruthy();
175
+ });
176
+ });
177
+
178
+ describe("PlanEditor — read-only (superseded plan)", () => {
179
+ it("renders the document with a superseded notice, no Edit and no Build", async () => {
180
+ renderEditor({
181
+ readOnly: true,
182
+ draft: undefined,
183
+ onBuildFromPlan: vi.fn(),
184
+ });
185
+
186
+ await waitFor(() =>
187
+ expect(screen.getByText("Rollout Plan")).toBeTruthy(),
188
+ );
189
+ expect(screen.getByText("Superseded by a newer plan")).toBeTruthy();
190
+ expect(screen.queryByText("Edit")).toBeNull();
191
+ expect(screen.queryByText("Build")).toBeNull();
192
+ });
193
+
194
+ it("never applies the current plan's draft to a superseded plan", async () => {
195
+ // Defense in depth for the wiring contract (the host passes no draft for
196
+ // a read-only plan): even if a draft controller leaks through, read-only
197
+ // rendering shows the artifact text.
198
+ renderEditor({
199
+ readOnly: true,
200
+ draft: draftMock({ draftText: "# Someone else's draft", isEdited: true }),
201
+ });
202
+
203
+ await waitFor(() =>
204
+ expect(screen.getByText("Rollout Plan")).toBeTruthy(),
205
+ );
206
+ expect(screen.queryByText("Someone else's draft")).toBeNull();
207
+ expect(screen.queryByText("Edited")).toBeNull();
208
+ });
209
+
210
+ it("keeps Rendered and Source views available", async () => {
211
+ renderEditor({ readOnly: true, draft: undefined });
212
+
213
+ await waitFor(() => expect(screen.getByText("Source")).toBeTruthy());
214
+ fireEvent.click(screen.getByText("Source"));
215
+ expect(screen.getByText(/# Rollout Plan/)).toBeTruthy();
216
+ });
217
+ });
@@ -0,0 +1,50 @@
1
+ import { describe, it, expect, afterEach } from "vitest";
2
+ import { render, screen, cleanup } from "@testing-library/react";
3
+ import { PlanStreamingDocument } from "../PlanStreamingDocument";
4
+
5
+ afterEach(cleanup);
6
+
7
+ describe("PlanStreamingDocument — live plan tab view", () => {
8
+ it("is a busy article with a Writing status pill", () => {
9
+ render(
10
+ <PlanStreamingDocument displayText={"# Live Plan\n\nFirst section"} />,
11
+ );
12
+
13
+ const doc = screen.getByRole("article", { name: "Plan document" });
14
+ expect(doc.getAttribute("aria-busy")).toBe("true");
15
+ expect(screen.getByRole("status").textContent).toContain("Writing…");
16
+ });
17
+
18
+ it("lifts the leading H1 into the header and renders the body as markdown", () => {
19
+ render(
20
+ <PlanStreamingDocument
21
+ displayText={"# Live Plan\n\n## Phase 1\n\n- step one"}
22
+ />,
23
+ );
24
+
25
+ const doc = screen.getByRole("article", { name: "Plan document" });
26
+ expect(doc.querySelector("header")!.textContent).toContain("Live Plan");
27
+ // The lifted title does not repeat inside the prose body.
28
+ expect(doc.querySelectorAll("h1")).toHaveLength(0);
29
+ expect(doc.textContent).toContain("step one");
30
+ });
31
+
32
+ it("renders headerless while the H1 line is still streaming in", () => {
33
+ // extractLeadingH1 requires the heading to terminate (newline or end);
34
+ // a lone "#" has no title yet — the document simply shows the raw text
35
+ // until the title resolves. No fabricated placeholder header.
36
+ render(<PlanStreamingDocument displayText={"# Re"} />);
37
+
38
+ const doc = screen.getByRole("article", { name: "Plan document" });
39
+ // "# Re" parses as a (partial) title, lifted into the header.
40
+ expect(doc.querySelector("header")!.textContent).toContain("Re");
41
+ });
42
+
43
+ it("offers no Edit or Build controls — a plan in flight cannot be acted on", () => {
44
+ render(<PlanStreamingDocument displayText={"# Live Plan\n\nBody"} />);
45
+
46
+ expect(screen.queryByText("Edit")).toBeNull();
47
+ expect(screen.queryByText("Build")).toBeNull();
48
+ expect(screen.queryByRole("tablist")).toBeNull();
49
+ });
50
+ });
@@ -0,0 +1,42 @@
1
+ import { describe, it, expect, vi, afterEach } from "vitest";
2
+ import { render, screen, cleanup, fireEvent } from "@testing-library/react";
3
+ import { SessionPanelChip } from "../SessionPanelChip";
4
+
5
+ // ---------------------------------------------------------------------------
6
+ // The chip is the panel's always-mounted toggle. Collapsed, it carries the
7
+ // pending-item count (arrivals never auto-open the panel); open, it is a bare
8
+ // hide affordance. Execution status deliberately never appears here (or in
9
+ // any other viewer chrome) — the thread itself communicates run state.
10
+ // ---------------------------------------------------------------------------
11
+
12
+ afterEach(cleanup);
13
+
14
+ describe("SessionPanelChip", () => {
15
+ it("collapsed: offers Show panel and carries the pending count", () => {
16
+ render(
17
+ <SessionPanelChip isOpen={false} onToggle={vi.fn()} badgeCount={3} />,
18
+ );
19
+ const button = screen.getByRole("button", { name: "Show panel" });
20
+ expect(button.getAttribute("aria-expanded")).toBe("false");
21
+ expect(button.textContent).toContain("3");
22
+ });
23
+
24
+ it("open: offers Hide panel without the count (the panel carries it)", () => {
25
+ render(<SessionPanelChip isOpen onToggle={vi.fn()} badgeCount={3} />);
26
+ const button = screen.getByRole("button", { name: "Hide panel" });
27
+ expect(button.getAttribute("aria-expanded")).toBe("true");
28
+ expect(button.textContent).not.toContain("3");
29
+ });
30
+
31
+ it("renders as a bare toggle when nothing is pending", () => {
32
+ render(<SessionPanelChip isOpen={false} onToggle={vi.fn()} />);
33
+ expect(screen.getByRole("button", { name: "Show panel" }).textContent).toBe("");
34
+ });
35
+
36
+ it("invokes onToggle on click", () => {
37
+ const onToggle = vi.fn();
38
+ render(<SessionPanelChip isOpen={false} onToggle={onToggle} />);
39
+ fireEvent.click(screen.getByRole("button", { name: "Show panel" }));
40
+ expect(onToggle).toHaveBeenCalledTimes(1);
41
+ });
42
+ });
@@ -3,6 +3,8 @@ import { render, screen, cleanup, fireEvent } from "@testing-library/react";
3
3
  import { create } from "@bufbuild/protobuf";
4
4
  import {
5
5
  CapturedFileChangeSchema,
6
+ FileChangeProgressSchema,
7
+ FileChangeProgressEntrySchema,
6
8
  FileChangeSetSchema,
7
9
  } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/filereview_pb";
8
10
  import { FileContentSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
@@ -39,10 +41,6 @@ vi.mock("../../composer", async (importOriginal) => {
39
41
  };
40
42
  });
41
43
 
42
- vi.mock("../inspector/SessionInspector", () => ({
43
- SessionInspector: () => <div data-testid="inspector-probe" />,
44
- }));
45
-
46
44
  const stubWorkspace = {
47
45
  entries: [],
48
46
  hasEntries: false,
@@ -74,6 +72,31 @@ function pendingChangeSet(id: string) {
74
72
  });
75
73
  }
76
74
 
75
+ function progressSnapshot() {
76
+ return create(FileChangeProgressSchema, {
77
+ changeSetId: "cs-1",
78
+ filesChanged: 2,
79
+ linesAdded: 4,
80
+ linesRemoved: 1,
81
+ entries: [
82
+ create(FileChangeProgressEntrySchema, {
83
+ pathAfter: "a.ts",
84
+ kind: FileChangeKind.ADD,
85
+ linesAdded: 4,
86
+ linesRemoved: 0,
87
+ }),
88
+ create(FileChangeProgressEntrySchema, {
89
+ pathBefore: "b.ts",
90
+ pathAfter: "b.ts",
91
+ kind: FileChangeKind.MODIFY,
92
+ linesAdded: 0,
93
+ linesRemoved: 1,
94
+ }),
95
+ ],
96
+ capturedAt: "2026-07-05T00:00:00Z",
97
+ });
98
+ }
99
+
77
100
  const stubConv = {
78
101
  session: { spec: {} },
79
102
  isLoading: false,
@@ -96,6 +119,7 @@ const stubConv = {
96
119
  submitApproval: vi.fn(),
97
120
  submittingApprovalIds: new Set<string>(),
98
121
  fileChangeSets: [] as ReturnType<typeof pendingChangeSet>[],
122
+ fileChangeProgress: undefined as ReturnType<typeof progressSnapshot> | undefined,
99
123
  submitFileDecision: vi.fn(),
100
124
  submittingFileDecisionKeys: new Set<string>(),
101
125
  fileDecisionErrors: new Map<string, Error>(),
@@ -134,11 +158,21 @@ vi.mock("../useSessionPageFlow", () => ({
134
158
  useSessionPageFlow: () => stubSessionPageFlow,
135
159
  }));
136
160
 
161
+ vi.mock("../../hooks", () => ({
162
+ useStigmer: () => ({
163
+ agentExecution: {
164
+ uploadAttachment: vi.fn(),
165
+ getArtifactContent: vi.fn(),
166
+ },
167
+ }),
168
+ }));
169
+
137
170
  import { SessionViewer } from "../SessionViewer";
138
171
 
139
172
  beforeEach(() => {
140
173
  threadProps.length = 0;
141
174
  stubConv.fileChangeSets = [];
175
+ stubConv.fileChangeProgress = undefined;
142
176
  stubConv.submitFileDecision = vi.fn();
143
177
  });
144
178
 
@@ -184,6 +218,34 @@ describe("SessionViewer — file-review dock wiring", () => {
184
218
  );
185
219
  });
186
220
 
221
+ it("renders no progress bar when no turn is capturing", () => {
222
+ render(<SessionViewer sessionId="ses_1" org="acme" />);
223
+ expect(
224
+ document.querySelector('[data-cursor-target="file-change-progress-bar"]'),
225
+ ).toBeNull();
226
+ });
227
+
228
+ it("shows the mid-run progress strip above the composer while a turn is capturing", () => {
229
+ // Progress is present (CAPTURING) and the dock is empty — the two are
230
+ // mutually exclusive per turn, so the strip stands in for the dock.
231
+ stubConv.fileChangeProgress = progressSnapshot();
232
+ render(<SessionViewer sessionId="ses_1" org="acme" />);
233
+
234
+ const bar = document.querySelector('[data-cursor-target="file-change-progress-bar"]');
235
+ expect(bar).toBeTruthy();
236
+ expect(screen.getByText(/2 files changing/)).toBeTruthy();
237
+ expect(
238
+ document.querySelector('[data-cursor-target="file-review-dock"]'),
239
+ ).toBeNull();
240
+
241
+ // Pinned in the fixed strip, ordered before the composer input.
242
+ const composer = screen.getByTestId("composer-probe");
243
+ expect(bar!.parentElement).toBe(composer.parentElement);
244
+ expect(
245
+ bar!.compareDocumentPosition(composer) & Node.DOCUMENT_POSITION_FOLLOWING,
246
+ ).toBeTruthy();
247
+ });
248
+
187
249
  it("gives the thread records-only file-review props (no decision callbacks)", () => {
188
250
  render(<SessionViewer sessionId="ses_1" org="acme" />);
189
251