@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.
Files changed (119) hide show
  1. package/package.json +89 -5
  2. package/src/agents/mcpServerPresets.test.ts +105 -0
  3. package/src/agents/mcpServerPresets.ts +380 -0
  4. package/src/agents/runtime/index.ts +7 -0
  5. package/src/agents/runtime/mapAgentSnapshot.ts +11 -8
  6. package/src/agents/runtime/pendingAsks.test.ts +117 -0
  7. package/src/agents/runtime/pendingAsks.ts +110 -0
  8. package/src/bridge/agentScopeDefaults.ts +65 -0
  9. package/src/bridge/agentTypes.ts +57 -3
  10. package/src/bridge/agents.d.mts +6 -0
  11. package/src/bridge/agents.mjs +10 -0
  12. package/src/bridge/agents.ts +4 -0
  13. package/src/bridge/collectionImagePaste.ts +19 -1
  14. package/src/bridge/context.mjs +32 -0
  15. package/src/bridge/credentials.d.mts +62 -0
  16. package/src/bridge/credentials.mjs +53 -0
  17. package/src/bridge/documents.d.mts +76 -0
  18. package/src/bridge/documents.mjs +40 -0
  19. package/src/bridge/events.d.mts +1 -0
  20. package/src/bridge/events.mjs +1 -0
  21. package/src/bridge/googleAuth.ts +7 -152
  22. package/src/bridge/mcpClient.d.mts +74 -0
  23. package/src/bridge/mcpClient.mjs +79 -0
  24. package/src/bridge/methods.d.mts +45 -0
  25. package/src/bridge/methods.mjs +46 -0
  26. package/src/bridge/notifications.d.mts +12 -0
  27. package/src/bridge/notifications.mjs +36 -0
  28. package/src/bridge/operations.d.mts +44 -0
  29. package/src/bridge/operations.mjs +40 -0
  30. package/src/bridge/pureRender/base.css +44 -0
  31. package/src/bridge/pureRender/document.ts +29 -2
  32. package/src/bridge/pureRender/index.ts +3 -0
  33. package/src/bridge/pureRender/normalize.ts +167 -0
  34. package/src/bridge/pureRender/sanitizeExportBody.test.ts +51 -0
  35. package/src/bridge/pureRender/sanitizeExportBody.ts +61 -0
  36. package/src/bridge/pureRender/styles.ts +125 -5
  37. package/src/bridge/pureRender/theme.test.ts +259 -0
  38. package/src/bridge/pureRender/theme.ts +19 -1
  39. package/src/bridge/pureRender/types.ts +33 -0
  40. package/src/bridge/pureRender/visualLayoutInspection.test.ts +26 -0
  41. package/src/bridge/pureRender/visualLayoutInspection.ts +75 -0
  42. package/src/bridge/react/useDocumentHotkeys.ts +41 -0
  43. package/src/bridge/react/useDocumentLifecycle.tsx +359 -0
  44. package/src/bridge/react/usePlatformAgentSessionDrive.test.tsx +29 -10
  45. package/src/bridge/react/usePlatformAgentSessionDrive.tsx +10 -81
  46. package/src/bridge/react/usePlatformAppSettings.test.tsx +105 -0
  47. package/src/bridge/react/usePlatformAppSettings.tsx +104 -0
  48. package/src/bridge/react/usePlatformJsonStore.test.tsx +152 -0
  49. package/src/bridge/react/usePlatformJsonStore.tsx +149 -0
  50. package/src/bridge/react/usePlatformOperations.tsx +75 -0
  51. package/src/bridge/storage.d.mts +23 -10
  52. package/src/bridge/storage.mjs +6 -3
  53. package/src/bridge/storage.test.ts +6 -6
  54. package/src/bridge/types.ts +7 -0
  55. package/src/components/agents/AgentComposer.tsx +10 -6
  56. package/src/components/agents/AgentDrawerPanel.test.tsx +2 -205
  57. package/src/components/agents/AgentDrawerPanel.tsx +23 -62
  58. package/src/components/agents/AgentMessageBubble.tsx +59 -33
  59. package/src/components/agents/AgentMessageList.tsx +4 -4
  60. package/src/components/agents/AgentQuestionPromptList.tsx +34 -212
  61. package/src/components/agents/AgentToolApprovalActions.tsx +13 -11
  62. package/src/components/agents/AgentToolCallCard.tsx +20 -20
  63. package/src/components/agents/AgentToolPendingList.tsx +6 -6
  64. package/src/components/agents/AgentToolPendingReview.tsx +6 -6
  65. package/src/components/agents/ContextPicker.tsx +239 -0
  66. package/src/components/agents/QuestionRequestList.tsx +278 -0
  67. package/src/components/agents/agentPanelStyles.ts +8 -31
  68. package/src/components/agents/agentTypes.ts +25 -41
  69. package/src/components/agents/index.ts +4 -0
  70. package/src/components/assets/asset-library/sidebar/AssetLibraryList.tsx +10 -4
  71. package/src/components/chrome/WorkspaceTabStrip.tsx +22 -4
  72. package/src/components/chrome/workspaceTabTypes.ts +2 -0
  73. package/src/components/common/chat/ChatBox.tsx +9 -9
  74. package/src/components/common/chat/ChatModelMenu.tsx +34 -4
  75. package/src/components/common/chat/ChatThread.tsx +23 -7
  76. package/src/components/common/connections/ProviderConnection.test.tsx +208 -0
  77. package/src/components/common/connections/ProviderConnection.tsx +277 -0
  78. package/src/components/common/connections/index.ts +5 -0
  79. package/src/components/common/containers/AppFrame.test.tsx +4 -4
  80. package/src/components/common/containers/AppFrame.tsx +26 -10
  81. package/src/components/common/containers/AppHeader.tsx +37 -15
  82. package/src/components/common/documents/DocumentHeaderActions.tsx +206 -0
  83. package/src/components/common/documents/DocumentSwitcher.tsx +1181 -0
  84. package/src/components/common/documents/index.ts +8 -0
  85. package/src/components/common/dropdown/MenuDropdownItem.tsx +14 -2
  86. package/src/components/common/dropdown/MenuPortal.tsx +3 -1
  87. package/src/components/common/dropdown/menuViewportPosition.test.ts +20 -10
  88. package/src/components/common/dropdown/menuViewportPosition.ts +35 -27
  89. package/src/components/common/overlays/Modal.tsx +13 -2
  90. package/src/components/common/research/EvidenceDossier.tsx +1232 -150
  91. package/src/components/common/research/index.ts +2 -0
  92. package/src/components/editor/EditorLinkPromptDialog.tsx +1 -1
  93. package/src/components/print-design/PrintDesignPanel.test.tsx +430 -40
  94. package/src/components/print-design/PrintDesignPanel.tsx +1770 -207
  95. package/src/components/print-design/index.ts +2 -0
  96. package/src/components/print-design/previewContent.test.ts +32 -0
  97. package/src/components/print-design/previewContent.ts +31 -0
  98. package/src/context/buildContextDocument.test.ts +240 -0
  99. package/src/context/buildContextDocument.ts +309 -0
  100. package/src/context/contextAccess.ts +66 -0
  101. package/src/context/contextConfig.ts +72 -0
  102. package/src/context/contextDocument.test.ts +155 -0
  103. package/src/context/contextDocument.ts +300 -0
  104. package/src/context/contextSections.test.ts +88 -0
  105. package/src/context/contextSections.ts +84 -0
  106. package/src/context/htmlToContextMarkdown.test.ts +134 -0
  107. package/src/context/htmlToContextMarkdown.ts +369 -0
  108. package/src/ics/generateIcs.test.ts +153 -0
  109. package/src/ics/generateIcs.ts +197 -0
  110. package/src/index.ts +3 -0
  111. package/src/net/httpRetry.test.ts +117 -0
  112. package/src/net/httpRetry.ts +111 -0
  113. package/src/theme/appAccents.test.ts +36 -35
  114. package/src/theme/appAccents.ts +93 -104
  115. package/src/theme/appIdentityCss.mjs +178 -229
  116. package/src/theme/appIdentityCss.ts +222 -231
  117. package/src/theme/themes/dark.ts +3 -1
  118. package/src/theme/themes/light.ts +3 -1
  119. package/src/bridge/googleProviderConfig.ts +0 -73
