@linzumi/cli 0.0.95-beta → 0.0.96-beta

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 CHANGED
@@ -58,7 +58,7 @@ Install the CLI or run it with `npx`:
58
58
  ```bash
59
59
  npm install -g @linzumi/cli@latest
60
60
  npx -y @linzumi/cli@latest signup
61
- npx -y @linzumi/cli@0.0.95-beta --version
61
+ npx -y @linzumi/cli@0.0.96-beta --version
62
62
  linzumi --version
63
63
  ```
64
64
 
package/dist/index.js CHANGED
@@ -19451,7 +19451,7 @@ var linzumiCliVersion, linzumiCliVersionText;
19451
19451
  var init_version = __esm({
19452
19452
  "src/version.ts"() {
19453
19453
  "use strict";
19454
- linzumiCliVersion = "0.0.95-beta";
19454
+ linzumiCliVersion = "0.0.96-beta";
19455
19455
  linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
19456
19456
  }
19457
19457
  });
@@ -22340,6 +22340,11 @@ function connectThreadCodexWorkerIpc(child) {
22340
22340
  onRequest: (callback) => {
22341
22341
  requestCallbacks.add(callback);
22342
22342
  },
22343
+ // The worker child exited/disconnected (onClosed) or close() was called.
22344
+ // A reconnect uses this to detect a DEAD cached client and respawn a fresh
22345
+ // worker instead of send()-ing on a closed channel (which throws "thread
22346
+ // Codex worker IPC client is closed" and strands the resume).
22347
+ isClosed: () => state.closed || child.connected === false,
22343
22348
  close: () => {
22344
22349
  state.closed = true;
22345
22350
  child.off("message", onMessage);
@@ -24324,6 +24329,35 @@ async function openLocalCodexRunner(options, log2, cleanup, close) {
24324
24329
  );
24325
24330
  threadRunnerProcesses.clear();
24326
24331
  });
24332
+ const evictStaleDynamicChannelSession = async (codexThreadId, expectClient) => {
24333
+ const session = dynamicChannelSessions.get(codexThreadId);
24334
+ const boundClient = dynamicChannelSessionCodexClients.get(codexThreadId);
24335
+ if (session === void 0) {
24336
+ return false;
24337
+ }
24338
+ if (expectClient !== void 0 && boundClient !== expectClient) {
24339
+ return false;
24340
+ }
24341
+ if (boundClient?.isClosed?.() !== true) {
24342
+ return false;
24343
+ }
24344
+ dynamicChannelSessions.delete(codexThreadId);
24345
+ dynamicChannelSessionCodexClients.delete(codexThreadId);
24346
+ dynamicChannelSessionAttachInFlight.delete(codexThreadId);
24347
+ log2("runner.thread_session_evicted_dead_worker", {
24348
+ codex_thread_id: codexThreadId,
24349
+ kandan_thread_id: session.currentKandanThreadId() ?? null
24350
+ });
24351
+ try {
24352
+ await session.close();
24353
+ } catch (error) {
24354
+ log2("runner.thread_session_evict_close_failed", {
24355
+ codex_thread_id: codexThreadId,
24356
+ message: error instanceof Error ? error.message : String(error)
24357
+ });
24358
+ }
24359
+ return true;
24360
+ };
24327
24361
  const attachThreadSessionWithCodex = async (args) => {
24328
24362
  const { control, cwd, codexThreadId, sessionCodex } = args;
24329
24363
  const portForwardWatcherRootPid = args.portForwardWatcherRootPid;
@@ -24335,7 +24369,10 @@ async function openLocalCodexRunner(options, log2, cleanup, close) {
24335
24369
  }
24336
24370
  const existingSession = dynamicChannelSessions.get(codexThreadId);
24337
24371
  if (existingSession !== void 0) {
24338
- return existingSession;
24372
+ const evicted = await evictStaleDynamicChannelSession(codexThreadId);
24373
+ if (!evicted) {
24374
+ return existingSession;
24375
+ }
24339
24376
  }
24340
24377
  const alreadyAttaching = dynamicChannelSessionAttachInFlight.get(codexThreadId);
24341
24378
  if (alreadyAttaching !== void 0) {
@@ -24641,6 +24678,18 @@ async function openLocalCodexRunner(options, log2, cleanup, close) {
24641
24678
  threadRunnerProcesses.delete(kandanThreadId);
24642
24679
  }
24643
24680
  });
24681
+ handle.onExit?.(() => {
24682
+ if (cleanup.closePromise !== void 0) {
24683
+ return;
24684
+ }
24685
+ for (const [codexThreadId, client] of Array.from(
24686
+ dynamicChannelSessionCodexClients.entries()
24687
+ )) {
24688
+ if (client === threadCodex) {
24689
+ void evictStaleDynamicChannelSession(codexThreadId, threadCodex);
24690
+ }
24691
+ }
24692
+ });
24644
24693
  log2("runner.thread_process_started", {
24645
24694
  kandanThreadId,
24646
24695
  cwd
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linzumi/cli",
3
- "version": "0.0.95-beta",
3
+ "version": "0.0.96-beta",
4
4
  "description": "Linzumi CLI — 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": {