@runuai/host 0.9.13 → 0.9.42

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 (97) hide show
  1. package/README.md +22 -5
  2. package/db/migrations/0014_host_inventory_event_index.sql +1 -0
  3. package/db/migrations/0015_host_settings.sql +9 -0
  4. package/db/migrations/0016_task_environment.sql +2 -0
  5. package/db/migrations/meta/_journal.json +21 -0
  6. package/db/schema.ts +80 -30
  7. package/images/standard/Dockerfile +36 -10
  8. package/images/standard/README.md +63 -18
  9. package/images/standard/container/corepack-version +1 -0
  10. package/images/standard/container/uai-init +308 -38
  11. package/images/standard/container/uai-materialize-runtimes +1527 -0
  12. package/lib/agent-cli.ts +69 -4
  13. package/lib/agent.ts +46 -7
  14. package/lib/agents/claude.ts +13 -8
  15. package/lib/agents/codex.ts +11 -6
  16. package/lib/agents/cursor.ts +39 -29
  17. package/lib/agents/durable-proc.ts +20 -27
  18. package/lib/agents/factory.ts +9 -25
  19. package/lib/agents/grok.ts +43 -30
  20. package/lib/agents/kimi.ts +44 -29
  21. package/lib/agents/opencode.ts +43 -31
  22. package/lib/agents/proc.ts +149 -114
  23. package/lib/agents/transport.ts +62 -50
  24. package/lib/agents/types.ts +6 -4
  25. package/lib/apple-runtime-recycle.ts +236 -0
  26. package/lib/apple-uninstall-teardown.ts +224 -0
  27. package/lib/browser-testing.ts +233 -93
  28. package/lib/codex-auth.ts +40 -6
  29. package/lib/command-db.ts +20 -0
  30. package/lib/container-runtime.ts +1338 -0
  31. package/lib/db.ts +1 -0
  32. package/lib/docker-exec.ts +87 -5
  33. package/lib/engine-accounts.ts +68 -5
  34. package/lib/engine-login.ts +1952 -0
  35. package/lib/enrollment-state.ts +251 -0
  36. package/lib/env-file.ts +155 -0
  37. package/lib/env.ts +4 -0
  38. package/lib/git-diff.ts +98 -32
  39. package/lib/git-identity.ts +199 -87
  40. package/lib/github-tokens.ts +202 -91
  41. package/lib/host-cloud-url.ts +62 -0
  42. package/lib/host-config.ts +279 -0
  43. package/lib/host-logs.ts +962 -0
  44. package/lib/keyed-promise-tail.ts +23 -0
  45. package/lib/legacy-runtime-v1.fixture.ts +627 -0
  46. package/lib/managed-activation-watcher.ts +72 -0
  47. package/lib/managed-install-owner-watcher.ts +55 -0
  48. package/lib/managed-operation-drain.ts +49 -0
  49. package/lib/managed-runtime.ts +3644 -0
  50. package/lib/managed-update-scheduler.ts +125 -0
  51. package/lib/mcp-gateway.ts +450 -23
  52. package/lib/orchestrator.ts +3070 -223
  53. package/lib/preview-sidecar.ts +57 -13
  54. package/lib/release-manifest.ts +708 -0
  55. package/lib/release-trust.ts +28 -0
  56. package/lib/runtime-activation-tail.ts +232 -0
  57. package/lib/runtime-archive.ts +1086 -0
  58. package/lib/runtime-authority.ts +79 -0
  59. package/lib/runtime-guard.ts +36 -0
  60. package/lib/runtime-provider-state.ts +169 -0
  61. package/lib/runtime-state.ts +232 -12
  62. package/lib/skills.ts +24 -3
  63. package/lib/ssh.ts +18 -0
  64. package/lib/standard-image.ts +1104 -141
  65. package/lib/stopped-task-status-queue.ts +44 -0
  66. package/lib/task-container-cli.ts +269 -0
  67. package/lib/task-diff.ts +66 -46
  68. package/lib/task-environment/apple-container.ts +757 -0
  69. package/lib/task-environment/docker.ts +945 -0
  70. package/lib/task-environment/index.ts +364 -0
  71. package/lib/task-environment/legacy-adoption.ts +443 -0
  72. package/lib/task-environment/registry.ts +58 -0
  73. package/lib/task-environment/types.ts +408 -0
  74. package/lib/task-identity.ts +19 -0
  75. package/lib/task-inventory.ts +585 -0
  76. package/lib/tunnel-registry.ts +135 -19
  77. package/lib/tunnel-runtime.ts +235 -0
  78. package/package.json +1 -1
  79. package/scripts/agent/_common.sh +123 -3
  80. package/scripts/agent/task-down.sh +146 -38
  81. package/scripts/agent/task-status.sh +19 -3
  82. package/scripts/agent/task-up.sh +1463 -109
  83. package/scripts/install/darwin.ts +848 -50
  84. package/scripts/install/linux.ts +838 -35
  85. package/scripts/install/types.ts +43 -0
  86. package/scripts/install/util.ts +215 -8
  87. package/scripts/install/win.ts +12 -0
  88. package/src/apple-tunnel-route.ts +104 -0
  89. package/src/cli.ts +1464 -72
  90. package/src/event-outbox.ts +83 -4
  91. package/src/index.ts +871 -50
  92. package/src/main.ts +1398 -255
  93. package/src/paths.ts +17 -1
  94. package/src/protocol.ts +695 -1
  95. package/src/runtime-bootstrap.ts +165 -0
  96. package/src/ui/server.ts +46 -10
  97. package/src/ui/types.ts +37 -0
