@puredesktop/puredesktop-ui-bridge 1.0.0-beta.1

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 (412) hide show
  1. package/package.json +96 -0
  2. package/src/agents/runtime/agentLiveReducer.test.ts +72 -0
  3. package/src/agents/runtime/agentLiveReducer.ts +139 -0
  4. package/src/agents/runtime/agentRunEventTypes.ts +115 -0
  5. package/src/agents/runtime/contextWindowUsage.test.ts +38 -0
  6. package/src/agents/runtime/contextWindowUsage.ts +25 -0
  7. package/src/agents/runtime/index.ts +24 -0
  8. package/src/agents/runtime/mapAgentMessages.ts +54 -0
  9. package/src/agents/runtime/mapAgentSnapshot.ts +71 -0
  10. package/src/agents/runtime/mergeUsageTurn.ts +23 -0
  11. package/src/agents/runtime/pendingToolCalls.test.ts +85 -0
  12. package/src/agents/runtime/pendingToolCalls.ts +14 -0
  13. package/src/agents/runtime/toolRequiresApproval.ts +20 -0
  14. package/src/agents/runtime/unresolvedToolCalls.ts +42 -0
  15. package/src/bridge/agentModelTiers.ts +50 -0
  16. package/src/bridge/agentToolHandlers.ts +23 -0
  17. package/src/bridge/agentToolHelpers.test.ts +27 -0
  18. package/src/bridge/agentToolHelpers.ts +20 -0
  19. package/src/bridge/agentTypes.ts +294 -0
  20. package/src/bridge/agents.d.mts +113 -0
  21. package/src/bridge/agents.mjs +233 -0
  22. package/src/bridge/agents.ts +62 -0
  23. package/src/bridge/appSettings.d.mts +9 -0
  24. package/src/bridge/appSettings.mjs +18 -0
  25. package/src/bridge/appSettings.ts +4 -0
  26. package/src/bridge/applyThemeFromHost.d.mts +7 -0
  27. package/src/bridge/applyThemeFromHost.mjs +33 -0
  28. package/src/bridge/assets.d.mts +66 -0
  29. package/src/bridge/assets.mjs +121 -0
  30. package/src/bridge/catalog.d.mts +5 -0
  31. package/src/bridge/catalog.mjs +24 -0
  32. package/src/bridge/catalog.ts +1 -0
  33. package/src/bridge/client.d.mts +19 -0
  34. package/src/bridge/client.mjs +147 -0
  35. package/src/bridge/collectionAssetAdapter.ts +63 -0
  36. package/src/bridge/collectionAssets.d.mts +1 -0
  37. package/src/bridge/collectionAssets.mjs +2 -0
  38. package/src/bridge/collectionAssets.ts +1 -0
  39. package/src/bridge/collectionDocumentHtml.test.ts +71 -0
  40. package/src/bridge/collectionDocumentHtml.ts +118 -0
  41. package/src/bridge/collectionImagePaste.test.ts +32 -0
  42. package/src/bridge/collectionImagePaste.ts +130 -0
  43. package/src/bridge/context.mjs +12 -0
  44. package/src/bridge/credentials.mjs +22 -0
  45. package/src/bridge/dialog.d.mts +5 -0
  46. package/src/bridge/dialog.mjs +13 -0
  47. package/src/bridge/events.d.mts +14 -0
  48. package/src/bridge/events.mjs +12 -0
  49. package/src/bridge/filePreviewKind.test.ts +43 -0
  50. package/src/bridge/filePreviewKind.ts +76 -0
  51. package/src/bridge/fs.d.mts +41 -0
  52. package/src/bridge/fs.mjs +82 -0
  53. package/src/bridge/fs.test.ts +16 -0
  54. package/src/bridge/fs.ts +10 -0
  55. package/src/bridge/index.ts +12 -0
  56. package/src/bridge/inlinePreview.d.mts +35 -0
  57. package/src/bridge/inlinePreview.mjs +99 -0
  58. package/src/bridge/inlinePreview.test.ts +56 -0
  59. package/src/bridge/inlinePreview.ts +13 -0
  60. package/src/bridge/methods.d.mts +115 -0
  61. package/src/bridge/methods.mjs +132 -0
  62. package/src/bridge/os.d.mts +11 -0
  63. package/src/bridge/os.mjs +26 -0
  64. package/src/bridge/plugins.d.mts +9 -0
  65. package/src/bridge/plugins.mjs +31 -0
  66. package/src/bridge/plugins.ts +5 -0
  67. package/src/bridge/preferences.d.mts +7 -0
  68. package/src/bridge/preferences.mjs +17 -0
  69. package/src/bridge/preferences.ts +13 -0
  70. package/src/bridge/printDocument.test.ts +47 -0
  71. package/src/bridge/printDocument.ts +75 -0
  72. package/src/bridge/pureRender/adapters.test.ts +144 -0
  73. package/src/bridge/pureRender/adapters.ts +175 -0
  74. package/src/bridge/pureRender/assets.test.ts +44 -0
  75. package/src/bridge/pureRender/base.css +76 -0
  76. package/src/bridge/pureRender/compiler.test.ts +279 -0
  77. package/src/bridge/pureRender/compiler.ts +660 -0
  78. package/src/bridge/pureRender/document.test.ts +283 -0
  79. package/src/bridge/pureRender/document.ts +35 -0
  80. package/src/bridge/pureRender/extraction.test.ts +432 -0
  81. package/src/bridge/pureRender/extraction.ts +1023 -0
  82. package/src/bridge/pureRender/flow.css +3 -0
  83. package/src/bridge/pureRender/index.ts +66 -0
  84. package/src/bridge/pureRender/normalize.test.ts +442 -0
  85. package/src/bridge/pureRender/normalize.ts +682 -0
  86. package/src/bridge/pureRender/presets.ts +365 -0
  87. package/src/bridge/pureRender/profiles/book.css +19 -0
  88. package/src/bridge/pureRender/profiles/manuscript.css +11 -0
  89. package/src/bridge/pureRender/profiles/writer.css +10 -0
  90. package/src/bridge/pureRender/reset.css +5 -0
  91. package/src/bridge/pureRender/samples.ts +94 -0
  92. package/src/bridge/pureRender/styles.ts +164 -0
  93. package/src/bridge/pureRender/theme.test.ts +53 -0
  94. package/src/bridge/pureRender/theme.ts +258 -0
  95. package/src/bridge/pureRender/tokens/default.css +36 -0
  96. package/src/bridge/pureRender/tokens/default.json +32 -0
  97. package/src/bridge/pureRender/types.ts +264 -0
  98. package/src/bridge/pureRender/visualLayoutInspection.test.ts +57 -0
  99. package/src/bridge/pureRender/visualLayoutInspection.ts +161 -0
  100. package/src/bridge/react/useDebouncedEffect.ts +21 -0
  101. package/src/bridge/react/useIpc.tsx +75 -0
  102. package/src/bridge/react/usePlatformAgentRunLiveState.tsx +78 -0
  103. package/src/bridge/react/usePlatformAgentSessionDrive.tsx +729 -0
  104. package/src/bridge/react/usePlatformAgentSessions.tsx +60 -0
  105. package/src/bridge/react/usePlatformAgentTools.tsx +82 -0
  106. package/src/bridge/react/usePlatformAppManifest.tsx +32 -0
  107. package/src/bridge/react/usePlatformBridge.tsx +56 -0
  108. package/src/bridge/react/usePlatformDeepLink.tsx +57 -0
  109. package/src/bridge/react/usePlatformFileBinaryDataUrl.tsx +54 -0
  110. package/src/bridge/react/usePlatformFilePreview.tsx +92 -0
  111. package/src/bridge/react/usePlatformPreferences.tsx +77 -0
  112. package/src/bridge/react/usePlatformThemeDocumentAttrs.ts +35 -0
  113. package/src/bridge/react/usePlatformThemeFromBridge.tsx +16 -0
  114. package/src/bridge/react/usePlatformViewportResource.test.tsx +106 -0
  115. package/src/bridge/react/usePlatformViewportResource.tsx +72 -0
  116. package/src/bridge/react/useScheduledTask.tsx +59 -0
  117. package/src/bridge/render.d.mts +31 -0
  118. package/src/bridge/render.mjs +62 -0
  119. package/src/bridge/render.ts +8 -0
  120. package/src/bridge/screenAnnotation.test.ts +103 -0
  121. package/src/bridge/screenAnnotation.ts +269 -0
  122. package/src/bridge/theme.d.mts +3 -0
  123. package/src/bridge/theme.mjs +9 -0
  124. package/src/bridge/types.ts +439 -0
  125. package/src/bridge/watch.d.mts +9 -0
  126. package/src/bridge/watch.mjs +34 -0
  127. package/src/bridge/watch.ts +1 -0
  128. package/src/bridge/window.d.mts +44 -0
  129. package/src/bridge/window.mjs +33 -0
  130. package/src/chrome/index.ts +1 -0
  131. package/src/components/accessibility/AccessibilityReviewDialog.test.tsx +104 -0
  132. package/src/components/accessibility/AccessibilityReviewDialog.tsx +350 -0
  133. package/src/components/accessibility/accessibilityReview.test.ts +101 -0
  134. package/src/components/accessibility/accessibilityReview.ts +639 -0
  135. package/src/components/accessibility/index.ts +16 -0
  136. package/src/components/agent-feedback/ScreenAnnotationAgentDialog.tsx +509 -0
  137. package/src/components/agent-feedback/index.ts +5 -0
  138. package/src/components/agents/AgentComposer.tsx +34 -0
  139. package/src/components/agents/AgentContextUsageBar.tsx +127 -0
  140. package/src/components/agents/AgentDrawerPanel.tsx +82 -0
  141. package/src/components/agents/AgentMarkdown.tsx +12 -0
  142. package/src/components/agents/AgentMessageBubble.tsx +82 -0
  143. package/src/components/agents/AgentMessageList.tsx +47 -0
  144. package/src/components/agents/AgentModelMenu.tsx +55 -0
  145. package/src/components/agents/AgentThinkingBlock.tsx +66 -0
  146. package/src/components/agents/AgentToolApprovalActions.tsx +65 -0
  147. package/src/components/agents/AgentToolCallCard.tsx +26 -0
  148. package/src/components/agents/AgentToolPendingList.tsx +39 -0
  149. package/src/components/agents/AgentToolPendingReview.tsx +118 -0
  150. package/src/components/agents/agentPanelStyles.ts +79 -0
  151. package/src/components/agents/agentTypes.ts +96 -0
  152. package/src/components/agents/formatToolCallArguments.test.ts +16 -0
  153. package/src/components/agents/formatToolCallArguments.ts +9 -0
  154. package/src/components/agents/index.ts +40 -0
  155. package/src/components/assets/AssetLibraryDialog.tsx +5 -0
  156. package/src/components/assets/asset-library/AssetLibraryDialog.tsx +43 -0
  157. package/src/components/assets/asset-library/AssetLibraryWorkspace.tsx +54 -0
  158. package/src/components/assets/asset-library/detail/AssetLibraryDetailActions.tsx +68 -0
  159. package/src/components/assets/asset-library/detail/AssetLibraryDetailHeader.tsx +56 -0
  160. package/src/components/assets/asset-library/detail/AssetLibraryDetailPane.tsx +90 -0
  161. package/src/components/assets/asset-library/detail/AssetLibraryDetailPreview.tsx +67 -0
  162. package/src/components/assets/asset-library/detail/AssetLibraryInlinePreview.tsx +87 -0
  163. package/src/components/assets/asset-library/detail/AssetLibraryInlineSourceField.tsx +29 -0
  164. package/src/components/assets/asset-library/detail/AssetLibraryMetadataFields.tsx +34 -0
  165. package/src/components/assets/asset-library/detail/AssetLibraryUsagePanel.tsx +46 -0
  166. package/src/components/assets/asset-library/detail/AssetLibraryVersionsPanel.tsx +145 -0
  167. package/src/components/assets/asset-library/helpers/assetKind.ts +74 -0
  168. package/src/components/assets/asset-library/helpers.ts +41 -0
  169. package/src/components/assets/asset-library/hooks/useAssetDetailDraft.ts +81 -0
  170. package/src/components/assets/asset-library/hooks/useAssetLibraryDialog.ts +233 -0
  171. package/src/components/assets/asset-library/hooks/useAssetLibraryMutations.ts +266 -0
  172. package/src/components/assets/asset-library/hooks/useAssetLibrarySelectionSync.ts +24 -0
  173. package/src/components/assets/asset-library/hooks/useAssetLibraryVersions.ts +145 -0
  174. package/src/components/assets/asset-library/hooks/useInlineAssetPreview.ts +44 -0
  175. package/src/components/assets/asset-library/index.ts +19 -0
  176. package/src/components/assets/asset-library/layout/assetLibraryLayout.ts +201 -0
  177. package/src/components/assets/asset-library/shared/fieldStyles.ts +62 -0
  178. package/src/components/assets/asset-library/sidebar/AssetLibraryFilterPills.tsx +89 -0
  179. package/src/components/assets/asset-library/sidebar/AssetLibraryList.tsx +91 -0
  180. package/src/components/assets/asset-library/sidebar/AssetLibraryListRow.tsx +99 -0
  181. package/src/components/assets/asset-library/sidebar/AssetLibraryListStatus.tsx +24 -0
  182. package/src/components/assets/asset-library/sidebar/AssetLibrarySidebar.tsx +48 -0
  183. package/src/components/assets/asset-library/sidebar/AssetLibrarySidebarActions.tsx +38 -0
  184. package/src/components/assets/asset-library/sidebar/AssetLibrarySidebarToolbar.tsx +78 -0
  185. package/src/components/assets/asset-library/sidebar/AssetListThumbnail.tsx +86 -0
  186. package/src/components/assets/asset-library/types.ts +128 -0
  187. package/src/components/assets/asset-library/utils/assetLibraryUtils.ts +181 -0
  188. package/src/components/assets/asset-library/utils/pathBasename.ts +5 -0
  189. package/src/components/assets/asset-library/utils/sanitizeUploadFileName.ts +7 -0
  190. package/src/components/assets/asset-library/utils/uploadCollectionAsset.ts +52 -0
  191. package/src/components/chrome/OverlayActionCapsule.test.tsx +82 -0
  192. package/src/components/chrome/OverlayActionCapsule.tsx +90 -0
  193. package/src/components/chrome/PanelTabStrip.tsx +113 -0
  194. package/src/components/chrome/PlatformIcon.tsx +27 -0
  195. package/src/components/chrome/PureAppWordmark.tsx +89 -0
  196. package/src/components/chrome/ShellWindowControls.tsx +51 -0
  197. package/src/components/chrome/ThemeModeButton.tsx +16 -0
  198. package/src/components/chrome/Titlebar.tsx +79 -0
  199. package/src/components/chrome/WorkspaceTabStrip.tsx +300 -0
  200. package/src/components/chrome/index.ts +31 -0
  201. package/src/components/chrome/workspaceTabTypes.ts +29 -0
  202. package/src/components/common/buttons/Button.tsx +241 -0
  203. package/src/components/common/buttons/ChoiceChip.tsx +73 -0
  204. package/src/components/common/buttons/CleanButton.tsx +34 -0
  205. package/src/components/common/buttons/IconButton.tsx +89 -0
  206. package/src/components/common/buttons/QuietAction.tsx +29 -0
  207. package/src/components/common/buttons/SegmentedControl.tsx +67 -0
  208. package/src/components/common/buttons/TextActionButton.tsx +55 -0
  209. package/src/components/common/buttons/TextLink.tsx +38 -0
  210. package/src/components/common/canvas/CanvasElementFrame.test.tsx +79 -0
  211. package/src/components/common/canvas/CanvasElementFrame.tsx +182 -0
  212. package/src/components/common/canvas/canvasGeometry.test.ts +66 -0
  213. package/src/components/common/canvas/canvasGeometry.ts +133 -0
  214. package/src/components/common/canvas/index.ts +27 -0
  215. package/src/components/common/canvas/useCanvasDragResize.test.tsx +152 -0
  216. package/src/components/common/canvas/useCanvasDragResize.ts +161 -0
  217. package/src/components/common/chat/ChatAssistantMessage.tsx +81 -0
  218. package/src/components/common/chat/ChatBox.tsx +189 -0
  219. package/src/components/common/chat/ChatMarkdown.tsx +109 -0
  220. package/src/components/common/chat/ChatModelMenu.tsx +258 -0
  221. package/src/components/common/chat/ChatStatusRow.tsx +24 -0
  222. package/src/components/common/chat/ChatThinkingIndicator.tsx +54 -0
  223. package/src/components/common/chat/ChatThread.tsx +59 -0
  224. package/src/components/common/chat/ChatToolRow.tsx +141 -0
  225. package/src/components/common/chat/ChatUserBubble.tsx +45 -0
  226. package/src/components/common/chat/chatUtils.ts +7 -0
  227. package/src/components/common/chat/index.ts +24 -0
  228. package/src/components/common/connections/ConnectionSetup.tsx +529 -0
  229. package/src/components/common/connections/index.ts +26 -0
  230. package/src/components/common/containers/AppFrame.test.tsx +47 -0
  231. package/src/components/common/containers/AppFrame.tsx +65 -0
  232. package/src/components/common/containers/AppHeader.tsx +60 -0
  233. package/src/components/common/containers/AutoFillGrid.tsx +37 -0
  234. package/src/components/common/containers/Collapsible.tsx +43 -0
  235. package/src/components/common/containers/CollapsibleGrid.tsx +174 -0
  236. package/src/components/common/containers/MotionScope.tsx +32 -0
  237. package/src/components/common/containers/PageHeader.tsx +35 -0
  238. package/src/components/common/containers/PanelToolbarHeader.tsx +113 -0
  239. package/src/components/common/containers/QuietDisclosure.tsx +91 -0
  240. package/src/components/common/containers/QuietSurface.tsx +41 -0
  241. package/src/components/common/containers/ScrollPanel.tsx +33 -0
  242. package/src/components/common/containers/StatusBar.tsx +42 -0
  243. package/src/components/common/containers/SurfacePanel.tsx +66 -0
  244. package/src/components/common/containers/ToolbarStrip.tsx +80 -0
  245. package/src/components/common/containers/flex.ts +117 -0
  246. package/src/components/common/containers/useOpenTransition.ts +33 -0
  247. package/src/components/common/context/ContextSelector.tsx +269 -0
  248. package/src/components/common/context/index.ts +7 -0
  249. package/src/components/common/desk/ActionReader.tsx +270 -0
  250. package/src/components/common/desk/ActivityLedger.tsx +143 -0
  251. package/src/components/common/desk/CreationDesk.tsx +139 -0
  252. package/src/components/common/desk/DailyBrief.tsx +160 -0
  253. package/src/components/common/desk/DeskCard.tsx +157 -0
  254. package/src/components/common/desk/index.ts +30 -0
  255. package/src/components/common/dropdown/ContextMenu.tsx +87 -0
  256. package/src/components/common/dropdown/MenuButtonDropdown.tsx +121 -0
  257. package/src/components/common/dropdown/MenuDropdown.tsx +63 -0
  258. package/src/components/common/dropdown/MenuDropdownEntry.tsx +51 -0
  259. package/src/components/common/dropdown/MenuDropdownItem.tsx +82 -0
  260. package/src/components/common/dropdown/MenuDropdownSubmenu.tsx +145 -0
  261. package/src/components/common/dropdown/MenuPanel.tsx +69 -0
  262. package/src/components/common/dropdown/MenuPortal.tsx +162 -0
  263. package/src/components/common/dropdown/MenuPortalLayer.tsx +6 -0
  264. package/src/components/common/dropdown/SelectMenu.tsx +243 -0
  265. package/src/components/common/dropdown/SelectMenuControl.tsx +23 -0
  266. package/src/components/common/dropdown/SelectMenuOptions.tsx +38 -0
  267. package/src/components/common/dropdown/menuPortalConstants.ts +11 -0
  268. package/src/components/common/dropdown/menuTypes.ts +71 -0
  269. package/src/components/common/dropdown/menuViewportPosition.test.ts +139 -0
  270. package/src/components/common/dropdown/menuViewportPosition.ts +122 -0
  271. package/src/components/common/dropdown/selectMenuLayout.test.ts +42 -0
  272. package/src/components/common/dropdown/selectMenuLayout.ts +123 -0
  273. package/src/components/common/dropdown/useMenuAnchorPosition.ts +109 -0
  274. package/src/components/common/dropdown/useSelectMenuAnchor.ts +30 -0
  275. package/src/components/common/evidence/StructuredEvidenceView.test.tsx +77 -0
  276. package/src/components/common/evidence/StructuredEvidenceView.tsx +312 -0
  277. package/src/components/common/evidence/index.ts +13 -0
  278. package/src/components/common/feedback/Badge.tsx +33 -0
  279. package/src/components/common/feedback/CapabilityPills.tsx +36 -0
  280. package/src/components/common/feedback/EmptyState.tsx +132 -0
  281. package/src/components/common/feedback/InfoHint.tsx +67 -0
  282. package/src/components/common/feedback/InlineBanner.tsx +82 -0
  283. package/src/components/common/feedback/PlatformChip.tsx +104 -0
  284. package/src/components/common/feedback/QuietPill.tsx +75 -0
  285. package/src/components/common/feedback/WorkProgressPanel.tsx +156 -0
  286. package/src/components/common/feedback/index.ts +33 -0
  287. package/src/components/common/inputs/BareInput.tsx +31 -0
  288. package/src/components/common/inputs/BareTextarea.tsx +10 -0
  289. package/src/components/common/inputs/Checkbox.tsx +13 -0
  290. package/src/components/common/inputs/FieldControlShell.tsx +49 -0
  291. package/src/components/common/inputs/FormField.tsx +40 -0
  292. package/src/components/common/inputs/HybridSearchField.tsx +280 -0
  293. package/src/components/common/inputs/InlineComposer.tsx +197 -0
  294. package/src/components/common/inputs/PaletteCirclePicker.tsx +26 -0
  295. package/src/components/common/inputs/PaletteDropdown.tsx +413 -0
  296. package/src/components/common/inputs/Radio.tsx +19 -0
  297. package/src/components/common/inputs/SearchField.tsx +128 -0
  298. package/src/components/common/inputs/SelectField.tsx +169 -0
  299. package/src/components/common/inputs/SurfacePalettePicker.tsx +54 -0
  300. package/src/components/common/inputs/TextAreaField.tsx +22 -0
  301. package/src/components/common/inputs/TextField.tsx +51 -0
  302. package/src/components/common/inputs/ToggleSwitch.tsx +110 -0
  303. package/src/components/common/inputs/WorkspacePicker.tsx +349 -0
  304. package/src/components/common/inputs/fieldStyles.ts +137 -0
  305. package/src/components/common/layout/PanelGroup.tsx +479 -0
  306. package/src/components/common/layout/index.ts +31 -0
  307. package/src/components/common/layout/panelLayoutConstants.ts +7 -0
  308. package/src/components/common/layout/panelLayoutPersistence.ts +35 -0
  309. package/src/components/common/layout/panelLayoutState.test.ts +38 -0
  310. package/src/components/common/layout/panelLayoutState.ts +174 -0
  311. package/src/components/common/layout/panelLayoutTypes.ts +19 -0
  312. package/src/components/common/layout/tabs/Tabs.tsx +136 -0
  313. package/src/components/common/lists/listRowStyles.ts +32 -0
  314. package/src/components/common/lists/quiet-ledger/QuietActivityList.tsx +64 -0
  315. package/src/components/common/lists/quiet-ledger/QuietLedgerRow.tsx +119 -0
  316. package/src/components/common/lists/quiet-ledger/index.ts +9 -0
  317. package/src/components/common/lists/reorderable/DragHandle.tsx +65 -0
  318. package/src/components/common/lists/reorderable/ReorderableList.tsx +280 -0
  319. package/src/components/common/lists/reorderable/ReorderableListRow.tsx +102 -0
  320. package/src/components/common/lists/reorderable/ReorderableSections.tsx +344 -0
  321. package/src/components/common/lists/reorderable/ReorderableSectionsDemo.tsx +94 -0
  322. package/src/components/common/lists/reorderable/index.ts +15 -0
  323. package/src/components/common/lists/reorderable/reorderableUtils.test.ts +28 -0
  324. package/src/components/common/lists/reorderable/reorderableUtils.ts +23 -0
  325. package/src/components/common/lists/reorderable/types.ts +40 -0
  326. package/src/components/common/lists/reorderable/useReorderableDragState.ts +49 -0
  327. package/src/components/common/media/ImageReferencePicker.tsx +242 -0
  328. package/src/components/common/menubar/MenuBar.tsx +78 -0
  329. package/src/components/common/menubar/MenuBarTrigger.tsx +70 -0
  330. package/src/components/common/narrative/NarrativeMention.tsx +74 -0
  331. package/src/components/common/navigation/PathBreadcrumbs.tsx +78 -0
  332. package/src/components/common/navigation/UnderlineTabs.tsx +83 -0
  333. package/src/components/common/overlays/InstallAppPromptDialog.tsx +59 -0
  334. package/src/components/common/overlays/Modal.tsx +285 -0
  335. package/src/components/common/overlays/ModalChromeHeader.tsx +105 -0
  336. package/src/components/common/overlays/ObjectActionStrip.tsx +80 -0
  337. package/src/components/common/people/AutoUpdateReviewList.tsx +182 -0
  338. package/src/components/common/people/EntityList.tsx +122 -0
  339. package/src/components/common/people/EntityPortrait.tsx +64 -0
  340. package/src/components/common/people/LinkedDossierList.tsx +99 -0
  341. package/src/components/common/people/OpportunityList.tsx +94 -0
  342. package/src/components/common/people/PeopleSourceList.tsx +145 -0
  343. package/src/components/common/people/RelationshipDossier.tsx +168 -0
  344. package/src/components/common/people/RelationshipMap.tsx +362 -0
  345. package/src/components/common/people/index.ts +40 -0
  346. package/src/components/common/preview/FileAudioPreview.tsx +89 -0
  347. package/src/components/common/preview/FileImagePreview.tsx +88 -0
  348. package/src/components/common/preview/FilePdfPreview.tsx +87 -0
  349. package/src/components/common/preview/FileTextPreview.tsx +96 -0
  350. package/src/components/common/preview/FileVideoPreview.tsx +87 -0
  351. package/src/components/common/preview/PlatformFilePreview.tsx +166 -0
  352. package/src/components/common/preview/previewLayout.ts +27 -0
  353. package/src/components/common/render/Each.tsx +42 -0
  354. package/src/components/common/research/EvidenceDossier.tsx +894 -0
  355. package/src/components/common/research/index.ts +7 -0
  356. package/src/components/common/tiles/CatalogCard.tsx +116 -0
  357. package/src/components/common/tiles/Tile.tsx +45 -0
  358. package/src/components/common/tiles/TileGrid.tsx +13 -0
  359. package/src/components/common/typography/Heading.tsx +27 -0
  360. package/src/components/common/typography/Kicker.tsx +30 -0
  361. package/src/components/common/typography/Text.tsx +80 -0
  362. package/src/components/credentials/CredentialsPanel.tsx +169 -0
  363. package/src/components/credentials/credentialsTypes.ts +14 -0
  364. package/src/components/data/DataChart.tsx +913 -0
  365. package/src/components/data/dataTable.ts +99 -0
  366. package/src/components/editor/EditorCommentPromptDialog.tsx +124 -0
  367. package/src/components/editor/EditorLinkPromptDialog.tsx +65 -0
  368. package/src/components/print-design/PrintDesignPanel.test.tsx +1446 -0
  369. package/src/components/print-design/PrintDesignPanel.tsx +3043 -0
  370. package/src/components/print-design/index.ts +9 -0
  371. package/src/components/proofing/PagedProofDialog.tsx +453 -0
  372. package/src/components/proofing/index.ts +4 -0
  373. package/src/editor/DocumentEditor.tsx +28 -0
  374. package/src/editor/EditorViewModeToggle.tsx +35 -0
  375. package/src/editor/index.ts +97 -0
  376. package/src/editor/toolbarOverlays.ts +8 -0
  377. package/src/index.ts +209 -0
  378. package/src/theme/ThemeProvider.tsx +113 -0
  379. package/src/theme/appAccents.ts +87 -0
  380. package/src/theme/buildThemeBridgePayload.ts +23 -0
  381. package/src/theme/composePlatformTheme.test.ts +30 -0
  382. package/src/theme/composePlatformTheme.ts +23 -0
  383. package/src/theme/platformFont.d.mts +7 -0
  384. package/src/theme/platformFont.mjs +20 -0
  385. package/src/theme/platformFont.ts +6 -0
  386. package/src/theme/reportsShellChromeSelectors.ts +136 -0
  387. package/src/theme/styled.d.ts +5 -0
  388. package/src/theme/surfacePalettes.ts +178 -0
  389. package/src/theme/surfaceRoleSelectors.ts +113 -0
  390. package/src/theme/themeVars.ts +13 -0
  391. package/src/theme/themes/dark.ts +59 -0
  392. package/src/theme/themes/light.ts +60 -0
  393. package/src/theme/themes/palette.ts +44 -0
  394. package/src/theme/themes/shared.ts +68 -0
  395. package/src/theme/tokens.ts +114 -0
  396. package/src/theme/utils/GlobalStyles.ts +88 -0
  397. package/src/theme/utils/appFrameDocumentStyles.d.mts +5 -0
  398. package/src/theme/utils/appFrameDocumentStyles.mjs +89 -0
  399. package/src/theme/utils/appFrameDocumentStyles.ts +5 -0
  400. package/src/theme/utils/applyTheme.ts +50 -0
  401. package/src/theme/utils/cssVariables.ts +49 -0
  402. package/src/theme/utils/useInjectThemeIntoIframe.ts +40 -0
  403. package/src/utils/extensionIconMap.ts +123 -0
  404. package/src/utils/generalUtils.ts +157 -0
  405. package/src/writing/DraftAssistantDialog.tsx +279 -0
  406. package/src/writing/WritingStyleManager.tsx +416 -0
  407. package/src/writing/condenseWritingStyle.ts +103 -0
  408. package/src/writing/draftTextWithAgent.ts +134 -0
  409. package/src/writing/index.ts +39 -0
  410. package/src/writing/styleStore.ts +32 -0
  411. package/src/writing/writingStyle.test.ts +122 -0
  412. package/src/writing/writingStyle.ts +217 -0
