codex-to-im 1.0.21 → 1.0.23

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 path10 = dijkstra.find_path(graph.map, "start", "end");
1575
+ const path9 = dijkstra.find_path(graph.map, "start", "end");
1576
1576
  const optimizedSegs = [];
1577
- for (let i = 1; i < path10.length - 1; i++) {
1578
- optimizedSegs.push(graph.table[path10[i]].node);
1577
+ for (let i = 1; i < path9.length - 1; i++) {
1578
+ optimizedSegs.push(graph.table[path9[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 fs10 = __require("fs");
4014
+ var fs8 = __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(path10, qrData, options, cb) {
4055
+ exports.renderToFile = function renderToFile(path9, 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 = fs10.createWriteStream(path10);
4066
+ const stream = fs8.createWriteStream(path9);
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(path10, qrData, options, cb) {
4128
+ exports.renderToFile = function renderToFile(path9, qrData, options, cb) {
4129
4129
  if (typeof cb === "undefined") {
4130
4130
  cb = options;
4131
4131
  options = void 0;
4132
4132
  }
4133
- const fs10 = __require("fs");
4133
+ const fs8 = __require("fs");
4134
4134
  const utf8 = exports.render(qrData, options);
4135
- fs10.writeFile(path10, utf8, cb);
4135
+ fs8.writeFile(path9, 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 path10 = "";
4256
+ let path9 = "";
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
- path10 += newRow ? svgCmd("M", col + margin, 0.5 + row + margin) : svgCmd("m", moveBy, 0);
4267
+ path9 += 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
- path10 += svgCmd("h", lineLength);
4272
+ path9 += svgCmd("h", lineLength);
4273
4273
  lineLength = 0;
4274
4274
  }
4275
4275
  } else {
4276
4276
  moveBy++;
4277
4277
  }
4278
4278
  }
4279
- return path10;
4279
+ return path9;
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 path10 = "<path " + getColorAttrib(opts.color.dark, "stroke") + ' d="' + qrToPath(data, size, opts.margin) + '"/>';
4287
+ const path9 = "<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 + path10 + "</svg>\n";
4290
+ const svgTag = '<svg xmlns="http://www.w3.org/2000/svg" ' + width + viewBox + ' shape-rendering="crispEdges">' + bg + path9 + "</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(path10, qrData, options, cb) {
4304
+ exports.renderToFile = function renderToFile(path9, qrData, options, cb) {
4305
4305
  if (typeof cb === "undefined") {
4306
4306
  cb = options;
4307
4307
  options = void 0;
4308
4308
  }
4309
- const fs10 = __require("fs");
4309
+ const fs8 = __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
- fs10.writeFile(path10, xmlStr, cb);
4312
+ fs8.writeFile(path9, 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(path10) {
4471
- return path10.slice((path10.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
4470
+ function getTypeFromFilename(path9) {
4471
+ return path9.slice((path9.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(path10, text2, opts, cb) {
4536
- if (typeof path10 !== "string" || !(typeof text2 === "string" || typeof text2 === "object")) {
4535
+ exports.toFile = function toFile(path9, text2, opts, cb) {
4536
+ if (typeof path9 !== "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(path10);
4543
+ const type = params.opts.type || getTypeFromFilename(path9);
4544
4544
  const renderer = getRendererFromType(type);
4545
- const renderToFile = renderer.renderToFile.bind(null, path10);
4545
+ const renderToFile = renderer.renderToFile.bind(null, path9);
4546
4546
  return render(renderToFile, text2, params);
4547
4547
  };
4548
4548
  exports.toFileStream = function toFileStream(stream, text2, opts) {
@@ -4568,8 +4568,7 @@ var require_lib = __commonJS({
4568
4568
  import http from "node:http";
4569
4569
  import crypto4 from "node:crypto";
4570
4570
  import net from "node:net";
4571
- import os6 from "node:os";
4572
- import fs9 from "node:fs";
4571
+ import os5 from "node:os";
4573
4572
 
4574
4573
  // src/config.ts
4575
4574
  import fs from "node:fs";
@@ -4581,15 +4580,9 @@ function toFeishuConfig(channel) {
4581
4580
  function toWeixinConfig(channel) {
4582
4581
  return channel?.provider === "weixin" ? channel.config : void 0;
4583
4582
  }
4584
- var LEGACY_CTI_HOME = path.join(os.homedir(), ".claude-to-im");
4585
4583
  var DEFAULT_CTI_HOME = path.join(os.homedir(), ".codex-to-im");
4586
4584
  var DEFAULT_WORKSPACE_ROOT = path.join(os.homedir(), "cx2im");
4587
- function resolveDefaultCtiHome() {
4588
- if (fs.existsSync(DEFAULT_CTI_HOME)) return DEFAULT_CTI_HOME;
4589
- if (fs.existsSync(LEGACY_CTI_HOME)) return LEGACY_CTI_HOME;
4590
- return DEFAULT_CTI_HOME;
4591
- }
4592
- var CTI_HOME = process.env.CTI_HOME || resolveDefaultCtiHome();
4585
+ var CTI_HOME = process.env.CTI_HOME || DEFAULT_CTI_HOME;
4593
4586
  var CONFIG_PATH = path.join(CTI_HOME, "config.env");
4594
4587
  var CONFIG_V2_PATH = path.join(CTI_HOME, "config.v2.json");
4595
4588
  function expandHomePath(value) {
@@ -4996,350 +4989,10 @@ function configToSettings(config) {
4996
4989
  return m;
4997
4990
  }
4998
4991
 
4999
- // src/permission-gateway.ts
5000
- var PendingPermissions = class {
5001
- pending = /* @__PURE__ */ new Map();
5002
- timeoutMs = 5 * 60 * 1e3;
5003
- // 5 minutes
5004
- waitFor(toolUseID) {
5005
- return new Promise((resolve) => {
5006
- const timer = setTimeout(() => {
5007
- this.pending.delete(toolUseID);
5008
- resolve({ behavior: "deny", message: "Permission request timed out" });
5009
- }, this.timeoutMs);
5010
- this.pending.set(toolUseID, { resolve, timer });
5011
- });
5012
- }
5013
- resolve(permissionRequestId, resolution) {
5014
- const entry = this.pending.get(permissionRequestId);
5015
- if (!entry) return false;
5016
- clearTimeout(entry.timer);
5017
- if (resolution.behavior === "allow") {
5018
- entry.resolve({ behavior: "allow" });
5019
- } else {
5020
- entry.resolve({ behavior: "deny", message: resolution.message || "Denied by user" });
5021
- }
5022
- this.pending.delete(permissionRequestId);
5023
- return true;
5024
- }
5025
- denyAll() {
5026
- for (const [, entry] of this.pending) {
5027
- clearTimeout(entry.timer);
5028
- entry.resolve({ behavior: "deny", message: "Bridge shutting down" });
5029
- }
5030
- this.pending.clear();
5031
- }
5032
- get size() {
5033
- return this.pending.size;
5034
- }
5035
- };
5036
-
5037
- // src/codex-provider.ts
4992
+ // src/desktop-sessions.ts
5038
4993
  import fs2 from "node:fs";
5039
4994
  import os2 from "node:os";
5040
4995
  import path2 from "node:path";
5041
-
5042
- // src/sse-utils.ts
5043
- function sseEvent(type, data) {
5044
- const payload = typeof data === "string" ? data : JSON.stringify(data);
5045
- return `data: ${JSON.stringify({ type, data: payload })}
5046
- `;
5047
- }
5048
-
5049
- // src/codex-provider.ts
5050
- var MIME_EXT = {
5051
- "image/png": ".png",
5052
- "image/jpeg": ".jpg",
5053
- "image/jpg": ".jpg",
5054
- "image/gif": ".gif",
5055
- "image/webp": ".webp"
5056
- };
5057
- function toApprovalPolicy(permissionMode) {
5058
- switch (permissionMode) {
5059
- case "never":
5060
- return "never";
5061
- case "acceptEdits":
5062
- return "on-failure";
5063
- case "plan":
5064
- return "on-request";
5065
- case "default":
5066
- return "on-request";
5067
- default:
5068
- return "on-request";
5069
- }
5070
- }
5071
- function shouldSkipGitRepoCheck() {
5072
- return process.env.CTI_CODEX_SKIP_GIT_REPO_CHECK === "true";
5073
- }
5074
- function normalizeSandboxMode(mode) {
5075
- if (mode === "read-only" || mode === "workspace-write" || mode === "danger-full-access") {
5076
- return mode;
5077
- }
5078
- return "workspace-write";
5079
- }
5080
- function normalizeReasoningEffort(value) {
5081
- if (value === "minimal" || value === "low" || value === "medium" || value === "high" || value === "xhigh") {
5082
- return value;
5083
- }
5084
- return void 0;
5085
- }
5086
- function shouldRetryFreshThread(message) {
5087
- const lower = message.toLowerCase();
5088
- return lower.includes("resuming session with different model") || lower.includes("no such session") || lower.includes("resume") && lower.includes("session");
5089
- }
5090
- var CodexProvider = class {
5091
- constructor(pendingPerms) {
5092
- this.pendingPerms = pendingPerms;
5093
- }
5094
- sdk = null;
5095
- codex = null;
5096
- /** Maps session IDs to Codex thread IDs for resume. */
5097
- threadIds = /* @__PURE__ */ new Map();
5098
- /**
5099
- * Lazily load the Codex SDK. Throws a clear error if the installation is incomplete.
5100
- */
5101
- async ensureSDK() {
5102
- if (this.sdk && this.codex) {
5103
- return { sdk: this.sdk, codex: this.codex };
5104
- }
5105
- try {
5106
- this.sdk = await Function('return import("@openai/codex-sdk")')();
5107
- } catch {
5108
- throw new Error(
5109
- "[CodexProvider] @openai/codex-sdk is missing from this codex-to-im installation. Reinstall codex-to-im or run npm install in the project root."
5110
- );
5111
- }
5112
- const apiKey = process.env.CTI_CODEX_API_KEY || process.env.CODEX_API_KEY || process.env.OPENAI_API_KEY || void 0;
5113
- const baseUrl = process.env.CTI_CODEX_BASE_URL || void 0;
5114
- const CodexClass = this.sdk.Codex;
5115
- this.codex = new CodexClass({
5116
- ...apiKey ? { apiKey } : {},
5117
- ...baseUrl ? { baseUrl } : {}
5118
- });
5119
- return { sdk: this.sdk, codex: this.codex };
5120
- }
5121
- streamChat(params) {
5122
- const self = this;
5123
- return new ReadableStream({
5124
- start(controller) {
5125
- (async () => {
5126
- const tempFiles = [];
5127
- try {
5128
- const { codex } = await self.ensureSDK();
5129
- const inMemoryThreadId = self.threadIds.get(params.sessionId);
5130
- let savedThreadId = inMemoryThreadId || params.sdkSessionId || void 0;
5131
- const approvalPolicy = toApprovalPolicy(params.permissionMode);
5132
- const sandboxMode = normalizeSandboxMode(params.sandboxMode);
5133
- const modelReasoningEffort = normalizeReasoningEffort(params.modelReasoningEffort);
5134
- const threadOptions = {
5135
- ...params.forceModel && params.model ? { model: params.model } : {},
5136
- ...params.workingDirectory ? { workingDirectory: params.workingDirectory } : {},
5137
- ...shouldSkipGitRepoCheck() ? { skipGitRepoCheck: true } : {},
5138
- sandboxMode,
5139
- ...modelReasoningEffort ? { modelReasoningEffort } : {},
5140
- approvalPolicy
5141
- };
5142
- const imageFiles = params.files?.filter(
5143
- (f) => f.type.startsWith("image/")
5144
- ) ?? [];
5145
- let input;
5146
- if (imageFiles.length > 0) {
5147
- const parts = [
5148
- { type: "text", text: params.prompt }
5149
- ];
5150
- for (const file of imageFiles) {
5151
- if (file.filePath && fs2.existsSync(file.filePath)) {
5152
- parts.push({ type: "local_image", path: file.filePath });
5153
- continue;
5154
- }
5155
- const ext = MIME_EXT[file.type] || ".png";
5156
- const tmpPath = path2.join(os2.tmpdir(), `cti-img-${Date.now()}-${Math.random().toString(36).slice(2)}${ext}`);
5157
- fs2.writeFileSync(tmpPath, Buffer.from(file.data, "base64"));
5158
- tempFiles.push(tmpPath);
5159
- parts.push({ type: "local_image", path: tmpPath });
5160
- }
5161
- input = parts;
5162
- } else {
5163
- input = params.prompt;
5164
- }
5165
- let retryFresh = false;
5166
- while (true) {
5167
- let thread;
5168
- if (savedThreadId) {
5169
- try {
5170
- thread = codex.resumeThread(savedThreadId, threadOptions);
5171
- } catch {
5172
- thread = codex.startThread(threadOptions);
5173
- }
5174
- } else {
5175
- thread = codex.startThread(threadOptions);
5176
- }
5177
- let sawAnyEvent = false;
5178
- try {
5179
- const { events } = await thread.runStreamed(input, {
5180
- signal: params.abortController?.signal
5181
- });
5182
- for await (const event of events) {
5183
- sawAnyEvent = true;
5184
- if (params.abortController?.signal.aborted) {
5185
- break;
5186
- }
5187
- switch (event.type) {
5188
- case "thread.started": {
5189
- const threadId = event.thread_id;
5190
- self.threadIds.set(params.sessionId, threadId);
5191
- controller.enqueue(sseEvent("status", {
5192
- session_id: threadId
5193
- }));
5194
- break;
5195
- }
5196
- case "item.completed": {
5197
- const item = event.item;
5198
- self.handleCompletedItem(controller, item);
5199
- break;
5200
- }
5201
- case "turn.completed": {
5202
- const usage = event.usage;
5203
- const threadId = self.threadIds.get(params.sessionId);
5204
- controller.enqueue(sseEvent("result", {
5205
- usage: usage ? {
5206
- input_tokens: usage.input_tokens ?? 0,
5207
- output_tokens: usage.output_tokens ?? 0,
5208
- cache_read_input_tokens: usage.cached_input_tokens ?? 0
5209
- } : void 0,
5210
- ...threadId ? { session_id: threadId } : {}
5211
- }));
5212
- break;
5213
- }
5214
- case "turn.failed": {
5215
- const error = event.message;
5216
- controller.enqueue(sseEvent("error", error || "Turn failed"));
5217
- break;
5218
- }
5219
- case "error": {
5220
- const error = event.message;
5221
- controller.enqueue(sseEvent("error", error || "Thread error"));
5222
- break;
5223
- }
5224
- }
5225
- }
5226
- break;
5227
- } catch (err) {
5228
- const message = err instanceof Error ? err.message : String(err);
5229
- if (savedThreadId && !retryFresh && !sawAnyEvent && shouldRetryFreshThread(message)) {
5230
- console.warn("[codex-provider] Resume failed, retrying with a fresh thread:", message);
5231
- savedThreadId = void 0;
5232
- retryFresh = true;
5233
- continue;
5234
- }
5235
- throw err;
5236
- }
5237
- }
5238
- controller.close();
5239
- } catch (err) {
5240
- const message = err instanceof Error ? err.message : String(err);
5241
- console.error("[codex-provider] Error:", err instanceof Error ? err.stack || err.message : err);
5242
- try {
5243
- controller.enqueue(sseEvent("error", message));
5244
- controller.close();
5245
- } catch {
5246
- }
5247
- } finally {
5248
- for (const tmp of tempFiles) {
5249
- try {
5250
- fs2.unlinkSync(tmp);
5251
- } catch {
5252
- }
5253
- }
5254
- }
5255
- })();
5256
- }
5257
- });
5258
- }
5259
- /**
5260
- * Map a completed Codex item to SSE events.
5261
- */
5262
- handleCompletedItem(controller, item) {
5263
- const itemType = item.type;
5264
- switch (itemType) {
5265
- case "agent_message": {
5266
- const text2 = item.text || "";
5267
- if (text2) {
5268
- controller.enqueue(sseEvent("text", text2));
5269
- }
5270
- break;
5271
- }
5272
- case "command_execution": {
5273
- const toolId = item.id || `tool-${Date.now()}`;
5274
- const command = item.command || "";
5275
- const output = item.aggregated_output || "";
5276
- const exitCode = item.exit_code;
5277
- const isError = exitCode != null && exitCode !== 0;
5278
- controller.enqueue(sseEvent("tool_use", {
5279
- id: toolId,
5280
- name: "Bash",
5281
- input: { command }
5282
- }));
5283
- const resultContent = output || (isError ? `Exit code: ${exitCode}` : "Done");
5284
- controller.enqueue(sseEvent("tool_result", {
5285
- tool_use_id: toolId,
5286
- content: resultContent,
5287
- is_error: isError
5288
- }));
5289
- break;
5290
- }
5291
- case "file_change": {
5292
- const toolId = item.id || `tool-${Date.now()}`;
5293
- const changes = item.changes || [];
5294
- const summary = changes.map((c) => `${c.kind}: ${c.path}`).join("\n");
5295
- controller.enqueue(sseEvent("tool_use", {
5296
- id: toolId,
5297
- name: "Edit",
5298
- input: { files: changes }
5299
- }));
5300
- controller.enqueue(sseEvent("tool_result", {
5301
- tool_use_id: toolId,
5302
- content: summary || "File changes applied",
5303
- is_error: false
5304
- }));
5305
- break;
5306
- }
5307
- case "mcp_tool_call": {
5308
- const toolId = item.id || `tool-${Date.now()}`;
5309
- const server2 = item.server || "";
5310
- const tool = item.tool || "";
5311
- const args = item.arguments;
5312
- const result = item.result;
5313
- const error = item.error;
5314
- const resultContent = result?.content ?? result?.structured_content;
5315
- const resultText = typeof resultContent === "string" ? resultContent : resultContent ? JSON.stringify(resultContent) : void 0;
5316
- controller.enqueue(sseEvent("tool_use", {
5317
- id: toolId,
5318
- name: `mcp__${server2}__${tool}`,
5319
- input: args
5320
- }));
5321
- controller.enqueue(sseEvent("tool_result", {
5322
- tool_use_id: toolId,
5323
- content: error?.message || resultText || "Done",
5324
- is_error: !!error
5325
- }));
5326
- break;
5327
- }
5328
- case "reasoning": {
5329
- const text2 = item.text || "";
5330
- if (text2) {
5331
- controller.enqueue(sseEvent("status", { reasoning: text2 }));
5332
- }
5333
- break;
5334
- }
5335
- }
5336
- }
5337
- };
5338
-
5339
- // src/desktop-sessions.ts
5340
- import fs3 from "node:fs";
5341
- import os3 from "node:os";
5342
- import path3 from "node:path";
5343
4996
  import crypto from "node:crypto";
5344
4997
  import { DatabaseSync } from "node:sqlite";
5345
4998
  var ACTIVE_WINDOW_MS = 15 * 60 * 1e3;
@@ -5347,31 +5000,31 @@ var MAX_SESSION_META_BYTES = 4 * 1024 * 1024;
5347
5000
  var MAX_SESSION_TITLE_SCAN_BYTES = 512 * 1024;
5348
5001
  var TITLE_MAX_CHARS = 72;
5349
5002
  function getCodexHome() {
5350
- return process.env.CODEX_HOME || path3.join(os3.homedir(), ".codex");
5003
+ return process.env.CODEX_HOME || path2.join(os2.homedir(), ".codex");
5351
5004
  }
5352
5005
  function getCodexSessionsRoot() {
5353
- return path3.join(getCodexHome(), "sessions");
5006
+ return path2.join(getCodexHome(), "sessions");
5354
5007
  }
5355
5008
  function getArchivedSessionsRoot() {
5356
- return path3.join(getCodexHome(), "archived_sessions");
5009
+ return path2.join(getCodexHome(), "archived_sessions");
5357
5010
  }
5358
5011
  function getSessionIndexPath() {
5359
- return path3.join(getCodexHome(), "session_index.jsonl");
5012
+ return path2.join(getCodexHome(), "session_index.jsonl");
5360
5013
  }
5361
5014
  function getCodexGlobalStatePath() {
5362
- return path3.join(getCodexHome(), ".codex-global-state.json");
5015
+ return path2.join(getCodexHome(), ".codex-global-state.json");
5363
5016
  }
5364
5017
  function getDesktopStateDbPath() {
5365
5018
  const codexHome = getCodexHome();
5366
5019
  let entries;
5367
5020
  try {
5368
- entries = fs3.readdirSync(codexHome, { withFileTypes: true });
5021
+ entries = fs2.readdirSync(codexHome, { withFileTypes: true });
5369
5022
  } catch {
5370
5023
  return null;
5371
5024
  }
5372
- const candidates = entries.filter((entry) => entry.isFile() && /^state_\d+\.sqlite$/i.test(entry.name)).map((entry) => path3.join(codexHome, entry.name)).sort((left, right) => {
5025
+ const candidates = entries.filter((entry) => entry.isFile() && /^state_\d+\.sqlite$/i.test(entry.name)).map((entry) => path2.join(codexHome, entry.name)).sort((left, right) => {
5373
5026
  try {
5374
- return fs3.statSync(right).mtimeMs - fs3.statSync(left).mtimeMs;
5027
+ return fs2.statSync(right).mtimeMs - fs2.statSync(left).mtimeMs;
5375
5028
  } catch {
5376
5029
  return 0;
5377
5030
  }
@@ -5385,21 +5038,21 @@ function extractThreadIdFromRolloutName(name) {
5385
5038
  function normalizeComparablePath(value) {
5386
5039
  if (!value) return "";
5387
5040
  const stripped = value.replace(/^\\\\\?\\/, "");
5388
- return path3.resolve(stripped).replace(/[\\/]+$/, "").toLowerCase();
5041
+ return path2.resolve(stripped).replace(/[\\/]+$/, "").toLowerCase();
5389
5042
  }
5390
5043
  function isInternalSkillWorkspace(cwd) {
5391
5044
  const normalizedCwd = normalizeComparablePath(cwd);
5392
5045
  if (!normalizedCwd) return false;
5393
- const skillsRoot = normalizeComparablePath(path3.join(getCodexHome(), "skills"));
5046
+ const skillsRoot = normalizeComparablePath(path2.join(getCodexHome(), "skills"));
5394
5047
  if (!skillsRoot) return false;
5395
5048
  return normalizedCwd === skillsRoot || normalizedCwd.startsWith(`${skillsRoot}\\`) || normalizedCwd.startsWith(`${skillsRoot}/`);
5396
5049
  }
5397
5050
  function loadSavedWorkspaceRoots() {
5398
5051
  const statePath = getCodexGlobalStatePath();
5399
- if (!fs3.existsSync(statePath)) return null;
5052
+ if (!fs2.existsSync(statePath)) return null;
5400
5053
  let parsed;
5401
5054
  try {
5402
- parsed = JSON.parse(fs3.readFileSync(statePath, "utf-8"));
5055
+ parsed = JSON.parse(fs2.readFileSync(statePath, "utf-8"));
5403
5056
  } catch {
5404
5057
  return null;
5405
5058
  }
@@ -5414,10 +5067,10 @@ function isWithinSavedWorkspaceRoots(cwd, roots) {
5414
5067
  }
5415
5068
  function loadArchivedThreadIds() {
5416
5069
  const archivedRoot = getArchivedSessionsRoot();
5417
- if (!fs3.existsSync(archivedRoot)) return /* @__PURE__ */ new Set();
5070
+ if (!fs2.existsSync(archivedRoot)) return /* @__PURE__ */ new Set();
5418
5071
  let entries;
5419
5072
  try {
5420
- entries = fs3.readdirSync(archivedRoot, { withFileTypes: true });
5073
+ entries = fs2.readdirSync(archivedRoot, { withFileTypes: true });
5421
5074
  } catch {
5422
5075
  return /* @__PURE__ */ new Set();
5423
5076
  }
@@ -5430,13 +5083,13 @@ function loadArchivedThreadIds() {
5430
5083
  return ids;
5431
5084
  }
5432
5085
  function readFirstLine(filePath, maxBytes = MAX_SESSION_META_BYTES) {
5433
- const fd = fs3.openSync(filePath, "r");
5086
+ const fd = fs2.openSync(filePath, "r");
5434
5087
  try {
5435
5088
  const chunks = [];
5436
5089
  let bytesReadTotal = 0;
5437
5090
  const buffer = Buffer.alloc(4096);
5438
5091
  while (bytesReadTotal < maxBytes) {
5439
- const bytesRead = fs3.readSync(fd, buffer, 0, buffer.length, bytesReadTotal);
5092
+ const bytesRead = fs2.readSync(fd, buffer, 0, buffer.length, bytesReadTotal);
5440
5093
  if (bytesRead <= 0) break;
5441
5094
  const slice = Buffer.from(buffer.subarray(0, bytesRead));
5442
5095
  chunks.push(slice);
@@ -5449,36 +5102,36 @@ function readFirstLine(filePath, maxBytes = MAX_SESSION_META_BYTES) {
5449
5102
  }
5450
5103
  return Buffer.concat(chunks).toString("utf-8").split(/\r?\n/, 1)[0] || "";
5451
5104
  } finally {
5452
- fs3.closeSync(fd);
5105
+ fs2.closeSync(fd);
5453
5106
  }
5454
5107
  }
5455
5108
  function readFilePrefix(filePath, maxBytes = MAX_SESSION_TITLE_SCAN_BYTES) {
5456
- const fd = fs3.openSync(filePath, "r");
5109
+ const fd = fs2.openSync(filePath, "r");
5457
5110
  try {
5458
5111
  const buffer = Buffer.alloc(Math.min(maxBytes, 64 * 1024));
5459
5112
  const chunks = [];
5460
5113
  let offset = 0;
5461
5114
  while (offset < maxBytes) {
5462
5115
  const bytesToRead = Math.min(buffer.length, maxBytes - offset);
5463
- const bytesRead = fs3.readSync(fd, buffer, 0, bytesToRead, offset);
5116
+ const bytesRead = fs2.readSync(fd, buffer, 0, bytesToRead, offset);
5464
5117
  if (bytesRead <= 0) break;
5465
5118
  chunks.push(Buffer.from(buffer.subarray(0, bytesRead)));
5466
5119
  offset += bytesRead;
5467
5120
  }
5468
5121
  return Buffer.concat(chunks).toString("utf-8");
5469
5122
  } finally {
5470
- fs3.closeSync(fd);
5123
+ fs2.closeSync(fd);
5471
5124
  }
5472
5125
  }
5473
5126
  function walkSessionFiles(dirPath, target) {
5474
5127
  let entries;
5475
5128
  try {
5476
- entries = fs3.readdirSync(dirPath, { withFileTypes: true });
5129
+ entries = fs2.readdirSync(dirPath, { withFileTypes: true });
5477
5130
  } catch {
5478
5131
  return;
5479
5132
  }
5480
5133
  for (const entry of entries) {
5481
- const entryPath = path3.join(dirPath, entry.name);
5134
+ const entryPath = path2.join(dirPath, entry.name);
5482
5135
  if (entry.isDirectory()) {
5483
5136
  walkSessionFiles(entryPath, target);
5484
5137
  continue;
@@ -5496,10 +5149,10 @@ function isDesktopLike(meta) {
5496
5149
  }
5497
5150
  function loadThreadIndexEntries(archivedThreadIds) {
5498
5151
  const indexPath = getSessionIndexPath();
5499
- if (!fs3.existsSync(indexPath)) return /* @__PURE__ */ new Map();
5152
+ if (!fs2.existsSync(indexPath)) return /* @__PURE__ */ new Map();
5500
5153
  let content = "";
5501
5154
  try {
5502
- content = fs3.readFileSync(indexPath, "utf-8");
5155
+ content = fs2.readFileSync(indexPath, "utf-8");
5503
5156
  } catch {
5504
5157
  return /* @__PURE__ */ new Map();
5505
5158
  }
@@ -5539,7 +5192,7 @@ function parseUpdatedAtValue(value) {
5539
5192
  }
5540
5193
  function loadVisibleDesktopThreads(limit) {
5541
5194
  const dbPath = getDesktopStateDbPath();
5542
- if (!dbPath || !fs3.existsSync(dbPath)) return null;
5195
+ if (!dbPath || !fs2.existsSync(dbPath)) return null;
5543
5196
  let db = null;
5544
5197
  try {
5545
5198
  db = new DatabaseSync(dbPath, { readOnly: true });
@@ -5585,7 +5238,7 @@ function buildFallbackTitle(threadId, filePath, cwd) {
5585
5238
  }
5586
5239
  } catch {
5587
5240
  }
5588
- const dirName = trimTitle(path3.basename(cwd || ""));
5241
+ const dirName = trimTitle(path2.basename(cwd || ""));
5589
5242
  if (dirName) return dirName;
5590
5243
  return `Session ${threadId.slice(0, 8)}`;
5591
5244
  }
@@ -5606,7 +5259,7 @@ function parseDesktopSession(filePath, threadIndexEntries, archivedThreadIds) {
5606
5259
  }
5607
5260
  let stat;
5608
5261
  try {
5609
- stat = fs3.statSync(filePath);
5262
+ stat = fs2.statSync(filePath);
5610
5263
  } catch {
5611
5264
  return null;
5612
5265
  }
@@ -5681,7 +5334,7 @@ function isSessionEventLine(line) {
5681
5334
  }
5682
5335
  function listDesktopSessions(limit) {
5683
5336
  const root = getCodexSessionsRoot();
5684
- if (!fs3.existsSync(root)) return [];
5337
+ if (!fs2.existsSync(root)) return [];
5685
5338
  const archivedThreadIds = loadArchivedThreadIds();
5686
5339
  const threadIndexEntries = loadThreadIndexEntries(archivedThreadIds);
5687
5340
  const savedWorkspaceRoots = loadSavedWorkspaceRoots();
@@ -5728,7 +5381,7 @@ function isArchivedDesktopThread(threadId) {
5728
5381
  }
5729
5382
 
5730
5383
  // src/session-bindings.ts
5731
- import path4 from "node:path";
5384
+ import path3 from "node:path";
5732
5385
  function asChannelProvider(value) {
5733
5386
  return value === "feishu" || value === "weixin" ? value : void 0;
5734
5387
  }
@@ -5774,13 +5427,13 @@ function getSessionName(session) {
5774
5427
  if (session.session_type === "draft") return "\u4E34\u65F6\u8349\u7A3F\u7EBF\u7A0B";
5775
5428
  if (session.session_type === "history_summary") return "\u5386\u53F2\u6458\u8981\u7EBF\u7A0B";
5776
5429
  if (session.name?.trim()) return session.name.trim();
5777
- if (session.working_directory) return path4.basename(session.working_directory);
5430
+ if (session.working_directory) return path3.basename(session.working_directory);
5778
5431
  return session.id.slice(0, 8);
5779
5432
  }
5780
5433
  function getSessionMode(store, session) {
5781
5434
  return session.preferred_mode || store.getSetting("bridge_default_mode") || "code";
5782
5435
  }
5783
- function bindStoreToSession(store, channelType, chatId, sessionId) {
5436
+ function bindStoreToSession(store, channelType, chatId, sessionId, chatMeta) {
5784
5437
  const session = store.getSession(sessionId);
5785
5438
  if (!session) return null;
5786
5439
  assertBindingTargetAvailable(
@@ -5794,6 +5447,8 @@ function bindStoreToSession(store, channelType, chatId, sessionId) {
5794
5447
  channelProvider: meta.provider,
5795
5448
  channelAlias: meta.alias,
5796
5449
  chatId,
5450
+ chatUserId: chatMeta?.chatUserId,
5451
+ chatDisplayName: chatMeta?.chatDisplayName,
5797
5452
  codepilotSessionId: session.id,
5798
5453
  sdkSessionId: session.sdk_session_id || "",
5799
5454
  workingDirectory: session.working_directory,
@@ -5815,6 +5470,8 @@ function bindStoreToSdkSession(store, channelType, chatId, sdkSessionId, opts) {
5815
5470
  channelProvider: meta.provider,
5816
5471
  channelAlias: meta.alias,
5817
5472
  chatId,
5473
+ chatUserId: opts?.chatUserId,
5474
+ chatDisplayName: opts?.chatDisplayName,
5818
5475
  codepilotSessionId: existing.id,
5819
5476
  sdkSessionId,
5820
5477
  workingDirectory: opts?.workingDirectory || existing.working_directory,
@@ -5824,7 +5481,7 @@ function bindStoreToSdkSession(store, channelType, chatId, sdkSessionId, opts) {
5824
5481
  }
5825
5482
  const workingDirectory = opts?.workingDirectory || "";
5826
5483
  const model = opts?.model || store.getSetting("bridge_default_model") || "";
5827
- const baseName = opts?.displayName || (workingDirectory ? path4.basename(workingDirectory) : sdkSessionId.slice(0, 8));
5484
+ const baseName = opts?.displayName || (workingDirectory ? path3.basename(workingDirectory) : sdkSessionId.slice(0, 8));
5828
5485
  const session = store.createSession(
5829
5486
  `Desktop: ${baseName}`,
5830
5487
  model,
@@ -5838,6 +5495,8 @@ function bindStoreToSdkSession(store, channelType, chatId, sdkSessionId, opts) {
5838
5495
  channelProvider: meta.provider,
5839
5496
  channelAlias: meta.alias,
5840
5497
  chatId,
5498
+ chatUserId: opts?.chatUserId,
5499
+ chatDisplayName: opts?.chatDisplayName,
5841
5500
  codepilotSessionId: session.id,
5842
5501
  sdkSessionId,
5843
5502
  workingDirectory: workingDirectory || session.working_directory,
@@ -5906,13 +5565,20 @@ function updateBindingTarget(store, bindingId, targetKey) {
5906
5565
  const desktop = getDesktopSessionByThreadId(threadId);
5907
5566
  bindStoreToSdkSession(store, binding.channelType, binding.chatId, threadId, desktop ? {
5908
5567
  workingDirectory: desktop.cwd,
5909
- displayName: desktop.title
5568
+ displayName: desktop.title,
5569
+ chatUserId: binding.chatUserId,
5570
+ chatDisplayName: binding.chatDisplayName
5910
5571
  } : {
5911
- workingDirectory: binding.workingDirectory
5572
+ workingDirectory: binding.workingDirectory,
5573
+ chatUserId: binding.chatUserId,
5574
+ chatDisplayName: binding.chatDisplayName
5912
5575
  });
5913
5576
  } else if (targetKey.startsWith("session:")) {
5914
5577
  const sessionId = targetKey.slice("session:".length);
5915
- const updated2 = bindStoreToSession(store, binding.channelType, binding.chatId, sessionId);
5578
+ const updated2 = bindStoreToSession(store, binding.channelType, binding.chatId, sessionId, {
5579
+ chatUserId: binding.chatUserId,
5580
+ chatDisplayName: binding.chatDisplayName
5581
+ });
5916
5582
  if (!updated2) {
5917
5583
  throw new Error("Session not found.");
5918
5584
  }
@@ -5934,36 +5600,37 @@ function removeBinding(store, bindingId) {
5934
5600
  }
5935
5601
 
5936
5602
  // src/service-manager.ts
5937
- import fs4 from "node:fs";
5938
- import os4 from "node:os";
5939
- import path5 from "node:path";
5603
+ import fs3 from "node:fs";
5604
+ import os3 from "node:os";
5605
+ import path4 from "node:path";
5940
5606
  import { spawn } from "node:child_process";
5941
5607
  import { fileURLToPath } from "node:url";
5942
- var moduleDir = path5.dirname(fileURLToPath(import.meta.url));
5943
- var packageRoot = path5.resolve(moduleDir, "..");
5944
- var runtimeDir = path5.join(CTI_HOME, "runtime");
5945
- var logsDir = path5.join(CTI_HOME, "logs");
5946
- var bridgePidFile = path5.join(runtimeDir, "bridge.pid");
5947
- var bridgeStatusFile = path5.join(runtimeDir, "status.json");
5948
- var uiStatusFile = path5.join(runtimeDir, "ui-server.json");
5608
+ var moduleDir = path4.dirname(fileURLToPath(import.meta.url));
5609
+ var packageRoot = path4.resolve(moduleDir, "..");
5610
+ var runtimeDir = path4.join(CTI_HOME, "runtime");
5611
+ var logsDir = path4.join(CTI_HOME, "logs");
5612
+ var bridgePidFile = path4.join(runtimeDir, "bridge.pid");
5613
+ var bridgeStatusFile = path4.join(runtimeDir, "status.json");
5614
+ var uiStatusFile = path4.join(runtimeDir, "ui-server.json");
5949
5615
  var uiPort = 4781;
5950
5616
  var bridgeAutostartTaskName = "CodexToIMBridge";
5951
- var bridgeAutostartLauncherFile = path5.join(runtimeDir, "bridge-autostart.ps1");
5617
+ var bridgeAutostartLauncherFile = path4.join(runtimeDir, "bridge-autostart.ps1");
5618
+ var npmUninstallLogFile = path4.join(runtimeDir, "npm-uninstall.log");
5952
5619
  var WINDOWS_HIDE = process.platform === "win32" ? { windowsHide: true } : {};
5953
5620
  function ensureDirs() {
5954
- fs4.mkdirSync(runtimeDir, { recursive: true });
5955
- fs4.mkdirSync(logsDir, { recursive: true });
5621
+ fs3.mkdirSync(runtimeDir, { recursive: true });
5622
+ fs3.mkdirSync(logsDir, { recursive: true });
5956
5623
  }
5957
5624
  function readJsonFile(filePath, fallback) {
5958
5625
  try {
5959
- return JSON.parse(fs4.readFileSync(filePath, "utf-8"));
5626
+ return JSON.parse(fs3.readFileSync(filePath, "utf-8"));
5960
5627
  } catch {
5961
5628
  return fallback;
5962
5629
  }
5963
5630
  }
5964
5631
  function readPid(filePath) {
5965
5632
  try {
5966
- const raw = fs4.readFileSync(filePath, "utf-8").trim();
5633
+ const raw = fs3.readFileSync(filePath, "utf-8").trim();
5967
5634
  const pid = Number(raw);
5968
5635
  return Number.isFinite(pid) ? pid : void 0;
5969
5636
  } catch {
@@ -5983,7 +5650,7 @@ function sleep(ms) {
5983
5650
  return new Promise((resolve) => setTimeout(resolve, ms));
5984
5651
  }
5985
5652
  function getCurrentWindowsUser() {
5986
- const user = process.env.USERNAME || os4.userInfo().username;
5653
+ const user = process.env.USERNAME || os3.userInfo().username;
5987
5654
  const domain = process.env.USERDOMAIN;
5988
5655
  return domain ? `${domain}\\${user}` : user;
5989
5656
  }
@@ -6084,12 +5751,12 @@ async function startBridge() {
6084
5751
  ensureDirs();
6085
5752
  const current = getBridgeStatus();
6086
5753
  if (current.running) return current;
6087
- const daemonEntry = path5.join(packageRoot, "dist", "daemon.mjs");
6088
- if (!fs4.existsSync(daemonEntry)) {
5754
+ const daemonEntry = path4.join(packageRoot, "dist", "daemon.mjs");
5755
+ if (!fs3.existsSync(daemonEntry)) {
6089
5756
  throw new Error(`Daemon bundle not found at ${daemonEntry}. Run npm run build first.`);
6090
5757
  }
6091
- const stdoutFd = fs4.openSync(path5.join(logsDir, "bridge-launcher.out.log"), "a");
6092
- const stderrFd = fs4.openSync(path5.join(logsDir, "bridge-launcher.err.log"), "a");
5758
+ const stdoutFd = fs3.openSync(path4.join(logsDir, "bridge-launcher.out.log"), "a");
5759
+ const stderrFd = fs3.openSync(path4.join(logsDir, "bridge-launcher.err.log"), "a");
6093
5760
  const child = spawn(process.execPath, [daemonEntry], {
6094
5761
  cwd: packageRoot,
6095
5762
  detached: true,
@@ -6192,37 +5859,37 @@ async function getBridgeAutostartStatus() {
6192
5859
  }
6193
5860
  function getBridgeLogs(lines = 200) {
6194
5861
  ensureDirs();
6195
- const filePath = path5.join(logsDir, "bridge.log");
6196
- if (!fs4.existsSync(filePath)) return "";
6197
- const all = fs4.readFileSync(filePath, "utf-8").split(/\r?\n/);
5862
+ const filePath = path4.join(logsDir, "bridge.log");
5863
+ if (!fs3.existsSync(filePath)) return "";
5864
+ const all = fs3.readFileSync(filePath, "utf-8").split(/\r?\n/);
6198
5865
  return all.slice(Math.max(0, all.length - lines)).join("\n");
6199
5866
  }
6200
5867
  function writeUiServerStatus(status) {
6201
5868
  ensureDirs();
6202
- fs4.writeFileSync(uiStatusFile, JSON.stringify(status, null, 2), "utf-8");
5869
+ fs3.writeFileSync(uiStatusFile, JSON.stringify(status, null, 2), "utf-8");
6203
5870
  }
6204
5871
  async function installCodexIntegration() {
6205
- const sourceSkill = path5.join(packageRoot, "SKILL.md");
6206
- if (!fs4.existsSync(sourceSkill)) {
5872
+ const sourceSkill = path4.join(packageRoot, "SKILL.md");
5873
+ if (!fs3.existsSync(sourceSkill)) {
6207
5874
  throw new Error(`SKILL.md not found at ${sourceSkill}`);
6208
5875
  }
6209
- const skillsDir = path5.join(os4.homedir(), ".codex", "skills");
6210
- const targetDir = path5.join(skillsDir, "codex-to-im");
6211
- fs4.mkdirSync(skillsDir, { recursive: true });
6212
- if (fs4.existsSync(targetDir)) {
5876
+ const skillsDir = path4.join(os3.homedir(), ".codex", "skills");
5877
+ const targetDir = path4.join(skillsDir, "codex-to-im");
5878
+ fs3.mkdirSync(skillsDir, { recursive: true });
5879
+ if (fs3.existsSync(targetDir)) {
6213
5880
  return { targetDir, method: "existing" };
6214
5881
  }
6215
5882
  try {
6216
- fs4.symlinkSync(packageRoot, targetDir, process.platform === "win32" ? "junction" : "dir");
5883
+ fs3.symlinkSync(packageRoot, targetDir, process.platform === "win32" ? "junction" : "dir");
6217
5884
  return { targetDir, method: "junction" };
6218
5885
  } catch {
6219
- fs4.cpSync(packageRoot, targetDir, {
5886
+ fs3.cpSync(packageRoot, targetDir, {
6220
5887
  recursive: true,
6221
5888
  filter: (source) => {
6222
- const relative = path5.relative(packageRoot, source);
5889
+ const relative = path4.relative(packageRoot, source);
6223
5890
  if (!relative) return true;
6224
- if (relative === ".git" || relative.startsWith(`.git${path5.sep}`)) return false;
6225
- if (relative === "node_modules" || relative.startsWith(`node_modules${path5.sep}`)) return false;
5891
+ if (relative === ".git" || relative.startsWith(`.git${path4.sep}`)) return false;
5892
+ if (relative === "node_modules" || relative.startsWith(`node_modules${path4.sep}`)) return false;
6226
5893
  return true;
6227
5894
  }
6228
5895
  });
@@ -6230,27 +5897,27 @@ async function installCodexIntegration() {
6230
5897
  }
6231
5898
  }
6232
5899
  function isCodexIntegrationInstalled() {
6233
- const targetDir = path5.join(os4.homedir(), ".codex", "skills", "codex-to-im");
6234
- return fs4.existsSync(path5.join(targetDir, "SKILL.md"));
5900
+ const targetDir = path4.join(os3.homedir(), ".codex", "skills", "codex-to-im");
5901
+ return fs3.existsSync(path4.join(targetDir, "SKILL.md"));
6235
5902
  }
6236
5903
 
6237
5904
  // src/store.ts
6238
- import fs5 from "node:fs";
6239
- import path6 from "node:path";
5905
+ import fs4 from "node:fs";
5906
+ import path5 from "node:path";
6240
5907
  import crypto2 from "node:crypto";
6241
- var DATA_DIR = path6.join(CTI_HOME, "data");
6242
- var MESSAGES_DIR = path6.join(DATA_DIR, "messages");
5908
+ var DATA_DIR = path5.join(CTI_HOME, "data");
5909
+ var MESSAGES_DIR = path5.join(DATA_DIR, "messages");
6243
5910
  function ensureDir(dir) {
6244
- fs5.mkdirSync(dir, { recursive: true });
5911
+ fs4.mkdirSync(dir, { recursive: true });
6245
5912
  }
6246
5913
  function atomicWrite(filePath, data) {
6247
5914
  const tmp = filePath + ".tmp";
6248
- fs5.writeFileSync(tmp, data, "utf-8");
6249
- fs5.renameSync(tmp, filePath);
5915
+ fs4.writeFileSync(tmp, data, "utf-8");
5916
+ fs4.renameSync(tmp, filePath);
6250
5917
  }
6251
5918
  function readJson(filePath, fallback) {
6252
5919
  try {
6253
- const raw = fs5.readFileSync(filePath, "utf-8");
5920
+ const raw = fs4.readFileSync(filePath, "utf-8");
6254
5921
  return JSON.parse(raw);
6255
5922
  } catch {
6256
5923
  return fallback;
@@ -6270,10 +5937,12 @@ function defaultAliasForProvider2(provider) {
6270
5937
  if (provider === "weixin") return "\u5FAE\u4FE1";
6271
5938
  return void 0;
6272
5939
  }
6273
- function normalizeLegacyBinding(binding) {
5940
+ function upgradeLegacyBinding(binding) {
6274
5941
  const config = loadConfig();
6275
- const legacyProvider = binding.channelType === "feishu" || binding.channelType === "weixin" ? binding.channelType : void 0;
6276
- const resolvedInstance = legacyProvider ? (config.channels || []).find((channel) => channel.provider === legacyProvider) : findChannelInstance(binding.channelType, config);
5942
+ const exactInstance = findChannelInstance(binding.channelType, config);
5943
+ const hasInstanceMetadata = Boolean(binding.channelProvider || binding.channelAlias);
5944
+ const legacyProvider = !exactInstance && !hasInstanceMetadata && (binding.channelType === "feishu" || binding.channelType === "weixin") ? binding.channelType : void 0;
5945
+ const resolvedInstance = exactInstance || (legacyProvider ? (config.channels || []).find((channel) => channel.provider === legacyProvider) : void 0);
6277
5946
  if (!resolvedInstance && !legacyProvider) {
6278
5947
  return {
6279
5948
  ...binding,
@@ -6317,44 +5986,44 @@ var JsonFileStore = class {
6317
5986
  this.reloadSessions();
6318
5987
  this.reloadBindings();
6319
5988
  const perms = readJson(
6320
- path6.join(DATA_DIR, "permissions.json"),
5989
+ path5.join(DATA_DIR, "permissions.json"),
6321
5990
  {}
6322
5991
  );
6323
5992
  for (const [id, p] of Object.entries(perms)) {
6324
5993
  this.permissionLinks.set(id, p);
6325
5994
  }
6326
5995
  const offsets = readJson(
6327
- path6.join(DATA_DIR, "offsets.json"),
5996
+ path5.join(DATA_DIR, "offsets.json"),
6328
5997
  {}
6329
5998
  );
6330
5999
  for (const [k, v] of Object.entries(offsets)) {
6331
6000
  this.offsets.set(k, v);
6332
6001
  }
6333
6002
  const dedup = readJson(
6334
- path6.join(DATA_DIR, "dedup.json"),
6003
+ path5.join(DATA_DIR, "dedup.json"),
6335
6004
  {}
6336
6005
  );
6337
6006
  for (const [k, v] of Object.entries(dedup)) {
6338
6007
  this.dedupKeys.set(k, v);
6339
6008
  }
6340
- this.auditLog = readJson(path6.join(DATA_DIR, "audit.json"), []);
6009
+ this.auditLog = readJson(path5.join(DATA_DIR, "audit.json"), []);
6341
6010
  }
6342
6011
  reloadSessions() {
6343
6012
  const sessions = readJson(
6344
- path6.join(DATA_DIR, "sessions.json"),
6013
+ path5.join(DATA_DIR, "sessions.json"),
6345
6014
  {}
6346
6015
  );
6347
6016
  this.sessions = new Map(Object.entries(sessions));
6348
6017
  }
6349
6018
  reloadBindings() {
6350
6019
  const bindings = readJson(
6351
- path6.join(DATA_DIR, "bindings.json"),
6020
+ path5.join(DATA_DIR, "bindings.json"),
6352
6021
  {}
6353
6022
  );
6354
6023
  const normalized = /* @__PURE__ */ new Map();
6355
6024
  let changed = false;
6356
6025
  for (const binding of Object.values(bindings)) {
6357
- const normalizedBinding = normalizeLegacyBinding(binding);
6026
+ const normalizedBinding = upgradeLegacyBinding(binding);
6358
6027
  if (didBindingChange(binding, normalizedBinding)) {
6359
6028
  changed = true;
6360
6029
  }
@@ -6367,47 +6036,47 @@ var JsonFileStore = class {
6367
6036
  }
6368
6037
  persistSessions() {
6369
6038
  writeJson(
6370
- path6.join(DATA_DIR, "sessions.json"),
6039
+ path5.join(DATA_DIR, "sessions.json"),
6371
6040
  Object.fromEntries(this.sessions)
6372
6041
  );
6373
6042
  }
6374
6043
  persistBindings() {
6375
6044
  writeJson(
6376
- path6.join(DATA_DIR, "bindings.json"),
6045
+ path5.join(DATA_DIR, "bindings.json"),
6377
6046
  Object.fromEntries(this.bindings)
6378
6047
  );
6379
6048
  }
6380
6049
  persistPermissions() {
6381
6050
  writeJson(
6382
- path6.join(DATA_DIR, "permissions.json"),
6051
+ path5.join(DATA_DIR, "permissions.json"),
6383
6052
  Object.fromEntries(this.permissionLinks)
6384
6053
  );
6385
6054
  }
6386
6055
  persistOffsets() {
6387
6056
  writeJson(
6388
- path6.join(DATA_DIR, "offsets.json"),
6057
+ path5.join(DATA_DIR, "offsets.json"),
6389
6058
  Object.fromEntries(this.offsets)
6390
6059
  );
6391
6060
  }
6392
6061
  persistDedup() {
6393
6062
  writeJson(
6394
- path6.join(DATA_DIR, "dedup.json"),
6063
+ path5.join(DATA_DIR, "dedup.json"),
6395
6064
  Object.fromEntries(this.dedupKeys)
6396
6065
  );
6397
6066
  }
6398
6067
  persistAudit() {
6399
- writeJson(path6.join(DATA_DIR, "audit.json"), this.auditLog);
6068
+ writeJson(path5.join(DATA_DIR, "audit.json"), this.auditLog);
6400
6069
  }
6401
6070
  persistMessages(sessionId) {
6402
6071
  const msgs = this.messages.get(sessionId) || [];
6403
- writeJson(path6.join(MESSAGES_DIR, `${sessionId}.json`), msgs);
6072
+ writeJson(path5.join(MESSAGES_DIR, `${sessionId}.json`), msgs);
6404
6073
  }
6405
6074
  loadMessages(sessionId) {
6406
6075
  if (this.messages.has(sessionId)) {
6407
6076
  return this.messages.get(sessionId);
6408
6077
  }
6409
6078
  const msgs = readJson(
6410
- path6.join(MESSAGES_DIR, `${sessionId}.json`),
6079
+ path5.join(MESSAGES_DIR, `${sessionId}.json`),
6411
6080
  []
6412
6081
  );
6413
6082
  this.messages.set(sessionId, msgs);
@@ -6575,7 +6244,7 @@ var JsonFileStore = class {
6575
6244
  }
6576
6245
  this.messages.delete(sessionId);
6577
6246
  try {
6578
- fs5.rmSync(path6.join(MESSAGES_DIR, `${sessionId}.json`), { force: true });
6247
+ fs4.rmSync(path5.join(MESSAGES_DIR, `${sessionId}.json`), { force: true });
6579
6248
  } catch {
6580
6249
  }
6581
6250
  this.persistSessions();
@@ -6758,8 +6427,8 @@ var JsonFileStore = class {
6758
6427
 
6759
6428
  // src/weixin-login.ts
6760
6429
  var import_qrcode = __toESM(require_lib(), 1);
6761
- import fs7 from "node:fs";
6762
- import path8 from "node:path";
6430
+ import fs6 from "node:fs";
6431
+ import path7 from "node:path";
6763
6432
  import { spawn as spawn2 } from "node:child_process";
6764
6433
 
6765
6434
  // src/adapters/weixin/weixin-api.ts
@@ -6812,24 +6481,24 @@ async function pollLoginQrStatus(qrcode, baseUrl) {
6812
6481
  }
6813
6482
 
6814
6483
  // src/weixin-store.ts
6815
- import fs6 from "node:fs";
6816
- import path7 from "node:path";
6817
- var DATA_DIR2 = path7.join(CTI_HOME, "data");
6818
- var ACCOUNTS_PATH = path7.join(DATA_DIR2, "weixin-accounts.json");
6819
- var CONTEXT_TOKENS_PATH = path7.join(DATA_DIR2, "weixin-context-tokens.json");
6484
+ import fs5 from "node:fs";
6485
+ import path6 from "node:path";
6486
+ var DATA_DIR2 = path6.join(CTI_HOME, "data");
6487
+ var ACCOUNTS_PATH = path6.join(DATA_DIR2, "weixin-accounts.json");
6488
+ var CONTEXT_TOKENS_PATH = path6.join(DATA_DIR2, "weixin-context-tokens.json");
6820
6489
  var DEFAULT_BASE_URL2 = "https://ilinkai.weixin.qq.com";
6821
6490
  var DEFAULT_CDN_BASE_URL2 = "https://novac2c.cdn.weixin.qq.com/c2c";
6822
6491
  function ensureDir2(dir) {
6823
- fs6.mkdirSync(dir, { recursive: true });
6492
+ fs5.mkdirSync(dir, { recursive: true });
6824
6493
  }
6825
6494
  function atomicWrite2(filePath, data) {
6826
6495
  const tmpPath = `${filePath}.tmp`;
6827
- fs6.writeFileSync(tmpPath, data, "utf-8");
6828
- fs6.renameSync(tmpPath, filePath);
6496
+ fs5.writeFileSync(tmpPath, data, "utf-8");
6497
+ fs5.renameSync(tmpPath, filePath);
6829
6498
  }
6830
6499
  function readJson2(filePath, fallback) {
6831
6500
  try {
6832
- const raw = fs6.readFileSync(filePath, "utf-8");
6501
+ const raw = fs5.readFileSync(filePath, "utf-8");
6833
6502
  return JSON.parse(raw);
6834
6503
  } catch {
6835
6504
  return fallback;
@@ -6941,10 +6610,10 @@ function deleteWeixinContextTokensByAccount(accountId) {
6941
6610
  var MAX_REFRESHES = 3;
6942
6611
  var QR_TTL_MS = 5 * 6e4;
6943
6612
  var POLL_INTERVAL_MS = 3e3;
6944
- var RUNTIME_DIR = path8.join(CTI_HOME, "runtime");
6945
- var HTML_PATH = path8.join(RUNTIME_DIR, "weixin-login.html");
6613
+ var RUNTIME_DIR = path7.join(CTI_HOME, "runtime");
6614
+ var HTML_PATH = path7.join(RUNTIME_DIR, "weixin-login.html");
6946
6615
  function ensureRuntimeDir() {
6947
- fs7.mkdirSync(RUNTIME_DIR, { recursive: true });
6616
+ fs6.mkdirSync(RUNTIME_DIR, { recursive: true });
6948
6617
  }
6949
6618
  function escapeHtml(text2) {
6950
6619
  return text2.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;");
@@ -7044,7 +6713,7 @@ async function writeQrHtml(session) {
7044
6713
  margin: 0,
7045
6714
  width: 300
7046
6715
  });
7047
- fs7.writeFileSync(HTML_PATH, buildQrHtml(session, qrSvg), "utf-8");
6716
+ fs6.writeFileSync(HTML_PATH, buildQrHtml(session, qrSvg), "utf-8");
7048
6717
  }
7049
6718
  function openQrHtml() {
7050
6719
  try {
@@ -7162,7 +6831,7 @@ async function runWeixinLogin(config = {}) {
7162
6831
  }
7163
6832
  var isMainModule = (() => {
7164
6833
  const entry = process.argv[1];
7165
- return !!entry && path8.resolve(entry) === path8.resolve(new URL(import.meta.url).pathname);
6834
+ return !!entry && path7.resolve(entry) === path7.resolve(new URL(import.meta.url).pathname);
7166
6835
  })();
7167
6836
  if (isMainModule) {
7168
6837
  runWeixinLogin().catch((err) => {
@@ -7172,14 +6841,14 @@ if (isMainModule) {
7172
6841
  }
7173
6842
 
7174
6843
  // src/codex-models.ts
7175
- import fs8 from "node:fs";
7176
- import os5 from "node:os";
7177
- import path9 from "node:path";
7178
- var DEFAULT_CODEX_CONFIG_PATH = path9.join(os5.homedir(), ".codex", "config.toml");
7179
- var DEFAULT_CODEX_MODELS_CACHE_PATH = path9.join(os5.homedir(), ".codex", "models_cache.json");
6844
+ import fs7 from "node:fs";
6845
+ import os4 from "node:os";
6846
+ import path8 from "node:path";
6847
+ var DEFAULT_CODEX_CONFIG_PATH = path8.join(os4.homedir(), ".codex", "config.toml");
6848
+ var DEFAULT_CODEX_MODELS_CACHE_PATH = path8.join(os4.homedir(), ".codex", "models_cache.json");
7180
6849
  function readConfiguredCodexModel(configPath = DEFAULT_CODEX_CONFIG_PATH) {
7181
6850
  try {
7182
- const raw = fs8.readFileSync(configPath, "utf-8");
6851
+ const raw = fs7.readFileSync(configPath, "utf-8");
7183
6852
  let inSection = false;
7184
6853
  for (const line of raw.split(/\r?\n/)) {
7185
6854
  const trimmed = line.trim();
@@ -7201,7 +6870,7 @@ function readConfiguredCodexModel(configPath = DEFAULT_CODEX_CONFIG_PATH) {
7201
6870
  }
7202
6871
  function listCachedCodexModels(cachePath = DEFAULT_CODEX_MODELS_CACHE_PATH) {
7203
6872
  try {
7204
- const raw = fs8.readFileSync(cachePath, "utf-8");
6873
+ const raw = fs7.readFileSync(cachePath, "utf-8");
7205
6874
  const parsed = JSON.parse(raw);
7206
6875
  if (!Array.isArray(parsed.models)) return [];
7207
6876
  const seen = /* @__PURE__ */ new Set();
@@ -7404,7 +7073,7 @@ function isLocalRequest(request) {
7404
7073
  return isLoopbackAddress(getRemoteAddress(request));
7405
7074
  }
7406
7075
  function getLanUrls(currentPort) {
7407
- const interfaces = os6.networkInterfaces();
7076
+ const interfaces = os5.networkInterfaces();
7408
7077
  const urls = /* @__PURE__ */ new Set();
7409
7078
  for (const records of Object.values(interfaces)) {
7410
7079
  for (const record of records || []) {
@@ -7712,53 +7381,6 @@ function deleteChannelInstance(current, channelId) {
7712
7381
  enabledChannels: Array.from(new Set(nextChannels.filter((channel) => channel.enabled).map((channel) => channel.provider)))
7713
7382
  };
7714
7383
  }
7715
- async function testCodexConnection(config) {
7716
- const provider = new CodexProvider(new PendingPermissions());
7717
- const abortController = new AbortController();
7718
- const timeout = setTimeout(() => abortController.abort(), 3e4);
7719
- const workingDirectory = config.defaultWorkspaceRoot || DEFAULT_WORKSPACE_ROOT;
7720
- fs9.mkdirSync(workingDirectory, { recursive: true });
7721
- try {
7722
- const stream = provider.streamChat({
7723
- prompt: "Reply with the single word OK.",
7724
- sessionId: `ui-test-${Date.now()}`,
7725
- workingDirectory,
7726
- permissionMode: "plan",
7727
- abortController
7728
- });
7729
- const reader = stream.getReader();
7730
- let responseText = "";
7731
- let raw = "";
7732
- while (true) {
7733
- const { done, value } = await reader.read();
7734
- if (done) break;
7735
- raw += value;
7736
- const lines = value.split("\n").map((line) => line.trim()).filter(Boolean);
7737
- for (const line of lines) {
7738
- if (!line.startsWith("data: ")) continue;
7739
- const parsed = JSON.parse(line.slice(6));
7740
- if (parsed.type === "text") {
7741
- responseText += parsed.data;
7742
- }
7743
- if (parsed.type === "error") {
7744
- return { ok: false, message: parsed.data, raw };
7745
- }
7746
- }
7747
- }
7748
- return {
7749
- ok: true,
7750
- message: responseText.trim() || "Codex SDK \u5DF2\u8FDE\u901A\uFF0C\u4F46\u6D4B\u8BD5\u6CA1\u6709\u8FD4\u56DE\u6587\u672C\u3002",
7751
- raw
7752
- };
7753
- } catch (error) {
7754
- return {
7755
- ok: false,
7756
- message: error instanceof Error ? error.message : String(error)
7757
- };
7758
- } finally {
7759
- clearTimeout(timeout);
7760
- }
7761
- }
7762
7384
  function renderLoginHtml() {
7763
7385
  return `<!doctype html>
7764
7386
  <html lang="zh-CN">
@@ -8066,7 +7688,7 @@ function renderHtml() {
8066
7688
 
8067
7689
  .status-grid {
8068
7690
  display: grid;
8069
- grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
7691
+ grid-template-columns: repeat(3, minmax(0, 1fr));
8070
7692
  gap: 16px;
8071
7693
  margin-bottom: 20px;
8072
7694
  }
@@ -8097,6 +7719,13 @@ function renderHtml() {
8097
7719
  word-break: break-word;
8098
7720
  }
8099
7721
 
7722
+ .status-meta {
7723
+ margin-top: 8px;
7724
+ color: var(--muted);
7725
+ font-size: 12px;
7726
+ line-height: 1.45;
7727
+ }
7728
+
8100
7729
  .panel {
8101
7730
  padding: 20px;
8102
7731
  }
@@ -9073,33 +8702,30 @@ function renderHtml() {
9073
8702
 
9074
8703
  <section class="status-grid">
9075
8704
  <div class="status-card">
9076
- <strong>Bridge</strong>
8705
+ <strong>\u6865\u63A5\u670D\u52A1</strong>
9077
8706
  <div class="status-value" id="bridgeStatus">-</div>
8707
+ <div class="status-meta" id="bridgeStatusMeta">-</div>
9078
8708
  </div>
9079
8709
  <div class="status-card">
9080
- <strong>Bridge \u5F00\u673A\u81EA\u542F\u52A8</strong>
8710
+ <strong>\u6865\u63A5\u670D\u52A1\u5F00\u673A\u81EA\u542F\u52A8</strong>
9081
8711
  <div class="status-value" id="autostartStatus">-</div>
9082
8712
  </div>
9083
8713
  <div class="status-card">
9084
- <strong>Codex Skill</strong>
8714
+ <strong>Codex \u6280\u80FD</strong>
9085
8715
  <div class="status-value" id="integrationStatus">-</div>
9086
8716
  </div>
9087
8717
  <div class="status-card">
9088
- <strong>Runtime</strong>
8718
+ <strong>\u8FD0\u884C\u65F6</strong>
9089
8719
  <div class="status-value" id="runtimeStatus">-</div>
9090
8720
  </div>
9091
8721
  <div class="status-card">
9092
- <strong>Desktop Sessions</strong>
8722
+ <strong>\u684C\u9762\u4F1A\u8BDD</strong>
9093
8723
  <div class="status-value" id="desktopSessionCount">-</div>
9094
8724
  </div>
9095
8725
  <div class="status-card">
9096
- <strong>IM Bindings</strong>
8726
+ <strong>\u804A\u5929\u7ED1\u5B9A</strong>
9097
8727
  <div class="status-value" id="bindingCount">-</div>
9098
8728
  </div>
9099
- <div class="status-card">
9100
- <strong>Config Home</strong>
9101
- <div class="status-value" id="homeStatus" style="font-size: 14px;">-</div>
9102
- </div>
9103
8729
  </section>
9104
8730
 
9105
8731
  <div class="overview-grid">
@@ -9107,24 +8733,23 @@ function renderHtml() {
9107
8733
  <div class="panel-header">
9108
8734
  <div>
9109
8735
  <h2>\u8FD0\u884C\u63A7\u5236</h2>
9110
- <p>\u4FDD\u5B58\u914D\u7F6E\u540E\uFF0C\u53EF\u4EE5\u76F4\u63A5\u5728\u8FD9\u91CC\u542F\u505C bridge\u3001\u6D4B\u8BD5 Codex \u6216\u5237\u65B0\u6574\u4F53\u72B6\u6001\u3002</p>
8736
+ <p>\u4FDD\u5B58\u914D\u7F6E\u540E\uFF0C\u53EF\u4EE5\u76F4\u63A5\u5728\u8FD9\u91CC\u542F\u505C\u6865\u63A5\u670D\u52A1\u6216\u5237\u65B0\u6574\u4F53\u72B6\u6001\u3002</p>
9111
8737
  </div>
9112
8738
  </div>
9113
8739
  <div class="actions">
9114
- <button class="primary" id="startBridgeBtn">\u542F\u52A8 Bridge</button>
9115
- <button id="stopBridgeBtn">\u505C\u6B62 Bridge</button>
9116
- <button id="restartBridgeBtn">\u91CD\u542F Bridge</button>
9117
- <button id="testCodexBtn">\u6D4B\u8BD5 Codex</button>
8740
+ <button class="primary" id="startBridgeBtn">\u542F\u52A8\u6865\u63A5\u670D\u52A1</button>
8741
+ <button id="stopBridgeBtn">\u505C\u6B62\u6865\u63A5\u670D\u52A1</button>
8742
+ <button id="restartBridgeBtn">\u91CD\u542F\u6865\u63A5\u670D\u52A1</button>
9118
8743
  <button id="refreshBtn">\u5237\u65B0\u72B6\u6001</button>
9119
8744
  </div>
9120
8745
 
9121
8746
  <div class="panel-block">
9122
8747
  <p class="panel-subtitle">\u5F53\u524D\u80FD\u529B</p>
9123
- <div class="notice">\u5DF2\u63A5\u901A\uFF1A\u4FDD\u5B58\u914D\u7F6E\u3001\u540E\u53F0\u542F\u505C\u3001\u98DE\u4E66\u51ED\u636E\u6D4B\u8BD5\u3001\u5FAE\u4FE1\u626B\u7801\u3001Codex \u8FDE\u63A5\u6D4B\u8BD5\u3001\u684C\u9762\u4F1A\u8BDD\u53D1\u73B0\u3001IM \u7ED1\u5B9A\u67E5\u770B\u4E0E\u7F51\u9875\u4FA7\u5207\u6362\u3002</div>
8748
+ <div class="notice">\u5DF2\u63A5\u901A\uFF1A\u4FDD\u5B58\u914D\u7F6E\u3001\u540E\u53F0\u542F\u505C\u3001\u98DE\u4E66\u51ED\u636E\u6D4B\u8BD5\u3001\u5FAE\u4FE1\u626B\u7801\u3001\u684C\u9762\u4F1A\u8BDD\u53D1\u73B0\u3001IM \u7ED1\u5B9A\u67E5\u770B\u4E0E\u7F51\u9875\u4FA7\u5207\u6362\u3002</div>
9124
8749
  </div>
9125
8750
 
9126
8751
  <div class="panel-block">
9127
- <p class="panel-subtitle">Bridge \u5F00\u673A\u81EA\u542F\u52A8</p>
8752
+ <p class="panel-subtitle">\u6865\u63A5\u670D\u52A1\u5F00\u673A\u81EA\u542F\u52A8</p>
9128
8753
  <div class="notice" id="autostartNotice">\u6B63\u5728\u68C0\u67E5\u5F53\u524D Windows \u4EFB\u52A1\u8BA1\u5212\u7A0B\u5E8F\u72B6\u6001\u2026</div>
9129
8754
  <div class="actions" style="margin-top: 12px;">
9130
8755
  <button id="refreshAutostartBtn">\u5237\u65B0\u5F00\u673A\u81EA\u542F\u52A8\u72B6\u6001</button>
@@ -9132,10 +8757,10 @@ function renderHtml() {
9132
8757
  </div>
9133
8758
 
9134
8759
  <div class="panel-block">
9135
- <p class="panel-subtitle">\u53EF\u9009 Codex Skill</p>
9136
- <div class="notice">bridge \u4E0D\u518D\u6CE8\u5165\u53D1\u9001\u9644\u4EF6\u7684\u63D0\u793A\u8BCD\u3002\u9700\u8981\u8BA9 Codex \u77E5\u9053\u201C\u53EF\u4EE5\u628A\u672C\u5730\u56FE\u7247/\u6587\u4EF6\u56DE\u53D1\u5230 IM\u201D\u65F6\uFF0C\u8BF7\u5B89\u88C5\u8FD9\u4E2A\u53EF\u9009 skill\u3002</div>
8760
+ <p class="panel-subtitle">\u53EF\u9009 Codex \u6280\u80FD</p>
8761
+ <div class="notice">\u6865\u63A5\u670D\u52A1\u4E0D\u518D\u6CE8\u5165\u53D1\u9001\u9644\u4EF6\u7684\u63D0\u793A\u8BCD\u3002\u9700\u8981\u8BA9 Codex \u77E5\u9053\u201C\u53EF\u4EE5\u628A\u672C\u5730\u56FE\u7247/\u6587\u4EF6\u56DE\u53D1\u5230 IM\u201D\u65F6\uFF0C\u8BF7\u5B89\u88C5\u8FD9\u4E2A\u53EF\u9009\u6280\u80FD\u3002</div>
9137
8762
  <div class="actions" style="margin-top: 12px;">
9138
- <button id="installIntegrationBtn">\u5B89\u88C5\u53EF\u9009 Codex Skill</button>
8763
+ <button id="installIntegrationBtn">\u5B89\u88C5\u53EF\u9009 Codex \u6280\u80FD</button>
9139
8764
  </div>
9140
8765
  </div>
9141
8766
 
@@ -9329,7 +8954,7 @@ function renderHtml() {
9329
8954
  </div>
9330
8955
  </div>
9331
8956
 
9332
- <div class="notice" style="margin-bottom: 16px;">\u6700\u77ED\u4F7F\u7528\u8DEF\u5F84\uFF1A\u5148\u53D1 <code>/t</code> \u67E5\u770B\u6700\u8FD1\u4F1A\u8BDD\uFF0C\u518D\u53D1 <code>/t 1</code> \u63A5\u7BA1\uFF1B\u4E4B\u540E\u76F4\u63A5\u53D1\u9001\u6587\u672C\u5373\u53EF\u7EE7\u7EED\u5F53\u524D\u4F1A\u8BDD\u3002\u8FD9\u91CC\u4FDD\u7559\u539F\u59CB\u547D\u4EE4\uFF0C\u4EC5\u7528\u4E8E\u540E\u53F0\u67E5\u9605\u548C\u517C\u5BB9\u65E7\u7528\u6CD5\u3002</div>
8957
+ <div class="notice" style="margin-bottom: 16px;">\u6700\u77ED\u4F7F\u7528\u8DEF\u5F84\uFF1A\u5148\u53D1 <code>/t</code> \u67E5\u770B\u6700\u8FD1\u4F1A\u8BDD\uFF0C\u518D\u53D1 <code>/t 1</code> \u63A5\u7BA1\uFF1B\u4E4B\u540E\u76F4\u63A5\u53D1\u9001\u6587\u672C\u5373\u53EF\u7EE7\u7EED\u5F53\u524D\u4F1A\u8BDD\u3002</div>
9333
8958
 
9334
8959
  <div class="command-sections">
9335
8960
  <section class="command-section">
@@ -10389,14 +10014,15 @@ function renderHtml() {
10389
10014
  state.autostartStatus = status.autostart || null;
10390
10015
  state.weixinAccounts = status.weixin && Array.isArray(status.weixin.linkedAccounts) ? status.weixin.linkedAccounts : [];
10391
10016
  fillForm(config);
10392
- const runningChannelText = adapterStatuses().length
10393
- ? ' \xB7 ' + adapterStatuses().filter((item) => item.running).map((item) => item.channelAlias || item.channelType).join(', ')
10394
- : '';
10395
- document.getElementById('bridgeStatus').textContent = status.bridge.running ? 'Running' + runningChannelText : 'Stopped';
10017
+ const adapters = adapterStatuses();
10018
+ const runningAdapters = adapters.filter((item) => item.running);
10019
+ document.getElementById('bridgeStatus').textContent = status.bridge.running ? '\u8FD0\u884C\u4E2D' : '\u5DF2\u505C\u6B62';
10020
+ document.getElementById('bridgeStatusMeta').textContent = adapters.length
10021
+ ? ('\u8FD0\u884C\u5B9E\u4F8B ' + runningAdapters.length + ' / ' + adapters.length)
10022
+ : '\u5F53\u524D\u6CA1\u6709\u901A\u9053\u5B9E\u4F8B\u5728\u8FD0\u884C';
10396
10023
  renderAutostartStatus(status.autostart || null);
10397
10024
  document.getElementById('integrationStatus').textContent = status.codexIntegrationInstalled ? '\u5DF2\u5B89\u88C5' : '\u672A\u5B89\u88C5';
10398
10025
  document.getElementById('runtimeStatus').textContent = config.runtime || 'codex';
10399
- document.getElementById('homeStatus').textContent = status.home;
10400
10026
  document.getElementById('overviewHomeStatus').textContent = status.home;
10401
10027
  document.getElementById('packageRoot').textContent = status.packageRoot;
10402
10028
  renderBindings({
@@ -10414,7 +10040,7 @@ function renderHtml() {
10414
10040
  valueEl.textContent = '\u4E0D\u652F\u6301';
10415
10041
  noticeEl.textContent = status && status.error
10416
10042
  ? status.error
10417
- : '\u5F53\u524D\u7CFB\u7EDF\u6682\u4E0D\u652F\u6301 Bridge \u5F00\u673A\u81EA\u542F\u52A8\u3002';
10043
+ : '\u5F53\u524D\u7CFB\u7EDF\u6682\u4E0D\u652F\u6301\u6865\u63A5\u670D\u52A1\u5F00\u673A\u81EA\u542F\u52A8\u3002';
10418
10044
  refreshBtn.disabled = true;
10419
10045
  return;
10420
10046
  }
@@ -10713,7 +10339,7 @@ function renderHtml() {
10713
10339
  try {
10714
10340
  await saveConfig();
10715
10341
  const result = await api('/api/bridge/start', { method: 'POST' });
10716
- showMessage('opsMessage', 'success', 'Bridge \u5DF2\u542F\u52A8\u3002PID: ' + (result.status.pid || '-'));
10342
+ showMessage('opsMessage', 'success', '\u6865\u63A5\u670D\u52A1\u5DF2\u542F\u52A8\u3002PID: ' + (result.status.pid || '-'));
10717
10343
  await loadStatus();
10718
10344
  await loadBindings();
10719
10345
  await loadLogs();
@@ -10726,7 +10352,7 @@ function renderHtml() {
10726
10352
  document.getElementById('stopBridgeBtn').addEventListener('click', async () => {
10727
10353
  try {
10728
10354
  await api('/api/bridge/stop', { method: 'POST' });
10729
- showMessage('opsMessage', 'success', 'Bridge \u5DF2\u505C\u6B62\u3002');
10355
+ showMessage('opsMessage', 'success', '\u6865\u63A5\u670D\u52A1\u5DF2\u505C\u6B62\u3002');
10730
10356
  await loadStatus();
10731
10357
  await loadBindings();
10732
10358
  } catch (error) {
@@ -10738,7 +10364,7 @@ function renderHtml() {
10738
10364
  try {
10739
10365
  await saveConfig();
10740
10366
  const result = await api('/api/bridge/restart', { method: 'POST' });
10741
- showMessage('opsMessage', 'success', 'Bridge \u5DF2\u91CD\u542F\u3002PID: ' + (result.status.pid || '-'));
10367
+ showMessage('opsMessage', 'success', '\u6865\u63A5\u670D\u52A1\u5DF2\u91CD\u542F\u3002PID: ' + (result.status.pid || '-'));
10742
10368
  await loadStatus();
10743
10369
  await loadBindings();
10744
10370
  await loadLogs();
@@ -10748,16 +10374,6 @@ function renderHtml() {
10748
10374
  }
10749
10375
  });
10750
10376
 
10751
- document.getElementById('testCodexBtn').addEventListener('click', async () => {
10752
- try {
10753
- await saveConfig();
10754
- const result = await api('/api/test/codex', { method: 'POST' });
10755
- showMessage('opsMessage', result.ok ? 'success' : 'error', result.message);
10756
- } catch (error) {
10757
- showMessage('opsMessage', 'error', error.message);
10758
- }
10759
- });
10760
-
10761
10377
  document.getElementById('refreshBtn').addEventListener('click', async () => {
10762
10378
  try {
10763
10379
  await loadStatus();
@@ -10883,9 +10499,6 @@ function renderHtml() {
10883
10499
  showMessage('opsMessage', 'error', error.message);
10884
10500
  });
10885
10501
 
10886
- setInterval(() => {
10887
- loadBindings().catch(() => {});
10888
- }, 4000);
10889
10502
  </script>
10890
10503
  </body>
10891
10504
  </html>`;
@@ -11098,11 +10711,6 @@ var server = http.createServer(async (request, response) => {
11098
10711
  });
11099
10712
  return;
11100
10713
  }
11101
- if (request.method === "POST" && url.pathname === "/api/test/codex") {
11102
- const result = await testCodexConnection(loadConfig());
11103
- json(response, 200, result);
11104
- return;
11105
- }
11106
10714
  if (request.method === "POST" && url.pathname === "/api/install-codex-integration") {
11107
10715
  const result = await installCodexIntegration();
11108
10716
  json(response, 200, result);