@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,361 @@
1
+ "use client";
2
+
3
+ import { useMemo, useState } from "react";
4
+ import Markdown from "react-markdown";
5
+ import { cn } from "@stigmer/theme";
6
+ import {
7
+ PLAN_DOCUMENT_MARKDOWN_COMPONENTS,
8
+ REMARK_PLUGINS,
9
+ extractLeadingH1,
10
+ unwrapEnclosingMarkdownFence,
11
+ } from "../internal/markdown-components.js";
12
+ import { useArtifactContent } from "../execution/useArtifactContent.js";
13
+ import { useBuildFromPlanHotkey } from "../execution/use-build-from-plan-hotkey.js";
14
+ import { formatArtifactSize } from "../execution/artifact-utils.js";
15
+ import type { SessionPlan } from "../library/detect-plan-artifact.js";
16
+ import type { PlanDraftController } from "./usePlanDraft.js";
17
+
18
+ /** Props for {@link PlanEditor}. */
19
+ export interface PlanEditorProps {
20
+ /** The plan to display (latest, or a superseded plan opened from its card). */
21
+ readonly plan: SessionPlan;
22
+ /**
23
+ * Draft controller owned by the viewer (survives panel collapse/unmounts).
24
+ * Consulted only when editable — a read-only (superseded) plan renders its
25
+ * own artifact text, never the current plan's draft.
26
+ */
27
+ readonly draft?: PlanDraftController;
28
+ /** Builds from the plan — the same action as the thread card's primary. */
29
+ readonly onBuildFromPlan?: () => void;
30
+ /** Disables the Build action (execution in flight, or build submitting). */
31
+ readonly buildDisabled?: boolean;
32
+ /**
33
+ * Renders the plan as a historical, read-only document: no Edit view, no
34
+ * Build action, and a "superseded" notice. Used when the user opens a plan
35
+ * that a newer plan has since replaced.
36
+ */
37
+ readonly readOnly?: boolean;
38
+ }
39
+
40
+ type PlanEditorView = "rendered" | "source" | "edit";
41
+
42
+ /**
43
+ * The plan document for the workspace surface's editor area — the wide-pane
44
+ * successor of the retired Plan sidebar facet, mounted as a virtual document
45
+ * (`SurfaceVirtualDocument`) under the {@link PLAN_DOCUMENT_ENTRY_ID} tab.
46
+ *
47
+ * Three views over one text:
48
+ * - **Rendered** — the plan as a document (same typography as the thread's
49
+ * plan rendering, title lifted from the leading H1).
50
+ * - **Source** — the raw markdown.
51
+ * - **Edit** — a plain-textarea editor over a LOCAL draft
52
+ * ({@link PlanDraftController}); the published artifact is never mutated.
53
+ * Building from an edited plan delivers the draft to the implement
54
+ * execution (edit-as-input).
55
+ *
56
+ * All views show the *effective* plan — the draft when one exists, the
57
+ * published artifact otherwise — so what the user reviews is exactly what
58
+ * Build will implement. An "Edited" indicator plus Revert makes the overlay
59
+ * visible and reversible.
60
+ *
61
+ * Editing is disabled for truncated content (the content RPC caps at 512 KB):
62
+ * editing a truncated plan would silently drop its tail on handoff. The
63
+ * document still renders read-only with the truncation notice.
64
+ *
65
+ * Holds no must-survive local state: the panel region unmounts wholesale on
66
+ * collapse, so anything that must outlive it (the draft, the fetched content
67
+ * cache) is owned above. The view pick resetting to Rendered on reopen is
68
+ * deliberate.
69
+ *
70
+ * All visual properties flow through `--stgm-*` tokens.
71
+ */
72
+ export function PlanEditor({
73
+ plan,
74
+ draft,
75
+ onBuildFromPlan,
76
+ buildDisabled,
77
+ readOnly,
78
+ }: PlanEditorProps) {
79
+ const [view, setView] = useState<PlanEditorView>("rendered");
80
+ const canBuild = !readOnly && onBuildFromPlan !== undefined;
81
+ const handleKeyDown = useBuildFromPlanHotkey(
82
+ canBuild ? onBuildFromPlan : undefined,
83
+ buildDisabled,
84
+ );
85
+
86
+ const { content, isTruncated, isLoading, error, refetch } =
87
+ useArtifactContent(
88
+ plan.executionId,
89
+ plan.artifact.storageKey,
90
+ undefined,
91
+ plan.artifact.contentHash,
92
+ );
93
+
94
+ const activeDraft = readOnly ? undefined : draft;
95
+ const effectiveText = activeDraft?.draftText ?? content;
96
+ // A read-only plan (or one without a draft controller) never offers Edit;
97
+ // a truncated plan only keeps it while an existing draft needs rescuing.
98
+ const canEdit = activeDraft !== undefined && (!isTruncated || activeDraft.isEdited);
99
+ const activeView: PlanEditorView = view === "edit" && !canEdit ? "rendered" : view;
100
+
101
+ if (isLoading) {
102
+ return (
103
+ <PlanEditorFrame>
104
+ <PlanEditorSkeleton />
105
+ </PlanEditorFrame>
106
+ );
107
+ }
108
+
109
+ if (error || effectiveText === null) {
110
+ return (
111
+ <PlanEditorFrame>
112
+ <div className="flex flex-col items-center gap-2 px-4 py-8 text-center">
113
+ <p className="text-xs text-muted-foreground">
114
+ Couldn&rsquo;t load the plan{error ? `: ${error.message}` : "."}
115
+ </p>
116
+ <button
117
+ type="button"
118
+ onClick={refetch}
119
+ className="rounded text-xs font-medium text-foreground underline-offset-2 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
120
+ >
121
+ Retry
122
+ </button>
123
+ </div>
124
+ </PlanEditorFrame>
125
+ );
126
+ }
127
+
128
+ return (
129
+ <PlanEditorFrame onKeyDown={handleKeyDown}>
130
+ {/* Toolbar: view tabs lead; state + the one primary action trail.
131
+ Narrow panes are first-class: rows wrap (flex-wrap) and every item
132
+ can shrink (min-w-0 + truncating labels), so the toolbar reflows
133
+ instead of forcing the document pane to scroll sideways. */}
134
+ <div className="flex min-w-0 flex-wrap items-center gap-2">
135
+ <div
136
+ className="inline-flex shrink-0 rounded-md bg-muted p-0.5"
137
+ role="tablist"
138
+ aria-label="Plan view"
139
+ >
140
+ <ViewTab
141
+ active={activeView === "rendered"}
142
+ onClick={() => setView("rendered")}
143
+ label="Rendered"
144
+ />
145
+ <ViewTab
146
+ active={activeView === "source"}
147
+ onClick={() => setView("source")}
148
+ label="Source"
149
+ />
150
+ {activeDraft !== undefined && (
151
+ <ViewTab
152
+ active={activeView === "edit"}
153
+ onClick={() => setView("edit")}
154
+ label="Edit"
155
+ disabled={!canEdit}
156
+ title={
157
+ !canEdit
158
+ ? "This plan is too large to edit in place — download it instead."
159
+ : undefined
160
+ }
161
+ />
162
+ )}
163
+ </div>
164
+ <span className="text-[0.65rem] tabular-nums text-muted-foreground-faint">
165
+ {formatArtifactSize(plan.artifact.sizeBytes)}
166
+ </span>
167
+
168
+ <div className="ml-auto flex min-w-0 flex-wrap items-center gap-3">
169
+ {activeDraft?.isEdited && (
170
+ <span className="inline-flex items-center gap-2">
171
+ <span className="rounded-md bg-accent px-1.5 py-0.5 text-[0.65rem] font-medium text-muted-foreground">
172
+ Edited
173
+ </span>
174
+ <button
175
+ type="button"
176
+ onClick={() => activeDraft.setDraft(null)}
177
+ className="rounded text-[0.65rem] font-medium text-muted-foreground underline-offset-2 hover:text-foreground hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
178
+ >
179
+ Revert
180
+ </button>
181
+ </span>
182
+ )}
183
+ {readOnly ? (
184
+ <span
185
+ role="status"
186
+ className="rounded-md bg-muted px-2 py-0.5 text-[0.65rem] font-medium text-muted-foreground"
187
+ >
188
+ Superseded by a newer plan
189
+ </span>
190
+ ) : (
191
+ onBuildFromPlan && (
192
+ <button
193
+ type="button"
194
+ disabled={buildDisabled}
195
+ onClick={onBuildFromPlan}
196
+ className={cn(
197
+ "inline-flex min-w-0 items-center gap-1.5 rounded-md px-3 py-1.5",
198
+ "text-xs font-medium transition-colors",
199
+ "bg-primary text-primary-foreground hover:bg-primary-hover",
200
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
201
+ "disabled:pointer-events-none disabled:opacity-50",
202
+ )}
203
+ >
204
+ <ImplementIcon />
205
+ <span className="truncate">
206
+ {buildDisabled ? "Starting build…" : "Build from plan"}
207
+ </span>
208
+ </button>
209
+ )
210
+ )}
211
+ </div>
212
+ </div>
213
+
214
+ {activeView === "rendered" && <RenderedPlan text={effectiveText} />}
215
+ {activeView === "source" && (
216
+ <pre className="overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs whitespace-pre-wrap text-foreground">
217
+ {effectiveText}
218
+ </pre>
219
+ )}
220
+ {activeView === "edit" && activeDraft !== undefined && (
221
+ <textarea
222
+ value={effectiveText}
223
+ onChange={(e) => activeDraft.setDraft(e.target.value)}
224
+ aria-label="Edit plan"
225
+ spellCheck={false}
226
+ rows={28}
227
+ className={cn(
228
+ "w-full flex-1 resize-y rounded-md border border-border bg-card p-3",
229
+ "font-mono text-xs leading-relaxed text-foreground",
230
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
231
+ )}
232
+ />
233
+ )}
234
+
235
+ {isTruncated && (
236
+ <p role="status" className="text-[0.65rem] text-muted-foreground">
237
+ Preview truncated — download the artifact for the full plan.
238
+ </p>
239
+ )}
240
+ </PlanEditorFrame>
241
+ );
242
+ }
243
+
244
+ /**
245
+ * The editor-area envelope: a centered document column so the plan reads as a
246
+ * page rather than stretching across the full pane width.
247
+ */
248
+ function PlanEditorFrame({
249
+ children,
250
+ onKeyDown,
251
+ }: {
252
+ readonly children: React.ReactNode;
253
+ readonly onKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;
254
+ }) {
255
+ return (
256
+ <div
257
+ role="article"
258
+ aria-label="Plan document"
259
+ onKeyDown={onKeyDown}
260
+ className="mx-auto flex w-full max-w-3xl flex-col gap-3 px-4 py-3"
261
+ >
262
+ {children}
263
+ </div>
264
+ );
265
+ }
266
+
267
+ /**
268
+ * The plan document: title lifted from the leading H1, body in the shared
269
+ * plan-document typography — identical treatment to the thread's plan
270
+ * rendering, so the plan reads the same on every surface.
271
+ */
272
+ function RenderedPlan({ text }: { readonly text: string }) {
273
+ const { title, body } = useMemo(
274
+ () => extractLeadingH1(unwrapEnclosingMarkdownFence(text, true)),
275
+ [text],
276
+ );
277
+
278
+ return (
279
+ <div className="overflow-hidden rounded-lg border border-border-muted bg-card">
280
+ {title && (
281
+ <header className="border-b border-border-muted bg-muted-faint px-4 py-2.5">
282
+ <span className="block truncate text-sm font-semibold text-foreground">
283
+ {title}
284
+ </span>
285
+ </header>
286
+ )}
287
+ <div className="stgm-prose px-4 py-4">
288
+ <Markdown
289
+ remarkPlugins={REMARK_PLUGINS}
290
+ components={PLAN_DOCUMENT_MARKDOWN_COMPONENTS}
291
+ >
292
+ {body}
293
+ </Markdown>
294
+ </div>
295
+ </div>
296
+ );
297
+ }
298
+
299
+ function PlanEditorSkeleton() {
300
+ return (
301
+ <div className="space-y-2 py-2" aria-hidden="true">
302
+ <div className="h-8 w-full animate-pulse rounded-md bg-muted" />
303
+ <div className="h-4 w-2/3 animate-pulse rounded bg-muted" />
304
+ <div className="h-4 w-full animate-pulse rounded bg-muted" />
305
+ <div className="h-4 w-5/6 animate-pulse rounded bg-muted" />
306
+ </div>
307
+ );
308
+ }
309
+
310
+ function ViewTab({
311
+ active,
312
+ onClick,
313
+ label,
314
+ disabled,
315
+ title,
316
+ }: {
317
+ readonly active: boolean;
318
+ readonly onClick: () => void;
319
+ readonly label: string;
320
+ readonly disabled?: boolean;
321
+ readonly title?: string;
322
+ }) {
323
+ return (
324
+ <button
325
+ type="button"
326
+ role="tab"
327
+ aria-selected={active}
328
+ onClick={onClick}
329
+ disabled={disabled}
330
+ title={title}
331
+ className={cn(
332
+ "rounded px-2 py-0.5 text-[0.65rem] font-medium transition-colors",
333
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
334
+ active
335
+ ? "bg-card text-foreground shadow-sm"
336
+ : "text-muted-foreground hover:text-foreground",
337
+ "disabled:pointer-events-none disabled:opacity-50",
338
+ )}
339
+ >
340
+ {label}
341
+ </button>
342
+ );
343
+ }
344
+
345
+ function ImplementIcon() {
346
+ return (
347
+ <svg
348
+ width="12"
349
+ height="12"
350
+ viewBox="0 0 12 12"
351
+ fill="none"
352
+ stroke="currentColor"
353
+ strokeWidth="1.5"
354
+ strokeLinecap="round"
355
+ strokeLinejoin="round"
356
+ aria-hidden="true"
357
+ >
358
+ <path d="M2 6h8M7 3l3 3-3 3" />
359
+ </svg>
360
+ );
361
+ }
@@ -0,0 +1,97 @@
1
+ "use client";
2
+
3
+ import { useMemo } from "react";
4
+ import { Streamdown } from "streamdown";
5
+ import {
6
+ PLAN_DOCUMENT_MARKDOWN_COMPONENTS,
7
+ extractLeadingH1,
8
+ } from "../internal/markdown-components.js";
9
+
10
+ /** Props for {@link PlanStreamingDocument}. */
11
+ export interface PlanStreamingDocumentProps {
12
+ /**
13
+ * The live plan text, already fence-stripped by `findStreamingPlan`
14
+ * (`StreamingPlan.displayText`). Grows on every stream commit.
15
+ */
16
+ readonly displayText: string;
17
+ }
18
+
19
+ /**
20
+ * The plan document tab's LIVE view: renders the plan as it streams, before
21
+ * any artifact exists. The streaming counterpart of {@link PlanEditor} — same
22
+ * centered document column, same header-lifted title, same plan-document
23
+ * typography — so the moment the turn completes and the artifact-backed
24
+ * editor takes over, the document simply stops moving rather than changing
25
+ * shape.
26
+ *
27
+ * Deliberately capability-free: no view tabs, no Edit, no Build — a plan in
28
+ * flight cannot be edited or implemented, and offering dead controls would
29
+ * misstate the turn's state. A "Writing…" status pill stands where the
30
+ * editor's toolbar will appear.
31
+ *
32
+ * Rendering goes through `Streamdown` (the same streaming-aware renderer the
33
+ * thread's `AiMessage` uses: block-level memoization, incomplete-syntax
34
+ * healing, animated caret) rather than `PlanEditor`'s static markdown — this
35
+ * component re-renders on every stream commit by design.
36
+ *
37
+ * All visual properties flow through `--stgm-*` tokens.
38
+ */
39
+ export function PlanStreamingDocument({
40
+ displayText,
41
+ }: PlanStreamingDocumentProps) {
42
+ const { title, body } = useMemo(
43
+ () => extractLeadingH1(displayText),
44
+ [displayText],
45
+ );
46
+
47
+ return (
48
+ <div
49
+ role="article"
50
+ aria-label="Plan document"
51
+ aria-busy="true"
52
+ className="mx-auto flex w-full max-w-3xl flex-col gap-3 px-4 py-3"
53
+ >
54
+ <div className="flex min-w-0 flex-wrap items-center gap-2">
55
+ <span
56
+ role="status"
57
+ className="inline-flex items-center gap-1.5 rounded-md bg-muted px-2 py-0.5 text-[0.65rem] font-medium text-muted-foreground"
58
+ >
59
+ <WritingDot />
60
+ Writing…
61
+ </span>
62
+ </div>
63
+
64
+ <div className="overflow-hidden rounded-lg border border-border-muted bg-card">
65
+ {title && (
66
+ <header className="border-b border-border-muted bg-muted-faint px-4 py-2.5">
67
+ <span className="block truncate text-sm font-semibold text-foreground">
68
+ {title}
69
+ </span>
70
+ </header>
71
+ )}
72
+ <div className="stgm-prose px-4 py-4">
73
+ <Streamdown
74
+ components={PLAN_DOCUMENT_MARKDOWN_COMPONENTS}
75
+ isAnimating
76
+ caret="block"
77
+ >
78
+ {body}
79
+ </Streamdown>
80
+ </div>
81
+ </div>
82
+ </div>
83
+ );
84
+ }
85
+
86
+ /**
87
+ * The pill's pulsing dot — a CSS animation inside `.stgm`, covered by the
88
+ * stylesheet's global `prefers-reduced-motion` rule (DD-015).
89
+ */
90
+ function WritingDot() {
91
+ return (
92
+ <span
93
+ aria-hidden="true"
94
+ className="size-1.5 animate-pulse rounded-full bg-primary"
95
+ />
96
+ );
97
+ }
@@ -0,0 +1,103 @@
1
+ "use client";
2
+
3
+ import { useEffect, useRef } from "react";
4
+ import { cn } from "@stigmer/theme";
5
+
6
+ /** Props for {@link SessionPanelChip}. */
7
+ export interface SessionPanelChipProps {
8
+ /** Whether the panel is currently expanded. */
9
+ readonly isOpen: boolean;
10
+ /** Toggles the panel open/collapsed. */
11
+ readonly onToggle: () => void;
12
+ /**
13
+ * Aggregate count of facet items (write-backs + artifacts) awaiting the
14
+ * user. Rendered as a dot-count while collapsed — the panel's only "something
15
+ * arrived" signal, since arrivals never auto-open the panel.
16
+ */
17
+ readonly badgeCount?: number;
18
+ }
19
+
20
+ /**
21
+ * The always-mounted top-right toggle for the unified session panel — the
22
+ * Cursor "Show panel" chip. Collapsed, it carries the pending-item count;
23
+ * open, it is the hide affordance. Being a small leaf, it is also the one
24
+ * place that may safely carry per-arrival re-renders while the panel subtree
25
+ * is unmounted. Execution status deliberately does not surface here (or
26
+ * anywhere else in the viewer chrome) — the thread itself communicates run
27
+ * state.
28
+ *
29
+ * All visual properties flow through `--stgm-*` tokens (DD-005).
30
+ */
31
+ export function SessionPanelChip({
32
+ isOpen,
33
+ onToggle,
34
+ badgeCount,
35
+ }: SessionPanelChipProps) {
36
+ const showCount = !isOpen && badgeCount != null && badgeCount > 0;
37
+
38
+ // Focus restoration: collapsing unmounts the panel subtree, so keyboard
39
+ // focus that lived inside it (rail, tabs, viewer) falls to <body>. Reclaim
40
+ // it here — the chip is the collapse's logical origin. Focus resting
41
+ // anywhere else (e.g. the composer) is respected. Opening deliberately does
42
+ // NOT move focus: the chip is a standard disclosure trigger.
43
+ const buttonRef = useRef<HTMLButtonElement>(null);
44
+ const prevOpenRef = useRef(isOpen);
45
+ useEffect(() => {
46
+ if (prevOpenRef.current && !isOpen && document.activeElement === document.body) {
47
+ buttonRef.current?.focus();
48
+ }
49
+ prevOpenRef.current = isOpen;
50
+ }, [isOpen]);
51
+
52
+ return (
53
+ <button
54
+ ref={buttonRef}
55
+ type="button"
56
+ onClick={onToggle}
57
+ aria-expanded={isOpen}
58
+ aria-label={isOpen ? "Hide panel" : "Show panel"}
59
+ title={isOpen ? "Hide panel" : "Show panel"}
60
+ className={cn(
61
+ "flex items-center gap-1.5 rounded-md border border-border bg-card px-1.5 py-1",
62
+ "text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
63
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
64
+ )}
65
+ >
66
+ {showCount && (
67
+ <span
68
+ aria-label={`${badgeCount} new items`}
69
+ className="inline-flex min-w-[1rem] items-center justify-center rounded-full bg-primary px-1 py-px text-[10px] font-medium leading-none text-primary-foreground"
70
+ >
71
+ {badgeCount}
72
+ </span>
73
+ )}
74
+ <PanelIcon open={isOpen} />
75
+ </button>
76
+ );
77
+ }
78
+
79
+ /**
80
+ * Panel-layout glyph: a frame with its right region filled while the panel is
81
+ * open, hollow while collapsed — mirroring the state it toggles to at a glance.
82
+ */
83
+ function PanelIcon({ open }: { readonly open: boolean }) {
84
+ return (
85
+ <svg
86
+ width="16"
87
+ height="16"
88
+ viewBox="0 0 16 16"
89
+ fill="none"
90
+ stroke="currentColor"
91
+ strokeWidth="1.3"
92
+ strokeLinecap="round"
93
+ strokeLinejoin="round"
94
+ aria-hidden="true"
95
+ >
96
+ <rect x="1.5" y="2.5" width="13" height="11" rx="1.5" />
97
+ <path d="M9.5 2.5v11" />
98
+ {open && (
99
+ <rect x="9.5" y="2.5" width="5" height="11" rx="1.5" fill="currentColor" stroke="none" />
100
+ )}
101
+ </svg>
102
+ );
103
+ }