@runuai/host 0.9.14 → 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 +33 -2
- 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 +3060 -218
- 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 +1405 -107
- 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 +766 -42
- 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/lib/preview-sidecar.ts
CHANGED
|
@@ -9,18 +9,20 @@
|
|
|
9
9
|
* (always local — no registry pull) under `node` with a ~5-line `net` TCP proxy;
|
|
10
10
|
* node streams give backpressure + handle WebSockets (Metro/HMR).
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* The cache deduplicates creation, but every tunnel open re-proves the exact
|
|
13
|
+
* sidecar container and its current Docker mapping. A process-lifetime cached
|
|
14
|
+
* localhost port is unsafe across an unnoticed daemon restart: another process
|
|
15
|
+
* can inherit that port before the bridge reconnects and triggers recovery.
|
|
16
16
|
*/
|
|
17
17
|
import net from "node:net";
|
|
18
18
|
|
|
19
19
|
import { dockerCli } from "./docker-exec";
|
|
20
|
+
import { inspectTunnelContainer } from "./tunnel-runtime";
|
|
20
21
|
|
|
21
22
|
/** Port the proxy listens on inside the sidecar (published to a random host port). */
|
|
22
23
|
const INNER_PORT = 9000;
|
|
23
24
|
const LABEL = "com.runuai.preview-sidecar.task";
|
|
25
|
+
const TARGET_LABEL = "com.runuai.preview-sidecar.target";
|
|
24
26
|
|
|
25
27
|
/** (taskId,name,containerPort) -> published 127.0.0.1 host port of a live sidecar. */
|
|
26
28
|
const cache = new Map<string, number>();
|
|
@@ -135,13 +137,18 @@ async function imageOf(appContainer: string): Promise<string | null> {
|
|
|
135
137
|
return r.status === 0 && r.stdout.trim() ? r.stdout.trim() : null;
|
|
136
138
|
}
|
|
137
139
|
|
|
138
|
-
/**
|
|
140
|
+
/** Live Docker proof -> the published 127.0.0.1 host port and labels, or null. */
|
|
141
|
+
async function publishedSidecar(
|
|
142
|
+
name: string,
|
|
143
|
+
): Promise<{ port: number; labels: Record<string, string> } | null> {
|
|
144
|
+
const proof = await inspectTunnelContainer(name, INNER_PORT);
|
|
145
|
+
return proof.kind === "running" && proof.published?.host === "127.0.0.1"
|
|
146
|
+
? { port: proof.published.port, labels: proof.labels }
|
|
147
|
+
: null;
|
|
148
|
+
}
|
|
149
|
+
|
|
139
150
|
async function publishedPort(name: string): Promise<number | null> {
|
|
140
|
-
|
|
141
|
-
timeoutMs: 5_000,
|
|
142
|
-
});
|
|
143
|
-
const m = r.stdout.match(/127\.0\.0\.1:(\d+)/);
|
|
144
|
-
return r.status === 0 && m ? Number(m[1]) : null;
|
|
151
|
+
return (await publishedSidecar(name))?.port ?? null;
|
|
145
152
|
}
|
|
146
153
|
|
|
147
154
|
async function createSidecar(args: {
|
|
@@ -152,6 +159,7 @@ async function createSidecar(args: {
|
|
|
152
159
|
}): Promise<number | null> {
|
|
153
160
|
const name = sidecarName(args.taskId, args.name);
|
|
154
161
|
const appContainer = `${args.composeProject}-app-1`;
|
|
162
|
+
const target = `${appContainer}:${args.containerPort}`;
|
|
155
163
|
|
|
156
164
|
// Reuse a still-running sidecar from a previous host process (--rm keeps it up
|
|
157
165
|
// across a host restart; the in-memory cache was cleared). `docker port` is an
|
|
@@ -163,9 +171,20 @@ async function createSidecar(args: {
|
|
|
163
171
|
// sidecar serves `socket hang up` forever: the recovery path invalidates the
|
|
164
172
|
// CACHE on a failed connect, then lands right back here and returns the same
|
|
165
173
|
// corpse. Nothing could break the cycle short of removing it by hand.
|
|
166
|
-
const existing = await
|
|
174
|
+
const existing = await publishedSidecar(name);
|
|
167
175
|
if (existing !== null) {
|
|
168
|
-
|
|
176
|
+
// The Docker name is stable per (task, preview name), while a task-scoped
|
|
177
|
+
// preview may later point that name at another container port. The
|
|
178
|
+
// process-local cache key carries the port, but it vanishes on host
|
|
179
|
+
// restart; without a durable target label a healthy old proxy would be
|
|
180
|
+
// reused and silently route the authenticated request to the wrong port.
|
|
181
|
+
// Legacy unlabeled sidecars rebuild once.
|
|
182
|
+
if (
|
|
183
|
+
existing.labels[TARGET_LABEL] === target &&
|
|
184
|
+
(await probeSidecar(existing.port))
|
|
185
|
+
) {
|
|
186
|
+
return existing.port;
|
|
187
|
+
}
|
|
169
188
|
await dockerCli(["rm", "-f", name], { timeoutMs: 10_000 });
|
|
170
189
|
}
|
|
171
190
|
|
|
@@ -179,6 +198,7 @@ async function createSidecar(args: {
|
|
|
179
198
|
"--name", name,
|
|
180
199
|
"--network", `${args.composeProject}_default`,
|
|
181
200
|
"--label", `${LABEL}=${args.taskId}`,
|
|
201
|
+
"--label", `${TARGET_LABEL}=${target}`,
|
|
182
202
|
"-p", `127.0.0.1::${INNER_PORT}`,
|
|
183
203
|
"--entrypoint", "node",
|
|
184
204
|
image,
|
|
@@ -224,7 +244,31 @@ export async function ensurePreviewSidecar(args: {
|
|
|
224
244
|
}): Promise<number | null> {
|
|
225
245
|
const key = cacheKey(args.taskId, args.name, args.containerPort);
|
|
226
246
|
const cached = cache.get(key);
|
|
227
|
-
if (cached !== undefined)
|
|
247
|
+
if (cached !== undefined) {
|
|
248
|
+
const current = await publishedSidecar(sidecarName(args.taskId, args.name));
|
|
249
|
+
const expectedTarget =
|
|
250
|
+
`${args.composeProject}-app-1:${args.containerPort}`;
|
|
251
|
+
const app =
|
|
252
|
+
current?.port === cached &&
|
|
253
|
+
current.labels[TARGET_LABEL] === expectedTarget
|
|
254
|
+
? await inspectTunnelContainer(
|
|
255
|
+
`${args.composeProject}-app-1`,
|
|
256
|
+
args.containerPort,
|
|
257
|
+
)
|
|
258
|
+
: null;
|
|
259
|
+
// The sidecar's PID is the proxy itself, and it resolves the app by stable
|
|
260
|
+
// Compose DNS name for each connection. Proving both exact containers are
|
|
261
|
+
// running avoids the old 150ms socket-settle penalty on every browser asset
|
|
262
|
+
// while still rejecting a localhost port inherited after daemon restart.
|
|
263
|
+
if (
|
|
264
|
+
current?.port === cached &&
|
|
265
|
+
current.labels[TARGET_LABEL] === expectedTarget &&
|
|
266
|
+
app?.kind === "running"
|
|
267
|
+
) {
|
|
268
|
+
return cached;
|
|
269
|
+
}
|
|
270
|
+
cache.delete(key);
|
|
271
|
+
}
|
|
228
272
|
|
|
229
273
|
let pending = inflight.get(key);
|
|
230
274
|
if (!pending) {
|