@opengeni/db 0.2.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.
Files changed (66) hide show
  1. package/dist/chunk-57MLICFR.js +121 -0
  2. package/dist/chunk-57MLICFR.js.map +1 -0
  3. package/dist/chunk-OGCE6O2X.js +52 -0
  4. package/dist/chunk-OGCE6O2X.js.map +1 -0
  5. package/dist/chunk-PSX56ZTL.js +1093 -0
  6. package/dist/chunk-PSX56ZTL.js.map +1 -0
  7. package/dist/chunk-PZ5AY32C.js +10 -0
  8. package/dist/chunk-PZ5AY32C.js.map +1 -0
  9. package/dist/index.d.ts +8 -0
  10. package/dist/index.js +5165 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/migrate.d.ts +40 -0
  13. package/dist/migrate.js +10 -0
  14. package/dist/migrate.js.map +1 -0
  15. package/dist/provision-roles.d.ts +2063 -0
  16. package/dist/provision-roles.js +8 -0
  17. package/dist/provision-roles.js.map +1 -0
  18. package/dist/schema-CaeZQAJQ.d.ts +9705 -0
  19. package/dist/schema.d.ts +3 -0
  20. package/dist/schema.js +110 -0
  21. package/dist/schema.js.map +1 -0
  22. package/drizzle/0000_initial.sql +179 -0
  23. package/drizzle/0001_workspace_auth_billing.sql +590 -0
  24. package/drizzle/0002_packs_and_social.sql +99 -0
  25. package/drizzle/0003_capability_catalog.sql +73 -0
  26. package/drizzle/0004_workspace_environments.sql +65 -0
  27. package/drizzle/0005_session_goals.sql +45 -0
  28. package/drizzle/0006_workspace_packs.sql +31 -0
  29. package/drizzle/0007_session_history_items.sql +66 -0
  30. package/drizzle/0008_session_first_party_mcp_permissions.sql +5 -0
  31. package/drizzle/0009_goal_sessions_first_party_goals_manage.sql +34 -0
  32. package/drizzle/0010_session_parent_linkage.sql +30 -0
  33. package/drizzle/0011_context_compaction.sql +33 -0
  34. package/drizzle/0012_compaction_summary_fractional_position.sql +19 -0
  35. package/drizzle/0013_session_compact_requested.sql +16 -0
  36. package/drizzle/0014_repair_orphaned_function_call_results.sql +125 -0
  37. package/drizzle/0015_workspace_agent_instructions.sql +17 -0
  38. package/drizzle/0016_session_create_idempotency.sql +27 -0
  39. package/drizzle/0017_sandbox_leases.sql +313 -0
  40. package/drizzle/0018_sandbox_os.sql +89 -0
  41. package/drizzle/0019_session_stream_acknowledgments.sql +94 -0
  42. package/drizzle/0020_session_recordings.sql +88 -0
  43. package/drizzle/0021_sandbox_pty_sessions.sql +70 -0
  44. package/drizzle/0022_sandbox_lease_terminal_url.sql +32 -0
  45. package/drizzle/0023_session_title.sql +19 -0
  46. package/drizzle/0024_codex_subscription_credentials.sql +51 -0
  47. package/drizzle/0024_sandboxes_enrollments_metrics.sql +262 -0
  48. package/drizzle/0025_device_enrollment_requests.sql +142 -0
  49. package/drizzle/0026_device_enrollment_user_code_resolver.sql +47 -0
  50. package/drizzle/0027_session_working_dir.sql +24 -0
  51. package/drizzle/0028_codex_multi_account.sql +85 -0
  52. package/drizzle/0029_session_history_item_producer.sql +31 -0
  53. package/drizzle/0030_agent_run_state_frozen_codex.sql +35 -0
  54. package/drizzle/0031_codex_usage_cache.sql +21 -0
  55. package/drizzle/0032_codex_account_cooldown.sql +18 -0
  56. package/drizzle/0033_codex_connector_cache.sql +20 -0
  57. package/drizzle/0034_sandbox_lease_image.sql +21 -0
  58. package/drizzle/meta/_journal.json +167 -0
  59. package/package.json +66 -0
  60. package/src/codex-token-resolver.ts +247 -0
  61. package/src/environment-crypto.ts +51 -0
  62. package/src/event-payload-sanitizer.ts +89 -0
  63. package/src/index.ts +7776 -0
  64. package/src/migrate.ts +95 -0
  65. package/src/provision-roles.ts +198 -0
  66. package/src/schema.ts +1110 -0
