@linzumi/cli 1.0.118 → 1.0.120
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.js +336 -336
- package/package.json +1 -1
- package/scripts/build-editor-parity-oracle.mjs +1523 -0
- package/scripts/build-forwarding-parity-oracle.mjs +1390 -0
- package/scripts/build-mcp-parity-oracle.mjs +357 -0
- package/scripts/build-mcp-selector-parity-oracle.mjs +65 -0
- package/scripts/build-vm-sandbox-parity-oracle.mjs +1266 -0
- package/scripts/build.mjs +41 -0
|
@@ -0,0 +1,1266 @@
|
|
|
1
|
+
// Spec: kandan/plans/2026-07-10-compute-nodes-rescript-commander-zero-ts-program.md
|
|
2
|
+
// (M3 cluster 14, vmSandbox).
|
|
3
|
+
// Relationship: Builds the TS-side PARITY ORACLE for the vmSandbox area of
|
|
4
|
+
// the ReScript commander port. The oracle esbuild-bundles the REAL TS
|
|
5
|
+
// vmSandbox modules - the egress-policy gate, the guest cloud turn codec +
|
|
6
|
+
// exit-line/preflight parses, every guest provisioning/liveness command
|
|
7
|
+
// builder, the packed-golden capability probe + CLI argv builders, the VM
|
|
8
|
+
// execution state file + marker registries, the golden select/query/gc
|
|
9
|
+
// planning stack, the golden build pure core (manifest/checksum/manager
|
|
10
|
+
// detection), the local/cloud readiness aggregators over scripted probes,
|
|
11
|
+
// the supervisor config codec + create-boundary egress resolution + the
|
|
12
|
+
// goldenUsableForEgress security decision, the guest cloud supervisor's
|
|
13
|
+
// pure predicates, the cloud backend codecs (key resolution, gates,
|
|
14
|
+
// redaction, SSE parse), the workspace-agent identity gate, the job
|
|
15
|
+
// worktree lifecycle over a scripted GitRunner, the relay script emitter,
|
|
16
|
+
// and the vm CLI help/dispatch surface - behind the cluster 1/2 one-shot
|
|
17
|
+
// BATCH driver (a JSON array of cases on stdin, a JSON array of results on
|
|
18
|
+
// stdout).
|
|
19
|
+
//
|
|
20
|
+
// Determinism: filesystem-touching ops run in per-case mkdtemp scratch dirs
|
|
21
|
+
// normalized through "$DIR"; env-reading ops take env as a PARAMETER where
|
|
22
|
+
// the TS function accepts one, and only the vmCli ops (whose bodies read
|
|
23
|
+
// process.env through defaulted params) set/restore process.env around the
|
|
24
|
+
// call. Scripted fetch/git/query seams are built from the case JSON.
|
|
25
|
+
//
|
|
26
|
+
// SECRETS: synthetic case payloads only; .differential/ is gitignored.
|
|
27
|
+
import { mkdir } from 'node:fs/promises';
|
|
28
|
+
import { dirname, join } from 'node:path';
|
|
29
|
+
import { fileURLToPath } from 'node:url';
|
|
30
|
+
import { build } from 'esbuild';
|
|
31
|
+
|
|
32
|
+
const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
33
|
+
|
|
34
|
+
const driverSource = `
|
|
35
|
+
import { mkdirSync, mkdtempSync, readFileSync, realpathSync, statSync, writeFileSync } from 'node:fs';
|
|
36
|
+
import { tmpdir } from 'node:os';
|
|
37
|
+
import { join } from 'node:path';
|
|
38
|
+
import {
|
|
39
|
+
DEFAULT_VM_EGRESS_MODE,
|
|
40
|
+
PLACEHOLDER_GATEWAY_CIDR,
|
|
41
|
+
assertEgressPolicyUpheld,
|
|
42
|
+
defaultGatewayEgressCidrs,
|
|
43
|
+
isPlaceholderEgressPolicy,
|
|
44
|
+
isValidEgressCidr,
|
|
45
|
+
isWideOpenCidr,
|
|
46
|
+
normalizeVmEgressMode,
|
|
47
|
+
openEgressPolicy,
|
|
48
|
+
resolveVmEgressPolicy,
|
|
49
|
+
resolveVmEgressPolicyForActiveVm,
|
|
50
|
+
} from './src/vmSandbox/vmEgressPolicy';
|
|
51
|
+
import {
|
|
52
|
+
GUEST_CLOUD_TURN_EXIT_PHASE,
|
|
53
|
+
GuestCloudTurnSecretEnv,
|
|
54
|
+
decodeGuestCloudTurnConfig,
|
|
55
|
+
encodeGuestCloudTurnConfig,
|
|
56
|
+
} from './src/vmSandbox/vmCloudTurnProtocol';
|
|
57
|
+
import {
|
|
58
|
+
CloudTurnError,
|
|
59
|
+
DEFAULT_CLOUD_TURN_TIMEOUT_MS,
|
|
60
|
+
cloudSupervisorConstsForTest,
|
|
61
|
+
cloudTurnTimeoutMs,
|
|
62
|
+
injectTurnSecrets,
|
|
63
|
+
parseCloudTurnExitLineForTest,
|
|
64
|
+
parsePreflightOutput,
|
|
65
|
+
} from './src/vmSandbox/vmCloudSupervisor';
|
|
66
|
+
import * as guestProvision from './src/vmSandbox/vmGuestProvision';
|
|
67
|
+
import * as guestCloudProvision from './src/vmSandbox/vmGuestCloudProvision';
|
|
68
|
+
import {
|
|
69
|
+
PackedGoldenUnavailableError,
|
|
70
|
+
isRegistryLocked,
|
|
71
|
+
machineCreateFromArgs,
|
|
72
|
+
macE2fsprogsSbin,
|
|
73
|
+
mkfsExt4Candidates,
|
|
74
|
+
packCreateFromVmArgs,
|
|
75
|
+
packedCreateRetryAttempts,
|
|
76
|
+
packedCreateRetryBaseMs,
|
|
77
|
+
packedSidecarPath,
|
|
78
|
+
probePackedGoldenCapability,
|
|
79
|
+
resolveSmolNativeLayout,
|
|
80
|
+
smolCliEnv,
|
|
81
|
+
smolNativePlatformDir,
|
|
82
|
+
} from './src/vmSandbox/vmPackedGolden';
|
|
83
|
+
import {
|
|
84
|
+
GOLDEN_MACHINE_NAME_PREFIX,
|
|
85
|
+
defaultGuestCpus,
|
|
86
|
+
defaultGuestMemoryMb,
|
|
87
|
+
goldensToReap,
|
|
88
|
+
guestCodexVersion,
|
|
89
|
+
isGoldenMachineName,
|
|
90
|
+
pinnedGuestCodexVersion,
|
|
91
|
+
pinnedSmolmachinesVersion,
|
|
92
|
+
readGoldenMachineRegistrations,
|
|
93
|
+
readVmExecutionState,
|
|
94
|
+
readVmMachines,
|
|
95
|
+
registerGoldenMachine,
|
|
96
|
+
registerVmMachine,
|
|
97
|
+
setVmExecutionEnabled,
|
|
98
|
+
unregisterGoldenMachines,
|
|
99
|
+
unregisterVmMachines,
|
|
100
|
+
vmExecutionEnabled,
|
|
101
|
+
vmMachineName,
|
|
102
|
+
vmRuntimeDirPath,
|
|
103
|
+
vmStateFilePath,
|
|
104
|
+
writeVmExecutionState,
|
|
105
|
+
} from './src/vmSandbox/vmExecutionConfig';
|
|
106
|
+
import { normalizeGitRemoteUrl } from './src/vmSandbox/vmGoldenKeys';
|
|
107
|
+
import { resolveGoldenForJob } from './src/vmSandbox/vmGoldenSelect';
|
|
108
|
+
import {
|
|
109
|
+
createGoldenQueryTransport,
|
|
110
|
+
goldenGraphqlEndpoint,
|
|
111
|
+
goldenImagesByProjectDocument,
|
|
112
|
+
latestGoldenImageDocument,
|
|
113
|
+
nodeToRecordForTest,
|
|
114
|
+
recordFromByProjectForTest,
|
|
115
|
+
recordFromLatestForTest,
|
|
116
|
+
} from './src/vmSandbox/vmGoldenQuery';
|
|
117
|
+
import {
|
|
118
|
+
defaultGoldenGcGraceMs,
|
|
119
|
+
defaultGoldenGcIntervalMs,
|
|
120
|
+
fetchGoldenKeepSet,
|
|
121
|
+
goldenGcProjectsDocument,
|
|
122
|
+
goldenGcViewerWorkspacesDocument,
|
|
123
|
+
reconcileGoldenMachines,
|
|
124
|
+
} from './src/vmSandbox/vmGoldenGc';
|
|
125
|
+
import {
|
|
126
|
+
buildLockfileHashes,
|
|
127
|
+
coldRebuildFallbackReason,
|
|
128
|
+
detectPackageManager,
|
|
129
|
+
goldenArtifactPath,
|
|
130
|
+
goldenBuildMachineName,
|
|
131
|
+
goldenBuildManifest,
|
|
132
|
+
goldenLockfileNames,
|
|
133
|
+
goldenManifestChecksum,
|
|
134
|
+
goldenToolchainProbes,
|
|
135
|
+
isWellFormedGoldenBuildResult,
|
|
136
|
+
packageManagerInstallScript,
|
|
137
|
+
repoKeyForTarget,
|
|
138
|
+
resolveSnapshotOutcome,
|
|
139
|
+
} from './src/vmSandbox/vmGoldenBuild';
|
|
140
|
+
import {
|
|
141
|
+
osLabelFor,
|
|
142
|
+
probeLocalVmReadiness,
|
|
143
|
+
runtimeVersionIsForkable,
|
|
144
|
+
} from './src/vmSandbox/vmLocalVmReadiness';
|
|
145
|
+
import {
|
|
146
|
+
SMOLCLOUD_COMPUTE_KEY_PREFIX,
|
|
147
|
+
probeSmolcloudReadiness,
|
|
148
|
+
smolcloudComputeKey,
|
|
149
|
+
} from './src/vmSandbox/vmCloudVmReadiness';
|
|
150
|
+
import {
|
|
151
|
+
decodeVmSupervisorConfig,
|
|
152
|
+
encodeVmSupervisorConfig,
|
|
153
|
+
forkRetryConstsForTest,
|
|
154
|
+
goldenUsableForEgress,
|
|
155
|
+
guestDiagnosticsMarker,
|
|
156
|
+
guestLinzumiMcpCodexArgs,
|
|
157
|
+
guestLinzumiMcpServerConfig,
|
|
158
|
+
isEagainForTest,
|
|
159
|
+
resolveCreateMachineEgressPolicy,
|
|
160
|
+
smolmachinesSupportsGoldenBoot,
|
|
161
|
+
vmSupervisorReadyPrefix,
|
|
162
|
+
} from './src/vmSandbox/vmCodexSupervisor';
|
|
163
|
+
import {
|
|
164
|
+
agentMessageTextFromParams,
|
|
165
|
+
assertDangerFullAccess,
|
|
166
|
+
guestTurnProgressConstsForTest,
|
|
167
|
+
isBenignReplyDedupe,
|
|
168
|
+
isSuccessfulAgentReplyToolCall,
|
|
169
|
+
} from './src/vmSandbox/guestCloudSupervisor';
|
|
170
|
+
import {
|
|
171
|
+
SMOLCLOUD_DEFAULT_BASE_URL,
|
|
172
|
+
cloudMachineSource,
|
|
173
|
+
cloudTimeoutConstsForTest,
|
|
174
|
+
encodeCloudPath,
|
|
175
|
+
parseSseExecEvents,
|
|
176
|
+
redactCloudSecrets,
|
|
177
|
+
resolveCloudConnection,
|
|
178
|
+
resolveSmolcloudApiKey,
|
|
179
|
+
vmCloudAgentExecutionEnabled,
|
|
180
|
+
vmCloudAgentExplicitlyDisabled,
|
|
181
|
+
vmCloudExecutionEnabled,
|
|
182
|
+
} from './src/vmSandbox/vmCloudBackend';
|
|
183
|
+
import {
|
|
184
|
+
AGENT_HOME,
|
|
185
|
+
AGENT_HOME_PROVISIONED_MARKER,
|
|
186
|
+
AGENT_MACHINE_NAME_PREFIX,
|
|
187
|
+
DEFAULT_AGENT_AUTO_STOP_SECONDS,
|
|
188
|
+
DEFAULT_AGENT_CPUS,
|
|
189
|
+
DEFAULT_AGENT_DISK_GB,
|
|
190
|
+
DEFAULT_AGENT_IMAGE,
|
|
191
|
+
DEFAULT_AGENT_MEMORY_MB,
|
|
192
|
+
DEFAULT_MAX_CONCURRENT_TURNS,
|
|
193
|
+
agentMachineName,
|
|
194
|
+
agentVolumeName,
|
|
195
|
+
assertValidWorkspacePublicId,
|
|
196
|
+
verifyWorkspaceAgentMachine,
|
|
197
|
+
} from './src/vmSandbox/vmCloudAgentWorkspace';
|
|
198
|
+
import {
|
|
199
|
+
JOB_WORKTREES_DIRNAME,
|
|
200
|
+
jobBranchName,
|
|
201
|
+
jobWorktreeMounts,
|
|
202
|
+
jobWorktreePath,
|
|
203
|
+
prepareJobWorktree,
|
|
204
|
+
removeJobWorktree,
|
|
205
|
+
resolveRepoToplevel,
|
|
206
|
+
} from './src/vmSandbox/vmJobWorktree';
|
|
207
|
+
import { vmRelayScriptSource, vmTunnelWireConstsForTest } from './src/vmSandbox/vmTunnel';
|
|
208
|
+
import { runVmCommand, vmHelpText } from './src/vmSandbox/vmCli';
|
|
209
|
+
import {
|
|
210
|
+
readyTimeoutMsForTest,
|
|
211
|
+
scrubSupervisorEnv,
|
|
212
|
+
startVmConstsForTest,
|
|
213
|
+
} from './src/vmSandbox/startVmCodexAppServer';
|
|
214
|
+
import { buildVmLinzumiMcpConfig } from './src/vmSandbox/startVmCodexAppServer';
|
|
215
|
+
|
|
216
|
+
const dirPlaceholder = '$DIR';
|
|
217
|
+
|
|
218
|
+
function scratch() {
|
|
219
|
+
return realpathSync(mkdtempSync(join(tmpdir(), 'linzumi-vm-sandbox-oracle-')));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function substitute(value, from, to) {
|
|
223
|
+
if (typeof value === 'string') {
|
|
224
|
+
return value.split(from).join(to);
|
|
225
|
+
}
|
|
226
|
+
if (Array.isArray(value)) {
|
|
227
|
+
return value.map((entry) => substitute(entry, from, to));
|
|
228
|
+
}
|
|
229
|
+
if (typeof value === 'object' && value !== null) {
|
|
230
|
+
return Object.fromEntries(
|
|
231
|
+
Object.entries(value).map(([key, entry]) => [
|
|
232
|
+
substitute(key, from, to),
|
|
233
|
+
substitute(entry, from, to),
|
|
234
|
+
])
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
return value;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function outcome(run) {
|
|
241
|
+
try {
|
|
242
|
+
const value = run();
|
|
243
|
+
return value === undefined ? { defined: false } : { defined: true, value };
|
|
244
|
+
} catch (error) {
|
|
245
|
+
return {
|
|
246
|
+
threw: true,
|
|
247
|
+
message: error instanceof Error ? error.message : String(error),
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async function outcomeAsync(run) {
|
|
253
|
+
try {
|
|
254
|
+
const value = await run();
|
|
255
|
+
return value === undefined ? { defined: false } : { defined: true, value };
|
|
256
|
+
} catch (error) {
|
|
257
|
+
return {
|
|
258
|
+
threw: true,
|
|
259
|
+
message: error instanceof Error ? error.message : String(error),
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function withCapturedWarn(run) {
|
|
265
|
+
const warns = [];
|
|
266
|
+
const original = console.warn;
|
|
267
|
+
console.warn = (line) => warns.push(String(line));
|
|
268
|
+
try {
|
|
269
|
+
return { outcome: outcome(run), warns };
|
|
270
|
+
} finally {
|
|
271
|
+
console.warn = original;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const savedEnv = {};
|
|
276
|
+
|
|
277
|
+
function setCaseEnv(env) {
|
|
278
|
+
for (const [key, value] of Object.entries(env ?? {})) {
|
|
279
|
+
savedEnv[key] = process.env[key];
|
|
280
|
+
if (value === null) {
|
|
281
|
+
delete process.env[key];
|
|
282
|
+
} else {
|
|
283
|
+
process.env[key] = value;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function restoreCaseEnv() {
|
|
289
|
+
for (const [key, value] of Object.entries(savedEnv)) {
|
|
290
|
+
if (value === undefined) {
|
|
291
|
+
delete process.env[key];
|
|
292
|
+
} else {
|
|
293
|
+
process.env[key] = value;
|
|
294
|
+
}
|
|
295
|
+
delete savedEnv[key];
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// --- Wire-order builders --------------------------------------------------------
|
|
300
|
+
|
|
301
|
+
// The guest cloud turn config in the exact runCloudTurn insertion order.
|
|
302
|
+
function turnConfigFromFields(fields) {
|
|
303
|
+
return {
|
|
304
|
+
codexVersion: fields.codexVersion,
|
|
305
|
+
input: fields.input,
|
|
306
|
+
...(fields.model === undefined ? {} : { model: fields.model }),
|
|
307
|
+
...(fields.reasoningEffort === undefined
|
|
308
|
+
? {}
|
|
309
|
+
: { reasoningEffort: fields.reasoningEffort }),
|
|
310
|
+
sandbox: fields.sandbox,
|
|
311
|
+
approvalPolicy: fields.approvalPolicy,
|
|
312
|
+
...(fields.modelProvider === undefined
|
|
313
|
+
? {}
|
|
314
|
+
: { modelProvider: fields.modelProvider }),
|
|
315
|
+
kandanUrl: fields.kandanUrl,
|
|
316
|
+
...(fields.threadId === undefined ? {} : { threadId: fields.threadId }),
|
|
317
|
+
...(fields.sourceSeq === undefined ? {} : { sourceSeq: fields.sourceSeq }),
|
|
318
|
+
...(fields.codexThreadId === undefined
|
|
319
|
+
? {}
|
|
320
|
+
: { codexThreadId: fields.codexThreadId }),
|
|
321
|
+
...(fields.ownerUsername === undefined
|
|
322
|
+
? {}
|
|
323
|
+
: { ownerUsername: fields.ownerUsername }),
|
|
324
|
+
cwd: fields.cwd,
|
|
325
|
+
appServerPort: fields.appServerPort,
|
|
326
|
+
...(fields.turnNonce === undefined ? {} : { turnNonce: fields.turnNonce }),
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// --- Guest command dispatch ------------------------------------------------------
|
|
331
|
+
|
|
332
|
+
function handleGuestCmd(testCase) {
|
|
333
|
+
const v = testCase.version;
|
|
334
|
+
switch (testCase.fn) {
|
|
335
|
+
case 'provisionMarkerPath':
|
|
336
|
+
return outcome(() => guestProvision.guestProvisionMarkerPath(v));
|
|
337
|
+
case 'provisionCommand':
|
|
338
|
+
return outcome(() => guestProvision.guestProvisionCommand(v));
|
|
339
|
+
case 'provisionCheckCommand':
|
|
340
|
+
return outcome(() => guestProvision.guestProvisionCheckCommand(v));
|
|
341
|
+
case 'ensureDnsCommand':
|
|
342
|
+
return outcome(() => guestProvision.guestEnsureDnsCommand());
|
|
343
|
+
case 'codexEnvFileContents':
|
|
344
|
+
return outcome(() =>
|
|
345
|
+
guestProvision.guestCodexEnvFileContents(
|
|
346
|
+
Object.fromEntries(testCase.envPairs)
|
|
347
|
+
)
|
|
348
|
+
);
|
|
349
|
+
case 'startCodexCommand':
|
|
350
|
+
return outcome(() =>
|
|
351
|
+
guestProvision.guestStartCodexCommand({
|
|
352
|
+
cwd: testCase.cwd,
|
|
353
|
+
codexArgs: testCase.codexArgs,
|
|
354
|
+
})
|
|
355
|
+
);
|
|
356
|
+
case 'scrubSecretsCommand':
|
|
357
|
+
return outcome(() => guestProvision.guestScrubSecretsCommand());
|
|
358
|
+
case 'readyzCheckCommand':
|
|
359
|
+
return outcome(() => guestProvision.guestReadyzCheckCommand(testCase.port));
|
|
360
|
+
case 'startRelayCommand':
|
|
361
|
+
return outcome(() => guestProvision.guestStartRelayCommand());
|
|
362
|
+
case 'stopCodexCommand':
|
|
363
|
+
return outcome(() => guestProvision.guestStopCodexCommand());
|
|
364
|
+
case 'resetCodexCommand':
|
|
365
|
+
return outcome(() => guestProvision.guestResetCodexCommand());
|
|
366
|
+
case 'diagnosticsCommand':
|
|
367
|
+
return outcome(() => guestProvision.guestDiagnosticsCommand());
|
|
368
|
+
case 'shellQuote':
|
|
369
|
+
return outcome(() => guestProvision.shellQuote(testCase.value));
|
|
370
|
+
case 'localPaths':
|
|
371
|
+
return outcome(() => ({
|
|
372
|
+
provisionMarkerVersion: guestProvision.provisionMarkerVersion,
|
|
373
|
+
guestRelayScriptPath: guestProvision.guestRelayScriptPath,
|
|
374
|
+
guestCodexLogPath: guestProvision.guestCodexLogPath,
|
|
375
|
+
guestRelayLogPath: guestProvision.guestRelayLogPath,
|
|
376
|
+
guestMcpServerScriptPath: guestProvision.guestMcpServerScriptPath,
|
|
377
|
+
guestSecretsDir: guestProvision.guestSecretsDir,
|
|
378
|
+
guestCodexHome: guestProvision.guestCodexHome,
|
|
379
|
+
guestMcpAuthFilePath: guestProvision.guestMcpAuthFilePath,
|
|
380
|
+
guestCodexEnvFilePath: guestProvision.guestCodexEnvFilePath,
|
|
381
|
+
guestCaBundlePath: guestProvision.guestCaBundlePath,
|
|
382
|
+
guestDnsNameservers: guestProvision.guestDnsNameservers,
|
|
383
|
+
}));
|
|
384
|
+
case 'cloudProvisionMarkerPath':
|
|
385
|
+
return outcome(() => guestCloudProvision.guestCloudProvisionMarkerPath(v));
|
|
386
|
+
case 'cloudProvisionCommand':
|
|
387
|
+
return outcome(() => guestCloudProvision.guestCloudProvisionCommand(v));
|
|
388
|
+
case 'cloudProvisionCheckCommand':
|
|
389
|
+
return outcome(() =>
|
|
390
|
+
guestCloudProvision.guestCloudProvisionCheckCommand(v)
|
|
391
|
+
);
|
|
392
|
+
case 'cloudPreflightCommand':
|
|
393
|
+
return outcome(() => guestCloudProvision.guestCloudPreflightCommand(v));
|
|
394
|
+
case 'cloudScrubSecretsCommand':
|
|
395
|
+
return outcome(() => guestCloudProvision.guestCloudScrubSecretsCommand());
|
|
396
|
+
case 'assertTurnNonce':
|
|
397
|
+
return outcome(() => {
|
|
398
|
+
guestCloudProvision.assertValidTurnNonce(testCase.nonce);
|
|
399
|
+
return 'ok';
|
|
400
|
+
});
|
|
401
|
+
case 'heartbeatPath':
|
|
402
|
+
return outcome(() => guestCloudProvision.guestCloudHeartbeatPath(testCase.nonce));
|
|
403
|
+
case 'exitMarkerPath':
|
|
404
|
+
return outcome(() => guestCloudProvision.guestCloudExitMarkerPath(testCase.nonce));
|
|
405
|
+
case 'turnProbeCommand':
|
|
406
|
+
return outcome(() => guestCloudProvision.guestCloudTurnProbeCommand(testCase.nonce));
|
|
407
|
+
case 'turnProbeCleanupCommand':
|
|
408
|
+
return outcome(() =>
|
|
409
|
+
guestCloudProvision.guestCloudTurnProbeCleanupCommand(testCase.nonce)
|
|
410
|
+
);
|
|
411
|
+
case 'cloudPaths':
|
|
412
|
+
return outcome(() => ({
|
|
413
|
+
cloudProvisionMarkerVersion: guestCloudProvision.cloudProvisionMarkerVersion,
|
|
414
|
+
guestCloudAppServerPort: guestCloudProvision.guestCloudAppServerPort,
|
|
415
|
+
guestCloudSupervisorPath: guestCloudProvision.guestCloudSupervisorPath,
|
|
416
|
+
guestCloudMcpBundlePath: guestCloudProvision.guestCloudMcpBundlePath,
|
|
417
|
+
guestCloudSecretsDir: guestCloudProvision.guestCloudSecretsDir,
|
|
418
|
+
guestCloudMcpAuthPath: guestCloudProvision.guestCloudMcpAuthPath,
|
|
419
|
+
guestCloudCodexHome: guestCloudProvision.guestCloudCodexHome,
|
|
420
|
+
guestCloudThreadMapPath: guestCloudProvision.guestCloudThreadMapPath,
|
|
421
|
+
guestCloudCaBundlePath: guestCloudProvision.guestCloudCaBundlePath,
|
|
422
|
+
guestCloudHeartbeatDir: guestCloudProvision.guestCloudHeartbeatDir,
|
|
423
|
+
guestHeartbeatIntervalMs: guestCloudProvision.GUEST_HEARTBEAT_INTERVAL_MS,
|
|
424
|
+
agentHome: AGENT_HOME,
|
|
425
|
+
agentHomeProvisionedMarker: AGENT_HOME_PROVISIONED_MARKER,
|
|
426
|
+
}));
|
|
427
|
+
default:
|
|
428
|
+
return { threw: true, message: 'unknown guestCmd fn ' + String(testCase.fn) };
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// --- Scripted seams ---------------------------------------------------------------
|
|
433
|
+
|
|
434
|
+
function scriptedGoldenQuery(spec, trace) {
|
|
435
|
+
return async (args) => {
|
|
436
|
+
trace.push({ t: 'query', args: { ...args, explicitGoldenId: args.explicitGoldenId ?? null } });
|
|
437
|
+
const scripted = spec[args.projectId] ?? spec['*'] ?? { kind: 'null' };
|
|
438
|
+
if (scripted.kind === 'throw') {
|
|
439
|
+
throw new Error(scripted.message);
|
|
440
|
+
}
|
|
441
|
+
return scripted.kind === 'record' ? scripted.record : null;
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function scriptedFetch(routes, requests) {
|
|
446
|
+
return async (url, init) => {
|
|
447
|
+
const urlText = String(url);
|
|
448
|
+
requests.push({
|
|
449
|
+
url: urlText,
|
|
450
|
+
method: init?.method ?? 'GET',
|
|
451
|
+
body: init?.body === undefined ? null : JSON.parse(init.body),
|
|
452
|
+
});
|
|
453
|
+
const route = routes.find((candidate) => urlText.endsWith(candidate.suffix));
|
|
454
|
+
if (route === undefined) {
|
|
455
|
+
throw new Error('no scripted route for ' + urlText);
|
|
456
|
+
}
|
|
457
|
+
if (route.abort === true) {
|
|
458
|
+
const error = new Error('This operation was aborted');
|
|
459
|
+
error.name = 'AbortError';
|
|
460
|
+
throw error;
|
|
461
|
+
}
|
|
462
|
+
if (route.networkError !== undefined) {
|
|
463
|
+
throw new Error(route.networkError);
|
|
464
|
+
}
|
|
465
|
+
return {
|
|
466
|
+
ok: route.status >= 200 && route.status < 300,
|
|
467
|
+
status: route.status,
|
|
468
|
+
statusText: route.statusText ?? '',
|
|
469
|
+
headers: { get: () => 'application/json' },
|
|
470
|
+
json: async () => route.body,
|
|
471
|
+
text: async () => JSON.stringify(route.body ?? ''),
|
|
472
|
+
};
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function scriptedGitRunner(script, trace) {
|
|
477
|
+
return async (cwd, args) => {
|
|
478
|
+
const key = args.join(' ');
|
|
479
|
+
trace.push({ t: 'git', cwd, args: [...args] });
|
|
480
|
+
const scripted = script[key];
|
|
481
|
+
if (scripted === undefined) {
|
|
482
|
+
throw new Error('no scripted git for ' + key);
|
|
483
|
+
}
|
|
484
|
+
if (scripted.err !== undefined) {
|
|
485
|
+
throw new Error(scripted.err);
|
|
486
|
+
}
|
|
487
|
+
return scripted.out ?? '';
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// --- Op dispatch --------------------------------------------------------------------
|
|
492
|
+
|
|
493
|
+
async function handle(testCase) {
|
|
494
|
+
switch (testCase.op) {
|
|
495
|
+
// ---- egress -------------------------------------------------------------------
|
|
496
|
+
case 'egressDefaults':
|
|
497
|
+
return outcome(() => ({
|
|
498
|
+
placeholder: PLACEHOLDER_GATEWAY_CIDR,
|
|
499
|
+
defaults: [...defaultGatewayEgressCidrs],
|
|
500
|
+
defaultMode: DEFAULT_VM_EGRESS_MODE,
|
|
501
|
+
}));
|
|
502
|
+
case 'egressNormalize':
|
|
503
|
+
return outcome(() => normalizeVmEgressMode(testCase.value));
|
|
504
|
+
case 'egressValidCidr':
|
|
505
|
+
return outcome(() => isValidEgressCidr(testCase.cidr));
|
|
506
|
+
case 'egressWideOpen':
|
|
507
|
+
return outcome(() => isWideOpenCidr(testCase.cidr));
|
|
508
|
+
case 'egressResolve':
|
|
509
|
+
return outcome(() => resolveVmEgressPolicy(testCase.env));
|
|
510
|
+
case 'egressPlaceholder':
|
|
511
|
+
return outcome(() => isPlaceholderEgressPolicy(testCase.env));
|
|
512
|
+
case 'egressOpenPolicy':
|
|
513
|
+
return outcome(() => openEgressPolicy());
|
|
514
|
+
case 'egressResolveActive': {
|
|
515
|
+
const logs = [];
|
|
516
|
+
const result = outcome(() =>
|
|
517
|
+
resolveVmEgressPolicyForActiveVm(testCase.env, testCase.mode, (line) =>
|
|
518
|
+
logs.push(line)
|
|
519
|
+
)
|
|
520
|
+
);
|
|
521
|
+
return { result, logs };
|
|
522
|
+
}
|
|
523
|
+
case 'egressAssert':
|
|
524
|
+
return outcome(() => assertEgressPolicyUpheld(testCase.policy));
|
|
525
|
+
// ---- turn codec ------------------------------------------------------------------
|
|
526
|
+
case 'turnEncode':
|
|
527
|
+
return outcome(() =>
|
|
528
|
+
encodeGuestCloudTurnConfig(turnConfigFromFields(testCase.fields))
|
|
529
|
+
);
|
|
530
|
+
case 'turnDecode':
|
|
531
|
+
return outcome(() => decodeGuestCloudTurnConfig(testCase.encoded));
|
|
532
|
+
case 'exitLine':
|
|
533
|
+
return outcome(() => parseCloudTurnExitLineForTest(testCase.line));
|
|
534
|
+
case 'preflightParse':
|
|
535
|
+
return outcome(() => parsePreflightOutput(testCase.stdout));
|
|
536
|
+
case 'injectSecrets':
|
|
537
|
+
return outcome(() =>
|
|
538
|
+
injectTurnSecrets({
|
|
539
|
+
codexVersion: 'x',
|
|
540
|
+
input: [],
|
|
541
|
+
sandbox: 'danger-full-access',
|
|
542
|
+
approvalPolicy: 'never',
|
|
543
|
+
kandanUrl: 'https://scripted.example',
|
|
544
|
+
cwd: '/scripted',
|
|
545
|
+
mcpAuthFileContents: testCase.mcpAuthFileContents,
|
|
546
|
+
...(testCase.llmProxyToken === undefined || testCase.llmProxyToken === null
|
|
547
|
+
? {}
|
|
548
|
+
: { llmProxyToken: testCase.llmProxyToken }),
|
|
549
|
+
})
|
|
550
|
+
);
|
|
551
|
+
case 'cloudTurnTimeout':
|
|
552
|
+
return outcome(() => cloudTurnTimeoutMs(testCase.env));
|
|
553
|
+
case 'cloudTurnError':
|
|
554
|
+
return outcome(() => {
|
|
555
|
+
const error = new CloudTurnError(testCase.message, testCase.retryable);
|
|
556
|
+
return { name: error.name, message: error.message, retryable: error.retryable };
|
|
557
|
+
});
|
|
558
|
+
case 'cloudConsts':
|
|
559
|
+
return outcome(() => ({
|
|
560
|
+
defaultCloudTurnTimeoutMs: DEFAULT_CLOUD_TURN_TIMEOUT_MS,
|
|
561
|
+
exitPhase: GUEST_CLOUD_TURN_EXIT_PHASE,
|
|
562
|
+
secretEnv: { ...GuestCloudTurnSecretEnv },
|
|
563
|
+
...cloudSupervisorConstsForTest,
|
|
564
|
+
}));
|
|
565
|
+
// ---- guest commands ------------------------------------------------------------------
|
|
566
|
+
case 'guestCmd':
|
|
567
|
+
return handleGuestCmd(testCase);
|
|
568
|
+
// ---- packed golden -------------------------------------------------------------------
|
|
569
|
+
case 'packedPlatformDir':
|
|
570
|
+
return outcome(() => smolNativePlatformDir(testCase.platform, testCase.arch));
|
|
571
|
+
case 'packedLayout':
|
|
572
|
+
return outcome(() =>
|
|
573
|
+
resolveSmolNativeLayout(testCase.runtimeDir, testCase.platform, testCase.arch)
|
|
574
|
+
);
|
|
575
|
+
case 'packedCapability':
|
|
576
|
+
return outcome(() =>
|
|
577
|
+
probePackedGoldenCapability({
|
|
578
|
+
runtimeDir: testCase.runtimeDir,
|
|
579
|
+
platform: testCase.platform,
|
|
580
|
+
arch: testCase.arch,
|
|
581
|
+
fileExists: (path) => testCase.files.includes(path),
|
|
582
|
+
hasMkfsExt4: () => testCase.mkfs === true,
|
|
583
|
+
})
|
|
584
|
+
);
|
|
585
|
+
case 'smolCliEnv':
|
|
586
|
+
return outcome(() => smolCliEnv(testCase.layout, testCase.baseEnv));
|
|
587
|
+
case 'packArgs':
|
|
588
|
+
return outcome(() =>
|
|
589
|
+
packCreateFromVmArgs({
|
|
590
|
+
machineName: testCase.machineName,
|
|
591
|
+
outBase: testCase.outBase,
|
|
592
|
+
layout: testCase.layout,
|
|
593
|
+
})
|
|
594
|
+
);
|
|
595
|
+
case 'sidecarPath':
|
|
596
|
+
return outcome(() => packedSidecarPath(testCase.outBase));
|
|
597
|
+
case 'machineFromArgs':
|
|
598
|
+
return outcome(() =>
|
|
599
|
+
machineCreateFromArgs({
|
|
600
|
+
jobMachineName: testCase.jobMachineName,
|
|
601
|
+
sidecarPath: testCase.sidecarPath,
|
|
602
|
+
})
|
|
603
|
+
);
|
|
604
|
+
case 'registryLocked':
|
|
605
|
+
return outcome(() => isRegistryLocked(testCase.message));
|
|
606
|
+
case 'packedConsts':
|
|
607
|
+
return outcome(() => ({
|
|
608
|
+
macE2fsprogsSbin,
|
|
609
|
+
mkfsExt4Candidates: [...mkfsExt4Candidates],
|
|
610
|
+
packedCreateRetryAttempts,
|
|
611
|
+
packedCreateRetryBaseMs,
|
|
612
|
+
}));
|
|
613
|
+
case 'packedUnavailableMessage':
|
|
614
|
+
return outcome(() => new PackedGoldenUnavailableError(testCase.blockers).message);
|
|
615
|
+
// ---- execution config -------------------------------------------------------------------
|
|
616
|
+
case 'pins':
|
|
617
|
+
return outcome(() => ({
|
|
618
|
+
pinnedSmolmachinesVersion,
|
|
619
|
+
pinnedGuestCodexVersion,
|
|
620
|
+
defaultGuestCpus,
|
|
621
|
+
defaultGuestMemoryMb,
|
|
622
|
+
goldenMachineNamePrefix: GOLDEN_MACHINE_NAME_PREFIX,
|
|
623
|
+
defaultAgentImage: DEFAULT_AGENT_IMAGE,
|
|
624
|
+
}));
|
|
625
|
+
case 'readVmState': {
|
|
626
|
+
const dir = scratch();
|
|
627
|
+
const path = join(dir, 'vm.json');
|
|
628
|
+
if (testCase.contents !== null) {
|
|
629
|
+
writeFileSync(path, testCase.contents);
|
|
630
|
+
}
|
|
631
|
+
return substitute(
|
|
632
|
+
outcome(() => readVmExecutionState(path)),
|
|
633
|
+
dir,
|
|
634
|
+
dirPlaceholder
|
|
635
|
+
);
|
|
636
|
+
}
|
|
637
|
+
case 'writeVmState': {
|
|
638
|
+
const dir = scratch();
|
|
639
|
+
const path = join(dir, 'nested', 'vm.json');
|
|
640
|
+
return substitute(
|
|
641
|
+
outcome(() => {
|
|
642
|
+
writeVmExecutionState(testCase.state, path);
|
|
643
|
+
return {
|
|
644
|
+
bytes: readFileSync(path, 'utf8'),
|
|
645
|
+
mode: statSync(path).mode & 0o777,
|
|
646
|
+
};
|
|
647
|
+
}),
|
|
648
|
+
dir,
|
|
649
|
+
dirPlaceholder
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
case 'setVmEnabled': {
|
|
653
|
+
const dir = scratch();
|
|
654
|
+
const path = join(dir, 'vm.json');
|
|
655
|
+
if (testCase.contents !== null) {
|
|
656
|
+
writeFileSync(path, testCase.contents);
|
|
657
|
+
}
|
|
658
|
+
return substitute(
|
|
659
|
+
outcome(() => {
|
|
660
|
+
const next = setVmExecutionEnabled(testCase.enabled, path);
|
|
661
|
+
return { next, bytes: readFileSync(path, 'utf8') };
|
|
662
|
+
}),
|
|
663
|
+
dir,
|
|
664
|
+
dirPlaceholder
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
case 'vmEnabled': {
|
|
668
|
+
const dir = scratch();
|
|
669
|
+
const path = join(dir, 'vm.json');
|
|
670
|
+
if (testCase.contents !== null) {
|
|
671
|
+
writeFileSync(path, testCase.contents);
|
|
672
|
+
}
|
|
673
|
+
const { outcome: result, warns } = withCapturedWarn(() =>
|
|
674
|
+
vmExecutionEnabled(testCase.env, path)
|
|
675
|
+
);
|
|
676
|
+
return substitute({ result, warns }, dir, dirPlaceholder);
|
|
677
|
+
}
|
|
678
|
+
case 'guestCodexVersion':
|
|
679
|
+
return outcome(() => guestCodexVersion(testCase.env));
|
|
680
|
+
case 'stateFilePath':
|
|
681
|
+
return outcome(() => vmStateFilePath(testCase.env));
|
|
682
|
+
case 'runtimeDirPath':
|
|
683
|
+
return outcome(() => vmRuntimeDirPath(testCase.env));
|
|
684
|
+
case 'vmMachineName':
|
|
685
|
+
return outcome(() =>
|
|
686
|
+
vmMachineName({ cwd: testCase.cwd, kandanThreadId: testCase.sessionId ?? undefined })
|
|
687
|
+
);
|
|
688
|
+
case 'goldensToReap':
|
|
689
|
+
return outcome(() => goldensToReap(testCase.present, testCase.keep));
|
|
690
|
+
case 'isGoldenName':
|
|
691
|
+
return outcome(() => isGoldenMachineName(testCase.name));
|
|
692
|
+
case 'registrySchedule': {
|
|
693
|
+
const dir = scratch();
|
|
694
|
+
const path = join(dir, 'vm.json');
|
|
695
|
+
const trace = [];
|
|
696
|
+
for (const step of testCase.script) {
|
|
697
|
+
if (step.step === 'registerMachine') {
|
|
698
|
+
trace.push({ t: 'registerMachine', result: outcome(() => registerVmMachine(step.name, path)) });
|
|
699
|
+
} else if (step.step === 'unregisterMachines') {
|
|
700
|
+
trace.push({ t: 'unregisterMachines', result: outcome(() => unregisterVmMachines(step.names, path)) });
|
|
701
|
+
} else if (step.step === 'listMachines') {
|
|
702
|
+
trace.push({ t: 'listMachines', names: readVmMachines(path) });
|
|
703
|
+
} else if (step.step === 'registerGolden') {
|
|
704
|
+
trace.push({ t: 'registerGolden', result: outcome(() => registerGoldenMachine(step.name, path)) });
|
|
705
|
+
} else if (step.step === 'unregisterGoldens') {
|
|
706
|
+
trace.push({ t: 'unregisterGoldens', result: outcome(() => unregisterGoldenMachines(step.names, path)) });
|
|
707
|
+
} else if (step.step === 'listGoldens') {
|
|
708
|
+
trace.push({
|
|
709
|
+
t: 'listGoldens',
|
|
710
|
+
names: readGoldenMachineRegistrations(path).map((r) => r.name),
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
return substitute({ trace }, dir, dirPlaceholder);
|
|
715
|
+
}
|
|
716
|
+
// ---- golden planning ------------------------------------------------------------------------
|
|
717
|
+
case 'normalizeGitRemote':
|
|
718
|
+
return outcome(() => normalizeGitRemoteUrl(testCase.raw));
|
|
719
|
+
case 'goldenEndpoint':
|
|
720
|
+
return outcome(() => goldenGraphqlEndpoint(testCase.baseUrl));
|
|
721
|
+
case 'goldenDocs':
|
|
722
|
+
return outcome(() => ({
|
|
723
|
+
latest: latestGoldenImageDocument,
|
|
724
|
+
byProject: goldenImagesByProjectDocument,
|
|
725
|
+
gcWorkspaces: goldenGcViewerWorkspacesDocument,
|
|
726
|
+
gcProjects: goldenGcProjectsDocument,
|
|
727
|
+
}));
|
|
728
|
+
case 'nodeToRecord':
|
|
729
|
+
return outcome(() => nodeToRecordForTest(testCase.node));
|
|
730
|
+
case 'recordFromLatest':
|
|
731
|
+
return outcome(() => recordFromLatestForTest(testCase.data));
|
|
732
|
+
case 'recordFromByProject': {
|
|
733
|
+
const warns = [];
|
|
734
|
+
const result = outcome(() =>
|
|
735
|
+
recordFromByProjectForTest(testCase.data, testCase.explicitGoldenId, (m) =>
|
|
736
|
+
warns.push(m)
|
|
737
|
+
)
|
|
738
|
+
);
|
|
739
|
+
return { result, warns };
|
|
740
|
+
}
|
|
741
|
+
case 'resolveGolden': {
|
|
742
|
+
const warns = [];
|
|
743
|
+
const trace = [];
|
|
744
|
+
const result = await outcomeAsync(() =>
|
|
745
|
+
resolveGoldenForJob({
|
|
746
|
+
projectId: testCase.projectId,
|
|
747
|
+
computeKey: testCase.computeKey,
|
|
748
|
+
explicitGoldenId: testCase.explicitGoldenId ?? undefined,
|
|
749
|
+
query:
|
|
750
|
+
testCase.query === null
|
|
751
|
+
? undefined
|
|
752
|
+
: scriptedGoldenQuery(testCase.query, trace),
|
|
753
|
+
artifactExists: (path) => (testCase.files ?? []).includes(path),
|
|
754
|
+
warn: (m) => warns.push(m),
|
|
755
|
+
})
|
|
756
|
+
);
|
|
757
|
+
return { result, warns, trace };
|
|
758
|
+
}
|
|
759
|
+
case 'queryTransport': {
|
|
760
|
+
const requests = [];
|
|
761
|
+
const warns = [];
|
|
762
|
+
const transport = createGoldenQueryTransport({
|
|
763
|
+
kandanUrl: testCase.baseUrl,
|
|
764
|
+
token: 'synthetic-token',
|
|
765
|
+
fetchImpl: scriptedFetch(testCase.routes, requests),
|
|
766
|
+
warn: (m) => warns.push(m),
|
|
767
|
+
});
|
|
768
|
+
const result = await outcomeAsync(() =>
|
|
769
|
+
transport({
|
|
770
|
+
projectId: testCase.projectId,
|
|
771
|
+
computeKey: testCase.computeKey,
|
|
772
|
+
explicitGoldenId: testCase.explicitGoldenId ?? undefined,
|
|
773
|
+
})
|
|
774
|
+
);
|
|
775
|
+
return { result, warns, requests };
|
|
776
|
+
}
|
|
777
|
+
case 'keepSet': {
|
|
778
|
+
const trace = [];
|
|
779
|
+
const serverLists = {
|
|
780
|
+
listWorkspaceIds: async () => {
|
|
781
|
+
if (testCase.workspaces.throw !== undefined) {
|
|
782
|
+
throw new Error(testCase.workspaces.throw);
|
|
783
|
+
}
|
|
784
|
+
return testCase.workspaces.ids;
|
|
785
|
+
},
|
|
786
|
+
listProjectIds: async (workspaceId) => {
|
|
787
|
+
const scripted = testCase.projects[workspaceId];
|
|
788
|
+
if (scripted === undefined || scripted.throw !== undefined) {
|
|
789
|
+
throw new Error(scripted?.throw ?? 'no scripted projects for ' + workspaceId);
|
|
790
|
+
}
|
|
791
|
+
return scripted.ids;
|
|
792
|
+
},
|
|
793
|
+
};
|
|
794
|
+
const result = await outcomeAsync(() =>
|
|
795
|
+
fetchGoldenKeepSet({
|
|
796
|
+
computeKey: testCase.computeKey,
|
|
797
|
+
serverLists,
|
|
798
|
+
query: scriptedGoldenQuery(testCase.query, trace),
|
|
799
|
+
})
|
|
800
|
+
);
|
|
801
|
+
return { result, trace };
|
|
802
|
+
}
|
|
803
|
+
case 'gcReconcile': {
|
|
804
|
+
const trace = [];
|
|
805
|
+
const logs = [];
|
|
806
|
+
const unregistered = [];
|
|
807
|
+
const result = await outcomeAsync(() =>
|
|
808
|
+
reconcileGoldenMachines({
|
|
809
|
+
computeKey: testCase.computeKey,
|
|
810
|
+
listPresent: () => testCase.present,
|
|
811
|
+
serverLists: {
|
|
812
|
+
listWorkspaceIds: async () => {
|
|
813
|
+
if (testCase.workspaces.throw !== undefined) {
|
|
814
|
+
throw new Error(testCase.workspaces.throw);
|
|
815
|
+
}
|
|
816
|
+
return testCase.workspaces.ids;
|
|
817
|
+
},
|
|
818
|
+
listProjectIds: async (workspaceId) => {
|
|
819
|
+
const scripted = testCase.projects[workspaceId];
|
|
820
|
+
if (scripted === undefined || scripted.throw !== undefined) {
|
|
821
|
+
throw new Error(scripted?.throw ?? 'no scripted projects for ' + workspaceId);
|
|
822
|
+
}
|
|
823
|
+
return scripted.ids;
|
|
824
|
+
},
|
|
825
|
+
},
|
|
826
|
+
query: scriptedGoldenQuery(testCase.query, trace),
|
|
827
|
+
deleteMachine: async (name) => {
|
|
828
|
+
const scripted = (testCase.deletes ?? {})[name] ?? { kind: 'deleted' };
|
|
829
|
+
if (scripted.kind === 'throw') {
|
|
830
|
+
throw new Error(scripted.message);
|
|
831
|
+
}
|
|
832
|
+
return scripted.kind;
|
|
833
|
+
},
|
|
834
|
+
unregister: (names) => unregistered.push(...names),
|
|
835
|
+
log: (line) => logs.push(line),
|
|
836
|
+
nowMs: () => testCase.nowMs,
|
|
837
|
+
graceMs: testCase.graceMs,
|
|
838
|
+
})
|
|
839
|
+
);
|
|
840
|
+
return { result, logs, unregistered };
|
|
841
|
+
}
|
|
842
|
+
case 'gcConsts':
|
|
843
|
+
return outcome(() => ({ defaultGoldenGcIntervalMs, defaultGoldenGcGraceMs }));
|
|
844
|
+
case 'detectPm':
|
|
845
|
+
return outcome(() => detectPackageManager(new Set(testCase.lockfiles)));
|
|
846
|
+
case 'pmScript':
|
|
847
|
+
return outcome(() => packageManagerInstallScript(testCase.manager));
|
|
848
|
+
case 'lockfileHashes':
|
|
849
|
+
return outcome(() => buildLockfileHashes(new Map(testCase.entries)));
|
|
850
|
+
case 'manifest':
|
|
851
|
+
return outcome(() => goldenBuildManifest(testCase.parts));
|
|
852
|
+
case 'manifestChecksum':
|
|
853
|
+
return outcome(() => goldenManifestChecksum(testCase.parts));
|
|
854
|
+
case 'wellFormed':
|
|
855
|
+
return outcome(() => isWellFormedGoldenBuildResult(testCase.value));
|
|
856
|
+
case 'coldReason':
|
|
857
|
+
return outcome(() => coldRebuildFallbackReason(testCase.sourceCommits));
|
|
858
|
+
case 'snapshotOutcome':
|
|
859
|
+
return outcome(() =>
|
|
860
|
+
resolveSnapshotOutcome({
|
|
861
|
+
snapshot: testCase.snapshot,
|
|
862
|
+
coldRebuild: testCase.coldRebuild,
|
|
863
|
+
})
|
|
864
|
+
);
|
|
865
|
+
case 'artifactPath':
|
|
866
|
+
return outcome(() => goldenArtifactPath(testCase.runtimeDir, testCase.machineName));
|
|
867
|
+
case 'goldenName':
|
|
868
|
+
return outcome(() =>
|
|
869
|
+
goldenBuildMachineName({
|
|
870
|
+
projectPublicId: testCase.projectPublicId ?? undefined,
|
|
871
|
+
computeKey: testCase.computeKey ?? undefined,
|
|
872
|
+
cwd: testCase.cwd,
|
|
873
|
+
})
|
|
874
|
+
);
|
|
875
|
+
case 'repoKey':
|
|
876
|
+
return outcome(() => repoKeyForTarget(testCase.target));
|
|
877
|
+
case 'buildCoreConsts':
|
|
878
|
+
return outcome(() => ({
|
|
879
|
+
goldenLockfileNames: [...goldenLockfileNames],
|
|
880
|
+
goldenToolchainProbes: goldenToolchainProbes.map((p) => ({
|
|
881
|
+
key: p.key,
|
|
882
|
+
command: [...p.command],
|
|
883
|
+
})),
|
|
884
|
+
}));
|
|
885
|
+
// ---- readiness ---------------------------------------------------------------------------------
|
|
886
|
+
case 'runtimeForkable':
|
|
887
|
+
return outcome(() => runtimeVersionIsForkable(testCase.version));
|
|
888
|
+
case 'osLabel':
|
|
889
|
+
return outcome(() => osLabelFor(testCase.platform, testCase.arch));
|
|
890
|
+
case 'localReadiness':
|
|
891
|
+
return await outcomeAsync(() =>
|
|
892
|
+
probeLocalVmReadiness({
|
|
893
|
+
platform: testCase.platform,
|
|
894
|
+
arch: testCase.arch,
|
|
895
|
+
runtimeDir: testCase.runtimeDir,
|
|
896
|
+
vmCapability: () => testCase.vmCapability,
|
|
897
|
+
installedRuntimeVersion: () => testCase.runtimeVersion ?? undefined,
|
|
898
|
+
fileExists: (path) => testCase.files.includes(path),
|
|
899
|
+
mkfsExt4Present: () => testCase.mkfs === true,
|
|
900
|
+
macNativeDeps: async () => testCase.macStatus,
|
|
901
|
+
workspaceLocalVmExecutionFlag: testCase.flag ?? null,
|
|
902
|
+
})
|
|
903
|
+
);
|
|
904
|
+
case 'cloudComputeKey':
|
|
905
|
+
return outcome(() => ({
|
|
906
|
+
prefix: SMOLCLOUD_COMPUTE_KEY_PREFIX,
|
|
907
|
+
key: smolcloudComputeKey(testCase.clusterId),
|
|
908
|
+
}));
|
|
909
|
+
case 'cloudReadiness': {
|
|
910
|
+
const requests = [];
|
|
911
|
+
return await outcomeAsync(() =>
|
|
912
|
+
probeSmolcloudReadiness({
|
|
913
|
+
env: testCase.env,
|
|
914
|
+
config: testCase.config,
|
|
915
|
+
fetchImpl: scriptedFetch(testCase.routes ?? [], requests),
|
|
916
|
+
})
|
|
917
|
+
);
|
|
918
|
+
}
|
|
919
|
+
case 'cloudReadinessUnreadableState': {
|
|
920
|
+
const dir = scratch();
|
|
921
|
+
const path = join(dir, 'vm.json');
|
|
922
|
+
writeFileSync(path, testCase.contents);
|
|
923
|
+
const result = await outcomeAsync(() =>
|
|
924
|
+
probeSmolcloudReadiness({ env: testCase.env, statePath: path })
|
|
925
|
+
);
|
|
926
|
+
return substitute(result, dir, dirPlaceholder);
|
|
927
|
+
}
|
|
928
|
+
// ---- supervisor core ---------------------------------------------------------------------------
|
|
929
|
+
case 'supEncode':
|
|
930
|
+
return outcome(() => encodeVmSupervisorConfig(testCase.payload));
|
|
931
|
+
case 'supDecode':
|
|
932
|
+
return outcome(() =>
|
|
933
|
+
decodeVmSupervisorConfig(
|
|
934
|
+
testCase.encoded ?? encodeVmSupervisorConfig(testCase.payload)
|
|
935
|
+
)
|
|
936
|
+
);
|
|
937
|
+
case 'guestMcpConfig':
|
|
938
|
+
return outcome(() => guestLinzumiMcpServerConfig(testCase.mcp, testCase.guestCwd));
|
|
939
|
+
case 'guestMcpArgs':
|
|
940
|
+
return outcome(() => guestLinzumiMcpCodexArgs(testCase.mcp, testCase.guestCwd));
|
|
941
|
+
case 'createEgress': {
|
|
942
|
+
const { outcome: result, warns } = withCapturedWarn(() =>
|
|
943
|
+
resolveCreateMachineEgressPolicy(testCase.config, testCase.env)
|
|
944
|
+
);
|
|
945
|
+
return { result, warns };
|
|
946
|
+
}
|
|
947
|
+
case 'goldenUsable': {
|
|
948
|
+
const { outcome: result, warns } = withCapturedWarn(() =>
|
|
949
|
+
goldenUsableForEgress(testCase.config, testCase.env)
|
|
950
|
+
);
|
|
951
|
+
return { result, warns };
|
|
952
|
+
}
|
|
953
|
+
case 'isEagain':
|
|
954
|
+
return outcome(() => isEagainForTest(testCase.message));
|
|
955
|
+
case 'supportsGoldenBoot':
|
|
956
|
+
return outcome(() =>
|
|
957
|
+
smolmachinesSupportsGoldenBoot({
|
|
958
|
+
Machine: {
|
|
959
|
+
create: async () => undefined,
|
|
960
|
+
connect: async () => undefined,
|
|
961
|
+
...(testCase.supportsImageBoot === undefined
|
|
962
|
+
? {}
|
|
963
|
+
: { supportsImageBoot: testCase.supportsImageBoot }),
|
|
964
|
+
},
|
|
965
|
+
})
|
|
966
|
+
);
|
|
967
|
+
case 'supConsts':
|
|
968
|
+
return outcome(() => ({
|
|
969
|
+
vmSupervisorReadyPrefix,
|
|
970
|
+
guestDiagnosticsMarker,
|
|
971
|
+
...forkRetryConstsForTest,
|
|
972
|
+
}));
|
|
973
|
+
case 'dangerAssert':
|
|
974
|
+
return outcome(() => {
|
|
975
|
+
assertDangerFullAccess({
|
|
976
|
+
codexVersion: 'x',
|
|
977
|
+
input: [],
|
|
978
|
+
sandbox: testCase.sandbox,
|
|
979
|
+
approvalPolicy: testCase.approvalPolicy,
|
|
980
|
+
kandanUrl: 'https://scripted.example',
|
|
981
|
+
cwd: '/scripted',
|
|
982
|
+
appServerPort: 4500,
|
|
983
|
+
});
|
|
984
|
+
return 'ok';
|
|
985
|
+
});
|
|
986
|
+
case 'agentText':
|
|
987
|
+
return outcome(() => agentMessageTextFromParams(testCase.params));
|
|
988
|
+
case 'replyToolCall':
|
|
989
|
+
return outcome(() => isSuccessfulAgentReplyToolCall(testCase.params));
|
|
990
|
+
case 'benignDedupe':
|
|
991
|
+
return outcome(() => isBenignReplyDedupe(testCase.message));
|
|
992
|
+
case 'progressConsts':
|
|
993
|
+
return outcome(() => ({ ...guestTurnProgressConstsForTest }));
|
|
994
|
+
case 'scrubEnv':
|
|
995
|
+
return outcome(() => scrubSupervisorEnv(testCase.env));
|
|
996
|
+
case 'readyTimeout':
|
|
997
|
+
return outcome(() => readyTimeoutMsForTest(testCase.env));
|
|
998
|
+
case 'startConsts':
|
|
999
|
+
return outcome(() => ({ ...startVmConstsForTest }));
|
|
1000
|
+
case 'buildMcpConfig': {
|
|
1001
|
+
const dir = scratch();
|
|
1002
|
+
let bundlePath;
|
|
1003
|
+
if (testCase.bundle === 'absent') {
|
|
1004
|
+
bundlePath = join(dir, 'missing-mcp-server.mjs');
|
|
1005
|
+
} else {
|
|
1006
|
+
bundlePath = join(dir, 'mcp-server.mjs');
|
|
1007
|
+
writeFileSync(bundlePath, testCase.bundle);
|
|
1008
|
+
}
|
|
1009
|
+
const { outcome: result, warns } = withCapturedWarn(() =>
|
|
1010
|
+
buildVmLinzumiMcpConfig({
|
|
1011
|
+
cwd: dir,
|
|
1012
|
+
kandanThreadId: undefined,
|
|
1013
|
+
appServerOptions: {},
|
|
1014
|
+
llmProxyToken: undefined,
|
|
1015
|
+
linzumiMcp:
|
|
1016
|
+
testCase.mcp === null
|
|
1017
|
+
? undefined
|
|
1018
|
+
: {
|
|
1019
|
+
authFileContents: testCase.mcp.authFileContents,
|
|
1020
|
+
kandanUrl: testCase.mcp.kandanUrl,
|
|
1021
|
+
ownerUsername: testCase.mcp.ownerUsername ?? undefined,
|
|
1022
|
+
threadId: testCase.mcp.threadId ?? undefined,
|
|
1023
|
+
...(testCase.mcp.agentSession === undefined
|
|
1024
|
+
? {}
|
|
1025
|
+
: { agentSession: testCase.mcp.agentSession }),
|
|
1026
|
+
},
|
|
1027
|
+
mcpServerBundlePath: bundlePath,
|
|
1028
|
+
})
|
|
1029
|
+
);
|
|
1030
|
+
return substitute({ result, warns }, dir, dirPlaceholder);
|
|
1031
|
+
}
|
|
1032
|
+
// ---- cloud codecs ----------------------------------------------------------------------------------
|
|
1033
|
+
case 'redact':
|
|
1034
|
+
return outcome(() => redactCloudSecrets(testCase.text));
|
|
1035
|
+
case 'encodePath':
|
|
1036
|
+
return outcome(() => encodeCloudPath(testCase.path));
|
|
1037
|
+
case 'machineSource':
|
|
1038
|
+
return outcome(() => cloudMachineSource(testCase.image));
|
|
1039
|
+
case 'sse': {
|
|
1040
|
+
const chunks = testCase.chunks;
|
|
1041
|
+
const encoder = new TextEncoder();
|
|
1042
|
+
const stream = new ReadableStream({
|
|
1043
|
+
start(controller) {
|
|
1044
|
+
for (const chunk of chunks) {
|
|
1045
|
+
controller.enqueue(encoder.encode(chunk));
|
|
1046
|
+
}
|
|
1047
|
+
controller.close();
|
|
1048
|
+
},
|
|
1049
|
+
});
|
|
1050
|
+
const events = [];
|
|
1051
|
+
for await (const event of parseSseExecEvents(stream)) {
|
|
1052
|
+
events.push(event);
|
|
1053
|
+
}
|
|
1054
|
+
return { events };
|
|
1055
|
+
}
|
|
1056
|
+
case 'apiKey':
|
|
1057
|
+
return outcome(() =>
|
|
1058
|
+
resolveSmolcloudApiKey(testCase.env, testCase.config ?? undefined, (path) => {
|
|
1059
|
+
const scripted = (testCase.keyFiles ?? {})[path];
|
|
1060
|
+
if (scripted === undefined) {
|
|
1061
|
+
throw new Error('ENOENT: no scripted key file ' + path);
|
|
1062
|
+
}
|
|
1063
|
+
return scripted;
|
|
1064
|
+
})
|
|
1065
|
+
);
|
|
1066
|
+
case 'cloudEnabled': {
|
|
1067
|
+
const dir = scratch();
|
|
1068
|
+
const path = join(dir, 'vm.json');
|
|
1069
|
+
if (testCase.contents !== null) {
|
|
1070
|
+
writeFileSync(path, testCase.contents);
|
|
1071
|
+
}
|
|
1072
|
+
return outcome(() => vmCloudExecutionEnabled(testCase.env, path));
|
|
1073
|
+
}
|
|
1074
|
+
case 'agentDisabled':
|
|
1075
|
+
return outcome(() => vmCloudAgentExplicitlyDisabled(testCase.env));
|
|
1076
|
+
case 'agentEnabled': {
|
|
1077
|
+
const dir = scratch();
|
|
1078
|
+
const path = join(dir, 'vm.json');
|
|
1079
|
+
if (testCase.contents !== null) {
|
|
1080
|
+
writeFileSync(path, testCase.contents);
|
|
1081
|
+
}
|
|
1082
|
+
return outcome(() => vmCloudAgentExecutionEnabled(testCase.env, path));
|
|
1083
|
+
}
|
|
1084
|
+
case 'connection':
|
|
1085
|
+
return outcome(() => {
|
|
1086
|
+
const conn = resolveCloudConnection({
|
|
1087
|
+
env: testCase.env,
|
|
1088
|
+
config: testCase.config ?? undefined,
|
|
1089
|
+
});
|
|
1090
|
+
return conn === undefined
|
|
1091
|
+
? undefined
|
|
1092
|
+
: { baseUrl: conn.baseUrl, apiKey: conn.apiKey };
|
|
1093
|
+
});
|
|
1094
|
+
case 'cloudBackendConsts':
|
|
1095
|
+
return outcome(() => ({
|
|
1096
|
+
defaultBaseUrl: SMOLCLOUD_DEFAULT_BASE_URL,
|
|
1097
|
+
...cloudTimeoutConstsForTest,
|
|
1098
|
+
agentMachineNamePrefix: AGENT_MACHINE_NAME_PREFIX,
|
|
1099
|
+
defaultAgentAutoStopSeconds: DEFAULT_AGENT_AUTO_STOP_SECONDS,
|
|
1100
|
+
defaultAgentCpus: DEFAULT_AGENT_CPUS,
|
|
1101
|
+
defaultAgentMemoryMb: DEFAULT_AGENT_MEMORY_MB,
|
|
1102
|
+
defaultAgentDiskGb: DEFAULT_AGENT_DISK_GB,
|
|
1103
|
+
defaultMaxConcurrentTurns: DEFAULT_MAX_CONCURRENT_TURNS,
|
|
1104
|
+
}));
|
|
1105
|
+
case 'workspaceId':
|
|
1106
|
+
return outcome(() => {
|
|
1107
|
+
assertValidWorkspacePublicId(testCase.id);
|
|
1108
|
+
return 'ok';
|
|
1109
|
+
});
|
|
1110
|
+
case 'agentNames':
|
|
1111
|
+
return outcome(() => ({
|
|
1112
|
+
machine: agentMachineName(testCase.id),
|
|
1113
|
+
volume: agentVolumeName(testCase.id),
|
|
1114
|
+
}));
|
|
1115
|
+
case 'verifyAgent':
|
|
1116
|
+
return outcome(() => {
|
|
1117
|
+
verifyWorkspaceAgentMachine(testCase.info, testCase.id);
|
|
1118
|
+
return 'ok';
|
|
1119
|
+
});
|
|
1120
|
+
// ---- worktree ---------------------------------------------------------------------------------------
|
|
1121
|
+
case 'worktreeNames':
|
|
1122
|
+
return outcome(() => ({
|
|
1123
|
+
dirname: JOB_WORKTREES_DIRNAME,
|
|
1124
|
+
branch: jobBranchName(testCase.jobId),
|
|
1125
|
+
path: jobWorktreePath(testCase.repoToplevel, testCase.jobId),
|
|
1126
|
+
}));
|
|
1127
|
+
case 'worktreeMounts':
|
|
1128
|
+
return outcome(() => jobWorktreeMounts(testCase.prepared));
|
|
1129
|
+
case 'resolveToplevel': {
|
|
1130
|
+
const trace = [];
|
|
1131
|
+
const result = await outcomeAsync(() =>
|
|
1132
|
+
resolveRepoToplevel(testCase.cwd, scriptedGitRunner(testCase.git, trace))
|
|
1133
|
+
);
|
|
1134
|
+
return { result, trace };
|
|
1135
|
+
}
|
|
1136
|
+
case 'worktreePrepare': {
|
|
1137
|
+
const dir = scratch();
|
|
1138
|
+
mkdirSync(join(dir, 'repo'), { recursive: true });
|
|
1139
|
+
const trace = [];
|
|
1140
|
+
const script = JSON.parse(
|
|
1141
|
+
JSON.stringify(testCase.git).split(dirPlaceholder).join(dir)
|
|
1142
|
+
);
|
|
1143
|
+
const result = await outcomeAsync(() =>
|
|
1144
|
+
prepareJobWorktree(
|
|
1145
|
+
{
|
|
1146
|
+
repoCwd: substitute(testCase.repoCwd, dirPlaceholder, dir),
|
|
1147
|
+
jobId: testCase.jobId,
|
|
1148
|
+
...(testCase.ref === undefined ? {} : { ref: testCase.ref }),
|
|
1149
|
+
},
|
|
1150
|
+
scriptedGitRunner(script, trace)
|
|
1151
|
+
)
|
|
1152
|
+
);
|
|
1153
|
+
return substitute({ result, trace }, dir, dirPlaceholder);
|
|
1154
|
+
}
|
|
1155
|
+
case 'worktreeRemove': {
|
|
1156
|
+
const trace = [];
|
|
1157
|
+
const result = await outcomeAsync(() =>
|
|
1158
|
+
removeJobWorktree(
|
|
1159
|
+
{
|
|
1160
|
+
repoToplevel: testCase.repoToplevel,
|
|
1161
|
+
worktreePath: testCase.worktreePath,
|
|
1162
|
+
},
|
|
1163
|
+
scriptedGitRunner(testCase.git, trace)
|
|
1164
|
+
)
|
|
1165
|
+
);
|
|
1166
|
+
return { result, trace };
|
|
1167
|
+
}
|
|
1168
|
+
// ---- relay + cli --------------------------------------------------------------------------------------
|
|
1169
|
+
case 'relayScript':
|
|
1170
|
+
return outcome(() =>
|
|
1171
|
+
vmRelayScriptSource({
|
|
1172
|
+
bridgePort: testCase.bridgePort,
|
|
1173
|
+
token: testCase.token,
|
|
1174
|
+
guestTargetPort: testCase.guestTargetPort,
|
|
1175
|
+
})
|
|
1176
|
+
);
|
|
1177
|
+
case 'tunnelConsts':
|
|
1178
|
+
return outcome(() => ({ ...vmTunnelWireConstsForTest }));
|
|
1179
|
+
case 'vmHelp': {
|
|
1180
|
+
const dir = scratch();
|
|
1181
|
+
setCaseEnv({
|
|
1182
|
+
LINZUMI_VM_CONFIG_FILE: join(dir, 'vm.json'),
|
|
1183
|
+
LINZUMI_VM_RUNTIME_DIR: join(dir, 'rt'),
|
|
1184
|
+
SMOLCLOUD_API_KEY: testCase.agentKey ?? null,
|
|
1185
|
+
SMOL_CLOUD_TOKEN: null,
|
|
1186
|
+
LINZUMI_VM_CLOUD: null,
|
|
1187
|
+
LINZUMI_VM_CLOUD_AGENT: null,
|
|
1188
|
+
});
|
|
1189
|
+
try {
|
|
1190
|
+
return outcome(() => vmHelpText());
|
|
1191
|
+
} finally {
|
|
1192
|
+
restoreCaseEnv();
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
case 'vmDispatch': {
|
|
1196
|
+
const dir = scratch();
|
|
1197
|
+
setCaseEnv({
|
|
1198
|
+
LINZUMI_VM_CONFIG_FILE: join(dir, 'vm.json'),
|
|
1199
|
+
LINZUMI_VM_RUNTIME_DIR: join(dir, 'rt'),
|
|
1200
|
+
SMOLCLOUD_API_KEY: testCase.agentKey ?? null,
|
|
1201
|
+
SMOL_CLOUD_TOKEN: null,
|
|
1202
|
+
LINZUMI_VM_CLOUD: null,
|
|
1203
|
+
LINZUMI_VM_CLOUD_AGENT: null,
|
|
1204
|
+
});
|
|
1205
|
+
const writes = [];
|
|
1206
|
+
try {
|
|
1207
|
+
const result = await outcomeAsync(() =>
|
|
1208
|
+
runVmCommand(testCase.args, (line) => writes.push(line))
|
|
1209
|
+
);
|
|
1210
|
+
let stateBytes = null;
|
|
1211
|
+
try {
|
|
1212
|
+
stateBytes = readFileSync(join(dir, 'vm.json'), 'utf8');
|
|
1213
|
+
} catch {
|
|
1214
|
+
stateBytes = null;
|
|
1215
|
+
}
|
|
1216
|
+
return substitute({ result, writes, stateBytes }, dir, dirPlaceholder);
|
|
1217
|
+
} finally {
|
|
1218
|
+
restoreCaseEnv();
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
default:
|
|
1222
|
+
return { threw: true, message: 'unknown op ' + String(testCase.op) };
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
let stdin = '';
|
|
1227
|
+
process.stdin.setEncoding('utf8');
|
|
1228
|
+
for await (const chunk of process.stdin) {
|
|
1229
|
+
stdin += chunk;
|
|
1230
|
+
}
|
|
1231
|
+
const cases = JSON.parse(stdin);
|
|
1232
|
+
const results = [];
|
|
1233
|
+
for (const testCase of cases) {
|
|
1234
|
+
results.push(await handle(testCase));
|
|
1235
|
+
}
|
|
1236
|
+
process.stdout.write(JSON.stringify(results));
|
|
1237
|
+
`;
|
|
1238
|
+
|
|
1239
|
+
await mkdir(join(packageRoot, '.differential'), { recursive: true });
|
|
1240
|
+
|
|
1241
|
+
// Some transitive imports resolve assets/ relative to the bundle at import
|
|
1242
|
+
// time (the build-differential-entry.mjs requirement).
|
|
1243
|
+
await mkdir(join(packageRoot, '.differential/assets'), { recursive: true });
|
|
1244
|
+
const { copyFile } = await import('node:fs/promises');
|
|
1245
|
+
await copyFile(
|
|
1246
|
+
join(packageRoot, 'src/assets/linzumi-logo.svg'),
|
|
1247
|
+
join(packageRoot, '.differential/assets/linzumi-logo.svg')
|
|
1248
|
+
);
|
|
1249
|
+
|
|
1250
|
+
await build({
|
|
1251
|
+
stdin: {
|
|
1252
|
+
contents: driverSource,
|
|
1253
|
+
resolveDir: packageRoot,
|
|
1254
|
+
sourcefile: 'vm-sandbox-parity-driver.ts',
|
|
1255
|
+
loader: 'ts',
|
|
1256
|
+
},
|
|
1257
|
+
bundle: true,
|
|
1258
|
+
platform: 'node',
|
|
1259
|
+
target: 'node20',
|
|
1260
|
+
format: 'esm',
|
|
1261
|
+
outfile: join(packageRoot, '.differential/vm-sandbox-parity-oracle.mjs'),
|
|
1262
|
+
minify: false,
|
|
1263
|
+
sourcemap: false,
|
|
1264
|
+
legalComments: 'none',
|
|
1265
|
+
external: ['ws', 'undici', 'blessed', '@anthropic-ai/claude-agent-sdk'],
|
|
1266
|
+
});
|