@linzumi/cli 1.0.272 → 1.0.274
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/impl-res/cloud-supervisor.mjs +69 -69
- package/dist/impl-res/index.js +355 -314
- package/dist/impl-res/mcp-server.mjs +34 -34
- package/dist/impl-ts/cloud-supervisor.mjs +69 -69
- package/dist/impl-ts/index.js +495 -495
- package/dist/impl-ts/mcp-server.mjs +1 -1
- package/dist/mcp-server.mjs +1 -1
- package/package.json +3 -2
- package/scripts/check-package-size-budget.mjs +9 -0
- package/scripts/build-auth-parity-oracle.mjs +0 -709
- package/scripts/build-canonical-codex-transpiler-oracle.mjs +0 -93
- package/scripts/build-config-identity-parity-oracle.mjs +0 -526
- package/scripts/build-core-commander-seams-parity-oracle.mjs +0 -799
- package/scripts/build-core-daemon-parity-oracle.mjs +0 -573
- package/scripts/build-core-dispatch-input-queue-parity-oracle.mjs +0 -225
- package/scripts/build-core-fate-ladder-parity-oracle.mjs +0 -350
- package/scripts/build-core-generation-overlap-parity-oracle.mjs +0 -292
- package/scripts/build-core-integration-parity-oracle.mjs +0 -453
- package/scripts/build-core-lifecycle-guards-parity-oracle.mjs +0 -443
- package/scripts/build-core-lock-parity-oracle.mjs +0 -462
- package/scripts/build-core-reconnect-resume-parity-oracle.mjs +0 -365
- package/scripts/build-core-startup-resume-scan-parity-oracle.mjs +0 -296
- package/scripts/build-core-supervisor-parity-oracle.mjs +0 -781
- package/scripts/build-cross-harness-failover-oracle.mjs +0 -349
- package/scripts/build-editor-parity-oracle.mjs +0 -1525
- package/scripts/build-forwarding-parity-oracle.mjs +0 -1390
- package/scripts/build-harness-claude-parity-oracle.mjs +0 -407
- package/scripts/build-harness-codex-parity-oracle.mjs +0 -479
- package/scripts/build-mcp-parity-oracle.mjs +0 -412
- package/scripts/build-mcp-selector-parity-oracle.mjs +0 -65
- package/scripts/build-onboarding-discovery-parity-oracle.mjs +0 -388
- package/scripts/build-onboarding-flow-parity-oracle.mjs +0 -562
- package/scripts/build-onboarding-gateway-parity-oracle.mjs +0 -313
- package/scripts/build-onboarding-support-parity-oracle.mjs +0 -519
- package/scripts/build-pipeline-parity-oracle.mjs +0 -614
- package/scripts/build-protocol-parity-oracle.mjs +0 -398
- package/scripts/build-queue-parity-oracle.mjs +0 -1012
- package/scripts/build-session-registry-parity-oracle.mjs +0 -582
- package/scripts/build-transport-parity-oracle.mjs +0 -694
- package/scripts/build-tui-parity-oracle.mjs +0 -577
- package/scripts/build-vm-sandbox-parity-oracle.mjs +0 -1281
- package/scripts/build-worker-entry-parity-oracle.mjs +0 -424
- package/scripts/build-worker-spawn-parity-oracle.mjs +0 -823
|
@@ -1,462 +0,0 @@
|
|
|
1
|
-
// Spec: kandan/plans/2026-07-10-compute-nodes-rescript-commander-zero-ts-program.md
|
|
2
|
-
// (M3 cluster 10, runner core - the workspace lock + operator takeover flow).
|
|
3
|
-
// Relationship: Builds the TS-side PARITY ORACLE for the commander
|
|
4
|
-
// workspace-lock port, the sibling of build-config-identity-parity-oracle.mjs
|
|
5
|
-
// (cluster 2). The oracle bundles the REAL runnerLock.ts +
|
|
6
|
-
// runnerLockTakeover.ts behind a one-shot batch driver: a JSON array of cases
|
|
7
|
-
// on stdin, a JSON array of results on stdout. The ReScript package's
|
|
8
|
-
// CoreLockParityConformance drives the SAME inputs through
|
|
9
|
-
// src/core/CommanderLock.res / CommanderLockTakeover.res in its own scratch
|
|
10
|
-
// directories and asserts accept/reject/value equivalence, pinned contract
|
|
11
|
-
// error strings, log/prompt/signal trace parity AND byte-identical lock-file
|
|
12
|
-
// trees - the cross-impl contract that lets both commanders share the
|
|
13
|
-
// ~/.linzumi/runners locks through M4.
|
|
14
|
-
//
|
|
15
|
-
// Determinism: every source of nondeterminism is pinned per case - the clock
|
|
16
|
-
// is a scripted per-case cell read through the injected `now`, pid liveness
|
|
17
|
-
// is a scripted set, SIGKILL/SIGTERM outcomes are scripted (per-pid /
|
|
18
|
-
// per-signal failure codes), prompts are scripted answer queues, and the
|
|
19
|
-
// takeover waits run on a virtual clock advanced by the injected `sleep`.
|
|
20
|
-
// Scratch paths are normalized through the "$DIR" placeholder in both
|
|
21
|
-
// directions.
|
|
22
|
-
//
|
|
23
|
-
// Like the sibling oracles, the output is a local test artifact
|
|
24
|
-
// (.differential/ is gitignored, never published) and stays unminified for
|
|
25
|
-
// debuggability.
|
|
26
|
-
import { mkdir } from 'node:fs/promises';
|
|
27
|
-
import { dirname, join } from 'node:path';
|
|
28
|
-
import { fileURLToPath } from 'node:url';
|
|
29
|
-
import { build } from 'esbuild';
|
|
30
|
-
|
|
31
|
-
const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
32
|
-
|
|
33
|
-
const driverSource = `
|
|
34
|
-
import {
|
|
35
|
-
mkdtempSync,
|
|
36
|
-
mkdirSync,
|
|
37
|
-
readdirSync,
|
|
38
|
-
readFileSync,
|
|
39
|
-
realpathSync,
|
|
40
|
-
statSync,
|
|
41
|
-
unlinkSync,
|
|
42
|
-
writeFileSync,
|
|
43
|
-
} from 'node:fs';
|
|
44
|
-
import { tmpdir } from 'node:os';
|
|
45
|
-
import { join, relative } from 'node:path';
|
|
46
|
-
import {
|
|
47
|
-
acquireIncomingGenerationRunnerLock,
|
|
48
|
-
acquireRunnerLock,
|
|
49
|
-
assessRunnerLockHolder,
|
|
50
|
-
compareCliVersions,
|
|
51
|
-
electronAutoConnectLaunchSource,
|
|
52
|
-
incomingGenerationRunnerLockPath,
|
|
53
|
-
readRunnerLockOwner,
|
|
54
|
-
RunnerLockHeldError,
|
|
55
|
-
runnerLockHeartbeatIntervalMs,
|
|
56
|
-
runnerLockHeldErrorName,
|
|
57
|
-
runnerLockPath,
|
|
58
|
-
runnerLockTakeoverAfterMs,
|
|
59
|
-
shouldAutoTakeOverForUpdate,
|
|
60
|
-
} from './src/runnerLock';
|
|
61
|
-
import {
|
|
62
|
-
isRunnerLockConflictReportedError,
|
|
63
|
-
resolveRunnerLockConflict,
|
|
64
|
-
RunnerLockConflictReportedError,
|
|
65
|
-
runnerLockConflictReport,
|
|
66
|
-
runnerLockConflictReportedErrorName,
|
|
67
|
-
runnerLockTakeoverForcefulStopMs,
|
|
68
|
-
runnerLockTakeoverGracefulStopMs,
|
|
69
|
-
runnerLockTakeoverPollMs,
|
|
70
|
-
runnerLockTakeoverSleep,
|
|
71
|
-
shouldResolveRunnerLockConflict,
|
|
72
|
-
} from './src/runnerLockTakeover';
|
|
73
|
-
|
|
74
|
-
// --- Placeholder + snapshot plumbing --------------------------------------------
|
|
75
|
-
|
|
76
|
-
const dirPlaceholder = '$DIR';
|
|
77
|
-
|
|
78
|
-
function scratch() {
|
|
79
|
-
// realpath so macOS /var -> /private/var never splits the two impls'
|
|
80
|
-
// placeholder substitution.
|
|
81
|
-
return realpathSync(mkdtempSync(join(tmpdir(), 'linzumi-core-lock-oracle-')));
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function substitute(value, from, to) {
|
|
85
|
-
if (typeof value === 'string') {
|
|
86
|
-
return value.split(from).join(to);
|
|
87
|
-
}
|
|
88
|
-
if (Array.isArray(value)) {
|
|
89
|
-
return value.map((entry) => substitute(entry, from, to));
|
|
90
|
-
}
|
|
91
|
-
if (typeof value === 'object' && value !== null) {
|
|
92
|
-
return Object.fromEntries(
|
|
93
|
-
Object.entries(value).map(([key, entry]) => [
|
|
94
|
-
substitute(key, from, to),
|
|
95
|
-
substitute(entry, from, to),
|
|
96
|
-
])
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
return value;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function snapshotFiles(dir) {
|
|
103
|
-
const files = {};
|
|
104
|
-
const walk = (current) => {
|
|
105
|
-
for (const name of readdirSync(current).sort()) {
|
|
106
|
-
const full = join(current, name);
|
|
107
|
-
if (statSync(full).isDirectory()) {
|
|
108
|
-
walk(full);
|
|
109
|
-
} else {
|
|
110
|
-
files[relative(dir, full)] = readFileSync(full, 'utf8');
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
walk(dir);
|
|
115
|
-
return files;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function outcome(run) {
|
|
119
|
-
try {
|
|
120
|
-
const value = run();
|
|
121
|
-
return value === undefined ? { defined: false } : { defined: true, value };
|
|
122
|
-
} catch (error) {
|
|
123
|
-
return {
|
|
124
|
-
threw: true,
|
|
125
|
-
name: error instanceof Error ? error.name : 'Error',
|
|
126
|
-
message: error instanceof Error ? error.message : String(error),
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// --- Pure surfaces ----------------------------------------------------------------
|
|
132
|
-
|
|
133
|
-
function handleLockPath(testCase) {
|
|
134
|
-
const dir = scratch();
|
|
135
|
-
const configPath = join(dir, 'config.json');
|
|
136
|
-
const result = outcome(() =>
|
|
137
|
-
runnerLockPath(testCase.machineId, configPath, testCase.linzumiUrl)
|
|
138
|
-
);
|
|
139
|
-
return substitute(result, dir, dirPlaceholder);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function handleAssessHolder(testCase) {
|
|
143
|
-
const alive = new Set(testCase.alivePids ?? []);
|
|
144
|
-
return outcome(() =>
|
|
145
|
-
assessRunnerLockHolder(
|
|
146
|
-
testCase.record,
|
|
147
|
-
(pid) => alive.has(pid),
|
|
148
|
-
() => new Date(testCase.nowMs)
|
|
149
|
-
)
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function handleShouldAutoTakeOver(testCase) {
|
|
154
|
-
return outcome(() =>
|
|
155
|
-
shouldAutoTakeOverForUpdate(
|
|
156
|
-
testCase.existing,
|
|
157
|
-
testCase.myVersion,
|
|
158
|
-
testCase.myLaunchSource,
|
|
159
|
-
testCase.holderState
|
|
160
|
-
)
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function handleHeldMessage(testCase) {
|
|
165
|
-
return outcome(() => {
|
|
166
|
-
const error = new RunnerLockHeldError(testCase.lockPath, testCase.record);
|
|
167
|
-
return { name: error.name, message: error.message };
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
async function handleConstants() {
|
|
172
|
-
await runnerLockTakeoverSleep(0);
|
|
173
|
-
const reported = new RunnerLockConflictReportedError();
|
|
174
|
-
return {
|
|
175
|
-
heartbeatIntervalMs: runnerLockHeartbeatIntervalMs,
|
|
176
|
-
takeoverAfterMs: runnerLockTakeoverAfterMs,
|
|
177
|
-
heldErrorName: runnerLockHeldErrorName,
|
|
178
|
-
electronAutoConnectLaunchSource,
|
|
179
|
-
gracefulStopMs: runnerLockTakeoverGracefulStopMs,
|
|
180
|
-
forcefulStopMs: runnerLockTakeoverForcefulStopMs,
|
|
181
|
-
pollMs: runnerLockTakeoverPollMs,
|
|
182
|
-
conflictReportedErrorName: runnerLockConflictReportedErrorName,
|
|
183
|
-
conflictReportedError: {
|
|
184
|
-
name: reported.name,
|
|
185
|
-
message: reported.message,
|
|
186
|
-
guard: isRunnerLockConflictReportedError(reported),
|
|
187
|
-
},
|
|
188
|
-
sleepResolved: true,
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// --- Lock lifecycle ------------------------------------------------------------------
|
|
193
|
-
|
|
194
|
-
function handleLockLifecycle(testCase) {
|
|
195
|
-
const dir = scratch();
|
|
196
|
-
const configPath = join(dir, 'config.json');
|
|
197
|
-
const actions = substitute(testCase.actions ?? [], dirPlaceholder, dir);
|
|
198
|
-
const killFailures = testCase.killFailures ?? {};
|
|
199
|
-
let clockMs = 0;
|
|
200
|
-
const alive = new Set();
|
|
201
|
-
const events = [];
|
|
202
|
-
const handles = new Map();
|
|
203
|
-
const now = () => new Date(clockMs);
|
|
204
|
-
const isPidAlive = (pid) => alive.has(pid);
|
|
205
|
-
const killPid = (pid) => {
|
|
206
|
-
events.push({ type: 'kill', pid });
|
|
207
|
-
const code = killFailures[String(pid)];
|
|
208
|
-
if (code !== undefined) {
|
|
209
|
-
const error = new Error(code);
|
|
210
|
-
error.code = code;
|
|
211
|
-
throw error;
|
|
212
|
-
}
|
|
213
|
-
alive.delete(pid);
|
|
214
|
-
};
|
|
215
|
-
const onTakeover = (takeover) => {
|
|
216
|
-
events.push({
|
|
217
|
-
type: 'takeover',
|
|
218
|
-
lockPath: takeover.lockPath,
|
|
219
|
-
holderPid: takeover.holderPid,
|
|
220
|
-
holderRunnerId: takeover.holderRunnerId,
|
|
221
|
-
reason: takeover.reason,
|
|
222
|
-
});
|
|
223
|
-
};
|
|
224
|
-
const runSetup = (setup) => {
|
|
225
|
-
for (const sub of setup ?? []) {
|
|
226
|
-
runAction(sub);
|
|
227
|
-
}
|
|
228
|
-
};
|
|
229
|
-
const acquireOptions = (action) => ({
|
|
230
|
-
machineId: action.machineId,
|
|
231
|
-
runnerId: action.runnerId,
|
|
232
|
-
cwd: action.cwd,
|
|
233
|
-
workspace: action.workspace ?? null,
|
|
234
|
-
...(action.linzumiUrl === undefined ? {} : { linzumiUrl: action.linzumiUrl }),
|
|
235
|
-
configPath,
|
|
236
|
-
pid: action.pid,
|
|
237
|
-
...(action.launchSource === undefined ? {} : { launchSource: action.launchSource }),
|
|
238
|
-
...(action.processGroupLeader === undefined
|
|
239
|
-
? {}
|
|
240
|
-
: { processGroupLeader: action.processGroupLeader }),
|
|
241
|
-
now,
|
|
242
|
-
isPidAlive,
|
|
243
|
-
cliVersion: action.cliVersion,
|
|
244
|
-
...(action.gracefulUpdateDrain === undefined
|
|
245
|
-
? {}
|
|
246
|
-
: { gracefulUpdateDrain: action.gracefulUpdateDrain }),
|
|
247
|
-
killPid,
|
|
248
|
-
onTakeover,
|
|
249
|
-
...(action.beforeReadExistingLock === undefined
|
|
250
|
-
? {}
|
|
251
|
-
: { beforeReadExistingLock: () => runSetup(action.beforeReadExistingLock) }),
|
|
252
|
-
...(action.beforeReplaceStaleLock === undefined
|
|
253
|
-
? {}
|
|
254
|
-
: { beforeReplaceStaleLock: () => runSetup(action.beforeReplaceStaleLock) }),
|
|
255
|
-
});
|
|
256
|
-
const runAction = (action) => {
|
|
257
|
-
switch (action.act) {
|
|
258
|
-
case 'setClock':
|
|
259
|
-
return outcome(() => {
|
|
260
|
-
clockMs = action.ms;
|
|
261
|
-
});
|
|
262
|
-
case 'setAlive':
|
|
263
|
-
return outcome(() => {
|
|
264
|
-
alive.clear();
|
|
265
|
-
for (const pid of action.pids) {
|
|
266
|
-
alive.add(pid);
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
case 'mkdir':
|
|
270
|
-
return outcome(() => {
|
|
271
|
-
mkdirSync(action.path, { recursive: true });
|
|
272
|
-
});
|
|
273
|
-
case 'writeFile':
|
|
274
|
-
return outcome(() => writeFileSync(action.path, action.contents, 'utf8'));
|
|
275
|
-
case 'unlink':
|
|
276
|
-
return outcome(() => unlinkSync(action.path));
|
|
277
|
-
case 'acquire':
|
|
278
|
-
return outcome(() => {
|
|
279
|
-
const handle = acquireRunnerLock(acquireOptions(action));
|
|
280
|
-
handles.set(action.id, handle);
|
|
281
|
-
return { path: handle.path };
|
|
282
|
-
});
|
|
283
|
-
case 'acquireIncoming':
|
|
284
|
-
return outcome(() => {
|
|
285
|
-
const handle = acquireIncomingGenerationRunnerLock({
|
|
286
|
-
...acquireOptions(action),
|
|
287
|
-
handoffHolderPid: action.handoffHolderPid,
|
|
288
|
-
});
|
|
289
|
-
handles.set(action.id, handle);
|
|
290
|
-
return { path: handle.path, promoted: handle.promoted() };
|
|
291
|
-
});
|
|
292
|
-
case 'heartbeat':
|
|
293
|
-
return outcome(() => handles.get(action.id).heartbeat());
|
|
294
|
-
case 'release':
|
|
295
|
-
return outcome(() => handles.get(action.id).release());
|
|
296
|
-
case 'promote':
|
|
297
|
-
return outcome(() => handles.get(action.id).promote());
|
|
298
|
-
case 'promoted':
|
|
299
|
-
return outcome(() => handles.get(action.id).promoted());
|
|
300
|
-
case 'handlePath':
|
|
301
|
-
return outcome(() => handles.get(action.id).path);
|
|
302
|
-
case 'readOwner':
|
|
303
|
-
return outcome(() => readRunnerLockOwner(action.path));
|
|
304
|
-
default:
|
|
305
|
-
return { threw: true, name: 'Error', message: 'unknown lock action ' + String(action.act) };
|
|
306
|
-
}
|
|
307
|
-
};
|
|
308
|
-
const results = actions.map((action) => runAction(action));
|
|
309
|
-
return substitute(
|
|
310
|
-
{ results, files: snapshotFiles(dir), events },
|
|
311
|
-
dir,
|
|
312
|
-
dirPlaceholder
|
|
313
|
-
);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// --- Takeover flow ----------------------------------------------------------------------
|
|
317
|
-
|
|
318
|
-
async function handleTakeoverFlow(testCase) {
|
|
319
|
-
const holder = testCase.holder;
|
|
320
|
-
const schedule = testCase.schedule ?? {};
|
|
321
|
-
let virtualMs = schedule.startMs ?? 0;
|
|
322
|
-
const sleeps = [];
|
|
323
|
-
const signals = [];
|
|
324
|
-
const reports = [];
|
|
325
|
-
const questions = [];
|
|
326
|
-
const logs = [];
|
|
327
|
-
const answers = [...(testCase.promptAnswers ?? [])];
|
|
328
|
-
const signalFailures = testCase.signalFailures ?? {};
|
|
329
|
-
const lockReleased = () =>
|
|
330
|
-
schedule.lockReleasedAtMs !== undefined && virtualMs >= schedule.lockReleasedAtMs;
|
|
331
|
-
const deps = {
|
|
332
|
-
isPidAlive: (pid) =>
|
|
333
|
-
pid < 0 && schedule.groupDeadAtMs !== undefined
|
|
334
|
-
? virtualMs < schedule.groupDeadAtMs
|
|
335
|
-
: schedule.pidDeadAtMs === undefined
|
|
336
|
-
? true
|
|
337
|
-
: virtualMs < schedule.pidDeadAtMs,
|
|
338
|
-
signalPid: (pid, signal) => {
|
|
339
|
-
signals.push({ pid, signal, atMs: virtualMs });
|
|
340
|
-
const code = signalFailures[signal];
|
|
341
|
-
if (code !== undefined) {
|
|
342
|
-
const error = new Error('scripted ' + signal + ' failure');
|
|
343
|
-
error.code = code;
|
|
344
|
-
throw error;
|
|
345
|
-
}
|
|
346
|
-
},
|
|
347
|
-
lockReleased,
|
|
348
|
-
currentLockOwner: () => {
|
|
349
|
-
if (schedule.ownerChange !== undefined && virtualMs >= schedule.ownerChange.atMs) {
|
|
350
|
-
return schedule.ownerChange.owner === null ? undefined : schedule.ownerChange.owner;
|
|
351
|
-
}
|
|
352
|
-
return holder;
|
|
353
|
-
},
|
|
354
|
-
sleep: (ms) => {
|
|
355
|
-
sleeps.push(ms);
|
|
356
|
-
virtualMs += ms;
|
|
357
|
-
return Promise.resolve();
|
|
358
|
-
},
|
|
359
|
-
now: () => virtualMs,
|
|
360
|
-
log: (event, payload) => {
|
|
361
|
-
logs.push({ event, payload });
|
|
362
|
-
},
|
|
363
|
-
};
|
|
364
|
-
const prompt = {
|
|
365
|
-
isInteractive: () => testCase.interactive === true,
|
|
366
|
-
writeReport: (text) => {
|
|
367
|
-
reports.push(text);
|
|
368
|
-
},
|
|
369
|
-
promptYesNo: (question) => {
|
|
370
|
-
questions.push(question);
|
|
371
|
-
return Promise.resolve(answers.length > 0 ? answers.shift() === true : false);
|
|
372
|
-
},
|
|
373
|
-
};
|
|
374
|
-
let result;
|
|
375
|
-
try {
|
|
376
|
-
const value = await resolveRunnerLockConflict({
|
|
377
|
-
holder,
|
|
378
|
-
lockPath: testCase.lockPath,
|
|
379
|
-
baseMessage: testCase.baseMessage,
|
|
380
|
-
takeOverWithoutPrompt: testCase.takeOverWithoutPrompt === true,
|
|
381
|
-
prompt,
|
|
382
|
-
takeover: deps,
|
|
383
|
-
});
|
|
384
|
-
result = { defined: true, value };
|
|
385
|
-
} catch (error) {
|
|
386
|
-
result = {
|
|
387
|
-
threw: true,
|
|
388
|
-
name: error instanceof Error ? error.name : 'Error',
|
|
389
|
-
message: error instanceof Error ? error.message : String(error),
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
return { outcome: result, sleeps, signals, reports, questions, logs, endMs: virtualMs };
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
// --- Dispatch --------------------------------------------------------------------------------
|
|
396
|
-
|
|
397
|
-
async function handle(testCase) {
|
|
398
|
-
switch (testCase.op) {
|
|
399
|
-
case 'constants':
|
|
400
|
-
return await handleConstants();
|
|
401
|
-
case 'lockPath':
|
|
402
|
-
return handleLockPath(testCase);
|
|
403
|
-
case 'incomingPath':
|
|
404
|
-
return outcome(() => incomingGenerationRunnerLockPath(testCase.primaryPath));
|
|
405
|
-
case 'compareVersions':
|
|
406
|
-
return outcome(() => compareCliVersions(testCase.a, testCase.b));
|
|
407
|
-
case 'assessHolder':
|
|
408
|
-
return handleAssessHolder(testCase);
|
|
409
|
-
case 'shouldAutoTakeOver':
|
|
410
|
-
return handleShouldAutoTakeOver(testCase);
|
|
411
|
-
case 'heldMessage':
|
|
412
|
-
return handleHeldMessage(testCase);
|
|
413
|
-
case 'conflictReport':
|
|
414
|
-
return outcome(() => runnerLockConflictReport(testCase.baseMessage));
|
|
415
|
-
case 'shouldResolve':
|
|
416
|
-
return outcome(() =>
|
|
417
|
-
shouldResolveRunnerLockConflict(testCase.defined === true ? {} : undefined)
|
|
418
|
-
);
|
|
419
|
-
case 'lockLifecycle':
|
|
420
|
-
return handleLockLifecycle(testCase);
|
|
421
|
-
case 'takeoverFlow':
|
|
422
|
-
return await handleTakeoverFlow(testCase);
|
|
423
|
-
default:
|
|
424
|
-
return { threw: true, name: 'Error', message: 'unknown op ' + String(testCase.op) };
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
let stdin = '';
|
|
429
|
-
process.stdin.setEncoding('utf8');
|
|
430
|
-
for await (const chunk of process.stdin) {
|
|
431
|
-
stdin += chunk;
|
|
432
|
-
}
|
|
433
|
-
const cases = JSON.parse(stdin);
|
|
434
|
-
const results = [];
|
|
435
|
-
for (const testCase of cases) {
|
|
436
|
-
results.push(await handle(testCase));
|
|
437
|
-
}
|
|
438
|
-
process.stdout.write(JSON.stringify(results));
|
|
439
|
-
`;
|
|
440
|
-
|
|
441
|
-
await mkdir(join(packageRoot, '.differential'), { recursive: true });
|
|
442
|
-
|
|
443
|
-
await build({
|
|
444
|
-
stdin: {
|
|
445
|
-
contents: driverSource,
|
|
446
|
-
resolveDir: packageRoot,
|
|
447
|
-
sourcefile: 'core-lock-parity-driver.ts',
|
|
448
|
-
loader: 'ts',
|
|
449
|
-
},
|
|
450
|
-
bundle: true,
|
|
451
|
-
platform: 'node',
|
|
452
|
-
target: 'node20',
|
|
453
|
-
format: 'esm',
|
|
454
|
-
outfile: join(packageRoot, '.differential/core-lock-parity-oracle.mjs'),
|
|
455
|
-
minify: false,
|
|
456
|
-
sourcemap: false,
|
|
457
|
-
legalComments: 'none',
|
|
458
|
-
// runnerLock.ts pulls localConfig/oauth; the same runtime externals as the
|
|
459
|
-
// sibling oracle builds stay external (installed in this package's
|
|
460
|
-
// node_modules; the oracle only exercises the lock/takeover exports).
|
|
461
|
-
external: ['ws', 'undici', 'blessed', '@anthropic-ai/claude-agent-sdk'],
|
|
462
|
-
});
|