@stigmer/react 3.1.1 → 3.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (426) hide show
  1. package/composer/SessionComposer.d.ts +24 -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/FilePathContext.d.ts +8 -1
  10. package/execution/FilePathContext.d.ts.map +1 -1
  11. package/execution/FilePathContext.js.map +1 -1
  12. package/execution/FilePathLink.d.ts.map +1 -1
  13. package/execution/FilePathLink.js +21 -6
  14. package/execution/FilePathLink.js.map +1 -1
  15. package/execution/MessageEntry.d.ts +29 -0
  16. package/execution/MessageEntry.d.ts.map +1 -1
  17. package/execution/MessageEntry.js +29 -5
  18. package/execution/MessageEntry.js.map +1 -1
  19. package/execution/MessageThread.d.ts +76 -13
  20. package/execution/MessageThread.d.ts.map +1 -1
  21. package/execution/MessageThread.js +178 -24
  22. package/execution/MessageThread.js.map +1 -1
  23. package/execution/PlanArtifactCard.d.ts +27 -18
  24. package/execution/PlanArtifactCard.d.ts.map +1 -1
  25. package/execution/PlanArtifactCard.js +13 -23
  26. package/execution/PlanArtifactCard.js.map +1 -1
  27. package/execution/PlanDocumentMessage.d.ts +32 -0
  28. package/execution/PlanDocumentMessage.d.ts.map +1 -0
  29. package/execution/PlanDocumentMessage.js +37 -0
  30. package/execution/PlanDocumentMessage.js.map +1 -0
  31. package/execution/PlanStreamingCard.d.ts +45 -0
  32. package/execution/PlanStreamingCard.d.ts.map +1 -0
  33. package/execution/PlanStreamingCard.js +35 -0
  34. package/execution/PlanStreamingCard.js.map +1 -0
  35. package/execution/index.d.ts +5 -1
  36. package/execution/index.d.ts.map +1 -1
  37. package/execution/index.js +2 -0
  38. package/execution/index.js.map +1 -1
  39. package/execution/useCreateAgentExecution.d.ts +10 -0
  40. package/execution/useCreateAgentExecution.d.ts.map +1 -1
  41. package/execution/useCreateAgentExecution.js +5 -1
  42. package/execution/useCreateAgentExecution.js.map +1 -1
  43. package/github/decodeGitHubContent.d.ts +29 -0
  44. package/github/decodeGitHubContent.d.ts.map +1 -0
  45. package/github/decodeGitHubContent.js +72 -0
  46. package/github/decodeGitHubContent.js.map +1 -0
  47. package/github/index.d.ts +1 -0
  48. package/github/index.d.ts.map +1 -1
  49. package/github/index.js +1 -0
  50. package/github/index.js.map +1 -1
  51. package/github/useGitHubFileReader.d.ts +26 -0
  52. package/github/useGitHubFileReader.d.ts.map +1 -0
  53. package/github/useGitHubFileReader.js +106 -0
  54. package/github/useGitHubFileReader.js.map +1 -0
  55. package/github/useGitHubTreeLister.d.ts.map +1 -1
  56. package/github/useGitHubTreeLister.js +6 -2
  57. package/github/useGitHubTreeLister.js.map +1 -1
  58. package/index.d.ts +9 -9
  59. package/index.d.ts.map +1 -1
  60. package/index.js +5 -5
  61. package/index.js.map +1 -1
  62. package/internal/ResizableSplit.d.ts +72 -22
  63. package/internal/ResizableSplit.d.ts.map +1 -1
  64. package/internal/ResizableSplit.js +96 -38
  65. package/internal/ResizableSplit.js.map +1 -1
  66. package/internal/VirtualizedThread.d.ts +5 -3
  67. package/internal/VirtualizedThread.d.ts.map +1 -1
  68. package/internal/VirtualizedThread.js +6 -4
  69. package/internal/VirtualizedThread.js.map +1 -1
  70. package/internal/file-icons/index.d.ts +17 -0
  71. package/internal/file-icons/index.d.ts.map +1 -0
  72. package/internal/file-icons/index.js +60 -0
  73. package/internal/file-icons/index.js.map +1 -0
  74. package/internal/file-tree/FileTreeNode.d.ts +18 -1
  75. package/internal/file-tree/FileTreeNode.d.ts.map +1 -1
  76. package/internal/file-tree/FileTreeNode.js +11 -2
  77. package/internal/file-tree/FileTreeNode.js.map +1 -1
  78. package/internal/markdown-components.d.ts +38 -1
  79. package/internal/markdown-components.d.ts.map +1 -1
  80. package/internal/markdown-components.js +86 -11
  81. package/internal/markdown-components.js.map +1 -1
  82. package/{workflow → internal}/motion-preference.d.ts +7 -4
  83. package/internal/motion-preference.d.ts.map +1 -0
  84. package/{workflow → internal}/motion-preference.js +7 -4
  85. package/internal/motion-preference.js.map +1 -0
  86. package/internal/store/index.d.ts +33 -0
  87. package/internal/store/index.d.ts.map +1 -1
  88. package/internal/store/index.js +59 -0
  89. package/internal/store/index.js.map +1 -1
  90. package/internal/store/workspace-editors-store.d.ts +145 -0
  91. package/internal/store/workspace-editors-store.d.ts.map +1 -0
  92. package/internal/store/workspace-editors-store.js +208 -0
  93. package/internal/store/workspace-editors-store.js.map +1 -0
  94. package/internal/store/workspace-file-selection-store.d.ts +38 -0
  95. package/internal/store/workspace-file-selection-store.d.ts.map +1 -0
  96. package/internal/store/workspace-file-selection-store.js +62 -0
  97. package/internal/store/workspace-file-selection-store.js.map +1 -0
  98. package/internal/useRevealLine.d.ts +49 -0
  99. package/internal/useRevealLine.d.ts.map +1 -0
  100. package/internal/useRevealLine.js +43 -0
  101. package/internal/useRevealLine.js.map +1 -0
  102. package/library/detect-plan-artifact.d.ts +21 -0
  103. package/library/detect-plan-artifact.d.ts.map +1 -1
  104. package/library/detect-plan-artifact.js +20 -0
  105. package/library/detect-plan-artifact.js.map +1 -1
  106. package/library/detect-streaming-plan.d.ts +45 -0
  107. package/library/detect-streaming-plan.d.ts.map +1 -0
  108. package/library/detect-streaming-plan.js +83 -0
  109. package/library/detect-streaming-plan.js.map +1 -0
  110. package/library/index.d.ts +4 -1
  111. package/library/index.d.ts.map +1 -1
  112. package/library/index.js +2 -1
  113. package/library/index.js.map +1 -1
  114. package/package.json +4 -4
  115. package/session/NewSessionViewer.d.ts +19 -4
  116. package/session/NewSessionViewer.d.ts.map +1 -1
  117. package/session/NewSessionViewer.js +52 -25
  118. package/session/NewSessionViewer.js.map +1 -1
  119. package/session/PlanEditor.d.ts +55 -0
  120. package/session/PlanEditor.d.ts.map +1 -0
  121. package/session/PlanEditor.js +88 -0
  122. package/session/PlanEditor.js.map +1 -0
  123. package/session/PlanStreamingDocument.d.ts +30 -0
  124. package/session/PlanStreamingDocument.d.ts.map +1 -0
  125. package/session/PlanStreamingDocument.js +37 -0
  126. package/session/PlanStreamingDocument.js.map +1 -0
  127. package/session/SessionPanelChip.d.ts +26 -0
  128. package/session/SessionPanelChip.d.ts.map +1 -0
  129. package/session/SessionPanelChip.js +40 -0
  130. package/session/SessionPanelChip.js.map +1 -0
  131. package/session/SessionViewer.d.ts +34 -7
  132. package/session/SessionViewer.d.ts.map +1 -1
  133. package/session/SessionViewer.js +315 -33
  134. package/session/SessionViewer.js.map +1 -1
  135. package/session/{inspector → facets}/ArtifactsTab.d.ts +10 -2
  136. package/session/facets/ArtifactsTab.d.ts.map +1 -0
  137. package/session/{inspector → facets}/ArtifactsTab.js +8 -3
  138. package/session/facets/ArtifactsTab.js.map +1 -0
  139. package/session/{inspector → facets}/ChangesTab.d.ts +3 -3
  140. package/session/facets/ChangesTab.d.ts.map +1 -0
  141. package/session/{inspector → facets}/ChangesTab.js +3 -3
  142. package/session/facets/ChangesTab.js.map +1 -0
  143. package/session/facets/InspectTab.d.ts.map +1 -0
  144. package/session/facets/InspectTab.js.map +1 -0
  145. package/session/{inspector → facets}/SetupTab.d.ts +11 -2
  146. package/session/facets/SetupTab.d.ts.map +1 -0
  147. package/session/{inspector → facets}/SetupTab.js +4 -3
  148. package/session/facets/SetupTab.js.map +1 -0
  149. package/session/{inspector → facets}/UsageTab.d.ts +1 -1
  150. package/session/facets/UsageTab.d.ts.map +1 -0
  151. package/session/{inspector → facets}/UsageTab.js +1 -1
  152. package/session/facets/UsageTab.js.map +1 -0
  153. package/session/{inspector → facets}/index.d.ts +0 -6
  154. package/session/facets/index.d.ts.map +1 -0
  155. package/session/{inspector → facets}/index.js +0 -3
  156. package/session/facets/index.js.map +1 -0
  157. package/session/index.d.ts +11 -2
  158. package/session/index.d.ts.map +1 -1
  159. package/session/index.js +15 -2
  160. package/session/index.js.map +1 -1
  161. package/session/plan-document.d.ts +9 -0
  162. package/session/plan-document.d.ts.map +1 -0
  163. package/session/plan-document.js +17 -0
  164. package/session/plan-document.js.map +1 -0
  165. package/session/useOpenFileChange.d.ts +20 -0
  166. package/session/useOpenFileChange.d.ts.map +1 -0
  167. package/session/useOpenFileChange.js +31 -0
  168. package/session/useOpenFileChange.js.map +1 -0
  169. package/session/usePlanDraft.d.ts +52 -0
  170. package/session/usePlanDraft.d.ts.map +1 -0
  171. package/session/usePlanDraft.js +63 -0
  172. package/session/usePlanDraft.js.map +1 -0
  173. package/session/useSessionConversation.d.ts +6 -0
  174. package/session/useSessionConversation.d.ts.map +1 -1
  175. package/session/useSessionConversation.js +1 -0
  176. package/session/useSessionConversation.js.map +1 -1
  177. package/session/useSessionPageFlow.d.ts.map +1 -1
  178. package/session/useSessionPageFlow.js +1 -0
  179. package/session/useSessionPageFlow.js.map +1 -1
  180. package/session/useSessionPanel.d.ts +120 -0
  181. package/session/useSessionPanel.d.ts.map +1 -0
  182. package/session/useSessionPanel.js +130 -0
  183. package/session/useSessionPanel.js.map +1 -0
  184. package/session/useSessionRailViews.d.ts +45 -0
  185. package/session/useSessionRailViews.d.ts.map +1 -0
  186. package/session/useSessionRailViews.js +105 -0
  187. package/session/useSessionRailViews.js.map +1 -0
  188. package/src/composer/SessionComposer.tsx +52 -10
  189. package/src/composer/__tests__/SessionComposer-contract.test.tsx +58 -4
  190. package/src/execution/ArtifactContentRenderer.tsx +101 -24
  191. package/src/execution/FilePathContext.tsx +8 -1
  192. package/src/execution/FilePathLink.tsx +22 -6
  193. package/src/execution/MessageEntry.tsx +111 -1
  194. package/src/execution/MessageThread.tsx +291 -36
  195. package/src/execution/PlanArtifactCard.tsx +63 -31
  196. package/src/execution/PlanDocumentMessage.tsx +96 -0
  197. package/src/execution/PlanStreamingCard.tsx +137 -0
  198. package/src/execution/__tests__/ArtifactContentRenderer.test.tsx +80 -1
  199. package/src/execution/__tests__/FilePathLink.test.tsx +87 -0
  200. package/src/execution/__tests__/MessageThread.test.tsx +101 -0
  201. package/src/execution/__tests__/PlanArtifactCard.test.tsx +66 -12
  202. package/src/execution/__tests__/PlanDocumentMessage.test.tsx +55 -0
  203. package/src/execution/__tests__/PlanStreamingCard.test.tsx +49 -0
  204. package/src/execution/__tests__/buildThreadItems-plan-completion.test.ts +504 -22
  205. package/src/execution/__tests__/message-entry.test.tsx +48 -0
  206. package/src/execution/__tests__/useCreateAgentExecution.test.tsx +85 -0
  207. package/src/execution/index.ts +7 -1
  208. package/src/execution/useCreateAgentExecution.ts +16 -1
  209. package/src/github/__tests__/decodeGitHubContent.test.ts +102 -0
  210. package/src/github/__tests__/useGitHubFileReader.test.ts +183 -0
  211. package/src/github/decodeGitHubContent.ts +83 -0
  212. package/src/github/index.ts +1 -0
  213. package/src/github/useGitHubFileReader.ts +152 -0
  214. package/src/github/useGitHubTreeLister.ts +6 -2
  215. package/src/index.ts +63 -9
  216. package/src/internal/ResizableSplit.tsx +184 -51
  217. package/src/internal/VirtualizedThread.tsx +12 -4
  218. package/src/internal/__tests__/ResizableSplit.test.tsx +125 -3
  219. package/src/internal/__tests__/markdown-components.test.tsx +68 -0
  220. package/src/internal/__tests__/useRevealLine.test.tsx +97 -0
  221. package/src/internal/file-icons/__tests__/file-icons.test.tsx +35 -0
  222. package/src/internal/file-icons/index.tsx +137 -0
  223. package/src/internal/file-tree/FileTreeNode.tsx +43 -3
  224. package/src/internal/file-tree/__tests__/FileTreeNode-explorer.test.tsx +86 -0
  225. package/src/internal/markdown-components.tsx +116 -11
  226. package/src/{workflow → internal}/motion-preference.ts +7 -4
  227. package/src/internal/store/__tests__/workspace-editors-store.test.ts +216 -0
  228. package/src/internal/store/__tests__/workspace-file-selection-store.test.ts +118 -0
  229. package/src/internal/store/index.ts +94 -0
  230. package/src/internal/store/workspace-editors-store.ts +315 -0
  231. package/src/internal/store/workspace-file-selection-store.ts +88 -0
  232. package/src/internal/useRevealLine.ts +81 -0
  233. package/src/library/__tests__/detect-plan-artifact.test.ts +48 -0
  234. package/src/library/__tests__/detect-streaming-plan.test.ts +234 -0
  235. package/src/library/detect-plan-artifact.ts +35 -0
  236. package/src/library/detect-streaming-plan.ts +108 -0
  237. package/src/library/index.ts +5 -0
  238. package/src/session/NewSessionViewer.tsx +123 -55
  239. package/src/session/PlanEditor.tsx +361 -0
  240. package/src/session/PlanStreamingDocument.tsx +97 -0
  241. package/src/session/SessionPanelChip.tsx +103 -0
  242. package/src/session/SessionViewer.tsx +617 -90
  243. package/src/session/__tests__/NewSessionViewer.test.tsx +148 -0
  244. package/src/session/__tests__/PlanEditor.test.tsx +217 -0
  245. package/src/session/__tests__/PlanStreamingDocument.test.tsx +50 -0
  246. package/src/session/__tests__/SessionPanelChip.test.tsx +42 -0
  247. package/src/session/__tests__/SessionViewer-fileReviewDock.test.tsx +9 -4
  248. package/src/session/__tests__/SessionViewer-transcriptFileOpen.test.tsx +205 -0
  249. package/src/session/__tests__/audienceWiring.test.tsx +55 -19
  250. package/src/session/__tests__/useOpenFileChange.test.tsx +82 -0
  251. package/src/session/__tests__/usePlanDraft.test.ts +102 -0
  252. package/src/session/__tests__/useSessionPanel.test.ts +298 -0
  253. package/src/session/__tests__/useSessionRailViews.test.tsx +124 -0
  254. package/src/session/{inspector → facets}/ArtifactsTab.tsx +27 -5
  255. package/src/session/{inspector → facets}/ChangesTab.tsx +3 -3
  256. package/src/session/{inspector → facets}/SetupTab.tsx +13 -1
  257. package/src/session/{inspector → facets}/UsageTab.tsx +1 -1
  258. package/src/session/{inspector → facets}/__tests__/ArtifactsTab.test.tsx +35 -1
  259. package/src/session/facets/__tests__/SetupTab.test.tsx +44 -0
  260. package/src/session/{inspector → facets}/index.ts +0 -16
  261. package/src/session/index.ts +30 -13
  262. package/src/session/plan-document.ts +19 -0
  263. package/src/session/useOpenFileChange.ts +53 -0
  264. package/src/session/usePlanDraft.ts +109 -0
  265. package/src/session/useSessionConversation.ts +7 -0
  266. package/src/session/useSessionPageFlow.ts +1 -0
  267. package/src/session/useSessionPanel.ts +288 -0
  268. package/src/session/useSessionRailViews.tsx +200 -0
  269. package/src/workflow/WorkflowExecutionGraph.tsx +1 -1
  270. package/src/workflow/index.ts +1 -1
  271. package/src/workflow/useFollowExecution.ts +1 -1
  272. package/src/workspace/EditorTabs.tsx +145 -0
  273. package/src/workspace/ExplorerTree.tsx +247 -0
  274. package/src/workspace/FileViewer.tsx +516 -0
  275. package/src/workspace/WorkspaceContentSearch.tsx +478 -0
  276. package/src/workspace/WorkspaceContentSearcher.ts +70 -0
  277. package/src/workspace/WorkspaceFileLister.ts +11 -0
  278. package/src/workspace/WorkspaceFileReader.ts +57 -0
  279. package/src/workspace/WorkspaceFileSearch.tsx +429 -0
  280. package/src/workspace/WorkspaceSurface.tsx +781 -0
  281. package/src/workspace/__tests__/EditorTabs.test.tsx +100 -0
  282. package/src/workspace/__tests__/ExplorerTree.test.tsx +152 -0
  283. package/src/workspace/__tests__/FileViewer.test.tsx +421 -0
  284. package/src/workspace/__tests__/WorkspaceContentSearch.test.tsx +196 -0
  285. package/src/workspace/__tests__/WorkspaceFileSearch.test.tsx +206 -0
  286. package/src/workspace/__tests__/WorkspaceSurface.test.tsx +348 -0
  287. package/src/workspace/__tests__/findChangeForSelection.test.ts +132 -0
  288. package/src/workspace/__tests__/matchContentPreview.test.ts +55 -0
  289. package/src/workspace/__tests__/matchWorkspaceFiles.test.ts +104 -0
  290. package/src/workspace/__tests__/resolveWorkspaceFileSelection.test.ts +135 -0
  291. package/src/workspace/__tests__/useWorkspaceContentSearch.test.tsx +196 -0
  292. package/src/workspace/__tests__/useWorkspaceFileContent.test.tsx +190 -0
  293. package/src/workspace/__tests__/useWorkspaceFileSearch.test.tsx +162 -0
  294. package/src/workspace/findChangeForSelection.ts +61 -0
  295. package/src/workspace/index.ts +56 -2
  296. package/src/workspace/matchContentPreview.ts +51 -0
  297. package/src/workspace/matchWorkspaceFiles.ts +86 -0
  298. package/src/workspace/resolveWorkspaceFileSelection.ts +119 -0
  299. package/src/workspace/useWorkspaceContentSearch.ts +228 -0
  300. package/src/workspace/useWorkspaceFileContent.ts +129 -0
  301. package/src/workspace/useWorkspaceFileSearch.ts +184 -0
  302. package/src/workspace/useWorkspaceFiles.ts +27 -27
  303. package/src/workspace/workspaceListingCache.ts +93 -0
  304. package/styles.css +1 -1
  305. package/workflow/WorkflowExecutionGraph.js +1 -1
  306. package/workflow/WorkflowExecutionGraph.js.map +1 -1
  307. package/workflow/index.d.ts +1 -1
  308. package/workflow/index.d.ts.map +1 -1
  309. package/workflow/index.js +1 -1
  310. package/workflow/index.js.map +1 -1
  311. package/workflow/useFollowExecution.js +1 -1
  312. package/workflow/useFollowExecution.js.map +1 -1
  313. package/workspace/EditorTabs.d.ts +29 -0
  314. package/workspace/EditorTabs.d.ts.map +1 -0
  315. package/workspace/EditorTabs.js +66 -0
  316. package/workspace/EditorTabs.js.map +1 -0
  317. package/workspace/ExplorerTree.d.ts +32 -0
  318. package/workspace/ExplorerTree.d.ts.map +1 -0
  319. package/workspace/ExplorerTree.js +45 -0
  320. package/workspace/ExplorerTree.js.map +1 -0
  321. package/workspace/FileViewer.d.ts +93 -0
  322. package/workspace/FileViewer.d.ts.map +1 -0
  323. package/workspace/FileViewer.js +182 -0
  324. package/workspace/FileViewer.js.map +1 -0
  325. package/workspace/WorkspaceContentSearch.d.ts +41 -0
  326. package/workspace/WorkspaceContentSearch.d.ts.map +1 -0
  327. package/workspace/WorkspaceContentSearch.js +195 -0
  328. package/workspace/WorkspaceContentSearch.js.map +1 -0
  329. package/workspace/WorkspaceContentSearcher.d.ts +59 -0
  330. package/workspace/WorkspaceContentSearcher.d.ts.map +1 -0
  331. package/workspace/WorkspaceContentSearcher.js +7 -0
  332. package/workspace/WorkspaceContentSearcher.js.map +1 -0
  333. package/workspace/WorkspaceFileLister.d.ts +11 -0
  334. package/workspace/WorkspaceFileLister.d.ts.map +1 -1
  335. package/workspace/WorkspaceFileReader.d.ts +48 -0
  336. package/workspace/WorkspaceFileReader.d.ts.map +1 -0
  337. package/workspace/WorkspaceFileReader.js +11 -0
  338. package/workspace/WorkspaceFileReader.js.map +1 -0
  339. package/workspace/WorkspaceFileSearch.d.ts +32 -0
  340. package/workspace/WorkspaceFileSearch.d.ts.map +1 -0
  341. package/workspace/WorkspaceFileSearch.js +155 -0
  342. package/workspace/WorkspaceFileSearch.js.map +1 -0
  343. package/workspace/WorkspaceSurface.d.ts +151 -0
  344. package/workspace/WorkspaceSurface.d.ts.map +1 -0
  345. package/workspace/WorkspaceSurface.js +184 -0
  346. package/workspace/WorkspaceSurface.js.map +1 -0
  347. package/workspace/findChangeForSelection.d.ts +19 -0
  348. package/workspace/findChangeForSelection.d.ts.map +1 -0
  349. package/workspace/findChangeForSelection.js +46 -0
  350. package/workspace/findChangeForSelection.js.map +1 -0
  351. package/workspace/index.d.ts +24 -2
  352. package/workspace/index.d.ts.map +1 -1
  353. package/workspace/index.js +13 -1
  354. package/workspace/index.js.map +1 -1
  355. package/workspace/matchContentPreview.d.ts +21 -0
  356. package/workspace/matchContentPreview.d.ts.map +1 -0
  357. package/workspace/matchContentPreview.js +36 -0
  358. package/workspace/matchContentPreview.js.map +1 -0
  359. package/workspace/matchWorkspaceFiles.d.ts +30 -0
  360. package/workspace/matchWorkspaceFiles.d.ts.map +1 -0
  361. package/workspace/matchWorkspaceFiles.js +58 -0
  362. package/workspace/matchWorkspaceFiles.js.map +1 -0
  363. package/workspace/resolveWorkspaceFileSelection.d.ts +19 -0
  364. package/workspace/resolveWorkspaceFileSelection.d.ts.map +1 -0
  365. package/workspace/resolveWorkspaceFileSelection.js +115 -0
  366. package/workspace/resolveWorkspaceFileSelection.js.map +1 -0
  367. package/workspace/useWorkspaceContentSearch.d.ts +69 -0
  368. package/workspace/useWorkspaceContentSearch.d.ts.map +1 -0
  369. package/workspace/useWorkspaceContentSearch.js +154 -0
  370. package/workspace/useWorkspaceContentSearch.js.map +1 -0
  371. package/workspace/useWorkspaceFileContent.d.ts +73 -0
  372. package/workspace/useWorkspaceFileContent.d.ts.map +1 -0
  373. package/workspace/useWorkspaceFileContent.js +57 -0
  374. package/workspace/useWorkspaceFileContent.js.map +1 -0
  375. package/workspace/useWorkspaceFileSearch.d.ts +61 -0
  376. package/workspace/useWorkspaceFileSearch.d.ts.map +1 -0
  377. package/workspace/useWorkspaceFileSearch.js +119 -0
  378. package/workspace/useWorkspaceFileSearch.js.map +1 -0
  379. package/workspace/useWorkspaceFiles.d.ts +13 -5
  380. package/workspace/useWorkspaceFiles.d.ts.map +1 -1
  381. package/workspace/useWorkspaceFiles.js +18 -19
  382. package/workspace/useWorkspaceFiles.js.map +1 -1
  383. package/workspace/workspaceListingCache.d.ts +47 -0
  384. package/workspace/workspaceListingCache.d.ts.map +1 -0
  385. package/workspace/workspaceListingCache.js +55 -0
  386. package/workspace/workspaceListingCache.js.map +1 -0
  387. package/session/inspector/ArtifactsTab.d.ts.map +0 -1
  388. package/session/inspector/ArtifactsTab.js.map +0 -1
  389. package/session/inspector/ChangesTab.d.ts.map +0 -1
  390. package/session/inspector/ChangesTab.js.map +0 -1
  391. package/session/inspector/InspectTab.d.ts.map +0 -1
  392. package/session/inspector/InspectTab.js.map +0 -1
  393. package/session/inspector/SessionInspector.d.ts +0 -64
  394. package/session/inspector/SessionInspector.d.ts.map +0 -1
  395. package/session/inspector/SessionInspector.js +0 -53
  396. package/session/inspector/SessionInspector.js.map +0 -1
  397. package/session/inspector/SetupTab.d.ts.map +0 -1
  398. package/session/inspector/SetupTab.js.map +0 -1
  399. package/session/inspector/UsageTab.d.ts.map +0 -1
  400. package/session/inspector/UsageTab.js.map +0 -1
  401. package/session/inspector/WorkspaceTab.d.ts +0 -35
  402. package/session/inspector/WorkspaceTab.d.ts.map +0 -1
  403. package/session/inspector/WorkspaceTab.js +0 -75
  404. package/session/inspector/WorkspaceTab.js.map +0 -1
  405. package/session/inspector/index.d.ts.map +0 -1
  406. package/session/inspector/index.js.map +0 -1
  407. package/session/inspector/useSessionInspector.d.ts +0 -49
  408. package/session/inspector/useSessionInspector.d.ts.map +0 -1
  409. package/session/inspector/useSessionInspector.js +0 -122
  410. package/session/inspector/useSessionInspector.js.map +0 -1
  411. package/src/session/inspector/SessionInspector.tsx +0 -162
  412. package/src/session/inspector/WorkspaceTab.tsx +0 -245
  413. package/src/session/inspector/__tests__/useSessionInspector.test.ts +0 -251
  414. package/src/session/inspector/useSessionInspector.ts +0 -178
  415. package/src/workspace/WorkspaceEntryFiles.tsx +0 -196
  416. package/workflow/motion-preference.d.ts.map +0 -1
  417. package/workflow/motion-preference.js.map +0 -1
  418. package/workspace/WorkspaceEntryFiles.d.ts +0 -22
  419. package/workspace/WorkspaceEntryFiles.d.ts.map +0 -1
  420. package/workspace/WorkspaceEntryFiles.js +0 -58
  421. package/workspace/WorkspaceEntryFiles.js.map +0 -1
  422. /package/session/{inspector → facets}/InspectTab.d.ts +0 -0
  423. /package/session/{inspector → facets}/InspectTab.js +0 -0
  424. /package/src/{workflow → internal}/__tests__/motion-preference.test.ts +0 -0
  425. /package/src/session/{inspector → facets}/InspectTab.tsx +0 -0
  426. /package/src/session/{inspector → facets}/__tests__/ChangesTab.test.tsx +0 -0
