codex-to-im 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1572,10 +1572,10 @@ var require_segments = __commonJS({
1572
1572
  const segs = getSegmentsFromString(data, Utils.isKanjiModeEnabled());
1573
1573
  const nodes = buildNodes(segs);
1574
1574
  const graph = buildGraph(nodes, version);
1575
- const path9 = dijkstra.find_path(graph.map, "start", "end");
1575
+ const path10 = dijkstra.find_path(graph.map, "start", "end");
1576
1576
  const optimizedSegs = [];
1577
- for (let i = 1; i < path9.length - 1; i++) {
1578
- optimizedSegs.push(graph.table[path9[i]].node);
1577
+ for (let i = 1; i < path10.length - 1; i++) {
1578
+ optimizedSegs.push(graph.table[path10[i]].node);
1579
1579
  }
1580
1580
  return exports.fromArray(mergeSegments(optimizedSegs));
1581
1581
  };
@@ -4011,7 +4011,7 @@ var require_utils2 = __commonJS({
4011
4011
  // node_modules/qrcode/lib/renderer/png.js
4012
4012
  var require_png2 = __commonJS({
4013
4013
  "node_modules/qrcode/lib/renderer/png.js"(exports) {
4014
- var fs8 = __require("fs");
4014
+ var fs10 = __require("fs");
4015
4015
  var PNG = require_png().PNG;
4016
4016
  var Utils = require_utils2();
4017
4017
  exports.render = function render(qrData, options) {
@@ -4052,7 +4052,7 @@ var require_png2 = __commonJS({
4052
4052
  });
4053
4053
  png.pack();
4054
4054
  };
4055
- exports.renderToFile = function renderToFile(path9, qrData, options, cb) {
4055
+ exports.renderToFile = function renderToFile(path10, qrData, options, cb) {
4056
4056
  if (typeof cb === "undefined") {
4057
4057
  cb = options;
4058
4058
  options = void 0;
@@ -4063,7 +4063,7 @@ var require_png2 = __commonJS({
4063
4063
  called = true;
4064
4064
  cb.apply(null, args);
4065
4065
  };
4066
- const stream = fs8.createWriteStream(path9);
4066
+ const stream = fs10.createWriteStream(path10);
4067
4067
  stream.on("error", done);
4068
4068
  stream.on("close", done);
4069
4069
  exports.renderToFileStream(stream, qrData, options);
@@ -4125,14 +4125,14 @@ var require_utf8 = __commonJS({
4125
4125
  }
4126
4126
  return output;
4127
4127
  };
4128
- exports.renderToFile = function renderToFile(path9, qrData, options, cb) {
4128
+ exports.renderToFile = function renderToFile(path10, qrData, options, cb) {
4129
4129
  if (typeof cb === "undefined") {
4130
4130
  cb = options;
4131
4131
  options = void 0;
4132
4132
  }
4133
- const fs8 = __require("fs");
4133
+ const fs10 = __require("fs");
4134
4134
  const utf8 = exports.render(qrData, options);
4135
- fs8.writeFile(path9, utf8, cb);
4135
+ fs10.writeFile(path10, utf8, cb);
4136
4136
  };
4137
4137
  }
4138
4138
  });
@@ -4253,7 +4253,7 @@ var require_svg_tag = __commonJS({
4253
4253
  return str;
4254
4254
  }
4255
4255
  function qrToPath(data, size, margin) {
4256
- let path9 = "";
4256
+ let path10 = "";
4257
4257
  let moveBy = 0;
4258
4258
  let newRow = false;
4259
4259
  let lineLength = 0;
@@ -4264,19 +4264,19 @@ var require_svg_tag = __commonJS({
4264
4264
  if (data[i]) {
4265
4265
  lineLength++;
4266
4266
  if (!(i > 0 && col > 0 && data[i - 1])) {
4267
- path9 += newRow ? svgCmd("M", col + margin, 0.5 + row + margin) : svgCmd("m", moveBy, 0);
4267
+ path10 += newRow ? svgCmd("M", col + margin, 0.5 + row + margin) : svgCmd("m", moveBy, 0);
4268
4268
  moveBy = 0;
4269
4269
  newRow = false;
4270
4270
  }
4271
4271
  if (!(col + 1 < size && data[i + 1])) {
4272
- path9 += svgCmd("h", lineLength);
4272
+ path10 += svgCmd("h", lineLength);
4273
4273
  lineLength = 0;
4274
4274
  }
4275
4275
  } else {
4276
4276
  moveBy++;
4277
4277
  }
4278
4278
  }
4279
- return path9;
4279
+ return path10;
4280
4280
  }
4281
4281
  exports.render = function render(qrData, options, cb) {
4282
4282
  const opts = Utils.getOptions(options);
@@ -4284,10 +4284,10 @@ var require_svg_tag = __commonJS({
4284
4284
  const data = qrData.modules.data;
4285
4285
  const qrcodesize = size + opts.margin * 2;
4286
4286
  const bg = !opts.color.light.a ? "" : "<path " + getColorAttrib(opts.color.light, "fill") + ' d="M0 0h' + qrcodesize + "v" + qrcodesize + 'H0z"/>';
4287
- const path9 = "<path " + getColorAttrib(opts.color.dark, "stroke") + ' d="' + qrToPath(data, size, opts.margin) + '"/>';
4287
+ const path10 = "<path " + getColorAttrib(opts.color.dark, "stroke") + ' d="' + qrToPath(data, size, opts.margin) + '"/>';
4288
4288
  const viewBox = 'viewBox="0 0 ' + qrcodesize + " " + qrcodesize + '"';
4289
4289
  const width = !opts.width ? "" : 'width="' + opts.width + '" height="' + opts.width + '" ';
4290
- const svgTag = '<svg xmlns="http://www.w3.org/2000/svg" ' + width + viewBox + ' shape-rendering="crispEdges">' + bg + path9 + "</svg>\n";
4290
+ const svgTag = '<svg xmlns="http://www.w3.org/2000/svg" ' + width + viewBox + ' shape-rendering="crispEdges">' + bg + path10 + "</svg>\n";
4291
4291
  if (typeof cb === "function") {
4292
4292
  cb(null, svgTag);
4293
4293
  }
@@ -4301,15 +4301,15 @@ var require_svg = __commonJS({
4301
4301
  "node_modules/qrcode/lib/renderer/svg.js"(exports) {
4302
4302
  var svgTagRenderer = require_svg_tag();
4303
4303
  exports.render = svgTagRenderer.render;
4304
- exports.renderToFile = function renderToFile(path9, qrData, options, cb) {
4304
+ exports.renderToFile = function renderToFile(path10, qrData, options, cb) {
4305
4305
  if (typeof cb === "undefined") {
4306
4306
  cb = options;
4307
4307
  options = void 0;
4308
4308
  }
4309
- const fs8 = __require("fs");
4309
+ const fs10 = __require("fs");
4310
4310
  const svgTag = exports.render(qrData, options);
4311
4311
  const xmlStr = '<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' + svgTag;
4312
- fs8.writeFile(path9, xmlStr, cb);
4312
+ fs10.writeFile(path10, xmlStr, cb);
4313
4313
  };
4314
4314
  }
4315
4315
  });
@@ -4467,8 +4467,8 @@ var require_server = __commonJS({
4467
4467
  cb
4468
4468
  };
4469
4469
  }
4470
- function getTypeFromFilename(path9) {
4471
- return path9.slice((path9.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
4470
+ function getTypeFromFilename(path10) {
4471
+ return path10.slice((path10.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
4472
4472
  }
4473
4473
  function getRendererFromType(type) {
4474
4474
  switch (type) {
@@ -4532,17 +4532,17 @@ var require_server = __commonJS({
4532
4532
  const renderer = getRendererFromType(params.opts.type);
4533
4533
  return render(renderer.renderToBuffer, text2, params);
4534
4534
  };
4535
- exports.toFile = function toFile(path9, text2, opts, cb) {
4536
- if (typeof path9 !== "string" || !(typeof text2 === "string" || typeof text2 === "object")) {
4535
+ exports.toFile = function toFile(path10, text2, opts, cb) {
4536
+ if (typeof path10 !== "string" || !(typeof text2 === "string" || typeof text2 === "object")) {
4537
4537
  throw new Error("Invalid argument");
4538
4538
  }
4539
4539
  if (arguments.length < 3 && !canPromise()) {
4540
4540
  throw new Error("Too few arguments provided");
4541
4541
  }
4542
4542
  const params = checkParams(text2, opts, cb);
4543
- const type = params.opts.type || getTypeFromFilename(path9);
4543
+ const type = params.opts.type || getTypeFromFilename(path10);
4544
4544
  const renderer = getRendererFromType(type);
4545
- const renderToFile = renderer.renderToFile.bind(null, path9);
4545
+ const renderToFile = renderer.renderToFile.bind(null, path10);
4546
4546
  return render(renderToFile, text2, params);
4547
4547
  };
4548
4548
  exports.toFileStream = function toFileStream(stream, text2, opts) {
@@ -4568,7 +4568,8 @@ 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 os5 from "node:os";
4571
+ import os6 from "node:os";
4572
+ import fs9 from "node:fs";
4572
4573
 
4573
4574
  // src/config.ts
4574
4575
  import fs from "node:fs";
@@ -4644,8 +4645,7 @@ function loadConfig() {
4644
4645
  return {
4645
4646
  runtime,
4646
4647
  enabledChannels: splitCsv(env.get("CTI_ENABLED_CHANNELS")) ?? ["feishu"],
4647
- defaultWorkDir: expandHomePath(env.get("CTI_DEFAULT_WORKDIR")) || process.cwd(),
4648
- defaultWorkspaceRoot: expandHomePath(env.get("CTI_DEFAULT_WORKSPACE_ROOT")) || DEFAULT_WORKSPACE_ROOT,
4648
+ defaultWorkspaceRoot: expandHomePath(env.get("CTI_DEFAULT_WORKSPACE_ROOT")) || void 0,
4649
4649
  defaultModel: env.get("CTI_DEFAULT_MODEL") || void 0,
4650
4650
  defaultMode: env.get("CTI_DEFAULT_MODE") || "code",
4651
4651
  historyMessageLimit: parsePositiveInt(env.get("CTI_HISTORY_MESSAGE_LIMIT")) ?? 8,
@@ -4693,7 +4693,6 @@ function saveConfig(config) {
4693
4693
  "CTI_ENABLED_CHANNELS",
4694
4694
  config.enabledChannels.join(",")
4695
4695
  );
4696
- out += formatEnvLine("CTI_DEFAULT_WORKDIR", config.defaultWorkDir);
4697
4696
  out += formatEnvLine("CTI_DEFAULT_WORKSPACE_ROOT", config.defaultWorkspaceRoot);
4698
4697
  if (config.defaultModel) out += formatEnvLine("CTI_DEFAULT_MODEL", config.defaultModel);
4699
4698
  out += formatEnvLine("CTI_DEFAULT_MODE", config.defaultMode);
@@ -4839,7 +4838,6 @@ function configToSettings(config) {
4839
4838
  m.set("bridge_weixin_base_url", config.weixinBaseUrl);
4840
4839
  if (config.weixinCdnBaseUrl)
4841
4840
  m.set("bridge_weixin_cdn_base_url", config.weixinCdnBaseUrl);
4842
- m.set("bridge_default_work_dir", config.defaultWorkDir);
4843
4841
  if (config.defaultWorkspaceRoot) {
4844
4842
  m.set("bridge_default_workspace_root", config.defaultWorkspaceRoot);
4845
4843
  }
@@ -4939,9 +4937,6 @@ function toApprovalPolicy(permissionMode) {
4939
4937
  return "on-request";
4940
4938
  }
4941
4939
  }
4942
- function shouldPassModelToCodex() {
4943
- return process.env.CTI_CODEX_PASS_MODEL === "true";
4944
- }
4945
4940
  function shouldSkipGitRepoCheck() {
4946
4941
  return process.env.CTI_CODEX_SKIP_GIT_REPO_CHECK === "true";
4947
4942
  }
@@ -5003,11 +4998,10 @@ var CodexProvider = class {
5003
4998
  const inMemoryThreadId = self.threadIds.get(params.sessionId);
5004
4999
  let savedThreadId = inMemoryThreadId || params.sdkSessionId || void 0;
5005
5000
  const approvalPolicy = toApprovalPolicy(params.permissionMode);
5006
- const passModel = shouldPassModelToCodex();
5007
5001
  const sandboxMode = normalizeSandboxMode(params.sandboxMode);
5008
5002
  const modelReasoningEffort = normalizeReasoningEffort(params.modelReasoningEffort);
5009
5003
  const threadOptions = {
5010
- ...passModel && params.model ? { model: params.model } : {},
5004
+ ...params.forceModel && params.model ? { model: params.model } : {},
5011
5005
  ...params.workingDirectory ? { workingDirectory: params.workingDirectory } : {},
5012
5006
  ...shouldSkipGitRepoCheck() ? { skipGitRepoCheck: true } : {},
5013
5007
  sandboxMode,
@@ -5477,7 +5471,7 @@ function bindStoreToSdkSession(store, channelType, chatId, sdkSessionId, opts) {
5477
5471
  mode: getSessionMode(store, existing)
5478
5472
  });
5479
5473
  }
5480
- const workingDirectory = opts?.workingDirectory || store.getSetting("bridge_default_work_dir") || process.env.HOME || "";
5474
+ const workingDirectory = opts?.workingDirectory || "";
5481
5475
  const model = opts?.model || store.getSetting("bridge_default_model") || "";
5482
5476
  const baseName = opts?.displayName || (workingDirectory ? path4.basename(workingDirectory) : sdkSessionId.slice(0, 8));
5483
5477
  const session = store.createSession(
@@ -6010,7 +6004,7 @@ var JsonFileStore = class {
6010
6004
  const session = {
6011
6005
  id: uuid(),
6012
6006
  name,
6013
- working_directory: cwd || this.getSetting("bridge_default_work_dir") || process.cwd(),
6007
+ working_directory: cwd || process.cwd(),
6014
6008
  model,
6015
6009
  preferred_mode: mode,
6016
6010
  system_prompt: systemPrompt,
@@ -6656,11 +6650,69 @@ if (isMainModule) {
6656
6650
  });
6657
6651
  }
6658
6652
 
6653
+ // src/codex-models.ts
6654
+ import fs8 from "node:fs";
6655
+ import os5 from "node:os";
6656
+ import path9 from "node:path";
6657
+ var DEFAULT_CODEX_CONFIG_PATH = path9.join(os5.homedir(), ".codex", "config.toml");
6658
+ var DEFAULT_CODEX_MODELS_CACHE_PATH = path9.join(os5.homedir(), ".codex", "models_cache.json");
6659
+ function readConfiguredCodexModel(configPath = DEFAULT_CODEX_CONFIG_PATH) {
6660
+ try {
6661
+ const raw = fs8.readFileSync(configPath, "utf-8");
6662
+ let inSection = false;
6663
+ for (const line of raw.split(/\r?\n/)) {
6664
+ const trimmed = line.trim();
6665
+ if (!trimmed || trimmed.startsWith("#")) continue;
6666
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
6667
+ inSection = true;
6668
+ continue;
6669
+ }
6670
+ if (inSection) continue;
6671
+ const match = trimmed.match(/^model\s*=\s*["']([^"']+)["']/);
6672
+ if (match?.[1]) {
6673
+ return match[1].trim();
6674
+ }
6675
+ }
6676
+ return null;
6677
+ } catch {
6678
+ return null;
6679
+ }
6680
+ }
6681
+ function listCachedCodexModels(cachePath = DEFAULT_CODEX_MODELS_CACHE_PATH) {
6682
+ try {
6683
+ const raw = fs8.readFileSync(cachePath, "utf-8");
6684
+ const parsed = JSON.parse(raw);
6685
+ if (!Array.isArray(parsed.models)) return [];
6686
+ const seen = /* @__PURE__ */ new Set();
6687
+ const models = [];
6688
+ for (const model of parsed.models) {
6689
+ if (typeof model?.slug !== "string" || !model.slug.trim()) continue;
6690
+ const slug = model.slug.trim();
6691
+ if (seen.has(slug)) continue;
6692
+ seen.add(slug);
6693
+ models.push({
6694
+ slug,
6695
+ displayName: typeof model.display_name === "string" && model.display_name.trim() ? model.display_name.trim() : slug,
6696
+ visibility: typeof model.visibility === "string" && model.visibility.trim() ? model.visibility.trim() : "list",
6697
+ supportedInApi: model.supported_in_api === true
6698
+ });
6699
+ }
6700
+ return models;
6701
+ } catch {
6702
+ return [];
6703
+ }
6704
+ }
6705
+ function listSelectableCodexModels(cachePath = DEFAULT_CODEX_MODELS_CACHE_PATH) {
6706
+ return listCachedCodexModels(cachePath).filter((model) => model.visibility !== "hide");
6707
+ }
6708
+
6659
6709
  // src/ui-server.ts
6660
6710
  var port = 4781;
6661
6711
  var serverStartTime = (/* @__PURE__ */ new Date()).toISOString();
6662
6712
  var supportedChannels = ["feishu", "weixin"];
6663
6713
  var AUTH_COOKIE_NAME = "cti_ui_auth";
6714
+ var availableCodexModels = listSelectableCodexModels();
6715
+ var availableCodexModelSlugs = new Set(availableCodexModels.map((model) => model.slug));
6664
6716
  function parsePreferredPort() {
6665
6717
  const raw = Number(process.env.CTI_UI_PORT || "4781");
6666
6718
  if (!Number.isInteger(raw) || raw <= 0 || raw > 65535) return 4781;
@@ -6791,7 +6843,7 @@ function isLocalRequest(request) {
6791
6843
  return isLoopbackAddress(getRemoteAddress(request));
6792
6844
  }
6793
6845
  function getLanUrls(currentPort) {
6794
- const interfaces = os5.networkInterfaces();
6846
+ const interfaces = os6.networkInterfaces();
6795
6847
  const urls = /* @__PURE__ */ new Set();
6796
6848
  for (const records of Object.values(interfaces)) {
6797
6849
  for (const record of records || []) {
@@ -6820,9 +6872,10 @@ function configToPayload(config) {
6820
6872
  return {
6821
6873
  runtime: config.runtime,
6822
6874
  enabledChannels: config.enabledChannels,
6823
- defaultWorkDir: config.defaultWorkDir,
6824
6875
  defaultWorkspaceRoot: config.defaultWorkspaceRoot || "",
6825
6876
  defaultModel: config.defaultModel || "",
6877
+ codexDefaultModel: readConfiguredCodexModel() || "",
6878
+ availableModels: availableCodexModels,
6826
6879
  defaultMode: config.defaultMode,
6827
6880
  historyMessageLimit: config.historyMessageLimit ?? 8,
6828
6881
  codexSkipGitRepoCheck: config.codexSkipGitRepoCheck === true,
@@ -6843,6 +6896,7 @@ function configToPayload(config) {
6843
6896
  }
6844
6897
  function mergeConfig(payload) {
6845
6898
  const current = loadConfig();
6899
+ const rawDefaultModel = typeof payload.defaultModel === "string" ? payload.defaultModel.trim() : void 0;
6846
6900
  const requestedChannels = Array.isArray(payload.enabledChannels) ? payload.enabledChannels.filter((value) => typeof value === "string") : current.enabledChannels;
6847
6901
  const uiAllowLan = payload.uiAllowLan === true;
6848
6902
  const requestedUiAccessToken = asString(payload.uiAccessToken);
@@ -6851,9 +6905,8 @@ function mergeConfig(payload) {
6851
6905
  ...current,
6852
6906
  runtime: payload.runtime === "claude" || payload.runtime === "auto" ? payload.runtime : "codex",
6853
6907
  enabledChannels: requestedChannels.filter((channel) => supportedChannels.includes(channel)),
6854
- defaultWorkDir: asString(payload.defaultWorkDir) || current.defaultWorkDir || process.cwd(),
6855
6908
  defaultWorkspaceRoot: asString(payload.defaultWorkspaceRoot),
6856
- defaultModel: asString(payload.defaultModel),
6909
+ defaultModel: rawDefaultModel === void 0 ? current.defaultModel : rawDefaultModel === "" ? void 0 : availableCodexModelSlugs.has(rawDefaultModel) ? rawDefaultModel : current.defaultModel,
6857
6910
  defaultMode: payload.defaultMode === "plan" || payload.defaultMode === "ask" ? payload.defaultMode : "code",
6858
6911
  historyMessageLimit: asPositiveInt(payload.historyMessageLimit) || current.historyMessageLimit || 8,
6859
6912
  codexSkipGitRepoCheck: payload.codexSkipGitRepoCheck === true,
@@ -6910,11 +6963,13 @@ async function testCodexConnection(config) {
6910
6963
  const provider = new CodexProvider(new PendingPermissions());
6911
6964
  const abortController = new AbortController();
6912
6965
  const timeout = setTimeout(() => abortController.abort(), 3e4);
6966
+ const workingDirectory = config.defaultWorkspaceRoot || DEFAULT_WORKSPACE_ROOT;
6967
+ fs9.mkdirSync(workingDirectory, { recursive: true });
6913
6968
  try {
6914
6969
  const stream = provider.streamChat({
6915
6970
  prompt: "Reply with the single word OK.",
6916
6971
  sessionId: `ui-test-${Date.now()}`,
6917
- workingDirectory: config.defaultWorkDir,
6972
+ workingDirectory,
6918
6973
  permissionMode: "plan",
6919
6974
  abortController
6920
6975
  });
@@ -8095,7 +8150,7 @@ function renderHtml() {
8095
8150
  <div class="page-header">
8096
8151
  <div>
8097
8152
  <h1 class="page-title">\u914D\u7F6E</h1>
8098
- <p class="page-copy">\u8FD9\u91CC\u7EF4\u62A4\u672C\u5730\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55\u3001\u8FD0\u884C\u6A21\u5F0F\u548C\u5168\u5C40\u884C\u4E3A\u5F00\u5173\u3002</p>
8153
+ <p class="page-copy">\u8FD9\u91CC\u7EF4\u62A4\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4\u3001\u8FD0\u884C\u6A21\u5F0F\u548C\u5168\u5C40\u884C\u4E3A\u5F00\u5173\u3002</p>
8099
8154
  </div>
8100
8155
  </div>
8101
8156
 
@@ -8103,7 +8158,7 @@ function renderHtml() {
8103
8158
  <div class="panel-header">
8104
8159
  <div>
8105
8160
  <h2>\u57FA\u7840\u914D\u7F6E</h2>
8106
- <p>\u4FDD\u5B58\u540E\u4F1A\u5199\u5165\u672C\u5730\u914D\u7F6E\u76EE\u5F55\u3002\u9ED8\u8BA4\u76EE\u5F55\u3001\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4\u3001Sandbox\u3001\u601D\u8003\u7EA7\u522B\u7B49\u4F1A\u5728\u4E0B\u4E00\u6B21\u8BF7\u6C42\u751F\u6548\uFF1B\u901A\u9053\u542F\u505C\u4F1A\u81EA\u52A8\u540C\u6B65\uFF1B\u53EA\u6709\u5C11\u6570\u8FD0\u884C\u65F6\u914D\u7F6E\u9700\u8981\u91CD\u542F Bridge\u3002</p>
8161
+ <p>\u4FDD\u5B58\u540E\u4F1A\u5199\u5165\u672C\u5730\u914D\u7F6E\u76EE\u5F55\u3002\u672A\u7ED1\u5B9A\u804A\u5929\u4F1A\u5148\u8FDB\u5165\u4E34\u65F6\u8349\u7A3F\u7EBF\u7A0B\uFF1B\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4\u3001Sandbox\u3001\u601D\u8003\u7EA7\u522B\u7B49\u4F1A\u5728\u4E0B\u4E00\u6B21\u8BF7\u6C42\u751F\u6548\uFF1B\u901A\u9053\u542F\u505C\u4F1A\u81EA\u52A8\u540C\u6B65\uFF1B\u53EA\u6709\u5C11\u6570\u8FD0\u884C\u65F6\u914D\u7F6E\u9700\u8981\u91CD\u542F Bridge\u3002</p>
8107
8162
  </div>
8108
8163
  <div class="toolbar">
8109
8164
  <button class="primary" id="saveConfigBtn">\u4FDD\u5B58\u914D\u7F6E</button>
@@ -8133,19 +8188,15 @@ function renderHtml() {
8133
8188
  <input id="historyMessageLimit" type="number" min="1" max="20" value="8" />
8134
8189
  </label>
8135
8190
  </div>
8136
- <label>
8137
- \u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55
8138
- <input id="defaultWorkDir" placeholder="D:\\workspace\\project" />
8139
- </label>
8140
8191
  <label>
8141
8192
  \u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4
8142
8193
  <input id="defaultWorkspaceRoot" placeholder="\u7559\u7A7A\u65F6\u4F7F\u7528 ~/cx2im" />
8143
8194
  </label>
8144
- <label>
8145
- \u9ED8\u8BA4\u6A21\u578B
8146
- <input id="defaultModel" placeholder="\u7559\u7A7A\u5219\u4F7F\u7528 runtime \u9ED8\u8BA4\u6A21\u578B" />
8147
- </label>
8148
- <div class="field-row">
8195
+ <div class="field-row triple">
8196
+ <label>
8197
+ \u9ED8\u8BA4\u6A21\u578B
8198
+ <select id="defaultModel"></select>
8199
+ </label>
8149
8200
  <label>
8150
8201
  Codex \u6587\u4EF6\u7CFB\u7EDF\u6743\u9650
8151
8202
  <select id="codexSandboxMode">
@@ -8165,7 +8216,7 @@ function renderHtml() {
8165
8216
  </select>
8166
8217
  </label>
8167
8218
  </div>
8168
- <div class="small">\u201C\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55\u201D\u7528\u4E8E\u65B0\u4F1A\u8BDD\u9ED8\u8BA4 cwd\uFF1B\u201C\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4\u201D\u7528\u4E8E <code>/new proj1</code> \u8FD9\u7C7B\u76F8\u5BF9\u9879\u76EE\u540D\u3002\u7559\u7A7A\u65F6\u4F1A\u6309\u5F53\u524D\u7CFB\u7EDF\u81EA\u52A8\u56DE\u9000\u5230 <code>~/cx2im</code>\u3002\u6587\u4EF6\u7CFB\u7EDF\u6743\u9650\u662F\u5168\u5C40\u9ED8\u8BA4\u503C\uFF0C\u601D\u8003\u7EA7\u522B\u53EF\u5728 IM \u4F1A\u8BDD\u91CC\u518D\u5355\u72EC\u8986\u76D6\u3002</div>
8219
+ <div class="small">\u672A\u7ED1\u5B9A\u7684 IM \u804A\u5929\u4F1A\u5148\u8FDB\u5165\u4E34\u65F6\u8349\u7A3F\u7EBF\u7A0B\uFF08\u7B49\u540C <code>/t 0</code>\uFF09\uFF1B\u201C\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4\u201D\u53EA\u7528\u4E8E <code>/new proj1</code> \u8FD9\u7C7B\u76F8\u5BF9\u9879\u76EE\u540D\u3002\u7559\u7A7A\u65F6\u4F1A\u6309\u5F53\u524D\u7CFB\u7EDF\u81EA\u52A8\u56DE\u9000\u5230 <code>~/cx2im</code>\u3002\u9ED8\u8BA4\u6A21\u578B\u5019\u9009\u9879\u6765\u81EA\u542F\u52A8\u65F6\u8BFB\u53D6\u7684 Codex \u6A21\u578B\u7F13\u5B58\uFF1A\u9690\u85CF\u6A21\u578B\u4E0D\u4F1A\u5C55\u793A\uFF0CCLI only \u6A21\u578B\u4F1A\u6807\u6210\u201C\u4EC5 IM / CLI\u201D\u3002\u7559\u7A7A\u5219\u7EE7\u7EED\u8DDF\u968F Codex \u5F53\u524D\u9ED8\u8BA4\u6A21\u578B\u3002\u6587\u4EF6\u7CFB\u7EDF\u6743\u9650\u662F\u5168\u5C40\u9ED8\u8BA4\u503C\uFF0C\u601D\u8003\u7EA7\u522B\u53EF\u5728 IM \u4F1A\u8BDD\u91CC\u518D\u5355\u72EC\u8986\u76D6\u3002</div>
8169
8220
  <div class="small">\u5F53\u524D\u9700\u8981\u91CD\u542F Bridge \u7684\u914D\u7F6E\uFF1A<code>Runtime</code>\u3001<code>\u81EA\u52A8\u6279\u51C6\u5DE5\u5177\u6743\u9650</code>\u3001<code>\u5141\u8BB8\u5728\u672A\u4FE1\u4EFB Git \u76EE\u5F55\u8FD0\u884C Codex</code>\u3001\u98DE\u4E66 <code>App ID</code>/<code>App Secret</code>/<code>Domain</code>\u3002</div>
8170
8221
  <div class="checkbox-row">
8171
8222
  <label class="checkbox"><input id="channelFeishu" type="checkbox" checked /> \u542F\u7528\u98DE\u4E66</label>
@@ -8231,8 +8282,8 @@ function renderHtml() {
8231
8282
  <div class="command-item"><div class="command-col-command"><code>/h</code></div><div class="command-col-original"><code>/help</code></div><div class="command-col-desc">\u67E5\u770B\u5E2E\u52A9\u3002</div></div>
8232
8283
  <div class="command-item"><div class="command-col-command"><code>/t</code></div><div class="command-col-original"><code>/threads</code></div><div class="command-col-desc">\u5217\u51FA\u6700\u8FD1\u684C\u9762\u4F1A\u8BDD\u3002</div></div>
8233
8284
  <div class="command-item"><div class="command-col-command"><code>/t &lt;\u5E8F\u53F7&gt;</code></div><div class="command-col-original"><code>/thread &lt;\u5E8F\u53F7&gt;</code></div><div class="command-col-desc">\u6309\u5E8F\u53F7\u63A5\u7BA1\u684C\u9762\u4F1A\u8BDD\u3002</div></div>
8234
- <div class="command-item"><div class="command-col-command"><code>/n [\u7EDD\u5BF9\u8DEF\u5F84 | \u9879\u76EE\u540D]</code></div><div class="command-col-original"><code>/new [\u7EDD\u5BF9\u8DEF\u5F84 | \u9879\u76EE\u540D]</code></div><div class="command-col-desc">\u65B0\u5EFA\u4F1A\u8BDD\uFF1B\u76F8\u5BF9\u9879\u76EE\u540D\u4F1A\u5728\u201C\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4\u201D\u4E0B\u521B\u5EFA\u76EE\u5F55\u3002</div></div>
8235
- <div class="command-item"><div class="command-col-command"><code>\u76F4\u63A5\u53D1\u9001\u6587\u672C</code></div><div class="command-col-original">\u2014</div><div class="command-col-desc">\u7EE7\u7EED\u5F53\u524D\u5DF2\u7ED1\u5B9A\u4F1A\u8BDD\u3002</div></div>
8285
+ <div class="command-item"><div class="command-col-command"><code>/n [\u7EDD\u5BF9\u8DEF\u5F84 | \u9879\u76EE\u540D]</code></div><div class="command-col-original"><code>/new [\u7EDD\u5BF9\u8DEF\u5F84 | \u9879\u76EE\u540D]</code></div><div class="command-col-desc">\u4E0D\u5E26\u53C2\u6570\u65F6\u5728\u5F53\u524D\u6B63\u5F0F\u4F1A\u8BDD\u76EE\u5F55\u4E0B\u65B0\u5EFA\u7EBF\u7A0B\uFF1B\u76F8\u5BF9\u9879\u76EE\u540D\u4F1A\u5728\u201C\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4\u201D\u4E0B\u521B\u5EFA\u76EE\u5F55\uFF1B\u5F53\u524D\u82E5\u662F\u4E34\u65F6\u8349\u7A3F\u7EBF\u7A0B\u5219\u4F1A\u62A5\u9519\u3002\u901A\u8FC7 IM \u521B\u5EFA\u7684\u65B0\u7EBF\u7A0B\u5F53\u524D\u53EA\u4FDD\u8BC1\u5728 IM \u4E2D\u53EF\u7EE7\u7EED\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u51FA\u73B0\u5728 Codex Desktop \u4F1A\u8BDD\u5217\u8868\u4E2D\u3002</div></div>
8286
+ <div class="command-item"><div class="command-col-command"><code>\u76F4\u63A5\u53D1\u9001\u6587\u672C</code></div><div class="command-col-original">\u2014</div><div class="command-col-desc">\u7EE7\u7EED\u5F53\u524D\u5DF2\u7ED1\u5B9A\u4F1A\u8BDD\uFF1B\u672A\u7ED1\u5B9A\u65F6\u4F1A\u81EA\u52A8\u8FDB\u5165\u4E34\u65F6\u8349\u7A3F\u7EBF\u7A0B\u3002</div></div>
8236
8287
  <div class="command-item"><div class="command-col-command"><code>/his</code></div><div class="command-col-original"><code>/history</code></div><div class="command-col-desc">\u67E5\u770B\u5F53\u524D\u4F1A\u8BDD\u6574\u7406\u540E\u7684\u6458\u8981\u3002</div></div>
8237
8288
  <div class="command-item"><div class="command-col-command"><code>/his raw</code></div><div class="command-col-original"><code>/history raw</code></div><div class="command-col-desc">\u67E5\u770B\u6700\u8FD1 N \u6761\u539F\u59CB\u6D88\u606F\u3002</div></div>
8238
8289
  </div>
@@ -8244,6 +8295,7 @@ function renderHtml() {
8244
8295
  <div class="command-list-head"><div>\u547D\u4EE4</div><div>\u539F\u59CB\u547D\u4EE4</div><div>\u8BF4\u660E</div></div>
8245
8296
  <div class="command-item"><div class="command-col-command"><code>/m</code></div><div class="command-col-original"><code>/mode</code></div><div class="command-col-desc">\u67E5\u770B\u5F53\u524D\u6A21\u5F0F\uFF1B\u53EF\u9009 <code>code</code>\u3001<code>plan</code>\u3001<code>ask</code>\u3002</div></div>
8246
8297
  <div class="command-item"><div class="command-col-command"><code>/r</code></div><div class="command-col-original"><code>/reasoning</code></div><div class="command-col-desc">\u67E5\u770B\u5F53\u524D\u601D\u8003\u7EA7\u522B\uFF1B\u53EF\u9009 <code>1=minimal</code>\u3001<code>2=low</code>\u3001<code>3=medium</code>\u3001<code>4=high</code>\u3001<code>5=xhigh</code>\u3002</div></div>
8298
+ <div class="command-item"><div class="command-col-command"><code>/model [slug|default]</code></div><div class="command-col-original"><code>/model [slug|default]</code></div><div class="command-col-desc">\u67E5\u770B\u6216\u5207\u6362\u5F53\u524D IM \u4F1A\u8BDD\u4F7F\u7528\u7684\u6A21\u578B\uFF1BCLI only \u6A21\u578B\u4F1A\u6807\u6CE8\u201C\u4EC5 IM / CLI\u201D\uFF0C\u5171\u4EAB\u684C\u9762\u7EBF\u7A0B\u53EA\u5141\u8BB8\u67E5\u770B\u4E0D\u5141\u8BB8\u5207\u6362\u3002</div></div>
8247
8299
  <div class="command-item"><div class="command-col-command"><code>/t 0</code></div><div class="command-col-original"><code>/thread 0</code></div><div class="command-col-desc">\u5207\u6362\u5230\u5F53\u524D\u804A\u5929\u7684\u4E34\u65F6\u8349\u7A3F\u7EBF\u7A0B\u3002</div></div>
8248
8300
  <div class="command-item"><div class="command-col-command"><code>/t 0 reset</code></div><div class="command-col-original"><code>/thread 0 reset</code></div><div class="command-col-desc">\u4E22\u5F03\u5F53\u524D\u8349\u7A3F\u4E0A\u4E0B\u6587\u5E76\u91CD\u5EFA\u4E00\u6761\u65B0\u7684\u8349\u7A3F\u7EBF\u7A0B\u3002</div></div>
8249
8301
  <div class="command-item"><div class="command-col-command">\u2014</div><div class="command-col-original"><code>/stop</code></div><div class="command-col-desc">\u505C\u6B62\u5F53\u524D\u4EFB\u52A1\u3002</div></div>
@@ -8315,11 +8367,11 @@ function renderHtml() {
8315
8367
  <label class="checkbox"><input id="feishuStreamingEnabled" type="checkbox" checked /> \u542F\u7528\u98DE\u4E66\u6D41\u5F0F\u54CD\u5E94\u5361\u7247</label>
8316
8368
  </div>
8317
8369
  <div class="checkbox-row">
8318
- <label class="checkbox"><input id="feishuCommandMarkdownEnabled" type="checkbox" checked /> \u547D\u4EE4\u53CD\u9988\u4F7F\u7528 Markdown</label>
8370
+ <label class="checkbox"><input id="feishuCommandMarkdownEnabled" type="checkbox" checked /> \u53CD\u9988\u4F7F\u7528markdown</label>
8319
8371
  </div>
8320
8372
  <div class="small">\u9700\u8981\u98DE\u4E66\u4FA7\u5DF2\u5F00\u901A\u53EF\u66F4\u65B0\u5361\u7247\u7684\u76F8\u5173\u80FD\u529B\uFF1B\u5982\u679C\u6743\u9650\u4E0D\u8DB3\uFF0C\u4F1A\u81EA\u52A8\u56DE\u9000\u4E3A\u6700\u7EC8\u7ED3\u679C\u6D88\u606F\u3002</div>
8321
8373
  <div class="small">\u53EA\u5F71\u54CD <code>/h</code>\u3001<code>/status</code>\u3001<code>/threads</code> \u8FD9\u7C7B\u7CFB\u7EDF\u53CD\u9988\uFF0C\u4E0D\u5F71\u54CD Codex \u539F\u59CB\u56DE\u590D\u3002</div>
8322
- <div class="small">\u4FEE\u6539\u98DE\u4E66 <code>App ID</code>\u3001<code>App Secret</code>\u3001<code>Domain</code> \u540E\uFF0C\u9700\u8981\u91CD\u542F Bridge \u8BA9\u5BA2\u6237\u7AEF\u91CD\u65B0\u521D\u59CB\u5316\uFF1B\u767D\u540D\u5355\u3001\u6D41\u5F0F\u5F00\u5173\u3001Markdown \u5F00\u5173\u4F1A\u5373\u65F6\u751F\u6548\u3002</div>
8374
+ <div class="small">\u4FEE\u6539\u98DE\u4E66 <code>App ID</code>\u3001<code>App Secret</code>\u3001<code>Domain</code> \u540E\uFF0C\u9700\u8981\u91CD\u542F Bridge \u8BA9\u5BA2\u6237\u7AEF\u91CD\u65B0\u521D\u59CB\u5316\uFF1B\u767D\u540D\u5355\u3001\u6D41\u5F0F\u5F00\u5173\u3001markdown \u5F00\u5173\u4F1A\u5373\u65F6\u751F\u6548\u3002</div>
8323
8375
  </div>
8324
8376
 
8325
8377
  <div class="panel-block">
@@ -8355,7 +8407,7 @@ function renderHtml() {
8355
8407
  <label class="checkbox"><input id="weixinMediaEnabled" type="checkbox" /> \u542F\u7528\u56FE\u7247 / \u6587\u4EF6 / \u89C6\u9891\u5165\u7AD9\u4E0B\u8F7D</label>
8356
8408
  </div>
8357
8409
  <div class="checkbox-row">
8358
- <label class="checkbox"><input id="weixinCommandMarkdownEnabled" type="checkbox" /> \u547D\u4EE4\u53CD\u9988\u4F7F\u7528 Markdown</label>
8410
+ <label class="checkbox"><input id="weixinCommandMarkdownEnabled" type="checkbox" /> \u53CD\u9988\u4F7F\u7528markdown</label>
8359
8411
  </div>
8360
8412
  </div>
8361
8413
  <div class="small">\u53EA\u5F71\u54CD <code>/h</code>\u3001<code>/status</code>\u3001<code>/threads</code> \u8FD9\u7C7B\u7CFB\u7EDF\u53CD\u9988\uFF0C\u4E0D\u5F71\u54CD Codex \u539F\u59CB\u56DE\u590D\u3002\u9ED8\u8BA4\u5173\u95ED\u3002</div>
@@ -8401,6 +8453,7 @@ function renderHtml() {
8401
8453
  <script>
8402
8454
  const state = {
8403
8455
  config: null,
8456
+ availableModels: [],
8404
8457
  uiAccess: null,
8405
8458
  bridgeStatus: null,
8406
8459
  desktopSessions: [],
@@ -8420,6 +8473,44 @@ function renderHtml() {
8420
8473
  .replaceAll('"', '&quot;');
8421
8474
  }
8422
8475
 
8476
+ function renderDefaultModelOptions(config) {
8477
+ const options = Array.isArray(config && config.availableModels) ? config.availableModels : [];
8478
+ state.availableModels = options;
8479
+
8480
+ const select = document.getElementById('defaultModel');
8481
+ const currentValue = config && typeof config.defaultModel === 'string' ? config.defaultModel : '';
8482
+ const codexDefaultModel = config && typeof config.codexDefaultModel === 'string' ? config.codexDefaultModel : '';
8483
+ const items = [];
8484
+ const seen = new Set();
8485
+
8486
+ items.push(
8487
+ '<option value="">' + escapeHtml(
8488
+ codexDefaultModel
8489
+ ? '\u8DDF\u968F Codex \u9ED8\u8BA4\u6A21\u578B\uFF08\u5F53\u524D ' + codexDefaultModel + '\uFF09'
8490
+ : '\u8DDF\u968F Codex \u9ED8\u8BA4\u6A21\u578B'
8491
+ ) + '</option>'
8492
+ );
8493
+
8494
+ for (const model of options) {
8495
+ if (!model || typeof model.slug !== 'string' || !model.slug) continue;
8496
+ if (seen.has(model.slug)) continue;
8497
+ seen.add(model.slug);
8498
+ const label = model.slug + (model.supportedInApi === false ? '\uFF08\u4EC5 IM / CLI\uFF09' : '');
8499
+ items.push(
8500
+ '<option value="' + escapeHtml(model.slug) + '">' + escapeHtml(label) + '</option>'
8501
+ );
8502
+ }
8503
+
8504
+ if (currentValue && !seen.has(currentValue)) {
8505
+ items.push(
8506
+ '<option value="' + escapeHtml(currentValue) + '">\u5F53\u524D\u914D\u7F6E\u503C\uFF08\u5DF2\u4E0D\u53EF\u7528\uFF09\uFF1A' + escapeHtml(currentValue) + '</option>'
8507
+ );
8508
+ }
8509
+
8510
+ select.innerHTML = items.join('');
8511
+ select.value = currentValue;
8512
+ }
8513
+
8423
8514
  function shortId(value) {
8424
8515
  if (!value) return '-';
8425
8516
  return value.length > 14 ? value.slice(0, 8) + '...' + value.slice(-4) : value;
@@ -8490,7 +8581,6 @@ function renderHtml() {
8490
8581
  runtime: document.getElementById('runtime').value,
8491
8582
  defaultMode: document.getElementById('defaultMode').value,
8492
8583
  historyMessageLimit: document.getElementById('historyMessageLimit').value,
8493
- defaultWorkDir: document.getElementById('defaultWorkDir').value,
8494
8584
  defaultWorkspaceRoot: document.getElementById('defaultWorkspaceRoot').value,
8495
8585
  defaultModel: document.getElementById('defaultModel').value,
8496
8586
  codexSkipGitRepoCheck: document.getElementById('codexSkipGitRepoCheck').checked,
@@ -8665,7 +8755,6 @@ function renderHtml() {
8665
8755
  const CONFIG_FIELD_LABELS = {
8666
8756
  runtime: 'Runtime',
8667
8757
  enabledChannels: '\u901A\u9053\u542F\u7528\u72B6\u6001',
8668
- defaultWorkDir: '\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55',
8669
8758
  defaultWorkspaceRoot: '\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4',
8670
8759
  defaultModel: '\u9ED8\u8BA4\u6A21\u578B',
8671
8760
  defaultMode: '\u9ED8\u8BA4\u6A21\u5F0F',
@@ -8681,9 +8770,9 @@ function renderHtml() {
8681
8770
  feishuDomain: '\u98DE\u4E66 Domain',
8682
8771
  feishuAllowedUsers: '\u98DE\u4E66 Allowed Users',
8683
8772
  feishuStreamingEnabled: '\u98DE\u4E66\u6D41\u5F0F\u54CD\u5E94\u5361\u7247',
8684
- feishuCommandMarkdownEnabled: '\u98DE\u4E66\u547D\u4EE4 Markdown',
8773
+ feishuCommandMarkdownEnabled: '\u98DE\u4E66\u53CD\u9988markdown',
8685
8774
  weixinMediaEnabled: '\u5FAE\u4FE1\u56FE\u7247/\u6587\u4EF6/\u89C6\u9891\u5165\u7AD9\u4E0B\u8F7D',
8686
- weixinCommandMarkdownEnabled: '\u5FAE\u4FE1\u547D\u4EE4 Markdown',
8775
+ weixinCommandMarkdownEnabled: '\u5FAE\u4FE1\u53CD\u9988markdown',
8687
8776
  };
8688
8777
 
8689
8778
  const BRIDGE_RESTART_FIELDS = new Set([
@@ -8700,7 +8789,6 @@ function renderHtml() {
8700
8789
  ]);
8701
8790
 
8702
8791
  const IMMEDIATE_FIELDS = new Set([
8703
- 'defaultWorkDir',
8704
8792
  'defaultWorkspaceRoot',
8705
8793
  'defaultModel',
8706
8794
  'defaultMode',
@@ -9110,9 +9198,8 @@ function renderHtml() {
9110
9198
  document.getElementById('runtime').value = config.runtime || 'codex';
9111
9199
  document.getElementById('defaultMode').value = config.defaultMode || 'code';
9112
9200
  document.getElementById('historyMessageLimit').value = String(config.historyMessageLimit || 8);
9113
- document.getElementById('defaultWorkDir').value = config.defaultWorkDir || '';
9114
9201
  document.getElementById('defaultWorkspaceRoot').value = config.defaultWorkspaceRoot || '';
9115
- document.getElementById('defaultModel').value = config.defaultModel || '';
9202
+ renderDefaultModelOptions(config);
9116
9203
  document.getElementById('codexSkipGitRepoCheck').checked = config.codexSkipGitRepoCheck === true;
9117
9204
  document.getElementById('codexSandboxMode').value = config.codexSandboxMode || 'workspace-write';
9118
9205
  document.getElementById('codexReasoningEffort').value = config.codexReasoningEffort || 'medium';
@@ -174,33 +174,32 @@ codex-to-im stop
174
174
 
175
175
  1. 选择 `Runtime`
176
176
  - 推荐:`codex`
177
- 2. 设置默认工作目录
178
- 3. 设置 `/history` 默认返回条数(可选)
179
- 4. 设置默认工作空间
177
+ 2. 设置 `/history` 默认返回条数(可选)
178
+ 3. 设置默认工作空间
180
179
  - 用于 `/new proj1` 这类相对项目名
181
180
  - 留空时自动回退到 `~/cx2im`,并按当前系统展开为实际路径
182
- 5. 选择 Codex 文件系统权限
181
+ 4. 选择 Codex 文件系统权限
183
182
  - 默认推荐 `workspace-write`
184
- 6. 选择 Codex 思考级别
183
+ 5. 选择 Codex 思考级别
185
184
  - 默认推荐 `medium`
186
185
  - 官方仅有 5 个级别:`minimal`、`low`、`medium`、`high`、`xhigh`
187
186
  - 如果这台机器就是你自己的本地开发机,希望 `codex-to-im` 直接承担更强的编码执行能力,建议改成:
188
187
  - 文件系统权限:`danger-full-access`
189
188
  - 思考级别:`xhigh`
190
- 7. 如果目标目录不是 Codex 已信任的 Git 仓库,可勾选“允许在未信任 Git 目录运行 Codex”
191
- 8. 如果要从局域网设备访问配置页,可勾选“允许局域网访问 Web 控制台”
192
- 9. 勾选要启用的通道
189
+ 6. 如果目标目录不是 Codex 已信任的 Git 仓库,可勾选“允许在未信任 Git 目录运行 Codex”
190
+ 7. 如果要从局域网设备访问配置页,可勾选“允许局域网访问 Web 控制台”
191
+ 8. 勾选要启用的通道
193
192
  - 飞书:勾选 `启用飞书`
194
193
  - 微信:勾选 `启用微信`
195
- 10. 飞书场景下填写:
194
+ 9. 飞书场景下填写:
196
195
  - `App ID`
197
196
  - `App Secret`
198
197
  - `Domain`
199
198
  - `Allowed Users` 可选
200
199
  - `启用飞书流式响应卡片` 可选
201
- 11. 微信场景下点击:
200
+ 10. 微信场景下点击:
202
201
  - `开始微信扫码`
203
- 12. 点击测试
202
+ 11. 点击测试
204
203
  - 飞书:`测试飞书凭据`
205
204
  - Codex:`测试 Codex`
206
205
  13. 点击:
@@ -220,7 +219,7 @@ codex-to-im stop
220
219
  - IM 里发送 `/history` 默认返回整理后的摘要;发送 `/history raw` 才会查看最近 N 条原始消息。
221
220
  - IM 里发送 `/reasoning high` 或 `/reasoning 4` 之类命令,可以只对当前会话覆盖思考级别。
222
221
  - IM 里发送 `/thread 0` 会进入临时草稿线程,适合短讨论或临时想法。
223
- - “通道”页里可以分别控制“命令反馈使用 Markdown”:
222
+ - “通道”页里可以分别控制“反馈使用 Markdown”:
224
223
  - 飞书默认开启
225
224
  - 微信默认关闭
226
225
  - 只影响 `/h`、`/status`、`/threads` 这类系统反馈,不影响 Codex 原始回复
@@ -228,6 +227,7 @@ codex-to-im stop
228
227
  - `/` / `/status` 当前会话
229
228
  - `/h` / `/help` 帮助
230
229
  - `/t` / `/threads` 最近桌面会话,`/t 1` / `/thread 1` 接管
230
+ - `/n` / `/new` 在当前正式会话目录下新建线程;这类线程当前只保证在 IM 中可继续,不会自动出现在 Codex Desktop 会话列表中
231
231
  - `/n proj1` / `/new proj1` 新建项目会话
232
232
  - `/m` / `/mode` 查看或切换模式,可选 `code` / `plan` / `ask`
233
233
  - `/r` / `/reasoning` 查看或切换思考级别,也支持 `1|2|3|4|5`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-to-im",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Installable Codex-to-IM bridge with local setup UI and background service",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -33,7 +33,7 @@
33
33
  "dependencies": {
34
34
  "@anthropic-ai/claude-agent-sdk": "^0.2.62",
35
35
  "@larksuiteoapi/node-sdk": "^1.59.0",
36
- "@openai/codex-sdk": "^0.110.0",
36
+ "@openai/codex-sdk": "^0.116.0",
37
37
  "discord.js": "^14.25.1",
38
38
  "markdown-it": "^14.1.1",
39
39
  "qrcode": "^1.5.4",