@@ -17,13 +17,31 @@ export interface OutboxEntry {
17
17
  seq: number;
18
18
  /** The full serialized `{kind:"event", seq, event}` frame, ready to send. */
19
19
  raw: string;
20
+ /** Exact UTF-8 wire bytes retained by this frame. */
21
+ bytes: number;
20
22
  }
21
23
 
24
+ export interface EventOutboxSink {
25
+ readonly bufferedAmount: number;
26
+ send(raw: string): void;
27
+ }
28
+
29
+ export type EventOutboxTransmitResult =
30
+ | "empty"
31
+ | "backpressured"
32
+ | "send_failed";
33
+
22
34
  /** Overflow bounds. Generous: a disconnect longer than this many events is a
23
35
  * real outage, not a deploy blip, and dropping OLDEST keeps the tail — the
24
36
  * most recent turn — intact for replay. */
25
37
  const MAX_ENTRIES = 10_000;
26
38
  const MAX_BYTES = 32 * 1024 * 1024;
39
+ // Match the historical `ws` single-message default and the authenticated
40
+ // cloud receiver ceiling. Task diffs and message_complete events are not yet
41
+ // field-bounded, so rolling hosts must retain one legitimate frame above the
42
+ // ordinary outbox/transport budgets. Anything larger could never reach the
43
+ // cloud and would otherwise put the host into a permanent reconnect loop.
44
+ export const MAX_EVENT_FRAME_BYTES = 100 * 1024 * 1024;
27
45
 
