@linzumi/cli 1.0.180 → 1.0.182

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.
@@ -1510,7 +1510,7 @@ To kick the agent off:
1510
1510
  `,O=Buffer.byteLength(T,"utf8");if(O>s)return l("runner_diagnostics.spool_entry_dropped",{reason:"entry_too_large",entry_bytes:O,max_entry_bytes:s}),!1;BEe(n,{recursive:!0}),m(u)+O>i&&f(),_(O);let P=b()?`
1511
1511
  `:"";return NEe(u,`${P}${T}`,"utf8"),!0}catch(R){return l("runner_diagnostics.spool_failed",{error:R instanceof Error?R.message:String(R)}),!1}},w=S=>{let R=[],T=KEe(S,"utf8");for(let O of T.split(`
1512
1512
  `))if(O.trim()!=="")try{let P=JSON.parse(O);P!==null&&typeof P=="object"&&R.push({parsed:P,raw:O})}catch{}return R};return{append:v,drain:async S=>{if(c)return{uploadedBatches:0,uploadedEntries:0,remainingBatches:p().length,skipped:!0};c=!0;let R=0,T=0;try{f(),_(0);let O=a()-o;for(let P of p()){let A;try{A=w(P)}catch(Z){l("runner_diagnostics.spool_batch_unreadable",{file:P,error:Z instanceof Error?Z.message:String(Z)}),y(P,"unreadable");continue}let q=A.filter(Z=>{let H=d1e(Z.parsed);return H===void 0||H>=O});if(q.length===0){y(P,"empty_or_expired");continue}let E=RR(P,".jsonl"),N=q.map(Z=>Z.raw).join(`
