@runuai/host 0.9.149 → 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.
Files changed (107) hide show
  1. package/db/migrations/0027_cloud_credential_foundation.sql +51 -0
  2. package/db/migrations/0028_leased_engine_runtimes.sql +11 -0
  3. package/db/migrations/meta/_journal.json +14 -0
  4. package/db/schema.ts +188 -0
  5. package/lib/agent-cli.ts +11 -13
  6. package/lib/agent.ts +177 -7
  7. package/lib/agents/durable-proc.ts +56 -44
  8. package/lib/agents/registry.ts +19 -3
  9. package/lib/agents/session-state.ts +23 -10
  10. package/lib/agents/transport.ts +101 -69
  11. package/lib/apple-one-off.ts +277 -0
  12. package/lib/apple-runtime-recycle.ts +4 -3
  13. package/lib/attachments.ts +19 -17
  14. package/lib/capture-flow.ts +319 -0
  15. package/lib/cloud-credential-cleanup-adapter.ts +123 -0
  16. package/lib/cloud-credential-host.ts +512 -0
  17. package/lib/cloud-credential-leases.ts +2544 -0
  18. package/lib/cloud-credential-runtime.ts +1035 -0
  19. package/lib/codex-auth.ts +21 -1
  20. package/lib/container-runtime.ts +76 -0
  21. package/lib/credential-cleanup-inventory.ts +405 -0
  22. package/lib/credential-consumers/engine-anchor.ts +1876 -0
  23. package/lib/credential-consumers/engines.ts +773 -0
  24. package/lib/credential-consumers/github.ts +594 -0
  25. package/lib/credential-consumers/mcp.ts +384 -0
  26. package/lib/credential-consumers/task-files.ts +127 -0
  27. package/lib/credential-store-pickup.ts +15 -2
  28. package/lib/credential-store.ts +361 -33
  29. package/lib/credentials-activation-authority.ts +546 -0
  30. package/lib/credentials-purge.ts +1006 -0
  31. package/lib/db.ts +11 -0
  32. package/lib/docker-exec.ts +3 -1
  33. package/lib/engine-accounts.ts +42 -32
  34. package/lib/engine-connect.ts +47 -2
  35. package/lib/engine-credential-env.ts +50 -0
  36. package/lib/engine-login.ts +83 -1
  37. package/lib/env-file.ts +62 -8
  38. package/lib/env.ts +5 -0
  39. package/lib/fs-aliases.ts +49 -0
  40. package/lib/git-clone-credentials.ts +334 -0
  41. package/lib/git-diff.ts +219 -177
  42. package/lib/git-identity.ts +59 -14
  43. package/lib/github-origin.ts +28 -0
  44. package/lib/github-tokens.ts +56 -21
  45. package/lib/host-env.ts +17 -4
  46. package/lib/launch-mode.ts +25 -0
  47. package/lib/legacy-runtime-retirement.ts +388 -0
  48. package/lib/machine-exec.ts +14 -3
  49. package/lib/machine-provider-aws.ts +50 -8
  50. package/lib/machine-provider-local.ts +4 -0
  51. package/lib/machine-provider.ts +4 -0
  52. package/lib/managed-operation-drain.ts +8 -0
  53. package/lib/managed-runtime.ts +371 -7
  54. package/lib/mcp-capture.ts +860 -0
  55. package/lib/mcp-connections.ts +8 -1
  56. package/lib/mcp-gateway.ts +168 -10
  57. package/lib/obs.ts +2 -6
  58. package/lib/orchestrator.ts +1847 -236
  59. package/lib/person-capture.ts +327 -0
  60. package/lib/project-env-legacy-tags.ts +130 -0
  61. package/lib/project-env-task-replica.ts +1752 -0
  62. package/lib/runner-boot.ts +10 -0
  63. package/lib/runtime-activation-tail.ts +50 -3
  64. package/lib/runtime-archive.ts +68 -1
  65. package/lib/runtime-reconnect.ts +86 -0
  66. package/lib/runtime-state.ts +429 -13
  67. package/lib/safe-http.ts +364 -0
  68. package/lib/secrets-proxy/task-trust.ts +34 -3
  69. package/lib/sidecar-resume.ts +18 -5
  70. package/lib/skills.ts +47 -8
  71. package/lib/standard-image.ts +157 -103
  72. package/lib/stopped-task-status-queue.ts +68 -10
  73. package/lib/task-credential-cleanup.ts +525 -0
  74. package/lib/task-diff-sandbox.ts +464 -0
  75. package/lib/task-diff.ts +66 -163
  76. package/lib/task-env-source.ts +68 -14
  77. package/lib/task-environment/anchor.ts +31 -0
  78. package/lib/task-environment/apple-container.ts +69 -28
  79. package/lib/task-environment/docker.ts +101 -20
  80. package/lib/task-environment/machine-environment.ts +61 -0
  81. package/lib/task-environment/machine-task-up.ts +459 -96
  82. package/lib/task-environment/machine.ts +101 -11
  83. package/lib/task-environment/self.ts +108 -50
  84. package/lib/task-environment/types.ts +89 -5
  85. package/lib/task-environment/workspace-files.ts +623 -25
  86. package/lib/task-environment/workspace-runtime.fixture.ts +50 -0
  87. package/lib/task-gateway-recovery.ts +4 -1
  88. package/lib/task-gateway-state.ts +15 -0
  89. package/lib/task-machine-swap-safety.ts +729 -0
  90. package/lib/token-broker-adopt.ts +344 -0
  91. package/lib/token-broker-lambda.ts +56 -2
  92. package/lib/token-broker-local.ts +28 -4
  93. package/lib/token-broker-revision.ts +310 -0
  94. package/lib/token-broker-ssm.ts +368 -28
  95. package/lib/token-lanes/openai-oauth.ts +7 -3
  96. package/lib/token-lanes/xai-oauth.ts +7 -3
  97. package/lib/transcript.ts +9 -5
  98. package/package.json +6 -2
  99. package/scripts/agent/task-up.sh +242 -100
  100. package/src/cloud-credentials.ts +2399 -0
  101. package/src/event-outbox.ts +8 -6
  102. package/src/index.ts +1386 -875
  103. package/src/main.ts +1062 -140
  104. package/src/outbound-frame.ts +31 -0
  105. package/src/project-env-policy.ts +125 -10
  106. package/src/protocol.ts +699 -23
  107. package/src/ui/server.ts +48 -10
