@loucompanion/forge-bridge 0.1.3-dev.d46a8e73d03d → 0.1.3-dev.e7b62d8fdd33

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 (145) hide show
  1. package/README.md +83 -0
  2. package/dist/bridge/bridge.base.d.ts +4 -1
  3. package/dist/bridge/bridge.service.d.ts +55 -3
  4. package/dist/bridge/bridge.service.js +834 -87
  5. package/dist/bridge/bridge.types.d.ts +89 -1
  6. package/dist/bridge/runner-host-capabilities.d.ts +15 -0
  7. package/dist/bridge/runner-host-capabilities.js +93 -0
  8. package/dist/cleanup/cleanup.service.d.ts +14 -2
  9. package/dist/cleanup/cleanup.service.js +496 -3
  10. package/dist/cleanup/cleanup.types.d.ts +10 -0
  11. package/dist/cleanup/index.d.ts +1 -1
  12. package/dist/cleanup/index.js +1 -1
  13. package/dist/cleanup/internals.d.ts +2 -2
  14. package/dist/cleanup/internals.js +1 -1
  15. package/dist/cli/cli.help.js +37 -3
  16. package/dist/cli/cli.service.d.ts +33 -2
  17. package/dist/cli/cli.service.js +209 -27
  18. package/dist/cli/local-config.d.ts +5 -0
  19. package/dist/cli/local-config.js +45 -1
  20. package/dist/runtime/aspnet-runtime-prebuild.d.ts +36 -0
  21. package/dist/runtime/aspnet-runtime-prebuild.js +340 -0
  22. package/dist/runtime/attempt-node-runtime-launcher.d.ts +17 -0
  23. package/dist/runtime/attempt-node-runtime-launcher.js +105 -0
  24. package/dist/runtime/attempt-process-supervisor-registry.d.ts +20 -0
  25. package/dist/runtime/attempt-process-supervisor-registry.js +64 -0
  26. package/dist/runtime/attempt-process-supervisor.d.ts +97 -0
  27. package/dist/runtime/attempt-process-supervisor.js +386 -0
  28. package/dist/runtime/docker-engine-probe.d.ts +83 -0
  29. package/dist/runtime/docker-engine-probe.js +300 -0
  30. package/dist/runtime/generated-output-reset.d.ts +10 -0
  31. package/dist/runtime/generated-output-reset.js +103 -0
  32. package/dist/runtime/host-listener-inspector.d.ts +46 -0
  33. package/dist/runtime/host-listener-inspector.js +349 -0
  34. package/dist/runtime/host-port-broker.d.ts +76 -0
  35. package/dist/runtime/host-port-broker.js +333 -0
  36. package/dist/runtime/host-runtime-contract.d.ts +47 -0
  37. package/dist/runtime/host-runtime-contract.js +700 -0
  38. package/dist/runtime/host-runtime-lease.d.ts +197 -0
  39. package/dist/runtime/host-runtime-lease.js +2203 -0
  40. package/dist/runtime/host-runtime-promotion.d.ts +23 -0
  41. package/dist/runtime/host-runtime-promotion.js +159 -0
  42. package/dist/runtime/memory-capacity.d.ts +68 -0
  43. package/dist/runtime/memory-capacity.js +121 -0
  44. package/dist/runtime/node-host-runtime-adapter.d.ts +54 -0
  45. package/dist/runtime/node-host-runtime-adapter.js +284 -0
  46. package/dist/runtime/playwright-host-runtime-adapter.d.ts +21 -0
  47. package/dist/runtime/playwright-host-runtime-adapter.js +231 -0
  48. package/dist/runtime/runtime-isolation-lease.d.ts +67 -0
  49. package/dist/runtime/runtime-isolation-lease.js +158 -0
  50. package/dist/runtime/workspace-resource-estimator.d.ts +17 -0
  51. package/dist/runtime/workspace-resource-estimator.js +174 -0
  52. package/dist/sandbox/preflight.d.ts +45 -1
  53. package/dist/sandbox/preflight.js +299 -34
  54. package/dist/sandbox/process.js +125 -40
  55. package/dist/sandbox/repository-lock.js +41 -3
  56. package/dist/sandbox/runtime.d.ts +66 -3
  57. package/dist/sandbox/runtime.js +670 -105
  58. package/dist/sandbox/sandbox.types.d.ts +10 -0
  59. package/dist/sandbox/smoke.d.ts +76 -0
  60. package/dist/sandbox/smoke.js +380 -0
  61. package/dist/sandbox/worker-supervisor.js +1 -1
  62. package/dist/sandbox/worker.js +2 -5
  63. package/dist/sandbox/workspace.service.d.ts +1 -0
  64. package/dist/sandbox/workspace.service.js +28 -5
  65. package/dist/session/managed-attempt-tools.d.ts +21 -0
  66. package/dist/session/managed-attempt-tools.js +912 -0
  67. package/dist/session/managed-build-coordinator.d.ts +5 -0
  68. package/dist/session/managed-build-coordinator.js +105 -0
  69. package/dist/session/managed-build-receipt.d.ts +21 -0
  70. package/dist/session/managed-build-receipt.js +335 -0
  71. package/dist/session/phase-completion.artifacts.d.ts +17 -0
  72. package/dist/session/phase-completion.artifacts.js +233 -24
  73. package/dist/session/phase-completion.d.ts +12 -2
  74. package/dist/session/phase-completion.helpers.d.ts +5 -0
  75. package/dist/session/phase-completion.helpers.js +51 -10
  76. package/dist/session/phase-completion.js +14 -3
  77. package/dist/session/phase-completion.prompts.d.ts +3 -3
  78. package/dist/session/phase-completion.prompts.js +24 -8
  79. package/dist/session/phase-completion.runtime.d.ts +13 -1
  80. package/dist/session/phase-completion.runtime.js +189 -8
  81. package/dist/session/phase-completion.schemas.js +117 -4
  82. package/dist/session/phase-completion.validation.d.ts +4 -1
  83. package/dist/session/phase-completion.validation.js +153 -22
  84. package/dist/session/pre-publication-validation.d.ts +46 -0
  85. package/dist/session/pre-publication-validation.js +208 -0
  86. package/dist/session/provider-cli/ci-repair-readiness.d.ts +16 -0
  87. package/dist/session/provider-cli/ci-repair-readiness.js +110 -0
  88. package/dist/session/provider-cli/provider-cli.artifacts.d.ts +3 -2
  89. package/dist/session/provider-cli/provider-cli.artifacts.js +65 -7
  90. package/dist/session/provider-cli/provider-cli.deterministic.js +49 -1
  91. package/dist/session/provider-cli/provider-cli.process.d.ts +25 -0
  92. package/dist/session/provider-cli/provider-cli.process.js +463 -34
  93. package/dist/session/provider-cli/provider-cli.prompts.d.ts +4 -1
  94. package/dist/session/provider-cli/provider-cli.prompts.js +108 -25
  95. package/dist/session/provider-cli/provider-cli.qa-sidecars.js +1 -0
  96. package/dist/session/provider-cli/provider-cli.repair-epoch.d.ts +6 -0
  97. package/dist/session/provider-cli/provider-cli.repair-epoch.js +11 -0
  98. package/dist/session/provider-cli/provider-cli.runtime.d.ts +1 -1
  99. package/dist/session/provider-cli/provider-cli.runtime.js +6 -3
  100. package/dist/session/provider-cli/provider-cli.service.d.ts +22 -2
  101. package/dist/session/provider-cli/provider-cli.service.js +524 -100
  102. package/dist/session/provider-cli/provider-cli.types.d.ts +5 -0
  103. package/dist/session/provider-cli/provider-output-state.d.ts +2 -0
  104. package/dist/session/provider-cli/provider-output-state.js +91 -16
  105. package/dist/session/provider-cli/provider-usage.d.ts +7 -0
  106. package/dist/session/provider-cli/provider-usage.js +28 -5
  107. package/dist/session/session-redaction.d.ts +3 -0
  108. package/dist/session/session-redaction.js +38 -0
  109. package/dist/session/session.base.d.ts +6 -1
  110. package/dist/session/session.service.d.ts +8 -2
  111. package/dist/session/session.service.js +522 -41
  112. package/dist/session/session.types.d.ts +72 -0
  113. package/dist/session/session.types.js +74 -3
  114. package/dist/shared/format/format-bytes.d.ts +1 -0
  115. package/dist/shared/format/format-bytes.js +9 -0
  116. package/dist/shared/path/path.d.ts +1 -0
  117. package/dist/shared/path/path.js +21 -1
  118. package/dist/shared/process/dotnet-toolchain.d.ts +14 -0
  119. package/dist/shared/process/dotnet-toolchain.js +179 -0
  120. package/dist/shared/process/host-process-recovery.d.ts +12 -0
  121. package/dist/shared/process/host-process-recovery.js +78 -0
  122. package/dist/shared/process/host-process-supervisor.d.ts +59 -0
  123. package/dist/shared/process/host-process-supervisor.js +330 -0
  124. package/dist/shared/process/process.d.ts +1 -0
  125. package/dist/shared/process/process.js +1 -0
  126. package/dist/shared/redaction/redaction.js +12 -2
  127. package/dist/version.d.ts +1 -1
  128. package/dist/version.js +1 -1
  129. package/dist/worktree/artifact-injector.d.ts +3 -2
  130. package/dist/worktree/artifact-injector.js +43 -4
  131. package/dist/worktree/dependency-warmer.d.ts +28 -1
  132. package/dist/worktree/dependency-warmer.js +308 -9
  133. package/dist/worktree/index.d.ts +2 -1
  134. package/dist/worktree/index.js +1 -0
  135. package/dist/worktree/prior-phase-artifact-hydrator.d.ts +2 -0
  136. package/dist/worktree/prior-phase-artifact-hydrator.js +136 -0
  137. package/dist/worktree/worktree-paths.d.ts +4 -0
  138. package/dist/worktree/worktree-paths.js +30 -0
  139. package/dist/worktree/worktree.base.d.ts +3 -0
  140. package/dist/worktree/worktree.service.d.ts +13 -2
  141. package/dist/worktree/worktree.service.js +238 -47
  142. package/dist/worktree/worktree.types.d.ts +5 -1
  143. package/package.json +5 -3
  144. package/runtime/windows-job-supervisor.ps1 +444 -0
  145. package/runtime/windows-listener-owner.ps1 +33 -0
