@runuai/host 0.9.150 → 0.9.151
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/db/migrations/0027_cloud_credential_foundation.sql +51 -0
- package/db/migrations/0028_leased_engine_runtimes.sql +11 -0
- package/db/migrations/meta/_journal.json +14 -0
- package/db/schema.ts +188 -0
- package/lib/agent-cli.ts +11 -13
- package/lib/agent.ts +177 -7
- package/lib/agents/durable-proc.ts +56 -44
- package/lib/agents/registry.ts +19 -3
- package/lib/agents/session-state.ts +23 -10
- package/lib/agents/transport.ts +101 -69
- package/lib/apple-one-off.ts +277 -0
- package/lib/apple-runtime-recycle.ts +4 -3
- package/lib/attachments.ts +19 -17
- package/lib/capture-flow.ts +319 -0
- package/lib/cloud-credential-cleanup-adapter.ts +123 -0
- package/lib/cloud-credential-host.ts +512 -0
- package/lib/cloud-credential-leases.ts +2544 -0
- package/lib/cloud-credential-runtime.ts +1035 -0
- package/lib/codex-auth.ts +21 -1
- package/lib/container-runtime.ts +76 -0
- package/lib/credential-cleanup-inventory.ts +405 -0
- package/lib/credential-consumers/engine-anchor.ts +1876 -0
- package/lib/credential-consumers/engines.ts +773 -0
- package/lib/credential-consumers/github.ts +594 -0
- package/lib/credential-consumers/mcp.ts +384 -0
- package/lib/credential-consumers/task-files.ts +127 -0
- package/lib/credential-store-pickup.ts +15 -2
- package/lib/credential-store.ts +361 -33
- package/lib/credentials-activation-authority.ts +546 -0
- package/lib/credentials-purge.ts +1006 -0
- package/lib/db.ts +11 -0
- package/lib/docker-exec.ts +3 -1
- package/lib/engine-accounts.ts +42 -32
- package/lib/engine-connect.ts +47 -2
- package/lib/engine-credential-env.ts +50 -0
- package/lib/engine-login.ts +83 -1
- package/lib/env-file.ts +62 -8
- package/lib/env.ts +5 -0
- package/lib/fs-aliases.ts +49 -0
- package/lib/git-clone-credentials.ts +334 -0
- package/lib/git-diff.ts +219 -177
- package/lib/git-identity.ts +59 -14
- package/lib/github-origin.ts +28 -0
- package/lib/github-tokens.ts +56 -21
- package/lib/host-env.ts +17 -4
- package/lib/launch-mode.ts +25 -0
- package/lib/legacy-runtime-retirement.ts +388 -0
- package/lib/machine-exec.ts +14 -3
- package/lib/machine-provider-aws.ts +50 -8
- package/lib/machine-provider-local.ts +4 -0
- package/lib/machine-provider.ts +4 -0
- package/lib/managed-operation-drain.ts +8 -0
- package/lib/managed-runtime.ts +371 -7
- package/lib/mcp-capture.ts +860 -0
- package/lib/mcp-connections.ts +8 -1
- package/lib/mcp-gateway.ts +168 -10
- package/lib/obs.ts +2 -6
- package/lib/orchestrator.ts +1830 -224
- package/lib/person-capture.ts +327 -0
- package/lib/project-env-legacy-tags.ts +130 -0
- package/lib/project-env-task-replica.ts +1752 -0
- package/lib/runner-boot.ts +10 -0
- package/lib/runtime-activation-tail.ts +50 -3
- package/lib/runtime-archive.ts +68 -1
- package/lib/runtime-reconnect.ts +86 -0
- package/lib/runtime-state.ts +429 -13
- package/lib/safe-http.ts +364 -0
- package/lib/secrets-proxy/task-trust.ts +34 -3
- package/lib/sidecar-resume.ts +18 -5
- package/lib/skills.ts +47 -8
- package/lib/standard-image.ts +157 -103
- package/lib/stopped-task-status-queue.ts +68 -10
- package/lib/task-credential-cleanup.ts +525 -0
- package/lib/task-diff-sandbox.ts +464 -0
- package/lib/task-diff.ts +66 -163
- package/lib/task-env-source.ts +68 -14
- package/lib/task-environment/anchor.ts +31 -0
- package/lib/task-environment/apple-container.ts +69 -28
- package/lib/task-environment/docker.ts +101 -20
- package/lib/task-environment/machine-environment.ts +61 -0
- package/lib/task-environment/machine-task-up.ts +459 -96
- package/lib/task-environment/machine.ts +101 -11
- package/lib/task-environment/self.ts +108 -50
- package/lib/task-environment/types.ts +89 -5
- package/lib/task-environment/workspace-files.ts +623 -25
- package/lib/task-environment/workspace-runtime.fixture.ts +50 -0
- package/lib/task-gateway-recovery.ts +4 -1
- package/lib/task-gateway-state.ts +15 -0
- package/lib/task-machine-swap-safety.ts +729 -0
- package/lib/token-broker-adopt.ts +344 -0
- package/lib/token-broker-lambda.ts +56 -2
- package/lib/token-broker-local.ts +28 -4
- package/lib/token-broker-revision.ts +310 -0
- package/lib/token-broker-ssm.ts +368 -28
- package/lib/token-lanes/openai-oauth.ts +7 -3
- package/lib/token-lanes/xai-oauth.ts +7 -3
- package/lib/transcript.ts +9 -5
- package/package.json +6 -2
- package/scripts/agent/task-up.sh +242 -100
- package/src/cloud-credentials.ts +2399 -0
- package/src/event-outbox.ts +8 -6
- package/src/index.ts +1386 -875
- package/src/main.ts +1061 -139
- package/src/outbound-frame.ts +31 -0
- package/src/project-env-policy.ts +125 -10
- package/src/protocol.ts +699 -23
- package/src/ui/server.ts +48 -10
|
@@ -148,16 +148,55 @@ export function awsUserData(authorizedPublicKey: string): string {
|
|
|
148
148
|
' chmod 700 "$home/.ssh"',
|
|
149
149
|
' chmod 600 "$home/.ssh/authorized_keys"',
|
|
150
150
|
"done",
|
|
151
|
+
// This user-data is emitted only by the task-machine provider. Owned
|
|
152
|
+
// runners use the host installer and never execute it, so their OS swap
|
|
153
|
+
// remains untouched.
|
|
154
|
+
//
|
|
151
155
|
// Swap BEFORE any workload: an Opus agent + a bundler + Chromium on a
|
|
152
|
-
// swapless machine hits the memory wall
|
|
153
|
-
//
|
|
154
|
-
//
|
|
155
|
-
//
|
|
156
|
-
//
|
|
156
|
+
// swapless machine hits the memory wall. The backing file is encrypted
|
|
157
|
+
// by a plain dm-crypt mapping whose key is read from /dev/urandom every
|
|
158
|
+
// time the mapping is created. /run's marker makes this idempotent within
|
|
159
|
+
// one boot; crypttab recreates the mapping (and therefore the key) after
|
|
160
|
+
// every boot. The persistent marker only says the backing file has been
|
|
161
|
+
// scrubbed once and has never subsequently held plaintext swap.
|
|
162
|
+
"if ! command -v cryptsetup >/dev/null 2>&1 || [ ! -x /lib/systemd/system-generators/systemd-cryptsetup-generator ]; then apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends cryptsetup; fi",
|
|
163
|
+
"mkdir -p /run/uai /var/lib/uai",
|
|
164
|
+
"chmod 700 /run/uai /var/lib/uai",
|
|
165
|
+
"touch /etc/crypttab /etc/fstab",
|
|
166
|
+
"crypttab_tmp=$(mktemp /etc/crypttab.uai.XXXXXX)",
|
|
167
|
+
"awk 'BEGIN { managed=0 } $0 == \"# BEGIN UAI TASK MACHINE SWAP\" { managed=1; next } $0 == \"# END UAI TASK MACHINE SWAP\" { managed=0; next } managed { next } /^[[:space:]]*#/ { print; next } $1 == \"uai-swap\" || $4 ~ /(^|,)swap(,|$)/ { print \"# uai-replaced-swap \" $0; next } { print }' /etc/crypttab > \"$crypttab_tmp\"",
|
|
168
|
+
"printf '%s\\n' '# BEGIN UAI TASK MACHINE SWAP' 'uai-swap /swapfile /dev/urandom swap,cipher=aes-xts-plain64,size=512' '# END UAI TASK MACHINE SWAP' >> \"$crypttab_tmp\"",
|
|
169
|
+
"chown root:root \"$crypttab_tmp\" && chmod 600 \"$crypttab_tmp\" && mv -f -- \"$crypttab_tmp\" /etc/crypttab",
|
|
170
|
+
"fstab_tmp=$(mktemp /etc/fstab.uai.XXXXXX)",
|
|
171
|
+
"awk 'BEGIN { managed=0 } $0 == \"# BEGIN UAI TASK MACHINE SWAP\" { managed=1; next } $0 == \"# END UAI TASK MACHINE SWAP\" { managed=0; next } managed { next } /^[[:space:]]*#/ { print; next } NF >= 3 && $3 == \"swap\" { print \"# uai-disabled-raw-swap \" $0; next } { print }' /etc/fstab > \"$fstab_tmp\"",
|
|
172
|
+
"printf '%s\\n' '# BEGIN UAI TASK MACHINE SWAP' '/dev/mapper/uai-swap none swap sw 0 0' '# END UAI TASK MACHINE SWAP' >> \"$fstab_tmp\"",
|
|
173
|
+
"chown root:root \"$fstab_tmp\" && chmod 644 \"$fstab_tmp\" && mv -f -- \"$fstab_tmp\" /etc/fstab",
|
|
174
|
+
"active_swap=$(awk 'NR > 1 { print $1 }' /proc/swaps)",
|
|
175
|
+
"if [ ! -f /run/uai/swap-ready-v1 ] || [ \"$active_swap\" != /dev/mapper/uai-swap ]; then",
|
|
176
|
+
// Failing to page every old raw-swap page back into RAM is fatal: the
|
|
177
|
+
// sidecar must not start beside durable plaintext merely to keep booting.
|
|
178
|
+
" swapoff -a",
|
|
179
|
+
" cryptsetup close uai-swap 2>/dev/null || true",
|
|
180
|
+
" if [ ! -f /var/lib/uai/swap-backing-initialized-v1 ]; then",
|
|
181
|
+
" if [ -L /swapfile ] || { [ -e /swapfile ] && [ ! -f /swapfile ]; }; then echo 'unsafe /swapfile type' >&2; exit 1; fi",
|
|
182
|
+
// An older task-machine release used this file as raw swap. One complete
|
|
183
|
+
// zero pass removes any pages it left before the file is reused solely as
|
|
184
|
+
// ciphertext backing. Crashes are safe: without the marker the next run
|
|
185
|
+
// repeats the scrub.
|
|
186
|
+
" if [ -f /swapfile ]; then shred --iterations=0 --zero -- /swapfile; fi",
|
|
187
|
+
" rm -f -- /swapfile",
|
|
188
|
+
" fi",
|
|
157
189
|
// 16G (owner decision 2026-08-31): the graceful-degradation floor has to
|
|
158
|
-
// absorb the whole heavy shape
|
|
159
|
-
// and the
|
|
160
|
-
"
|
|
190
|
+
// absorb the whole heavy shape. Every command is mandatory; failure keeps
|
|
191
|
+
// cloud-init and therefore the task machine unavailable.
|
|
192
|
+
" fallocate -l 16G /swapfile",
|
|
193
|
+
" chown root:root /swapfile && chmod 600 /swapfile",
|
|
194
|
+
" cryptsetup open --batch-mode --type plain --cipher aes-xts-plain64 --key-size 512 --key-file /dev/urandom /swapfile uai-swap",
|
|
195
|
+
" mkswap /dev/mapper/uai-swap >/dev/null",
|
|
196
|
+
" swapon /dev/mapper/uai-swap",
|
|
197
|
+
" touch /var/lib/uai/swap-backing-initialized-v1 /run/uai/swap-ready-v1",
|
|
198
|
+
" chmod 600 /var/lib/uai/swap-backing-initialized-v1 /run/uai/swap-ready-v1",
|
|
199
|
+
"fi",
|
|
161
200
|
// The task OWNS its machine (ADR-121 — per-customer kernel isolation is
|
|
162
201
|
// the whole point); denying sudo just breaks project setups that
|
|
163
202
|
// container tasks handle fine (live 2026-08-31: a Hightop machine task
|
|
@@ -609,6 +648,8 @@ export function createAwsMachineProvider(
|
|
|
609
648
|
id: machineId,
|
|
610
649
|
taskLabel: instance.taskLabel,
|
|
611
650
|
state,
|
|
651
|
+
// Still stopping: its processes run until the instance is stopped.
|
|
652
|
+
...(instance.state === "stopping" ? { frozen: true as const } : {}),
|
|
612
653
|
address: state === "running" ? instance.privateIp : null,
|
|
613
654
|
};
|
|
614
655
|
}
|
|
@@ -860,6 +901,7 @@ export function createAwsMachineProvider(
|
|
|
860
901
|
: instance.instanceId,
|
|
861
902
|
taskLabel: instance.taskLabel,
|
|
862
903
|
state,
|
|
904
|
+
...(instance.state === "stopping" ? { frozen: true as const } : {}),
|
|
863
905
|
address: state === "running" ? instance.privateIp : null,
|
|
864
906
|
};
|
|
865
907
|
});
|
|
@@ -75,6 +75,7 @@ interface InspectShape {
|
|
|
75
75
|
name: string;
|
|
76
76
|
taskLabel: string | null;
|
|
77
77
|
state: MachineState;
|
|
78
|
+
frozen?: true;
|
|
78
79
|
address: string | null;
|
|
79
80
|
sshPort: number | null;
|
|
80
81
|
}
|
|
@@ -148,6 +149,7 @@ function parseInspect(id: string, stdout: string): InspectShape | null {
|
|
|
148
149
|
name,
|
|
149
150
|
taskLabel,
|
|
150
151
|
state: stateFromDocker(stateObj?.Status),
|
|
152
|
+
...(stateObj?.Status === "paused" ? { frozen: true as const } : {}),
|
|
151
153
|
address,
|
|
152
154
|
sshPort,
|
|
153
155
|
};
|
|
@@ -171,6 +173,7 @@ export function createLocalMachineProvider(
|
|
|
171
173
|
id,
|
|
172
174
|
taskLabel: record.taskLabel,
|
|
173
175
|
state: record.state,
|
|
176
|
+
...(record.frozen ? { frozen: true as const } : {}),
|
|
174
177
|
address: record.state === "running" ? record.address : null,
|
|
175
178
|
...(record.state === "running" && record.sshPort !== null
|
|
176
179
|
? { sshPort: record.sshPort }
|
|
@@ -322,6 +325,7 @@ export function createLocalMachineProvider(
|
|
|
322
325
|
id: record.name,
|
|
323
326
|
taskLabel: record.taskLabel,
|
|
324
327
|
state: record.state,
|
|
328
|
+
...(record.frozen ? { frozen: true as const } : {}),
|
|
325
329
|
address: record.state === "running" ? record.address : null,
|
|
326
330
|
...(record.state === "running" && record.sshPort !== null
|
|
327
331
|
? { sshPort: record.sshPort }
|
package/lib/machine-provider.ts
CHANGED
|
@@ -48,6 +48,10 @@ export interface MachineSpec {
|
|
|
48
48
|
export interface MachineInfo {
|
|
49
49
|
/** Backend-native identifier: instance id or container id/name. */
|
|
50
50
|
id: string;
|
|
51
|
+
/** Stopped as far as work goes, yet its processes still exist (a paused
|
|
52
|
+
* container, an instance still stopping): they could run or write again
|
|
53
|
+
* without a new start. */
|
|
54
|
+
frozen?: true;
|
|
51
55
|
/** The recorded task ownership label, null when the machine carries none
|
|
52
56
|
* (a foreign machine occupying a reserved name is never ours to touch). */
|
|
53
57
|
taskLabel: string | null;
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
export class ManagedOperationDrain {
|
|
7
7
|
private active = 0;
|
|
8
8
|
private accepting = true;
|
|
9
|
+
private idleWaiters: Array<() => void> = [];
|
|
9
10
|
|
|
10
11
|
constructor(private readonly onSettled: () => void) {}
|
|
11
12
|
|
|
@@ -22,6 +23,12 @@ export class ManagedOperationDrain {
|
|
|
22
23
|
this.accepting = false;
|
|
23
24
|
}
|
|
24
25
|
|
|
26
|
+
/** Resolves once nothing tracked is under way (at once when nothing is). */
|
|
27
|
+
idle(): Promise<void> {
|
|
28
|
+
if (this.active === 0) return Promise.resolve();
|
|
29
|
+
return new Promise<void>((resolve) => this.idleWaiters.push(resolve));
|
|
30
|
+
}
|
|
31
|
+
|
|
25
32
|
track<T>(operation: () => Promise<T>): Promise<T> {
|
|
26
33
|
if (!this.accepting) {
|
|
27
34
|
return Promise.reject(
|
|
@@ -44,6 +51,7 @@ export class ManagedOperationDrain {
|
|
|
44
51
|
if (this.active < 0) {
|
|
45
52
|
throw new Error("managed operation drain settled more work than it tracked");
|
|
46
53
|
}
|
|
54
|
+
if (this.active === 0) for (const resolve of this.idleWaiters.splice(0)) resolve();
|
|
47
55
|
this.onSettled();
|
|
48
56
|
}
|
|
49
57
|
}
|