codex-to-im 1.0.41 → 1.0.43

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.
@@ -1572,10 +1572,10 @@ var require_segments = __commonJS({
1572
1572
  const segs = getSegmentsFromString(data, Utils.isKanjiModeEnabled());
1573
1573
  const nodes = buildNodes(segs);
1574
1574
  const graph = buildGraph(nodes, version);
1575
- const path9 = dijkstra.find_path(graph.map, "start", "end");
1575
+ const path10 = dijkstra.find_path(graph.map, "start", "end");
1576
1576
  const optimizedSegs = [];
1577
- for (let i = 1; i < path9.length - 1; i++) {
1578
- optimizedSegs.push(graph.table[path9[i]].node);
1577
+ for (let i = 1; i < path10.length - 1; i++) {
1578
+ optimizedSegs.push(graph.table[path10[i]].node);
1579
1579
  }
1580
1580
  return exports.fromArray(mergeSegments(optimizedSegs));
1581
1581
  };
@@ -4011,7 +4011,7 @@ var require_utils2 = __commonJS({
4011
4011
  // node_modules/qrcode/lib/renderer/png.js
4012
4012
  var require_png2 = __commonJS({
4013
4013
  "node_modules/qrcode/lib/renderer/png.js"(exports) {
4014
- var fs8 = __require("fs");
4014
+ var fs9 = __require("fs");
4015
4015
  var PNG = require_png().PNG;
4016
4016
  var Utils = require_utils2();
4017
4017
  exports.render = function render(qrData, options) {
@@ -4052,7 +4052,7 @@ var require_png2 = __commonJS({
4052
4052
  });
4053
4053
  png.pack();
4054
4054
  };
4055
- exports.renderToFile = function renderToFile(path9, qrData, options, cb) {
4055
+ exports.renderToFile = function renderToFile(path10, qrData, options, cb) {
4056
4056
  if (typeof cb === "undefined") {
4057
4057
  cb = options;
4058
4058
  options = void 0;
@@ -4063,7 +4063,7 @@ var require_png2 = __commonJS({
4063
4063
  called = true;
4064
4064
  cb.apply(null, args);
4065
4065
  };
4066
- const stream = fs8.createWriteStream(path9);
4066
+ const stream = fs9.createWriteStream(path10);
4067
4067
  stream.on("error", done);
4068
4068
  stream.on("close", done);
4069
4069
  exports.renderToFileStream(stream, qrData, options);
@@ -4125,14 +4125,14 @@ var require_utf8 = __commonJS({
4125
4125
  }
4126
4126
  return output;
4127
4127
  };
4128
- exports.renderToFile = function renderToFile(path9, qrData, options, cb) {
4128
+ exports.renderToFile = function renderToFile(path10, qrData, options, cb) {
4129
4129
  if (typeof cb === "undefined") {
4130
4130
  cb = options;
4131
4131
  options = void 0;
4132
4132
  }
4133
- const fs8 = __require("fs");
4133
+ const fs9 = __require("fs");
4134
4134
  const utf8 = exports.render(qrData, options);
4135
- fs8.writeFile(path9, utf8, cb);
4135
+ fs9.writeFile(path10, utf8, cb);
4136
4136
  };
4137
4137
  }
4138
4138
  });
@@ -4253,7 +4253,7 @@ var require_svg_tag = __commonJS({
4253
4253
  return str;
4254
4254
  }
4255
4255
  function qrToPath(data, size, margin) {
4256
- let path9 = "";
4256
+ let path10 = "";
4257
4257
  let moveBy = 0;
4258
4258
  let newRow = false;
4259
4259
  let lineLength = 0;
@@ -4264,19 +4264,19 @@ var require_svg_tag = __commonJS({
4264
4264
  if (data[i]) {
4265
4265
  lineLength++;
4266
4266
  if (!(i > 0 && col > 0 && data[i - 1])) {
4267
- path9 += newRow ? svgCmd("M", col + margin, 0.5 + row + margin) : svgCmd("m", moveBy, 0);
4267
+ path10 += newRow ? svgCmd("M", col + margin, 0.5 + row + margin) : svgCmd("m", moveBy, 0);
4268
4268
  moveBy = 0;
4269
4269
  newRow = false;
4270
4270
  }
4271
4271
  if (!(col + 1 < size && data[i + 1])) {
4272
- path9 += svgCmd("h", lineLength);
4272
+ path10 += svgCmd("h", lineLength);
4273
4273
  lineLength = 0;
4274
4274
  }
4275
4275
  } else {
4276
4276
  moveBy++;
4277
4277
  }
4278
4278
  }
4279
- return path9;
4279
+ return path10;
4280
4280
  }
4281
4281
  exports.render = function render(qrData, options, cb) {
4282
4282
  const opts = Utils.getOptions(options);
@@ -4284,10 +4284,10 @@ var require_svg_tag = __commonJS({
4284
4284
  const data = qrData.modules.data;
4285
4285
  const qrcodesize = size + opts.margin * 2;
4286
4286
  const bg = !opts.color.light.a ? "" : "<path " + getColorAttrib(opts.color.light, "fill") + ' d="M0 0h' + qrcodesize + "v" + qrcodesize + 'H0z"/>';
4287
- const path9 = "<path " + getColorAttrib(opts.color.dark, "stroke") + ' d="' + qrToPath(data, size, opts.margin) + '"/>';
4287
+ const path10 = "<path " + getColorAttrib(opts.color.dark, "stroke") + ' d="' + qrToPath(data, size, opts.margin) + '"/>';
4288
4288
  const viewBox = 'viewBox="0 0 ' + qrcodesize + " " + qrcodesize + '"';
4289
4289
  const width = !opts.width ? "" : 'width="' + opts.width + '" height="' + opts.width + '" ';
4290
- const svgTag = '<svg xmlns="http://www.w3.org/2000/svg" ' + width + viewBox + ' shape-rendering="crispEdges">' + bg + path9 + "</svg>\n";
4290
+ const svgTag = '<svg xmlns="http://www.w3.org/2000/svg" ' + width + viewBox + ' shape-rendering="crispEdges">' + bg + path10 + "</svg>\n";
4291
4291
  if (typeof cb === "function") {
4292
4292
  cb(null, svgTag);
4293
4293
  }
@@ -4301,15 +4301,15 @@ var require_svg = __commonJS({
4301
4301
  "node_modules/qrcode/lib/renderer/svg.js"(exports) {
4302
4302
  var svgTagRenderer = require_svg_tag();
4303
4303
  exports.render = svgTagRenderer.render;
4304
- exports.renderToFile = function renderToFile(path9, qrData, options, cb) {
4304
+ exports.renderToFile = function renderToFile(path10, qrData, options, cb) {
4305
4305
  if (typeof cb === "undefined") {
4306
4306
  cb = options;
4307
4307
  options = void 0;
4308
4308
  }
4309
- const fs8 = __require("fs");
4309
+ const fs9 = __require("fs");
4310
4310
  const svgTag = exports.render(qrData, options);
4311
4311
  const xmlStr = '<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' + svgTag;
4312
- fs8.writeFile(path9, xmlStr, cb);
4312
+ fs9.writeFile(path10, xmlStr, cb);
4313
4313
  };
4314
4314
  }
4315
4315
  });
@@ -4467,8 +4467,8 @@ var require_server = __commonJS({
4467
4467
  cb
4468
4468
  };
4469
4469
  }
4470
- function getTypeFromFilename(path9) {
4471
- return path9.slice((path9.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
4470
+ function getTypeFromFilename(path10) {
4471
+ return path10.slice((path10.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
4472
4472
  }
4473
4473
  function getRendererFromType(type) {
4474
4474
  switch (type) {
@@ -4532,17 +4532,17 @@ var require_server = __commonJS({
4532
4532
  const renderer = getRendererFromType(params.opts.type);
4533
4533
  return render(renderer.renderToBuffer, text2, params);
4534
4534
  };
4535
- exports.toFile = function toFile(path9, text2, opts, cb) {
4536
- if (typeof path9 !== "string" || !(typeof text2 === "string" || typeof text2 === "object")) {
4535
+ exports.toFile = function toFile(path10, text2, opts, cb) {
4536
+ if (typeof path10 !== "string" || !(typeof text2 === "string" || typeof text2 === "object")) {
4537
4537
  throw new Error("Invalid argument");
4538
4538
  }
4539
4539
  if (arguments.length < 3 && !canPromise()) {
4540
4540
  throw new Error("Too few arguments provided");
4541
4541
  }
4542
4542
  const params = checkParams(text2, opts, cb);
4543
- const type = params.opts.type || getTypeFromFilename(path9);
4543
+ const type = params.opts.type || getTypeFromFilename(path10);
4544
4544
  const renderer = getRendererFromType(type);
4545
- const renderToFile = renderer.renderToFile.bind(null, path9);
4545
+ const renderToFile = renderer.renderToFile.bind(null, path10);
4546
4546
  return render(renderToFile, text2, params);
4547
4547
  };
4548
4548
  exports.toFileStream = function toFileStream(stream, text2, opts) {
@@ -4593,6 +4593,9 @@ function normalizeChannelId(value) {
4593
4593
  }
4594
4594
 
4595
4595
  // src/config.ts
4596
+ function isSupportedChannelProvider(value) {
4597
+ return value === "feishu" || value === "weixin";
4598
+ }
4596
4599
  function toFeishuConfig(channel) {
4597
4600
  return channel?.provider === "feishu" ? channel.config : void 0;
4598
4601
  }
@@ -4668,6 +4671,8 @@ function readConfigV2File() {
4668
4671
  try {
4669
4672
  const parsed = JSON.parse(fs.readFileSync(CONFIG_V2_PATH, "utf-8"));
4670
4673
  if (parsed && parsed.schemaVersion === 2 && parsed.runtime && Array.isArray(parsed.channels)) {
4674
+ parsed.runtime.provider = normalizeRuntimeProvider(parsed.runtime.provider);
4675
+ parsed.channels = normalizeChannelInstances(parsed.channels);
4671
4676
  return parsed;
4672
4677
  }
4673
4678
  return null;
@@ -4687,9 +4692,32 @@ function defaultAliasForProvider(provider) {
4687
4692
  function buildDefaultChannelId(provider) {
4688
4693
  return `${provider}-default`;
4689
4694
  }
4695
+ function normalizeRuntimeProvider(_value) {
4696
+ return "codex";
4697
+ }
4698
+ function normalizeChannelInstances(value) {
4699
+ if (!Array.isArray(value)) return [];
4700
+ return value.flatMap((entry) => {
4701
+ if (!entry || typeof entry !== "object") return [];
4702
+ const record = entry;
4703
+ if (!isSupportedChannelProvider(record.provider)) return [];
4704
+ const provider = record.provider;
4705
+ const config = record.config && typeof record.config === "object" ? record.config : {};
4706
+ const timestamp = nowIso();
4707
+ return [{
4708
+ id: normalizeChannelId(
4709
+ typeof record.id === "string" && record.id.trim() ? record.id : buildDefaultChannelId(provider)
4710
+ ),
4711
+ alias: typeof record.alias === "string" && record.alias.trim() ? record.alias.trim() : defaultAliasForProvider(provider),
4712
+ provider,
4713
+ enabled: record.enabled === true,
4714
+ createdAt: typeof record.createdAt === "string" ? record.createdAt : timestamp,
4715
+ updatedAt: typeof record.updatedAt === "string" ? record.updatedAt : timestamp,
4716
+ config
4717
+ }];
4718
+ });
4719
+ }
4690
4720
  function migrateLegacyEnvToV2(env) {
4691
- const rawRuntime = env.get("CTI_RUNTIME") || "codex";
4692
- const runtime = ["claude", "codex", "auto"].includes(rawRuntime) ? rawRuntime : "codex";
4693
4721
  const enabledChannels = splitCsv(env.get("CTI_ENABLED_CHANNELS")) ?? ["feishu"];
4694
4722
  const timestamp = nowIso();
4695
4723
  const channels = [];
@@ -4736,7 +4764,7 @@ function migrateLegacyEnvToV2(env) {
4736
4764
  return {
4737
4765
  schemaVersion: 2,
4738
4766
  runtime: {
4739
- provider: runtime,
4767
+ provider: "codex",
4740
4768
  defaultWorkspaceRoot: expandHomePath(env.get("CTI_DEFAULT_WORKSPACE_ROOT")) || void 0,
4741
4769
  defaultModel: env.get("CTI_DEFAULT_MODEL") || void 0,
4742
4770
  defaultMode: env.get("CTI_DEFAULT_MODE") || "code",
@@ -4747,8 +4775,7 @@ function migrateLegacyEnvToV2(env) {
4747
4775
  codexSandboxMode: parseSandboxMode(env.get("CTI_CODEX_SANDBOX_MODE")) ?? "workspace-write",
4748
4776
  codexReasoningEffort: parseReasoningEffort(env.get("CTI_CODEX_REASONING_EFFORT")) ?? "medium",
4749
4777
  uiAllowLan: env.get("CTI_UI_ALLOW_LAN") === "true",
4750
- uiAccessToken: env.get("CTI_UI_ACCESS_TOKEN") || void 0,
4751
- autoApprove: env.get("CTI_AUTO_APPROVE") === "true"
4778
+ uiAccessToken: env.get("CTI_UI_ACCESS_TOKEN") || void 0
4752
4779
  },
4753
4780
  channels
4754
4781
  };
@@ -4775,13 +4802,13 @@ function expandConfig(v2) {
4775
4802
  codexSandboxMode: v2.runtime.codexSandboxMode ?? "workspace-write",
4776
4803
  codexReasoningEffort: v2.runtime.codexReasoningEffort ?? "medium",
4777
4804
  uiAllowLan: v2.runtime.uiAllowLan === true,
4778
- uiAccessToken: v2.runtime.uiAccessToken || void 0,
4779
- autoApprove: v2.runtime.autoApprove === true
4805
+ uiAccessToken: v2.runtime.uiAccessToken || void 0
4780
4806
  };
4781
4807
  }
4782
4808
  function buildV2FileFromExpandedConfig(config, current) {
4783
4809
  const hasExplicitChannels = Array.isArray(config.channels);
4784
4810
  let channels = hasExplicitChannels ? [...config.channels || []] : [...current?.channels || []];
4811
+ channels = normalizeChannelInstances(channels);
4785
4812
  return {
4786
4813
  schemaVersion: 2,
4787
4814
  runtime: {
@@ -4796,8 +4823,7 @@ function buildV2FileFromExpandedConfig(config, current) {
4796
4823
  codexSandboxMode: config.codexSandboxMode,
4797
4824
  codexReasoningEffort: config.codexReasoningEffort,
4798
4825
  uiAllowLan: config.uiAllowLan,
4799
- uiAccessToken: config.uiAccessToken,
4800
- autoApprove: config.autoApprove
4826
+ uiAccessToken: config.uiAccessToken
4801
4827
  },
4802
4828
  channels: channels.map((channel) => ({
4803
4829
  ...channel,
@@ -4827,8 +4853,7 @@ function loadConfig() {
4827
4853
  codexSkipGitRepoCheck: true,
4828
4854
  codexSandboxMode: "workspace-write",
4829
4855
  codexReasoningEffort: "medium",
4830
- uiAllowLan: false,
4831
- autoApprove: false
4856
+ uiAllowLan: false
4832
4857
  },
4833
4858
  channels: []
4834
4859
  };
@@ -4894,7 +4919,6 @@ function saveConfig(config) {
4894
4919
  out += formatEnvLine("CTI_WEIXIN_COMMAND_MARKDOWN_ENABLED", String(weixinConfig.feedbackMarkdownEnabled));
4895
4920
  }
4896
4921
  }
4897
- out += formatEnvLine("CTI_AUTO_APPROVE", String(next.runtime.autoApprove === true));
4898
4922
  ensureConfigDir();
4899
4923
  const tmpPath = CONFIG_PATH + ".tmp";
4900
4924
  fs.writeFileSync(tmpPath, out, { mode: 384 });
@@ -4908,13 +4932,14 @@ function findChannelInstance(channelId, config) {
4908
4932
  }
4909
4933
  function configToSettings(config) {
4910
4934
  const m = /* @__PURE__ */ new Map();
4935
+ const channels = normalizeChannelInstances(config.channels || []);
4911
4936
  const current = {
4912
4937
  schemaVersion: 2,
4913
4938
  runtime: {
4914
4939
  provider: config.runtime,
4915
4940
  defaultMode: config.defaultMode
4916
4941
  },
4917
- channels: config.channels || []
4942
+ channels
4918
4943
  };
4919
4944
  const feishu = getChannelByProvider(current, "feishu");
4920
4945
  const weixin = getChannelByProvider(current, "weixin");
@@ -4959,23 +4984,8 @@ function configToSettings(config) {
4959
4984
  );
4960
4985
  m.set(
4961
4986
  "bridge_channel_instances_json",
4962
- JSON.stringify(config.channels || [])
4963
- );
4964
- m.set(
4965
- "bridge_telegram_enabled",
4966
- config.enabledChannels.includes("telegram") ? "true" : "false"
4967
- );
4968
- if (config.tgBotToken) m.set("telegram_bot_token", config.tgBotToken);
4969
- if (config.tgAllowedUsers) m.set("telegram_bridge_allowed_users", config.tgAllowedUsers.join(","));
4970
- if (config.tgChatId) m.set("telegram_chat_id", config.tgChatId);
4971
- m.set(
4972
- "bridge_discord_enabled",
4973
- config.enabledChannels.includes("discord") ? "true" : "false"
4987
+ JSON.stringify(channels)
4974
4988
  );
4975
- if (config.discordBotToken) m.set("bridge_discord_bot_token", config.discordBotToken);
4976
- if (config.discordAllowedUsers) m.set("bridge_discord_allowed_users", config.discordAllowedUsers.join(","));
4977
- if (config.discordAllowedChannels) m.set("bridge_discord_allowed_channels", config.discordAllowedChannels.join(","));
4978
- if (config.discordAllowedGuilds) m.set("bridge_discord_allowed_guilds", config.discordAllowedGuilds.join(","));
4979
4989
  m.set(
4980
4990
  "bridge_feishu_enabled",
4981
4991
  feishu?.enabled === true ? "true" : "false"
@@ -4992,19 +5002,6 @@ function configToSettings(config) {
4992
5002
  "bridge_feishu_command_markdown_enabled",
4993
5003
  feishuConfig?.feedbackMarkdownEnabled === false ? "false" : "true"
4994
5004
  );
4995
- m.set(
4996
- "bridge_qq_enabled",
4997
- config.enabledChannels.includes("qq") ? "true" : "false"
4998
- );
4999
- if (config.qqAppId) m.set("bridge_qq_app_id", config.qqAppId);
5000
- if (config.qqAppSecret) m.set("bridge_qq_app_secret", config.qqAppSecret);
5001
- if (config.qqAllowedUsers) m.set("bridge_qq_allowed_users", config.qqAllowedUsers.join(","));
5002
- if (config.qqImageEnabled !== void 0) {
5003
- m.set("bridge_qq_image_enabled", String(config.qqImageEnabled));
5004
- }
5005
- if (config.qqMaxImageSize !== void 0) {
5006
- m.set("bridge_qq_max_image_size", String(config.qqMaxImageSize));
5007
- }
5008
5005
  m.set(
5009
5006
  "bridge_weixin_enabled",
5010
5007
  weixin?.enabled === true ? "true" : "false"
@@ -5414,6 +5411,42 @@ function isArchivedDesktopThread(threadId) {
5414
5411
 
5415
5412
  // src/session-bindings.ts
5416
5413
  import path3 from "node:path";
5414
+
5415
+ // src/lib/bridge/binding-audit.ts
5416
+ function describeBinding(binding) {
5417
+ if (!binding) return "none";
5418
+ const parts = [
5419
+ `session=${binding.codepilotSessionId}`,
5420
+ `sdk=${binding.sdkSessionId || "-"}`,
5421
+ `mode=${binding.mode}`
5422
+ ];
5423
+ if (binding.workingDirectory) {
5424
+ parts.push(`cwd=${binding.workingDirectory}`);
5425
+ }
5426
+ return parts.join(", ");
5427
+ }
5428
+ function recordBindingChange(store, input) {
5429
+ const from = describeBinding(input.fromBinding);
5430
+ const to = describeBinding(input.toBinding);
5431
+ const details = [
5432
+ `action=${input.action}`,
5433
+ `from=[${from}]`,
5434
+ `to=[${to}]`
5435
+ ];
5436
+ if (input.source) details.push(`source=${input.source}`);
5437
+ if (input.reason) details.push(`reason=${input.reason}`);
5438
+ store.insertAuditLog({
5439
+ channelType: input.address.channelType,
5440
+ channelProvider: input.address.channelProvider || input.toBinding?.channelProvider || input.fromBinding?.channelProvider,
5441
+ channelAlias: input.address.channelAlias || input.toBinding?.channelAlias || input.fromBinding?.channelAlias,
5442
+ chatId: input.address.chatId,
5443
+ direction: "inbound",
5444
+ messageId: input.messageId || `binding-change:${Date.now()}`,
5445
+ summary: `Binding change: ${details.join("; ")}`
5446
+ });
5447
+ }
5448
+
5449
+ // src/session-bindings.ts
5417
5450
  function asChannelProvider(value) {
5418
5451
  return value === "feishu" || value === "weixin" ? value : void 0;
5419
5452
  }
@@ -5591,6 +5624,7 @@ function updateBindingTarget(store, bindingId, targetKey) {
5591
5624
  if (!binding) {
5592
5625
  throw new Error("Binding not found.");
5593
5626
  }
5627
+ const fromBinding = { ...binding };
5594
5628
  if (targetKey.startsWith("desktop:")) {
5595
5629
  const threadId = targetKey.slice("desktop:".length);
5596
5630
  const desktop = getDesktopSessionByThreadId(threadId);
@@ -5616,6 +5650,20 @@ function updateBindingTarget(store, bindingId, targetKey) {
5616
5650
  } else {
5617
5651
  throw new Error("Unsupported target.");
5618
5652
  }
5653
+ const toBinding = store.getChannelBinding(binding.channelType, binding.chatId);
5654
+ recordBindingChange(store, {
5655
+ action: "web_switch",
5656
+ address: {
5657
+ channelType: binding.channelType,
5658
+ channelProvider: binding.channelProvider,
5659
+ channelAlias: binding.channelAlias,
5660
+ chatId: binding.chatId
5661
+ },
5662
+ fromBinding,
5663
+ toBinding,
5664
+ source: "web_ui",
5665
+ reason: `target=${targetKey}`
5666
+ });
5619
5667
  const updated = listBindingSummaries(store).find((item) => item.id === bindingId);
5620
5668
  if (!updated) {
5621
5669
  throw new Error("Updated binding not found.");
@@ -5627,50 +5675,102 @@ function removeBinding(store, bindingId) {
5627
5675
  if (!binding) {
5628
5676
  throw new Error("Binding not found.");
5629
5677
  }
5678
+ const fromBinding = { ...binding };
5630
5679
  store.deleteChannelBinding(bindingId);
5680
+ recordBindingChange(store, {
5681
+ action: "web_unbind",
5682
+ address: {
5683
+ channelType: binding.channelType,
5684
+ channelProvider: binding.channelProvider,
5685
+ channelAlias: binding.channelAlias,
5686
+ chatId: binding.chatId
5687
+ },
5688
+ fromBinding,
5689
+ toBinding: null,
5690
+ source: "web_ui"
5691
+ });
5631
5692
  }
5632
5693
 
5633
5694
  // src/service-manager.ts
5634
- import fs3 from "node:fs";
5695
+ import fs4 from "node:fs";
5635
5696
  import os3 from "node:os";
5636
- import path4 from "node:path";
5697
+ import path5 from "node:path";
5637
5698
  import { spawn } from "node:child_process";
5638
5699
  import { fileURLToPath } from "node:url";
5639
- var moduleDir = path4.dirname(fileURLToPath(import.meta.url));
5640
- var packageRoot = path4.resolve(moduleDir, "..");
5700
+
5701
+ // src/bridge-instance-lock.ts
5702
+ import fs3 from "node:fs";
5703
+ import path4 from "node:path";
5641
5704
  var runtimeDir = path4.join(CTI_HOME, "runtime");
5642
- var logsDir = path4.join(CTI_HOME, "logs");
5643
- var bridgePidFile = path4.join(runtimeDir, "bridge.pid");
5644
- var bridgeStatusFile = path4.join(runtimeDir, "status.json");
5645
- var bridgeStartLockFile = path4.join(runtimeDir, "bridge.start.lock");
5646
- var uiStatusFile = path4.join(runtimeDir, "ui-server.json");
5705
+ var bridgeInstanceLockFile = path4.join(runtimeDir, "bridge.instance.lock");
5706
+ function readJsonFile(filePath, fallback) {
5707
+ try {
5708
+ return JSON.parse(fs3.readFileSync(filePath, "utf-8"));
5709
+ } catch {
5710
+ return fallback;
5711
+ }
5712
+ }
5713
+ function isProcessAlive(pid) {
5714
+ if (!pid) return false;
5715
+ try {
5716
+ process.kill(pid, 0);
5717
+ return true;
5718
+ } catch {
5719
+ return false;
5720
+ }
5721
+ }
5722
+ function readBridgeInstanceLock(filePath = bridgeInstanceLockFile) {
5723
+ const parsed = readJsonFile(filePath, null);
5724
+ const pid = Number(parsed?.pid);
5725
+ const createdAt = typeof parsed?.createdAt === "string" ? parsed.createdAt : "";
5726
+ if (!Number.isFinite(pid) || pid <= 0 || !createdAt) return null;
5727
+ return { pid, createdAt };
5728
+ }
5729
+ function clearStaleBridgeInstanceLock(filePath = bridgeInstanceLockFile, isAlive = isProcessAlive) {
5730
+ const existing = readBridgeInstanceLock(filePath);
5731
+ if (existing && isAlive(existing.pid)) return;
5732
+ try {
5733
+ fs3.unlinkSync(filePath);
5734
+ } catch {
5735
+ }
5736
+ }
5737
+
5738
+ // src/service-manager.ts
5739
+ var moduleDir = path5.dirname(fileURLToPath(import.meta.url));
5740
+ var packageRoot = path5.resolve(moduleDir, "..");
5741
+ var runtimeDir2 = path5.join(CTI_HOME, "runtime");
5742
+ var logsDir = path5.join(CTI_HOME, "logs");
5743
+ var bridgePidFile = path5.join(runtimeDir2, "bridge.pid");
5744
+ var bridgeStatusFile = path5.join(runtimeDir2, "status.json");
5745
+ var bridgeStartLockFile = path5.join(runtimeDir2, "bridge.start.lock");
5746
+ var uiStatusFile = path5.join(runtimeDir2, "ui-server.json");
5647
5747
  var uiPort = 4781;
5648
5748
  var bridgeAutostartTaskName = "CodexToIMBridge";
5649
- var bridgeAutostartLauncherFile = path4.join(runtimeDir, "bridge-autostart.ps1");
5650
- var npmUninstallLogFile = path4.join(runtimeDir, "npm-uninstall.log");
5749
+ var bridgeAutostartLauncherFile = path5.join(runtimeDir2, "bridge-autostart.ps1");
5750
+ var npmUninstallLogFile = path5.join(runtimeDir2, "npm-uninstall.log");
5651
5751
  var WINDOWS_HIDE = process.platform === "win32" ? { windowsHide: true } : {};
5652
5752
  var BRIDGE_START_LOCK_STALE_MS = 3e4;
5653
5753
  function ensureDirs() {
5654
- fs3.mkdirSync(runtimeDir, { recursive: true });
5655
- fs3.mkdirSync(logsDir, { recursive: true });
5754
+ fs4.mkdirSync(runtimeDir2, { recursive: true });
5755
+ fs4.mkdirSync(logsDir, { recursive: true });
5656
5756
  }
5657
- function readJsonFile(filePath, fallback) {
5757
+ function readJsonFile2(filePath, fallback) {
5658
5758
  try {
5659
- return JSON.parse(fs3.readFileSync(filePath, "utf-8"));
5759
+ return JSON.parse(fs4.readFileSync(filePath, "utf-8"));
5660
5760
  } catch {
5661
5761
  return fallback;
5662
5762
  }
5663
5763
  }
5664
5764
  function readPid(filePath) {
5665
5765
  try {
5666
- const raw = fs3.readFileSync(filePath, "utf-8").trim();
5766
+ const raw = fs4.readFileSync(filePath, "utf-8").trim();
5667
5767
  const pid = Number(raw);
5668
5768
  return Number.isFinite(pid) ? pid : void 0;
5669
5769
  } catch {
5670
5770
  return void 0;
5671
5771
  }
5672
5772
  }
5673
- function isProcessAlive(pid) {
5773
+ function isProcessAlive2(pid) {
5674
5774
  if (!pid) return false;
5675
5775
  try {
5676
5776
  process.kill(pid, 0);
@@ -5679,32 +5779,37 @@ function isProcessAlive(pid) {
5679
5779
  return false;
5680
5780
  }
5681
5781
  }
5682
- function collectTrackedBridgePids(bridgePid, statusPid) {
5782
+ function collectTrackedBridgePids(bridgePid, statusPid, instanceLockPid) {
5683
5783
  const unique = /* @__PURE__ */ new Set();
5684
- for (const pid of [bridgePid, statusPid]) {
5784
+ for (const pid of [bridgePid, statusPid, instanceLockPid]) {
5685
5785
  if (Number.isFinite(pid) && pid > 0) {
5686
5786
  unique.add(pid);
5687
5787
  }
5688
5788
  }
5689
5789
  return [...unique];
5690
5790
  }
5691
- function resolveTrackedBridgePid(bridgePid, statusPid, isAlive = isProcessAlive) {
5791
+ function resolveTrackedBridgePid(bridgePid, statusPid, instanceLockPid, isAlive = isProcessAlive2) {
5692
5792
  if (isAlive(bridgePid)) return bridgePid;
5693
5793
  if (isAlive(statusPid)) return statusPid;
5694
- return bridgePid ?? statusPid;
5794
+ if (isAlive(instanceLockPid)) return instanceLockPid;
5795
+ return bridgePid ?? statusPid ?? instanceLockPid;
5695
5796
  }
5696
5797
  function getTrackedBridgePids(status) {
5697
- const resolvedStatus = status ?? readJsonFile(bridgeStatusFile, { running: false });
5698
- return collectTrackedBridgePids(readPid(bridgePidFile), resolvedStatus.pid);
5798
+ const resolvedStatus = status ?? readJsonFile2(bridgeStatusFile, { running: false });
5799
+ return collectTrackedBridgePids(
5800
+ readPid(bridgePidFile),
5801
+ resolvedStatus.pid,
5802
+ readBridgeInstanceLock()?.pid
5803
+ );
5699
5804
  }
5700
5805
  function clearBridgePidFile() {
5701
5806
  try {
5702
- fs3.unlinkSync(bridgePidFile);
5807
+ fs4.unlinkSync(bridgePidFile);
5703
5808
  } catch {
5704
5809
  }
5705
5810
  }
5706
5811
  function readBridgeStartLock(filePath = bridgeStartLockFile) {
5707
- const parsed = readJsonFile(filePath, null);
5812
+ const parsed = readJsonFile2(filePath, null);
5708
5813
  const pid = Number(parsed?.pid);
5709
5814
  const createdAt = typeof parsed?.createdAt === "string" ? parsed.createdAt : "";
5710
5815
  if (!Number.isFinite(pid) || pid <= 0 || !createdAt) return null;
@@ -5714,7 +5819,7 @@ function isBridgeStartLockStale(lock, options = {}) {
5714
5819
  if (!lock) return true;
5715
5820
  const nowMs = options.nowMs ?? Date.now();
5716
5821
  const staleMs = options.staleMs ?? BRIDGE_START_LOCK_STALE_MS;
5717
- const isAlive = options.isAlive ?? isProcessAlive;
5822
+ const isAlive = options.isAlive ?? isProcessAlive2;
5718
5823
  const createdAtMs = Date.parse(lock.createdAt);
5719
5824
  if (!Number.isFinite(createdAtMs)) return true;
5720
5825
  if (!isAlive(lock.pid)) return true;
@@ -5730,7 +5835,7 @@ function tryAcquireBridgeStartLock(options = {}) {
5730
5835
  };
5731
5836
  for (let attempt = 0; attempt < 2; attempt += 1) {
5732
5837
  try {
5733
- fs3.writeFileSync(filePath, JSON.stringify(payload, null, 2), { encoding: "utf-8", flag: "wx" });
5838
+ fs4.writeFileSync(filePath, JSON.stringify(payload, null, 2), { encoding: "utf-8", flag: "wx" });
5734
5839
  return { acquired: true };
5735
5840
  } catch (error) {
5736
5841
  const code = error.code;
@@ -5744,7 +5849,7 @@ function tryAcquireBridgeStartLock(options = {}) {
5744
5849
  return { acquired: false, holderPid: existing2?.pid };
5745
5850
  }
5746
5851
  try {
5747
- fs3.unlinkSync(filePath);
5852
+ fs4.unlinkSync(filePath);
5748
5853
  } catch {
5749
5854
  }
5750
5855
  }
@@ -5756,14 +5861,14 @@ function releaseBridgeStartLock(filePath = bridgeStartLockFile, ownerPid = proce
5756
5861
  const existing = readBridgeStartLock(filePath);
5757
5862
  if (!existing) {
5758
5863
  try {
5759
- fs3.unlinkSync(filePath);
5864
+ fs4.unlinkSync(filePath);
5760
5865
  } catch {
5761
5866
  }
5762
5867
  return;
5763
5868
  }
5764
5869
  if (existing.pid !== ownerPid) return;
5765
5870
  try {
5766
- fs3.unlinkSync(filePath);
5871
+ fs4.unlinkSync(filePath);
5767
5872
  } catch {
5768
5873
  }
5769
5874
  }
@@ -5820,9 +5925,13 @@ function getUiServerUrl(port2 = uiPort) {
5820
5925
  return `http://127.0.0.1:${port2}`;
5821
5926
  }
5822
5927
  function getBridgeStatus() {
5823
- const status = readJsonFile(bridgeStatusFile, { running: false });
5824
- const pid = resolveTrackedBridgePid(readPid(bridgePidFile), status.pid);
5825
- if (!isProcessAlive(pid)) {
5928
+ const status = readJsonFile2(bridgeStatusFile, { running: false });
5929
+ const pid = resolveTrackedBridgePid(
5930
+ readPid(bridgePidFile),
5931
+ status.pid,
5932
+ readBridgeInstanceLock()?.pid
5933
+ );
5934
+ if (!isProcessAlive2(pid)) {
5826
5935
  return {
5827
5936
  ...status,
5828
5937
  pid,
@@ -5836,8 +5945,8 @@ function getBridgeStatus() {
5836
5945
  };
5837
5946
  }
5838
5947
  function getUiServerStatus() {
5839
- const status = readJsonFile(uiStatusFile, { running: false, port: uiPort });
5840
- if (!isProcessAlive(status.pid)) {
5948
+ const status = readJsonFile2(uiStatusFile, { running: false, port: uiPort });
5949
+ if (!isProcessAlive2(status.pid)) {
5841
5950
  return {
5842
5951
  ...status,
5843
5952
  running: false,
@@ -5907,7 +6016,7 @@ async function waitForBridgeStartupTurn(timeoutMs = 2e4) {
5907
6016
  async function startBridge() {
5908
6017
  ensureDirs();
5909
6018
  const current = getBridgeStatus();
5910
- const extraAlivePids = getTrackedBridgePids(current).filter((pid) => pid !== current.pid && isProcessAlive(pid));
6019
+ const extraAlivePids = getTrackedBridgePids(current).filter((pid) => pid !== current.pid && isProcessAlive2(pid));
5911
6020
  if (current.running && extraAlivePids.length === 0) return current;
5912
6021
  if (current.running && extraAlivePids.length > 0) {
5913
6022
  await stopBridge();
@@ -5932,17 +6041,17 @@ async function startBridge() {
5932
6041
  startLockHeld = true;
5933
6042
  try {
5934
6043
  const currentAfterLock = getBridgeStatus();
5935
- const extraAlivePidsAfterLock = getTrackedBridgePids(currentAfterLock).filter((pid) => pid !== currentAfterLock.pid && isProcessAlive(pid));
6044
+ const extraAlivePidsAfterLock = getTrackedBridgePids(currentAfterLock).filter((pid) => pid !== currentAfterLock.pid && isProcessAlive2(pid));
5936
6045
  if (currentAfterLock.running && extraAlivePidsAfterLock.length === 0) return currentAfterLock;
5937
6046
  if (currentAfterLock.running && extraAlivePidsAfterLock.length > 0) {
5938
6047
  await stopBridge();
5939
6048
  }
5940
- const daemonEntry = path4.join(packageRoot, "dist", "daemon.mjs");
5941
- if (!fs3.existsSync(daemonEntry)) {
6049
+ const daemonEntry = path5.join(packageRoot, "dist", "daemon.mjs");
6050
+ if (!fs4.existsSync(daemonEntry)) {
5942
6051
  throw new Error(`Daemon bundle not found at ${daemonEntry}. Run npm run build first.`);
5943
6052
  }
5944
- const stdoutFd = fs3.openSync(path4.join(logsDir, "bridge-launcher.out.log"), "a");
5945
- const stderrFd = fs3.openSync(path4.join(logsDir, "bridge-launcher.err.log"), "a");
6053
+ const stdoutFd = fs4.openSync(path5.join(logsDir, "bridge-launcher.out.log"), "a");
6054
+ const stderrFd = fs4.openSync(path5.join(logsDir, "bridge-launcher.err.log"), "a");
5946
6055
  const child = spawn(process.execPath, [daemonEntry], {
5947
6056
  cwd: packageRoot,
5948
6057
  detached: true,
@@ -5965,10 +6074,11 @@ async function startBridge() {
5965
6074
  }
5966
6075
  }
5967
6076
  async function stopBridge() {
5968
- const status = readJsonFile(bridgeStatusFile, { running: false });
5969
- const pids = getTrackedBridgePids(status).filter((pid) => isProcessAlive(pid));
6077
+ const status = readJsonFile2(bridgeStatusFile, { running: false });
6078
+ const pids = getTrackedBridgePids(status).filter((pid) => isProcessAlive2(pid));
5970
6079
  if (pids.length === 0) {
5971
6080
  clearBridgePidFile();
6081
+ clearStaleBridgeInstanceLock();
5972
6082
  return { ...getBridgeStatus(), running: false };
5973
6083
  }
5974
6084
  for (const pid of pids) {
@@ -5990,13 +6100,15 @@ async function stopBridge() {
5990
6100
  }
5991
6101
  const startedAt = Date.now();
5992
6102
  while (Date.now() - startedAt < 1e4) {
5993
- if (pids.every((pid) => !isProcessAlive(pid))) {
6103
+ if (pids.every((pid) => !isProcessAlive2(pid))) {
5994
6104
  clearBridgePidFile();
6105
+ clearStaleBridgeInstanceLock();
5995
6106
  return getBridgeStatus();
5996
6107
  }
5997
6108
  await sleep(300);
5998
6109
  }
5999
6110
  clearBridgePidFile();
6111
+ clearStaleBridgeInstanceLock();
6000
6112
  return getBridgeStatus();
6001
6113
  }
6002
6114
  async function restartBridge() {
@@ -6059,37 +6171,37 @@ async function getBridgeAutostartStatus() {
6059
6171
  }
6060
6172
  function getBridgeLogs(lines = 200) {
6061
6173
  ensureDirs();
6062
- const filePath = path4.join(logsDir, "bridge.log");
6063
- if (!fs3.existsSync(filePath)) return "";
6064
- const all = fs3.readFileSync(filePath, "utf-8").split(/\r?\n/);
6174
+ const filePath = path5.join(logsDir, "bridge.log");
6175
+ if (!fs4.existsSync(filePath)) return "";
6176
+ const all = fs4.readFileSync(filePath, "utf-8").split(/\r?\n/);
6065
6177
  return all.slice(Math.max(0, all.length - lines)).join("\n");
6066
6178
  }
6067
6179
  function writeUiServerStatus(status) {
6068
6180
  ensureDirs();
6069
- fs3.writeFileSync(uiStatusFile, JSON.stringify(status, null, 2), "utf-8");
6181
+ fs4.writeFileSync(uiStatusFile, JSON.stringify(status, null, 2), "utf-8");
6070
6182
  }
6071
6183
  async function installCodexIntegration() {
6072
- const sourceSkill = path4.join(packageRoot, "SKILL.md");
6073
- if (!fs3.existsSync(sourceSkill)) {
6184
+ const sourceSkill = path5.join(packageRoot, "SKILL.md");
6185
+ if (!fs4.existsSync(sourceSkill)) {
6074
6186
  throw new Error(`SKILL.md not found at ${sourceSkill}`);
6075
6187
  }
6076
- const skillsDir = path4.join(os3.homedir(), ".codex", "skills");
6077
- const targetDir = path4.join(skillsDir, "codex-to-im");
6078
- fs3.mkdirSync(skillsDir, { recursive: true });
6079
- if (fs3.existsSync(targetDir)) {
6188
+ const skillsDir = path5.join(os3.homedir(), ".codex", "skills");
6189
+ const targetDir = path5.join(skillsDir, "codex-to-im");
6190
+ fs4.mkdirSync(skillsDir, { recursive: true });
6191
+ if (fs4.existsSync(targetDir)) {
6080
6192
  return { targetDir, method: "existing" };
6081
6193
  }
6082
6194
  try {
6083
- fs3.symlinkSync(packageRoot, targetDir, process.platform === "win32" ? "junction" : "dir");
6195
+ fs4.symlinkSync(packageRoot, targetDir, process.platform === "win32" ? "junction" : "dir");
6084
6196
  return { targetDir, method: "junction" };
6085
6197
  } catch {
6086
- fs3.cpSync(packageRoot, targetDir, {
6198
+ fs4.cpSync(packageRoot, targetDir, {
6087
6199
  recursive: true,
6088
6200
  filter: (source) => {
6089
- const relative = path4.relative(packageRoot, source);
6201
+ const relative = path5.relative(packageRoot, source);
6090
6202
  if (!relative) return true;
6091
- if (relative === ".git" || relative.startsWith(`.git${path4.sep}`)) return false;
6092
- if (relative === "node_modules" || relative.startsWith(`node_modules${path4.sep}`)) return false;
6203
+ if (relative === ".git" || relative.startsWith(`.git${path5.sep}`)) return false;
6204
+ if (relative === "node_modules" || relative.startsWith(`node_modules${path5.sep}`)) return false;
6093
6205
  return true;
6094
6206
  }
6095
6207
  });
@@ -6097,27 +6209,27 @@ async function installCodexIntegration() {
6097
6209
  }
6098
6210
  }
6099
6211
  function isCodexIntegrationInstalled() {
6100
- const targetDir = path4.join(os3.homedir(), ".codex", "skills", "codex-to-im");
6101
- return fs3.existsSync(path4.join(targetDir, "SKILL.md"));
6212
+ const targetDir = path5.join(os3.homedir(), ".codex", "skills", "codex-to-im");
6213
+ return fs4.existsSync(path5.join(targetDir, "SKILL.md"));
6102
6214
  }
6103
6215
 
6104
6216
  // src/store.ts
6105
- import fs4 from "node:fs";
6106
- import path5 from "node:path";
6217
+ import fs5 from "node:fs";
6218
+ import path6 from "node:path";
6107
6219
  import crypto2 from "node:crypto";
6108
- var DATA_DIR = path5.join(CTI_HOME, "data");
6109
- var MESSAGES_DIR = path5.join(DATA_DIR, "messages");
6220
+ var DATA_DIR = path6.join(CTI_HOME, "data");
6221
+ var MESSAGES_DIR = path6.join(DATA_DIR, "messages");
6110
6222
  function ensureDir(dir) {
6111
- fs4.mkdirSync(dir, { recursive: true });
6223
+ fs5.mkdirSync(dir, { recursive: true });
6112
6224
  }
6113
6225
  function atomicWrite(filePath, data) {
6114
6226
  const tmp = filePath + ".tmp";
6115
- fs4.writeFileSync(tmp, data, "utf-8");
6116
- fs4.renameSync(tmp, filePath);
6227
+ fs5.writeFileSync(tmp, data, "utf-8");
6228
+ fs5.renameSync(tmp, filePath);
6117
6229
  }
6118
6230
  function readJson(filePath, fallback) {
6119
6231
  try {
6120
- const raw = fs4.readFileSync(filePath, "utf-8");
6232
+ const raw = fs5.readFileSync(filePath, "utf-8");
6121
6233
  return JSON.parse(raw);
6122
6234
  } catch {
6123
6235
  return fallback;
@@ -6186,38 +6298,38 @@ var JsonFileStore = class {
6186
6298
  this.reloadSessions();
6187
6299
  this.reloadBindings();
6188
6300
  const perms = readJson(
6189
- path5.join(DATA_DIR, "permissions.json"),
6301
+ path6.join(DATA_DIR, "permissions.json"),
6190
6302
  {}
6191
6303
  );
6192
6304
  for (const [id, p] of Object.entries(perms)) {
6193
6305
  this.permissionLinks.set(id, p);
6194
6306
  }
6195
6307
  const offsets = readJson(
6196
- path5.join(DATA_DIR, "offsets.json"),
6308
+ path6.join(DATA_DIR, "offsets.json"),
6197
6309
  {}
6198
6310
  );
6199
6311
  for (const [k, v] of Object.entries(offsets)) {
6200
6312
  this.offsets.set(k, v);
6201
6313
  }
6202
6314
  const dedup = readJson(
6203
- path5.join(DATA_DIR, "dedup.json"),
6315
+ path6.join(DATA_DIR, "dedup.json"),
6204
6316
  {}
6205
6317
  );
6206
6318
  for (const [k, v] of Object.entries(dedup)) {
6207
6319
  this.dedupKeys.set(k, v);
6208
6320
  }
6209
- this.auditLog = readJson(path5.join(DATA_DIR, "audit.json"), []);
6321
+ this.auditLog = readJson(path6.join(DATA_DIR, "audit.json"), []);
6210
6322
  }
6211
6323
  reloadSessions() {
6212
6324
  const sessions = readJson(
6213
- path5.join(DATA_DIR, "sessions.json"),
6325
+ path6.join(DATA_DIR, "sessions.json"),
6214
6326
  {}
6215
6327
  );
6216
6328
  this.sessions = new Map(Object.entries(sessions));
6217
6329
  }
6218
6330
  reloadBindings() {
6219
6331
  const bindings = readJson(
6220
- path5.join(DATA_DIR, "bindings.json"),
6332
+ path6.join(DATA_DIR, "bindings.json"),
6221
6333
  {}
6222
6334
  );
6223
6335
  const normalized = /* @__PURE__ */ new Map();
@@ -6236,47 +6348,47 @@ var JsonFileStore = class {
6236
6348
  }
6237
6349
  persistSessions() {
6238
6350
  writeJson(
6239
- path5.join(DATA_DIR, "sessions.json"),
6351
+ path6.join(DATA_DIR, "sessions.json"),
6240
6352
  Object.fromEntries(this.sessions)
6241
6353
  );
6242
6354
  }
6243
6355
  persistBindings() {
6244
6356
  writeJson(
6245
- path5.join(DATA_DIR, "bindings.json"),
6357
+ path6.join(DATA_DIR, "bindings.json"),
6246
6358
  Object.fromEntries(this.bindings)
6247
6359
  );
6248
6360
  }
6249
6361
  persistPermissions() {
6250
6362
  writeJson(
6251
- path5.join(DATA_DIR, "permissions.json"),
6363
+ path6.join(DATA_DIR, "permissions.json"),
6252
6364
  Object.fromEntries(this.permissionLinks)
6253
6365
  );
6254
6366
  }
6255
6367
  persistOffsets() {
6256
6368
  writeJson(
6257
- path5.join(DATA_DIR, "offsets.json"),
6369
+ path6.join(DATA_DIR, "offsets.json"),
6258
6370
  Object.fromEntries(this.offsets)
6259
6371
  );
6260
6372
  }
6261
6373
  persistDedup() {
6262
6374
  writeJson(
6263
- path5.join(DATA_DIR, "dedup.json"),
6375
+ path6.join(DATA_DIR, "dedup.json"),
6264
6376
  Object.fromEntries(this.dedupKeys)
6265
6377
  );
6266
6378
  }
6267
6379
  persistAudit() {
6268
- writeJson(path5.join(DATA_DIR, "audit.json"), this.auditLog);
6380
+ writeJson(path6.join(DATA_DIR, "audit.json"), this.auditLog);
6269
6381
  }
6270
6382
  persistMessages(sessionId) {
6271
6383
  const msgs = this.messages.get(sessionId) || [];
6272
- writeJson(path5.join(MESSAGES_DIR, `${sessionId}.json`), msgs);
6384
+ writeJson(path6.join(MESSAGES_DIR, `${sessionId}.json`), msgs);
6273
6385
  }
6274
6386
  loadMessages(sessionId) {
6275
6387
  if (this.messages.has(sessionId)) {
6276
6388
  return this.messages.get(sessionId);
6277
6389
  }
6278
6390
  const msgs = readJson(
6279
- path5.join(MESSAGES_DIR, `${sessionId}.json`),
6391
+ path6.join(MESSAGES_DIR, `${sessionId}.json`),
6280
6392
  []
6281
6393
  );
6282
6394
  this.messages.set(sessionId, msgs);
@@ -6444,7 +6556,7 @@ var JsonFileStore = class {
6444
6556
  }
6445
6557
  this.messages.delete(sessionId);
6446
6558
  try {
6447
- fs4.rmSync(path5.join(MESSAGES_DIR, `${sessionId}.json`), { force: true });
6559
+ fs5.rmSync(path6.join(MESSAGES_DIR, `${sessionId}.json`), { force: true });
6448
6560
  } catch {
6449
6561
  }
6450
6562
  this.persistSessions();
@@ -6627,8 +6739,8 @@ var JsonFileStore = class {
6627
6739
 
6628
6740
  // src/weixin-login.ts
6629
6741
  var import_qrcode = __toESM(require_lib(), 1);
6630
- import fs6 from "node:fs";
6631
- import path7 from "node:path";
6742
+ import fs7 from "node:fs";
6743
+ import path8 from "node:path";
6632
6744
  import crypto4 from "node:crypto";
6633
6745
  import { spawn as spawn2 } from "node:child_process";
6634
6746
 
@@ -6682,24 +6794,24 @@ async function pollLoginQrStatus(qrcode, baseUrl) {
6682
6794
  }
6683
6795
 
6684
6796
  // src/weixin-store.ts
6685
- import fs5 from "node:fs";
6686
- import path6 from "node:path";
6687
- var DATA_DIR2 = path6.join(CTI_HOME, "data");
6688
- var ACCOUNTS_PATH = path6.join(DATA_DIR2, "weixin-accounts.json");
6689
- var CONTEXT_TOKENS_PATH = path6.join(DATA_DIR2, "weixin-context-tokens.json");
6797
+ import fs6 from "node:fs";
6798
+ import path7 from "node:path";
6799
+ var DATA_DIR2 = path7.join(CTI_HOME, "data");
6800
+ var ACCOUNTS_PATH = path7.join(DATA_DIR2, "weixin-accounts.json");
6801
+ var CONTEXT_TOKENS_PATH = path7.join(DATA_DIR2, "weixin-context-tokens.json");
6690
6802
  var DEFAULT_BASE_URL2 = "https://ilinkai.weixin.qq.com";
6691
6803
  var DEFAULT_CDN_BASE_URL2 = "https://novac2c.cdn.weixin.qq.com/c2c";
6692
6804
  function ensureDir2(dir) {
6693
- fs5.mkdirSync(dir, { recursive: true });
6805
+ fs6.mkdirSync(dir, { recursive: true });
6694
6806
  }
6695
6807
  function atomicWrite2(filePath, data) {
6696
6808
  const tmpPath = `${filePath}.tmp`;
6697
- fs5.writeFileSync(tmpPath, data, "utf-8");
6698
- fs5.renameSync(tmpPath, filePath);
6809
+ fs6.writeFileSync(tmpPath, data, "utf-8");
6810
+ fs6.renameSync(tmpPath, filePath);
6699
6811
  }
6700
6812
  function readJson2(filePath, fallback) {
6701
6813
  try {
6702
- const raw = fs5.readFileSync(filePath, "utf-8");
6814
+ const raw = fs6.readFileSync(filePath, "utf-8");
6703
6815
  return JSON.parse(raw);
6704
6816
  } catch {
6705
6817
  return fallback;
@@ -6789,11 +6901,11 @@ var MAX_REFRESHES = 3;
6789
6901
  var QR_TTL_MS = 5 * 6e4;
6790
6902
  var POLL_INTERVAL_MS = 3e3;
6791
6903
  var WEB_SESSION_TTL_MS = 15 * 6e4;
6792
- var RUNTIME_DIR = path7.join(CTI_HOME, "runtime");
6793
- var HTML_PATH = path7.join(RUNTIME_DIR, "weixin-login.html");
6904
+ var RUNTIME_DIR = path8.join(CTI_HOME, "runtime");
6905
+ var HTML_PATH = path8.join(RUNTIME_DIR, "weixin-login.html");
6794
6906
  var webLoginSessions = /* @__PURE__ */ new Map();
6795
6907
  function ensureRuntimeDir() {
6796
- fs6.mkdirSync(RUNTIME_DIR, { recursive: true });
6908
+ fs7.mkdirSync(RUNTIME_DIR, { recursive: true });
6797
6909
  }
6798
6910
  function escapeHtml(text2) {
6799
6911
  return text2.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;");
@@ -7106,7 +7218,7 @@ function buildWeixinLoginPopupHtml(sessionId) {
7106
7218
  async function writeQrHtml(session) {
7107
7219
  ensureRuntimeDir();
7108
7220
  const qrSvg = await buildQrSvg(session.qrImageUrl);
7109
- fs6.writeFileSync(HTML_PATH, buildQrHtml(qrSvg), "utf-8");
7221
+ fs7.writeFileSync(HTML_PATH, buildQrHtml(qrSvg), "utf-8");
7110
7222
  }
7111
7223
  function openQrHtml() {
7112
7224
  try {
@@ -7367,7 +7479,7 @@ async function runWeixinLogin(config = {}) {
7367
7479
  }
7368
7480
  var isMainModule = (() => {
7369
7481
  const entry = process.argv[1];
7370
- return !!entry && path7.resolve(entry) === path7.resolve(new URL(import.meta.url).pathname);
7482
+ return !!entry && path8.resolve(entry) === path8.resolve(new URL(import.meta.url).pathname);
7371
7483
  })();
7372
7484
  if (isMainModule) {
7373
7485
  runWeixinLogin().catch((err) => {
@@ -7377,14 +7489,14 @@ if (isMainModule) {
7377
7489
  }
7378
7490
 
7379
7491
  // src/codex-models.ts
7380
- import fs7 from "node:fs";
7492
+ import fs8 from "node:fs";
7381
7493
  import os4 from "node:os";
7382
- import path8 from "node:path";
7383
- var DEFAULT_CODEX_CONFIG_PATH = path8.join(os4.homedir(), ".codex", "config.toml");
7384
- var DEFAULT_CODEX_MODELS_CACHE_PATH = path8.join(os4.homedir(), ".codex", "models_cache.json");
7494
+ import path9 from "node:path";
7495
+ var DEFAULT_CODEX_CONFIG_PATH = path9.join(os4.homedir(), ".codex", "config.toml");
7496
+ var DEFAULT_CODEX_MODELS_CACHE_PATH = path9.join(os4.homedir(), ".codex", "models_cache.json");
7385
7497
  function readConfiguredCodexModel(configPath = DEFAULT_CODEX_CONFIG_PATH) {
7386
7498
  try {
7387
- const raw = fs7.readFileSync(configPath, "utf-8");
7499
+ const raw = fs8.readFileSync(configPath, "utf-8");
7388
7500
  let inSection = false;
7389
7501
  for (const line of raw.split(/\r?\n/)) {
7390
7502
  const trimmed = line.trim();
@@ -7406,7 +7518,7 @@ function readConfiguredCodexModel(configPath = DEFAULT_CODEX_CONFIG_PATH) {
7406
7518
  }
7407
7519
  function listCachedCodexModels(cachePath = DEFAULT_CODEX_MODELS_CACHE_PATH) {
7408
7520
  try {
7409
- const raw = fs7.readFileSync(cachePath, "utf-8");
7521
+ const raw = fs8.readFileSync(cachePath, "utf-8");
7410
7522
  const parsed = JSON.parse(raw);
7411
7523
  if (!Array.isArray(parsed.models)) return [];
7412
7524
  const seen = /* @__PURE__ */ new Set();
@@ -7661,8 +7773,7 @@ function configToPayload(config) {
7661
7773
  codexReasoningEffort: config.codexReasoningEffort || "medium",
7662
7774
  uiAllowLan: config.uiAllowLan === true,
7663
7775
  uiAccessToken: config.uiAccessToken || "",
7664
- autoApprove: config.autoApprove === true,
7665
- channels: (config.channels || []).map(channelToPayload)
7776
+ channels: (config.channels || []).filter((channel) => isSupportedChannelProvider(channel.provider)).map(channelToPayload)
7666
7777
  };
7667
7778
  }
7668
7779
  function mergeConfig(payload) {
@@ -7673,7 +7784,7 @@ function mergeConfig(payload) {
7673
7784
  const uiAccessToken = requestedUiAccessToken || current.uiAccessToken || (uiAllowLan ? generateAccessToken() : void 0);
7674
7785
  return {
7675
7786
  ...current,
7676
- runtime: payload.runtime === "claude" || payload.runtime === "auto" ? payload.runtime : "codex",
7787
+ runtime: "codex",
7677
7788
  enabledChannels: current.enabledChannels,
7678
7789
  defaultWorkspaceRoot: asString(payload.defaultWorkspaceRoot),
7679
7790
  defaultModel: rawDefaultModel === void 0 ? current.defaultModel : rawDefaultModel === "" ? void 0 : availableCodexModelSlugs.has(rawDefaultModel) ? rawDefaultModel : current.defaultModel,
@@ -7686,7 +7797,6 @@ function mergeConfig(payload) {
7686
7797
  codexReasoningEffort: payload.codexReasoningEffort === "minimal" || payload.codexReasoningEffort === "low" || payload.codexReasoningEffort === "high" || payload.codexReasoningEffort === "xhigh" ? payload.codexReasoningEffort : "medium",
7687
7798
  uiAllowLan,
7688
7799
  uiAccessToken,
7689
- autoApprove: payload.autoApprove === true,
7690
7800
  channels: current.channels
7691
7801
  };
7692
7802
  }
@@ -9502,8 +9612,6 @@ function renderHtml() {
9502
9612
  Runtime
9503
9613
  <select id="runtime">
9504
9614
  <option value="codex" selected>codex</option>
9505
- <option value="auto">auto</option>
9506
- <option value="claude">claude</option>
9507
9615
  </select>
9508
9616
  </label>
9509
9617
  <label>
@@ -9519,11 +9627,11 @@ function renderHtml() {
9519
9627
  <input id="historyMessageLimit" type="number" min="1" max="20" value="8" />
9520
9628
  </label>
9521
9629
  <label>
9522
- \u9759\u9ED8\u68C0\u6D4B\u542F\u52A8\u65F6\u957F\uFF08\u79D2\uFF09
9630
+ \u4E0A\u6B21\u54CD\u5E94\u8DDD\u4ECA\u663E\u793A\u542F\u52A8\u65F6\u957F\uFF08\u79D2\uFF09
9523
9631
  <input id="streamStatusIdleStartSeconds" type="number" min="1" value="180" />
9524
9632
  </label>
9525
9633
  <label>
9526
- \u9759\u9ED8\u68C0\u6D4B\u95F4\u9694\uFF08\u79D2\uFF09
9634
+ \u4E0A\u6B21\u54CD\u5E94\u8DDD\u4ECA\u68C0\u67E5\u95F4\u9694\uFF08\u79D2\uFF09
9527
9635
  <input id="streamStatusCheckIntervalSeconds" type="number" min="1" value="10" />
9528
9636
  </label>
9529
9637
  </div>
@@ -9555,11 +9663,8 @@ function renderHtml() {
9555
9663
  </select>
9556
9664
  </label>
9557
9665
  </div>
9558
- <div class="small">\u672A\u7ED1\u5B9A\u7684 IM \u804A\u5929\u4F1A\u5148\u8FDB\u5165\u4E34\u65F6\u8349\u7A3F\u7EBF\u7A0B\uFF08\u7B49\u540C <code>/t 0</code>\uFF09\uFF1B\u201C\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4\u201D\u53EA\u7528\u4E8E <code>/new proj1</code> \u8FD9\u7C7B\u76F8\u5BF9\u9879\u76EE\u540D\u3002\u7559\u7A7A\u65F6\u4F1A\u6309\u5F53\u524D\u7CFB\u7EDF\u81EA\u52A8\u56DE\u9000\u5230 <code>~/cx2im</code>\u3002\u9ED8\u8BA4\u6A21\u578B\u5019\u9009\u9879\u6765\u81EA\u542F\u52A8\u65F6\u8BFB\u53D6\u7684 Codex \u6A21\u578B\u7F13\u5B58\uFF1A\u9690\u85CF\u6A21\u578B\u4E0D\u4F1A\u5C55\u793A\uFF0CCLI only \u6A21\u578B\u4F1A\u6807\u6210\u201C\u4EC5 IM / CLI\u201D\u3002\u7559\u7A7A\u5219\u7EE7\u7EED\u8DDF\u968F Codex \u5F53\u524D\u9ED8\u8BA4\u6A21\u578B\u3002\u6587\u4EF6\u7CFB\u7EDF\u6743\u9650\u662F\u5168\u5C40\u9ED8\u8BA4\u503C\uFF0C\u601D\u8003\u7EA7\u522B\u53EF\u5728 IM \u4F1A\u8BDD\u91CC\u518D\u5355\u72EC\u8986\u76D6\u3002\u9759\u9ED8\u68C0\u6D4B\u914D\u7F6E\u53EA\u5F71\u54CD\u98DE\u4E66\u957F\u4EFB\u52A1\u5E95\u90E8\u201C\u6700\u8FD1 X \u65E0\u65B0\u8F93\u51FA\u201D\u7684\u51FA\u73B0\u65F6\u673A\u3002</div>
9559
- <div class="small">\u5F53\u524D\u9700\u8981\u91CD\u542F Bridge \u7684\u914D\u7F6E\uFF1A<code>Runtime</code>\u3001<code>\u81EA\u52A8\u6279\u51C6\u5DE5\u5177\u6743\u9650</code>\u3001<code>\u5141\u8BB8\u5728\u672A\u4FE1\u4EFB Git \u76EE\u5F55\u8FD0\u884C Codex</code>\u3002\u901A\u9053\u5B9E\u4F8B\u7684\u63A5\u5165\u914D\u7F6E\u8BF7\u5728\u201C\u901A\u9053\u201D\u9875\u7EF4\u62A4\u3002</div>
9560
- <div class="checkbox-row">
9561
- <label class="checkbox"><input id="autoApprove" type="checkbox" /> \u81EA\u52A8\u6279\u51C6\u5DE5\u5177\u6743\u9650</label>
9562
- </div>
9666
+ <div class="small">\u672A\u7ED1\u5B9A\u7684 IM \u804A\u5929\u4F1A\u5148\u8FDB\u5165\u4E34\u65F6\u8349\u7A3F\u7EBF\u7A0B\uFF08\u7B49\u540C <code>/t 0</code>\uFF09\uFF1B\u201C\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4\u201D\u53EA\u7528\u4E8E <code>/new proj1</code> \u8FD9\u7C7B\u76F8\u5BF9\u9879\u76EE\u540D\u3002\u7559\u7A7A\u65F6\u4F1A\u6309\u5F53\u524D\u7CFB\u7EDF\u81EA\u52A8\u56DE\u9000\u5230 <code>~/cx2im</code>\u3002\u9ED8\u8BA4\u6A21\u578B\u5019\u9009\u9879\u6765\u81EA\u542F\u52A8\u65F6\u8BFB\u53D6\u7684 Codex \u6A21\u578B\u7F13\u5B58\uFF1A\u9690\u85CF\u6A21\u578B\u4E0D\u4F1A\u5C55\u793A\uFF0CCLI only \u6A21\u578B\u4F1A\u6807\u6210\u201C\u4EC5 IM / CLI\u201D\u3002\u7559\u7A7A\u5219\u7EE7\u7EED\u8DDF\u968F Codex \u5F53\u524D\u9ED8\u8BA4\u6A21\u578B\u3002\u6587\u4EF6\u7CFB\u7EDF\u6743\u9650\u662F\u5168\u5C40\u9ED8\u8BA4\u503C\uFF0C\u601D\u8003\u7EA7\u522B\u53EF\u5728 IM \u4F1A\u8BDD\u91CC\u518D\u5355\u72EC\u8986\u76D6\u3002\u4E0A\u6B21\u54CD\u5E94\u8DDD\u4ECA\u914D\u7F6E\u53EA\u5F71\u54CD\u98DE\u4E66\u957F\u4EFB\u52A1\u5E95\u90E8\u201C\u4E0A\u6B21\u54CD\u5E94\u8DDD\u4ECA X\u201D\u7684\u51FA\u73B0\u65F6\u673A\u3002</div>
9667
+ <div class="small">\u5F53\u524D\u9700\u8981\u91CD\u542F Bridge \u7684\u914D\u7F6E\uFF1A<code>Runtime</code>\u3001<code>\u5141\u8BB8\u5728\u672A\u4FE1\u4EFB Git \u76EE\u5F55\u8FD0\u884C Codex</code>\u3002\u901A\u9053\u5B9E\u4F8B\u7684\u63A5\u5165\u914D\u7F6E\u8BF7\u5728\u201C\u901A\u9053\u201D\u9875\u7EF4\u62A4\u3002</div>
9563
9668
  <div class="checkbox-row">
9564
9669
  <label class="checkbox"><input id="codexSkipGitRepoCheck" type="checkbox" checked /> \u5141\u8BB8\u5728\u672A\u4FE1\u4EFB Git \u76EE\u5F55\u8FD0\u884C Codex</label>
9565
9670
  </div>
@@ -9884,7 +9989,6 @@ function renderHtml() {
9884
9989
  codexReasoningEffort: document.getElementById('codexReasoningEffort').value,
9885
9990
  uiAllowLan: document.getElementById('uiAllowLan').checked,
9886
9991
  uiAccessToken: document.getElementById('uiAccessToken').value,
9887
- autoApprove: document.getElementById('autoApprove').checked,
9888
9992
  };
9889
9993
  }
9890
9994
 
@@ -10054,20 +10158,18 @@ function renderHtml() {
10054
10158
  defaultModel: '\u9ED8\u8BA4\u6A21\u578B',
10055
10159
  defaultMode: '\u9ED8\u8BA4\u6A21\u5F0F',
10056
10160
  historyMessageLimit: '/history \u8FD4\u56DE\u6761\u6570',
10057
- streamStatusIdleStartSeconds: '\u9759\u9ED8\u68C0\u6D4B\u542F\u52A8\u65F6\u957F',
10058
- streamStatusCheckIntervalSeconds: '\u9759\u9ED8\u68C0\u6D4B\u95F4\u9694',
10161
+ streamStatusIdleStartSeconds: '\u4E0A\u6B21\u54CD\u5E94\u8DDD\u4ECA\u663E\u793A\u542F\u52A8\u65F6\u957F',
10162
+ streamStatusCheckIntervalSeconds: '\u4E0A\u6B21\u54CD\u5E94\u8DDD\u4ECA\u68C0\u67E5\u95F4\u9694',
10059
10163
  codexSkipGitRepoCheck: '\u5141\u8BB8\u5728\u672A\u4FE1\u4EFB Git \u76EE\u5F55\u8FD0\u884C Codex',
10060
10164
  codexSandboxMode: 'Codex \u6587\u4EF6\u7CFB\u7EDF\u6743\u9650',
10061
10165
  codexReasoningEffort: 'Codex \u601D\u8003\u7EA7\u522B',
10062
10166
  uiAllowLan: '\u5141\u8BB8\u5C40\u57DF\u7F51\u8BBF\u95EE Web \u63A7\u5236\u53F0',
10063
10167
  uiAccessToken: '\u5C40\u57DF\u7F51\u8BBF\u95EE token',
10064
- autoApprove: '\u81EA\u52A8\u6279\u51C6\u5DE5\u5177\u6743\u9650',
10065
10168
  };
10066
10169
 
10067
10170
  const BRIDGE_RESTART_FIELDS = new Set([
10068
10171
  'runtime',
10069
10172
  'codexSkipGitRepoCheck',
10070
- 'autoApprove',
10071
10173
  ]);
10072
10174
 
10073
10175
  const AUTO_SYNC_FIELDS = new Set([]);
@@ -10659,7 +10761,6 @@ function renderHtml() {
10659
10761
  document.getElementById('codexReasoningEffort').value = config.codexReasoningEffort || 'medium';
10660
10762
  document.getElementById('uiAllowLan').checked = config.uiAllowLan === true;
10661
10763
  document.getElementById('uiAccessToken').value = config.uiAccessToken || '';
10662
- document.getElementById('autoApprove').checked = config.autoApprove === true;
10663
10764
  renderUiAccess();
10664
10765
  ensureActiveChannelId();
10665
10766
  renderChannelsWorkspace();