@opengeni/contracts 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -8,7 +8,295 @@ var SessionStatus = z.enum([
8
8
  "failed",
9
9
  "cancelled"
10
10
  ]);
11
- var SandboxBackend = z.enum(["docker", "modal", "local", "none"]);
11
+ var SandboxBackend = z.enum([
12
+ "docker",
13
+ "modal",
14
+ "local",
15
+ "none",
16
+ "daytona",
17
+ "runloop",
18
+ "e2b",
19
+ "blaxel",
20
+ "cloudflare",
21
+ "vercel"
22
+ ]);
23
+ var SandboxOs = z.enum(["linux", "macos", "windows"]);
24
+ var SandboxCapabilityName = z.enum([
25
+ "FileSystem",
26
+ // Channel A: list/read/write/search (Pierre tree)
27
+ "Terminal",
28
+ // Channel A: command-output firehose (+ future pty-ws)
29
+ "Git",
30
+ // Channel A: status/diff/log/show (Pierre diff)
31
+ "DesktopStream",
32
+ // Channel B: noVNC pixels over a scoped tunnel URL
33
+ "Recording"
34
+ // ffmpeg x11grab -> object storage
35
+ ]);
36
+ var DESKTOP_STREAM_PORT = 6080;
37
+ var TERMINAL_STREAM_PORT = 7681;
38
+ var CAPABILITY_DESCRIPTORS = {
39
+ modal: {
40
+ backend: "modal",
41
+ backendId: "modal",
42
+ tier: "desktop",
43
+ os: { supported: ["linux"], default: "linux" },
44
+ capabilities: {
45
+ FileSystem: { available: true, readOnly: false },
46
+ Terminal: { available: true, transport: "sse-events", pty: true },
47
+ Git: { available: true },
48
+ DesktopStream: { available: true, transport: "vnc-ws" },
49
+ Recording: { available: true }
50
+ },
51
+ lifetime: {
52
+ hardLifetimeMs: 24 * 60 * 60 * 1e3,
53
+ requiresSnapshotRollover: true,
54
+ hasIdleKiller: true,
55
+ supportsSuspendResume: true,
56
+ resumeIsLockFree: true
57
+ },
58
+ snapshot: { kind: "native-fs", hasTarFallback: true },
59
+ portExposure: { kind: "provider-tunnel", supportsOnDemandPorts: false },
60
+ // pre-declare 6080
61
+ workspaceRoot: "/workspace",
62
+ nativeBucketMount: true,
63
+ persistable: true,
64
+ supportsRunAs: true
65
+ },
66
+ daytona: {
67
+ backend: "daytona",
68
+ backendId: "daytona",
69
+ tier: "desktop",
70
+ os: { supported: ["linux"], default: "linux" },
71
+ capabilities: {
72
+ FileSystem: { available: true, readOnly: false },
73
+ Terminal: { available: true, transport: "sse-events", pty: true },
74
+ Git: { available: true },
75
+ DesktopStream: { available: true, transport: "vnc-ws" },
76
+ Recording: { available: true }
77
+ },
78
+ lifetime: {
79
+ requiresSnapshotRollover: false,
80
+ hasIdleKiller: true,
81
+ supportsSuspendResume: true,
82
+ resumeIsLockFree: false
83
+ },
84
+ snapshot: { kind: "native-snapshot-id", hasTarFallback: true },
85
+ portExposure: { kind: "preview-url", supportsOnDemandPorts: false },
86
+ workspaceRoot: "/workspace",
87
+ nativeBucketMount: false,
88
+ persistable: true,
89
+ supportsRunAs: true
90
+ },
91
+ runloop: {
92
+ backend: "runloop",
93
+ backendId: "runloop",
94
+ tier: "desktop",
95
+ os: { supported: ["linux"], default: "linux" },
96
+ capabilities: {
97
+ FileSystem: { available: true, readOnly: false },
98
+ Terminal: { available: true, transport: "sse-events", pty: false },
99
+ Git: { available: true },
100
+ DesktopStream: { available: true, transport: "vnc-ws" },
101
+ Recording: { available: true }
102
+ },
103
+ lifetime: {
104
+ requiresSnapshotRollover: false,
105
+ hasIdleKiller: true,
106
+ supportsSuspendResume: true,
107
+ resumeIsLockFree: false
108
+ },
109
+ snapshot: { kind: "native-snapshot-id", hasTarFallback: true },
110
+ portExposure: { kind: "provider-tunnel", supportsOnDemandPorts: false },
111
+ // CR9: pre-declare 6080
112
+ workspaceRoot: "/workspace",
113
+ nativeBucketMount: false,
114
+ persistable: true,
115
+ supportsRunAs: false
116
+ },
117
+ e2b: {
118
+ backend: "e2b",
119
+ backendId: "e2b",
120
+ tier: "desktop",
121
+ os: { supported: ["linux"], default: "linux" },
122
+ capabilities: {
123
+ FileSystem: { available: true, readOnly: false },
124
+ Terminal: { available: true, transport: "sse-events", pty: false },
125
+ // pty-until-proven=no
126
+ Git: { available: true },
127
+ DesktopStream: { available: true, transport: "vnc-ws" },
128
+ Recording: { available: true }
129
+ },
130
+ lifetime: {
131
+ requiresSnapshotRollover: false,
132
+ hasIdleKiller: true,
133
+ supportsSuspendResume: true,
134
+ resumeIsLockFree: false
135
+ },
136
+ snapshot: { kind: "native-snapshot-id", hasTarFallback: true },
137
+ portExposure: { kind: "preview-url", supportsOnDemandPorts: false },
138
+ workspaceRoot: "/home/user",
139
+ nativeBucketMount: false,
140
+ persistable: true,
141
+ supportsRunAs: false
142
+ },
143
+ blaxel: {
144
+ backend: "blaxel",
145
+ backendId: "blaxel",
146
+ tier: "desktop",
147
+ os: { supported: ["linux"], default: "linux" },
148
+ capabilities: {
149
+ FileSystem: { available: true, readOnly: false },
150
+ Terminal: { available: true, transport: "sse-events", pty: false },
151
+ // pty-until-proven=no
152
+ Git: { available: true },
153
+ DesktopStream: { available: true, transport: "vnc-ws" },
154
+ Recording: { available: true }
155
+ },
156
+ lifetime: {
157
+ requiresSnapshotRollover: false,
158
+ hasIdleKiller: true,
159
+ supportsSuspendResume: false,
160
+ resumeIsLockFree: false
161
+ },
162
+ snapshot: { kind: "tar-only", hasTarFallback: true },
163
+ portExposure: { kind: "provider-tunnel", supportsOnDemandPorts: true },
164
+ // only on-demand backend
165
+ workspaceRoot: "/workspace",
166
+ nativeBucketMount: false,
167
+ persistable: true,
168
+ supportsRunAs: false
169
+ },
170
+ cloudflare: {
171
+ backend: "cloudflare",
172
+ backendId: "cloudflare",
173
+ tier: "headless",
174
+ os: { supported: ["linux"], default: "linux" },
175
+ capabilities: {
176
+ FileSystem: { available: true, readOnly: false },
177
+ Terminal: { available: true, transport: "sse-events", pty: true },
178
+ Git: { available: true },
179
+ DesktopStream: { available: false, transport: null },
180
+ Recording: { available: false }
181
+ },
182
+ lifetime: {
183
+ requiresSnapshotRollover: false,
184
+ hasIdleKiller: true,
185
+ supportsSuspendResume: false,
186
+ resumeIsLockFree: false
187
+ },
188
+ snapshot: { kind: "tar-only", hasTarFallback: true },
189
+ portExposure: { kind: "provider-tunnel", supportsOnDemandPorts: false },
190
+ workspaceRoot: "/workspace",
191
+ nativeBucketMount: false,
192
+ persistable: true,
193
+ supportsRunAs: true
194
+ },
195
+ vercel: {
196
+ backend: "vercel",
197
+ backendId: "vercel",
198
+ tier: "headless",
199
+ os: { supported: ["linux"], default: "linux" },
200
+ capabilities: {
201
+ FileSystem: { available: true, readOnly: false },
202
+ Terminal: { available: true, transport: "sse-events", pty: false },
203
+ Git: { available: true },
204
+ DesktopStream: { available: false, transport: null },
205
+ Recording: { available: false }
206
+ },
207
+ lifetime: {
208
+ hardLifetimeMs: 5 * 60 * 60 * 1e3,
209
+ requiresSnapshotRollover: true,
210
+ hasIdleKiller: true,
211
+ supportsSuspendResume: true,
212
+ resumeIsLockFree: false
213
+ },
214
+ snapshot: { kind: "tar-only", hasTarFallback: true },
215
+ portExposure: { kind: "preview-url", supportsOnDemandPorts: false },
216
+ workspaceRoot: "/vercel/sandbox",
217
+ nativeBucketMount: false,
218
+ persistable: true,
219
+ supportsRunAs: false
220
+ },
221
+ docker: {
222
+ backend: "docker",
223
+ backendId: "docker",
224
+ tier: "dev",
225
+ os: { supported: ["linux"], default: "linux" },
226
+ capabilities: {
227
+ FileSystem: { available: true, readOnly: false },
228
+ Terminal: { available: true, transport: "sse-events", pty: true },
229
+ Git: { available: true },
230
+ DesktopStream: { available: false, transport: null },
231
+ // local
232
+ Recording: { available: false }
233
+ },
234
+ lifetime: {
235
+ requiresSnapshotRollover: false,
236
+ hasIdleKiller: false,
237
+ supportsSuspendResume: false,
238
+ resumeIsLockFree: true
239
+ },
240
+ snapshot: { kind: "native-dir", hasTarFallback: true },
241
+ portExposure: { kind: "local-port", supportsOnDemandPorts: false },
242
+ workspaceRoot: "/workspace",
243
+ nativeBucketMount: false,
244
+ persistable: true,
245
+ supportsRunAs: true
246
+ },
247
+ local: {
248
+ backend: "local",
249
+ // The SDK's UnixLocalSandboxClient reports backendId "unix_local" — this MUST
250
+ // match it (it is the resume-fence field compared against client.backendId).
251
+ backendId: "unix_local",
252
+ tier: "dev",
253
+ os: { supported: ["linux"], default: "linux" },
254
+ capabilities: {
255
+ FileSystem: { available: true, readOnly: false },
256
+ Terminal: { available: true, transport: "sse-events", pty: true },
257
+ Git: { available: true },
258
+ DesktopStream: { available: false, transport: null },
259
+ Recording: { available: false }
260
+ },
261
+ lifetime: {
262
+ requiresSnapshotRollover: false,
263
+ hasIdleKiller: false,
264
+ supportsSuspendResume: false,
265
+ resumeIsLockFree: true
266
+ },
267
+ snapshot: { kind: "native-dir", hasTarFallback: true },
268
+ portExposure: { kind: "local-port", supportsOnDemandPorts: false },
269
+ workspaceRoot: "/workspace",
270
+ nativeBucketMount: false,
271
+ persistable: false,
272
+ supportsRunAs: false
273
+ },
274
+ none: {
275
+ backend: "none",
276
+ backendId: "none",
277
+ tier: "none",
278
+ os: { supported: ["linux"], default: "linux" },
279
+ capabilities: {
280
+ FileSystem: { available: false, readOnly: true },
281
+ Terminal: { available: false, transport: null, pty: false },
282
+ Git: { available: false },
283
+ DesktopStream: { available: false, transport: null },
284
+ Recording: { available: false }
285
+ },
286
+ lifetime: {
287
+ requiresSnapshotRollover: false,
288
+ hasIdleKiller: false,
289
+ supportsSuspendResume: false,
290
+ resumeIsLockFree: true
291
+ },
292
+ snapshot: { kind: "none", hasTarFallback: false },
293
+ portExposure: { kind: "none", supportsOnDemandPorts: false },
294
+ workspaceRoot: "/workspace",
295
+ nativeBucketMount: false,
296
+ persistable: false,
297
+ supportsRunAs: false
298
+ }
299
+ };
12
300
  var ReasoningEffort = z.enum(["none", "minimal", "low", "medium", "high", "xhigh"]);
