codex-to-im 1.0.14 → 1.0.15

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.
package/README.md CHANGED
@@ -121,6 +121,7 @@ codex-to-im stop
121
121
  - `/` 或 `/status`:查看当前会话、线程、模型、模式、思考级别、共享镜像状态。
122
122
  - `/t`:查看最近 10 条桌面线程。
123
123
  - `/t all`:查看全部桌面线程。
124
+ - `/t n 100`:查看最近 100 条桌面线程。
124
125
  - `/t 1`:切换到第 1 条桌面线程。
125
126
  - `/t 0`:切换到当前聊天的临时线程。
126
127
  - `/new`:在当前正式会话目录下新建线程。
@@ -149,7 +150,7 @@ codex-to-im stop
149
150
  - `/new` 创建的是 IM 线程,当前只保证在 IM 中可继续;不保证会自动出现在 Codex Desktop 会话列表中。
150
151
  - 一个会话只能绑定一个聊天,跨飞书/微信也互斥。
151
152
  - 飞书附件当前支持图片和文件;视频目前按文件发送,不承诺原生预览。
152
- - `/t` 默认只显示最近 10 条桌面线程;需要更多时用 `/t all`。
153
+ - `/t` 默认只显示最近 10 条桌面线程;需要更多时用 `/t all` 或 `/t n 100`。
153
154
 
154
155
  ## 更多文档
155
156
 
package/README_EN.md CHANGED
@@ -136,7 +136,7 @@ Useful commands:
136
136
 
137
137
  - `/` / `/status` shows the current session
138
138
  - `/h` / `/help` shows help
139
- - `/t` / `/threads` lists the most recent 10 desktop threads, `/t all` / `/threads all` lists all of them, and `/t 1` / `/thread 1` binds the first one
139
+ - `/t` / `/threads` lists the most recent 10 desktop threads, `/t all` / `/threads all` lists all of them, `/t n 100` / `/threads n 100` lists the most recent 100 desktop threads, and `/t 1` / `/thread 1` binds the first one
140
140
  - `/n` / `/new` creates a new thread in the current formal session directory; these IM-created threads are only guaranteed to continue inside IM and will not automatically appear in the Codex Desktop thread list
141
141
  - `/n proj1` / `/new proj1` creates a new project session under the default workspace root
142
142
  - `/m` / `/mode` shows or changes the current mode; options: `code` / `plan` / `ask`
package/dist/daemon.mjs CHANGED
@@ -14606,7 +14606,7 @@ function buildFallbackTitle(threadId, filePath, cwd) {
14606
14606
  continue;
14607
14607
  }
14608
14608
  if (!isSessionEventLine(parsed) || parsed.payload?.type !== "user_message") continue;
14609
- const firstUserMessage = trimTitle(normalizeFreeText(parsed.payload.message || ""));
14609
+ const firstUserMessage = trimTitle(extractNormalizedFreeText(parsed.payload.message));
14610
14610
  if (firstUserMessage) return firstUserMessage;
14611
14611
  }
