@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,200 @@
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 { SurfaceRailView } from "../workspace/WorkspaceSurface.js";
6
+ import type { SelectedThreadItem } from "../internal/store/selection-store.js";
7
+ import type { ApplyResourceResult } from "../library/useApplyResource.js";
8
+ import { useSessionWriteBacks } from "./useSessionWriteBacks.js";
9
+ import { useSessionArtifacts } from "./useSessionArtifacts.js";
10
+ import { SetupTab, type SetupTabProps } from "./facets/SetupTab.js";
11
+ import { ChangesTab } from "./facets/ChangesTab.js";
12
+ import { ArtifactsTab } from "./facets/ArtifactsTab.js";
13
+ import { UsageTab } from "./facets/UsageTab.js";
14
+ import { InspectTab } from "./facets/InspectTab.js";
15
+
16
+ /** Options for {@link useSessionRailViews}. */
17
+ export interface UseSessionRailViewsOptions {
18
+ /** All executions in the session — drives Changes/Artifacts/Usage. */
19
+ readonly allExecutions: readonly AgentExecution[];
20
+ /** Organization slug for artifact Apply CTA. */
21
+ readonly org: string;
22
+ /** Session configuration for the Config facet. */
23
+ readonly sessionConfig: SetupTabProps | undefined;
24
+ /** Currently selected thread item — surfaces the Inspect facet. */
25
+ readonly selectedItem: SelectedThreadItem | null;
26
+ /** Called after a resource is applied from the Artifacts facet. */
27
+ readonly onApplied?: (result: ApplyResourceResult) => void;
28
+ /** Implement a plan — the Artifacts facet's preview action for `plan.md`. */
29
+ readonly onImplementPlan?: () => void;
30
+ /**
31
+ * Open a plan in the panel's plan document tab. Routed to the Artifacts
32
+ * facet so clicking `plan.md` there opens the editor-area document instead
33
+ * of the preview modal.
34
+ */
35
+ readonly onOpenPlan?: (executionId: string) => void;
36
+ /**
37
+ * Whether to offer the execution-derived facets (Changes / Artifacts /
38
+ * Usage). The launcher passes `false` — before a session exists there are no
39
+ * executions to aggregate, so only Config applies.
40
+ * @default true
41
+ */
42
+ readonly includeExecutionFacets?: boolean;
43
+ }
44
+
45
+ /**
46
+ * Composes the session facets (Config / Changes / Artifacts / Usage / Inspect)
47
+ * as {@link SurfaceRailView}s for the workspace surface's activity rail.
48
+ *
49
+ * This is the session-domain half of the unified panel: the surface stays a
50
+ * domain-pure workspace organism and these views are injected into its rail
51
+ * (DD-004 composition). Contextual visibility mirrors the retired inspector's
52
+ * tab rules — Changes/Artifacts surface only when data exists (with count
53
+ * badges), Inspect only when a thread item is selected.
54
+ */
55
+ export function useSessionRailViews({
56
+ allExecutions,
57
+ org,
58
+ sessionConfig,
59
+ selectedItem,
60
+ onApplied,
61
+ onImplementPlan,
62
+ onOpenPlan,
63
+ includeExecutionFacets = true,
64
+ }: UseSessionRailViewsOptions): readonly SurfaceRailView[] {
65
+ const { hasWriteBacks, writeBackCount } = useSessionWriteBacks(allExecutions);
66
+ const { hasArtifacts, artifactCount } = useSessionArtifacts(allExecutions);
67
+
68
+ return useMemo(() => {
69
+ const views: SurfaceRailView[] = [];
70
+
71
+ if (sessionConfig) {
72
+ views.push({
73
+ id: "configure",
74
+ label: "Config",
75
+ icon: <GearIcon />,
76
+ content: <SetupTab {...sessionConfig} />,
77
+ });
78
+ }
79
+
80
+ if (includeExecutionFacets) {
81
+ if (hasWriteBacks) {
82
+ views.push({
83
+ id: "changes",
84
+ label: "Changes",
85
+ icon: <ChangesIcon />,
86
+ badge: writeBackCount,
87
+ content: <ChangesTab executions={allExecutions} />,
88
+ });
89
+ }
90
+
91
+ if (hasArtifacts) {
92
+ views.push({
93
+ id: "artifacts",
94
+ label: "Artifacts",
95
+ icon: <ArtifactsIcon />,
96
+ badge: artifactCount,
97
+ content: (
98
+ <ArtifactsTab
99
+ executions={allExecutions}
100
+ org={org}
101
+ onApplied={onApplied}
102
+ onImplementPlan={onImplementPlan}
103
+ onOpenPlan={onOpenPlan}
104
+ />
105
+ ),
106
+ });
107
+ }
108
+
109
+ views.push({
110
+ id: "usage",
111
+ label: "Usage",
112
+ icon: <UsageIcon />,
113
+ content: <UsageTab executions={allExecutions} />,
114
+ });
115
+ }
116
+
117
+ if (selectedItem) {
118
+ views.push({
119
+ id: "inspect",
120
+ label: "Inspect",
121
+ icon: <InspectIcon />,
122
+ content: <InspectTab selectedItem={selectedItem} />,
123
+ });
124
+ }
125
+
126
+ return views;
127
+ }, [
128
+ sessionConfig,
129
+ includeExecutionFacets,
130
+ hasWriteBacks,
131
+ writeBackCount,
132
+ hasArtifacts,
133
+ artifactCount,
134
+ allExecutions,
135
+ org,
136
+ onApplied,
137
+ onImplementPlan,
138
+ onOpenPlan,
139
+ selectedItem,
140
+ ]);
141
+ }
142
+
143
+ // ---------------------------------------------------------------------------
144
+ // Inline SVG icons — monochrome, `currentColor`-tinted (DD-005; SDK
145
+ // independence — no lucide dependency)
146
+ // ---------------------------------------------------------------------------
147
+
148
+ function GearIcon() {
149
+ return (
150
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
151
+ <circle cx="12" cy="12" r="3" />
152
+ <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33h.01a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51h.01a1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82v.01a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" />
153
+ </svg>
154
+ );
155
+ }
156
+
157
+ /** Source-control style branch glyph — the session's git write-backs. */
158
+ function ChangesIcon() {
159
+ return (
160
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
161
+ <circle cx="6" cy="6" r="2.5" />
162
+ <circle cx="6" cy="18" r="2.5" />
163
+ <circle cx="18" cy="8" r="2.5" />
164
+ <path d="M6 8.5v7" />
165
+ <path d="M18 10.5a7 7 0 0 1-7 5H8.5" />
166
+ </svg>
167
+ );
168
+ }
169
+
170
+ function ArtifactsIcon() {
171
+ return (
172
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
173
+ <path d="M21 8l-9-5-9 5v8l9 5 9-5z" />
174
+ <path d="M3 8l9 5 9-5" />
175
+ <path d="M12 13v9" />
176
+ </svg>
177
+ );
178
+ }
179
+
180
+ function UsageIcon() {
181
+ return (
182
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
183
+ <path d="M3 20h18" />
184
+ <path d="M6 20v-6" />
185
+ <path d="M11 20V9" />
186
+ <path d="M16 20v-9" />
187
+ <path d="M21 20V5" />
188
+ </svg>
189
+ );
190
+ }
191
+
192
+ /** Crosshair glyph — inspecting a selected thread item. */
193
+ function InspectIcon() {
194
+ return (
195
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
196
+ <circle cx="12" cy="12" r="7" />
197
+ <path d="M12 2v4M12 18v4M2 12h4M18 12h4" />
198
+ </svg>
199
+ );
200
+ }
@@ -26,7 +26,7 @@ import { useFollowExecution, computeFollowSelection } from "./useFollowExecution
26
26
  import { useActiveTaskName } from "./useActiveTaskName.js";
