@opengeni/runtime 3.0.1 → 4.0.0-canary.35585322809001
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/dist/assets/codemode-client.json +1 -0
- package/dist/chunk-4A4XTKKX.js +1 -0
- package/dist/{chunk-RIJ6DCYS.js → chunk-HCGLD7NH.js} +9817 -9494
- package/dist/chunk-HCGLD7NH.js.map +1 -0
- package/dist/{chunk-FHGLYLBL.js → chunk-SPT3PLMX.js} +1 -87
- package/dist/chunk-SPT3PLMX.js.map +1 -0
- package/dist/{chunk-GB763TSV.js → chunk-TE27J65Q.js} +1 -1
- package/dist/chunk-TE27J65Q.js.map +1 -0
- package/dist/{chunk-46BFUGFL.js → chunk-WIHICNWS.js} +1660 -388
- package/dist/chunk-WIHICNWS.js.map +1 -0
- package/dist/{chunk-UU6EJR52.js → chunk-YU4VRTR4.js} +2 -2
- package/dist/chunk-YU4VRTR4.js.map +1 -0
- package/dist/chunk-ZG2YH25H.js +94 -0
- package/dist/chunk-ZG2YH25H.js.map +1 -0
- package/dist/codex-tool-search.d.ts +5 -4
- package/dist/context-compaction.d.ts +19 -0
- package/dist/gmail-rest-mcp.js +1 -1
- package/dist/index.d.ts +30 -22
- package/dist/index.js +25 -5
- package/dist/lazy-manifest-OEYEHNVY.js +45 -0
- package/dist/lazy-manifest-OEYEHNVY.js.map +1 -0
- package/dist/lazy-manifest.d.ts +6 -0
- package/dist/lazy-tool-transport.d.ts +3 -2
- package/dist/{localSources-PVFCAPN2.js → localSources-TWHTEKGO.js} +3 -2
- package/dist/localSources-TWHTEKGO.js.map +1 -0
- package/dist/metrics.d.ts +6 -0
- package/dist/operational-instructions.d.ts +1 -1
- package/dist/prepared-compaction-request.d.ts +8 -0
- package/dist/provider-history-adapter.d.ts +2 -2
- package/dist/runtime-skills.d.ts +3 -10
- package/dist/sandbox/codemode-client.d.ts +17 -0
- package/dist/sandbox/codemode-token.d.ts +3 -3
- package/dist/sandbox/index.d.ts +2 -1
- package/dist/sandbox/index.js +8 -2
- package/dist/sandbox/materialization-verification-error.d.ts +27 -0
- package/dist/sandbox/provider-command-session.d.ts +44 -2
- package/dist/sandbox/providers/modal-command-control.d.ts +32 -29
- package/dist/sandbox/providers/modal-command-router-wire.d.ts +49 -0
- package/dist/sandbox/providers/modal-command-session.d.ts +2 -1
- package/dist/sandbox/providers/modal-legacy-command-control.d.ts +50 -0
- package/dist/sandbox/providers/modal-materialization-verification.d.ts +7 -0
- package/dist/sandbox/providers/modal.d.ts +0 -8
- package/dist/sandbox/routing/routing-session.d.ts +21 -0
- package/dist/sandbox/turn-tool-cancellation.d.ts +1 -0
- package/dist/skill-library.d.ts +0 -6
- package/dist/skill-library.js +1 -1
- package/dist/workspace-tool-gateway.js +7 -5
- package/package.json +13 -11
- package/src/bundled_artifact_skills/opengeni-documents/SKILL.md +19 -0
- package/src/bundled_artifact_skills/opengeni-documents/references/api.md +22 -0
- package/src/bundled_default_skills/opengeni-client/SKILL.md +349 -0
- package/src/bundled_default_skills/opengeni-client/agents/openai.yaml +4 -0
- package/src/bundled_default_skills/opengeni-client/references/api-workflows.md +256 -0
- package/src/bundled_default_skills/opengeni-client/references/compatibility-and-troubleshooting.md +84 -0
- package/src/bundled_default_skills/opengeni-client/references/customer-skill-template.md +96 -0
- package/src/bundled_default_skills/opengeni-client/references/data-tools-and-credentials.md +99 -0
- package/src/bundled_default_skills/opengeni-client/references/discovery-and-autonomy.md +81 -0
- package/src/bundled_default_skills/opengeni-client/references/external-users-and-connect.md +457 -0
- package/src/bundled_default_skills/opengeni-client/references/isolation-and-authorization.md +77 -0
- package/src/bundled_default_skills/opengeni-client/references/product-integration-shapes.md +232 -0
- package/src/bundled_default_skills/opengeni-client/references/product-shapes-and-ui.md +116 -0
- package/src/bundled_default_skills/opengeni-client/references/runtime-profile-and-verification.md +157 -0
- package/src/bundled_default_skills/opengeni-help/SKILL.md +101 -0
- package/src/bundled_management_skills/opengeni-skills/SKILL.md +33 -3
- package/src/codex-tool-search.ts +13 -5
- package/src/context-compaction.ts +87 -4
- package/src/gmail-rest-mcp.ts +1 -2
- package/src/index.ts +363 -131
- package/src/lazy-manifest.ts +55 -0
- package/src/lazy-tool-transport.ts +15 -2
- package/src/metrics.ts +6 -0
- package/src/model-request-capture.ts +3 -0
- package/src/operational-instructions.ts +11 -2
- package/src/prepared-compaction-request.ts +51 -0
- package/src/provider-history-adapter.ts +12 -3
- package/src/runtime-skills.ts +3 -17
- package/src/sandbox/codemode-client.ts +204 -0
- package/src/sandbox/codemode-token.ts +7 -2
- package/src/sandbox/index.ts +7 -0
- package/src/sandbox/materialization-verification-error.ts +65 -0
- package/src/sandbox/provider-command-session.ts +70 -2
- package/src/sandbox/providers/modal-command-control.ts +386 -242
- package/src/sandbox/providers/modal-command-router-wire.ts +248 -0
- package/src/sandbox/providers/modal-command-session.ts +177 -4
- package/src/sandbox/providers/modal-legacy-command-control.ts +351 -0
- package/src/sandbox/providers/modal-materialization-verification.ts +122 -0
- package/src/sandbox/providers/modal.ts +1 -9
- package/src/sandbox/routing/routing-session.ts +417 -79
- package/src/sandbox/turn-tool-cancellation.ts +38 -2
- package/src/skill-catalog.ts +1 -0
- package/src/skill-library.ts +0 -6
- package/src/workspace-governance.ts +0 -1
- package/src/workspace-skills.ts +114 -74
- package/dist/chunk-46BFUGFL.js.map +0 -1
- package/dist/chunk-FHGLYLBL.js.map +0 -1
- package/dist/chunk-GB763TSV.js.map +0 -1
- package/dist/chunk-RIJ6DCYS.js.map +0 -1
- package/dist/chunk-UU6EJR52.js.map +0 -1
- /package/dist/{localSources-PVFCAPN2.js.map → chunk-4A4XTKKX.js.map} +0 -0
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
NoopSnapshotSpec,
|
|
3
2
|
applyInlineManifestEntryToState,
|
|
4
3
|
applyInlineManifestToState,
|
|
5
4
|
applyLocalSourceManifestEntryToState,
|
|
@@ -14,14 +13,11 @@ import {
|
|
|
14
13
|
imageOutputFromBytes,
|
|
15
14
|
isHostPathStrictlyWithinRoot,
|
|
16
15
|
isHostPathWithinRoot,
|
|
17
|
-
isNoopSnapshotSpec,
|
|
18
16
|
manifestContainsLocalSource,
|
|
19
17
|
manifestWithMaterializedEnvironmentReferences,
|
|
20
18
|
materializeLocalSourceManifest,
|
|
21
|
-
normalizeSandboxClientCreateArgs,
|
|
22
19
|
relativeHostPathEscapesRoot,
|
|
23
20
|
resolveSandboxAbsolutePath,
|
|
24
|
-
resolveSandboxArchiveLimits,
|
|
25
21
|
resolveSandboxRelativePath,
|
|
26
22
|
resolveSandboxWorkdir,
|
|
27
23
|
runSandboxProcess,
|
|
@@ -29,9 +25,15 @@ import {
|
|
|
29
25
|
toUint8Array,
|
|
30
26
|
truncateOutput,
|
|
31
27
|
validateCredentialPair,
|
|
32
|
-
validateRemoteSandboxPathForManifest
|
|
28
|
+
validateRemoteSandboxPathForManifest
|
|
29
|
+
} from "./chunk-SPT3PLMX.js";
|
|
30
|
+
import {
|
|
31
|
+
NoopSnapshotSpec,
|
|
32
|
+
isNoopSnapshotSpec,
|
|
33
|
+
normalizeSandboxClientCreateArgs,
|
|
34
|
+
resolveSandboxArchiveLimits,
|
|
33
35
|
validateSandboxArchiveLimits
|
|
34
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-ZG2YH25H.js";
|
|
35
37
|
import {
|
|
36
38
|
Environment,
|
|
37
39
|
FileMode,
|
|
@@ -154,7 +156,7 @@ async function enterOperation(gate) {
|
|
|
154
156
|
gate.activeOperations += 1;
|
|
155
157
|
return false;
|
|
156
158
|
}
|
|
157
|
-
await new Promise((
|
|
159
|
+
await new Promise((resolve7) => gate.operationWaiters.push(resolve7));
|
|
158
160
|
return true;
|
|
159
161
|
}
|
|
160
162
|
function leaveOperation(gate) {
|
|
@@ -175,7 +177,7 @@ async function enterCapture(gate) {
|
|
|
175
177
|
gate.captureActive = true;
|
|
176
178
|
return;
|
|
177
179
|
}
|
|
178
|
-
await new Promise((
|
|
180
|
+
await new Promise((resolve7) => gate.captureWaiters.push(resolve7));
|
|
179
181
|
}
|
|
180
182
|
function leaveCapture(gate) {
|
|
181
183
|
if (!gate.captureActive) {
|
|
@@ -394,9 +396,9 @@ function stdoutFromExecResult(value) {
|
|
|
394
396
|
function execFailureDiagnostic(value) {
|
|
395
397
|
if (!value || typeof value !== "object") return "result=unstructured";
|
|
396
398
|
const result = value;
|
|
397
|
-
const
|
|
399
|
+
const status2 = typeof result.exitCode === "number" ? `exitCode=${result.exitCode}` : typeof result.status === "number" ? `status=${result.status}` : "exitCode=unknown";
|
|
398
400
|
const stderr = typeof result.stderr === "string" ? result.stderr.replace(/\s+/g, " ").trim().slice(0, 240) : "";
|
|
399
|
-
return stderr.length > 0 ? `${
|
|
401
|
+
return stderr.length > 0 ? `${status2}, stderr=${stderr}` : status2;
|
|
400
402
|
}
|
|
401
403
|
function isTransientRootDirectoryFingerprintRace(value) {
|
|
402
404
|
if (!value || typeof value !== "object") return false;
|
|
@@ -659,7 +661,7 @@ async function fingerprintRemoteWorkspace(target) {
|
|
|
659
661
|
});
|
|
660
662
|
match = stdoutFromExecResult(result).trim().match(/^OPENGENI_WORKSPACE_FINGERPRINT_V1 ([a-f0-9]{64}) ([0-9]+) ([0-9]+) ([0-9]+)$/);
|
|
661
663
|
if (match || !isTransientRootDirectoryFingerprintRace(result) || attempt === 3) break;
|
|
662
|
-
await new Promise((
|
|
664
|
+
await new Promise((resolve7) => setTimeout(resolve7, attempt * 25));
|
|
663
665
|
}
|
|
664
666
|
if (!match) {
|
|
665
667
|
throw new WorkspaceArchiveIntegrityError(
|
|
@@ -2257,8 +2259,8 @@ function trimTarString(value) {
|
|
|
2257
2259
|
function decodeBytes(bytes) {
|
|
2258
2260
|
return new TextDecoder().decode(bytes);
|
|
2259
2261
|
}
|
|
2260
|
-
function joinTarName(name,
|
|
2261
|
-
return
|
|
2262
|
+
function joinTarName(name, prefix2) {
|
|
2263
|
+
return prefix2 ? `${prefix2}/${name}` : name;
|
|
2262
2264
|
}
|
|
2263
2265
|
function blocksEqual(left, right) {
|
|
2264
2266
|
if (left.byteLength !== right.byteLength) {
|
|
@@ -2578,7 +2580,7 @@ function waitForPtyWebSocketOpen(socket, timeoutMs, providerName) {
|
|
|
2578
2580
|
if (readyState === 1) {
|
|
2579
2581
|
return Promise.resolve();
|
|
2580
2582
|
}
|
|
2581
|
-
return new Promise((
|
|
2583
|
+
return new Promise((resolve7, reject) => {
|
|
2582
2584
|
let settled = false;
|
|
2583
2585
|
let removeOpen = () => {
|
|
2584
2586
|
};
|
|
@@ -2601,7 +2603,7 @@ function waitForPtyWebSocketOpen(socket, timeoutMs, providerName) {
|
|
|
2601
2603
|
callback();
|
|
2602
2604
|
};
|
|
2603
2605
|
removeOpen = addPtyWebSocketListener(socket, "open", () => {
|
|
2604
|
-
settle(
|
|
2606
|
+
settle(resolve7);
|
|
2605
2607
|
});
|
|
2606
2608
|
removeError = addPtyWebSocketListener(socket, "error", (event) => {
|
|
2607
2609
|
settle(() => reject(new UserError(`${providerName} PTY WebSocket failed to connect: ${formatWebSocketEvent(event)}`)));
|
|
@@ -2613,7 +2615,7 @@ function waitForPtyWebSocketOpen(socket, timeoutMs, providerName) {
|
|
|
2613
2615
|
settle(() => reject(new UserError(`${providerName} PTY WebSocket connection timed out.`)));
|
|
2614
2616
|
}, timeoutMs);
|
|
2615
2617
|
if (socket.readyState === 1) {
|
|
2616
|
-
settle(
|
|
2618
|
+
settle(resolve7);
|
|
2617
2619
|
return;
|
|
2618
2620
|
}
|
|
2619
2621
|
});
|
|
@@ -2708,11 +2710,11 @@ function consumePtyOutput(entry) {
|
|
|
2708
2710
|
return output;
|
|
2709
2711
|
}
|
|
2710
2712
|
function waitForPtyNotification(entry, timeoutMs) {
|
|
2711
|
-
return new Promise((
|
|
2713
|
+
return new Promise((resolve7) => {
|
|
2712
2714
|
const done = () => {
|
|
2713
2715
|
clearTimeout(timer);
|
|
2714
2716
|
entry.waiters.delete(done);
|
|
2715
|
-
|
|
2717
|
+
resolve7();
|
|
2716
2718
|
};
|
|
2717
2719
|
const timer = setTimeout(done, timeoutMs);
|
|
2718
2720
|
entry.waiters.add(done);
|
|
@@ -2885,9 +2887,9 @@ function readProviderErrorRetryability(value, seen, depth) {
|
|
|
2885
2887
|
if (typed !== null) {
|
|
2886
2888
|
return typed;
|
|
2887
2889
|
}
|
|
2888
|
-
const
|
|
2889
|
-
if (
|
|
2890
|
-
const retryable = retryabilityForHttpStatus(
|
|
2890
|
+
const status2 = readProviderStatus(value);
|
|
2891
|
+
if (status2 !== void 0) {
|
|
2892
|
+
const retryable = retryabilityForHttpStatus(status2);
|
|
2891
2893
|
if (retryable !== null) {
|
|
2892
2894
|
return retryable;
|
|
2893
2895
|
}
|
|
@@ -2946,21 +2948,21 @@ function retryabilityForErrorType(value) {
|
|
|
2946
2948
|
}
|
|
2947
2949
|
function readProviderStatus(value) {
|
|
2948
2950
|
for (const key of ["status", "statusCode", "httpStatus", "httpStatusCode"]) {
|
|
2949
|
-
const
|
|
2950
|
-
if (typeof
|
|
2951
|
-
return
|
|
2951
|
+
const status2 = value[key];
|
|
2952
|
+
if (typeof status2 === "number" && Number.isInteger(status2)) {
|
|
2953
|
+
return status2;
|
|
2952
2954
|
}
|
|
2953
|
-
if (typeof
|
|
2954
|
-
return Number(
|
|
2955
|
+
if (typeof status2 === "string" && /^\d+$/u.test(status2)) {
|
|
2956
|
+
return Number(status2);
|
|
2955
2957
|
}
|
|
2956
2958
|
}
|
|
2957
2959
|
return void 0;
|
|
2958
2960
|
}
|
|
2959
|
-
function retryabilityForHttpStatus(
|
|
2960
|
-
if ([408, 425, 429, 500, 502, 503, 504].includes(
|
|
2961
|
+
function retryabilityForHttpStatus(status2) {
|
|
2962
|
+
if ([408, 425, 429, 500, 502, 503, 504].includes(status2)) {
|
|
2961
2963
|
return true;
|
|
2962
2964
|
}
|
|
2963
|
-
if ([400, 401, 403, 404, 409, 422].includes(
|
|
2965
|
+
if ([400, 401, 403, 404, 409, 422].includes(status2)) {
|
|
2964
2966
|
return false;
|
|
2965
2967
|
}
|
|
2966
2968
|
return null;
|
|
@@ -3740,7 +3742,7 @@ var NATIVE_SNAPSHOT_PREFIXES = {
|
|
|
3740
3742
|
vercel: "UC_VERCEL_SNAPSHOT_V1\n"
|
|
3741
3743
|
};
|
|
3742
3744
|
function encodeNativeSnapshotRef2(ref) {
|
|
3743
|
-
const
|
|
3745
|
+
const prefix2 = NATIVE_SNAPSHOT_PREFIXES[ref.provider];
|
|
3744
3746
|
const body = JSON.stringify({
|
|
3745
3747
|
snapshot_id: ref.snapshotId,
|
|
3746
3748
|
...ref.workspacePersistence ? { workspace_persistence: ref.workspacePersistence } : {}
|
|
@@ -3748,16 +3750,16 @@ function encodeNativeSnapshotRef2(ref) {
|
|
|
3748
3750
|
snapshot_id: ref.snapshotId,
|
|
3749
3751
|
workspace_persistence: ref.workspacePersistence
|
|
3750
3752
|
}).sort());
|
|
3751
|
-
return new TextEncoder().encode(`${
|
|
3753
|
+
return new TextEncoder().encode(`${prefix2}${body}`);
|
|
3752
3754
|
}
|
|
3753
3755
|
function decodeNativeSnapshotRef3(data) {
|
|
3754
3756
|
const text = new TextDecoder().decode(toWorkspaceArchiveBytes(data));
|
|
3755
|
-
for (const [provider,
|
|
3756
|
-
if (!text.startsWith(
|
|
3757
|
+
for (const [provider, prefix2] of Object.entries(NATIVE_SNAPSHOT_PREFIXES)) {
|
|
3758
|
+
if (!text.startsWith(prefix2)) {
|
|
3757
3759
|
continue;
|
|
3758
3760
|
}
|
|
3759
3761
|
try {
|
|
3760
|
-
const payload = JSON.parse(text.slice(
|
|
3762
|
+
const payload = JSON.parse(text.slice(prefix2.length));
|
|
3761
3763
|
if (typeof payload.snapshot_id !== "string" || !payload.snapshot_id) {
|
|
3762
3764
|
return void 0;
|
|
3763
3765
|
}
|
|
@@ -4409,8 +4411,8 @@ async function runRequiredMountCommand(options, command) {
|
|
|
4409
4411
|
function joinShellArgs(args) {
|
|
4410
4412
|
return args.map(shellQuote).join(" ");
|
|
4411
4413
|
}
|
|
4412
|
-
function joinRemotePath(base,
|
|
4413
|
-
const normalizedPrefix =
|
|
4414
|
+
function joinRemotePath(base, prefix2) {
|
|
4415
|
+
const normalizedPrefix = prefix2?.replace(/^\/+|\/+$/gu, "");
|
|
4414
4416
|
return normalizedPrefix ? `${base}/${normalizedPrefix}` : base;
|
|
4415
4417
|
}
|
|
4416
4418
|
function resolveRcloneRemoteName(pattern, options) {
|
|
@@ -4665,12 +4667,12 @@ function buildBlaxelDriveMountConfig(entry, mountPath) {
|
|
|
4665
4667
|
}
|
|
4666
4668
|
function buildS3FuseMountScript(config) {
|
|
4667
4669
|
const credentialPath = s3fsCredentialPath(config.mountPath, config.artifactScope);
|
|
4668
|
-
const
|
|
4670
|
+
const credentials2 = config.accessKeyId && config.secretAccessKey ? `${config.accessKeyId}:${config.secretAccessKey}${config.sessionToken ? `:${config.sessionToken}` : ""}` : void 0;
|
|
4669
4671
|
const bucket = config.prefix ? `${config.bucket}:/${config.prefix.replace(/^\/+|\/+$/gu, "")}` : config.bucket;
|
|
4670
4672
|
const options = [
|
|
4671
4673
|
"allow_other",
|
|
4672
4674
|
"nonempty",
|
|
4673
|
-
|
|
4675
|
+
credentials2 ? `passwd_file=${credentialPath}` : "public_bucket=1",
|
|
4674
4676
|
...config.endpointUrl ? [`url=${config.endpointUrl}`] : [],
|
|
4675
4677
|
...!config.endpointUrl && config.region ? [
|
|
4676
4678
|
`url=https://s3.${config.region}.amazonaws.com`,
|
|
@@ -4682,7 +4684,7 @@ function buildS3FuseMountScript(config) {
|
|
|
4682
4684
|
const command = [
|
|
4683
4685
|
ensureBlaxelToolCommand("s3fs"),
|
|
4684
4686
|
`mkdir -p -- ${shellQuote(config.mountPath)}`,
|
|
4685
|
-
...
|
|
4687
|
+
...credentials2 ? [`chmod 600 ${shellQuote(credentialPath)}`] : [],
|
|
4686
4688
|
[
|
|
4687
4689
|
"s3fs",
|
|
4688
4690
|
shellQuote(bucket),
|
|
@@ -4691,7 +4693,7 @@ function buildS3FuseMountScript(config) {
|
|
|
4691
4693
|
shellQuote(options.join(","))
|
|
4692
4694
|
].join(" ")
|
|
4693
4695
|
].join(" && ");
|
|
4694
|
-
if (!
|
|
4696
|
+
if (!credentials2) {
|
|
4695
4697
|
return command;
|
|
4696
4698
|
}
|
|
4697
4699
|
return `${command}; status=$?; rm -f -- ${shellQuote(credentialPath)}; exit $status`;
|
|
@@ -4846,12 +4848,12 @@ function gcsCredentialPath(mountPath, artifactScope) {
|
|
|
4846
4848
|
return `/tmp/gcs-creds-${safeId(`${artifactScope}:${mountPath}`)}.json`;
|
|
4847
4849
|
}
|
|
4848
4850
|
function gcsAccessTokenArtifactPaths(mountPath, artifactScope) {
|
|
4849
|
-
const
|
|
4851
|
+
const prefix2 = `/tmp/gcs-access-token-${safeId(`${artifactScope}:${mountPath}`)}`;
|
|
4850
4852
|
return {
|
|
4851
|
-
serverPath: `${
|
|
4852
|
-
socketPath: `${
|
|
4853
|
-
pidPath: `${
|
|
4854
|
-
payloadPath: `${
|
|
4853
|
+
serverPath: `${prefix2}.py`,
|
|
4854
|
+
socketPath: `${prefix2}.sock`,
|
|
4855
|
+
pidPath: `${prefix2}.pid`,
|
|
4856
|
+
payloadPath: `${prefix2}.json`
|
|
4855
4857
|
};
|
|
4856
4858
|
}
|
|
4857
4859
|
function usesGcsAccessTokenSecret(config) {
|
|
@@ -5687,8 +5689,8 @@ function generateBlaxelSandboxName() {
|
|
|
5687
5689
|
return `openai-agents-${Math.random().toString(16).slice(2, 10)}`;
|
|
5688
5690
|
}
|
|
5689
5691
|
function isBlaxelSandboxNonResumable(sandbox) {
|
|
5690
|
-
const
|
|
5691
|
-
return
|
|
5692
|
+
const status2 = sandbox.status?.trim().toUpperCase();
|
|
5693
|
+
return status2 ? BLAXEL_NON_RESUMABLE_SANDBOX_STATUSES.has(status2) : false;
|
|
5692
5694
|
}
|
|
5693
5695
|
function assertBlaxelSandboxReusable(sandbox, sandboxName) {
|
|
5694
5696
|
if (!isBlaxelSandboxNonResumable(sandbox)) {
|
|
@@ -5853,8 +5855,8 @@ function buildShellCommand(command, environment) {
|
|
|
5853
5855
|
}
|
|
5854
5856
|
function remoteWriteTempPath(path) {
|
|
5855
5857
|
const dir = posixDirname(path);
|
|
5856
|
-
const
|
|
5857
|
-
return `${
|
|
5858
|
+
const prefix2 = dir === "/" ? "" : dir;
|
|
5859
|
+
return `${prefix2}/.openai-agents-write-${randomUUID()}`;
|
|
5858
5860
|
}
|
|
5859
5861
|
function resolveBlaxelTimeouts(options) {
|
|
5860
5862
|
return {
|
|
@@ -6303,8 +6305,8 @@ function isR2Mount(entry) {
|
|
|
6303
6305
|
function isGCSMount(entry) {
|
|
6304
6306
|
return entry.type === "gcs_mount";
|
|
6305
6307
|
}
|
|
6306
|
-
function normalizePrefix(
|
|
6307
|
-
return
|
|
6308
|
+
function normalizePrefix(prefix2) {
|
|
6309
|
+
return prefix2;
|
|
6308
6310
|
}
|
|
6309
6311
|
function buildCredentials(args) {
|
|
6310
6312
|
validateCredentialPair4(args);
|
|
@@ -6565,7 +6567,7 @@ var CloudflareSandboxSession = class {
|
|
|
6565
6567
|
async materializeEntry(args) {
|
|
6566
6568
|
assertSandboxEntryMetadataSupported("CloudflareSandboxClient", args.path, args.entry, MOUNT_MANIFEST_METADATA_SUPPORT);
|
|
6567
6569
|
if (entryContainsLocalSource(args.entry)) {
|
|
6568
|
-
const { applyLocalSourceManifestEntryToState: applyLocalSourceManifestEntryToState2 } = await import("./localSources-
|
|
6570
|
+
const { applyLocalSourceManifestEntryToState: applyLocalSourceManifestEntryToState2 } = await import("./localSources-TWHTEKGO.js");
|
|
6569
6571
|
await applyLocalSourceManifestEntryToState2(this.state, args.path, args.entry, "cloudflare", this.writer(), this.remotePathResolver, this.manifestMaterializationOptions(args.runAs));
|
|
6570
6572
|
return;
|
|
6571
6573
|
}
|
|
@@ -6576,7 +6578,7 @@ var CloudflareSandboxSession = class {
|
|
|
6576
6578
|
assertSandboxManifestMetadataSupported("CloudflareSandboxClient", manifest, MOUNT_MANIFEST_METADATA_SUPPORT);
|
|
6577
6579
|
assertCloudflareManifestMountsSupported(manifest);
|
|
6578
6580
|
if (manifestContainsLocalSource(manifest)) {
|
|
6579
|
-
const { applyLocalSourceManifestToState: applyLocalSourceManifestToState2 } = await import("./localSources-
|
|
6581
|
+
const { applyLocalSourceManifestToState: applyLocalSourceManifestToState2 } = await import("./localSources-TWHTEKGO.js");
|
|
6580
6582
|
await applyLocalSourceManifestToState2(this.state, manifest, "cloudflare", this.writer(), this.remotePathResolver, this.manifestMaterializationOptions(runAs));
|
|
6581
6583
|
return;
|
|
6582
6584
|
}
|
|
@@ -7214,11 +7216,11 @@ async function cloudflareProviderHttpErrorWithBody(operation, response, context
|
|
|
7214
7216
|
...cause ? { cause } : {}
|
|
7215
7217
|
});
|
|
7216
7218
|
}
|
|
7217
|
-
function cloudflareRetryabilityForStatus(
|
|
7218
|
-
if (
|
|
7219
|
+
function cloudflareRetryabilityForStatus(status2) {
|
|
7220
|
+
if (status2 === 500 || status2 === 503) {
|
|
7219
7221
|
return true;
|
|
7220
7222
|
}
|
|
7221
|
-
if (
|
|
7223
|
+
if (status2 === 400) {
|
|
7222
7224
|
return false;
|
|
7223
7225
|
}
|
|
7224
7226
|
return null;
|
|
@@ -7256,7 +7258,7 @@ function truncateCloudflareErrorBody(body) {
|
|
|
7256
7258
|
return body.length > 500 ? `${body.slice(0, 497)}...` : body;
|
|
7257
7259
|
}
|
|
7258
7260
|
function waitForCloudflarePtyReady(socket) {
|
|
7259
|
-
return new Promise((
|
|
7261
|
+
return new Promise((resolve7, reject) => {
|
|
7260
7262
|
let removeMessage = () => {
|
|
7261
7263
|
};
|
|
7262
7264
|
let removeClose = () => {
|
|
@@ -7278,7 +7280,7 @@ function waitForCloudflarePtyReady(socket) {
|
|
|
7278
7280
|
if (isRecord(payload)) {
|
|
7279
7281
|
if (payload.type === "ready") {
|
|
7280
7282
|
cleanup();
|
|
7281
|
-
|
|
7283
|
+
resolve7();
|
|
7282
7284
|
return;
|
|
7283
7285
|
}
|
|
7284
7286
|
if (payload.type === "error") {
|
|
@@ -7447,8 +7449,8 @@ function shouldParseStreamedPayloadAsSse(body, headers) {
|
|
|
7447
7449
|
if (contentType.split(";", 1)[0]?.trim() === "text/event-stream") {
|
|
7448
7450
|
return true;
|
|
7449
7451
|
}
|
|
7450
|
-
const
|
|
7451
|
-
return startsWithSseFrame(new TextDecoder().decode(
|
|
7452
|
+
const prefix2 = body.subarray(0, Math.min(body.byteLength, STREAMED_PAYLOAD_SSE_SNIFF_BYTES));
|
|
7453
|
+
return startsWithSseFrame(new TextDecoder().decode(prefix2));
|
|
7452
7454
|
}
|
|
7453
7455
|
function startsWithSseFrame(text) {
|
|
7454
7456
|
const trimmed = text.trimStart();
|
|
@@ -8344,7 +8346,7 @@ async function deleteDaytonaSandboxWithRetry(deleteSandbox) {
|
|
|
8344
8346
|
throw error;
|
|
8345
8347
|
}
|
|
8346
8348
|
attempt += 1;
|
|
8347
|
-
await new Promise((
|
|
8349
|
+
await new Promise((resolve7) => setTimeout(resolve7, delayMs));
|
|
8348
8350
|
}
|
|
8349
8351
|
}
|
|
8350
8352
|
}
|
|
@@ -8578,12 +8580,12 @@ function assertLocalWorkspaceEntryMetadataSupported(providerName, logicalPath, e
|
|
|
8578
8580
|
assertLocalWorkspaceEntryMetadataSupported(providerName, joinLogicalPath(logicalPath, childPath), childEntry, options);
|
|
8579
8581
|
}
|
|
8580
8582
|
}
|
|
8581
|
-
async function materializeEntries(workspaceRootPath, entries,
|
|
8583
|
+
async function materializeEntries(workspaceRootPath, entries, prefix2 = "", options = {}) {
|
|
8582
8584
|
await runLimited(Object.entries(entries), resolveManifestEntryConcurrency(options.concurrencyLimits), async ([path, entry]) => {
|
|
8583
8585
|
if (options.skipMountEntries && isMount(entry)) {
|
|
8584
8586
|
return;
|
|
8585
8587
|
}
|
|
8586
|
-
const logicalPath =
|
|
8588
|
+
const logicalPath = prefix2 ? `${prefix2}/${normalizeRelativePath(path)}` : normalizeRelativePath(path);
|
|
8587
8589
|
await materializeLocalWorkspaceManifestEntry(workspaceRootPath, logicalPath, entry, options);
|
|
8588
8590
|
});
|
|
8589
8591
|
}
|
|
@@ -10280,13 +10282,13 @@ var UnixLocalSandboxSession = class {
|
|
|
10280
10282
|
trackChildProcess(child, options = {}) {
|
|
10281
10283
|
let resolveDone = () => {
|
|
10282
10284
|
};
|
|
10283
|
-
const donePromise = new Promise((
|
|
10284
|
-
resolveDone =
|
|
10285
|
+
const donePromise = new Promise((resolve7) => {
|
|
10286
|
+
resolveDone = resolve7;
|
|
10285
10287
|
});
|
|
10286
10288
|
let resolveOutputClosed = () => {
|
|
10287
10289
|
};
|
|
10288
|
-
const outputClosedPromise = new Promise((
|
|
10289
|
-
resolveOutputClosed =
|
|
10290
|
+
const outputClosedPromise = new Promise((resolve7) => {
|
|
10291
|
+
resolveOutputClosed = resolve7;
|
|
10290
10292
|
});
|
|
10291
10293
|
const activeProcess = {
|
|
10292
10294
|
child,
|
|
@@ -10568,13 +10570,13 @@ function buildCommandEnvironment(args) {
|
|
|
10568
10570
|
};
|
|
10569
10571
|
}
|
|
10570
10572
|
function translateRootManifestCommandInput(command, workspaceRootPath) {
|
|
10571
|
-
return command.replace(/(^|[\s"'=<>])\/([^\s"'|&;<>(){}]*)/g, (_match,
|
|
10573
|
+
return command.replace(/(^|[\s"'=<>])\/([^\s"'|&;<>(){}]*)/g, (_match, prefix2, pathSuffix) => `${prefix2}${workspaceRootPath}/${pathSuffix}`);
|
|
10572
10574
|
}
|
|
10573
10575
|
function translateManifestRootCommandInput(command, manifestRoot, workspaceRootPath) {
|
|
10574
10576
|
const escapedManifestRoot = escapeRegExp(manifestRoot);
|
|
10575
10577
|
const pathPrefix = String.raw`(^|[\s"'=<>])`;
|
|
10576
10578
|
const pathSuffix = String.raw`(?=$|[\/\s"'|&;<>(){}])`;
|
|
10577
|
-
return command.replace(new RegExp(`${pathPrefix}${escapedManifestRoot}${pathSuffix}`, "g"), (_match,
|
|
10579
|
+
return command.replace(new RegExp(`${pathPrefix}${escapedManifestRoot}${pathSuffix}`, "g"), (_match, prefix2) => `${prefix2}${workspaceRootPath}`);
|
|
10578
10580
|
}
|
|
10579
10581
|
function translateRootManifestCommandOutput(output, workspaceRootPath) {
|
|
10580
10582
|
return translateWorkspaceRootCommandOutput(output, "/", workspaceRootPath);
|
|
@@ -10665,7 +10667,7 @@ async function waitForProcessOrTimeout(activeProcess, timeoutMs) {
|
|
|
10665
10667
|
}
|
|
10666
10668
|
await Promise.race([
|
|
10667
10669
|
activeProcess.donePromise,
|
|
10668
|
-
new Promise((
|
|
10670
|
+
new Promise((resolve7) => setTimeout(resolve7, timeoutMs))
|
|
10669
10671
|
]);
|
|
10670
10672
|
if (activeProcess.done) {
|
|
10671
10673
|
await activeProcess.outputClosedPromise;
|
|
@@ -11754,13 +11756,13 @@ async function runDockerProcess(args, input) {
|
|
|
11754
11756
|
child.stderr.on("data", (chunk) => {
|
|
11755
11757
|
stderrChunks.push(chunk);
|
|
11756
11758
|
});
|
|
11757
|
-
const closed = new Promise((
|
|
11759
|
+
const closed = new Promise((resolve7) => {
|
|
11758
11760
|
child.on("close", (code) => {
|
|
11759
|
-
|
|
11761
|
+
resolve7(code ?? 1);
|
|
11760
11762
|
});
|
|
11761
11763
|
child.on("error", (error) => {
|
|
11762
11764
|
stderrChunks.push(Buffer.from(error.message));
|
|
11763
|
-
|
|
11765
|
+
resolve7(1);
|
|
11764
11766
|
});
|
|
11765
11767
|
});
|
|
11766
11768
|
if (input !== void 0) {
|
|
@@ -12952,8 +12954,8 @@ function dockerRcloneBoxOptions(entry) {
|
|
|
12952
12954
|
"box-owned-by": entry.ownedBy
|
|
12953
12955
|
});
|
|
12954
12956
|
}
|
|
12955
|
-
function joinRemotePath2(base,
|
|
12956
|
-
const normalizedPrefix =
|
|
12957
|
+
function joinRemotePath2(base, prefix2) {
|
|
12958
|
+
const normalizedPrefix = prefix2?.replace(/^\/+|\/+$/gu, "");
|
|
12957
12959
|
return normalizedPrefix ? `${base}/${normalizedPrefix}` : base;
|
|
12958
12960
|
}
|
|
12959
12961
|
function normalizeBoxRemotePath2(path) {
|
|
@@ -13984,17 +13986,17 @@ function buildModalCloudBucketMountConfig(mount, options = {}) {
|
|
|
13984
13986
|
sessionToken,
|
|
13985
13987
|
mountType: mount.type
|
|
13986
13988
|
});
|
|
13987
|
-
const
|
|
13989
|
+
const credentials2 = compactCredentials({
|
|
13988
13990
|
AWS_ACCESS_KEY_ID: accessKeyId,
|
|
13989
13991
|
AWS_SECRET_ACCESS_KEY: secretAccessKey,
|
|
13990
13992
|
AWS_SESSION_TOKEN: sessionToken
|
|
13991
13993
|
});
|
|
13992
|
-
assertNoInlineCredentialsWithSecret(mount,
|
|
13994
|
+
assertNoInlineCredentialsWithSecret(mount, credentials2, options.secretName);
|
|
13993
13995
|
return {
|
|
13994
13996
|
bucketName: mount.bucket,
|
|
13995
13997
|
bucketEndpointUrl: mount.endpointUrl,
|
|
13996
13998
|
keyPrefix: mount.prefix,
|
|
13997
|
-
credentials,
|
|
13999
|
+
credentials: credentials2,
|
|
13998
14000
|
secretName: options.secretName,
|
|
13999
14001
|
secretEnvironmentName: options.secretEnvironmentName,
|
|
14000
14002
|
readOnly: mount.readOnly ?? true
|
|
@@ -14008,11 +14010,11 @@ function buildModalCloudBucketMountConfig(mount, options = {}) {
|
|
|
14008
14010
|
secretAccessKey,
|
|
14009
14011
|
mountType: mount.type
|
|
14010
14012
|
});
|
|
14011
|
-
const
|
|
14013
|
+
const credentials2 = compactCredentials({
|
|
14012
14014
|
AWS_ACCESS_KEY_ID: accessKeyId,
|
|
14013
14015
|
AWS_SECRET_ACCESS_KEY: secretAccessKey
|
|
14014
14016
|
});
|
|
14015
|
-
assertNoInlineCredentialsWithSecret(mount,
|
|
14017
|
+
assertNoInlineCredentialsWithSecret(mount, credentials2, options.secretName);
|
|
14016
14018
|
const customDomain = readOptionalString(mount, "customDomain");
|
|
14017
14019
|
if (!customDomain && !mount.accountId) {
|
|
14018
14020
|
throw new SandboxMountError("Modal R2 bucket mounts require accountId or customDomain.", {
|
|
@@ -14024,7 +14026,7 @@ function buildModalCloudBucketMountConfig(mount, options = {}) {
|
|
|
14024
14026
|
bucketName: mount.bucket,
|
|
14025
14027
|
bucketEndpointUrl: customDomain ?? `https://${mount.accountId}.r2.cloudflarestorage.com`,
|
|
14026
14028
|
keyPrefix: mount.prefix,
|
|
14027
|
-
credentials,
|
|
14029
|
+
credentials: credentials2,
|
|
14028
14030
|
secretName: options.secretName,
|
|
14029
14031
|
secretEnvironmentName: options.secretEnvironmentName,
|
|
14030
14032
|
readOnly: mount.readOnly ?? true
|
|
@@ -14045,16 +14047,16 @@ function buildModalCloudBucketMountConfig(mount, options = {}) {
|
|
|
14045
14047
|
mountType: mount.type
|
|
14046
14048
|
});
|
|
14047
14049
|
}
|
|
14048
|
-
const
|
|
14050
|
+
const credentials2 = accessId && secretAccessKey ? {
|
|
14049
14051
|
GOOGLE_ACCESS_KEY_ID: accessId,
|
|
14050
14052
|
GOOGLE_ACCESS_KEY_SECRET: secretAccessKey
|
|
14051
14053
|
} : void 0;
|
|
14052
|
-
assertNoInlineCredentialsWithSecret(mount,
|
|
14054
|
+
assertNoInlineCredentialsWithSecret(mount, credentials2, options.secretName);
|
|
14053
14055
|
return {
|
|
14054
14056
|
bucketName: mount.bucket,
|
|
14055
14057
|
bucketEndpointUrl: endpointUrl ?? "https://storage.googleapis.com",
|
|
14056
14058
|
keyPrefix: mount.prefix,
|
|
14057
|
-
credentials,
|
|
14059
|
+
credentials: credentials2,
|
|
14058
14060
|
secretName: options.secretName,
|
|
14059
14061
|
secretEnvironmentName: options.secretEnvironmentName,
|
|
14060
14062
|
readOnly: mount.readOnly ?? true
|
|
@@ -14089,16 +14091,16 @@ function validateSecretOptions(mount, options) {
|
|
|
14089
14091
|
});
|
|
14090
14092
|
}
|
|
14091
14093
|
}
|
|
14092
|
-
function assertNoInlineCredentialsWithSecret(mount,
|
|
14093
|
-
if (secretName &&
|
|
14094
|
+
function assertNoInlineCredentialsWithSecret(mount, credentials2, secretName) {
|
|
14095
|
+
if (secretName && credentials2 && Object.keys(credentials2).length > 0) {
|
|
14094
14096
|
throw new SandboxMountError("Modal cloud bucket mounts do not support both inline credentials and secretName.", {
|
|
14095
14097
|
provider: "modal",
|
|
14096
14098
|
mountType: mount.type
|
|
14097
14099
|
});
|
|
14098
14100
|
}
|
|
14099
14101
|
}
|
|
14100
|
-
function compactCredentials(
|
|
14101
|
-
const compact = Object.fromEntries(Object.entries(
|
|
14102
|
+
function compactCredentials(credentials2) {
|
|
14103
|
+
const compact = Object.fromEntries(Object.entries(credentials2).filter(([, value]) => value !== void 0));
|
|
14102
14104
|
return Object.keys(compact).length > 0 ? compact : void 0;
|
|
14103
14105
|
}
|
|
14104
14106
|
function validateCredentialPair6(args) {
|
|
@@ -14337,9 +14339,9 @@ var ModalSandboxSession = class {
|
|
|
14337
14339
|
stderr += chunk;
|
|
14338
14340
|
});
|
|
14339
14341
|
try {
|
|
14340
|
-
const
|
|
14342
|
+
const status2 = await process2.wait();
|
|
14341
14343
|
await stderrPump.promise;
|
|
14342
|
-
return { status, stderr };
|
|
14344
|
+
return { status: status2, stderr };
|
|
14343
14345
|
} catch (error) {
|
|
14344
14346
|
await stderrPump.cancel();
|
|
14345
14347
|
throw error;
|
|
@@ -15475,8 +15477,8 @@ async function waitForProcessOrTimeout2(activeProcess, timeoutMs) {
|
|
|
15475
15477
|
try {
|
|
15476
15478
|
await Promise.race([
|
|
15477
15479
|
activeProcess.donePromise,
|
|
15478
|
-
new Promise((
|
|
15479
|
-
timeout = setTimeout(
|
|
15480
|
+
new Promise((resolve7) => {
|
|
15481
|
+
timeout = setTimeout(resolve7, timeoutMs);
|
|
15480
15482
|
unrefTimer(timeout);
|
|
15481
15483
|
})
|
|
15482
15484
|
]);
|
|
@@ -15652,9 +15654,9 @@ function normalizeWindowsAbsolutePath(value) {
|
|
|
15652
15654
|
throw new TypeError("Connected Machine device-namespace paths are not supported");
|
|
15653
15655
|
}
|
|
15654
15656
|
if (WINDOWS_DRIVE_ABSOLUTE.test(portable)) {
|
|
15655
|
-
const
|
|
15657
|
+
const prefix2 = `${portable[0].toUpperCase()}:/`;
|
|
15656
15658
|
const normalized = normalizeSegments(portable.slice(3).split("/"), 0).join("/");
|
|
15657
|
-
return normalized ? `${
|
|
15659
|
+
return normalized ? `${prefix2}${normalized}` : prefix2;
|
|
15658
15660
|
}
|
|
15659
15661
|
if (WINDOWS_UNC_ABSOLUTE.test(portable)) {
|
|
15660
15662
|
const segments = portable.slice(2).split("/").filter(Boolean);
|
|
@@ -15770,22 +15772,22 @@ function parseExecResponseBanner(raw) {
|
|
|
15770
15772
|
}
|
|
15771
15773
|
if (delimiter.index > EXEC_BANNER_HEADER_MAX_CHARS) return { kind: "invalid" };
|
|
15772
15774
|
const header = raw.slice(0, delimiter.index);
|
|
15773
|
-
const
|
|
15775
|
+
const status2 = [];
|
|
15774
15776
|
for (const line of header.split(/\r?\n/u)) {
|
|
15775
15777
|
const running = RUNNING_LINE.exec(line);
|
|
15776
15778
|
if (running) {
|
|
15777
|
-
|
|
15779
|
+
status2.push({ kind: "running", value: running[1] });
|
|
15778
15780
|
continue;
|
|
15779
15781
|
}
|
|
15780
15782
|
const exited = EXITED_LINE.exec(line);
|
|
15781
15783
|
if (exited) {
|
|
15782
|
-
|
|
15784
|
+
status2.push({ kind: "exited", value: exited[1] });
|
|
15783
15785
|
continue;
|
|
15784
15786
|
}
|
|
15785
15787
|
if (PROCESS_STATUS_PREFIX.test(line)) return { kind: "invalid" };
|
|
15786
15788
|
}
|
|
15787
|
-
if (
|
|
15788
|
-
const terminal =
|
|
15789
|
+
if (status2.length !== 1) return { kind: "invalid" };
|
|
15790
|
+
const terminal = status2[0];
|
|
15789
15791
|
const value = Number(terminal.value);
|
|
15790
15792
|
if (!Number.isSafeInteger(value)) return { kind: "invalid" };
|
|
15791
15793
|
if (terminal.kind === "running") {
|
|
@@ -15846,9 +15848,42 @@ function notifyDurableOpOwnershipTransferred(opId) {
|
|
|
15846
15848
|
storage.getStore()?.onDurableOpOwnershipTransferred?.(opId);
|
|
15847
15849
|
}
|
|
15848
15850
|
|
|
15851
|
+
// src/sandbox/routing/routing-session.ts
|
|
15852
|
+
import { isDeepStrictEqual } from "util";
|
|
15853
|
+
|
|
15849
15854
|
// src/sandbox/provider-command-session.ts
|
|
15850
15855
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
15856
|
+
var ProviderCommandStartRejectedError = class extends Error {
|
|
15857
|
+
constructor(cause) {
|
|
15858
|
+
super("Provider rejected command before start", { cause });
|
|
15859
|
+
this.name = "ProviderCommandStartRejectedError";
|
|
15860
|
+
}
|
|
15861
|
+
};
|
|
15851
15862
|
var admission = new AsyncLocalStorage2();
|
|
15863
|
+
var pendingSupervision = new AsyncLocalStorage2();
|
|
15864
|
+
function withPendingCommandSupervision(state, fn) {
|
|
15865
|
+
return state ? pendingSupervision.run(state, fn) : fn();
|
|
15866
|
+
}
|
|
15867
|
+
function markPendingCommandSupervised() {
|
|
15868
|
+
const state = pendingSupervision.getStore();
|
|
15869
|
+
if (state) state.managed = true;
|
|
15870
|
+
}
|
|
15871
|
+
var supervisionReady = new AsyncLocalStorage2();
|
|
15872
|
+
var supervisedLaunch = new AsyncLocalStorage2();
|
|
15873
|
+
function withSupervisedLaunchReservation(reservation, fn) {
|
|
15874
|
+
return supervisedLaunch.run(reservation, fn);
|
|
15875
|
+
}
|
|
15876
|
+
async function reserveSupervisedLaunch(command) {
|
|
15877
|
+
const reservation = supervisedLaunch.getStore();
|
|
15878
|
+
if (!reservation) throw new Error("Supervised launch requires durable pre-dispatch reservation");
|
|
15879
|
+
await reservation.reserve(command);
|
|
15880
|
+
}
|
|
15881
|
+
function withCommandSupervisionReady(ready, fn) {
|
|
15882
|
+
return supervisionReady.run(ready, fn);
|
|
15883
|
+
}
|
|
15884
|
+
function admittedCommandSupervisionReady() {
|
|
15885
|
+
return supervisionReady.getStore() === true;
|
|
15886
|
+
}
|
|
15852
15887
|
var MAX_PROVIDER_COMMAND_HANDLE = 2147483647;
|
|
15853
15888
|
function withProviderCommandHandle(handle, fn) {
|
|
15854
15889
|
if (handle === void 0) return fn();
|
|
@@ -15860,6 +15895,36 @@ function admittedProviderCommandHandle() {
|
|
|
15860
15895
|
return admission.getStore();
|
|
15861
15896
|
}
|
|
15862
15897
|
|
|
15898
|
+
// src/sandbox/materialization-verification-error.ts
|
|
15899
|
+
var EXPLANATIONS = {
|
|
15900
|
+
path_not_visible: "the provider could not see the destination path",
|
|
15901
|
+
command_failed: "the visibility-check command exited unsuccessfully",
|
|
15902
|
+
command_pending: "the visibility-check command was still running; path visibility is unconfirmed",
|
|
15903
|
+
invalid_response: "the visibility check returned no valid success confirmation",
|
|
15904
|
+
command_error: "the provider could not complete the visibility-check command"
|
|
15905
|
+
};
|
|
15906
|
+
var SandboxMaterializationVerificationError = class extends Error {
|
|
15907
|
+
constructor(diagnostic, options) {
|
|
15908
|
+
super(
|
|
15909
|
+
`Sandbox materialization verification failed: ${EXPLANATIONS[diagnostic.reason]}: ${diagnostic.path}`,
|
|
15910
|
+
options
|
|
15911
|
+
);
|
|
15912
|
+
this.diagnostic = diagnostic;
|
|
15913
|
+
this.name = "SandboxMaterializationVerificationError";
|
|
15914
|
+
}
|
|
15915
|
+
code = "sandbox_materialization_verification_failed";
|
|
15916
|
+
};
|
|
15917
|
+
var providerDiagnostics = /* @__PURE__ */ new WeakMap();
|
|
15918
|
+
function retainMaterializationVerificationDiagnostic(error, diagnostic) {
|
|
15919
|
+
if (error !== null && (typeof error === "object" || typeof error === "function")) {
|
|
15920
|
+
providerDiagnostics.set(error, diagnostic);
|
|
15921
|
+
}
|
|
15922
|
+
}
|
|
15923
|
+
function materializationVerificationDiagnostic(error) {
|
|
15924
|
+
if (error instanceof SandboxMaterializationVerificationError) return error.diagnostic;
|
|
15925
|
+
return error !== null && (typeof error === "object" || typeof error === "function") ? providerDiagnostics.get(error) : void 0;
|
|
15926
|
+
}
|
|
15927
|
+
|
|
15863
15928
|
// src/sandbox/routing/routing-session.ts
|
|
15864
15929
|
import { CAPABILITY_DESCRIPTORS as CAPABILITY_DESCRIPTORS2 } from "@opengeni/contracts";
|
|
15865
15930
|
|
|
@@ -16295,6 +16360,11 @@ function renderSelfhostedFault(error) {
|
|
|
16295
16360
|
}
|
|
16296
16361
|
|
|
16297
16362
|
// src/sandbox/routing/routing-session.ts
|
|
16363
|
+
function eligibleForSupervision(args) {
|
|
16364
|
+
return Boolean(
|
|
16365
|
+
args && typeof args === "object" && !args.tty && !args.runAs
|
|
16366
|
+
);
|
|
16367
|
+
}
|
|
16298
16368
|
function recordFirstOperationPhase(timing, phase, durationMs, outcome) {
|
|
16299
16369
|
if (!timing) return;
|
|
16300
16370
|
const prior = timing.phases[phase];
|
|
@@ -16491,6 +16561,7 @@ var RoutingSandboxSession = class {
|
|
|
16491
16561
|
cachedEpoch;
|
|
16492
16562
|
cachedSandboxId;
|
|
16493
16563
|
cached;
|
|
16564
|
+
homeResolutions = /* @__PURE__ */ new Map();
|
|
16494
16565
|
// The last-resolved backend, exposed via the `state` getter (a method-free read
|
|
16495
16566
|
// of the active backend's `state`). Updated on every resolve.
|
|
16496
16567
|
lastResolved;
|
|
@@ -16573,6 +16644,18 @@ var RoutingSandboxSession = class {
|
|
|
16573
16644
|
if (this.cachedEpoch === pointer.activeEpoch && this.cachedSandboxId === pointer.activeSandboxId && this.cached) {
|
|
16574
16645
|
return this.cached;
|
|
16575
16646
|
}
|
|
16647
|
+
if (pointer.activeSandboxId !== null) return await this.resolvePointer(pointer);
|
|
16648
|
+
const pending = this.homeResolutions.get(pointer.activeEpoch);
|
|
16649
|
+
if (pending) return await pending;
|
|
16650
|
+
const resolution = this.resolvePointer(pointer);
|
|
16651
|
+
this.homeResolutions.set(pointer.activeEpoch, resolution);
|
|
16652
|
+
try {
|
|
16653
|
+
return await resolution;
|
|
16654
|
+
} finally {
|
|
16655
|
+
this.homeResolutions.delete(pointer.activeEpoch);
|
|
16656
|
+
}
|
|
16657
|
+
}
|
|
16658
|
+
async resolvePointer(pointer) {
|
|
16576
16659
|
const fromEpoch = this.cachedEpoch ?? pointer.activeEpoch;
|
|
16577
16660
|
const resolved = await this.deps.resolveActiveBackend(pointer);
|
|
16578
16661
|
if (resolved.session === this) {
|
|
@@ -16934,6 +17017,15 @@ var RoutingSandboxSession = class {
|
|
|
16934
17017
|
const providerSessionId = providerSessionIdFromArgs(args);
|
|
16935
17018
|
if (providerSessionId === null) throw new RoutingRetainedProcessNotFoundError(-1);
|
|
16936
17019
|
const record = this.retainedProcess(providerSessionId);
|
|
17020
|
+
if (!modelVisible && args && typeof args === "object" && args.chars === "" && record.process.providerCommand?.kind === "modal-router-v1" && record.process.providerCommand.supervision) {
|
|
17021
|
+
await this.ensureParentPromotion(record);
|
|
17022
|
+
if (!await record.backend.session.cancelSupervisedCommand?.(
|
|
17023
|
+
providerSessionId,
|
|
17024
|
+
"explicit_stop"
|
|
17025
|
+
))
|
|
17026
|
+
throw new Error("Supervised command cancellation is unavailable");
|
|
17027
|
+
args = { ...args, chars: "" };
|
|
17028
|
+
}
|
|
16937
17029
|
await this.captureRetainedOutput(record);
|
|
16938
17030
|
const priorTerminal = await this.flushPendingProcessMutation(record);
|
|
16939
17031
|
if (priorTerminal !== null) {
|
|
@@ -16965,6 +17057,23 @@ var RoutingSandboxSession = class {
|
|
|
16965
17057
|
}
|
|
16966
17058
|
async captureRetainedOutput(record, result) {
|
|
16967
17059
|
if (!this.deps.captureProcessOutput) return;
|
|
17060
|
+
const atomicReceipt = record.pendingProviderReceipt ?? (typeof result === "string" ? result : void 0);
|
|
17061
|
+
if (atomicReceipt && record.backend.session.captureCommandOutput && record.backend.session.getProviderCommandOutput?.(atomicReceipt)?.command.kind === "modal-router-v1") {
|
|
17062
|
+
record.pendingProviderReceipt = atomicReceipt;
|
|
17063
|
+
try {
|
|
17064
|
+
if (await record.backend.session.captureCommandOutput(atomicReceipt)) {
|
|
17065
|
+
delete record.pendingProviderReceipt;
|
|
17066
|
+
return;
|
|
17067
|
+
}
|
|
17068
|
+
} catch (error) {
|
|
17069
|
+
throw new RoutingMutationOutcomeUnknownError(
|
|
17070
|
+
"captureProcessOutput",
|
|
17071
|
+
"Provider output atomic capture remains pending; the provider operation was not replayed",
|
|
17072
|
+
{ cause: error, retainedProcess: record.process }
|
|
17073
|
+
);
|
|
17074
|
+
}
|
|
17075
|
+
delete record.pendingProviderReceipt;
|
|
17076
|
+
}
|
|
16968
17077
|
const providerPage = record.backend.session.getProviderCommandOutput?.(result);
|
|
16969
17078
|
const structured = result && typeof result === "object" ? result : null;
|
|
16970
17079
|
if (providerPage) {
|
|
@@ -17038,17 +17147,29 @@ var RoutingSandboxSession = class {
|
|
|
17038
17147
|
* A non-fence error propagates immediately (it is a real op failure, not a swap
|
|
17039
17148
|
* race).
|
|
17040
17149
|
*/
|
|
17041
|
-
async dispatch(op, mutatesWorkspace, fn) {
|
|
17150
|
+
async dispatch(op, mutatesWorkspace, fn, supervisionEligible = false) {
|
|
17042
17151
|
const firstOperationObserver = this.deps.onFirstOperation;
|
|
17043
17152
|
if (this.firstOperationClaimed || !firstOperationObserver) {
|
|
17044
|
-
return await this.dispatchWithRetries(
|
|
17153
|
+
return await this.dispatchWithRetries(
|
|
17154
|
+
op,
|
|
17155
|
+
mutatesWorkspace,
|
|
17156
|
+
fn,
|
|
17157
|
+
void 0,
|
|
17158
|
+
supervisionEligible
|
|
17159
|
+
);
|
|
17045
17160
|
}
|
|
17046
17161
|
this.firstOperationClaimed = true;
|
|
17047
17162
|
const startedAt = performance.now();
|
|
17048
17163
|
const timing = { phases: {} };
|
|
17049
17164
|
let outcome = "failed";
|
|
17050
17165
|
try {
|
|
17051
|
-
const result = await this.dispatchWithRetries(
|
|
17166
|
+
const result = await this.dispatchWithRetries(
|
|
17167
|
+
op,
|
|
17168
|
+
mutatesWorkspace,
|
|
17169
|
+
fn,
|
|
17170
|
+
timing,
|
|
17171
|
+
supervisionEligible
|
|
17172
|
+
);
|
|
17052
17173
|
outcome = "completed";
|
|
17053
17174
|
return result;
|
|
17054
17175
|
} finally {
|
|
@@ -17063,7 +17184,24 @@ var RoutingSandboxSession = class {
|
|
|
17063
17184
|
}
|
|
17064
17185
|
}
|
|
17065
17186
|
}
|
|
17066
|
-
|
|
17187
|
+
/** Classify loss on the copied backend, including read-only preflight. This
|
|
17188
|
+
* path never admits work or retries the failed operation on a new route. */
|
|
17189
|
+
async throwProviderError(op, backend, error) {
|
|
17190
|
+
if (!isFenceError(error) && backend.sandboxId === null && this.deps.onDefaultBackendError) {
|
|
17191
|
+
const loss = await this.deps.onDefaultBackendError({
|
|
17192
|
+
op,
|
|
17193
|
+
error,
|
|
17194
|
+
kind: backend.kind,
|
|
17195
|
+
backend
|
|
17196
|
+
});
|
|
17197
|
+
if (loss) {
|
|
17198
|
+
this.invalidate(backend);
|
|
17199
|
+
throw new RoutingBackendRecoveryRequiredError(op, loss.leaseEpoch, loss.recovery);
|
|
17200
|
+
}
|
|
17201
|
+
}
|
|
17202
|
+
throw error;
|
|
17203
|
+
}
|
|
17204
|
+
async dispatchWithRetries(op, mutatesWorkspace, fn, firstOperationTiming, supervisionEligible = false) {
|
|
17067
17205
|
let attempt = 0;
|
|
17068
17206
|
let lastError;
|
|
17069
17207
|
while (attempt <= this.maxFenceRetries) {
|
|
@@ -17081,7 +17219,23 @@ var RoutingSandboxSession = class {
|
|
|
17081
17219
|
resolutionOutcome
|
|
17082
17220
|
);
|
|
17083
17221
|
}
|
|
17222
|
+
const supervisionReady2 = supervisionEligible && backend.kind === "modal" && (await this.deps.providerSupervisionReady?.() ?? false);
|
|
17223
|
+
let verifiedSupervision;
|
|
17224
|
+
if (supervisionReady2) {
|
|
17225
|
+
if (!backend.session.verifyCommandSupervisionCapability || !this.deps.afterMutation || !this.deps.providerCommandPersistence)
|
|
17226
|
+
throw new Error(
|
|
17227
|
+
"Supervised command requires exact-instance verification and durable reservation wiring"
|
|
17228
|
+
);
|
|
17229
|
+
try {
|
|
17230
|
+
verifiedSupervision = await backend.session.verifyCommandSupervisionCapability();
|
|
17231
|
+
} catch (error) {
|
|
17232
|
+
return await this.throwProviderError(op, backend, error);
|
|
17233
|
+
}
|
|
17234
|
+
if (backend.providerInstanceId && verifiedSupervision.sandboxId !== backend.providerInstanceId)
|
|
17235
|
+
throw new Error("Supervision capability does not match the admitted provider instance");
|
|
17236
|
+
}
|
|
17084
17237
|
let admission2;
|
|
17238
|
+
let reservedProcess;
|
|
17085
17239
|
if (mutatesWorkspace && this.deps.beforeMutation) {
|
|
17086
17240
|
const admissionStartedAt = performance.now();
|
|
17087
17241
|
let admissionWaitMs = 0;
|
|
@@ -17090,17 +17244,16 @@ var RoutingSandboxSession = class {
|
|
|
17090
17244
|
admission2 = await this.deps.beforeMutation({
|
|
17091
17245
|
op,
|
|
17092
17246
|
backend,
|
|
17093
|
-
|
|
17094
|
-
|
|
17095
|
-
|
|
17096
|
-
|
|
17097
|
-
|
|
17098
|
-
|
|
17099
|
-
|
|
17100
|
-
|
|
17101
|
-
|
|
17102
|
-
|
|
17103
|
-
} : {}
|
|
17247
|
+
onCaptureWait: (observation) => {
|
|
17248
|
+
admissionWaitMs += Math.max(0, observation.durationMs);
|
|
17249
|
+
recordFirstOperationPhase(
|
|
17250
|
+
firstOperationTiming,
|
|
17251
|
+
"snapshotWait",
|
|
17252
|
+
observation.durationMs,
|
|
17253
|
+
observation.outcome
|
|
17254
|
+
);
|
|
17255
|
+
this.observeCaptureWait(op, backend, "admission", observation);
|
|
17256
|
+
}
|
|
17104
17257
|
});
|
|
17105
17258
|
admissionOutcome = "completed";
|
|
17106
17259
|
} finally {
|
|
@@ -17123,9 +17276,50 @@ var RoutingSandboxSession = class {
|
|
|
17123
17276
|
backend,
|
|
17124
17277
|
() => withProviderCommandHandle(
|
|
17125
17278
|
this.deps.providerCommandHandle?.(admission2),
|
|
17126
|
-
() =>
|
|
17279
|
+
() => withCommandSupervisionReady(
|
|
17280
|
+
supervisionReady2,
|
|
17281
|
+
() => withSupervisedLaunchReservation(
|
|
17282
|
+
{
|
|
17283
|
+
reserve: async (command) => {
|
|
17284
|
+
const handle = this.deps.providerCommandHandle?.(admission2);
|
|
17285
|
+
if (!supervisionReady2 || !handle || reservedProcess || !command.supervision)
|
|
17286
|
+
throw new Error("Invalid supervised launch reservation");
|
|
17287
|
+
if (command.sandboxId !== verifiedSupervision?.sandboxId || command.taskId !== verifiedSupervision.taskId)
|
|
17288
|
+
throw new Error(
|
|
17289
|
+
"Modal task changed after supervision capability verification"
|
|
17290
|
+
);
|
|
17291
|
+
const process2 = {
|
|
17292
|
+
id: crypto.randomUUID(),
|
|
17293
|
+
providerSessionId: handle,
|
|
17294
|
+
providerCommand: command
|
|
17295
|
+
};
|
|
17296
|
+
reservedProcess = process2;
|
|
17297
|
+
const reservationResult = await this.deps.afterMutation({
|
|
17298
|
+
op,
|
|
17299
|
+
backend,
|
|
17300
|
+
admission: admission2,
|
|
17301
|
+
outcome: "resolved",
|
|
17302
|
+
retainedProcess: process2
|
|
17303
|
+
});
|
|
17304
|
+
if (reservationResult)
|
|
17305
|
+
throw new RoutingMutationOutcomeUnknownError(
|
|
17306
|
+
op,
|
|
17307
|
+
"Supervised launch reservation lost authority before dispatch",
|
|
17308
|
+
{ retainedProcess: process2 }
|
|
17309
|
+
);
|
|
17310
|
+
const persisted = await this.deps.providerCommandPersistence(process2).load();
|
|
17311
|
+
if (!persisted || !isDeepStrictEqual(persisted, command))
|
|
17312
|
+
throw new Error(
|
|
17313
|
+
"Supervised launch reservation did not retain the exact invocation"
|
|
17314
|
+
);
|
|
17315
|
+
this.registerRetainedProcess(process2, backend).durable = true;
|
|
17316
|
+
}
|
|
17317
|
+
},
|
|
17318
|
+
() => fn(backend.session, backend)
|
|
17319
|
+
)
|
|
17320
|
+
)
|
|
17127
17321
|
),
|
|
17128
|
-
|
|
17322
|
+
(observation) => {
|
|
17129
17323
|
providerWaitMs += Math.max(0, observation.durationMs);
|
|
17130
17324
|
recordFirstOperationPhase(
|
|
17131
17325
|
firstOperationTiming,
|
|
@@ -17133,7 +17327,8 @@ var RoutingSandboxSession = class {
|
|
|
17133
17327
|
observation.durationMs,
|
|
17134
17328
|
observation.outcome
|
|
17135
17329
|
);
|
|
17136
|
-
|
|
17330
|
+
this.observeCaptureWait(op, backend, "provider", observation);
|
|
17331
|
+
}
|
|
17137
17332
|
);
|
|
17138
17333
|
providerOutcome = "completed";
|
|
17139
17334
|
} finally {
|
|
@@ -17145,6 +17340,29 @@ var RoutingSandboxSession = class {
|
|
|
17145
17340
|
);
|
|
17146
17341
|
}
|
|
17147
17342
|
} catch (error) {
|
|
17343
|
+
if (reservedProcess) {
|
|
17344
|
+
if (error instanceof ProviderCommandStartRejectedError && reservedProcess.providerCommand?.kind === "modal-router-v1") {
|
|
17345
|
+
const persistence = this.deps.providerCommandPersistence?.(reservedProcess);
|
|
17346
|
+
if (persistence?.rejectSupervisedLaunch) {
|
|
17347
|
+
try {
|
|
17348
|
+
await persistence.rejectSupervisedLaunch(reservedProcess.providerCommand);
|
|
17349
|
+
} catch (cause) {
|
|
17350
|
+
throw new RoutingMutationOutcomeUnknownError(
|
|
17351
|
+
op,
|
|
17352
|
+
"Never-started provider rejection could not settle its exact reservation",
|
|
17353
|
+
{ cause, retainedProcess: reservedProcess }
|
|
17354
|
+
);
|
|
17355
|
+
}
|
|
17356
|
+
this.retainedProcesses.delete(reservedProcess.providerSessionId);
|
|
17357
|
+
throw error;
|
|
17358
|
+
}
|
|
17359
|
+
}
|
|
17360
|
+
throw new RoutingMutationOutcomeUnknownError(
|
|
17361
|
+
op,
|
|
17362
|
+
"Reserved supervised launch did not return; exact invocation retained and not replayed",
|
|
17363
|
+
{ cause: error, retainedProcess: reservedProcess }
|
|
17364
|
+
);
|
|
17365
|
+
}
|
|
17148
17366
|
const partialMutation = error instanceof ChannelAPartialMutationError;
|
|
17149
17367
|
if (mutatesWorkspace && this.deps.afterMutation) {
|
|
17150
17368
|
const settlementStartedAt = performance.now();
|
|
@@ -17181,19 +17399,7 @@ var RoutingSandboxSession = class {
|
|
|
17181
17399
|
);
|
|
17182
17400
|
}
|
|
17183
17401
|
if (!isFenceError(error)) {
|
|
17184
|
-
|
|
17185
|
-
const loss = await this.deps.onDefaultBackendError({
|
|
17186
|
-
op,
|
|
17187
|
-
error,
|
|
17188
|
-
kind: backend.kind,
|
|
17189
|
-
backend
|
|
17190
|
-
});
|
|
17191
|
-
if (loss) {
|
|
17192
|
-
this.invalidate(backend);
|
|
17193
|
-
throw new RoutingBackendRecoveryRequiredError(op, loss.leaseEpoch, loss.recovery);
|
|
17194
|
-
}
|
|
17195
|
-
}
|
|
17196
|
-
throw error;
|
|
17402
|
+
return await this.throwProviderError(op, backend, error);
|
|
17197
17403
|
}
|
|
17198
17404
|
this.invalidate(backend);
|
|
17199
17405
|
if (mutatesWorkspace) {
|
|
@@ -17209,13 +17415,13 @@ var RoutingSandboxSession = class {
|
|
|
17209
17415
|
}
|
|
17210
17416
|
const yieldedSessionId = mutatesWorkspace && (op === "exec" || op === "execCommand") ? providerSessionIdFromResult(result) : null;
|
|
17211
17417
|
const providerCommand = yieldedSessionId === null ? null : backend.session.getProviderCommand?.(yieldedSessionId);
|
|
17212
|
-
const retainedProcess = yieldedSessionId === null ? void 0 : {
|
|
17418
|
+
const retainedProcess = reservedProcess ?? (yieldedSessionId === null ? void 0 : {
|
|
17213
17419
|
id: crypto.randomUUID(),
|
|
17214
17420
|
providerSessionId: yieldedSessionId,
|
|
17215
17421
|
...providerCommand ? { providerCommand } : {}
|
|
17216
|
-
};
|
|
17217
|
-
const retainedRecord = retainedProcess ? this.registerRetainedProcess(retainedProcess, backend) : null;
|
|
17218
|
-
if (mutatesWorkspace && this.deps.afterMutation) {
|
|
17422
|
+
});
|
|
17423
|
+
const retainedRecord = retainedProcess ? reservedProcess ? this.retainedProcess(reservedProcess.providerSessionId) : this.registerRetainedProcess(retainedProcess, backend) : null;
|
|
17424
|
+
if (mutatesWorkspace && this.deps.afterMutation && !reservedProcess) {
|
|
17219
17425
|
const settlement = {
|
|
17220
17426
|
op,
|
|
17221
17427
|
backend,
|
|
@@ -17270,6 +17476,17 @@ var RoutingSandboxSession = class {
|
|
|
17270
17476
|
}
|
|
17271
17477
|
if (retainedRecord) {
|
|
17272
17478
|
await this.captureRetainedOutput(retainedRecord, result);
|
|
17479
|
+
try {
|
|
17480
|
+
await backend.session.releaseSupervisedCommand?.(
|
|
17481
|
+
retainedRecord.process.providerSessionId
|
|
17482
|
+
);
|
|
17483
|
+
} catch (cause) {
|
|
17484
|
+
throw new RoutingMutationOutcomeUnknownError(
|
|
17485
|
+
op,
|
|
17486
|
+
"Supervisor release is unresolved after durable retention; the exact command remains tracked and was not replayed",
|
|
17487
|
+
{ cause, retainedProcess: retainedRecord.process }
|
|
17488
|
+
);
|
|
17489
|
+
}
|
|
17273
17490
|
return result;
|
|
17274
17491
|
}
|
|
17275
17492
|
let current;
|
|
@@ -17302,14 +17519,28 @@ var RoutingSandboxSession = class {
|
|
|
17302
17519
|
}
|
|
17303
17520
|
throw lastError ?? new Error(`routing op "${op}" exhausted fence retries`);
|
|
17304
17521
|
}
|
|
17522
|
+
observeCaptureWait(op, backend, captureWaitStage, observation) {
|
|
17523
|
+
try {
|
|
17524
|
+
this.deps.onCaptureWait?.({
|
|
17525
|
+
backend: backend.kind,
|
|
17526
|
+
op,
|
|
17527
|
+
outcome: observation.outcome === "completed" ? "ok" : "failed",
|
|
17528
|
+
durationMs: observation.durationMs,
|
|
17529
|
+
captureWaitStage
|
|
17530
|
+
});
|
|
17531
|
+
} catch {
|
|
17532
|
+
}
|
|
17533
|
+
}
|
|
17305
17534
|
async invokeProviderOperation(op, backend, fn, onCaptureWait) {
|
|
17306
17535
|
const startedAt = performance.now();
|
|
17307
17536
|
let outcome = "failed";
|
|
17537
|
+
let materializationFailureReason;
|
|
17308
17538
|
try {
|
|
17309
17539
|
const result = await withSandboxProviderOperation(backend.session, fn, onCaptureWait);
|
|
17310
17540
|
outcome = "ok";
|
|
17311
17541
|
return result;
|
|
17312
17542
|
} catch (error) {
|
|
17543
|
+
materializationFailureReason = materializationVerificationDiagnostic(error)?.reason;
|
|
17313
17544
|
if ((op === "readFile" || op === "listDir" || op === "pathExists" || op === "viewImage") && isDefinitePathNotFoundError(error)) {
|
|
17314
17545
|
outcome = "not_found";
|
|
17315
17546
|
}
|
|
@@ -17320,7 +17551,8 @@ var RoutingSandboxSession = class {
|
|
|
17320
17551
|
backend: backend.kind,
|
|
17321
17552
|
op,
|
|
17322
17553
|
outcome,
|
|
17323
|
-
durationMs: Math.max(0, performance.now() - startedAt)
|
|
17554
|
+
durationMs: Math.max(0, performance.now() - startedAt),
|
|
17555
|
+
...materializationFailureReason ? { materializationFailureReason } : {}
|
|
17324
17556
|
});
|
|
17325
17557
|
} catch {
|
|
17326
17558
|
}
|
|
@@ -17355,28 +17587,38 @@ var RoutingSandboxSession = class {
|
|
|
17355
17587
|
// dispatches to the active backend at call-time. A missing backend method
|
|
17356
17588
|
// degrades via the natural fallback or RoutingUnsupportedError.
|
|
17357
17589
|
async exec(args) {
|
|
17358
|
-
return this.dispatch(
|
|
17359
|
-
|
|
17360
|
-
|
|
17361
|
-
|
|
17362
|
-
|
|
17363
|
-
|
|
17364
|
-
|
|
17365
|
-
|
|
17366
|
-
|
|
17590
|
+
return this.dispatch(
|
|
17591
|
+
"exec",
|
|
17592
|
+
true,
|
|
17593
|
+
async (s) => {
|
|
17594
|
+
if (s.exec) {
|
|
17595
|
+
return s.exec(args);
|
|
17596
|
+
}
|
|
17597
|
+
if (s.execCommand) {
|
|
17598
|
+
return structuredExecResultFromBanner(await s.execCommand(args));
|
|
17599
|
+
}
|
|
17600
|
+
throw new RoutingUnsupportedError("exec", this.cached?.kind ?? "unknown");
|
|
17601
|
+
},
|
|
17602
|
+
eligibleForSupervision(args)
|
|
17603
|
+
);
|
|
17367
17604
|
}
|
|
17368
17605
|
async execCommand(args) {
|
|
17369
17606
|
try {
|
|
17370
|
-
return await this.dispatch(
|
|
17371
|
-
|
|
17372
|
-
|
|
17373
|
-
|
|
17374
|
-
|
|
17375
|
-
|
|
17376
|
-
|
|
17377
|
-
|
|
17378
|
-
|
|
17379
|
-
|
|
17607
|
+
return await this.dispatch(
|
|
17608
|
+
"execCommand",
|
|
17609
|
+
true,
|
|
17610
|
+
async (s) => {
|
|
17611
|
+
if (s.execCommand) {
|
|
17612
|
+
return s.execCommand(args);
|
|
17613
|
+
}
|
|
17614
|
+
if (s.exec) {
|
|
17615
|
+
const r = await s.exec(args);
|
|
17616
|
+
return r.stdout ?? r.output ?? "";
|
|
17617
|
+
}
|
|
17618
|
+
throw new RoutingUnsupportedError("execCommand", this.cached?.kind ?? "unknown");
|
|
17619
|
+
},
|
|
17620
|
+
eligibleForSupervision(args)
|
|
17621
|
+
);
|
|
17380
17622
|
} catch (error) {
|
|
17381
17623
|
return this.renderSelfhostedFaultOrThrow(error);
|
|
17382
17624
|
}
|
|
@@ -17439,7 +17681,10 @@ var RoutingSandboxSession = class {
|
|
|
17439
17681
|
await this.writeStdinForProcessControl({
|
|
17440
17682
|
sessionId: record.process.providerSessionId,
|
|
17441
17683
|
chars: "",
|
|
17442
|
-
|
|
17684
|
+
// A near-zero provider long-poll can expire before even an already
|
|
17685
|
+
// completed command's terminal batch is delivered. Use the ordinary
|
|
17686
|
+
// bounded command-read window; never infer completion from silence.
|
|
17687
|
+
yieldTimeMs: 250
|
|
17443
17688
|
});
|
|
17444
17689
|
return true;
|
|
17445
17690
|
}
|
|
@@ -17495,6 +17740,15 @@ var RoutingSandboxSession = class {
|
|
|
17495
17740
|
async writeStdinForProcessControl(args) {
|
|
17496
17741
|
return await this.dispatchProcessControl(args);
|
|
17497
17742
|
}
|
|
17743
|
+
async cancelSupervisedCommand(providerSessionId, reason) {
|
|
17744
|
+
const record = this.retainedProcesses.get(providerSessionId);
|
|
17745
|
+
if (!record || record.process.providerCommand?.kind !== "modal-router-v1" || !record.process.providerCommand.supervision)
|
|
17746
|
+
return false;
|
|
17747
|
+
await this.ensureParentPromotion(record);
|
|
17748
|
+
if (!record.backend.session.cancelSupervisedCommand)
|
|
17749
|
+
throw new Error("Supervised command control is unavailable");
|
|
17750
|
+
return await record.backend.session.cancelSupervisedCommand(providerSessionId, reason);
|
|
17751
|
+
}
|
|
17498
17752
|
/** Empty-input eager reads belong to the model's foreground wait, while
|
|
17499
17753
|
* cancellation/drain reads use the non-observing control method above. */
|
|
17500
17754
|
async writeStdinForProcessRead(args) {
|
|
@@ -17511,6 +17765,10 @@ var RoutingSandboxSession = class {
|
|
|
17511
17765
|
const exactProviderSessionId = positiveProviderSessionId(providerSessionId);
|
|
17512
17766
|
if (exactProviderSessionId === null) throw new RoutingRetainedProcessNotFoundError(-1);
|
|
17513
17767
|
const record = this.retainedProcess(exactProviderSessionId);
|
|
17768
|
+
if (record.process.providerCommand?.kind === "modal-router-v1" && record.process.providerCommand.supervision)
|
|
17769
|
+
throw new Error(
|
|
17770
|
+
"Legacy process helpers are unavailable for a supervised command; use its native control protocol"
|
|
17771
|
+
);
|
|
17514
17772
|
const priorTerminal = await this.flushPendingProcessMutation(record);
|
|
17515
17773
|
if (priorTerminal !== null) return priorTerminal;
|
|
17516
17774
|
if (record.pendingTerminal) {
|
|
@@ -17793,6 +18051,9 @@ var RoutingSandboxSession = class {
|
|
|
17793
18051
|
};
|
|
17794
18052
|
var MATERIALIZED_PATH_MARKER = "__OPENGENI_MATERIALIZED_PATH_VISIBLE__";
|
|
17795
18053
|
async function assertProviderCanSeeMaterializedPath(session, path) {
|
|
18054
|
+
if (session.verifyMaterializedPath) {
|
|
18055
|
+
return session.verifyMaterializedPath(path, providerManifestRoot(session) ?? "/workspace");
|
|
18056
|
+
}
|
|
17796
18057
|
const command = `test -e ${shellSingleQuote(path)} && printf %s ${shellSingleQuote(
|
|
17797
18058
|
MATERIALIZED_PATH_MARKER
|
|
17798
18059
|
)}`;
|
|
@@ -17804,18 +18065,56 @@ async function assertProviderCanSeeMaterializedPath(session, path) {
|
|
|
17804
18065
|
tty: false
|
|
17805
18066
|
};
|
|
17806
18067
|
let output;
|
|
17807
|
-
|
|
17808
|
-
|
|
17809
|
-
} else if (session.exec) {
|
|
17810
|
-
output = formatExecResult(await session.exec(args));
|
|
17811
|
-
} else {
|
|
18068
|
+
let result;
|
|
18069
|
+
if (!session.execCommand && !session.exec) {
|
|
17812
18070
|
throw new RoutingUnsupportedError("materializeEntry.verify", "unknown");
|
|
17813
18071
|
}
|
|
17814
|
-
|
|
17815
|
-
|
|
17816
|
-
|
|
17817
|
-
|
|
18072
|
+
try {
|
|
18073
|
+
result = session.execCommand ? await session.execCommand(args) : await session.exec(args);
|
|
18074
|
+
} catch (cause) {
|
|
18075
|
+
retainMaterializationVerificationDiagnostic(cause, {
|
|
18076
|
+
reason: "command_error",
|
|
18077
|
+
path,
|
|
18078
|
+
workdir: args.workdir,
|
|
18079
|
+
command,
|
|
18080
|
+
output: null,
|
|
18081
|
+
exitCode: null,
|
|
18082
|
+
providerSessionId: null,
|
|
18083
|
+
causeMessage: cause instanceof Error ? cause.message : String(cause)
|
|
18084
|
+
});
|
|
18085
|
+
throw cause;
|
|
18086
|
+
}
|
|
18087
|
+
try {
|
|
18088
|
+
output = formatExecResult(result);
|
|
18089
|
+
} catch (cause) {
|
|
18090
|
+
const record = result && typeof result === "object" ? result : {};
|
|
18091
|
+
const returnedOutput = [record.output, record.stderr, record.stdout].filter((value) => typeof value === "string").join("\n");
|
|
18092
|
+
throw new SandboxMaterializationVerificationError({
|
|
18093
|
+
reason: "invalid_response",
|
|
18094
|
+
path,
|
|
18095
|
+
workdir: args.workdir,
|
|
18096
|
+
command,
|
|
18097
|
+
output: returnedOutput || null,
|
|
18098
|
+
exitCode: null,
|
|
18099
|
+
providerSessionId: null,
|
|
18100
|
+
causeMessage: cause instanceof Error ? cause.message : String(cause)
|
|
18101
|
+
});
|
|
18102
|
+
}
|
|
18103
|
+
const status2 = parseExecResponseBanner(output);
|
|
18104
|
+
const markerPresent = stripExecBanner(output).includes(MATERIALIZED_PATH_MARKER);
|
|
18105
|
+
if (markerPresent && (status2.kind === "absent" || status2.kind === "exited" && status2.exitCode === 0)) {
|
|
18106
|
+
return;
|
|
17818
18107
|
}
|
|
18108
|
+
const reason = status2.kind === "running" ? "command_pending" : status2.kind === "exited" && status2.exitCode === 1 ? "path_not_visible" : status2.kind === "exited" && status2.exitCode !== 0 ? "command_failed" : "invalid_response";
|
|
18109
|
+
throw new SandboxMaterializationVerificationError({
|
|
18110
|
+
reason,
|
|
18111
|
+
path,
|
|
18112
|
+
workdir: args.workdir,
|
|
18113
|
+
command,
|
|
18114
|
+
output,
|
|
18115
|
+
exitCode: status2.kind === "exited" ? status2.exitCode : null,
|
|
18116
|
+
providerSessionId: status2.kind === "running" ? status2.sessionId : null
|
|
18117
|
+
});
|
|
17819
18118
|
}
|
|
17820
18119
|
function providerManifestRoot(session) {
|
|
17821
18120
|
const root = session.state?.manifest?.root;
|
|
@@ -17959,7 +18258,7 @@ var SHELL_MARKER_DIR = "/tmp/opengeni-turn-shell";
|
|
|
17959
18258
|
var RETAINED_SHELL_MARKER_PENDING_EXIT_CODE = 74;
|
|
17960
18259
|
var RETAINED_SHELL_GROUP_LIVE_EXIT_CODE = 75;
|
|
17961
18260
|
var RETAINED_SHELL_PROOF_INCONCLUSIVE_EXIT_CODE = 76;
|
|
17962
|
-
var delay = async (milliseconds) => await new Promise((
|
|
18261
|
+
var delay = async (milliseconds) => await new Promise((resolve7) => setTimeout(resolve7, milliseconds));
|
|
17963
18262
|
async function usesRemoteOperationCancellation(session) {
|
|
17964
18263
|
const resolved = await session?.commandCancellationTransport?.();
|
|
17965
18264
|
if (resolved !== void 0) {
|
|
@@ -18441,7 +18740,10 @@ var TurnToolCancellationControllerImpl = class {
|
|
|
18441
18740
|
try {
|
|
18442
18741
|
initialNative = await runWithToolCallCorrelation(
|
|
18443
18742
|
correlationId,
|
|
18444
|
-
async () => await
|
|
18743
|
+
async () => await withPendingCommandSupervision(
|
|
18744
|
+
pendingStart?.supervision,
|
|
18745
|
+
() => invokeExecNative(commandInput)
|
|
18746
|
+
),
|
|
18445
18747
|
{
|
|
18446
18748
|
onDurableOpOwnershipTransferStarted: (opId) => remoteExec?.releaseCancellationAuthority(opId)
|
|
18447
18749
|
}
|
|
@@ -18692,7 +18994,10 @@ var TurnToolCancellationControllerImpl = class {
|
|
|
18692
18994
|
try {
|
|
18693
18995
|
output = await runWithToolCallCorrelation(
|
|
18694
18996
|
correlationId,
|
|
18695
|
-
async () => await
|
|
18997
|
+
async () => await withPendingCommandSupervision(
|
|
18998
|
+
pendingStart?.supervision,
|
|
18999
|
+
() => tool.invoke(runContext, cancellableInput, details)
|
|
19000
|
+
),
|
|
18696
19001
|
{
|
|
18697
19002
|
onDurableOpOwnershipTransferStarted: (opId) => remoteExec?.releaseCancellationAuthority(opId)
|
|
18698
19003
|
}
|
|
@@ -19005,11 +19310,12 @@ This process is turn-scoped; it will stop when this turn ends or is interrupted.
|
|
|
19005
19310
|
}
|
|
19006
19311
|
registerPendingShellStart(input) {
|
|
19007
19312
|
let resolveSettled;
|
|
19008
|
-
const settledPromise = new Promise((
|
|
19009
|
-
resolveSettled =
|
|
19313
|
+
const settledPromise = new Promise((resolve7) => {
|
|
19314
|
+
resolveSettled = resolve7;
|
|
19010
19315
|
});
|
|
19011
19316
|
const entry = {
|
|
19012
19317
|
...input,
|
|
19318
|
+
supervision: { managed: false },
|
|
19013
19319
|
cancellationPath: shellCancellationPath(input.markerPath),
|
|
19014
19320
|
settled: false,
|
|
19015
19321
|
settledPromise,
|
|
@@ -19041,6 +19347,10 @@ This process is turn-scoped; it will stop when this turn ends or is interrupted.
|
|
|
19041
19347
|
}
|
|
19042
19348
|
}
|
|
19043
19349
|
}
|
|
19350
|
+
if (state.supervision.managed) {
|
|
19351
|
+
await state.settledPromise;
|
|
19352
|
+
return;
|
|
19353
|
+
}
|
|
19044
19354
|
while (true) {
|
|
19045
19355
|
try {
|
|
19046
19356
|
const output = await this.invokePendingShellCancellationCommand(state);
|
|
@@ -19080,8 +19390,8 @@ This process is turn-scoped; it will stop when this turn ends or is interrupted.
|
|
|
19080
19390
|
}
|
|
19081
19391
|
registerRemoteExec(session, opId) {
|
|
19082
19392
|
let resolveSettled;
|
|
19083
|
-
const settledPromise = new Promise((
|
|
19084
|
-
resolveSettled =
|
|
19393
|
+
const settledPromise = new Promise((resolve7) => {
|
|
19394
|
+
resolveSettled = resolve7;
|
|
19085
19395
|
});
|
|
19086
19396
|
let cancellation = null;
|
|
19087
19397
|
const entry = {
|
|
@@ -19118,6 +19428,17 @@ This process is turn-scoped; it will stop when this turn ends or is interrupted.
|
|
|
19118
19428
|
return state.cancellation;
|
|
19119
19429
|
}
|
|
19120
19430
|
async cancelShellSessionOnce(state) {
|
|
19431
|
+
if (await state.processSession?.cancelSupervisedCommand?.(state.sessionId, "explicit_stop")) {
|
|
19432
|
+
while (state.processSession?.hasRetainedProcess?.(state.sessionId) === true) {
|
|
19433
|
+
if (await this.rawWrite(state, "", SHELL_POLL_MS)) {
|
|
19434
|
+
await this.forgetShellSessionAfterExactSettlement(state);
|
|
19435
|
+
return;
|
|
19436
|
+
}
|
|
19437
|
+
await delay(SHELL_POLL_MS);
|
|
19438
|
+
}
|
|
19439
|
+
this.shellSessions.delete(state.sessionId);
|
|
19440
|
+
return;
|
|
19441
|
+
}
|
|
19121
19442
|
if (!state.markerPath) {
|
|
19122
19443
|
while (true) {
|
|
19123
19444
|
if ((state.writeInvoke || state.processSession?.writeStdinForProcessControl) && await this.rawWrite(state, "", SHELL_POLL_MS)) {
|
|
@@ -19756,15 +20077,15 @@ var SandboxChannelAService = class {
|
|
|
19756
20077
|
if (stdout.includes("__OPENGENI_FS_NOT_FOUND__") || exitCode === 66) {
|
|
19757
20078
|
throw new ChannelANotFoundError(`file not found: ${path}`);
|
|
19758
20079
|
}
|
|
19759
|
-
const
|
|
19760
|
-
const successIndex = stdout.indexOf(
|
|
20080
|
+
const prefix2 = "__OPENGENI_FS_READ_OK__\n";
|
|
20081
|
+
const successIndex = stdout.indexOf(prefix2);
|
|
19761
20082
|
if (successIndex < 0 || exitCode !== null && exitCode !== 0) {
|
|
19762
20083
|
throw new ChannelAUnavailableError(
|
|
19763
20084
|
"Workspace files are temporarily unavailable. Retry the file read."
|
|
19764
20085
|
);
|
|
19765
20086
|
}
|
|
19766
20087
|
const bytes = Buffer.from(
|
|
19767
|
-
stdout.slice(successIndex +
|
|
20088
|
+
stdout.slice(successIndex + prefix2.length).replace(/\n/g, ""),
|
|
19768
20089
|
"base64"
|
|
19769
20090
|
);
|
|
19770
20091
|
return this.shapeRead(path, bytes, req);
|
|
@@ -20114,12 +20435,12 @@ var SandboxChannelAService = class {
|
|
|
20114
20435
|
if (result.stdout.includes(integrityMarker) || result.exitCode === 74) {
|
|
20115
20436
|
throw new ChannelAUnavailableError("Workspace file source failed integrity verification.");
|
|
20116
20437
|
}
|
|
20117
|
-
const
|
|
20118
|
-
const markerIndex = result.stdout.indexOf(
|
|
20438
|
+
const prefix2 = `${okMarker} `;
|
|
20439
|
+
const markerIndex = result.stdout.indexOf(prefix2);
|
|
20119
20440
|
if (markerIndex < 0 || result.exitCode !== null && result.exitCode !== 0 || result.stdout.includes(unavailableMarker)) {
|
|
20120
20441
|
throw new ChannelAUnavailableError("Workspace file import is temporarily unavailable.");
|
|
20121
20442
|
}
|
|
20122
|
-
const outcome = result.stdout.slice(markerIndex +
|
|
20443
|
+
const outcome = result.stdout.slice(markerIndex + prefix2.length).trim();
|
|
20123
20444
|
if (outcome !== "created" && outcome !== "replaced" && outcome !== "replayed") {
|
|
20124
20445
|
throw new ChannelAUnavailableError("Workspace file import returned an invalid receipt.");
|
|
20125
20446
|
}
|
|
@@ -20487,19 +20808,19 @@ var SandboxChannelAService = class {
|
|
|
20487
20808
|
}
|
|
20488
20809
|
async gitStatus(req) {
|
|
20489
20810
|
const repo = assertSafeRelPathOrRoot(req.path, this.workspaceRoot);
|
|
20490
|
-
const
|
|
20811
|
+
const status2 = await this.readConfinedCommandBytes(
|
|
20491
20812
|
repo,
|
|
20492
20813
|
`if [ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = true ]; then printf '${GIT_STATUS_REPO_FRAME}\\0'; git status --porcelain=v2 --branch -z; else printf '${GIT_STATUS_REPO_FRAME}not-repo\\0'; fi`,
|
|
20493
20814
|
GIT_METADATA_MAX_BYTES
|
|
20494
20815
|
);
|
|
20495
|
-
if (
|
|
20816
|
+
if (status2.truncated) {
|
|
20496
20817
|
throw new ChannelAUnavailableError(
|
|
20497
20818
|
"Workspace Git metadata exceeded the safe capture limit. Retry with a narrower path."
|
|
20498
20819
|
);
|
|
20499
20820
|
}
|
|
20500
20821
|
const repoFrame = Buffer.from(`${GIT_STATUS_REPO_FRAME}${NUL}`);
|
|
20501
20822
|
const notRepoFrame = Buffer.from(`${GIT_STATUS_REPO_FRAME}not-repo${NUL}`);
|
|
20502
|
-
if (
|
|
20823
|
+
if (status2.bytes.equals(notRepoFrame)) {
|
|
20503
20824
|
return {
|
|
20504
20825
|
isRepo: false,
|
|
20505
20826
|
head: null,
|
|
@@ -20512,13 +20833,13 @@ var SandboxChannelAService = class {
|
|
|
20512
20833
|
revision: this.revision
|
|
20513
20834
|
};
|
|
20514
20835
|
}
|
|
20515
|
-
if (!
|
|
20836
|
+
if (!status2.bytes.subarray(0, repoFrame.byteLength).equals(repoFrame)) {
|
|
20516
20837
|
throw new ChannelAUnavailableError(
|
|
20517
20838
|
"Workspace Git data is temporarily unavailable. Retry the operation."
|
|
20518
20839
|
);
|
|
20519
20840
|
}
|
|
20520
20841
|
return {
|
|
20521
|
-
...parsePorcelainV2(decodeGitMetadataUtf8(
|
|
20842
|
+
...parsePorcelainV2(decodeGitMetadataUtf8(status2.bytes.subarray(repoFrame.byteLength))),
|
|
20522
20843
|
revision: this.revision
|
|
20523
20844
|
};
|
|
20524
20845
|
}
|
|
@@ -20903,11 +21224,11 @@ var SandboxChannelAService = class {
|
|
|
20903
21224
|
});
|
|
20904
21225
|
const statusLine = stdout.split("\n").find((line) => line.startsWith(REPOSITORY_DISCOVERY_STATUS_PREFIX));
|
|
20905
21226
|
const embeddedStatus = statusLine ? Number.parseInt(statusLine.slice(REPOSITORY_DISCOVERY_STATUS_PREFIX.length), 10) : null;
|
|
20906
|
-
const
|
|
20907
|
-
if (
|
|
21227
|
+
const status2 = Number.isInteger(embeddedStatus) ? embeddedStatus : null;
|
|
21228
|
+
if (status2 === 124) {
|
|
20908
21229
|
return { repos: [], complete: false, degradedReason: "command_timed_out" };
|
|
20909
21230
|
}
|
|
20910
|
-
if (
|
|
21231
|
+
if (status2 !== 0) {
|
|
20911
21232
|
return { repos: [], complete: false, degradedReason: "command_failed" };
|
|
20912
21233
|
}
|
|
20913
21234
|
const lines = stdout.split("\n").map((l) => l.trim()).filter((line) => Boolean(line) && !line.startsWith(REPOSITORY_DISCOVERY_STATUS_PREFIX));
|
|
@@ -21252,13 +21573,13 @@ var SandboxChannelAService = class {
|
|
|
21252
21573
|
* worker agent-turn side after FS-mutating tools). */
|
|
21253
21574
|
async emitGitChanged(repoPath, reason) {
|
|
21254
21575
|
try {
|
|
21255
|
-
const
|
|
21576
|
+
const status2 = await this.gitStatus({ path: repoPath });
|
|
21256
21577
|
const payload = {
|
|
21257
|
-
head:
|
|
21258
|
-
dirty:
|
|
21259
|
-
ahead:
|
|
21260
|
-
behind:
|
|
21261
|
-
changedFileCount:
|
|
21578
|
+
head: status2.head,
|
|
21579
|
+
dirty: status2.files.length > 0,
|
|
21580
|
+
ahead: status2.ahead,
|
|
21581
|
+
behind: status2.behind,
|
|
21582
|
+
changedFileCount: status2.files.length,
|
|
21262
21583
|
reason,
|
|
21263
21584
|
revision: this.revision,
|
|
21264
21585
|
leaseEpoch: this.leaseEpoch
|
|
@@ -21685,14 +22006,14 @@ function readNulFrameField(bytes, cursor) {
|
|
|
21685
22006
|
return { value: bytes.subarray(cursor, end), cursor: end + 1 };
|
|
21686
22007
|
}
|
|
21687
22008
|
function parseCombinedUntrackedSnapshots(bytes) {
|
|
21688
|
-
const
|
|
21689
|
-
if (!bytes.subarray(0,
|
|
22009
|
+
const prefix2 = Buffer.from(`${GIT_UNTRACKED_CAPTURE_FRAME}${NUL}`);
|
|
22010
|
+
if (!bytes.subarray(0, prefix2.byteLength).equals(prefix2)) {
|
|
21690
22011
|
throw new ChannelAUnavailableError(
|
|
21691
22012
|
"Workspace Git data is temporarily unavailable. Retry the operation."
|
|
21692
22013
|
);
|
|
21693
22014
|
}
|
|
21694
22015
|
const snapshots = [];
|
|
21695
|
-
let cursor =
|
|
22016
|
+
let cursor = prefix2.byteLength;
|
|
21696
22017
|
while (cursor < bytes.byteLength) {
|
|
21697
22018
|
const kindField = readNulFrameField(bytes, cursor);
|
|
21698
22019
|
cursor = kindField.cursor;
|
|
@@ -21743,14 +22064,14 @@ function splitUnifiedPatchFiles(patch) {
|
|
|
21743
22064
|
function parseUnifiedPatch(patch) {
|
|
21744
22065
|
const lines = patch.split("\n");
|
|
21745
22066
|
const hunks = [];
|
|
21746
|
-
let
|
|
22067
|
+
let status2 = "modified";
|
|
21747
22068
|
let current = null;
|
|
21748
22069
|
let oldNo = 0;
|
|
21749
22070
|
let newNo = 0;
|
|
21750
22071
|
for (const line of lines) {
|
|
21751
|
-
if (line.startsWith("new file mode"))
|
|
21752
|
-
else if (line.startsWith("deleted file mode"))
|
|
21753
|
-
else if (line.startsWith("rename from") || line.startsWith("rename to"))
|
|
22072
|
+
if (line.startsWith("new file mode")) status2 = "added";
|
|
22073
|
+
else if (line.startsWith("deleted file mode")) status2 = "deleted";
|
|
22074
|
+
else if (line.startsWith("rename from") || line.startsWith("rename to")) status2 = "renamed";
|
|
21754
22075
|
if (line.startsWith("@@")) {
|
|
21755
22076
|
const m = line.match(/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)$/);
|
|
21756
22077
|
if (m) {
|
|
@@ -21788,13 +22109,107 @@ function parseUnifiedPatch(patch) {
|
|
|
21788
22109
|
newNo++;
|
|
21789
22110
|
}
|
|
21790
22111
|
}
|
|
21791
|
-
return { hunks, status };
|
|
22112
|
+
return { hunks, status: status2 };
|
|
21792
22113
|
}
|
|
21793
22114
|
|
|
21794
22115
|
// src/sandbox/providers/modal-command-session.ts
|
|
21795
22116
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
22117
|
+
import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
|
|
22118
|
+
|
|
22119
|
+
// src/sandbox/providers/modal-materialization-verification.ts
|
|
22120
|
+
var MARKER = "__OPENGENI_MATERIALIZED_PATH_VISIBLE__";
|
|
22121
|
+
var OUTPUT_LIMIT = 16 * 1024;
|
|
22122
|
+
async function verifyModalMaterializedPath(control, path, workdir, pending, observationTimeoutMs = 3e4) {
|
|
22123
|
+
const quote2 = (value) => `'${value.replaceAll("'", `'"'"'`)}'`;
|
|
22124
|
+
const command = `test -e ${quote2(path)} && printf %s ${quote2(MARKER)}`;
|
|
22125
|
+
const cancellation = new AbortController();
|
|
22126
|
+
const deadlineReason = new Error("Materialization visibility observation deadline exceeded");
|
|
22127
|
+
let providerCommand;
|
|
22128
|
+
let stdout = "";
|
|
22129
|
+
let stderr = "";
|
|
22130
|
+
const diagnostic = (reason, exitCode = null) => ({
|
|
22131
|
+
reason,
|
|
22132
|
+
path,
|
|
22133
|
+
workdir,
|
|
22134
|
+
command,
|
|
22135
|
+
output: (stdout + stderr).slice(0, OUTPUT_LIMIT),
|
|
22136
|
+
exitCode,
|
|
22137
|
+
providerSessionId: null,
|
|
22138
|
+
...providerCommand ? {
|
|
22139
|
+
providerExecution: {
|
|
22140
|
+
sandboxId: providerCommand.sandboxId,
|
|
22141
|
+
taskId: providerCommand.taskId,
|
|
22142
|
+
execId: providerCommand.execId
|
|
22143
|
+
}
|
|
22144
|
+
} : {}
|
|
22145
|
+
});
|
|
22146
|
+
const timer = setTimeout(() => {
|
|
22147
|
+
cancellation.abort(deadlineReason);
|
|
22148
|
+
}, observationTimeoutMs);
|
|
22149
|
+
timer.unref();
|
|
22150
|
+
pending.add(cancellation);
|
|
22151
|
+
try {
|
|
22152
|
+
providerCommand = await control.start(
|
|
22153
|
+
{ cmd: command, workdir, shell: "sh", login: false, tty: false },
|
|
22154
|
+
cancellation.signal
|
|
22155
|
+
);
|
|
22156
|
+
for (; ; ) {
|
|
22157
|
+
cancellation.signal.throwIfAborted();
|
|
22158
|
+
const page = await control.readProbe(providerCommand, 1e3, cancellation);
|
|
22159
|
+
cancellation.signal.throwIfAborted();
|
|
22160
|
+
if (page.command.sandboxId !== providerCommand.sandboxId || page.command.taskId !== providerCommand.taskId || page.command.execId !== providerCommand.execId) {
|
|
22161
|
+
throw new SandboxMaterializationVerificationError(diagnostic("invalid_response"));
|
|
22162
|
+
}
|
|
22163
|
+
providerCommand = page.command;
|
|
22164
|
+
for (const chunk of page.chunks) {
|
|
22165
|
+
if (chunk.stream === "stdout") stdout += chunk.text;
|
|
22166
|
+
else stderr += chunk.text;
|
|
22167
|
+
}
|
|
22168
|
+
if (stdout.length + stderr.length > OUTPUT_LIMIT) {
|
|
22169
|
+
throw new SandboxMaterializationVerificationError(diagnostic("invalid_response"));
|
|
22170
|
+
}
|
|
22171
|
+
if (page.exitCode === null) {
|
|
22172
|
+
await new Promise((resolve7) => setImmediate(resolve7));
|
|
22173
|
+
continue;
|
|
22174
|
+
}
|
|
22175
|
+
if (page.exitCode === 0 && stdout === MARKER) return;
|
|
22176
|
+
throw new SandboxMaterializationVerificationError(
|
|
22177
|
+
diagnostic(
|
|
22178
|
+
page.exitCode === 1 ? "path_not_visible" : page.exitCode === 0 ? "invalid_response" : "command_failed",
|
|
22179
|
+
page.exitCode
|
|
22180
|
+
)
|
|
22181
|
+
);
|
|
22182
|
+
}
|
|
22183
|
+
} catch (error) {
|
|
22184
|
+
if (cancellation.signal.reason === deadlineReason) {
|
|
22185
|
+
throw new SandboxMaterializationVerificationError(
|
|
22186
|
+
{
|
|
22187
|
+
...diagnostic("command_pending"),
|
|
22188
|
+
causeMessage: "Observation deadline exceeded; provider process completion is unconfirmed"
|
|
22189
|
+
},
|
|
22190
|
+
{ cause: error }
|
|
22191
|
+
);
|
|
22192
|
+
}
|
|
22193
|
+
if (!(error instanceof SandboxMaterializationVerificationError)) {
|
|
22194
|
+
retainMaterializationVerificationDiagnostic(error, {
|
|
22195
|
+
...diagnostic("command_error"),
|
|
22196
|
+
causeMessage: error instanceof Error ? error.message : String(error)
|
|
22197
|
+
});
|
|
22198
|
+
}
|
|
22199
|
+
throw error;
|
|
22200
|
+
} finally {
|
|
22201
|
+
cancellation.abort(new Error("Materialization visibility observation finished"));
|
|
22202
|
+
clearTimeout(timer);
|
|
22203
|
+
pending.delete(cancellation);
|
|
22204
|
+
}
|
|
22205
|
+
}
|
|
22206
|
+
|
|
22207
|
+
// src/sandbox/providers/modal-command-session.ts
|
|
21796
22208
|
function sameExecution(a, b) {
|
|
21797
|
-
return a.sandboxId === b.sandboxId && a.taskId === b.taskId && a.execId === b.execId &&
|
|
22209
|
+
return a.kind === b.kind && a.sandboxId === b.sandboxId && a.taskId === b.taskId && a.execId === b.execId && isDeepStrictEqual2(
|
|
22210
|
+
"supervision" in a ? a.supervision : void 0,
|
|
22211
|
+
"supervision" in b ? b.supervision : void 0
|
|
22212
|
+
) && Boolean(a.pty) === Boolean(b.pty);
|
|
21798
22213
|
}
|
|
21799
22214
|
function installModalCommandSession(session, control) {
|
|
21800
22215
|
markTypedExecHandleLoss(session);
|
|
@@ -21802,10 +22217,48 @@ function installModalCommandSession(session, control) {
|
|
|
21802
22217
|
const originalWrite = session.writeStdin?.bind(session);
|
|
21803
22218
|
const cancelLegacyStart = session.cancelPendingExecCommand?.bind(session);
|
|
21804
22219
|
const pendingStarts = /* @__PURE__ */ new Set();
|
|
22220
|
+
session.verifyCommandSupervisionCapability = async () => {
|
|
22221
|
+
if (!control.verifySupervisionCapability)
|
|
22222
|
+
throw new Error("Modal instance lacks supervised command capability verification");
|
|
22223
|
+
return await control.verifySupervisionCapability();
|
|
22224
|
+
};
|
|
22225
|
+
session.verifyMaterializedPath = (path, workdir) => verifyModalMaterializedPath(control, path, workdir, pendingStarts);
|
|
21805
22226
|
const entries = /* @__PURE__ */ new Map();
|
|
21806
22227
|
const setupHandles = /* @__PURE__ */ new Map();
|
|
21807
22228
|
let nextSetupHandle = MAX_PROVIDER_COMMAND_HANDLE + 1;
|
|
21808
22229
|
const receipts = /* @__PURE__ */ new Map();
|
|
22230
|
+
const atomicallyCaptured = /* @__PURE__ */ new WeakSet();
|
|
22231
|
+
const supervise = async (entry, release = false) => {
|
|
22232
|
+
if (entry.command.kind !== "modal-router-v1" || !entry.command.supervision) return;
|
|
22233
|
+
const persistence = entry.persistence;
|
|
22234
|
+
if (!persistence?.recordSupervisionReceipt || !persistence.loadSupervisionReceipt || !persistence.cancellationRequested || !control.supervisionControl)
|
|
22235
|
+
throw new Error("Supervised command requires durable control persistence");
|
|
22236
|
+
let receipt = await persistence.loadSupervisionReceipt();
|
|
22237
|
+
if (!receipt) {
|
|
22238
|
+
const action = await persistence.cancellationRequested() ? "cancel" : release ? "release" : "status";
|
|
22239
|
+
const observation = await control.supervisionControl(entry.command, action);
|
|
22240
|
+
receipt = observation.receipt ?? null;
|
|
22241
|
+
if (receipt) await persistence.recordSupervisionReceipt(receipt);
|
|
22242
|
+
}
|
|
22243
|
+
if (receipt) {
|
|
22244
|
+
await control.supervisionControl(entry.command, "ack", receipt.receiptId).catch(() => void 0);
|
|
22245
|
+
}
|
|
22246
|
+
};
|
|
22247
|
+
const captureRouterPage = async (entry, page) => {
|
|
22248
|
+
if (page.command.kind !== "modal-router-v1" || !page.expected || !entry.persistence?.captureRouterPage)
|
|
22249
|
+
throw new Error("Modal byte-offset output requires atomic retained capture");
|
|
22250
|
+
const result = await entry.persistence.captureRouterPage({
|
|
22251
|
+
expected: page.expected,
|
|
22252
|
+
command: page.command,
|
|
22253
|
+
stdout: page.chunks.filter((chunk) => chunk.stream === "stdout").map((chunk) => chunk.text).join(""),
|
|
22254
|
+
stderr: page.chunks.filter((chunk) => chunk.stream === "stderr").map((chunk) => chunk.text).join("")
|
|
22255
|
+
});
|
|
22256
|
+
if (!sameExecution(entry.command, result.command))
|
|
22257
|
+
throw new Error("Modal output capture changed execution identity");
|
|
22258
|
+
entry.command = result.command;
|
|
22259
|
+
if (result.captured) atomicallyCaptured.add(page);
|
|
22260
|
+
return result.captured;
|
|
22261
|
+
};
|
|
21809
22262
|
const setupPage = (raw, handle, sdkHandle) => {
|
|
21810
22263
|
const banner = parseExecResponseBanner(raw);
|
|
21811
22264
|
if (banner.kind === "exited") {
|
|
@@ -21839,8 +22292,24 @@ function installModalCommandSession(session, control) {
|
|
|
21839
22292
|
if (!retained || !sameExecution(entry.command, retained))
|
|
21840
22293
|
throw new Error("Original Modal command identity is unavailable");
|
|
21841
22294
|
entry.command = retained;
|
|
22295
|
+
await supervise(entry).catch(() => void 0);
|
|
22296
|
+
}
|
|
22297
|
+
let page = await control.read(entry.command, yieldTimeMs, signal);
|
|
22298
|
+
if (entry.persistence && page.command.kind === "modal-router-v1") {
|
|
22299
|
+
let captured = false;
|
|
22300
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
22301
|
+
if (await captureRouterPage(entry, page)) {
|
|
22302
|
+
captured = true;
|
|
22303
|
+
break;
|
|
22304
|
+
}
|
|
22305
|
+
if (attempt < 2) page = await control.read(entry.command, yieldTimeMs, signal);
|
|
22306
|
+
}
|
|
22307
|
+
if (!captured) throw new Error("Modal command output cursor changed during bounded capture");
|
|
22308
|
+
}
|
|
22309
|
+
if (page.command.kind === "modal-router-v1" && page.command.supervision) {
|
|
22310
|
+
const receipt = await entry.persistence?.loadSupervisionReceipt?.();
|
|
22311
|
+
page = { ...page, exitCode: receipt && page.exitCode === 0 ? receipt.leaderExitCode : null };
|
|
21842
22312
|
}
|
|
21843
|
-
const page = await control.read(entry.command, yieldTimeMs, signal);
|
|
21844
22313
|
return formatPage(handle, page, maxOutputTokens);
|
|
21845
22314
|
};
|
|
21846
22315
|
session.execCommand = async (args) => {
|
|
@@ -21859,8 +22328,14 @@ function installModalCommandSession(session, control) {
|
|
|
21859
22328
|
const cancellation = new AbortController();
|
|
21860
22329
|
pendingStarts.add(cancellation);
|
|
21861
22330
|
try {
|
|
21862
|
-
const
|
|
22331
|
+
const command = await control.start(args, cancellation.signal);
|
|
22332
|
+
const entry = entries.get(handle) ?? { command };
|
|
22333
|
+
if (!sameExecution(entry.command, command))
|
|
22334
|
+
throw new Error("Reserved Modal command changed during dispatch");
|
|
21863
22335
|
entries.set(handle, entry);
|
|
22336
|
+
if (entry.command.kind === "modal-router-v1" && entry.command.supervision) {
|
|
22337
|
+
return formatPage(handle, { command: entry.command, chunks: [], exitCode: null });
|
|
22338
|
+
}
|
|
21864
22339
|
try {
|
|
21865
22340
|
return await read(
|
|
21866
22341
|
handle,
|
|
@@ -21891,6 +22366,25 @@ function installModalCommandSession(session, control) {
|
|
|
21891
22366
|
const entry = entries.get(handle);
|
|
21892
22367
|
return entry ? structuredClone(entry.command) : null;
|
|
21893
22368
|
};
|
|
22369
|
+
session.releaseSupervisedCommand = async (handle) => {
|
|
22370
|
+
const entry = entries.get(handle);
|
|
22371
|
+
if (!entry || entry.command.kind !== "modal-router-v1" || !entry.command.supervision) return;
|
|
22372
|
+
const retained = await entry.persistence?.load();
|
|
22373
|
+
if (!retained || !sameExecution(entry.command, retained))
|
|
22374
|
+
throw new Error("Supervisor release requires committed initial retention");
|
|
22375
|
+
entry.command = retained;
|
|
22376
|
+
await supervise(entry, true);
|
|
22377
|
+
};
|
|
22378
|
+
session.cancelSupervisedCommand = async (handle, reason) => {
|
|
22379
|
+
const entry = entries.get(handle);
|
|
22380
|
+
if (!entry || entry.command.kind !== "modal-router-v1" || !entry.command.supervision)
|
|
22381
|
+
return false;
|
|
22382
|
+
if (!entry.persistence?.requestCancellation)
|
|
22383
|
+
throw new Error("Supervisor cancellation requires durable intent");
|
|
22384
|
+
await entry.persistence.requestCancellation(reason);
|
|
22385
|
+
await supervise(entry);
|
|
22386
|
+
return true;
|
|
22387
|
+
};
|
|
21894
22388
|
session.bindProviderCommand = (handle, command, persistence) => {
|
|
21895
22389
|
if (!Number.isSafeInteger(handle) || handle <= 0 || handle > MAX_PROVIDER_COMMAND_HANDLE)
|
|
21896
22390
|
throw new Error("Invalid retained Modal command handle");
|
|
@@ -21900,6 +22394,39 @@ function installModalCommandSession(session, control) {
|
|
|
21900
22394
|
entries.set(handle, { command: structuredClone(command), persistence });
|
|
21901
22395
|
};
|
|
21902
22396
|
session.getProviderCommandOutput = (result) => typeof result === "string" ? receipts.get(result)?.page ?? null : null;
|
|
22397
|
+
session.captureCommandOutput = async (result) => {
|
|
22398
|
+
const receipt = receipts.get(result);
|
|
22399
|
+
if (!receipt || receipt.page.command.kind !== "modal-router-v1") return false;
|
|
22400
|
+
if (receipt.page.command.supervision && !receipt.page.expected && receipt.page.exitCode === null && receipt.page.chunks.length === 0) {
|
|
22401
|
+
receipts.delete(result);
|
|
22402
|
+
return true;
|
|
22403
|
+
}
|
|
22404
|
+
if (atomicallyCaptured.has(receipt.page)) {
|
|
22405
|
+
receipts.delete(result);
|
|
22406
|
+
return true;
|
|
22407
|
+
}
|
|
22408
|
+
const entry = entries.get(receipt.handle);
|
|
22409
|
+
if (!entry?.persistence?.captureRouterPage || !receipt.page.expected)
|
|
22410
|
+
throw new Error("Modal byte-offset output requires atomic retained capture");
|
|
22411
|
+
if (!await captureRouterPage(entry, receipt.page)) {
|
|
22412
|
+
const target = receipt.page.command;
|
|
22413
|
+
const covered = () => entry.command.kind === "modal-router-v1" && ["stdout", "stderr"].every((stream) => {
|
|
22414
|
+
const current = entry.command.streams[stream];
|
|
22415
|
+
if (!("byteOffset" in current)) return false;
|
|
22416
|
+
const wanted = target.streams[stream];
|
|
22417
|
+
return current.byteOffset >= wanted.byteOffset && (!wanted.eof || current.eof) && (wanted.exitCode === null || current.exitCode === wanted.exitCode);
|
|
22418
|
+
});
|
|
22419
|
+
for (let attempt = 0; !covered() && attempt < 3; attempt++) {
|
|
22420
|
+
const refreshedReceipt = await read(receipt.handle, entry, 250);
|
|
22421
|
+
const refreshed = receipts.get(refreshedReceipt);
|
|
22422
|
+
if (refreshed && atomicallyCaptured.has(refreshed.page)) receipts.delete(refreshedReceipt);
|
|
22423
|
+
}
|
|
22424
|
+
if (!covered())
|
|
22425
|
+
throw new Error("Initial Modal output tail remains uncommitted after bounded capture");
|
|
22426
|
+
}
|
|
22427
|
+
receipts.delete(result);
|
|
22428
|
+
return true;
|
|
22429
|
+
};
|
|
21903
22430
|
session.acknowledgeCommandOutput = async (result) => {
|
|
21904
22431
|
const receipt = receipts.get(result);
|
|
21905
22432
|
if (!receipt) return;
|
|
@@ -21927,7 +22454,7 @@ function installModalCommandSession(session, control) {
|
|
|
21927
22454
|
const retained = await entry.persistence.load();
|
|
21928
22455
|
if (!retained || !sameExecution(entry.command, retained))
|
|
21929
22456
|
throw new Error("Original Modal command identity is unavailable");
|
|
21930
|
-
const index = await entry.persistence.reserveInput();
|
|
22457
|
+
const index = await entry.persistence.reserveInput(Buffer.byteLength(args.chars));
|
|
21931
22458
|
await control.write(retained, args.chars, index);
|
|
21932
22459
|
}
|
|
21933
22460
|
return read(args.sessionId, entry, args.yieldTimeMs ?? 250, args.maxOutputTokens);
|
|
@@ -21935,9 +22462,17 @@ function installModalCommandSession(session, control) {
|
|
|
21935
22462
|
}
|
|
21936
22463
|
|
|
21937
22464
|
// src/sandbox/providers/modal-command-control.ts
|
|
22465
|
+
import { randomUUID as randomUUID6, randomBytes } from "crypto";
|
|
22466
|
+
import { posix as posix3 } from "path";
|
|
22467
|
+
import {
|
|
22468
|
+
SandboxProviderCommand,
|
|
22469
|
+
CommandSupervisionReceipt
|
|
22470
|
+
} from "@opengeni/contracts";
|
|
22471
|
+
|
|
22472
|
+
// src/sandbox/providers/modal-legacy-command-control.ts
|
|
21938
22473
|
import { posix as posix2 } from "path";
|
|
21939
22474
|
import { ModalClient } from "modal";
|
|
21940
|
-
import {
|
|
22475
|
+
import { ModalLegacyProviderCommand } from "@opengeni/contracts";
|
|
21941
22476
|
var modalCommandAbortMiddleware = async function* (call, options) {
|
|
21942
22477
|
options.signal?.throwIfAborted();
|
|
21943
22478
|
return yield* call.next(call.request, options);
|
|
@@ -22074,49 +22609,76 @@ var ModalCommandControl = class _ModalCommandControl {
|
|
|
22074
22609
|
};
|
|
22075
22610
|
}
|
|
22076
22611
|
async read(command, yieldTimeMs, signal) {
|
|
22612
|
+
return this.readOutput(command, yieldTimeMs, signal);
|
|
22613
|
+
}
|
|
22614
|
+
/** Fixed internal probes own their cancellation controller and must drain
|
|
22615
|
+
* both reads before relinquishing the surrounding provider-operation gate.
|
|
22616
|
+
* Retained-command readers keep their existing signal/receipt contract.
|
|
22617
|
+
*/
|
|
22618
|
+
async readProbe(command, yieldTimeMs, cancellation) {
|
|
22619
|
+
return this.readOutput(
|
|
22620
|
+
command,
|
|
22621
|
+
yieldTimeMs,
|
|
22622
|
+
cancellation.signal,
|
|
22623
|
+
(error) => cancellation.abort(error)
|
|
22624
|
+
);
|
|
22625
|
+
}
|
|
22626
|
+
async readOutput(command, yieldTimeMs, signal, cancelSiblings) {
|
|
22077
22627
|
signal?.throwIfAborted();
|
|
22078
22628
|
this.assertIdentity(command);
|
|
22079
22629
|
const next = structuredClone(command);
|
|
22080
|
-
|
|
22081
|
-
|
|
22082
|
-
|
|
22083
|
-
|
|
22084
|
-
|
|
22085
|
-
|
|
22086
|
-
|
|
22087
|
-
|
|
22088
|
-
|
|
22089
|
-
|
|
22090
|
-
|
|
22091
|
-
|
|
22092
|
-
|
|
22093
|
-
|
|
22094
|
-
|
|
22095
|
-
|
|
22096
|
-
|
|
22097
|
-
|
|
22098
|
-
|
|
22099
|
-
|
|
22100
|
-
|
|
22101
|
-
|
|
22102
|
-
|
|
22103
|
-
|
|
22104
|
-
|
|
22105
|
-
|
|
22106
|
-
|
|
22107
|
-
|
|
22108
|
-
|
|
22109
|
-
|
|
22110
|
-
|
|
22111
|
-
|
|
22112
|
-
|
|
22113
|
-
|
|
22114
|
-
|
|
22115
|
-
|
|
22116
|
-
|
|
22117
|
-
|
|
22630
|
+
let failure;
|
|
22631
|
+
const reads = ["stdout", "stderr"].map(async (stream) => {
|
|
22632
|
+
const cursor = command.streams[stream];
|
|
22633
|
+
if (cursor.exitCode !== null) return null;
|
|
22634
|
+
const descriptor = stream === "stdout" ? 1 : 2;
|
|
22635
|
+
for await (const batch of this.client.containerExecGetOutput(
|
|
22636
|
+
{
|
|
22637
|
+
execId: command.execId,
|
|
22638
|
+
timeout: Math.max(0, yieldTimeMs) / 1e3,
|
|
22639
|
+
lastBatchIndex: cursor.batchIndex,
|
|
22640
|
+
fileDescriptor: descriptor,
|
|
22641
|
+
getRawBytes: true
|
|
22642
|
+
},
|
|
22643
|
+
signal ? { signal } : void 0
|
|
22644
|
+
)) {
|
|
22645
|
+
if (batch.batchIndex <= cursor.batchIndex) continue;
|
|
22646
|
+
if (!Number.isSafeInteger(batch.batchIndex))
|
|
22647
|
+
throw new Error("Invalid Modal output cursor");
|
|
22648
|
+
const terminal = batch.exitCode !== void 0;
|
|
22649
|
+
if (terminal && !Number.isSafeInteger(batch.exitCode))
|
|
22650
|
+
throw new Error("Invalid Modal exit status");
|
|
22651
|
+
const decoded = decodePage(
|
|
22652
|
+
cursor.utf8Remainder,
|
|
22653
|
+
batch.items.filter((item) => item.fileDescriptor === descriptor).map((item) => item.messageBytes),
|
|
22654
|
+
terminal
|
|
22655
|
+
);
|
|
22656
|
+
next.streams[stream] = {
|
|
22657
|
+
batchIndex: batch.batchIndex,
|
|
22658
|
+
utf8Remainder: decoded.remainder,
|
|
22659
|
+
exitCode: terminal ? batch.exitCode : null
|
|
22660
|
+
};
|
|
22661
|
+
return {
|
|
22662
|
+
stream,
|
|
22663
|
+
chunkId: `modal:${command.execId}:${stream}:${cursor.batchIndex}:${batch.batchIndex}`,
|
|
22664
|
+
text: decoded.text
|
|
22665
|
+
};
|
|
22666
|
+
}
|
|
22667
|
+
return null;
|
|
22668
|
+
}).map(
|
|
22669
|
+
(read) => !cancelSiblings ? read : read.catch((error) => {
|
|
22670
|
+
failure ??= { error };
|
|
22671
|
+
cancelSiblings(error);
|
|
22672
|
+
throw error;
|
|
22118
22673
|
})
|
|
22119
22674
|
);
|
|
22675
|
+
const pages = cancelSiblings ? await Promise.allSettled(reads).then((results) => {
|
|
22676
|
+
if (failure) throw failure.error;
|
|
22677
|
+
return results.map((result) => {
|
|
22678
|
+
if (result.status === "rejected") throw result.reason;
|
|
22679
|
+
return result.value;
|
|
22680
|
+
});
|
|
22681
|
+
}) : await Promise.all(reads);
|
|
22120
22682
|
const stdoutExit = next.streams.stdout.exitCode;
|
|
22121
22683
|
const stderrExit = next.streams.stderr.exitCode;
|
|
22122
22684
|
if (stdoutExit !== null && stderrExit !== null && stdoutExit !== stderrExit)
|
|
@@ -22142,12 +22704,549 @@ var ModalCommandControl = class _ModalCommandControl {
|
|
|
22142
22704
|
);
|
|
22143
22705
|
}
|
|
22144
22706
|
assertIdentity(command) {
|
|
22145
|
-
|
|
22707
|
+
ModalLegacyProviderCommand.parse(command);
|
|
22146
22708
|
if (command.kind !== "modal-control-v1" || command.sandboxId !== this.sandboxId || !command.taskId || !command.execId)
|
|
22147
22709
|
throw new Error("Modal command locator does not match the original sandbox");
|
|
22148
22710
|
}
|
|
22149
22711
|
};
|
|
22150
22712
|
|
|
22713
|
+
// src/sandbox/providers/modal-command-router-wire.ts
|
|
22714
|
+
import { Client, Metadata, credentials, status } from "@grpc/grpc-js";
|
|
22715
|
+
import protobuf from "protobufjs";
|
|
22716
|
+
var modalRouterWire = protobuf.parse(`syntax = "proto3";
|
|
22717
|
+
message Identity { string task_id = 1; string exec_id = 2; }
|
|
22718
|
+
message Pty {
|
|
22719
|
+
bool enabled = 1; uint32 winsz_rows = 2; uint32 winsz_cols = 3;
|
|
22720
|
+
string env_term = 4; string env_colorterm = 5; string env_term_program = 6;
|
|
22721
|
+
int32 pty_type = 7; bool no_terminate_on_idle_stdin = 8;
|
|
22722
|
+
}
|
|
22723
|
+
message Start {
|
|
22724
|
+
string task_id = 1; string exec_id = 2; repeated string command_args = 3;
|
|
22725
|
+
int32 stdout_config = 4; int32 stderr_config = 5;
|
|
22726
|
+
optional uint32 timeout_secs = 6; optional string workdir = 7;
|
|
22727
|
+
repeated string secret_ids = 8; optional Pty pty_info = 9;
|
|
22728
|
+
bool runtime_debug = 10; string container_id = 11; map<string,string> env = 12;
|
|
22729
|
+
}
|
|
22730
|
+
message Read {
|
|
22731
|
+
string task_id = 1; string exec_id = 2; uint64 offset = 3; int32 file_descriptor = 4;
|
|
22732
|
+
}
|
|
22733
|
+
message Data { bytes data = 1; }
|
|
22734
|
+
message Poll { optional int32 code = 1; optional int32 signal = 2; }
|
|
22735
|
+
message Write {
|
|
22736
|
+
string task_id = 1; string exec_id = 2; uint64 offset = 3; bytes data = 4; bool eof = 5;
|
|
22737
|
+
}
|
|
22738
|
+
message Empty {}
|
|
22739
|
+
`).root;
|
|
22740
|
+
var prefix = "/modal.task_command_router.TaskCommandRouter/";
|
|
22741
|
+
var maxPageBytes = 64 * 1024;
|
|
22742
|
+
var maxWireBytes = 4 * 1024 * 1024;
|
|
22743
|
+
var ModalCommandStartRejectedError = class extends ProviderCommandStartRejectedError {
|
|
22744
|
+
constructor(code, cause) {
|
|
22745
|
+
super(cause);
|
|
22746
|
+
this.code = code;
|
|
22747
|
+
this.name = "ModalCommandStartRejectedError";
|
|
22748
|
+
}
|
|
22749
|
+
};
|
|
22750
|
+
function encode(type, value) {
|
|
22751
|
+
const codec = modalRouterWire.lookupType(type);
|
|
22752
|
+
return Buffer.from(codec.encode(codec.fromObject(value)).finish());
|
|
22753
|
+
}
|
|
22754
|
+
var ModalCommandRouterWire = class {
|
|
22755
|
+
client;
|
|
22756
|
+
metadata;
|
|
22757
|
+
closed = false;
|
|
22758
|
+
constructor(access, trustedRoots) {
|
|
22759
|
+
const url = new URL(access.url);
|
|
22760
|
+
if (url.protocol !== "https:" || url.username || url.password || !access.jwt)
|
|
22761
|
+
throw new Error("Modal command router requires authenticated TLS");
|
|
22762
|
+
this.client = new Client(url.host, credentials.createSsl(trustedRoots), {
|
|
22763
|
+
"grpc.max_receive_message_length": maxWireBytes,
|
|
22764
|
+
"grpc.max_send_message_length": maxWireBytes,
|
|
22765
|
+
"grpc.enable_retries": 0
|
|
22766
|
+
});
|
|
22767
|
+
this.metadata = new Metadata();
|
|
22768
|
+
this.metadata.set("authorization", `Bearer ${access.jwt}`);
|
|
22769
|
+
}
|
|
22770
|
+
close() {
|
|
22771
|
+
this.closed = true;
|
|
22772
|
+
this.client.close();
|
|
22773
|
+
}
|
|
22774
|
+
async unary(method, requestType, responseType, request, signal) {
|
|
22775
|
+
signal?.throwIfAborted();
|
|
22776
|
+
if (this.closed) throw new Error("Modal command router is closed");
|
|
22777
|
+
return await new Promise((resolve7, reject) => {
|
|
22778
|
+
const call = this.client.makeUnaryRequest(
|
|
22779
|
+
prefix + method,
|
|
22780
|
+
(value) => encode(requestType, value),
|
|
22781
|
+
(bytes) => modalRouterWire.lookupType(responseType).decode(bytes),
|
|
22782
|
+
request,
|
|
22783
|
+
this.metadata,
|
|
22784
|
+
{ deadline: Date.now() + 3e4 },
|
|
22785
|
+
(error, result) => {
|
|
22786
|
+
signal?.removeEventListener("abort", abort);
|
|
22787
|
+
if (signal?.aborted) reject(signal.reason);
|
|
22788
|
+
else if (error) reject(error);
|
|
22789
|
+
else if (result) resolve7(result);
|
|
22790
|
+
else reject(new Error("Modal command router returned no response"));
|
|
22791
|
+
}
|
|
22792
|
+
);
|
|
22793
|
+
const abort = () => call.cancel();
|
|
22794
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
22795
|
+
if (signal?.aborted) abort();
|
|
22796
|
+
});
|
|
22797
|
+
}
|
|
22798
|
+
async start(request, signal) {
|
|
22799
|
+
try {
|
|
22800
|
+
await this.unary(
|
|
22801
|
+
"TaskExecStart",
|
|
22802
|
+
"Start",
|
|
22803
|
+
"Empty",
|
|
22804
|
+
{
|
|
22805
|
+
...request,
|
|
22806
|
+
stdoutConfig: 1,
|
|
22807
|
+
stderrConfig: 1
|
|
22808
|
+
},
|
|
22809
|
+
signal
|
|
22810
|
+
);
|
|
22811
|
+
} catch (error) {
|
|
22812
|
+
const code = error?.code;
|
|
22813
|
+
if (typeof code === "number" && [
|
|
22814
|
+
status.INVALID_ARGUMENT,
|
|
22815
|
+
status.NOT_FOUND,
|
|
22816
|
+
status.PERMISSION_DENIED,
|
|
22817
|
+
status.UNAUTHENTICATED,
|
|
22818
|
+
status.UNIMPLEMENTED
|
|
22819
|
+
].includes(code))
|
|
22820
|
+
throw new ModalCommandStartRejectedError(code, error);
|
|
22821
|
+
throw error;
|
|
22822
|
+
}
|
|
22823
|
+
}
|
|
22824
|
+
async write(identity, offset, data, signal) {
|
|
22825
|
+
if (!Number.isSafeInteger(offset) || offset < 0)
|
|
22826
|
+
throw new Error("Invalid Modal stdin byte offset");
|
|
22827
|
+
await this.unary(
|
|
22828
|
+
"TaskExecStdinWrite",
|
|
22829
|
+
"Write",
|
|
22830
|
+
"Empty",
|
|
22831
|
+
{ ...identity, offset, data, eof: false },
|
|
22832
|
+
signal
|
|
22833
|
+
);
|
|
22834
|
+
}
|
|
22835
|
+
async poll(identity, signal) {
|
|
22836
|
+
const value = await this.unary("TaskExecPoll", "Identity", "Poll", identity, signal);
|
|
22837
|
+
const decoded = modalRouterWire.lookupType("Poll").toObject(value);
|
|
22838
|
+
if (decoded.code !== void 0) return decoded.code;
|
|
22839
|
+
if (decoded.signal !== void 0) return 128 + decoded.signal;
|
|
22840
|
+
return null;
|
|
22841
|
+
}
|
|
22842
|
+
async read(identity, stream, offset, waitMs, signal) {
|
|
22843
|
+
signal?.throwIfAborted();
|
|
22844
|
+
if (this.closed) throw new Error("Modal command router is closed");
|
|
22845
|
+
if (!Number.isSafeInteger(offset) || offset < 0 || !Number.isFinite(waitMs) || waitMs < 0 || waitMs > 5e4)
|
|
22846
|
+
throw new Error("Invalid Modal output read bounds");
|
|
22847
|
+
const chunks = [];
|
|
22848
|
+
let length = 0;
|
|
22849
|
+
let limited = false;
|
|
22850
|
+
return await new Promise((resolve7, reject) => {
|
|
22851
|
+
const call = this.client.makeServerStreamRequest(
|
|
22852
|
+
prefix + "TaskExecStdioRead",
|
|
22853
|
+
(value) => encode("Read", value),
|
|
22854
|
+
(bytes) => modalRouterWire.lookupType("Data").decode(bytes),
|
|
22855
|
+
{ ...identity, offset, fileDescriptor: stream === "stdout" ? 0 : 1 },
|
|
22856
|
+
this.metadata,
|
|
22857
|
+
{ deadline: Date.now() + Math.max(1, waitMs) }
|
|
22858
|
+
);
|
|
22859
|
+
const abort = () => call.cancel();
|
|
22860
|
+
const finish = (eof, error) => {
|
|
22861
|
+
signal?.removeEventListener("abort", abort);
|
|
22862
|
+
if (signal?.aborted) reject(signal.reason);
|
|
22863
|
+
else if (error) reject(error);
|
|
22864
|
+
else resolve7({ bytes: Buffer.concat(chunks, length), eof });
|
|
22865
|
+
};
|
|
22866
|
+
call.on("data", (value) => {
|
|
22867
|
+
if (limited) return;
|
|
22868
|
+
const part = Buffer.from(value.data).subarray(0, maxPageBytes - length);
|
|
22869
|
+
if (part.length) {
|
|
22870
|
+
chunks.push(part);
|
|
22871
|
+
length += part.length;
|
|
22872
|
+
}
|
|
22873
|
+
if (length === maxPageBytes) {
|
|
22874
|
+
limited = true;
|
|
22875
|
+
call.cancel();
|
|
22876
|
+
}
|
|
22877
|
+
});
|
|
22878
|
+
call.once("error", (error) => {
|
|
22879
|
+
if (limited && error.code === status.CANCELLED || error.code === status.DEADLINE_EXCEEDED)
|
|
22880
|
+
finish(false);
|
|
22881
|
+
else finish(false, error);
|
|
22882
|
+
});
|
|
22883
|
+
call.once("end", () => finish(!limited));
|
|
22884
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
22885
|
+
if (signal?.aborted) abort();
|
|
22886
|
+
});
|
|
22887
|
+
}
|
|
22888
|
+
};
|
|
22889
|
+
|
|
22890
|
+
// src/sandbox/providers/modal-command-control.ts
|
|
22891
|
+
var ModalCommandControl2 = class _ModalCommandControl {
|
|
22892
|
+
constructor(client, sandboxIdentity, root, environment) {
|
|
22893
|
+
this.sandboxIdentity = sandboxIdentity;
|
|
22894
|
+
this.root = root;
|
|
22895
|
+
this.environment = environment;
|
|
22896
|
+
this.client = commandControlPlane(client);
|
|
22897
|
+
this.legacy = ModalCommandControl.forSandbox(client, sandboxIdentity, root, environment);
|
|
22898
|
+
}
|
|
22899
|
+
routers = /* @__PURE__ */ new Map();
|
|
22900
|
+
client;
|
|
22901
|
+
legacy;
|
|
22902
|
+
closed = false;
|
|
22903
|
+
static forSandbox(client, sandboxId, root, environment = {}) {
|
|
22904
|
+
if (client.version() !== "0.9.0")
|
|
22905
|
+
throw new Error("Modal command control requires the verified 0.9.0 SDK contract");
|
|
22906
|
+
return new _ModalCommandControl(client, sandboxId, root, environment);
|
|
22907
|
+
}
|
|
22908
|
+
get sandboxId() {
|
|
22909
|
+
return typeof this.sandboxIdentity === "function" ? this.sandboxIdentity() : this.sandboxIdentity;
|
|
22910
|
+
}
|
|
22911
|
+
async withRouter(taskId, signal, run2) {
|
|
22912
|
+
signal?.throwIfAborted();
|
|
22913
|
+
if (this.closed) throw new Error("Modal command control is closed");
|
|
22914
|
+
let pending = this.routers.get(taskId);
|
|
22915
|
+
const reused = Boolean(pending);
|
|
22916
|
+
if (!pending) {
|
|
22917
|
+
pending = (async () => {
|
|
22918
|
+
const access = await this.client.taskGetCommandRouterAccess(
|
|
22919
|
+
{ taskId },
|
|
22920
|
+
signal ? { signal } : void 0
|
|
22921
|
+
);
|
|
22922
|
+
let refreshAt = Date.now() + 6e4;
|
|
22923
|
+
try {
|
|
22924
|
+
const payload = JSON.parse(
|
|
22925
|
+
Buffer.from(access.jwt.split(".")[1] ?? "", "base64url").toString()
|
|
22926
|
+
);
|
|
22927
|
+
if (typeof payload.exp === "number" && Number.isFinite(payload.exp))
|
|
22928
|
+
refreshAt = Math.min(refreshAt, payload.exp * 1e3 - 15e3);
|
|
22929
|
+
} catch {
|
|
22930
|
+
}
|
|
22931
|
+
return { router: new ModalCommandRouterWire(access), users: 0, refreshAt };
|
|
22932
|
+
})();
|
|
22933
|
+
this.routers.set(taskId, pending);
|
|
22934
|
+
void pending.catch(() => {
|
|
22935
|
+
if (this.routers.get(taskId) === pending) this.routers.delete(taskId);
|
|
22936
|
+
});
|
|
22937
|
+
}
|
|
22938
|
+
const entry = await pending;
|
|
22939
|
+
if (reused && !entry.users && Date.now() > entry.refreshAt) {
|
|
22940
|
+
clearTimeout(entry.idle);
|
|
22941
|
+
entry.router.close();
|
|
22942
|
+
this.routers.delete(taskId);
|
|
22943
|
+
return await this.withRouter(taskId, signal, run2);
|
|
22944
|
+
}
|
|
22945
|
+
clearTimeout(entry.idle);
|
|
22946
|
+
entry.users++;
|
|
22947
|
+
try {
|
|
22948
|
+
signal?.throwIfAborted();
|
|
22949
|
+
return await run2(entry.router);
|
|
22950
|
+
} finally {
|
|
22951
|
+
entry.users--;
|
|
22952
|
+
if (!entry.users) {
|
|
22953
|
+
entry.idle = setTimeout(() => {
|
|
22954
|
+
if (this.routers.get(taskId) === pending && !entry.users) {
|
|
22955
|
+
this.routers.delete(taskId);
|
|
22956
|
+
entry.router.close();
|
|
22957
|
+
}
|
|
22958
|
+
}, 3e4);
|
|
22959
|
+
entry.idle.unref?.();
|
|
22960
|
+
}
|
|
22961
|
+
}
|
|
22962
|
+
}
|
|
22963
|
+
async close() {
|
|
22964
|
+
this.closed = true;
|
|
22965
|
+
const entries = await Promise.allSettled(this.routers.values());
|
|
22966
|
+
this.routers.clear();
|
|
22967
|
+
for (const entry of entries)
|
|
22968
|
+
if (entry.status === "fulfilled") {
|
|
22969
|
+
clearTimeout(entry.value.idle);
|
|
22970
|
+
entry.value.router.close();
|
|
22971
|
+
}
|
|
22972
|
+
}
|
|
22973
|
+
async start(args, signal) {
|
|
22974
|
+
signal?.throwIfAborted();
|
|
22975
|
+
const supervised = admittedCommandSupervisionReady() && !args.tty && !args.runAs;
|
|
22976
|
+
if (supervised) markPendingCommandSupervised();
|
|
22977
|
+
const sandboxId = this.sandboxId;
|
|
22978
|
+
const workdir = posix3.resolve(this.root, args.workdir ?? this.root);
|
|
22979
|
+
if (workdir !== this.root && !workdir.startsWith(`${this.root.replace(/\/$/u, "")}/`))
|
|
22980
|
+
throw new Error("Command workdir is outside the sandbox workspace");
|
|
22981
|
+
const task = await this.client.sandboxGetTaskId({ sandboxId }, signal ? { signal } : void 0);
|
|
22982
|
+
if (!task.taskId || task.taskResult) throw new Error("Modal command task is unavailable");
|
|
22983
|
+
const taskId = task.taskId;
|
|
22984
|
+
if (this.sandboxId !== sandboxId)
|
|
22985
|
+
throw new Error("Modal sandbox changed during command preparation");
|
|
22986
|
+
const execId = randomUUID6();
|
|
22987
|
+
const invocationId = randomUUID6();
|
|
22988
|
+
const supervision = supervised ? {
|
|
22989
|
+
protocol: "native-subreaper-v1",
|
|
22990
|
+
invocationId,
|
|
22991
|
+
nonce: randomBytes(32).toString("hex"),
|
|
22992
|
+
controlPath: `/tmp/opengeni-supervision/${invocationId}.sock`
|
|
22993
|
+
} : void 0;
|
|
22994
|
+
let commandArgs = [
|
|
22995
|
+
args.shell ?? "/bin/sh",
|
|
22996
|
+
args.shell && (args.login ?? true) ? "-lc" : "-c",
|
|
22997
|
+
args.cmd
|
|
22998
|
+
];
|
|
22999
|
+
if (args.runAs) {
|
|
23000
|
+
const user = shellQuote(args.runAs), invocation = commandArgs.map(shellQuote).join(" ");
|
|
23001
|
+
commandArgs = [
|
|
23002
|
+
"/bin/sh",
|
|
23003
|
+
"-c",
|
|
23004
|
+
`if [ "$(id -u)" = ${user} ] || [ "$(id -un 2>/dev/null)" = ${user} ]; then exec ${invocation}; elif [ "$(id -u)" = 0 ]; then exec su -s /bin/sh ${user} -c ${shellQuote(`exec ${invocation}`)}; else exec sudo -n -u ${user} -- ${invocation}; fi`
|
|
23005
|
+
];
|
|
23006
|
+
}
|
|
23007
|
+
const env = typeof this.environment === "function" ? this.environment() : this.environment;
|
|
23008
|
+
if (supervision)
|
|
23009
|
+
commandArgs = [
|
|
23010
|
+
"/usr/local/bin/opengeni-command-supervisor",
|
|
23011
|
+
"launch",
|
|
23012
|
+
"--invocation",
|
|
23013
|
+
supervision.invocationId,
|
|
23014
|
+
"--nonce",
|
|
23015
|
+
supervision.nonce,
|
|
23016
|
+
"--socket",
|
|
23017
|
+
supervision.controlPath,
|
|
23018
|
+
"--",
|
|
23019
|
+
...commandArgs
|
|
23020
|
+
];
|
|
23021
|
+
const command = {
|
|
23022
|
+
kind: "modal-router-v1",
|
|
23023
|
+
sandboxId,
|
|
23024
|
+
taskId,
|
|
23025
|
+
execId,
|
|
23026
|
+
...args.tty ? { pty: true } : {},
|
|
23027
|
+
...supervision ? { supervision } : {},
|
|
23028
|
+
streams: {
|
|
23029
|
+
stdout: { byteOffset: 0, utf8Remainder: "", eof: false, exitCode: null },
|
|
23030
|
+
stderr: { byteOffset: 0, utf8Remainder: "", eof: false, exitCode: null }
|
|
23031
|
+
}
|
|
23032
|
+
};
|
|
23033
|
+
if (supervision) await reserveSupervisedLaunch(command);
|
|
23034
|
+
try {
|
|
23035
|
+
await this.withRouter(
|
|
23036
|
+
taskId,
|
|
23037
|
+
signal,
|
|
23038
|
+
(router) => router.start(
|
|
23039
|
+
{
|
|
23040
|
+
taskId,
|
|
23041
|
+
execId,
|
|
23042
|
+
commandArgs,
|
|
23043
|
+
workdir,
|
|
23044
|
+
env,
|
|
23045
|
+
...args.tty ? {
|
|
23046
|
+
ptyInfo: {
|
|
23047
|
+
enabled: true,
|
|
23048
|
+
winszRows: 24,
|
|
23049
|
+
winszCols: 80,
|
|
23050
|
+
envTerm: "xterm",
|
|
23051
|
+
ptyType: 1,
|
|
23052
|
+
noTerminateOnIdleStdin: true
|
|
23053
|
+
}
|
|
23054
|
+
} : {}
|
|
23055
|
+
},
|
|
23056
|
+
signal
|
|
23057
|
+
)
|
|
23058
|
+
);
|
|
23059
|
+
} catch (error) {
|
|
23060
|
+
if (!supervision || error instanceof ModalCommandStartRejectedError) throw error;
|
|
23061
|
+
}
|
|
23062
|
+
return command;
|
|
23063
|
+
}
|
|
23064
|
+
/** Read-only, authenticated control execution on this exact instance. Never
|
|
23065
|
+
* inferred from a fleet image selector or user command stdout. No cache: warm
|
|
23066
|
+
* instances and route/task replacement must each pass before admission. */
|
|
23067
|
+
async verifySupervisionCapability() {
|
|
23068
|
+
const sandboxId = this.sandboxId;
|
|
23069
|
+
const signal = AbortSignal.timeout(5e3);
|
|
23070
|
+
const task = await this.client.sandboxGetTaskId({ sandboxId }, { signal });
|
|
23071
|
+
if (!task.taskId || task.taskResult) throw new Error("Modal command task is unavailable");
|
|
23072
|
+
await this.withRouter(task.taskId, signal, async (router) => {
|
|
23073
|
+
const identity = { taskId: task.taskId, execId: randomUUID6() };
|
|
23074
|
+
await router.start(
|
|
23075
|
+
{
|
|
23076
|
+
...identity,
|
|
23077
|
+
commandArgs: ["/usr/local/bin/opengeni-command-supervisor", "capabilities"],
|
|
23078
|
+
workdir: "/tmp",
|
|
23079
|
+
env: {}
|
|
23080
|
+
},
|
|
23081
|
+
signal
|
|
23082
|
+
);
|
|
23083
|
+
let offset = 0;
|
|
23084
|
+
let output = "";
|
|
23085
|
+
let eof = false;
|
|
23086
|
+
let exit = null;
|
|
23087
|
+
while (!eof || exit === null) {
|
|
23088
|
+
signal.throwIfAborted();
|
|
23089
|
+
const page = await router.read(identity, "stdout", offset, 250, signal);
|
|
23090
|
+
offset += page.bytes.length;
|
|
23091
|
+
if (offset > 128) throw new Error("Modal supervision capability response exceeds bound");
|
|
23092
|
+
output += page.bytes.toString("utf8");
|
|
23093
|
+
eof = page.eof;
|
|
23094
|
+
exit = await router.poll(identity, signal);
|
|
23095
|
+
}
|
|
23096
|
+
if (exit !== 0 || output !== "native-subreaper-v1")
|
|
23097
|
+
throw new Error(
|
|
23098
|
+
"Exact Modal instance lacks compatible native supervision; command not admitted"
|
|
23099
|
+
);
|
|
23100
|
+
});
|
|
23101
|
+
if (sandboxId !== this.sandboxId)
|
|
23102
|
+
throw new Error("Modal instance changed during supervision capability verification");
|
|
23103
|
+
return { sandboxId, taskId: task.taskId };
|
|
23104
|
+
}
|
|
23105
|
+
/** Separate authenticated provider execution of the installed control helper.
|
|
23106
|
+
* User command streams are never inspected for control evidence. */
|
|
23107
|
+
async supervisionControl(command, action, receiptId) {
|
|
23108
|
+
SandboxProviderCommand.parse(command);
|
|
23109
|
+
const descriptor = command.supervision;
|
|
23110
|
+
if (!descriptor || command.sandboxId !== this.sandboxId)
|
|
23111
|
+
throw new Error("Supervised command identity is unavailable");
|
|
23112
|
+
const identity = { taskId: command.taskId, execId: randomUUID6() };
|
|
23113
|
+
const signal = AbortSignal.timeout(5e3);
|
|
23114
|
+
return await this.withRouter(command.taskId, signal, async (router) => {
|
|
23115
|
+
await router.start(
|
|
23116
|
+
{
|
|
23117
|
+
...identity,
|
|
23118
|
+
commandArgs: [
|
|
23119
|
+
"/usr/local/bin/opengeni-command-supervisor",
|
|
23120
|
+
"control",
|
|
23121
|
+
"--invocation",
|
|
23122
|
+
descriptor.invocationId,
|
|
23123
|
+
"--nonce",
|
|
23124
|
+
descriptor.nonce,
|
|
23125
|
+
"--socket",
|
|
23126
|
+
descriptor.controlPath,
|
|
23127
|
+
"--action",
|
|
23128
|
+
action,
|
|
23129
|
+
...receiptId ? ["--receipt", receiptId] : []
|
|
23130
|
+
],
|
|
23131
|
+
workdir: "/tmp",
|
|
23132
|
+
env: {}
|
|
23133
|
+
},
|
|
23134
|
+
signal
|
|
23135
|
+
);
|
|
23136
|
+
const buffers = [];
|
|
23137
|
+
let offset = 0;
|
|
23138
|
+
let eof = false;
|
|
23139
|
+
let exit = null;
|
|
23140
|
+
while (!eof || exit === null) {
|
|
23141
|
+
signal.throwIfAborted();
|
|
23142
|
+
const page = await router.read(identity, "stdout", offset, 250, signal);
|
|
23143
|
+
offset += page.bytes.length;
|
|
23144
|
+
if (offset > 4096) throw new Error("Supervisor control response exceeds its bound");
|
|
23145
|
+
buffers.push(page.bytes);
|
|
23146
|
+
eof = page.eof;
|
|
23147
|
+
exit = await router.poll(identity, signal);
|
|
23148
|
+
}
|
|
23149
|
+
if (exit !== 0) throw new Error("Supervisor control is unavailable");
|
|
23150
|
+
const result = JSON.parse(Buffer.concat(buffers).toString("utf8"));
|
|
23151
|
+
if (!result || !["idle", "running", "quiescent"].includes(result.state))
|
|
23152
|
+
throw new Error("Invalid supervisor control response");
|
|
23153
|
+
if (result.receipt !== void 0) {
|
|
23154
|
+
result.receipt = CommandSupervisionReceipt.parse(result.receipt);
|
|
23155
|
+
if (result.receipt.invocationId !== descriptor.invocationId)
|
|
23156
|
+
throw new Error("Supervisor receipt invocation mismatch");
|
|
23157
|
+
}
|
|
23158
|
+
if (result.state === "quiescent" !== Boolean(result.receipt))
|
|
23159
|
+
throw new Error("Supervisor quiescence response lacks its receipt");
|
|
23160
|
+
return result;
|
|
23161
|
+
});
|
|
23162
|
+
}
|
|
23163
|
+
async read(command, waitMs, signal) {
|
|
23164
|
+
SandboxProviderCommand.parse(command);
|
|
23165
|
+
if (command.sandboxId !== this.sandboxId)
|
|
23166
|
+
throw new Error("Modal command does not belong to this sandbox");
|
|
23167
|
+
if (command.kind === "modal-control-v1") return await this.legacy.read(command, waitMs, signal);
|
|
23168
|
+
const next = structuredClone(command);
|
|
23169
|
+
const cancellation = new AbortController();
|
|
23170
|
+
const abort = () => cancellation.abort(signal?.reason);
|
|
23171
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
23172
|
+
if (signal?.aborted) abort();
|
|
23173
|
+
try {
|
|
23174
|
+
return await this.withRouter(command.taskId, cancellation.signal, async (router) => {
|
|
23175
|
+
const operations = [
|
|
23176
|
+
...["stdout", "stderr"].map(
|
|
23177
|
+
async (stream) => command.streams[stream].eof ? { bytes: Buffer.alloc(0), eof: true } : await router.read(
|
|
23178
|
+
command,
|
|
23179
|
+
stream,
|
|
23180
|
+
command.streams[stream].byteOffset,
|
|
23181
|
+
waitMs,
|
|
23182
|
+
cancellation.signal
|
|
23183
|
+
)
|
|
23184
|
+
),
|
|
23185
|
+
router.poll(command, cancellation.signal)
|
|
23186
|
+
];
|
|
23187
|
+
const results = await Promise.allSettled(
|
|
23188
|
+
operations.map(
|
|
23189
|
+
(operation) => operation.catch((error) => {
|
|
23190
|
+
cancellation.abort(error);
|
|
23191
|
+
throw error;
|
|
23192
|
+
})
|
|
23193
|
+
)
|
|
23194
|
+
);
|
|
23195
|
+
const failed = results.find((result) => result.status === "rejected");
|
|
23196
|
+
if (failed?.status === "rejected") throw failed.reason;
|
|
23197
|
+
const stdout = results[0].value;
|
|
23198
|
+
const stderr = results[1].value;
|
|
23199
|
+
const exit = results[2].value;
|
|
23200
|
+
const chunks = [];
|
|
23201
|
+
for (const [stream, page] of [
|
|
23202
|
+
["stdout", stdout],
|
|
23203
|
+
["stderr", stderr]
|
|
23204
|
+
]) {
|
|
23205
|
+
const old = command.streams[stream];
|
|
23206
|
+
const decoded = decodePage(old.utf8Remainder, [page.bytes], page.eof);
|
|
23207
|
+
const byteOffset = old.byteOffset + page.bytes.length;
|
|
23208
|
+
if (!Number.isSafeInteger(byteOffset)) throw new Error("Modal output offset exhausted");
|
|
23209
|
+
next.streams[stream] = {
|
|
23210
|
+
byteOffset,
|
|
23211
|
+
utf8Remainder: decoded.remainder,
|
|
23212
|
+
eof: page.eof,
|
|
23213
|
+
exitCode: page.eof ? exit : null
|
|
23214
|
+
};
|
|
23215
|
+
if (decoded.text)
|
|
23216
|
+
chunks.push({
|
|
23217
|
+
stream,
|
|
23218
|
+
chunkId: `modal-router:${command.execId}:${stream}:${old.byteOffset}:${byteOffset}:${page.eof ? 1 : 0}`,
|
|
23219
|
+
text: decoded.text
|
|
23220
|
+
});
|
|
23221
|
+
}
|
|
23222
|
+
return {
|
|
23223
|
+
command: next,
|
|
23224
|
+
expected: structuredClone(command),
|
|
23225
|
+
chunks,
|
|
23226
|
+
exitCode: next.streams.stdout.eof && next.streams.stderr.eof ? exit : null,
|
|
23227
|
+
streamFidelity: command.pty ? "merged" : "separate"
|
|
23228
|
+
};
|
|
23229
|
+
});
|
|
23230
|
+
} finally {
|
|
23231
|
+
signal?.removeEventListener("abort", abort);
|
|
23232
|
+
}
|
|
23233
|
+
}
|
|
23234
|
+
async readProbe(command, waitMs, cancellation) {
|
|
23235
|
+
return await this.read(command, waitMs, cancellation.signal);
|
|
23236
|
+
}
|
|
23237
|
+
async write(command, chars, index) {
|
|
23238
|
+
SandboxProviderCommand.parse(command);
|
|
23239
|
+
if (command.sandboxId !== this.sandboxId)
|
|
23240
|
+
throw new Error("Modal command does not belong to this sandbox");
|
|
23241
|
+
if (command.kind === "modal-control-v1") return await this.legacy.write(command, chars, index);
|
|
23242
|
+
await this.withRouter(
|
|
23243
|
+
command.taskId,
|
|
23244
|
+
void 0,
|
|
23245
|
+
(router) => router.write(command, index, Buffer.from(chars))
|
|
23246
|
+
);
|
|
23247
|
+
}
|
|
23248
|
+
};
|
|
23249
|
+
|
|
22151
23250
|
// src/sandbox/providers/modal.ts
|
|
22152
23251
|
var MODAL_ORPHAN_SWEEP_LIMIT = 50;
|
|
22153
23252
|
var OPENGENI_MODAL_SDK_VERSION = "0.9.0";
|
|
@@ -22231,8 +23330,8 @@ var MODAL_TASK_EXEC_START_ERROR_MAX_NODES = 64;
|
|
|
22231
23330
|
var MODAL_TASK_EXEC_START_ERROR_MAX_AGGREGATE_ERRORS = 32;
|
|
22232
23331
|
function modalHttpStatus(value) {
|
|
22233
23332
|
if (typeof value !== "number" && typeof value !== "string") return null;
|
|
22234
|
-
const
|
|
22235
|
-
return Number.isInteger(
|
|
23333
|
+
const status2 = Number(value);
|
|
23334
|
+
return Number.isInteger(status2) && status2 >= 100 && status2 <= 599 ? status2 : null;
|
|
22236
23335
|
}
|
|
22237
23336
|
function hasContradictoryModalHttpStatus(record) {
|
|
22238
23337
|
const values = [record.status, record.statusCode, record.httpStatus, record.httpStatusCode];
|
|
@@ -22471,7 +23570,7 @@ function installOpenGeniModalSnapshotPolicy(session) {
|
|
|
22471
23570
|
throw new Error("Modal command control requires its original authenticated SDK profile");
|
|
22472
23571
|
installModalCommandSession(
|
|
22473
23572
|
mutable,
|
|
22474
|
-
|
|
23573
|
+
ModalCommandControl2.forSandbox(
|
|
22475
23574
|
{
|
|
22476
23575
|
cpClient: mutable.modal.cpClient,
|
|
22477
23576
|
version: mutable.modal.version.bind(mutable.modal),
|
|
@@ -23055,9 +24154,9 @@ import {
|
|
|
23055
24154
|
SandboxApiException,
|
|
23056
24155
|
createDefaultAdapterFactory
|
|
23057
24156
|
} from "@alibaba-group/opensandbox";
|
|
23058
|
-
import { createHash as createHash6, randomUUID as
|
|
24157
|
+
import { createHash as createHash6, randomUUID as randomUUID7 } from "crypto";
|
|
23059
24158
|
import { lstat as lstat6, readFile as readLocalFile, readdir as readdir6 } from "fs/promises";
|
|
23060
|
-
import { posix as
|
|
24159
|
+
import { posix as posix4 } from "path";
|
|
23061
24160
|
|
|
23062
24161
|
// src/sandbox/stream-port.ts
|
|
23063
24162
|
import { DESKTOP_STREAM_PORT as DESKTOP_STREAM_PORT3 } from "@opengeni/contracts";
|
|
@@ -23124,8 +24223,8 @@ function joinExposedPortPath(endpointPath, requestPath) {
|
|
|
23124
24223
|
throw new StreamPortUnavailableError("exposed-port request path is invalid");
|
|
23125
24224
|
}
|
|
23126
24225
|
const raw = typeof endpointPath === "string" && endpointPath.length > 0 ? endpointPath : "/";
|
|
23127
|
-
const
|
|
23128
|
-
return `${
|
|
24226
|
+
const prefix2 = (raw.startsWith("/") ? raw : `/${raw}`).replace(/\/+$/u, "") || "";
|
|
24227
|
+
return `${prefix2}${requestPath}`;
|
|
23129
24228
|
}
|
|
23130
24229
|
var OPENSANDBOX_LIFECYCLE_PROXY_PATH = /\/v1\/sandboxes\/[^/]+\/proxy\/\d+(?:\/|$)/u;
|
|
23131
24230
|
var OPENSANDBOX_SIGNED_URI_PATH = /^\/([^/]{1,128})\/(\d{1,5})\/([0-9a-z]{1,13})\/([0-9a-z]{8,64})(?:\/|$)/iu;
|
|
@@ -23376,7 +24475,7 @@ function workspacePath(path, options = {}) {
|
|
|
23376
24475
|
if (raw.includes("\0") || raw.includes("\\")) {
|
|
23377
24476
|
throw new SandboxConfigurationError(`Invalid OpenSandbox path: ${path}`);
|
|
23378
24477
|
}
|
|
23379
|
-
const absolute = raw.startsWith("/") ?
|
|
24478
|
+
const absolute = raw.startsWith("/") ? posix4.normalize(raw) : posix4.join(WORKSPACE_ROOT, raw);
|
|
23380
24479
|
const allowed = absolute === WORKSPACE_ROOT || absolute.startsWith(`${WORKSPACE_ROOT}/`) || options.allowPrivate === true && isAllowedPrivatePath(absolute);
|
|
23381
24480
|
if (!allowed) {
|
|
23382
24481
|
throw new SandboxConfigurationError(
|
|
@@ -23402,7 +24501,7 @@ function commandForArgs(args) {
|
|
|
23402
24501
|
return `${shellQuote(requestedShell)}${args.login === false ? "" : " -l"} -c ${shellQuote(args.cmd)}`;
|
|
23403
24502
|
}
|
|
23404
24503
|
function delay2(ms) {
|
|
23405
|
-
return new Promise((
|
|
24504
|
+
return new Promise((resolve7) => setTimeout(resolve7, Math.max(0, ms)));
|
|
23406
24505
|
}
|
|
23407
24506
|
function consumeProcessOutput(process2) {
|
|
23408
24507
|
const events = process2.events.slice(process2.cursor);
|
|
@@ -23666,10 +24765,10 @@ var OpenSandboxSession = class {
|
|
|
23666
24765
|
this.state.workspaceReady = true;
|
|
23667
24766
|
}
|
|
23668
24767
|
beginCommand(args) {
|
|
23669
|
-
const opId = nextDurableOpId() ?? `anon_${
|
|
24768
|
+
const opId = nextDurableOpId() ?? `anon_${randomUUID7()}`;
|
|
23670
24769
|
let resolveExecutionId;
|
|
23671
|
-
const executionIdReady = new Promise((
|
|
23672
|
-
resolveExecutionId =
|
|
24770
|
+
const executionIdReady = new Promise((resolve7) => {
|
|
24771
|
+
resolveExecutionId = resolve7;
|
|
23673
24772
|
});
|
|
23674
24773
|
const process2 = {
|
|
23675
24774
|
opId,
|
|
@@ -23744,18 +24843,18 @@ var OpenSandboxSession = class {
|
|
|
23744
24843
|
const provider = await this.ensureStarted();
|
|
23745
24844
|
while (true) {
|
|
23746
24845
|
try {
|
|
23747
|
-
const
|
|
23748
|
-
if (
|
|
23749
|
-
if (
|
|
23750
|
-
process2.events.push({ stream: "stderr", text: `${
|
|
24846
|
+
const status2 = await provider.commands.getCommandStatus(executionId);
|
|
24847
|
+
if (status2.running === false) {
|
|
24848
|
+
if (status2.error) {
|
|
24849
|
+
process2.events.push({ stream: "stderr", text: `${status2.error}
|
|
23751
24850
|
` });
|
|
23752
24851
|
}
|
|
23753
24852
|
process2.settled = true;
|
|
23754
24853
|
process2.transportUncertain = false;
|
|
23755
24854
|
this.processesByOpId.delete(process2.opId);
|
|
23756
24855
|
return {
|
|
23757
|
-
exitCode:
|
|
23758
|
-
...
|
|
24856
|
+
exitCode: status2.exitCode ?? 1,
|
|
24857
|
+
...status2.error ? { error: status2.error } : {}
|
|
23759
24858
|
};
|
|
23760
24859
|
}
|
|
23761
24860
|
} catch {
|
|
@@ -23886,14 +24985,14 @@ var OpenSandboxSession = class {
|
|
|
23886
24985
|
);
|
|
23887
24986
|
}
|
|
23888
24987
|
const provider = await this.ensureStarted();
|
|
23889
|
-
const
|
|
23890
|
-
if (
|
|
23891
|
-
process2.events.push({ stream: "stderr", text: `${
|
|
24988
|
+
const status2 = await provider.commands.getCommandStatus(executionId);
|
|
24989
|
+
if (status2.error) {
|
|
24990
|
+
process2.events.push({ stream: "stderr", text: `${status2.error}
|
|
23892
24991
|
` });
|
|
23893
24992
|
}
|
|
23894
24993
|
const consumed2 = consumeProcessOutput(process2);
|
|
23895
24994
|
const output2 = truncateOutput(consumed2.output, args.maxOutputTokens);
|
|
23896
|
-
if (
|
|
24995
|
+
if (status2.running !== false) {
|
|
23897
24996
|
return formatExecResponse({
|
|
23898
24997
|
output: output2.text,
|
|
23899
24998
|
wallTimeSeconds: elapsedSeconds(startedAt),
|
|
@@ -23907,7 +25006,7 @@ var OpenSandboxSession = class {
|
|
|
23907
25006
|
return formatExecResponse({
|
|
23908
25007
|
output: output2.text,
|
|
23909
25008
|
wallTimeSeconds: elapsedSeconds(startedAt),
|
|
23910
|
-
exitCode:
|
|
25009
|
+
exitCode: status2.exitCode ?? 1,
|
|
23911
25010
|
...output2.originalTokenCount !== void 0 ? { originalTokenCount: output2.originalTokenCount } : {}
|
|
23912
25011
|
});
|
|
23913
25012
|
}
|
|
@@ -23964,7 +25063,7 @@ var OpenSandboxSession = class {
|
|
|
23964
25063
|
const provider = await this.ensureStarted();
|
|
23965
25064
|
const target = workspacePath(args.path, { allowPrivate: true });
|
|
23966
25065
|
if (args.createParents ?? true) {
|
|
23967
|
-
await provider.files.createDirectories([{ path:
|
|
25066
|
+
await provider.files.createDirectories([{ path: posix4.dirname(target) }]);
|
|
23968
25067
|
}
|
|
23969
25068
|
await provider.files.writeFiles([{ path: target, data: args.content }]);
|
|
23970
25069
|
return typeof args.content === "string" ? new TextEncoder().encode(args.content).byteLength : args.content.byteLength;
|
|
@@ -23993,7 +25092,7 @@ var OpenSandboxSession = class {
|
|
|
23993
25092
|
return entries.map((entry) => {
|
|
23994
25093
|
const entryPath = workspacePath(entry.path);
|
|
23995
25094
|
return {
|
|
23996
|
-
name:
|
|
25095
|
+
name: posix4.basename(entryPath),
|
|
23997
25096
|
path: absoluteOutput ? entryPath : entryPath === WORKSPACE_ROOT ? "" : entryPath.slice(WORKSPACE_ROOT.length + 1),
|
|
23998
25097
|
type: entry.type === "directory" ? "dir" : entry.type === "file" ? "file" : "other"
|
|
23999
25098
|
};
|
|
@@ -24082,7 +25181,7 @@ var OpenSandboxSession = class {
|
|
|
24082
25181
|
const entries = await readdir6(source, { withFileTypes: true });
|
|
24083
25182
|
for (const entry of entries) {
|
|
24084
25183
|
const sourcePath = `${source.replace(/\/$/u, "")}/${entry.name}`;
|
|
24085
|
-
const destinationPath =
|
|
25184
|
+
const destinationPath = posix4.join(destination, entry.name);
|
|
24086
25185
|
if (entry.isSymbolicLink()) {
|
|
24087
25186
|
throw new SandboxUnsupportedFeatureError(
|
|
24088
25187
|
`OpenSandbox local_dir source contains a symbolic link: ${sourcePath}`
|
|
@@ -24110,13 +25209,13 @@ var OpenSandboxSession = class {
|
|
|
24110
25209
|
if (entry.type === "dir") {
|
|
24111
25210
|
await provider.files.createDirectories([{ path: target }]);
|
|
24112
25211
|
for (const [childPath, child] of Object.entries(entry.children ?? {})) {
|
|
24113
|
-
await this.materialize(
|
|
25212
|
+
await this.materialize(posix4.join(path, childPath), child);
|
|
24114
25213
|
}
|
|
24115
25214
|
await this.applyPermissions(target, entry);
|
|
24116
25215
|
return;
|
|
24117
25216
|
}
|
|
24118
25217
|
if (entry.type === "file") {
|
|
24119
|
-
await provider.files.createDirectories([{ path:
|
|
25218
|
+
await provider.files.createDirectories([{ path: posix4.dirname(target) }]);
|
|
24120
25219
|
await provider.files.writeFiles([{ path: target, data: entry.content }]);
|
|
24121
25220
|
await this.applyPermissions(target, entry);
|
|
24122
25221
|
return;
|
|
@@ -24128,7 +25227,7 @@ var OpenSandboxSession = class {
|
|
|
24128
25227
|
`OpenSandbox local_file source must be a regular non-symlink file: ${entry.src}`
|
|
24129
25228
|
);
|
|
24130
25229
|
}
|
|
24131
|
-
await provider.files.createDirectories([{ path:
|
|
25230
|
+
await provider.files.createDirectories([{ path: posix4.dirname(target) }]);
|
|
24132
25231
|
await provider.files.writeFiles([
|
|
24133
25232
|
{ path: target, data: new Uint8Array(await readLocalFile(entry.src)) }
|
|
24134
25233
|
]);
|
|
@@ -24141,7 +25240,7 @@ var OpenSandboxSession = class {
|
|
|
24141
25240
|
return;
|
|
24142
25241
|
}
|
|
24143
25242
|
if (entry.type === "git_repo") {
|
|
24144
|
-
const temp = `/tmp/opengeni-git-${
|
|
25243
|
+
const temp = `/tmp/opengeni-git-${randomUUID7()}`;
|
|
24145
25244
|
const subpath = entry.subpath ? normalizeRelativePath(entry.subpath) : null;
|
|
24146
25245
|
const script = [
|
|
24147
25246
|
"set -eu",
|
|
@@ -24207,7 +25306,7 @@ var OpenSandboxSession = class {
|
|
|
24207
25306
|
);
|
|
24208
25307
|
}
|
|
24209
25308
|
async persistWorkspaceTar() {
|
|
24210
|
-
const archivePath = `${PRIVATE_ROOT}/capture-${
|
|
25309
|
+
const archivePath = `${PRIVATE_ROOT}/capture-${randomUUID7()}.tar`;
|
|
24211
25310
|
const excludes = [
|
|
24212
25311
|
...this.state.manifest.ephemeralPersistencePaths(),
|
|
24213
25312
|
".opengeni-old-*",
|
|
@@ -24264,9 +25363,9 @@ tar ${excludeArgs.join(" ")} --sort=name --mtime='@0' --owner=0 --group=0 --nume
|
|
|
24264
25363
|
maxInputBytes: limits.maxInputBytes
|
|
24265
25364
|
});
|
|
24266
25365
|
}
|
|
24267
|
-
const archivePath = `${PRIVATE_ROOT}/restore-${
|
|
24268
|
-
const stagingPath = `${WORKSPACE_ROOT}/.opengeni-restore-${
|
|
24269
|
-
const backupPath = `${WORKSPACE_ROOT}/.opengeni-old-${
|
|
25366
|
+
const archivePath = `${PRIVATE_ROOT}/restore-${randomUUID7()}.tar`;
|
|
25367
|
+
const stagingPath = `${WORKSPACE_ROOT}/.opengeni-restore-${randomUUID7()}`;
|
|
25368
|
+
const backupPath = `${WORKSPACE_ROOT}/.opengeni-old-${randomUUID7()}`;
|
|
24270
25369
|
await this.writeFile({
|
|
24271
25370
|
path: archivePath,
|
|
24272
25371
|
content: bytes,
|
|
@@ -24365,12 +25464,12 @@ function withOpenSandboxDesktopViewerPath(endpoint, port, signedEndpoints) {
|
|
|
24365
25464
|
if (signedEndpoints) return endpoint;
|
|
24366
25465
|
if (port !== OPENSANDBOX_DESKTOP_STREAM_PORT) return endpoint;
|
|
24367
25466
|
const rawPath = typeof endpoint.path === "string" && endpoint.path.length > 0 ? endpoint.path : "/";
|
|
24368
|
-
const
|
|
24369
|
-
if (
|
|
24370
|
-
if (/\/vnc(_lite)?\.html$/u.test(
|
|
25467
|
+
const prefix2 = (rawPath.startsWith("/") ? rawPath : `/${rawPath}`).replace(/\/+$/u, "");
|
|
25468
|
+
if (prefix2.length === 0) return endpoint;
|
|
25469
|
+
if (/\/vnc(_lite)?\.html$/u.test(prefix2) || prefix2.endsWith("/websockify")) {
|
|
24371
25470
|
return endpoint;
|
|
24372
25471
|
}
|
|
24373
|
-
const path = `${
|
|
25472
|
+
const path = `${prefix2}/vnc.html`;
|
|
24374
25473
|
const url = typeof endpoint.url === "string" && endpoint.url.length > 0 ? `${endpoint.url.replace(/\/+$/u, "")}/vnc.html` : endpoint.url;
|
|
24375
25474
|
return { ...endpoint, path, ...url ? { url } : {} };
|
|
24376
25475
|
}
|
|
@@ -25648,8 +26747,8 @@ function isRunloopConflictError(error) {
|
|
|
25648
26747
|
if (!isRecord(error)) {
|
|
25649
26748
|
return false;
|
|
25650
26749
|
}
|
|
25651
|
-
const
|
|
25652
|
-
if (
|
|
26750
|
+
const status2 = error.status ?? error.statusCode;
|
|
26751
|
+
if (status2 === 409 || status2 === "409") {
|
|
25653
26752
|
return true;
|
|
25654
26753
|
}
|
|
25655
26754
|
const code = error.code;
|
|
@@ -26062,7 +27161,7 @@ function decideSelfhostedRetry(input) {
|
|
|
26062
27161
|
return { action: "fail" };
|
|
26063
27162
|
}
|
|
26064
27163
|
var defaultSelfhostedRetryClock = {
|
|
26065
|
-
sleep: (ms) => new Promise((
|
|
27164
|
+
sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
|
|
26066
27165
|
jitter: () => Math.random()
|
|
26067
27166
|
};
|
|
26068
27167
|
|
|
@@ -26455,8 +27554,8 @@ var OpConsumer = class {
|
|
|
26455
27554
|
}
|
|
26456
27555
|
async run(exec, deadlineMs, wallMs, yieldOptions) {
|
|
26457
27556
|
this.captureOnly = exec === null;
|
|
26458
|
-
const settled = new Promise((
|
|
26459
|
-
this.settleResolve =
|
|
27557
|
+
const settled = new Promise((resolve7, reject) => {
|
|
27558
|
+
this.settleResolve = resolve7;
|
|
26460
27559
|
this.settleReject = reject;
|
|
26461
27560
|
});
|
|
26462
27561
|
this.subscription = await this.deps.transport.subscribe(
|
|
@@ -26481,8 +27580,8 @@ var OpConsumer = class {
|
|
|
26481
27580
|
const phase = await Promise.race([
|
|
26482
27581
|
settled.then(() => "settled"),
|
|
26483
27582
|
liveness.wall,
|
|
26484
|
-
new Promise((
|
|
26485
|
-
yieldTimer = setTimeout(() =>
|
|
27583
|
+
new Promise((resolve7) => {
|
|
27584
|
+
yieldTimer = setTimeout(() => resolve7("yield"), yieldOptions.yieldMs);
|
|
26486
27585
|
})
|
|
26487
27586
|
]);
|
|
26488
27587
|
if (phase === "yield" && this.exitSeq === void 0) {
|
|
@@ -26632,12 +27731,12 @@ var OpConsumer = class {
|
|
|
26632
27731
|
if (result.$case !== "opStart") {
|
|
26633
27732
|
throw protocolError(`op-stream start: unexpected result ${result.$case}`);
|
|
26634
27733
|
}
|
|
26635
|
-
const
|
|
27734
|
+
const status2 = result.opStart.status;
|
|
26636
27735
|
if (!result.opStart.accepted) {
|
|
26637
|
-
throw this.refusedStart(
|
|
27736
|
+
throw this.refusedStart(status2);
|
|
26638
27737
|
}
|
|
26639
|
-
if (
|
|
26640
|
-
throw lostToControlError(
|
|
27738
|
+
if (status2?.state === OpState2.OP_STATE_LOST) {
|
|
27739
|
+
throw lostToControlError(status2);
|
|
26641
27740
|
}
|
|
26642
27741
|
return drainingRetries + blipRetries;
|
|
26643
27742
|
} catch (error) {
|
|
@@ -26669,8 +27768,8 @@ var OpConsumer = class {
|
|
|
26669
27768
|
}
|
|
26670
27769
|
}
|
|
26671
27770
|
}
|
|
26672
|
-
refusedStart(
|
|
26673
|
-
if (
|
|
27771
|
+
refusedStart(status2) {
|
|
27772
|
+
if (status2?.exit?.cancelled) {
|
|
26674
27773
|
return new SelfhostedControlError({
|
|
26675
27774
|
message: "The command was cancelled before the machine admitted it.",
|
|
26676
27775
|
code: ErrorCode3.ERROR_CODE_TIMEOUT,
|
|
@@ -26679,8 +27778,8 @@ var OpConsumer = class {
|
|
|
26679
27778
|
detail: { cancelled: "true" }
|
|
26680
27779
|
});
|
|
26681
27780
|
}
|
|
26682
|
-
if (
|
|
26683
|
-
return lostToControlError(
|
|
27781
|
+
if (status2?.state === OpState2.OP_STATE_LOST) {
|
|
27782
|
+
return lostToControlError(status2);
|
|
26684
27783
|
}
|
|
26685
27784
|
return protocolError("op-stream start: the runner refused the op without a typed reason");
|
|
26686
27785
|
}
|
|
@@ -26916,12 +28015,12 @@ var OpConsumer = class {
|
|
|
26916
28015
|
if (result.$case !== "opStatus") {
|
|
26917
28016
|
throw protocolError(`op-stream query: unexpected result ${result.$case}`);
|
|
26918
28017
|
}
|
|
26919
|
-
const
|
|
26920
|
-
if (
|
|
26921
|
-
reject(lostToControlError(
|
|
28018
|
+
const status2 = result.opStatus;
|
|
28019
|
+
if (status2.state === OpState2.OP_STATE_LOST) {
|
|
28020
|
+
reject(lostToControlError(status2));
|
|
26922
28021
|
return;
|
|
26923
28022
|
}
|
|
26924
|
-
if (BigInt(
|
|
28023
|
+
if (BigInt(status2.nextSeq) > this.lastApplied + 1n) {
|
|
26925
28024
|
this.requestAttachHeal();
|
|
26926
28025
|
}
|
|
26927
28026
|
} catch (error) {
|
|
@@ -26989,14 +28088,14 @@ function protocolError(message) {
|
|
|
26989
28088
|
retryable: false
|
|
26990
28089
|
});
|
|
26991
28090
|
}
|
|
26992
|
-
function lostToControlError(
|
|
26993
|
-
const reason =
|
|
28091
|
+
function lostToControlError(status2) {
|
|
28092
|
+
const reason = status2.lostReason === OpLostReason.OP_LOST_REASON_EVICTED ? "its retained result was evicted before collection" : status2.lostReason === OpLostReason.OP_LOST_REASON_AGENT_RESTARTED ? "the machine agent restarted and the op did not survive" : "the runner reported it lost";
|
|
26994
28093
|
return new SelfhostedControlError({
|
|
26995
28094
|
message: `The command's result is no longer available on the machine (${reason}). Check whether its effects already took place before re-running it.`,
|
|
26996
28095
|
code: ErrorCode3.ERROR_CODE_STREAM,
|
|
26997
28096
|
reason: null,
|
|
26998
28097
|
retryable: false,
|
|
26999
|
-
detail: { lost_reason: String(
|
|
28098
|
+
detail: { lost_reason: String(status2.lostReason) }
|
|
27000
28099
|
});
|
|
27001
28100
|
}
|
|
27002
28101
|
function runnerFailureToControlError(exit) {
|
|
@@ -28475,8 +29574,8 @@ function sniffImageMediaType2(bytes, path) {
|
|
|
28475
29574
|
return mediaTypeFromPath(path);
|
|
28476
29575
|
}
|
|
28477
29576
|
function looksLikeSvg(bytes) {
|
|
28478
|
-
const
|
|
28479
|
-
return
|
|
29577
|
+
const prefix2 = decoder.decode(bytes.subarray(0, Math.min(bytes.byteLength, 512))).trimStart().toLowerCase();
|
|
29578
|
+
return prefix2.startsWith("<svg") || /^<\?xml[\s\S]*<svg/u.test(prefix2);
|
|
28480
29579
|
}
|
|
28481
29580
|
function mediaTypeFromPath(path) {
|
|
28482
29581
|
const p = path?.trim().toLowerCase() ?? "";
|
|
@@ -28977,8 +30076,8 @@ var VercelMountOperationMutex = class {
|
|
|
28977
30076
|
async runExclusive(operation) {
|
|
28978
30077
|
const previous = this.tail;
|
|
28979
30078
|
let release;
|
|
28980
|
-
this.tail = new Promise((
|
|
28981
|
-
release =
|
|
30079
|
+
this.tail = new Promise((resolve7) => {
|
|
30080
|
+
release = resolve7;
|
|
28982
30081
|
});
|
|
28983
30082
|
await previous;
|
|
28984
30083
|
try {
|
|
@@ -29534,8 +30633,8 @@ var VercelSandboxSession = class _VercelSandboxSession extends RemoteSandboxSess
|
|
|
29534
30633
|
}
|
|
29535
30634
|
async replaceSandboxFromSnapshot(snapshotId, options = {}) {
|
|
29536
30635
|
const previousSandbox = this.sandbox;
|
|
29537
|
-
const
|
|
29538
|
-
const sandbox = await this.createAndPrepareSandboxFromSnapshot(snapshotId,
|
|
30636
|
+
const credentials2 = await this.resolveSnapshotCredentials();
|
|
30637
|
+
const sandbox = await this.createAndPrepareSandboxFromSnapshot(snapshotId, credentials2);
|
|
29539
30638
|
try {
|
|
29540
30639
|
await stopVercelSandbox(previousSandbox);
|
|
29541
30640
|
} catch (error) {
|
|
@@ -29578,8 +30677,8 @@ var VercelSandboxSession = class _VercelSandboxSession extends RemoteSandboxSess
|
|
|
29578
30677
|
async resolveSnapshotCredentials() {
|
|
29579
30678
|
return selectVercelSessionCredentials(this.state, this.credentials);
|
|
29580
30679
|
}
|
|
29581
|
-
async createAndPrepareSandboxFromSnapshot(snapshotId,
|
|
29582
|
-
const sandbox = await this.createSandboxFromSnapshot(snapshotId,
|
|
30680
|
+
async createAndPrepareSandboxFromSnapshot(snapshotId, credentials2) {
|
|
30681
|
+
const sandbox = await this.createSandboxFromSnapshot(snapshotId, credentials2);
|
|
29583
30682
|
const resolvedCredentials = selectVercelSessionCredentials(this.state, this.credentials);
|
|
29584
30683
|
const replacementSession = new _VercelSandboxSession({
|
|
29585
30684
|
credentials: resolvedCredentials,
|
|
@@ -29607,9 +30706,9 @@ var VercelSandboxSession = class _VercelSandboxSession extends RemoteSandboxSess
|
|
|
29607
30706
|
}
|
|
29608
30707
|
return sandbox;
|
|
29609
30708
|
}
|
|
29610
|
-
async createSandboxFromSnapshot(snapshotId,
|
|
30709
|
+
async createSandboxFromSnapshot(snapshotId, credentials2) {
|
|
29611
30710
|
const Sandbox = await loadVercelSandboxClass();
|
|
29612
|
-
const authentication = await withProviderError("VercelSandboxClient", "vercel", "restore snapshot", async () => await runWithLegacyVercelAuthenticationFallback(this.state,
|
|
30711
|
+
const authentication = await withProviderError("VercelSandboxClient", "vercel", "restore snapshot", async () => await runWithLegacyVercelAuthenticationFallback(this.state, credentials2, async (resolvedCredentials) => await Sandbox.create({
|
|
29613
30712
|
...resolvedCredentials,
|
|
29614
30713
|
source: {
|
|
29615
30714
|
type: "snapshot",
|
|
@@ -29740,9 +30839,9 @@ var VercelSandboxClient = class {
|
|
|
29740
30839
|
}, async () => {
|
|
29741
30840
|
const Sandbox = await loadVercelSandboxClass();
|
|
29742
30841
|
const environment = await materializeEnvironment(resolvedManifest, resolvedOptions.env);
|
|
29743
|
-
const
|
|
30842
|
+
const credentials2 = resolveVercelCredentials(createArgs.options ?? {}, this.options);
|
|
29744
30843
|
const sandbox = await withProviderError("VercelSandboxClient", "vercel", "create sandbox", async () => await Sandbox.create({
|
|
29745
|
-
...
|
|
30844
|
+
...credentials2,
|
|
29746
30845
|
...resolvedOptions.runtime ? { runtime: resolvedOptions.runtime } : {},
|
|
29747
30846
|
...resolvedOptions.resources ? { resources: resolvedOptions.resources } : {},
|
|
29748
30847
|
...resolvedOptions.exposedPorts ? { ports: resolvedOptions.exposedPorts } : {},
|
|
@@ -29753,14 +30852,14 @@ var VercelSandboxClient = class {
|
|
|
29753
30852
|
}), { runtime: resolvedOptions.runtime });
|
|
29754
30853
|
const session = new VercelSandboxSession({
|
|
29755
30854
|
sandbox,
|
|
29756
|
-
credentials,
|
|
30855
|
+
credentials: credentials2,
|
|
29757
30856
|
concurrencyLimits: createArgs.concurrencyLimits,
|
|
29758
30857
|
archiveLimits: createArgs.archiveLimits,
|
|
29759
30858
|
state: {
|
|
29760
30859
|
manifest: persistentManifest,
|
|
29761
30860
|
sandboxId: sandbox.sandboxId,
|
|
29762
|
-
authenticationMode:
|
|
29763
|
-
...
|
|
30861
|
+
authenticationMode: credentials2.token ? "explicit" : "sdk",
|
|
30862
|
+
...credentials2,
|
|
29764
30863
|
runtime: resolvedOptions.runtime,
|
|
29765
30864
|
resources: resolvedOptions.resources,
|
|
29766
30865
|
configuredExposedPorts: resolvedOptions.exposedPorts,
|
|
@@ -29790,12 +30889,12 @@ var VercelSandboxClient = class {
|
|
|
29790
30889
|
}
|
|
29791
30890
|
async serializeSessionState(state, options) {
|
|
29792
30891
|
state.manifest = sanitizeVercelMountManifest(state.manifest);
|
|
29793
|
-
const
|
|
29794
|
-
applyVercelCredentials(state,
|
|
30892
|
+
const credentials2 = selectVercelSessionCredentials(state, this.options);
|
|
30893
|
+
applyVercelCredentials(state, credentials2);
|
|
29795
30894
|
if (!hasVercelMounts(state.manifest) && state.workspacePersistence === "snapshot" && state.snapshotSupported !== false && state.snapshotSandboxId !== state.sandboxId && (options?.reuseLiveSession === false || options?.willCloseAfterSerialize)) {
|
|
29796
30895
|
await captureVercelSnapshot(state, {
|
|
29797
30896
|
options: {
|
|
29798
|
-
...
|
|
30897
|
+
...credentials2
|
|
29799
30898
|
}
|
|
29800
30899
|
});
|
|
29801
30900
|
}
|
|
@@ -29850,9 +30949,9 @@ var VercelSandboxClient = class {
|
|
|
29850
30949
|
});
|
|
29851
30950
|
}
|
|
29852
30951
|
const Sandbox = await loadVercelSandboxClass();
|
|
29853
|
-
const
|
|
30952
|
+
const credentials2 = selectVercelSessionCredentials(state, this.options);
|
|
29854
30953
|
const resumeFromSnapshot = hasFreshVercelSnapshot(state);
|
|
29855
|
-
const authentication = resumeFromSnapshot ? await withProviderError("VercelSandboxClient", "vercel", "resume sandbox from snapshot", async () => await runWithLegacyVercelAuthenticationFallback(state,
|
|
30954
|
+
const authentication = resumeFromSnapshot ? await withProviderError("VercelSandboxClient", "vercel", "resume sandbox from snapshot", async () => await runWithLegacyVercelAuthenticationFallback(state, credentials2, async (resolvedCredentials2) => await Sandbox.create({
|
|
29856
30955
|
...resolvedCredentials2,
|
|
29857
30956
|
source: {
|
|
29858
30957
|
type: "snapshot",
|
|
@@ -29865,7 +30964,7 @@ var VercelSandboxClient = class {
|
|
|
29865
30964
|
...state.networkPolicy ? { networkPolicy: state.networkPolicy } : {},
|
|
29866
30965
|
...state.timeoutMs !== void 0 ? { timeout: state.timeoutMs } : {},
|
|
29867
30966
|
env: state.environment
|
|
29868
|
-
})), { snapshotId: state.snapshotId, sandboxId: state.sandboxId }) : await withProviderError("VercelSandboxClient", "vercel", "resume sandbox", async () => await runWithLegacyVercelAuthenticationFallback(state,
|
|
30967
|
+
})), { snapshotId: state.snapshotId, sandboxId: state.sandboxId }) : await withProviderError("VercelSandboxClient", "vercel", "resume sandbox", async () => await runWithLegacyVercelAuthenticationFallback(state, credentials2, async (resolvedCredentials2) => await Sandbox.get({
|
|
29869
30968
|
sandboxId: state.sandboxId,
|
|
29870
30969
|
...resolvedCredentials2
|
|
29871
30970
|
})), { sandboxId: state.sandboxId });
|
|
@@ -30086,14 +31185,14 @@ function selectVercelSessionCredentials(state, ...fallbackLayers) {
|
|
|
30086
31185
|
}
|
|
30087
31186
|
return selectVercelCredentials(state, ...fallbackLayers);
|
|
30088
31187
|
}
|
|
30089
|
-
async function runWithLegacyVercelAuthenticationFallback(state,
|
|
31188
|
+
async function runWithLegacyVercelAuthenticationFallback(state, credentials2, operation) {
|
|
30090
31189
|
const serializedCredentials = normalizeVercelCredentials(state);
|
|
30091
31190
|
const hasLegacySerializedCredentials = state.authenticationMode === void 0 && serializedCredentials.token !== void 0;
|
|
30092
|
-
const authenticationMode = state.authenticationMode ?? (hasLegacySerializedCredentials ? void 0 :
|
|
31191
|
+
const authenticationMode = state.authenticationMode ?? (hasLegacySerializedCredentials ? void 0 : credentials2.token ? "explicit" : "sdk");
|
|
30093
31192
|
try {
|
|
30094
31193
|
return {
|
|
30095
|
-
value: await operation(
|
|
30096
|
-
credentials,
|
|
31194
|
+
value: await operation(credentials2),
|
|
31195
|
+
credentials: credentials2,
|
|
30097
31196
|
authenticationMode
|
|
30098
31197
|
};
|
|
30099
31198
|
} catch (error) {
|
|
@@ -30110,7 +31209,7 @@ async function runWithLegacyVercelAuthenticationFallback(state, credentials, ope
|
|
|
30110
31209
|
}
|
|
30111
31210
|
function isVercelUnauthorizedError(error) {
|
|
30112
31211
|
const details = providerErrorDetails(error);
|
|
30113
|
-
return [details.status, details.httpStatus, details.responseStatus].some((
|
|
31212
|
+
return [details.status, details.httpStatus, details.responseStatus].some((status2) => status2 === 401 || status2 === "401");
|
|
30114
31213
|
}
|
|
30115
31214
|
function applyVercelAuthentication(state, authentication) {
|
|
30116
31215
|
applyVercelCredentials(state, authentication.credentials);
|
|
@@ -30120,11 +31219,11 @@ function applyVercelAuthentication(state, authentication) {
|
|
|
30120
31219
|
state.authenticationMode = authentication.authenticationMode;
|
|
30121
31220
|
}
|
|
30122
31221
|
}
|
|
30123
|
-
function applyVercelCredentials(state,
|
|
31222
|
+
function applyVercelCredentials(state, credentials2) {
|
|
30124
31223
|
delete state.projectId;
|
|
30125
31224
|
delete state.teamId;
|
|
30126
31225
|
delete state.token;
|
|
30127
|
-
const normalized = normalizeVercelCredentials(
|
|
31226
|
+
const normalized = normalizeVercelCredentials(credentials2);
|
|
30128
31227
|
if (normalized.token) {
|
|
30129
31228
|
state.projectId = normalized.projectId;
|
|
30130
31229
|
state.teamId = normalized.teamId;
|
|
@@ -30144,8 +31243,8 @@ async function captureVercelSnapshot(state, args = {}) {
|
|
|
30144
31243
|
}
|
|
30145
31244
|
let sandbox = args.sandbox;
|
|
30146
31245
|
if (!sandbox) {
|
|
30147
|
-
const
|
|
30148
|
-
const authentication = await withProviderError("VercelSandboxClient", "vercel", "look up sandbox for snapshot", async () => await runWithLegacyVercelAuthenticationFallback(state,
|
|
31246
|
+
const credentials2 = selectVercelSessionCredentials(state, args.options ?? {});
|
|
31247
|
+
const authentication = await withProviderError("VercelSandboxClient", "vercel", "look up sandbox for snapshot", async () => await runWithLegacyVercelAuthenticationFallback(state, credentials2, async (resolvedCredentials) => await (await loadVercelSandboxClass()).get({
|
|
30149
31248
|
sandboxId: state.sandboxId,
|
|
30150
31249
|
...resolvedCredentials
|
|
30151
31250
|
})), { sandboxId: state.sandboxId });
|
|
@@ -30191,7 +31290,7 @@ async function waitForVercelSandboxRunning(session, timeoutMs = 3e4) {
|
|
|
30191
31290
|
if (await session.running()) {
|
|
30192
31291
|
return;
|
|
30193
31292
|
}
|
|
30194
|
-
await new Promise((
|
|
31293
|
+
await new Promise((resolve7) => setTimeout(resolve7, 250));
|
|
30195
31294
|
}
|
|
30196
31295
|
throw new SandboxLifecycleError(`Vercel sandbox ${session.state.sandboxId} did not become runnable within ${timeoutMs}ms.`, {
|
|
30197
31296
|
provider: "vercel",
|
|
@@ -30718,7 +31817,7 @@ function safeDiagnostic(signals) {
|
|
|
30718
31817
|
return [code ? `code=${code}` : "", numeric !== void 0 ? `status=${numeric}` : ""].filter(Boolean).join(" ");
|
|
30719
31818
|
}
|
|
30720
31819
|
function hasTransientSignal(signals) {
|
|
30721
|
-
return signals.codes.some((code) => TRANSIENT_CODES.has(code)) || signals.numbers.some((
|
|
31820
|
+
return signals.codes.some((code) => TRANSIENT_CODES.has(code)) || signals.numbers.some((status2) => GRPC_TRANSIENT.has(status2));
|
|
30722
31821
|
}
|
|
30723
31822
|
function hasModalTerminalSandboxMessage(signals) {
|
|
30724
31823
|
return signals.messages.some(
|
|
@@ -30749,7 +31848,7 @@ function classifyProviderSandboxFailure(backendId, error) {
|
|
|
30749
31848
|
if (hasTransientSignal(signals)) {
|
|
30750
31849
|
return { kind: "transient_transport", diagnostic };
|
|
30751
31850
|
}
|
|
30752
|
-
if (signals.numbers.some((
|
|
31851
|
+
if (signals.numbers.some((status2) => status2 === 404) || signals.codes.some((code) => NOT_FOUND_CODES.has(code))) {
|
|
30753
31852
|
return { kind: "not_found", diagnostic };
|
|
30754
31853
|
}
|
|
30755
31854
|
if (backendId === "modal" && hasModalTerminalSandboxMessage(signals)) {
|
|
@@ -31231,12 +32330,12 @@ function pumpOperationWaiters(state) {
|
|
|
31231
32330
|
}
|
|
31232
32331
|
}
|
|
31233
32332
|
function acquireOperation(state, deadline) {
|
|
31234
|
-
return new Promise((
|
|
32333
|
+
return new Promise((resolve7, reject) => {
|
|
31235
32334
|
const waiter = {
|
|
31236
32335
|
epoch: state.epoch,
|
|
31237
32336
|
settled: false,
|
|
31238
32337
|
resolve: () => {
|
|
31239
|
-
|
|
32338
|
+
resolve7(() => {
|
|
31240
32339
|
if (state.owner !== waiter) return;
|
|
31241
32340
|
state.owner = null;
|
|
31242
32341
|
pumpOperationWaiters(state);
|
|
@@ -31296,12 +32395,12 @@ function trackProviderCall(state, promise) {
|
|
|
31296
32395
|
}
|
|
31297
32396
|
function boundedProviderDrain(pending) {
|
|
31298
32397
|
if (pending.length === 0) return Promise.resolve();
|
|
31299
|
-
return new Promise((
|
|
32398
|
+
return new Promise((resolve7) => {
|
|
31300
32399
|
let remaining = pending.length;
|
|
31301
32400
|
let timer;
|
|
31302
32401
|
const finish = () => {
|
|
31303
32402
|
if (timer) clearTimeout(timer);
|
|
31304
|
-
|
|
32403
|
+
resolve7();
|
|
31305
32404
|
};
|
|
31306
32405
|
timer = setTimeout(finish, DISPLAY_STACK_DRAIN_GRACE_MS);
|
|
31307
32406
|
timer.unref?.();
|
|
@@ -31421,10 +32520,10 @@ async function cleanupDisplayStackProcess(session, pending, deadline) {
|
|
|
31421
32520
|
deadline
|
|
31422
32521
|
);
|
|
31423
32522
|
const output = execResultOutput(result);
|
|
31424
|
-
const
|
|
32523
|
+
const status2 = /OPENGENI_DISPLAY_CLEANUP status=(stopped|absent|alive|invalid)/u.exec(
|
|
31425
32524
|
output
|
|
31426
32525
|
)?.[1];
|
|
31427
|
-
return
|
|
32526
|
+
return status2 === "stopped";
|
|
31428
32527
|
} catch {
|
|
31429
32528
|
return false;
|
|
31430
32529
|
}
|
|
@@ -31455,13 +32554,13 @@ function telemetryReporter(options, started, now = monotonicNow) {
|
|
|
31455
32554
|
const context = options.telemetryContext;
|
|
31456
32555
|
const sink = options.onTelemetry ?? (context ? (event) => console.info(`[display-stack] ${JSON.stringify(event)}`) : void 0);
|
|
31457
32556
|
const emittedSandboxStages = /* @__PURE__ */ new Set();
|
|
31458
|
-
const emit = (stage,
|
|
32557
|
+
const emit = (stage, status2, fields = {}) => {
|
|
31459
32558
|
if (!sink) return;
|
|
31460
32559
|
const event = {
|
|
31461
32560
|
type: "display_stack.stage",
|
|
31462
32561
|
requestId: id,
|
|
31463
32562
|
stage,
|
|
31464
|
-
status,
|
|
32563
|
+
status: status2,
|
|
31465
32564
|
elapsedMs: fields.elapsedMs ?? now() - started,
|
|
31466
32565
|
source: fields.source ?? "host",
|
|
31467
32566
|
classification: fields.classification ?? "unknown",
|
|
@@ -31942,7 +33041,7 @@ function shellQuote5(value) {
|
|
|
31942
33041
|
}
|
|
31943
33042
|
|
|
31944
33043
|
// src/sandbox/browser-control-client.ts
|
|
31945
|
-
import { createHash as createHash7, randomUUID as
|
|
33044
|
+
import { createHash as createHash7, randomUUID as randomUUID8 } from "crypto";
|
|
31946
33045
|
import { posix as posixPath2 } from "path";
|
|
31947
33046
|
import {
|
|
31948
33047
|
BROWSER_CONTROL_MAX_JSON_BYTES,
|
|
@@ -32006,9 +33105,9 @@ var ComputerFrameEvidenceMismatchError = class extends BrowserControlProtocolErr
|
|
|
32006
33105
|
}
|
|
32007
33106
|
};
|
|
32008
33107
|
var BrowserControlRequestError = class extends Error {
|
|
32009
|
-
constructor(
|
|
33108
|
+
constructor(status2, error) {
|
|
32010
33109
|
super(error.message);
|
|
32011
|
-
this.status =
|
|
33110
|
+
this.status = status2;
|
|
32012
33111
|
this.error = error;
|
|
32013
33112
|
this.retryable = error.retryable;
|
|
32014
33113
|
}
|
|
@@ -32049,7 +33148,7 @@ async function provisionBrowserControlClient(session, input) {
|
|
|
32049
33148
|
input.adminTokenFile ?? BROWSER_CONTROL_ADMIN_TOKEN_FILE,
|
|
32050
33149
|
"browser controller admin token file"
|
|
32051
33150
|
);
|
|
32052
|
-
const temporaryTokenFile = `${adminTokenFile}.new.${
|
|
33151
|
+
const temporaryTokenFile = `${adminTokenFile}.new.${randomUUID8()}`;
|
|
32053
33152
|
const parent = adminTokenFile.slice(0, adminTokenFile.lastIndexOf("/")) || "/";
|
|
32054
33153
|
try {
|
|
32055
33154
|
await runChecked(
|
|
@@ -32477,7 +33576,7 @@ var BrowserControlClient = class {
|
|
|
32477
33576
|
);
|
|
32478
33577
|
}
|
|
32479
33578
|
const controllerPort = await this.controllerPort();
|
|
32480
|
-
const directory = `${CLIENT_ROOT}/${
|
|
33579
|
+
const directory = `${CLIENT_ROOT}/${randomUUID8()}`;
|
|
32481
33580
|
const configPath = `${directory}/curl.conf`;
|
|
32482
33581
|
const requestPath = `${directory}/request.json`;
|
|
32483
33582
|
const responsePath = `${directory}/response.json`;
|
|
@@ -32533,7 +33632,7 @@ var BrowserControlClient = class {
|
|
|
32533
33632
|
`browser controller transport failed (curl exit ${curlExit})`
|
|
32534
33633
|
);
|
|
32535
33634
|
}
|
|
32536
|
-
const
|
|
33635
|
+
const status2 = parseHttpStatus(await readText(this.session, statusPath, 32, timeoutMs));
|
|
32537
33636
|
const responseText = await readText(
|
|
32538
33637
|
this.session,
|
|
32539
33638
|
responsePath,
|
|
@@ -32543,7 +33642,7 @@ var BrowserControlClient = class {
|
|
|
32543
33642
|
if (Buffer.byteLength(responseText) > BROWSER_CONTROL_MAX_JSON_BYTES) {
|
|
32544
33643
|
throw new BrowserControlProtocolError("browser controller response is too large");
|
|
32545
33644
|
}
|
|
32546
|
-
return parseEnvelope(responseText,
|
|
33645
|
+
return parseEnvelope(responseText, status2);
|
|
32547
33646
|
} catch (error) {
|
|
32548
33647
|
if (error instanceof BrowserControlRequestError || error instanceof BrowserControlProtocolError || error instanceof RangeError) {
|
|
32549
33648
|
throw error;
|
|
@@ -32603,7 +33702,7 @@ var BrowserControlClient = class {
|
|
|
32603
33702
|
);
|
|
32604
33703
|
}
|
|
32605
33704
|
const controllerPort = await this.controllerPort();
|
|
32606
|
-
const directory = `${CLIENT_ROOT}/${
|
|
33705
|
+
const directory = `${CLIENT_ROOT}/${randomUUID8()}`;
|
|
32607
33706
|
const configPath = `${directory}/curl.conf`;
|
|
32608
33707
|
const responsePath = `${directory}/response.bin`;
|
|
32609
33708
|
const responseHeadersPath = `${directory}/response.headers`;
|
|
@@ -32650,15 +33749,15 @@ var BrowserControlClient = class {
|
|
|
32650
33749
|
`browser controller transport failed (curl exit ${curlExit})`
|
|
32651
33750
|
);
|
|
32652
33751
|
}
|
|
32653
|
-
const
|
|
32654
|
-
if (
|
|
33752
|
+
const status2 = parseHttpStatus(await readText(this.session, statusPath, 32, timeoutMs));
|
|
33753
|
+
if (status2 < 200 || status2 >= 300) {
|
|
32655
33754
|
const responseText = await readText(
|
|
32656
33755
|
this.session,
|
|
32657
33756
|
responsePath,
|
|
32658
33757
|
BROWSER_CONTROL_MAX_JSON_BYTES + 1,
|
|
32659
33758
|
timeoutMs
|
|
32660
33759
|
);
|
|
32661
|
-
parseEnvelope(responseText,
|
|
33760
|
+
parseEnvelope(responseText, status2);
|
|
32662
33761
|
throw new BrowserControlProtocolError("browser controller image response is invalid");
|
|
32663
33762
|
}
|
|
32664
33763
|
const headers = parseCurlResponseHeaders(
|
|
@@ -33300,7 +34399,7 @@ function looksLikeBrowserControlEnvelope(body) {
|
|
|
33300
34399
|
return false;
|
|
33301
34400
|
}
|
|
33302
34401
|
}
|
|
33303
|
-
function parseEnvelope(body,
|
|
34402
|
+
function parseEnvelope(body, status2) {
|
|
33304
34403
|
let value;
|
|
33305
34404
|
try {
|
|
33306
34405
|
value = JSON.parse(body);
|
|
@@ -33310,10 +34409,10 @@ function parseEnvelope(body, status) {
|
|
|
33310
34409
|
if (!isRecord3(value) || value.protocolVersion !== BROWSER_CONTROL_PROTOCOL_VERSION) {
|
|
33311
34410
|
throw new BrowserControlProtocolError("browser controller protocol version is invalid");
|
|
33312
34411
|
}
|
|
33313
|
-
if (value.ok === true &&
|
|
33314
|
-
if (value.ok === false &&
|
|
34412
|
+
if (value.ok === true && status2 >= 200 && status2 < 300 && "data" in value) return value.data;
|
|
34413
|
+
if (value.ok === false && status2 >= 400 && status2 <= 599) {
|
|
33315
34414
|
const parsed = InteractionError.safeParse(value.error);
|
|
33316
|
-
if (parsed.success) throw new BrowserControlRequestError(
|
|
34415
|
+
if (parsed.success) throw new BrowserControlRequestError(status2, parsed.data);
|
|
33317
34416
|
}
|
|
33318
34417
|
throw new BrowserControlProtocolError("browser controller response envelope is invalid");
|
|
33319
34418
|
}
|
|
@@ -33786,7 +34885,7 @@ async function readText(session, path, maxBytes, timeoutMs) {
|
|
|
33786
34885
|
} catch {
|
|
33787
34886
|
}
|
|
33788
34887
|
}
|
|
33789
|
-
const sizeMarker = `OPENGENI_BROWSER_PRIVATE_SIZE_${
|
|
34888
|
+
const sizeMarker = `OPENGENI_BROWSER_PRIVATE_SIZE_${randomUUID8()}`;
|
|
33790
34889
|
const sizeOutput = await runPrivateReadCommand(
|
|
33791
34890
|
session,
|
|
33792
34891
|
[
|
|
@@ -33805,7 +34904,7 @@ async function readText(session, path, maxBytes, timeoutMs) {
|
|
|
33805
34904
|
for (let offset = 0; offset < requestedBytes; offset += PRIVATE_READ_CHUNK_BYTES) {
|
|
33806
34905
|
const chunkIndex = Math.floor(offset / PRIVATE_READ_CHUNK_BYTES);
|
|
33807
34906
|
const expectedBytes = Math.min(PRIVATE_READ_CHUNK_BYTES, requestedBytes - offset);
|
|
33808
|
-
const marker = `OPENGENI_BROWSER_PRIVATE_CHUNK_${
|
|
34907
|
+
const marker = `OPENGENI_BROWSER_PRIVATE_CHUNK_${randomUUID8()}`;
|
|
33809
34908
|
const output = await runPrivateReadCommand(
|
|
33810
34909
|
session,
|
|
33811
34910
|
[
|
|
@@ -33834,7 +34933,7 @@ async function readBytes(session, path, maxBytes, timeoutMs) {
|
|
|
33834
34933
|
if (!Number.isSafeInteger(maxBytes) || maxBytes < 1 || maxBytes > COMPUTER_SCREENSHOT_MAX_BYTES) {
|
|
33835
34934
|
throw new RangeError("browser private binary response limit is invalid");
|
|
33836
34935
|
}
|
|
33837
|
-
const sizeMarker = `OPENGENI_BROWSER_PRIVATE_SIZE_${
|
|
34936
|
+
const sizeMarker = `OPENGENI_BROWSER_PRIVATE_SIZE_${randomUUID8()}`;
|
|
33838
34937
|
const sizeOutput = await runPrivateReadCommand(
|
|
33839
34938
|
session,
|
|
33840
34939
|
[
|
|
@@ -33856,7 +34955,7 @@ async function readBytes(session, path, maxBytes, timeoutMs) {
|
|
|
33856
34955
|
for (let offset = 0; offset < size; offset += PRIVATE_READ_CHUNK_BYTES) {
|
|
33857
34956
|
const chunkIndex = Math.floor(offset / PRIVATE_READ_CHUNK_BYTES);
|
|
33858
34957
|
const expectedBytes = Math.min(PRIVATE_READ_CHUNK_BYTES, size - offset);
|
|
33859
|
-
const marker = `OPENGENI_BROWSER_PRIVATE_CHUNK_${
|
|
34958
|
+
const marker = `OPENGENI_BROWSER_PRIVATE_CHUNK_${randomUUID8()}`;
|
|
33860
34959
|
const output = await runPrivateReadCommand(
|
|
33861
34960
|
session,
|
|
33862
34961
|
[
|
|
@@ -34067,11 +35166,11 @@ function parseUnsignedInteger(value, label) {
|
|
|
34067
35166
|
return parsed;
|
|
34068
35167
|
}
|
|
34069
35168
|
function parseHttpStatus(value) {
|
|
34070
|
-
const
|
|
34071
|
-
if (
|
|
35169
|
+
const status2 = parseUnsignedInteger(value, "HTTP status");
|
|
35170
|
+
if (status2 < 100 || status2 > 599) {
|
|
34072
35171
|
throw new BrowserControlProtocolError("HTTP status is invalid");
|
|
34073
35172
|
}
|
|
34074
|
-
return
|
|
35173
|
+
return status2;
|
|
34075
35174
|
}
|
|
34076
35175
|
function isRecord3(value) {
|
|
34077
35176
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -34465,7 +35564,7 @@ async function materializeRunCredentials(session, material, options) {
|
|
|
34465
35564
|
throw new RunCredentialValidationError("executionGeneration must be a non-negative integer");
|
|
34466
35565
|
}
|
|
34467
35566
|
const nonce = crypto.randomUUID();
|
|
34468
|
-
const
|
|
35567
|
+
const prefix2 = `${attemptId}-${options.executionGeneration}-`;
|
|
34469
35568
|
const versionName = `${attemptId}-${options.executionGeneration}-${nonce}`;
|
|
34470
35569
|
const stage = `${root}/versions/.stage-${versionName}`;
|
|
34471
35570
|
const version = `${root}/versions/${versionName}`;
|
|
@@ -34530,7 +35629,7 @@ async function materializeRunCredentials(session, material, options) {
|
|
|
34530
35629
|
] : options.pruneOtherAttempts ? [
|
|
34531
35630
|
`find ${shellQuote7(`${root}/versions`)} -mindepth 1 -maxdepth 1 ! -name ${shellQuote7(`${attemptId}-${options.executionGeneration}-*`)} -exec rm -rf -- {} +`
|
|
34532
35631
|
] : options.pruneSupersededGenerations ? [
|
|
34533
|
-
`for candidate in ${shellQuote7(`${root}/versions`)}/${
|
|
35632
|
+
`for candidate in ${shellQuote7(`${root}/versions`)}/${prefix2}*; do`,
|
|
34534
35633
|
` [ -e "$candidate" ] || continue`,
|
|
34535
35634
|
` name=\${candidate##*/}`,
|
|
34536
35635
|
` [ "$name" = ${shellQuote7(versionName)} ] || [ "$name" = "$previous" ] || rm -rf -- "$candidate"`,
|
|
@@ -34562,7 +35661,7 @@ async function clearRunCredentialsForAttempt(session, options, commandRunner) {
|
|
|
34562
35661
|
if (!Number.isSafeInteger(options.executionGeneration) || options.executionGeneration < 0) {
|
|
34563
35662
|
throw new RunCredentialValidationError("executionGeneration must be a non-negative integer");
|
|
34564
35663
|
}
|
|
34565
|
-
const
|
|
35664
|
+
const prefix2 = `${attemptId}-${options.executionGeneration}-`;
|
|
34566
35665
|
await runCredentialCommand(
|
|
34567
35666
|
session,
|
|
34568
35667
|
[
|
|
@@ -34570,11 +35669,11 @@ async function clearRunCredentialsForAttempt(session, options, commandRunner) {
|
|
|
34570
35669
|
...pointerLockAcquireCommands(root).map((line) => ` ${line}`),
|
|
34571
35670
|
` if [ -r ${shellQuote7(`${root}/current`)} ]; then`,
|
|
34572
35671
|
` current=$(cat -- ${shellQuote7(`${root}/current`)} 2>/dev/null || :)`,
|
|
34573
|
-
` case "$current" in ${shellQuote7(
|
|
35672
|
+
` case "$current" in ${shellQuote7(prefix2)}*) rm -f -- ${shellQuote7(`${root}/current`)} ;; esac`,
|
|
34574
35673
|
" fi",
|
|
34575
35674
|
` if [ -d ${shellQuote7(`${root}/versions`)} ]; then`,
|
|
34576
|
-
` find ${shellQuote7(`${root}/versions`)} -mindepth 1 -maxdepth 1 -name ${shellQuote7(`${
|
|
34577
|
-
` find ${shellQuote7(`${root}/versions`)} -mindepth 1 -maxdepth 1 -name ${shellQuote7(`.stage-${
|
|
35675
|
+
` find ${shellQuote7(`${root}/versions`)} -mindepth 1 -maxdepth 1 -name ${shellQuote7(`${prefix2}*`)} -exec rm -rf -- {} +`,
|
|
35676
|
+
` find ${shellQuote7(`${root}/versions`)} -mindepth 1 -maxdepth 1 -name ${shellQuote7(`.stage-${prefix2}*`)} -exec rm -rf -- {} +`,
|
|
34578
35677
|
" fi",
|
|
34579
35678
|
...pointerLockReleaseCommands().map((line) => ` ${line}`),
|
|
34580
35679
|
"fi"
|
|
@@ -34659,8 +35758,175 @@ function withRunCredentialsClient(client, sessionId, onSessionReady) {
|
|
|
34659
35758
|
}
|
|
34660
35759
|
|
|
34661
35760
|
// src/sandbox/codemode-token.ts
|
|
34662
|
-
import { createHash as
|
|
35761
|
+
import { createHash as createHash9 } from "crypto";
|
|
34663
35762
|
import { posix as posixPath3 } from "path";
|
|
35763
|
+
|
|
35764
|
+
// src/sandbox/codemode-client.ts
|
|
35765
|
+
import { createHash as createHash8, randomUUID as randomUUID9 } from "crypto";
|
|
35766
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
35767
|
+
import { dirname as dirname5, join as join8, posix as posix5, resolve as resolve6 } from "path";
|
|
35768
|
+
import { fileURLToPath } from "url";
|
|
35769
|
+
function managedCodemodeClientDigest(client) {
|
|
35770
|
+
return createHash8("sha256").update(JSON.stringify(client)).digest("hex");
|
|
35771
|
+
}
|
|
35772
|
+
function managedCodemodeClientDirectory(client, workspaceRoot = "/workspace") {
|
|
35773
|
+
if (!posix5.isAbsolute(workspaceRoot) || workspaceRoot.includes("\0")) {
|
|
35774
|
+
throw new Error("Managed Codemode client workspace root must be absolute");
|
|
35775
|
+
}
|
|
35776
|
+
return posix5.join(
|
|
35777
|
+
workspaceRoot,
|
|
35778
|
+
".opengeni/codemode-clients",
|
|
35779
|
+
managedCodemodeClientDigest(client)
|
|
35780
|
+
);
|
|
35781
|
+
}
|
|
35782
|
+
async function buildManagedCodemodeClient(root) {
|
|
35783
|
+
const bundle = async (entry, format, banner) => {
|
|
35784
|
+
const result = await Bun.build({
|
|
35785
|
+
entrypoints: [join8(root, entry)],
|
|
35786
|
+
target: "node",
|
|
35787
|
+
format,
|
|
35788
|
+
minify: true,
|
|
35789
|
+
sourcemap: "none",
|
|
35790
|
+
...banner ? { banner } : {}
|
|
35791
|
+
});
|
|
35792
|
+
if (!result.success || result.outputs.length !== 1) {
|
|
35793
|
+
throw new Error(`Managed Codemode client build failed: ${entry}`);
|
|
35794
|
+
}
|
|
35795
|
+
return await result.outputs[0].text();
|
|
35796
|
+
};
|
|
35797
|
+
return {
|
|
35798
|
+
version: 1,
|
|
35799
|
+
files: {
|
|
35800
|
+
ogtool: await bundle("packages/ogtool/src/cli.ts", "cjs", "#!/usr/bin/env node"),
|
|
35801
|
+
"client.mjs": await bundle("packages/codemode/src/index.ts", "esm"),
|
|
35802
|
+
// The extensionless executable must not inherit a user's ESM workspace.
|
|
35803
|
+
"package.json": '{"type":"commonjs"}\n'
|
|
35804
|
+
}
|
|
35805
|
+
};
|
|
35806
|
+
}
|
|
35807
|
+
var releaseClient;
|
|
35808
|
+
function loadManagedCodemodeClient() {
|
|
35809
|
+
return releaseClient ??= (async () => {
|
|
35810
|
+
const moduleDir = dirname5(fileURLToPath(import.meta.url));
|
|
35811
|
+
const root = resolve6(moduleDir, "../../../..");
|
|
35812
|
+
if (import.meta.url.endsWith("/src/sandbox/codemode-client.ts") && existsSync2(join8(root, "packages/ogtool/src/cli.ts"))) {
|
|
35813
|
+
return await buildManagedCodemodeClient(root);
|
|
35814
|
+
}
|
|
35815
|
+
const candidates = [
|
|
35816
|
+
join8(moduleDir, "assets/codemode-client.json"),
|
|
35817
|
+
join8(moduleDir, "../assets/codemode-client.json"),
|
|
35818
|
+
join8(moduleDir, "../../dist/assets/codemode-client.json")
|
|
35819
|
+
];
|
|
35820
|
+
for (const path of candidates) {
|
|
35821
|
+
if (!existsSync2(path)) continue;
|
|
35822
|
+
const value = JSON.parse(readFileSync2(path, "utf8"));
|
|
35823
|
+
if (!value || typeof value !== "object" || value.version !== 1 || Object.keys(value).sort().join(",") !== "files,version" || typeof value.files?.ogtool !== "string" || typeof value.files?.["client.mjs"] !== "string" || value.files?.["package.json"] !== '{"type":"commonjs"}\n' || Object.keys(value.files).sort().join(",") !== "client.mjs,ogtool,package.json") {
|
|
35824
|
+
throw new Error(
|
|
35825
|
+
"Invalid deployment-owned managed Codemode client asset; rebuild the worker release"
|
|
35826
|
+
);
|
|
35827
|
+
}
|
|
35828
|
+
return value;
|
|
35829
|
+
}
|
|
35830
|
+
throw new Error(
|
|
35831
|
+
"Managed Codemode client asset missing; rebuild and deploy the matching worker/runtime package (do not install latest or replace the sandbox)"
|
|
35832
|
+
);
|
|
35833
|
+
})();
|
|
35834
|
+
}
|
|
35835
|
+
function quote(value) {
|
|
35836
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
35837
|
+
}
|
|
35838
|
+
async function installManagedCodemodeClient(session, client, run2, runAs, workspaceRoot = "/workspace") {
|
|
35839
|
+
const directory = managedCodemodeClientDirectory(client, workspaceRoot);
|
|
35840
|
+
const digest = managedCodemodeClientDigest(client);
|
|
35841
|
+
const verify = `
|
|
35842
|
+
const fs = require('node:fs'), crypto = require('node:crypto');
|
|
35843
|
+
const root = ${JSON.stringify(directory)};
|
|
35844
|
+
if (!fs.lstatSync(root).isDirectory()) process.exit(1);
|
|
35845
|
+
for (const name of ['ogtool', 'client.mjs', 'package.json']) {
|
|
35846
|
+
if (!fs.lstatSync(root + '/' + name).isFile()) process.exit(1);
|
|
35847
|
+
}
|
|
35848
|
+
fs.accessSync(root + '/ogtool', fs.constants.X_OK);
|
|
35849
|
+
const files = {ogtool: fs.readFileSync(root + '/ogtool', 'utf8'), 'client.mjs': fs.readFileSync(root + '/client.mjs', 'utf8'), 'package.json': fs.readFileSync(root + '/package.json', 'utf8')};
|
|
35850
|
+
if (crypto.createHash('sha256').update(JSON.stringify({version: 1, files})).digest('hex') !== ${JSON.stringify(digest)}) process.exit(1);
|
|
35851
|
+
`;
|
|
35852
|
+
if (sandboxCommandExitCode(await run2(`node -e ${quote(verify)} 2>/dev/null`)) === 0) return;
|
|
35853
|
+
const editor = session.createEditor?.(runAs);
|
|
35854
|
+
if (!editor)
|
|
35855
|
+
throw new Error(
|
|
35856
|
+
"Managed Codemode client delivery requires sandbox file ingress; update the sandbox provider adapter"
|
|
35857
|
+
);
|
|
35858
|
+
const stage = `${posix5.dirname(directory)}/stage-${randomUUID9()}.json`;
|
|
35859
|
+
let installationFailure;
|
|
35860
|
+
try {
|
|
35861
|
+
await editor.createFile({
|
|
35862
|
+
type: "create_file",
|
|
35863
|
+
path: stage,
|
|
35864
|
+
diff: `+${JSON.stringify(client)}`
|
|
35865
|
+
});
|
|
35866
|
+
const install = `
|
|
35867
|
+
const fs = require('node:fs'), crypto = require('node:crypto');
|
|
35868
|
+
const raw = fs.readFileSync(${JSON.stringify(stage)}, 'utf8').trim();
|
|
35869
|
+
if (crypto.createHash('sha256').update(raw).digest('hex') !== ${JSON.stringify(digest)}) throw Error('Codemode client transfer integrity failure');
|
|
35870
|
+
const data = JSON.parse(raw), root = ${JSON.stringify(directory)};
|
|
35871
|
+
fs.mkdirSync(root, {recursive: true});
|
|
35872
|
+
if (!fs.lstatSync(root).isDirectory()) throw Error('Codemode client directory must not be a symlink');
|
|
35873
|
+
for (const name of ['package.json', 'ogtool', 'client.mjs']) {
|
|
35874
|
+
const tmp = root + '/' + name + '.' + crypto.randomUUID();
|
|
35875
|
+
fs.writeFileSync(tmp, data.files[name], {mode: 0o755, flag: 'wx'});
|
|
35876
|
+
fs.renameSync(tmp, root + '/' + name);
|
|
35877
|
+
}
|
|
35878
|
+
`;
|
|
35879
|
+
const result = await run2(`node -e ${quote(install)} && node -e ${quote(verify)}`);
|
|
35880
|
+
if (sandboxCommandExitCode(result) !== 0) {
|
|
35881
|
+
throw new Error(
|
|
35882
|
+
"Managed Codemode client delivery failed; verify Node and sandbox file ingress, then retry with the same worker release"
|
|
35883
|
+
);
|
|
35884
|
+
}
|
|
35885
|
+
} catch (error) {
|
|
35886
|
+
installationFailure = { error };
|
|
35887
|
+
}
|
|
35888
|
+
let cleanupFailure;
|
|
35889
|
+
try {
|
|
35890
|
+
await editor.deleteFile({ type: "delete_file", path: stage });
|
|
35891
|
+
} catch (editorFailure) {
|
|
35892
|
+
try {
|
|
35893
|
+
const cleanup = await run2(
|
|
35894
|
+
`node -e ${quote(`require('node:fs').rmSync(${JSON.stringify(stage)}, {force: true})`)}`
|
|
35895
|
+
);
|
|
35896
|
+
if (sandboxCommandExitCode(cleanup) !== 0) {
|
|
35897
|
+
throw new Error("Staging file removal failed", { cause: editorFailure });
|
|
35898
|
+
}
|
|
35899
|
+
} catch (commandFailure2) {
|
|
35900
|
+
cleanupFailure = new AggregateError(
|
|
35901
|
+
[editorFailure, commandFailure2],
|
|
35902
|
+
"Both cleanup paths failed",
|
|
35903
|
+
{ cause: commandFailure2 }
|
|
35904
|
+
);
|
|
35905
|
+
}
|
|
35906
|
+
}
|
|
35907
|
+
if (cleanupFailure) {
|
|
35908
|
+
throw new AggregateError(
|
|
35909
|
+
installationFailure ? [installationFailure.error, cleanupFailure] : [cleanupFailure],
|
|
35910
|
+
"Managed Codemode client staging cleanup failed; restore sandbox file ingress/command execution before retrying",
|
|
35911
|
+
{ cause: installationFailure?.error ?? cleanupFailure }
|
|
35912
|
+
);
|
|
35913
|
+
}
|
|
35914
|
+
if (installationFailure) throw installationFailure.error;
|
|
35915
|
+
}
|
|
35916
|
+
function managedCodemodeClientEnvironment(directory) {
|
|
35917
|
+
return [
|
|
35918
|
+
// A routing proxy can switch to a Connected Machine during the attempt.
|
|
35919
|
+
// Its native client is projected by the connection-bound exec transport.
|
|
35920
|
+
'if [ -z "${OPENGENI_CODEMODE_NATIVE_CLIENT:-}" ]; then',
|
|
35921
|
+
` export PATH=${quote(directory)}:"$PATH"`,
|
|
35922
|
+
` export OPENGENI_CODEMODE_CLIENT_MODULE=${quote(`${directory}/client.mjs`)}`,
|
|
35923
|
+
"else",
|
|
35924
|
+
" unset OPENGENI_CODEMODE_CLIENT_MODULE",
|
|
35925
|
+
"fi"
|
|
35926
|
+
];
|
|
35927
|
+
}
|
|
35928
|
+
|
|
35929
|
+
// src/sandbox/codemode-token.ts
|
|
34664
35930
|
var MAX_CODEMODE_SESSION_ID_BYTES = 512;
|
|
34665
35931
|
var CodemodeTokenPathError = class extends Error {
|
|
34666
35932
|
constructor(message) {
|
|
@@ -34691,21 +35957,22 @@ function codemodeTokenFileForSession(manifestTokenFile, sessionId) {
|
|
|
34691
35957
|
manifestTokenFile,
|
|
34692
35958
|
"Codemode manifest token file"
|
|
34693
35959
|
);
|
|
34694
|
-
const digest =
|
|
35960
|
+
const digest = createHash9("sha256").update(assertCodemodeSessionId(sessionId)).digest("hex");
|
|
34695
35961
|
return posixPath3.join(posixPath3.dirname(normalizedManifestFile), "codemode-tokens", digest);
|
|
34696
35962
|
}
|
|
34697
35963
|
function codemodeTokenFileFromEnvironment(environment, sessionId) {
|
|
34698
35964
|
const manifestTokenFile = environment.OPENGENI_CODEMODE_TOKEN_FILE ?? `${environment.HOME ?? "/workspace"}/.opengeni/codemode-token`;
|
|
34699
35965
|
return codemodeTokenFileForSession(manifestTokenFile, sessionId);
|
|
34700
35966
|
}
|
|
34701
|
-
function withCodemodeTokenEnvironment(cmd, tokenFile, codemodeUrl) {
|
|
35967
|
+
function withCodemodeTokenEnvironment(cmd, tokenFile, codemodeUrl, clientDirectory) {
|
|
34702
35968
|
return [
|
|
34703
35969
|
`export OPENGENI_CODEMODE_TOKEN_FILE=${shellCodemodePath(tokenFile)}`,
|
|
34704
35970
|
...codemodeUrl ? [`export OPENGENI_CODEMODE_URL=${shellQuote8(codemodeUrl)}`] : [],
|
|
35971
|
+
...clientDirectory ? managedCodemodeClientEnvironment(clientDirectory) : [],
|
|
34705
35972
|
cmd
|
|
34706
35973
|
].join("\n");
|
|
34707
35974
|
}
|
|
34708
|
-
function withCodemodeTokenSession(session, tokenFile, codemodeUrl) {
|
|
35975
|
+
function withCodemodeTokenSession(session, tokenFile, codemodeUrl, clientDirectory) {
|
|
34709
35976
|
return new Proxy(session, {
|
|
34710
35977
|
get(target, property, receiver) {
|
|
34711
35978
|
if (property === "exec" || property === "execCommand") {
|
|
@@ -34713,7 +35980,7 @@ function withCodemodeTokenSession(session, tokenFile, codemodeUrl) {
|
|
|
34713
35980
|
if (!command) return void 0;
|
|
34714
35981
|
return async (args) => await command.call(target, {
|
|
34715
35982
|
...args,
|
|
34716
|
-
cmd: withCodemodeTokenEnvironment(args.cmd, tokenFile, codemodeUrl)
|
|
35983
|
+
cmd: withCodemodeTokenEnvironment(args.cmd, tokenFile, codemodeUrl, clientDirectory)
|
|
34717
35984
|
});
|
|
34718
35985
|
}
|
|
34719
35986
|
const value = Reflect.get(target, property, receiver);
|
|
@@ -34721,12 +35988,12 @@ function withCodemodeTokenSession(session, tokenFile, codemodeUrl) {
|
|
|
34721
35988
|
}
|
|
34722
35989
|
});
|
|
34723
35990
|
}
|
|
34724
|
-
function withCodemodeTokenClient(client, tokenFile, codemodeUrl) {
|
|
35991
|
+
function withCodemodeTokenClient(client, tokenFile, codemodeUrl, clientDirectory) {
|
|
34725
35992
|
const decorated = /* @__PURE__ */ new WeakMap();
|
|
34726
35993
|
const wrap = (session) => {
|
|
34727
35994
|
const existing = decorated.get(session);
|
|
34728
35995
|
if (existing) return existing;
|
|
34729
|
-
const wrapped = withCodemodeTokenSession(session, tokenFile, codemodeUrl);
|
|
35996
|
+
const wrapped = withCodemodeTokenSession(session, tokenFile, codemodeUrl, clientDirectory);
|
|
34730
35997
|
decorated.set(session, wrapped);
|
|
34731
35998
|
return wrapped;
|
|
34732
35999
|
};
|
|
@@ -35162,11 +36429,11 @@ var MockAgentResponder = class {
|
|
|
35162
36429
|
return ok(req.requestId, { $case: "fsRemove", fsRemove: {} });
|
|
35163
36430
|
}
|
|
35164
36431
|
case "fsList": {
|
|
35165
|
-
const
|
|
36432
|
+
const prefix2 = normalize(op.fsList.path).replace(/\/?$/, "/");
|
|
35166
36433
|
const res = {
|
|
35167
|
-
entries: [...this.files.keys()].filter((p) => p.startsWith(
|
|
36434
|
+
entries: [...this.files.keys()].filter((p) => p.startsWith(prefix2)).map((p) => {
|
|
35168
36435
|
const bytes = this.files.get(p);
|
|
35169
|
-
const rel = p.slice(
|
|
36436
|
+
const rel = p.slice(prefix2.length);
|
|
35170
36437
|
return {
|
|
35171
36438
|
name: rel.split("/").pop() ?? rel,
|
|
35172
36439
|
path: rel,
|
|
@@ -35718,18 +36985,18 @@ function errorResponse2(requestId2, code, message) {
|
|
|
35718
36985
|
result: void 0
|
|
35719
36986
|
};
|
|
35720
36987
|
}
|
|
35721
|
-
function startResponse(requestId2,
|
|
36988
|
+
function startResponse(requestId2, status2, accepted = true) {
|
|
35722
36989
|
return {
|
|
35723
36990
|
requestId: requestId2,
|
|
35724
36991
|
error: void 0,
|
|
35725
|
-
result: { $case: "opStart", opStart: { accepted, status } }
|
|
36992
|
+
result: { $case: "opStart", opStart: { accepted, status: status2 } }
|
|
35726
36993
|
};
|
|
35727
36994
|
}
|
|
35728
|
-
function statusOnly(requestId2,
|
|
36995
|
+
function statusOnly(requestId2, status2) {
|
|
35729
36996
|
return {
|
|
35730
36997
|
requestId: requestId2,
|
|
35731
36998
|
error: void 0,
|
|
35732
|
-
result: { $case: "opStatus", opStatus:
|
|
36999
|
+
result: { $case: "opStatus", opStatus: status2 }
|
|
35733
37000
|
};
|
|
35734
37001
|
}
|
|
35735
37002
|
function lostStatus(opId) {
|
|
@@ -36328,7 +37595,7 @@ async function verifySandboxExecReadiness(established, timeoutMs = MODAL_EXEC_RE
|
|
|
36328
37595
|
}
|
|
36329
37596
|
const remainingMs = deadline - Date.now();
|
|
36330
37597
|
if (remainingMs <= 0) throw timeoutError();
|
|
36331
|
-
await new Promise((
|
|
37598
|
+
await new Promise((resolve7) => setTimeout(resolve7, Math.min(100, remainingMs)));
|
|
36332
37599
|
result = await execProbe();
|
|
36333
37600
|
}
|
|
36334
37601
|
}
|
|
@@ -37040,6 +38307,8 @@ export {
|
|
|
37040
38307
|
parseExecBannerSessionId,
|
|
37041
38308
|
parseExecBannerExitCode,
|
|
37042
38309
|
isExecSessionLostBanner,
|
|
38310
|
+
SandboxMaterializationVerificationError,
|
|
38311
|
+
materializationVerificationDiagnostic,
|
|
37043
38312
|
normalizeConnectedMachineWorkspaceRoot,
|
|
37044
38313
|
isWindowsConnectedMachinePath,
|
|
37045
38314
|
isConnectedMachineAbsolutePath,
|
|
@@ -37236,6 +38505,9 @@ export {
|
|
|
37236
38505
|
withRunCredentialEnvironment,
|
|
37237
38506
|
withRunCredentialsSession,
|
|
37238
38507
|
withRunCredentialsClient,
|
|
38508
|
+
managedCodemodeClientDirectory,
|
|
38509
|
+
loadManagedCodemodeClient,
|
|
38510
|
+
installManagedCodemodeClient,
|
|
37239
38511
|
CodemodeTokenPathError,
|
|
37240
38512
|
shellCodemodePath,
|
|
37241
38513
|
codemodeTokenFileForSession,
|
|
@@ -37293,4 +38565,4 @@ export {
|
|
|
37293
38565
|
collectSandboxEnvironment2 as collectSandboxEnvironment,
|
|
37294
38566
|
parseExposedPorts2 as parseExposedPorts
|
|
37295
38567
|
};
|
|
37296
|
-
//# sourceMappingURL=chunk-
|
|
38568
|
+
//# sourceMappingURL=chunk-WIHICNWS.js.map
|