codex-to-im 1.0.22 → 1.0.26

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,37 +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");
5952
- var npmUninstallLogFile = path5.join(runtimeDir, "npm-uninstall.log");
5617
+ var bridgeAutostartLauncherFile = path4.join(runtimeDir, "bridge-autostart.ps1");
5618
+ var npmUninstallLogFile = path4.join(runtimeDir, "npm-uninstall.log");
5953
5619
  var WINDOWS_HIDE = process.platform === "win32" ? { windowsHide: true } : {};
5954
5620
  function ensureDirs() {
5955
- fs4.mkdirSync(runtimeDir, { recursive: true });
5956
- fs4.mkdirSync(logsDir, { recursive: true });
5621
+ fs3.mkdirSync(runtimeDir, { recursive: true });
5622
+ fs3.mkdirSync(logsDir, { recursive: true });
5957
5623
  }
5958
5624
  function readJsonFile(filePath, fallback) {
5959
5625
  try {
5960
- return JSON.parse(fs4.readFileSync(filePath, "utf-8"));
5626
+ return JSON.parse(fs3.readFileSync(filePath, "utf-8"));
5961
5627
  } catch {
5962
5628
  return fallback;
5963
5629
  }
5964
5630
  }
5965
5631
  function readPid(filePath) {
5966
5632
  try {
5967
- const raw = fs4.readFileSync(filePath, "utf-8").trim();
5633
+ const raw = fs3.readFileSync(filePath, "utf-8").trim();
5968
5634
  const pid = Number(raw);
5969
5635
  return Number.isFinite(pid) ? pid : void 0;
5970
5636
  } catch {
@@ -5984,7 +5650,7 @@ function sleep(ms) {
5984
5650
  return new Promise((resolve) => setTimeout(resolve, ms));
5985
5651
  }
5986
5652
  function getCurrentWindowsUser() {
5987
- const user = process.env.USERNAME || os4.userInfo().username;
5653
+ const user = process.env.USERNAME || os3.userInfo().username;
5988
5654
  const domain = process.env.USERDOMAIN;
5989
5655
  return domain ? `${domain}\\${user}` : user;
5990
5656
  }
@@ -6085,12 +5751,12 @@ async function startBridge() {
6085
5751
  ensureDirs();
6086
5752
  const current = getBridgeStatus();
6087
5753
  if (current.running) return current;
6088
- const daemonEntry = path5.join(packageRoot, "dist", "daemon.mjs");
6089
- if (!fs4.existsSync(daemonEntry)) {
5754
+ const daemonEntry = path4.join(packageRoot, "dist", "daemon.mjs");
5755
+ if (!fs3.existsSync(daemonEntry)) {
6090
5756
  throw new Error(`Daemon bundle not found at ${daemonEntry}. Run npm run build first.`);
6091
5757
  }
6092
- const stdoutFd = fs4.openSync(path5.join(logsDir, "bridge-launcher.out.log"), "a");
6093
- 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");
6094
5760
  const child = spawn(process.execPath, [daemonEntry], {
6095
5761
  cwd: packageRoot,
6096
5762
  detached: true,
@@ -6193,37 +5859,37 @@ async function getBridgeAutostartStatus() {
6193
5859
  }
6194
5860
  function getBridgeLogs(lines = 200) {
6195
5861
  ensureDirs();
6196
- const filePath = path5.join(logsDir, "bridge.log");
6197
- if (!fs4.existsSync(filePath)) return "";
6198
- 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/);
6199
5865
  return all.slice(Math.max(0, all.length - lines)).join("\n");
6200
5866
  }
6201
5867
  function writeUiServerStatus(status) {
6202
5868
  ensureDirs();
6203
- fs4.writeFileSync(uiStatusFile, JSON.stringify(status, null, 2), "utf-8");
5869
+ fs3.writeFileSync(uiStatusFile, JSON.stringify(status, null, 2), "utf-8");
6204
5870
  }
6205
5871
  async function installCodexIntegration() {
6206
- const sourceSkill = path5.join(packageRoot, "SKILL.md");
6207
- if (!fs4.existsSync(sourceSkill)) {
5872
+ const sourceSkill = path4.join(packageRoot, "SKILL.md");
5873
+ if (!fs3.existsSync(sourceSkill)) {
6208
5874
  throw new Error(`SKILL.md not found at ${sourceSkill}`);
6209
5875
  }
6210
- const skillsDir = path5.join(os4.homedir(), ".codex", "skills");
6211
- const targetDir = path5.join(skillsDir, "codex-to-im");
6212
- fs4.mkdirSync(skillsDir, { recursive: true });
6213
- 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)) {
6214
5880
  return { targetDir, method: "existing" };
6215
5881
  }
6216
5882
  try {
6217
- fs4.symlinkSync(packageRoot, targetDir, process.platform === "win32" ? "junction" : "dir");
5883
+ fs3.symlinkSync(packageRoot, targetDir, process.platform === "win32" ? "junction" : "dir");
6218
5884
  return { targetDir, method: "junction" };
6219
5885
  } catch {
6220
- fs4.cpSync(packageRoot, targetDir, {
5886
+ fs3.cpSync(packageRoot, targetDir, {
6221
5887
  recursive: true,
6222
5888
  filter: (source) => {
6223
- const relative = path5.relative(packageRoot, source);
5889
+ const relative = path4.relative(packageRoot, source);
6224
5890
  if (!relative) return true;
6225
- if (relative === ".git" || relative.startsWith(`.git${path5.sep}`)) return false;
6226
- 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;
6227
5893
  return true;
6228
5894
  }
6229
5895
  });
@@ -6231,27 +5897,27 @@ async function installCodexIntegration() {
6231
5897
  }
6232
5898
  }
6233
5899
  function isCodexIntegrationInstalled() {
6234
- const targetDir = path5.join(os4.homedir(), ".codex", "skills", "codex-to-im");
6235
- 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"));
6236
5902
  }
6237
5903
 
6238
5904
  // src/store.ts
6239
- import fs5 from "node:fs";
6240
- import path6 from "node:path";
5905
+ import fs4 from "node:fs";
5906
+ import path5 from "node:path";
6241
5907
  import crypto2 from "node:crypto";
6242
- var DATA_DIR = path6.join(CTI_HOME, "data");
6243
- 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");
6244
5910
  function ensureDir(dir) {
6245
- fs5.mkdirSync(dir, { recursive: true });
5911
+ fs4.mkdirSync(dir, { recursive: true });
6246
5912
  }
6247
5913
  function atomicWrite(filePath, data) {
6248
5914
  const tmp = filePath + ".tmp";
6249
- fs5.writeFileSync(tmp, data, "utf-8");
6250
- fs5.renameSync(tmp, filePath);
5915
+ fs4.writeFileSync(tmp, data, "utf-8");
5916
+ fs4.renameSync(tmp, filePath);
6251
5917
  }
6252
5918
  function readJson(filePath, fallback) {
6253
5919
  try {
6254
- const raw = fs5.readFileSync(filePath, "utf-8");
5920
+ const raw = fs4.readFileSync(filePath, "utf-8");
6255
5921
  return JSON.parse(raw);
6256
5922
  } catch {
6257
5923
  return fallback;
@@ -6271,10 +5937,12 @@ function defaultAliasForProvider2(provider) {
6271
5937
  if (provider === "weixin") return "\u5FAE\u4FE1";
6272
5938
  return void 0;
6273
5939
  }
6274
- function normalizeLegacyBinding(binding) {
5940
+ function upgradeLegacyBinding(binding) {
6275
5941
  const config = loadConfig();
6276
- const legacyProvider = binding.channelType === "feishu" || binding.channelType === "weixin" ? binding.channelType : void 0;
6277
- 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);
6278
5946
  if (!resolvedInstance && !legacyProvider) {
6279
5947
  return {
6280
5948
  ...binding,
@@ -6318,44 +5986,44 @@ var JsonFileStore = class {
6318
5986
  this.reloadSessions();
6319
5987
  this.reloadBindings();
6320
5988
  const perms = readJson(
6321
- path6.join(DATA_DIR, "permissions.json"),
5989
+ path5.join(DATA_DIR, "permissions.json"),
6322
5990
  {}
6323
5991
  );
6324
5992
  for (const [id, p] of Object.entries(perms)) {
6325
5993
  this.permissionLinks.set(id, p);
6326
5994
  }
6327
5995
  const offsets = readJson(
6328
- path6.join(DATA_DIR, "offsets.json"),
5996
+ path5.join(DATA_DIR, "offsets.json"),
6329
5997
  {}
6330
5998
  );
6331
5999
  for (const [k, v] of Object.entries(offsets)) {
6332
6000
  this.offsets.set(k, v);
6333
6001
  }
6334
6002
  const dedup = readJson(
6335
- path6.join(DATA_DIR, "dedup.json"),
6003
+ path5.join(DATA_DIR, "dedup.json"),
6336
6004
  {}
6337
6005
  );
6338
6006
  for (const [k, v] of Object.entries(dedup)) {
6339
6007
  this.dedupKeys.set(k, v);
6340
6008
  }
6341
- this.auditLog = readJson(path6.join(DATA_DIR, "audit.json"), []);
6009
+ this.auditLog = readJson(path5.join(DATA_DIR, "audit.json"), []);
6342
6010
  }
6343
6011
  reloadSessions() {
6344
6012
  const sessions = readJson(
6345
- path6.join(DATA_DIR, "sessions.json"),
6013
+ path5.join(DATA_DIR, "sessions.json"),
6346
6014
  {}
6347
6015
  );
6348
6016
  this.sessions = new Map(Object.entries(sessions));
6349
6017
  }
6350
6018
  reloadBindings() {
6351
6019
  const bindings = readJson(
6352
- path6.join(DATA_DIR, "bindings.json"),
6020
+ path5.join(DATA_DIR, "bindings.json"),
6353
6021
  {}
6354
6022
  );
6355
6023
  const normalized = /* @__PURE__ */ new Map();
6356
6024
  let changed = false;
6357
6025
  for (const binding of Object.values(bindings)) {
6358
- const normalizedBinding = normalizeLegacyBinding(binding);
6026
+ const normalizedBinding = upgradeLegacyBinding(binding);
6359
6027
  if (didBindingChange(binding, normalizedBinding)) {
6360
6028
  changed = true;
6361
6029
  }
@@ -6368,47 +6036,47 @@ var JsonFileStore = class {
6368
6036
  }
6369
6037
  persistSessions() {
6370
6038
  writeJson(
6371
- path6.join(DATA_DIR, "sessions.json"),
6039
+ path5.join(DATA_DIR, "sessions.json"),
6372
6040
  Object.fromEntries(this.sessions)
6373
6041
  );
6374
6042
  }
6375
6043
  persistBindings() {
6376
6044
  writeJson(
6377
- path6.join(DATA_DIR, "bindings.json"),
6045
+ path5.join(DATA_DIR, "bindings.json"),
6378
6046
  Object.fromEntries(this.bindings)
6379
6047
  );
6380
6048
  }
6381
6049
  persistPermissions() {
6382
6050
  writeJson(
6383
- path6.join(DATA_DIR, "permissions.json"),
6051
+ path5.join(DATA_DIR, "permissions.json"),
6384
6052
  Object.fromEntries(this.permissionLinks)
6385
6053
  );
6386
6054
  }
6387
6055
  persistOffsets() {
6388
6056
  writeJson(
6389
- path6.join(DATA_DIR, "offsets.json"),
6057
+ path5.join(DATA_DIR, "offsets.json"),
6390
6058
  Object.fromEntries(this.offsets)
6391
6059
  );
6392
6060
  }
6393
6061
  persistDedup() {
6394
6062
  writeJson(
6395
- path6.join(DATA_DIR, "dedup.json"),
6063
+ path5.join(DATA_DIR, "dedup.json"),
6396
6064
  Object.fromEntries(this.dedupKeys)
6397
6065
  );
6398
6066
  }
6399
6067
  persistAudit() {
6400
- writeJson(path6.join(DATA_DIR, "audit.json"), this.auditLog);
6068
+ writeJson(path5.join(DATA_DIR, "audit.json"), this.auditLog);
6401
6069
  }
6402
6070
  persistMessages(sessionId) {
6403
6071
  const msgs = this.messages.get(sessionId) || [];
6404
- writeJson(path6.join(MESSAGES_DIR, `${sessionId}.json`), msgs);
6072
+ writeJson(path5.join(MESSAGES_DIR, `${sessionId}.json`), msgs);
6405
6073
  }
6406
6074
  loadMessages(sessionId) {
6407
6075
  if (this.messages.has(sessionId)) {
6408
6076
  return this.messages.get(sessionId);
6409
6077
  }
6410
6078
  const msgs = readJson(
6411
- path6.join(MESSAGES_DIR, `${sessionId}.json`),
6079
+ path5.join(MESSAGES_DIR, `${sessionId}.json`),
6412
6080
  []
6413
6081
  );
6414
6082
  this.messages.set(sessionId, msgs);
@@ -6576,7 +6244,7 @@ var JsonFileStore = class {
6576
6244
  }
6577
6245
  this.messages.delete(sessionId);
6578
6246
  try {
6579
- fs5.rmSync(path6.join(MESSAGES_DIR, `${sessionId}.json`), { force: true });
6247
+ fs4.rmSync(path5.join(MESSAGES_DIR, `${sessionId}.json`), { force: true });
6580
6248
  } catch {
6581
6249
  }
6582
6250
  this.persistSessions();
@@ -6759,8 +6427,8 @@ var JsonFileStore = class {
6759
6427
 
6760
6428
  // src/weixin-login.ts
6761
6429
  var import_qrcode = __toESM(require_lib(), 1);
6762
- import fs7 from "node:fs";
6763
- import path8 from "node:path";
6430
+ import fs6 from "node:fs";
6431
+ import path7 from "node:path";
6764
6432
  import { spawn as spawn2 } from "node:child_process";
6765
6433
 
6766
6434
  // src/adapters/weixin/weixin-api.ts
@@ -6813,24 +6481,24 @@ async function pollLoginQrStatus(qrcode, baseUrl) {
6813
6481
  }
6814
6482
 
6815
6483
  // src/weixin-store.ts
6816
- import fs6 from "node:fs";
6817
- import path7 from "node:path";
6818
- var DATA_DIR2 = path7.join(CTI_HOME, "data");
6819
- var ACCOUNTS_PATH = path7.join(DATA_DIR2, "weixin-accounts.json");
6820
- 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");
6821
6489
  var DEFAULT_BASE_URL2 = "https://ilinkai.weixin.qq.com";
6822
6490
  var DEFAULT_CDN_BASE_URL2 = "https://novac2c.cdn.weixin.qq.com/c2c";
6823
6491
  function ensureDir2(dir) {
6824
- fs6.mkdirSync(dir, { recursive: true });
6492
+ fs5.mkdirSync(dir, { recursive: true });
6825
6493
  }
6826
6494
  function atomicWrite2(filePath, data) {
6827
6495
  const tmpPath = `${filePath}.tmp`;
6828
- fs6.writeFileSync(tmpPath, data, "utf-8");
6829
- fs6.renameSync(tmpPath, filePath);
6496
+ fs5.writeFileSync(tmpPath, data, "utf-8");
6497
+ fs5.renameSync(tmpPath, filePath);
6830
6498
  }
6831
6499
  function readJson2(filePath, fallback) {
6832
6500
  try {
6833
- const raw = fs6.readFileSync(filePath, "utf-8");
6501
+ const raw = fs5.readFileSync(filePath, "utf-8");
6834
6502
  return JSON.parse(raw);
6835
6503
  } catch {
6836
6504
  return fallback;
@@ -6942,10 +6610,10 @@ function deleteWeixinContextTokensByAccount(accountId) {
6942
6610
  var MAX_REFRESHES = 3;
6943
6611
  var QR_TTL_MS = 5 * 6e4;
6944
6612
  var POLL_INTERVAL_MS = 3e3;
6945
- var RUNTIME_DIR = path8.join(CTI_HOME, "runtime");
6946
- 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");
6947
6615
  function ensureRuntimeDir() {
6948
- fs7.mkdirSync(RUNTIME_DIR, { recursive: true });
6616
+ fs6.mkdirSync(RUNTIME_DIR, { recursive: true });
6949
6617
  }
6950
6618
  function escapeHtml(text2) {
6951
6619
  return text2.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;");
@@ -7045,7 +6713,7 @@ async function writeQrHtml(session) {
7045
6713
  margin: 0,
7046
6714
  width: 300
7047
6715
  });
7048
- fs7.writeFileSync(HTML_PATH, buildQrHtml(session, qrSvg), "utf-8");
6716
+ fs6.writeFileSync(HTML_PATH, buildQrHtml(session, qrSvg), "utf-8");
7049
6717
  }
7050
6718
  function openQrHtml() {
7051
6719
  try {
@@ -7163,7 +6831,7 @@ async function runWeixinLogin(config = {}) {
7163
6831
  }
7164
6832
  var isMainModule = (() => {
7165
6833
  const entry = process.argv[1];
7166
- 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);
7167
6835
  })();
7168
6836
  if (isMainModule) {
7169
6837
  runWeixinLogin().catch((err) => {
@@ -7173,14 +6841,14 @@ if (isMainModule) {
7173
6841
  }
7174
6842
 
7175
6843
  // src/codex-models.ts
7176
- import fs8 from "node:fs";
7177
- import os5 from "node:os";
7178
- import path9 from "node:path";
7179
- var DEFAULT_CODEX_CONFIG_PATH = path9.join(os5.homedir(), ".codex", "config.toml");
7180
- 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");
7181
6849
  function readConfiguredCodexModel(configPath = DEFAULT_CODEX_CONFIG_PATH) {
7182
6850
  try {
7183
- const raw = fs8.readFileSync(configPath, "utf-8");
6851
+ const raw = fs7.readFileSync(configPath, "utf-8");
7184
6852
  let inSection = false;
7185
6853
  for (const line of raw.split(/\r?\n/)) {
7186
6854
  const trimmed = line.trim();
@@ -7202,7 +6870,7 @@ function readConfiguredCodexModel(configPath = DEFAULT_CODEX_CONFIG_PATH) {
7202
6870
  }
7203
6871
  function listCachedCodexModels(cachePath = DEFAULT_CODEX_MODELS_CACHE_PATH) {
7204
6872
  try {
7205
- const raw = fs8.readFileSync(cachePath, "utf-8");
6873
+ const raw = fs7.readFileSync(cachePath, "utf-8");
7206
6874
  const parsed = JSON.parse(raw);
7207
6875
  if (!Array.isArray(parsed.models)) return [];
7208
6876
  const seen = /* @__PURE__ */ new Set();
@@ -7405,7 +7073,7 @@ function isLocalRequest(request) {
7405
7073
  return isLoopbackAddress(getRemoteAddress(request));
7406
7074
  }
7407
7075
  function getLanUrls(currentPort) {
7408
- const interfaces = os6.networkInterfaces();
7076
+ const interfaces = os5.networkInterfaces();
7409
7077
  const urls = /* @__PURE__ */ new Set();
7410
7078
  for (const records of Object.values(interfaces)) {
7411
7079
  for (const record of records || []) {
@@ -7713,53 +7381,6 @@ function deleteChannelInstance(current, channelId) {
7713
7381
  enabledChannels: Array.from(new Set(nextChannels.filter((channel) => channel.enabled).map((channel) => channel.provider)))
7714
7382
  };
7715
7383
  }
7716
- async function testCodexConnection(config) {
7717
- const provider = new CodexProvider(new PendingPermissions());
7718
- const abortController = new AbortController();
7719
- const timeout = setTimeout(() => abortController.abort(), 3e4);
7720
- const workingDirectory = config.defaultWorkspaceRoot || DEFAULT_WORKSPACE_ROOT;
7721
- fs9.mkdirSync(workingDirectory, { recursive: true });
7722
- try {
7723
- const stream = provider.streamChat({
7724
- prompt: "Reply with the single word OK.",
7725
- sessionId: `ui-test-${Date.now()}`,
7726
- workingDirectory,
7727
- permissionMode: "plan",
7728
- abortController
7729
- });
7730
- const reader = stream.getReader();
7731
- let responseText = "";
7732
- let raw = "";
7733
- while (true) {
7734
- const { done, value } = await reader.read();
7735
- if (done) break;
7736
- raw += value;
7737
- const lines = value.split("\n").map((line) => line.trim()).filter(Boolean);
7738
- for (const line of lines) {
7739
- if (!line.startsWith("data: ")) continue;
7740
- const parsed = JSON.parse(line.slice(6));
7741
- if (parsed.type === "text") {
7742
- responseText += parsed.data;
7743
- }
7744
- if (parsed.type === "error") {
7745
- return { ok: false, message: parsed.data, raw };
7746
- }
7747
- }
7748
- }
7749
- return {
7750
- ok: true,
7751
- message: responseText.trim() || "Codex SDK \u5DF2\u8FDE\u901A\uFF0C\u4F46\u6D4B\u8BD5\u6CA1\u6709\u8FD4\u56DE\u6587\u672C\u3002",
7752
- raw
7753
- };
7754
- } catch (error) {
7755
- return {
7756
- ok: false,
7757
- message: error instanceof Error ? error.message : String(error)
7758
- };
7759
- } finally {
7760
- clearTimeout(timeout);
7761
- }
7762
- }
7763
7384
  function renderLoginHtml() {
7764
7385
  return `<!doctype html>
7765
7386
  <html lang="zh-CN">
@@ -8067,7 +7688,7 @@ function renderHtml() {
8067
7688
 
8068
7689
  .status-grid {
8069
7690
  display: grid;
8070
- grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
7691
+ grid-template-columns: repeat(3, minmax(0, 1fr));
8071
7692
  gap: 16px;
8072
7693
  margin-bottom: 20px;
8073
7694
  }
@@ -8098,6 +7719,13 @@ function renderHtml() {
8098
7719
  word-break: break-word;
8099
7720
  }
8100
7721
 
7722
+ .status-meta {
7723
+ margin-top: 8px;
7724
+ color: var(--muted);
7725
+ font-size: 12px;
7726
+ line-height: 1.45;
7727
+ }
7728
+
8101
7729
  .panel {
8102
7730
  padding: 20px;
8103
7731
  }
@@ -9074,33 +8702,30 @@ function renderHtml() {
9074
8702
 
9075
8703
  <section class="status-grid">
9076
8704
  <div class="status-card">
9077
- <strong>Bridge</strong>
8705
+ <strong>\u6865\u63A5\u670D\u52A1</strong>
9078
8706
  <div class="status-value" id="bridgeStatus">-</div>
8707
+ <div class="status-meta" id="bridgeStatusMeta">-</div>
9079
8708
  </div>
9080
8709
  <div class="status-card">
9081
- <strong>Bridge \u5F00\u673A\u81EA\u542F\u52A8</strong>
8710
+ <strong>\u6865\u63A5\u670D\u52A1\u5F00\u673A\u81EA\u542F\u52A8</strong>
9082
8711
  <div class="status-value" id="autostartStatus">-</div>
9083
8712
  </div>
9084
8713
  <div class="status-card">
9085
- <strong>Codex Skill</strong>
8714
+ <strong>Codex \u6280\u80FD</strong>
9086
8715
  <div class="status-value" id="integrationStatus">-</div>
9087
8716
  </div>
9088
8717
  <div class="status-card">
9089
- <strong>Runtime</strong>
8718
+ <strong>\u8FD0\u884C\u65F6</strong>
9090
8719
  <div class="status-value" id="runtimeStatus">-</div>
9091
8720
  </div>
9092
8721
  <div class="status-card">
9093
- <strong>Desktop Sessions</strong>
8722
+ <strong>\u684C\u9762\u4F1A\u8BDD</strong>
9094
8723
  <div class="status-value" id="desktopSessionCount">-</div>
9095
8724
  </div>
9096
8725
  <div class="status-card">
9097
- <strong>IM Bindings</strong>
8726
+ <strong>\u804A\u5929\u7ED1\u5B9A</strong>
9098
8727
  <div class="status-value" id="bindingCount">-</div>
9099
8728
  </div>
9100
- <div class="status-card">
9101
- <strong>Config Home</strong>
9102
- <div class="status-value" id="homeStatus" style="font-size: 14px;">-</div>
9103
- </div>
9104
8729
  </section>
9105
8730
 
9106
8731
  <div class="overview-grid">
@@ -9108,24 +8733,23 @@ function renderHtml() {
9108
8733
  <div class="panel-header">
9109
8734
  <div>
9110
8735
  <h2>\u8FD0\u884C\u63A7\u5236</h2>
9111
- <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>
9112
8737
  </div>
9113
8738
  </div>
9114
8739
  <div class="actions">
9115
- <button class="primary" id="startBridgeBtn">\u542F\u52A8 Bridge</button>
9116
- <button id="stopBridgeBtn">\u505C\u6B62 Bridge</button>
9117
- <button id="restartBridgeBtn">\u91CD\u542F Bridge</button>
9118
- <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>
9119
8743
  <button id="refreshBtn">\u5237\u65B0\u72B6\u6001</button>
9120
8744
  </div>
9121
8745
 
9122
8746
  <div class="panel-block">
9123
8747
  <p class="panel-subtitle">\u5F53\u524D\u80FD\u529B</p>
9124
- <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>
9125
8749
  </div>
9126
8750
 
9127
8751
  <div class="panel-block">
9128
- <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>
9129
8753
  <div class="notice" id="autostartNotice">\u6B63\u5728\u68C0\u67E5\u5F53\u524D Windows \u4EFB\u52A1\u8BA1\u5212\u7A0B\u5E8F\u72B6\u6001\u2026</div>
9130
8754
  <div class="actions" style="margin-top: 12px;">
9131
8755
  <button id="refreshAutostartBtn">\u5237\u65B0\u5F00\u673A\u81EA\u542F\u52A8\u72B6\u6001</button>
@@ -9133,10 +8757,10 @@ function renderHtml() {
9133
8757
  </div>
9134
8758
 
9135
8759
  <div class="panel-block">
9136
- <p class="panel-subtitle">\u53EF\u9009 Codex Skill</p>
9137
- <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>
9138
8762
  <div class="actions" style="margin-top: 12px;">
9139
- <button id="installIntegrationBtn">\u5B89\u88C5\u53EF\u9009 Codex Skill</button>
8763
+ <button id="installIntegrationBtn">\u5B89\u88C5\u53EF\u9009 Codex \u6280\u80FD</button>
9140
8764
  </div>
9141
8765
  </div>
9142
8766
 
@@ -9330,7 +8954,7 @@ function renderHtml() {
9330
8954
  </div>
9331
8955
  </div>
9332
8956
 
9333
- <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>
9334
8958
 
9335
8959
  <div class="command-sections">
9336
8960
  <section class="command-section">
@@ -10390,14 +10014,15 @@ function renderHtml() {
10390
10014
  state.autostartStatus = status.autostart || null;
10391
10015
  state.weixinAccounts = status.weixin && Array.isArray(status.weixin.linkedAccounts) ? status.weixin.linkedAccounts : [];
10392
10016
  fillForm(config);
10393
- const runningChannelText = adapterStatuses().length
10394
- ? ' \xB7 ' + adapterStatuses().filter((item) => item.running).map((item) => item.channelAlias || item.channelType).join(', ')
10395
- : '';
10396
- 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';
10397
10023
  renderAutostartStatus(status.autostart || null);
10398
10024
  document.getElementById('integrationStatus').textContent = status.codexIntegrationInstalled ? '\u5DF2\u5B89\u88C5' : '\u672A\u5B89\u88C5';
10399
10025
  document.getElementById('runtimeStatus').textContent = config.runtime || 'codex';
10400
- document.getElementById('homeStatus').textContent = status.home;
10401
10026
  document.getElementById('overviewHomeStatus').textContent = status.home;
10402
10027
  document.getElementById('packageRoot').textContent = status.packageRoot;
10403
10028
  renderBindings({
@@ -10415,7 +10040,7 @@ function renderHtml() {
10415
10040
  valueEl.textContent = '\u4E0D\u652F\u6301';
10416
10041
  noticeEl.textContent = status && status.error
10417
10042
  ? status.error
10418
- : '\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';
10419
10044
  refreshBtn.disabled = true;
10420
10045
  return;
10421
10046
  }
@@ -10714,7 +10339,7 @@ function renderHtml() {
10714
10339
  try {
10715
10340
  await saveConfig();
10716
10341
  const result = await api('/api/bridge/start', { method: 'POST' });
10717
- 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 || '-'));
10718
10343
  await loadStatus();
10719
10344
  await loadBindings();
10720
10345
  await loadLogs();
@@ -10727,7 +10352,7 @@ function renderHtml() {
10727
10352
  document.getElementById('stopBridgeBtn').addEventListener('click', async () => {
10728
10353
  try {
10729
10354
  await api('/api/bridge/stop', { method: 'POST' });
10730
- showMessage('opsMessage', 'success', 'Bridge \u5DF2\u505C\u6B62\u3002');
10355
+ showMessage('opsMessage', 'success', '\u6865\u63A5\u670D\u52A1\u5DF2\u505C\u6B62\u3002');
10731
10356
  await loadStatus();
10732
10357
  await loadBindings();
10733
10358
  } catch (error) {
@@ -10739,7 +10364,7 @@ function renderHtml() {
10739
10364
  try {
10740
10365
  await saveConfig();
10741
10366
  const result = await api('/api/bridge/restart', { method: 'POST' });
10742
- 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 || '-'));
10743
10368
  await loadStatus();
10744
10369
  await loadBindings();
10745
10370
  await loadLogs();
@@ -10749,16 +10374,6 @@ function renderHtml() {
10749
10374
  }
10750
10375
  });
10751
10376
 
10752
- document.getElementById('testCodexBtn').addEventListener('click', async () => {
10753
- try {
10754
- await saveConfig();
10755
- const result = await api('/api/test/codex', { method: 'POST' });
10756
- showMessage('opsMessage', result.ok ? 'success' : 'error', result.message);
10757
- } catch (error) {
10758
- showMessage('opsMessage', 'error', error.message);
10759
- }
10760
- });
10761
-
10762
10377
  document.getElementById('refreshBtn').addEventListener('click', async () => {
10763
10378
  try {
10764
10379
  await loadStatus();
@@ -11096,11 +10711,6 @@ var server = http.createServer(async (request, response) => {
11096
10711
  });
11097
10712
  return;
11098
10713
  }
11099
- if (request.method === "POST" && url.pathname === "/api/test/codex") {
11100
- const result = await testCodexConnection(loadConfig());
11101
- json(response, 200, result);
11102
- return;
11103
- }
11104
10714
  if (request.method === "POST" && url.pathname === "/api/install-codex-integration") {
11105
10715
  const result = await installCodexIntegration();
11106
10716
  json(response, 200, result);