@@ -0,0 +1,124 @@
1
+ import { describe, it, expect, vi, afterEach } from "vitest";
2
+ import { renderHook, cleanup } from "@testing-library/react";
3
+
4
+ // ---------------------------------------------------------------------------
5
+ // useSessionRailViews composes the session facets as injected rail views for
6
+ // the workspace surface. The facet components themselves have their own
7
+ // suites; here we prove the composition rules — ordering, contextual
8
+ // visibility (Changes/Artifacts only with data, Inspect only with a
9
+ // selection), and count badges — by mocking the aggregation hooks.
10
+ // ---------------------------------------------------------------------------
11
+
12
+ const writeBacksState = { hasWriteBacks: false, writeBackCount: 0 };
13
+ const artifactsState = { hasArtifacts: false, artifactCount: 0 };
14
+
15
+ vi.mock("../useSessionWriteBacks", () => ({
16
+ useSessionWriteBacks: () => writeBacksState,
17
+ }));
18
+ vi.mock("../useSessionArtifacts", () => ({
19
+ useSessionArtifacts: () => artifactsState,
20
+ }));
21
+
22
+ import { useSessionRailViews } from "../useSessionRailViews";
23
+ import type { SetupTabProps } from "../facets/SetupTab";
24
+ import type { SelectedThreadItem } from "../../internal/store/selection-store";
25
+
26
+ const sessionConfig = {
27
+ agentRef: null,
28
+ isDefaultAgent: true,
29
+ mcpServerUsages: [],
30
+ skillRefs: [],
31
+ sessionVariables: null,
32
+ harness: "native",
33
+ executionTarget: undefined,
34
+ modelId: undefined,
35
+ } as SetupTabProps;
36
+
37
+ function renderViews(
38
+ overrides: Partial<Parameters<typeof useSessionRailViews>[0]> = {},
39
+ ) {
40
+ return renderHook(() =>
41
+ useSessionRailViews({
42
+ allExecutions: [],
43
+ org: "acme",
44
+ sessionConfig,
45
+ selectedItem: null,
46
+ ...overrides,
47
+ }),
48
+ );
49
+ }
50
+
51
+ afterEach(() => {
52
+ cleanup();
53
+ writeBacksState.hasWriteBacks = false;
54
+ writeBacksState.writeBackCount = 0;
55
+ artifactsState.hasArtifacts = false;
56
+ artifactsState.artifactCount = 0;
57
+ });
58
+
59
+ describe("useSessionRailViews", () => {
60
+ it("always offers Config and Usage; Changes/Artifacts/Inspect are contextual", () => {
61
+ const { result } = renderViews();
62
+ expect(result.current.map((v) => v.id)).toEqual(["configure", "usage"]);
63
+ });
64
+
65
+ it("omits Config when no session configuration is provided", () => {
66
+ const { result } = renderViews({ sessionConfig: undefined });
67
+ expect(result.current.map((v) => v.id)).toEqual(["usage"]);
68
+ });
69
+
70
+ it("surfaces Changes with a write-back count badge", () => {
71
+ writeBacksState.hasWriteBacks = true;
72
+ writeBacksState.writeBackCount = 2;
73
+ const { result } = renderViews();
74
+ const changes = result.current.find((v) => v.id === "changes");
75
+ expect(changes?.badge).toBe(2);
76
+ expect(result.current.map((v) => v.id)).toEqual([
77
+ "configure",
78
+ "changes",
79
+ "usage",
80
+ ]);
81
+ });
82
+
83
+ it("surfaces Artifacts with a count badge", () => {
84
+ artifactsState.hasArtifacts = true;
85
+ artifactsState.artifactCount = 4;
86
+ const { result } = renderViews();
87
+ const artifacts = result.current.find((v) => v.id === "artifacts");
88
+ expect(artifacts?.badge).toBe(4);
89
+ });
90
+
91
+ it("surfaces Inspect only while a thread item is selected", () => {
92
+ const selectedItem = { kind: "toolCall" } as unknown as SelectedThreadItem;
93
+ const { result, rerender } = renderHook(
94
+ ({ item }: { item: SelectedThreadItem | null }) =>
95
+ useSessionRailViews({
96
+ allExecutions: [],
97
+ org: "acme",
98
+ sessionConfig,
99
+ selectedItem: item,
100
+ }),
101
+ { initialProps: { item: selectedItem as SelectedThreadItem | null } },
102
+ );
103
+ expect(result.current.some((v) => v.id === "inspect")).toBe(true);
104
+ rerender({ item: null });
105
+ expect(result.current.some((v) => v.id === "inspect")).toBe(false);
106
+ });
107
+
108
+ it("keeps full inspector ordering: Config, Changes, Artifacts, Usage, Inspect", () => {
109
+ writeBacksState.hasWriteBacks = true;
110
+ writeBacksState.writeBackCount = 1;
111
+ artifactsState.hasArtifacts = true;
112
+ artifactsState.artifactCount = 1;
113
+ const { result } = renderViews({
114
+ selectedItem: { kind: "toolCall" } as unknown as SelectedThreadItem,
115
+ });
116
+ expect(result.current.map((v) => v.id)).toEqual([
117
+ "configure",
118
+ "changes",
119
+ "artifacts",
120
+ "usage",
121
+ "inspect",
122
+ ]);
123
+ });
124
+ });
@@ -21,22 +21,44 @@ export interface ArtifactsTabProps {
21
21
  * action as the message-thread plan card.
22
22
  */
23
23
  readonly onImplementPlan?: () => void;
24
+ /**
25
+ * Open a plan in the session panel's plan document tab. When provided, a
26
+ * `plan.md` artifact routes there instead of the preview modal — the plan
27
+ * is a first-class document, not a popup. Non-plan artifacts keep the
28
+ * modal. When omitted (hosts without the plan tab) the modal remains for
29
+ * every artifact.
30
+ */
31
+ readonly onOpenPlan?: (executionId: string) => void;
24
32
  }
