@puredesktop/puredesktop-ui-bridge 2.1.4 → 2.1.6
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.
- package/package.json +19 -1
- package/src/agents/runtime/mapAgentSnapshot.test.ts +1 -3
- package/src/agents/runtime/mapAgentSnapshot.ts +8 -4
- package/src/agents/runtime/mergeUsageTurn.ts +1 -2
- package/src/agents/runtime/pendingToolCalls.test.ts +1 -3
- package/src/agents/runtime/unresolvedToolCalls.ts +1 -2
- package/src/bridge/agentModelTiers.ts +9 -4
- package/src/bridge/agents.mjs +3 -1
- package/src/bridge/calendarDraftIntent.ts +12 -4
- package/src/bridge/calendarInviteIntent.ts +18 -5
- package/src/bridge/client.mjs +45 -45
- package/src/bridge/dialog.d.mts +8 -8
- package/src/bridge/dialog.mjs +40 -40
- package/src/bridge/dialog.test.ts +73 -73
- package/src/bridge/fs.d.mts +41 -41
- package/src/bridge/fs.mjs +56 -56
- package/src/bridge/fs.test.ts +83 -83
- package/src/bridge/fs.ts +28 -28
- package/src/bridge/googleAuth.ts +3 -1
- package/src/bridge/methods.d.mts +6 -0
- package/src/bridge/methods.mjs +7 -0
- package/src/bridge/network.d.mts +17 -17
- package/src/bridge/network.mjs +22 -22
- package/src/bridge/pureRender/base.css +324 -76
- package/src/bridge/pureRender/compiler.ts +1 -1
- package/src/bridge/pureRender/document.test.ts +2 -2
- package/src/bridge/pureRender/extraction.test.ts +24 -12
- package/src/bridge/pureRender/extraction.ts +10 -7
- package/src/bridge/pureRender/flow.css +17 -3
- package/src/bridge/pureRender/normalize.ts +28 -26
- package/src/bridge/pureRender/presets.ts +7 -7
- package/src/bridge/pureRender/profiles/book.css +122 -19
- package/src/bridge/pureRender/profiles/manuscript.css +57 -11
- package/src/bridge/pureRender/profiles/writer.css +48 -10
- package/src/bridge/pureRender/reset.css +20 -5
- package/src/bridge/pureRender/theme.ts +37 -9
- package/src/bridge/pureRender/tokens/default.css +45 -33
- package/src/bridge/react/usePlatformAgentRunLiveState.tsx +4 -1
- package/src/bridge/react/usePlatformAgentSessionDrive.tsx +13 -4
- package/src/bridge/screenAnnotation.test.ts +4 -1
- package/src/bridge/screenAnnotation.ts +6 -2
- package/src/bridge/storage.d.mts +27 -27
- package/src/bridge/storage.mjs +18 -18
- package/src/bridge/storage.test.ts +49 -49
- package/src/bridge/types.ts +62 -58
- package/src/bridge/window.d.mts +3 -1
- package/src/bridge/workspace.d.mts +7 -0
- package/src/bridge/workspace.mjs +8 -0
- package/src/bridge/workspace.ts +1 -0
- package/src/commitments/commitments.test.ts +10 -3
- package/src/commitments/commitments.ts +18 -4
- package/src/components/accessibility/AccessibilityReviewDialog.tsx +7 -2
- package/src/components/accessibility/accessibilityReview.test.ts +11 -4
- package/src/components/accessibility/accessibilityReview.ts +18 -10
- package/src/components/agent-feedback/ScreenAnnotationAgentDialog.tsx +9 -2
- package/src/components/agents/AgentContextUsageBar.tsx +5 -3
- package/src/components/agents/AgentDrawerPanel.test.tsx +15 -3
- package/src/components/agents/AgentMessageBubble.tsx +1 -3
- package/src/components/agents/AgentQuestionPromptList.tsx +3 -3
- package/src/components/agents/AgentToolApprovalActions.tsx +1 -3
- package/src/components/agents/agentPanelStyles.ts +1 -1
- package/src/components/agents/agentToolDisplay.ts +4 -1
- package/src/components/assets/asset-library/AssetLibraryDialog.tsx +2 -0
- package/src/components/assets/asset-library/AssetLibraryWorkspace.tsx +2 -0
- package/src/components/assets/asset-library/detail/AssetLibraryDetailHeader.test.tsx +40 -0
- package/src/components/assets/asset-library/detail/AssetLibraryDetailHeader.tsx +7 -3
- package/src/components/assets/asset-library/detail/AssetLibraryDetailPreview.tsx +8 -8
- package/src/components/assets/asset-library/hooks/useAssetLibraryDialog.ts +13 -2
- package/src/components/assets/asset-library/hooks/useAssetLibraryMutations.ts +18 -1
- package/src/components/assets/asset-library/sidebar/AssetLibraryListRow.tsx +9 -6
- package/src/components/assets/asset-library/sidebar/AssetLibrarySidebarToolbar.tsx +3 -1
- package/src/components/assets/asset-library/sidebar/AssetListThumbnail.tsx +1 -1
- package/src/components/assets/asset-library/types.ts +6 -0
- package/src/components/chrome/OverlayActionCapsule.tsx +2 -2
- package/src/components/chrome/PanelTabStrip.tsx +3 -2
- package/src/components/chrome/PureAppWordmark.tsx +15 -15
- package/src/components/chrome/WorkspaceTabStrip.tsx +19 -14
- package/src/components/chrome/documentChromePolicy.test.ts +34 -0
- package/src/components/chrome/documentChromePolicy.ts +15 -0
- package/src/components/chrome/index.ts +4 -0
- package/src/components/chrome/workspaceTabTypes.ts +2 -0
- package/src/components/common/buttons/Button.tsx +60 -10
- package/src/components/common/buttons/ChoiceChip.tsx +2 -2
- package/src/components/common/buttons/IconButton.tsx +26 -0
- package/src/components/common/buttons/SegmentedControl.tsx +23 -7
- package/src/components/common/canvas/CanvasElementFrame.tsx +37 -28
- package/src/components/common/canvas/canvasGeometry.test.ts +4 -5
- package/src/components/common/canvas/canvasGeometry.ts +1 -4
- package/src/components/common/canvas/useCanvasDragResize.test.tsx +10 -10
- package/src/components/common/canvas/useCanvasDragResize.ts +1 -4
- package/src/components/common/cards/OpenReviewCard.tsx +6 -6
- package/src/components/common/chat/ChatBox.test.tsx +9 -1
- package/src/components/common/chat/ChatBox.tsx +3 -4
- package/src/components/common/chat/ChatMarkdown.tsx +1 -1
- package/src/components/common/chat/ChatModelMenu.tsx +1 -1
- package/src/components/common/chat/ChatThinkingIndicator.tsx +1 -1
- package/src/components/common/chat/ChatThread.tsx +2 -1
- package/src/components/common/chat/ChatToolRow.tsx +2 -2
- package/src/components/common/chat/ChatUserBubble.tsx +1 -1
- package/src/components/common/connections/ConnectionSetup.tsx +6 -6
- package/src/components/common/containers/AppFrame.test.tsx +37 -36
- package/src/components/common/containers/AppFrame.tsx +15 -0
- package/src/components/common/containers/AppHeader.tsx +6 -3
- package/src/components/common/containers/SurfacePanel.tsx +1 -0
- package/src/components/common/containers/useOpacityPresence.ts +10 -15
- package/src/components/common/context/ContextSelector.tsx +10 -10
- package/src/components/common/desk/CreationDesk.tsx +23 -11
- package/src/components/common/desk/DailyBrief.tsx +18 -7
- package/src/components/common/desk/DeskCard.tsx +11 -6
- package/src/components/common/dropdown/MenuButtonDropdown.tsx +58 -6
- package/src/components/common/dropdown/MenuDropdownItem.tsx +23 -3
- package/src/components/common/dropdown/MenuPanel.tsx +8 -8
- package/src/components/common/dropdown/SelectMenu.tsx +8 -3
- package/src/components/common/dropdown/menuTypes.ts +2 -1
- package/src/components/common/evidence/StructuredEvidenceView.tsx +9 -5
- package/src/components/common/feedback/Badge.tsx +19 -5
- package/src/components/common/feedback/CapabilityPills.tsx +1 -1
- package/src/components/common/feedback/InfoHint.tsx +2 -2
- package/src/components/common/feedback/PlatformChip.tsx +9 -9
- package/src/components/common/feedback/QuietPill.tsx +5 -8
- package/src/components/common/feedback/WorkProgressPanel.tsx +14 -14
- package/src/components/common/files/FileTable.tsx +8 -2
- package/src/components/common/inputs/Checkbox.tsx +1 -1
- package/src/components/common/inputs/EditableSecretField.tsx +1 -3
- package/src/components/common/inputs/InlineComposer.tsx +2 -2
- package/src/components/common/inputs/PaletteDropdown.tsx +33 -23
- package/src/components/common/inputs/SurfacePalettePicker.tsx +1 -1
- package/src/components/common/inputs/ToggleSwitch.tsx +2 -2
- package/src/components/common/inputs/WorkspacePicker.tsx +3 -3
- package/src/components/common/lists/listRowStyles.ts +4 -2
- package/src/components/common/lists/quiet-ledger/index.ts +1 -4
- package/src/components/common/lists/reorderable/DragHandle.tsx +1 -1
- package/src/components/common/lists/reorderable/ReorderableSections.tsx +2 -1
- package/src/components/common/media/ImageReferencePicker.tsx +22 -14
- package/src/components/common/narrative/NarrativeMention.tsx +15 -9
- package/src/components/common/navigation/NavigationCardRow.tsx +2 -2
- package/src/components/common/navigation/UnderlineTabs.tsx +1 -0
- package/src/components/common/overlays/Modal.tsx +52 -3
- package/src/components/common/overlays/ObjectActionStrip.tsx +2 -2
- package/src/components/common/people/AutoUpdateReviewList.tsx +2 -2
- package/src/components/common/people/EntityList.tsx +7 -3
- package/src/components/common/people/EntityPortrait.tsx +6 -1
- package/src/components/common/people/LinkedDossierList.tsx +3 -1
- package/src/components/common/people/RelationshipMap.tsx +3 -9
- package/src/components/common/research/EvidenceDossier.tsx +24 -20
- package/src/components/common/tiles/CatalogCard.tsx +1 -1
- package/src/components/credentials/CredentialsPanel.tsx +2 -6
- package/src/components/data/DataChart.tsx +119 -94
- package/src/components/data/dataTable.ts +4 -1
- package/src/components/editor/DocumentAppChrome.tsx +172 -0
- package/src/components/editor/EditorCommentPromptDialog.tsx +1 -1
- package/src/components/editor/EditorLinkPromptDialog.tsx +1 -1
- package/src/components/print-design/PrintDesignPanel.test.tsx +8 -6
- package/src/components/print-design/PrintDesignPanel.tsx +18 -25
- package/src/components/proofing/PagedProofDialog.tsx +17 -4
- package/src/editor/EditorViewModeToggle.tsx +6 -2
- package/src/editor/index.ts +6 -0
- package/src/theme/ThemeProvider.tsx +5 -2
- package/src/theme/appAccents.test.ts +51 -0
- package/src/theme/appAccents.ts +151 -88
- package/src/theme/appIdentityCss.mjs +256 -0
- package/src/theme/appIdentityCss.ts +256 -0
- package/src/theme/composePlatformTheme.test.ts +43 -14
- package/src/theme/platformFont.d.mts +2 -2
- package/src/theme/platformFont.mjs +4 -3
- package/src/theme/reportsShellChromeSelectors.ts +14 -132
- package/src/theme/surfaceCss.mjs +37 -0
- package/src/theme/surfaceCss.ts +37 -0
- package/src/theme/surfacePalettes.ts +120 -79
- package/src/theme/surfaceRoleSelectors.ts +135 -71
- package/src/theme/themes/dark.ts +44 -43
- package/src/theme/themes/light.ts +40 -38
- package/src/theme/themes/palette.ts +32 -30
- package/src/theme/themes/shared.ts +17 -17
- package/src/theme/utils/GlobalStyles.ts +10 -6
- package/src/theme/utils/appFrameDocumentStyles.mjs +6 -1
- package/src/theme/utils/cssVariables.ts +169 -0
- package/src/writing/DraftAssistantDialog.tsx +85 -85
- package/src/writing/WritingStyleManager.tsx +6 -3
- package/src/writing/draftTextWithAgent.ts +47 -50
- package/src/writing/styleStore.ts +4 -3
- package/src/writing/writingStyle.test.ts +8 -2
- package/src/writing/writingStyle.ts +19 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@puredesktop/puredesktop-ui-bridge",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.6",
|
|
4
4
|
"description": "PureScience plugin SDK — bridge client, theme, and shared UI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -278,6 +278,10 @@
|
|
|
278
278
|
"./bridge/window.mjs": "./src/bridge/window.mjs",
|
|
279
279
|
"./bridge/window": "./src/bridge/window.mjs",
|
|
280
280
|
"./bridge/window.js": "./src/bridge/window.mjs",
|
|
281
|
+
"./bridge/workspace.mjs": "./src/bridge/workspace.mjs",
|
|
282
|
+
"./bridge/workspace": "./src/bridge/workspace.ts",
|
|
283
|
+
"./bridge/workspace.js": "./src/bridge/workspace.ts",
|
|
284
|
+
"./bridge/workspace.ts": "./src/bridge/workspace.ts",
|
|
281
285
|
"./chrome/index.ts": "./src/chrome/index.ts",
|
|
282
286
|
"./chrome/index": "./src/chrome/index.ts",
|
|
283
287
|
"./chrome/index.js": "./src/chrome/index.ts",
|
|
@@ -474,6 +478,9 @@
|
|
|
474
478
|
"./components/assets/AssetLibraryDialog.tsx": "./src/components/assets/AssetLibraryDialog.tsx",
|
|
475
479
|
"./components/assets/AssetLibraryDialog": "./src/components/assets/AssetLibraryDialog.tsx",
|
|
476
480
|
"./components/assets/AssetLibraryDialog.js": "./src/components/assets/AssetLibraryDialog.tsx",
|
|
481
|
+
"./components/chrome/documentChromePolicy.ts": "./src/components/chrome/documentChromePolicy.ts",
|
|
482
|
+
"./components/chrome/documentChromePolicy": "./src/components/chrome/documentChromePolicy.ts",
|
|
483
|
+
"./components/chrome/documentChromePolicy.js": "./src/components/chrome/documentChromePolicy.ts",
|
|
477
484
|
"./components/chrome/index.ts": "./src/components/chrome/index.ts",
|
|
478
485
|
"./components/chrome/index": "./src/components/chrome/index.ts",
|
|
479
486
|
"./components/chrome/index.js": "./src/components/chrome/index.ts",
|
|
@@ -1023,6 +1030,9 @@
|
|
|
1023
1030
|
"./components/data/dataTable.ts": "./src/components/data/dataTable.ts",
|
|
1024
1031
|
"./components/data/dataTable": "./src/components/data/dataTable.ts",
|
|
1025
1032
|
"./components/data/dataTable.js": "./src/components/data/dataTable.ts",
|
|
1033
|
+
"./components/editor/DocumentAppChrome.tsx": "./src/components/editor/DocumentAppChrome.tsx",
|
|
1034
|
+
"./components/editor/DocumentAppChrome": "./src/components/editor/DocumentAppChrome.tsx",
|
|
1035
|
+
"./components/editor/DocumentAppChrome.js": "./src/components/editor/DocumentAppChrome.tsx",
|
|
1026
1036
|
"./components/editor/EditorCommentPromptDialog.tsx": "./src/components/editor/EditorCommentPromptDialog.tsx",
|
|
1027
1037
|
"./components/editor/EditorCommentPromptDialog": "./src/components/editor/EditorCommentPromptDialog.tsx",
|
|
1028
1038
|
"./components/editor/EditorCommentPromptDialog.js": "./src/components/editor/EditorCommentPromptDialog.tsx",
|
|
@@ -1062,6 +1072,10 @@
|
|
|
1062
1072
|
"./theme/appAccents.ts": "./src/theme/appAccents.ts",
|
|
1063
1073
|
"./theme/appAccents": "./src/theme/appAccents.ts",
|
|
1064
1074
|
"./theme/appAccents.js": "./src/theme/appAccents.ts",
|
|
1075
|
+
"./theme/appIdentityCss.mjs": "./src/theme/appIdentityCss.mjs",
|
|
1076
|
+
"./theme/appIdentityCss": "./src/theme/appIdentityCss.ts",
|
|
1077
|
+
"./theme/appIdentityCss.js": "./src/theme/appIdentityCss.ts",
|
|
1078
|
+
"./theme/appIdentityCss.ts": "./src/theme/appIdentityCss.ts",
|
|
1065
1079
|
"./theme/buildThemeBridgePayload.ts": "./src/theme/buildThemeBridgePayload.ts",
|
|
1066
1080
|
"./theme/buildThemeBridgePayload": "./src/theme/buildThemeBridgePayload.ts",
|
|
1067
1081
|
"./theme/buildThemeBridgePayload.js": "./src/theme/buildThemeBridgePayload.ts",
|
|
@@ -1075,6 +1089,10 @@
|
|
|
1075
1089
|
"./theme/reportsShellChromeSelectors.ts": "./src/theme/reportsShellChromeSelectors.ts",
|
|
1076
1090
|
"./theme/reportsShellChromeSelectors": "./src/theme/reportsShellChromeSelectors.ts",
|
|
1077
1091
|
"./theme/reportsShellChromeSelectors.js": "./src/theme/reportsShellChromeSelectors.ts",
|
|
1092
|
+
"./theme/surfaceCss.mjs": "./src/theme/surfaceCss.mjs",
|
|
1093
|
+
"./theme/surfaceCss": "./src/theme/surfaceCss.ts",
|
|
1094
|
+
"./theme/surfaceCss.js": "./src/theme/surfaceCss.ts",
|
|
1095
|
+
"./theme/surfaceCss.ts": "./src/theme/surfaceCss.ts",
|
|
1078
1096
|
"./theme/surfacePalettes.ts": "./src/theme/surfacePalettes.ts",
|
|
1079
1097
|
"./theme/surfacePalettes": "./src/theme/surfacePalettes.ts",
|
|
1080
1098
|
"./theme/surfacePalettes.js": "./src/theme/surfacePalettes.ts",
|
|
@@ -91,8 +91,6 @@ describe('mapApprovalPendingToolCalls', () => {
|
|
|
91
91
|
}
|
|
92
92
|
expect(
|
|
93
93
|
mapApprovalPendingToolCalls(snapshot, policy, ['call-accepted']),
|
|
94
|
-
).toEqual([
|
|
95
|
-
{ id: 'call-manual', name: 'book.review', arguments: {} },
|
|
96
|
-
])
|
|
94
|
+
).toEqual([{ id: 'call-manual', name: 'book.review', arguments: {} }])
|
|
97
95
|
})
|
|
98
96
|
})
|
|
@@ -12,8 +12,10 @@ import { toolRequiresApproval } from './toolRequiresApproval.js'
|
|
|
12
12
|
|
|
13
13
|
const VISIBLE_ROLES = new Set(['user', 'assistant', 'tool'])
|
|
14
14
|
|
|
15
|
-
export function mapRunState(
|
|
16
|
-
|
|
15
|
+
export function mapRunState(
|
|
16
|
+
state: string,
|
|
17
|
+
): (typeof AgentUiRunState)[keyof typeof AgentUiRunState] {
|
|
18
|
+
return state as (typeof AgentUiRunState)[keyof typeof AgentUiRunState]
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
export function mapSnapshotToMessages(
|
|
@@ -69,7 +71,9 @@ export function mapPendingToolCalls(
|
|
|
69
71
|
snapshot: PlatformAgentRunSnapshot | null,
|
|
70
72
|
): AgentUiToolCall[] {
|
|
71
73
|
if (!snapshot) return []
|
|
72
|
-
return derivePendingToolCalls(snapshot.messages, snapshot.state).map(
|
|
74
|
+
return derivePendingToolCalls(snapshot.messages, snapshot.state).map(
|
|
75
|
+
mapToolCall,
|
|
76
|
+
)
|
|
73
77
|
}
|
|
74
78
|
|
|
75
79
|
/** Pending tools that still need explicit user approval. */
|
|
@@ -111,7 +115,7 @@ function mapToolCallWithResult(
|
|
|
111
115
|
}
|
|
112
116
|
|
|
113
117
|
export function isComposerEnabled(
|
|
114
|
-
runState: typeof AgentUiRunState[keyof typeof AgentUiRunState] | null,
|
|
118
|
+
runState: (typeof AgentUiRunState)[keyof typeof AgentUiRunState] | null,
|
|
115
119
|
busy: boolean,
|
|
116
120
|
): boolean {
|
|
117
121
|
if (busy) return false
|
|
@@ -6,8 +6,7 @@ export function mergeUsageTurn(
|
|
|
6
6
|
delta: AgentUsageTurnDelta,
|
|
7
7
|
estimated = false,
|
|
8
8
|
): PlatformAgentRunUsage {
|
|
9
|
-
const turnTotal =
|
|
10
|
-
delta.totalTokens ?? delta.inputTokens + delta.outputTokens
|
|
9
|
+
const turnTotal = delta.totalTokens ?? delta.inputTokens + delta.outputTokens
|
|
11
10
|
const next: PlatformAgentRunUsage = {
|
|
12
11
|
inputTokens: (base?.inputTokens ?? 0) + delta.inputTokens,
|
|
13
12
|
outputTokens: (base?.outputTokens ?? 0) + delta.outputTokens,
|
|
@@ -31,9 +31,7 @@ describe('derivePendingToolCalls', () => {
|
|
|
31
31
|
{
|
|
32
32
|
role: 'assistant',
|
|
33
33
|
content: '',
|
|
34
|
-
toolCalls: [
|
|
35
|
-
{ id: 'tc-1', name: 'book:read', arguments: {} },
|
|
36
|
-
],
|
|
34
|
+
toolCalls: [{ id: 'tc-1', name: 'book:read', arguments: {} }],
|
|
37
35
|
},
|
|
38
36
|
],
|
|
39
37
|
AgentUiRunState.AwaitingUser,
|
|
@@ -26,8 +26,7 @@ export function unresolvedToolCalls(
|
|
|
26
26
|
messages
|
|
27
27
|
.filter(
|
|
28
28
|
message =>
|
|
29
|
-
message.role === 'tool' &&
|
|
30
|
-
typeof message.toolCallId === 'string',
|
|
29
|
+
message.role === 'tool' && typeof message.toolCallId === 'string',
|
|
31
30
|
)
|
|
32
31
|
.map(message => message.toolCallId as string),
|
|
33
32
|
)
|
|
@@ -8,7 +8,9 @@ export const DEFAULT_AGENT_LOW_LEVEL_MODEL_ID = 'deepseek:deepseek-v4-flash'
|
|
|
8
8
|
export const AGENT_AUTO_MODEL_ID = 'auto'
|
|
9
9
|
export const AGENT_AUTO_MODEL_LABEL = 'Auto'
|
|
10
10
|
|
|
11
|
-
export function isAgentAutoModelId(
|
|
11
|
+
export function isAgentAutoModelId(
|
|
12
|
+
modelId: string | undefined | null,
|
|
13
|
+
): boolean {
|
|
12
14
|
return modelId === AGENT_AUTO_MODEL_ID
|
|
13
15
|
}
|
|
14
16
|
|
|
@@ -36,9 +38,12 @@ export interface PlatformAgentSessionScopeDefaults {
|
|
|
36
38
|
|
|
37
39
|
/** Resolve tier ids from shell preferences with catalog fallbacks. */
|
|
38
40
|
export function resolveAgentModelTiersFromPrefs(
|
|
39
|
-
prefs:
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
prefs:
|
|
42
|
+
| {
|
|
43
|
+
agentModelTiers?: Partial<PlatformAgentModelTiers>
|
|
44
|
+
}
|
|
45
|
+
| null
|
|
46
|
+
| undefined,
|
|
42
47
|
): PlatformAgentModelTiers {
|
|
43
48
|
const stored = prefs?.agentModelTiers
|
|
44
49
|
return {
|
package/src/bridge/agents.mjs
CHANGED
|
@@ -129,7 +129,9 @@ export async function advanceAgentSessionPending(request) {
|
|
|
129
129
|
* @returns {Promise<import('./agentTypes.js').PlatformAgentSessionDriveResult>}
|
|
130
130
|
*/
|
|
131
131
|
export async function interruptAgentSession(request) {
|
|
132
|
-
return bridge.call(PLATFORM_BRIDGE_METHODS.AGENTS_SESSION_INTERRUPT, [
|
|
132
|
+
return bridge.call(PLATFORM_BRIDGE_METHODS.AGENTS_SESSION_INTERRUPT, [
|
|
133
|
+
request,
|
|
134
|
+
])
|
|
133
135
|
}
|
|
134
136
|
|
|
135
137
|
/**
|
|
@@ -39,17 +39,25 @@ export interface CalendarDraftIntentStore {
|
|
|
39
39
|
intents: Record<string, CalendarDraftIntent>
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
export function calendarDraftResourceId(
|
|
43
|
-
|
|
42
|
+
export function calendarDraftResourceId(
|
|
43
|
+
accountId: string,
|
|
44
|
+
threadId: string,
|
|
45
|
+
): string {
|
|
46
|
+
return `${CALENDAR_DRAFT_INTENT_PREFIX}${encodeURIComponent(
|
|
47
|
+
accountId,
|
|
48
|
+
)}:${encodeURIComponent(threadId)}`
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
export function isCalendarDraftResourceId(resourceId: string): boolean {
|
|
47
52
|
return resourceId.startsWith(CALENDAR_DRAFT_INTENT_PREFIX)
|
|
48
53
|
}
|
|
49
54
|
|
|
50
|
-
export function normalizeCalendarDraftIntentStore(
|
|
55
|
+
export function normalizeCalendarDraftIntentStore(
|
|
56
|
+
value: unknown,
|
|
57
|
+
): CalendarDraftIntentStore {
|
|
51
58
|
if (!value || typeof value !== 'object') return { intents: {} }
|
|
52
59
|
const intents = (value as Partial<CalendarDraftIntentStore>).intents
|
|
53
|
-
if (!intents || typeof intents !== 'object' || Array.isArray(intents))
|
|
60
|
+
if (!intents || typeof intents !== 'object' || Array.isArray(intents))
|
|
61
|
+
return { intents: {} }
|
|
54
62
|
return { intents: intents as Record<string, CalendarDraftIntent> }
|
|
55
63
|
}
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
export const CALENDAR_INVITE_INTENT_STORAGE_SLUG = 'calendar'
|
|
2
|
-
export const CALENDAR_INVITE_INTENT_STORAGE_FILE =
|
|
2
|
+
export const CALENDAR_INVITE_INTENT_STORAGE_FILE =
|
|
3
|
+
'calendar-invite-intents.json'
|
|
3
4
|
export const CALENDAR_INVITE_INTENT_PREFIX = 'calendar-invite:mail:'
|
|
4
5
|
|
|
5
6
|
export type CalendarInviteMethod = 'REQUEST' | 'REPLY' | 'CANCEL' | 'PUBLISH'
|
|
6
|
-
export type CalendarInviteResponse =
|
|
7
|
+
export type CalendarInviteResponse =
|
|
8
|
+
| 'accepted'
|
|
9
|
+
| 'declined'
|
|
10
|
+
| 'tentative'
|
|
11
|
+
| 'needsAction'
|
|
7
12
|
|
|
8
13
|
export interface CalendarInviteContact {
|
|
9
14
|
name: string
|
|
@@ -48,15 +53,23 @@ export interface CalendarInviteIntentStore {
|
|
|
48
53
|
intents: Record<string, CalendarInviteIntent>
|
|
49
54
|
}
|
|
50
55
|
|
|
51
|
-
export function calendarInviteResourceId(
|
|
52
|
-
|
|
56
|
+
export function calendarInviteResourceId(
|
|
57
|
+
accountId: string,
|
|
58
|
+
messageId: string,
|
|
59
|
+
uid: string,
|
|
60
|
+
): string {
|
|
61
|
+
return `${CALENDAR_INVITE_INTENT_PREFIX}${encodeURIComponent(
|
|
62
|
+
accountId,
|
|
63
|
+
)}:${encodeURIComponent(messageId)}:${encodeURIComponent(uid)}`
|
|
53
64
|
}
|
|
54
65
|
|
|
55
66
|
export function isCalendarInviteResourceId(resourceId: string): boolean {
|
|
56
67
|
return resourceId.startsWith(CALENDAR_INVITE_INTENT_PREFIX)
|
|
57
68
|
}
|
|
58
69
|
|
|
59
|
-
export function normalizeCalendarInviteIntentStore(
|
|
70
|
+
export function normalizeCalendarInviteIntentStore(
|
|
71
|
+
value: unknown,
|
|
72
|
+
): CalendarInviteIntentStore {
|
|
60
73
|
if (!value || typeof value !== 'object') return { intents: {} }
|
|
61
74
|
const intents = (value as Partial<CalendarInviteIntentStore>).intents
|
|
62
75
|
if (!intents || typeof intents !== 'object') return { intents: {} }
|
package/src/bridge/client.mjs
CHANGED
|
@@ -21,16 +21,16 @@ const HANDSHAKE_MS = 800
|
|
|
21
21
|
let readyPromise = null
|
|
22
22
|
let bridgeMeta = null
|
|
23
23
|
let eventListenerAttached = false
|
|
24
|
-
const eventListeners = new Map()
|
|
25
|
-
|
|
26
|
-
function postHandshake() {
|
|
27
|
-
window.parent.postMessage({ channel: CHANNEL, type: 'handshake' }, '*')
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function ensureEventListener() {
|
|
31
|
-
if (eventListenerAttached) return
|
|
32
|
-
eventListenerAttached = true
|
|
33
|
-
window.addEventListener('message', event => {
|
|
24
|
+
const eventListeners = new Map()
|
|
25
|
+
|
|
26
|
+
function postHandshake() {
|
|
27
|
+
window.parent.postMessage({ channel: CHANNEL, type: 'handshake' }, '*')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function ensureEventListener() {
|
|
31
|
+
if (eventListenerAttached) return
|
|
32
|
+
eventListenerAttached = true
|
|
33
|
+
window.addEventListener('message', event => {
|
|
34
34
|
const data = event.data
|
|
35
35
|
if (!data || data.channel !== CHANNEL || data.type !== 'event') return
|
|
36
36
|
const handlers = eventListeners.get(data.name)
|
|
@@ -58,24 +58,24 @@ function offEvent(name, handler) {
|
|
|
58
58
|
eventListeners.get(name)?.delete(handler)
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
function waitForReady() {
|
|
62
|
-
if (readyPromise) return readyPromise
|
|
63
|
-
readyPromise = new Promise((resolve, reject) => {
|
|
64
|
-
const timeout = window.setTimeout(() => {
|
|
65
|
-
window.clearInterval(handshakeTimer)
|
|
66
|
-
reject(
|
|
67
|
-
new Error(
|
|
61
|
+
function waitForReady() {
|
|
62
|
+
if (readyPromise) return readyPromise
|
|
63
|
+
readyPromise = new Promise((resolve, reject) => {
|
|
64
|
+
const timeout = window.setTimeout(() => {
|
|
65
|
+
window.clearInterval(handshakeTimer)
|
|
66
|
+
reject(
|
|
67
|
+
new Error(
|
|
68
68
|
'PureScience plugin bridge ready timeout (is this page inside the desktop iframe?)',
|
|
69
69
|
),
|
|
70
70
|
)
|
|
71
71
|
}, 15_000)
|
|
72
72
|
|
|
73
|
-
const onMessage = event => {
|
|
74
|
-
const data = event.data
|
|
75
|
-
if (!data || data.channel !== CHANNEL || data.type !== 'ready') return
|
|
76
|
-
window.clearTimeout(timeout)
|
|
77
|
-
window.clearInterval(handshakeTimer)
|
|
78
|
-
window.removeEventListener('message', onMessage)
|
|
73
|
+
const onMessage = event => {
|
|
74
|
+
const data = event.data
|
|
75
|
+
if (!data || data.channel !== CHANNEL || data.type !== 'ready') return
|
|
76
|
+
window.clearTimeout(timeout)
|
|
77
|
+
window.clearInterval(handshakeTimer)
|
|
78
|
+
window.removeEventListener('message', onMessage)
|
|
79
79
|
const viewport =
|
|
80
80
|
data.viewport &&
|
|
81
81
|
typeof data.viewport === 'object' &&
|
|
@@ -100,21 +100,21 @@ function waitForReady() {
|
|
|
100
100
|
}
|
|
101
101
|
applyThemeFromHost(data.theme)
|
|
102
102
|
resolve(bridgeMeta)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
window.addEventListener('message', onMessage)
|
|
106
|
-
postHandshake()
|
|
107
|
-
const handshakeTimer = window.setInterval(postHandshake, HANDSHAKE_MS)
|
|
108
|
-
})
|
|
109
|
-
return readyPromise
|
|
110
|
-
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
window.addEventListener('message', onMessage)
|
|
106
|
+
postHandshake()
|
|
107
|
+
const handshakeTimer = window.setInterval(postHandshake, HANDSHAKE_MS)
|
|
108
|
+
})
|
|
109
|
+
return readyPromise
|
|
110
|
+
}
|
|
111
111
|
|
|
112
|
-
function call(method, args = []) {
|
|
113
|
-
return waitForReady().then(
|
|
114
|
-
() =>
|
|
115
|
-
new Promise((resolve, reject) => {
|
|
116
|
-
const id = `req-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
|
|
117
|
-
const onMessage = event => {
|
|
112
|
+
function call(method, args = []) {
|
|
113
|
+
return waitForReady().then(
|
|
114
|
+
() =>
|
|
115
|
+
new Promise((resolve, reject) => {
|
|
116
|
+
const id = `req-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
|
|
117
|
+
const onMessage = event => {
|
|
118
118
|
const data = event.data
|
|
119
119
|
if (
|
|
120
120
|
!data ||
|
|
@@ -124,14 +124,14 @@ function call(method, args = []) {
|
|
|
124
124
|
) {
|
|
125
125
|
return
|
|
126
126
|
}
|
|
127
|
-
window.removeEventListener('message', onMessage)
|
|
128
|
-
if (data.ok) resolve(data.result)
|
|
129
|
-
else reject(new Error(data.error || 'Bridge request failed'))
|
|
130
|
-
}
|
|
131
|
-
window.addEventListener('message', onMessage)
|
|
132
|
-
window.parent.postMessage(
|
|
133
|
-
{ channel: CHANNEL, type: 'request', id, method, args },
|
|
134
|
-
'*',
|
|
127
|
+
window.removeEventListener('message', onMessage)
|
|
128
|
+
if (data.ok) resolve(data.result)
|
|
129
|
+
else reject(new Error(data.error || 'Bridge request failed'))
|
|
130
|
+
}
|
|
131
|
+
window.addEventListener('message', onMessage)
|
|
132
|
+
window.parent.postMessage(
|
|
133
|
+
{ channel: CHANNEL, type: 'request', id, method, args },
|
|
134
|
+
'*',
|
|
135
135
|
)
|
|
136
136
|
}),
|
|
137
137
|
)
|
package/src/bridge/dialog.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export interface PlatformDialogPathResult {
|
|
2
|
-
path: string | null
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export declare function openPlatformFolderDialog(): Promise<string | null>
|
|
6
|
-
export declare function savePlatformFolderDialog(): Promise<string | null>
|
|
7
|
-
export declare function openPlatformImageDialog(): Promise<string | null>
|
|
8
|
-
export declare function openPlatformFileDialog(): Promise<string | null>
|
|
1
|
+
export interface PlatformDialogPathResult {
|
|
2
|
+
path: string | null
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export declare function openPlatformFolderDialog(): Promise<string | null>
|
|
6
|
+
export declare function savePlatformFolderDialog(): Promise<string | null>
|
|
7
|
+
export declare function openPlatformImageDialog(): Promise<string | null>
|
|
8
|
+
export declare function openPlatformFileDialog(): Promise<string | null>
|
package/src/bridge/dialog.mjs
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
import { bridge } from './client.mjs'
|
|
2
|
-
import { PLATFORM_BRIDGE_METHODS } from './methods.mjs'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @returns {Promise<string | null>} Absolute path to the picked folder, or null if cancelled.
|
|
6
|
-
*/
|
|
7
|
-
export async function openPlatformFolderDialog() {
|
|
8
|
-
const result = await bridge.call(
|
|
9
|
-
PLATFORM_BRIDGE_METHODS.DIALOG_OPEN_FOLDER,
|
|
10
|
-
[],
|
|
11
|
-
)
|
|
12
|
-
return result?.path ?? null
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @returns {Promise<string | null>} Absolute path to the picked parent folder, or null if cancelled.
|
|
17
|
-
*/
|
|
18
|
-
export async function savePlatformFolderDialog() {
|
|
19
|
-
const result = await bridge.call(
|
|
20
|
-
PLATFORM_BRIDGE_METHODS.DIALOG_SAVE_FOLDER,
|
|
21
|
-
[],
|
|
22
|
-
)
|
|
23
|
-
return result?.path ?? null
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* @returns {Promise<string | null>} Absolute path to the picked image, or null if cancelled.
|
|
28
|
-
*/
|
|
29
|
-
export async function openPlatformImageDialog() {
|
|
1
|
+
import { bridge } from './client.mjs'
|
|
2
|
+
import { PLATFORM_BRIDGE_METHODS } from './methods.mjs'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @returns {Promise<string | null>} Absolute path to the picked folder, or null if cancelled.
|
|
6
|
+
*/
|
|
7
|
+
export async function openPlatformFolderDialog() {
|
|
8
|
+
const result = await bridge.call(
|
|
9
|
+
PLATFORM_BRIDGE_METHODS.DIALOG_OPEN_FOLDER,
|
|
10
|
+
[],
|
|
11
|
+
)
|
|
12
|
+
return result?.path ?? null
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @returns {Promise<string | null>} Absolute path to the picked parent folder, or null if cancelled.
|
|
17
|
+
*/
|
|
18
|
+
export async function savePlatformFolderDialog() {
|
|
19
|
+
const result = await bridge.call(
|
|
20
|
+
PLATFORM_BRIDGE_METHODS.DIALOG_SAVE_FOLDER,
|
|
21
|
+
[],
|
|
22
|
+
)
|
|
23
|
+
return result?.path ?? null
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @returns {Promise<string | null>} Absolute path to the picked image, or null if cancelled.
|
|
28
|
+
*/
|
|
29
|
+
export async function openPlatformImageDialog() {
|
|
30
30
|
const result = await bridge.call(
|
|
31
31
|
PLATFORM_BRIDGE_METHODS.DIALOG_OPEN_IMAGE,
|
|
32
32
|
[],
|
|
33
|
-
)
|
|
34
|
-
return result?.path ?? null
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* @returns {Promise<string | null>} Absolute path to the picked file, or null if cancelled.
|
|
39
|
-
*/
|
|
40
|
-
export async function openPlatformFileDialog() {
|
|
41
|
-
const result = await bridge.call(PLATFORM_BRIDGE_METHODS.DIALOG_OPEN_FILE, [])
|
|
42
|
-
return result?.path ?? null
|
|
43
|
-
}
|
|
33
|
+
)
|
|
34
|
+
return result?.path ?? null
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @returns {Promise<string | null>} Absolute path to the picked file, or null if cancelled.
|
|
39
|
+
*/
|
|
40
|
+
export async function openPlatformFileDialog() {
|
|
41
|
+
const result = await bridge.call(PLATFORM_BRIDGE_METHODS.DIALOG_OPEN_FILE, [])
|
|
42
|
+
return result?.path ?? null
|
|
43
|
+
}
|
|
@@ -1,73 +1,73 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
-
import { PLATFORM_BRIDGE_METHODS } from './methods.mjs'
|
|
3
|
-
|
|
4
|
-
const bridgeCall = vi.hoisted(() => vi.fn())
|
|
5
|
-
|
|
6
|
-
vi.mock('./client.mjs', () => ({
|
|
7
|
-
bridge: {
|
|
8
|
-
call: bridgeCall,
|
|
9
|
-
},
|
|
10
|
-
}))
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
openPlatformFileDialog,
|
|
14
|
-
openPlatformFolderDialog,
|
|
15
|
-
openPlatformImageDialog,
|
|
16
|
-
savePlatformFolderDialog,
|
|
17
|
-
} from './dialog.mjs'
|
|
18
|
-
|
|
19
|
-
beforeEach(() => {
|
|
20
|
-
bridgeCall.mockReset()
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
describe('dialog bridge helpers', () => {
|
|
24
|
-
it('opens a folder dialog using the shell method with no arguments', async () => {
|
|
25
|
-
bridgeCall.mockResolvedValue({ path: '/tmp' })
|
|
26
|
-
|
|
27
|
-
await expect(openPlatformFolderDialog()).resolves.toBe('/tmp')
|
|
28
|
-
|
|
29
|
-
expect(bridgeCall).toHaveBeenCalledWith(
|
|
30
|
-
PLATFORM_BRIDGE_METHODS.DIALOG_OPEN_FOLDER,
|
|
31
|
-
[],
|
|
32
|
-
)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
it('opens a save folder dialog using the shell method with no arguments', async () => {
|
|
36
|
-
bridgeCall.mockResolvedValue({ path: '/tmp/project' })
|
|
37
|
-
|
|
38
|
-
await expect(savePlatformFolderDialog()).resolves.toBe('/tmp/project')
|
|
39
|
-
|
|
40
|
-
expect(bridgeCall).toHaveBeenCalledWith(
|
|
41
|
-
PLATFORM_BRIDGE_METHODS.DIALOG_SAVE_FOLDER,
|
|
42
|
-
[],
|
|
43
|
-
)
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
it('opens an image dialog using the shell method with no arguments', async () => {
|
|
47
|
-
bridgeCall.mockResolvedValue({ path: '/tmp/image.png' })
|
|
48
|
-
|
|
49
|
-
await expect(openPlatformImageDialog()).resolves.toBe('/tmp/image.png')
|
|
50
|
-
|
|
51
|
-
expect(bridgeCall).toHaveBeenCalledWith(
|
|
52
|
-
PLATFORM_BRIDGE_METHODS.DIALOG_OPEN_IMAGE,
|
|
53
|
-
[],
|
|
54
|
-
)
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
it('opens a file dialog using the shell method with no arguments', async () => {
|
|
58
|
-
bridgeCall.mockResolvedValue({ path: '/tmp/file.md' })
|
|
59
|
-
|
|
60
|
-
await expect(openPlatformFileDialog()).resolves.toBe('/tmp/file.md')
|
|
61
|
-
|
|
62
|
-
expect(bridgeCall).toHaveBeenCalledWith(
|
|
63
|
-
PLATFORM_BRIDGE_METHODS.DIALOG_OPEN_FILE,
|
|
64
|
-
[],
|
|
65
|
-
)
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
it('returns null when the shell dialog is cancelled', async () => {
|
|
69
|
-
bridgeCall.mockResolvedValue({ path: null })
|
|
70
|
-
|
|
71
|
-
await expect(openPlatformFolderDialog()).resolves.toBeNull()
|
|
72
|
-
})
|
|
73
|
-
})
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import { PLATFORM_BRIDGE_METHODS } from './methods.mjs'
|
|
3
|
+
|
|
4
|
+
const bridgeCall = vi.hoisted(() => vi.fn())
|
|
5
|
+
|
|
6
|
+
vi.mock('./client.mjs', () => ({
|
|
7
|
+
bridge: {
|
|
8
|
+
call: bridgeCall,
|
|
9
|
+
},
|
|
10
|
+
}))
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
openPlatformFileDialog,
|
|
14
|
+
openPlatformFolderDialog,
|
|
15
|
+
openPlatformImageDialog,
|
|
16
|
+
savePlatformFolderDialog,
|
|
17
|
+
} from './dialog.mjs'
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
bridgeCall.mockReset()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
describe('dialog bridge helpers', () => {
|
|
24
|
+
it('opens a folder dialog using the shell method with no arguments', async () => {
|
|
25
|
+
bridgeCall.mockResolvedValue({ path: '/tmp' })
|
|
26
|
+
|
|
27
|
+
await expect(openPlatformFolderDialog()).resolves.toBe('/tmp')
|
|
28
|
+
|
|
29
|
+
expect(bridgeCall).toHaveBeenCalledWith(
|
|
30
|
+
PLATFORM_BRIDGE_METHODS.DIALOG_OPEN_FOLDER,
|
|
31
|
+
[],
|
|
32
|
+
)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('opens a save folder dialog using the shell method with no arguments', async () => {
|
|
36
|
+
bridgeCall.mockResolvedValue({ path: '/tmp/project' })
|
|
37
|
+
|
|
38
|
+
await expect(savePlatformFolderDialog()).resolves.toBe('/tmp/project')
|
|
39
|
+
|
|
40
|
+
expect(bridgeCall).toHaveBeenCalledWith(
|
|
41
|
+
PLATFORM_BRIDGE_METHODS.DIALOG_SAVE_FOLDER,
|
|
42
|
+
[],
|
|
43
|
+
)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('opens an image dialog using the shell method with no arguments', async () => {
|
|
47
|
+
bridgeCall.mockResolvedValue({ path: '/tmp/image.png' })
|
|
48
|
+
|
|
49
|
+
await expect(openPlatformImageDialog()).resolves.toBe('/tmp/image.png')
|
|
50
|
+
|
|
51
|
+
expect(bridgeCall).toHaveBeenCalledWith(
|
|
52
|
+
PLATFORM_BRIDGE_METHODS.DIALOG_OPEN_IMAGE,
|
|
53
|
+
[],
|
|
54
|
+
)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('opens a file dialog using the shell method with no arguments', async () => {
|
|
58
|
+
bridgeCall.mockResolvedValue({ path: '/tmp/file.md' })
|
|
59
|
+
|
|
60
|
+
await expect(openPlatformFileDialog()).resolves.toBe('/tmp/file.md')
|
|
61
|
+
|
|
62
|
+
expect(bridgeCall).toHaveBeenCalledWith(
|
|
63
|
+
PLATFORM_BRIDGE_METHODS.DIALOG_OPEN_FILE,
|
|
64
|
+
[],
|
|
65
|
+
)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('returns null when the shell dialog is cancelled', async () => {
|
|
69
|
+
bridgeCall.mockResolvedValue({ path: null })
|
|
70
|
+
|
|
71
|
+
await expect(openPlatformFolderDialog()).resolves.toBeNull()
|
|
72
|
+
})
|
|
73
|
+
})
|