@@ -1,9 +1,10 @@
1
- export interface GoogleOauthTokens {
2
- accessToken: string
3
- refreshToken?: string
4
- expiresAt: number
5
- scope: string
6
- }
1
+ /**
2
+ * Google OAuth scope sets apps request through the shell-owned credential
3
+ * flow (`credentials.connectOAuth`). The OAuth client machinery itself —
4
+ * PKCE, authorize URL, token exchange, refresh — lives in the Electron main
5
+ * process (`packages/shell/src/modules/credentials/googleOAuth.ts`); no
6
+ * renderer ever handles credential material.
7
+ */
7
8
 
8
9
  export const GMAIL_SCOPES = [
9
10
  'https://www.googleapis.com/auth/gmail.modify',
@@ -13,149 +14,3 @@ export const GMAIL_SCOPES = [
13
14
  export const CALENDAR_SCOPES = [
14
15
  'https://www.googleapis.com/auth/calendar.events',
15
16
  ]
16
-
17
- export const GOOGLE_AUTHORIZATION_ENDPOINT =
18
- 'https://accounts.google.com/o/oauth2/v2/auth'
19
- export const GOOGLE_TOKEN_ENDPOINT = 'https://oauth2.googleapis.com/token'
20
-
21
- const EXPIRY_SLACK_MS = 60_000
22
-
23
- export interface PkcePair {
24
- verifier: string
25
- challenge: string
26
- }
27
-
28
- function base64UrlEncode(bytes: Uint8Array): string {
29
- let binary = ''
30
- for (const byte of bytes) {
31
- binary += String.fromCharCode(byte)
32
- }
33
- return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
34
- }
35
-
36
- export function randomUrlSafeString(byteLength = 32): string {
37
- const bytes = new Uint8Array(byteLength)
38
- crypto.getRandomValues(bytes)
39
- return base64UrlEncode(bytes)
40
- }
41
-
42
- export async function createPkcePair(): Promise<PkcePair> {
43
- const verifier = randomUrlSafeString(48)
44
- const digest = await crypto.subtle.digest(
45
- 'SHA-256',
46
- new TextEncoder().encode(verifier),
47
- )
48
- return { verifier, challenge: base64UrlEncode(new Uint8Array(digest)) }
49
- }
50
-
51
- export interface GoogleAuthUrlInput {
52
- clientId: string
53
- challenge: string
54
- state: string
55
- scopes?: string[]
56
- }
57
-
58
- export function buildGoogleAuthorizationUrl(input: GoogleAuthUrlInput): string {
59
- const url = new URL(GOOGLE_AUTHORIZATION_ENDPOINT)
60
- url.searchParams.set('client_id', input.clientId)
61
- url.searchParams.set('response_type', 'code')
62
- url.searchParams.set('scope', (input.scopes ?? CALENDAR_SCOPES).join(' '))
63
- url.searchParams.set('code_challenge', input.challenge)
64
- url.searchParams.set('code_challenge_method', 'S256')
65
- url.searchParams.set('state', input.state)
66
- url.searchParams.set('access_type', 'offline')
67
- url.searchParams.set('prompt', 'consent')
68
- return url.toString()
69
- }
70
-
71
- interface GoogleTokenResponse {
72
- access_token: string
73
- refresh_token?: string
74
- expires_in: number
75
- scope: string
76
- }
77
-
78
- export function tokensFromTokenResponse(
79
- payload: GoogleTokenResponse,
80
- previousRefreshToken?: string,
81
- now = Date.now(),
82
- ): GoogleOauthTokens {
83
- const refreshToken = payload.refresh_token ?? previousRefreshToken
84
- return {
85
- accessToken: payload.access_token,
86
- ...(refreshToken === undefined ? {} : { refreshToken }),
87
- expiresAt: now + payload.expires_in * 1000,
88
- scope: payload.scope,
89
- }
90
- }
91
-
92
- export function accessTokenIsFresh(
93
- tokens: GoogleOauthTokens,
94
- now = Date.now(),
95
- ): boolean {
96
- return tokens.expiresAt - EXPIRY_SLACK_MS > now
97
- }
98
-
99
- export interface TokenExchangeInput {
100
- clientId: string
101
- clientSecret?: string
102
- code: string
103
- verifier: string
104
- redirectUri: string
105
- }
106
-
107
- type FormPost = (
108
- url: string,
109
- body: string,
110
- ) => Promise<{ ok: boolean; status: number; body: string }>
111
-
112
- export async function exchangeCodeForTokens(
113
- post: FormPost,
114
- input: TokenExchangeInput,
115
- ): Promise<GoogleOauthTokens> {
116
- const body = new URLSearchParams({
117
- client_id: input.clientId,
118
- grant_type: 'authorization_code',
119
- code: input.code,
120
- code_verifier: input.verifier,
121
- redirect_uri: input.redirectUri,
122
- })
123
- if (input.clientSecret) body.set('client_secret', input.clientSecret)
124
- const response = await post(GOOGLE_TOKEN_ENDPOINT, body.toString())
125
- if (!response.ok) {
126
- throw new Error(
127
- `Google token exchange failed (${response.status}): ${response.body}`,
128
- )
129
- }
130
- return tokensFromTokenResponse(
131
- JSON.parse(response.body) as GoogleTokenResponse,
132
- )
133
- }
134
-
135
- export interface TokenRefreshInput {
136
- clientId: string
137
- clientSecret?: string
138
- refreshToken: string
139
- }
140
-
141
- export async function refreshAccessToken(
142
- post: FormPost,
143
- input: TokenRefreshInput,
144
- ): Promise<GoogleOauthTokens> {
145
- const body = new URLSearchParams({
146
- client_id: input.clientId,
147
- grant_type: 'refresh_token',
148
- refresh_token: input.refreshToken,
149
- })
150
- if (input.clientSecret) body.set('client_secret', input.clientSecret)
151
- const response = await post(GOOGLE_TOKEN_ENDPOINT, body.toString())
152
- if (!response.ok) {
153
- throw new Error(
154
- `Google token refresh failed (${response.status}): ${response.body}`,
155
- )
156
- }
157
- return tokensFromTokenResponse(
158
- JSON.parse(response.body) as GoogleTokenResponse,
159
- input.refreshToken,
160
- )
161
- }
@@ -0,0 +1,74 @@
1
+ export type McpClientTransportType = 'http' | 'sse' | 'stdio'
2
+ export type McpClientAuthType = 'none' | 'bearer' | 'apiKey'
3
+
4
+ /** A configured external MCP server (no secret material — that stays shell-side). */
5
+ export interface McpClientServerConfig {
6
+ /** Stable slug — `[a-z0-9-]+`. */
7
+ id: string
8
+ label: string
9
+ transport: McpClientTransportType
10
+ /** Remote endpoint for `http` / `sse` transports. */
11
+ url?: string
12
+ /** Executable for the `stdio` transport. */
13
+ command?: string
14
+ args?: string[]
15
+ enabled: boolean
16
+ authType: McpClientAuthType
17
+ /** Env var the stored secret is injected as, when `authType` is `apiKey`. */
18
+ apiKeyEnvVar?: string
19
+ /** Short tool names opted into auto-run; everything else asks first. */
20
+ autoApproveTools?: string[]
21
+ }
22
+
23
+ export interface McpClientServerView extends McpClientServerConfig {
24
+ hasSecret: boolean
25
+ }
26
+
27
+ export interface McpClientSettingsView {
28
+ enabled: boolean
29
+ servers: McpClientServerView[]
30
+ }
31
+
32
+ export interface McpClientTestResult {
33
+ ok: boolean
34
+ serverId: string
35
+ toolNames: string[]
36
+ error?: string
37
+ }
38
+
39
+ export interface McpToolInfo {
40
+ name: string
41
+ description?: string
42
+ inputSchema: Record<string, unknown>
43
+ }
44
+
45
+ export interface McpToolRunResult {
46
+ content: string
47
+ isError: boolean
48
+ }
49
+
50
+ export function listMcpClientSettings(): Promise<McpClientSettingsView>
51
+ export function setMcpClientEnabled(
52
+ enabled: boolean,
53
+ ): Promise<McpClientSettingsView>
54
+ export function upsertMcpClientServer(
55
+ config: McpClientServerConfig,
56
+ ): Promise<McpClientSettingsView>
57
+ export function removeMcpClientServer(
58
+ serverId: string,
59
+ ): Promise<McpClientSettingsView>
60
+ export function setMcpClientServerSecret(
61
+ serverId: string,
62
+ value: string | null,
63
+ ): Promise<McpClientSettingsView>
64
+ export function testMcpClientServer(
65
+ config: McpClientServerConfig,
66
+ ): Promise<McpClientTestResult>
67
+ export function listMcpClientServerTools(
68
+ serverId: string,
69
+ ): Promise<McpToolInfo[]>
70
+ export function callMcpClientServerTool(
71
+ serverId: string,
72
+ toolName: string,
73
+ args: Record<string, unknown>,
74
+ ): Promise<McpToolRunResult>
@@ -0,0 +1,79 @@
1
+ import { bridge } from './client.mjs'
2
+ import { PLATFORM_BRIDGE_METHODS } from './methods.mjs'
3
+
4
+ /**
5
+ * Outbound MCP client registry (external MCP servers whose tools in-app
6
+ * agents can call). Secret material never crosses this bridge — only the
7
+ * redacted settings view does. The shell gates these methods to the
8
+ * assistant app: this is machine-level, secret-bearing configuration.
9
+ */
10
+
11
+ /**
12
+ * @returns {Promise<import('./mcpClient.d.mts').McpClientSettingsView>}
13
+ */
14
+ export async function listMcpClientSettings() {
15
+ return bridge.call(PLATFORM_BRIDGE_METHODS.MCPCLIENT_LIST, [])
16
+ }
17
+
18
+ /**
19
+ * @param {boolean} enabled
20
+ * @returns {Promise<import('./mcpClient.d.mts').McpClientSettingsView>}
21
+ */
22
+ export async function setMcpClientEnabled(enabled) {
23
+ return bridge.call(PLATFORM_BRIDGE_METHODS.MCPCLIENT_SET_ENABLED, [enabled])
24
+ }
25
+
26
+ /**
27
+ * @param {import('./mcpClient.d.mts').McpClientServerConfig} config
28
+ * @returns {Promise<import('./mcpClient.d.mts').McpClientSettingsView>}
29
+ */
30
+ export async function upsertMcpClientServer(config) {
31
+ return bridge.call(PLATFORM_BRIDGE_METHODS.MCPCLIENT_UPSERT, [config])
32
+ }
33
+
34
+ /**
35
+ * @param {string} serverId
36
+ * @returns {Promise<import('./mcpClient.d.mts').McpClientSettingsView>}
37
+ */
38
+ export async function removeMcpClientServer(serverId) {
39
+ return bridge.call(PLATFORM_BRIDGE_METHODS.MCPCLIENT_REMOVE, [serverId])
40
+ }
41
+
42
+ /**
43
+ * @param {string} serverId
44
+ * @param {string | null} value
45
+ * @returns {Promise<import('./mcpClient.d.mts').McpClientSettingsView>}
46
+ */
47
+ export async function setMcpClientServerSecret(serverId, value) {
48
+ return bridge.call(PLATFORM_BRIDGE_METHODS.MCPCLIENT_SET_SECRET, [
49
+ { serverId, value },
50
+ ])
51
+ }
52
+
53
+ /**
54
+ * @param {import('./mcpClient.d.mts').McpClientServerConfig} config
55
+ * @returns {Promise<import('./mcpClient.d.mts').McpClientTestResult>}
56
+ */
57
+ export async function testMcpClientServer(config) {
58
+ return bridge.call(PLATFORM_BRIDGE_METHODS.MCPCLIENT_TEST, [config])
59
+ }
60
+
61
+ /**
62
+ * @param {string} serverId
63
+ * @returns {Promise<import('./mcpClient.d.mts').McpToolInfo[]>}
64
+ */
65
+ export async function listMcpClientServerTools(serverId) {
66
+ return bridge.call(PLATFORM_BRIDGE_METHODS.MCPCLIENT_LIST_TOOLS, [serverId])
67
+ }
68
+
69
+ /**
70
+ * @param {string} serverId
71
+ * @param {string} toolName
72
+ * @param {Record<string, unknown>} args
73
+ * @returns {Promise<import('./mcpClient.d.mts').McpToolRunResult>}
74
+ */
75
+ export async function callMcpClientServerTool(serverId, toolName, args) {
76
+ return bridge.call(PLATFORM_BRIDGE_METHODS.MCPCLIENT_CALL_TOOL, [
77
+ { serverId, toolName, arguments: args },
78
+ ])
79
+ }
@@ -8,6 +8,7 @@ export declare const PLATFORM_BRIDGE_METHODS: {
8
8
  readonly WORKSPACE_OPEN_APP: 'workspace.openApp'
9
9
  readonly WORKSPACE_OPEN_PALETTE: 'workspace.openPalette'
10
10
  readonly WORKSPACE_UPDATE_CURRENT_TAB: 'workspace.updateCurrentTab'
11
+ readonly WORKSPACE_SET_OVERLAY_OPEN: 'workspace.setOverlayOpen'
11
12
  readonly SCHEDULER_REGISTER: 'scheduler.register'
12
13
  readonly SCHEDULER_UNREGISTER: 'scheduler.unregister'
13
14
  readonly CATALOG_CONSUME_PENDING_OPEN: 'catalog.consumePendingOpen'
@@ -19,6 +20,8 @@ export declare const PLATFORM_BRIDGE_METHODS: {
19
20
  readonly SETTINGS_APP_UPDATE: 'settings.app.update'
20
21
  readonly STORAGE_READ_JSON: 'storage.readJson'
21
22
  readonly STORAGE_WRITE_JSON: 'storage.writeJson'
23
+ readonly OPERATIONS_RECORD: 'operations.record'
24
+ readonly OPERATIONS_LIST: 'operations.list'
22
25
  readonly FS_LIST: 'fs.list'
23
26
  readonly FS_READ_PREVIEW: 'fs.readPreview'
24
27
  readonly FS_READ_BINARY: 'fs.readBinary'
@@ -60,23 +63,49 @@ export declare const PLATFORM_BRIDGE_METHODS: {
60
63
  readonly ASSETS_TRANSFORM: 'assets.transform'
61
64
  readonly ASSETS_GET_CONTEXT: 'assets.getContext'
62
65
  readonly NETWORK_FETCH: 'network.fetch'
66
+ readonly RESEARCH_QUERY: 'research.query'
63
67
  readonly VISION_GENERATE_IMAGE: 'vision.generateImage'
68
+ readonly NOTIFICATIONS_SCHEDULE: 'notifications.schedule'
69
+ readonly NOTIFICATIONS_CANCEL: 'notifications.cancel'
70
+ readonly NOTIFICATIONS_CANCEL_ALL: 'notifications.cancelAll'
64
71
  readonly OAUTH_LOOPBACK_AUTHORIZE: 'oauth.loopbackAuthorize'
65
72
  readonly SECRETS_GET: 'secrets.get'
66
73
  readonly SECRETS_SET: 'secrets.set'
67
74
  readonly SECRETS_DELETE: 'secrets.delete'
68
75
  readonly SECRETS_STATUS: 'secrets.status'
76
+ readonly MYTOOLS_LIST: 'mytools.list'
77
+ readonly MYTOOLS_SAVE: 'mytools.save'
78
+ readonly MYTOOLS_UPDATE: 'mytools.update'
79
+ readonly MYTOOLS_DELETE: 'mytools.delete'
80
+ readonly MYTOOLS_TEST: 'mytools.test'
81
+ readonly MYTOOLS_RESEARCH: 'mytools.research'
82
+ readonly MCPCLIENT_LIST: 'mcpClient.list'
83
+ readonly MCPCLIENT_SET_ENABLED: 'mcpClient.setEnabled'
84
+ readonly MCPCLIENT_UPSERT: 'mcpClient.upsertServer'
85
+ readonly MCPCLIENT_REMOVE: 'mcpClient.removeServer'
86
+ readonly MCPCLIENT_SET_SECRET: 'mcpClient.setSecret'
87
+ readonly MCPCLIENT_TEST: 'mcpClient.testServer'
88
+ readonly MCPCLIENT_LIST_TOOLS: 'mcpClient.listTools'
89
+ readonly MCPCLIENT_CALL_TOOL: 'mcpClient.callTool'
69
90
  readonly DEBUG_EMIT_EVENT: 'debug.emitEvent'
70
91
  readonly PLUGINS_INSTALL: 'plugins.install'
71
92
  readonly PLUGINS_EVALUATE_BUILD: 'plugins.evaluateBuild'
72
93
  readonly PLUGINS_PREPARE_REGISTRATION: 'plugins.prepareRegistration'
73
94
  readonly CONTEXT_PUBLISH: 'context.publish'
95
+ readonly CONTEXT_RESOLVE: 'context.resolve'
96
+ readonly CONTEXT_READ: 'context.read'
97
+ readonly CONTEXT_SEARCH: 'context.search'
74
98
  readonly PEOPLE_SUGGEST: 'people.suggest'
75
99
  readonly PEOPLE_RESEARCH: 'people.research'
76
100
  readonly CREDENTIALS_STORAGE_STATUS: 'credentials.storageStatus'
77
101
  readonly CREDENTIALS_LIST: 'credentials.list'
78
102
  readonly CREDENTIALS_SET: 'credentials.set'
79
103
  readonly CREDENTIALS_DELETE: 'credentials.delete'
104
+ readonly CREDENTIALS_STATUS: 'credentials.status'
105
+ readonly CREDENTIALS_SET_OAUTH_CONFIG: 'credentials.setOAuthConfig'
106
+ readonly CREDENTIALS_CONNECT_OAUTH: 'credentials.connectOAuth'
107
+ readonly CREDENTIALS_DISCONNECT: 'credentials.disconnect'
108
+ readonly CREDENTIALS_OAUTH_ACCESS_TOKEN: 'credentials.oauthAccessToken'
80
109
  readonly AGENTS_SESSIONS_CREATE: 'agents.sessions.create'
81
110
  readonly AGENTS_SESSIONS_LIST: 'agents.sessions.list'
82
111
  readonly AGENTS_SESSIONS_READ: 'agents.sessions.read'
@@ -87,6 +116,7 @@ export declare const PLATFORM_BRIDGE_METHODS: {
87
116
  readonly AGENTS_JOBS_READ: 'agents.jobs.read'
88
117
  readonly AGENTS_JOBS_CANCEL: 'agents.jobs.cancel'
89
118
  readonly AGENTS_JOBS_RUN_NOW: 'agents.jobs.runNow'
119
+ readonly AGENTS_DELEGATIONS_LIST: 'agents.delegations.list'
90
120
  readonly AGENTS_SESSION_SEND_MESSAGE: 'agents.session.sendMessage'
91
121
  readonly AGENTS_SESSION_APPROVE_TOOLS: 'agents.session.approveTools'
92
122
  readonly AGENTS_SESSION_REJECT_TOOLS: 'agents.session.rejectTools'
@@ -102,6 +132,15 @@ export declare const PLATFORM_BRIDGE_METHODS: {
102
132
  readonly AGENTS_LOCAL_MODELS_STATUS: 'agents.localModels.status'
103
133
  readonly AGENTS_TOOLS_REGISTER: 'agents.tools.register'
104
134
  readonly AGENTS_TOOLS_COMPLETE: 'agents.tools.complete'
135
+ readonly DOCUMENTS_CREATE_DRAFT: 'documents.createDraft'
136
+ readonly DOCUMENTS_AUTOSAVE: 'documents.autosave'
137
+ readonly DOCUMENTS_PROMOTE: 'documents.promote'
138
+ readonly DOCUMENTS_RENAME: 'documents.rename'
139
+ readonly DOCUMENTS_DUPLICATE: 'documents.duplicate'
140
+ readonly DOCUMENTS_LIST_BY_TYPE: 'documents.listByType'
141
+ readonly DOCUMENTS_RECENTS_LIST: 'documents.recents.list'
142
+ readonly DOCUMENTS_RECENTS_TOUCH: 'documents.recents.touch'
143
+ readonly DOCUMENTS_SUGGEST_LOCATION: 'documents.suggestLocation'
105
144
  }
106
145
 
107
146
  export declare const PLATFORM_BRIDGE_METHOD_PREFIXES: {
@@ -119,12 +158,18 @@ export declare const PLATFORM_BRIDGE_METHOD_PREFIXES: {
119
158
  readonly WATCH: 'watch.'
120
159
  readonly ASSETS: 'assets.'
121
160
  readonly NETWORK: 'network.'
161
+ readonly RESEARCH: 'research.'
122
162
  readonly VISION: 'vision.'
163
+ readonly NOTIFICATIONS: 'notifications.'
123
164
  readonly OAUTH: 'oauth.'
124
165
  readonly SECRETS: 'secrets.'
166
+ readonly MYTOOLS: 'mytools.'
167
+ readonly MCPCLIENT: 'mcpClient.'
125
168
  readonly AGENTS: 'agents.'
126
169
  readonly PEOPLE: 'people.'
127
170
  readonly DEBUG: 'debug.'
171
+ readonly DOCUMENTS: 'documents.'
172
+ readonly OPERATIONS: 'operations.'
128
173
  }
129
174
 
130
175
  export type PlatformBridgeMethodName =
@@ -11,6 +11,7 @@ export const PLATFORM_BRIDGE_METHODS = {
11
11
  WORKSPACE_OPEN_APP: 'workspace.openApp',
12
12
  WORKSPACE_OPEN_PALETTE: 'workspace.openPalette',
13
13
  WORKSPACE_UPDATE_CURRENT_TAB: 'workspace.updateCurrentTab',
14
+ WORKSPACE_SET_OVERLAY_OPEN: 'workspace.setOverlayOpen',
14
15
  SCHEDULER_REGISTER: 'scheduler.register',
15
16
  SCHEDULER_UNREGISTER: 'scheduler.unregister',
16
17
  CATALOG_CONSUME_PENDING_OPEN: 'catalog.consumePendingOpen',
@@ -26,6 +27,8 @@ export const PLATFORM_BRIDGE_METHODS = {
26
27
 
27
28
  STORAGE_READ_JSON: 'storage.readJson',
28
29
  STORAGE_WRITE_JSON: 'storage.writeJson',
30
+ OPERATIONS_RECORD: 'operations.record',
31
+ OPERATIONS_LIST: 'operations.list',
29
32
 
30
33
  FS_LIST: 'fs.list',
31
34
  FS_READ_PREVIEW: 'fs.readPreview',
@@ -75,12 +78,31 @@ export const PLATFORM_BRIDGE_METHODS = {
75
78
  ASSETS_GET_CONTEXT: 'assets.getContext',
76
79
 
77
80
  NETWORK_FETCH: 'network.fetch',
81
+ RESEARCH_QUERY: 'research.query',
78
82
  VISION_GENERATE_IMAGE: 'vision.generateImage',
83
+ NOTIFICATIONS_SCHEDULE: 'notifications.schedule',
84
+ NOTIFICATIONS_CANCEL: 'notifications.cancel',
85
+ NOTIFICATIONS_CANCEL_ALL: 'notifications.cancelAll',
79
86
  OAUTH_LOOPBACK_AUTHORIZE: 'oauth.loopbackAuthorize',
80
87
  SECRETS_GET: 'secrets.get',
81
88
  SECRETS_SET: 'secrets.set',
82
89
  SECRETS_DELETE: 'secrets.delete',
83
90
  SECRETS_STATUS: 'secrets.status',
91
+ MYTOOLS_LIST: 'mytools.list',
92
+ MYTOOLS_SAVE: 'mytools.save',
93
+ MYTOOLS_UPDATE: 'mytools.update',
94
+ MYTOOLS_DELETE: 'mytools.delete',
95
+ MYTOOLS_TEST: 'mytools.test',
96
+ MYTOOLS_RESEARCH: 'mytools.research',
97
+
98
+ MCPCLIENT_LIST: 'mcpClient.list',
99
+ MCPCLIENT_SET_ENABLED: 'mcpClient.setEnabled',
100
+ MCPCLIENT_UPSERT: 'mcpClient.upsertServer',
101
+ MCPCLIENT_REMOVE: 'mcpClient.removeServer',
102
+ MCPCLIENT_SET_SECRET: 'mcpClient.setSecret',
103
+ MCPCLIENT_TEST: 'mcpClient.testServer',
104
+ MCPCLIENT_LIST_TOOLS: 'mcpClient.listTools',
105
+ MCPCLIENT_CALL_TOOL: 'mcpClient.callTool',
84
106
 
85
107
  DEBUG_EMIT_EVENT: 'debug.emitEvent',
86
108
 
@@ -88,6 +110,9 @@ export const PLATFORM_BRIDGE_METHODS = {
88
110
  PLUGINS_EVALUATE_BUILD: 'plugins.evaluateBuild',
89
111
  PLUGINS_PREPARE_REGISTRATION: 'plugins.prepareRegistration',
90
112
  CONTEXT_PUBLISH: 'context.publish',
113
+ CONTEXT_RESOLVE: 'context.resolve',
114
+ CONTEXT_READ: 'context.read',
115
+ CONTEXT_SEARCH: 'context.search',
91
116
  PEOPLE_SUGGEST: 'people.suggest',
92
117
  PEOPLE_RESEARCH: 'people.research',
93
118
 
@@ -95,6 +120,11 @@ export const PLATFORM_BRIDGE_METHODS = {
95
120
  CREDENTIALS_LIST: 'credentials.list',
96
121
  CREDENTIALS_SET: 'credentials.set',
97
122
  CREDENTIALS_DELETE: 'credentials.delete',
123
+ CREDENTIALS_STATUS: 'credentials.status',
124
+ CREDENTIALS_SET_OAUTH_CONFIG: 'credentials.setOAuthConfig',
125
+ CREDENTIALS_CONNECT_OAUTH: 'credentials.connectOAuth',
126
+ CREDENTIALS_DISCONNECT: 'credentials.disconnect',
127
+ CREDENTIALS_OAUTH_ACCESS_TOKEN: 'credentials.oauthAccessToken',
98
128
 
99
129
  AGENTS_SESSIONS_CREATE: 'agents.sessions.create',
100
130
  AGENTS_SESSIONS_LIST: 'agents.sessions.list',
@@ -107,6 +137,7 @@ export const PLATFORM_BRIDGE_METHODS = {
107
137
  AGENTS_JOBS_READ: 'agents.jobs.read',
108
138
  AGENTS_JOBS_CANCEL: 'agents.jobs.cancel',
109
139
  AGENTS_JOBS_RUN_NOW: 'agents.jobs.runNow',
140
+ AGENTS_DELEGATIONS_LIST: 'agents.delegations.list',
110
141
 
111
142
  AGENTS_SESSION_SEND_MESSAGE: 'agents.session.sendMessage',
112
143
  AGENTS_SESSION_APPROVE_TOOLS: 'agents.session.approveTools',
@@ -124,6 +155,15 @@ export const PLATFORM_BRIDGE_METHODS = {
124
155
  AGENTS_LOCAL_MODELS_STATUS: 'agents.localModels.status',
125
156
  AGENTS_TOOLS_REGISTER: 'agents.tools.register',
126
157
  AGENTS_TOOLS_COMPLETE: 'agents.tools.complete',
158
+ DOCUMENTS_CREATE_DRAFT: 'documents.createDraft',
159
+ DOCUMENTS_AUTOSAVE: 'documents.autosave',
160
+ DOCUMENTS_PROMOTE: 'documents.promote',
161
+ DOCUMENTS_RENAME: 'documents.rename',
162
+ DOCUMENTS_DUPLICATE: 'documents.duplicate',
163
+ DOCUMENTS_LIST_BY_TYPE: 'documents.listByType',
164
+ DOCUMENTS_RECENTS_LIST: 'documents.recents.list',
165
+ DOCUMENTS_RECENTS_TOUCH: 'documents.recents.touch',
166
+ DOCUMENTS_SUGGEST_LOCATION: 'documents.suggestLocation',
127
167
  }
128
168
 
129
169
  export const PLATFORM_BRIDGE_METHOD_PREFIXES = {
@@ -141,10 +181,16 @@ export const PLATFORM_BRIDGE_METHOD_PREFIXES = {
141
181
  WATCH: 'watch.',
142
182
  ASSETS: 'assets.',
143
183
  NETWORK: 'network.',
184
+ RESEARCH: 'research.',
144
185
  VISION: 'vision.',
186
+ NOTIFICATIONS: 'notifications.',
145
187
  OAUTH: 'oauth.',
146
188
  SECRETS: 'secrets.',
189
+ MYTOOLS: 'mytools.',
190
+ MCPCLIENT: 'mcpClient.',
147
191
  AGENTS: 'agents.',
148
192
  PEOPLE: 'people.',
149
193
  DEBUG: 'debug.',
194
+ DOCUMENTS: 'documents.',
195
+ OPERATIONS: 'operations.',
150
196
  }
@@ -0,0 +1,12 @@
1
+ export function scheduleNotification(request: {
2
+ id: string
3
+ title: string
4
+ body?: string
5
+ fireAt: number
6
+ }): Promise<{ ok: true }>
7
+
8
+ export function cancelNotification(request: {
9
+ id: string
10
+ }): Promise<{ ok: true }>
11
+
12
+ export function cancelAllNotifications(): Promise<{ ok: true }>
@@ -0,0 +1,36 @@
1
+ import { bridge } from './client.mjs'
2
+ import { PLATFORM_BRIDGE_METHODS } from './methods.mjs'
3
+
4
+ /**
5
+ * OS notification scheduling — a benign local capability (no plugin permission).
6
+ * Schedules are held in the shell main process and die when the app quits;
7
+ * reminders while the app is closed are out of scope. The app-side scheduler
8
+ * that decides *what* to schedule is the caller's responsibility.
9
+ */
10
+
11
+ /**
12
+ * Schedule an OS notification to fire at `fireAt`. Reusing an `id` replaces any
13
+ * pending schedule (dedupe). `fireAt` in the past fires ~immediately.
14
+ * @param {{ id: string, title: string, body?: string, fireAt: number }} request
15
+ * @returns {Promise<{ ok: true }>}
16
+ */
17
+ export async function scheduleNotification(request) {
18
+ return bridge.call(PLATFORM_BRIDGE_METHODS.NOTIFICATIONS_SCHEDULE, [request])
19
+ }
20
+
21
+ /**
22
+ * Cancel a pending schedule; no-op if the id is unknown.
23
+ * @param {{ id: string }} request
24
+ * @returns {Promise<{ ok: true }>}
25
+ */
26
+ export async function cancelNotification(request) {
27
+ return bridge.call(PLATFORM_BRIDGE_METHODS.NOTIFICATIONS_CANCEL, [request])
28
+ }
29
+
30
+ /**
31
+ * Clear every pending schedule (used when an app reloads its reminder set).
32
+ * @returns {Promise<{ ok: true }>}
33
+ */
34
+ export async function cancelAllNotifications() {
35
+ return bridge.call(PLATFORM_BRIDGE_METHODS.NOTIFICATIONS_CANCEL_ALL, [])
36
+ }
@@ -0,0 +1,44 @@
1
+ export type PlatformOperationLane = 'user' | 'agent'
2
+
3
+ export interface PlatformOperationInput {
4
+ /** Who acted: a person in the UI, or an agent doing work. */
5
+ lane: PlatformOperationLane
6
+ /** Stable machine-readable kind, dot-namespaced, e.g. `document.save`. */
7
+ kind: string
8
+ /** Originating app slug, or `shell` for platform-level operations. */
9
+ appSlug: string
10
+ /** One human-readable sentence describing the operation. */
11
+ summary: string
12
+ /** Optional free-form elaboration. */
13
+ detail?: string
14
+ /** Optional references (path, sessionId, runId, …) for drill-down. */
15
+ refs?: Record<string, string>
16
+ }
17
+
18
+ export interface PlatformOperation extends PlatformOperationInput {
19
+ id: string
20
+ /** ISO timestamp stamped by the shell. */
21
+ at: string
22
+ }
23
+
24
+ export interface PlatformOperationsListQuery {
25
+ lane?: PlatformOperationLane
26
+ /** Max entries returned, newest first. */
27
+ limit?: number
28
+ }
29
+
30
+ export interface PlatformOperationsListResult {
31
+ operations: PlatformOperation[]
32
+ }
33
+
34
+ export declare function recordPlatformOperation(
35
+ input: PlatformOperationInput,
36
+ ): Promise<PlatformOperation>
37
+
38
+ export declare function listPlatformOperations(
39
+ query?: PlatformOperationsListQuery,
40
+ ): Promise<PlatformOperationsListResult>
41
+
42
+ export declare function onPlatformOperationRecorded(
43
+ listener: (operation: PlatformOperation) => void,
44
+ ): () => void
@@ -0,0 +1,40 @@
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
+ * Platform operations ledger: one suite-wide record of what happened,
7
+ * split into two lanes — `user` interactions and `agent` interactions.
8
+ * The shell stores every entry and broadcasts each append, so UIs (the
9
+ * PureAssistant tab in particular) can follow activity in real time.
10
+ */
11
+
12
+ /**
13
+ * Record one operation into the ledger.
14
+ *
15
+ * @param {import('./operations.d.mts').PlatformOperationInput} input
16
+ * @returns {Promise<import('./operations.d.mts').PlatformOperation>}
17
+ */
18
+ export async function recordPlatformOperation(input) {
19
+ return bridge.call(PLATFORM_BRIDGE_METHODS.OPERATIONS_RECORD, [input])
20
+ }
21
+
22
+ /**
23
+ * List recorded operations, newest first.
24
+ *
25
+ * @param {import('./operations.d.mts').PlatformOperationsListQuery} [query]
26
+ * @returns {Promise<import('./operations.d.mts').PlatformOperationsListResult>}
27
+ */
28
+ export async function listPlatformOperations(query) {
29
+ return bridge.call(PLATFORM_BRIDGE_METHODS.OPERATIONS_LIST, [query ?? {}])
30
+ }
31
+
32
+ /**
33
+ * Subscribe to ledger appends. The listener receives each new operation.
34
+ *
35
+ * @param {(operation: import('./operations.d.mts').PlatformOperation) => void} listener
36
+ * @returns {() => void} unsubscribe
37
+ */
38
+ export function onPlatformOperationRecorded(listener) {
39
+ return bridge.onEvent(PLATFORM_BRIDGE_EVENTS.OPERATIONS_CHANGED, listener)
40
+ }