remote-codex 0.11.30 → 0.11.32

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 (37) hide show
  1. package/README.md +12 -4
  2. package/apps/relay-server/dist/index.js +2956 -164
  3. package/apps/supervisor-api/dist/index.js +521 -64
  4. package/apps/supervisor-web/dist/apple-touch-icon.png +0 -0
  5. package/apps/supervisor-web/dist/assets/index-CGHHTNkM.js +21 -0
  6. package/apps/supervisor-web/dist/assets/index-CdjTdnJt.css +1 -0
  7. package/apps/supervisor-web/dist/assets/thread-ui-B9eC2H4u.js +3677 -0
  8. package/apps/supervisor-web/dist/favicon-16x16.png +0 -0
  9. package/apps/supervisor-web/dist/favicon-32x32.png +0 -0
  10. package/apps/supervisor-web/dist/favicon-48x48.png +0 -0
  11. package/apps/supervisor-web/dist/icon-192.png +0 -0
  12. package/apps/supervisor-web/dist/icon-512.png +0 -0
  13. package/apps/supervisor-web/dist/index.html +10 -4
  14. package/apps/supervisor-web/dist/remote-codex-icon.png +0 -0
  15. package/apps/supervisor-web/dist/site.webmanifest +19 -0
  16. package/bin/remote-codex.mjs +6 -3
  17. package/config/codex-model-pricing.json +44 -0
  18. package/package.json +1 -1
  19. package/packages/agent-runtime/src/model-pricing.ts +66 -6
  20. package/packages/agent-runtime/src/types.ts +13 -0
  21. package/packages/claude/src/runtimeAdapter.test.ts +64 -0
  22. package/packages/claude/src/runtimeAdapter.ts +64 -0
  23. package/packages/codex/src/appServerManager.ts +16 -0
  24. package/packages/codex/src/modelPricing.test.ts +84 -0
  25. package/packages/codex/src/runtimeAdapter.test.ts +44 -0
  26. package/packages/codex/src/runtimeAdapter.ts +66 -0
  27. package/packages/codex/src/types.ts +3 -1
  28. package/packages/db/migrations/0029_thread_turn_delivery.sql +19 -0
  29. package/packages/db/src/repositories.ts +96 -1
  30. package/packages/db/src/schema.ts +20 -0
  31. package/packages/opencode/src/runtimeAdapter.ts +15 -0
  32. package/packages/shared/src/index.ts +203 -7
  33. package/scripts/run-web-service.mjs +2 -2
  34. package/scripts/service-manager.mjs +2 -2
  35. package/apps/supervisor-web/dist/assets/index-BnpZn_3_.js +0 -6
  36. package/apps/supervisor-web/dist/assets/index-CJFMmjP5.css +0 -1
  37. package/apps/supervisor-web/dist/assets/thread-ui-C0VPL4Uk.js +0 -3677
@@ -484,6 +484,20 @@ function mapCodexNotification(event: CodexServerEvent): AgentRuntimeEvent | null
484
484
  }
485
485
  }
486
486
 
