@pstdio/sdk 0.24.1 → 0.35.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.
package/dist/data.d.ts CHANGED
@@ -1,47 +1,27 @@
1
- export declare const applyFrontmatter: (frontmatter: string, content: string) => string;
2
-
3
- declare interface ArtifactFile {
4
- path: string;
5
- size?: number;
6
- updatedAt?: string;
7
- }
8
-
9
- declare interface ArtifactMount {
10
- exists(path: string): Promise<boolean>;
11
- readText(path: string): Promise<string>;
12
- writeText(path: string, value: string): Promise<void>;
13
- readBytes(path: string): Promise<Uint8Array>;
14
- writeBytes(path: string, value: Uint8Array): Promise<void>;
15
- list(pattern?: string): Promise<ArtifactFile[]>;
16
- listDirs(path?: string): Promise<string[]>;
17
- delete(path: string): Promise<void>;
18
- }
19
-
20
- export declare const assertSafePathSegment: (value: string) => void;
21
-
22
- export declare const createDraftLayout: (root: string, document: string) => {
23
- directory: (name: string) => string;
24
- markdown: (name: string, suffix?: string) => string;
25
- files: (name: string, suffix?: string) => string;
26
- };
27
-
28
- export declare const findClosingFrontmatterDelimiter: (content: string) => {
29
- end: number;
30
- start: number;
31
- } | null;
32
-
33
- export declare const quoteYamlScalar: (value: string) => string;
34
-
35
- export declare const requireRepoFiles: (repoFiles: ArtifactMount | undefined) => ArtifactMount;
36
-
37
- export declare const resolveByIdOrName: <TItem extends {
38
- id: string;
39
- }>(items: TItem[], value: string, nameOf: (item: TItem) => string, label: string) => string;
40
-
41
- export declare const sameName: (a: string, b: string) => boolean;
42
-
43
- export declare const stripFrontmatter: (content: string) => string;
44
-
45
- export declare const unquoteYamlScalar: (value: string) => string;
46
-
47
- export { }
1
+ import { Lr as ArtifactMount } from "./index-x7CdJPRb.js";
2
+ //#region src/data/draft-layout.d.ts
3
+ export declare const assertSafePathSegment: (value: string) => void;
4
+ export declare const requireRepoFiles: (repoFiles: ArtifactMount | undefined) => ArtifactMount;
5
+ export declare const createDraftLayout: (root: string, document: string) => {
6
+ directory: (name: string) => string;
7
+ markdown: (name: string, suffix?: string) => string;
8
+ files: (name: string, suffix?: string) => string;
9
+ };
10
+ //#endregion
11
+ //#region src/data/frontmatter.d.ts
12
+ export declare const quoteYamlScalar: (value: string) => string;
13
+ export declare const findClosingFrontmatterDelimiter: (content: string) => {
14
+ end: number;
15
+ start: number;
16
+ } | null;
17
+ export declare const stripFrontmatter: (content: string) => string;
18
+ export declare const applyFrontmatter: (frontmatter: string, content: string) => string;
19
+ export declare const unquoteYamlScalar: (value: string) => string;
20
+ //#endregion
21
+ //#region src/data/resolve.d.ts
22
+ export declare const sameName: (a: string, b: string) => boolean;
23
+ export declare const resolveByIdOrName: <TItem extends {
24
+ id: string;
25
+ }>(items: TItem[], value: string, nameOf: (item: TItem) => string, label: string) => string;
26
+ //#endregion
27
+ export {};
@@ -1,3 +1,7 @@
1
+ // ../pstdio-api-contracts/src/extension-kernel/api-versions.ts
2
+ var numericIdentifier = "(?:0|[1-9]\\d*)";
3
+ var prereleaseIdentifier = `(?:${numericIdentifier}|\\d*[A-Za-z-][0-9A-Za-z-]*)`;
4
+ var exactVersion = new RegExp(`^${numericIdentifier}\\.${numericIdentifier}\\.${numericIdentifier}(?:-${prereleaseIdentifier}(?:\\.${prereleaseIdentifier})*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$`);
1
5
  // ../pstdio-api-contracts/src/extension-kernel/types/composition.ts