14612
14612
  } catch {
@@ -14669,6 +14669,48 @@ function normalizeFreeText(text2) {
14669
14669
  function normalizeStructuredText(text2) {
14670
14670
  return text2.replace(/\r\n/g, "\n").trim();
14671
14671
  }
14672
+ function collectStructuredTextParts(value, parts, depth = 0) {
14673
+ if (value == null || depth > 6) return;
14674
+ if (typeof value === "string") {
14675
+ parts.push(value);
14676
+ return;
14677
+ }
14678
+ if (Array.isArray(value)) {
14679
+ for (const item of value) {
14680
+ collectStructuredTextParts(item, parts, depth + 1);
14681
+ }
14682
+ return;
14683
+ }
14684
+ if (typeof value !== "object") return;
14685
+ const record = value;
14686
+ if (typeof record.text === "string") {
14687
+ parts.push(record.text);
14688
+ }
14689
+ if (typeof record.message === "string") {
14690
+ parts.push(record.message);
14691
+ }
14692
+ if (typeof record.summary === "string") {
14693
+ parts.push(record.summary);
14694
+ }
14695
+ if ("content" in record) {
14696
+ collectStructuredTextParts(record.content, parts, depth + 1);
14697
+ }
14698
+ if ("items" in record) {
14699
+ collectStructuredTextParts(record.items, parts, depth + 1);
14700
+ }
14701
+ }
14702
+ function extractNormalizedFreeText(value) {
14703
+ if (typeof value === "string") return normalizeFreeText(value);
14704
+ const parts = [];
14705
+ collectStructuredTextParts(value, parts);
14706
+ return parts.length > 0 ? normalizeFreeText(parts.join("\n")) : "";
14707
+ }
14708
+ function extractNormalizedStructuredText(value) {
14709
+ if (typeof value === "string") return normalizeStructuredText(value);
14710
+ const parts = [];
14711
+ collectStructuredTextParts(value, parts);
14712
+ return parts.length > 0 ? normalizeStructuredText(parts.join("\n\n")) : "";
14713
+ }
14672
14714
  function createDesktopEventSignature(rawLine) {
14673
14715
  return crypto7.createHash("sha1").update(rawLine).digest("hex");
14674
14716
  }
@@ -14756,7 +14798,7 @@ ${text2}`;
14756
14798
  }
14757
14799
  function pushDesktopSessionEvent(events, parsed, rawLine) {
14758
14800
  if (isSessionEventLine(parsed) && parsed.payload?.type === "user_message") {
14759
- const text2 = normalizeStructuredText(parsed.payload.message || "");
14801
+ const text2 = extractNormalizedStructuredText(parsed.payload.message);
14760
14802
  if (!text2) return;
14761
14803
  events.push({
14762
14804
  signature: createDesktopEventSignature(rawLine),
@@ -14767,7 +14809,7 @@ function pushDesktopSessionEvent(events, parsed, rawLine) {
14767
14809
  return;
14768
14810
  }
14769
14811
  if (isSessionEventLine(parsed) && parsed.payload?.type === "task_complete") {
14770
- const text2 = normalizeStructuredText(parsed.payload.last_agent_message || "");
14812
+ const text2 = extractNormalizedStructuredText(parsed.payload.last_agent_message);
14771
14813
  if (!text2) return;
14772
14814
  const lastEvent = events[events.length - 1];
14773
14815
  if (lastEvent?.role === "assistant" && lastEvent.content === text2) {
@@ -14804,7 +14846,7 @@ function pushDesktopMirrorRecord(records, parsed, rawLine, activeTurnId) {
14804
14846
  return;
14805
14847
  }
14806
14848
  if (isSessionEventLine(parsed) && parsed.payload?.type === "user_message") {
14807
- const text2 = normalizeStructuredText(parsed.payload.message || "");
14849
+ const text2 = extractNormalizedStructuredText(parsed.payload.message);
14808
14850
  if (!text2) return;
14809
14851
  records.push({
14810
14852
  signature: createDesktopEventSignature(rawLine),
@@ -14821,7 +14863,7 @@ function pushDesktopMirrorRecord(records, parsed, rawLine, activeTurnId) {
14821
14863
  signature: createDesktopEventSignature(rawLine),
14822
14864
  type: "task_complete",
14823
14865
  role: "assistant",
14824
- content: normalizeStructuredText(parsed.payload.last_agent_message || ""),
14866
+ content: extractNormalizedStructuredText(parsed.payload.last_agent_message),
14825
14867
  timestamp: parsed.timestamp || "",
14826
14868
  turnId: parsed.payload.turn_id || ""
14827
14869
  });
@@ -14841,8 +14883,8 @@ function pushDesktopMirrorRecord(records, parsed, rawLine, activeTurnId) {
14841
14883
  return;
14842
14884
  }
14843
14885
  if (isSessionMessageLine(parsed) && parsed.payload?.type === "function_call") {
14844
- const toolName = normalizeFreeText(parsed.payload.name || "");
14845
- const toolId = normalizeFreeText(parsed.payload.call_id || "") || createDesktopEventSignature(rawLine);
14886
+ const toolName = extractNormalizedFreeText(parsed.payload.name);
14887
+ const toolId = extractNormalizedFreeText(parsed.payload.call_id) || createDesktopEventSignature(rawLine);
14846
14888
  if (!toolName) return;
14847
14889
  records.push({
14848
14890
  signature: createDesktopEventSignature(rawLine),
@@ -14856,11 +14898,11 @@ function pushDesktopMirrorRecord(records, parsed, rawLine, activeTurnId) {
14856
14898
  return;
14857
14899
  }
14858
14900
  if (isSessionMessageLine(parsed) && parsed.payload?.type === "function_call_output") {
14859
- const toolId = normalizeFreeText(parsed.payload.call_id || "") || createDesktopEventSignature(rawLine);
14901
+ const toolId = extractNormalizedFreeText(parsed.payload.call_id) || createDesktopEventSignature(rawLine);
14860
14902
  records.push({
14861
14903
  signature: createDesktopEventSignature(rawLine),
14862
14904
  type: "tool_finished",
14863
- content: normalizeFreeText(parsed.payload.output || ""),
14905
+ content: extractNormalizedFreeText(parsed.payload.output),
14864
14906
  timestamp: parsed.timestamp || "",
14865
14907
  ...activeTurnId ? { turnId: activeTurnId } : {},
14866
14908
  toolId,
@@ -16755,7 +16797,7 @@ function resolveCommandAlias(rawCommand, args) {
16755
16797
  case "/h":
16756
16798
  return "/help";
16757
16799
  case "/t":
16758
- return args ? "/thread" : "/threads";
16800
+ return !args ? "/threads" : /^(all|n\b)/i.test(args.trim()) ? "/threads" : "/thread";
16759
16801
  case "/s":
16760
16802
  return args ? "/use" : "/sessions";
16761
16803
  case "/n":
@@ -16791,6 +16833,20 @@ function resolveByIndexOrPrefix(raw, items, getId) {
16791
16833
  function getDisplayedDesktopThreads(limit = 10) {
16792
16834
  return listDesktopSessions(limit);
16793
16835
  }
16836
+ function parseDesktopThreadListArgs(args) {
16837
+ const trimmed = args.trim().toLowerCase();
16838
+ if (!trimmed) {
16839
+ return { showAll: false, limit: 10 };
16840
+ }
16841
+ if (trimmed === "all") {
16842
+ return { showAll: true, limit: 0 };
16843
+ }
16844
+ const match2 = trimmed.match(/^n\s+(\d+)$/);
16845
+ if (!match2) return null;
16846
+ const limit = Number(match2[1]);
16847
+ if (!Number.isInteger(limit) || limit < 1) return null;
16848
+ return { showAll: false, limit };
16849
+ }
16794
16850
  function getDisplayedBridgeSessions(currentSessionId) {
16795
16851
  const { store } = getBridgeContext();
16796
16852
  const sessions = store.listSessions().filter((session) => session.hidden !== true).toReversed();
@@ -16899,9 +16955,9 @@ function buildIndexedCommandList(title, items, footer = [], markdown = false) {
16899
16955
  footer.filter(Boolean).forEach((line) => lines.push(line));
16900
16956
  return lines.join("\n").trim();
16901
16957
  }
16902
- function buildDesktopThreadsCommandResponse(desktopSessions, markdown, showAll) {
16958
+ function buildDesktopThreadsCommandResponse(desktopSessions, markdown, showAll, limit = 10) {
16903
16959
  return buildIndexedCommandList(
16904
- showAll ? "\u5168\u90E8\u684C\u9762\u4F1A\u8BDD" : "\u6700\u8FD1\u684C\u9762\u4F1A\u8BDD",
16960
+ showAll ? "\u5168\u90E8\u684C\u9762\u4F1A\u8BDD" : `\u6700\u8FD1 ${limit} \u6761\u684C\u9762\u4F1A\u8BDD`,
16905
16961
  desktopSessions.map((session) => ({
16906
16962
  heading: session.title || "\u672A\u547D\u540D\u7EBF\u7A0B",
16907
16963
  details: [
@@ -16914,7 +16970,8 @@ function buildDesktopThreadsCommandResponse(desktopSessions, markdown, showAll)
16914
16970
  "\u53D1\u9001 `/t` \u53EF\u53EA\u770B\u6700\u8FD1 10 \u6761\u3002"
16915
16971
  ] : [
16916
16972
  "\u53D1\u9001 `/t 1` \u53EF\u63A5\u7BA1\u7B2C 1 \u6761\u684C\u9762\u4F1A\u8BDD\u3002",
16917
- "\u53D1\u9001 `/t all` \u53EF\u67E5\u770B\u5168\u90E8\u684C\u9762\u4F1A\u8BDD\u3002"
16973
+ "\u53D1\u9001 `/t all` \u53EF\u67E5\u770B\u5168\u90E8\u684C\u9762\u4F1A\u8BDD\u3002",
16974
+ "\u53D1\u9001 `/t n 100` \u53EF\u67E5\u770B\u6700\u8FD1 100 \u6761\u684C\u9762\u4F1A\u8BDD\u3002"
16918
16975
  ],
16919
16976
  markdown
16920
16977
  );
@@ -18251,7 +18308,19 @@ async function reconcileMirrorSubscriptions() {
18251
18308
  try {
18252
18309
  syncMirrorSubscriptionSet();
18253
18310
  for (const subscription of state.mirrorSubscriptions.values()) {
18254
- await reconcileMirrorSubscription(subscription);
18311
+ try {
18312
+ await reconcileMirrorSubscription(subscription);
18313
+ } catch (error) {
18314
+ stopMirrorStreaming(subscription, "interrupted");
18315
+ resetMirrorReadState(subscription);
18316
+ subscription.status = "stale";
18317
+ subscription.dirty = false;
18318
+ console.error(
18319
+ `[bridge-manager] Mirror reconcile failed for thread ${subscription.threadId}:`,
18320
+ error instanceof Error ? error.stack || error.message : error
18321
+ );
18322
+ syncMirrorSessionState(subscription.sessionId);
18323
+ }
18255
18324
  }
18256
18325
  } finally {
18257
18326
  state.mirrorSyncInFlight = false;
@@ -18890,11 +18959,11 @@ async function handleCommand(adapter, msg, text2) {
18890
18959
  break;
18891
18960
  }
18892
18961
  if (!args) {
18893
- response = "\u7528\u6CD5\uFF1A/thread <\u5E8F\u53F7>\uFF0C\u6216 /thread 0 \u8FDB\u5165\u4E34\u65F6\u8349\u7A3F\u7EBF\u7A0B\uFF1B\u53D1\u9001 /t all \u53EF\u67E5\u770B\u5168\u90E8\u684C\u9762\u4F1A\u8BDD";
18962
+ response = "\u7528\u6CD5\uFF1A/thread <\u5E8F\u53F7>\uFF0C\u6216 /thread 0 \u8FDB\u5165\u4E34\u65F6\u8349\u7A3F\u7EBF\u7A0B\uFF1B\u53D1\u9001 /t all \u67E5\u770B\u5168\u90E8\uFF0C\u6216 /t n 100 \u67E5\u770B\u6700\u8FD1 100 \u6761\u684C\u9762\u4F1A\u8BDD";
18894
18963
  break;
18895
18964
  }
18896
18965
  if (args === "all") {
18897
- const desktopSessions = getDisplayedDesktopThreads();
18966
+ const desktopSessions = getDisplayedDesktopThreads(void 0);
18898
18967
  if (desktopSessions.length === 0) {
18899
18968
  response = "\u6CA1\u6709\u627E\u5230\u684C\u9762\u4F1A\u8BDD\u3002\u5148\u5728 Codex Desktop App \u4E2D\u6253\u5F00\u4E00\u4E2A\u4F1A\u8BDD\uFF0C\u518D\u56DE\u6765\u8BD5\u4E00\u6B21\u3002";
18900
18969
  break;
@@ -18962,8 +19031,13 @@ async function handleCommand(adapter, msg, text2) {
18962
19031
  break;
18963
19032
  }
18964
19033
  case "/threads": {
18965
- const showAll = args === "all";
18966
- const desktopSessions = getDisplayedDesktopThreads(showAll ? void 0 : 10);
19034
+ const listArgs = parseDesktopThreadListArgs(args);
19035
+ if (!listArgs) {
19036
+ response = "\u7528\u6CD5\uFF1A/threads\u3001/threads all\u3001/threads n 100";
19037
+ break;
19038
+ }
19039
+ const { showAll, limit } = listArgs;
19040
+ const desktopSessions = getDisplayedDesktopThreads(showAll ? void 0 : limit);
18967
19041
  if (desktopSessions.length === 0) {
18968
19042
  response = showAll ? "\u6CA1\u6709\u627E\u5230\u684C\u9762\u4F1A\u8BDD\u3002\u5148\u5728 Codex Desktop App \u4E2D\u6253\u5F00\u4E00\u4E2A\u4F1A\u8BDD\uFF0C\u518D\u56DE\u6765\u8BD5\u4E00\u6B21\u3002" : "\u6CA1\u6709\u627E\u5230\u6700\u8FD1\u684C\u9762\u4F1A\u8BDD\u3002\u5148\u5728 Codex Desktop App \u4E2D\u6253\u5F00\u4E00\u4E2A\u4F1A\u8BDD\uFF0C\u518D\u56DE\u6765\u8BD5\u4E00\u6B21\u3002";
18969
19043
  break;
@@ -18971,7 +19045,8 @@ async function handleCommand(adapter, msg, text2) {
18971
19045
  response = buildDesktopThreadsCommandResponse(
18972
19046
  desktopSessions,
18973
19047
  responseParseMode === "Markdown",
18974
- showAll
19048
+ showAll,
19049
+ limit
18975
19050
  );
18976
19051
  break;
18977
19052
  }
@@ -19344,6 +19419,7 @@ ${truncateHistoryContent(formatStoredMessageContent(message.content))}`;
19344
19419
  "- `/h` \u5E2E\u52A9",
19345
19420
  "- `/t` \u6700\u8FD1 10 \u6761\u684C\u9762\u4F1A\u8BDD",
19346
19421
  "- `/t all` \u5168\u90E8\u684C\u9762\u4F1A\u8BDD",
19422
+ "- `/t n 100` \u6700\u8FD1 100 \u6761\u684C\u9762\u4F1A\u8BDD",
19347
19423
  "- `/t 1` \u63A5\u7BA1\u7B2C 1 \u6761\u4F1A\u8BDD",
19348
19424
  "- `/n` \u5728\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u4E0B\u65B0\u5EFA\u7EBF\u7A0B\uFF08\u4EC5\u4FDD\u8BC1 IM \u53EF\u7EE7\u7EED\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u51FA\u73B0\u5728\u684C\u9762\u4F1A\u8BDD\u5217\u8868\uFF09",
19349
19425
  "- `/n proj1` \u5728\u9ED8\u8BA4\u5DE5\u4F5C\u7A7A\u95F4\u4E0B\u65B0\u5EFA\u9879\u76EE\u4F1A\u8BDD",
@@ -5447,7 +5447,7 @@ function buildFallbackTitle(threadId, filePath, cwd) {
5447
5447
  continue;
5448
5448
  }
5449
5449
  if (!isSessionEventLine(parsed) || parsed.payload?.type !== "user_message") continue;
5450
- const firstUserMessage = trimTitle(normalizeFreeText(parsed.payload.message || ""));
5450
+ const firstUserMessage = trimTitle(extractNormalizedFreeText(parsed.payload.message));
5451
5451
  if (firstUserMessage) return firstUserMessage;
5452
5452
  }
5453
5453
  } catch {
@@ -5507,6 +5507,42 @@ function trimTitle(text2) {
5507
5507
  function normalizeFreeText(text2) {
5508
5508
  return text2.replace(/\s+/g, " ").trim();
5509
5509
  }
5510
+ function collectStructuredTextParts(value, parts, depth = 0) {
5511
+ if (value == null || depth > 6) return;
5512
+ if (typeof value === "string") {
5513
+ parts.push(value);
5514
+ return;
5515
+ }
5516
+ if (Array.isArray(value)) {
5517
+ for (const item of value) {
5518
+ collectStructuredTextParts(item, parts, depth + 1);
5519
+ }
5520
+ return;
5521
+ }
5522
+ if (typeof value !== "object") return;
5523
+ const record = value;
5524
+ if (typeof record.text === "string") {
5525
+ parts.push(record.text);
5526
+ }
5527
+ if (typeof record.message === "string") {
5528
+ parts.push(record.message);
5529
+ }
5530
+ if (typeof record.summary === "string") {
5531
+ parts.push(record.summary);
5532
+ }
5533
+ if ("content" in record) {
5534
+ collectStructuredTextParts(record.content, parts, depth + 1);
5535
+ }
5536
+ if ("items" in record) {
5537
+ collectStructuredTextParts(record.items, parts, depth + 1);
5538
+ }
5539
+ }
5540
+ function extractNormalizedFreeText(value) {
5541
+ if (typeof value === "string") return normalizeFreeText(value);
5542
+ const parts = [];
5543
+ collectStructuredTextParts(value, parts);
5544
+ return parts.length > 0 ? normalizeFreeText(parts.join("\n")) : "";
5545
+ }
5510
5546
  function isSessionEventLine(line) {
5511
5547
  return line.type === "event_msg";
5512
5548
  }
@@ -8730,8 +8766,9 @@ function renderHtml() {
8730
8766
  <div class="command-list-head"><div>\u547D\u4EE4</div><div>\u539F\u59CB\u547D\u4EE4</div><div>\u8BF4\u660E</div></div>
8731
8767
  <div class="command-item"><div class="command-col-command"><code>/</code></div><div class="command-col-original"><code>/status</code></div><div class="command-col-desc">\u67E5\u770B\u5F53\u524D\u4F1A\u8BDD\u3002</div></div>
8732
8768
  <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>
8733
- <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 10 \u6761\u684C\u9762\u4F1A\u8BDD\u3002</div></div>
8734
- <div class="command-item"><div class="command-col-command"><code>/t all</code></div><div class="command-col-original"><code>/threads all</code></div><div class="command-col-desc">\u5217\u51FA\u5168\u90E8\u684C\u9762\u4F1A\u8BDD\u3002</div></div>
8769
+ <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 10 \u6761\u684C\u9762\u4F1A\u8BDD\u3002</div></div>
8770
+ <div class="command-item"><div class="command-col-command"><code>/t all</code></div><div class="command-col-original"><code>/threads all</code></div><div class="command-col-desc">\u5217\u51FA\u5168\u90E8\u684C\u9762\u4F1A\u8BDD\u3002</div></div>
8771
+ <div class="command-item"><div class="command-col-command"><code>/t n 100</code></div><div class="command-col-original"><code>/threads n 100</code></div><div class="command-col-desc">\u5217\u51FA\u6700\u8FD1 100 \u6761\u684C\u9762\u4F1A\u8BDD\u3002</div></div>
8735
8772
  <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>
8736
8773
  <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>
8737
8774
  <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>
@@ -227,7 +227,7 @@ codex-to-im stop
227
227
  - IM 里也支持一组短命令别名:
228
228
  - `/` / `/status` 当前会话
229
229
  - `/h` / `/help` 帮助
230
- - `/t` / `/threads` 最近 10 条桌面会话,`/t all` / `/threads all` 查看全部,`/t 1` / `/thread 1` 接管
230
+ - `/t` / `/threads` 最近 10 条桌面会话,`/t all` / `/threads all` 查看全部,`/t n 100` / `/threads n 100` 查看最近 100 条,`/t 1` / `/thread 1` 接管
231
231
  - `/n` / `/new` 在当前正式会话目录下新建线程;这类线程当前只保证在 IM 中可继续,不会自动出现在 Codex Desktop 会话列表中
232
232
  - `/n proj1` / `/new proj1` 新建项目会话
233
233
  - `/m` / `/mode` 查看或切换模式,可选 `code` / `plan` / `ask`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-to-im",
3
- "version": "1.0.14",
3
+ "version": "1.0.15",
4
4
  "description": "Installable Codex-to-IM bridge with local setup UI and background service",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/zhangle1987/codex-to-im#readme",