@@ -0,0 +1,2063 @@
1
+ import { SessionEventType, Permission, CapabilityKind, CapabilitySource, ScheduledTaskStatus, ScheduledTaskScheduleSpec, ScheduledTaskRunMode, ScheduledTaskOverlapPolicy, ScheduledTaskAgentConfig, SessionGoalCreatedBy, SocialProvider, SocialConnectionStatus, SessionTurnSource, ResourceRef, ToolRef, ReasoningEffort, SandboxBackend, SessionGoal, CapabilityPack, SessionTurn, SessionEvent, SessionStatus, Session, BillingBalance, AccessContext, FileAsset, ApiKey, ScheduledTask, ScheduledTaskTriggerType, ScheduledTaskRun, SandboxOs, SocialConnection, SocialPost, Workspace, WorkspaceEnvironment, CapabilityInstallation, PackInstallation, SessionTurnStatus, CapabilityCatalogItem, FileUploadStatus, ManagedAccount, AccessGrant, WorkspaceRegisteredPack, UsageEvent, WorkspaceMember, SessionGoalStatus, WorkspaceEnvironmentVariableMetadata, PackInstallationStatus, ScheduledTaskRunStatus } from '@opengeni/contracts';
2
+ import { environmentsEncryptionKeyBytes, Settings } from '@opengeni/config';
3
+ import { refreshCodexToken, CodexTokenSnapshot, CodexUsagePayload } from '@opengeni/codex';
4
+ import { PgDatabase } from 'drizzle-orm/pg-core';
5
+ import { s as schema, e as enrollmentOsValues, a as enrollmentExposureValues, d as deviceEnrollmentStatusValues, b as enrollmentStatusValues, c as sandboxKindValues, f as sessionRecordingCodecValues, g as sessionRecordingModeValues, h as sessionRecordingStateValues } from './schema-CaeZQAJQ.js';
6
+ import 'drizzle-orm';
7
+ import './migrate.js';
8
+
9
+ /**
10
+ * Encrypts one workspace environment variable value with AES-256-GCM under an
11
+ * operator key held outside Postgres. Output format: `v1:<b64 iv>:<b64 ciphertext||tag>`.
12
+ */
13
+ declare function encryptEnvironmentValue(key: Uint8Array, plaintext: string): string;
14
+ /**
15
+ * Decrypts a stored `v1:` value. Error messages never echo plaintext or
16
+ * ciphertext: unknown versions throw "unsupported environment value format",
17
+ * auth-tag mismatches throw "environment value decryption failed".
18
+ */
19
+ declare function decryptEnvironmentValue(key: Uint8Array, stored: string): string;
20
+
21
+ /**
22
+ * Last line of defense against a session event crashing a whole turn.
23
+ *
24
+ * Postgres `text`/`jsonb` cannot store a NUL byte (U+0000) nor lone UTF-16
25
+ * surrogates. Raw exec output routinely carries both -- chrome/crashpad logs,
26
+ * `cat` of a binary, random bytes -- and the worker persists that output verbatim
27
+ * inside `agent.toolCall.output` / `sandbox.command.output` event payloads. When
28
+ * such a payload reaches `INSERT INTO session_events`, the driver rejects it
29
+ * ("Failed query: insert into session_events") and the turn dies.
30
+ *
31
+ * `sanitizeEventPayload` deep-walks any payload value (objects, arrays, nested)
32
+ * and, for every string, strips NUL and rewrites invalid/lone UTF-16 surrogates
33
+ * to the Unicode replacement char (U+FFFD), so the result is always valid UTF-8
34
+ * that jsonb can store. It is cheap and total: only strings are touched, and only
35
+ * the two disallowed classes of code unit -- no meaningful text is lost, no
36
+ * truncation (truncation is handled elsewhere).
37
+ */
38
+ /**
39
+ * Strip NUL and repair invalid/lone UTF-16 surrogates in a single string.
40
+ * Returns the input unchanged (same reference) when it is already clean, so the
41
+ * common case allocates nothing.
42
+ */
43
+ declare function sanitizeEventString(value: string): string;
44
+ /**
45
+ * Deep-walk a session event payload and sanitize every string value. Mirrors the
46
+ * shape of the worker redaction deep-walk: objects, arrays, and nested
47
+ * combinations are traversed; non-string leaves pass through untouched. Object
48
+ * keys are sanitized too -- they are jsonb-constrained the same as values.
49
+ */
50
+ declare function sanitizeEventPayload<T>(payload: T): T;
51
+
52
+ type ProvisionResult = {
53
+ appRole: string | null;
54
+ temporalRole: string | null;
55
+ temporalDatabases: string[];
56
+ schema: string;
57
+ rlsStrategy: RlsStrategy;
58
+ };
59
+ type ProvisionRolesOptions = {
60
+ /**
61
+ * The schema OpenGeni's tables live in. The app-role GRANTs target this
62
+ * schema + `opengeni_private`. Defaults to `public` (standalone).
63
+ */
64
+ targetSchema?: string;
65
+ /**
66
+ * RLS posture (Step I). `"force"` (default) provisions the non-owner
67
+ * `opengeni_app` login role and GRANTs it table DML in the target schema —
68
+ * the role OpenGeni connects as under FORCE-RLS. `"scoped"` SKIPS the app-role
69
+ * provisioning entirely: the embedded host runs OpenGeni's queries over a role
70
+ * IT owns/manages (typically the schema owner), so OpenGeni neither creates
71
+ * nor grants the `opengeni_app` role. Temporal-role provisioning is unaffected
72
+ * by strategy.
73
+ */
74
+ rlsStrategy?: RlsStrategy;
75
+ appRole?: string;
76
+ appPassword?: string;
77
+ temporalRole?: string;
78
+ temporalPassword?: string;
79
+ temporalDatabases?: string[];
80
+ };
81
+ /**
82
+ * SDK entry point (Step I): provision the OpenGeni database roles + grants over
83
+ * a host-supplied admin connection. This is the named, parameterized form of the
84
+ * historical env-driven `provision-roles` script (which still works as a CLI via
85
+ * the `import.meta.main` block at the bottom — it just reads env into these
86
+ * options).
87
+ *
88
+ * STANDALONE (default): `provisionRoles(adminConnection)` with no options →
89
+ * `targetSchema: "public"`, `rlsStrategy: "force"`, reads `opengeni_app` creds
90
+ * from env. Byte-for-byte the historical script behavior.
91
+ *
92
+ * EMBEDDED: `provisionRoles(adminConnection, { targetSchema, rlsStrategy })` lets
93
+ * a host provision the app role over a dedicated schema (force) OR skip the
94
+ * app role entirely and own the connection role itself (scoped).
95
+ */
96
+ declare function provisionRoles(adminConnection: string, options?: ProvisionRolesOptions): Promise<ProvisionResult>;
97
+
98
+ type CodexAuthDeps = {
99
+ loadCredential: typeof loadCodexCredentialForRun;
100
+ recordRefresh: typeof recordCodexTokenRefresh;
101
+ setStatus: typeof setCodexCredentialStatus;
102
+ refresh: typeof refreshCodexToken;
103
+ encrypt: typeof encryptEnvironmentValue;
104
+ keyBytes: typeof environmentsEncryptionKeyBytes;
105
+ };
106
+ declare function buildCodexTokenResolver(db: Database, settings: Settings, workspaceId: string, credentialId: string, deps?: CodexAuthDeps): {
107
+ getToken: () => Promise<CodexTokenSnapshot>;
108
+ refresh: () => Promise<CodexTokenSnapshot>;
109
+ };
110
+ /**
111
+ * THE single per-account usage path both the api route and an (optional) worker
112
+ * poll call, so the refresh discipline and the cache-write can never drift.
113
+ *
114
+ * 1. resolve a REFRESHING bearer for THIS account (proactive staleness refresh,
115
+ * single-flight, (id,version) CAS-persist) — this is what stops an idle
116
+ * account's expired JWT from 401-ing the usage read.
117
+ * 2. fetch GET /wham/usage with that bearer.
118
+ * 3. normalize (§3) into the P2/P3 contract.
119
+ * 4. on any windows present, write the five usage-cache columns (the TTL clock).
120
+ *
121
+ * A refresh that stamps needs_relogin returns { status:"error", reason } and never
122
+ * hits the provider; a transient refresh error returns a plain error payload.
123
+ */
124
+ declare function fetchCodexUsageForAccount(db: Database, settings: Settings, workspaceId: string, credentialId: string): Promise<CodexUsagePayload>;
125
+
126
+ type Database = PgDatabase<any, typeof schema>;
127
+ type DbClient = {
128
+ db: Database;
129
+ close: () => Promise<void>;
130
+ };
131
+ type RlsContext = {
132
+ accountId: string;
133
+ workspaceId?: string | null;
134
+ };
135
+ /**
136
+ * RLS posture for the connection OpenGeni's query layer runs over (Step I, §7.7).
137
+ *
138
+ * - `"force"` (DEFAULT — today's standalone behavior, byte-for-byte): OpenGeni
139
+ * connects as a NON-OWNER role (`opengeni_app`) and every table carries
140
+ * `FORCE ROW LEVEL SECURITY`, so the workspace/account GUCs set by
141
+ * `setRlsContext` are the ONLY thing that admits rows — even the table owner
142
+ * is subject to RLS. This is the Fork-A isolation guarantee.
143
+ * - `"scoped"` (embedded Fork-B opt-in): the host runs OpenGeni's queries over a
144
+ * role that OWNS the dedicated schema (RLS need not be forced for that role),
145
+ * relying on the host's own tenant boundary. OpenGeni STILL emits the
146
+ * `set_config('opengeni.account_id'/'workspace_id', …)` GUCs defensively on
147
+ * every scoped query, so the application query path is byte-identical between
148
+ * the two strategies and the app code is RLS-mode-agnostic. The strategy is a
149
+ * declared posture (consumed by `provisionRoles` and as a documented
150
+ * invariant), NOT a query-path branch — there is deliberately no `if
151
+ * (strategy === …)` anywhere in the helpers below. Picking `"scoped"` does not
152
+ * relax any GUC; it only changes which DB role the host provisions/connects as
153
+ * and asserts that the host accepts owning the isolation boundary.
154
+ */
155
+ type RlsStrategy = "force" | "scoped";
156
+ /**
157
+ * Resolve a host-IdP/Better-Auth user *identifier* by email. Injected via
158
+ * `createDb({ userLookup })` (Step I). UNSET → today's raw parameterized select
159
+ * against Better Auth's `auth_users` table (see `getManagedUserByEmail`), which
160
+ * relies on the postgres-js array-shaped `db.execute` result. An embedded host
161
+ * whose identity lives elsewhere (a different IdP table, a different driver, or
162
+ * a non-`auth_users` user store) injects this closure so OpenGeni never touches
163
+ * `auth_users` directly. Returns the user id, or null when no such user exists.
164
+ */
165
+ type UserLookup = (db: Database, email: string) => Promise<string | null>;
166
+ type CreateDbOptions = {
167
+ /**
168
+ * The Postgres `search_path` for this connection (Step I, §7.8 runtime half).
169
+ * UNSET → today's behavior: NO `search_path` startup parameter is sent, so the
170
+ * server default applies (`public` for standalone, where every table + the
171
+ * `vector` extension + `gen_random_uuid()` live). For an embedded dedicated
172
+ * schema, pass e.g. `"opengeni,opengeni_private,public"` — postgres-js sends
173
+ * it as a per-session startup parameter (the supported, query-param-free way;
174
+ * URL `?search_path=` is IGNORED by postgres-js). Keep `public` LAST so the
175
+ * `vector` type and `gen_random_uuid()` (which live in `public` on the
176
+ * pgvector image) still resolve — the SPIKE-1 live footgun.
177
+ */
178
+ searchPath?: string;
179
+ /** RLS posture; defaults to `"force"` (today's standalone). */
180
+ rlsStrategy?: RlsStrategy;
181
+ /** Host-provided user-by-email resolver; unset → today's raw `auth_users` query. */
182
+ userLookup?: UserLookup;
183
+ /** postgres-js pool size; defaults to today's `10`. */
184
+ max?: number;
185
+ };
186
+ /** The strategy bound to a handle (or the `"force"` default). */
187
+ declare function rlsStrategyFor(db: Database): RlsStrategy;
188
+ declare function createDb(databaseUrl: string, options?: CreateDbOptions): DbClient;
189
+ /**
190
+ * Register a host's `rlsStrategy`/`userLookup` against an externally-constructed
191
+ * `Database` handle (e.g. one the embedded host built from its own driver and
192
+ * injected, rather than via `createDb`). Lets the same WeakMap-backed lookups
193
+ * work for injected handles. Standalone never calls this (it uses `createDb`).
194
+ */
195
+ declare function registerDbBinding(db: Database, binding: {
196
+ rlsStrategy?: RlsStrategy;
197
+ userLookup?: UserLookup;
198
+ }): void;
199
+ declare function setRlsContext(db: Database, context: RlsContext): Promise<void>;
200
+ declare function withRlsContext<T>(db: Database, context: RlsContext, fn: (db: Database) => Promise<T>): Promise<T>;
201
+ declare function rlsContextForWorkspace(db: Database, workspaceId: string): Promise<RlsContext>;
202
+ declare function withWorkspaceRls<T>(db: Database, workspaceId: string, fn: (db: Database) => Promise<T>): Promise<T>;
203
+ declare function withWorkspaceUsageLock<T>(db: Database, workspaceId: string, fn: (db: Database) => Promise<T>): Promise<T>;
204
+ declare function withAccountRls<T>(db: Database, accountId: string, fn: (db: Database) => Promise<T>): Promise<T>;
205
+ declare const allWorkspacePermissions: Permission[];
206
+ declare const allAccountPermissions: Permission[];
207
+ type BootstrapWorkspaceInput = {
208
+ accountExternalSource: string;
209
+ accountExternalId: string;
210
+ accountName: string;
211
+ workspaceExternalSource: string;
212
+ workspaceExternalId: string;
213
+ workspaceName: string;
214
+ subjectId: string;
215
+ subjectLabel?: string;
216
+ accountPermissions?: Permission[];
217
+ workspacePermissions?: Permission[];
218
+ };
219
+ declare function bootstrapWorkspace(db: Database, input: BootstrapWorkspaceInput): Promise<AccessContext>;
220
+ declare function ensureManagedAccessForUser(db: Database, input: {
221
+ userId: string;
222
+ email: string;
223
+ name: string;
224
+ }): Promise<AccessContext>;
225
+ declare function getWorkspace(db: Database, workspaceId: string): Promise<Workspace | null>;
226
+ declare function getManagedAccount(db: Database, accountId: string): Promise<ManagedAccount | null>;
227
+ declare function requireWorkspace(db: Database, workspaceId: string): Promise<Workspace>;
228
+ declare function listWorkspacesForSubject(db: Database, subjectId: string, limit?: number): Promise<Workspace[]>;
229
+ declare function countWorkspacesForAccount(db: Database, accountId: string): Promise<number>;
230
+ declare function createWorkspace(db: Database, input: {
231
+ accountId: string;
232
+ name: string;
233
+ slug?: string | null;
234
+ externalSource?: string | null;
235
+ externalId?: string | null;
236
+ agentInstructions?: string | null;
237
+ }): Promise<Workspace>;
238
+ declare function grantWorkspaceAccess(db: Database, input: {
239
+ accountId: string;
240
+ workspaceId: string;
241
+ subjectId: string;
242
+ subjectLabel?: string;
243
+ role?: string;
244
+ permissions: Permission[];
245
+ }): Promise<void>;
246
+ declare function updateWorkspace(db: Database, workspaceId: string, input: {
247
+ name?: string;
248
+ slug?: string | null;
249
+ agentInstructions?: string | null;
250
+ }): Promise<Workspace>;
251
+ declare function getWorkspaceGrant(db: Database, subjectId: string, workspaceId: string): Promise<AccessGrant | null>;
252
+ declare function listWorkspaceMembers(db: Database, workspaceId: string): Promise<WorkspaceMember[]>;
253
+ declare function removeWorkspaceMember(db: Database, workspaceId: string, subjectId: string): Promise<boolean>;
254
+ /**
255
+ * Resolve a managed user email to its user id.
256
+ *
257
+ * STANDALONE (default, unchanged): the `auth_users` table is owned by Better
258
+ * Auth and is NOT in the Drizzle schema, so this runs the raw parameterized
259
+ * select below — matching emails case-insensitively, returning the id or null.
260
+ *
261
+ * EMBEDDED (Step I `userLookup` port): when the handle was built via
262
+ * `createDb({ userLookup })` (or registered with `registerDbBinding`), this
263
+ * delegates to the host's resolver instead — so a host whose identity lives in
264
+ * a different IdP/table/driver never forces OpenGeni to touch `auth_users`. The
265
+ * raw query also assumes the postgres-js array-shaped `db.execute` result; the
266
+ * port is the cross-driver escape hatch for that too.
267
+ *
268
+ * Used to add an already-registered user to a workspace; email invites for
269
+ * unknown users are deferred.
270
+ */
271
+ declare function getManagedUserByEmail(db: Database, email: string): Promise<string | null>;
272
+ declare function deleteWorkspace(db: Database, workspaceId: string): Promise<void>;
273
+ declare function createApiKey(db: Database, input: {
274
+ accountId: string;
275
+ workspaceId?: string | null;
276
+ name: string;
277
+ prefix: string;
278
+ keyHash: string;
279
+ permissions: Permission[];
280
+ expiresAt?: Date | null;
281
+ }): Promise<ApiKey>;
282
+ declare function listApiKeys(db: Database, workspaceId: string): Promise<ApiKey[]>;
283
+ declare function countActiveApiKeysForWorkspace(db: Database, workspaceId: string): Promise<number>;
284
+ declare function revokeApiKey(db: Database, workspaceId: string, apiKeyId: string): Promise<ApiKey>;
285
+ declare function findActiveApiKeyByHash(db: Database, keyHash: string): Promise<ApiKey | null>;
286
+ type GitHubInstallation = {
287
+ id: string;
288
+ accountId: string;
289
+ workspaceId: string;
290
+ installationId: number;
291
+ accountLogin: string | null;
292
+ accountType: string | null;
293
+ createdAt: string;
294
+ updatedAt: string;
295
+ };
296
+ declare function upsertGitHubInstallation(db: Database, input: {
297
+ accountId: string;
298
+ workspaceId: string;
299
+ installationId: number;
300
+ accountLogin?: string | null;
301
+ accountType?: string | null;
302
+ }): Promise<GitHubInstallation>;
303
+ declare function listGitHubInstallationsForWorkspace(db: Database, workspaceId: string): Promise<GitHubInstallation[]>;
304
+ declare function listGitHubInstallationIdsForWorkspace(db: Database, workspaceId: string): Promise<number[]>;
305
+ declare function recordUsageEvent(db: Database, input: {
306
+ accountId: string;
307
+ workspaceId: string;
308
+ subjectId?: string | null;
309
+ eventType: string;
310
+ quantity: number;
311
+ unit: string;
312
+ sourceResourceType?: string | null;
313
+ sourceResourceId?: string | null;
314
+ idempotencyKey: string;
315
+ occurredAt?: Date;
316
+ }): Promise<UsageEvent>;
317
+ declare function listUsageEvents(db: Database, input: {
318
+ accountId: string;
319
+ workspaceId?: string;
320
+ limit?: number;
321
+ }): Promise<UsageEvent[]>;
322
+ declare function sumUsageQuantity(db: Database, input: {
323
+ accountId?: string;
324
+ workspaceId?: string;
325
+ eventType: string;
326
+ since?: Date;
327
+ }): Promise<number>;
328
+ declare function applyCreditLedgerEntry(db: Database, input: {
329
+ accountId: string;
330
+ workspaceId?: string | null;
331
+ type: string;
332
+ amountMicros: number;
333
+ sourceType?: string | null;
334
+ sourceId?: string | null;
335
+ idempotencyKey: string;
336
+ metadata?: Record<string, unknown>;
337
+ occurredAt?: Date;
338
+ }): Promise<BillingBalance>;
339
+ declare function applyCreditDebitUpToBalance(db: Database, input: {
340
+ accountId: string;
341
+ workspaceId?: string | null;
342
+ type: string;
343
+ requestedAmountMicros: number;
344
+ sourceType?: string | null;
345
+ sourceId?: string | null;
346
+ idempotencyKey: string;
347
+ metadata?: Record<string, unknown>;
348
+ occurredAt?: Date;
349
+ }): Promise<{
350
+ balance: BillingBalance;
351
+ debitedMicros: number;
352
+ }>;
353
+ declare function hasCreditLedgerEntry(db: Database, accountId: string, idempotencyKey: string): Promise<boolean>;
354
+ declare function getBillingCustomer(db: Database, accountId: string, provider?: string): Promise<{
355
+ accountId: string;
356
+ provider: string;
357
+ providerCustomerId: string;
358
+ email: string | null;
359
+ } | null>;
360
+ declare function upsertBillingCustomer(db: Database, input: {
361
+ accountId: string;
362
+ provider?: string;
363
+ providerCustomerId: string;
364
+ email?: string | null;
365
+ }): Promise<void>;
366
+ declare function recordStripeWebhookEvent(db: Database, input: {
367
+ id: string;
368
+ type: string;
369
+ livemode: boolean;
370
+ payload: unknown;
371
+ }): Promise<boolean>;
372
+ declare function isStripeWebhookProcessed(db: Database, id: string): Promise<boolean>;
373
+ declare function markStripeWebhookProcessed(db: Database, id: string): Promise<void>;
374
+ declare function getBillingBalance(db: Database, accountId: string): Promise<BillingBalance>;
375
+ declare function countScheduledTasksForWorkspace(db: Database, workspaceId: string): Promise<number>;
376
+ type AppendEventInput = {
377
+ type: SessionEventType;
378
+ payload?: unknown;
379
+ clientEventId?: string;
380
+ turnId?: string | null;
381
+ producerId?: string;
382
+ producerSeq?: number;
383
+ occurredAt?: Date;
384
+ };
385
+ type CreateScheduledTaskInput = {
386
+ id?: string;
387
+ accountId: string;
388
+ workspaceId: string;
389
+ name: string;
390
+ status: ScheduledTaskStatus;
391
+ schedule: ScheduledTaskScheduleSpec;
392
+ temporalScheduleId: string;
393
+ runMode: ScheduledTaskRunMode;
394
+ overlapPolicy: ScheduledTaskOverlapPolicy;
395
+ agentConfig: ScheduledTaskAgentConfig;
396
+ environmentId?: string | null;
397
+ metadata: Record<string, unknown>;
398
+ };
399
+ type UpdateScheduledTaskInput = Partial<{
400
+ name: string;
401
+ status: ScheduledTaskStatus;
402
+ schedule: ScheduledTaskScheduleSpec;
403
+ runMode: ScheduledTaskRunMode;
404
+ overlapPolicy: ScheduledTaskOverlapPolicy;
405
+ agentConfig: ScheduledTaskAgentConfig;
406
+ reusableSessionId: string | null;
407
+ environmentId: string | null;
408
+ metadata: Record<string, unknown>;
409
+ }>;
410
+ type CreatePackInstallationInput = {
411
+ accountId: string;
412
+ workspaceId: string;
413
+ packId: string;
414
+ metadata?: Record<string, unknown>;
415
+ };
416
+ type RegisterWorkspacePackInput = {
417
+ accountId: string;
418
+ workspaceId: string;
419
+ pack: CapabilityPack;
420
+ };
421
+ type CreateSocialConnectionInput = {
422
+ accountId: string;
423
+ workspaceId: string;
424
+ provider: SocialProvider;
425
+ accountHandle: string;
426
+ accountName?: string | null;
427
+ externalAccountId?: string | null;
428
+ status: SocialConnectionStatus;
429
+ scopes?: string[];
430
+ credentialRef?: string | null;
431
+ tokenMetadata?: Record<string, unknown>;
432
+ metadata?: Record<string, unknown>;
433
+ };
434
+ type CreateSocialPostInput = {
435
+ accountId: string;
436
+ workspaceId: string;
437
+ connectionId: string;
438
+ externalPostId?: string | null;
439
+ url?: string | null;
440
+ authorHandle?: string | null;
441
+ text: string;
442
+ publishedAt: Date;
443
+ metrics?: Record<string, number>;
444
+ raw?: Record<string, unknown>;
445
+ };
446
+ type CreateCapabilityCatalogItemInput = {
447
+ accountId: string;
448
+ workspaceId: string;
449
+ id: string;
450
+ kind: Exclude<CapabilityKind, "pack">;
451
+ source: CapabilitySource;
452
+ name: string;
453
+ description?: string | null;
454
+ category?: string;
455
+ tags?: string[];
456
+ homepageUrl?: string | null;
457
+ endpointUrl?: string | null;
458
+ installUrl?: string | null;
459
+ authModel?: string | null;
460
+ metadata?: Record<string, unknown>;
461
+ };
462
+ type EnableCapabilityInstallationInput = {
463
+ accountId: string;
464
+ workspaceId: string;
465
+ capabilityId: string;
466
+ kind: CapabilityKind;
467
+ config?: Record<string, unknown>;
468
+ metadata?: Record<string, unknown>;
469
+ };
470
+ type EnabledMcpCapabilityServer = {
471
+ capabilityId: string;
472
+ id: string;
473
+ name: string;
474
+ url: string;
475
+ allowedTools?: string[];
476
+ timeoutMs?: number;
477
+ cacheToolsList?: boolean;
478
+ /**
479
+ * Credential request headers stored encrypted at enable time
480
+ * (AES-256-GCM under the workspace-environments key). Decrypted only at
481
+ * the runtime boundary that builds the MCP client; never exposed by the
482
+ * capability API surface.
483
+ */
484
+ headersEncrypted?: Record<string, string>;
485
+ };
486
+ type EnqueueSessionTurnInput = {
487
+ accountId: string;
488
+ workspaceId: string;
489
+ sessionId: string;
490
+ triggerEventId: string;
491
+ temporalWorkflowId: string;
492
+ source: SessionTurnSource;
493
+ prompt: string;
494
+ resources: ResourceRef[];
495
+ tools: ToolRef[];
496
+ model: string;
497
+ reasoningEffort: ReasoningEffort;
498
+ sandboxBackend: SandboxBackend;
499
+ metadata: Record<string, unknown>;
500
+ };
501
+ type UpdateQueuedSessionTurnInput = Partial<{
502
+ prompt: string;
503
+ resources: ResourceRef[];
504
+ tools: ToolRef[];
505
+ model: string;
506
+ reasoningEffort: ReasoningEffort;
507
+ sandboxBackend: SandboxBackend;
508
+ metadata: Record<string, unknown>;
509
+ }>;
510
+ declare function createFileUpload(db: Database, input: {
511
+ accountId: string;
512
+ workspaceId: string;
513
+ fileId: string;
514
+ filename: string;
515
+ safeFilename: string;
516
+ contentType: string;
517
+ sizeBytes: number;
518
+ sha256?: string | null;
519
+ bucket: string;
520
+ objectKey: string;
521
+ expiresAt: Date;
522
+ }): Promise<{
523
+ file: FileAsset;
524
+ uploadId: string;
525
+ expiresAt: string;
526
+ }>;
527
+ declare function getFile(db: Database, workspaceId: string, fileId: string): Promise<FileAsset | null>;
528
+ declare function requireFile(db: Database, workspaceId: string, fileId: string): Promise<FileAsset>;
529
+ declare function getFileUpload(db: Database, workspaceId: string, uploadId: string): Promise<{
530
+ id: string;
531
+ status: FileUploadStatus;
532
+ expiresAt: Date;
533
+ file: FileAsset;
534
+ } | null>;
535
+ declare function completeFileUpload(db: Database, workspaceId: string, uploadId: string): Promise<FileAsset>;
536
+ declare function markFileUploadFailed(db: Database, workspaceId: string, uploadId: string, fileId: string): Promise<void>;
537
+ declare function enablePackInstallation(db: Database, input: CreatePackInstallationInput): Promise<PackInstallation>;
538
+ declare function listPackInstallations(db: Database, workspaceId: string): Promise<PackInstallation[]>;
539
+ declare function getPackInstallation(db: Database, workspaceId: string, packId: string): Promise<PackInstallation | null>;
540
+ declare function updatePackInstallationStatus(db: Database, workspaceId: string, packId: string, status: PackInstallationStatus): Promise<PackInstallation>;
541
+ declare function registerWorkspacePack(db: Database, input: RegisterWorkspacePackInput): Promise<{
542
+ pack: WorkspaceRegisteredPack;
543
+ created: boolean;
544
+ }>;
545
+ declare function listWorkspacePacks(db: Database, workspaceId: string): Promise<WorkspaceRegisteredPack[]>;
546
+ declare function getWorkspacePack(db: Database, workspaceId: string, packId: string): Promise<WorkspaceRegisteredPack | null>;
547
+ declare function deleteWorkspacePack(db: Database, workspaceId: string, packId: string): Promise<boolean>;
548
+ declare function upsertCapabilityCatalogItem(db: Database, input: CreateCapabilityCatalogItemInput): Promise<CapabilityCatalogItem>;
549
+ declare function listCapabilityCatalogItems(db: Database, workspaceId: string): Promise<CapabilityCatalogItem[]>;
550
+ declare function getCapabilityCatalogItem(db: Database, workspaceId: string, capabilityId: string): Promise<CapabilityCatalogItem | null>;
551
+ declare function enableCapabilityInstallation(db: Database, input: EnableCapabilityInstallationInput): Promise<CapabilityInstallation>;
552
+ declare function disableCapabilityInstallation(db: Database, workspaceId: string, capabilityId: string): Promise<CapabilityInstallation>;
553
+ declare function listCapabilityInstallations(db: Database, workspaceId: string): Promise<CapabilityInstallation[]>;
554
+ declare function getCapabilityInstallation(db: Database, workspaceId: string, capabilityId: string): Promise<CapabilityInstallation | null>;
555
+ declare function listEnabledMcpCapabilityServers(db: Database, workspaceId: string): Promise<EnabledMcpCapabilityServer[]>;
556
+ /**
557
+ * Decrypts an enabled capability MCP's stored credential headers. Returns
558
+ * null when the server has none, and "unavailable" when headers exist but
559
+ * cannot be recovered (missing key or failed decryption) — in which case the
560
+ * server must be skipped rather than connected without credentials.
561
+ */
562
+ declare function decryptedCapabilityHeaders(server: EnabledMcpCapabilityServer, encryptionKey: Uint8Array | null): Record<string, string> | null | "unavailable";
563
+ /**
564
+ * Returns the encrypted credential-header map stored on a capability
565
+ * installation, or null when none is stored. This is the only read path for
566
+ * the ciphertext besides listEnabledMcpCapabilityServers; the generic
567
+ * installation mapping redacts it to header names.
568
+ */
569
+ declare function getStoredCapabilityHeaderCiphertext(db: Database, workspaceId: string, capabilityId: string): Promise<Record<string, string> | null>;
570
+ declare function mcpServerIdForCapability(capabilityId: string, metadata?: Record<string, unknown>): string;
571
+ declare function createSocialConnection(db: Database, input: CreateSocialConnectionInput): Promise<SocialConnection>;
572
+ declare function listSocialConnections(db: Database, workspaceId: string, limit?: number): Promise<SocialConnection[]>;
573
+ declare function getSocialConnection(db: Database, workspaceId: string, connectionId: string): Promise<SocialConnection | null>;
574
+ declare function requireSocialConnection(db: Database, workspaceId: string, connectionId: string): Promise<SocialConnection>;
575
+ declare function createSocialPost(db: Database, input: CreateSocialPostInput): Promise<SocialPost>;
576
+ declare function listSocialPosts(db: Database, options: {
577
+ workspaceId: string;
578
+ connectionIds?: string[];
579
+ since?: Date;
580
+ limit?: number;
581
+ }): Promise<SocialPost[]>;
582
+ declare function createScheduledTask(db: Database, input: CreateScheduledTaskInput): Promise<ScheduledTask>;
583
+ declare function updateScheduledTask(db: Database, workspaceId: string, taskId: string, input: UpdateScheduledTaskInput): Promise<ScheduledTask>;
584
+ declare function getScheduledTask(db: Database, workspaceId: string, taskId: string): Promise<ScheduledTask | null>;
585
+ declare function requireScheduledTask(db: Database, workspaceId: string, taskId: string): Promise<ScheduledTask>;
586
+ declare function listScheduledTasks(db: Database, workspaceId: string, limit?: number): Promise<ScheduledTask[]>;
587
+ declare function deleteScheduledTask(db: Database, workspaceId: string, taskId: string): Promise<void>;
588
+ declare function createScheduledTaskRun(db: Database, input: {
589
+ workspaceId: string;
590
+ taskId: string;
591
+ triggerType: ScheduledTaskTriggerType;
592
+ scheduledAt?: Date | null;
593
+ firedAt?: Date;
594
+ }): Promise<ScheduledTaskRun>;
595
+ declare function updateScheduledTaskRun(db: Database, workspaceId: string, runId: string, input: Partial<{
596
+ status: ScheduledTaskRunStatus;
597
+ sessionId: string | null;
598
+ triggerEventId: string | null;
599
+ error: string | null;
600
+ }>): Promise<ScheduledTaskRun>;
601
+ declare function listScheduledTaskRuns(db: Database, workspaceId: string, taskId: string, limit?: number): Promise<ScheduledTaskRun[]>;
602
+ declare function createWorkspaceEnvironment(db: Database, input: {
603
+ accountId: string;
604
+ workspaceId: string;
605
+ name: string;
606
+ description?: string | null;
607
+ variables?: Array<{
608
+ name: string;
609
+ valueEncrypted: string;
610
+ }>;
611
+ }): Promise<WorkspaceEnvironment>;
612
+ declare function listWorkspaceEnvironments(db: Database, workspaceId: string): Promise<WorkspaceEnvironment[]>;
613
+ declare function getWorkspaceEnvironment(db: Database, workspaceId: string, environmentId: string): Promise<WorkspaceEnvironment | null>;
614
+ declare function getWorkspaceEnvironmentByName(db: Database, workspaceId: string, name: string): Promise<WorkspaceEnvironment | null>;
615
+ declare function updateWorkspaceEnvironment(db: Database, workspaceId: string, environmentId: string, input: {
616
+ name?: string;
617
+ description?: string | null;
618
+ }): Promise<WorkspaceEnvironment>;
619
+ declare function deleteWorkspaceEnvironment(db: Database, workspaceId: string, environmentId: string): Promise<boolean>;
620
+ declare function countWorkspaceEnvironments(db: Database, workspaceId: string): Promise<number>;
621
+ declare function countScheduledTasksUsingEnvironment(db: Database, workspaceId: string, environmentId: string): Promise<number>;
622
+ declare function countActiveSessionsUsingEnvironment(db: Database, workspaceId: string, environmentId: string): Promise<number>;
623
+ declare function setWorkspaceEnvironmentVariable(db: Database, input: {
624
+ accountId: string;
625
+ workspaceId: string;
626
+ environmentId: string;
627
+ name: string;
628
+ valueEncrypted: string;
629
+ }): Promise<WorkspaceEnvironmentVariableMetadata>;
630
+ declare function deleteWorkspaceEnvironmentVariable(db: Database, workspaceId: string, environmentId: string, name: string): Promise<boolean>;
631
+ /**
632
+ * The ONLY helper that selects value_encrypted. Used exclusively by the worker
633
+ * activity that materializes a sandbox for a run whose session carries an
634
+ * environment attachment. Do not call from API routes: values are write-only.
635
+ */
636
+ declare function getWorkspaceEnvironmentValuesForRun(db: Database, workspaceId: string, environmentId: string): Promise<{
637
+ environment: {
638
+ id: string;
639
+ name: string;
640
+ description: string | null;
641
+ };
642
+ values: Record<string, string>;
643
+ } | null>;
644
+ type WorkspaceEnvironmentForRun = {
645
+ id: string;
646
+ name: string;
647
+ description: string | null;
648
+ values: Record<string, string>;
649
+ };
650
+ /**
651
+ * Load and decrypt the workspace environment attached to a run's session. SHARED
652
+ * by the worker TURN path (apps/worker agent-turn) AND the API-direct ATTACH paths
653
+ * (viewer / Channel-A / desktop / terminal) so a box first warmed by an attach is
654
+ * created with the SAME decrypted workspace-environment values the turn declares —
655
+ * the box-manifest env must match the agent-manifest env or the SDK's
656
+ * `validateNoEnvironmentDelta` throws when the agent injects its manifest into the
657
+ * resumed non-owned box.
658
+ *
659
+ * `environmentId === null` is the unattached path: zero DB work and behavior
660
+ * byte-identical to deployments without this feature. Attached runs fail closed: a
661
+ * missing key or a deleted environment throws (names/ids only in messages) instead
662
+ * of silently running without the secrets the run expects.
663
+ */
664
+ declare function loadWorkspaceEnvironmentForRun(db: Database, settings: Settings, workspaceId: string, environmentId: string | null): Promise<WorkspaceEnvironmentForRun | null>;
665
+ type CodexCredentialTokens = {
666
+ accessToken: string;
667
+ refreshToken: string;
668
+ idToken: string;
669
+ };
670
+ type CodexCredentialForRun = {
671
+ id: string;
672
+ version: number;
673
+ workspaceId: string;
674
+ tokens: CodexCredentialTokens;
675
+ chatgptAccountId: string | null;
676
+ scopes: string | null;
677
+ planType: string | null;
678
+ isFedramp: boolean;
679
+ expiresAt: Date | null;
680
+ lastRefreshAt: Date | null;
681
+ status: string;
682
+ lastError: string | null;
683
+ };
684
+ /**
685
+ * Login / rotation write (multi-account P1). Caller passes the PRE-encrypted
686
+ * credential blob. Keyed on the composite partial index (workspace, chatgpt
687
+ * account): re-connecting the SAME ChatGPT account updates that row in place
688
+ * (re-asserts account_id, bumps version); connecting a NEW account inserts a new
689
+ * row. Returns the row id + whether it was newly inserted. The route — not this
690
+ * accessor — auto-activates a brand-new first account and ensures the
691
+ * rotation-settings row exists.
692
+ */
693
+ declare function upsertCodexSubscriptionCredential(db: Database, input: {
694
+ accountId: string;
695
+ workspaceId: string;
696
+ credentialEncrypted: string;
697
+ chatgptAccountId: string | null;
698
+ scopes: string | null;
699
+ planType: string | null;
700
+ isFedramp: boolean;
701
+ expiresAt: Date | null;
702
+ lastRefreshAt: Date | null;
703
+ accountEmail?: string | null;
704
+ label?: string | null;
705
+ }): Promise<{
706
+ id: string;
707
+ isNew: boolean;
708
+ }>;
709
+ /**
710
+ * The ONLY decrypt-read accessor. Fails closed. Never call from an API route that
711
+ * returns the result.
712
+ *
713
+ * The run's account is the resolved pin-or-active credential id, not LIMIT 1: the
714
+ * caller (worker) resolves the effective credential id and passes it here so a
715
+ * pinned session loads its SPECIFIC account. RLS still constrains the row to the
716
+ * workspace; an unknown/disconnected id returns null → the caller treats it as
717
+ * "needs relogin / re-pick".
718
+ */
719
+ declare function loadCodexCredentialForRun(db: Database, settings: Settings, workspaceId: string, credentialId: string): Promise<CodexCredentialForRun | null>;
720
+ /**
721
+ * Persist rotated tokens after a successful refresh. Caller pre-encrypts.
722
+ *
723
+ * COMPARE-AND-SET (P1-c): the write is guarded by the (id, version) the resolver
724
+ * loaded. If a disconnect→reconnect replaced/rotated the row between the load and
725
+ * this write, the guard matches 0 rows and we DO NOT clobber the freshly
726
+ * reconnected credential with tokens from the now-defunct family. Returns true
727
+ * iff the guarded row was updated; false means "credential changed under me —
728
+ * the rotation is moot, drop it."
729
+ */
730
+ declare function recordCodexTokenRefresh(db: Database, input: {
731
+ id: string;
732
+ version: number;
733
+ workspaceId: string;
734
+ credentialEncrypted: string;
735
+ expiresAt: Date | null;
736
+ lastRefreshAt: Date;
737
+ }): Promise<boolean>;
738
+ /**
739
+ * Surface a permanent or transient failure on a SPECIFIC credential row.
740
+ *
741
+ * COMPARE-AND-SET (P1-c): the status is stamped only if the row STILL matches the
742
+ * (id, version) the resolver loaded. This stops a refresh that began before a
743
+ * disconnect→reconnect (or a manual account switch) from stamping `needs_relogin`
744
+ * on the brand-new, good credential — with N accounts per workspace a
745
+ * workspace-wide write would be flat-out wrong (it would scribble on every
746
+ * account). Returns true iff the guarded row was updated.
747
+ */
748
+ declare function setCodexCredentialStatus(db: Database, workspaceId: string, status: "active" | "needs_relogin" | "error", lastError: string | null, target: {
749
+ id: string;
750
+ version: number;
751
+ }): Promise<boolean>;
752
+ /**
753
+ * Metadata-only read for API routes, repointed to the per-workspace ACTIVE
754
+ * credential. NEVER selects credential_encrypted.
755
+ *
756
+ * Reads codex_rotation_settings.active_credential_id and joins the credential by
757
+ * id (deterministic). If the pointer is NULL but credentials exist (the
758
+ * mid-disconnect window), it falls back to the most-recently-connected row and
759
+ * lazily repairs the pointer so the next read is deterministic. The returned
760
+ * `credentialId` is the active row's id (null when no credential exists at all).
761
+ */
762
+ declare function getCodexCredentialStatus(db: Database, workspaceId: string): Promise<{
763
+ connected: boolean;
764
+ credentialId: string | null;
765
+ chatgptAccountId: string | null;
766
+ scopes: string | null;
767
+ planType: string | null;
768
+ status: string;
769
+ expiresAt: Date | null;
770
+ lastRefreshAt: Date | null;
771
+ lastError: string | null;
772
+ } | null>;
773
+ /**
774
+ * Single source of truth for "this workspace has an ACTIVE ChatGPT/Codex
775
+ * subscription connected AND the feature is enabled for this deployment."
776
+ *
777
+ * This is the SAME condition `settingsWithCodexCredential` (worker) uses to
778
+ * decide whether to inject the synthetic codex-subscription provider, so billing
779
+ * and provider-injection cannot drift. Metadata-only read (never the secret).
780
+ */
781
+ declare function workspaceCodexSubscriptionActive(db: Database, settings: Pick<Settings, "codexSubscriptionEnabled">, workspaceId: string): Promise<boolean>;
782
+ /**
783
+ * CANONICAL "is this a Codex-billed turn?" predicate.
784
+ *
785
+ * True iff: the turn's model is a `codex/<slug>` id (`isCodexBilledModel`) AND
786
+ * the deployment flag is on AND the workspace has an ACTIVE credential. A true
787
+ * result means the turn is paid by the USER's ChatGPT/Codex plan and MUST consume
788
+ * ZERO OpenGeni credits: callers skip the credit-balance / model-cost / token
789
+ * gates and skip OpenGeni pricing + credit debit.
790
+ *
791
+ * The prefix ALONE never returns true: an unconnected user typing `codex/...`
792
+ * gets the normal gates (and the worker fails the turn for a missing credential),
793
+ * so there is no free/uncapped-run bypass.
794
+ */
795
+ declare function isCodexBilledTurn(input: {
796
+ db: Database;
797
+ settings: Pick<Settings, "codexSubscriptionEnabled">;
798
+ workspaceId: string;
799
+ model: string | null | undefined;
800
+ /**
801
+ * Precomputed `workspaceCodexSubscriptionActive` result (P2-b). When the caller
802
+ * already resolved the active flag for provider injection, pass it here so the
803
+ * billed-turn predicate and the routing overlay read the credential ONCE and
804
+ * cannot disagree across a concurrent disconnect/reconnect — a drift that would
805
+ * either wrongly debit OpenGeni credits for a ChatGPT-paid turn or the inverse.
806
+ */
807
+ active?: boolean;
808
+ }): Promise<boolean>;
809
+ type CodexAccountStatus = {
810
+ id: string;
811
+ chatgptAccountId: string | null;
812
+ label: string | null;
813
+ accountEmail: string | null;
814
+ planType: string | null;
815
+ status: string;
816
+ isActive: boolean;
817
+ expiresAt: Date | null;
818
+ lastRefreshAt: Date | null;
819
+ lastError: string | null;
820
+ primaryUsedPercent: number | null;
821
+ primaryResetAt: Date | null;
822
+ secondaryUsedPercent: number | null;
823
+ secondaryResetAt: Date | null;
824
+ usageCheckedAt: Date | null;
825
+ exhaustedUntil: Date | null;
826
+ connectorNamespaces: string[] | null;
827
+ connectorsCheckedAt: Date | null;
828
+ };
829
+ /**
830
+ * Metadata-only list of every connected Codex account in the workspace, for the
831
+ * accounts UI + the worker's selection resolver. NEVER decrypts. `isActive` marks
832
+ * the workspace active pointer. Ordered by created_at ASC (stable list order).
833
+ */
834
+ declare function listCodexAccountStatuses(db: Database, workspaceId: string): Promise<CodexAccountStatus[]>;
835
+ /** The P2 usage-cache snapshot written by the refreshing usage wrapper. */
836
+ type CodexAccountUsageSnapshot = {
837
+ primaryUsedPercent: number | null;
838
+ primaryResetAt: Date | null;
839
+ secondaryUsedPercent: number | null;
840
+ secondaryResetAt: Date | null;
841
+ checkedAt: Date;
842
+ };
843
+ /**
844
+ * Cache-write for P2 quota bars: persist the five plaintext usage columns on a
845
+ * SPECIFIC credential row. NEVER touches credential_encrypted. RLS-scoped, guarded
846
+ * by (id, workspace_id) so it can only write a row the workspace owns. Returns true
847
+ * iff a row was updated (false ⇒ the credential was disconnected under us — the
848
+ * snapshot is moot, drop it). This is the only writer of the usage_checked_at TTL
849
+ * clock that `listCodexAccountStatuses` reads back.
850
+ */
851
+ declare function recordCodexAccountUsage(db: Database, workspaceId: string, credentialId: string, snapshot: CodexAccountUsageSnapshot): Promise<boolean>;
852
+ type CodexRotationSettings = {
853
+ activeCredentialId: string | null;
854
+ rotationEnabled: boolean;
855
+ rotationStrategy: string;
856
+ };
857
+ /** The per-workspace rotation/active-pointer row (null when none exists yet). */
858
+ declare function getCodexRotationSettings(db: Database, workspaceId: string): Promise<CodexRotationSettings | null>;
859
+ /** Idempotently ensure the per-workspace rotation-settings row exists. */
860
+ declare function ensureCodexRotationSettings(db: Database, accountId: string, workspaceId: string): Promise<void>;
861
+ /**
862
+ * THE manual-switch primitive (workspace scope). Validates the credential id
863
+ * belongs to the workspace, then one-cell UPDATEs active_credential_id. Returns
864
+ * false if the id is unknown (so the route can 404).
865
+ */
866
+ declare function setActiveCodexCredential(db: Database, workspaceId: string, credentialId: string): Promise<boolean>;
867
+ /**
868
+ * P3 rotation cooldown writer: stamp `exhausted_until` on a SPECIFIC credential row so the
869
+ * rotation engine treats it as cooling-down (capped) until `until`. Pass `until = null` to
870
+ * clear the cooldown. Modeled EXACTLY on recordCodexAccountUsage: RLS-scoped, guarded by
871
+ * (id, workspace_id), and — critically — NO `version` bump and NO `updatedAt` touch, so it can
872
+ * never race the (id, version) token-refresh CAS in recordCodexTokenRefresh / setCodexCredentialStatus.
873
+ * Returns true iff a row was updated (false ⇒ the credential was disconnected under us).
874
+ */
875
+ declare function setCodexCredentialExhausted(db: Database, workspaceId: string, credentialId: string, until: Date | null): Promise<boolean>;
876
+ /**
877
+ * P3 reactive-rotation boundedness (Finding 1b): the number of CONSECUTIVE rotated
878
+ * 429-failover turns since the session last had a SUCCESSFUL turn. Counts
879
+ * `turn.failed` events carrying the `rotated` marker that occurred AFTER the most
880
+ * recent `turn.completed` event (the natural reset anchor — any successful turn
881
+ * moves the anchor past every prior failover, so the streak resets to 0). The
882
+ * reactive 429 catch consults this to bound its otherwise-0-delay re-dispatch:
883
+ * once the streak exceeds ~(connected accounts + margin) the path degrades to a
884
+ * fixed positive idle instead of another hot re-dispatch (invariant 4: NO THRASH),
885
+ * covering the double-fault where a cooldown write did not persist AND the 429
886
+ * carried no usage headers. Derived from persisted events so it is correct across
887
+ * the Temporal re-dispatch (each failover is a NEW turn, but its event survives).
888
+ */
889
+ declare function countConsecutiveReactiveRotations(db: Database, workspaceId: string, sessionId: string): Promise<number>;
890
+ /**
891
+ * P4 connector-set cache writer: persist the set of ORIGINAL-dotted connector
892
+ * namespaces a SPECIFIC credential exposes via codex_apps (+ the freshness clock).
893
+ * Modeled byte-for-byte on recordCodexAccountUsage / setCodexCredentialExhausted:
894
+ * RLS-scoped, guarded by (id, workspace_id), and — critically — NO `version` bump and
895
+ * NO `updatedAt` touch, so it can never race the (id, version) token-refresh CAS.
896
+ *
897
+ * The CALLER must only invoke this with a NON-EMPTY set: codex_apps connects
898
+ * best-effort (a transient failure yields an empty tools/list), and overwriting a
899
+ * known non-empty set with [] would falsely "drop" coverage on a flaky turn. A
900
+ * genuinely connector-less account stays null (the ranker treats null as unknown).
901
+ * Returns true iff a row was updated (false ⇒ the credential was disconnected under us).
902
+ */
903
+ declare function recordCodexAccountConnectors(db: Database, workspaceId: string, credentialId: string, namespaces: string[]): Promise<boolean>;
904
+ /** The supported rotation strategies (P3). */
905
+ declare const CODEX_ROTATION_STRATEGIES: readonly ["most_remaining", "round_robin", "drain_then_next"];
906
+ type CodexRotationStrategy = (typeof CODEX_ROTATION_STRATEGIES)[number];
907
+ /**
908
+ * P3 rotation-settings write path: one-cell UPDATE of `rotation_enabled` and/or
909
+ * `rotation_strategy` on the per-workspace row. Validates the strategy enum (rejects unknown).
910
+ * Guarded by workspaceId; ensureCodexRotationSettings guarantees the row exists. Returns the
911
+ * effective settings after the patch (null when no row exists yet — caller should ensure first).
912
+ */
913
+ declare function updateCodexRotationSettings(db: Database, workspaceId: string, patch: {
914
+ rotationEnabled?: boolean;
915
+ rotationStrategy?: CodexRotationStrategy;
916
+ }): Promise<CodexRotationSettings | null>;
917
+ /** P1 rename (label only); P3 widens to rotation fields. */
918
+ declare function renameCodexAccount(db: Database, workspaceId: string, credentialId: string, label: string | null): Promise<boolean>;
919
+ type SessionCodexState = {
920
+ pinnedCredentialId: string | null;
921
+ lastCredentialId: string | null;
922
+ };
923
+ /** The session's pin + last-ran-on Codex account (drives the worker resolver + indicator). */
924
+ declare function getSessionCodexState(db: Database, workspaceId: string, sessionId: string): Promise<SessionCodexState | null>;
925
+ /**
926
+ * Per-session pin (manual override). pinnedCredentialId === null clears the pin
927
+ * (follow the workspace active). Validates the id belongs to the workspace when
928
+ * non-null. Returns false if the session is unknown or the id is invalid.
929
+ */
930
+ declare function setSessionCodexPin(db: Database, workspaceId: string, sessionId: string, pinnedCredentialId: string | null): Promise<boolean>;
931
+ /** Written by the worker at the turn boundary; drives the in-session indicator. */
932
+ declare function recordSessionActiveCodexCredential(db: Database, workspaceId: string, sessionId: string, credentialId: string): Promise<void>;
933
+ /**
934
+ * Disconnect ONE account. DELETE WHERE id = credentialId AND workspace_id. If it
935
+ * was the active pointer, the FK ON DELETE SET NULL clears it; this fn then
936
+ * re-picks the most-recently-connected remaining account as active, atomically in
937
+ * the same RLS txn. Returns whether a row was removed + the new active id.
938
+ */
939
+ declare function disconnectCodexAccount(db: Database, workspaceId: string, credentialId: string): Promise<{
940
+ removed: boolean;
941
+ newActiveCredentialId: string | null;
942
+ }>;
943
+ /** Legacy "disconnect all" (old workspace-wide behavior). Returns rows removed. */
944
+ declare function disconnectAllCodexAccounts(db: Database, workspaceId: string): Promise<number>;
945
+ declare function recordAuditEvent(db: Database, input: {
946
+ accountId: string;
947
+ workspaceId?: string | null;
948
+ subjectId?: string | null;
949
+ action: string;
950
+ targetType?: string | null;
951
+ targetId?: string | null;
952
+ metadata?: Record<string, unknown>;
953
+ }): Promise<void>;
954
+ declare function createSession(db: Database, input: {
955
+ accountId: string;
956
+ workspaceId: string;
957
+ initialMessage: string;
958
+ resources: ResourceRef[];
959
+ tools?: ToolRef[];
960
+ metadata: Record<string, unknown>;
961
+ model: string;
962
+ sandboxBackend: SandboxBackend;
963
+ environmentId?: string | null;
964
+ firstPartyMcpPermissions?: Permission[] | null;
965
+ parentSessionId?: string | null;
966
+ createIdempotencyKey?: string | null;
967
+ sandboxGroupId?: string | null;
968
+ sandboxOs?: SandboxOs;
969
+ }): Promise<Session>;
970
+ /**
971
+ * Inserts a session under a workspace-scoped CREATE idempotency key, collapsing
972
+ * a concurrent race on the same key to a single row. On the unique-violation
973
+ * the conflicting insert does nothing (`onConflictDoNothing` on the partial
974
+ * unique index) and the now-existing winning row is fetched and returned, so
975
+ * two near-simultaneous creates with the same key yield ONE session and both
976
+ * callers see the same id. `created` distinguishes the winner (true: this call
977
+ * inserted and must run the rest of the start flow) from the loser/dup (false:
978
+ * the row already existed and must be returned as-is).
979
+ */
980
+ declare function createSessionWithIdempotencyKey(db: Database, input: {
981
+ accountId: string;
982
+ workspaceId: string;
983
+ initialMessage: string;
984
+ resources: ResourceRef[];
985
+ tools?: ToolRef[];
986
+ metadata: Record<string, unknown>;
987
+ model: string;
988
+ sandboxBackend: SandboxBackend;
989
+ environmentId?: string | null;
990
+ firstPartyMcpPermissions?: Permission[] | null;
991
+ parentSessionId?: string | null;
992
+ createIdempotencyKey: string;
993
+ sandboxGroupId?: string | null;
994
+ sandboxOs?: SandboxOs;
995
+ }): Promise<{
996
+ session: Session;
997
+ created: boolean;
998
+ }>;
999
+ declare function getSessionByCreateIdempotencyKey(db: Database, workspaceId: string, createIdempotencyKey: string): Promise<Session | null>;
1000
+ declare function getSession(db: Database, workspaceId: string, sessionId: string): Promise<Session | null>;
1001
+ /**
1002
+ * Resolve ANY session that belongs to a shared-sandbox group (addendum 05 §D.3,
1003
+ * stress (e)). Used by the create-session `sandbox:{groupId}` join path to (1)
1004
+ * prove the group exists and (2) inherit its box's (backend, os).
1005
+ *
1006
+ * `workspaceId` is a MANDATORY access boundary, NOT optional: the group uuid is
1007
+ * caller-supplied, so the workspace filter (inside RLS) is what forbids a
1008
+ * cross-workspace join — a foreign group returns null → the caller 404s. The
1009
+ * group uuid itself is never an authorization boundary. Returns the first member
1010
+ * session (any one suffices to read the shared box's backend/os); null when the
1011
+ * group has no session in this workspace.
1012
+ */
1013
+ declare function getAnySessionInGroup(db: Database, workspaceId: string, sandboxGroupId: string): Promise<Session | null>;
1014
+ /**
1015
+ * The DISTINCT environmentIds across a group's member sessions (workspace-
1016
+ * scoped; null = no environment attached). The env-aware create check compares
1017
+ * a joiner against EVERY member — an arbitrary single member (getAnySessionInGroup)
1018
+ * makes the compatibility verdict nondeterministic for legacy env-blind groups
1019
+ * whose members carry mixed environmentIds.
1020
+ */
1021
+ declare function listDistinctEnvironmentIdsInGroup(db: Database, workspaceId: string, sandboxGroupId: string): Promise<Array<string | null>>;
1022
+ declare function listSessions(db: Database, workspaceId: string, limit?: number): Promise<Session[]>;
1023
+ /**
1024
+ * Count sessions still attached to a live Temporal workflow: queued, running,
1025
+ * or awaiting an approval (requires_action). idle has no running execution and
1026
+ * failed/cancelled are terminal, so neither blocks a workspace delete. The
1027
+ * delete path uses this to refuse (409) while a session could still be running
1028
+ * in Temporal, since there is no clean session-terminate to call first.
1029
+ */
1030
+ declare function countActiveSessionsForWorkspace(db: Database, workspaceId: string): Promise<number>;
1031
+ declare function requireSession(db: Database, workspaceId: string, sessionId: string): Promise<Session>;
1032
+ declare function listSessionEvents(db: Database, workspaceId: string, sessionId: string, after?: number, limit?: number): Promise<SessionEvent[]>;
1033
+ declare function getSessionEvent(db: Database, workspaceId: string, eventId: string): Promise<SessionEvent | null>;
1034
+ declare function getLatestRunState(db: Database, workspaceId: string, sessionId: string): Promise<{
1035
+ id: string;
1036
+ serializedRunState: string;
1037
+ pendingApprovals: unknown[];
1038
+ frozenCodexCredentialId: string | null;
1039
+ } | null>;
1040
+ /**
1041
+ * Append conversation items (verbatim SDK AgentInputItems) to the session's
1042
+ * history. Idempotent on (workspace, session, position): concurrent or
1043
+ * repeated writers (streaming writes + turn-end reconciliation) converge
1044
+ * instead of duplicating.
1045
+ */
1046
+ declare function appendSessionHistoryItems(db: Database, input: {
1047
+ accountId: string;
1048
+ workspaceId: string;
1049
+ sessionId: string;
1050
+ turnId?: string | null;
1051
+ producerCodexCredentialId?: string | null;
1052
+ items: Array<{
1053
+ position: number;
1054
+ item: Record<string, unknown>;
1055
+ }>;
1056
+ }): Promise<void>;
1057
+ declare function getSessionHistoryItems(db: Database, workspaceId: string, sessionId: string): Promise<Array<{
1058
+ position: number;
1059
+ item: Record<string, unknown>;
1060
+ }>>;
1061
+ /**
1062
+ * The LIVE conversation-truth read path: only active rows, position-ordered.
1063
+ * After a client-side context compaction this returns [active summary,
1064
+ * ...active recent tail]; with no compaction yet it equals
1065
+ * getSessionHistoryItems. The model-facing read path uses this so superseded
1066
+ * (summarized-away) prefix rows are excluded while the full transcript stays in
1067
+ * the table as an audit trail.
1068
+ */
1069
+ declare function getActiveSessionHistoryItems(db: Database, workspaceId: string, sessionId: string): Promise<Array<{
1070
+ position: number;
1071
+ item: Record<string, unknown>;
1072
+ producerCodexCredentialId: string | null;
1073
+ }>>;
1074
+ /**
1075
+ * Count of ACTIVE (live, model-facing) history rows for a session. This is the
1076
+ * length of the history the next turn is seeded from — the dual-write slice
1077
+ * index — which after a compaction is far smaller than the total persisted-row
1078
+ * count (countSessionHistoryItems still includes the superseded prefix).
1079
+ */
1080
+ declare function countActiveSessionHistoryItems(db: Database, workspaceId: string, sessionId: string): Promise<number>;
1081
+ /**
1082
+ * Pure TypeScript SPEC for the one-time orphan repair (migration 0014),
1083
+ * mirroring its SQL WHERE clause so the deletion rule is unit-testable without a
1084
+ * database. Given the ACTIVE history rows of a single session in position order,
1085
+ * returns the indices of the orphaned tool-call RESULT rows the repair deletes.
1086
+ *
1087
+ * An orphan is a result-type row (function_call_result / computer_call_result /
1088
+ * shell_call_output / apply_patch_call_output) with no matching CALL of the
1089
+ * paired type, same correlation id (camelCase `callId` OR snake_case `call_id`),
1090
+ * at a STRICTLY EARLIER position in the same session. This is exactly the
1091
+ * session-bricking row the Responses API 400s on ("No tool call found for
1092
+ * function call output").
1093
+ *
1094
+ * DANGLING CALLS (a call with no result yet) are intentionally NOT returned: a
1095
+ * call awaiting a not-yet-settled result is valid, not corruption. Only unpaired
1096
+ * results are removed.
1097
+ *
1098
+ * EXISTENCE, not consumption: like the migration's `NOT EXISTS (... earlier
1099
+ * call ...)`, a result is kept whenever ANY earlier matching call exists. A
1100
+ * second result that re-uses a call_id already settled earlier is therefore NOT
1101
+ * flagged here (a matching call still exists before it) — this conservative
1102
+ * choice matches the SQL exactly and never deletes a row whose call is present;
1103
+ * the read-path sanitizer (which consumes calls one-for-one) still drops such a
1104
+ * rare duplicate in-memory, so the model request stays valid regardless.
1105
+ *
1106
+ * Callers pass rows already ordered by position. The earlier-position test is
1107
+ * by array order (the SQL orders by the numeric position column, which the read
1108
+ * path also orders by), so identical inputs yield identical decisions.
1109
+ */
1110
+ declare function orphanedResultRowIndicesForRepair(activeRowsInPositionOrder: ReadonlyArray<{
1111
+ item: Record<string, unknown>;
1112
+ }>): number[];
1113
+ /**
1114
+ * Apply a client-side context compaction as an atomic, audit-preserving write:
1115
+ *
1116
+ * - supersede (set active=false) every active row whose position lies in
1117
+ * [0, boundaryPosition) — i.e. the summarized prefix — EXCLUDING the tail.
1118
+ * Rows are never deleted.
1119
+ * - insert ONE active synthetic summary row at `summaryPosition` (a FRACTIONAL
1120
+ * position — boundaryPosition - 0.5 — that sorts immediately before the kept
1121
+ * tail and collides with NO existing row, so no real prefix row is ever
1122
+ * overwritten). Idempotent on position: a retry that finds the summary row
1123
+ * already there does not duplicate it (it only re-activates the existing
1124
+ * summary row at that fractional position) and — crucially — never mutates
1125
+ * the real row at boundaryPosition - 1.
1126
+ *
1127
+ * The caller computes the boundary from the orphan-safe planner so no tool-call
1128
+ * pair straddles the cut. `summaryPosition` must be < boundaryPosition (between
1129
+ * the last superseded prefix row and the kept tail), guaranteeing it sorts
1130
+ * before the tail. Because positions are whole numbers and summaries are
1131
+ * half-steps, the summary's fractional position can never equal a real row.
1132
+ */
1133
+ declare function applyContextCompaction(db: Database, input: {
1134
+ accountId: string;
1135
+ workspaceId: string;
1136
+ sessionId: string;
1137
+ turnId?: string | null;
1138
+ /** Active prefix rows with position < boundaryPosition get superseded. */
1139
+ boundaryPosition: number;
1140
+ /** Fractional position for the new summary row (must be < boundaryPosition). */
1141
+ summaryPosition: number;
1142
+ summaryItem: Record<string, unknown>;
1143
+ }): Promise<void>;
1144
+ /**
1145
+ * The next free WHOLE-NUMBER history position for a session: one past the
1146
+ * largest existing position (active or superseded), floored so the synthetic
1147
+ * summary's fractional half-step never shifts the count. The dual-write
1148
+ * watermark uses this to append new rows at fresh absolute positions, decoupled
1149
+ * from the in-memory history length (which, after a compaction, is far shorter
1150
+ * than the total persisted-row count and so cannot serve as the next position).
1151
+ */
1152
+ declare function nextSessionHistoryPosition(db: Database, workspaceId: string, sessionId: string): Promise<number>;
1153
+ /**
1154
+ * Record the actual input-token count of the most recent turn's final model
1155
+ * call, for the next turn's pre-read compaction trigger.
1156
+ */
1157
+ declare function setSessionLastInputTokens(db: Database, workspaceId: string, sessionId: string, lastInputTokens: number): Promise<void>;
1158
+ /**
1159
+ * The neutral marker written by clearSessionContext as the sole active history
1160
+ * row. It keeps getActiveSessionHistoryItems().length > 0 so the items read
1161
+ * path (run-input.ts messageInput) stays selected and never falls through to
1162
+ * the getLatestRunState blob — that fallback is the resurrection vector a clear
1163
+ * must defeat. A plain user message is a valid, sanitizer-clean item.
1164
+ */
1165
+ declare function clearedContextMarkerItem(): Record<string, unknown>;
1166
+ /**
1167
+ * The sentinel serializedRunState written by clearSessionContext, re-exported
1168
+ * from @opengeni/contracts so the writer (here) and the readers (run-input /
1169
+ * runtime) share one definition. It is audit-honest (carries no prior
1170
+ * conversation) and is NOT a real Agents-SDK run state — it has no
1171
+ * `$schemaVersion`/history, so `RunState.fromString` throws on it.
1172
+ *
1173
+ * Both run-state read paths therefore guard against it explicitly via
1174
+ * {@link isClearedRunStateBlob}:
1175
+ * - the message path (run-input messageInput) honors it in BOTH items and
1176
+ * run_state history modes — in items mode the boundary marker keeps the
1177
+ * active read non-empty so the blob is never reached, and in run_state mode
1178
+ * the sentinel is recognized and treated as a fresh empty start;
1179
+ * - the approval path is additionally refused by the API for mid-turn /
1180
+ * requires_action sessions, so it never sees the sentinel.
1181
+ * Stored so getLatestRunState (the run_state-source read path) reflects the
1182
+ * clear instead of resurrecting the pre-clear blob.
1183
+ */
1184
+ declare const CLEARED_RUN_STATE: string;
1185
+ type ClearSessionContextResult = {
1186
+ /** Active history rows superseded (active=true -> false). */
1187
+ supersededItems: number;
1188
+ /** Position of the inserted neutral boundary marker. */
1189
+ markerPosition: number;
1190
+ /** stateVersion of the fresh cleared run-state row. */
1191
+ runStateVersion: number;
1192
+ };
1193
+ /**
1194
+ * Clear a session's conversation context in ONE transaction, audit-preserving
1195
+ * and idempotent. Defeats the RunState-fallback resurrection on BOTH model read
1196
+ * paths:
1197
+ *
1198
+ * (a) supersede every active session_history_items row (active=true -> false).
1199
+ * Nothing is deleted — the full transcript stays as an audit trail, same
1200
+ * pattern as applyContextCompaction.
1201
+ * (b) insert ONE active neutral boundary marker at max(position)+1 so the
1202
+ * active read path returns length 1 (not 0) and run-input.ts stays on the
1203
+ * items route, away from the getLatestRunState blob (the bug).
1204
+ * (c) insert a fresh agent_run_states row (stateVersion = max+1) with an empty
1205
+ * cleared blob and pendingApprovals:[], so getLatestRunState (approval /
1206
+ * run_state-source read path) also reflects the clear.
1207
+ *
1208
+ * Also resets last_input_tokens to 0 so the next turn's compaction trigger
1209
+ * starts fresh against the now-short context.
1210
+ *
1211
+ * Idempotent: a re-run supersedes the (now sole, already-marker) active row,
1212
+ * inserts another marker at the next position, and another cleared run-state.
1213
+ * The post-conditions (one active marker row, latest run-state cleared) hold.
1214
+ */
1215
+ declare function clearSessionContext(db: Database, input: {
1216
+ accountId: string;
1217
+ workspaceId: string;
1218
+ sessionId: string;
1219
+ }): Promise<ClearSessionContextResult>;
1220
+ declare function countSessionHistoryItems(db: Database, workspaceId: string, sessionId: string): Promise<number>;
1221
+ /**
1222
+ * Set the operator /compact request flag. The worker honors it before the next
1223
+ * turn (forced client-side compaction) and clears it. Idempotent: repeated
1224
+ * requests collapse to one pending compaction.
1225
+ */
1226
+ declare function requestSessionCompaction(db: Database, workspaceId: string, sessionId: string): Promise<void>;
1227
+ /**
1228
+ * Atomically consume the /compact request flag: clear it and report whether it
1229
+ * was set. The worker calls this pre-turn; only the call that observed `true`
1230
+ * runs the forced compaction, so concurrent turns can't double-compact.
1231
+ */
1232
+ declare function consumeSessionCompactionRequest(db: Database, workspaceId: string, sessionId: string): Promise<boolean>;
1233
+ /**
1234
+ * Number of conversation-truth items a specific turn persisted. The
1235
+ * worker-death requeue path uses this to decide whether the re-dispatched
1236
+ * turn must enter through a resume notice (its partial progress is already
1237
+ * part of conversation truth, so replaying the original trigger would hand
1238
+ * the model duplicate input) or can replay its original trigger cleanly.
1239
+ */
1240
+ declare function countTurnSessionHistoryItems(db: Database, workspaceId: string, turnId: string): Promise<number>;
1241
+ /**
1242
+ * Persist the session's sandbox recovery descriptor (the small versioned
1243
+ * envelope used to reattach / snapshot-restore / rebuild the sandbox),
1244
+ * decoupled from the RunState blob.
1245
+ */
1246
+ declare function upsertSandboxSessionEnvelope(db: Database, input: {
1247
+ accountId: string;
1248
+ workspaceId: string;
1249
+ sessionId: string;
1250
+ envelope: Record<string, unknown>;
1251
+ }): Promise<void>;
1252
+ declare function getSandboxSessionEnvelope(db: Database, workspaceId: string, sessionId: string): Promise<Record<string, unknown> | null>;
1253
+ type SessionRecordingState = (typeof sessionRecordingStateValues)[number];
1254
+ type SessionRecordingMode = (typeof sessionRecordingModeValues)[number];
1255
+ type SessionRecordingCodec = (typeof sessionRecordingCodecValues)[number];
1256
+ type SessionRecordingRow = {
1257
+ id: string;
1258
+ workspaceId: string;
1259
+ sessionId: string;
1260
+ turnId: string | null;
1261
+ state: SessionRecordingState;
1262
+ mode: SessionRecordingMode;
1263
+ codec: SessionRecordingCodec;
1264
+ storageKey: string | null;
1265
+ sizeBytes: number | null;
1266
+ durationSeconds: number | null;
1267
+ width: number;
1268
+ height: number;
1269
+ reason: string | null;
1270
+ createdAt: Date;
1271
+ finalizedAt: Date | null;
1272
+ };
1273
+ declare function insertRecording(db: Database, input: {
1274
+ id: string;
1275
+ accountId: string;
1276
+ workspaceId: string;
1277
+ sessionId: string;
1278
+ turnId?: string | null;
1279
+ mode: SessionRecordingMode;
1280
+ codec: SessionRecordingCodec;
1281
+ width: number;
1282
+ height: number;
1283
+ reason?: string | null;
1284
+ }): Promise<SessionRecordingRow>;
1285
+ declare function updateRecording(db: Database, input: {
1286
+ accountId: string;
1287
+ workspaceId: string;
1288
+ recordingId: string;
1289
+ state: SessionRecordingState;
1290
+ storageKey?: string | null;
1291
+ sizeBytes?: number | null;
1292
+ durationSeconds?: number | null;
1293
+ reason?: string | null;
1294
+ finalized?: boolean;
1295
+ }): Promise<SessionRecordingRow | null>;
1296
+ /**
1297
+ * Hard-delete a recording row. Used to DISCARD an on-turn recording that captured
1298
+ * NO computer-use activity (a plain text turn): the row was inserted at
1299
+ * `beginRecording` (state "recording") but the turn never drove the desktop, so it
1300
+ * is removed entirely rather than surfaced as a phantom recording or a failure. No
1301
+ * other table FK-references session_recordings, so the delete is self-contained.
1302
+ */
1303
+ declare function deleteRecording(db: Database, input: {
1304
+ accountId: string;
1305
+ workspaceId: string;
1306
+ recordingId: string;
1307
+ }): Promise<void>;
1308
+ declare function getRecording(db: Database, workspaceId: string, recordingId: string): Promise<SessionRecordingRow | null>;
1309
+ declare function listRecordings(db: Database, workspaceId: string, sessionId: string): Promise<SessionRecordingRow[]>;
1310
+ type SandboxPtySessionRow = {
1311
+ id: string;
1312
+ accountId: string;
1313
+ workspaceId: string;
1314
+ sessionId: string;
1315
+ execSessionId: number | null;
1316
+ leaseEpoch: number;
1317
+ cols: number;
1318
+ rows: number;
1319
+ shell: string;
1320
+ cwd: string;
1321
+ status: "open" | "closed";
1322
+ openedBy: string;
1323
+ lastInputAt: string;
1324
+ createdAt: string;
1325
+ closedAt: string | null;
1326
+ };
1327
+ declare function insertPtySession(db: Database, input: {
1328
+ id: string;
1329
+ accountId: string;
1330
+ workspaceId: string;
1331
+ sessionId: string;
1332
+ execSessionId?: number | null;
1333
+ leaseEpoch: number;
1334
+ cols: number;
1335
+ rows: number;
1336
+ shell: string;
1337
+ cwd: string;
1338
+ openedBy: string;
1339
+ }): Promise<SandboxPtySessionRow>;
1340
+ /** Read an OPEN PTY row by ptyId. Returns null when absent or already closed. */
1341
+ declare function getOpenPtySession(db: Database, workspaceId: string, ptyId: string): Promise<SandboxPtySessionRow | null>;
1342
+ /** Stamp the SDK exec-session id (known only after the open exec yields a still-
1343
+ * running process) + refresh the input-activity TTL. */
1344
+ declare function updatePtySessionActivity(db: Database, input: {
1345
+ accountId: string;
1346
+ workspaceId: string;
1347
+ ptyId: string;
1348
+ execSessionId?: number | null;
1349
+ cols?: number;
1350
+ rows?: number;
1351
+ }): Promise<SandboxPtySessionRow | null>;
1352
+ /** Mark a PTY closed (idempotent — a double close on a closed row is a no-op). */
1353
+ declare function closePtySession(db: Database, input: {
1354
+ accountId: string;
1355
+ workspaceId: string;
1356
+ ptyId: string;
1357
+ }): Promise<SandboxPtySessionRow | null>;
1358
+ /** List a session's OPEN PTYs (reattach + reap). */
1359
+ declare function listOpenPtySessions(db: Database, workspaceId: string, sessionId: string): Promise<SandboxPtySessionRow[]>;
1360
+ type SandboxLeaseLiveness = "cold" | "warming" | "warm" | "draining";
1361
+ type LeaseHolderKind = "turn" | "viewer";
1362
+ interface LeaseSnapshot {
1363
+ id: string;
1364
+ sandboxGroupId: string;
1365
+ liveness: SandboxLeaseLiveness;
1366
+ refcount: number;
1367
+ turnHolders: number;
1368
+ viewerHolders: number;
1369
+ instanceId: string | null;
1370
+ backend: string;
1371
+ os: string;
1372
+ image: string | null;
1373
+ dataPlaneUrl: string | null;
1374
+ terminalDataPlaneUrl: string | null;
1375
+ leaseEpoch: number;
1376
+ resumeBackendId: string | null;
1377
+ resumeState: Record<string, unknown> | null;
1378
+ expiresAt: Date;
1379
+ }
1380
+ interface AcquireLeaseInput {
1381
+ accountId: string;
1382
+ workspaceId: string;
1383
+ sandboxGroupId: string;
1384
+ kind: LeaseHolderKind;
1385
+ holderId: string;
1386
+ subjectId?: string | null;
1387
+ backend: string;
1388
+ os?: string;
1389
+ image?: string | null;
1390
+ leaseTtlMs: number;
1391
+ expectedEpoch?: number;
1392
+ }
1393
+ type AcquireLeaseResult = {
1394
+ role: "spawner";
1395
+ lease: LeaseSnapshot;
1396
+ } | {
1397
+ role: "attached";
1398
+ lease: LeaseSnapshot;
1399
+ } | {
1400
+ role: "rearmed";
1401
+ lease: LeaseSnapshot;
1402
+ } | {
1403
+ role: "fenced";
1404
+ lease: LeaseSnapshot;
1405
+ };
1406
+ declare class SandboxLeaseSupersededError extends Error {
1407
+ readonly sandboxGroupId: string;
1408
+ readonly leaseEpoch: number;
1409
+ constructor(sandboxGroupId: string, leaseEpoch: number);
1410
+ }
1411
+ declare class SandboxImageConflictError extends Error {
1412
+ readonly sandboxGroupId: string;
1413
+ readonly currentImage: string;
1414
+ readonly requestedImage: string;
1415
+ constructor(sandboxGroupId: string, currentImage: string, requestedImage: string);
1416
+ }
1417
+ declare function acquireLease(db: Database, input: AcquireLeaseInput): Promise<AcquireLeaseResult>;
1418
+ declare function commitWarmingToWarm(db: Database, input: {
1419
+ accountId: string;
1420
+ workspaceId: string;
1421
+ sandboxGroupId: string;
1422
+ expectedEpoch: number;
1423
+ instanceId: string;
1424
+ dataPlaneUrl?: string | null;
1425
+ resumeBackendId?: string | null;
1426
+ resumeState?: Record<string, unknown> | null;
1427
+ leaseTtlMs: number;
1428
+ }): Promise<{
1429
+ committed: boolean;
1430
+ lease: LeaseSnapshot | null;
1431
+ }>;
1432
+ declare function failWarmingToCold(db: Database, input: {
1433
+ accountId: string;
1434
+ workspaceId: string;
1435
+ sandboxGroupId: string;
1436
+ expectedEpoch: number;
1437
+ }): Promise<void>;
1438
+ declare function releaseLeaseHolder(db: Database, input: {
1439
+ accountId: string;
1440
+ workspaceId: string;
1441
+ sandboxGroupId: string;
1442
+ kind: LeaseHolderKind;
1443
+ holderId: string;
1444
+ idleGraceMs: number;
1445
+ }): Promise<{
1446
+ liveness: SandboxLeaseLiveness;
1447
+ refcount: number;
1448
+ } | null>;
1449
+ declare function heartbeatLeaseHolder(db: Database, input: {
1450
+ accountId: string;
1451
+ workspaceId: string;
1452
+ sandboxGroupId: string;
1453
+ kind: LeaseHolderKind;
1454
+ holderId: string;
1455
+ leaseTtlMs: number;
1456
+ expectedEpoch: number;
1457
+ }): Promise<boolean>;
1458
+ interface ReapDrainable {
1459
+ workspaceId: string;
1460
+ sandboxGroupId: string;
1461
+ instanceId: string | null;
1462
+ leaseEpoch: number;
1463
+ }
1464
+ declare function reapStaleLeaseHolders(db: Database, input: {
1465
+ workspaceId: string;
1466
+ viewerHolderTtlMs: number;
1467
+ idleGraceMs: number;
1468
+ }): Promise<{
1469
+ reapedViewers: number;
1470
+ warmingReset: number;
1471
+ drained: ReapDrainable[];
1472
+ }>;
1473
+ declare function reapStaleLeaseHoldersGlobal(db: Database, input: {
1474
+ viewerHolderTtlMs: number;
1475
+ idleGraceMs: number;
1476
+ }): Promise<ReapDrainable[]>;
1477
+ interface MeterableWarmLease {
1478
+ accountId: string;
1479
+ workspaceId: string;
1480
+ sandboxGroupId: string;
1481
+ leaseEpoch: number;
1482
+ backend: string;
1483
+ }
1484
+ declare function listMeterableWarmLeases(db: Database): Promise<MeterableWarmLease[]>;
1485
+ declare function reArmDrainingLease(db: Database, input: {
1486
+ accountId: string;
1487
+ workspaceId: string;
1488
+ sandboxGroupId: string;
1489
+ leaseTtlMs: number;
1490
+ }): Promise<{
1491
+ rearmed: boolean;
1492
+ }>;
1493
+ declare function confirmDrainCold(db: Database, input: {
1494
+ accountId: string;
1495
+ workspaceId: string;
1496
+ sandboxGroupId: string;
1497
+ expectedEpoch: number;
1498
+ }): Promise<{
1499
+ wentCold: boolean;
1500
+ }>;
1501
+ declare function persistDrainSnapshot(db: Database, input: {
1502
+ accountId: string;
1503
+ workspaceId: string;
1504
+ sandboxGroupId: string;
1505
+ expectedEpoch: number;
1506
+ /** base64 of the provider snapshot-ref / tar archive from persistWorkspace().
1507
+ * Pass null to CAS-check without writing (for backends with no persistWorkspace). */
1508
+ workspaceArchive: string | null;
1509
+ }): Promise<{
1510
+ wrote: boolean;
1511
+ priorArchive: string | null;
1512
+ }>;
1513
+ declare function readLease(db: Database, workspaceId: string, sandboxGroupId: string): Promise<LeaseSnapshot | null>;
1514
+ declare function recordLeaseDataPlaneUrl(db: Database, input: {
1515
+ accountId: string;
1516
+ workspaceId: string;
1517
+ sandboxGroupId: string;
1518
+ expectedEpoch: number;
1519
+ dataPlaneUrl: string | null;
1520
+ }): Promise<LeaseSnapshot | null>;
1521
+ declare function recordLeaseTerminalDataPlaneUrl(db: Database, input: {
1522
+ accountId: string;
1523
+ workspaceId: string;
1524
+ sandboxGroupId: string;
1525
+ expectedEpoch: number;
1526
+ terminalDataPlaneUrl: string | null;
1527
+ }): Promise<LeaseSnapshot | null>;
1528
+ type SandboxKind = (typeof sandboxKindValues)[number];
1529
+ type EnrollmentExposure = (typeof enrollmentExposureValues)[number];
1530
+ type EnrollmentStatus = (typeof enrollmentStatusValues)[number];
1531
+ type EnrollmentOs = (typeof enrollmentOsValues)[number];
1532
+ type EnrollmentRecord = {
1533
+ id: string;
1534
+ accountId: string;
1535
+ workspaceId: string;
1536
+ pubkey: string;
1537
+ exposure: EnrollmentExposure;
1538
+ hasDisplay: boolean;
1539
+ allowScreenControl: boolean;
1540
+ status: EnrollmentStatus;
1541
+ os: EnrollmentOs;
1542
+ arch: string;
1543
+ lastSeenAt: string | null;
1544
+ createdAt: string;
1545
+ revokedAt: string | null;
1546
+ updatedAt: string;
1547
+ };
1548
+ type SandboxRecord = {
1549
+ id: string;
1550
+ accountId: string;
1551
+ workspaceId: string;
1552
+ kind: SandboxKind;
1553
+ name: string;
1554
+ enrollmentId: string | null;
1555
+ createdAt: string;
1556
+ updatedAt: string;
1557
+ };
1558
+ declare function createEnrollment(db: Database, input: {
1559
+ accountId: string;
1560
+ workspaceId: string;
1561
+ pubkey: string;
1562
+ exposure?: EnrollmentExposure;
1563
+ hasDisplay?: boolean;
1564
+ allowScreenControl?: boolean;
1565
+ os?: EnrollmentOs;
1566
+ arch?: string;
1567
+ }): Promise<EnrollmentRecord>;
1568
+ declare function getEnrollment(db: Database, workspaceId: string, enrollmentId: string): Promise<EnrollmentRecord | null>;
1569
+ declare function listEnrollments(db: Database, workspaceId: string, options?: {
1570
+ status?: EnrollmentStatus;
1571
+ }): Promise<EnrollmentRecord[]>;
1572
+ declare function revokeEnrollment(db: Database, input: {
1573
+ accountId: string;
1574
+ workspaceId: string;
1575
+ enrollmentId: string;
1576
+ }): Promise<{
1577
+ revoked: boolean;
1578
+ }>;
1579
+ declare function touchEnrollmentLastSeen(db: Database, input: {
1580
+ accountId: string;
1581
+ workspaceId: string;
1582
+ enrollmentId: string;
1583
+ }): Promise<void>;
1584
+ declare function setEnrollmentHasDisplay(db: Database, input: {
1585
+ accountId: string;
1586
+ workspaceId: string;
1587
+ enrollmentId: string;
1588
+ hasDisplay: boolean;
1589
+ }): Promise<{
1590
+ updated: boolean;
1591
+ }>;
1592
+ type DeviceEnrollmentStatus = (typeof deviceEnrollmentStatusValues)[number];
1593
+ type DeviceEnrollmentRequestRecord = {
1594
+ id: string;
1595
+ deviceCode: string;
1596
+ userCode: string;
1597
+ accountId: string;
1598
+ workspaceId: string;
1599
+ pubkey: string;
1600
+ os: EnrollmentOs;
1601
+ arch: string;
1602
+ machineName: string | null;
1603
+ requestedExposure: EnrollmentExposure;
1604
+ canOfferDisplay: boolean;
1605
+ requestsScreenControl: boolean;
1606
+ status: DeviceEnrollmentStatus;
1607
+ approvedBySubjectId: string | null;
1608
+ approvedBySubjectLabel: string | null;
1609
+ allowScreenControl: boolean;
1610
+ approvedAt: string | null;
1611
+ enrollmentId: string | null;
1612
+ sandboxId: string | null;
1613
+ expiresAt: string;
1614
+ createdAt: string;
1615
+ updatedAt: string;
1616
+ };
1617
+ declare function createDeviceEnrollmentRequest(db: Database, input: {
1618
+ accountId: string;
1619
+ workspaceId: string;
1620
+ deviceCode: string;
1621
+ userCode: string;
1622
+ pubkey: string;
1623
+ os?: EnrollmentOs;
1624
+ arch?: string;
1625
+ machineName?: string | null;
1626
+ requestedExposure?: EnrollmentExposure;
1627
+ canOfferDisplay?: boolean;
1628
+ requestsScreenControl?: boolean;
1629
+ expiresAt: Date;
1630
+ }): Promise<DeviceEnrollmentRequestRecord>;
1631
+ declare function getDeviceEnrollmentRequestByDeviceCode(db: Database, deviceCode: string): Promise<DeviceEnrollmentRequestRecord | null>;
1632
+ declare function getPendingDeviceEnrollmentRequestByUserCode(db: Database, workspaceId: string, userCode: string): Promise<DeviceEnrollmentRequestRecord | null>;
1633
+ declare function getPendingDeviceEnrollmentRequestByUserCodeGlobal(db: Database, userCode: string): Promise<DeviceEnrollmentRequestRecord | null>;
1634
+ declare function finalizeEnrollmentByToken(db: Database, input: {
1635
+ accountId: string;
1636
+ workspaceId: string;
1637
+ pubkey: string;
1638
+ hasDisplay: boolean;
1639
+ allowScreenControl: boolean;
1640
+ os: EnrollmentOs;
1641
+ arch: string;
1642
+ sandboxName: string;
1643
+ now?: Date;
1644
+ }): Promise<{
1645
+ enrollment: EnrollmentRecord;
1646
+ sandbox: SandboxRecord;
1647
+ }>;
1648
+ declare function approveDeviceEnrollmentRequest(db: Database, input: {
1649
+ accountId: string;
1650
+ workspaceId: string;
1651
+ requestId: string;
1652
+ allowScreenControl: boolean;
1653
+ approvedBySubjectId: string;
1654
+ approvedBySubjectLabel?: string | null;
1655
+ sandboxName: string;
1656
+ now?: Date;
1657
+ }): Promise<{
1658
+ approved: boolean;
1659
+ enrollment: EnrollmentRecord | null;
1660
+ sandbox: SandboxRecord | null;
1661
+ }>;
1662
+ declare function denyDeviceEnrollmentRequest(db: Database, input: {
1663
+ accountId: string;
1664
+ workspaceId: string;
1665
+ requestId: string;
1666
+ }): Promise<{
1667
+ denied: boolean;
1668
+ }>;
1669
+ declare function consumeDeviceEnrollmentRequest(db: Database, input: {
1670
+ accountId: string;
1671
+ workspaceId: string;
1672
+ requestId: string;
1673
+ }): Promise<{
1674
+ consumed: boolean;
1675
+ }>;
1676
+ declare function createSandbox(db: Database, input: {
1677
+ accountId: string;
1678
+ workspaceId: string;
1679
+ kind: SandboxKind;
1680
+ name: string;
1681
+ enrollmentId?: string | null;
1682
+ }): Promise<SandboxRecord>;
1683
+ declare function getSandbox(db: Database, workspaceId: string, sandboxId: string): Promise<SandboxRecord | null>;
1684
+ declare function listSandboxes(db: Database, workspaceId: string): Promise<SandboxRecord[]>;
1685
+ type ActiveSandboxPointer = {
1686
+ activeSandboxId: string | null;
1687
+ activeEpoch: number;
1688
+ workingDir: string | null;
1689
+ };
1690
+ declare function readActiveSandbox(db: Database, workspaceId: string, sessionId: string): Promise<ActiveSandboxPointer | null>;
1691
+ declare function setActiveSandbox(db: Database, input: {
1692
+ accountId: string;
1693
+ workspaceId: string;
1694
+ sessionId: string;
1695
+ targetSandboxId: string | null;
1696
+ expectedEpoch: number;
1697
+ workingDir?: string | null;
1698
+ }): Promise<{
1699
+ swapped: boolean;
1700
+ pointer: ActiveSandboxPointer | null;
1701
+ }>;
1702
+ type MachineMetricsSample = {
1703
+ cpuPercent?: number | null;
1704
+ load1?: number | null;
1705
+ load5?: number | null;
1706
+ load15?: number | null;
1707
+ memUsedBytes?: number | null;
1708
+ memTotalBytes?: number | null;
1709
+ diskUsedBytes?: number | null;
1710
+ diskTotalBytes?: number | null;
1711
+ gpuUtilPercent?: number | null;
1712
+ gpuMemUsedBytes?: number | null;
1713
+ gpuMemTotalBytes?: number | null;
1714
+ contention?: number | null;
1715
+ sampledAt: Date;
1716
+ };
1717
+ declare function upsertMachineMetricsLatest(db: Database, input: {
1718
+ accountId: string;
1719
+ workspaceId: string;
1720
+ enrollmentId: string;
1721
+ sample: MachineMetricsSample;
1722
+ }): Promise<void>;
1723
+ declare function insertMachineMetricsSeries(db: Database, input: {
1724
+ accountId: string;
1725
+ workspaceId: string;
1726
+ enrollmentId: string;
1727
+ sample: MachineMetricsSample;
1728
+ }): Promise<void>;
1729
+ declare const MACHINE_METRICS_SERIES_INTERVAL_MS = 60000;
1730
+ /**
1731
+ * Ingest ONE sampled metrics point for an enrollment (the M10 ingestion seam):
1732
+ * 1. UPSERT machine_metrics_latest (the "now" row, one per enrollment) — always.
1733
+ * 2. APPEND a machine_metrics_series row only when >= ~1/min has elapsed since
1734
+ * the last series row (downsample) — so the 5s heartbeat cadence does not
1735
+ * flood the history table.
1736
+ * Both happen under the same RLS context. Returns whether a series row was
1737
+ * appended (the downsample decision) so the caller / tests can assert the ~1/min
1738
+ * spacing. A null/absent `sampledAt` on the prior row treats it as "no prior" →
1739
+ * append.
1740
+ */
1741
+ declare function ingestMachineMetricsSample(db: Database, input: {
1742
+ accountId: string;
1743
+ workspaceId: string;
1744
+ enrollmentId: string;
1745
+ sample: MachineMetricsSample;
1746
+ /** Override the downsample interval (tests). Defaults to ~1/min. */
1747
+ seriesIntervalMs?: number;
1748
+ }): Promise<{
1749
+ latestUpserted: true;
1750
+ seriesAppended: boolean;
1751
+ }>;
1752
+ type MachineMetricsRow = {
1753
+ enrollmentId: string;
1754
+ cpuPercent: number | null;
1755
+ load1: number | null;
1756
+ load5: number | null;
1757
+ load15: number | null;
1758
+ memUsedBytes: number | null;
1759
+ memTotalBytes: number | null;
1760
+ diskUsedBytes: number | null;
1761
+ diskTotalBytes: number | null;
1762
+ gpuUtilPercent: number | null;
1763
+ gpuMemUsedBytes: number | null;
1764
+ gpuMemTotalBytes: number | null;
1765
+ contention: number | null;
1766
+ sampledAt: string;
1767
+ };
1768
+ declare function readMachineMetricsLatest(db: Database, workspaceId: string, enrollmentId: string): Promise<MachineMetricsRow | null>;
1769
+ declare function readMachineMetricsLatestForWorkspace(db: Database, workspaceId: string): Promise<Map<string, MachineMetricsRow>>;
1770
+ declare function readMachineMetricsSeries(db: Database, input: {
1771
+ workspaceId: string;
1772
+ enrollmentId: string;
1773
+ since: Date;
1774
+ limit?: number;
1775
+ }): Promise<MachineMetricsRow[]>;
1776
+ interface StreamAcknowledgment {
1777
+ acknowledgedUnredacted: boolean;
1778
+ acknowledgedShared: boolean;
1779
+ }
1780
+ declare function recordStreamAcknowledgment(db: Database, input: {
1781
+ accountId: string;
1782
+ workspaceId: string;
1783
+ sandboxGroupId: string;
1784
+ subjectId: string;
1785
+ acknowledgeUnredacted: boolean;
1786
+ acknowledgeShared: boolean;
1787
+ }): Promise<StreamAcknowledgment>;
1788
+ declare function getStreamAcknowledgment(db: Database, input: {
1789
+ workspaceId: string;
1790
+ sandboxGroupId: string;
1791
+ subjectId: string;
1792
+ }): Promise<StreamAcknowledgment | null>;
1793
+ declare function listSessionIdsInGroup(db: Database, workspaceId: string, sandboxGroupId: string): Promise<string[]>;
1794
+ declare function revokeViewer(db: Database, input: {
1795
+ accountId: string;
1796
+ workspaceId: string;
1797
+ sandboxGroupId: string;
1798
+ viewerId: string;
1799
+ idleGraceMs: number;
1800
+ }): Promise<{
1801
+ liveness: SandboxLeaseLiveness;
1802
+ refcount: number;
1803
+ } | null>;
1804
+ interface AccrueWarmSecondsResult {
1805
+ /** false when nothing was accrued (epoch fenced / not warm / no elapsed / the
1806
+ * first tick that only seeds the cursor). */
1807
+ accrued: boolean;
1808
+ /** Whole seconds metered this tick (0 when accrued:false). */
1809
+ seconds: number;
1810
+ /** The monotonic tick index this accrual was recorded under. */
1811
+ tick: number;
1812
+ /** usd_micros charged for this tick (0 when rate is 0). */
1813
+ costMicros: number;
1814
+ }
1815
+ /**
1816
+ * Accrue warm-seconds for the elapsed wall-clock since the lease's last meter
1817
+ * cursor, idempotent on (sandbox_group_id, lease_epoch, tick). EPOCH-FENCED +
1818
+ * liveness-guarded (warm only): a stale-epoch tick or a draining/cold lease is a
1819
+ * no-op, so a superseded writer that re-fires cannot mis-meter. The FIRST tick on
1820
+ * a never-metered lease (last_meter_at IS NULL) only SEEDS the cursor — it
1821
+ * accrues nothing (there is no prior cursor to diff against), matching the
1822
+ * "delta since last tick" contract. warmRateMicrosPerSecond > 0 also records a
1823
+ * sandbox.warm_cost event (cost = seconds x rate) AND debits the same micros from
1824
+ * the credit balance via applyCreditDebitUpToBalance (the model-cost precedent),
1825
+ * idempotent on the SAME (group, epoch, tick) key. The usage event is the
1826
+ * REQUESTED cost; the ledger is the ACTUAL debit (they legitimately differ when
1827
+ * balance is low — M2). Set debitCredits:false to meter without debiting.
1828
+ */
1829
+ declare function accrueWarmSeconds(db: Database, input: {
1830
+ accountId: string;
1831
+ workspaceId: string;
1832
+ sandboxGroupId: string;
1833
+ /** The epoch the tick observed; the fence — a stale writer no-ops. */
1834
+ expectedEpoch: number;
1835
+ /** usd_micros per warm-second for this box's backend (0 = meter only, no cost). */
1836
+ warmRateMicrosPerSecond: number;
1837
+ /** Optional attribution: the founding/observing session (visibility only — the
1838
+ * group meter key makes the workspace charge correct regardless). */
1839
+ subjectId?: string | null;
1840
+ /** Debit credits for warm-cost (default true). The force-drain at 0 balance
1841
+ * depends on this decrementing the balance. */
1842
+ debitCredits?: boolean;
1843
+ }): Promise<AccrueWarmSecondsResult>;
1844
+ interface ForceDrainResult {
1845
+ /** Whether the workspace was over a limit (0 balance or over the warm cap). */
1846
+ overLimit: boolean;
1847
+ /** The reason, for observability. */
1848
+ reason: "balance" | "warm_cap" | null;
1849
+ /** The (workspaceId, sandboxGroupId) viewer-only boxes CASed warm->draining. */
1850
+ drained: {
1851
+ workspaceId: string;
1852
+ sandboxGroupId: string;
1853
+ }[];
1854
+ }
1855
+ declare function forceDrainOverLimitViewerOnlyBoxes(db: Database, input: {
1856
+ workspaceId: string;
1857
+ /** account balance gate: when <= 0 (and a billing/managed mode is on) drain. */
1858
+ balanceMicros: number;
1859
+ enforceBalance: boolean;
1860
+ /** warm-second cap (cumulative this UTC month). 0 = unbounded (no cap gate). */
1861
+ maxWarmSecondsPerWorkspace: number;
1862
+ /** start of the cap window (caller passes startOfUtcMonth() so the fn stays
1863
+ * time-source-agnostic for tests). */
1864
+ capWindowStart?: Date;
1865
+ /** drain-grace horizon stamped on the newly-draining rows (matches the reaper). */
1866
+ idleGraceMs: number;
1867
+ }): Promise<ForceDrainResult>;
1868
+ declare function saveRunState(db: Database, input: {
1869
+ accountId: string;
1870
+ workspaceId: string;
1871
+ sessionId: string;
1872
+ turnId?: string | null;
1873
+ serializedRunState: string;
1874
+ pendingApprovals: unknown[];
1875
+ frozenCodexCredentialId?: string | null;
1876
+ }): Promise<void>;
1877
+ type CreateSessionGoalInput = {
1878
+ accountId: string;
1879
+ workspaceId: string;
1880
+ sessionId: string;
1881
+ text: string;
1882
+ successCriteria?: string | null;
1883
+ maxAutoContinuations?: number | null;
1884
+ createdBy: SessionGoalCreatedBy;
1885
+ };
1886
+ declare function createSessionGoal(db: Database, input: CreateSessionGoalInput): Promise<SessionGoal>;
1887
+ declare function getSessionGoal(db: Database, workspaceId: string, sessionId: string): Promise<SessionGoal | null>;
1888
+ /**
1889
+ * goal_set semantics: insert, or replace the existing goal in place. A replace
1890
+ * re-activates the goal (even when paused or completed), bumps the version,
1891
+ * and resets the continuation counters — re-stating the objective re-arms the
1892
+ * auto-continuation budget.
1893
+ */
1894
+ declare function upsertSessionGoal(db: Database, input: CreateSessionGoalInput): Promise<{
1895
+ goal: SessionGoal;
1896
+ replaced: boolean;
1897
+ }>;
1898
+ /**
1899
+ * goal_update semantics: revise text/criteria without changing status. The
1900
+ * version bump counts as progress for the no-progress detector.
1901
+ */
1902
+ declare function updateSessionGoal(db: Database, workspaceId: string, sessionId: string, input: {
1903
+ text?: string;
1904
+ successCriteria?: string | null;
1905
+ }): Promise<SessionGoal>;
1906
+ /**
1907
+ * Sets a session's display title. The clobber guard lives entirely in this
1908
+ * single atomic UPDATE: a user-set title is permanent, so agent/auto writes
1909
+ * carry an `AND title_source IS DISTINCT FROM 'user'` guard (NULL-safe in
1910
+ * Postgres) while user writes are unconditional. Never read-modify-write.
1911
+ * Returns `{ updated, title }`: `updated` is false when an agent write was
1912
+ * skipped because a user title already pinned the session, true otherwise;
1913
+ * `title` is the resulting title (null when skipped).
1914
+ */
1915
+ declare function updateSessionTitle(db: Database, input: {
1916
+ workspaceId: string;
1917
+ sessionId: string;
1918
+ title: string;
1919
+ source: "user" | "agent";
1920
+ }): Promise<{
1921
+ updated: boolean;
1922
+ title: string | null;
1923
+ }>;
1924
+ /**
1925
+ * Status transition helper. Idempotent: requesting the current status returns
1926
+ * `changed: false` so callers can skip emitting a duplicate event. `completed`
1927
+ * is terminal for transitions; only `upsertSessionGoal` can replace a
1928
+ * completed goal. Resuming to `active` clears the pause fields and resets the
1929
+ * continuation counters.
1930
+ */
1931
+ declare function setSessionGoalStatus(db: Database, workspaceId: string, sessionId: string, input: {
1932
+ status: SessionGoalStatus;
1933
+ evidence?: string;
1934
+ rationale?: string;
1935
+ pausedReason?: string;
1936
+ }): Promise<{
1937
+ goal: SessionGoal;
1938
+ changed: boolean;
1939
+ }>;
1940
+ declare function setSessionGoalLastContinuationTurn(db: Database, workspaceId: string, sessionId: string, turnId: string): Promise<void>;
1941
+ type GoalContinuationDecision = {
1942
+ decision: "none";
1943
+ } | {
1944
+ decision: "queue";
1945
+ } | {
1946
+ decision: "paused";
1947
+ reason: "no_progress" | "max_auto_continuations" | "limits";
1948
+ goal: SessionGoal;
1949
+ } | {
1950
+ decision: "continue";
1951
+ goal: SessionGoal;
1952
+ autoContinuation: number;
1953
+ cap: number | null;
1954
+ };
1955
+ /**
1956
+ * Core continuation decision, taken in one transaction with the goal row
1957
+ * locked. Queued work always wins; any non-terminal turn (queued, running, or
1958
+ * requires_action awaiting a human approval) blocks auto-continuation. The
1959
+ * no-progress and max-continuation guards mutate counters here only, so a
1960
+ * replaying workflow re-reads recorded activity results and never recomputes
1961
+ * them.
1962
+ */
1963
+ declare function evaluateGoalContinuation(db: Database, input: {
1964
+ workspaceId: string;
1965
+ sessionId: string;
1966
+ defaultMaxAutoContinuations?: number | null;
1967
+ noProgressLimit: number;
1968
+ budgetBlocked?: string | null;
1969
+ }): Promise<GoalContinuationDecision>;
1970
+ declare function createTurn(db: Database, input: {
1971
+ workspaceId: string;
1972
+ sessionId: string;
1973
+ triggerEventId: string;
1974
+ temporalWorkflowId: string;
1975
+ }): Promise<string>;
1976
+ declare function enqueueSessionTurn(db: Database, input: EnqueueSessionTurnInput): Promise<SessionTurn>;
1977
+ declare function claimNextQueuedTurn(db: Database, workspaceId: string, sessionId: string, workflowId: string): Promise<SessionTurn | null>;
1978
+ declare function setSessionStatus(db: Database, workspaceId: string, sessionId: string, status: SessionStatus, activeTurnId?: string | null): Promise<void>;
1979
+ type WakeParentForChildCompletionInput = {
1980
+ workspaceId: string;
1981
+ parentSessionId: string;
1982
+ clientEventId: string;
1983
+ text: string;
1984
+ childCompletion: Record<string, unknown>;
1985
+ reasoningEffortFallback: ReasoningEffort;
1986
+ };
1987
+ type WakeParentForChildCompletionResult = {
1988
+ delivered: false;
1989
+ reason: "already_delivered" | "parent_cancelled";
1990
+ } | {
1991
+ delivered: true;
1992
+ turn: SessionTurn;
1993
+ triggerEvent: SessionEvent;
1994
+ events: SessionEvent[];
1995
+ temporalWorkflowId: string;
1996
+ };
1997
+ /**
1998
+ * Deliver a one-shot completion wake from a spawned worker into its parent
1999
+ * (manager) session: append a system-authored `user.message`, transition the
2000
+ * parent idle/failed -> queued (a queued/running parent already has a turn in
2001
+ * flight and keeps it), and enqueue the resulting turn. The whole thing runs
2002
+ * under the parent's row lock in one transaction, and is idempotent on
2003
+ * `clientEventId`: a duplicate call for the same terminal episode (activity
2004
+ * retry, the workflow's idle re-check) is a no-op that enqueues no second
2005
+ * turn. The caller publishes the returned events and signals the parent's
2006
+ * Temporal workflow (signalWithStart) only when `delivered` is true.
2007
+ *
2008
+ * Mirrors `acceptSessionUserMessage`/`postUserMessageTurn` in the API domain:
2009
+ * cancelled is the one parent state that refuses the wake (an explicit stop);
2010
+ * failed stays revivable, matching the revivable-failed-sessions contract.
2011
+ */
2012
+ declare function wakeParentSessionForChildCompletion(db: Database, input: WakeParentForChildCompletionInput): Promise<WakeParentForChildCompletionResult>;
2013
+ declare function setTemporalWorkflowId(db: Database, workspaceId: string, sessionId: string, workflowId: string): Promise<void>;
2014
+ declare function finishTurn(db: Database, workspaceId: string, turnId: string, status: SessionStatus | SessionTurnStatus): Promise<void>;
2015
+ /**
2016
+ * Put a preempted (worker shutdown mid-flight) turn back on the session
2017
+ * queue so the workflow's next claim re-dispatches it on a healthy worker.
2018
+ * The trigger event is swapped when the resumed attempt should enter
2019
+ * through a synthesized resume notice instead of replaying the original
2020
+ * trigger (the original input is already part of persisted conversation
2021
+ * truth by then). Keeping the original position lets the resumed turn run
2022
+ * before any turns queued behind it. Accepts `running` turns and
2023
+ * `requires_action` turns: an approval rerun re-dispatches the same turn
2024
+ * without a fresh claim, so the row still carries the approval-wait status
2025
+ * while the rerun activity executes.
2026
+ */
2027
+ declare function requeuePreemptedTurn(db: Database, workspaceId: string, turnId: string, triggerEventId: string): Promise<void>;
2028
+ /**
2029
+ * Bump the per-turn worker-death redispatch counter and return the new value.
2030
+ * Stored in the turn row's metadata (not workflow-local state) so the
2031
+ * crash-loop guard is replay-safe: the count survives workflow replay, worker
2032
+ * restarts, and even a session-workflow re-run, and the increment is a single
2033
+ * atomic statement.
2034
+ */
2035
+ declare function incrementTurnWorkerDeathRedispatches(db: Database, workspaceId: string, turnId: string): Promise<number>;
2036
+ declare function getSessionTurn(db: Database, workspaceId: string, turnId: string): Promise<SessionTurn | null>;
2037
+ declare function listSessionTurns(db: Database, workspaceId: string, sessionId: string, limit?: number): Promise<SessionTurn[]>;
2038
+ declare function updateQueuedSessionTurn(db: Database, workspaceId: string, turnId: string, input: UpdateQueuedSessionTurnInput): Promise<SessionTurn>;
2039
+ declare function cancelQueuedSessionTurn(db: Database, workspaceId: string, turnId: string): Promise<SessionTurn>;
2040
+ declare function reorderQueuedSessionTurns(db: Database, workspaceId: string, sessionId: string, turnIds: string[]): Promise<SessionTurn[]>;
2041
+ declare function appendSessionEvents(db: Database, workspaceId: string, sessionId: string, inputs: AppendEventInput[]): Promise<SessionEvent[]>;
2042
+ declare function appendSessionEventsAndUpdateSession(db: Database, workspaceId: string, sessionId: string, inputs: AppendEventInput[], update: {
2043
+ resources?: ResourceRef[];
2044
+ tools?: ToolRef[];
2045
+ model?: string;
2046
+ metadata?: Record<string, unknown>;
2047
+ status?: SessionStatus;
2048
+ activeTurnId?: string | null;
2049
+ }): Promise<SessionEvent[]>;
2050
+ declare function appendSessionEventsWithLockedSessionUpdate(db: Database, workspaceId: string, sessionId: string, build: (session: Session) => {
2051
+ events: AppendEventInput[];
2052
+ update?: {
2053
+ resources?: ResourceRef[];
2054
+ tools?: ToolRef[];
2055
+ model?: string;
2056
+ metadata?: Record<string, unknown>;
2057
+ status?: SessionStatus;
2058
+ activeTurnId?: string | null;
2059
+ };
2060
+ }): Promise<SessionEvent[]>;
2061
+ declare function sessionSubject(workspaceId: string, sessionId: string): string;
2062
+
2063
+ export { type SessionCodexState as $, type AccrueWarmSecondsResult as A, type BootstrapWorkspaceInput as B, CLEARED_RUN_STATE as C, type Database as D, type EnableCapabilityInstallationInput as E, type EnrollmentOs as F, type EnrollmentRecord as G, type EnrollmentStatus as H, type ForceDrainResult as I, type GitHubInstallation as J, type GoalContinuationDecision as K, type LeaseHolderKind as L, type LeaseSnapshot as M, MACHINE_METRICS_SERIES_INTERVAL_MS as N, type MachineMetricsRow as O, type MachineMetricsSample as P, type ProvisionResult, type ProvisionRolesOptions, type MeterableWarmLease as Q, type ReapDrainable as R, type RegisterWorkspacePackInput as S, type RlsContext as T, type RlsStrategy as U, SandboxImageConflictError as V, type SandboxKind as W, type SandboxLeaseLiveness as X, SandboxLeaseSupersededError as Y, type SandboxPtySessionRow as Z, type SandboxRecord as _, type AcquireLeaseInput as a, decryptedCapabilityHeaders as a$, type SessionRecordingCodec as a0, type SessionRecordingMode as a1, type SessionRecordingRow as a2, type SessionRecordingState as a3, type StreamAcknowledgment as a4, type UpdateQueuedSessionTurnInput as a5, type UpdateScheduledTaskInput as a6, type UserLookup as a7, type WakeParentForChildCompletionInput as a8, type WakeParentForChildCompletionResult as a9, countActiveSessionHistoryItems as aA, countActiveSessionsForWorkspace as aB, countActiveSessionsUsingEnvironment as aC, countConsecutiveReactiveRotations as aD, countScheduledTasksForWorkspace as aE, countScheduledTasksUsingEnvironment as aF, countSessionHistoryItems as aG, countTurnSessionHistoryItems as aH, countWorkspaceEnvironments as aI, countWorkspacesForAccount as aJ, createApiKey as aK, createDb as aL, createDeviceEnrollmentRequest as aM, createEnrollment as aN, createFileUpload as aO, createSandbox as aP, createScheduledTask as aQ, createScheduledTaskRun as aR, createSession as aS, createSessionGoal as aT, createSessionWithIdempotencyKey as aU, createSocialConnection as aV, createSocialPost as aW, createTurn as aX, createWorkspace as aY, createWorkspaceEnvironment as aZ, decryptEnvironmentValue as a_, type WorkspaceEnvironmentForRun as aa, accrueWarmSeconds as ab, acquireLease as ac, allAccountPermissions as ad, allWorkspacePermissions as ae, appendSessionEvents as af, appendSessionEventsAndUpdateSession as ag, appendSessionEventsWithLockedSessionUpdate as ah, appendSessionHistoryItems as ai, applyContextCompaction as aj, applyCreditDebitUpToBalance as ak, applyCreditLedgerEntry as al, approveDeviceEnrollmentRequest as am, bootstrapWorkspace as an, buildCodexTokenResolver as ao, cancelQueuedSessionTurn as ap, claimNextQueuedTurn as aq, clearSessionContext as ar, clearedContextMarkerItem as as, closePtySession as at, commitWarmingToWarm as au, completeFileUpload as av, confirmDrainCold as aw, consumeDeviceEnrollmentRequest as ax, consumeSessionCompactionRequest as ay, countActiveApiKeysForWorkspace as az, type AcquireLeaseResult as b, hasCreditLedgerEntry as b$, deleteRecording as b0, deleteScheduledTask as b1, deleteWorkspace as b2, deleteWorkspaceEnvironment as b3, deleteWorkspaceEnvironmentVariable as b4, deleteWorkspacePack as b5, denyDeviceEnrollmentRequest as b6, disableCapabilityInstallation as b7, disconnectAllCodexAccounts as b8, disconnectCodexAccount as b9, getManagedAccount as bA, getManagedUserByEmail as bB, getOpenPtySession as bC, getPackInstallation as bD, getPendingDeviceEnrollmentRequestByUserCode as bE, getPendingDeviceEnrollmentRequestByUserCodeGlobal as bF, getRecording as bG, getSandbox as bH, getSandboxSessionEnvelope as bI, getScheduledTask as bJ, getSession as bK, getSessionByCreateIdempotencyKey as bL, getSessionCodexState as bM, getSessionEvent as bN, getSessionGoal as bO, getSessionHistoryItems as bP, getSessionTurn as bQ, getSocialConnection as bR, getStoredCapabilityHeaderCiphertext as bS, getStreamAcknowledgment as bT, getWorkspace as bU, getWorkspaceEnvironment as bV, getWorkspaceEnvironmentByName as bW, getWorkspaceEnvironmentValuesForRun as bX, getWorkspaceGrant as bY, getWorkspacePack as bZ, grantWorkspaceAccess as b_, enableCapabilityInstallation as ba, enablePackInstallation as bb, encryptEnvironmentValue as bc, enqueueSessionTurn as bd, ensureCodexRotationSettings as be, ensureManagedAccessForUser as bf, evaluateGoalContinuation as bg, failWarmingToCold as bh, fetchCodexUsageForAccount as bi, finalizeEnrollmentByToken as bj, findActiveApiKeyByHash as bk, finishTurn as bl, forceDrainOverLimitViewerOnlyBoxes as bm, getActiveSessionHistoryItems as bn, getAnySessionInGroup as bo, getBillingBalance as bp, getBillingCustomer as bq, getCapabilityCatalogItem as br, getCapabilityInstallation as bs, getCodexCredentialStatus as bt, getCodexRotationSettings as bu, getDeviceEnrollmentRequestByDeviceCode as bv, getEnrollment as bw, getFile as bx, getFileUpload as by, getLatestRunState as bz, type ActiveSandboxPointer as c, releaseLeaseHolder as c$, heartbeatLeaseHolder as c0, incrementTurnWorkerDeathRedispatches as c1, ingestMachineMetricsSample as c2, insertMachineMetricsSeries as c3, insertPtySession as c4, insertRecording as c5, isCodexBilledTurn as c6, isStripeWebhookProcessed as c7, listApiKeys as c8, listCapabilityCatalogItems as c9, loadWorkspaceEnvironmentForRun as cA, markFileUploadFailed as cB, markStripeWebhookProcessed as cC, mcpServerIdForCapability as cD, nextSessionHistoryPosition as cE, orphanedResultRowIndicesForRepair as cF, persistDrainSnapshot as cG, reArmDrainingLease as cH, readActiveSandbox as cI, readLease as cJ, readMachineMetricsLatest as cK, readMachineMetricsLatestForWorkspace as cL, readMachineMetricsSeries as cM, reapStaleLeaseHolders as cN, reapStaleLeaseHoldersGlobal as cO, recordAuditEvent as cP, recordCodexAccountConnectors as cQ, recordCodexAccountUsage as cR, recordCodexTokenRefresh as cS, recordLeaseDataPlaneUrl as cT, recordLeaseTerminalDataPlaneUrl as cU, recordSessionActiveCodexCredential as cV, recordStreamAcknowledgment as cW, recordStripeWebhookEvent as cX, recordUsageEvent as cY, registerDbBinding as cZ, registerWorkspacePack as c_, listCapabilityInstallations as ca, listCodexAccountStatuses as cb, listDistinctEnvironmentIdsInGroup as cc, listEnabledMcpCapabilityServers as cd, listEnrollments as ce, listGitHubInstallationIdsForWorkspace as cf, listGitHubInstallationsForWorkspace as cg, listMeterableWarmLeases as ch, listOpenPtySessions as ci, listPackInstallations as cj, listRecordings as ck, listSandboxes as cl, listScheduledTaskRuns as cm, listScheduledTasks as cn, listSessionEvents as co, listSessionIdsInGroup as cp, listSessionTurns as cq, listSessions as cr, listSocialConnections as cs, listSocialPosts as ct, listUsageEvents as cu, listWorkspaceEnvironments as cv, listWorkspaceMembers as cw, listWorkspacePacks as cx, listWorkspacesForSubject as cy, loadCodexCredentialForRun as cz, type AppendEventInput as d, removeWorkspaceMember as d0, renameCodexAccount as d1, reorderQueuedSessionTurns as d2, requestSessionCompaction as d3, requeuePreemptedTurn as d4, requireFile as d5, requireScheduledTask as d6, requireSession as d7, requireSocialConnection as d8, requireWorkspace as d9, updatePackInstallationStatus as dA, updatePtySessionActivity as dB, updateQueuedSessionTurn as dC, updateRecording as dD, updateScheduledTask as dE, updateScheduledTaskRun as dF, updateSessionGoal as dG, updateSessionTitle as dH, updateWorkspace as dI, updateWorkspaceEnvironment as dJ, upsertBillingCustomer as dK, upsertCapabilityCatalogItem as dL, upsertCodexSubscriptionCredential as dM, upsertGitHubInstallation as dN, upsertMachineMetricsLatest as dO, upsertSandboxSessionEnvelope as dP, upsertSessionGoal as dQ, wakeParentSessionForChildCompletion as dR, withAccountRls as dS, withRlsContext as dT, withWorkspaceRls as dU, withWorkspaceUsageLock as dV, workspaceCodexSubscriptionActive as dW, revokeApiKey as da, revokeEnrollment as db, revokeViewer as dc, rlsContextForWorkspace as dd, rlsStrategyFor as de, sanitizeEventPayload as df, sanitizeEventString as dg, saveRunState as dh, sessionSubject as di, setActiveCodexCredential as dj, setActiveSandbox as dk, setCodexCredentialExhausted as dl, setCodexCredentialStatus as dm, setEnrollmentHasDisplay as dn, setRlsContext as dp, setSessionCodexPin as dq, setSessionGoalLastContinuationTurn as dr, setSessionGoalStatus as ds, setSessionLastInputTokens as dt, setSessionStatus as du, setTemporalWorkflowId as dv, setWorkspaceEnvironmentVariable as dw, sumUsageQuantity as dx, touchEnrollmentLastSeen as dy, updateCodexRotationSettings as dz, CODEX_ROTATION_STRATEGIES as e, type ClearSessionContextResult as f, type CodexAccountStatus as g, type CodexAccountUsageSnapshot as h, type CodexAuthDeps as i, type CodexCredentialForRun as j, type CodexCredentialTokens as k, type CodexRotationSettings as l, type CodexRotationStrategy as m, type CreateCapabilityCatalogItemInput as n, type CreateDbOptions as o, type CreatePackInstallationInput as p, provisionRoles, type CreateScheduledTaskInput as q, type CreateSessionGoalInput as r, type CreateSocialConnectionInput as s, type CreateSocialPostInput as t, type DbClient as u, type DeviceEnrollmentRequestRecord as v, type DeviceEnrollmentStatus as w, type EnabledMcpCapabilityServer as x, type EnqueueSessionTurnInput as y, type EnrollmentExposure as z };