28
46
  export class EventOutbox {
29
47
  private entries: OutboxEntry[] = [];
@@ -38,15 +56,20 @@ export class EventOutbox {
38
56
  enqueue(event: HostEvent): number {
39
57
  const seq = this.nextSeq++;
40
58
  const raw = JSON.stringify({ kind: "event", seq, event });
41
- this.entries.push({ seq, raw });
42
- this.totalBytes += raw.length;
59
+ const bytes = Buffer.byteLength(raw, "utf8");
60
+ if (bytes > MAX_EVENT_FRAME_BYTES) {
61
+ this.droppedSinceDrain += 1;
62
+ return seq;
63
+ }
64
+ this.entries.push({ seq, raw, bytes });
65
+ this.totalBytes += bytes;
43
66
  while (
44
67
  this.entries.length > MAX_ENTRIES ||
45
68
  (this.totalBytes > MAX_BYTES && this.entries.length > 1)
46
69
  ) {
47
70
  const dropped = this.entries.shift();
48
71
  if (!dropped) break;
49
- this.totalBytes -= dropped.raw.length;
72
+ this.totalBytes -= dropped.bytes;
50
73
  // Only a NEVER-SENT entry is a real loss; an unacked-but-sent one most
51
74
  // likely landed and just lost its ack.
52
75
  if (dropped.seq > this.sentUpTo) this.droppedSinceDrain += 1;
@@ -59,7 +82,7 @@ export class EventOutbox {
59
82
  let i = 0;
60
83
  for (const entry of this.entries) {
61
84
  if (entry.seq > seq) break;
62
- this.totalBytes -= entry.raw.length;
85
+ this.totalBytes -= entry.bytes;
63
86
  i += 1;
64
87
  }
65
88
  if (i > 0) this.entries.splice(0, i);
@@ -87,6 +110,19 @@ export class EventOutbox {
87
110
  return due;
88
111
  }
89
112
 
113
+ /** Oldest due entry without advancing the transmit cursor. */
114
+ nextDue(): OutboxEntry | null {
115
+ return this.entries.find((entry) => entry.seq > this.sentUpTo) ?? null;
116
+ }
117
+
118
+ /** Advance only the exact next due entry after the caller queues it. */
119
+ markSent(seq: number): boolean {
120
+ const due = this.nextDue();
121
+ if (!due || due.seq !== seq) return false;
122
+ this.sentUpTo = seq;
123
+ return true;
124
+ }
125
+
90
126
  /** Never-sent entries lost to overflow since the last call; resets. */
91
127
  takeDroppedCount(): number {
92
128
  const n = this.droppedSinceDrain;
@@ -102,3 +138,46 @@ export class EventOutbox {
102
138
  return this.totalBytes;
103
139
  }
104
140
  }
141
+
142
+ /**
143
+ * Queue due frames only until the transport reaches its high-water mark.
144
+ * Entries advance one at a time after `send` accepts them, so a slow socket
145
+ * leaves the remainder replayable in the bounded outbox instead of moving the
146
+ * whole backlog into the WebSocket implementation's own buffer.
147
+ */
148
+ export function transmitEventOutbox(
149
+ outbox: EventOutbox,
150
+ sink: EventOutboxSink,
151
+ maxBufferedBytes: number,
152
+ ): EventOutboxTransmitResult {
153
+ let projectedBufferedBytes = sink.bufferedAmount;
154
+ while (true) {
155
+ const entry = outbox.nextDue();
156
+ if (!entry) return "empty";
157
+ if (
158
+ maxBufferedBytes <= 0 ||
159
+ (projectedBufferedBytes > 0 &&
160
+ (projectedBufferedBytes >= maxBufferedBytes ||
161
+ entry.bytes > maxBufferedBytes - projectedBufferedBytes))
162
+ ) {
163
+ return "backpressured";
164
+ }
165
+ try {
166
+ sink.send(entry.raw);
167
+ } catch {
168
+ return "send_failed";
169
+ }
170
+ if (!outbox.markSent(entry.seq)) return "send_failed";
171
+ projectedBufferedBytes = Math.max(
172
+ sink.bufferedAmount,
173
+ projectedBufferedBytes + entry.bytes,
174
+ );
175
+
176
+ // A rolling-compatible frame above the normal high-water budget gets one
177
+ // empty transport to itself. Do not depend on a sink updating
178
+ // `bufferedAmount` synchronously before protecting the following frame.
179
+ if (entry.bytes > maxBufferedBytes) {
180
+ return outbox.nextDue() ? "backpressured" : "empty";
181
+ }
182
+ }
183
+ }