@foxden-app/foxclaw 0.5.34 → 0.5.35

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/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  All notable FoxClaw changes are listed here. Each release note is bilingual so GitHub Releases and the npm package are useful to both Chinese and English readers.
4
4
 
5
+ ## 0.5.35 - 2026-06-17
6
+
7
+ ### 中文
8
+ - `/status`、`/auth`、`/auth sync status/events/trace` 在 Telegram 上优先使用 RichMessage 展示,内部状态会自动整理成标题、表格、列表和可展开原文。
9
+ - 保留微信和 RichMessage 失败 fallback:微信继续走原文本通道,Telegram rich 发送失败时退回原 HTML/plain 内容,不影响按钮和回调。
10
+
11
+ ### English
12
+ - `/status`, `/auth`, and `/auth sync status/events/trace` now prefer RichMessage on Telegram, rendering internal diagnostics as headings, tables, lists, and expandable plain-text details.
13
+ - Weixin and RichMessage failure fallbacks are preserved: Weixin keeps the previous text path, and Telegram falls back without breaking buttons or callbacks.
14
+
5
15
  ## 0.5.34 - 2026-06-17
6
16
 
7
17
  ### 中文
@@ -229,6 +229,7 @@ export declare class BridgeSessionCore {
229
229
  private sendHtmlMessage;
230
230
  private sendRichHtmlMessage;
231
231
  private sendRichMarkdownMessage;
232
+ private sendRichInternalMessage;
232
233
  private editMessage;
233
234
  private editHtmlMessage;
234
235
  private editRichHtmlMessage;
@@ -508,7 +508,7 @@ export class BridgeSessionCore {
508
508
  }
509
509
  lines.push(...codexUsageLines);
510
510
  lines.push(...codexLocalUsageLines);
511
- await this.sendMessage(scopeId, lines.join('\n'));
511
+ await this.sendRichInternalMessage(scopeId, '/status', lines.join('\n'));
512
512
  return;
513
513
  }
