@linzumi/cli 1.0.93 → 1.0.94
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 +1 -1
- package/package.json +1 -1
- package/scripts/build-protocol-parity-oracle.mjs +192 -0
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -1470,7 +1470,7 @@ To kick the agent off:
|
|
|
1470
1470
|
`,j=Buffer.byteLength(P,"utf8");if(j>s)return l("runner_diagnostics.spool_entry_dropped",{reason:"entry_too_large",entry_bytes:j,max_entry_bytes:s}),!1;Ove(n,{recursive:!0}),m(u)+j>i&&f(),_(j);let E=v()?`
|
|
1471
1471
|
`:"";return Dve(u,`${E}${P}`,"utf8"),!0}catch(I){return l("runner_diagnostics.spool_failed",{error:I instanceof Error?I.message:String(I)}),!1}},b=S=>{let I=[],P=jve(S,"utf8");for(let j of P.split(`
|
|
1472
1472
|
`))if(j.trim()!=="")try{let E=JSON.parse(j);E!==null&&typeof E=="object"&&I.push({parsed:E,raw:j})}catch{}return I};return{append:k,drain:async S=>{if(c)return{uploadedBatches:0,uploadedEntries:0,remainingBatches:p().length,skipped:!0};c=!0;let I=0,P=0;try{f(),_(0);let j=a()-o;for(let E of p()){let L;try{L=b(E)}catch(Q){l("runner_diagnostics.spool_batch_unreadable",{file:E,error:Q instanceof Error?Q.message:String(Q)}),y(E,"unreadable");continue}let N=L.filter(Q=>{let ge=Yve(Q.parsed);return ge===void 0||ge>=j});if(N.length===0){y(E,"empty_or_expired");continue}let M=UT(E,".jsonl"),B=N.map(Q=>Q.raw).join(`
|
|
1473
|
-
`),J=N.map(Q=>Q.parsed.spooled_at).filter(Q=>typeof Q=="string"),G={bundle_name:"runner-diagnostics-spool",exported_at:new Date(a()).toISOString(),idempotency_key:M,diagnostics:{kind:"runner_diagnostic_log",spool_batch:!0,idempotency_key:M,entry_count:N.length,...J.length===0?{}:{first_spooled_at:J[0],last_spooled_at:J[J.length-1]}},telemetry_ndjson:B};try{await S(G)}catch(Q){l("runner_diagnostics.spool_upload_failed",{file:E,remaining_batches:p().length,error:Q instanceof Error?Q.message:String(Q)});break}I+=1,P+=N.length;try{JU(E)}catch(Q){l("runner_diagnostics.spool_delete_failed",{file:E,error:Q instanceof Error?Q.message:String(Q)})}}}catch(j){l("runner_diagnostics.spool_drain_failed",{error:j instanceof Error?j.message:String(j)})}finally{c=!1}return{uploadedBatches:I,uploadedEntries:P,remainingBatches:p().length,skipped:!1}},pendingBatchFiles:p}}var Uve,Bve,Jve,Kve,Vve,KU,Hve,Gve,WU=F(()=>{"use strict";Uy();Uve=32*1024*1024,Bve=10080*60*1e3,Jve=4*1024*1024,Kve=1024*1024,Vve="spool.jsonl",KU=/^batch-(\d{1,16})-[0-9a-f-]+\.jsonl$/;Hve=/\b([A-Z][A-Z0-9_]{1,})=("[^"\n]*"|'[^'\n]*'|[^\s"'`;,)\]}]+)/g,Gve=/(?:\/(?:[A-Za-z0-9._@~+-]|%[0-9A-Fa-f]{2})+){2,}/g});var Lt,JT,Xs=F(()=>{"use strict";Lt="1.0.
|
|
1473
|
+
`),J=N.map(Q=>Q.parsed.spooled_at).filter(Q=>typeof Q=="string"),G={bundle_name:"runner-diagnostics-spool",exported_at:new Date(a()).toISOString(),idempotency_key:M,diagnostics:{kind:"runner_diagnostic_log",spool_batch:!0,idempotency_key:M,entry_count:N.length,...J.length===0?{}:{first_spooled_at:J[0],last_spooled_at:J[J.length-1]}},telemetry_ndjson:B};try{await S(G)}catch(Q){l("runner_diagnostics.spool_upload_failed",{file:E,remaining_batches:p().length,error:Q instanceof Error?Q.message:String(Q)});break}I+=1,P+=N.length;try{JU(E)}catch(Q){l("runner_diagnostics.spool_delete_failed",{file:E,error:Q instanceof Error?Q.message:String(Q)})}}}catch(j){l("runner_diagnostics.spool_drain_failed",{error:j instanceof Error?j.message:String(j)})}finally{c=!1}return{uploadedBatches:I,uploadedEntries:P,remainingBatches:p().length,skipped:!1}},pendingBatchFiles:p}}var Uve,Bve,Jve,Kve,Vve,KU,Hve,Gve,WU=F(()=>{"use strict";Uy();Uve=32*1024*1024,Bve=10080*60*1e3,Jve=4*1024*1024,Kve=1024*1024,Vve="spool.jsonl",KU=/^batch-(\d{1,16})-[0-9a-f-]+\.jsonl$/;Hve=/\b([A-Z][A-Z0-9_]{1,})=("[^"\n]*"|'[^'\n]*'|[^\s"'`;,)\]}]+)/g,Gve=/(?:\/(?:[A-Za-z0-9._@~+-]|%[0-9A-Fa-f]{2})+){2,}/g});var Lt,JT,Xs=F(()=>{"use strict";Lt="1.0.94",JT=`linzumi ${Lt}`});import{closeSync as GU,existsSync as VT,mkdirSync as eSe,openSync as ZU,readFileSync as QU,renameSync as nSe,unlinkSync as fd,writeFileSync as tSe,writeSync as XU}from"node:fs";import{dirname as YU,join as rSe}from"node:path";function WT(e){return e instanceof ls||e instanceof Error&&e.name===n9&&"lockPath"in e&&"heldBy"in e}function HT(e,n=Vn(),t){let r=t===void 0?encodeURIComponent(e):sd(t);return rSe(YU(n),"runners",`${r}.lock`)}function Xx(e){let n=HT(e.machineId,e.configPath,e.linzumiUrl),t=e.isPidAlive??d9,r=e.now??(()=>new Date),o=e.killPid??gSe,i=r().toISOString(),s={version:1,machineId:e.machineId,runnerId:e.runnerId,pid:e.pid??process.pid,cwd:e.cwd,workspace:e.workspace,...e.linzumiUrl===void 0?{}:{linzumiUrl:Fn(e.linzumiUrl)},...e.launchSource===void 0?{}:{launchSource:e.launchSource},startedAt:i,heartbeatAt:i,cliVersion:e.cliVersion??Lt,...e.gracefulUpdateDrain===!0?{gracefulUpdateDrain:!0}:{}};aSe(e.machineId,e.configPath,e.linzumiUrl,t,r,o,e.onTakeover),dSe(n,s,t,r,o,e.onTakeover,e.beforeReadExistingLock,e.beforeReplaceStaleLock);let a=()=>t9(n,s,r),d=setInterval(a,e9);return d.unref(),{path:n,record:s,heartbeat:a,release:()=>{clearInterval(d),s9(n,s)}}}function t9(e,n,t){try{let r=e0(e);if(r===void 0||r.machineId!==n.machineId||r.runnerId!==n.runnerId||r.pid!==n.pid||r.startedAt!==n.startedAt)return;let o={...r,heartbeatAt:t().toISOString()},i=`${e}.tmp`;tSe(i,`${JSON.stringify(o,null,2)}
|
|
1474
1474
|
`,"utf8"),nSe(i,e)}catch{}}function md(e,n,t){if(!n(e.pid))return{state:"dead"};let r=e.heartbeatAt??e.startedAt,o=Date.parse(r);return Number.isNaN(o)||t().getTime()-o>oSe?{state:"wedged",reason:e.heartbeatAt===void 0?"missing_heartbeat":"stale_heartbeat"}:{state:"live"}}function r9(e,n,t,r){return t!==Yx||e.launchSource!==Yx?!1:r.state!=="live"?!0:iSe(n,e.cliVersion)>0}function iSe(e,n){let t=HU(e),r=HU(n);for(let o=0;o<3;o++){let i=t.core[o],s=r.core[o];if(i===void 0||s===void 0)throw new Error(`compareCliVersions: unexpected undefined at core index ${o}`);if(i!==s)return i>s?1:-1}return t.prerelease.length===0&&r.prerelease.length===0?0:t.prerelease.length===0?1:r.prerelease.length===0?-1:sSe(t.prerelease,r.prerelease)}function HU(e){let n=e.trim().replace(/^v/i,"").split("+",1)[0]??"",t=n.indexOf("-"),r=t===-1?n:n.slice(0,t),o=t===-1?"":n.slice(t+1),i=r.split("."),s=[KT(i[0]),KT(i[1]),KT(i[2])],a=o===""?[]:o.split(".").filter(d=>d!=="");return{core:s,prerelease:a}}function KT(e){let n=Number.parseInt(e??"",10);return Number.isInteger(n)&&n>=0?n:0}function sSe(e,n){let t=Math.max(e.length,n.length);for(let r=0;r<t;r++){let o=e[r],i=n[r];if(o===void 0)return-1;if(i===void 0)return 1;let s=Number.parseInt(o,10),a=Number.parseInt(i,10),d=s.toString()===o,u=a.toString()===i;if(d&&u){if(s!==a)return s>a?1:-1}else{if(d!==u)return d?-1:1;if(o!==i)return o>i?1:-1}}return 0}function o9(e,n,t,r,o){try{r(n.pid)}catch(i){let s=i!==null&&typeof i=="object"&&"code"in i?i.code:void 0;if(s!=="ESRCH")throw s==="EPERM"||s==="EACCES"?new Error(`Cannot take over the runner lock at ${e}: its holder process (pid ${n.pid}) is owned by another user and cannot be stopped. Stop that process, or remove the lock file, then retry.`):i}o?.({lockPath:e,holderPid:n.pid,holderRunnerId:n.runnerId,reason:t})}function aSe(e,n,t,r,o,i,s){if(t===void 0||yr(t)!==yr(Bt))return;let a=HT(e,n),d=e0(a);if(d!==void 0){if(md(d,r,o).state==="live")throw new ls(a,d);i9(a,r,()=>{let u=VT(a)?GT(a):void 0;if(u===void 0)return;let c=md(u,r,o);if(c.state==="live")throw new ls(a,u);c.state==="wedged"&&o9(a,u,c.reason,i,s),fd(a)})}}function dSe(e,n,t,r,o,i,s,a){if(Qx(e,n))return;s?.();let d=e0(e);if(d===void 0){if(Qx(e,n))return;throw new Error(`another Linzumi runner lock appeared while starting: ${e}`)}if(md(d,t,r).state==="live")throw new ls(e,d);a?.(),i9(e,t,()=>{let u=VT(e)?GT(e):void 0;if(u!==void 0){let c=md(u,t,r);if(c.state==="live")throw new ls(e,u);c.state==="wedged"&&o9(e,u,c.reason,o,i),fd(e)}if(!Qx(e,n))throw new Error(`another Linzumi runner lock appeared while starting: ${e}`)})}function Qx(e,n){eSe(YU(e),{recursive:!0});try{let t=ZU(e,"wx");try{XU(t,`${JSON.stringify(n,null,2)}
|
|
1475
1475
|
`)}finally{GU(t)}return!0}catch(t){if(Lc(t,"EEXIST"))return!1;throw t}}function i9(e,n,t){let r=`${e}.replace`;for(;;)try{let o=ZU(r,"wx");try{XU(o,`${process.pid}
|
|
1476
1476
|
`),t()}finally{GU(o),fd(r)}return}catch(o){if(Lc(o,"EEXIST")){let i=uSe(r);if(i===void 0)continue;if(n(i))throw new Error(["another Linzumi runner is already replacing a stale runner lock",`lock: ${e}`,"Wait for that startup to finish, then retry."].join(`
|
package/package.json
CHANGED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
// Spec: kandan/plans/2026-07-10-compute-nodes-rescript-commander-zero-ts-program.md
|
|
2
|
+
// (M3 cluster 1, protocol-types).
|
|
3
|
+
// Relationship: Builds the TS-side PARITY ORACLE for the protocol/type
|
|
4
|
+
// cluster of the ReScript commander port. The oracle bundles the REAL TS
|
|
5
|
+
// protocol modules (protocol.ts, json.ts, localCodexMessageState.ts,
|
|
6
|
+
// terminalFailureRetry.ts, localConfig.ts) behind a one-shot batch driver:
|
|
7
|
+
// it reads a JSON array of cases on stdin and writes a JSON array of
|
|
8
|
+
// results on stdout. The ReScript package's parity conformance
|
|
9
|
+
// (packages/linzumi-cli-rescript/src/parity/ProtocolParityConformance.res)
|
|
10
|
+
// drives the SAME inputs through the sury schemas/functions and asserts
|
|
11
|
+
// accept/reject/normalized-output equivalence - so the two protocol layers
|
|
12
|
+
// cannot drift silently.
|
|
13
|
+
//
|
|
14
|
+
// Like build-differential-entry.mjs, the output is a local test artifact
|
|
15
|
+
// (.differential/ is gitignored, never published) and stays unminified for
|
|
16
|
+
// debuggability.
|
|
17
|
+
import { mkdir } from 'node:fs/promises';
|
|
18
|
+
import { dirname, join } from 'node:path';
|
|
19
|
+
import { fileURLToPath } from 'node:url';
|
|
20
|
+
import { build } from 'esbuild';
|
|
21
|
+
|
|
22
|
+
const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
23
|
+
|
|
24
|
+
const driverSource = `
|
|
25
|
+
import { mkdtempSync, writeFileSync } from 'node:fs';
|
|
26
|
+
import { tmpdir } from 'node:os';
|
|
27
|
+
import { join } from 'node:path';
|
|
28
|
+
import {
|
|
29
|
+
isJsonObject,
|
|
30
|
+
parseJsonObject,
|
|
31
|
+
requireString,
|
|
32
|
+
requirePositiveInteger,
|
|
33
|
+
extractCodexIds,
|
|
34
|
+
} from './src/protocol';
|
|
35
|
+
import {
|
|
36
|
+
objectValue,
|
|
37
|
+
arrayValue,
|
|
38
|
+
stringValue,
|
|
39
|
+
integerValue,
|
|
40
|
+
stringListValue,
|
|
41
|
+
parseJsonObjectOrUndefined,
|
|
42
|
+
} from './src/json';
|
|
43
|
+
import {
|
|
44
|
+
approvalRequestKey,
|
|
45
|
+
codexApprovalMessageState,
|
|
46
|
+
fleetBreakerHoldReason,
|
|
47
|
+
parkedAsOwnTurnQueuedReason,
|
|
48
|
+
parkedAsOwnTurnReasonDetail,
|
|
49
|
+
processingReasonForCodexNotification,
|
|
50
|
+
queuedBehindEarlierMessagesReason,
|
|
51
|
+
queuedBehindRunningTurnReason,
|
|
52
|
+
queuedBehindReasonPrefix,
|
|
53
|
+
queuedBehindRunningTurnReasonPrefix,
|
|
54
|
+
resumingAfterStreamStallReason,
|
|
55
|
+
steeredIntoRunningTurnReason,
|
|
56
|
+
} from './src/localCodexMessageState';
|
|
57
|
+
import { parseFleetBreakerPayload } from './src/fleetBreaker';
|
|
58
|
+
import {
|
|
59
|
+
fateRetryable,
|
|
60
|
+
isTerminalFailureFate,
|
|
61
|
+
terminalFailureClasses,
|
|
62
|
+
terminalFailureFate,
|
|
63
|
+
terminalFailureFates,
|
|
64
|
+
terminalFailureRetryableStamp,
|
|
65
|
+
} from './src/terminalFailureRetry';
|
|
66
|
+
import { readLocalConfig, readLocalSignupAuth } from './src/localConfig';
|
|
67
|
+
|
|
68
|
+
const jsonHelpers = {
|
|
69
|
+
isJsonObject,
|
|
70
|
+
parseJsonObject,
|
|
71
|
+
requireString,
|
|
72
|
+
requirePositiveInteger,
|
|
73
|
+
extractCodexIds,
|
|
74
|
+
objectValue,
|
|
75
|
+
arrayValue,
|
|
76
|
+
stringValue,
|
|
77
|
+
integerValue,
|
|
78
|
+
stringListValue,
|
|
79
|
+
parseJsonObjectOrUndefined,
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const messageStateFns = {
|
|
83
|
+
approvalRequestKey,
|
|
84
|
+
codexApprovalMessageState,
|
|
85
|
+
parkedAsOwnTurnQueuedReason,
|
|
86
|
+
parkedAsOwnTurnReasonDetail,
|
|
87
|
+
processingReasonForCodexNotification,
|
|
88
|
+
queuedBehindEarlierMessagesReason,
|
|
89
|
+
queuedBehindRunningTurnReason,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// Encode a call outcome so undefined stays distinguishable from null after
|
|
93
|
+
// JSON serialization.
|
|
94
|
+
function outcome(run) {
|
|
95
|
+
try {
|
|
96
|
+
const value = run();
|
|
97
|
+
return value === undefined ? { defined: false } : { defined: true, value };
|
|
98
|
+
} catch (error) {
|
|
99
|
+
return { threw: true, message: error instanceof Error ? error.message : String(error) };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function handle(testCase) {
|
|
104
|
+
switch (testCase.op) {
|
|
105
|
+
case 'jsonHelper': {
|
|
106
|
+
const fn = jsonHelpers[testCase.fn];
|
|
107
|
+
if (fn === undefined) {
|
|
108
|
+
return { threw: true, message: 'unknown jsonHelper ' + testCase.fn };
|
|
109
|
+
}
|
|
110
|
+
return outcome(() => fn(...testCase.args));
|
|
111
|
+
}
|
|
112
|
+
case 'messageState': {
|
|
113
|
+
const fn = messageStateFns[testCase.fn];
|
|
114
|
+
if (fn === undefined) {
|
|
115
|
+
return { threw: true, message: 'unknown messageState fn ' + testCase.fn };
|
|
116
|
+
}
|
|
117
|
+
return outcome(() => fn(...testCase.args));
|
|
118
|
+
}
|
|
119
|
+
case 'constants':
|
|
120
|
+
return {
|
|
121
|
+
resumingAfterStreamStallReason,
|
|
122
|
+
steeredIntoRunningTurnReason,
|
|
123
|
+
queuedBehindReasonPrefix,
|
|
124
|
+
queuedBehindRunningTurnReasonPrefix,
|
|
125
|
+
fleetBreakerHoldReason,
|
|
126
|
+
};
|
|
127
|
+
case 'fleetBreakerParse':
|
|
128
|
+
return outcome(() => parseFleetBreakerPayload(testCase.value));
|
|
129
|
+
case 'fateTables': {
|
|
130
|
+
const retryableByFate = {};
|
|
131
|
+
for (const fate of terminalFailureFates) {
|
|
132
|
+
retryableByFate[fate] = fateRetryable(fate);
|
|
133
|
+
}
|
|
134
|
+
const fateByClass = {};
|
|
135
|
+
const stampByClass = {};
|
|
136
|
+
for (const failureClass of terminalFailureClasses) {
|
|
137
|
+
fateByClass[failureClass] = terminalFailureFate(failureClass);
|
|
138
|
+
stampByClass[failureClass] = terminalFailureRetryableStamp(failureClass);
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
fates: [...terminalFailureFates],
|
|
142
|
+
retryableByFate,
|
|
143
|
+
classes: [...terminalFailureClasses],
|
|
144
|
+
fateByClass,
|
|
145
|
+
stampByClass,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
case 'isFate':
|
|
149
|
+
return outcome(() => isTerminalFailureFate(testCase.value));
|
|
150
|
+
case 'localConfig': {
|
|
151
|
+
const dir = mkdtempSync(join(tmpdir(), 'linzumi-protocol-parity-'));
|
|
152
|
+
const path = join(dir, 'config.json');
|
|
153
|
+
writeFileSync(path, testCase.contents, 'utf8');
|
|
154
|
+
const config = outcome(() => readLocalConfig(path));
|
|
155
|
+
const signupAuth = outcome(() => readLocalSignupAuth(path));
|
|
156
|
+
return { config, signupAuth };
|
|
157
|
+
}
|
|
158
|
+
default:
|
|
159
|
+
return { threw: true, message: 'unknown op ' + String(testCase.op) };
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
let stdin = '';
|
|
164
|
+
process.stdin.setEncoding('utf8');
|
|
165
|
+
for await (const chunk of process.stdin) {
|
|
166
|
+
stdin += chunk;
|
|
167
|
+
}
|
|
168
|
+
const cases = JSON.parse(stdin);
|
|
169
|
+
process.stdout.write(JSON.stringify(cases.map(handle)));
|
|
170
|
+
`;
|
|
171
|
+
|
|
172
|
+
await mkdir(join(packageRoot, '.differential'), { recursive: true });
|
|
173
|
+
|
|
174
|
+
await build({
|
|
175
|
+
stdin: {
|
|
176
|
+
contents: driverSource,
|
|
177
|
+
resolveDir: packageRoot,
|
|
178
|
+
sourcefile: 'protocol-parity-driver.ts',
|
|
179
|
+
loader: 'ts',
|
|
180
|
+
},
|
|
181
|
+
bundle: true,
|
|
182
|
+
platform: 'node',
|
|
183
|
+
target: 'node20',
|
|
184
|
+
format: 'esm',
|
|
185
|
+
outfile: join(packageRoot, '.differential/protocol-parity-oracle.mjs'),
|
|
186
|
+
minify: false,
|
|
187
|
+
sourcemap: false,
|
|
188
|
+
legalComments: 'none',
|
|
189
|
+
// The protocol modules are dependency-light; anything that leaks in from
|
|
190
|
+
// the wider commander graph stays external exactly like the entry build.
|
|
191
|
+
external: ['ws', 'undici', 'blessed', '@anthropic-ai/claude-agent-sdk'],
|
|
192
|
+
});
|