@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.
- package/README.md +22 -5
- package/db/migrations/0014_host_inventory_event_index.sql +1 -0
- package/db/migrations/0015_host_settings.sql +9 -0
- package/db/migrations/0016_task_environment.sql +2 -0
- package/db/migrations/meta/_journal.json +21 -0
- package/db/schema.ts +80 -30
- package/images/standard/Dockerfile +36 -10
- package/images/standard/README.md +63 -18
- package/images/standard/container/corepack-version +1 -0
- package/images/standard/container/uai-init +308 -38
- package/images/standard/container/uai-materialize-runtimes +1527 -0
- package/lib/agent-cli.ts +69 -4
- package/lib/agent.ts +46 -7
- package/lib/agents/claude.ts +13 -8
- package/lib/agents/codex.ts +11 -6
- package/lib/agents/cursor.ts +39 -29
- package/lib/agents/durable-proc.ts +20 -27
- package/lib/agents/factory.ts +9 -25
- package/lib/agents/grok.ts +43 -30
- package/lib/agents/kimi.ts +44 -29
- package/lib/agents/opencode.ts +43 -31
- package/lib/agents/proc.ts +149 -114
- package/lib/agents/transport.ts +62 -50
- package/lib/agents/types.ts +6 -4
- package/lib/apple-runtime-recycle.ts +236 -0
- package/lib/apple-uninstall-teardown.ts +224 -0
- package/lib/browser-testing.ts +233 -93
- package/lib/codex-auth.ts +40 -6
- package/lib/command-db.ts +20 -0
- package/lib/container-runtime.ts +1338 -0
- package/lib/db.ts +1 -0
- package/lib/docker-exec.ts +87 -5
- package/lib/engine-accounts.ts +68 -5
- package/lib/engine-login.ts +1952 -0
- package/lib/enrollment-state.ts +251 -0
- package/lib/env-file.ts +155 -0
- package/lib/env.ts +4 -0
- package/lib/git-diff.ts +98 -32
- package/lib/git-identity.ts +199 -87
- package/lib/github-tokens.ts +202 -91
- package/lib/host-cloud-url.ts +62 -0
- package/lib/host-config.ts +279 -0
- package/lib/host-logs.ts +962 -0
- package/lib/keyed-promise-tail.ts +23 -0
- package/lib/legacy-runtime-v1.fixture.ts +627 -0
- package/lib/managed-activation-watcher.ts +72 -0
- package/lib/managed-install-owner-watcher.ts +55 -0
- package/lib/managed-operation-drain.ts +49 -0
- package/lib/managed-runtime.ts +3644 -0
- package/lib/managed-update-scheduler.ts +125 -0
- package/lib/mcp-gateway.ts +450 -23
- package/lib/orchestrator.ts +3070 -223
- package/lib/preview-sidecar.ts +57 -13
- package/lib/release-manifest.ts +708 -0
- package/lib/release-trust.ts +28 -0
- package/lib/runtime-activation-tail.ts +232 -0
- package/lib/runtime-archive.ts +1086 -0
- package/lib/runtime-authority.ts +79 -0
- package/lib/runtime-guard.ts +36 -0
- package/lib/runtime-provider-state.ts +169 -0
- package/lib/runtime-state.ts +232 -12
- package/lib/skills.ts +24 -3
- package/lib/ssh.ts +18 -0
- package/lib/standard-image.ts +1104 -141
- package/lib/stopped-task-status-queue.ts +44 -0
- package/lib/task-container-cli.ts +269 -0
- package/lib/task-diff.ts +66 -46
- package/lib/task-environment/apple-container.ts +757 -0
- package/lib/task-environment/docker.ts +945 -0
- package/lib/task-environment/index.ts +364 -0
- package/lib/task-environment/legacy-adoption.ts +443 -0
- package/lib/task-environment/registry.ts +58 -0
- package/lib/task-environment/types.ts +408 -0
- package/lib/task-identity.ts +19 -0
- package/lib/task-inventory.ts +585 -0
- package/lib/tunnel-registry.ts +135 -19
- package/lib/tunnel-runtime.ts +235 -0
- package/package.json +1 -1
- package/scripts/agent/_common.sh +123 -3
- package/scripts/agent/task-down.sh +146 -38
- package/scripts/agent/task-status.sh +19 -3
- package/scripts/agent/task-up.sh +1463 -109
- package/scripts/install/darwin.ts +848 -50
- package/scripts/install/linux.ts +838 -35
- package/scripts/install/types.ts +43 -0
- package/scripts/install/util.ts +215 -8
- package/scripts/install/win.ts +12 -0
- package/src/apple-tunnel-route.ts +104 -0
- package/src/cli.ts +1464 -72
- package/src/event-outbox.ts +83 -4
- package/src/index.ts +871 -50
- package/src/main.ts +1398 -255
- package/src/paths.ts +17 -1
- package/src/protocol.ts +695 -1
- package/src/runtime-bootstrap.ts +165 -0
- package/src/ui/server.ts +46 -10
- package/src/ui/types.ts +37 -0
package/src/event-outbox.ts
CHANGED
|
@@ -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
|
-
|
|
42
|
-
|
|
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.
|
|
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.
|
|
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
|
+
}
|