@puredesktop/puredesktop-ui-bridge 2.1.7 → 2.1.9
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 +89 -5
- package/src/agents/mcpServerPresets.test.ts +105 -0
- package/src/agents/mcpServerPresets.ts +380 -0
- package/src/agents/runtime/index.ts +7 -0
- package/src/agents/runtime/mapAgentSnapshot.ts +11 -8
- package/src/agents/runtime/pendingAsks.test.ts +117 -0
- package/src/agents/runtime/pendingAsks.ts +110 -0
- package/src/bridge/agentScopeDefaults.ts +65 -0
- package/src/bridge/agentTypes.ts +57 -3
- package/src/bridge/agents.d.mts +6 -0
- package/src/bridge/agents.mjs +10 -0
- package/src/bridge/agents.ts +4 -0
- package/src/bridge/collectionImagePaste.ts +19 -1
- package/src/bridge/context.mjs +32 -0
- package/src/bridge/credentials.d.mts +62 -0
- package/src/bridge/credentials.mjs +53 -0
- package/src/bridge/documents.d.mts +76 -0
- package/src/bridge/documents.mjs +40 -0
- package/src/bridge/events.d.mts +1 -0
- package/src/bridge/events.mjs +1 -0
- package/src/bridge/googleAuth.ts +7 -152
- package/src/bridge/mcpClient.d.mts +74 -0
- package/src/bridge/mcpClient.mjs +79 -0
- package/src/bridge/methods.d.mts +45 -0
- package/src/bridge/methods.mjs +46 -0
- package/src/bridge/notifications.d.mts +12 -0
- package/src/bridge/notifications.mjs +36 -0
- package/src/bridge/operations.d.mts +44 -0
- package/src/bridge/operations.mjs +40 -0
- package/src/bridge/pureRender/base.css +44 -0
- package/src/bridge/pureRender/document.ts +29 -2
- package/src/bridge/pureRender/index.ts +3 -0
- package/src/bridge/pureRender/normalize.ts +167 -0
- package/src/bridge/pureRender/sanitizeExportBody.test.ts +51 -0
- package/src/bridge/pureRender/sanitizeExportBody.ts +61 -0
- package/src/bridge/pureRender/styles.ts +125 -5
- package/src/bridge/pureRender/theme.test.ts +259 -0
- package/src/bridge/pureRender/theme.ts +19 -1
- package/src/bridge/pureRender/types.ts +33 -0
- package/src/bridge/pureRender/visualLayoutInspection.test.ts +26 -0
- package/src/bridge/pureRender/visualLayoutInspection.ts +75 -0
- package/src/bridge/react/useDocumentHotkeys.ts +41 -0
- package/src/bridge/react/useDocumentLifecycle.tsx +359 -0
- package/src/bridge/react/usePlatformAgentSessionDrive.test.tsx +29 -10
- package/src/bridge/react/usePlatformAgentSessionDrive.tsx +10 -81
- package/src/bridge/react/usePlatformAppSettings.test.tsx +105 -0
- package/src/bridge/react/usePlatformAppSettings.tsx +104 -0
- package/src/bridge/react/usePlatformJsonStore.test.tsx +152 -0
- package/src/bridge/react/usePlatformJsonStore.tsx +149 -0
- package/src/bridge/react/usePlatformOperations.tsx +75 -0
- package/src/bridge/storage.d.mts +23 -10
- package/src/bridge/storage.mjs +6 -3
- package/src/bridge/storage.test.ts +6 -6
- package/src/bridge/types.ts +7 -0
- package/src/components/agents/AgentComposer.tsx +10 -6
- package/src/components/agents/AgentDrawerPanel.test.tsx +2 -205
- package/src/components/agents/AgentDrawerPanel.tsx +23 -62
- package/src/components/agents/AgentMessageBubble.tsx +59 -33
- package/src/components/agents/AgentMessageList.tsx +4 -4
- package/src/components/agents/AgentQuestionPromptList.tsx +34 -212
- package/src/components/agents/AgentToolApprovalActions.tsx +13 -11
- package/src/components/agents/AgentToolCallCard.tsx +20 -20
- package/src/components/agents/AgentToolPendingList.tsx +6 -6
- package/src/components/agents/AgentToolPendingReview.tsx +6 -6
- package/src/components/agents/ContextPicker.tsx +239 -0
- package/src/components/agents/QuestionRequestList.tsx +278 -0
- package/src/components/agents/agentPanelStyles.ts +8 -31
- package/src/components/agents/agentTypes.ts +25 -41
- package/src/components/agents/index.ts +4 -0
- package/src/components/assets/asset-library/sidebar/AssetLibraryList.tsx +10 -4
- package/src/components/chrome/WorkspaceTabStrip.tsx +22 -4
- package/src/components/chrome/workspaceTabTypes.ts +2 -0
- package/src/components/common/chat/ChatBox.tsx +9 -9
- package/src/components/common/chat/ChatModelMenu.tsx +34 -4
- package/src/components/common/chat/ChatThread.tsx +23 -7
- package/src/components/common/connections/ProviderConnection.test.tsx +208 -0
- package/src/components/common/connections/ProviderConnection.tsx +277 -0
- package/src/components/common/connections/index.ts +5 -0
- package/src/components/common/containers/AppFrame.test.tsx +4 -4
- package/src/components/common/containers/AppFrame.tsx +26 -10
- package/src/components/common/containers/AppHeader.tsx +37 -15
- package/src/components/common/documents/DocumentHeaderActions.tsx +206 -0
- package/src/components/common/documents/DocumentSwitcher.tsx +1181 -0
- package/src/components/common/documents/index.ts +8 -0
- package/src/components/common/dropdown/MenuDropdownItem.tsx +14 -2
- package/src/components/common/dropdown/MenuPortal.tsx +3 -1
- package/src/components/common/dropdown/menuViewportPosition.test.ts +20 -10
- package/src/components/common/dropdown/menuViewportPosition.ts +35 -27
- package/src/components/common/overlays/Modal.tsx +13 -2
- package/src/components/common/research/EvidenceDossier.tsx +1232 -150
- package/src/components/common/research/index.ts +2 -0
- package/src/components/editor/EditorLinkPromptDialog.tsx +1 -1
- package/src/components/print-design/PrintDesignPanel.test.tsx +430 -40
- package/src/components/print-design/PrintDesignPanel.tsx +1770 -207
- package/src/components/print-design/index.ts +2 -0
- package/src/components/print-design/previewContent.test.ts +32 -0
- package/src/components/print-design/previewContent.ts +31 -0
- package/src/context/buildContextDocument.test.ts +240 -0
- package/src/context/buildContextDocument.ts +309 -0
- package/src/context/contextAccess.ts +66 -0
- package/src/context/contextConfig.ts +72 -0
- package/src/context/contextDocument.test.ts +155 -0
- package/src/context/contextDocument.ts +300 -0
- package/src/context/contextSections.test.ts +88 -0
- package/src/context/contextSections.ts +84 -0
- package/src/context/htmlToContextMarkdown.test.ts +134 -0
- package/src/context/htmlToContextMarkdown.ts +369 -0
- package/src/ics/generateIcs.test.ts +153 -0
- package/src/ics/generateIcs.ts +197 -0
- package/src/index.ts +3 -0
- package/src/net/httpRetry.test.ts +117 -0
- package/src/net/httpRetry.ts +111 -0
- package/src/theme/appAccents.test.ts +36 -35
- package/src/theme/appAccents.ts +93 -104
- package/src/theme/appIdentityCss.mjs +178 -229
- package/src/theme/appIdentityCss.ts +222 -231
- package/src/theme/themes/dark.ts +3 -1
- package/src/theme/themes/light.ts +3 -1
- package/src/bridge/googleProviderConfig.ts +0 -73
|
@@ -4,10 +4,15 @@ import type { PlatformAppManifest } from '../../../bridge/types.js'
|
|
|
4
4
|
|
|
5
5
|
export type { PlatformAppManifest }
|
|
6
6
|
|
|
7
|
-
export interface AppHeaderProps {
|
|
8
|
-
manifest: PlatformAppManifest
|
|
9
|
-
/** Optional slot for the app's tools — the header earns its row. */
|
|
10
|
-
actions?: React.ReactNode
|
|
7
|
+
export interface AppHeaderProps {
|
|
8
|
+
manifest: PlatformAppManifest
|
|
9
|
+
/** Optional slot for the app's tools — the header earns its row. */
|
|
10
|
+
actions?: React.ReactNode
|
|
11
|
+
/**
|
|
12
|
+
* Convention: the open document's file name, shown beside the wordmark
|
|
13
|
+
* (like any document-based app's window title).
|
|
14
|
+
*/
|
|
15
|
+
documentName?: React.ReactNode
|
|
11
16
|
}
|
|
12
17
|
|
|
13
18
|
/**
|
|
@@ -28,6 +33,21 @@ const StyledHeader = styled.header`
|
|
|
28
33
|
background: var(--pure-chrome-wordmark-bar, #fbfbfc);
|
|
29
34
|
`
|
|
30
35
|
|
|
36
|
+
const DocumentName = styled.span`
|
|
37
|
+
overflow: hidden;
|
|
38
|
+
max-width: 36ch;
|
|
39
|
+
color: var(--platform-colors-text-muted, rgb(46 51 56 / 62%));
|
|
40
|
+
font-size: 12px;
|
|
41
|
+
text-overflow: ellipsis;
|
|
42
|
+
white-space: nowrap;
|
|
43
|
+
|
|
44
|
+
&::before {
|
|
45
|
+
content: '·';
|
|
46
|
+
margin-right: var(--platform-spacing-sm, 8px);
|
|
47
|
+
color: var(--platform-colors-text-muted, rgb(46 51 56 / 38%));
|
|
48
|
+
}
|
|
49
|
+
`
|
|
50
|
+
|
|
31
51
|
const ActionSlot = styled.div`
|
|
32
52
|
display: flex;
|
|
33
53
|
align-items: center;
|
|
@@ -46,17 +66,19 @@ const ActionSlot = styled.div`
|
|
|
46
66
|
|
|
47
67
|
export const APP_HEADER_ACTIONS_PORTAL_ID = 'purescience-app-header-actions'
|
|
48
68
|
|
|
49
|
-
export function AppHeader({
|
|
50
|
-
manifest,
|
|
51
|
-
actions,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
69
|
+
export function AppHeader({
|
|
70
|
+
manifest,
|
|
71
|
+
actions,
|
|
72
|
+
documentName,
|
|
73
|
+
}: AppHeaderProps): React.ReactElement {
|
|
74
|
+
return (
|
|
75
|
+
<StyledHeader>
|
|
76
|
+
<PureAppWordmark
|
|
77
|
+
appName={manifest.navigationLabel ?? manifest.slug}
|
|
78
|
+
size="sm"
|
|
79
|
+
accentName
|
|
80
|
+
/>
|
|
81
|
+
{documentName ? <DocumentName>{documentName}</DocumentName> : null}
|
|
60
82
|
<ActionSlot id={APP_HEADER_ACTIONS_PORTAL_ID}>{actions}</ActionSlot>
|
|
61
83
|
</StyledHeader>
|
|
62
84
|
)
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { useCallback, type ReactElement } from 'react'
|
|
2
|
+
import { styled } from 'styled-components'
|
|
3
|
+
import { MenuButtonDropdown } from '../dropdown/MenuButtonDropdown.js'
|
|
4
|
+
import type { MenuActionItem, MenuEntry } from '../dropdown/menuTypes.js'
|
|
5
|
+
import type { DocumentLifecycle } from '../../../bridge/react/useDocumentLifecycle.js'
|
|
6
|
+
import { bridge } from '../../../bridge/client.mjs'
|
|
7
|
+
import { PLATFORM_BRIDGE_METHODS } from '../../../bridge/methods.mjs'
|
|
8
|
+
import { suggestPlatformDocumentLocation } from '../../../bridge/documents.mjs'
|
|
9
|
+
|
|
10
|
+
export interface DocumentHeaderActionsProps {
|
|
11
|
+
lifecycle: DocumentLifecycle
|
|
12
|
+
/** Current document title, used when a draft is named-and-filed. */
|
|
13
|
+
title: string
|
|
14
|
+
/** App's own menu entries, appended after the shared document actions. */
|
|
15
|
+
menuItems?: MenuEntry[]
|
|
16
|
+
onSelectMenuItem?: (item: MenuActionItem) => void
|
|
17
|
+
/** Open the app's DocumentSwitcher (also reachable via ⌘O). */
|
|
18
|
+
onOpenSwitcher?: () => void
|
|
19
|
+
/** Explicit save handler for filed documents; defaults to flush(). */
|
|
20
|
+
onSave?: () => void
|
|
21
|
+
saveLabel?: string
|
|
22
|
+
menuLabel?: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function savedLabel(savedAt: string | null): string {
|
|
26
|
+
if (!savedAt) return 'Saved'
|
|
27
|
+
return `Saved ${new Date(savedAt).toLocaleTimeString([], {
|
|
28
|
+
hour: '2-digit',
|
|
29
|
+
minute: '2-digit',
|
|
30
|
+
})}`
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The shared document lifecycle cluster for an app's existing header row
|
|
35
|
+
* (AppFrame `headerActions`): quiet autosave status · filing-location chip ·
|
|
36
|
+
* a dynamic Save / "Name & file" action · the app's menu with the shared
|
|
37
|
+
* document actions merged in. One component, no extra bars.
|
|
38
|
+
*/
|
|
39
|
+
export function DocumentHeaderActions({
|
|
40
|
+
lifecycle,
|
|
41
|
+
title,
|
|
42
|
+
menuItems = [],
|
|
43
|
+
onSelectMenuItem,
|
|
44
|
+
onOpenSwitcher,
|
|
45
|
+
onSave,
|
|
46
|
+
saveLabel = 'Save',
|
|
47
|
+
menuLabel = 'Options',
|
|
48
|
+
}: DocumentHeaderActionsProps): ReactElement {
|
|
49
|
+
const { doc } = lifecycle
|
|
50
|
+
|
|
51
|
+
// The location chip already says "Drafts" — the status only reports save
|
|
52
|
+
// state, never duplicates location.
|
|
53
|
+
const statusText = doc.error
|
|
54
|
+
? doc.error
|
|
55
|
+
: doc.saving
|
|
56
|
+
? 'Saving…'
|
|
57
|
+
: doc.status === 'none'
|
|
58
|
+
? ''
|
|
59
|
+
: savedLabel(doc.savedAt)
|
|
60
|
+
|
|
61
|
+
const locationLabel =
|
|
62
|
+
doc.status === 'draft'
|
|
63
|
+
? 'Drafts'
|
|
64
|
+
: doc.status === 'filed'
|
|
65
|
+
? doc.path?.split('/').slice(-2, -1)[0] ?? ''
|
|
66
|
+
: ''
|
|
67
|
+
|
|
68
|
+
const moveDocument = useCallback(async () => {
|
|
69
|
+
const suggestion = await suggestPlatformDocumentLocation().catch(() => null)
|
|
70
|
+
const picked = await bridge.call<{ path: string | null }>(
|
|
71
|
+
PLATFORM_BRIDGE_METHODS.DIALOG_OPEN_FOLDER,
|
|
72
|
+
[
|
|
73
|
+
{
|
|
74
|
+
title: 'Choose a folder for this document',
|
|
75
|
+
defaultPath: suggestion?.dir,
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
)
|
|
79
|
+
if (!picked?.path) return
|
|
80
|
+
await lifecycle.promote(title || 'Untitled', picked.path)
|
|
81
|
+
}, [lifecycle, title])
|
|
82
|
+
|
|
83
|
+
const documentMenuItems: MenuEntry[] = [
|
|
84
|
+
...(onOpenSwitcher
|
|
85
|
+
? [{ id: 'document-open', label: 'Open…', shortcut: '⌘O' }]
|
|
86
|
+
: []),
|
|
87
|
+
{ id: 'document-move', label: 'Move…', disabled: !doc.path },
|
|
88
|
+
{ id: 'document-duplicate', label: 'Duplicate', disabled: !doc.path },
|
|
89
|
+
{
|
|
90
|
+
id: 'document-reveal-files',
|
|
91
|
+
label: 'Reveal in PureFiles',
|
|
92
|
+
disabled: !doc.path,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: 'document-reveal-finder',
|
|
96
|
+
label: 'Find in Finder',
|
|
97
|
+
disabled: !doc.path,
|
|
98
|
+
},
|
|
99
|
+
]
|
|
100
|
+
const mergedItems: MenuEntry[] = menuItems.length
|
|
101
|
+
? [...documentMenuItems, { type: 'divider' }, ...menuItems]
|
|
102
|
+
: documentMenuItems
|
|
103
|
+
|
|
104
|
+
const handleSelect = useCallback(
|
|
105
|
+
(item: MenuActionItem) => {
|
|
106
|
+
if (item.id === 'document-open') onOpenSwitcher?.()
|
|
107
|
+
else if (item.id === 'document-move') void moveDocument()
|
|
108
|
+
else if (item.id === 'document-duplicate') void lifecycle.duplicate()
|
|
109
|
+
else if (item.id === 'document-reveal-files') void lifecycle.openInFiles()
|
|
110
|
+
else if (item.id === 'document-reveal-finder')
|
|
111
|
+
void lifecycle.revealInFinder()
|
|
112
|
+
else onSelectMenuItem?.(item)
|
|
113
|
+
},
|
|
114
|
+
[lifecycle, moveDocument, onOpenSwitcher, onSelectMenuItem],
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
const handleSave = useCallback(() => {
|
|
118
|
+
if (doc.status === 'draft') {
|
|
119
|
+
void lifecycle.promote(title || 'Untitled')
|
|
120
|
+
return
|
|
121
|
+
}
|
|
122
|
+
if (onSave) onSave()
|
|
123
|
+
else void lifecycle.flush()
|
|
124
|
+
}, [doc.status, lifecycle, onSave, title])
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<Cluster role="group" aria-label="Document">
|
|
128
|
+
{statusText ? (
|
|
129
|
+
<StatusText $error={Boolean(doc.error)} aria-live="polite">
|
|
130
|
+
{statusText}
|
|
131
|
+
</StatusText>
|
|
132
|
+
) : null}
|
|
133
|
+
{locationLabel ? (
|
|
134
|
+
<LocationChip
|
|
135
|
+
type="button"
|
|
136
|
+
title={doc.path ?? undefined}
|
|
137
|
+
onClick={() => void moveDocument()}
|
|
138
|
+
>
|
|
139
|
+
{locationLabel}
|
|
140
|
+
</LocationChip>
|
|
141
|
+
) : null}
|
|
142
|
+
<SaveAction type="button" onClick={handleSave}>
|
|
143
|
+
{doc.status === 'draft' ? 'Name & file' : saveLabel}
|
|
144
|
+
</SaveAction>
|
|
145
|
+
<MenuButtonDropdown
|
|
146
|
+
label={menuLabel}
|
|
147
|
+
items={mergedItems}
|
|
148
|
+
variant="subtle"
|
|
149
|
+
size="sm"
|
|
150
|
+
onSelectItem={handleSelect}
|
|
151
|
+
/>
|
|
152
|
+
</Cluster>
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
//#region styled-components
|
|
157
|
+
|
|
158
|
+
const Cluster = styled.div`
|
|
159
|
+
display: flex;
|
|
160
|
+
align-items: center;
|
|
161
|
+
gap: 10px;
|
|
162
|
+
`
|
|
163
|
+
|
|
164
|
+
const StatusText = styled.span<{ $error?: boolean }>`
|
|
165
|
+
color: ${props =>
|
|
166
|
+
props.$error
|
|
167
|
+
? 'var(--platform-colors-danger, #b3261e)'
|
|
168
|
+
: 'var(--platform-colors-text-muted, rgb(46 51 56 / 60%))'};
|
|
169
|
+
font-size: 11.5px;
|
|
170
|
+
white-space: nowrap;
|
|
171
|
+
`
|
|
172
|
+
|
|
173
|
+
const LocationChip = styled.button`
|
|
174
|
+
padding: 1px 9px;
|
|
175
|
+
border: 1px solid var(--platform-colors-border, rgb(46 51 56 / 16%));
|
|
176
|
+
border-radius: 999px;
|
|
177
|
+
background: transparent;
|
|
178
|
+
color: var(--platform-colors-text-muted, rgb(46 51 56 / 66%));
|
|
179
|
+
font-family: var(--platform-typography-font-family-mono, monospace);
|
|
180
|
+
font-size: 10.5px;
|
|
181
|
+
letter-spacing: 0.03em;
|
|
182
|
+
cursor: pointer;
|
|
183
|
+
|
|
184
|
+
&:hover {
|
|
185
|
+
border-color: var(--platform-colors-accent, #0067b8);
|
|
186
|
+
color: var(--platform-colors-text, #1c1a17);
|
|
187
|
+
}
|
|
188
|
+
`
|
|
189
|
+
|
|
190
|
+
const SaveAction = styled.button`
|
|
191
|
+
padding: 0;
|
|
192
|
+
border: 0;
|
|
193
|
+
background: transparent;
|
|
194
|
+
color: var(--platform-colors-text-muted, rgb(46 51 56 / 72%));
|
|
195
|
+
font-size: 12px;
|
|
196
|
+
font-weight: 700;
|
|
197
|
+
letter-spacing: 0.06em;
|
|
198
|
+
text-transform: uppercase;
|
|
199
|
+
cursor: pointer;
|
|
200
|
+
|
|
201
|
+
&:hover {
|
|
202
|
+
color: var(--platform-colors-text, #1c1a17);
|
|
203
|
+
}
|
|
204
|
+
`
|
|
205
|
+
|
|
206
|
+
//#endregion
|