@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.
Files changed (44) hide show
  1. package/README.md +1 -1
  2. package/dist/impl-res/cloud-supervisor.mjs +69 -69
  3. package/dist/impl-res/index.js +355 -314
  4. package/dist/impl-res/mcp-server.mjs +34 -34
  5. package/dist/impl-ts/cloud-supervisor.mjs +69 -69
  6. package/dist/impl-ts/index.js +495 -495
  7. package/dist/impl-ts/mcp-server.mjs +1 -1
  8. package/dist/mcp-server.mjs +1 -1
  9. package/package.json +3 -2
  10. package/scripts/check-package-size-budget.mjs +9 -0
  11. package/scripts/build-auth-parity-oracle.mjs +0 -709
  12. package/scripts/build-canonical-codex-transpiler-oracle.mjs +0 -93
  13. package/scripts/build-config-identity-parity-oracle.mjs +0 -526
  14. package/scripts/build-core-commander-seams-parity-oracle.mjs +0 -799
  15. package/scripts/build-core-daemon-parity-oracle.mjs +0 -573
  16. package/scripts/build-core-dispatch-input-queue-parity-oracle.mjs +0 -225
  17. package/scripts/build-core-fate-ladder-parity-oracle.mjs +0 -350
  18. package/scripts/build-core-generation-overlap-parity-oracle.mjs +0 -292
  19. package/scripts/build-core-integration-parity-oracle.mjs +0 -453
  20. package/scripts/build-core-lifecycle-guards-parity-oracle.mjs +0 -443
  21. package/scripts/build-core-lock-parity-oracle.mjs +0 -462
  22. package/scripts/build-core-reconnect-resume-parity-oracle.mjs +0 -365
  23. package/scripts/build-core-startup-resume-scan-parity-oracle.mjs +0 -296
  24. package/scripts/build-core-supervisor-parity-oracle.mjs +0 -781
  25. package/scripts/build-cross-harness-failover-oracle.mjs +0 -349
  26. package/scripts/build-editor-parity-oracle.mjs +0 -1525
  27. package/scripts/build-forwarding-parity-oracle.mjs +0 -1390
  28. package/scripts/build-harness-claude-parity-oracle.mjs +0 -407
  29. package/scripts/build-harness-codex-parity-oracle.mjs +0 -479
  30. package/scripts/build-mcp-parity-oracle.mjs +0 -412
  31. package/scripts/build-mcp-selector-parity-oracle.mjs +0 -65
  32. package/scripts/build-onboarding-discovery-parity-oracle.mjs +0 -388
  33. package/scripts/build-onboarding-flow-parity-oracle.mjs +0 -562
  34. package/scripts/build-onboarding-gateway-parity-oracle.mjs +0 -313
  35. package/scripts/build-onboarding-support-parity-oracle.mjs +0 -519
  36. package/scripts/build-pipeline-parity-oracle.mjs +0 -614
  37. package/scripts/build-protocol-parity-oracle.mjs +0 -398
  38. package/scripts/build-queue-parity-oracle.mjs +0 -1012
  39. package/scripts/build-session-registry-parity-oracle.mjs +0 -582
  40. package/scripts/build-transport-parity-oracle.mjs +0 -694
  41. package/scripts/build-tui-parity-oracle.mjs +0 -577
  42. package/scripts/build-vm-sandbox-parity-oracle.mjs +0 -1281
  43. package/scripts/build-worker-entry-parity-oracle.mjs +0 -424
  44. 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
- });