@pstdio/pocketcoder-sdk 0.3.1 → 0.5.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/README.md CHANGED
@@ -42,3 +42,57 @@ metadata-only terminal audit history.
42
42
  Use `client.raw(path, init)` for endpoints not yet represented by a typed
43
43
  resource client. API failures throw `PocketCoderError`; expired or deleted
44
44
  conversation history throws the more specific `ConversationGoneError`.
45
+
46
+ ## Resolve one user turn after preservation
47
+
48
+ Create one long-lived `WorkspaceTurnResolver` in a trusted backend. Call it
49
+ only when handling a user turn. A ready workspace is returned unchanged. A
50
+ preserved workspace is resumed through your callback, checked against the
51
+ source checkpoint, and returned only after it becomes ready.
52
+
53
+ ```ts
54
+ import {
55
+ PocketCoderClient,
56
+ WorkspaceTurnResolver,
57
+ } from "@pstdio/pocketcoder-sdk";
58
+
59
+ const client = new PocketCoderClient({
60
+ baseUrl: process.env.POCKETCODER_URL!,
61
+ apiKey: process.env.POCKETCODER_KEY!,
62
+ });
63
+
64
+ const resolver = new WorkspaceTurnResolver({
65
+ client,
66
+ resumeWorkspace: async ({ source, attemptId, signal }) => {
67
+ // Mint fresh workspace-scoped input. It must expire with the new workspace.
68
+ const launchInput = await issueWorkspaceBootstrap({ signal });
69
+ const result = await client.workspaces.resume(
70
+ source.id,
71
+ {
72
+ external_id: `turn-${attemptId}`,
73
+ launch_input: launchInput,
74
+ },
75
+ attemptId,
76
+ { signal },
77
+ );
78
+ return result.workspace;
79
+ },
80
+ });
81
+
82
+ export async function handleTurn(sourceWorkspaceId: string, prompt: string) {
83
+ const { workspace } = await resolver.resolve(sourceWorkspaceId);
84
+ await client.agent.sendMessage(workspace.id, { content: prompt });
85
+ return { workspace_id: workspace.id };
86
+ }
87
+ ```
88
+
89
+ The key needs `workspaces:read`; a callback that calls `resume()` also needs
90
+ `workspaces:restore`. Prompt relay and attachments need `services:relay` and
91
+ `attachments:write` respectively.
92
+
93
+ The resolver stores no A-to-B mapping. Return the resolved id through your
94
+ normal request or session state if a later request needs it. Canceling one
95
+ caller stops that caller's wait. It does not roll back a resume request already
96
+ accepted by the server, and another caller may join the same in-memory attempt.
97
+ Lifecycle failures use fixed messages and never expose callback errors or
98
+ launch input.
package/dist/index.d.ts CHANGED
@@ -98,6 +98,8 @@ type ErrorCode = keyof typeof ERROR_CODES;
98
98
  //#region ../contracts/src/workspace.d.ts
99
99
  declare const WORKSPACE_STATES: readonly ["queued", "provisioning", "connected", "ready", "preserving", "terminating", "succeeded", "failed", "canceled", "expired", "preserved"];
100
100
  type WorkspaceState = (typeof WORKSPACE_STATES)[number];