@@ -1,5 +1,13 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { StringDecoder } from "node:string_decoder";
3
+ const terminationSigkillDelayMs = 5_000;
4
+ const forcedCloseSettleDelayMs = 5_000;
5
+ const expectedStdinCloseErrorCodes = new Set(["EPIPE", "ECONNRESET", "ERR_STREAM_DESTROYED"]);
6
+ function isExpectedStdinCloseError(error) {
7
+ return "code" in error
8
+ && typeof error.code === "string"
9
+ && expectedStdinCloseErrorCodes.has(error.code);
10
+ }
3
11
  export async function runSandboxProcess(request) {
4
12
  const limit = Math.max(1024, request.maxOutputBytes ?? 1024 * 1024);
5
13
  return await new Promise((resolve, reject) => {
@@ -14,10 +22,15 @@ export async function runSandboxProcess(request) {
14
22
  let stderr = Buffer.alloc(0);
15
23
  let truncated = false;
16
24
  let settled = false;
25
+ let terminating = false;
26
+ let discardStdoutLineCallbacks = false;
17
27
  let stdoutText = "";
18
28
  const stdoutDecoder = new StringDecoder("utf8");
19
29
  let stdoutLineChain = Promise.resolve();
20
30
  let stdoutLineError = null;
31
+ let timeout = null;
32
+ let sigkillTimer = null;
33
+ let forcedSettleTimer = null;
21
34
  const append = (current, chunk) => {
22
35
  if (current.length >= limit) {
23
36
  truncated = true;
@@ -31,9 +44,87 @@ export async function runSandboxProcess(request) {
31
44
  }
32
45
  return Buffer.concat([current, chunk.subarray(0, remaining)]);
33
46
  };
34
- child.stdout.on("data", (chunk) => {
47
+ const appendStderrLine = (line) => {
48
+ stderr = append(stderr, Buffer.from(`\n${line}\n`));
49
+ };
50
+ const cleanup = () => {
51
+ if (timeout)
52
+ clearTimeout(timeout);
53
+ if (sigkillTimer)
54
+ clearTimeout(sigkillTimer);
55
+ if (forcedSettleTimer)
56
+ clearTimeout(forcedSettleTimer);
57
+ child.stdout.removeListener("data", onStdoutData);
58
+ child.stderr.removeListener("data", onStderrData);
59
+ child.removeListener("error", onProcessError);
60
+ child.removeListener("close", onProcessClose);
61
+ request.signal?.removeEventListener("abort", abort);
62
+ };
63
+ const settle = async (code, force) => {
64
+ if (settled)
65
+ return;
66
+ settled = true;
67
+ discardStdoutLineCallbacks = force;
68
+ cleanup();
69
+ if (stdoutLineError) {
70
+ reject(stdoutLineError);
71
+ return;
72
+ }
73
+ if (!force) {
74
+ if (request.onStdoutLine)
75
+ stdoutText += stdoutDecoder.end();
76
+ if (request.onStdoutLine && stdoutText) {
77
+ stdoutLineChain = stdoutLineChain.then(() => request.onStdoutLine(stdoutText));
78
+ }
79
+ await stdoutLineChain.catch(error => { stdoutLineError ??= error; });
80
+ if (stdoutLineError) {
81
+ reject(stdoutLineError);
82
+ return;
83
+ }
84
+ }
85
+ resolve({
86
+ exitCode: code ?? 1,
87
+ stdout: stdout.toString("utf8"),
88
+ stderr: stderr.toString("utf8"),
89
+ truncated
90
+ });
91
+ };
92
+ const forceSettle = (reason) => {
93
+ if (settled)
94
+ return;
95
+ appendStderrLine(reason);
96
+ void settle(1, true);
97
+ };
98
+ const killChild = (signal) => {
99
+ if (child.exitCode !== null || child.signalCode !== null)
100
+ return;
101
+ try {
102
+ child.kill(signal);
103
+ }
104
+ catch {
105
+ // The process may have exited between timeout/abort and close. Still let the
106
+ // supervisor timers settle if close never arrives.
107
+ }
108
+ };
109
+ const terminate = (reason) => {
110
+ if (settled || terminating)
111
+ return;
112
+ terminating = true;
113
+ appendStderrLine(reason);
114
+ killChild("SIGTERM");
115
+ sigkillTimer = setTimeout(() => {
116
+ killChild("SIGKILL");
117
+ forcedSettleTimer = setTimeout(() => forceSettle("process did not close after SIGKILL; forcing supervisor settlement"), forcedCloseSettleDelayMs);
118
+ forcedSettleTimer.unref?.();
119
+ }, terminationSigkillDelayMs);
120
+ sigkillTimer.unref?.();
121
+ };
122
+ const abort = () => terminate(String(request.signal?.reason ?? "process aborted"));
123
+ const onStdoutData = (chunk) => {
124
+ if (settled)
125
+ return;
35
126
  stdout = append(stdout, chunk);
36
- if (!request.onStdoutLine)
127
+ if (!request.onStdoutLine || settled)
37
128
  return;
38
129
  stdoutText += stdoutDecoder.write(chunk);
39
130
  if (Buffer.byteLength(stdoutText, "utf8") > 1024 * 1024 && !stdoutText.includes("\n")) {
@@ -48,6 +139,8 @@ export async function runSandboxProcess(request) {
48
139
  child.stdout.pause();
49
140
  for (const line of lines) {
50
141
  stdoutLineChain = stdoutLineChain.then(async () => {
142
+ if (discardStdoutLineCallbacks)
143
+ return;
51
144
  if (Buffer.byteLength(line, "utf8") > 1024 * 1024)
52
145
  throw new Error("sandbox process emitted an oversized stdout line");
53
146
  await request.onStdoutLine(line);
@@ -62,57 +155,49 @@ export async function runSandboxProcess(request) {
62
155
  if (!settled)
63
156
  child.stdout.resume();
64
157
  });
65
- });
66
- child.stderr.on("data", (chunk) => { stderr = append(stderr, chunk); });
67
- child.on("error", (error) => {
158
+ };
159
+ const onStderrData = (chunk) => {
160
+ if (!settled)
161
+ stderr = append(stderr, chunk);
162
+ };
163
+ const onProcessError = (error) => {
68
164
  if (!settled) {
69
165
  settled = true;
166
+ cleanup();
70
167
  reject(error);
71
168
  }
72
- });
73
- const terminate = (reason) => {
74
- if (child.exitCode !== null)
169
+ };
170
+ const onStdinError = (error) => {
171
+ if (isExpectedStdinCloseError(error))
75
172
  return;
76
- child.kill("SIGTERM");
77
- setTimeout(() => child.kill("SIGKILL"), 5_000).unref?.();
78
- if (!settled) {
79
- // Completion is still resolved by close so stderr remains available.
80
- stderr = append(stderr, Buffer.from(`\n${reason}\n`));
81
- }
173
+ onProcessError(error);
82
174
  };
83
- const timeout = request.timeoutMs
175
+ const onProcessClose = (code) => {
176
+ void settle(code, false);
177
+ };
178
+ child.stdout.on("data", onStdoutData);
179
+ child.stderr.on("data", onStderrData);
180
+ child.on("error", onProcessError);
181
+ child.on("close", onProcessClose);
182
+ // Keep this listener for the lifetime of stdin. A pipe error can be emitted
183
+ // after the child close event has settled the supervisor promise.
184
+ child.stdin?.on("error", onStdinError);
185
+ timeout = request.timeoutMs
84
186
  ? setTimeout(() => terminate(`process timeout after ${request.timeoutMs}ms`), request.timeoutMs)
85
187
  : null;
86
188
  timeout?.unref?.();
87
- const abort = () => terminate(String(request.signal?.reason ?? "process aborted"));
88
189
  request.signal?.addEventListener("abort", abort, { once: true });
89
- if (request.input !== undefined) {
90
- child.stdin.end(request.input);
190
+ if (request.signal?.aborted) {
191
+ abort();
91
192
  }
92
- child.on("close", async (code) => {
93
- if (settled)
94
- return;
95
- settled = true;
96
- if (timeout)
97
- clearTimeout(timeout);
98
- request.signal?.removeEventListener("abort", abort);
99
- if (request.onStdoutLine)
100
- stdoutText += stdoutDecoder.end();
101
- if (request.onStdoutLine && stdoutText) {
102
- stdoutLineChain = stdoutLineChain.then(() => request.onStdoutLine(stdoutText));
193
+ if (request.input !== undefined) {
194
+ try {
195
+ child.stdin.end(request.input);
103
196
  }
104
- await stdoutLineChain.catch(error => { stdoutLineError ??= error; });
105
- if (stdoutLineError) {
106
- reject(stdoutLineError);
107
- return;
197
+ catch (error) {
198
+ onStdinError(error instanceof Error ? error : new Error(String(error)));
108
199
  }
109
- resolve({
110
- exitCode: code ?? 1,
111
- stdout: stdout.toString("utf8"),
112
- stderr: stderr.toString("utf8"),
113
- truncated
114
- });
115
- });
200
+ }
116
201
  });
117
202
  }
118
203
  export async function requireSandboxProcess(request) {
@@ -1,14 +1,19 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
+ import { constants as fsConstants } from "node:fs";
2
3
  import fs from "node:fs/promises";
3
4
  import path from "node:path";
5
+ import { resolvePathIdentity } from "../shared/path/path.js";
6
+ const LOCK_HEARTBEAT_INTERVAL_MS = 30_000;
7
+ const LOCK_STALE_AFTER_MS = 2 * 60_000;
4
8
  export class RepositoryCoordinatorLock {
5
9
  stateRoot;
6
10
  constructor(stateRoot) {
7
11
  this.stateRoot = stateRoot;
8
12
  }
9
13
  async withLock(repoPath, action, signal) {
10
- const resolved = path.resolve(repoPath);
11
- const key = createHash("sha256").update(resolved.toLowerCase()).digest("hex");
14
+ const resolved = await resolvePathIdentity(repoPath);
15
+ const keyInput = process.platform === "win32" ? resolved.toLowerCase() : resolved;
16
+ const key = createHash("sha256").update(keyInput).digest("hex");
12
17
  const root = path.join(this.stateRoot, "repo-locks");
13
18
  const target = path.join(root, `${key}.lock`);
14
19
  const token = randomUUID();
@@ -41,10 +46,12 @@ export class RepositoryCoordinatorLock {
41
46
  await abortableDelay(50, signal);
42
47
  }
43
48
  }
49
+ const heartbeat = startHeartbeat(target, token);
44
50
  try {
45
51
  return await action();
46
52
  }
47
53
  finally {
54
+ clearInterval(heartbeat);
48
55
  const owner = await readOwner(target);
49
56
  if (owner?.token === token)
50
57
  await fs.rm(target, { force: true });
@@ -58,7 +65,7 @@ async function staleLock(target) {
58
65
  const owner = await readOwner(target);
59
66
  if (!owner || typeof owner.pid !== "number" || !Number.isInteger(owner.pid) || owner.pid <= 0)
60
67
  return true;
61
- if (Date.now() - stat.mtimeMs > 10 * 60_000)
68
+ if (Date.now() - stat.mtimeMs >= LOCK_STALE_AFTER_MS)
62
69
  return true;
63
70
  try {
64
71
  process.kill(owner.pid, 0);
@@ -68,6 +75,37 @@ async function staleLock(target) {
68
75
  return true;
69
76
  }
70
77
  }
78
+ function startHeartbeat(target, token) {
79
+ let refreshing = false;
80
+ const timer = setInterval(() => {
81
+ if (refreshing)
82
+ return;
83
+ refreshing = true;
84
+ void refreshHeartbeat(target, token).finally(() => { refreshing = false; });
85
+ }, LOCK_HEARTBEAT_INTERVAL_MS);
86
+ timer.unref?.();
87
+ return timer;
88
+ }
89
+ async function refreshHeartbeat(target, token) {
90
+ let handle = null;
91
+ try {
92
+ handle = await fs.open(target, fsConstants.O_RDWR | fsConstants.O_NOFOLLOW);
93
+ const stat = await handle.stat();
94
+ if (!stat.isFile() || stat.size > 16 * 1024)
95
+ return;
96
+ const owner = await handle.readFile("utf8").then(value => JSON.parse(value)).catch(() => null);
97
+ if (owner?.token !== token)
98
+ return;
99
+ const now = new Date();
100
+ await handle.utimes(now, now);
101
+ }
102
+ catch {
103
+ // A missing or replaced lock is no longer owned by this action.
104
+ }
105
+ finally {
106
+ await handle?.close().catch(() => undefined);
107
+ }
108
+ }
71
109
  async function readOwner(target) {
72
110
  return await fs.readFile(target, "utf8").then(value => JSON.parse(value)).catch(() => null);
73
111
  }
@@ -2,6 +2,7 @@ import type { BridgeServiceConfig } from "../bridge/bridge.types.js";
2
2
  import type { SessionEventSink } from "../session/session.base.js";
3
3
  import { type RunOnceDispatchPacket, type RunOnceResultPacket } from "../session/session.types.js";
4
4
  import type { SandboxService, ValidatedSandboxContract } from "./sandbox.types.js";
5
+ import { type RuntimeIsolationLease } from "../runtime/runtime-isolation-lease.js";
5
6
  export interface SandboxRuntime {
6
7
  runOnce(dispatch: RunOnceDispatchPacket, sink: SessionEventSink, signal?: AbortSignal): Promise<RunOnceResultPacket>;
7
8
  reap(options?: SandboxReapOptions): Promise<void>;
@@ -41,6 +42,28 @@ export interface SandboxRuntimeSnapshot {
41
42
  readonly active: number;
42
43
  readonly degraded: number;
43
44
  }
45
+ export interface SandboxContainerMemoryPeak {
46
+ readonly containerId: string;
47
+ readonly name: string;
48
+ readonly role: string;
49
+ readonly peakMemoryBytes: number;
50
+ }
51
+ export interface SandboxPeakMemoryTelemetry {
52
+ readonly schemaVersion: 1;
53
+ readonly source: "docker_stats_sampled";
54
+ readonly sampleIntervalMs: number;
55
+ readonly sampleCount: number;
56
+ readonly failedSampleCount: number;
57
+ readonly peakMemoryBytes: number;
58
+ readonly firstSampledAt: string;
59
+ readonly lastSampledAt: string;
60
+ readonly containers: readonly SandboxContainerMemoryPeak[];
61
+ }
62
+ export interface DockerStatsMemorySample {
63
+ readonly containerId: string;
64
+ readonly name: string;
65
+ readonly memoryBytes: number;
66
+ }
44
67
  export interface SandboxPublicationGrantRequest {
45
68
  readonly dispatchAttemptId: string;
46
69
  readonly leaseId: string;
@@ -84,6 +107,7 @@ export declare class DockerSandboxRuntime implements SandboxRuntime {
84
107
  private buildImageCore;
85
108
  private runBuildStage;
86
109
  private ensureBuildxBuilder;
110
+ private stopBuildxBuilder;
87
111
  private initializeVolumes;
88
112
  private inspectContainerState;
89
113
  private initializeServiceSecrets;
@@ -102,9 +126,12 @@ export declare class DockerSandboxRuntime implements SandboxRuntime {
102
126
  private readImageCacheRecord;
103
127
  private collectExpiredImages;
104
128
  private purgeRestrictedAuditArtifacts;
129
+ private inspectImageMetadata;
130
+ private startPeakMemorySampler;
105
131
  private docker;
106
132
  private dockerArgs;
107
133
  }
134
+ export declare function managedBranchUpdateExpectedValue(current: string, expectedInput: string, imported: string): string;
108
135
  export declare function publicationPushArgs(branch: string, resultCommitSha: string, inputCommitSha: string, remoteCommitSha: string, remote?: string): string[] | null;
109
136
  export declare function validatePublicationCredential(credential: SandboxPublicationCredential, nowMs?: number): void;
110
137
  export declare function publicationCredentialEnvironment(credential: SandboxPublicationCredential, environment?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
@@ -129,6 +156,7 @@ export declare function selectSandboxConfigRefs(executionPolicy: string, configu
129
156
  readonly refs: readonly string[];
130
157
  readonly approvedSha: string | null;
131
158
  };
159
+ export declare function selectSandboxInputRefs(worktreeKey: string, baseBranch: string): readonly string[];
132
160
  export declare function sandboxTimeLimits(environment?: NodeJS.ProcessEnv): {
133
161
  readonly hardWallMs: number;
134
162
  readonly idleMs: number;
@@ -144,8 +172,10 @@ export interface ImageCacheRecord {
144
172
  readonly overlayTag: string;
145
173
  readonly imageDigest: string;
146
174
  readonly helperImageDigest: string;
175
+ readonly bridgeRuntimeDigest?: string;
147
176
  readonly policyDigest: string;
148
177
  }
178
+ export declare function sandboxWorkerFailureMessage(exitCode: number, stderr: string, containerError: string | null): string;
149
179
  interface ResourceNames {
150
180
  prefix: string;
151
181
  container: string;
@@ -162,18 +192,30 @@ interface SandboxRuntimeVolume {
162
192
  readonly name: string;
163
193
  readonly role: string;
164
194
  }
195
+ export declare function parseDockerMemoryBytes(value: string): number | null;
196
+ export declare function parseDockerStatsMemorySample(output: string): DockerStatsMemorySample[];
165
197
  interface ActiveSandbox {
166
198
  dispatchAttemptId: string;
167
199
  fencingToken: string;
168
200
  expiresAt: string;
169
201
  controller: AbortController;
170
202
  phase: "starting" | "active";
203
+ runtimeLease: RuntimeIsolationLease;
171
204
  ledger: SandboxLedger | null;
172
205
  leaseControlKey: string;
173
206
  }
174
207
  export declare function assertSandboxImportCurrent(expected: Pick<ActiveSandbox, "dispatchAttemptId" | "fencingToken" | "expiresAt">, current: Pick<ActiveSandbox, "dispatchAttemptId" | "fencingToken"> | undefined, signal: AbortSignal, nowMs?: number): void;
175
208
  interface SandboxLedger {
176
- schemaVersion: 1;
209
+ schemaVersion: 3;
210
+ runtimeLease: RuntimeIsolationLease;
211
+ resources: ResourceNames;
212
+ labels: Record<string, string>;
213
+ includeCredentials?: boolean;
214
+ peakMemory?: SandboxPeakMemoryTelemetry;
215
+ }
216
+ interface LegacySandboxLedger {
217
+ schemaVersion: 2;
218
+ resourceLeaseId: string;
177
219
  dispatchAttemptId: string;
178
220
  fencingToken: string;
179
221
  runnerInstanceId: string;
@@ -181,13 +223,18 @@ interface SandboxLedger {
181
223
  resources: ResourceNames;
182
224
  labels: Record<string, string>;
183
225
  includeCredentials?: boolean;
226
+ peakMemory?: SandboxPeakMemoryTelemetry;
184
227
  }
228
+ export declare function validSandboxLedger(value: unknown): boolean;
229
+ export declare function normalizeSandboxLedger(value: unknown): SandboxLedger | null;
185
230
  export declare function resourceNames(attemptHex: string, perAttemptCaches?: readonly string[]): ResourceNames;
186
231
  export declare function dockerObjectId(output: string, kind: "container" | "network"): string;
187
232
  export declare function sandboxRuntimeVolumes(resources: ResourceNames, includeEgressPolicy?: boolean, includeCredentials?: boolean): SandboxRuntimeVolume[];
188
233
  export declare function sandboxRuntimeCleanupVolumeNames(resources: ResourceNames, includeCredentials?: boolean): string[];
234
+ export declare function sandboxResourceLabels(dispatch: RunOnceDispatchPacket, image: string, contract: string): Record<string, string>;
189
235
  export declare function mayReapManagedResource(labels: Readonly<Record<string, string>>, runnerId: string, liveAttempts: ReadonlySet<string>): boolean;
190
- export declare function shouldReapSandboxLedger(ledger: Readonly<Pick<SandboxLedger, "dispatchAttemptId" | "fencingToken" | "runnerInstanceId" | "expiresAt">>, currentRunnerInstanceId: string, serverAttempt: SandboxAttemptSnapshot | undefined, snapshotAvailable: boolean, nowMs?: number): boolean;
236
+ export declare function shouldReapSandboxLedger(ledger: Readonly<Pick<SandboxLedger, "runtimeLease">> | Readonly<Pick<LegacySandboxLedger, "dispatchAttemptId" | "fencingToken" | "runnerInstanceId" | "expiresAt">>, currentRunnerInstanceId: string, serverAttempt: SandboxAttemptSnapshot | undefined, snapshotAvailable: boolean, nowMs?: number): boolean;
237
+ export declare function bridgeRuntimeCacheMatches(record: Pick<ImageCacheRecord, "bridgeRuntimeDigest"> | null | undefined, expectedDigest: string, imageLabels: readonly (Readonly<Record<string, string>> | null | undefined)[]): boolean;
191
238
  export declare function prepareOverlayBuildRoot(overlayRoot: string): Promise<void>;
192
239
  export declare function extractOciLayoutArchive(archivePath: string, destination: string, signal?: AbortSignal): Promise<void>;
193
240
  export declare function ociLayoutContextRef(layoutPath: string): string;
@@ -200,6 +247,20 @@ export declare function readOciLayoutImageDigest(layoutRoot: string): Promise<st
200
247
  export declare function removeExtractedOciLayout(layoutRoot: string): Promise<void>;
201
248
  export declare function ociLayoutScanTarget(layoutPath: string): string;
202
249
  export declare function agentOverlayDockerignore(): string;
250
+ export interface SandboxImageCacheKeyInput {
251
+ readonly contextDigest: string;
252
+ readonly contractDigest: string;
253
+ readonly platform: string;
254
+ readonly architecture: string;
255
+ readonly bridgeVersion: string;
256
+ readonly bridgeRuntimeDigest: string;
257
+ readonly toolingImage: string;
258
+ readonly codexVersion: string;
259
+ readonly policy: string;
260
+ readonly policyConfigurationDigest: string;
261
+ }
262
+ export declare function sandboxImageCacheKey(input: SandboxImageCacheKeyInput): string;
263
+ export declare function bridgeRuntimeContentDigest(packageRoot: string): Promise<string>;
203
264
  export declare function agentOverlayDockerfile(toolingImage: string, projectContextName: string, installMode: BridgePackageInstallMode, codexVersion: string): string;
204
265
  export type BridgePackageInstallMode = "ci" | "install";
205
266
  export declare function copyBridgePackageManifests(packageRoot: string, bridgeRoot: string): Promise<BridgePackageInstallMode>;
@@ -211,17 +272,19 @@ export declare function buildResourcePolicy(environment?: NodeJS.ProcessEnv): {
211
272
  readonly nofile: number;
212
273
  readonly sharedMemory: string;
213
274
  readonly builderPidsLimit: number;
275
+ readonly builderMemoryBytes: number;
214
276
  };
215
277
  export declare function dedicatedBuildxBuilderName(runnerId: string, dockerContext: string | null | undefined): string;
216
278
  export declare function dedicatedBuildxBuilderContainerName(builder: string): string;
217
279
  export declare function selectImageGcCandidates(records: readonly ImageCacheRecord[], keepPerProject: number, ttlMs: number, nowMs: number): ImageCacheRecord[];
218
280
  export declare function workerCreateArgs(dispatch: RunOnceDispatchPacket, contract: ValidatedSandboxContract, resources: ResourceNames, labels: Record<string, string>, image: string, securityOptions?: readonly string[]): string[];
281
+ export declare function validateSandboxMemoryReservation(dispatch: RunOnceDispatchPacket, contract: ValidatedSandboxContract): void;
219
282
  export declare function cacheVolumeArgs(contract: ValidatedSandboxContract, resources: ResourceNames): string[];
220
283
  export declare function proxyEnvironmentArgs(dispatch: RunOnceDispatchPacket, contract: ValidatedSandboxContract, resources: ResourceNames): string[];
221
284
  export declare function egressProxyConfig(allowedHosts: readonly string[]): string;
222
285
  export declare function serviceContainerArgs(service: SandboxService, image: string, resources: ResourceNames, labels: Record<string, string>, securityOptions: readonly string[], environment?: NodeJS.ProcessEnv): string[];
223
286
  export declare function resolveSandboxSecurityOptions(executionPolicy: string, environment?: NodeJS.ProcessEnv): string[];
224
- export declare function networkCreateArgs(dispatch: RunOnceDispatchPacket, environment?: NodeJS.ProcessEnv): string[];
287
+ export declare function networkCreateArgs(dispatch: RunOnceDispatchPacket, environment?: NodeJS.ProcessEnv, allowOpenPublicSandbox?: boolean): string[];
225
288
  export declare function classifySandboxRuntimeFailure(value: string): {
226
289
  readonly code: string;
227
290
  readonly phase: string;