514
514
  case 'account': {
@@ -3377,6 +3377,12 @@ export class BridgeSessionCore {
3377
3377
  async sendRichMarkdownMessage(scopeId, text, inlineKeyboard) {
3378
3378
  return this.sendRichHtmlMessage(scopeId, renderTelegramMarkdownRichHtml(text), escapeTelegramHtml(text), inlineKeyboard);
3379
3379
  }
3380
+ async sendRichInternalMessage(scopeId, title, text, inlineKeyboard) {
3381
+ if (scopeId.startsWith(BRIDGE_SCOPE_WEIXIN_PREFIX)) {
3382
+ return this.sendMessage(scopeId, text, inlineKeyboard);
3383
+ }
3384
+ return this.sendRichHtmlMessage(scopeId, formatRichInternalMessage(title, text), escapeTelegramHtml(text), inlineKeyboard);
3385
+ }
3380
3386
  async editMessage(scopeId, messageId, text, inlineKeyboard) {
3381
3387
  await this.messaging.editPlain(scopeId, messageId, text, inlineKeyboard);
3382
3388
  }
@@ -4572,17 +4578,20 @@ export class BridgeSessionCore {
4572
4578
  await this.refreshCurrentCodexAuthQuota(state);
4573
4579
  const record = createPendingAuthChoiceList(scopeId, state.candidates, listRequest);
4574
4580
  this.pendingAuthChoiceLists.set(record.localId, record);
4575
- const messageId = await this.sendMessage(scopeId, renderAuthListMessage(locale, state, this.authDisplayBotLabel(), parseWeixinBridgeScope(scopeId) !== null, record), authChoiceKeyboard(locale, record));
4581
+ const authListMessage = renderAuthListMessage(locale, state, this.authDisplayBotLabel(), parseWeixinBridgeScope(scopeId) !== null, record);
4582
+ const messageId = await this.sendRichInternalMessage(scopeId, '/auth', authListMessage, authChoiceKeyboard(locale, record));
4576
4583
  record.messageId = messageId;
4577
4584
  }
4578
4585
  async handleAuthSyncCommand(scopeId, locale, args) {
4579
4586
  const action = args[0]?.toLowerCase() ?? 'status';
4580
4587
  if (action === 'status') {
4581
- await this.sendMessage(scopeId, formatAuthSyncStatus(locale, this.coordinator?.getAuthSyncStatus?.() ?? null, this.getRuntimeStatus().authProactiveRefresh ?? null));
4588
+ const message = formatAuthSyncStatus(locale, this.coordinator?.getAuthSyncStatus?.() ?? null, this.getRuntimeStatus().authProactiveRefresh ?? null);
4589
+ await this.sendRichInternalMessage(scopeId, '/auth sync status', message);
4582
4590
  return;
4583
4591
  }
4584
4592
  if (action === 'events') {
4585
- await this.sendMessage(scopeId, formatAuthSyncEvents(locale, this.coordinator?.getAuthSyncStatus?.() ?? null, args.slice(1).join(' ').trim() || null));
4593
+ const message = formatAuthSyncEvents(locale, this.coordinator?.getAuthSyncStatus?.() ?? null, args.slice(1).join(' ').trim() || null);
4594
+ await this.sendRichInternalMessage(scopeId, '/auth sync events', message);
4586
4595
  return;
4587
4596
  }
4588
4597
  if (action === 'trace') {
@@ -4591,7 +4600,7 @@ export class BridgeSessionCore {
4591
4600
  await this.sendMessage(scopeId, t(locale, 'auth_sync_trace_missing'));
4592
4601
  return;
4593
4602
  }
4594
- await this.sendMessage(scopeId, formatAuthSyncTrace(locale, this.coordinator?.getAuthSyncStatus?.() ?? null, requestId));
4603
+ await this.sendRichInternalMessage(scopeId, '/auth sync trace', formatAuthSyncTrace(locale, this.coordinator?.getAuthSyncStatus?.() ?? null, requestId));
4595
4604
  return;
4596
4605
  }
4597
4606
  if (action === 'test') {
@@ -8440,6 +8449,69 @@ function formatRichDemoFallbackMessage(locale) {
8440
8449
  telegramPreCode('sendRichMessage({ rich_message: { html } })', 'typescript'),
8441
8450
  ].join('\n');
8442
8451
  }
8452
+ function formatRichInternalMessage(title, text) {
8453
+ const sections = splitRichInternalSections(text);
8454
+ const body = sections.map(formatRichInternalSection).filter(Boolean).join('\n');
8455
+ return [
8456
+ `<h3>${escapeTelegramHtml(title)}</h3>`,
8457
+ body || `<p>${escapeTelegramHtml(text)}</p>`,
8458
+ telegramDetails('Plain text', telegramPreCode(text, 'text')),
8459
+ '<footer>FoxClaw · RichMessage</footer>',
8460
+ ].join('\n');
8461
+ }
8462
+ function splitRichInternalSections(text) {
8463
+ const sections = [];
8464
+ let current = [];
8465
+ for (const rawLine of text.split('\n')) {
8466
+ const line = rawLine.trimEnd();
8467
+ if (!line.trim()) {
8468
+ if (current.length > 0) {
8469
+ sections.push(current);
8470
+ current = [];
8471
+ }
8472
+ continue;
8473
+ }
8474
+ current.push(line);
8475
+ }
8476
+ if (current.length > 0) {
8477
+ sections.push(current);
8478
+ }
8479
+ return sections;
8480
+ }
8481
+ function formatRichInternalSection(lines) {
8482
+ const rows = lines
8483
+ .map(parseRichInternalKeyValue)
8484
+ .filter((row) => row !== null);
8485
+ if (rows.length >= Math.max(2, Math.floor(lines.length * 0.6))) {
8486
+ return [
8487
+ '<table bordered striped>',
8488
+ ...rows.map(([key, value]) => (`<tr><td>${escapeTelegramHtml(key)}</td><td>${formatRichInternalValue(value)}</td></tr>`)),
8489
+ '</table>',
8490
+ ].join('\n');
8491
+ }
8492
+ return [
8493
+ '<ul>',
8494
+ ...lines.map(line => `<li>${formatRichInternalValue(line.replace(/^\s*[-*]\s+/, '').replace(/^\s*\d+[.)]\s+/, ''))}</li>`),
8495
+ '</ul>',
8496
+ ].join('\n');
8497
+ }
8498
+ function parseRichInternalKeyValue(line) {
8499
+ const separator = line.includes(':') ? ':' : ':';
8500
+ const index = line.indexOf(separator);
8501
+ if (index <= 0) {
8502
+ return null;
8503
+ }
8504
+ const key = line.slice(0, index).trim();
8505
+ const value = line.slice(index + separator.length).trim();
8506
+ if (!key || !value || key.length > 80) {
8507
+ return null;
8508
+ }
8509
+ return [key, value];
8510
+ }
8511
+ function formatRichInternalValue(value) {
8512
+ const escaped = escapeTelegramHtml(value);
8513
+ return escaped.replace(/`([^`]+)`/g, '<code>$1</code>');
8514
+ }
8443
8515
  function clipRichMessageText(value, limit) {
8444
8516
  if (value.length <= limit) {
8445
8517
  return value;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@foxden-app/foxclaw",
3
- "version": "0.5.34",
3
+ "version": "0.5.35",
4
4
  "description": "Foxden local execution claw for controlling Codex from trusted chat interfaces.",
5
5
  "type": "module",
6
6
  "main": "dist/main.js",