101
+ declare const AGENT_STATES: readonly ["unknown", "running", "stable"];
102
+ type AgentState = (typeof AGENT_STATES)[number];
101
103
  declare const WorkspaceCreateRequestSchema: z.ZodObject<{
102
104
  external_id: z.ZodString;
103
105
  template: z.ZodObject<{
@@ -483,33 +485,6 @@ declare class AdministrationApi {
483
485
  }>;
484
486
  }
485
487
  //#endregion
486
- //#region src/attachments.d.ts
487
- type UploadBody = NonNullable<RequestInit["body"]>;
488
- interface AttachmentUploadInput {
489
- id?: string;
490
- name: string;
491
- mediaType?: string;
492
- body: UploadBody;
493
- sizeBytes: number;
494
- signal?: AbortSignal;
495
- onProgress?: (uploadedBytes: number, totalBytes: number) => void;
496
- }
497
- interface AgentMessageInput {
498
- content: string;
499
- attachmentIds?: string[];
500
- signal?: AbortSignal;
501
- }
502
- declare class AttachmentsApi {
503
- private readonly transport;
504
- constructor(transport: PocketCoderTransport);
505
- upload(workspaceId: string, input: AttachmentUploadInput): Promise<AttachmentDescriptor>;
506
- }
507
- declare class AgentApi {
508
- private readonly transport;
509
- constructor(transport: PocketCoderTransport);
510
- sendMessage(workspaceId: string, input: AgentMessageInput): Promise<void>;
511
- }
512
- //#endregion
513
488
  //#region src/common.d.ts
514
489
  interface Page<T> {
515
490
  items: T[];
@@ -520,256 +495,6 @@ interface CursorListQuery {
520
495
  cursor?: string;
521
496
  }
522
497
  //#endregion
523
- //#region src/checkpoints.d.ts
524
- declare class CheckpointsApi {
525
- private readonly transport;
526
- constructor(transport: PocketCoderTransport);
527
- list(workspaceId: string, query?: CursorListQuery & {
528
- state?: CheckpointState;
529
- }, options?: RequestOptions): Promise<Page<{
530
- id: string;
531
- workspace_id: string;
532
- state: "deleted" | "creating" | "ready" | "failed" | "deleting";
533
- reason_code: string | null;
534
- template: {
535
- name: string;
536
- version: string;
537
- digest: string;
538
- };
539
- manifest_digest: string | null;
540
- logical_bytes: number | null;
541
- stored_bytes: number | null;
542
- file_count: number | null;
543
- mounts: string[];
544
- conversation_restore: "unknown" | "supported" | "filesystem_only";
545
- label: string | null;
546
- created_at: string;
547
- ready_at: string | null;
548
- expires_at: string | null;
549
- }>>;
550
- get(id: string, options?: RequestOptions): Promise<{
551
- id: string;
552
- workspace_id: string;
553
- state: "deleted" | "creating" | "ready" | "failed" | "deleting";
554
- reason_code: string | null;
555
- template: {
556
- name: string;
557
- version: string;
558
- digest: string;
559
- };
560
- manifest_digest: string | null;
561
- logical_bytes: number | null;
562
- stored_bytes: number | null;
563
- file_count: number | null;
564
- mounts: string[];
565
- conversation_restore: "unknown" | "supported" | "filesystem_only";
566
- label: string | null;
567
- created_at: string;
568
- ready_at: string | null;
569
- expires_at: string | null;
570
- }>;
571
- verify(id: string, key: string, options?: RequestOptions): Promise<{
572
- id: string;
573
- kind: "preserve" | "restore" | "verify" | "delete";
574
- state: "failed" | "pending" | "running" | "succeeded";
575
- workspace_id: string | null;
576
- checkpoint_id: string | null;
577
- result_workspace_id: string | null;
578
- reason_code: string | null;
579
- created_at: string;
580
- updated_at: string;
581
- completed_at: string | null;
582
- }>;
583
- delete(id: string, key: string, options?: RequestOptions): Promise<{
584
- id: string;
585
- kind: "preserve" | "restore" | "verify" | "delete";
586
- state: "failed" | "pending" | "running" | "succeeded";
587
- workspace_id: string | null;
588
- checkpoint_id: string | null;
589
- result_workspace_id: string | null;
590
- reason_code: string | null;
591
- created_at: string;
592
- updated_at: string;
593
- completed_at: string | null;
594
- }>;
595
- restore(id: string, input: RestoreRequest, key: string, options?: RequestOptions): Promise<{
596
- workspace: {
597
- id: string;
598
- external_id: string;
599
- template: {
600
- name: string;
601
- version: string;
602
- digest: string;
603
- };
604
- state: "ready" | "failed" | "succeeded" | "queued" | "provisioning" | "connected" | "preserving" | "terminating" | "canceled" | "expired" | "preserved";
605
- reason_code: "child_exit_success" | "child_exit_failure" | "setup_failed" | "bootstrap_failed" | "registration_timeout" | "health_failed" | "child_crash" | "provider_lost" | "disconnect_timeout" | "canceled_by_caller" | "deadline_expired" | "idle_expired" | "queue_timeout" | "launch_failed" | "preserve_requested" | "preserved_by_policy" | "checkpoint_created" | "checkpoint_failed" | "checkpoint_corrupt" | "checkpoint_quota_exceeded" | "checkpoint_storage_lost" | "restore_requested" | "restore_failed" | "image_unavailable" | "source_resolution_failed" | "secret_resolution_failed" | "operation_conflict" | "network_policy_failed" | null;
606
- agent_state: "unknown" | "running" | "stable";
607
- change_cursor: number;
608
- provider_kind: string | null;
609
- provisioning_mode: "cold" | "warm" | null;
610
- network: {
611
- state: "ready" | "disabled" | "starting" | "degraded";
612
- };
613
- health: Record<string, string>;
614
- created_at: string;
615
- updated_at: string;
616
- connected_at: string | null;
617
- ready_at: string | null;
618
- deadline_at: string;
619
- terminal_at: string | null;
620
- metadata: Record<string, string>;
621
- origin_workspace_id: string | null;
622
- restored_from_checkpoint_id: string | null;
623
- source: {
624
- kind: "git";
625
- repository: string;
626
- requested_revision: string;
627
- resolved_commit: string | null;
628
- } | null;
629
- persistence: {
630
- enabled: boolean;
631
- conversation_restore: "unknown" | "supported" | "filesystem_only";
632
- conversation_resume: {
633
- status: "unknown" | "supported" | "unsupported";
634
- reason: "filesystem_only" | "capability_unknown" | null;
635
- };
636
- latest_checkpoint_id: string | null;
637
- };
638
- outputs: Record<string, unknown>;
639
- failure: {
640
- reason_code: "child_exit_success" | "child_exit_failure" | "setup_failed" | "bootstrap_failed" | "registration_timeout" | "health_failed" | "child_crash" | "provider_lost" | "disconnect_timeout" | "canceled_by_caller" | "deadline_expired" | "idle_expired" | "queue_timeout" | "launch_failed" | "preserve_requested" | "preserved_by_policy" | "checkpoint_created" | "checkpoint_failed" | "checkpoint_corrupt" | "checkpoint_quota_exceeded" | "checkpoint_storage_lost" | "restore_requested" | "restore_failed" | "image_unavailable" | "source_resolution_failed" | "secret_resolution_failed" | "operation_conflict" | "network_policy_failed";
641
- log_tail: string;
642
- log_tail_truncated: boolean;
643
- last_log_seq: number | null;
644
- } | null;
645
- };
646
- operation: {
647
- id: string;
648
- kind: "preserve" | "restore" | "verify" | "delete";
649
- state: "failed" | "pending" | "running" | "succeeded";
650
- workspace_id: string | null;
651
- checkpoint_id: string | null;
652
- result_workspace_id: string | null;
653
- reason_code: string | null;
654
- created_at: string;
655
- updated_at: string;
656
- completed_at: string | null;
657
- };
658
- }>;
659
- private operationRequest;
660
- }
661
- declare class OperationsApi {
662
- private readonly transport;
663
- constructor(transport: PocketCoderTransport);
664
- get(id: string, options?: RequestOptions): Promise<{
665
- id: string;
666
- kind: "preserve" | "restore" | "verify" | "delete";
667
- state: "failed" | "pending" | "running" | "succeeded";
668
- workspace_id: string | null;
669
- checkpoint_id: string | null;
670
- result_workspace_id: string | null;
671
- reason_code: string | null;
672
- created_at: string;
673
- updated_at: string;
674
- completed_at: string | null;
675
- }>;
676
- }
677
- //#endregion
678
- //#region src/conversations.d.ts
679
- type ConversationMessage = ConversationMessageResource;
680
- type ConversationPage = Page<ConversationMessageResource>;
681
- declare class ConversationsApi {
682
- private readonly transport;
683
- constructor(transport: PocketCoderTransport);
684
- list(id: string, query?: CursorListQuery, options?: RequestOptions): Promise<Page<{
685
- message_id: string;
686
- role: "user" | "assistant" | "system" | "tool";
687
- content: string;
688
- occurred_at: string;
689
- metadata: Record<string, string>;
690
- seq: number;
691
- }>>;
692
- }
693
- //#endregion
694
- //#region src/diagnostics.d.ts
695
- declare class WorkspaceCursorApi<T> {
696
- private readonly transport;
697
- private readonly resource;
698
- private readonly schema;
699
- constructor(transport: PocketCoderTransport, resource: string, schema: z.ZodType<{
700
- items: T[];
701
- next_cursor: string | null;
702
- }>);
703
- list(workspaceId: string, query?: CursorListQuery, options?: RequestOptions): Promise<Page<T>>;
704
- }
705
- declare class LogsApi extends WorkspaceCursorApi<LogChunk> {
706
- constructor(transport: PocketCoderTransport);
707
- }
708
- declare class NetworkEventsApi extends WorkspaceCursorApi<NetworkEvent> {
709
- constructor(transport: PocketCoderTransport);
710
- }
711
- declare class OutputsApi extends WorkspaceCursorApi<OutputResource> {
712
- constructor(transport: PocketCoderTransport);
713
- }
714
- //#endregion
715
- //#region src/templates.d.ts
716
- type TemplateSummary = TemplateListItem;
717
- declare class TemplatesApi {
718
- private readonly transport;
719
- constructor(transport: PocketCoderTransport);
720
- page(query?: CursorListQuery, options?: RequestOptions): Promise<Page<{
721
- name: string;
722
- version: string;
723
- digest: string;
724
- status: "active" | "available" | "retired";
725
- description?: string | undefined;
726
- }>>;
727
- list(options?: RequestOptions): Promise<{
728
- name: string;
729
- version: string;
730
- digest: string;
731
- status: "active" | "available" | "retired";
732
- description?: string | undefined;
733
- }[]>;
734
- }
735
- //#endregion
736
- //#region src/terminals.d.ts
737
- interface TerminalConnectOptions {
738
- sessionId?: string;
739
- }
740
- declare class TerminalConnection {
741
- readonly socket: WebSocket;
742
- private readonly messageListeners;
743
- private readonly openListeners;
744
- private readonly closeListeners;
745
- private readonly errorListeners;
746
- private readonly pendingMessages;
747
- private opened;
748
- private closedEvent;
749
- private errored;
750
- constructor(socket: WebSocket);
751
- onMessage(listener: (message: ServerTerminalMessage) => void): () => void;
752
- onOpen(listener: () => void): () => void;
753
- onClose(listener: (event: CloseEvent) => void): () => void;
754
- onError(listener: () => void): () => void;
755
- sendInput(value: Uint8Array | string): void;
756
- resize(rows: number, cols: number): void;
757
- close(code?: number, reason?: string): void;
758
- private handleMessage;
759
- }
760
- declare class TerminalsApi {
761
- private readonly transport;
762
- constructor(transport: PocketCoderTransport);
763
- connect(workspaceId: string, options?: TerminalConnectOptions): TerminalConnection;
764
- list(workspaceId: string, query?: {
765
- cursor?: string;
766
- limit?: number;
767
- }, options?: RequestOptions): Promise<{
768
- items: TerminalSession[];
769
- nextCursor: string | null;
770
- }>;
771
- }
772
- //#endregion
773
498
  //#region src/workspaces.d.ts
774
499
  interface WorkspaceCreateInput {
775
500
  externalId: string;
@@ -800,7 +525,7 @@ declare class WorkspacesApi {
800
525
  version: string;
801
526
  digest: string;
802
527
  };
803
- state: "ready" | "failed" | "succeeded" | "queued" | "provisioning" | "connected" | "preserving" | "terminating" | "canceled" | "expired" | "preserved";
528
+ state: "queued" | "provisioning" | "connected" | "ready" | "preserving" | "terminating" | "succeeded" | "failed" | "canceled" | "expired" | "preserved";
804
529
  reason_code: "child_exit_success" | "child_exit_failure" | "setup_failed" | "bootstrap_failed" | "registration_timeout" | "health_failed" | "child_crash" | "provider_lost" | "disconnect_timeout" | "canceled_by_caller" | "deadline_expired" | "idle_expired" | "queue_timeout" | "launch_failed" | "preserve_requested" | "preserved_by_policy" | "checkpoint_created" | "checkpoint_failed" | "checkpoint_corrupt" | "checkpoint_quota_exceeded" | "checkpoint_storage_lost" | "restore_requested" | "restore_failed" | "image_unavailable" | "source_resolution_failed" | "secret_resolution_failed" | "operation_conflict" | "network_policy_failed" | null;
805
530
  agent_state: "unknown" | "running" | "stable";
806
531
  change_cursor: number;
@@ -850,7 +575,7 @@ declare class WorkspacesApi {
850
575
  version: string;
851
576
  digest: string;
852
577
  };
853
- state: "ready" | "failed" | "succeeded" | "queued" | "provisioning" | "connected" | "preserving" | "terminating" | "canceled" | "expired" | "preserved";
578
+ state: "queued" | "provisioning" | "connected" | "ready" | "preserving" | "terminating" | "succeeded" | "failed" | "canceled" | "expired" | "preserved";
854
579
  reason_code: "child_exit_success" | "child_exit_failure" | "setup_failed" | "bootstrap_failed" | "registration_timeout" | "health_failed" | "child_crash" | "provider_lost" | "disconnect_timeout" | "canceled_by_caller" | "deadline_expired" | "idle_expired" | "queue_timeout" | "launch_failed" | "preserve_requested" | "preserved_by_policy" | "checkpoint_created" | "checkpoint_failed" | "checkpoint_corrupt" | "checkpoint_quota_exceeded" | "checkpoint_storage_lost" | "restore_requested" | "restore_failed" | "image_unavailable" | "source_resolution_failed" | "secret_resolution_failed" | "operation_conflict" | "network_policy_failed" | null;
855
580
  agent_state: "unknown" | "running" | "stable";
856
581
  change_cursor: number;
@@ -900,7 +625,7 @@ declare class WorkspacesApi {
900
625
  version: string;
901
626
  digest: string;
902
627
  };
903
- state: "ready" | "failed" | "succeeded" | "queued" | "provisioning" | "connected" | "preserving" | "terminating" | "canceled" | "expired" | "preserved";
628
+ state: "queued" | "provisioning" | "connected" | "ready" | "preserving" | "terminating" | "succeeded" | "failed" | "canceled" | "expired" | "preserved";
904
629
  reason_code: "child_exit_success" | "child_exit_failure" | "setup_failed" | "bootstrap_failed" | "registration_timeout" | "health_failed" | "child_crash" | "provider_lost" | "disconnect_timeout" | "canceled_by_caller" | "deadline_expired" | "idle_expired" | "queue_timeout" | "launch_failed" | "preserve_requested" | "preserved_by_policy" | "checkpoint_created" | "checkpoint_failed" | "checkpoint_corrupt" | "checkpoint_quota_exceeded" | "checkpoint_storage_lost" | "restore_requested" | "restore_failed" | "image_unavailable" | "source_resolution_failed" | "secret_resolution_failed" | "operation_conflict" | "network_policy_failed" | null;
905
630
  agent_state: "unknown" | "running" | "stable";
906
631
  change_cursor: number;
@@ -950,7 +675,7 @@ declare class WorkspacesApi {
950
675
  version: string;
951
676
  digest: string;
952
677
  };
953
- state: "ready" | "failed" | "succeeded" | "queued" | "provisioning" | "connected" | "preserving" | "terminating" | "canceled" | "expired" | "preserved";
678
+ state: "queued" | "provisioning" | "connected" | "ready" | "preserving" | "terminating" | "succeeded" | "failed" | "canceled" | "expired" | "preserved";
954
679
  reason_code: "child_exit_success" | "child_exit_failure" | "setup_failed" | "bootstrap_failed" | "registration_timeout" | "health_failed" | "child_crash" | "provider_lost" | "disconnect_timeout" | "canceled_by_caller" | "deadline_expired" | "idle_expired" | "queue_timeout" | "launch_failed" | "preserve_requested" | "preserved_by_policy" | "checkpoint_created" | "checkpoint_failed" | "checkpoint_corrupt" | "checkpoint_quota_exceeded" | "checkpoint_storage_lost" | "restore_requested" | "restore_failed" | "image_unavailable" | "source_resolution_failed" | "secret_resolution_failed" | "operation_conflict" | "network_policy_failed" | null;
955
680
  agent_state: "unknown" | "running" | "stable";
956
681
  change_cursor: number;
@@ -1000,7 +725,7 @@ declare class WorkspacesApi {
1000
725
  version: string;
1001
726
  digest: string;
1002
727
  };
1003
- state: "ready" | "failed" | "succeeded" | "queued" | "provisioning" | "connected" | "preserving" | "terminating" | "canceled" | "expired" | "preserved";
728
+ state: "queued" | "provisioning" | "connected" | "ready" | "preserving" | "terminating" | "succeeded" | "failed" | "canceled" | "expired" | "preserved";
1004
729
  reason_code: "child_exit_success" | "child_exit_failure" | "setup_failed" | "bootstrap_failed" | "registration_timeout" | "health_failed" | "child_crash" | "provider_lost" | "disconnect_timeout" | "canceled_by_caller" | "deadline_expired" | "idle_expired" | "queue_timeout" | "launch_failed" | "preserve_requested" | "preserved_by_policy" | "checkpoint_created" | "checkpoint_failed" | "checkpoint_corrupt" | "checkpoint_quota_exceeded" | "checkpoint_storage_lost" | "restore_requested" | "restore_failed" | "image_unavailable" | "source_resolution_failed" | "secret_resolution_failed" | "operation_conflict" | "network_policy_failed" | null;
1005
730
  agent_state: "unknown" | "running" | "stable";
1006
731
  change_cursor: number;
@@ -1053,7 +778,7 @@ declare class WorkspacesApi {
1053
778
  version: string;
1054
779
  digest: string;
1055
780
  };
1056
- state: "ready" | "failed" | "succeeded" | "queued" | "provisioning" | "connected" | "preserving" | "terminating" | "canceled" | "expired" | "preserved";
781
+ state: "queued" | "provisioning" | "connected" | "ready" | "preserving" | "terminating" | "succeeded" | "failed" | "canceled" | "expired" | "preserved";
1057
782
  reason_code: "child_exit_success" | "child_exit_failure" | "setup_failed" | "bootstrap_failed" | "registration_timeout" | "health_failed" | "child_crash" | "provider_lost" | "disconnect_timeout" | "canceled_by_caller" | "deadline_expired" | "idle_expired" | "queue_timeout" | "launch_failed" | "preserve_requested" | "preserved_by_policy" | "checkpoint_created" | "checkpoint_failed" | "checkpoint_corrupt" | "checkpoint_quota_exceeded" | "checkpoint_storage_lost" | "restore_requested" | "restore_failed" | "image_unavailable" | "source_resolution_failed" | "secret_resolution_failed" | "operation_conflict" | "network_policy_failed" | null;
1058
783
  agent_state: "unknown" | "running" | "stable";
1059
784
  change_cursor: number;
@@ -1106,7 +831,57 @@ declare class WorkspacesApi {
1106
831
  version: string;
1107
832
  digest: string;
1108
833
  };
1109
- state: "ready" | "failed" | "succeeded" | "queued" | "provisioning" | "connected" | "preserving" | "terminating" | "canceled" | "expired" | "preserved";
834
+ state: "queued" | "provisioning" | "connected" | "ready" | "preserving" | "terminating" | "succeeded" | "failed" | "canceled" | "expired" | "preserved";
835
+ reason_code: "child_exit_success" | "child_exit_failure" | "setup_failed" | "bootstrap_failed" | "registration_timeout" | "health_failed" | "child_crash" | "provider_lost" | "disconnect_timeout" | "canceled_by_caller" | "deadline_expired" | "idle_expired" | "queue_timeout" | "launch_failed" | "preserve_requested" | "preserved_by_policy" | "checkpoint_created" | "checkpoint_failed" | "checkpoint_corrupt" | "checkpoint_quota_exceeded" | "checkpoint_storage_lost" | "restore_requested" | "restore_failed" | "image_unavailable" | "source_resolution_failed" | "secret_resolution_failed" | "operation_conflict" | "network_policy_failed" | null;
836
+ agent_state: "unknown" | "running" | "stable";
837
+ change_cursor: number;
838
+ provider_kind: string | null;
839
+ provisioning_mode: "cold" | "warm" | null;
840
+ network: {
841
+ state: "ready" | "disabled" | "starting" | "degraded";
842
+ };
843
+ health: Record<string, string>;
844
+ created_at: string;
845
+ updated_at: string;
846
+ connected_at: string | null;
847
+ ready_at: string | null;
848
+ deadline_at: string;
849
+ terminal_at: string | null;
850
+ metadata: Record<string, string>;
851
+ origin_workspace_id: string | null;
852
+ restored_from_checkpoint_id: string | null;
853
+ source: {
854
+ kind: "git";
855
+ repository: string;
856
+ requested_revision: string;
857
+ resolved_commit: string | null;
858
+ } | null;
859
+ persistence: {
860
+ enabled: boolean;
861
+ conversation_restore: "unknown" | "supported" | "filesystem_only";
862
+ conversation_resume: {
863
+ status: "unknown" | "supported" | "unsupported";
864
+ reason: "filesystem_only" | "capability_unknown" | null;
865
+ };
866
+ latest_checkpoint_id: string | null;
867
+ };
868
+ outputs: Record<string, unknown>;
869
+ failure: {
870
+ reason_code: "child_exit_success" | "child_exit_failure" | "setup_failed" | "bootstrap_failed" | "registration_timeout" | "health_failed" | "child_crash" | "provider_lost" | "disconnect_timeout" | "canceled_by_caller" | "deadline_expired" | "idle_expired" | "queue_timeout" | "launch_failed" | "preserve_requested" | "preserved_by_policy" | "checkpoint_created" | "checkpoint_failed" | "checkpoint_corrupt" | "checkpoint_quota_exceeded" | "checkpoint_storage_lost" | "restore_requested" | "restore_failed" | "image_unavailable" | "source_resolution_failed" | "secret_resolution_failed" | "operation_conflict" | "network_policy_failed";
871
+ log_tail: string;
872
+ log_tail_truncated: boolean;
873
+ last_log_seq: number | null;
874
+ } | null;
875
+ }>;
876
+ waitForAgentInput(id: string, timeoutMs: number, options?: RequestOptions): Promise<{
877
+ id: string;
878
+ external_id: string;
879
+ template: {
880
+ name: string;
881
+ version: string;
882
+ digest: string;
883
+ };
884
+ state: "queued" | "provisioning" | "connected" | "ready" | "preserving" | "terminating" | "succeeded" | "failed" | "canceled" | "expired" | "preserved";
1110
885
  reason_code: "child_exit_success" | "child_exit_failure" | "setup_failed" | "bootstrap_failed" | "registration_timeout" | "health_failed" | "child_crash" | "provider_lost" | "disconnect_timeout" | "canceled_by_caller" | "deadline_expired" | "idle_expired" | "queue_timeout" | "launch_failed" | "preserve_requested" | "preserved_by_policy" | "checkpoint_created" | "checkpoint_failed" | "checkpoint_corrupt" | "checkpoint_quota_exceeded" | "checkpoint_storage_lost" | "restore_requested" | "restore_failed" | "image_unavailable" | "source_resolution_failed" | "secret_resolution_failed" | "operation_conflict" | "network_policy_failed" | null;
1111
886
  agent_state: "unknown" | "running" | "stable";
1112
887
  change_cursor: number;
@@ -1148,7 +923,92 @@ declare class WorkspacesApi {
1148
923
  last_log_seq: number | null;
1149
924
  } | null;
1150
925
  }>;
1151
- preserve(id: string, input: PreserveRequest, key: string, options?: RequestOptions): Promise<{
926
+ preserve(id: string, input: PreserveRequest, key: string, options?: RequestOptions): Promise<{
927
+ workspace: {
928
+ id: string;
929
+ external_id: string;
930
+ template: {
931
+ name: string;
932
+ version: string;
933
+ digest: string;
934
+ };
935
+ state: "queued" | "provisioning" | "connected" | "ready" | "preserving" | "terminating" | "succeeded" | "failed" | "canceled" | "expired" | "preserved";
936
+ reason_code: "child_exit_success" | "child_exit_failure" | "setup_failed" | "bootstrap_failed" | "registration_timeout" | "health_failed" | "child_crash" | "provider_lost" | "disconnect_timeout" | "canceled_by_caller" | "deadline_expired" | "idle_expired" | "queue_timeout" | "launch_failed" | "preserve_requested" | "preserved_by_policy" | "checkpoint_created" | "checkpoint_failed" | "checkpoint_corrupt" | "checkpoint_quota_exceeded" | "checkpoint_storage_lost" | "restore_requested" | "restore_failed" | "image_unavailable" | "source_resolution_failed" | "secret_resolution_failed" | "operation_conflict" | "network_policy_failed" | null;
937
+ agent_state: "unknown" | "running" | "stable";
938
+ change_cursor: number;
939
+ provider_kind: string | null;
940
+ provisioning_mode: "cold" | "warm" | null;
941
+ network: {
942
+ state: "ready" | "disabled" | "starting" | "degraded";
943
+ };
944
+ health: Record<string, string>;
945
+ created_at: string;
946
+ updated_at: string;
947
+ connected_at: string | null;
948
+ ready_at: string | null;
949
+ deadline_at: string;
950
+ terminal_at: string | null;
951
+ metadata: Record<string, string>;
952
+ origin_workspace_id: string | null;
953
+ restored_from_checkpoint_id: string | null;
954
+ source: {
955
+ kind: "git";
956
+ repository: string;
957
+ requested_revision: string;
958
+ resolved_commit: string | null;
959
+ } | null;
960
+ persistence: {
961
+ enabled: boolean;
962
+ conversation_restore: "unknown" | "supported" | "filesystem_only";
963
+ conversation_resume: {
964
+ status: "unknown" | "supported" | "unsupported";
965
+ reason: "filesystem_only" | "capability_unknown" | null;
966
+ };
967
+ latest_checkpoint_id: string | null;
968
+ };
969
+ outputs: Record<string, unknown>;
970
+ failure: {
971
+ reason_code: "child_exit_success" | "child_exit_failure" | "setup_failed" | "bootstrap_failed" | "registration_timeout" | "health_failed" | "child_crash" | "provider_lost" | "disconnect_timeout" | "canceled_by_caller" | "deadline_expired" | "idle_expired" | "queue_timeout" | "launch_failed" | "preserve_requested" | "preserved_by_policy" | "checkpoint_created" | "checkpoint_failed" | "checkpoint_corrupt" | "checkpoint_quota_exceeded" | "checkpoint_storage_lost" | "restore_requested" | "restore_failed" | "image_unavailable" | "source_resolution_failed" | "secret_resolution_failed" | "operation_conflict" | "network_policy_failed";
972
+ log_tail: string;
973
+ log_tail_truncated: boolean;
974
+ last_log_seq: number | null;
975
+ } | null;
976
+ };
977
+ checkpoint: {
978
+ id: string;
979
+ workspace_id: string;
980
+ state: "ready" | "failed" | "creating" | "deleting" | "deleted";
981
+ reason_code: string | null;
982
+ template: {
983
+ name: string;
984
+ version: string;
985
+ digest: string;
986
+ };
987
+ manifest_digest: string | null;
988
+ logical_bytes: number | null;
989
+ stored_bytes: number | null;
990
+ file_count: number | null;
991
+ mounts: string[];
992
+ conversation_restore: "unknown" | "supported" | "filesystem_only";
993
+ label: string | null;
994
+ created_at: string;
995
+ ready_at: string | null;
996
+ expires_at: string | null;
997
+ };
998
+ operation: {
999
+ id: string;
1000
+ kind: "preserve" | "restore" | "verify" | "delete";
1001
+ state: "succeeded" | "failed" | "running" | "pending";
1002
+ workspace_id: string | null;
1003
+ checkpoint_id: string | null;
1004
+ result_workspace_id: string | null;
1005
+ reason_code: string | null;
1006
+ created_at: string;
1007
+ updated_at: string;
1008
+ completed_at: string | null;
1009
+ };
1010
+ }>;
1011
+ recreate(id: string, input: RestoreRequest, key: string, options?: RequestOptions): Promise<{
1152
1012
  workspace: {
1153
1013
  id: string;
1154
1014
  external_id: string;
@@ -1157,7 +1017,7 @@ declare class WorkspacesApi {
1157
1017
  version: string;
1158
1018
  digest: string;
1159
1019
  };
1160
- state: "ready" | "failed" | "succeeded" | "queued" | "provisioning" | "connected" | "preserving" | "terminating" | "canceled" | "expired" | "preserved";
1020
+ state: "queued" | "provisioning" | "connected" | "ready" | "preserving" | "terminating" | "succeeded" | "failed" | "canceled" | "expired" | "preserved";
1161
1021
  reason_code: "child_exit_success" | "child_exit_failure" | "setup_failed" | "bootstrap_failed" | "registration_timeout" | "health_failed" | "child_crash" | "provider_lost" | "disconnect_timeout" | "canceled_by_caller" | "deadline_expired" | "idle_expired" | "queue_timeout" | "launch_failed" | "preserve_requested" | "preserved_by_policy" | "checkpoint_created" | "checkpoint_failed" | "checkpoint_corrupt" | "checkpoint_quota_exceeded" | "checkpoint_storage_lost" | "restore_requested" | "restore_failed" | "image_unavailable" | "source_resolution_failed" | "secret_resolution_failed" | "operation_conflict" | "network_policy_failed" | null;
1162
1022
  agent_state: "unknown" | "running" | "stable";
1163
1023
  change_cursor: number;
@@ -1199,31 +1059,10 @@ declare class WorkspacesApi {
1199
1059
  last_log_seq: number | null;
1200
1060
  } | null;
1201
1061
  };
1202
- checkpoint: {
1203
- id: string;
1204
- workspace_id: string;
1205
- state: "deleted" | "creating" | "ready" | "failed" | "deleting";
1206
- reason_code: string | null;
1207
- template: {
1208
- name: string;
1209
- version: string;
1210
- digest: string;
1211
- };
1212
- manifest_digest: string | null;
1213
- logical_bytes: number | null;
1214
- stored_bytes: number | null;
1215
- file_count: number | null;
1216
- mounts: string[];
1217
- conversation_restore: "unknown" | "supported" | "filesystem_only";
1218
- label: string | null;
1219
- created_at: string;
1220
- ready_at: string | null;
1221
- expires_at: string | null;
1222
- };
1223
1062
  operation: {
1224
1063
  id: string;
1225
1064
  kind: "preserve" | "restore" | "verify" | "delete";
1226
- state: "failed" | "pending" | "running" | "succeeded";
1065
+ state: "succeeded" | "failed" | "running" | "pending";
1227
1066
  workspace_id: string | null;
1228
1067
  checkpoint_id: string | null;
1229
1068
  result_workspace_id: string | null;
@@ -1233,7 +1072,7 @@ declare class WorkspacesApi {
1233
1072
  completed_at: string | null;
1234
1073
  };
1235
1074
  }>;
1236
- recreate(id: string, input: RestoreRequest, key: string, options?: RequestOptions): Promise<{
1075
+ resume(id: string, input: RestoreRequest, key: string, options?: RequestOptions): Promise<{
1237
1076
  workspace: {
1238
1077
  id: string;
1239
1078
  external_id: string;
@@ -1242,7 +1081,7 @@ declare class WorkspacesApi {
1242
1081
  version: string;
1243
1082
  digest: string;
1244
1083
  };
1245
- state: "ready" | "failed" | "succeeded" | "queued" | "provisioning" | "connected" | "preserving" | "terminating" | "canceled" | "expired" | "preserved";
1084
+ state: "queued" | "provisioning" | "connected" | "ready" | "preserving" | "terminating" | "succeeded" | "failed" | "canceled" | "expired" | "preserved";
1246
1085
  reason_code: "child_exit_success" | "child_exit_failure" | "setup_failed" | "bootstrap_failed" | "registration_timeout" | "health_failed" | "child_crash" | "provider_lost" | "disconnect_timeout" | "canceled_by_caller" | "deadline_expired" | "idle_expired" | "queue_timeout" | "launch_failed" | "preserve_requested" | "preserved_by_policy" | "checkpoint_created" | "checkpoint_failed" | "checkpoint_corrupt" | "checkpoint_quota_exceeded" | "checkpoint_storage_lost" | "restore_requested" | "restore_failed" | "image_unavailable" | "source_resolution_failed" | "secret_resolution_failed" | "operation_conflict" | "network_policy_failed" | null;
1247
1086
  agent_state: "unknown" | "running" | "stable";
1248
1087
  change_cursor: number;
@@ -1287,7 +1126,7 @@ declare class WorkspacesApi {
1287
1126
  operation: {
1288
1127
  id: string;
1289
1128
  kind: "preserve" | "restore" | "verify" | "delete";
1290
- state: "failed" | "pending" | "running" | "succeeded";
1129
+ state: "succeeded" | "failed" | "running" | "pending";
1291
1130
  workspace_id: string | null;
1292
1131
  checkpoint_id: string | null;
1293
1132
  result_workspace_id: string | null;
@@ -1296,8 +1135,118 @@ declare class WorkspacesApi {
1296
1135
  updated_at: string;
1297
1136
  completed_at: string | null;
1298
1137
  };
1138
+ resume: {
1139
+ status: "supported";
1140
+ reason: null;
1141
+ source_workspace_id: string;
1142
+ checkpoint_id: string;
1143
+ };
1299
1144
  }>;
1300
- resume(id: string, input: RestoreRequest, key: string, options?: RequestOptions): Promise<{
1145
+ private jsonOperation;
1146
+ }
1147
+ //#endregion
1148
+ //#region src/attachments.d.ts
1149
+ type UploadBody = NonNullable<RequestInit["body"]>;
1150
+ interface AttachmentUploadInput {
1151
+ id?: string;
1152
+ name: string;
1153
+ mediaType?: string;
1154
+ body: UploadBody;
1155
+ sizeBytes: number;
1156
+ signal?: AbortSignal;
1157
+ onProgress?: (uploadedBytes: number, totalBytes: number) => void;
1158
+ }
1159
+ interface AgentMessageInput {
1160
+ content: string;
1161
+ attachmentIds?: string[];
1162
+ signal?: AbortSignal;
1163
+ readyTimeoutMs?: number;
1164
+ }
1165
+ declare class AttachmentsApi {
1166
+ private readonly transport;
1167
+ constructor(transport: PocketCoderTransport);
1168
+ upload(workspaceId: string, input: AttachmentUploadInput): Promise<AttachmentDescriptor>;
1169
+ }
1170
+ declare class AgentApi {
1171
+ private readonly transport;
1172
+ private readonly workspaces;
1173
+ constructor(transport: PocketCoderTransport, workspaces: WorkspacesApi);
1174
+ sendMessage(workspaceId: string, input: AgentMessageInput): Promise<void>;
1175
+ }
1176
+ //#endregion
1177
+ //#region src/checkpoints.d.ts
1178
+ declare class CheckpointsApi {
1179
+ private readonly transport;
1180
+ constructor(transport: PocketCoderTransport);
1181
+ list(workspaceId: string, query?: CursorListQuery & {
1182
+ state?: CheckpointState;
1183
+ }, options?: RequestOptions): Promise<Page<{
1184
+ id: string;
1185
+ workspace_id: string;
1186
+ state: "ready" | "failed" | "creating" | "deleting" | "deleted";
1187
+ reason_code: string | null;
1188
+ template: {
1189
+ name: string;
1190
+ version: string;
1191
+ digest: string;
1192
+ };
1193
+ manifest_digest: string | null;
1194
+ logical_bytes: number | null;
1195
+ stored_bytes: number | null;
1196
+ file_count: number | null;
1197
+ mounts: string[];
1198
+ conversation_restore: "unknown" | "supported" | "filesystem_only";
1199
+ label: string | null;
1200
+ created_at: string;
1201
+ ready_at: string | null;
1202
+ expires_at: string | null;
1203
+ }>>;
1204
+ get(id: string, options?: RequestOptions): Promise<{
1205
+ id: string;
1206
+ workspace_id: string;
1207
+ state: "ready" | "failed" | "creating" | "deleting" | "deleted";
1208
+ reason_code: string | null;
1209
+ template: {
1210
+ name: string;
1211
+ version: string;
1212
+ digest: string;
1213
+ };
1214
+ manifest_digest: string | null;
1215
+ logical_bytes: number | null;
1216
+ stored_bytes: number | null;
1217
+ file_count: number | null;
1218
+ mounts: string[];
1219
+ conversation_restore: "unknown" | "supported" | "filesystem_only";
1220
+ label: string | null;
1221
+ created_at: string;
1222
+ ready_at: string | null;
1223
+ expires_at: string | null;
1224
+ }>;
1225
+ verify(id: string, key: string, options?: RequestOptions): Promise<{
1226
+ id: string;
1227
+ kind: "preserve" | "restore" | "verify" | "delete";
1228
+ state: "succeeded" | "failed" | "running" | "pending";
1229
+ workspace_id: string | null;
1230
+ checkpoint_id: string | null;
1231
+ result_workspace_id: string | null;
1232
+ reason_code: string | null;
1233
+ created_at: string;
1234
+ updated_at: string;
1235
+ completed_at: string | null;
1236
+ }>;
1237
+ delete(id: string, key: string, options?: RequestOptions): Promise<{
1238
+ id: string;
1239
+ kind: "preserve" | "restore" | "verify" | "delete";
1240
+ state: "succeeded" | "failed" | "running" | "pending";
1241
+ workspace_id: string | null;
1242
+ checkpoint_id: string | null;
1243
+ result_workspace_id: string | null;
1244
+ reason_code: string | null;
1245
+ created_at: string;
1246
+ updated_at: string;
1247
+ completed_at: string | null;
1248
+ }>;
1249
+ restore(id: string, input: RestoreRequest, key: string, options?: RequestOptions): Promise<{
1301
1250
  workspace: {
1302
1251
  id: string;
1303
1252
  external_id: string;
@@ -1306,7 +1255,7 @@ declare class WorkspacesApi {
1306
1255
  version: string;
1307
1256
  digest: string;
1308
1257
  };
1309
- state: "ready" | "failed" | "succeeded" | "queued" | "provisioning" | "connected" | "preserving" | "terminating" | "canceled" | "expired" | "preserved";
1258
+ state: "queued" | "provisioning" | "connected" | "ready" | "preserving" | "terminating" | "succeeded" | "failed" | "canceled" | "expired" | "preserved";
1310
1259
  reason_code: "child_exit_success" | "child_exit_failure" | "setup_failed" | "bootstrap_failed" | "registration_timeout" | "health_failed" | "child_crash" | "provider_lost" | "disconnect_timeout" | "canceled_by_caller" | "deadline_expired" | "idle_expired" | "queue_timeout" | "launch_failed" | "preserve_requested" | "preserved_by_policy" | "checkpoint_created" | "checkpoint_failed" | "checkpoint_corrupt" | "checkpoint_quota_exceeded" | "checkpoint_storage_lost" | "restore_requested" | "restore_failed" | "image_unavailable" | "source_resolution_failed" | "secret_resolution_failed" | "operation_conflict" | "network_policy_failed" | null;
1311
1260
  agent_state: "unknown" | "running" | "stable";
1312
1261
  change_cursor: number;
@@ -1351,7 +1300,7 @@ declare class WorkspacesApi {
1351
1300
  operation: {
1352
1301
  id: string;
1353
1302
  kind: "preserve" | "restore" | "verify" | "delete";
1354
- state: "failed" | "pending" | "running" | "succeeded";
1303
+ state: "succeeded" | "failed" | "running" | "pending";
1355
1304
  workspace_id: string | null;
1356
1305
  checkpoint_id: string | null;
1357
1306
  result_workspace_id: string | null;
@@ -1360,14 +1309,119 @@ declare class WorkspacesApi {
1360
1309
  updated_at: string;
1361
1310
  completed_at: string | null;
1362
1311
  };
1363
- resume: {
1364
- status: "supported";
1365
- reason: null;
1366
- source_workspace_id: string;
1367
- checkpoint_id: string;
1368
- };
1369
1312
  }>;
1370
- private jsonOperation;
1313
+ private operationRequest;
1314
+ }
1315
+ declare class OperationsApi {
1316
+ private readonly transport;
1317
+ constructor(transport: PocketCoderTransport);
1318
+ get(id: string, options?: RequestOptions): Promise<{
1319
+ id: string;
1320
+ kind: "preserve" | "restore" | "verify" | "delete";
1321
+ state: "succeeded" | "failed" | "running" | "pending";
1322
+ workspace_id: string | null;
1323
+ checkpoint_id: string | null;
1324
+ result_workspace_id: string | null;
1325
+ reason_code: string | null;
1326
+ created_at: string;
1327
+ updated_at: string;
1328
+ completed_at: string | null;
1329
+ }>;
1330
+ }
1331
+ //#endregion
1332
+ //#region src/conversations.d.ts
1333
+ type ConversationMessage = ConversationMessageResource;
1334
+ type ConversationPage = Page<ConversationMessageResource>;
1335
+ declare class ConversationsApi {
1336
+ private readonly transport;
1337
+ constructor(transport: PocketCoderTransport);
1338
+ list(id: string, query?: CursorListQuery, options?: RequestOptions): Promise<Page<{
1339
+ message_id: string;
1340
+ role: "user" | "assistant" | "system" | "tool";
1341
+ content: string;
1342
+ occurred_at: string;
1343
+ metadata: Record<string, string>;
1344
+ seq: number;
1345
+ }>>;
1346
+ }
1347
+ //#endregion
1348
+ //#region src/diagnostics.d.ts
1349
+ declare class WorkspaceCursorApi<T> {
1350
+ private readonly transport;
1351
+ private readonly resource;
1352
+ private readonly schema;
1353
+ constructor(transport: PocketCoderTransport, resource: string, schema: z.ZodType<{
1354
+ items: T[];
1355
+ next_cursor: string | null;
1356
+ }>);
1357
+ list(workspaceId: string, query?: CursorListQuery, options?: RequestOptions): Promise<Page<T>>;
1358
+ }
1359
+ declare class LogsApi extends WorkspaceCursorApi<LogChunk> {
1360
+ constructor(transport: PocketCoderTransport);
1361
+ }
1362
+ declare class NetworkEventsApi extends WorkspaceCursorApi<NetworkEvent> {
1363
+ constructor(transport: PocketCoderTransport);
1364
+ }
1365
+ declare class OutputsApi extends WorkspaceCursorApi<OutputResource> {
1366
+ constructor(transport: PocketCoderTransport);
1367
+ }
1368
+ //#endregion
1369
+ //#region src/templates.d.ts
1370
+ type TemplateSummary = TemplateListItem;
1371
+ declare class TemplatesApi {
1372
+ private readonly transport;
1373
+ constructor(transport: PocketCoderTransport);
1374
+ page(query?: CursorListQuery, options?: RequestOptions): Promise<Page<{
1375
+ name: string;
1376
+ version: string;
1377
+ digest: string;
1378
+ status: "active" | "available" | "retired";
1379
+ description?: string | undefined;
1380
+ }>>;
1381
+ list(options?: RequestOptions): Promise<{
1382
+ name: string;
1383
+ version: string;
1384
+ digest: string;
1385
+ status: "active" | "available" | "retired";
1386
+ description?: string | undefined;
1387
+ }[]>;
1388
+ }
1389
+ //#endregion
1390
+ //#region src/terminals.d.ts
1391
+ interface TerminalConnectOptions {
1392
+ sessionId?: string;
1393
+ }
1394
+ declare class TerminalConnection {
1395
+ readonly socket: WebSocket;
1396
+ private readonly messageListeners;
1397
+ private readonly openListeners;
1398
+ private readonly closeListeners;
1399
+ private readonly errorListeners;
1400
+ private readonly pendingMessages;
1401
+ private opened;
1402
+ private closedEvent;
1403
+ private errored;
1404
+ constructor(socket: WebSocket);
1405
+ onMessage(listener: (message: ServerTerminalMessage) => void): () => void;
1406
+ onOpen(listener: () => void): () => void;
1407
+ onClose(listener: (event: CloseEvent) => void): () => void;
1408
+ onError(listener: () => void): () => void;
1409
+ sendInput(value: Uint8Array | string): void;
1410
+ resize(rows: number, cols: number): void;
1411
+ close(code?: number, reason?: string): void;
1412
+ private handleMessage;
1413
+ }
1414
+ declare class TerminalsApi {
1415
+ private readonly transport;
1416
+ constructor(transport: PocketCoderTransport);
1417
+ connect(workspaceId: string, options?: TerminalConnectOptions): TerminalConnection;
1418
+ list(workspaceId: string, query?: {
1419
+ cursor?: string;
1420
+ limit?: number;
1421
+ }, options?: RequestOptions): Promise<{
1422
+ items: TerminalSession[];
1423
+ nextCursor: string | null;
1424
+ }>;
1371
1425
  }
1372
1426
  //#endregion
1373
1427
  //#region src/client.d.ts
@@ -1413,5 +1467,48 @@ declare class WorkspaceTerminalError extends Error {
1413
1467
  readonly workspace: WorkspaceResource;
1414
1468
  constructor(workspace: WorkspaceResource);
1415
1469
  }
1470
+ declare class AgentNotReadyError extends Error {
1471
+ readonly workspaceId: string;
1472
+ readonly agentState: AgentState;
1473
+ constructor(workspaceId: string, agentState: AgentState, timeoutMs: number);
1474
+ }
1475
+ declare function isPocketCoderErrorCode(value: unknown): value is ErrorCode;
1476
+ //#endregion
1477
+ //#region src/workspace-turn-resolver.d.ts
1478
+ type WorkspaceTurnResolutionErrorCode = "not_resumable" | "resume_handler_missing" | "resume_failed" | "invalid_resumed_workspace" | "readiness_failed";
1479
+ declare class WorkspaceTurnResolutionError extends Error {
1480
+ readonly code: WorkspaceTurnResolutionErrorCode;
1481
+ constructor(code: WorkspaceTurnResolutionErrorCode, cause?: unknown);
1482
+ }
1483
+ interface ResumeWorkspaceContext {
1484
+ source: WorkspaceResource;
1485
+ attemptId: string;
1486
+ signal: AbortSignal;
1487
+ }
1488
+ interface WorkspaceTurnResolverOptions {
1489
+ client: PocketCoderClient;
1490
+ resumeWorkspace?: (context: ResumeWorkspaceContext) => Promise<WorkspaceResource>;
1491
+ resumeTimeoutMs?: number;
1492
+ }
1493
+ interface ResolveWorkspaceTurnOptions {
1494
+ signal?: AbortSignal;
1495
+ }
1496
+ interface ResolvedWorkspaceTurn {
1497
+ workspace: WorkspaceResource;
1498
+ resumed: boolean;
1499
+ }
1500
+ declare class WorkspaceTurnResolver {
1501
+ private readonly client;
1502
+ private readonly resumeWorkspace;
1503
+ private readonly resumeTimeoutMs;
1504
+ private readonly attempts;
1505
+ constructor(options: WorkspaceTurnResolverOptions);
1506
+ resolve(sourceWorkspaceId: string, options?: ResolveWorkspaceTurnOptions): Promise<ResolvedWorkspaceTurn>;
1507
+ private start;
1508
+ private run;
1509
+ private waitForPreserved;
1510
+ private assertResumable;
1511
+ private assertLineage;
1512
+ }
1416
1513
  //#endregion
1417
- export { AdministrationApi, AgentApi, type AgentMessageInput, type AttachmentDescriptor, type AttachmentUploadInput, AttachmentsApi, type CheckpointResource, type CheckpointState, CheckpointsApi, type ClientErrorCode, ConversationGoneError, type ConversationMessage, type ConversationPage, ConversationsApi, type CursorListQuery, type LogChunk, LogsApi, type NetworkEvent, NetworkEventsApi, type OperationKind, type OperationResource, type OperationState, OperationsApi, type OutputResource, OutputsApi, type Page, PocketCoderClient, type PocketCoderClientConfig, PocketCoderError, type PreserveRequest, type RequestOptions, type RestoreRequest, type ServerTerminalMessage, type StorageState, TERMINAL_WORKSPACE_STATES, type TemplateSummary, TemplatesApi, type TerminalConnectOptions, TerminalConnection, type TerminalSession, TerminalsApi, type WebSocketFactory, type WorkspaceCreateInput, type WorkspaceListQuery, type WorkspaceResource, type WorkspaceState, type WorkspaceSummary, WorkspaceTerminalError, WorkspacesApi, splitAttachmentManifest };
1514
+ export { AdministrationApi, AgentApi, type AgentMessageInput, AgentNotReadyError, type AttachmentDescriptor, type AttachmentUploadInput, AttachmentsApi, type CheckpointResource, type CheckpointState, CheckpointsApi, type ClientErrorCode, ConversationGoneError, type ConversationMessage, type ConversationPage, ConversationsApi, type CursorListQuery, type LogChunk, LogsApi, type NetworkEvent, NetworkEventsApi, type OperationKind, type OperationResource, type OperationState, OperationsApi, type OutputResource, OutputsApi, type Page, PocketCoderClient, type PocketCoderClientConfig, PocketCoderError, type PreserveRequest, type RequestOptions, type ResolveWorkspaceTurnOptions, type ResolvedWorkspaceTurn, type RestoreRequest, type ResumeWorkspaceContext, type ServerTerminalMessage, type StorageState, TERMINAL_WORKSPACE_STATES, type TemplateSummary, TemplatesApi, type TerminalConnectOptions, TerminalConnection, type TerminalSession, TerminalsApi, type WebSocketFactory, type WorkspaceCreateInput, type WorkspaceListQuery, type WorkspaceResource, type WorkspaceState, type WorkspaceSummary, WorkspaceTerminalError, WorkspaceTurnResolutionError, type WorkspaceTurnResolutionErrorCode, WorkspaceTurnResolver, type WorkspaceTurnResolverOptions, WorkspacesApi, isPocketCoderErrorCode, splitAttachmentManifest };
package/dist/index.js CHANGED
@@ -531,7 +531,9 @@ const AttachmentResolvedPayload = z.object({
531
531
  descriptors: z.array(AttachmentDescriptorSchema).optional(),
532
532
  missing_id: z.uuid().optional()
533
533
  });
534
- const errorCodes = Object.keys({
534
+ //#endregion
535
+ //#region ../contracts/src/errors.ts
536
+ const ERROR_CODES = {
535
537
  "auth.invalid_key": 401,
536
538
  "auth.missing_scope": 403,
537
539
  "auth.disabled_principal": 403,
@@ -583,7 +585,8 @@ const errorCodes = Object.keys({
583
585
  "attachment.unsupported": 409,
584
586
  "attachment.interrupted": 503,
585
587
  "internal.error": 500
586
- });
588
+ };
589
+ const errorCodes = Object.keys(ERROR_CODES);
587
590
  const ErrorEnvelopeSchema = z.object({ error: z.object({
588
591
  code: z.enum(errorCodes),
589
592
  message: z.string().min(1),
@@ -700,7 +703,8 @@ const HarnessSchema = z.object({
700
703
  const AgentSchema = HarnessSchema.extend({
701
704
  type: z.string().regex(/^[a-z0-9][a-z0-9-]{0,63}$/).default("custom"),
702
705
  transport: z.enum(["pty", "acp"]).default("pty"),
703
- termWidth: z.number().int().min(10).max(65535).optional()
706
+ termWidth: z.number().int().min(10).max(65535).optional(),
707
+ stateFile: z.string().refine(isAbsolutePath, "expected an absolute path").optional()
704
708
  });
705
709
  const TerminalSchema = z.object({
706
710
  command: CommandSchema,
@@ -748,7 +752,8 @@ const TimeoutsSchema = z.object({
748
752
  });
749
753
  const ResourcesSchema = z.object({
750
754
  cpu: z.string().regex(/^\d+(\.\d+)?m?$/),
751
- memory: z.string().regex(/^\d+(Mi|Gi)$/)
755
+ memory: z.string().regex(/^\d+(Mi|Gi)$/),
756
+ ephemeralStorage: z.string().regex(/^\d+(Mi|Gi)$/).optional()
752
757
  });
753
758
  const RepositorySchema = z.object({
754
759
  url: z.url().refine((value) => {
@@ -814,11 +819,14 @@ const TemplateSpecSchema = z.object({
814
819
  message: "either agent or harness is required"
815
820
  });
816
821
  if (!spec.agent) return;
817
- if (spec.agent.transport === "acp" && spec.agent.termWidth !== void 0) ctx.addIssue({
818
- code: "custom",
819
- path: ["agent", "termWidth"],
820
- message: "termWidth is only valid for PTY transport"
821
- });
822
+ if (spec.agent.transport === "acp") for (const field of ["termWidth", "stateFile"]) {
823
+ if (spec.agent[field] === void 0) continue;
824
+ ctx.addIssue({
825
+ code: "custom",
826
+ path: ["agent", field],
827
+ message: `${field} is only valid for PTY transport`
828
+ });
829
+ }
822
830
  for (const field of [
823
831
  "harness",
824
832
  "services",
@@ -898,6 +906,7 @@ function agentApiHarness(spec) {
898
906
  spec.agent.type,
899
907
  ...spec.agent.transport === "acp" ? ["--experimental-acp"] : [],
900
908
  ...spec.agent.termWidth === void 0 ? [] : ["--term-width", String(spec.agent.termWidth)],
909
+ ...spec.agent.stateFile === void 0 ? [] : ["--state-file", spec.agent.stateFile],
901
910
  "--port",
902
911
  "3284",
903
912
  "--",
@@ -1105,6 +1114,7 @@ function validatePersistence(spec, ctx) {
1105
1114
  const mounts = spec.persistence.mounts;
1106
1115
  for (const [index, mount] of mounts.entries()) validatePersistenceMount(spec, mounts, mount, index, seenNames, ctx);
1107
1116
  validateSourceMount(spec, mounts, ctx);
1117
+ validateAgentStateFile(spec, mounts, ctx);
1108
1118
  if (spec.persistence.conversationRestore === "supported" && (!spec.persistence.sessionCompatibility || mounts.length < 2)) ctx.addIssue({
1109
1119
  code: "custom",
1110
1120
  path: [
@@ -1115,6 +1125,43 @@ function validatePersistence(spec, ctx) {
1115
1125
  message: "supported conversation restore requires sessionCompatibility and a separate harness-state mount"
1116
1126
  });
1117
1127
  }
1128
+ function validateAgentStateFile(spec, mounts, ctx) {
1129
+ if (!isAgentApiNative(spec)) return;
1130
+ const stateFile = spec.agent.stateFile;
1131
+ const normalized = stateFile !== void 0 && isNormalizedFilesystemPath(stateFile);
1132
+ if (stateFile !== void 0 && !normalized) ctx.addIssue({
1133
+ code: "custom",
1134
+ path: [
1135
+ "spec",
1136
+ "agent",
1137
+ "stateFile"
1138
+ ],
1139
+ message: "stateFile must be a normalized absolute filesystem path"
1140
+ });
1141
+ if (spec.agent.transport === "acp" && spec.persistence.conversationRestore === "supported") {
1142
+ ctx.addIssue({
1143
+ code: "custom",
1144
+ path: [
1145
+ "spec",
1146
+ "persistence",
1147
+ "conversationRestore"
1148
+ ],
1149
+ message: "supported conversation restore requires PTY transport"
1150
+ });
1151
+ return;
1152
+ }
1153
+ if (spec.persistence.conversationRestore !== "supported") return;
1154
+ if (normalized && mounts.some((mount) => stateFile.startsWith(`${mount.target}/`))) return;
1155
+ ctx.addIssue({
1156
+ code: "custom",
1157
+ path: [
1158
+ "spec",
1159
+ "agent",
1160
+ "stateFile"
1161
+ ],
1162
+ message: "supported conversation restore requires agent.stateFile below a persistence mount"
1163
+ });
1164
+ }
1118
1165
  function validatePersistenceMount(spec, mounts, mount, index, seenNames, ctx) {
1119
1166
  const path = [
1120
1167
  "spec",
@@ -1779,6 +1826,19 @@ var WorkspaceTerminalError = class extends Error {
1779
1826
  this.workspace = workspace;
1780
1827
  }
1781
1828
  };
1829
+ var AgentNotReadyError = class extends Error {
1830
+ workspaceId;
1831
+ agentState;
1832
+ constructor(workspaceId, agentState, timeoutMs) {
1833
+ super(`agent in workspace ${workspaceId} was still ${agentState} after ${timeoutMs}ms and cannot accept a message`);
1834
+ this.name = "AgentNotReadyError";
1835
+ this.workspaceId = workspaceId;
1836
+ this.agentState = agentState;
1837
+ }
1838
+ };
1839
+ function isPocketCoderErrorCode(value) {
1840
+ return typeof value === "string" && value in ERROR_CODES;
1841
+ }
1782
1842
  function responseError(response, body) {
1783
1843
  const parsed = ErrorEnvelopeSchema.safeParse(body);
1784
1844
  if (!parsed.success) return new PocketCoderError({
@@ -1797,6 +1857,7 @@ function responseError(response, body) {
1797
1857
  }
1798
1858
  //#endregion
1799
1859
  //#region src/attachments.ts
1860
+ const DEFAULT_READY_TIMEOUT_MS = 12e4;
1800
1861
  function contentDisposition(name) {
1801
1862
  const clean = name.replace(/[\r\n]/g, "");
1802
1863
  if (/^[ -~]*$/.test(clean)) return `attachment; filename="${clean.replace(/(["\\])/g, "\\$1")}"`;
@@ -1835,10 +1896,13 @@ var AttachmentsApi = class {
1835
1896
  };
1836
1897
  var AgentApi = class {
1837
1898
  transport;
1838
- constructor(transport) {
1899
+ workspaces;
1900
+ constructor(transport, workspaces) {
1839
1901
  this.transport = transport;
1902
+ this.workspaces = workspaces;
1840
1903
  }
1841
1904
  async sendMessage(workspaceId, input) {
1905
+ await this.workspaces.waitForAgentInput(workspaceId, input.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS, input.signal ? { signal: input.signal } : {});
1842
1906
  const response = await this.transport.raw(`/v1/workspaces/${encodeURIComponent(workspaceId)}/agent/message`, {
1843
1907
  method: "POST",
1844
1908
  ...input.signal ? { signal: input.signal } : {},
@@ -2278,6 +2342,17 @@ var WorkspacesApi = class {
2278
2342
  }
2279
2343
  return workspace;
2280
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
+ }
2281
2356
  preserve(id, input, key, options = {}) {
2282
2357
  return this.jsonOperation(`/v1/workspaces/${encodeURIComponent(id)}/preserve`, input, key, PreserveResponseSchema, options);
2283
2358
  }
@@ -2317,7 +2392,7 @@ var PocketCoderClient = class {
2317
2392
  this.templates = new TemplatesApi(this.transport);
2318
2393
  this.workspaces = new WorkspacesApi(this.transport);
2319
2394
  this.attachments = new AttachmentsApi(this.transport);
2320
- this.agent = new AgentApi(this.transport);
2395
+ this.agent = new AgentApi(this.transport, this.workspaces);
2321
2396
  this.conversations = new ConversationsApi(this.transport);
2322
2397
  this.checkpoints = new CheckpointsApi(this.transport);
2323
2398
  this.operations = new OperationsApi(this.transport);
@@ -2332,4 +2407,148 @@ var PocketCoderClient = class {
2332
2407
  }
2333
2408
  };
2334
2409
  //#endregion
2335
- export { AdministrationApi, AgentApi, AttachmentsApi, CheckpointsApi, ConversationGoneError, ConversationsApi, LogsApi, NetworkEventsApi, OperationsApi, OutputsApi, PocketCoderClient, PocketCoderError, TERMINAL_WORKSPACE_STATES, TemplatesApi, TerminalConnection, TerminalsApi, WorkspaceTerminalError, WorkspacesApi, splitAttachmentManifest };
2410
+ //#region src/workspace-turn-resolver.ts
2411
+ const ERROR_MESSAGES = {
2412
+ not_resumable: "workspace cannot be resumed",
2413
+ resume_handler_missing: "workspace resume handler is not configured",
2414
+ resume_failed: "workspace resume failed",
2415
+ invalid_resumed_workspace: "workspace resume returned an invalid workspace",
2416
+ readiness_failed: "resumed workspace did not become ready"
2417
+ };
2418
+ var WorkspaceTurnResolutionError = class extends Error {
2419
+ code;
2420
+ constructor(code, cause) {
2421
+ super(ERROR_MESSAGES[code], cause === void 0 ? void 0 : { cause });
2422
+ this.name = "WorkspaceTurnResolutionError";
2423
+ this.code = code;
2424
+ }
2425
+ };
2426
+ const NON_RESUMABLE_STATES = /* @__PURE__ */ new Set([
2427
+ "failed",
2428
+ "canceled",
2429
+ "expired",
2430
+ "succeeded",
2431
+ "terminating"
2432
+ ]);
2433
+ function aborted(signal) {
2434
+ return signal.reason ?? new DOMException("The operation was aborted", "AbortError");
2435
+ }
2436
+ function waitForCaller(promise, signal) {
2437
+ if (!signal) return promise;
2438
+ if (signal.aborted) return Promise.reject(aborted(signal));
2439
+ return new Promise((resolve, reject) => {
2440
+ const onAbort = () => reject(aborted(signal));
2441
+ signal.addEventListener("abort", onAbort, { once: true });
2442
+ promise.then((value) => {
2443
+ signal.removeEventListener("abort", onAbort);
2444
+ resolve(value);
2445
+ }, (error) => {
2446
+ signal.removeEventListener("abort", onAbort);
2447
+ reject(error);
2448
+ });
2449
+ });
2450
+ }
2451
+ function requireRemaining(deadline, failure) {
2452
+ const remaining = deadline - Date.now();
2453
+ if (remaining <= 0) throw new WorkspaceTurnResolutionError(failure);
2454
+ return remaining;
2455
+ }
2456
+ var WorkspaceTurnResolver = class {
2457
+ client;
2458
+ resumeWorkspace;
2459
+ resumeTimeoutMs;
2460
+ attempts = /* @__PURE__ */ new Map();
2461
+ constructor(options) {
2462
+ this.client = options.client;
2463
+ this.resumeWorkspace = options.resumeWorkspace;
2464
+ this.resumeTimeoutMs = options.resumeTimeoutMs ?? 3e5;
2465
+ }
2466
+ async resolve(sourceWorkspaceId, options = {}) {
2467
+ if (options.signal?.aborted) throw aborted(options.signal);
2468
+ const attempt = this.attempts.get(sourceWorkspaceId) ?? this.start(sourceWorkspaceId);
2469
+ attempt.waiters += 1;
2470
+ try {
2471
+ return await waitForCaller(attempt.promise, options.signal);
2472
+ } finally {
2473
+ attempt.waiters -= 1;
2474
+ if (attempt.waiters === 0 && !attempt.resumeStarted && !attempt.settled) attempt.controller.abort(new DOMException("No callers remain", "AbortError"));
2475
+ }
2476
+ }
2477
+ start(sourceWorkspaceId) {
2478
+ const attempt = {
2479
+ controller: new AbortController(),
2480
+ promise: Promise.resolve(void 0),
2481
+ waiters: 0,
2482
+ resumeStarted: false,
2483
+ settled: false
2484
+ };
2485
+ this.attempts.set(sourceWorkspaceId, attempt);
2486
+ attempt.promise = this.run(sourceWorkspaceId, attempt).finally(() => {
2487
+ attempt.settled = true;
2488
+ if (this.attempts.get(sourceWorkspaceId) === attempt) this.attempts.delete(sourceWorkspaceId);
2489
+ });
2490
+ attempt.promise.catch(() => {});
2491
+ return attempt;
2492
+ }
2493
+ async run(sourceWorkspaceId, attempt) {
2494
+ const deadline = Date.now() + this.resumeTimeoutMs;
2495
+ let source = await this.client.workspaces.get(sourceWorkspaceId, { signal: attempt.controller.signal });
2496
+ if (source.state === "ready") return {
2497
+ workspace: source,
2498
+ resumed: false
2499
+ };
2500
+ if (source.state === "preserving") source = await this.waitForPreserved(source, deadline, attempt.controller.signal);
2501
+ this.assertResumable(source);
2502
+ if (!this.resumeWorkspace) throw new WorkspaceTurnResolutionError("resume_handler_missing");
2503
+ attempt.resumeStarted = true;
2504
+ const attemptId = crypto.randomUUID();
2505
+ let allocated;
2506
+ try {
2507
+ allocated = await this.resumeWorkspace({
2508
+ source,
2509
+ attemptId,
2510
+ signal: attempt.controller.signal
2511
+ });
2512
+ } catch (error) {
2513
+ throw new WorkspaceTurnResolutionError("resume_failed", error);
2514
+ }
2515
+ let fetched;
2516
+ try {
2517
+ fetched = await this.client.workspaces.get(allocated.id, { signal: attempt.controller.signal });
2518
+ } catch (error) {
2519
+ throw new WorkspaceTurnResolutionError("invalid_resumed_workspace", error);
2520
+ }
2521
+ this.assertLineage(source, fetched);
2522
+ try {
2523
+ return {
2524
+ workspace: await this.client.workspaces.waitForReady(fetched, requireRemaining(deadline, "readiness_failed"), { signal: attempt.controller.signal }),
2525
+ resumed: true
2526
+ };
2527
+ } catch (error) {
2528
+ if (error instanceof WorkspaceTurnResolutionError) throw error;
2529
+ throw new WorkspaceTurnResolutionError("readiness_failed", error);
2530
+ }
2531
+ }
2532
+ async waitForPreserved(initial, deadline, signal) {
2533
+ let workspace = initial;
2534
+ while (workspace.state === "preserving") {
2535
+ const remaining = requireRemaining(deadline, "resume_failed");
2536
+ try {
2537
+ workspace = (await this.client.workspaces.change(workspace.id, workspace.change_cursor, Math.max(1, Math.min(30, Math.ceil(remaining / 1e3))), { signal })).workspace;
2538
+ } catch (error) {
2539
+ if (signal.aborted) throw error;
2540
+ throw new WorkspaceTurnResolutionError("resume_failed", error);
2541
+ }
2542
+ }
2543
+ if (workspace.state === "failed") throw new WorkspaceTurnResolutionError("resume_failed");
2544
+ return workspace;
2545
+ }
2546
+ assertResumable(workspace) {
2547
+ if (workspace.state !== "preserved" || NON_RESUMABLE_STATES.has(workspace.state) || workspace.persistence.conversation_resume.status !== "supported" || !workspace.persistence.latest_checkpoint_id) throw new WorkspaceTurnResolutionError("not_resumable");
2548
+ }
2549
+ assertLineage(source, resumedWorkspace) {
2550
+ if (resumedWorkspace.id === source.id || resumedWorkspace.origin_workspace_id !== source.id || resumedWorkspace.restored_from_checkpoint_id !== source.persistence.latest_checkpoint_id) throw new WorkspaceTurnResolutionError("invalid_resumed_workspace");
2551
+ }
2552
+ };
2553
+ //#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 };
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "type:library"
7
7
  ]
8
8
  },
9
- "version": "0.3.1",
9
+ "version": "0.5.0",
10
10
  "private": false,
11
11
  "description": "Runtime-validated TypeScript client for the PocketCoder control plane.",
12
12
  "type": "module",