@@ -0,0 +1,31 @@
1
+ /**
2
+ * What the runner may send the cloud. The cloud's bridge closes a runner's
3
+ * connection on any frame past its ceiling (100 MiB, lib/host-bridge.ts), so
4
+ * a frame that would serialize past it is never sent: a command's result is
5
+ * replaced by its failure, and anything else is dropped. Either way the
6
+ * connection, and every other task's traffic on it, stays open.
7
+ */
8
+ import { HostErrorCode, type HostToCloud } from "./protocol";
9
+
10
+ /** Under the cloud's ceiling, with room to spare. */
11
+ export const MAX_OUTBOUND_FRAME_BYTES = 96 * 1024 * 1024;
12
+
13
+ /** The serialized frame to send for `frame`: itself, a command result's
14
+ * failure in its place, or null when nothing of it can be sent. */
15
+ export function outboundFrameJson(frame: HostToCloud): string | null {
16
+ const json = JSON.stringify(frame);
17
+ if (Buffer.byteLength(json, "utf8") <= MAX_OUTBOUND_FRAME_BYTES) return json;
18
+ if (frame.kind === "result") {
19
+ return JSON.stringify({
20
+ kind: "result",
21
+ commandId: frame.commandId,
22
+ result: {
23
+ ok: false,
24
+ code: HostErrorCode.Internal,
25
+ message: "the result is too large to send",
26
+ },
27
+ } satisfies HostToCloud);
28
+ }
29
+ console.warn(`[host] dropped an outbound ${frame.kind} frame past the bridge's size limit`);
30
+ return null;
31
+ }
@@ -32,9 +32,11 @@
32
32
 
33
33
  import {
34
34
  MAX_PROJECT_ENV_PROXY_DOMAINS,
35
+ isDeclaredProjectEnvBinding,
35
36
  isProjectEnvBinding,
36
37
  isProjectEnvSchemaDeclaration,
37
38
  type ProjectEnvBinding,
39
+ type ProjectEnvPlaceholderShape,
38
40
  type ProjectEnvSchemaDeclaration,
39
41
  } from "./protocol";
40
42
 
