@pstdio/pocketcoder-sdk 0.5.0 → 0.6.1

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 (3) hide show
  1. package/dist/index.d.ts +575 -218
  2. package/dist/index.js +592 -380
  3. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1,6 +1,221 @@
1
1
  import { z } from "zod";
2
2
  import { isIP } from "node:net";
3
- //#region ../contracts/src/pagination.ts
3
+ //#region ../contracts/src/attachments/attachment.ts
4
+ const ATTACHMENT_MAX_FILE_BYTES = 26214400;
5
+ const ATTACHMENT_CHUNK_BYTES = 524288;
6
+ const AttachmentMediaTypeSchema = z.string().regex(/^[\w.+-]+\/[\w.+-]+$/).max(255);
7
+ const AttachmentDescriptorSchema = z.object({
8
+ id: z.uuid(),
9
+ name: z.string().min(1).max(255),
10
+ path: z.string().min(1),
11
+ media_type: AttachmentMediaTypeSchema,
12
+ size_bytes: z.number().int().min(0).max(ATTACHMENT_MAX_FILE_BYTES),
13
+ sha256: z.string().regex(/^[0-9a-f]{64}$/)
14
+ });
15
+ z.looseObject({
16
+ type: z.literal("user"),
17
+ content: z.string(),
18
+ attachment_ids: z.array(z.uuid()).min(1).max(10).refine((ids) => new Set(ids).size === ids.length, "attachment_ids must be unique").optional()
19
+ });
20
+ const MANIFEST_OPEN = "<pocketcoder-attachments>";
21
+ const MANIFEST_CLOSE = "</pocketcoder-attachments>";
22
+ function splitAttachmentManifest(content) {
23
+ const open = content.lastIndexOf(MANIFEST_OPEN);
24
+ if (open < 0 || !content.trimEnd().endsWith(MANIFEST_CLOSE)) return {
25
+ text: content,
26
+ attachments: null
27
+ };
28
+ const close = content.lastIndexOf(MANIFEST_CLOSE);
29
+ const parsed = z.array(AttachmentDescriptorSchema).safeParse(safeJson(content.slice(open + 25, close)));
30
+ if (!parsed.success) return {
31
+ text: content,
32
+ attachments: null
33
+ };
34
+ return {
35
+ text: content.slice(0, open).trimEnd(),
36
+ attachments: parsed.data
37
+ };
38
+ }
39
+ function safeJson(value) {
40
+ try {
41
+ return JSON.parse(value);
42
+ } catch {
43
+ return;
44
+ }
45
+ }
46
+ const AttachmentStartPayload = z.object({
47
+ operation_id: z.uuid(),
48
+ attachment_id: z.uuid(),
49
+ name: z.string().min(1).max(255),
50
+ media_type: AttachmentMediaTypeSchema,
51
+ size_bytes: z.number().int().min(0).max(ATTACHMENT_MAX_FILE_BYTES)
52
+ });
53
+ const AttachmentChunkPayload = z.object({
54
+ operation_id: z.uuid(),
55
+ seq: z.number().int().nonnegative(),
56
+ content_b64: z.string().max(Math.ceil(ATTACHMENT_CHUNK_BYTES / 3) * 4 + 4)
57
+ });
58
+ const AttachmentFinishPayload = z.object({ operation_id: z.uuid() });
59
+ const AttachmentAbortPayload = z.object({
60
+ operation_id: z.uuid(),
61
+ reason: z.string().max(512)
62
+ });
63
+ const AttachmentResolvePayload = z.object({
64
+ operation_id: z.uuid(),
65
+ attachment_ids: z.array(z.uuid()).min(1).max(10)
66
+ });
67
+ const AttachmentAckPayload = z.object({
68
+ operation_id: z.uuid(),
69
+ seq: z.number().int().nonnegative(),
70
+ received_bytes: z.number().int().nonnegative()
71
+ });
72
+ const AttachmentResultPayload = z.object({
73
+ operation_id: z.uuid(),
74
+ status: z.enum([
75
+ "created",
76
+ "existing",
77
+ "conflict",
78
+ "failed"
79
+ ]),
80
+ descriptor: AttachmentDescriptorSchema.optional(),
81
+ failure_code: z.enum([
82
+ "invalid",
83
+ "too_large",
84
+ "sequence",
85
+ "io",
86
+ "interrupted"
87
+ ]).optional(),
88
+ detail: z.string().max(512).optional()
89
+ });
90
+ const AttachmentResolvedPayload = z.object({
91
+ operation_id: z.uuid(),
92
+ descriptors: z.array(AttachmentDescriptorSchema).optional(),
93
+ missing_id: z.uuid().optional()
94
+ });
95
+ //#endregion
96
+ //#region ../contracts/src/common/scopes.ts
97
+ const SCOPES = [
98
+ "templates:read",
99
+ "workspaces:create",
100
+ "workspaces:read",
101
+ "workspaces:cancel",
102
+ "workspaces:purge",
103
+ "workspaces:recover",
104
+ "keys:read",
105
+ "keys:write",
106
+ "workspaces:preserve",
107
+ "workspaces:restore",
108
+ "checkpoints:read",
109
+ "checkpoints:delete",
110
+ "outputs:read",
111
+ "conversations:read",
112
+ "conversations:write",
113
+ "conversations:delete",
114
+ "services:relay",
115
+ "attachments:write",
116
+ "logs:read",
117
+ "network:read",
118
+ "terminal:attach",
119
+ "terminal:read",
120
+ "admin"
121
+ ];
122
+ z.strictObject({
123
+ request_id: z.string().min(1).max(128).regex(/^[A-Za-z0-9._:-]+$/),
124
+ scopes: z.array(z.enum(SCOPES)).min(1).max(SCOPES.length),
125
+ expires_at: z.iso.datetime()
126
+ });
127
+ const KeyResourceSchema = z.object({
128
+ id: z.uuid(),
129
+ principal_id: z.uuid(),
130
+ scopes: z.array(z.string()),
131
+ effective_scopes: z.array(z.string()),
132
+ managed_principal_ids: z.array(z.uuid()),
133
+ issuance_request_id: z.string().nullable(),
134
+ created_at: z.iso.datetime(),
135
+ expires_at: z.iso.datetime().nullable(),
136
+ revoked_at: z.iso.datetime().nullable(),
137
+ last_used_at: z.iso.datetime().nullable()
138
+ });
139
+ const KeyIssueResponseSchema = z.object({
140
+ key: KeyResourceSchema,
141
+ token: z.string().nullable()
142
+ });
143
+ const KeyListResponseSchema = z.object({
144
+ items: z.array(KeyResourceSchema),
145
+ next_cursor: z.uuid().nullable()
146
+ });
147
+ //#endregion
148
+ //#region ../contracts/src/common/duration.ts
149
+ const DURATION_RE = /^(\d+)(ms|s|m|h)$/;
150
+ function isDuration(value) {
151
+ return DURATION_RE.test(value);
152
+ }
153
+ //#endregion
154
+ //#region ../contracts/src/common/errors.ts
155
+ const ERROR_CODES = {
156
+ "auth.invalid_key": 401,
157
+ "auth.missing_scope": 403,
158
+ "auth.disabled_principal": 403,
159
+ "principal.not_found": 404,
160
+ "key.not_found": 404,
161
+ "validation.invalid": 400,
162
+ "idempotency.conflict": 409,
163
+ "capacity.queue_full": 429,
164
+ "capacity.waiters_full": 429,
165
+ "template.not_found": 404,
166
+ "template.version_not_found": 404,
167
+ "template.not_authorized": 403,
168
+ "workspace.not_found": 404,
169
+ "workspace.external_id_conflict": 409,
170
+ "workspace.not_ready": 409,
171
+ "workspace.terminal": 410,
172
+ "workspace.disconnected": 503,
173
+ "terminal.not_declared": 422,
174
+ "terminal.session_limit": 409,
175
+ "terminal.session_not_found": 404,
176
+ "terminal.session_closed": 409,
177
+ "terminal.protocol_unsupported": 426,
178
+ "workspace.persistence_not_enabled": 409,
179
+ "workspace.preserving": 409,
180
+ "checkpoint.not_found": 404,
181
+ "checkpoint.not_ready": 409,
182
+ "checkpoint.none_ready": 409,
183
+ "checkpoint.corrupt": 409,
184
+ "checkpoint.quota_exceeded": 413,
185
+ "checkpoint.in_use": 409,
186
+ "restore.template_not_authorized": 403,
187
+ "restore.image_unavailable": 409,
188
+ "restore.incompatible": 409,
189
+ "resume.unsupported": 409,
190
+ "conversation.expired": 410,
191
+ "conversation.deleted": 410,
192
+ "operation.conflict": 409,
193
+ "source.not_allowed": 422,
194
+ "source.invalid_revision": 422,
195
+ "secret.unavailable": 503,
196
+ "storage.capacity_exhausted": 507,
197
+ "relay.body_too_large": 413,
198
+ "relay.route_not_allowed": 422,
199
+ "relay.streaming_unsupported": 409,
200
+ "relay.deadline_exceeded": 504,
201
+ "relay.upstream_error": 502,
202
+ "attachment.invalid": 400,
203
+ "attachment.too_large": 413,
204
+ "attachment.not_found": 404,
205
+ "attachment.conflict": 409,
206
+ "attachment.unsupported": 409,
207
+ "attachment.interrupted": 503,
208
+ "internal.error": 500
209
+ };
210
+ const errorCodes = Object.keys(ERROR_CODES);
211
+ const ErrorEnvelopeSchema = z.object({ error: z.object({
212
+ code: z.enum(errorCodes),
213
+ message: z.string().min(1),
214
+ request_id: z.string().min(1),
215
+ details: z.record(z.string(), z.unknown()).optional()
216
+ }) });
217
+ //#endregion
218
+ //#region ../contracts/src/common/pagination.ts
4
219
  const CursorSchema = z.string().min(1).max(2048);