25
33
 
26
34
  /**
27
- * Artifacts facet for the SessionInspector.
35
+ * Artifacts facet for the session panel (a `useSessionRailViews` rail view).
28
36
  *
29
37
  * Wraps `useSessionArtifacts` → `ArtifactCard` list with
30
38
  * `ArtifactPreviewModal` — the same content as `ArtifactsWidget`
31
39
  * without the section heading.
32
40
  */
33
- export function ArtifactsTab({ executions, org, onApplied, onImplementPlan }: ArtifactsTabProps) {
41
+ export function ArtifactsTab({
42
+ executions,
43
+ org,
44
+ onApplied,
45
+ onImplementPlan,
46
+ onOpenPlan,
47
+ }: ArtifactsTabProps) {
34
48
  const { artifacts, hasArtifacts } = useSessionArtifacts(executions);
35
49
  const [previewEntry, setPreviewEntry] = useState<SessionArtifactEntry | null>(null);
36
50
 
37
- const handlePreview = useCallback((entry: SessionArtifactEntry) => {
38
- setPreviewEntry(entry);
39
- }, []);
51
+ const handlePreview = useCallback(
52
+ (entry: SessionArtifactEntry) => {
53
+ // The plan opens as a document (the panel's plan tab), never a popup.
54
+ if (onOpenPlan && isPlanArtifact(entry.artifact)) {
55
+ onOpenPlan(entry.executionId);
56
+ return;
57
+ }
58
+ setPreviewEntry(entry);
59
+ },
60
+ [onOpenPlan],
61
+ );
40
62
 
41
63
  const handleClosePreview = useCallback(() => {
42
64
  setPreviewEntry(null);
@@ -9,15 +9,15 @@ export interface ChangesTabProps {
9
9
  }
10
10
 
11
11
  /**
12
- * Changes facet for the SessionInspector — the session's git write-backs
12
+ * Changes facet for the session panel — the session's git write-backs
13
13
  * (branch/commit/PR), one `WriteBackCard` per entry.
14
14
  *
15
15
  * Local file changes deliberately do NOT render here: they live in the
16
16
  * transcript, where each stamped edit row shows its diff in place and the
17
17
  * per-turn decision bar carries the review controls and file list
18
18
  * (`FileReviewCard`). Duplicating them in a side panel gave the same change a
19
- * third rendering with no added authority. The tab therefore only surfaces
20
- * once a write-back exists (see `buildVisibleTabs`).
19
+ * third rendering with no added authority. The facet therefore only surfaces
20
+ * once a write-back exists (see `useSessionRailViews`).
21
21
  */
22
22
  export function ChangesTab({ executions }: ChangesTabProps) {
23
23
  const { writeBacks, hasWriteBacks } = useSessionWriteBacks(executions);
@@ -32,11 +32,20 @@ export interface SetupTabProps {
32
32
  * buttons. When absent, sections are read-only (DD-011).
33
33
  */
34
34
  readonly mutations?: SetupTabMutationCallbacks;
35
+ /**
36
+ * Host-injected access management control (e.g. the Console's
37
+ * `ManageAccessButton`) rendered as the facet's final section. A slot keeps
38
+ * the SDK auth-agnostic (DD-004); the injected control owns its own
39
+ * visibility (permission gating), so this section renders no chrome of its
40
+ * own — an empty heading over a denied control would read as breakage.
41
+ */
42
+ readonly accessSlot?: React.ReactNode;
35
43
  }
36
44
 
37
45
  /**
38
46
  * Persistent session configuration panel (Configure tab) — shows agent,
39
- * MCP servers, skills, run config, and session variables.
47
+ * MCP servers, skills, run config, session variables, and the host's
48
+ * access management control (via `accessSlot`).
40
49
  *
41
50
  * Workspace management has moved to the dedicated Workspace tab.
42
51
  *
@@ -56,6 +65,7 @@ export function SetupTab({
56
65
  executionTarget,
57
66
  modelId,
58
67
  mutations,
68
+ accessSlot,
59
69
  }: SetupTabProps) {
60
70
  const hasSessionVars = sessionVariables != null && !sessionVariables.isEmpty;
61
71
 
@@ -86,6 +96,8 @@ export function SetupTab({
86
96
  {hasSessionVars && (
87
97
  <SessionVarsSection entries={sessionVariables.entries} />
88
98
  )}
99
+
100
+ {accessSlot && <section>{accessSlot}</section>}
89
101
  </div>
90
102
  );
91
103
  }
@@ -9,7 +9,7 @@ export interface UsageTabProps {
9
9
  }
10
10
 
11
11
  /**
12
- * Usage facet for the SessionInspector.
12
+ * Usage facet for the session panel (a `useSessionRailViews` rail view).
13
13
  *
14
14
  * Uses `useSessionUsage` to determine if data exists, then delegates
15
15
  * rendering to the existing `UsageWidget`. Shows an empty state when
@@ -38,13 +38,17 @@ function createStigmerMock(): Stigmer {
38
38
  } as unknown as Stigmer;
39
39
  }
40
40
 
41
- function renderTab(onImplementPlan?: () => void) {
41
+ function renderTab(
42
+ onImplementPlan?: () => void,
43
+ onOpenPlan?: (executionId: string) => void,
44
+ ) {
42
45
  return render(
43
46
  <StigmerContext.Provider value={createStigmerMock()}>
44
47
  <ArtifactsTab
45
48
  executions={[execution]}
46
49
  org="acme"
47
50
  onImplementPlan={onImplementPlan}
51
+ onOpenPlan={onOpenPlan}
48
52
  />
49
53
  </StigmerContext.Provider>,
50
54
  );
@@ -87,3 +91,33 @@ describe("ArtifactsTab — plan 'Build from plan' wiring", () => {
87
91
  expect(onImplementPlan).toHaveBeenCalledTimes(1);
88
92
  });
89
93
  });
94
+
95
+ describe("ArtifactsTab — plan routes to the plan document tab", () => {
96
+ it("routes a plan.md preview to onOpenPlan (no modal) when provided", () => {
97
+ const onOpenPlan = vi.fn();
98
+ renderTab(vi.fn(), onOpenPlan);
99
+
100
+ openPreviewFor("plan.md");
101
+
102
+ expect(onOpenPlan).toHaveBeenCalledWith("aex_1");
103
+ expect(document.querySelector("dialog")).toBeNull();
104
+ });
105
+
106
+ it("keeps the modal for non-plan artifacts even when onOpenPlan is provided", () => {
107
+ const onOpenPlan = vi.fn();
108
+ renderTab(vi.fn(), onOpenPlan);
109
+
110
+ openPreviewFor("notes.md");
111
+
112
+ expect(onOpenPlan).not.toHaveBeenCalled();
113
+ expect(document.querySelector("dialog")).toBeTruthy();
114
+ });
115
+
116
+ it("keeps the modal for plan.md when onOpenPlan is omitted (hosts without the plan tab)", () => {
117
+ renderTab(vi.fn());
118
+
119
+ openPreviewFor("plan.md");
120
+
121
+ expect(document.querySelector("dialog")).toBeTruthy();
122
+ });
123
+ });
@@ -0,0 +1,44 @@
1
+ import { describe, it, expect, afterEach } from "vitest";
2
+ import { render, screen, cleanup } from "@testing-library/react";
3
+ import { SetupTab, type SetupTabProps } from "../SetupTab";
4
+
5
+ // ---------------------------------------------------------------------------
6
+ // The Config facet's access section: a host-injected slot with no chrome of
7
+ // its own — the injected control (e.g. the Console's ManageAccessButton) owns
8
+ // its visibility, so the facet must render nothing extra when the slot is
9
+ // absent or the control gates itself away.
10
+ // ---------------------------------------------------------------------------
11
+
12
+ afterEach(cleanup);
13
+
14
+ const BASE_PROPS: SetupTabProps = {
15
+ agentRef: null,
16
+ isDefaultAgent: false,
17
+ mcpServerUsages: [],
18
+ skillRefs: [],
19
+ sessionVariables: null,
20
+ harness: "native",
21
+ executionTarget: undefined,
22
+ modelId: undefined,
23
+ };
24
+
25
+ describe("SetupTab — access slot", () => {
26
+ it("renders the injected access control", () => {
27
+ render(
28
+ <SetupTab
29
+ {...BASE_PROPS}
30
+ accessSlot={<button type="button">Manage access</button>}
31
+ />,
32
+ );
33
+ expect(
34
+ screen.getByRole("button", { name: "Manage access" }),
35
+ ).toBeDefined();
36
+ });
37
+
38
+ it("renders no access section when the slot is absent", () => {
39
+ const { container } = render(<SetupTab {...BASE_PROPS} />);
40
+ expect(screen.queryByRole("button", { name: "Manage access" })).toBeNull();
41
+ // Only the four always-on sections (run config, agent, MCP, skills).
42
+ expect(container.querySelectorAll("section")).toHaveLength(4);
43
+ });
44
+ });
@@ -1,13 +1,3 @@
1
- export { SessionInspector } from "./SessionInspector.js";
2
- export type { SessionInspectorProps } from "./SessionInspector.js";
3
-
4
- export { useSessionInspector, buildVisibleTabs } from "./useSessionInspector.js";
5
- export type {
6
- SessionInspectorTabId,
7
- UseSessionInspectorOptions,
8
- UseSessionInspectorReturn,
9
- } from "./useSessionInspector.js";
10
-
11
1
  export { ChangesTab } from "./ChangesTab.js";
12
2
  export type { ChangesTabProps } from "./ChangesTab.js";
13
3
 
@@ -25,9 +15,3 @@ export type {
25
15
  SetupTabProps,
26
16
  SetupTabMutationCallbacks,
27
17
  } from "./SetupTab.js";
28
-
29
- export { WorkspaceTab } from "./WorkspaceTab.js";
30
- export type {
31
- WorkspaceTabProps,
32
- WorkspaceTabActions,
33
- } from "./WorkspaceTab.js";
@@ -102,24 +102,41 @@ export type { SessionViewerProps } from "./SessionViewer.js";
102
102
  export { NewSessionViewer } from "./NewSessionViewer.js";
103
103
  export type { NewSessionViewerProps } from "./NewSessionViewer.js";
104
104
 
105
- // Selection types (for platform builders using SessionInspector directly)
105
+ // Unified session-panel controller drives the WorkspaceSurface open-editor
106
+ // group, the collapsed/open state, and the rail-view FSM (for platform
107
+ // builders embedding the surface directly).
108
+ export { useSessionPanel } from "./useSessionPanel.js";
109
+ export type {
110
+ SessionPanelController,
111
+ UseSessionPanelOptions,
112
+ } from "./useSessionPanel.js";
113
+
114
+ // Plan draft — viewer-owned in-place edit of the session's current plan
115
+ // (edit-as-input; the published plan.md artifact is never mutated).
116
+ export { usePlanDraft, planDraftKey } from "./usePlanDraft.js";
117
+ export type { PlanDraftController } from "./usePlanDraft.js";
118
+
119
+ // Plan document — the editor-area plan surface (mounted as a virtual document
120
+ // in the workspace surface) and the identity of its tab.
121
+ export { PlanEditor } from "./PlanEditor.js";
122
+ export type { PlanEditorProps } from "./PlanEditor.js";
123
+ export { PlanStreamingDocument } from "./PlanStreamingDocument.js";
124
+ export type { PlanStreamingDocumentProps } from "./PlanStreamingDocument.js";
125
+ export {
126
+ PLAN_DOCUMENT_ENTRY_ID,
127
+ PLAN_DOCUMENT_PATH,
128
+ } from "./plan-document.js";
129
+
130
+ // Selection types (for platform builders composing their own Inspect facet)
106
131
  export type { SelectedThreadItem } from "../internal/store/selection-store.js";
107
132
 
108
- // SessionInspectortabbed right-side inspector panel
109
- export {
110
- SessionInspector,
111
- useSessionInspector,
112
- buildVisibleTabs,
113
- SetupTab,
114
- } from "./inspector/index.js";
133
+ // Session facet components the panel's rail views (Config et al.), also
134
+ // independently importable (DD-003).
135
+ export { SetupTab } from "./facets/index.js";
115
136
  export type {
116
- SessionInspectorProps,
117
- SessionInspectorTabId,
118
- UseSessionInspectorOptions,
119
- UseSessionInspectorReturn,
120
137
  SetupTabProps,
121
138
  SetupTabMutationCallbacks,
122
- } from "./inspector/index.js";
139
+ } from "./facets/index.js";
123
140
 
124
141
  // Session utilities (re-exported from @stigmer/sdk)
125
142
  export { PENDING_SUBJECT, resolvedSubject } from "@stigmer/sdk";
@@ -0,0 +1,19 @@
1
+ // Identity of the session's plan tab in the workspace surface's editor group.
2
+ //
3
+ // Kept in its own module (not in PlanEditor.tsx) so behavior-only consumers —
4
+ // useSessionPanel opens the tab, SessionViewer routes to it — depend on the
5
+ // identity without pulling the component (and its markdown renderer) into
6
+ // their module graph (DD-003 headless-first).
7
+
8
+ import { virtualEntryId } from "../internal/store/index.js";
9
+ import { PLAN_ARTIFACT_NAME } from "../library/detect-plan-artifact.js";
10
+
11
+ /**
12
+ * Virtual entry id of the plan document tab. One tab per session — the host
13
+ * swaps WHICH plan the tab shows (latest editable, or a superseded plan
14
+ * read-only); the tab itself never multiplies.
15
+ */
16
+ export const PLAN_DOCUMENT_ENTRY_ID = virtualEntryId("plan");
17
+
18
+ /** The plan tab's path — doubles as its tab label, matching the artifact name. */
19
+ export const PLAN_DOCUMENT_PATH = PLAN_ARTIFACT_NAME;
@@ -0,0 +1,53 @@
1
+ "use client";
2
+
3
+ import { useMemo } from "react";
4
+ import type { AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
5
+ import type { FileChange } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
6
+ import type { WorkspaceEntry } from "../workspace/useWorkspaceEntries.js";
7
+ import type { SelectedWorkspaceFile } from "../internal/store/workspace-file-selection-store.js";
8
+ import { findChangeForSelection } from "../workspace/findChangeForSelection.js";
9
+ import { useSessionFileChanges } from "./useSessionFileChanges.js";
10
+
11
+ /**
12
+ * Stable empty executions passed to {@link useSessionFileChanges} while no file
13
+ * is open, so the (fetch-free) net-change fold stays trivial during streaming
14
+ * and only folds once a file is actually being viewed.
15
+ */
16
+ const EMPTY_EXECUTIONS: readonly AgentExecution[] = [];
17
+
18
+ /**
19
+ * Correlate the open workspace file with the one session {@link FileChange} that
20
+ * touched it, so a changed file can default to its authoritative
21
+ * `baseline→candidate` diff (Slice 4 / DD-06).
22
+ *
23
+ * The net-change fold is skipped while no file is open (via `EMPTY_EXECUTIONS`),
24
+ * and the join reuses the same DD-08 resolver + entries + sandbox root that
25
+ * opened the file — so "the diff shown" can never disagree with "the file
26
+ * opened". Both the inspector's Viewer tab and the workspace surface consume
27
+ * this single hook rather than re-deriving the correlation.
28
+ *
29
+ * @returns the matching change, or `null` when the open file was not changed
30
+ * this session (or no file is open).
31
+ */
32
+ export function useOpenFileChange(
33
+ selectedFile: SelectedWorkspaceFile | null | undefined,
34
+ allExecutions: readonly AgentExecution[],
35
+ entries: readonly WorkspaceEntry[] | undefined,
36
+ sandboxWorkspaceRoot: string | undefined,
37
+ ): FileChange | null {
38
+ const { fileChanges } = useSessionFileChanges(
39
+ selectedFile ? allExecutions : EMPTY_EXECUTIONS,
40
+ );
41
+ return useMemo(
42
+ () =>
43
+ selectedFile && entries
44
+ ? findChangeForSelection(
45
+ selectedFile,
46
+ fileChanges,
47
+ entries,
48
+ sandboxWorkspaceRoot,
49
+ ) ?? null
50
+ : null,
51
+ [selectedFile, fileChanges, entries, sandboxWorkspaceRoot],
52
+ );
53
+ }
@@ -0,0 +1,109 @@
1
+ "use client";
2
+
3
+ import { useCallback, useMemo, useRef, useState } from "react";
4
+ import type { SessionPlan } from "../library/detect-plan-artifact.js";
5
+
6
+ /**
7
+ * Identity of a plan for draft scoping: the execution that published it plus
8
+ * the artifact's content hash. A refined plan (new execution) or a republished
9
+ * plan (same key, new hash) produces a NEW identity, which orphans any draft
10
+ * of the previous plan — a draft of plan N must never silently ride along
11
+ * once plan N+1 exists.
12
+ */
13
+ export function planDraftKey(plan: SessionPlan): string {
14
+ return `${plan.executionId}:${plan.artifact.contentHash}`;
15
+ }
16
+
17
+ /** Controller returned by {@link usePlanDraft}. */
18
+ export interface PlanDraftController {
19
+ /**
20
+ * The user's in-place edit of the current plan, or `null` when the plan is
21
+ * unedited. Always scoped to the CURRENT plan — a draft made against a
22
+ * superseded plan reads as `null` here (it is dropped, never migrated).
23
+ */
24
+ readonly draftText: string | null;
25
+ /** True when the current plan has an active draft. */
26
+ readonly isEdited: boolean;
27
+ /**
28
+ * Set (or update) the draft for the current plan. Pass `null` to revert to
29
+ * the published plan. No-ops when the session has no plan.
30
+ */
31
+ readonly setDraft: (text: string | null) => void;
32
+ /**
33
+ * Snapshot reader for submit-time consumers: returns the current draft (or
34
+ * `null`) without the caller depending on draft state. Referentially stable
35
+ * for the lifetime of the component (DD-010) — "Build from plan" reads the
36
+ * draft through this at click time, so per-keystroke draft updates never
37
+ * re-bind the build callback or re-render the conversation column.
38
+ */
39
+ readonly readDraft: () => string | null;
40
+ }
41
+
42
+ interface DraftState {
43
+ readonly key: string;
44
+ readonly text: string;
45
+ }
46
+
47
+ /**
48
+ * Owns the local draft of the session's current plan (Phase: refine before
49
+ * build). The draft is a client-side overlay — the published `plan.md`
50
+ * artifact is immutable and is never written back (edit-as-input, not
51
+ * artifact mutation). The approved plan (draft if edited, else the artifact
52
+ * text) is delivered to the implement execution as an attachment.
53
+ *
54
+ * Ownership lives at the viewer level, NOT inside the plan document tab's
55
+ * editor: the panel subtree unmounts wholesale on collapse (and the editor
56
+ * remounts per plan identity), so editor-local state would be destroyed by
57
+ * every collapse or tab switch — silently losing the user's edits.
58
+ *
59
+ * Supersession is derived, not synchronized: the draft is stored with the
60
+ * plan identity it was made against ({@link planDraftKey}), and reads resolve
61
+ * against the CURRENT plan's identity. When a newer plan arrives the old
62
+ * draft simply stops matching — no effect, no cleanup, no stale-flush race.
63
+ */
64
+ export function usePlanDraft(
65
+ plan: SessionPlan | undefined,
66
+ ): PlanDraftController {
67
+ const [draft, setDraftState] = useState<DraftState | null>(null);
68
+
69
+ const currentKey = plan ? planDraftKey(plan) : null;
70
+ const draftText =
71
+ draft !== null && currentKey !== null && draft.key === currentKey
72
+ ? draft.text
73
+ : null;
74
+
75
+ // Render-synced mirrors so `readDraft` stays referentially stable while
76
+ // always observing the latest draft/plan (the useSessionPanel viewRef
77
+ // pattern).
78
+ const draftRef = useRef(draft);
79
+ draftRef.current = draft;
80
+ const currentKeyRef = useRef(currentKey);
81
+ currentKeyRef.current = currentKey;
82
+
83
+ const setDraft = useCallback(
84
+ (text: string | null) => {
85
+ const key = currentKeyRef.current;
86
+ if (!key) return;
87
+ setDraftState(text === null ? null : { key, text });
88
+ },
89
+ [],
90
+ );
91
+
92
+ const readDraft = useCallback((): string | null => {
93
+ const current = draftRef.current;
94
+ const key = currentKeyRef.current;
95
+ return current !== null && key !== null && current.key === key
96
+ ? current.text
97
+ : null;
98
+ }, []);
99
+
100
+ return useMemo(
101
+ () => ({
102
+ draftText,
103
+ isEdited: draftText !== null,
104
+ setDraft,
105
+ readDraft,
106
+ }),
107
+ [draftText, setDraft, readDraft],
108
+ );
109
+ }
@@ -96,6 +96,12 @@ export interface SendFollowUpOptions {
96
96
  * - `"plan"`: read-only analysis, no file mutations.
97
97
  */
98
98
  readonly interactionMode?: "agent" | "plan";
99
+ /**
100
+ * Marks this execution as a "Build from plan" turn.
101
+ *
102
+ * @see {@link CreateAgentExecutionInput.buildFromPlan}
103
+ */
104
+ readonly buildFromPlan?: boolean;
99
105
  /**
100
106
  * Auto-approve every tool call for this execution (bypass the HITL gate).
101
107
  *
@@ -581,6 +587,7 @@ export function useSessionConversation(
581
587
  runtimeEnv: options?.runtimeEnv,
582
588
  attachments: options?.attachments,
583
589
  interactionMode: options?.interactionMode,
590
+ buildFromPlan: options?.buildFromPlan,
584
591
  autoApproveAll: options?.autoApproveAll,
585
592
  workspaceFileRefs: options?.workspaceFileRefs,
586
593
  });
@@ -405,6 +405,7 @@ export function useSessionPageFlow(
405
405
  runtimeEnv,
406
406
  attachments: context?.attachments,
407
407
  interactionMode: context?.interactionMode,
408
+ buildFromPlan: context?.buildFromPlan,
408
409
  // Sourced from the session-scoped preference set at the approval gate,
409
410
  // not from the composer (the pre-arm toggle was removed).
410
411
  autoApproveAll: autoApproveAll || undefined,