@@ -49,11 +51,17 @@ import {
49
51
  * pin each retained epoch's results on a fixed set of inputs: a tripwire,
50
52
  * not a proof.
51
53
  */
52
- export const PROJECT_ENV_POLICY_EPOCH = 1;
54
+ export const PROJECT_ENV_POLICY_EPOCH = 2;
53
55
 
54
56
  /** Every policy epoch this build derives under, oldest first. A runner
55
- * advertises this set; the cloud derives under the newest it shares. */
56
- export const PROJECT_ENV_POLICY_EPOCHS: readonly number[] = [1];
57
+ * advertises this set; the cloud derives under the newest it shares.
58
+ *
59
+ * - 1: ADR-153.
60
+ * - 2: ADR-154 §9, a key the owner declared proxied in Settings (a `proxy`
61
+ * binding with `declared`): the repository can only narrow it. Every other
62
+ * binding derives exactly as under 1, so it is stored under 1
63
+ * (`projectEnvBindingEpoch`) and needs no upgrade. */
64
+ export const PROJECT_ENV_POLICY_EPOCHS: readonly number[] = [1, 2];
57
65
 
58
66
  /** What one task gets for a key. */
59
67
  export type ProjectEnvDecision =
@@ -141,13 +149,15 @@ const deliversValue = (binding: ProjectEnvBinding | null): boolean =>
141
149
  binding === null || binding.kind === "passthrough";
142
150
 
143
151
  /**
144
- * What a task gets for one key, what its declaration proposes beyond the
145
- * binding, and why a wider ask cannot be proposed if so. `binding` is null
146
- * for a row the owner never approved. Both arguments are checked: see the
147
- * file's header.
152
+ * What a task gets for one key under epoch 1 (ADR-153), frozen: what its
153
+ * declaration proposes beyond the binding, and why a wider ask cannot be
154
+ * proposed if so. A binding declared in Settings did not exist under it, and
155
+ * is one it cannot accept.
148
156
  */
149
- export function projectEnvKeyPolicy(schemaInput: unknown, bindingInput: unknown): ProjectEnvKeyPolicy {
150
- if (bindingInput !== null && !isProjectEnvBinding(bindingInput)) return policy(withhold("binding_invalid"));
157
+ function projectEnvKeyPolicyV1(schemaInput: unknown, bindingInput: unknown): ProjectEnvKeyPolicy {
158
+ if (bindingInput !== null && (!isProjectEnvBinding(bindingInput) || isDeclaredProjectEnvBinding(bindingInput))) {
159
+ return policy(withhold("binding_invalid"));
160
+ }
151
161
  const binding = bindingInput as ProjectEnvBinding | null;
152
162
  const schema = evidenceOf(schemaInput);
153
163
 
@@ -198,6 +208,66 @@ export function projectEnvKeyPolicy(schemaInput: unknown, bindingInput: unknown)
198
208
  }
199
209
  }
200
210
 
211
+ /**
212
+ * ADR-154 §9: a key the owner declared proxied in Settings. Declaring was the
213
+ * owner's approval of exactly these domains, which the repository's schema
214
+ * can only narrow:
215
+ * - unreadable, undeclared, plain or `passthrough`: proxied to the declared
216
+ * domains, and nothing proposed (the repository never asks to deliver it);
217
+ * - `@proxy=omit`, or an unsupported directive: withheld;
218
+ * - `@proxy` naming some of the declared domains: proxied to those; any it
219
+ * names beyond them are a proposal (still declared), as in ADR-153, or
220
+ * blocked past the domain limit.
221
+ */
222
+ function declaredKeyPolicy(
223
+ schema: ProjectEnvSchemaEvidence,
224
+ binding: Extract<ProjectEnvBinding, { kind: "proxy" }> & { declared: { placeholder: ProjectEnvPlaceholderShape | null } },
225
+ ): ProjectEnvKeyPolicy {
226
+ const settings = sorted(binding.domains);
227
+ const asDeclared: ProjectEnvDecision = { kind: "proxy", domains: settings };
228
+ if (schema.status === "unavailable") return policy(asDeclared);
229
+ const directive = schema.declaration?.directive ?? { kind: "none" as const };
230
+ switch (directive.kind) {
231
+ case "none":
232
+ case "passthrough":
233
+ return policy(asDeclared);
234
+ case "omit":
235
+ return policy(withhold("repository_omits"));
236
+ case "unsupported":
237
+ return policy(withhold(directive.reason));
238
+ case "proxy": {
239
+ const declared = sorted(directive.domains);
240
+ const allowed = declared.filter((domain) => settings.includes(domain));
241
+ const decision: ProjectEnvDecision =
242
+ allowed.length > 0 ? { kind: "proxy", domains: allowed } : withhold("awaiting_approval");
243
+ if (allowed.length === declared.length) return policy(decision);
244
+ const union = sorted([...settings, ...declared]);
245
+ if (union.length > MAX_PROJECT_ENV_PROXY_DOMAINS) {
246
+ return policy(allowed.length > 0 ? decision : withhold("too_many_domains"), null, "too_many_domains");
247
+ }
248
+ return policy(decision, { kind: "proxy", domains: union, declared: { placeholder: binding.declared.placeholder } });
249
+ }
250
+ }
251
+ }
252
+
253
+ /**
254
+ * What a task gets for one key under the newest epoch (2), what its
255
+ * declaration proposes beyond the binding, and why a wider ask cannot be
256
+ * proposed if so. `binding` is null for a row the owner never approved. Both
257
+ * arguments are checked: see the file's header. A binding declared in
258
+ * Settings follows `declaredKeyPolicy`; every other derives as under epoch 1.
259
+ */
260
+ export function projectEnvKeyPolicy(schemaInput: unknown, bindingInput: unknown): ProjectEnvKeyPolicy {
261
+ if (bindingInput !== null && !isProjectEnvBinding(bindingInput)) return policy(withhold("binding_invalid"));
262
+ if (isDeclaredProjectEnvBinding(bindingInput as ProjectEnvBinding | null)) {
263
+ return declaredKeyPolicy(
264
+ evidenceOf(schemaInput),
265
+ bindingInput as Parameters<typeof declaredKeyPolicy>[1],
266
+ );
267
+ }
268
+ return projectEnvKeyPolicyV1(schemaInput, bindingInput);
269
+ }
270
+
201
271
  /**
202
272
  * The binding a value is stored with when its row has none yet (ADR-153 §4:
203
273
  * "a value set in settings is stored atomically with the policy the owner
@@ -239,6 +309,8 @@ export function initialProjectEnvBinding(schemaInput: unknown): ProjectEnvBindin
239
309
  export function projectEnvKeyPolicyAt(epoch: unknown, schemaInput: unknown, bindingInput: unknown): ProjectEnvKeyPolicy {
240
310
  switch (epoch) {
241
311
  case 1:
312
+ return projectEnvKeyPolicyV1(schemaInput, bindingInput);
313
+ case 2:
242
314
  return projectEnvKeyPolicy(schemaInput, bindingInput);
243
315
  default:
244
316
  return policy(withhold("policy_epoch_unknown"));
@@ -246,16 +318,59 @@ export function projectEnvKeyPolicyAt(epoch: unknown, schemaInput: unknown, bind
246
318
  }
247
319
 
248
320
  /** The binding a first save stores under a given epoch; withheld under an
249
- * epoch this build does not know. */
321
+ * epoch this build does not know. Epoch 2 stores what 1 does: a Settings
322
+ * declaration is the owner's own act, never a first save's. */
250
323
  export function initialProjectEnvBindingAt(epoch: unknown, schemaInput: unknown): ProjectEnvBinding | null {
251
324
  switch (epoch) {
252
325
  case 1:
326
+ case 2:
253
327
  return initialProjectEnvBinding(schemaInput);
254
328
  default:
255
329
  return { kind: "withhold", reason: "policy_epoch_unknown" };
256
330
  }
257
331
  }
258
332
 
333
+ /**
334
+ * The placeholder shape a proxied key's task gets, under its binding's
335
+ * epoch: the repository's `@placeholder` when its schema declares the key
336
+ * proxied with one; under epoch 2 a Settings declaration's shape next; null
337
+ * otherwise (the default shape). Only meaningful for a key the policy
338
+ * proxies; checked like the policy's own inputs.
339
+ */
340
+ export function projectEnvPlaceholderAt(
341
+ epoch: unknown,
342
+ schemaInput: unknown,
343
+ bindingInput: unknown,
344
+ ): ProjectEnvPlaceholderShape | null {
345
+ if (epoch !== 1 && epoch !== 2) return null;
346
+ const schema = evidenceOf(schemaInput);
347
+ const fromSchema =
348
+ schema.status === "resolved" && schema.declaration?.directive.kind === "proxy"
349
+ ? (schema.declaration.placeholder ?? null)
350
+ : null;
351
+ if (fromSchema !== null || epoch === 1) return fromSchema;
352
+ const binding = bindingInput !== null && isProjectEnvBinding(bindingInput) ? bindingInput : null;
353
+ return isDeclaredProjectEnvBinding(binding) ? binding.declared.placeholder : null;
354
+ }
355
+
356
+ /**
357
+ * The epoch to store a binding under: the lowest this build knows whose
358
+ * derivation for it is the newest's, never below `floor` (a record's epoch
359
+ * only moves up). A declared binding needs 2; every other means under 1 what
360
+ * it means under 2, so it stays readable by runners that know only 1.
361
+ */
362
+ export function projectEnvBindingEpoch(binding: ProjectEnvBinding | null, floor = 1): number {
363
+ return Math.max(isDeclaredProjectEnvBinding(binding) ? 2 : 1, floor);
364
+ }
365
+
366
+ /** Whether moving a binding from one epoch to a newer one changes what any
367
+ * task would get: only then is an upgrade offered for the owner's Approve. */
368
+ export function projectEnvEpochUpgradeChanges(fromEpoch: number, toEpoch: number, binding: unknown): boolean {
369
+ if (fromEpoch >= toEpoch) return false;
370
+ // Epochs 1 and 2 derive the same for every binding valid under 1.
371
+ return !(fromEpoch === 1 && toEpoch === 2 && !(isProjectEnvBinding(binding) && isDeclaredProjectEnvBinding(binding)));
372
+ }
373
+
259
374
  /** The most policy epochs a runner may advertise. */
260
375
  export const MAX_ADVERTISED_PROJECT_ENV_POLICY_EPOCHS = 64;
261
376