5
220
  function CursorPageSchema(item) {
6
221
  return z.object({
@@ -15,7 +230,74 @@ function CursorQuerySchema(maxLimit, defaultLimit) {
15
230
  });
16
231
  }
17
232
  //#endregion
18
- //#region ../contracts/src/conversation.ts
233
+ //#region ../contracts/src/conversations/facts.ts
234
+ const ConversationFactSchema = z.discriminatedUnion("type", [
235
+ z.object({ type: z.literal("intermediate") }),
236
+ z.object({ type: z.literal("final_response") }),
237
+ z.object({ type: z.literal("tool_only") }),
238
+ z.object({
239
+ type: z.literal("activity_started"),
240
+ activity_id: z.uuid(),
241
+ kind: z.enum([
242
+ "tool",
243
+ "attachment",
244
+ "workspace",
245
+ "retrieval"
246
+ ]),
247
+ label: z.string().min(1).max(160),
248
+ started_at: z.iso.datetime().nullable()
249
+ }),
250
+ z.object({
251
+ type: z.literal("activity_finished"),
252
+ activity_id: z.uuid(),
253
+ ended_at: z.iso.datetime().nullable(),
254
+ outcome: z.enum([
255
+ "completed",
256
+ "failed",
257
+ "interrupted",
258
+ "canceled"
259
+ ])
260
+ }),
261
+ z.object({
262
+ type: z.literal("turn_terminal"),
263
+ outcome: z.enum([
264
+ "completed",
265
+ "failed",
266
+ "interrupted",
267
+ "canceled",
268
+ "lost"
269
+ ])
270
+ })
271
+ ]);
272
+ //#endregion
273
+ //#region ../contracts/src/conversations/identity.ts
274
+ const ConversationRequestIdentitySchema = z.object({
275
+ schema: z.literal("pocketcoder.conversation/v2"),
276
+ authority: z.enum(["external", "generic"]),
277
+ conversation_id: z.uuid(),
278
+ request_id: z.uuid(),
279
+ turn_id: z.uuid(),
280
+ request_fingerprint: z.string().regex(/^[0-9a-f]{64}$/)
281
+ });
282
+ const ConversationRequestReceiptSchema = z.object({
283
+ kind: z.enum(["accepted", "replayed"]),
284
+ identity: ConversationRequestIdentitySchema,
285
+ accepted_at: z.iso.datetime()
286
+ });
287
+ const ConversationMessageIdentitySchema = ConversationRequestIdentitySchema.extend({
288
+ event_id: z.uuid(),
289
+ message_id: z.string().min(1).max(256),
290
+ sequence: z.number().int().nonnegative(),
291
+ revision: z.number().int().positive(),
292
+ fact: ConversationFactSchema.optional()
293
+ });
294
+ const ConversationProtocolSupportSchema = z.object({
295
+ schema: z.literal("pocketcoder.conversation/v2"),
296
+ request_identity_authorities: z.array(z.enum(["external", "generic"])),
297
+ producer_capabilities: z.null()
298
+ });
299
+ //#endregion
300
+ //#region ../contracts/src/conversations/conversation.ts
19
301
  const CONVERSATION_ROLES = [
20
302
  "user",
21
303
  "assistant",
@@ -28,14 +310,21 @@ const ConversationMessageInputSchema = z.object({
28
310
  role: z.enum(CONVERSATION_ROLES),
29
311
  content: z.string().max(262144),
30
312
  occurred_at: z.iso.datetime(),
31
- metadata: ConversationMetadataSchema.default({})
313
+ metadata: ConversationMetadataSchema.default({}),
314
+ identity: ConversationMessageIdentitySchema.nullable().optional()
315
+ });
316
+ const ConversationMessageResourceSchema = ConversationMessageInputSchema.extend({
317
+ seq: z.number().int().positive(),
318
+ identity: ConversationMessageIdentitySchema.nullable().default(null)
32
319
  });
33
- const ConversationMessageResourceSchema = ConversationMessageInputSchema.extend({ seq: z.number().int().positive() });
34
320
  CursorQuerySchema(200, 100);
35
- const ConversationPageSchema = CursorPageSchema(ConversationMessageResourceSchema).extend({ retention: z.object({
36
- status: z.literal("retained"),
37
- expires_at: z.iso.datetime().nullable()
38
- }) });
321
+ const ConversationPageSchema = CursorPageSchema(ConversationMessageResourceSchema).extend({
322
+ protocol: ConversationProtocolSupportSchema.nullable().default(null),
323
+ retention: z.object({
324
+ status: z.literal("retained"),
325
+ expires_at: z.iso.datetime().nullable()
326
+ })
327
+ });
39
328
  const ConversationResumeOutcomeSchema = z.object({
40
329
  status: z.literal("supported"),
41
330
  reason: z.null(),
@@ -43,13 +332,61 @@ const ConversationResumeOutcomeSchema = z.object({
43
332
  checkpoint_id: z.uuid()
44
333
  });
45
334
  //#endregion
46
- //#region ../contracts/src/duration.ts
47
- const DURATION_RE = /^(\d+)(ms|s|m|h)$/;
48
- function isDuration(value) {
49
- return DURATION_RE.test(value);
335
+ //#region ../contracts/src/network/network.ts
336
+ const DOMAIN_LABEL = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
337
+ function isDomain(value) {
338
+ const domain = value.startsWith("*.") ? value.slice(2) : value;
339
+ return domain.length <= 253 && !domain.endsWith(".") && isIP(domain) === 0 && domain.split(".").length >= 2 && domain.split(".").every((label) => DOMAIN_LABEL.test(label));
50
340
  }
341
+ const NetworkRuleSchema = z.object({
342
+ domain: z.string().refine(isDomain, "expected a lowercase ASCII domain or leading *. wildcard"),
343
+ ports: z.array(z.number().int().min(1).max(65535)).min(1).max(32).default([80, 443]),
344
+ allowPrivate: z.boolean().default(false)
345
+ }).superRefine((rule, ctx) => {
346
+ if (new Set(rule.ports).size !== rule.ports.length) ctx.addIssue({
347
+ code: "custom",
348
+ path: ["ports"],
349
+ message: "ports must be unique"
350
+ });
351
+ });
352
+ const UnrestrictedNetworkPolicySchema = z.object({ mode: z.literal("unrestricted") });
353
+ const RestrictedNetworkPolicySchema = z.object({
354
+ mode: z.literal("restricted"),
355
+ allow: z.array(NetworkRuleSchema).max(256).default([])
356
+ });
357
+ const NetworkPolicySchema = z.preprocess((value) => value ?? { mode: "unrestricted" }, z.discriminatedUnion("mode", [UnrestrictedNetworkPolicySchema, RestrictedNetworkPolicySchema]));
358
+ const NETWORK_STATES = [
359
+ "disabled",
360
+ "starting",
361
+ "ready",
362
+ "degraded"
363
+ ];
364
+ const NetworkEventInputSchema = z.object({
365
+ source_seq: z.number().int().positive(),
366
+ occurred_at: z.iso.datetime(),
367
+ decision: z.enum(["allow", "deny"]),
368
+ transport: z.enum(["http", "https"]),
369
+ host: z.string().min(1).max(253),
370
+ port: z.number().int().min(1).max(65535),
371
+ method: z.string().max(32).nullable().default(null),
372
+ path: z.string().max(2048).refine((path) => !path.includes("?") && !path.includes("#"), "path cannot contain query or fragment").nullable().default(null),
373
+ matched_rule: z.string().max(512).nullable().default(null),
374
+ reason: z.string().min(1).max(128)
375
+ });
376
+ z.object({
377
+ source_session_id: z.uuid(),
378
+ events: z.array(NetworkEventInputSchema).min(1).max(100)
379
+ });
380
+ const NetworkEventSchema = NetworkEventInputSchema.omit({ source_seq: true }).extend({
381
+ seq: z.number().int().positive(),
382
+ workspace_id: z.uuid(),
383
+ source_session_id: z.uuid(),
384
+ source_seq: z.number().int().positive()
385
+ });
386
+ CursorQuerySchema(200, 100);
387
+ const NetworkEventPageSchema = CursorPageSchema(NetworkEventSchema);
51
388
  //#endregion
52
- //#region ../contracts/src/persistence.ts
389
+ //#region ../contracts/src/persistence/persistence.ts
53
390
  const DurationValueSchema = z.string().refine(isDuration, { message: "expected a duration like 15s, 20m, or 2h" });
54
391
  const LAUNCH_MODES = ["create", "restore"];
55
392
  const CONVERSATION_RESTORE_CAPABILITIES = [
@@ -117,7 +454,8 @@ const OPERATION_KINDS = [
117
454
  "preserve",
118
455
  "restore",
119
456
  "verify",
120
- "delete"
457
+ "delete",
458
+ "purge"
121
459
  ];
122
460
  const OPERATION_STATES = [
123
461
  "pending",
@@ -194,61 +532,7 @@ z.object({
194
532
  file_count: z.number().int().nonnegative()
195
533
  });
196
534
  //#endregion
197
- //#region ../contracts/src/network.ts
198
- const DOMAIN_LABEL = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
199
- function isDomain(value) {
200
- const domain = value.startsWith("*.") ? value.slice(2) : value;
201
- return domain.length <= 253 && !domain.endsWith(".") && isIP(domain) === 0 && domain.split(".").length >= 2 && domain.split(".").every((label) => DOMAIN_LABEL.test(label));
202
- }
203
- const NetworkRuleSchema = z.object({
204
- domain: z.string().refine(isDomain, "expected a lowercase ASCII domain or leading *. wildcard"),
205
- ports: z.array(z.number().int().min(1).max(65535)).min(1).max(32).default([80, 443]),
206
- allowPrivate: z.boolean().default(false)
207
- }).superRefine((rule, ctx) => {
208
- if (new Set(rule.ports).size !== rule.ports.length) ctx.addIssue({
209
- code: "custom",
210
- path: ["ports"],
211
- message: "ports must be unique"
212
- });
213
- });
214
- const UnrestrictedNetworkPolicySchema = z.object({ mode: z.literal("unrestricted") });
215
- const RestrictedNetworkPolicySchema = z.object({
216
- mode: z.literal("restricted"),
217
- allow: z.array(NetworkRuleSchema).max(256).default([])
218
- });
219
- const NetworkPolicySchema = z.preprocess((value) => value ?? { mode: "unrestricted" }, z.discriminatedUnion("mode", [UnrestrictedNetworkPolicySchema, RestrictedNetworkPolicySchema]));
220
- const NETWORK_STATES = [
221
- "disabled",
222
- "starting",
223
- "ready",
224
- "degraded"
225
- ];
226
- const NetworkEventInputSchema = z.object({
227
- source_seq: z.number().int().positive(),
228
- occurred_at: z.iso.datetime(),
229
- decision: z.enum(["allow", "deny"]),
230
- transport: z.enum(["http", "https"]),
231
- host: z.string().min(1).max(253),
232
- port: z.number().int().min(1).max(65535),
233
- method: z.string().max(32).nullable().default(null),
234
- path: z.string().max(2048).refine((path) => !path.includes("?") && !path.includes("#"), "path cannot contain query or fragment").nullable().default(null),
235
- matched_rule: z.string().max(512).nullable().default(null),
236
- reason: z.string().min(1).max(128)
237
- });
238
- z.object({
239
- source_session_id: z.uuid(),
240
- events: z.array(NetworkEventInputSchema).min(1).max(100)
241
- });
242
- const NetworkEventSchema = NetworkEventInputSchema.omit({ source_seq: true }).extend({
243
- seq: z.number().int().positive(),
244
- workspace_id: z.uuid(),
245
- source_session_id: z.uuid(),
246
- source_seq: z.number().int().positive()
247
- });
248
- CursorQuerySchema(200, 100);
249
- const NetworkEventPageSchema = CursorPageSchema(NetworkEventSchema);
250
- //#endregion
251
- //#region ../contracts/src/workspace.ts
535
+ //#region ../contracts/src/workspaces/workspace.ts
252
536
  const WORKSPACE_STATES = [
253
537
  "queued",
254
538
  "provisioning",
@@ -377,7 +661,7 @@ z.object({
377
661
  cursor: z.string().optional()
378
662
  });
379
663
  //#endregion
380
- //#region ../contracts/src/api.ts
664
+ //#region ../contracts/src/protocol/api.ts
381
665
  const TemplatePageSchema = CursorPageSchema(z.object({
382
666
  name: z.string(),
383
667
  version: z.string(),
@@ -438,161 +722,6 @@ const StoragePruneResultSchema = z.object({
438
722
  skipped: z.number().int().nonnegative(),
439
723
  transcripts_deleted: z.number().int().nonnegative()
440
724
  });
441
- //#endregion
442
- //#region ../contracts/src/attachment.ts
443
- const ATTACHMENT_MAX_FILE_BYTES = 26214400;
444
- const ATTACHMENT_CHUNK_BYTES = 524288;
445
- const AttachmentMediaTypeSchema = z.string().regex(/^[\w.+-]+\/[\w.+-]+$/).max(255);
446
- const AttachmentDescriptorSchema = z.object({
447
- id: z.uuid(),
448
- name: z.string().min(1).max(255),
449
- path: z.string().min(1),
450
- media_type: AttachmentMediaTypeSchema,
451
- size_bytes: z.number().int().min(0).max(ATTACHMENT_MAX_FILE_BYTES),
452
- sha256: z.string().regex(/^[0-9a-f]{64}$/)
453
- });
454
- z.looseObject({
455
- type: z.literal("user"),
456
- content: z.string(),
457
- attachment_ids: z.array(z.uuid()).min(1).max(10).refine((ids) => new Set(ids).size === ids.length, "attachment_ids must be unique").optional()
458
- });
459
- const MANIFEST_OPEN = "<pocketcoder-attachments>";
460
- const MANIFEST_CLOSE = "</pocketcoder-attachments>";
461
- function splitAttachmentManifest(content) {
462
- const open = content.lastIndexOf(MANIFEST_OPEN);
463
- if (open < 0 || !content.trimEnd().endsWith(MANIFEST_CLOSE)) return {
464
- text: content,
465
- attachments: null
466
- };
467
- const close = content.lastIndexOf(MANIFEST_CLOSE);
468
- const parsed = z.array(AttachmentDescriptorSchema).safeParse(safeJson(content.slice(open + 25, close)));
469
- if (!parsed.success) return {
470
- text: content,
471
- attachments: null
472
- };
473
- return {
474
- text: content.slice(0, open).trimEnd(),
475
- attachments: parsed.data
476
- };
477
- }
478
- function safeJson(value) {
479
- try {
480
- return JSON.parse(value);
481
- } catch {
482
- return;
483
- }
484
- }
485
- const AttachmentStartPayload = z.object({
486
- operation_id: z.uuid(),
487
- attachment_id: z.uuid(),
488
- name: z.string().min(1).max(255),
489
- media_type: AttachmentMediaTypeSchema,
490
- size_bytes: z.number().int().min(0).max(ATTACHMENT_MAX_FILE_BYTES)
491
- });
492
- const AttachmentChunkPayload = z.object({
493
- operation_id: z.uuid(),
494
- seq: z.number().int().nonnegative(),
495
- content_b64: z.string().max(Math.ceil(ATTACHMENT_CHUNK_BYTES / 3) * 4 + 4)
496
- });
497
- const AttachmentFinishPayload = z.object({ operation_id: z.uuid() });
498
- const AttachmentAbortPayload = z.object({
499
- operation_id: z.uuid(),
500
- reason: z.string().max(512)
501
- });
502
- const AttachmentResolvePayload = z.object({
503
- operation_id: z.uuid(),
504
- attachment_ids: z.array(z.uuid()).min(1).max(10)
505
- });
506
- const AttachmentAckPayload = z.object({
507
- operation_id: z.uuid(),
508
- seq: z.number().int().nonnegative(),
509
- received_bytes: z.number().int().nonnegative()
510
- });
511
- const AttachmentResultPayload = z.object({
512
- operation_id: z.uuid(),
513
- status: z.enum([
514
- "created",
515
- "existing",
516
- "conflict",
517
- "failed"
518
- ]),
519
- descriptor: AttachmentDescriptorSchema.optional(),
520
- failure_code: z.enum([
521
- "invalid",
522
- "too_large",
523
- "sequence",
524
- "io",
525
- "interrupted"
526
- ]).optional(),
527
- detail: z.string().max(512).optional()
528
- });
529
- const AttachmentResolvedPayload = z.object({
530
- operation_id: z.uuid(),
531
- descriptors: z.array(AttachmentDescriptorSchema).optional(),
532
- missing_id: z.uuid().optional()
533
- });
534
- //#endregion
535
- //#region ../contracts/src/errors.ts
536
- const ERROR_CODES = {
537
- "auth.invalid_key": 401,
538
- "auth.missing_scope": 403,
539
- "auth.disabled_principal": 403,
540
- "validation.invalid": 400,
541
- "idempotency.conflict": 409,
542
- "capacity.queue_full": 429,
543
- "capacity.waiters_full": 429,
544
- "template.not_found": 404,
545
- "template.version_not_found": 404,
546
- "template.not_authorized": 403,
547
- "workspace.not_found": 404,
548
- "workspace.external_id_conflict": 409,
549
- "workspace.not_ready": 409,
550
- "workspace.terminal": 410,
551
- "workspace.disconnected": 503,
552
- "terminal.not_declared": 422,
553
- "terminal.session_limit": 409,
554
- "terminal.session_not_found": 404,
555
- "terminal.session_closed": 409,
556
- "terminal.protocol_unsupported": 426,
557
- "workspace.persistence_not_enabled": 409,
558
- "workspace.preserving": 409,
559
- "checkpoint.not_found": 404,
560
- "checkpoint.not_ready": 409,
561
- "checkpoint.none_ready": 409,
562
- "checkpoint.corrupt": 409,
563
- "checkpoint.quota_exceeded": 413,
564
- "checkpoint.in_use": 409,
565
- "restore.template_not_authorized": 403,
566
- "restore.image_unavailable": 409,
567
- "restore.incompatible": 409,
568
- "resume.unsupported": 409,
569
- "conversation.expired": 410,
570
- "conversation.deleted": 410,
571
- "operation.conflict": 409,
572
- "source.not_allowed": 422,
573
- "source.invalid_revision": 422,
574
- "secret.unavailable": 503,
575
- "storage.capacity_exhausted": 507,
576
- "relay.body_too_large": 413,
577
- "relay.route_not_allowed": 422,
578
- "relay.streaming_unsupported": 409,
579
- "relay.deadline_exceeded": 504,
580
- "relay.upstream_error": 502,
581
- "attachment.invalid": 400,
582
- "attachment.too_large": 413,
583
- "attachment.not_found": 404,
584
- "attachment.conflict": 409,
585
- "attachment.unsupported": 409,
586
- "attachment.interrupted": 503,
587
- "internal.error": 500
588
- };
589
- const errorCodes = Object.keys(ERROR_CODES);
590
- const ErrorEnvelopeSchema = z.object({ error: z.object({
591
- code: z.enum(errorCodes),
592
- message: z.string().min(1),
593
- request_id: z.string().min(1),
594
- details: z.record(z.string(), z.unknown()).optional()
595
- }) });
596
725
  WORKSPACE_STATES.map((s) => `workspace.${s}`);
597
726
  z.object({
598
727
  id: z.uuid(),
@@ -624,7 +753,7 @@ z.object({
624
753
  })
625
754
  });
626
755
  //#endregion
627
- //#region ../contracts/src/logs.ts
756
+ //#region ../contracts/src/protocol/logs.ts
628
757
  const LogChunkSchema = z.object({
629
758
  seq: z.number().int().positive(),
630
759
  stream: z.string(),
@@ -634,47 +763,14 @@ const LogChunkSchema = z.object({
634
763
  CursorQuerySchema(1e3, 200);
635
764
  const LogPageSchema = CursorPageSchema(LogChunkSchema);
636
765
  //#endregion
637
- //#region ../contracts/src/protocol-stream.ts
638
- const ProxyStreamStartPayload = z.object({
639
- request_id: z.uuid(),
640
- status: z.number().int().min(100).max(599),
641
- headers: z.record(z.string(), z.string())
642
- });
643
- const ProxyStreamChunkPayload = z.object({
644
- request_id: z.uuid(),
645
- seq: z.number().int().nonnegative(),
646
- content_b64: z.string().max(87400)
647
- });
648
- const ProxyStreamEndPayload = z.object({
649
- request_id: z.uuid(),
650
- error_code: z.enum([
651
- "unreachable",
652
- "deadline",
653
- "too_large"
654
- ]).optional()
655
- });
656
- const ProxyStreamAckPayload = z.object({
657
- request_id: z.uuid(),
658
- seq: z.number().int().nonnegative()
659
- });
660
- const ProxyStreamCancelPayload = z.object({
661
- request_id: z.uuid(),
662
- reason: z.enum([
663
- "downstream_closed",
664
- "deadline",
665
- "too_large",
666
- "workspace_disconnected"
667
- ])
668
- });
669
- //#endregion
670
- //#region ../contracts/src/template-constants.ts
766
+ //#region ../contracts/src/templates/template-constants.ts
671
767
  function isAbsolutePath(value) {
672
768
  return value.startsWith("/") && ![...value].some((character) => character.codePointAt(0) === 0);
673
769
  }
674
770
  const SECRET_ENV_PATTERN = /(SECRET|TOKEN|PASSWORD|PASSWD|API_?KEY|PRIVATE_?KEY|CREDENTIAL)/i;
675
771
  const SECRET_REFERENCE_PREFIX = "secretRef:";
676
772
  //#endregion
677
- //#region ../contracts/src/template-schema.ts
773
+ //#region ../contracts/src/templates/template-schema.ts
678
774
  const NAME_RE = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/;
679
775
  const SEMVER_RE = /^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/;
680
776
  const IMAGE_DIGEST_RE = /^[^\s@]+@sha256:[0-9a-f]{64}$/;
@@ -864,7 +960,7 @@ const TemplateManifestBaseSchema = z.object({
864
960
  spec: TemplateSpecSchema
865
961
  });
866
962
  //#endregion
867
- //#region ../contracts/src/template-runtime.ts
963
+ //#region ../contracts/src/templates/template-runtime.ts
868
964
  const LEGACY_AGENTAPI_SERVICE = ServiceSchema.parse({
869
965
  baseUrl: "http://127.0.0.1:3284",
870
966
  routes: [
@@ -920,7 +1016,7 @@ function templateServices(spec) {
920
1016
  return isAgentApiNative(spec) ? { agent: AGENTAPI_SERVICE } : spec.services;
921
1017
  }
922
1018
  //#endregion
923
- //#region ../contracts/src/template-validation.ts
1019
+ //#region ../contracts/src/templates/template-validation.ts
924
1020
  function envSources(spec) {
925
1021
  const sources = [[["spec", "env"], spec.env], [isAgentApiNative(spec) ? [
926
1022
  "spec",
@@ -1259,12 +1355,14 @@ TemplateManifestBaseSchema.superRefine((manifest, ctx) => {
1259
1355
  validateTemplateSpec(manifest.spec, ctx);
1260
1356
  });
1261
1357
  //#endregion
1262
- //#region ../contracts/src/terminal.ts
1358
+ //#region ../contracts/src/terminals/terminal.ts
1263
1359
  const TERMINAL_CHUNK_BYTES = 32768;
1264
1360
  const TERMINAL_REPLAY_BUFFER_BYTES = 65536;
1265
1361
  function base64Schema(maxBytes) {
1266
1362
  return z.string().regex(/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/).refine((value) => {
1267
- const padding = value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0;
1363
+ let padding = 0;
1364
+ if (value.endsWith("==")) padding = 2;
1365
+ else if (value.endsWith("=")) padding = 1;
1268
1366
  return value.length / 4 * 3 - padding <= maxBytes;
1269
1367
  }, `decoded payload must not exceed ${maxBytes} bytes`);
1270
1368
  }
@@ -1368,8 +1466,41 @@ const TerminalSessionSchema = z.object({
1368
1466
  bytes_in: z.number().int().nonnegative(),
1369
1467
  bytes_out: z.number().int().nonnegative()
1370
1468
  });
1371
- CursorQuerySchema(200, 50);
1372
- const TerminalSessionPageSchema = CursorPageSchema(TerminalSessionSchema);
1469
+ CursorQuerySchema(200, 50);
1470
+ const TerminalSessionPageSchema = CursorPageSchema(TerminalSessionSchema);
1471
+ //#endregion
1472
+ //#region ../contracts/src/protocol/protocol-stream.ts
1473
+ const ProxyStreamStartPayload = z.object({
1474
+ request_id: z.uuid(),
1475
+ status: z.number().int().min(100).max(599),
1476
+ headers: z.record(z.string(), z.string())
1477
+ });
1478
+ const ProxyStreamChunkPayload = z.object({
1479
+ request_id: z.uuid(),
1480
+ seq: z.number().int().nonnegative(),
1481
+ content_b64: z.string().max(87400)
1482
+ });
1483
+ const ProxyStreamEndPayload = z.object({
1484
+ request_id: z.uuid(),
1485
+ error_code: z.enum([
1486
+ "unreachable",
1487
+ "deadline",
1488
+ "too_large"
1489
+ ]).optional()
1490
+ });
1491
+ const ProxyStreamAckPayload = z.object({
1492
+ request_id: z.uuid(),
1493
+ seq: z.number().int().nonnegative()
1494
+ });
1495
+ const ProxyStreamCancelPayload = z.object({
1496
+ request_id: z.uuid(),
1497
+ reason: z.enum([
1498
+ "downstream_closed",
1499
+ "deadline",
1500
+ "too_large",
1501
+ "workspace_disconnected"
1502
+ ])
1503
+ });
1373
1504
  const ProviderInputSchema = z.object({
1374
1505
  workspace_id: z.uuid(),
1375
1506
  server_url: z.string(),
@@ -1779,7 +1910,7 @@ z.discriminatedUnion("type", [
1779
1910
  })
1780
1911
  ]);
1781
1912
  //#endregion
1782
- //#region src/admin.ts
1913
+ //#region src/resources/admin/admin.ts
1783
1914
  var AdministrationApi = class {
1784
1915
  transport;
1785
1916
  constructor(transport) {
@@ -1799,7 +1930,7 @@ var AdministrationApi = class {
1799
1930
  }
1800
1931
  };
1801
1932
  //#endregion
1802
- //#region src/errors.ts
1933
+ //#region src/transport/errors.ts
1803
1934
  z.enum(["client.non_json_response", "client.invalid_response"]);
1804
1935
  var PocketCoderError = class extends Error {
1805
1936
  code;
@@ -1856,7 +1987,7 @@ function responseError(response, body) {
1856
1987
  });
1857
1988
  }
1858
1989
  //#endregion
1859
- //#region src/attachments.ts
1990
+ //#region src/resources/attachments/attachments.ts
1860
1991
  const DEFAULT_READY_TIMEOUT_MS = 12e4;
1861
1992
  function contentDisposition(name) {
1862
1993
  const clean = name.replace(/[\r\n]/g, "");
@@ -1929,7 +2060,7 @@ var AgentApi = class {
1929
2060
  }
1930
2061
  };
1931
2062
  //#endregion
1932
- //#region src/common.ts
2063
+ //#region src/transport/common.ts
1933
2064
  function queryString(values) {
1934
2065
  const params = new URLSearchParams();
1935
2066
  for (const [key, value] of Object.entries(values)) if (value !== void 0) params.set(key, String(value));
@@ -1942,7 +2073,7 @@ function page(body) {
1942
2073
  };
1943
2074
  }
1944
2075
  //#endregion
1945
- //#region src/checkpoints.ts
2076
+ //#region src/resources/checkpoints/checkpoints.ts
1946
2077
  var CheckpointsApi = class {
1947
2078
  transport;
1948
2079
  constructor(transport) {
@@ -1990,21 +2121,33 @@ var OperationsApi = class {
1990
2121
  }
1991
2122
  };
1992
2123
  //#endregion
1993
- //#region src/conversations.ts
2124
+ //#region src/resources/conversations/conversations.ts
1994
2125
  var ConversationsApi = class {
1995
2126
  transport;
1996
2127
  constructor(transport) {
1997
2128
  this.transport = transport;
1998
2129
  }
1999
2130
  async list(id, query = {}, options = {}) {
2000
- return page(await this.transport.request(`/v1/workspaces/${encodeURIComponent(id)}/conversation?${queryString({
2131
+ const body = await this.transport.request(`/v1/workspaces/${encodeURIComponent(id)}/conversation?${queryString({
2001
2132
  cursor: query.cursor,
2002
2133
  limit: query.limit ?? 100
2003
- })}`, ConversationPageSchema, options));
2134
+ })}`, ConversationPageSchema, options);
2135
+ return {
2136
+ ...page(body),
2137
+ protocol: body.protocol,
2138
+ retention: body.retention
2139
+ };
2140
+ }
2141
+ async acceptRequest(id, identity, options = {}) {
2142
+ return this.transport.request(`/v1/workspaces/${encodeURIComponent(id)}/conversation/requests`, ConversationRequestReceiptSchema, {
2143
+ ...options,
2144
+ method: "POST",
2145
+ body: JSON.stringify(identity)
2146
+ });
2004
2147
  }
2005
2148
  };
2006
2149
  //#endregion
2007
- //#region src/diagnostics.ts
2150
+ //#region src/resources/diagnostics/diagnostics.ts
2008
2151
  var WorkspaceCursorApi = class {
2009
2152
  transport;
2010
2153
  resource;
@@ -2037,7 +2180,69 @@ var OutputsApi = class extends WorkspaceCursorApi {
2037
2180
  }
2038
2181
  };
2039
2182
  //#endregion
2040
- //#region src/templates.ts
2183
+ //#region src/resources/keys/keys.ts
2184
+ var KeysApi = class {
2185
+ transport;
2186
+ constructor(transport) {
2187
+ this.transport = transport;
2188
+ }
2189
+ list(principalId, query = {}, options = {}) {
2190
+ return this.transport.request(`/v1/principals/${encodeURIComponent(principalId)}/keys?${queryString({
2191
+ limit: query.limit,
2192
+ cursor: query.cursor,
2193
+ request_id: query.requestId
2194
+ })}`, KeyListResponseSchema, options);
2195
+ }
2196
+ async *all(principalId, query = {}, options = {}) {
2197
+ let cursor;
2198
+ do {
2199
+ const page = await this.list(principalId, {
2200
+ ...query,
2201
+ cursor
2202
+ }, options);
2203
+ yield* page.items;
2204
+ cursor = page.next_cursor ?? void 0;
2205
+ } while (cursor);
2206
+ }
2207
+ issue(principalId, input, options = {}) {
2208
+ return this.transport.request(`/v1/principals/${encodeURIComponent(principalId)}/keys`, KeyIssueResponseSchema, {
2209
+ method: "POST",
2210
+ body: JSON.stringify(input),
2211
+ signal: options.signal
2212
+ });
2213
+ }
2214
+ revoke(principalId, keyId, options = {}) {
2215
+ return this.transport.request(`/v1/principals/${encodeURIComponent(principalId)}/keys/${encodeURIComponent(keyId)}`, z.object({ revoked: z.literal(true) }), {
2216
+ method: "DELETE",
2217
+ signal: options.signal
2218
+ });
2219
+ }
2220
+ revokeAll(principalId, options = {}) {
2221
+ return this.transport.request(`/v1/principals/${encodeURIComponent(principalId)}/keys`, z.object({ revoked: z.literal(true) }), {
2222
+ method: "DELETE",
2223
+ signal: options.signal
2224
+ });
2225
+ }
2226
+ };
2227
+ var RecoveryApi = class {
2228
+ transport;
2229
+ constructor(transport) {
2230
+ this.transport = transport;
2231
+ }
2232
+ purge(principalId, workspaceId, executionKey, options = {}) {
2233
+ return this.transport.request(`/v1/principals/${encodeURIComponent(principalId)}/workspaces/${encodeURIComponent(workspaceId)}/purge`, OperationResourceSchema, {
2234
+ method: "POST",
2235
+ headers: { "Idempotency-Key": executionKey },
2236
+ body: "{}",
2237
+ signal: options.signal
2238
+ });
2239
+ }
2240
+ operation(principalId, operationId, options = {}) {
2241
+ return this.transport.request(`/v1/principals/${encodeURIComponent(principalId)}/operations/${encodeURIComponent(operationId)}`, OperationResourceSchema, options);
2242
+ }
2243
+ };
2244
+ //#endregion
2245
+ //#region src/resources/templates/templates.ts
2041
2246
  var TemplatesApi = class {
2042
2247
  transport;
2043
2248
  constructor(transport) {
@@ -2054,7 +2259,7 @@ var TemplatesApi = class {
2054
2259
  }
2055
2260
  };
2056
2261
  //#endregion
2057
- //#region src/terminals.ts
2262
+ //#region src/resources/terminals/terminals.ts
2058
2263
  var TerminalConnection = class {
2059
2264
  socket;
2060
2265
  messageListeners = /* @__PURE__ */ new Set();
@@ -2156,7 +2361,109 @@ var TerminalsApi = class {
2156
2361
  }
2157
2362
  };
2158
2363
  //#endregion
2159
- //#region src/transport.ts
2364
+ //#region src/resources/workspaces/workspaces.ts
2365
+ const TERMINAL_WORKSPACE_STATES = new Set(TERMINAL_STATES);
2366
+ var WorkspacesApi = class {
2367
+ transport;
2368
+ constructor(transport) {
2369
+ this.transport = transport;
2370
+ }
2371
+ async list(query = {}, options = {}) {
2372
+ return page(await this.transport.request(`/v1/workspaces?${queryString({
2373
+ state: query.state,
2374
+ template: query.template,
2375
+ external_id: query.externalId,
2376
+ limit: query.limit ?? 50,
2377
+ cursor: query.cursor
2378
+ })}`, WorkspacePageSchema, options));
2379
+ }
2380
+ async *all(query = {}, options = {}) {
2381
+ let cursor;
2382
+ do {
2383
+ const current = await this.list({
2384
+ ...query,
2385
+ cursor
2386
+ }, options);
2387
+ for (const workspace of current.items) yield workspace;
2388
+ cursor = current.nextCursor ?? void 0;
2389
+ } while (cursor);
2390
+ }
2391
+ get(id, options = {}) {
2392
+ return this.transport.request(`/v1/workspaces/${encodeURIComponent(id)}`, WorkspaceResourceSchema, options);
2393
+ }
2394
+ create(input, options = {}) {
2395
+ const body = {
2396
+ external_id: input.externalId,
2397
+ template: {
2398
+ name: input.templateName,
2399
+ ...input.templateVersion ? { version: input.templateVersion } : {}
2400
+ },
2401
+ ...input.launchInput ? { launch_input: input.launchInput } : {},
2402
+ ...input.metadata ? { metadata: input.metadata } : {},
2403
+ ...input.source ? { source: input.source } : {}
2404
+ };
2405
+ return this.transport.request("/v1/workspaces", WorkspaceResourceSchema, {
2406
+ method: "POST",
2407
+ signal: options.signal,
2408
+ headers: { "Idempotency-Key": input.idempotencyKey ?? input.externalId },
2409
+ body: JSON.stringify(body)
2410
+ });
2411
+ }
2412
+ cancel(id, options = {}) {
2413
+ return this.transport.request(`/v1/workspaces/${encodeURIComponent(id)}/cancel`, WorkspaceResourceSchema, {
2414
+ method: "POST",
2415
+ signal: options.signal
2416
+ });
2417
+ }
2418
+ change(id, after, wait, options = {}) {
2419
+ return this.transport.request(`/v1/workspaces/${encodeURIComponent(id)}/changes?after=${after}&wait=${wait}`, WorkspaceChangeSchema, options);
2420
+ }
2421
+ async waitForReady(initial, timeoutMs, options = {}) {
2422
+ const deadline = Date.now() + timeoutMs;
2423
+ let workspace = initial;
2424
+ while (workspace.state !== "ready") {
2425
+ if (TERMINAL_STATES.includes(workspace.state)) throw new WorkspaceTerminalError(workspace);
2426
+ const remainingMs = deadline - Date.now();
2427
+ if (remainingMs <= 0) throw new Error(`workspace ${workspace.id} did not become ready within ${timeoutMs}ms`);
2428
+ workspace = (await this.change(workspace.id, workspace.change_cursor, Math.max(1, Math.min(30, Math.ceil(remainingMs / 1e3))), options)).workspace;
2429
+ options.onTick?.(workspace);
2430
+ }
2431
+ return workspace;
2432
+ }
2433
+ async waitForAgentInput(id, timeoutMs, options = {}) {
2434
+ const deadline = Date.now() + timeoutMs;
2435
+ let workspace = await this.get(id, options);
2436
+ while (workspace.agent_state !== "stable") {
2437
+ if (TERMINAL_STATES.includes(workspace.state)) throw new WorkspaceTerminalError(workspace);
2438
+ const remainingMs = deadline - Date.now();
2439
+ if (remainingMs <= 0) throw new AgentNotReadyError(workspace.id, workspace.agent_state, timeoutMs);
2440
+ workspace = (await this.change(workspace.id, workspace.change_cursor, Math.max(1, Math.min(30, Math.ceil(remainingMs / 1e3))), options)).workspace;
2441
+ }
2442
+ return workspace;
2443
+ }
2444
+ preserve(id, input, key, options = {}) {
2445
+ return this.jsonOperation(`/v1/workspaces/${encodeURIComponent(id)}/preserve`, input, key, PreserveResponseSchema, options);
2446
+ }
2447
+ purge(id, key, options = {}) {
2448
+ return this.jsonOperation(`/v1/workspaces/${encodeURIComponent(id)}/purge`, {}, key, OperationResourceSchema, options);
2449
+ }
2450
+ recreate(id, input, key, options = {}) {
2451
+ return this.jsonOperation(`/v1/workspaces/${encodeURIComponent(id)}/recreate`, input, key, RestoreResponseSchema, options);
2452
+ }
2453
+ resume(id, input, key, options = {}) {
2454
+ return this.jsonOperation(`/v1/workspaces/${encodeURIComponent(id)}/resume`, input, key, ResumeResponseSchema, options);
2455
+ }
2456
+ jsonOperation(path, input, key, schema, options) {
2457
+ return this.transport.request(path, schema, {
2458
+ method: "POST",
2459
+ signal: options.signal,
2460
+ headers: { "Idempotency-Key": key },
2461
+ body: JSON.stringify(input)
2462
+ });
2463
+ }
2464
+ };
2465
+ //#endregion
2466
+ //#region src/transport/transport.ts
2160
2467
  function baseUrlOf(value) {
2161
2468
  let url;
2162
2469
  try {
@@ -2273,105 +2580,6 @@ async function delay(milliseconds, signal) {
2273
2580
  });
2274
2581
  }
2275
2582
  //#endregion
2276
- //#region src/workspaces.ts
2277
- const TERMINAL_WORKSPACE_STATES = new Set(TERMINAL_STATES);
2278
- var WorkspacesApi = class {
2279
- transport;
2280
- constructor(transport) {
2281
- this.transport = transport;
2282
- }
2283
- async list(query = {}, options = {}) {
2284
- return page(await this.transport.request(`/v1/workspaces?${queryString({
2285
- state: query.state,
2286
- template: query.template,
2287
- external_id: query.externalId,
2288
- limit: query.limit ?? 50,
2289
- cursor: query.cursor
2290
- })}`, WorkspacePageSchema, options));
2291
- }
2292
- async *all(query = {}, options = {}) {
2293
- let cursor;
2294
- do {
2295
- const current = await this.list({
2296
- ...query,
2297
- cursor
2298
- }, options);
2299
- for (const workspace of current.items) yield workspace;
2300
- cursor = current.nextCursor ?? void 0;
2301
- } while (cursor);
2302
- }
2303
- get(id, options = {}) {
2304
- return this.transport.request(`/v1/workspaces/${encodeURIComponent(id)}`, WorkspaceResourceSchema, options);
2305
- }
2306
- create(input, options = {}) {
2307
- const body = {
2308
- external_id: input.externalId,
2309
- template: {
2310
- name: input.templateName,
2311
- ...input.templateVersion ? { version: input.templateVersion } : {}
2312
- },
2313
- ...input.launchInput ? { launch_input: input.launchInput } : {},
2314
- ...input.metadata ? { metadata: input.metadata } : {},
2315
- ...input.source ? { source: input.source } : {}
2316
- };
2317
- return this.transport.request("/v1/workspaces", WorkspaceResourceSchema, {
2318
- method: "POST",
2319
- signal: options.signal,
2320
- headers: { "Idempotency-Key": input.idempotencyKey ?? input.externalId },
2321
- body: JSON.stringify(body)
2322
- });
2323
- }
2324
- cancel(id, options = {}) {
2325
- return this.transport.request(`/v1/workspaces/${encodeURIComponent(id)}/cancel`, WorkspaceResourceSchema, {
2326
- method: "POST",
2327
- signal: options.signal
2328
- });
2329
- }
2330
- change(id, after, wait, options = {}) {
2331
- return this.transport.request(`/v1/workspaces/${encodeURIComponent(id)}/changes?after=${after}&wait=${wait}`, WorkspaceChangeSchema, options);
2332
- }
2333
- async waitForReady(initial, timeoutMs, options = {}) {
2334
- const deadline = Date.now() + timeoutMs;
2335
- let workspace = initial;
2336
- while (workspace.state !== "ready") {
2337
- if (TERMINAL_STATES.includes(workspace.state)) throw new WorkspaceTerminalError(workspace);
2338
- const remainingMs = deadline - Date.now();
2339
- if (remainingMs <= 0) throw new Error(`workspace ${workspace.id} did not become ready within ${timeoutMs}ms`);
2340
- workspace = (await this.change(workspace.id, workspace.change_cursor, Math.max(1, Math.min(30, Math.ceil(remainingMs / 1e3))), options)).workspace;
2341
- options.onTick?.(workspace);
2342
- }
2343
- return workspace;
2344
- }
2345
- async waitForAgentInput(id, timeoutMs, options = {}) {
2346
- const deadline = Date.now() + timeoutMs;
2347
- let workspace = await this.get(id, options);
2348
- while (workspace.agent_state !== "stable") {
2349
- if (TERMINAL_STATES.includes(workspace.state)) throw new WorkspaceTerminalError(workspace);
2350
- const remainingMs = deadline - Date.now();
2351
- if (remainingMs <= 0) throw new AgentNotReadyError(workspace.id, workspace.agent_state, timeoutMs);
2352
- workspace = (await this.change(workspace.id, workspace.change_cursor, Math.max(1, Math.min(30, Math.ceil(remainingMs / 1e3))), options)).workspace;
2353
- }
2354
- return workspace;
2355
- }
2356
- preserve(id, input, key, options = {}) {
2357
- return this.jsonOperation(`/v1/workspaces/${encodeURIComponent(id)}/preserve`, input, key, PreserveResponseSchema, options);
2358
- }
2359
- recreate(id, input, key, options = {}) {
2360
- return this.jsonOperation(`/v1/workspaces/${encodeURIComponent(id)}/recreate`, input, key, RestoreResponseSchema, options);
2361
- }
2362
- resume(id, input, key, options = {}) {
2363
- return this.jsonOperation(`/v1/workspaces/${encodeURIComponent(id)}/resume`, input, key, ResumeResponseSchema, options);
2364
- }
2365
- jsonOperation(path, input, key, schema, options) {
2366
- return this.transport.request(path, schema, {
2367
- method: "POST",
2368
- signal: options.signal,
2369
- headers: { "Idempotency-Key": key },
2370
- body: JSON.stringify(input)
2371
- });
2372
- }
2373
- };
2374
- //#endregion
2375
2583
  //#region src/client.ts
2376
2584
  var PocketCoderClient = class {
2377
2585
  transport;
@@ -2387,6 +2595,8 @@ var PocketCoderClient = class {
2387
2595
  outputs;
2388
2596
  administration;
2389
2597
  terminals;
2598
+ keys;
2599
+ recovery;
2390
2600
  constructor(config, fetchImpl = fetch) {
2391
2601
  this.transport = new PocketCoderTransport(config, fetchImpl);
2392
2602
  this.templates = new TemplatesApi(this.transport);
@@ -2401,13 +2611,15 @@ var PocketCoderClient = class {
2401
2611
  this.outputs = new OutputsApi(this.transport);
2402
2612
  this.administration = new AdministrationApi(this.transport);
2403
2613
  this.terminals = new TerminalsApi(this.transport);
2614
+ this.keys = new KeysApi(this.transport);
2615
+ this.recovery = new RecoveryApi(this.transport);
2404
2616
  }
2405
2617
  raw(path, init = {}) {
2406
2618
  return this.transport.raw(path, init);
2407
2619
  }
2408
2620
  };
2409
2621
  //#endregion
2410
- //#region src/workspace-turn-resolver.ts
2622
+ //#region src/resources/workspaces/workspace-turn-resolver.ts
2411
2623
  const ERROR_MESSAGES = {
2412
2624
  not_resumable: "workspace cannot be resumed",
2413
2625
  resume_handler_missing: "workspace resume handler is not configured",
@@ -2551,4 +2763,4 @@ var WorkspaceTurnResolver = class {
2551
2763
  }
2552
2764
  };
2553
2765
  //#endregion
2554
- export { AdministrationApi, AgentApi, AgentNotReadyError, AttachmentsApi, CheckpointsApi, ConversationGoneError, ConversationsApi, LogsApi, NetworkEventsApi, OperationsApi, OutputsApi, PocketCoderClient, PocketCoderError, TERMINAL_WORKSPACE_STATES, TemplatesApi, TerminalConnection, TerminalsApi, WorkspaceTerminalError, WorkspaceTurnResolutionError, WorkspaceTurnResolver, WorkspacesApi, isPocketCoderErrorCode, splitAttachmentManifest };
2766
+ export { AdministrationApi, AgentApi, AgentNotReadyError, AttachmentsApi, CheckpointsApi, ConversationGoneError, ConversationsApi, KeysApi, LogsApi, NetworkEventsApi, OperationsApi, OutputsApi, PocketCoderClient, PocketCoderError, RecoveryApi, TERMINAL_WORKSPACE_STATES, TemplatesApi, TerminalConnection, TerminalsApi, WorkspaceTerminalError, WorkspaceTurnResolutionError, WorkspaceTurnResolver, WorkspacesApi, isPocketCoderErrorCode, splitAttachmentManifest };