1513
- `),V=q.map(Z=>Z.parsed.spooled_at).filter(Z=>typeof Z=="string"),G={bundle_name:"runner-diagnostics-spool",exported_at:new Date(a()).toISOString(),idempotency_key:E,diagnostics:{kind:"runner_diagnostic_log",spool_batch:!0,idempotency_key:E,entry_count:q.length,...V.length===0?{}:{first_spooled_at:V[0],last_spooled_at:V[V.length-1]}},telemetry_ndjson:N};try{await S(G)}catch(Z){l("runner_diagnostics.spool_upload_failed",{file:P,remaining_batches:p().length,error:Z instanceof Error?Z.message:String(Z)});break}R+=1,T+=q.length;try{UJ(P)}catch(Z){l("runner_diagnostics.spool_delete_failed",{file:P,error:Z instanceof Error?Z.message:String(Z)})}}}catch(O){l("runner_diagnostics.spool_drain_failed",{error:O instanceof Error?O.message:String(O)})}finally{c=!1}return{uploadedBatches:R,uploadedEntries:T,remainingBatches:p().length,skipped:!1}},pendingBatchFiles:p}}var QEe,XEe,YEe,e1e,n1e,BJ,r1e,o1e,KJ=F(()=>{"use strict";jx();QEe=32*1024*1024,XEe=10080*60*1e3,YEe=4*1024*1024,e1e=1024*1024,n1e="spool.jsonl",BJ=/^batch-(\d{1,16})-[0-9a-f-]+\.jsonl$/;r1e=/\b([A-Z][A-Z0-9_]{1,})=("[^"\n]*"|'[^'\n]*'|[^\s"'`;,)\]}]+)/g,o1e=/(?:\/(?:[A-Za-z0-9._@~+-]|%[0-9A-Fa-f]{2})+){2,}/g});var Vt,DR,Sa=F(()=>{"use strict";Vt="1.0.180",DR=`linzumi ${Vt}`});import{closeSync as WJ,existsSync as AR,mkdirSync as u1e,openSync as HJ,readFileSync as GJ,renameSync as c1e,unlinkSync as eu,writeFileSync as l1e,writeSync as ZJ}from"node:fs";import{dirname as QJ,join as p1e}from"node:path";function OR(e){return e instanceof Ds||e instanceof Error&&e.name===YJ&&"lockPath"in e&&"heldBy"in e}function $R(e,n=et(),t){let r=t===void 0?encodeURIComponent(e):Vd(t);return p1e(QJ(n),"runners",`${r}.lock`)}function Qb(e){let n=$R(e.machineId,e.configPath,e.linzumiUrl),t=e.isPidAlive??sK,r=e.now??(()=>new Date),o=e.killPid??C1e,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:zn(e.linzumiUrl)},...e.launchSource===void 0?{}:{launchSource:e.launchSource},startedAt:i,heartbeatAt:i,cliVersion:e.cliVersion??Vt,...e.gracefulUpdateDrain===!0?{gracefulUpdateDrain:!0}:{}};g1e(e.machineId,e.configPath,e.linzumiUrl,t,r,o,e.onTakeover),y1e(n,s,t,r,o,e.onTakeover,e.beforeReadExistingLock,e.beforeReplaceStaleLock);let a=()=>eK(n,s,r),d=setInterval(a,XJ);return d.unref(),{path:n,record:s,heartbeat:a,release:()=>{clearInterval(d),oK(n,s)}}}function eK(e,n,t){try{let r=Yb(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`;l1e(i,`${JSON.stringify(o,null,2)}
1513
+ `),V=q.map(Z=>Z.parsed.spooled_at).filter(Z=>typeof Z=="string"),G={bundle_name:"runner-diagnostics-spool",exported_at:new Date(a()).toISOString(),idempotency_key:E,diagnostics:{kind:"runner_diagnostic_log",spool_batch:!0,idempotency_key:E,entry_count:q.length,...V.length===0?{}:{first_spooled_at:V[0],last_spooled_at:V[V.length-1]}},telemetry_ndjson:N};try{await S(G)}catch(Z){l("runner_diagnostics.spool_upload_failed",{file:P,remaining_batches:p().length,error:Z instanceof Error?Z.message:String(Z)});break}R+=1,T+=q.length;try{UJ(P)}catch(Z){l("runner_diagnostics.spool_delete_failed",{file:P,error:Z instanceof Error?Z.message:String(Z)})}}}catch(O){l("runner_diagnostics.spool_drain_failed",{error:O instanceof Error?O.message:String(O)})}finally{c=!1}return{uploadedBatches:R,uploadedEntries:T,remainingBatches:p().length,skipped:!1}},pendingBatchFiles:p}}var QEe,XEe,YEe,e1e,n1e,BJ,r1e,o1e,KJ=F(()=>{"use strict";jx();QEe=32*1024*1024,XEe=10080*60*1e3,YEe=4*1024*1024,e1e=1024*1024,n1e="spool.jsonl",BJ=/^batch-(\d{1,16})-[0-9a-f-]+\.jsonl$/;r1e=/\b([A-Z][A-Z0-9_]{1,})=("[^"\n]*"|'[^'\n]*'|[^\s"'`;,)\]}]+)/g,o1e=/(?:\/(?:[A-Za-z0-9._@~+-]|%[0-9A-Fa-f]{2})+){2,}/g});var Vt,DR,Sa=F(()=>{"use strict";Vt="1.0.182",DR=`linzumi ${Vt}`});import{closeSync as WJ,existsSync as AR,mkdirSync as u1e,openSync as HJ,readFileSync as GJ,renameSync as c1e,unlinkSync as eu,writeFileSync as l1e,writeSync as ZJ}from"node:fs";import{dirname as QJ,join as p1e}from"node:path";function OR(e){return e instanceof Ds||e instanceof Error&&e.name===YJ&&"lockPath"in e&&"heldBy"in e}function $R(e,n=et(),t){let r=t===void 0?encodeURIComponent(e):Vd(t);return p1e(QJ(n),"runners",`${r}.lock`)}function Qb(e){let n=$R(e.machineId,e.configPath,e.linzumiUrl),t=e.isPidAlive??sK,r=e.now??(()=>new Date),o=e.killPid??C1e,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:zn(e.linzumiUrl)},...e.launchSource===void 0?{}:{launchSource:e.launchSource},startedAt:i,heartbeatAt:i,cliVersion:e.cliVersion??Vt,...e.gracefulUpdateDrain===!0?{gracefulUpdateDrain:!0}:{}};g1e(e.machineId,e.configPath,e.linzumiUrl,t,r,o,e.onTakeover),y1e(n,s,t,r,o,e.onTakeover,e.beforeReadExistingLock,e.beforeReplaceStaleLock);let a=()=>eK(n,s,r),d=setInterval(a,XJ);return d.unref(),{path:n,record:s,heartbeat:a,release:()=>{clearInterval(d),oK(n,s)}}}function eK(e,n,t){try{let r=Yb(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`;l1e(i,`${JSON.stringify(o,null,2)}
1514
1514
  `,"utf8"),c1e(i,e)}catch{}}function nu(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>f1e?{state:"wedged",reason:e.heartbeatAt===void 0?"missing_heartbeat":"stale_heartbeat"}:{state:"live"}}function nK(e,n,t,r){return t!==Xb||e.launchSource!==Xb?!1:r.state!=="live"?!0:m1e(n,e.cliVersion)>0}function m1e(e,n){let t=VJ(e),r=VJ(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:h1e(t.prerelease,r.prerelease)}function VJ(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=[MR(i[0]),MR(i[1]),MR(i[2])],a=o===""?[]:o.split(".").filter(d=>d!=="");return{core:s,prerelease:a}}function MR(e){let n=Number.parseInt(e??"",10);return Number.isInteger(n)&&n>=0?n:0}function h1e(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 tK(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 g1e(e,n,t,r,o,i,s){if(t===void 0||kr(t)!==kr(Xt))return;let a=$R(e,n),d=Yb(a);if(d!==void 0){if(nu(d,r,o).state==="live")throw new Ds(a,d);rK(a,r,()=>{let u=AR(a)?LR(a):void 0;if(u===void 0)return;let c=nu(u,r,o);if(c.state==="live")throw new Ds(a,u);c.state==="wedged"&&tK(a,u,c.reason,i,s),eu(a)})}}function y1e(e,n,t,r,o,i,s,a){if(Zb(e,n))return;s?.();let d=Yb(e);if(d===void 0){if(Zb(e,n))return;throw new Error(`another Linzumi runner lock appeared while starting: ${e}`)}if(nu(d,t,r).state==="live")throw new Ds(e,d);a?.(),rK(e,t,()=>{let u=AR(e)?LR(e):void 0;if(u!==void 0){let c=nu(u,t,r);if(c.state==="live")throw new Ds(e,u);c.state==="wedged"&&tK(e,u,c.reason,o,i),eu(e)}if(!Zb(e,n))throw new Error(`another Linzumi runner lock appeared while starting: ${e}`)})}function Zb(e,n){u1e(QJ(e),{recursive:!0});try{let t=HJ(e,"wx");try{ZJ(t,`${JSON.stringify(n,null,2)}
1515
1515
  `)}finally{WJ(t)}return!0}catch(t){if(Rl(t,"EEXIST"))return!1;throw t}}function rK(e,n,t){let r=`${e}.replace`;for(;;)try{let o=HJ(r,"wx");try{ZJ(o,`${process.pid}
1516
1516
  `),t()}finally{WJ(o),eu(r)}return}catch(o){if(Rl(o,"EEXIST")){let i=_1e(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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linzumi/cli",
3
- "version": "1.0.180",
3
+ "version": "1.0.182",
4
4
  "description": "Linzumi CLI \u2014 point a Codex agent at the real code on your laptop, with your team watching and steering from shared threads.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -54,6 +54,7 @@ import {
54
54
  fetchThreadTranscriptForRehydrationForTest,
55
55
  resumeCodexThreadForReconnect,
56
56
  } from './src/runner';
57
+ import { withCodexCompletionSnapshotRequestTimeout } from './src/channelSession';
57
58
 
58
59
  // Scripted codex JSON-RPC request seam: replies are consumed in call
59
60
  // order; every call is traced with its params. An exhausted script
@@ -179,6 +180,45 @@ async function runFetchTranscriptCase(input) {
179
180
  return { trace };
180
181
  }
181
182
 
183
+ // The completion-snapshot bound (channelSession.ts
184
+ // withCodexCompletionSnapshotRequestTimeout - the 2026-07-28 impl-res
185
+ // silent-wedge law): the REAL wrapper runs against a scripted request
186
+ // (result / rejection / never-settle hang). When the case carries an
187
+ // explicit boundMs, it is passed as the third argument (the non-positive
188
+ // unbounded guard); otherwise the wrapper resolves its bound through the
189
+ // SAME LINZUMI_CODEX_START_REQUEST_TIMEOUT_MS knob as the start bound
190
+ // (codexCompletionSnapshotRequestTimeoutMs delegates to it), set per case
191
+ // - a hang genuinely waits the (small) bound out.
192
+ async function runSnapshotTimeoutCase(input) {
193
+ process.env.LINZUMI_CODEX_START_REQUEST_TIMEOUT_MS = String(
194
+ input.timeoutMs
195
+ );
196
+ const trace = [];
197
+ const step = input.requestStep ?? {};
198
+ const request =
199
+ step.hang === true
200
+ ? new Promise(() => {})
201
+ : step.reject !== undefined
202
+ ? Promise.reject(new Error(step.reject))
203
+ : Promise.resolve({ result: step.result ?? {} });
204
+ const outcome = await (input.boundMs === undefined
205
+ ? withCodexCompletionSnapshotRequestTimeout(input.method, request)
206
+ : withCodexCompletionSnapshotRequestTimeout(
207
+ input.method,
208
+ request,
209
+ input.boundMs
210
+ )
211
+ ).then(
212
+ (value) => ({ ok: true, value }),
213
+ (error) => ({
214
+ ok: false,
215
+ message: error instanceof Error ? error.message : String(error),
216
+ })
217
+ );
218
+ trace.push({ t: 'outcome', outcome });
219
+ return { trace };
220
+ }
221
+
182
222
  async function runCase(input) {
183
223
  switch (input.kind) {
184
224
  case 'resumeRun':
@@ -187,6 +227,8 @@ async function runCase(input) {
187
227
  return runFetchMessagesCase(input);
188
228
  case 'fetchTranscriptRun':
189
229
  return runFetchTranscriptCase(input);
230
+ case 'snapshotTimeoutRun':
231
+ return runSnapshotTimeoutCase(input);
190
232
  default:
191
233
  return { error: 'unknown case kind ' + String(input.kind) };
192
234
  }