@@ -0,0 +1,264 @@
1
+ export type PureRenderProfile = 'writer' | 'manuscript' | 'book'
2
+
3
+ export interface PureRenderMetadata {
4
+ title?: string
5
+ authorsHtml?: string
6
+ authorsText?: string
7
+ affiliationsHtml?: string
8
+ affiliationsText?: string
9
+ abstractHtml?: string
10
+ abstractText?: string
11
+ keywords?: readonly string[]
12
+ profileLabel?: string
13
+ }
14
+
15
+ export interface PureRenderOptions {
16
+ variant?: 'two-column' | string
17
+ pageSize?: string
18
+ outline?: boolean
19
+ }
20
+
21
+ export interface PureRenderRequest {
22
+ html: string
23
+ profile: PureRenderProfile
24
+ theme?: PureRenderTheme
25
+ metadata?: PureRenderMetadata
26
+ options?: PureRenderOptions
27
+ }
28
+
29
+ export interface PureRenderTheme {
30
+ $schema?: string
31
+ name: string
32
+ version: string
33
+ color: {
34
+ ink: string
35
+ 'ink-soft': string
36
+ muted: string
37
+ surface?: string
38
+ paper?: string
39
+ rule: string
40
+ 'rule-soft': string
41
+ accent: string
42
+ 'accent-ink'?: string
43
+ }
44
+ type: {
45
+ body: string
46
+ lead: number | string
47
+ measure: string
48
+ scaleRatio: number
49
+ fonts: {
50
+ display?: string
51
+ serif: string
52
+ sans: string
53
+ mono: string
54
+ }
55
+ }
56
+ rhythm: string
57
+ page?: {
58
+ trim?: string
59
+ margin?: string
60
+ columns?: number
61
+ recto_verso?: boolean
62
+ }
63
+ setting?: {
64
+ align?: 'justified' | 'flush-left' | string
65
+ hyphenate?: boolean
66
+ }
67
+ enforced_rules?: readonly string[]
68
+ profile_rules?: PureRenderProfileRules
69
+ }
70
+
71
+ export interface PureRenderProfileRules {
72
+ running_heads?: {
73
+ presence?: 'present' | 'absent' | string
74
+ position?: string
75
+ transform?: 'uppercase' | 'small-caps' | 'title-case' | 'none' | string
76
+ rule?: 'none' | 'hairline' | 'solid' | string
77
+ font_role?: 'display' | 'body' | 'caption' | 'sans' | string
78
+ }
79
+ folio?: {
80
+ position?: string
81
+ style?: 'plain' | 'small-caps' | 'bracketed' | string
82
+ suppress_on?: readonly string[]
83
+ }
84
+ opener?: {
85
+ spacing?: 'compact' | 'balanced' | 'generous' | string
86
+ recto_start?: boolean
87
+ ornament?: 'none' | 'rule' | 'divider' | 'fleuron' | 'chapter-mark' | string
88
+ drop_cap?: boolean
89
+ }
90
+ ornaments?: {
91
+ kind?: 'none' | 'rule' | 'divider' | 'fleuron' | 'chapter-mark' | string
92
+ weight?: 'hairline' | 'light' | 'medium' | string
93
+ placement?: string
94
+ }
95
+ table?: {
96
+ rule_weight?: 'hairline' | 'light' | 'medium' | string
97
+ header_treatment?: string
98
+ density?: 'airy' | 'balanced' | 'dense' | string
99
+ }
100
+ caption?: {
101
+ position?: 'above' | 'below' | string
102
+ label_style?: 'bold' | 'small-caps' | 'plain' | string
103
+ alignment?: 'left' | 'center' | 'justified' | string
104
+ }
105
+ }
106
+
107
+ export interface PureRenderValidationError {
108
+ code: string
109
+ message: string
110
+ }
111
+
112
+ export interface PureRenderNormalizeResult {
113
+ html: string
114
+ title: string
115
+ errors: PureRenderValidationError[]
116
+ }
117
+
118
+ export interface PrintStyleProfile {
119
+ schema_version: '1.0' | string
120
+ sources?: readonly { id: string; note?: string }[]
121
+ exemplar_quality: {
122
+ usable: boolean
123
+ reason: string
124
+ confidence: number
125
+ }
126
+ observations: {
127
+ palette?: readonly PrintStylePaletteObservation[]
128
+ type?: readonly PrintStyleTypeObservation[]
129
+ type_pairing?: PrintStyleTypePairingObservation
130
+ type_scale?: PrintStyleTypeScaleObservation
131
+ text_setting?: PrintStyleTextSettingObservation
132
+ page_model?: PrintStylePageModelObservation
133
+ running_heads?: PrintStyleRunningHeadsObservation
134
+ folio?: PrintStyleFolioObservation
135
+ opener?: PrintStyleOpenerObservation
136
+ ornaments?: PrintStyleOrnamentObservation
137
+ table_treatment?: PrintStyleTableTreatmentObservation
138
+ caption_treatment?: PrintStyleCaptionTreatmentObservation
139
+ finish?: { register?: string; confidence?: number }
140
+ }
141
+ rules?: readonly PrintStyleRule[]
142
+ derived?: unknown
143
+ }
144
+
145
+ export interface PrintStylePaletteObservation {
146
+ role: 'surface' | 'ink' | 'accent' | 'secondary' | string
147
+ approx_hex?: string
148
+ coverage?: 'dominant' | 'frequent' | 'sparse' | string
149
+ where_seen?: string
150
+ confidence: number
151
+ }
152
+
153
+ export interface PrintStyleTypeObservation {
154
+ role: 'display' | 'body' | 'caption' | 'mono' | string
155
+ class: 'serif' | 'sans' | 'slab' | 'script' | string
156
+ mood?:
157
+ | 'old-style'
158
+ | 'transitional'
159
+ | 'slab'
160
+ | 'humanist-sans'
161
+ | 'grotesque-sans'
162
+ | 'geometric-sans'
163
+ | 'mono'
164
+ | string
165
+ serif_detail?: 'bracketed' | 'slab' | 'hairline' | 'wedge' | 'none' | string
166
+ confidence: number
167
+ }
168
+
169
+ export interface PrintStyleTypePairingObservation {
170
+ size_contrast?: 'dramatic' | 'moderate' | 'subtle' | string
171
+ confidence?: number
172
+ }
173
+
174
+ export interface PrintStyleTypeScaleObservation {
175
+ body_pt?: number
176
+ title_scale?: number
177
+ chapter_title_scale?: number
178
+ section_scale?: number
179
+ caption_scale?: number
180
+ footnote_scale?: number
181
+ confidence?: number
182
+ }
183
+
184
+ export interface PrintStyleTextSettingObservation {
185
+ alignment?: 'justified' | 'flush-left' | string
186
+ hyphenation?: 'present' | 'absent' | string
187
+ measure_cpl?: number
188
+ leading_feel?: 'tight' | 'normal' | 'airy' | string
189
+ confidence?: number
190
+ }
191
+
192
+ export interface PrintStylePageModelObservation {
193
+ columns?: number
194
+ margin_generosity?: 'tight' | 'moderate' | 'generous' | string
195
+ margin_asymmetry?: string
196
+ running_heads?: 'present' | 'absent' | string
197
+ folio_position?: string
198
+ caption_position?: 'above' | 'below' | string
199
+ confidence?: number
200
+ }
201
+
202
+ export interface PrintStyleRunningHeadsObservation {
203
+ presence?: 'present' | 'absent' | string
204
+ position?: string
205
+ transform?: 'uppercase' | 'small-caps' | 'title-case' | 'none' | string
206
+ rule?: 'none' | 'hairline' | 'solid' | string
207
+ font_role?: 'display' | 'body' | 'caption' | 'sans' | string
208
+ evidence?: string
209
+ confidence?: number
210
+ }
211
+
212
+ export interface PrintStyleFolioObservation {
213
+ position?: string
214
+ style?: 'plain' | 'small-caps' | 'bracketed' | string
215
+ suppress_on?: readonly string[]
216
+ evidence?: string
217
+ confidence?: number
218
+ }
219
+
220
+ export interface PrintStyleOpenerObservation {
221
+ spacing?: 'compact' | 'balanced' | 'generous' | string
222
+ recto_start?: boolean
223
+ ornament?: 'none' | 'rule' | 'divider' | 'fleuron' | 'chapter-mark' | string
224
+ drop_cap?: boolean
225
+ evidence?: string
226
+ confidence?: number
227
+ }
228
+
229
+ export interface PrintStyleOrnamentObservation {
230
+ kind?: 'none' | 'rule' | 'divider' | 'fleuron' | 'chapter-mark' | string
231
+ weight?: 'hairline' | 'light' | 'medium' | string
232
+ placement?: string
233
+ evidence?: string
234
+ confidence?: number
235
+ }
236
+
237
+ export interface PrintStyleTableTreatmentObservation {
238
+ rule_weight?: 'hairline' | 'light' | 'medium' | string
239
+ header_treatment?: string
240
+ row_rules?: 'none' | 'hairline' | 'light' | string
241
+ density?: 'airy' | 'balanced' | 'dense' | string
242
+ evidence?: string
243
+ confidence?: number
244
+ }
245
+
246
+ export interface PrintStyleCaptionTreatmentObservation {
247
+ position?: 'above' | 'below' | string
248
+ label_style?: 'bold' | 'small-caps' | 'plain' | string
249
+ alignment?: 'left' | 'center' | 'justified' | string
250
+ evidence?: string
251
+ confidence?: number
252
+ }
253
+
254
+ export interface PrintStyleRule {
255
+ rule: string
256
+ evidence?: string
257
+ confidence: number
258
+ }
259
+
260
+ export interface CompilePrintThemeResult {
261
+ theme: PureRenderTheme | null
262
+ decisions: readonly [type: string, message: string][]
263
+ rules: readonly string[]
264
+ }
@@ -0,0 +1,57 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { inspectPureRenderVisualLayout } from './visualLayoutInspection.js'
3
+
4
+ describe('inspectPureRenderVisualLayout', () => {
5
+ it('observes clean pages without requesting vision review', () => {
6
+ const result = inspectPureRenderVisualLayout({
7
+ pageCount: 3,
8
+ topGapRatio: 0.08,
9
+ bottomGapRatio: 0.12,
10
+ usedHeightRatio: 0.8,
11
+ blankBeforeFigureRatio: 0.1,
12
+ imageVisible: true,
13
+ captionOrphaned: false,
14
+ strandedHeading: false,
15
+ })
16
+
17
+ expect(result.decision).toBe('observe')
18
+ expect(result.requiresVisionReview).toBe(false)
19
+ expect(result.issues).toEqual([])
20
+ })
21
+
22
+ it('reuses image break candidate logic for stranded figure pages', () => {
23
+ const result = inspectPureRenderVisualLayout({
24
+ pageCount: 5,
25
+ problemPage: 2,
26
+ figurePage: 3,
27
+ imagePage: 3,
28
+ captionPage: 3,
29
+ headingPage: 2,
30
+ blankBeforeFigureRatio: 0.62,
31
+ imageVisible: true,
32
+ captionOrphaned: false,
33
+ strandedHeading: true,
34
+ })
35
+
36
+ expect(result.decision).toBe('rerender-compact-figure-candidate')
37
+ expect(result.requiresVisionReview).toBe(false)
38
+ expect(result.issues).toEqual([
39
+ 'large-pre-figure-blank',
40
+ 'stranded-heading',
41
+ ])
42
+ expect(result.candidate?.id).toBe('compact-figure')
43
+ })
44
+
45
+ it('rejects caption orphan candidates deterministically', () => {
46
+ const result = inspectPureRenderVisualLayout({
47
+ imagePage: 2,
48
+ captionPage: 3,
49
+ imageVisible: true,
50
+ captionOrphaned: true,
51
+ })
52
+
53
+ expect(result.decision).toBe('reject-candidate')
54
+ expect(result.requiresVisionReview).toBe(false)
55
+ expect(result.issues).toContain('caption-orphan')
56
+ })
57
+ })
@@ -0,0 +1,161 @@
1
+ export type PureRenderVisualIssue =
2
+ | 'large-pre-figure-blank'
3
+ | 'sparse-sample-page'
4
+ | 'stranded-heading'
5
+ | 'caption-orphan'
6
+ | 'image-not-visible-on-risk-page'
7
+ | 'blank-page'
8
+
9
+ export type PureRenderVisualDecision =
10
+ | 'observe'
11
+ | 'rerender-candidate'
12
+ | 'rerender-compact-figure-candidate'
13
+ | 'reject-candidate'
14
+ | 'accept-candidate-for-review'
15
+ | 'needs-vision-review'
16
+
17
+ export interface PureRenderVisualLayoutMetrics {
18
+ pageCount?: number
19
+ problemPage?: number
20
+ figurePage?: number
21
+ imagePage?: number
22
+ captionPage?: number
23
+ headingPage?: number
24
+ blankBeforeFigurePx?: number
25
+ blankBeforeFigureRatio?: number
26
+ blankPageCount?: number
27
+ imageVisible?: boolean
28
+ captionVisible?: boolean
29
+ captionOrphaned?: boolean
30
+ strandedHeading?: boolean | null
31
+ topGapRatio?: number
32
+ bottomGapRatio?: number
33
+ usedHeightRatio?: number
34
+ }
35
+
36
+ export interface PureRenderVisualCandidate {
37
+ id: string
38
+ label: string
39
+ summary: string
40
+ cssPatch?: string
41
+ }
42
+
43
+ export interface PureRenderVisualInspection {
44
+ decision: PureRenderVisualDecision
45
+ recommendation: string
46
+ requiresUserReview: boolean
47
+ requiresVisionReview: boolean
48
+ issues: PureRenderVisualIssue[]
49
+ metrics: PureRenderVisualLayoutMetrics
50
+ candidate?: PureRenderVisualCandidate
51
+ }
52
+
53
+ const LARGE_PRE_FIGURE_BLANK_RATIO = 0.5
54
+ const SPARSE_PAGE_USED_HEIGHT_RATIO = 0.25
55
+ const LARGE_BOTTOM_GAP_RATIO = 0.55
56
+
57
+ export function inspectPureRenderVisualLayout(
58
+ metrics: PureRenderVisualLayoutMetrics | undefined,
59
+ ): PureRenderVisualInspection {
60
+ const normalized = metrics ?? {}
61
+ const issues = visualIssuesForMetrics(normalized)
62
+ const hasIssue = issues.length > 0
63
+ const hasHardFailure =
64
+ issues.includes('caption-orphan') ||
65
+ issues.includes('image-not-visible-on-risk-page')
66
+ const canTryCompactFigure =
67
+ issues.includes('large-pre-figure-blank') ||
68
+ issues.includes('stranded-heading') ||
69
+ issues.includes('image-not-visible-on-risk-page')
70
+
71
+ if (!hasIssue) {
72
+ return {
73
+ decision: 'observe',
74
+ recommendation:
75
+ 'No deterministic visual layout issue was detected on the sampled Paged.js output.',
76
+ requiresUserReview: false,
77
+ requiresVisionReview: false,
78
+ issues,
79
+ metrics: normalized,
80
+ }
81
+ }
82
+
83
+ if (hasHardFailure && issues.includes('caption-orphan')) {
84
+ return {
85
+ decision: 'reject-candidate',
86
+ recommendation:
87
+ 'Reject this placement: the caption appears detached from its figure.',
88
+ requiresUserReview: true,
89
+ requiresVisionReview: false,
90
+ issues,
91
+ metrics: normalized,
92
+ }
93
+ }
94
+
95
+ if (canTryCompactFigure) {
96
+ return {
97
+ decision: 'rerender-compact-figure-candidate',
98
+ recommendation:
99
+ 'Try a compact figure candidate before promoting any shared CSS change; the current page appears to strand a heading, hide a figure, or leave a large pre-figure blank.',
100
+ requiresUserReview: true,
101
+ requiresVisionReview: false,
102
+ issues,
103
+ metrics: normalized,
104
+ candidate: {
105
+ id: 'compact-figure',
106
+ label: 'Compact figure candidate',
107
+ summary:
108
+ 'Cap figure media height and keep the caption attached so the next render can be compared against the current page.',
109
+ cssPatch:
110
+ 'figure { break-inside: avoid; } figure img, figure svg { max-height: 72mm; object-fit: contain; margin-left: auto; margin-right: auto; }',
111
+ },
112
+ }
113
+ }
114
+
115
+ return {
116
+ decision: 'rerender-candidate',
117
+ recommendation:
118
+ 'Try an alternate placement candidate and compare screenshots before changing production CSS.',
119
+ requiresUserReview: true,
120
+ requiresVisionReview: true,
121
+ issues,
122
+ metrics: normalized,
123
+ }
124
+ }
125
+
126
+ export function visualIssuesForMetrics(
127
+ metrics: PureRenderVisualLayoutMetrics,
128
+ ): PureRenderVisualIssue[] {
129
+ const issues: PureRenderVisualIssue[] = []
130
+ if (
131
+ typeof metrics.blankBeforeFigureRatio === 'number' &&
132
+ metrics.blankBeforeFigureRatio >= LARGE_PRE_FIGURE_BLANK_RATIO
133
+ ) {
134
+ issues.push('large-pre-figure-blank')
135
+ }
136
+ if (
137
+ typeof metrics.usedHeightRatio === 'number' &&
138
+ metrics.usedHeightRatio < SPARSE_PAGE_USED_HEIGHT_RATIO
139
+ ) {
140
+ issues.push('sparse-sample-page')
141
+ } else if (
142
+ typeof metrics.bottomGapRatio === 'number' &&
143
+ metrics.bottomGapRatio > LARGE_BOTTOM_GAP_RATIO &&
144
+ metrics.imageVisible === false
145
+ ) {
146
+ issues.push('sparse-sample-page')
147
+ }
148
+ if ((metrics.blankPageCount ?? 0) > 0) {
149
+ issues.push('blank-page')
150
+ }
151
+ if (metrics.strandedHeading === true) {
152
+ issues.push('stranded-heading')
153
+ }
154
+ if (metrics.captionOrphaned === true) {
155
+ issues.push('caption-orphan')
156
+ }
157
+ if (metrics.imageVisible === false) {
158
+ issues.push('image-not-visible-on-risk-page')
159
+ }
160
+ return Array.from(new Set(issues))
161
+ }
@@ -0,0 +1,21 @@
1
+ import { useEffect, useRef } from 'react'
2
+
3
+ /**
4
+ * Run an effect after `delayMs` when `deps` change (leading edge cancelled).
5
+ * Shared by host workspace persist and other bridge clients.
6
+ */
7
+ export function useDebouncedEffect(
8
+ effect: () => void | (() => void),
9
+ deps: React.DependencyList,
10
+ delayMs: number,
11
+ ): void {
12
+ const effectRef = useRef(effect)
13
+ effectRef.current = effect
14
+
15
+ useEffect(() => {
16
+ const timeout = window.setTimeout(() => {
17
+ return effectRef.current()
18
+ }, delayMs)
19
+ return () => window.clearTimeout(timeout)
20
+ }, [delayMs, ...deps])
21
+ }
@@ -0,0 +1,75 @@
1
+ import { useCallback, useEffect, useState, type DependencyList } from 'react'
2
+
3
+ export interface UseIpcOptions {
4
+ /** When false, skip the request and leave loading false (default true). */
5
+ enabled?: boolean
6
+ }
7
+
8
+ export interface UseIpcResult<T> {
9
+ data: T | null
10
+ error: Error | null
11
+ loading: boolean
12
+ /** Re-run the request (increments an internal reload token). */
13
+ reload: () => void
14
+ }
15
+
16
+ /**
17
+ * Run an async loader in `useEffect` with cancellation-safe setState.
18
+ *
19
+ * Plugin apps use this for bridge / lib calls — not Electron IPC directly.
20
+ * Same pattern as ps-book `useIpc`, adapted for `@purescience/platform-ui`.
21
+ *
22
+ * @example
23
+ * const { data: entries, error, loading, reload } = useIpc(
24
+ * () => listBookRegistry(),
25
+ * [],
26
+ * )
27
+ */
28
+ export function useIpc<T>(
29
+ fn: () => Promise<T>,
30
+ deps: DependencyList,
31
+ options: UseIpcOptions = {},
32
+ ): UseIpcResult<T> {
33
+ const enabled = options.enabled ?? true
34
+ const [data, setData] = useState<T | null>(null)
35
+ const [error, setError] = useState<Error | null>(null)
36
+ const [loading, setLoading] = useState(false)
37
+ const [reloadToken, setReloadToken] = useState(0)
38
+
39
+ const reload = useCallback(() => {
40
+ setReloadToken(token => token + 1)
41
+ }, [])
42
+
43
+ useEffect(() => {
44
+ if (!enabled) return
45
+
46
+ let cancelled = false
47
+ setLoading(true)
48
+ setError(null)
49
+
50
+ async function load(): Promise<void> {
51
+ try {
52
+ const result = await fn()
53
+ if (cancelled) return
54
+ setData(result)
55
+ setError(null)
56
+ } catch (cause) {
57
+ if (cancelled) return
58
+ setData(null)
59
+ setError(cause instanceof Error ? cause : new Error(String(cause)))
60
+ } finally {
61
+ if (!cancelled) setLoading(false)
62
+ }
63
+ }
64
+
65
+ void load()
66
+
67
+ return () => {
68
+ cancelled = true
69
+ }
70
+ // fn is intentionally excluded — callers list stable deps (paths, slugs, …).
71
+ // eslint-disable-next-line react-hooks/exhaustive-deps
72
+ }, [enabled, reloadToken, ...deps])
73
+
74
+ return { data, error, loading, reload }
75
+ }
@@ -0,0 +1,78 @@
1
+ import { useCallback, useEffect, useState } from 'react'
2
+ import {
3
+ AgentRunEventType,
4
+ createIdleLiveTurn,
5
+ mergeUsageTurn,
6
+ reduceAgentLiveTurn,
7
+ type PlatformAgentRunEventPayload,
8
+ } from '../../agents/runtime/index.js'
9
+ import type { PlatformAgentRunSnapshot } from '../agentTypes.js'
10
+ import { onAgentRunEvent } from '../agents.mjs'
11
+ import type { AgentLiveTurn } from '../../components/agents/agentTypes.js'
12
+
13
+ /** Subscribe to bridge run events for one runId (streaming overlay + usage). */
14
+ export function usePlatformAgentRunLiveState(runId: string | undefined): {
15
+ liveRunSnapshot: PlatformAgentRunSnapshot | null
16
+ liveTurn: AgentLiveTurn
17
+ applySnapshot: (snapshot: PlatformAgentRunSnapshot) => void
18
+ resetLiveState: () => void
19
+ } {
20
+ const [liveRunSnapshot, setLiveRunSnapshot] =
21
+ useState<PlatformAgentRunSnapshot | null>(null)
22
+ const [liveTurn, setLiveTurn] = useState<AgentLiveTurn>(createIdleLiveTurn)
23
+
24
+ const applySnapshot = useCallback((snapshot: PlatformAgentRunSnapshot) => {
25
+ setLiveRunSnapshot(snapshot)
26
+ }, [])
27
+
28
+ const resetLiveState = useCallback(() => {
29
+ setLiveRunSnapshot(null)
30
+ setLiveTurn(createIdleLiveTurn())
31
+ }, [])
32
+
33
+ useEffect(() => {
34
+ if (!runId) {
35
+ setLiveRunSnapshot(null)
36
+ setLiveTurn(createIdleLiveTurn())
37
+ return
38
+ }
39
+
40
+ let live = createIdleLiveTurn()
41
+
42
+ const unsubscribe = onAgentRunEvent(event => {
43
+ const payload = event as PlatformAgentRunEventPayload
44
+ if (payload.runId !== runId) return
45
+
46
+ if (
47
+ payload.type === AgentRunEventType.StateChanged &&
48
+ 'snapshot' in payload
49
+ ) {
50
+ setLiveRunSnapshot(payload.snapshot)
51
+ }
52
+
53
+ if (payload.type === AgentRunEventType.UsageUpdated && 'usage' in payload) {
54
+ setLiveRunSnapshot(current => {
55
+ if (!current) return current
56
+ const usage = mergeUsageTurn(
57
+ current.usage,
58
+ payload.usage,
59
+ payload.estimated,
60
+ )
61
+ return { ...current, usage }
62
+ })
63
+ }
64
+
65
+ live = reduceAgentLiveTurn(live, payload)
66
+ setLiveTurn(live)
67
+ })
68
+
69
+ return unsubscribe
70
+ }, [runId])
71
+
72
+ return {
73
+ liveRunSnapshot,
74
+ liveTurn,
75
+ applySnapshot,
76
+ resetLiveState,
77
+ }
78
+ }