2
6
  var dockedWorkbenchRegions = ["sidenav", "main", "secondary", "side"];
3
7
  var extensionPanelRegions = ["main", "secondary", "side"];
@@ -133,6 +137,11 @@ var workspaceSlots = {
133
137
  var projectEvents = {
134
138
  opened: hostEventRef("project.opened")
135
139
  };
140
+ var viewDataEvents = {
141
+ sessionsChanged: hostEventRef("view.sessions.changed"),
142
+ workspacesChanged: hostEventRef("view.workspaces.changed"),
143
+ repositoriesChanged: hostEventRef("view.repositories.changed")
144
+ };
136
145
  var sessionEvents = {
137
146
  started: hostEventRef("session.started"),
138
147
  resumed: hostEventRef("session.resumed"),
@@ -163,6 +172,98 @@ var l10n = (key, defaultValue) => ({
163
172
  ...defaultValue === undefined ? {} : { default: defaultValue }
164
173
  });
165
174
  var isLocalizedString = (value) => typeof value === "object" && value !== null && ("$l10n" in value) && typeof value.$l10n === "string";
175
+ // ../pstdio-api-contracts/src/extension-kernel/navigation-href.ts
176
+ var isNavigationHref = (href) => {
177
+ if (typeof href !== "string")
178
+ return false;
179
+ try {
180
+ const { protocol } = new URL(href);
181
+ return protocol === "https:" || protocol === "http:";
182
+ } catch {
183
+ return false;
184
+ }
185
+ };
186
+
187
+ // ../pstdio-api-contracts/src/extension-kernel/navigation.ts
188
+ var isRecord = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
189
+ var isContributionRef = (value, kind) => isRecord(value) && value.kind === kind && typeof value.id === "string";
190
+ var isResource = (value) => isRecord(value) && typeof value.type === "string" && typeof value.id === "string";
191
+ var isOpenIntent = (value) => value === undefined || value === "preview" || value === "pin";
192
+ var isPageTarget = (value, ancestors = new Set) => {
193
+ if (!isRecord(value) || value.kind !== "page" || !isContributionRef(value.page, "page"))
194
+ return false;
195
+ if (ancestors.has(value))
196
+ return false;
197
+ if (value.resource !== undefined && !isResource(value.resource))
198
+ return false;
199
+ if (value.section !== undefined && !isRecord(value.section))
200
+ return false;
201
+ if (!isOpenIntent(value.open))
202
+ return false;
203
+ if (value.parent === undefined)
204
+ return true;
205
+ const next = new Set(ancestors);
206
+ next.add(value);
207
+ return isPageTarget(value.parent, next);
208
+ };
209
+ var isPanelTarget = (value) => {
210
+ if (!isRecord(value) || value.kind !== "panel" || !isRecord(value.panel))
211
+ return false;
212
+ const panel = value.panel;
213
+ const validPanel = isContributionRef(panel, "placement") || panel.kind === "page-slot" && isContributionRef(panel.page, "page") && typeof panel.id === "string";
214
+ return validPanel && (value.resource === undefined || isResource(value.resource)) && isOpenIntent(value.open);
215
+ };
216
+ var isItemTarget = (value) => {
217
+ if (!isRecord(value))
218
+ return false;
219
+ if (value.kind === "page")
220
+ return isPageTarget(value);
221
+ if (value.kind === "panel")
222
+ return isPanelTarget(value);
223
+ if (value.kind === "href")
224
+ return isNavigationHref(value.href);
225
+ return value.kind === "command" && isRecord(value.target) && isContributionRef(value.target.command, "command") && (value.target.params === undefined || isRecord(value.target.params));
226
+ };
227
+ var isNavigationTarget = (value) => {
228
+ if (isItemTarget(value))
229
+ return true;
230
+ if (!isRecord(value) || value.kind !== "compound" || !Array.isArray(value.targets) || value.targets.length === 0) {
231
+ return false;
232
+ }
233
+ return value.targets.every((target) => isPageTarget(target) || isPanelTarget(target));
234
+ };
235
+ var withExtensionOwner = (ref, extensionId) => ref.extensionId !== undefined || extensionId === undefined ? ref : { ...ref, extensionId };
236
+ var toPageTarget = (target, extensionId, projectId) => ({
237
+ ...target,
238
+ page: withExtensionOwner(target.page, extensionId),
239
+ ...target.resource ? { resource: qualifyResource(target.resource, extensionId, projectId) } : {},
240
+ ...target.parent ? { parent: toPageTarget(target.parent, extensionId, projectId) } : {}
241
+ });
242
+ var qualifyResource = (resource, extensionId, projectId) => ({
243
+ ...resource,
244
+ extensionId: resource.extensionId ?? extensionId,
245
+ projectId: resource.projectId ?? projectId
246
+ });
247
+ var qualifyNavigationTarget = (target, extensionId, projectId) => {
248
+ if (!isNavigationTarget(target))
249
+ throw new Error("Invalid navigation target.");
250
+ if (target.kind === "page")
251
+ return toPageTarget(target, extensionId, projectId);
252
+ if (target.kind === "panel")
253
+ return {
254
+ ...target,
255
+ panel: target.panel.kind === "page-slot" ? { ...target.panel, page: withExtensionOwner(target.panel.page, extensionId) } : withExtensionOwner(target.panel, extensionId),
256
+ ...target.resource ? { resource: qualifyResource(target.resource, extensionId, projectId) } : {}
257
+ };
258
+ if (target.kind === "command")
259
+ return { ...target, target: { ...target.target, command: withExtensionOwner(target.target.command, extensionId) } };
260
+ if (target.kind === "href")
261
+ return target;
262
+ return {
263
+ ...target,
264
+ targets: target.targets.map((item) => qualifyNavigationTarget(item, extensionId, projectId))
265
+ };
266
+ };
166
267
  // ../pstdio-api-contracts/src/extension-kernel/package-asset.ts
167
268
  var packageAsset = (path, baseUrl) => ({
168
269
  kind: "package-asset",
@@ -199,8 +300,181 @@ var WEBVIEW_HOST_CAPABILITIES = [
199
300
  ...WEBVIEW_SCOPED_DECLARABLE_CAPABILITIES,
200
301
  ...ALWAYS_AVAILABLE_WEBVIEW_CAPABILITIES
201
302
  ];
303
+ // ../pstdio-api-contracts/src/history-turn-evidence.ts
304
+ var historyTurnEvidence = (known, native, prompt, body) => {
305
+ const signatures = (turn) => JSON.stringify([prompt(turn), body(turn)]);
306
+ if (known.length === native.length && known.every((turn, index) => signatures(turn) === signatures(native[index]))) {
307
+ return signatures;
308
+ }
309
+ const tokens = (turns) => {
310
+ const positions = new Map;
311
+ turns.forEach((turn, index) => {
312
+ for (const value of new Set(body(turn))) {
313
+ const token = JSON.stringify([prompt(turn), value]);
314
+ positions.set(token, positions.has(token) ? -1 : index);
315
+ }
316
+ });
317
+ return positions;
318
+ };
319
+ const left = tokens(known);
320
+ const right = tokens(native);
321
+ const matches = new Map;
322
+ const reverse = new Map;
323
+ for (const [token, index] of left) {
324
+ const other = right.get(token);
325
+ if (index < 0 || other === undefined || other < 0)
326
+ continue;
327
+ const targets = matches.get(index) ?? new Set;
328
+ targets.add(other);
329
+ matches.set(index, targets);
330
+ const sources = reverse.get(other) ?? new Set;
331
+ sources.add(index);
332
+ reverse.set(other, sources);
333
+ }
334
+ const keys = new Map;
335
+ known.forEach((turn, index) => {
336
+ keys.set(turn, `known:${index}`);
337
+ });
338
+ native.forEach((turn, index) => {
339
+ keys.set(turn, `native:${index}`);
340
+ });
341
+ for (const [index, targets] of matches) {
342
+ if (targets.size !== 1)
343
+ continue;
344
+ const other = [...targets][0];
345
+ if (reverse.get(other)?.size !== 1)
346
+ continue;
347
+ const key = `pair:${index}:${other}`;
348
+ keys.set(known[index], key);
349
+ keys.set(native[other], key);
350
+ }
351
+ return (turn) => keys.get(turn);
352
+ };
353
+
354
+ // ../pstdio-api-contracts/src/history-reconciliation.ts
355
+ class HistoryConflict extends Error {
356
+ }
357
+ var submittedPrompt = (message) => message.parts.filter((part) => part.type === "text").map((part) => part.text).join(`
358
+ `).replace(/\n\n<session-attachments>[\s\S]*<\/session-attachments>\s*$/, "").trim();
359
+ var historyValueKey = (value) => JSON.stringify(value, (_key, item) => {
360
+ if (!item || typeof item !== "object" || Array.isArray(item))
361
+ return item;
362
+ return Object.fromEntries(Object.entries(item).sort(([a], [b]) => a.localeCompare(b)));
363
+ });
364
+ var historyMessageKey = (message) => historyValueKey([message.role, message.parts]);
365
+ var positions = (items, key) => {
366
+ const result = new Map;
367
+ items.forEach((item, index) => {
368
+ const value = key(item);
369
+ const indices = result.get(value) ?? [];
370
+ indices.push(index);
371
+ result.set(value, indices);
372
+ });
373
+ return result;
374
+ };
375
+ var mergeOrderedHistory = (known, native, key, merge, refineKey) => {
376
+ if (!known.length)
377
+ return native;
378
+ if (!native.length)
379
+ return known;
380
+ const knownPositions = positions(known, key);
381
+ const nativePositions = positions(native, key);
382
+ const anchors = [];
383
+ for (const [value, indices] of knownPositions) {
384
+ const other = nativePositions.get(value);
385
+ if (indices.length === 1 && other?.length === 1)
386
+ anchors.push([indices[0], other[0]]);
387
+ }
388
+ if (!anchors.length) {
389
+ if (refineKey) {
390
+ const refined = mergeOrderedHistory(known, native, refineKey(known, native), merge);
391
+ return refined;
392
+ }
393
+ if (known.length === native.length && known.every((item, index) => key(item) === key(native[index]))) {
394
+ return known.map((item, index) => merge(item, native[index]));
395
+ }
396
+ throw new HistoryConflict("ambiguous_interval");
397
+ }
398
+ let left = 0;
399
+ let right = 0;
400
+ const result = [];
401
+ for (const [a, b] of anchors) {
402
+ if (b < right)
403
+ throw new HistoryConflict("conflicting_order");
404
+ result.push(...mergeOrderedHistory(known.slice(left, a), native.slice(right, b), key, merge, refineKey));
405
+ result.push(merge(known[a], native[b]));
406
+ left = a + 1;
407
+ right = b + 1;
408
+ }
409
+ result.push(...mergeOrderedHistory(known.slice(left), native.slice(right), key, merge, refineKey));
410
+ return result;
411
+ };
412
+ var splitHistoryTurns = (messages) => {
413
+ const turns = [];
414
+ for (const message of messages) {
415
+ if (message.role === "user" || !turns.length)
416
+ turns.push([]);
417
+ turns[turns.length - 1].push(message);
418
+ }
419
+ return turns;
420
+ };
421
+ var mergeHistoryMetadata = (known, native) => {
422
+ const files = native.parts.filter((part) => part.type === "file");
423
+ const fileKeys = new Set(files.map((part) => part.fileId ?? part.url));
424
+ const missing = known.parts.filter((part) => part.type === "file" && !fileKeys.has(part.fileId ?? part.url));
425
+ const parts = native.role === "user" ? [...known.parts.filter((part) => part.type === "text"), ...native.parts.filter((part) => part.type !== "text")] : native.parts;
426
+ return { ...known, ...native, parts: [...parts, ...missing] };
427
+ };
428
+ var isUsage = (message) => message.role === "system" && message.parts.length > 0 && message.parts.every((part) => part.type === "token_usage");
429
+ var combineTextRuns = (messages) => {
430
+ const runs = [];
431
+ for (const message of messages) {
432
+ const previous = runs.at(-1);
433
+ const part = message.parts[0];
434
+ const previousPart = previous?.parts[0];
435
+ if (previous && message.role === previous.role && message.parts.length === 1 && previous.parts.length === 1 && (part.type === "text" || part.type === "reasoning") && previousPart?.type === part.type) {
436
+ runs[runs.length - 1] = { ...previous, parts: [{ ...part, text: previousPart.text + part.text }] };
437
+ } else
438
+ runs.push(message);
439
+ }
440
+ return runs;
441
+ };
442
+ var reconcileMessageHistory = (input, projection = {}) => {
443
+ const key = projection.key ?? historyMessageKey;
444
+ const merge = projection.merge ?? mergeHistoryMetadata;
445
+ const generated = projection.isGenerated ?? isUsage;
446
+ const mergeTurn = (known, native) => {
447
+ const startsWithUser = known[0]?.role === "user" && native[0]?.role === "user";
448
+ const body = (turn) => combineTextRuns(turn.slice(startsWithUser ? 1 : 0).filter((message) => !generated(message)));
449
+ const messages = mergeOrderedHistory(body(known), body(native), key, merge);
450
+ const metadata = [...native.filter(generated)];
451
+ const counts = new Map;
452
+ metadata.forEach((message) => {
453
+ counts.set(historyMessageKey(message), (counts.get(historyMessageKey(message)) ?? 0) + 1);
454
+ });
455
+ for (const message of known.filter(generated)) {
456
+ const value = historyMessageKey(message);
457
+ const remaining = counts.get(value) ?? 0;
458
+ if (remaining)
459
+ counts.set(value, remaining - 1);
460
+ else
461
+ metadata.push(message);
462
+ }
463
+ return [...startsWithUser ? [mergeHistoryMetadata(known[0], native[0])] : [], ...messages, ...metadata];
464
+ };
465
+ try {
466
+ const prompt = (turn) => turn[0]?.role === "user" ? `user:${submittedPrompt(turn[0])}` : "prefix";
467
+ const turns = mergeOrderedHistory(splitHistoryTurns(input.knownMessages), splitHistoryTurns(input.nativeMessages), prompt, mergeTurn, (known, native) => historyTurnEvidence(known, native, prompt, (turn) => combineTextRuns(turn.slice(1).filter((message) => !generated(message))).map(key)));
468
+ const messages = turns.flat().map((message, index) => message.index === undefined ? message : { ...message, index });
469
+ return { kind: "recovered", messages };
470
+ } catch (error) {
471
+ if (error instanceof HistoryConflict)
472
+ return { kind: "conflict", category: error.message };
473
+ throw error;
474
+ }
475
+ };
202
476
  // package.json
203
- var version = "0.24.1";
477
+ var version = "0.35.0";
204
478
 
205
479
  // src/version.ts
206
480
  var SDK_VERSION = version;
@@ -640,7 +914,8 @@ var createWebviewClient = (host, options) => {
640
914
  const runCommand = async (commandKey, params) => {
641
915
  const response = await host.call("commands.execute", {
642
916
  commandId: `${extensionId}.command.${commandKey}`,
643
- params
917
+ params,
918
+ ...options?.workspaceId ? { workspaceId: options.workspaceId } : {}
644
919
  });
645
920
  return unwrapCommandOutcome(response);
646
921
  };
@@ -684,6 +959,7 @@ export {
684
959
  ALWAYS_AVAILABLE_WEBVIEW_CAPABILITIES,
685
960
  EXTENSION_API_VERSION,
686
961
  EXTENSION_EVENTS_SCOPE,
962
+ HistoryConflict,
687
963
  SDK_VERSION,
688
964
  WEBVIEW_DECLARABLE_CAPABILITIES,
689
965
  WEBVIEW_HOST_CAPABILITIES,
@@ -732,13 +1008,18 @@ export {
732
1008
  eventRef,
733
1009
  extensionPanelRegions,
734
1010
  gitEvents,
1011
+ historyMessageKey,
1012
+ historyValueKey,
735
1013
  isLocalizedString,
1014
+ isNavigationTarget,
736
1015
  isValidLocalContributionId,
737
1016
  isWorkbenchProjectUrl,
738
1017
  l10n,
739
1018
  localContributionIdGrammar,
740
1019
  localContributionIdPattern,
741
1020
  matchesResourceWhen,
1021
+ mergeHistoryMetadata,
1022
+ mergeOrderedHistory,
742
1023
  packageAsset,
743
1024
  params,
744
1025
  parsePageUrl,
@@ -746,7 +1027,9 @@ export {
746
1027
  projectEvents,
747
1028
  projectPrefix,
748
1029
  projectSlots,
1030
+ qualifyNavigationTarget,
749
1031
  qualifyRef,
1032
+ reconcileMessageHistory,
750
1033
  resolveEventReferenceId,
751
1034
  resourceKey,
752
1035
  resourceMenuSlotRef2 as resourceMenuSlotRef,
@@ -754,7 +1037,10 @@ export {
754
1037
  serializeWorkbenchPageUrl,
755
1038
  sessionEvents,
756
1039
  sessionSlots,
1040
+ splitHistoryTurns,
1041
+ submittedPrompt,
757
1042
  unwrapCommandOutcome,
1043
+ viewDataEvents,
758
1044
  workbenchModeDefinitions,
759
1045
  workbenchModes,
760
1046
  workbenchPageDefinitions,
@@ -1,23 +1,18 @@
1
- import { QueryKey } from '@tanstack/react-query';
2
- import { UseMutationResult } from '@tanstack/react-query';
3
- import { UseQueryResult } from '@tanstack/react-query';
4
-
5
- declare interface CommandMutationInput<TParams, TResult> {
6
- command: (params: TParams) => Promise<TResult>;
7
- invalidate?: QueryKey[];
8
- }
9
-
10
- declare interface CommandQueryInput<TResult> {
11
- queryKey: QueryKey;
12
- command: () => Promise<TResult>;
13
- enabled?: boolean;
14
- staleTime?: number;
15
- }
16
-
17
- /** Writes server state via a typed client command and refreshes affected queries on success. */
18
- export declare const useCommandMutation: <TParams, TResult>(input: CommandMutationInput<TParams, TResult>) => UseMutationResult<TResult, Error, TParams, unknown>;
19
-
20
- /** Reads server state via a typed client command, cached and deduped by react-query. */
21
- export declare const useCommandQuery: <TResult>(input: CommandQueryInput<TResult>) => UseQueryResult<TResult>;
22
-
23
- export { }
1
+ import { QueryKey, UseQueryResult } from "@tanstack/react-query";
2
+ //#region src/extensions/react/index.d.ts
3
+ interface CommandQueryInput<TResult> {
4
+ queryKey: QueryKey;
5
+ command: () => Promise<TResult>;
6
+ enabled?: boolean;
7
+ staleTime?: number;
8
+ }
9
+ /** Reads server state via a typed client command, cached and deduped by react-query. */
10
+ export declare const useCommandQuery: <TResult>(input: CommandQueryInput<TResult>) => UseQueryResult<TResult>;
11
+ interface CommandMutationInput<TParams, TResult> {
12
+ command: (params: TParams) => Promise<TResult>;
13
+ invalidate?: QueryKey[];
14
+ }
15
+ /** Writes server state via a typed client command and refreshes affected queries on success. */
16
+ export declare const useCommandMutation: <TParams, TResult>(input: CommandMutationInput<TParams, TResult>) => import("@tanstack/react-query").UseMutationResult<TResult, Error, TParams, unknown>;
17
+ //#endregion
18
+ export {};