27
27
  import { useExecutionAnnouncements } from "./useExecutionAnnouncements.js";
28
28
  import { ExecutionActiveTaskIndicator } from "./ExecutionActiveTaskIndicator.js";
29
- import { getAnimationDuration } from "./motion-preference.js";
29
+ import { getAnimationDuration } from "../internal/motion-preference.js";
30
30
 
31
31
  /** Props for {@link WorkflowExecutionGraph}. */
32
32
  export interface WorkflowExecutionGraphProps {
@@ -531,7 +531,7 @@ export {
531
531
  type ExecutionActiveTaskIndicatorProps,
532
532
  } from "./ExecutionActiveTaskIndicator.js";
533
533
  export { useExecutionAnnouncements } from "./useExecutionAnnouncements.js";
534
- export { getAnimationDuration, prefersReducedMotion } from "./motion-preference.js";
534
+ export { getAnimationDuration, prefersReducedMotion } from "../internal/motion-preference.js";
535
535
 
536
536
  // T05: Shared formatting utilities
537
537
  export {
@@ -4,7 +4,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
4
4
  import type { Node, Viewport } from "@xyflow/react";
5
5
  import { useReactFlow } from "@xyflow/react";
6
6
  import type { CanvasTaskNodeData } from "./workflow-graph-conversions.js";
7
- import { getAnimationDuration } from "./motion-preference.js";
7
+ import { getAnimationDuration } from "../internal/motion-preference.js";
8
8
 
9
9
  /**
10
10
  * Follow-execution state machine states.
@@ -0,0 +1,174 @@
1
+ "use client";
2
+
3
+ import { useCallback, type KeyboardEvent, type MouseEvent } from "react";
4
+ import { cn } from "@stigmer/theme";
5
+ import { editorKey, type OpenEditor } from "../internal/store/index.js";
6
+
7
+ /**
8
+ * Deterministic, space-free DOM id for a tab, built from an instance-scoped
9
+ * `prefix` (a `useId()` value) and the editor `key`. Shared by the tab (its
10
+ * `id`) and the editor body (its `aria-labelledby`) so the two associate; the
11
+ * key is percent-encoded because editor keys embed file paths that may contain
12
+ * characters (spaces) illegal in a space-separated IDREF.
13
+ */
14
+ export function editorTabDomId(prefix: string, key: string): string {
15
+ return `${prefix}${encodeURIComponent(key)}`;
16
+ }
17
+
18
+ /** Props for {@link EditorTabs}. */
19
+ export interface EditorTabsProps {
20
+ /** Open editors in tab order. */
21
+ readonly editors: readonly OpenEditor[];
22
+ /** Key of the active editor (`editorKey(entryId, path)`), or `null`. */
23
+ readonly activeKey: string | null;
24
+ /** Focus an open editor (single click). */
25
+ readonly onActivate: (entryId: string, path: string) => void;
26
+ /** Pin an editor (double-click) so it stops being the reusable preview tab. */
27
+ readonly onPin: (entryId: string, path: string) => void;
28
+ /** Close an editor (close button or middle click). */
29
+ readonly onClose: (entryId: string, path: string) => void;
30
+ /**
31
+ * DOM id of the editor body (`role="tabpanel"`). When provided together with
32
+ * {@link tabIdPrefix}, each tab gets a stable `id` and `aria-controls` linking
33
+ * it to that panel. Optional so the strip degrades gracefully without a panel.
34
+ */
35
+ readonly panelId?: string;
36
+ /** Instance-scoped prefix for per-tab ids (see {@link editorTabDomId}). */
37
+ readonly tabIdPrefix?: string;
38
+ /** Additional CSS classes for the root element. */
39
+ readonly className?: string;
40
+ }
41
+
42
+ /**
43
+ * The editor group's tab strip, following VS Code preview-tab semantics:
44
+ * a single-click preview tab renders in italics and is reused as the user
45
+ * browses; double-clicking a tab pins it (persistent). Each tab has a close
46
+ * control, also reachable by middle-click.
47
+ *
48
+ * A `role="tablist"` of `role="tab"` items; the matching `tabpanel` is the
49
+ * editor body rendered by the surface. Arrow keys move focus between tabs and
50
+ * activate; Delete/Backspace closes the focused tab. The visual close "X" is a
51
+ * presentational (`aria-hidden`) mouse affordance — assistive tech closes via
52
+ * the keyboard, so the X is not a nested interactive control (WCAG 4.1.2). All
53
+ * visual properties flow through `--stgm-*` tokens (DD-005).
54
+ */
55
+ export function EditorTabs({
56
+ editors,
57
+ activeKey,
58
+ onActivate,
59
+ onPin,
60
+ onClose,
61
+ panelId,
62
+ tabIdPrefix,
63
+ className,
64
+ }: EditorTabsProps) {
65
+ const move = useCallback(
66
+ (from: number, delta: number) => {
67
+ const next = from + delta;
68
+ if (next < 0 || next >= editors.length) return;
69
+ const editor = editors[next];
70
+ onActivate(editor.entryId, editor.path);
71
+ },
72
+ [editors, onActivate],
73
+ );
74
+
75
+ return (
76
+ <div
77
+ role="tablist"
78
+ aria-label="Open editors"
79
+ aria-orientation="horizontal"
80
+ className={cn(
81
+ "flex shrink-0 items-stretch overflow-x-auto border-b border-border",
82
+ className,
83
+ )}
84
+ >
85
+ {editors.map((editor, index) => {
86
+ const key = editorKey(editor.entryId, editor.path);
87
+ const isActive = key === activeKey;
88
+ const lastSlash = editor.path.lastIndexOf("/");
89
+ const basename =
90
+ lastSlash >= 0 ? editor.path.slice(lastSlash + 1) : editor.path;
91
+
92
+ const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {
93
+ if (e.key === "ArrowRight") {
94
+ e.preventDefault();
95
+ move(index, 1);
96
+ } else if (e.key === "ArrowLeft") {
97
+ e.preventDefault();
98
+ move(index, -1);
99
+ } else if (e.key === "Enter" || e.key === " ") {
100
+ e.preventDefault();
101
+ onActivate(editor.entryId, editor.path);
102
+ } else if (e.key === "Delete" || e.key === "Backspace") {
103
+ e.preventDefault();
104
+ onClose(editor.entryId, editor.path);
105
+ }
106
+ };
107
+
108
+ const handleAuxClick = (e: MouseEvent<HTMLDivElement>) => {
109
+ // Middle click closes, matching browser/editor tab conventions.
110
+ if (e.button === 1) {
111
+ e.preventDefault();
112
+ onClose(editor.entryId, editor.path);
113
+ }
114
+ };
115
+
116
+ return (
117
+ <div
118
+ key={key}
119
+ role="tab"
120
+ id={tabIdPrefix ? editorTabDomId(tabIdPrefix, key) : undefined}
121
+ aria-selected={isActive}
122
+ aria-controls={panelId}
123
+ tabIndex={isActive ? 0 : -1}
124
+ title={editor.path}
125
+ onClick={() => onActivate(editor.entryId, editor.path)}
126
+ onDoubleClick={() => onPin(editor.entryId, editor.path)}
127
+ onAuxClick={handleAuxClick}
128
+ onKeyDown={handleKeyDown}
129
+ className={cn(
130
+ "group flex max-w-[12rem] shrink-0 cursor-pointer items-center gap-1.5 border-r border-border px-3 py-1.5 text-xs transition-colors",
131
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
132
+ isActive
133
+ ? "bg-background text-foreground"
134
+ : "bg-muted-faint text-muted-foreground hover:bg-muted hover:text-foreground",
135
+ )}
136
+ >
137
+ <span className={cn("truncate", editor.preview && "italic")}>
138
+ {basename}
139
+ </span>
140
+ {/* The visual close "X" is a presentational mouse affordance, NOT a
141
+ nested interactive control: a `<button>` inside `role="tab"` would
142
+ violate WCAG 4.1.2 (axe `nested-interactive`). Assistive tech and
143
+ keyboard users close the focused tab via Delete/Backspace (handled
144
+ above), so `aria-hidden` here removes the redundant nested control
145
+ without losing the close action for anyone. */}
146
+ <span
147
+ aria-hidden="true"
148
+ title={`Close ${basename}`}
149
+ onClick={(e) => {
150
+ e.stopPropagation();
151
+ onClose(editor.entryId, editor.path);
152
+ }}
153
+ className={cn(
154
+ "shrink-0 cursor-pointer rounded p-0.5 text-muted-foreground transition-opacity hover:bg-accent-hover hover:text-foreground",
155
+ isActive ? "opacity-100" : "opacity-0 group-hover:opacity-100",
156
+ )}
157
+ >
158
+ <CloseIcon />
159
+ </span>
160
+ </div>
161
+ );
162
+ })}
163
+ </div>
164
+ );
165
+ }
166
+
167
+ function CloseIcon() {
168
+ return (
169
+ <svg width="12" height="12" viewBox="0 0 14 14" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
170
+ <path d="M3.5 3.5L10.5 10.5" />
171
+ <path d="M10.5 3.5L3.5 10.5" />
172
+ </svg>
173
+ );
174
+ }
@@ -0,0 +1,253 @@
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+ import { cn } from "@stigmer/theme";
5
+ import { FileTreeNode } from "../internal/file-tree/index.js";
6
+ import type { SelectedWorkspaceFile } from "../internal/store/index.js";
7
+ import { useWorkspaceFiles } from "./useWorkspaceFiles.js";
8
+ import type { WorkspaceEntry } from "./useWorkspaceEntries.js";
9
+ import type { WorkspaceFileLister } from "./WorkspaceFileLister.js";
10
+
11
+ /** Props for {@link ExplorerTree}. */
12
+ export interface ExplorerTreeProps {
13
+ /** Workspace entries, each rendered as a collapsible root (multi-root). */
14
+ readonly entries: readonly WorkspaceEntry[];
15
+ /** Platform-injected file lister. */
16
+ readonly lister: WorkspaceFileLister;
17
+ /** The active file, highlighted in the tree. */
18
+ readonly selectedFile: SelectedWorkspaceFile | null;
19
+ /** Single click: open as a preview tab. */
20
+ readonly onOpenFile: (entryId: string, path: string) => void;
21
+ /** Double click: pin the file (persistent tab). */
22
+ readonly onActivateFile: (entryId: string, path: string) => void;
23
+ /**
24
+ * Detach a workspace entry. When provided, each root header carries a remove
25
+ * control (VS Code's "Remove Folder from Workspace"); when absent the
26
+ * explorer is browse-only.
27
+ */
28
+ readonly onRemoveEntry?: (entryId: string) => void;
29
+ }
30
+
31
+ /**
32
+ * The workspace surface's multi-root file explorer — the bare, VS Code-style
33
+ * tree: file-type icons, indent guides, single-click preview / double-click
34
+ * pin, optional per-root remove controls. Search lives in the surface's rail,
35
+ * not per root; listings come from the shared `useWorkspaceFiles` cache.
36
+ *
37
+ * All visual properties flow through `--stgm-*` tokens (DD-005).
38
+ */
39
+ export function ExplorerTree({
40
+ entries,
41
+ lister,
42
+ selectedFile,
43
+ onOpenFile,
44
+ onActivateFile,
45
+ onRemoveEntry,
46
+ }: ExplorerTreeProps) {
47
+ return (
48
+ <div className="flex flex-col">
49
+ {entries.map((entry, index) => (
50
+ <ExplorerRoot
51
+ key={entry.id}
52
+ entry={entry}
53
+ lister={lister}
54
+ defaultExpanded={index === 0}
55
+ selectedPath={
56
+ selectedFile?.entryId === entry.id ? selectedFile.path : undefined
57
+ }
58
+ onOpenFile={onOpenFile}
59
+ onActivateFile={onActivateFile}
60
+ onRemove={onRemoveEntry}
61
+ />
62
+ ))}
63
+ </div>
64
+ );
65
+ }
66
+
67
+ /** One workspace root: a collapsible header over its file tree. */
68
+ function ExplorerRoot({
69
+ entry,
70
+ lister,
71
+ defaultExpanded,
72
+ selectedPath,
73
+ onOpenFile,
74
+ onActivateFile,
75
+ onRemove,
76
+ }: {
77
+ readonly entry: WorkspaceEntry;
78
+ readonly lister: WorkspaceFileLister;
79
+ readonly defaultExpanded: boolean;
80
+ readonly selectedPath: string | undefined;
81
+ readonly onOpenFile: (entryId: string, path: string) => void;
82
+ readonly onActivateFile: (entryId: string, path: string) => void;
83
+ readonly onRemove?: (entryId: string) => void;
84
+ }) {
85
+ const [expanded, setExpanded] = useState(defaultExpanded);
86
+ const { tree, isLoading, error, truncated, refresh } = useWorkspaceFiles({
87
+ entry: expanded ? entry : null,
88
+ lister,
89
+ });
90
+
91
+ return (
92
+ <div className="flex flex-col">
93
+ <div className="group/root flex items-stretch">
94
+ <button
95
+ type="button"
96
+ onClick={() => setExpanded((prev) => !prev)}
97
+ aria-expanded={expanded}
98
+ className={cn(
99
+ "flex min-w-0 flex-1 items-center gap-1.5 px-1.5 py-1 text-left text-[0.7rem] font-semibold uppercase tracking-wide text-foreground transition-colors hover:bg-accent-hover",
100
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
101
+ )}
102
+ title={entry.type === "local" ? entry.localPath : entry.gitUrl}
103
+ >
104
+ <span
105
+ aria-hidden="true"
106
+ className="text-[10px] text-muted-foreground-subtle"
107
+ >
108
+ {expanded ? "▼" : "▶"}
109
+ </span>
110
+ <span className="truncate">{entry.name}</span>
111
+ </button>
112
+ {onRemove && (
113
+ <button
114
+ type="button"
115
+ onClick={() => onRemove(entry.id)}
116
+ aria-label={`Remove ${entry.name} from workspace`}
117
+ title={`Remove ${entry.name} from workspace`}
118
+ className={cn(
119
+ "shrink-0 px-1.5 text-muted-foreground opacity-0 transition-opacity",
120
+ "group-hover/root:opacity-100 focus-visible:opacity-100",
121
+ "hover:text-destructive focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
122
+ )}
123
+ >
124
+ <RemoveIcon />
125
+ </button>
126
+ )}
127
+ </div>
128
+
129
+ {expanded && (
130
+ <ExplorerRootBody
131
+ entryName={entry.name}
132
+ entryId={entry.id}
133
+ tree={tree}
134
+ isLoading={isLoading}
135
+ error={error}
136
+ truncated={truncated}
137
+ selectedPath={selectedPath}
138
+ onOpenFile={onOpenFile}
139
+ onActivateFile={onActivateFile}
140
+ onRetry={refresh}
141
+ />
142
+ )}
143
+ </div>
144
+ );
145
+ }
146
+
147
+ function ExplorerRootBody({
148
+ entryName,
149
+ entryId,
150
+ tree,
151
+ isLoading,
152
+ error,
153
+ truncated,
154
+ selectedPath,
155
+ onOpenFile,
156
+ onActivateFile,
157
+ onRetry,
158
+ }: {
159
+ readonly entryName: string;
160
+ readonly entryId: string;
161
+ readonly tree: ReturnType<typeof useWorkspaceFiles>["tree"];
162
+ readonly isLoading: boolean;
163
+ readonly error: Error | null;
164
+ readonly truncated: boolean;
165
+ readonly selectedPath: string | undefined;
166
+ readonly onOpenFile: (entryId: string, path: string) => void;
167
+ readonly onActivateFile: (entryId: string, path: string) => void;
168
+ readonly onRetry: () => void;
169
+ }) {
170
+ if (isLoading) {
171
+ return (
172
+ <div
173
+ // role="status" both announces the loading state to assistive tech and
174
+ // makes aria-label permitted here (a role-less generic div cannot carry
175
+ // an accessible name — axe `aria-prohibited-attr`).
176
+ role="status"
177
+ className="space-y-1.5 px-2 py-2"
178
+ aria-busy="true"
179
+ aria-label={`Loading files for ${entryName}`}
180
+ >
181
+ {[1, 2, 3, 4].map((i) => (
182
+ <div
183
+ key={i}
184
+ className="h-3.5 animate-pulse rounded bg-muted"
185
+ style={{ width: `${50 + i * 10}%` }}
186
+ aria-hidden="true"
187
+ />
188
+ ))}
189
+ </div>
190
+ );
191
+ }
192
+
193
+ if (error) {
194
+ return (
195
+ <div className="px-2 py-2 text-xs text-destructive">
196
+ Failed to list files: {error.message}
197
+ <button
198
+ type="button"
199
+ onClick={onRetry}
200
+ className="ml-2 rounded-sm underline transition-colors hover:text-destructive focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
201
+ >
202
+ Retry
203
+ </button>
204
+ </div>
205
+ );
206
+ }
207
+
208
+ if (tree.length === 0) {
209
+ return (
210
+ <p className="px-3 py-2 text-xs text-muted-foreground">No files found.</p>
211
+ );
212
+ }
213
+
214
+ return (
215
+ <>
216
+ <nav aria-label={`File tree for ${entryName}`}>
217
+ <ul className="py-0.5 pl-1.5" role="tree">
218
+ {tree.map((node) => (
219
+ <FileTreeNode
220
+ key={node.path}
221
+ node={node}
222
+ selectedPath={selectedPath ?? ""}
223
+ onSelect={(path) => onOpenFile(entryId, path)}
224
+ onActivate={(path) => onActivateFile(entryId, path)}
225
+ depth={0}
226
+ enableDrag
227
+ showIcons
228
+ indentGuides
229
+ maxInitialDepth={0}
230
+ />
231
+ ))}
232
+ </ul>
233
+ </nav>
234
+ {truncated && (
235
+ <p className="px-3 py-1.5 text-[0.65rem] text-muted-foreground">
236
+ Showing a partial listing — too many files to load in full.
237
+ </p>
238
+ )}
239
+ </>
240
+ );
241
+ }
242
+
243
+ // ---------------------------------------------------------------------------
244
+ // Inline SVG icons (SDK independence — no lucide dependency)
245
+ // ---------------------------------------------------------------------------
246
+
247
+ function RemoveIcon() {
248
+ return (
249
+ <svg width="12" height="12" viewBox="0 0 14 14" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
250
+ <path d="M4 4L10 10M10 4L4 10" />
251
+ </svg>
252
+ );
253
+ }