@loucompanion/forge-bridge 0.1.3-dev.c24058d57ab3 → 0.1.3-dev.c28767e94230
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.
|
@@ -76,5 +76,9 @@ export declare class SignalRBridgeConnection implements BridgeConnection {
|
|
|
76
76
|
}
|
|
77
77
|
export declare function defaultBridgeServiceConfig(overrides?: Partial<BridgeServiceConfig>): BridgeServiceConfig;
|
|
78
78
|
export declare function resolveBridgeRunnerHubUrl(serverUrl: string): URL;
|
|
79
|
+
export declare function canReapManagedSandboxes(preflight: {
|
|
80
|
+
readonly healthy: boolean;
|
|
81
|
+
readonly unavailableCode?: string | null;
|
|
82
|
+
}): boolean;
|
|
79
83
|
export type SandboxResourceVector = DispatchSandboxResourceRequest;
|
|
80
84
|
export declare function canReserveSandboxResources(used: SandboxResourceVector, requested: SandboxResourceVector, capacity: SandboxResourceVector): boolean;
|
|
@@ -9,7 +9,7 @@ import { redactSecrets, redactText } from "../shared/redaction/redaction.js";
|
|
|
9
9
|
import { BridgeSessionService } from "../session/session.service.js";
|
|
10
10
|
import { failureResult, parseRunOnceDispatchPacket } from "../session/session.types.js";
|
|
11
11
|
import { forgeBridgeVersion } from "../version.js";
|
|
12
|
-
import { DockerPreflight } from "../sandbox/preflight.js";
|
|
12
|
+
import { canRunDockerMaintenance, DockerPreflight } from "../sandbox/preflight.js";
|
|
13
13
|
import { DockerSandboxRuntime } from "../sandbox/runtime.js";
|
|
14
14
|
import { codexSandboxProviderAuthAdapter, sandboxProviderAuthAdapterFor, sandboxProviderAuthUnavailableMessage } from "../sandbox/provider-auth/codex.js";
|
|
15
15
|
export class ForgeBridgeService {
|
|
@@ -1001,8 +1001,8 @@ function abortPromise(signal) {
|
|
|
1001
1001
|
}
|
|
1002
1002
|
return new Promise((resolve) => signal.addEventListener("abort", () => resolve(), { once: true }));
|
|
1003
1003
|
}
|
|
1004
|
-
function canReapManagedSandboxes(preflight) {
|
|
1005
|
-
return preflight
|
|
1004
|
+
export function canReapManagedSandboxes(preflight) {
|
|
1005
|
+
return canRunDockerMaintenance(preflight);
|
|
1006
1006
|
}
|
|
1007
1007
|
function sandboxNetworkPolicyFailure(dispatch) {
|
|
1008
1008
|
const sandbox = dispatch.sandbox;
|
|
@@ -27,6 +27,10 @@ export declare class DockerPreflight {
|
|
|
27
27
|
run(force?: boolean): Promise<SandboxPreflightResult>;
|
|
28
28
|
private inspect;
|
|
29
29
|
}
|
|
30
|
+
export declare function canRunDockerMaintenance(preflight: {
|
|
31
|
+
readonly healthy: boolean;
|
|
32
|
+
readonly unavailableCode?: string | null;
|
|
33
|
+
}): boolean;
|
|
30
34
|
export declare function evaluateDiskPressure(availableBytes: number, totalBytes: number, minimumAvailableBytes: number, highWatermarkPercent: number, lowWatermarkPercent: number, pressureLatched: boolean): boolean;
|
|
31
35
|
export declare function storagePolicyAvailable(storageQuota: boolean, environment?: NodeJS.ProcessEnv): boolean;
|
|
32
36
|
export declare class DockerContextOwnershipLock {
|
|
@@ -26,7 +26,7 @@ export class DockerPreflight {
|
|
|
26
26
|
async refresh() {
|
|
27
27
|
await fs.mkdir(this.options.stateRoot ?? path.join(os.homedir(), ".forge", "bridge", "sandboxes"), { recursive: true, mode: 0o700 });
|
|
28
28
|
const result = await this.run(true);
|
|
29
|
-
if (result
|
|
29
|
+
if (canRunDockerMaintenance(result)) {
|
|
30
30
|
await this.ownership.acquire(this.options.dockerContext);
|
|
31
31
|
}
|
|
32
32
|
return result;
|
|
@@ -108,14 +108,27 @@ export class DockerPreflight {
|
|
|
108
108
|
const availableMemoryBytes = os.freemem();
|
|
109
109
|
const cpuCount = Math.max(1, os.availableParallelism?.() ?? os.cpus().length);
|
|
110
110
|
const availableCpuMillis = Math.max(0, (cpuCount - 1) * 1000);
|
|
111
|
-
const
|
|
112
|
-
const
|
|
113
|
-
const
|
|
114
|
-
const
|
|
111
|
+
const memoryReserveBytes = 2 * 1024 ** 3;
|
|
112
|
+
const sandboxMemoryBytes = 2 * 1024 ** 3;
|
|
113
|
+
const sandboxCpuMillis = 2_000;
|
|
114
|
+
const memorySlots = Math.max(0, Math.floor((availableMemoryBytes - memoryReserveBytes) / sandboxMemoryBytes));
|
|
115
|
+
const cpuSlots = Math.max(0, Math.floor(availableCpuMillis / sandboxCpuMillis));
|
|
116
|
+
const configuredMax = positiveInteger(this.options.maxConcurrentSandboxes, positiveInteger(process.env.FORGE_MAX_CONCURRENT_SANDBOXES, 3));
|
|
117
|
+
const capacityLowCode = !diskLow && memorySlots <= 0 ? "docker_memory_low" : !diskLow && cpuSlots <= 0 ? "docker_cpu_low" : null;
|
|
118
|
+
const maxConcurrentSandboxes = diskLow || capacityLowCode ? 0 : Math.min(3, configuredMax, cpuSlots, memorySlots);
|
|
119
|
+
const unavailableCode = diskLow ? "docker_disk_low" : capacityLowCode;
|
|
120
|
+
const unavailableReason = diskLow
|
|
121
|
+
? `Docker workspace has only ${disk.available} bytes available.`
|
|
122
|
+
: unavailableCode === "docker_memory_low"
|
|
123
|
+
? `Docker host has ${availableMemoryBytes} bytes free; at least ${memoryReserveBytes + sandboxMemoryBytes} bytes are needed for one sandbox plus reserve.`
|
|
124
|
+
: unavailableCode === "docker_cpu_low"
|
|
125
|
+
? `Docker host has ${availableCpuMillis} available CPU millis; at least ${sandboxCpuMillis} are needed for one sandbox.`
|
|
126
|
+
: null;
|
|
115
127
|
const features = { rootless, userNamespaces, cgroupV2, seccomp, lsm, storageQuota, storagePolicy, compose, internalNetwork: true, buildkit, imagePolicy, securityProfile, egressProxy };
|
|
128
|
+
const capacityAvailable = unavailableCode === null;
|
|
116
129
|
return {
|
|
117
|
-
available:
|
|
118
|
-
healthy:
|
|
130
|
+
available: capacityAvailable,
|
|
131
|
+
healthy: capacityAvailable,
|
|
119
132
|
generation: this.generation,
|
|
120
133
|
runtimeVersion: `docker/${String(info.ServerVersion ?? "unknown")}${rootless ? "-rootless" : "-desktop"}`,
|
|
121
134
|
maxConcurrentSandboxes,
|
|
@@ -123,12 +136,16 @@ export class DockerPreflight {
|
|
|
123
136
|
availableCpuMillis,
|
|
124
137
|
availableWorkspaceBytes: disk.available,
|
|
125
138
|
diskLow,
|
|
126
|
-
unavailableCode
|
|
127
|
-
unavailableReason
|
|
139
|
+
unavailableCode,
|
|
140
|
+
unavailableReason,
|
|
128
141
|
features,
|
|
129
142
|
};
|
|
130
143
|
}
|
|
131
144
|
}
|
|
145
|
+
const dockerMaintenanceUnavailableCodes = new Set(["docker_disk_low", "docker_memory_low", "docker_cpu_low"]);
|
|
146
|
+
export function canRunDockerMaintenance(preflight) {
|
|
147
|
+
return preflight.healthy || dockerMaintenanceUnavailableCodes.has(preflight.unavailableCode ?? "");
|
|
148
|
+
}
|
|
132
149
|
export function evaluateDiskPressure(availableBytes, totalBytes, minimumAvailableBytes, highWatermarkPercent, lowWatermarkPercent, pressureLatched) {
|
|
133
150
|
if (availableBytes < minimumAvailableBytes)
|
|
134
151
|
return true;
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const forgeBridgeVersion = "0.1.3-dev.
|
|
1
|
+
export declare const forgeBridgeVersion = "0.1.3-dev.c28767e94230";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const forgeBridgeVersion = "0.1.3-dev.
|
|
1
|
+
export const forgeBridgeVersion = "0.1.3-dev.c28767e94230";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loucompanion/forge-bridge",
|
|
3
|
-
"version": "0.1.3-dev.
|
|
3
|
+
"version": "0.1.3-dev.c28767e94230",
|
|
4
4
|
"description": "Forge runner bridge CLI for connecting local developer machines to Forge dispatch.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|