13
301
  var ErrorCode = z.enum([
14
302
  "unauthenticated",
@@ -53,8 +341,28 @@ var Permission = z.enum([
53
341
  "sessions:create",
54
342
  "sessions:read",
55
343
  "sessions:control",
344
+ // Sandbox-surfacing (master-spine §C.3 / crosscut PART 1.2). stream:view is a
345
+ // REAL, distinct permission — strictly BROADER than sessions:read — because the
346
+ // pixel plane (Channel B) is UN-REDACTED: a viewer of raw pixels can see cloud
347
+ // creds the agent cat's into a terminal, which the redacted Channel-A event log
348
+ // never exposes. sessions:read is NOT permission to watch raw pixels.
349
+ "stream:view",
350
+ // SEPARATE from stream:view: raw input to the desktop (bypasses approvalQueue /
351
+ // interrupt). NEVER granted by default in v1 (the input plane is OFF —
352
+ // streamControlEnabled=false); the permission exists so later hardening is a
353
+ // flag flip, not a redesign.
354
+ "stream:control",
355
+ // Accept the pixel-plane secret-leak acknowledgment (consent gate before the
356
+ // un-redacted desktop URL is handed out).
357
+ "stream:acknowledge",
56
358
  "files:upload",
57
359
  "files:read",
360
+ // Channel-A structured write surface (FS writes / apply-patch); distinct from
361
+ // files:read so a read-only viewer can't mutate the box filesystem.
362
+ "files:write",
363
+ // Attach to an interactive PTY (terminal-as-pty, Channel A); distinct from
364
+ // sessions:read which only reads the command-output firehose.
365
+ "terminal:attach",
58
366
  "documents:manage",
59
367
  "documents:search",
60
368
  "scheduled_tasks:manage",
@@ -157,6 +465,53 @@ async function verifyDelegatedAccessToken(secret, token, nowSeconds = Math.floor
157
465
  }
158
466
  return payload.data;
159
467
  }
468
+ var StreamTokenPayload = z.object({
469
+ workspaceId: z.string().uuid(),
470
+ sessionId: z.string().uuid(),
471
+ // Identifies the sandbox_lease_holders row (the viewer holder).
472
+ viewerId: z.string().uuid(),
473
+ // Fence: the token logically dies when the box is re-elected (epoch++).
474
+ leaseEpoch: z.number().int().nonnegative(),
475
+ // v1 is always "view"; "control" is the never-granted raw-input plane.
476
+ mode: z.enum(["view", "control"]),
477
+ // 6080 (noVNC); pins the token to ONE exposed port.
478
+ port: z.number().int().positive(),
479
+ // Short TTL (120s default); rotation is event-driven under the epoch fence,
480
+ // not on a keepalive clock.
481
+ exp: z.number().int().positive()
482
+ });
483
+ async function signStreamToken(secret, payload) {
484
+ const encodedPayload = base64UrlEncode(JSON.stringify(StreamTokenPayload.parse(payload)));
485
+ const signature = await hmacSha256Base64Url(secret, encodedPayload);
486
+ return `ogs_${encodedPayload}.${signature}`;
487
+ }
488
+ async function verifyStreamToken(secret, token, nowSeconds = Math.floor(Date.now() / 1e3)) {
489
+ if (!token.startsWith("ogs_")) {
490
+ return null;
491
+ }
492
+ const withoutPrefix = token.slice("ogs_".length);
493
+ const dot = withoutPrefix.lastIndexOf(".");
494
+ if (dot <= 0) {
495
+ return null;
496
+ }
497
+ const encodedPayload = withoutPrefix.slice(0, dot);
498
+ const signature = withoutPrefix.slice(dot + 1);
499
+ const expected = await hmacSha256Base64Url(secret, encodedPayload);
500
+ if (!constantTimeEqual(signature, expected)) {
501
+ return null;
502
+ }
503
+ let decoded;
504
+ try {
505
+ decoded = JSON.parse(base64UrlDecode(encodedPayload));
506
+ } catch {
507
+ return null;
508
+ }
509
+ const payload = StreamTokenPayload.safeParse(decoded);
510
+ if (!payload.success || payload.data.exp < nowSeconds) {
511
+ return null;
512
+ }
513
+ return payload.data;
514
+ }
160
515
  var CreateWorkspaceRequest = z.object({
161
516
  accountId: z.string().uuid().optional(),
162
517
  name: z.string().min(1),
@@ -197,6 +552,27 @@ var CreateApiKeyResponse = z.object({
197
552
  apiKey: ApiKey,
198
553
  token: z.string().min(1)
199
554
  });
555
+ var WorkspaceMember = z.object({
556
+ subjectId: z.string().min(1),
557
+ subjectLabel: z.string().nullable(),
558
+ role: z.string(),
559
+ permissions: z.array(Permission),
560
+ createdAt: z.string()
561
+ });
562
+ var ListWorkspaceMembersResponse = z.object({
563
+ members: z.array(WorkspaceMember)
564
+ });
565
+ var AddWorkspaceMemberRequest = z.object({
566
+ // Resolved against the managed (Better Auth) users; email invites for
567
+ // not-yet-registered users are deferred, so an unknown email returns 404.
568
+ email: z.string().email(),
569
+ role: z.string().min(1).optional(),
570
+ permissions: z.array(Permission)
571
+ });
572
+ var UpdateWorkspaceMemberRequest = z.object({
573
+ role: z.string().min(1).optional(),
574
+ permissions: z.array(Permission)
575
+ });
200
576
  var UsageEventType = z.enum([
201
577
  "agent_run.created",
202
578
  "agent_run.completed",
@@ -206,7 +582,16 @@ var UsageEventType = z.enum([
206
582
  "file.deleted",
207
583
  "document.indexed",
208
584
  "scheduled_task.fired",
209
- "api_key.request"
585
+ "api_key.request",
586
+ // --- sandbox warm-time metering (P2.1) ---
587
+ // Wall-clock seconds a box was warm — the billable warm-time meter. Accrued on
588
+ // the two stateless ticks (turn heartbeat + reaper sweep), idempotent on
589
+ // (sandbox_group_id, lease_epoch, tick) so a shared box (N sessions) is metered
590
+ // EXACTLY ONCE per tick (N sessions != N x bill). Orthogonal to model.tokens /
591
+ // model.cost (model API cost vs provider compute cost — both real, no overlap).
592
+ "sandbox.warm_seconds",
593
+ // usd_micros: warm-seconds x the per-provider per-second warm rate.
594
+ "sandbox.warm_cost"
210
595
  ]);
211
596
  var UsageEvent = z.object({
212
597
  id: z.string().uuid(),
@@ -481,6 +866,9 @@ var UpdateSessionGoalRequest = z.object({
481
866
  status: z.enum(["paused", "active"]),
482
867
  rationale: z.string().min(1).optional()
483
868
  });
869
+ var UpdateSessionRequest = z.object({
870
+ title: z.string().min(1).max(200)
871
+ });
484
872
  var ClearSessionContextRequest = z.object({
485
873
  confirm: z.literal(true)
486
874
  });
@@ -519,6 +907,8 @@ var SessionTurn = z.object({
519
907
  model: z.string().min(1),
520
908
  reasoningEffort: ReasoningEffort,
521
909
  sandboxBackend: SandboxBackend,
910
+ // Per-turn OS override. NULL = inherit the session's sandboxOs.
911
+ sandboxOs: SandboxOs.nullable(),
522
912
  metadata: z.record(z.string(), z.unknown()),
523
913
  startedAt: z.string().nullable(),
524
914
  finishedAt: z.string().nullable(),
@@ -943,11 +1333,19 @@ var Session = z.object({
943
1333
  accountId: z.string().uuid(),
944
1334
  status: SessionStatus,
945
1335
  initialMessage: z.string(),
1336
+ title: z.string().nullable(),
1337
+ titleSource: z.enum(["user", "agent"]).nullable(),
946
1338
  resources: z.array(ResourceRef),
947
1339
  tools: z.array(ToolRef),
948
1340
  metadata: z.record(z.string(), z.unknown()),
949
1341
  model: z.string(),
950
1342
  sandboxBackend: SandboxBackend,
1343
+ // The OS the session's box runs. Defaults to 'linux' (today's only OS).
1344
+ sandboxOs: SandboxOs,
1345
+ // The shared-sandbox group the session's box belongs to. Equals the session's
1346
+ // own id for a singleton group (today's 1:1 default); equals the parent's
1347
+ // group when spawned shared (both sessions run in ONE box).
1348
+ sandboxGroupId: z.string().uuid(),
951
1349
  environmentId: z.string().uuid().nullable(),
952
1350
  // Non-default first-party MCP token permissions (manager-style sessions);
953
1351
  // null means the fixed worker default set.
@@ -1003,8 +1401,433 @@ var SessionEventType = z.enum([
1003
1401
  "goal.completed",
1004
1402
  "goal.paused",
1005
1403
  "goal.resumed",
1006
- "goal.continuation"
1404
+ "goal.continuation",
1405
+ // Channel-B desktop pixel-plane signals (07-channel-b §1.2). The pixel socket
1406
+ // carries opaque RFB and cannot carry a control message the client can act on,
1407
+ // so these ride the durable, sequenced, gap-filled Channel-A SSE spine.
1408
+ "stream.url.rotated",
1409
+ // re-minted {url,token,expiresAt} on box rollover (event-driven)
1410
+ "stream.opened",
1411
+ // a viewer attached (audit + refcount visibility)
1412
+ "stream.closed",
1413
+ // a viewer detached / was reaped
1414
+ "stream.revoked",
1415
+ // a grant was revoked → connected clients MUST disconnect now
1416
+ // Channel-B recording signals (P4.3 / module 05 §3.4). The "agent films itself
1417
+ // proving the fix" loop: ffmpeg x11grab of the SAME :0 humans watch → artifact
1418
+ // → storage. The artifact ref rides the AVAILABLE event (storageKey, NOT a
1419
+ // long-lived URL — clients mint a short-TTL signed GET via the route).
1420
+ "recording.started",
1421
+ // ffmpeg launched on :0 (mode/codec/dimensions)
1422
+ "recording.available",
1423
+ // finalized: bytes PUT to storage, replayable
1424
+ "recording.failed",
1425
+ // ffmpeg/box-death/rollover/upload error — no artifact
1426
+ // Channel-A structured-service notifications (P4.4 / modules/08-channel-a.md
1427
+ // §2.2). The A2 reads (fs/git/terminal exec) are SYNCHRONOUS API-direct point
1428
+ // queries (their result is the HTTP response, NEVER an event). What rides A1
1429
+ // here are the side-effect NOTIFICATIONS — a path changed, git state changed,
1430
+ // a pty opened/printed/exited — durable, sequenced, gap-filled like every
1431
+ // other session event, so any viewer's Pierre tree / diff / terminal stays
1432
+ // live. fs.changed/git.changed are cache-invalidation signals; the pty.*
1433
+ // events carry the interactive terminal byte stream.
1434
+ "fs.changed",
1435
+ // a path was created/modified/deleted (write or agent mutation)
1436
+ "git.changed",
1437
+ // working-tree/index/HEAD changed (debounced re-probe)
1438
+ "terminal.pty.started",
1439
+ // an interactive PTY session opened (carries ptyId)
1440
+ "terminal.pty.output.delta",
1441
+ // PTY stdout/stderr bytes (separate from command.output)
1442
+ "terminal.pty.exited",
1443
+ // PTY session ended (exitCode/reason)
1444
+ "session.title_set"
1445
+ ]);
1446
+ var StreamUrlRotatedPayload = z.object({
1447
+ url: z.string().url(),
1448
+ token: z.string().nullable(),
1449
+ expiresAt: z.string().datetime().nullable(),
1450
+ // The epoch the new URL was minted under (the box-rollover fence the client
1451
+ // reconciles against). A client must drop a rotation event whose epoch it has
1452
+ // already advanced past.
1453
+ leaseEpoch: z.number().int().nonnegative(),
1454
+ transport: z.literal("vnc-ws"),
1455
+ // The viewer holder this URL is for (so a client filters out other viewers').
1456
+ viewerId: z.string().uuid().nullable().default(null)
1457
+ });
1458
+ var StreamOpenedPayload = z.object({
1459
+ viewerId: z.string().uuid(),
1460
+ shared: z.boolean().default(false),
1461
+ viewerCount: z.number().int().nonnegative()
1462
+ });
1463
+ var StreamClosedPayload = z.object({
1464
+ viewerId: z.string().uuid(),
1465
+ reason: z.enum(["client-disconnect", "reaped", "revoked", "box-rollover"]),
1466
+ viewerCount: z.number().int().nonnegative()
1467
+ });
1468
+ var StreamRevokedPayload = z.object({
1469
+ viewerId: z.string().uuid().nullable().default(null),
1470
+ reason: z.enum(["grant-revoked", "session-failed", "admin"])
1471
+ });
1472
+ var RecordingMode = z.enum(["manual", "on-turn", "on-verify"]);
1473
+ var RecordingCodec = z.enum(["h264-mp4", "vp9-webm"]);
1474
+ var RecordingContentType = z.enum(["video/mp4", "video/webm"]);
1475
+ var RecordingStartedPayload = z.object({
1476
+ recordingId: z.string().uuid(),
1477
+ turnId: z.string().uuid().nullable(),
1478
+ mode: RecordingMode,
1479
+ codec: RecordingCodec,
1480
+ dimensions: z.tuple([z.number().int().positive(), z.number().int().positive()]),
1481
+ framerate: z.number().int().positive(),
1482
+ startedAt: z.string(),
1483
+ // ISO
1484
+ // The verification rationale ("agent-verification: tf apply succeeded"). Agent-
1485
+ // authored free text — the producer caps + scrubs it before emit.
1486
+ reason: z.string().nullable().optional()
1487
+ });
1488
+ var RecordingAvailablePayload = z.object({
1489
+ recordingId: z.string().uuid(),
1490
+ turnId: z.string().uuid().nullable(),
1491
+ codec: RecordingCodec,
1492
+ contentType: RecordingContentType,
1493
+ // The @opengeni/storage object key. NO long-lived URL in the event — clients
1494
+ // mint a short-TTL signed GET via GET …/recordings/:id/url.
1495
+ storageKey: z.string(),
1496
+ durationSeconds: z.number().nonnegative().nullable(),
1497
+ sizeBytes: z.number().int().nonnegative(),
1498
+ dimensions: z.tuple([z.number().int().positive(), z.number().int().positive()])
1499
+ });
1500
+ var RecordingFailedReason = z.enum([
1501
+ "ffmpeg-error",
1502
+ "box-death",
1503
+ "box-rollover",
1504
+ "upload-failed",
1505
+ "max-bytes-exceeded",
1506
+ "display-unavailable"
1507
+ ]);
1508
+ var RecordingFailedPayload = z.object({
1509
+ recordingId: z.string().uuid(),
1510
+ turnId: z.string().uuid().nullable(),
1511
+ reason: RecordingFailedReason,
1512
+ // ffmpeg-stderr tail / error detail — agent/ffmpeg-controlled, so the producer
1513
+ // caps + scrubs it before emit (it rides redact() like every payload).
1514
+ detail: z.string().nullable().optional()
1515
+ });
1516
+ var SandboxCommandOutputDeltaPayload = z.object({
1517
+ stream: z.enum(["stdout", "stderr"]).default("stdout"),
1518
+ chunk: z.string(),
1519
+ // raw bytes, utf-8 (lossy) — terminal is opaque-ish
1520
+ commandId: z.string().optional(),
1521
+ // groups deltas to one agent command
1522
+ seq: z.number().int().nonnegative().optional()
1523
+ // intra-command ordering hint
1524
+ });
1525
+ var FsChangeKind = z.enum(["created", "modified", "deleted", "renamed"]);
1526
+ var FsChangedPayload = z.object({
1527
+ changes: z.array(z.object({
1528
+ path: z.string(),
1529
+ // workspace-relative POSIX path
1530
+ kind: FsChangeKind,
1531
+ isDir: z.boolean().default(false),
1532
+ sizeBytes: z.number().int().nonnegative().nullable().default(null),
1533
+ oldPath: z.string().optional()
1534
+ // for "renamed"
1535
+ })).min(1),
1536
+ source: z.enum(["write", "watch", "agent"]).default("write"),
1537
+ // Monotonic FS revision (per-lease, paired with leaseEpoch for staleness).
1538
+ revision: z.number().int().nonnegative(),
1539
+ // The lease epoch the revision was minted under: a client invalidates on a
1540
+ // (leaseEpoch, revision) tuple change, never a bare revision compare (H3 —
1541
+ // revision resets to 0 on box re-key, so a bare monotonic compare goes stale).
1542
+ leaseEpoch: z.number().int().nonnegative().default(0)
1543
+ });
1544
+ var GitChangedPayload = z.object({
1545
+ head: z.string().nullable(),
1546
+ // current branch or detached SHA
1547
+ dirty: z.boolean(),
1548
+ // working tree has uncommitted changes
1549
+ ahead: z.number().int().nonnegative().default(0),
1550
+ behind: z.number().int().nonnegative().default(0),
1551
+ changedFileCount: z.number().int().nonnegative(),
1552
+ reason: z.enum(["commit", "checkout", "stage", "worktree", "fetch", "unknown"]).default("unknown"),
1553
+ revision: z.number().int().nonnegative().default(0),
1554
+ leaseEpoch: z.number().int().nonnegative().default(0)
1555
+ });
1556
+ var TerminalPtyStartedPayload = z.object({
1557
+ ptyId: z.string().uuid(),
1558
+ cols: z.number().int().positive(),
1559
+ rows: z.number().int().positive(),
1560
+ shell: z.string(),
1561
+ // resolved shell, e.g. "/bin/bash"
1562
+ cwd: z.string()
1563
+ });
1564
+ var TerminalPtyOutputDeltaPayload = z.object({
1565
+ ptyId: z.string().uuid(),
1566
+ stream: z.enum(["stdout", "stderr"]).default("stdout"),
1567
+ chunk: z.string(),
1568
+ // raw terminal bytes (incl. ANSI), utf-8 lossy
1569
+ seq: z.number().int().nonnegative()
1570
+ // strict per-pty ordering (owner-assigned)
1571
+ });
1572
+ var TerminalPtyExitedPayload = z.object({
1573
+ ptyId: z.string().uuid(),
1574
+ exitCode: z.number().int().nullable(),
1575
+ reason: z.enum(["exit", "killed", "owner_gone", "timeout"])
1576
+ });
1577
+ var FsNodeType = z.enum(["file", "dir", "symlink", "other"]);
1578
+ var FsTreeNode = z.lazy(() => z.object({
1579
+ name: z.string(),
1580
+ path: z.string(),
1581
+ type: FsNodeType,
1582
+ sizeBytes: z.number().int().nonnegative().nullable(),
1583
+ mtimeMs: z.number().int().nonnegative().nullable(),
1584
+ mode: z.number().int().nullable(),
1585
+ children: z.array(FsTreeNode).optional(),
1586
+ truncated: z.boolean().default(false)
1587
+ }));
1588
+ var FsListRequest = z.object({
1589
+ path: z.string().default(""),
1590
+ // "" = workspace root
1591
+ depth: z.number().int().min(0).max(8).default(1),
1592
+ maxEntries: z.number().int().positive().max(2e4).default(2e3),
1593
+ includeHidden: z.boolean().default(true)
1594
+ });
1595
+ var FsListResponse = z.object({
1596
+ root: FsTreeNode,
1597
+ revision: z.number().int().nonnegative(),
1598
+ truncated: z.boolean()
1599
+ // global cap hit
1600
+ });
1601
+ var FsEncoding = z.enum(["utf8", "base64"]);
1602
+ var FsReadRequest = z.object({
1603
+ path: z.string(),
1604
+ encoding: FsEncoding.default("utf8"),
1605
+ maxBytes: z.number().int().positive().max(25 * 1024 * 1024).default(5 * 1024 * 1024)
1606
+ });
1607
+ var FsReadResponse = z.object({
1608
+ path: z.string(),
1609
+ encoding: FsEncoding,
1610
+ content: z.string(),
1611
+ // text or base64 per encoding
1612
+ sizeBytes: z.number().int().nonnegative(),
1613
+ // bytes returned (== content size)
1614
+ truncated: z.boolean(),
1615
+ // sizeBytes hit maxBytes; content is the prefix
1616
+ isBinary: z.boolean(),
1617
+ // sniffed NUL byte in first 8KB
1618
+ revision: z.number().int().nonnegative()
1619
+ });
1620
+ var FsWriteRequest = z.object({
1621
+ path: z.string(),
1622
+ encoding: FsEncoding.default("utf8"),
1623
+ content: z.string(),
1624
+ overwrite: z.boolean().default(true),
1625
+ // false + existing path => 409
1626
+ createParents: z.boolean().default(true)
1627
+ });
1628
+ var FsWriteResponse = z.object({
1629
+ path: z.string(),
1630
+ sizeBytes: z.number().int().nonnegative(),
1631
+ revision: z.number().int().nonnegative()
1632
+ // == the fs.changed revision
1633
+ });
1634
+ var FsDeleteRequest = z.object({
1635
+ path: z.string(),
1636
+ recursive: z.boolean().default(false)
1637
+ // required true to delete a non-empty dir
1638
+ });
1639
+ var FsDeleteResponse = z.object({ revision: z.number().int().nonnegative() });
1640
+ var FsMoveRequest = z.object({
1641
+ path: z.string(),
1642
+ newPath: z.string(),
1643
+ overwrite: z.boolean().default(false),
1644
+ // false + existing destination => 409
1645
+ createParents: z.boolean().default(true)
1646
+ });
1647
+ var FsMoveResponse = z.object({
1648
+ path: z.string(),
1649
+ newPath: z.string(),
1650
+ revision: z.number().int().nonnegative()
1651
+ // == the fs.changed revision
1652
+ });
1653
+ var FsMkdirRequest = z.object({
1654
+ path: z.string(),
1655
+ recursive: z.boolean().default(true)
1656
+ // false + existing path => 400
1657
+ });
1658
+ var FsMkdirResponse = z.object({
1659
+ path: z.string(),
1660
+ revision: z.number().int().nonnegative()
1661
+ // == the fs.changed revision
1662
+ });
1663
+ var GitFileStatusCode = z.enum([
1664
+ "added",
1665
+ "modified",
1666
+ "deleted",
1667
+ "renamed",
1668
+ "copied",
1669
+ "untracked",
1670
+ "ignored",
1671
+ "conflicted",
1672
+ "typechange"
1007
1673
  ]);
1674
+ var GitFileStatus = z.object({
1675
+ path: z.string(),
1676
+ oldPath: z.string().nullable(),
1677
+ // for renamed/copied
1678
+ index: GitFileStatusCode.nullable(),
1679
+ // staged change (X in porcelain XY)
1680
+ worktree: GitFileStatusCode.nullable(),
1681
+ // unstaged change (Y in porcelain XY)
1682
+ isConflicted: z.boolean().default(false)
1683
+ });
1684
+ var GitStatusRequest = z.object({
1685
+ path: z.string().default("")
1686
+ // repo root within workspace (multi-repo support)
1687
+ });
1688
+ var GitStatusResponse = z.object({
1689
+ isRepo: z.boolean(),
1690
+ head: z.string().nullable(),
1691
+ // branch name
1692
+ detached: z.boolean().default(false),
1693
+ upstream: z.string().nullable(),
1694
+ ahead: z.number().int().nonnegative().default(0),
1695
+ behind: z.number().int().nonnegative().default(0),
1696
+ files: z.array(GitFileStatus),
1697
+ revision: z.number().int().nonnegative()
1698
+ });
1699
+ var GitDiffLineType = z.enum(["context", "add", "del", "meta"]);
1700
+ var GitDiffLine = z.object({
1701
+ type: GitDiffLineType,
1702
+ // null on the side that doesn't have the line (add => oldNo null; del => newNo null)
1703
+ oldNo: z.number().int().positive().nullable(),
1704
+ newNo: z.number().int().positive().nullable(),
1705
+ text: z.string()
1706
+ // line WITHOUT leading +/-/space marker
1707
+ });
1708
+ var GitDiffHunk = z.object({
1709
+ oldStart: z.number().int().nonnegative(),
1710
+ oldLines: z.number().int().nonnegative(),
1711
+ newStart: z.number().int().nonnegative(),
1712
+ newLines: z.number().int().nonnegative(),
1713
+ header: z.string(),
1714
+ // the @@ ... @@ section heading
1715
+ lines: z.array(GitDiffLine)
1716
+ });
1717
+ var GitFileDiff = z.object({
1718
+ path: z.string(),
1719
+ oldPath: z.string().nullable(),
1720
+ status: GitFileStatusCode,
1721
+ isBinary: z.boolean().default(false),
1722
+ isImage: z.boolean().default(false),
1723
+ additions: z.number().int().nonnegative(),
1724
+ deletions: z.number().int().nonnegative(),
1725
+ hunks: z.array(GitDiffHunk),
1726
+ // empty if binary or truncated
1727
+ truncated: z.boolean().default(false)
1728
+ // diff exceeded maxBytes; hunks omitted
1729
+ });
1730
+ var GitDiffRequest = z.object({
1731
+ path: z.string().default(""),
1732
+ // repo root
1733
+ // diff selectors, mutually exclusive precedence: refs > staged > worktree
1734
+ staged: z.boolean().default(false),
1735
+ // --cached (index vs HEAD)
1736
+ fromRef: z.string().optional(),
1737
+ toRef: z.string().optional(),
1738
+ pathspec: z.array(z.string()).default([]),
1739
+ contextLines: z.number().int().min(0).max(10).default(3),
1740
+ maxBytesPerFile: z.number().int().positive().max(2 * 1024 * 1024).default(512 * 1024)
1741
+ });
1742
+ var GitDiffResponse = z.object({
1743
+ files: z.array(GitFileDiff),
1744
+ revision: z.number().int().nonnegative()
1745
+ });
1746
+ var GitLogRequest = z.object({
1747
+ path: z.string().default(""),
1748
+ ref: z.string().default("HEAD"),
1749
+ maxCount: z.number().int().positive().max(1e3).default(100),
1750
+ skip: z.number().int().nonnegative().default(0),
1751
+ pathspec: z.array(z.string()).default([])
1752
+ });
1753
+ var GitCommit = z.object({
1754
+ sha: z.string(),
1755
+ shortSha: z.string(),
1756
+ parents: z.array(z.string()),
1757
+ author: z.object({ name: z.string(), email: z.string(), timestamp: z.number().int() }),
1758
+ committer: z.object({ name: z.string(), email: z.string(), timestamp: z.number().int() }),
1759
+ subject: z.string(),
1760
+ body: z.string(),
1761
+ refs: z.array(z.string()).default([])
1762
+ // decorations: branch/tag pointers
1763
+ });
1764
+ var GitLogResponse = z.object({ commits: z.array(GitCommit), hasMore: z.boolean() });
1765
+ var GitShowRequest = z.object({
1766
+ path: z.string().default(""),
1767
+ ref: z.string(),
1768
+ // a commit/tag/tree-ish
1769
+ filePath: z.string().optional(),
1770
+ // ref + filePath => raw blob ("open file at commit")
1771
+ encoding: FsEncoding.default("utf8"),
1772
+ maxBytesPerFile: z.number().int().positive().max(2 * 1024 * 1024).default(512 * 1024)
1773
+ });
1774
+ var GitShowResponse = z.object({
1775
+ commit: GitCommit.nullable(),
1776
+ // null when fetching a raw blob
1777
+ files: z.array(GitFileDiff),
1778
+ // commit diff vs first parent
1779
+ blob: z.object({ content: z.string(), encoding: FsEncoding, sizeBytes: z.number().int(), truncated: z.boolean() }).nullable(),
1780
+ revision: z.number().int().nonnegative()
1781
+ });
1782
+ var TerminalExecRequest = z.object({
1783
+ command: z.string().min(1),
1784
+ cwd: z.string().default(""),
1785
+ // workspace-relative
1786
+ // Soft per-call wall-clock bound (the box yields output back when reached).
1787
+ timeoutMs: z.number().int().positive().max(12e4).default(3e4),
1788
+ // Stream the deltas onto A1 as the agent firehose (so other viewers see it),
1789
+ // in addition to returning the buffered result inline.
1790
+ emitStream: z.boolean().default(true)
1791
+ });
1792
+ var TerminalExecResponse = z.object({
1793
+ stdout: z.string(),
1794
+ stderr: z.string(),
1795
+ exitCode: z.number().int().nullable(),
1796
+ // True when the process was still running when the call yielded (a long
1797
+ // command); the remaining output drains onto A1 if emitStream was set.
1798
+ running: z.boolean(),
1799
+ wallTimeSeconds: z.number().nonnegative()
1800
+ });
1801
+ var PtyOpenRequest = z.object({
1802
+ cols: z.number().int().positive().max(500).default(80),
1803
+ rows: z.number().int().positive().max(300).default(24),
1804
+ cwd: z.string().default(""),
1805
+ // workspace-relative
1806
+ shell: z.string().optional()
1807
+ // default: resolved login shell
1808
+ });
1809
+ var PtyOpenResponse = z.object({
1810
+ ptyId: z.string().uuid(),
1811
+ // output streams as terminal.pty.output.delta on the SSE channel the client holds
1812
+ streamVia: z.literal("sse-events"),
1813
+ supportsInput: z.boolean()
1814
+ // false on backends without writeStdin
1815
+ });
1816
+ var PtyWriteRequest = z.object({ ptyId: z.string().uuid(), data: z.string() });
1817
+ var PtyResizeRequest = z.object({ ptyId: z.string().uuid(), cols: z.number().int().positive(), rows: z.number().int().positive() });
1818
+ var PtyCloseRequest = z.object({ ptyId: z.string().uuid() });
1819
+ var SessionStructuredCapabilities = z.object({
1820
+ FileSystem: z.object({ available: z.boolean(), readOnly: z.boolean(), root: z.string() }),
1821
+ Terminal: z.object({
1822
+ events: z.boolean(),
1823
+ // command.output firehose (always on if a box exists)
1824
+ exec: z.boolean(),
1825
+ // synchronous terminal exec
1826
+ pty: z.object({ available: z.boolean() })
1827
+ // interactive stdin (writeStdin)
1828
+ }),
1829
+ Git: z.object({ available: z.boolean(), repos: z.array(z.string()) })
1830
+ });
1008
1831
  var SessionEvent = z.object({
1009
1832
  id: z.string().uuid(),
1010
1833
  workspaceId: z.string().uuid(),
@@ -1040,7 +1863,24 @@ var CreateSessionRequest = z.object({
1040
1863
  // the fixed worker default — how an operator hands a manager-style session
1041
1864
  // the orchestration/environment/github tools. Capped at creation: every
1042
1865
  // requested permission must be held by the creating grant (no escalation).
1043
- firstPartyMcpPermissions: z.array(Permission).optional()
1866
+ firstPartyMcpPermissions: z.array(Permission).optional(),
1867
+ // Shared-sandbox placement (addendum 05 §D.1). Three-way union; OMITTED ⇒
1868
+ // today's behavior (a context-dependent default resolved server-side: from
1869
+ // inside a session → "shared" with the creator's box, top-level → "new").
1870
+ // - "shared": join the CREATOR's box. Requires a parent session (inferred
1871
+ // from the worker-signed sessionId claim, never caller-supplied);
1872
+ // top-level "shared" is a 422.
1873
+ // - "new": mint a fresh singleton box (group ≡ the new session's id).
1874
+ // - {groupId}: join a SPECIFIC sibling group in THIS workspace (manager
1875
+ // fan-out). Validated workspace-scoped (cross-workspace → 404).
1876
+ // A shared spawn inherits the box's (backend, os) — it is literally the same
1877
+ // box; the child cannot pick its own backend. Cross-workspace sharing is
1878
+ // forbidden by construction (the parent/group reads are RLS-workspace-scoped).
1879
+ sandbox: z.union([
1880
+ z.literal("shared"),
1881
+ z.literal("new"),
1882
+ z.object({ groupId: z.string().uuid() })
1883
+ ]).optional()
1044
1884
  });
1045
1885
  var ClientSessionEvent = z.discriminatedUnion("type", [
1046
1886
  z.object({
@@ -1110,10 +1950,142 @@ var ClientAuthConfig = z.discriminatedUnion("mode", [
1110
1950
  session: z.literal("cookie")
1111
1951
  })
1112
1952
  ]);
1953
+ var CapabilityUnavailableReason = z.enum([
1954
+ "backend_unsupported",
1955
+ "os_unsupported",
1956
+ "not_provisioned",
1957
+ "disabled_by_policy",
1958
+ "lease_cold",
1959
+ "tier_headless"
1960
+ ]);
1961
+ var SessionCapabilities = z.object({
1962
+ sessionId: z.string().uuid(),
1963
+ backend: SandboxBackend,
1964
+ os: SandboxOs,
1965
+ liveness: z.enum(["cold", "warming", "warm", "draining"]),
1966
+ // Echoed on viewer heartbeats (the split-brain fence).
1967
+ leaseEpoch: z.number().int().nonnegative(),
1968
+ viewerHeartbeatIntervalMs: z.number().int().positive().default(3e4),
1969
+ FileSystem: z.object({
1970
+ available: z.boolean(),
1971
+ readOnly: z.boolean(),
1972
+ root: z.string(),
1973
+ pathSep: z.enum(["/", "\\"]),
1974
+ treeMode: z.enum(["lazy", "snapshot"]),
1975
+ reason: CapabilityUnavailableReason.nullable()
1976
+ }),
1977
+ Terminal: z.object({
1978
+ transport: z.enum(["sse-events", "pty-ws"]).nullable(),
1979
+ ptyCapable: z.boolean(),
1980
+ shell: z.string(),
1981
+ // The direct-to-provider ttyd PTY-over-websocket URL (pty-ws) resolved on the
1982
+ // SAME tunnel as the desktop; null on a cold lease / read-only sse-events
1983
+ // firehose / degraded terminal. The scoped stream token is recorded against
1984
+ // the holder (NEVER a URL query param), symmetric with DesktopStream.
1985
+ url: z.string().url().nullable(),
1986
+ token: z.string().nullable(),
1987
+ // ISO absolute expiry of the minted stream token (symmetric with
1988
+ // DesktopStream.expiresAt). Null when no live URL/token is minted.
1989
+ expiresAt: z.string().nullable(),
1990
+ reason: CapabilityUnavailableReason.nullable()
1991
+ }),
1992
+ Git: z.object({
1993
+ available: z.boolean(),
1994
+ repos: z.array(z.string()),
1995
+ reason: CapabilityUnavailableReason.nullable()
1996
+ }),
1997
+ DesktopStream: z.object({
1998
+ transport: z.enum(["vnc-ws", "rdp-ws", "webrtc"]).nullable(),
1999
+ client: z.enum(["novnc", "web-rdp"]).nullable(),
2000
+ mode: z.enum(["read-only", "interactive"]).default("read-only"),
2001
+ url: z.string().url().nullable(),
2002
+ token: z.string().nullable(),
2003
+ expiresAt: z.string().nullable(),
2004
+ resolution: z.tuple([z.number().int().positive(), z.number().int().positive()]).default([1024, 768]),
2005
+ // REQUIRED, no default (the server must assert un-redacted pixels).
2006
+ unredacted: z.boolean(),
2007
+ requiresAcknowledgment: z.boolean(),
2008
+ acknowledged: z.boolean(),
2009
+ // SHARED-EXPOSURE disclosure (addendum E.1). `shared` is true when the box's
2010
+ // group has >1 session: watching this desktop ALSO shows the sibling
2011
+ // sessions' agents on the one :0 framebuffer (the pixels cannot be redacted).
2012
+ // `sharedSessionIds` lists the OTHER sessions whose agents may appear — IDS
2013
+ // ONLY, never their goal/metadata/conversation (a viewer of A must not be
2014
+ // able to use "I can see B's id" to subscribe to B's events; stress g). When
2015
+ // shared, the consent gate requires the shared-exposure acknowledgment (409
2016
+ // shared_acknowledgment_required) before the desktop path is handed out.
2017
+ shared: z.boolean().default(false),
2018
+ sharedSessionIds: z.array(z.string().uuid()).default([]),
2019
+ reason: CapabilityUnavailableReason.nullable()
2020
+ }),
2021
+ Recording: z.object({
2022
+ available: z.boolean(),
2023
+ modes: z.array(z.enum(["manual", "on-turn", "on-verify"])),
2024
+ codecs: z.array(z.enum(["h264-mp4", "vp9-webm"])),
2025
+ reason: CapabilityUnavailableReason.nullable()
2026
+ }),
2027
+ // The AGENT drives the SAME :0 (xdotool/XTEST + scrot) the human watches; the
2028
+ // human viewer plane is read-only by default (§6). `available` == desktop-
2029
+ // capable backend && computerUseEnabled; `readOnly` reports whether the agent
2030
+ // driver itself is gated to no-op input (v1 default false — the agent clicks).
2031
+ ComputerUse: z.object({
2032
+ available: z.boolean(),
2033
+ readOnly: z.boolean(),
2034
+ reason: CapabilityUnavailableReason.nullable()
2035
+ }),
2036
+ negotiatedAt: z.string()
2037
+ });
2038
+ var AttachViewerRequest = z.object({
2039
+ viewerId: z.string().uuid().optional(),
2040
+ desktop: z.boolean().optional()
2041
+ });
2042
+ var ViewerHolder = z.object({
2043
+ viewerId: z.string().uuid(),
2044
+ sandboxGroupId: z.string().uuid(),
2045
+ liveness: z.enum(["cold", "warming", "warm", "draining"]),
2046
+ // The epoch the viewer is fenced on; echoed back on heartbeats.
2047
+ leaseEpoch: z.number().int().nonnegative(),
2048
+ viewerHeartbeatIntervalMs: z.number().int().positive(),
2049
+ // The desktop pixel tunnel URL the viewer connects to directly; null until
2050
+ // P4 mints it (gated until then).
2051
+ dataPlaneUrl: z.string().nullable()
2052
+ });
2053
+ var AcknowledgeStreamRequest = z.object({
2054
+ // The principal accepts that the desktop pixel plane is un-redacted (can show
2055
+ // cloud creds the agent cat's into a terminal). Always true to record consent;
2056
+ // present for self-documentation + a future explicit withdraw.
2057
+ acknowledgeUnredacted: z.boolean().default(true),
2058
+ // The principal accepts the shared-exposure disclosure: watching this desktop
2059
+ // also shows sibling sessions' agents on the one framebuffer.
2060
+ acknowledgeShared: z.boolean().default(false)
2061
+ });
2062
+ var AcknowledgeStreamResponse = z.object({
2063
+ acknowledged: z.boolean(),
2064
+ acknowledgedShared: z.boolean()
2065
+ });
2066
+ var ViewerHeartbeatRequest = z.object({
2067
+ leaseEpoch: z.number().int().nonnegative()
2068
+ });
2069
+ var ViewerHeartbeatResponse = z.object({
2070
+ // false ⇒ the holder was reaped or the epoch is stale; the client re-attaches.
2071
+ alive: z.boolean()
2072
+ });
2073
+ var ClientModel = z.object({
2074
+ id: z.string(),
2075
+ label: z.string(),
2076
+ provider: z.string(),
2077
+ // provider id
2078
+ providerLabel: z.string(),
2079
+ api: z.enum(["responses", "chat"]),
2080
+ contextWindowTokens: z.number().int().positive().optional()
2081
+ });
1113
2082
  var ClientConfig = z.object({
1114
2083
  deploymentRevision: z.string(),
1115
2084
  defaultModel: z.string(),
1116
2085
  allowedModels: z.array(z.string()).min(1),
2086
+ // Richer model list (provider-grouped) for the picker. Defaults to [] for
2087
+ // back-compat: callers that only read allowedModels are unaffected.
2088
+ models: z.array(ClientModel).default([]),
1117
2089
  defaultReasoningEffort: ReasoningEffort,
1118
2090
  allowedReasoningEfforts: z.array(ReasoningEffort).min(1),
1119
2091
  mcpServers: z.array(z.object({
@@ -1125,7 +2097,16 @@ var ClientConfig = z.object({
1125
2097
  maxSizeBytes: z.number().int().positive()
1126
2098
  }),
1127
2099
  productAccessMode: ProductAccessMode,
1128
- auth: ClientAuthConfig.default({ mode: "none" })
2100
+ auth: ClientAuthConfig.default({ mode: "none" }),
2101
+ // Server-wide hint: does this deployment support Channel-A structured services
2102
+ // at all (P4.4). Per-session availability is negotiated on /stream-capabilities
2103
+ // (it depends on the session's pinned backend); this is the coarse on/off the
2104
+ // client uses to decide whether to even attempt the fs/git/terminal panels.
2105
+ structuredServices: z.object({
2106
+ fileSystem: z.boolean(),
2107
+ git: z.boolean(),
2108
+ terminalEvents: z.boolean()
2109
+ }).default({ fileSystem: false, git: false, terminalEvents: false })
1129
2110
  });
1130
2111
  function base64UrlEncode(value) {
1131
2112
  return Buffer.from(value, "utf8").toString("base64url");
@@ -1161,10 +2142,15 @@ export {
1161
2142
  AccessGrant,
1162
2143
  AccountGrant,
1163
2144
  AccountRole,
2145
+ AcknowledgeStreamRequest,
2146
+ AcknowledgeStreamResponse,
1164
2147
  AddDocumentRequest,
2148
+ AddWorkspaceMemberRequest,
1165
2149
  ApiKey,
2150
+ AttachViewerRequest,
1166
2151
  BillingBalance,
1167
2152
  BillingMode,
2153
+ CAPABILITY_DESCRIPTORS,
1168
2154
  CLEARED_RUN_STATE_BLOB,
1169
2155
  CLEARED_RUN_STATE_MARKER,
1170
2156
  CapabilityCatalogItem,
@@ -1181,9 +2167,11 @@ export {
1181
2167
  CapabilityPackSkillFile,
1182
2168
  CapabilityRuntime,
1183
2169
  CapabilitySource,
2170
+ CapabilityUnavailableReason,
1184
2171
  ClearSessionContextRequest,
1185
2172
  ClientAuthConfig,
1186
2173
  ClientConfig,
2174
+ ClientModel,
1187
2175
  ClientSessionEvent,
1188
2176
  CompactSessionContextRequest,
1189
2177
  CompactSessionContextResult,
@@ -1202,6 +2190,7 @@ export {
1202
2190
  CreateSocialPostRequest,
1203
2191
  CreateWorkspaceEnvironmentRequest,
1204
2192
  CreateWorkspaceRequest,
2193
+ DESKTOP_STREAM_PORT,
1205
2194
  DelegatedAccessTokenPayload,
1206
2195
  DiscoverMcpCapabilitiesResponse,
1207
2196
  Document,
@@ -1221,11 +2210,45 @@ export {
1221
2210
  FileResourceRef,
1222
2211
  FileStatus,
1223
2212
  FileUploadStatus,
2213
+ FsChangeKind,
2214
+ FsChangedPayload,
2215
+ FsDeleteRequest,
2216
+ FsDeleteResponse,
2217
+ FsEncoding,
2218
+ FsListRequest,
2219
+ FsListResponse,
2220
+ FsMkdirRequest,
2221
+ FsMkdirResponse,
2222
+ FsMoveRequest,
2223
+ FsMoveResponse,
2224
+ FsNodeType,
2225
+ FsReadRequest,
2226
+ FsReadResponse,
2227
+ FsTreeNode,
2228
+ FsWriteRequest,
2229
+ FsWriteResponse,
2230
+ GitChangedPayload,
2231
+ GitCommit,
2232
+ GitDiffHunk,
2233
+ GitDiffLine,
2234
+ GitDiffLineType,
2235
+ GitDiffRequest,
2236
+ GitDiffResponse,
2237
+ GitFileDiff,
2238
+ GitFileStatus,
2239
+ GitFileStatusCode,
1224
2240
  GitHubAppManifestCreate,
1225
2241
  GitHubRepository,
2242
+ GitLogRequest,
2243
+ GitLogResponse,
2244
+ GitShowRequest,
2245
+ GitShowResponse,
2246
+ GitStatusRequest,
2247
+ GitStatusResponse,
1226
2248
  GoalSpec,
1227
2249
  LimitAction,
1228
2250
  LimitDecision,
2251
+ ListWorkspaceMembersResponse,
1229
2252
  ManagedAccount,
1230
2253
  MarketingDailyAnalysisTaskRequest,
1231
2254
  PackInstallation,
@@ -1233,13 +2256,28 @@ export {
1233
2256
  PageInfo,
1234
2257
  Permission,
1235
2258
  ProductAccessMode,
2259
+ PtyCloseRequest,
2260
+ PtyOpenRequest,
2261
+ PtyOpenResponse,
2262
+ PtyResizeRequest,
2263
+ PtyWriteRequest,
1236
2264
  ReasoningEffort,
2265
+ RecordingAvailablePayload,
2266
+ RecordingCodec,
2267
+ RecordingContentType,
2268
+ RecordingFailedPayload,
2269
+ RecordingFailedReason,
2270
+ RecordingMode,
2271
+ RecordingStartedPayload,
1237
2272
  RegisterCapabilityPackRequest,
1238
2273
  ReorderSessionTurnsRequest,
1239
2274
  RepositoryResourceRef,
1240
2275
  ResourceRef,
1241
2276
  ResourceRefConflictError,
1242
2277
  SandboxBackend,
2278
+ SandboxCapabilityName,
2279
+ SandboxCommandOutputDeltaPayload,
2280
+ SandboxOs,
1243
2281
  ScheduledTask,
1244
2282
  ScheduledTaskAgentConfig,
1245
2283
  ScheduledTaskOverlapPolicy,
@@ -1251,6 +2289,7 @@ export {
1251
2289
  ScheduledTaskTriggerType,
1252
2290
  Session,
1253
2291
  SessionBusMessage,
2292
+ SessionCapabilities,
1254
2293
  SessionEvent,
1255
2294
  SessionEventType,
1256
2295
  SessionGoal,
@@ -1258,6 +2297,7 @@ export {
1258
2297
  SessionGoalPausedReason,
1259
2298
  SessionGoalStatus,
1260
2299
  SessionStatus,
2300
+ SessionStructuredCapabilities,
1261
2301
  SessionTurn,
1262
2302
  SessionTurnSource,
1263
2303
  SessionTurnStatus,
@@ -1267,20 +2307,37 @@ export {
1267
2307
  SocialPost,
1268
2308
  SocialProvider,
1269
2309
  StaticUsageLimits,
2310
+ StreamClosedPayload,
2311
+ StreamOpenedPayload,
2312
+ StreamRevokedPayload,
2313
+ StreamTokenPayload,
2314
+ StreamUrlRotatedPayload,
2315
+ TERMINAL_STREAM_PORT,
2316
+ TerminalExecRequest,
2317
+ TerminalExecResponse,
2318
+ TerminalPtyExitedPayload,
2319
+ TerminalPtyOutputDeltaPayload,
2320
+ TerminalPtyStartedPayload,
1270
2321
  ToolRef,
1271
2322
  TriggerScheduledTaskRequest,
1272
2323
  UpdateScheduledTaskRequest,
1273
2324
  UpdateSessionGoalRequest,
2325
+ UpdateSessionRequest,
1274
2326
  UpdateSessionTurnRequest,
1275
2327
  UpdateWorkspaceEnvironmentRequest,
2328
+ UpdateWorkspaceMemberRequest,
1276
2329
  UpdateWorkspaceRequest,
1277
2330
  UsageEvent,
1278
2331
  UsageEventType,
1279
2332
  UsageLimitsMode,
2333
+ ViewerHeartbeatRequest,
2334
+ ViewerHeartbeatResponse,
2335
+ ViewerHolder,
1280
2336
  Workspace,
1281
2337
  WorkspaceEnvironment,
1282
2338
  WorkspaceEnvironmentVariableMetadata,
1283
2339
  WorkspaceEnvironmentVariableName,
2340
+ WorkspaceMember,
1284
2341
  WorkspaceRegisteredPack,
1285
2342
  isClearedRunStateBlob,
1286
2343
  mergeResourceRefs,
@@ -1289,7 +2346,9 @@ export {
1289
2346
  reasoningEffortForMetadata,
1290
2347
  resourceIdentityKey,
1291
2348
  signDelegatedAccessToken,
2349
+ signStreamToken,
1292
2350
  stableJson,
1293
- verifyDelegatedAccessToken
2351
+ verifyDelegatedAccessToken,
2352
+ verifyStreamToken
1294
2353
  };
1295
2354
  //# sourceMappingURL=index.js.map