487
+ function formatRateLimitWindowLabel(
488
+ durationMinutes: number | null,
489
+ fallback: string,
490
+ ) {
491
+ if (durationMinutes === null) return fallback;
492
+ if (durationMinutes % (60 * 24) === 0) {
493
+ return `${durationMinutes / (60 * 24)}d`;
494
+ }
495
+ if (durationMinutes % 60 === 0) {
496
+ return `${durationMinutes / 60}h`;
497
+ }
498
+ return `${durationMinutes}m`;
499
+ }
500
+
487
501
  function mapCodexRuntimeError(error: unknown): never {
488
502
  if (error instanceof AgentRuntimeError) {
489
503
  throw error;
@@ -617,6 +631,58 @@ export class CodexRuntimeAdapter extends EventEmitter implements AgentRuntime {
617
631
  return mapStatus(this.manager.getStatus());
618
632
  }
619
633
 
634
+ async getSubscriptionUsage() {
635
+ const account = await codexRuntimeCall(() => this.manager.readAccount());
636
+ if (account.account?.type === 'apiKey') {
637
+ return {
638
+ provider: 'codex' as const,
639
+ authKind: 'apiKey' as const,
640
+ observedAt: new Date().toISOString(),
641
+ stale: false,
642
+ windows: [],
643
+ };
644
+ }
645
+ if (account.account?.type !== 'chatgpt') {
646
+ return null;
647
+ }
648
+ const response = await codexRuntimeCall(() =>
649
+ this.manager.readAccountRateLimits(),
650
+ );
651
+ const buckets = response.rateLimitsByLimitId;
652
+ const snapshot =
653
+ (buckets && (buckets.codex ?? Object.values(buckets)[0])) ??
654
+ response.rateLimits;
655
+ const record = snapshot && typeof snapshot === 'object'
656
+ ? (snapshot as Record<string, unknown>)
657
+ : {};
658
+ const windows = ['primary', 'secondary'].flatMap((id) => {
659
+ const value = record[id];
660
+ if (!value || typeof value !== 'object') return [];
661
+ const window = value as Record<string, unknown>;
662
+ const usedPercent = Number(window.usedPercent);
663
+ if (!Number.isFinite(usedPercent)) return [];
664
+ const duration = Number(window.windowDurationMins);
665
+ const durationMinutes = Number.isFinite(duration) ? duration : null;
666
+ const resetsAt = Number(window.resetsAt);
667
+ return [{
668
+ id,
669
+ durationMinutes,
670
+ label: formatRateLimitWindowLabel(durationMinutes, id),
671
+ usedPercent: Math.max(0, Math.min(100, usedPercent)),
672
+ resetsAt: Number.isFinite(resetsAt)
673
+ ? new Date(resetsAt * 1000).toISOString()
674
+ : null,
675
+ }];
676
+ });
677
+ return {
678
+ provider: 'codex' as const,
679
+ authKind: 'subscription' as const,
680
+ observedAt: new Date().toISOString(),
681
+ stale: false,
682
+ windows,
683
+ };
684
+ }
685
+
620
686
  start() {
621
687
  return codexRuntimeCall(() => this.manager.start());
622
688
  }
@@ -63,7 +63,9 @@ export type ReasoningEffort =
63
63
  | 'low'
64
64
  | 'medium'
65
65
  | 'high'
66
- | 'xhigh';
66
+ | 'xhigh'
67
+ | 'max'
68
+ | 'ultra';
67
69
 
68
70
  export type CollaborationModeKind = 'default' | 'plan';
69
71
  export type SandboxMode = 'read-only' | 'workspace-write' | 'danger-full-access';
@@ -0,0 +1,19 @@
1
+ ALTER TABLE threads ADD COLUMN active_turn_collaboration_mode TEXT;
2
+
3
+ ALTER TABLE thread_pending_steers
4
+ ADD COLUMN delivery TEXT NOT NULL DEFAULT 'steer';
5
+
6
+ ALTER TABLE thread_pending_steers
7
+ ADD COLUMN turn_config_json TEXT;
8
+
9
+ CREATE TABLE IF NOT EXISTS thread_prompt_requests (
10
+ id TEXT PRIMARY KEY,
11
+ thread_id TEXT NOT NULL,
12
+ client_request_id TEXT NOT NULL,
13
+ status TEXT NOT NULL,
14
+ created_at TEXT NOT NULL,
15
+ updated_at TEXT NOT NULL
16
+ );
17
+
18
+ CREATE UNIQUE INDEX IF NOT EXISTS thread_prompt_requests_thread_client_request_idx
19
+ ON thread_prompt_requests(thread_id, client_request_id);
@@ -1,6 +1,6 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
 
3
- import { and, desc, eq, inArray } from 'drizzle-orm';
3
+ import { and, desc, eq, inArray, lt } from 'drizzle-orm';
4
4
 
5
5
  import { DatabaseClient } from './client';
6
6
  import { getDefaultHostRecord } from './client';
@@ -12,6 +12,7 @@ import {
12
12
  threadGoals,
13
13
  threadHistoryItems,
14
14
  threadPendingSteers,
15
+ threadPromptRequests,
15
16
  threadTurnMetadata,
16
17
  threads,
17
18
  viewerSessions,
@@ -36,6 +37,7 @@ export interface CreateThreadRecordInput {
36
37
  fastBaseModel?: string | null;
37
38
  fastBaseReasoningEffort?: string | null;
38
39
  collaborationMode?: string;
40
+ activeTurnCollaborationMode?: string | null;
39
41
  approvalMode: string;
40
42
  sandboxMode?: string | null;
41
43
  summaryText?: string | null;
@@ -54,6 +56,7 @@ export interface UpdateThreadRecordInput {
54
56
  fastBaseModel?: string | null;
55
57
  fastBaseReasoningEffort?: string | null;
56
58
  collaborationMode?: string;
59
+ activeTurnCollaborationMode?: string | null;
57
60
  approvalMode?: string;
58
61
  sandboxMode?: string | null;
59
62
  status?: string;
@@ -83,6 +86,8 @@ export interface CreateThreadPendingSteerRecordInput {
83
86
  clientRequestId?: string | null;
84
87
  displayPrompt: string;
85
88
  submittedPrompt: string;
89
+ delivery?: 'steer' | 'continuation';
90
+ turnConfigJson?: string | null;
86
91
  }
87
92
 
88
93
  export interface UpsertThreadHistoryItemRecordInput {
@@ -283,6 +288,7 @@ export function createThreadRecord(db: DatabaseClient, input: CreateThreadRecord
283
288
  fastBaseModel: input.fastBaseModel ?? null,
284
289
  fastBaseReasoningEffort: input.fastBaseReasoningEffort ?? null,
285
290
  collaborationMode: input.collaborationMode ?? 'default',
291
+ activeTurnCollaborationMode: input.activeTurnCollaborationMode ?? null,
286
292
  approvalMode: input.approvalMode,
287
293
  sandboxMode: input.sandboxMode ?? null,
288
294
  status: 'idle',
@@ -538,6 +544,8 @@ export function createThreadPendingSteerRecord(
538
544
  clientRequestId: input.clientRequestId ?? null,
539
545
  displayPrompt: input.displayPrompt,
540
546
  submittedPrompt: input.submittedPrompt,
547
+ delivery: input.delivery ?? 'steer',
548
+ turnConfigJson: input.turnConfigJson ?? null,
541
549
  createdAt: now,
542
550
  updatedAt: now,
543
551
  };
@@ -557,6 +565,93 @@ export function deleteThreadPendingSteerRecordsByThreadId(
557
565
  db.delete(threadPendingSteers).where(eq(threadPendingSteers.threadId, threadId)).run();
558
566
  }
559
567
 
568
+ export function getThreadPromptRequestRecord(
569
+ db: DatabaseClient,
570
+ threadId: string,
571
+ clientRequestId: string,
572
+ ) {
573
+ return db
574
+ .select()
575
+ .from(threadPromptRequests)
576
+ .where(
577
+ and(
578
+ eq(threadPromptRequests.threadId, threadId),
579
+ eq(threadPromptRequests.clientRequestId, clientRequestId),
580
+ ),
581
+ )
582
+ .get();
583
+ }
584
+
585
+ export function createThreadPromptRequestRecord(
586
+ db: DatabaseClient,
587
+ threadId: string,
588
+ clientRequestId: string,
589
+ ) {
590
+ const now = new Date().toISOString();
591
+ db.insert(threadPromptRequests)
592
+ .values({
593
+ id: randomUUID(),
594
+ threadId,
595
+ clientRequestId,
596
+ status: 'processing',
597
+ createdAt: now,
598
+ updatedAt: now,
599
+ })
600
+ .onConflictDoNothing()
601
+ .run();
602
+ return getThreadPromptRequestRecord(db, threadId, clientRequestId)!;
603
+ }
604
+
605
+ export function markThreadPromptRequestAccepted(
606
+ db: DatabaseClient,
607
+ threadId: string,
608
+ clientRequestId: string,
609
+ ) {
610
+ db.update(threadPromptRequests)
611
+ .set({ status: 'accepted', updatedAt: new Date().toISOString() })
612
+ .where(
613
+ and(
614
+ eq(threadPromptRequests.threadId, threadId),
615
+ eq(threadPromptRequests.clientRequestId, clientRequestId),
616
+ ),
617
+ )
618
+ .run();
619
+ }
620
+
621
+ export function deleteExpiredThreadPromptRequestRecords(
622
+ db: DatabaseClient,
623
+ cutoff: string,
624
+ ) {
625
+ return db
626
+ .delete(threadPromptRequests)
627
+ .where(lt(threadPromptRequests.updatedAt, cutoff))
628
+ .run();
629
+ }
630
+
631
+ export function deleteThreadPromptRequestRecord(
632
+ db: DatabaseClient,
633
+ threadId: string,
634
+ clientRequestId: string,
635
+ ) {
636
+ db.delete(threadPromptRequests)
637
+ .where(
638
+ and(
639
+ eq(threadPromptRequests.threadId, threadId),
640
+ eq(threadPromptRequests.clientRequestId, clientRequestId),
641
+ ),
642
+ )
643
+ .run();
644
+ }
645
+
646
+ export function deleteThreadPromptRequestRecordsByThreadId(
647
+ db: DatabaseClient,
648
+ threadId: string,
649
+ ) {
650
+ db.delete(threadPromptRequests)
651
+ .where(eq(threadPromptRequests.threadId, threadId))
652
+ .run();
653
+ }
654
+
560
655
  export function listThreadActivityNotesByThreadId(
561
656
  db: DatabaseClient,
562
657
  threadId: string,
@@ -33,6 +33,7 @@ export const threads = sqliteTable('threads', {
33
33
  fastBaseModel: text('fast_base_model'),
34
34
  fastBaseReasoningEffort: text('fast_base_reasoning_effort'),
35
35
  collaborationMode: text('collaboration_mode').notNull().default('default'),
36
+ activeTurnCollaborationMode: text('active_turn_collaboration_mode'),
36
37
  approvalMode: text('approval_mode'),
37
38
  sandboxMode: text('sandbox_mode'),
38
39
  status: text('status'),
@@ -113,10 +114,29 @@ export const threadPendingSteers = sqliteTable('thread_pending_steers', {
113
114
  clientRequestId: text('client_request_id'),
114
115
  displayPrompt: text('display_prompt').notNull(),
115
116
  submittedPrompt: text('submitted_prompt').notNull(),
117
+ delivery: text('delivery').notNull().default('steer'),
118
+ turnConfigJson: text('turn_config_json'),
116
119
  createdAt: text('created_at').notNull(),
117
120
  updatedAt: text('updated_at').notNull(),
118
121
  });
119
122
 
123
+ export const threadPromptRequests = sqliteTable(
124
+ 'thread_prompt_requests',
125
+ {
126
+ id: text('id').primaryKey(),
127
+ threadId: text('thread_id').notNull(),
128
+ clientRequestId: text('client_request_id').notNull(),
129
+ status: text('status').notNull(),
130
+ createdAt: text('created_at').notNull(),
131
+ updatedAt: text('updated_at').notNull(),
132
+ },
133
+ (table) => ({
134
+ threadClientRequestUnique: uniqueIndex(
135
+ 'thread_prompt_requests_thread_client_request_idx',
136
+ ).on(table.threadId, table.clientRequestId),
137
+ }),
138
+ );
139
+
120
140
  export const threadHistoryItems = sqliteTable(
121
141
  'thread_history_items',
122
142
  {
@@ -439,6 +439,13 @@ function openCodeUsageFromTokens(tokens: unknown) {
439
439
  const cachedInputTokens = nonNegativeNumberValue(
440
440
  tokens.cachedInputTokens ?? tokens.cached_input_tokens ?? cache?.read,
441
441
  ) ?? 0;
442
+ const cacheWriteInputTokens = nonNegativeNumberValue(
443
+ tokens.cacheWriteInputTokens ??
444
+ tokens.cache_write_input_tokens ??
445
+ tokens.cacheWriteTokens ??
446
+ tokens.cache_write_tokens ??
447
+ cache?.write,
448
+ ) ?? 0;
442
449
  const totalTokens = nonNegativeNumberValue(tokens.total ?? tokens.totalTokens ?? tokens.total_tokens)
443
450
  ?? inputTokens + outputTokens;
444
451
 
@@ -451,6 +458,7 @@ function openCodeUsageFromTokens(tokens: unknown) {
451
458
  totalTokens,
452
459
  inputTokens,
453
460
  cachedInputTokens,
461
+ ...(cacheWriteInputTokens > 0 ? { cacheWriteInputTokens } : {}),
454
462
  outputTokens,
455
463
  reasoningOutputTokens,
456
464
  },
@@ -524,6 +532,13 @@ function turnTokenUsage(messages: unknown[], model: ReturnType<typeof parseModel
524
532
  totalTokens: sum.totalTokens + usage.totalTokens,
525
533
  inputTokens: sum.inputTokens + usage.inputTokens,
526
534
  cachedInputTokens: sum.cachedInputTokens + usage.cachedInputTokens,
535
+ ...((sum.cacheWriteInputTokens ?? 0) + (usage.cacheWriteInputTokens ?? 0) > 0
536
+ ? {
537
+ cacheWriteInputTokens:
538
+ (sum.cacheWriteInputTokens ?? 0) +
539
+ (usage.cacheWriteInputTokens ?? 0),
540
+ }
541
+ : {}),
527
542
  outputTokens: sum.outputTokens + usage.outputTokens,
528
543
  reasoningOutputTokens: sum.reasoningOutputTokens + usage.reasoningOutputTokens,
529
544
  }), firstRecord);
@@ -1,6 +1,4 @@
1
- import type {
2
- AgentBackendIdDto,
3
- } from './agent-providers';
1
+ import type { AgentBackendIdDto } from './agent-providers';
4
2
 
5
3
  export {
6
4
  agentBackendIds,
@@ -110,6 +108,9 @@ export interface RelayDeviceDto {
110
108
  connectedAt: string | null;
111
109
  lastHeartbeatAt: string | null;
112
110
  createdAt: string;
111
+ hostedStatus?: RelayHostedSandboxStatusDto | null;
112
+ hostedActiveTurnCount?: number;
113
+ hostedIdleDeadlineAt?: string | null;
113
114
  }
114
115
 
115
116
  export interface RelayAdminUserDto extends RelayUserDto {
@@ -145,6 +146,12 @@ export interface RelayRegistrationSettingsDto {
145
146
  enabled: boolean;
146
147
  registrationPassword: string | null;
147
148
  approvalRequired: boolean;
149
+ googleAuthEnabled: boolean;
150
+ githubAuthEnabled: boolean;
151
+ emailVerificationEnabled: boolean;
152
+ googleAuthAvailable: boolean;
153
+ githubAuthAvailable: boolean;
154
+ emailVerificationAvailable: boolean;
148
155
  }
149
156
 
150
157
  export interface RelayPendingRegistrationDto {
@@ -152,6 +159,7 @@ export interface RelayPendingRegistrationDto {
152
159
  email: string;
153
160
  username: string;
154
161
  createdAt: string;
162
+ provider?: 'password' | 'google' | 'github';
155
163
  }
156
164
 
157
165
  export type RelayThreadAccessDto = 'read' | 'control';
@@ -297,6 +305,7 @@ export interface RelaySessionDto {
297
305
  authenticated: boolean;
298
306
  user: RelayUserDto | null;
299
307
  registrationEnabled: boolean;
308
+ registrationSettings?: RelayRegistrationSettingsDto;
300
309
  }
301
310
 
302
311
  export interface RelayLoginResultDto {
@@ -337,6 +346,153 @@ export interface RelayAdminSummaryDto {
337
346
  registrationEnabled: boolean;
338
347
  }
339
348
 
349
+ export type RelayHostedSandboxProviderDto = 'disabled' | 'incus';
350
+
351
+ export interface RelayHostedSandboxCapabilityDto {
352
+ provider: RelayHostedSandboxProviderDto;
353
+ configured: boolean;
354
+ reachable: boolean;
355
+ available: boolean;
356
+ reasonCode: string | null;
357
+ reason: string | null;
358
+ checkedAt: string;
359
+ limits?: {
360
+ maxInstances: number;
361
+ maxRunningInstances: number;
362
+ };
363
+ capacity?: {
364
+ totalInstances: number;
365
+ runningInstances: number;
366
+ };
367
+ metrics?: {
368
+ cpuCount: number;
369
+ load1: number;
370
+ loadPerCpu: number;
371
+ memoryTotalMiB: number;
372
+ memoryAvailableMiB: number;
373
+ diskTotalGiB: number;
374
+ diskAvailableGiB: number;
375
+ monitorPath: string;
376
+ };
377
+ alerts?: Array<{
378
+ code: 'host_memory_low' | 'host_disk_low' | 'host_load_high';
379
+ severity: 'warning';
380
+ message: string;
381
+ }>;
382
+ }
383
+
384
+ export type RelayHostedSandboxStatusDto =
385
+ | 'requested'
386
+ | 'creating'
387
+ | 'starting'
388
+ | 'provisioning'
389
+ | 'stopped'
390
+ | 'online'
391
+ | 'stopping'
392
+ | 'error'
393
+ | 'deleting';
394
+
395
+ export type RelayHostedSandboxOperationActionDto =
396
+ | 'create'
397
+ | 'start'
398
+ | 'stop'
399
+ | 'snapshot'
400
+ | 'delete'
401
+ | 'rotate_credential';
402
+
403
+ export type RelayHostedSandboxOperationStatusDto =
404
+ | 'pending'
405
+ | 'running'
406
+ | 'succeeded'
407
+ | 'failed';
408
+
409
+ export interface RelayHostedSandboxResourcesDto {
410
+ cpuCount: number;
411
+ memoryMiB: number;
412
+ diskGiB: number;
413
+ }
414
+
415
+ export interface RelayHostedCodexConfigDto {
416
+ modelProvider: string;
417
+ model: string;
418
+ reviewModel: string;
419
+ reasoningEffort: 'low' | 'medium' | 'high' | 'xhigh';
420
+ baseUrl: string;
421
+ wireApi: 'responses';
422
+ requiresOpenaiAuth: boolean;
423
+ disableResponseStorage: boolean;
424
+ networkAccess: 'enabled' | 'disabled';
425
+ goals: boolean;
426
+ }
427
+
428
+ export interface RelayHostedSandboxMemberDto {
429
+ userId: string;
430
+ username: string;
431
+ email: string;
432
+ }
433
+
434
+ export interface RelayHostedCodexFilesDto {
435
+ configToml: string;
436
+ authJson: string;
437
+ }
438
+
439
+ export interface RelayHostedSandboxDto {
440
+ id: string;
441
+ deviceId: string;
442
+ deviceName: string;
443
+ assignedUserId: string;
444
+ assignedUsername: string;
445
+ assignedUsers: RelayHostedSandboxMemberDto[];
446
+ workspaceIsolationEnabled: boolean;
447
+ createdByAdminUserId: string;
448
+ provider: 'incus';
449
+ providerInstanceId: string | null;
450
+ imageVersion: string;
451
+ resources: RelayHostedSandboxResourcesDto;
452
+ status: RelayHostedSandboxStatusDto;
453
+ lastErrorCode: string | null;
454
+ lastErrorMessage: string | null;
455
+ activeTurnCount: number;
456
+ lastUserActivityAt: string | null;
457
+ idleDeadlineAt: string | null;
458
+ runningSince: string | null;
459
+ createdAt: string;
460
+ updatedAt: string;
461
+ }
462
+
463
+ export interface RelayHostedSandboxOperationDto {
464
+ id: string;
465
+ sandboxId: string;
466
+ action: RelayHostedSandboxOperationActionDto;
467
+ status: RelayHostedSandboxOperationStatusDto;
468
+ errorCode: string | null;
469
+ errorMessage: string | null;
470
+ createdAt: string;
471
+ updatedAt: string;
472
+ }
473
+
474
+ export interface RelayHostedSandboxDetailDto extends RelayHostedSandboxDto {
475
+ operations: RelayHostedSandboxOperationDto[];
476
+ }
477
+
478
+ export interface RelayHostedSandboxReconciliationDto {
479
+ status: 'never_run' | 'healthy' | 'issues' | 'unavailable';
480
+ checkedAt: string | null;
481
+ errorCode: string | null;
482
+ missingInstanceSandboxIds: string[];
483
+ missingCredentialSandboxIds: string[];
484
+ orphanInstances: Array<{
485
+ id: string;
486
+ status: string;
487
+ snapshots: string[];
488
+ }>;
489
+ orphanCredentials: Array<{
490
+ credentialRef: string;
491
+ createdAt: string;
492
+ }>;
493
+ orphanSnapshotCount: number;
494
+ }
495
+
340
496
  export type RelaySupervisorEnvelope =
341
497
  | {
342
498
  type: 'relay.connected';
@@ -348,6 +504,16 @@ export type RelaySupervisorEnvelope =
348
504
  timestamp: string;
349
505
  deviceId?: string;
350
506
  }
507
+ | {
508
+ type: 'relay.activity';
509
+ timestamp: string;
510
+ deviceId?: string;
511
+ payload: {
512
+ kind: 'turn_started' | 'turn_terminal';
513
+ threadId: string;
514
+ turnId: string;
515
+ };
516
+ }
351
517
  | {
352
518
  type: 'relay.request';
353
519
  timestamp: string;
@@ -408,6 +574,22 @@ export interface AgentRuntimeStatusDto {
408
574
  restartCount: number;
409
575
  }
410
576
 
577
+ export interface AgentSubscriptionUsageWindowDto {
578
+ id: string;
579
+ durationMinutes: number | null;
580
+ label: string;
581
+ usedPercent: number;
582
+ resetsAt: string | null;
583
+ }
584
+
585
+ export interface AgentSubscriptionUsageDto {
586
+ provider: 'codex' | 'claude';
587
+ authKind: 'subscription' | 'apiKey' | 'unknown';
588
+ observedAt: string;
589
+ stale: boolean;
590
+ windows: AgentSubscriptionUsageWindowDto[];
591
+ }
592
+
411
593
  export interface AgentProviderCapabilitiesDto {
412
594
  sessions: {
413
595
  list: boolean;
@@ -535,6 +717,7 @@ export interface VersionDto {
535
717
  export interface HealthDto {
536
718
  status: 'ok';
537
719
  timestamp: string;
720
+ activeTurnCount: number;
538
721
  }
539
722
 
540
723
  export type ProviderHostFileNameDto = string;
@@ -596,7 +779,9 @@ export interface CreateWorkspaceFromGitInput {
596
779
  label?: string;
597
780
  }
598
781
 
599
- export type CreateWorkspaceInput = CreateWorkspaceFromPathInput | CreateWorkspaceFromGitInput;
782
+ export type CreateWorkspaceInput =
783
+ | CreateWorkspaceFromPathInput
784
+ | CreateWorkspaceFromGitInput;
600
785
 
601
786
  export interface WorkspaceSettingsDto {
602
787
  workspaceRoot: string;
@@ -702,9 +887,13 @@ export type ReasoningEffortDto =
702
887
  | 'medium'
703
888
  | 'high'
704
889
  | 'xhigh'
705
- | 'max';
890
+ | 'max'
891
+ | 'ultra';
706
892
  export type CollaborationModeDto = 'default' | 'plan';
707
- export type SandboxModeDto = 'read-only' | 'workspace-write' | 'danger-full-access';
893
+ export type SandboxModeDto =
894
+ | 'read-only'
895
+ | 'workspace-write'
896
+ | 'danger-full-access';
708
897
 
709
898
  export interface ReasoningEffortOptionDto {
710
899
  reasoningEffort: ReasoningEffortDto;
@@ -894,6 +1083,7 @@ export interface ThreadTurnTokenBreakdownDto {
894
1083
  totalTokens: number;
895
1084
  inputTokens: number;
896
1085
  cachedInputTokens: number;
1086
+ cacheWriteInputTokens?: number;
897
1087
  outputTokens: number;
898
1088
  reasoningOutputTokens: number;
899
1089
  }
@@ -912,6 +1102,7 @@ export interface ThreadTurnPriceEstimateDto {
912
1102
  currency: 'USD';
913
1103
  inputUsd: number;
914
1104
  cachedInputUsd: number;
1105
+ cacheWriteInputUsd?: number;
915
1106
  outputUsd: number;
916
1107
  totalUsd: number;
917
1108
  }
@@ -1050,7 +1241,11 @@ export type AgentHookSourceDto =
1050
1241
  | 'legacyManagedConfigFile'
1051
1242
  | 'legacyManagedConfigMdm'
1052
1243
  | 'unknown';
1053
- export type AgentHookTrustStatusDto = 'managed' | 'untrusted' | 'trusted' | 'modified';
1244
+ export type AgentHookTrustStatusDto =
1245
+ | 'managed'
1246
+ | 'untrusted'
1247
+ | 'trusted'
1248
+ | 'modified';
1054
1249
 
1055
1250
  export interface AgentHookDto {
1056
1251
  key: string;
@@ -1153,6 +1348,7 @@ export interface ThreadPendingSteerDto {
1153
1348
  clientRequestId: string | null;
1154
1349
  turnId: string;
1155
1350
  prompt: string;
1351
+ delivery: 'steer' | 'continuation';
1156
1352
  createdAt: string;
1157
1353
  }
1158
1354
 
@@ -13,9 +13,9 @@ const sourceCheckout =
13
13
  const defaultServicePort = sourceCheckout ? 4173 : 45673;
14
14
  const defaultApiPort = sourceCheckout ? 8787 : 45674;
15
15
 
16
- const serviceHost = process.env.SERVICE_HOST ?? '127.0.0.1';
16
+ const serviceHost = process.env.SERVICE_HOST ?? '0.0.0.0';
17
17
  const servicePort = parsePort(process.env.SERVICE_PORT, defaultServicePort);
18
- const apiHost = process.env.SERVICE_API_HOST ?? '127.0.0.1';
18
+ const apiHost = process.env.SERVICE_API_HOST ?? '0.0.0.0';
19
19
  const apiPort = parsePort(process.env.SERVICE_API_PORT, defaultApiPort);
20
20
  const distDir = path.resolve(
21
21
  process.env.SERVICE_WEB_DIST_DIR ?? path.join(repoRoot, 'apps/supervisor-web/dist')
@@ -23,9 +23,9 @@ const webIndex = path.join(repoRoot, 'apps', 'supervisor-web', 'dist', 'index.ht
23
23
  const defaultServicePort = supportsSourceRestart ? 4173 : 45673;
24
24
  const defaultApiPort = supportsSourceRestart ? 8787 : 45674;
25
25
 
26
- const serviceHost = process.env.SERVICE_HOST ?? '127.0.0.1';
26
+ const serviceHost = process.env.SERVICE_HOST ?? '0.0.0.0';
27
27
  const servicePort = parsePort(process.env.SERVICE_PORT, defaultServicePort);
28
- const apiHost = process.env.SERVICE_API_HOST ?? '127.0.0.1';
28
+ const apiHost = process.env.SERVICE_API_HOST ?? '0.0.0.0';
29
29
  const apiPort = parsePort(process.env.SERVICE_API_PORT, defaultApiPort);
30
30
 
31
31
  const command = process.argv[2];