@panda-agent/panda-app-sdk 0.1.0 → 0.4.0

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.
@@ -3,7 +3,8 @@ export { createAppSdk } from './create-app-sdk.js';
3
3
  export { createUtilityProcessTransport } from './transport/utility-process.js';
4
4
  export type * from './types.js';
5
5
  export declare const PandaApp: {
6
- connectUtilityProcess(): {
6
+ connect: () => {
7
+ ready: () => Promise<void>;
7
8
  auth: {
8
9
  getCurrentUser: () => Promise<import("./types.js").AppUser | null>;
9
10
  };
@@ -17,6 +18,7 @@ export declare const PandaApp: {
17
18
  scene?: string;
18
19
  preferredModelId?: string;
19
20
  }) => Promise<import("./types.js").ModelListItem | null>;
21
+ chat: (request: import("./types.js").ModelChatRequest) => Promise<import("./types.js").ModelChatResult>;
20
22
  };
21
23
  workspace: {
22
24
  list: (request: {
@@ -28,9 +30,32 @@ export declare const PandaApp: {
28
30
  touch?: boolean;
29
31
  }) => Promise<import("./types.js").WorkspaceListItem>;
30
32
  };
33
+ artifacts: {
34
+ list: (request: import("./types.js").ArtifactsListRequest) => Promise<import("./types.js").ArtifactsListResult>;
35
+ snapshot: (request: import("./types.js").ArtifactsListRequest) => Promise<import("./types.js").ArtifactsSnapshotResult>;
36
+ readText: (request: import("./types.js").ArtifactsReadRequest) => Promise<import("./types.js").ArtifactReadTextResult>;
37
+ readDataUrl: (request: import("./types.js").ArtifactsReadRequest) => Promise<import("./types.js").ArtifactReadDataUrlResult>;
38
+ };
39
+ conversationData: {
40
+ readActivity: (ref: import("./types.js").ConversationRef, query: import("./types.js").ConversationActivityQuery) => Promise<import("./types.js").ConversationActivity>;
41
+ listConversations: (query?: import("./types.js").ConversationListQuery) => Promise<import("./types.js").ConversationDataPage<import("./types.js").ConversationDataListItem>>;
42
+ readRecords: (ref: import("./types.js").ConversationRef, query: import("./types.js").ConversationRecordsQuery) => Promise<import("./types.js").ConversationDataPage<import("./types.js").ConversationDataRecord>>;
43
+ readRecord: (ref: import("./types.js").ConversationRef, recordId: string, query?: import("./types.js").ConversationRecordQuery) => Promise<import("./types.js").ConversationDataRecord>;
44
+ getRuntime: (ref: import("./types.js").ConversationRef, options?: {
45
+ streamingPreview?: boolean;
46
+ }) => Promise<import("./types.js").ConversationRuntimeObservation>;
47
+ listRuntime: (query?: import("./types.js").ConversationListQuery) => Promise<import("./types.js").ConversationDataPage<import("./types.js").ConversationDataListItem>>;
48
+ getLocations: (ref: import("./types.js").ConversationRef) => Promise<import("./types.js").ConversationRecordLocation[]>;
49
+ };
31
50
  conversation: {
51
+ create: (options?: import("./types.js").CreateConversationOptions) => Promise<import("./types.js").CreateConversationResult>;
32
52
  createForApp: (options?: import("./types.js").CreateForAppOptions) => Promise<import("./types.js").CreateForAppResult>;
33
53
  disposeForApp: (conversationId: string) => Promise<unknown>;
54
+ listForApp: (workspaceId?: string) => Promise<unknown>;
55
+ attach: (conversationId: string) => Promise<{
56
+ conversationId: string;
57
+ }>;
58
+ detach: (conversationId: string) => Promise<unknown>;
34
59
  submitMessage: (conversationId: string, prompt: string) => Promise<unknown>;
35
60
  getMessages: (conversationId: string) => Promise<unknown>;
36
61
  subscribe: (options: import("./types.js").ConversationSubscribeOptions & {
@@ -46,9 +71,16 @@ export declare const PandaApp: {
46
71
  }) => Promise<unknown>;
47
72
  };
48
73
  session: {
49
- mount: (conversationId: string, appId: string, replaceConfirmed?: boolean) => Promise<unknown>;
50
- unmount: (conversationId: string) => Promise<unknown>;
51
- getMount: (conversationId: string) => Promise<unknown>;
74
+ getContext: () => Promise<import("./types.js").SessionContext>;
75
+ mount: (conversationId: string, appId: string) => Promise<unknown>;
76
+ unmount: (conversationId: string, appId: string) => Promise<unknown>;
77
+ listMounts: (conversationId: string) => Promise<unknown>;
78
+ };
79
+ todo: {
80
+ get: (conversationId: string) => Promise<import("./types.js").TodoSnapshot>;
81
+ };
82
+ memory: {
83
+ listSessionEntries: (conversationId: string) => Promise<import("./types.js").MemorySessionEntries>;
52
84
  };
53
85
  ingress: {
54
86
  submit: (conversationId: string, prompt: string) => Promise<{
@@ -56,6 +88,37 @@ export declare const PandaApp: {
56
88
  status: string;
57
89
  }>;
58
90
  };
91
+ agent: {
92
+ invokeSkill: (request: import("./types.js").InvokeSkillRequest) => Promise<import("./types.js").InvokeSkillResult>;
93
+ invokeSubagent: (request: import("./types.js").InvokeSubagentRequest) => Promise<import("./types.js").InvokeSubagentResult>;
94
+ cancelSubagent: (invocationId: string) => Promise<import("./types.js").CancelSubagentResult>;
95
+ };
96
+ ui: {
97
+ theme: () => Promise<import("./types.js").AppUiThemeResult>;
98
+ openExternal: (url: string) => Promise<void>;
99
+ sessionSurface: {
100
+ getState: () => Promise<import("./types.js").SessionSurfaceState>;
101
+ show: (options?: {
102
+ activate?: boolean;
103
+ reason?: string;
104
+ }) => Promise<unknown>;
105
+ collapse: () => Promise<unknown>;
106
+ };
107
+ };
108
+ storage: {
109
+ global: {
110
+ get: (key: string) => Promise<import("./types.js").AppJsonValue | undefined>;
111
+ set: (key: string, value: import("./types.js").AppJsonValue) => Promise<unknown>;
112
+ delete: (key: string) => Promise<unknown>;
113
+ list: (prefix?: string) => Promise<import("./types.js").AppStorageListItem[]>;
114
+ };
115
+ session: {
116
+ get: (key: string) => Promise<import("./types.js").AppJsonValue | undefined>;
117
+ set: (key: string, value: import("./types.js").AppJsonValue) => Promise<unknown>;
118
+ delete: (key: string) => Promise<unknown>;
119
+ list: (prefix?: string) => Promise<import("./types.js").AppStorageListItem[]>;
120
+ };
121
+ };
59
122
  tools: {
60
123
  list: (request: {
61
124
  workspace?: import("./types.js").WorkspaceRef;
@@ -100,7 +163,190 @@ export declare const PandaApp: {
100
163
  homeDir: string;
101
164
  pandaVersion: string;
102
165
  appSdkVersion: string;
166
+ capabilities?: {
167
+ invocationToolPolicy?: boolean;
168
+ appPrivateMcp?: boolean;
169
+ };
170
+ }>;
171
+ supports: (requiredVersion: string) => Promise<boolean>;
172
+ };
173
+ dialog: {
174
+ showOpen: (request?: import("./types.js").DialogShowOpenRequest) => Promise<import("./types.js").DialogShowOpenResult>;
175
+ readPickedFile: (request: import("./types.js").DialogReadPickedFileRequest) => Promise<import("./types.js").DialogReadPickedFileResult>;
176
+ releasePick: (pickToken: string) => Promise<unknown>;
177
+ showSave: (request?: import("./types.js").DialogShowSaveRequest) => Promise<import("./types.js").DialogShowSaveResult>;
178
+ writeSaveFile: (request: import("./types.js").DialogWriteSaveFileRequest) => Promise<import("./types.js").DialogWriteSaveFileResult>;
179
+ pickAndReadFile: (options?: import("./types.js").DialogPickAndReadFileOptions) => Promise<import("./types.js").DialogReadPickedFileResult | null>;
180
+ saveFile: (options: import("./types.js").DialogSaveFileOptions) => Promise<string | null>;
181
+ };
182
+ };
183
+ /** @deprecated Use PandaApp.connect() instead. */
184
+ connectUtilityProcess: () => {
185
+ ready: () => Promise<void>;
186
+ auth: {
187
+ getCurrentUser: () => Promise<import("./types.js").AppUser | null>;
188
+ };
189
+ model: {
190
+ list: (options?: {
191
+ enabledOnly?: boolean;
192
+ visibleOnly?: boolean;
193
+ scene?: string;
194
+ }) => Promise<import("./types.js").ModelListItem[]>;
195
+ resolveForScene: (request?: {
196
+ scene?: string;
197
+ preferredModelId?: string;
198
+ }) => Promise<import("./types.js").ModelListItem | null>;
199
+ chat: (request: import("./types.js").ModelChatRequest) => Promise<import("./types.js").ModelChatResult>;
200
+ };
201
+ workspace: {
202
+ list: (request: {
203
+ limit: number;
204
+ includeEphemeral?: boolean;
205
+ }) => Promise<import("./types.js").WorkspaceListItem[]>;
206
+ ensureLocal: (request: {
207
+ path: string;
208
+ touch?: boolean;
209
+ }) => Promise<import("./types.js").WorkspaceListItem>;
210
+ };
211
+ artifacts: {
212
+ list: (request: import("./types.js").ArtifactsListRequest) => Promise<import("./types.js").ArtifactsListResult>;
213
+ snapshot: (request: import("./types.js").ArtifactsListRequest) => Promise<import("./types.js").ArtifactsSnapshotResult>;
214
+ readText: (request: import("./types.js").ArtifactsReadRequest) => Promise<import("./types.js").ArtifactReadTextResult>;
215
+ readDataUrl: (request: import("./types.js").ArtifactsReadRequest) => Promise<import("./types.js").ArtifactReadDataUrlResult>;
216
+ };
217
+ conversationData: {
218
+ readActivity: (ref: import("./types.js").ConversationRef, query: import("./types.js").ConversationActivityQuery) => Promise<import("./types.js").ConversationActivity>;
219
+ listConversations: (query?: import("./types.js").ConversationListQuery) => Promise<import("./types.js").ConversationDataPage<import("./types.js").ConversationDataListItem>>;
220
+ readRecords: (ref: import("./types.js").ConversationRef, query: import("./types.js").ConversationRecordsQuery) => Promise<import("./types.js").ConversationDataPage<import("./types.js").ConversationDataRecord>>;
221
+ readRecord: (ref: import("./types.js").ConversationRef, recordId: string, query?: import("./types.js").ConversationRecordQuery) => Promise<import("./types.js").ConversationDataRecord>;
222
+ getRuntime: (ref: import("./types.js").ConversationRef, options?: {
223
+ streamingPreview?: boolean;
224
+ }) => Promise<import("./types.js").ConversationRuntimeObservation>;
225
+ listRuntime: (query?: import("./types.js").ConversationListQuery) => Promise<import("./types.js").ConversationDataPage<import("./types.js").ConversationDataListItem>>;
226
+ getLocations: (ref: import("./types.js").ConversationRef) => Promise<import("./types.js").ConversationRecordLocation[]>;
227
+ };
228
+ conversation: {
229
+ create: (options?: import("./types.js").CreateConversationOptions) => Promise<import("./types.js").CreateConversationResult>;
230
+ createForApp: (options?: import("./types.js").CreateForAppOptions) => Promise<import("./types.js").CreateForAppResult>;
231
+ disposeForApp: (conversationId: string) => Promise<unknown>;
232
+ listForApp: (workspaceId?: string) => Promise<unknown>;
233
+ attach: (conversationId: string) => Promise<{
234
+ conversationId: string;
235
+ }>;
236
+ detach: (conversationId: string) => Promise<unknown>;
237
+ submitMessage: (conversationId: string, prompt: string) => Promise<unknown>;
238
+ getMessages: (conversationId: string) => Promise<unknown>;
239
+ subscribe: (options: import("./types.js").ConversationSubscribeOptions & {
240
+ onEvent?: import("./types.js").AppEventHandler;
241
+ }) => Promise<{
242
+ subscriptionId: string;
243
+ unsubscribe: () => Promise<void>;
244
+ }>;
245
+ awaitTurn: (options: {
246
+ conversationId: string;
247
+ turnId?: string;
248
+ timeoutMs?: number;
249
+ }) => Promise<unknown>;
250
+ };
251
+ session: {
252
+ getContext: () => Promise<import("./types.js").SessionContext>;
253
+ mount: (conversationId: string, appId: string) => Promise<unknown>;
254
+ unmount: (conversationId: string, appId: string) => Promise<unknown>;
255
+ listMounts: (conversationId: string) => Promise<unknown>;
256
+ };
257
+ todo: {
258
+ get: (conversationId: string) => Promise<import("./types.js").TodoSnapshot>;
259
+ };
260
+ memory: {
261
+ listSessionEntries: (conversationId: string) => Promise<import("./types.js").MemorySessionEntries>;
262
+ };
263
+ ingress: {
264
+ submit: (conversationId: string, prompt: string) => Promise<{
265
+ conversationId: string;
266
+ status: string;
267
+ }>;
268
+ };
269
+ agent: {
270
+ invokeSkill: (request: import("./types.js").InvokeSkillRequest) => Promise<import("./types.js").InvokeSkillResult>;
271
+ invokeSubagent: (request: import("./types.js").InvokeSubagentRequest) => Promise<import("./types.js").InvokeSubagentResult>;
272
+ cancelSubagent: (invocationId: string) => Promise<import("./types.js").CancelSubagentResult>;
273
+ };
274
+ ui: {
275
+ theme: () => Promise<import("./types.js").AppUiThemeResult>;
276
+ openExternal: (url: string) => Promise<void>;
277
+ sessionSurface: {
278
+ getState: () => Promise<import("./types.js").SessionSurfaceState>;
279
+ show: (options?: {
280
+ activate?: boolean;
281
+ reason?: string;
282
+ }) => Promise<unknown>;
283
+ collapse: () => Promise<unknown>;
284
+ };
285
+ };
286
+ storage: {
287
+ global: {
288
+ get: (key: string) => Promise<import("./types.js").AppJsonValue | undefined>;
289
+ set: (key: string, value: import("./types.js").AppJsonValue) => Promise<unknown>;
290
+ delete: (key: string) => Promise<unknown>;
291
+ list: (prefix?: string) => Promise<import("./types.js").AppStorageListItem[]>;
292
+ };
293
+ session: {
294
+ get: (key: string) => Promise<import("./types.js").AppJsonValue | undefined>;
295
+ set: (key: string, value: import("./types.js").AppJsonValue) => Promise<unknown>;
296
+ delete: (key: string) => Promise<unknown>;
297
+ list: (prefix?: string) => Promise<import("./types.js").AppStorageListItem[]>;
298
+ };
299
+ };
300
+ tools: {
301
+ list: (request: {
302
+ workspace?: import("./types.js").WorkspaceRef;
303
+ workspaceId?: string;
304
+ }) => Promise<Array<{
305
+ name: string;
306
+ displayName: string;
307
+ description: string;
308
+ kind: string;
309
+ }>>;
310
+ execute: (request: {
311
+ toolName: string;
312
+ args?: Record<string, unknown>;
313
+ workspace?: import("./types.js").WorkspaceRef;
314
+ workspaceId?: string;
315
+ }) => Promise<{
316
+ toolName: string;
317
+ workspaceId: string;
318
+ ok: boolean;
319
+ llmContent?: string;
320
+ error?: {
321
+ message: string;
322
+ type?: string;
323
+ };
324
+ displayData?: unknown;
325
+ }>;
326
+ };
327
+ runtime: {
328
+ now: () => Promise<{
329
+ timestamp: number;
330
+ iso: string;
331
+ timeZone: string;
332
+ utcOffsetMinutes: number;
333
+ }>;
334
+ getHost: () => Promise<{
335
+ platform: string;
336
+ arch: string;
337
+ osName: string;
338
+ hostProduct: string;
339
+ shell: string;
340
+ shellKind: string;
341
+ homeDir: string;
342
+ pandaVersion: string;
343
+ appSdkVersion: string;
344
+ capabilities?: {
345
+ invocationToolPolicy?: boolean;
346
+ appPrivateMcp?: boolean;
347
+ };
103
348
  }>;
349
+ supports: (requiredVersion: string) => Promise<boolean>;
104
350
  };
105
351
  dialog: {
106
352
  showOpen: (request?: import("./types.js").DialogShowOpenRequest) => Promise<import("./types.js").DialogShowOpenResult>;
@@ -4,30 +4,75 @@ var APP_UTILITY_INVOKE_RESULT = "app-utility:invoke-result";
4
4
  var APP_UTILITY_READY = "app-utility:ready";
5
5
  var APP_UTILITY_EVENT = "app-utility:event";
6
6
 
7
+ // src/semver.ts
8
+ function compareSemver(v1, v2) {
9
+ const parse = (v) => {
10
+ const parts = v.split(".");
11
+ const nums = [];
12
+ for (let i = 0; i < 3; i++) {
13
+ const n = parseInt(parts[i] ?? "0", 10);
14
+ nums.push(Number.isFinite(n) ? n : 0);
15
+ }
16
+ return nums;
17
+ };
18
+ const a = parse(v1);
19
+ const b = parse(v2);
20
+ for (let i = 0; i < 3; i++) {
21
+ if (a[i] > b[i]) return 1;
22
+ if (a[i] < b[i]) return -1;
23
+ }
24
+ return 0;
25
+ }
26
+
7
27
  // src/create-app-sdk.ts
8
28
  function createAppSdk(transport) {
29
+ const policyPreflights = /* @__PURE__ */ new Map();
30
+ let ready;
9
31
  return {
32
+ /** Report this side ready. Initialization and the first usable render must finish before calling. */
33
+ ready: () => ready ??= transport.ready ? transport.ready() : Promise.reject(new Error("This Panda host does not support App readiness")),
10
34
  auth: {
11
35
  getCurrentUser: () => transport.invoke("auth.getCurrentUser", [])
12
36
  },
13
37
  model: {
14
38
  list: (options) => transport.invoke("model.list", [options ?? {}]),
15
- resolveForScene: (request) => transport.invoke("model.resolveForScene", [request ?? {}])
39
+ resolveForScene: (request) => transport.invoke("model.resolveForScene", [request ?? {}]),
40
+ chat: (request) => transport.invoke("model.chat", [request])
16
41
  },
17
42
  workspace: {
18
43
  list: (request) => transport.invoke("workspace.list", [request]),
19
44
  ensureLocal: (request) => transport.invoke("workspace.ensureLocal", [request])
20
45
  },
46
+ artifacts: {
47
+ list: (request) => transport.invoke("artifacts.list", [request]),
48
+ snapshot: (request) => transport.invoke("artifacts.snapshot", [request]),
49
+ readText: (request) => transport.invoke("artifacts.readText", [request]),
50
+ readDataUrl: (request) => transport.invoke("artifacts.readDataUrl", [request])
51
+ },
52
+ conversationData: {
53
+ readActivity: (ref, query) => transport.invoke("conversationData.readActivity", [ref, query]),
54
+ listConversations: (query) => transport.invoke("conversationData.listConversations", [query ?? {}]),
55
+ readRecords: (ref, query) => transport.invoke("conversationData.readRecords", [ref, query]),
56
+ readRecord: (ref, recordId, query) => transport.invoke("conversationData.readRecord", [ref, recordId, query ?? {}]),
57
+ getRuntime: (ref, options) => transport.invoke("conversationData.getRuntime", [ref, options ?? {}]),
58
+ listRuntime: (query) => transport.invoke("conversationData.listRuntime", [query ?? {}]),
59
+ getLocations: (ref) => transport.invoke("conversationData.getLocations", [ref])
60
+ },
21
61
  conversation: {
62
+ create: (options) => transport.invoke("conversation.create", [options ?? {}]),
22
63
  createForApp: (options) => transport.invoke("conversation.createForApp", [options ?? {}]),
23
64
  disposeForApp: (conversationId) => transport.invoke("conversation.disposeForApp", [conversationId]),
65
+ listForApp: (workspaceId) => transport.invoke("conversation.listForApp", workspaceId === void 0 ? [] : [workspaceId]),
66
+ attach: (conversationId) => transport.invoke("conversation.attach", [conversationId]),
67
+ detach: (conversationId) => transport.invoke("conversation.detach", [conversationId]),
24
68
  submitMessage: (conversationId, prompt) => transport.invoke("conversation.submitMessage", [conversationId, prompt]),
25
69
  getMessages: (conversationId) => transport.invoke("conversation.getMessages", [conversationId]),
26
70
  subscribe: async (options) => {
27
- const result = await transport.invoke("conversation.subscribe", [options]);
71
+ const { onEvent, ...request } = options;
72
+ const result = await transport.invoke("conversation.subscribe", [request]);
28
73
  let offEvent;
29
- if (options.onEvent) {
30
- offEvent = transport.subscribe(result.subscriptionId, options.onEvent);
74
+ if (onEvent) {
75
+ offEvent = transport.subscribe(result.subscriptionId, onEvent);
31
76
  }
32
77
  return {
33
78
  subscriptionId: result.subscriptionId,
@@ -40,20 +85,85 @@ function createAppSdk(transport) {
40
85
  awaitTurn: (options) => transport.invoke("conversation.awaitTurn", [options])
41
86
  },
42
87
  session: {
43
- mount: (conversationId, appId, replaceConfirmed) => transport.invoke("mountSession", [conversationId, appId, replaceConfirmed === true]),
44
- unmount: (conversationId) => transport.invoke("unmountSession", [conversationId]),
45
- getMount: (conversationId) => transport.invoke("getSessionMount", [conversationId])
88
+ getContext: () => transport.invoke("session.getContext", []),
89
+ mount: (conversationId, appId) => transport.invoke("mountSession", [conversationId, appId]),
90
+ unmount: (conversationId, appId) => transport.invoke("unmountSession", [conversationId, appId]),
91
+ listMounts: (conversationId) => transport.invoke("listSessionMounts", [conversationId])
92
+ },
93
+ todo: {
94
+ get: (conversationId) => transport.invoke("todo.get", [conversationId])
95
+ },
96
+ memory: {
97
+ listSessionEntries: (conversationId) => transport.invoke("memory.listSessionEntries", [conversationId])
46
98
  },
47
99
  ingress: {
48
100
  submit: (conversationId, prompt) => transport.invoke("ingress.submit", [conversationId, prompt])
49
101
  },
102
+ agent: {
103
+ invokeSkill: (request) => transport.invoke("agent.invokeSkill", [request]),
104
+ invokeSubagent: async (request) => {
105
+ const restricted = request.allowedTools !== void 0 || request.readableFiles !== void 0;
106
+ const id = restricted ? request.invocationId?.trim() : void 0;
107
+ if (id && policyPreflights.has(id)) throw new Error("Duplicate subagent invocationId");
108
+ const pending = { cancelled: false };
109
+ if (id) policyPreflights.set(id, pending);
110
+ try {
111
+ if (restricted) {
112
+ const host = await transport.invoke("runtime.getHost", []);
113
+ if (pending.cancelled) throw new Error("Subagent cancelled before dispatch");
114
+ if (host?.capabilities?.invocationToolPolicy !== true) {
115
+ throw Object.assign(new Error("Host does not support invocation tool policies; refusing an unrestricted fallback"), { code: "APP_HOST_CAPABILITY_REQUIRED" });
116
+ }
117
+ }
118
+ if (id) policyPreflights.delete(id);
119
+ return await transport.invoke("agent.invokeSubagent", [request]);
120
+ } finally {
121
+ if (id && policyPreflights.get(id) === pending) policyPreflights.delete(id);
122
+ }
123
+ },
124
+ cancelSubagent: async (invocationId) => {
125
+ const pending = policyPreflights.get(invocationId.trim());
126
+ if (pending) {
127
+ pending.cancelled = true;
128
+ return { cancelled: true };
129
+ }
130
+ return transport.invoke("agent.cancelSubagent", [{ invocationId }]);
131
+ }
132
+ },
133
+ ui: {
134
+ theme: () => transport.invoke("ui.theme", []),
135
+ openExternal: (url) => transport.invoke("ui.openExternal", [{ url }]),
136
+ sessionSurface: {
137
+ getState: () => transport.invoke("ui.sessionSurface.getState", []),
138
+ show: (options) => transport.invoke("ui.sessionSurface.show", [options ?? {}]),
139
+ collapse: () => transport.invoke("ui.sessionSurface.collapse", [])
140
+ }
141
+ },
142
+ storage: {
143
+ global: {
144
+ get: (key) => transport.invoke("storage.global.get", [key]),
145
+ set: (key, value) => transport.invoke("storage.global.set", [key, value]),
146
+ delete: (key) => transport.invoke("storage.global.delete", [key]),
147
+ list: (prefix) => transport.invoke("storage.global.list", prefix === void 0 ? [] : [prefix])
148
+ },
149
+ session: {
150
+ get: (key) => transport.invoke("storage.session.get", [key]),
151
+ set: (key, value) => transport.invoke("storage.session.set", [key, value]),
152
+ delete: (key) => transport.invoke("storage.session.delete", [key]),
153
+ list: (prefix) => transport.invoke("storage.session.list", prefix === void 0 ? [] : [prefix])
154
+ }
155
+ },
50
156
  tools: {
51
157
  list: (request) => transport.invoke("tools.list", [request]),
52
158
  execute: (request) => transport.invoke("tools.execute", [request])
53
159
  },
54
160
  runtime: {
55
161
  now: () => transport.invoke("runtime.now", []),
56
- getHost: () => transport.invoke("runtime.getHost", [])
162
+ getHost: () => transport.invoke("runtime.getHost", []),
163
+ supports: async (requiredVersion) => {
164
+ const host = await transport.invoke("runtime.getHost", []);
165
+ return compareSemver(host.appSdkVersion, requiredVersion) >= 0;
166
+ }
57
167
  },
58
168
  dialog: {
59
169
  showOpen: (request) => transport.invoke("dialog.showOpen", [request ?? {}]),
@@ -105,11 +215,21 @@ function newRequestId() {
105
215
  // src/transport/shared/pending-invoke.ts
106
216
  function createPendingInvoke(newRequestId2) {
107
217
  const pending = /* @__PURE__ */ new Map();
108
- function invoke(postMessage, invokeType, path, args) {
218
+ function invoke(postMessage, invokeType, path, args, timeoutMs) {
109
219
  const requestId = newRequestId2();
110
220
  return new Promise((resolve, reject) => {
111
- pending.set(requestId, { resolve, reject });
112
- postMessage({ type: invokeType, requestId, path, args });
221
+ const timer = timeoutMs ? setTimeout(() => {
222
+ pending.delete(requestId);
223
+ reject(new Error("App ready acknowledgement timed out; update or reopen the Panda host"));
224
+ }, timeoutMs) : void 0;
225
+ pending.set(requestId, { resolve, reject, timer });
226
+ try {
227
+ postMessage({ type: invokeType, requestId, path, args });
228
+ } catch (error) {
229
+ pending.delete(requestId);
230
+ clearTimeout(timer);
231
+ reject(error);
232
+ }
113
233
  });
114
234
  }
115
235
  function handleInvokeResult(message) {
@@ -121,6 +241,7 @@ function createPendingInvoke(newRequestId2) {
121
241
  return;
122
242
  }
123
243
  pending.delete(message.requestId);
244
+ clearTimeout(entry.timer);
124
245
  if (message.ok) {
125
246
  entry.resolve(message.result);
126
247
  } else {
@@ -185,6 +306,9 @@ function createUtilityProcessTransport() {
185
306
  }
186
307
  });
187
308
  return {
309
+ ready: async () => {
310
+ await createInvoke((message) => parentPort.postMessage(message), APP_UTILITY_READY, "app.ready", [], 3e4);
311
+ },
188
312
  invoke(path, args) {
189
313
  return createInvoke(
190
314
  (message) => {
@@ -200,10 +324,11 @@ function createUtilityProcessTransport() {
200
324
  }
201
325
 
202
326
  // src/node.ts
327
+ var connect = () => createAppSdk(createUtilityProcessTransport());
203
328
  var PandaApp = {
204
- connectUtilityProcess() {
205
- return createAppSdk(createUtilityProcessTransport());
206
- }
329
+ connect,
330
+ /** @deprecated Use PandaApp.connect() instead. */
331
+ connectUtilityProcess: connect
207
332
  };
208
333
  export {
209
334
  APP_UTILITY_EVENT,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@panda-agent/panda-app-sdk",
3
- "version": "0.1.0",
3
+ "version": "0.4.0",
4
4
  "private": false,
5
5
  "description": "Panda 智能应用 SDK — iframe / Utility Process 客户端",
6
6
  "license": "MIT",