@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,72 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react'
2
+ import { bridge } from '../client.mjs'
3
+ import { PLATFORM_BRIDGE_EVENTS } from '../events.mjs'
4
+ import { PLATFORM_BRIDGE_METHODS } from '../methods.mjs'
5
+ import type { PlatformBridgeReadyMeta, ResourceOpenEvent } from '../types.js'
6
+
7
+ function isResourceOpenEvent(value: unknown): value is ResourceOpenEvent {
8
+ return (
9
+ typeof value === 'object' &&
10
+ value !== null &&
11
+ typeof (value as ResourceOpenEvent).path === 'string' &&
12
+ (value as ResourceOpenEvent).path.trim().length > 0
13
+ )
14
+ }
15
+
16
+ export interface UsePlatformViewportResourceResult {
17
+ /** Latest resource for this viewport (boot binding or warm `resource.open`). */
18
+ resource: ResourceOpenEvent | null
19
+ /** Clears `resource` after the app has applied it (avoids re-open loops). */
20
+ clearResource: () => void
21
+ }
22
+
23
+ /**
24
+ * Per-tab resource binding from the shell workspace.
25
+ * Prefer `meta.viewport.resource` on bridge ready; also listens for `resource.open`.
26
+ */
27
+ export function usePlatformViewportResource(
28
+ ready: boolean,
29
+ meta: PlatformBridgeReadyMeta | null,
30
+ ): UsePlatformViewportResourceResult {
31
+ const [resource, setResource] = useState<ResourceOpenEvent | null>(null)
32
+ const bootTabIdRef = useRef<string | null>(null)
33
+
34
+ useEffect(() => {
35
+ return bridge.onEvent(PLATFORM_BRIDGE_EVENTS.RESOURCE_OPEN, payload => {
36
+ if (!isResourceOpenEvent(payload)) return
37
+ setResource(payload)
38
+ })
39
+ }, [])
40
+
41
+ useEffect(() => {
42
+ if (!ready || !meta?.viewport) return
43
+ if (bootTabIdRef.current === meta.viewport.tabId) return
44
+ bootTabIdRef.current = meta.viewport.tabId
45
+ if (meta.viewport.resource) {
46
+ setResource(meta.viewport.resource)
47
+ return
48
+ }
49
+
50
+ let cancelled = false
51
+ bridge
52
+ .call<{ resource?: ResourceOpenEvent | null }>(
53
+ PLATFORM_BRIDGE_METHODS.CATALOG_CONSUME_PENDING_OPEN,
54
+ [],
55
+ )
56
+ .then(result => {
57
+ if (cancelled || !isResourceOpenEvent(result?.resource)) return
58
+ setResource(result.resource)
59
+ })
60
+ .catch(() => undefined)
61
+
62
+ return () => {
63
+ cancelled = true
64
+ }
65
+ }, [meta, ready])
66
+
67
+ const clearResource = useCallback(() => {
68
+ setResource(null)
69
+ }, [])
70
+
71
+ return { resource, clearResource }
72
+ }
@@ -0,0 +1,59 @@
1
+ import { useEffect, useRef } from 'react'
2
+ import { bridge } from '../client.mjs'
3
+ import { PLATFORM_BRIDGE_EVENTS } from '../events.mjs'
4
+ import { PLATFORM_BRIDGE_METHODS } from '../methods.mjs'
5
+
6
+ /**
7
+ * Run `task` every `everyMinutes`, scheduled by the shell
8
+ * (`scheduler.register` + `schedule.fire` events) so all recurring work
9
+ * across the suite is declared in one place. Outside the shell
10
+ * (standalone dev) it falls back to a plain interval. `enabled: false`
11
+ * unregisters.
12
+ */
13
+ export function useScheduledTask(
14
+ taskName: string,
15
+ everyMinutes: number,
16
+ task: () => void,
17
+ options?: { enabled?: boolean },
18
+ ): void {
19
+ const taskRef = useRef(task)
20
+ taskRef.current = task
21
+ const enabled = options?.enabled ?? true
22
+
23
+ useEffect(() => {
24
+ if (!enabled) return undefined
25
+
26
+ const standalone = typeof window !== 'undefined' && window.parent === window
27
+ if (standalone) {
28
+ const timer = setInterval(
29
+ () => taskRef.current(),
30
+ Math.max(1, everyMinutes) * 60_000,
31
+ )
32
+ return () => clearInterval(timer)
33
+ }
34
+
35
+ const unsubscribe = bridge.onEvent(
36
+ PLATFORM_BRIDGE_EVENTS.SCHEDULE_FIRE,
37
+ payload => {
38
+ if ((payload as { taskName?: string } | null)?.taskName === taskName) {
39
+ taskRef.current()
40
+ }
41
+ },
42
+ )
43
+ void bridge
44
+ .waitForReady()
45
+ .then(() =>
46
+ bridge.call(PLATFORM_BRIDGE_METHODS.SCHEDULER_REGISTER, [
47
+ { taskName, everyMinutes },
48
+ ]),
49
+ )
50
+ .catch(() => undefined)
51
+
52
+ return () => {
53
+ unsubscribe()
54
+ void bridge
55
+ .call(PLATFORM_BRIDGE_METHODS.SCHEDULER_UNREGISTER, [{ taskName }])
56
+ .catch(() => undefined)
57
+ }
58
+ }, [enabled, everyMinutes, taskName])
59
+ }
@@ -0,0 +1,31 @@
1
+ import type {
2
+ PrintPageSize,
3
+ RenderPagedPreviewRequest,
4
+ RenderPagedPreviewResult,
5
+ RenderPagedSnapshotRequest,
6
+ RenderPagedSnapshotResult,
7
+ RenderPrintHtmlRequest,
8
+ } from './types.js'
9
+
10
+ export declare function renderPrintHtml(
11
+ request: RenderPrintHtmlRequest,
12
+ ): Promise<string>
13
+
14
+ export declare function preparePagedPreview(
15
+ request: RenderPagedPreviewRequest,
16
+ ): Promise<RenderPagedPreviewResult>
17
+
18
+ export declare function capturePagedSnapshot(
19
+ request: RenderPagedSnapshotRequest,
20
+ ): Promise<RenderPagedSnapshotResult>
21
+
22
+ export declare function getDefaultPrintStylesheet(
23
+ pageSize?: PrintPageSize,
24
+ ): Promise<string>
25
+
26
+ /** @returns unsubscribe */
27
+ export declare function onRenderProgress(
28
+ listener: (event: import('./types.js').RenderProgress) => void,
29
+ ): () => void
30
+
31
+ export declare function renderCancel(): Promise<void>
@@ -0,0 +1,62 @@
1
+ import { bridge } from './client.mjs'
2
+ import { PLATFORM_BRIDGE_EVENTS } from './events.mjs'
3
+ import { PLATFORM_BRIDGE_METHODS } from './methods.mjs'
4
+
5
+ /**
6
+ * Print an app-prepared HTML file to PDF (shell: Paged.js + Electron printToPDF).
7
+ * Requires `render` permission in plugin.json.
8
+ *
9
+ * @param {import('./types.js').RenderPrintHtmlRequest} request
10
+ * @returns {Promise<string>} Absolute path to the output PDF
11
+ */
12
+ export async function renderPrintHtml(request) {
13
+ return bridge.call(PLATFORM_BRIDGE_METHODS.RENDER_PRINT_HTML, [request])
14
+ }
15
+
16
+ /**
17
+ * Prepare an app print HTML file for preview (shell: Paged.js pagination).
18
+ * Requires `render` permission in plugin.json.
19
+ *
20
+ * @param {import('./types.js').RenderPagedPreviewRequest} request
21
+ * @returns {Promise<import('./types.js').RenderPagedPreviewResult>}
22
+ */
23
+ export async function preparePagedPreview(request) {
24
+ return bridge.call(PLATFORM_BRIDGE_METHODS.RENDER_PREPARE_PAGED_PREVIEW, [
25
+ request,
26
+ ])
27
+ }
28
+
29
+ /**
30
+ * Capture a paginated page image from an app print HTML file.
31
+ * Requires `render` permission.
32
+ *
33
+ * @param {import('./types.js').RenderPagedSnapshotRequest} request
34
+ * @returns {Promise<import('./types.js').RenderPagedSnapshotResult>}
35
+ */
36
+ export async function capturePagedSnapshot(request) {
37
+ return bridge.call(PLATFORM_BRIDGE_METHODS.RENDER_CAPTURE_PAGED_SNAPSHOT, [
38
+ request,
39
+ ])
40
+ }
41
+
42
+ /**
43
+ * Default Paged.js print CSS for a built-in page size (shell-owned).
44
+ * Requires `render` permission.
45
+ *
46
+ * @param {import('./types.js').PrintPageSize} [pageSize='A5']
47
+ * @returns {Promise<string>}
48
+ */
49
+ export async function getDefaultPrintStylesheet(pageSize = 'A5') {
50
+ return bridge.call(PLATFORM_BRIDGE_METHODS.RENDER_GET_PRINT_STYLESHEET, [
51
+ pageSize,
52
+ ])
53
+ }
54
+
55
+ /** @returns {() => void} unsubscribe */
56
+ export function onRenderProgress(listener) {
57
+ return bridge.onEvent(PLATFORM_BRIDGE_EVENTS.RENDER_PROGRESS, listener)
58
+ }
59
+
60
+ export async function renderCancel() {
61
+ return bridge.call(PLATFORM_BRIDGE_METHODS.RENDER_CANCEL, [])
62
+ }
@@ -0,0 +1,8 @@
1
+ export {
2
+ getDefaultPrintStylesheet,
3
+ onRenderProgress,
4
+ capturePagedSnapshot,
5
+ preparePagedPreview,
6
+ renderCancel,
7
+ renderPrintHtml,
8
+ } from './render.mjs'
@@ -0,0 +1,103 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import {
3
+ defaultAnnotationMessage,
4
+ selectTextFromCandidates,
5
+ type TextCandidate,
6
+ } from './screenAnnotation.js'
7
+
8
+ const candidates: TextCandidate[] = [
9
+ { text: 'First paragraph', rect: { x: 0, y: 0, width: 100, height: 20 } },
10
+ { text: 'Second paragraph', rect: { x: 0, y: 30, width: 100, height: 20 } },
11
+ { text: 'Far away', rect: { x: 0, y: 500, width: 100, height: 20 } },
12
+ ]
13
+
14
+ describe('selectTextFromCandidates', () => {
15
+ it('returns text of blocks overlapping the selection, in order', () => {
16
+ expect(
17
+ selectTextFromCandidates(candidates, {
18
+ x: 10,
19
+ y: 10,
20
+ width: 50,
21
+ height: 30,
22
+ }),
23
+ ).toBe('First paragraph\n\nSecond paragraph')
24
+ })
25
+
26
+ it('excludes blocks outside the selection', () => {
27
+ expect(
28
+ selectTextFromCandidates(candidates, {
29
+ x: 10,
30
+ y: 0,
31
+ width: 50,
32
+ height: 15,
33
+ }),
34
+ ).toBe('First paragraph')
35
+ })
36
+
37
+ it('dedupes and normalizes whitespace', () => {
38
+ expect(
39
+ selectTextFromCandidates(
40
+ [
41
+ { text: ' Hello world ', rect: { x: 0, y: 0, width: 10, height: 10 } },
42
+ { text: 'Hello world', rect: { x: 0, y: 0, width: 10, height: 10 } },
43
+ ],
44
+ { x: 0, y: 0, width: 10, height: 10 },
45
+ ),
46
+ ).toBe('Hello world')
47
+ })
48
+
49
+ it('returns empty string when nothing overlaps', () => {
50
+ expect(
51
+ selectTextFromCandidates(candidates, {
52
+ x: 1000,
53
+ y: 1000,
54
+ width: 10,
55
+ height: 10,
56
+ }),
57
+ ).toBe('')
58
+ })
59
+ })
60
+
61
+ describe('defaultAnnotationMessage', () => {
62
+ const baseCapture = {
63
+ imageDataUrl: 'data:image/png;base64,AAAA',
64
+ rect: { x: 0, y: 0, width: 10, height: 10 },
65
+ mode: 'content' as const,
66
+ note: 'tighten this',
67
+ hasMarks: false,
68
+ optionValues: {},
69
+ }
70
+
71
+ it('includes the note and resolved text in content mode', () => {
72
+ const message = defaultAnnotationMessage({
73
+ capture: baseCapture,
74
+ resolvedText: 'The paragraph text',
75
+ })
76
+ expect(message).toContain('tighten this')
77
+ expect(message).toContain('The paragraph text')
78
+ expect(message).toContain('annotated screenshot')
79
+ })
80
+
81
+ it('omits the resolved-text block in vibe mode', () => {
82
+ const message = defaultAnnotationMessage({
83
+ capture: { ...baseCapture, mode: 'ui', note: '' },
84
+ resolvedText: '',
85
+ })
86
+ expect(message).toContain('vibe mode')
87
+ expect(message).not.toContain('captured region')
88
+ })
89
+
90
+ it('adds pen-focus guidance only when marks were drawn', () => {
91
+ const withoutMarks = defaultAnnotationMessage({
92
+ capture: baseCapture,
93
+ resolvedText: 'text',
94
+ })
95
+ expect(withoutMarks).not.toContain('focus on what they marked')
96
+
97
+ const withMarks = defaultAnnotationMessage({
98
+ capture: { ...baseCapture, hasMarks: true },
99
+ resolvedText: 'text',
100
+ })
101
+ expect(withMarks).toContain('focus on what they marked')
102
+ })
103
+ })
@@ -0,0 +1,269 @@
1
+ import {
2
+ callAgentRunModel,
3
+ createAgentSession,
4
+ resolveAgentRunToolCalls,
5
+ startAgentRun,
6
+ } from './agents.js'
7
+ import { startScreenCapture } from './window.mjs'
8
+ import type {
9
+ PlatformScreenCaptureOption,
10
+ PlatformScreenCaptureRect,
11
+ PlatformScreenCaptureResult,
12
+ } from './window.mjs'
13
+
14
+ /**
15
+ * Shared screen-annotation capture → agent flow. Any app can call
16
+ * {@link captureAndSendToAgent}: it opens the shell's chromeless capture
17
+ * overlay, resolves the text under the selection (content mode), and starts an
18
+ * agent run with the annotated image attached. App-specific wording and tools
19
+ * are supplied via `buildMessage`.
20
+ *
21
+ * Requires the `agents` permission in plugin.json.
22
+ */
23
+
24
+ const DEFAULT_MAX_STEPS = 8
25
+
26
+ export interface TextCandidate {
27
+ text: string
28
+ rect: PlatformScreenCaptureRect
29
+ }
30
+
31
+ function rectsIntersect(
32
+ a: PlatformScreenCaptureRect,
33
+ b: PlatformScreenCaptureRect,
34
+ ): boolean {
35
+ return (
36
+ a.x < b.x + b.width &&
37
+ a.x + a.width > b.x &&
38
+ a.y < b.y + b.height &&
39
+ a.y + a.height > b.y
40
+ )
41
+ }
42
+
43
+ /**
44
+ * Pure core: pick the text of candidates whose rect overlaps the selection, in
45
+ * order, deduped + whitespace-normalized. Separated from the DOM so it is
46
+ * unit-testable (jsdom has no layout).
47
+ */
48
+ export function selectTextFromCandidates(
49
+ candidates: TextCandidate[],
50
+ selection: PlatformScreenCaptureRect,
51
+ ): string {
52
+ const seen = new Set<string>()
53
+ const parts: string[] = []
54
+ for (const candidate of candidates) {
55
+ if (!rectsIntersect(candidate.rect, selection)) continue
56
+ const text = candidate.text.replace(/\s+/g, ' ').trim()
57
+ if (!text || seen.has(text)) continue
58
+ seen.add(text)
59
+ parts.push(text)
60
+ }
61
+ return parts.join('\n\n')
62
+ }
63
+
64
+ const DEFAULT_BLOCK_SELECTOR =
65
+ 'p, li, h1, h2, h3, h4, h5, h6, blockquote, figcaption, td, th, pre, dt, dd'
66
+
67
+ export interface ResolveSelectionTextOptions {
68
+ /** Root to search within. Defaults to the active editor / contenteditable. */
69
+ root?: ParentNode | null
70
+ /** Block-level selector to collect. */
71
+ selector?: string
72
+ }
73
+
74
+ /**
75
+ * Resolve the text that intersects an app-local selection rect (CSS px relative
76
+ * to the app's own document viewport). Reads block elements inside the editor
77
+ * surface; returns '' when nothing meaningful overlaps.
78
+ */
79
+ export function resolveSelectionText(
80
+ selection: PlatformScreenCaptureRect,
81
+ options: ResolveSelectionTextOptions = {},
82
+ ): string {
83
+ const root =
84
+ options.root ??
85
+ document.querySelector('.ProseMirror, [contenteditable="true"]')
86
+ if (!root) return ''
87
+ const selector = options.selector ?? DEFAULT_BLOCK_SELECTOR
88
+ const blocks = Array.from(root.querySelectorAll<HTMLElement>(selector))
89
+ const candidates: TextCandidate[] = blocks.map(element => {
90
+ const r = element.getBoundingClientRect()
91
+ return {
92
+ text: element.textContent ?? '',
93
+ rect: { x: r.left, y: r.top, width: r.width, height: r.height },
94
+ }
95
+ })
96
+ return selectTextFromCandidates(candidates, selection)
97
+ }
98
+
99
+ export interface ScreenAnnotationResult {
100
+ capture: PlatformScreenCaptureResult
101
+ /** Text resolved under the selection (content mode); '' in vibe mode. */
102
+ resolvedText: string
103
+ }
104
+
105
+ /** In-progress + terminal states a caller can reflect with quiet UI. */
106
+ export type CaptureAgentStatus =
107
+ | 'working'
108
+ | 'applied'
109
+ | 'no-changes'
110
+ | 'needs-approval'
111
+ | 'error'
112
+
113
+ export interface CaptureAgentOutcome {
114
+ sessionId: string | null
115
+ status: 'applied' | 'no-changes' | 'needs-approval' | 'error' | 'cancelled'
116
+ error?: string
117
+ }
118
+
119
+ export interface CaptureAndSendOptions {
120
+ appSlug: string
121
+ /** What this capture transforms, shown in the overlay (e.g. "book content", "page design"). */
122
+ label?: string
123
+ /** Contextual option controls rendered in the overlay (e.g. design scope). */
124
+ options?: PlatformScreenCaptureOption[]
125
+ /** Build the agent user message from the capture + resolved text. */
126
+ buildMessage?: (result: ScreenAnnotationResult) => string
127
+ /** Session title (string or builder). */
128
+ title?: string | ((result: ScreenAnnotationResult) => string)
129
+ /** Resolve text under the selection in content mode. Defaults to {@link resolveSelectionText}. */
130
+ resolveText?: (rect: PlatformScreenCaptureRect) => string
131
+ /** Total model + tool-resolution turns to drive. Default 8. */
132
+ maxSteps?: number
133
+ /** Progress callback for quiet UI: 'working' first, then a terminal status. */
134
+ onStatus?: (status: CaptureAgentStatus) => void
135
+ }
136
+
137
+ /**
138
+ * Guidance for interpreting pen marks. The marks (circles, underlines, arrows)
139
+ * indicate the focus; their scope is a judgment call the agent must make.
140
+ */
141
+ export function penFocusGuidance(): string {
142
+ return [
143
+ 'The user drew marks on the screenshot — focus on what they marked, not the whole captured region.',
144
+ 'Marks may circle, underline, or point at content. Use judgment about scope: the user may mean exactly the marked words, the sentence that contains them, or the whole paragraph/section.',
145
+ 'Infer the most sensible scope from the marks and the note together. If it is genuinely ambiguous, prefer the smallest coherent unit (usually the sentence) unless the note implies a larger change.',
146
+ ].join('\n')
147
+ }
148
+
149
+ /** Generic fallback message when an app doesn't supply `buildMessage`. */
150
+ export function defaultAnnotationMessage({
151
+ capture,
152
+ resolvedText,
153
+ }: ScreenAnnotationResult): string {
154
+ const note = capture.note.trim()
155
+ return [
156
+ capture.mode === 'content'
157
+ ? 'The user captured and annotated a region of this app and wants a change applied there.'
158
+ : 'The user captured and annotated a region of the app UI (vibe mode).',
159
+ '',
160
+ note ? `Note from the user:\n${note}` : 'No extra note.',
161
+ capture.hasMarks ? `\n${penFocusGuidance()}` : '',
162
+ resolvedText
163
+ ? `\nText in the captured region (for reference — the marks show the focus):\n"""\n${resolvedText}\n"""`
164
+ : '',
165
+ '',
166
+ 'Use the attached annotated screenshot (with the user’s drawing) to make the change.',
167
+ ]
168
+ .filter(line => line !== '')
169
+ .join('\n')
170
+ }
171
+
172
+ interface DataUrlImage {
173
+ mediaType: string
174
+ dataBase64: string
175
+ }
176
+
177
+ function splitDataUrl(dataUrl: string): DataUrlImage | null {
178
+ const match = /^data:([^;]+);base64,(.+)$/s.exec(dataUrl)
179
+ if (!match) return null
180
+ return { mediaType: match[1], dataBase64: match[2] }
181
+ }
182
+
183
+ /**
184
+ * Open the capture overlay and, on send, run an agent end to end: call the
185
+ * model, then route + resolve its tool calls so the edit is actually applied
186
+ * (not left pending). Content mode targets the app's own agent (scope 'app');
187
+ * vibe mode targets a global agent. `onStatus` reports progress so the caller
188
+ * can show quiet feedback. Returns an outcome describing what happened.
189
+ */
190
+ export async function captureAndSendToAgent(
191
+ options: CaptureAndSendOptions,
192
+ ): Promise<CaptureAgentOutcome> {
193
+ const capture = await startScreenCapture({
194
+ label: options.label,
195
+ options: options.options,
196
+ })
197
+ if (!capture) return { sessionId: null, status: 'cancelled' }
198
+
199
+ const resolveText = options.resolveText ?? resolveSelectionText
200
+ const resolvedText =
201
+ capture.mode === 'content' ? resolveText(capture.rect) : ''
202
+ const result: ScreenAnnotationResult = { capture, resolvedText }
203
+
204
+ const buildMessage = options.buildMessage ?? defaultAnnotationMessage
205
+ const message = buildMessage(result)
206
+ const image = splitDataUrl(capture.imageDataUrl)
207
+ const title =
208
+ typeof options.title === 'function'
209
+ ? options.title(result)
210
+ : options.title ?? 'Screen annotation'
211
+
212
+ const scope = capture.mode === 'content' ? ('app' as const) : ('global' as const)
213
+
214
+ options.onStatus?.('working')
215
+ try {
216
+ const record = await createAgentSession({
217
+ scope,
218
+ ...(scope === 'app' ? { appSlug: options.appSlug } : {}),
219
+ title,
220
+ })
221
+ const session = {
222
+ scope,
223
+ ...(scope === 'app' ? { appSlug: options.appSlug } : {}),
224
+ sessionId: record.sessionId,
225
+ }
226
+
227
+ let snapshot = await startAgentRun({
228
+ session,
229
+ message,
230
+ ...(image ? { images: [image] } : {}),
231
+ })
232
+ const runId = snapshot.runId
233
+ const maxSteps = options.maxSteps ?? DEFAULT_MAX_STEPS
234
+ let appliedTools = false
235
+
236
+ for (let step = 0; step < maxSteps; step += 1) {
237
+ if (snapshot.state === 'ready') {
238
+ snapshot = await callAgentRunModel({ runId, sessionId: record.sessionId })
239
+ continue
240
+ }
241
+ if (snapshot.state === 'pending_tools') {
242
+ const resolved = await resolveAgentRunToolCalls({ runId, session })
243
+ if (resolved.state === 'pending_tools') {
244
+ // A tool still needs explicit approval — hand off to the drawer.
245
+ options.onStatus?.('needs-approval')
246
+ return { sessionId: record.sessionId, status: 'needs-approval' }
247
+ }
248
+ appliedTools = true
249
+ snapshot = resolved
250
+ continue
251
+ }
252
+ break
253
+ }
254
+
255
+ if (snapshot.state === 'failed') {
256
+ const error = snapshot.error ?? 'The agent run failed.'
257
+ options.onStatus?.('error')
258
+ return { sessionId: record.sessionId, status: 'error', error }
259
+ }
260
+
261
+ const status = appliedTools ? 'applied' : 'no-changes'
262
+ options.onStatus?.(status)
263
+ return { sessionId: record.sessionId, status }
264
+ } catch (cause) {
265
+ const error = cause instanceof Error ? cause.message : String(cause)
266
+ options.onStatus?.('error')
267
+ return { sessionId: null, status: 'error', error }
268
+ }
269
+ }
@@ -0,0 +1,3 @@
1
+ export function setSurfacePalette(
2
+ paletteId: string,
3
+ ): Promise<import('./types.ts').PlatformShellPreferences>
@@ -0,0 +1,9 @@
1
+ import { bridge } from './client.mjs'
2
+ import { PLATFORM_BRIDGE_METHODS } from './methods.mjs'
3
+
4
+ /** Ask the shell to store a surface palette for the calling app (whole desktop theme). */
5
+ export async function setSurfacePalette(paletteId) {
6
+ return bridge.call(PLATFORM_BRIDGE_METHODS.THEME_SET_SURFACE_PALETTE, [
7
+ { paletteId },
8
+ ])
9
+ }