claude-codex-wechat 0.1.37 → 0.1.39

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.
@@ -99,17 +99,22 @@ import { homedir } from "node:os";
99
99
  import { fileURLToPath } from "node:url";
100
100
  import { z as z2 } from "zod";
101
101
  var BRIDGE_API_URL2 = process.env.BRIDGE_API_URL || "http://localhost:8787";
102
- function findDouyinScript() {
103
- const here = dirname(fileURLToPath(import.meta.url));
104
- const candidates = [
105
- // Bundled with project (primary)
106
- join(here, "..", "scripts", "douyin-download.mjs"),
107
- // Built output
108
- join(here, "..", "..", "mcp", "scripts", "douyin-download.mjs"),
102
+ function douyinScriptCandidates(baseDir) {
103
+ return [
104
+ // Source layout: src/mcp/tools -> src/mcp/scripts
105
+ join(baseDir, "..", "scripts", "douyin-download.mjs"),
106
+ // Bundled layout: dist/mcp/mediaServer.js -> dist/mcp/scripts
107
+ join(baseDir, "scripts", "douyin-download.mjs"),
108
+ // Older/alternate dist layout fallback
109
+ join(baseDir, "..", "..", "mcp", "scripts", "douyin-download.mjs"),
109
110
  // User skills locations (cross-platform)
110
111
  join(homedir(), ".agents", "skills", "douyin-download", "scripts", "douyin-download.mjs"),
111
112
  join(homedir(), ".claude", "skills", "douyin-download", "scripts", "douyin-download.mjs")
112
113
  ];
114
+ }
115
+ function findDouyinScript() {
116
+ const here = dirname(fileURLToPath(import.meta.url));
117
+ const candidates = douyinScriptCandidates(here);
113
118
  for (const p of candidates) {
114
119
  const resolved = resolve(p);
115
120
  if (existsSync(resolved)) return resolved;
@@ -3452,6 +3452,34 @@ var CodexAppServerClient = class {
3452
3452
  };
3453
3453
 
3454
3454
  // src/providers/codex/codexInteractiveRunner.ts
3455
+ var IDLE_SENTINEL2 = /* @__PURE__ */ Symbol("idle_timeout");
3456
+ function withIdleTimeout(promise, ms) {
3457
+ if (!ms || ms <= 0) return promise;
3458
+ return new Promise((resolve2, reject) => {
3459
+ let settled = false;
3460
+ const timer = setTimeout(() => {
3461
+ if (!settled) {
3462
+ settled = true;
3463
+ resolve2(IDLE_SENTINEL2);
3464
+ }
3465
+ }, ms);
3466
+ timer.unref?.();
3467
+ void promise.then(
3468
+ (value) => {
3469
+ if (settled) return;
3470
+ settled = true;
3471
+ clearTimeout(timer);
3472
+ resolve2(value);
3473
+ },
3474
+ (error) => {
3475
+ if (settled) return;
3476
+ settled = true;
3477
+ clearTimeout(timer);
3478
+ reject(error);
3479
+ }
3480
+ );
3481
+ });
3482
+ }
3455
3483
  function readAgentMessageItemId(value) {
3456
3484
  if (!value || typeof value !== "object") return void 0;
3457
3485
  const record = value;
@@ -3491,9 +3519,11 @@ var CodexInteractiveRunner = class {
3491
3519
  sessions = /* @__PURE__ */ new Map();
3492
3520
  command;
3493
3521
  syncThreadForResume;
3522
+ idleTimeoutMs;
3494
3523
  constructor(input = {}) {
3495
3524
  this.command = input.command;
3496
3525
  this.syncThreadForResume = input.syncThreadForResume ?? syncCodexThreadForResume;
3526
+ this.idleTimeoutMs = input.idleTimeoutMs ?? 18e4;
3497
3527
  }
3498
3528
  async startSession(input) {
3499
3529
  const session = {
@@ -3513,7 +3543,11 @@ var CodexInteractiveRunner = class {
3513
3543
  async *sendMessage(input) {
3514
3544
  const session = this.sessions.get(input.bridgeSessionId);
3515
3545
  if (!session) throw new Error(`codex_session_not_found:${input.bridgeSessionId}`);
3516
- const client = await this.ensureClient(session);
3546
+ const client = await this.requireLiveClient(session);
3547
+ if (!client) {
3548
+ yield { type: "error", error: "idle_timeout", code: "idle_timeout" };
3549
+ return;
3550
+ }
3517
3551
  session.pendingEvents = [];
3518
3552
  session.activeMessage = void 0;
3519
3553
  session.activeTurnId = void 0;
@@ -3522,20 +3556,30 @@ var CodexInteractiveRunner = class {
3522
3556
  session.turnCompletedResolver = resolve2;
3523
3557
  });
3524
3558
  if (session.threadId) {
3525
- await client.request("thread/resume", {
3559
+ const resumed = await withIdleTimeout(client.request("thread/resume", {
3526
3560
  threadId: session.threadId,
3527
3561
  cwd: session.cwd,
3528
3562
  persistExtendedHistory: true
3529
- }).catch(() => void 0);
3563
+ }).catch(() => void 0), this.idleTimeoutMs);
3564
+ if (resumed === IDLE_SENTINEL2) {
3565
+ await this.handleIdleTimeout(session);
3566
+ yield { type: "error", error: "idle_timeout", code: "idle_timeout" };
3567
+ return;
3568
+ }
3530
3569
  } else {
3531
- const started = await client.request("thread/start", {
3570
+ const started = await withIdleTimeout(client.request("thread/start", {
3532
3571
  cwd: session.cwd,
3533
3572
  threadSource: "user",
3534
3573
  persistExtendedHistory: true,
3535
3574
  experimentalRawEvents: true,
3536
3575
  sandboxPolicy: { type: "disabled" },
3537
3576
  approvalMode: "never"
3538
- });
3577
+ }), this.idleTimeoutMs);
3578
+ if (started === IDLE_SENTINEL2) {
3579
+ await this.handleIdleTimeout(session);
3580
+ yield { type: "error", error: "idle_timeout", code: "idle_timeout" };
3581
+ return;
3582
+ }
3539
3583
  session.threadId = readThreadId(started);
3540
3584
  session.providerSessionId = session.threadId;
3541
3585
  if (!session.threadId) throw new Error("codex_app_server_missing_thread_id");
@@ -3550,15 +3594,27 @@ var CodexInteractiveRunner = class {
3550
3594
  }
3551
3595
  };
3552
3596
  }
3553
- const response = await client.request("turn/start", {
3597
+ const response = await withIdleTimeout(client.request("turn/start", {
3554
3598
  threadId: session.threadId,
3555
3599
  cwd: session.cwd,
3556
3600
  input: [{ type: "text", text: input.text }]
3557
- });
3601
+ }), this.idleTimeoutMs);
3602
+ if (response === IDLE_SENTINEL2) {
3603
+ await this.handleIdleTimeout(session);
3604
+ while (session.pendingEvents.length > 0) yield session.pendingEvents.shift();
3605
+ yield { type: "error", error: "idle_timeout", code: "idle_timeout" };
3606
+ return;
3607
+ }
3558
3608
  const maybeTurnId = readTurnId(response);
3559
3609
  if (maybeTurnId) session.activeTurnId = maybeTurnId;
3560
3610
  for (; ; ) {
3561
- const event = await this.takeNextEvent(session);
3611
+ const event = await withIdleTimeout(this.takeNextEvent(session), this.idleTimeoutMs);
3612
+ if (event === IDLE_SENTINEL2) {
3613
+ await this.handleIdleTimeout(session);
3614
+ while (session.pendingEvents.length > 0) yield session.pendingEvents.shift();
3615
+ yield { type: "error", error: "idle_timeout", code: "idle_timeout" };
3616
+ return;
3617
+ }
3562
3618
  if (!event) break;
3563
3619
  yield event;
3564
3620
  }
@@ -3617,7 +3673,14 @@ var CodexInteractiveRunner = class {
3617
3673
  command: this.command,
3618
3674
  cwd: session.cwd
3619
3675
  });
3620
- await client.initialize();
3676
+ session.client = client;
3677
+ try {
3678
+ await client.initialize();
3679
+ } catch (error) {
3680
+ session.client = void 0;
3681
+ await client.dispose().catch(() => void 0);
3682
+ throw error;
3683
+ }
3621
3684
  client.onNotification("item/agentMessage/delta", (params) => {
3622
3685
  const record = params;
3623
3686
  if (typeof record.delta !== "string" || !record.delta) return;
@@ -3647,9 +3710,27 @@ var CodexInteractiveRunner = class {
3647
3710
  client.onRequest("item/fileChange/requestApproval", async (_id, params) => {
3648
3711
  return { decision: "approve" };
3649
3712
  });
3650
- session.client = client;
3651
3713
  return client;
3652
3714
  }
3715
+ async requireLiveClient(session) {
3716
+ const client = await withIdleTimeout(this.ensureClient(session), this.idleTimeoutMs);
3717
+ if (client === IDLE_SENTINEL2) {
3718
+ await this.handleIdleTimeout(session);
3719
+ return null;
3720
+ }
3721
+ return client;
3722
+ }
3723
+ async handleIdleTimeout(session) {
3724
+ this.flushActiveMessage(session);
3725
+ session.turnClosed = true;
3726
+ session.eventResolver?.();
3727
+ session.eventResolver = void 0;
3728
+ session.turnCompletedResolver?.();
3729
+ session.turnCompletedResolver = void 0;
3730
+ const client = session.client;
3731
+ session.client = void 0;
3732
+ await client?.dispose().catch(() => void 0);
3733
+ }
3653
3734
  flushActiveMessage(session) {
3654
3735
  if (!session.activeMessage?.text) return;
3655
3736
  this.enqueueEvent(session, { type: "text_delta", text: session.activeMessage.text });
@@ -3735,7 +3816,12 @@ function createDefaultProviders(input = {}) {
3735
3816
  });
3736
3817
  return [
3737
3818
  new ClaudeCodeProvider({ runner: claudeRunner }),
3738
- new CodexProvider({ runner: new CodexInteractiveRunner({ command: input.codexCommand }) })
3819
+ new CodexProvider({
3820
+ runner: new CodexInteractiveRunner({
3821
+ command: input.codexCommand,
3822
+ idleTimeoutMs: readEnvInt(process.env.BRIDGE_CODEX_IDLE_TIMEOUT_MS, 18e4)
3823
+ })
3824
+ })
3739
3825
  ];
3740
3826
  }
3741
3827
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-codex-wechat",
3
- "version": "0.1.37",
3
+ "version": "0.1.39",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@11.5.0",