botmux 2.44.0 → 2.46.0

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.
Files changed (192) hide show
  1. package/README.en.md +1 -2
  2. package/README.md +1 -2
  3. package/dist/cli/bots-list-output.d.ts +8 -0
  4. package/dist/cli/bots-list-output.d.ts.map +1 -1
  5. package/dist/cli/bots-list-output.js +9 -0
  6. package/dist/cli/bots-list-output.js.map +1 -1
  7. package/dist/cli.d.ts.map +1 -1
  8. package/dist/cli.js +6 -0
  9. package/dist/cli.js.map +1 -1
  10. package/dist/core/command-handler.d.ts.map +1 -1
  11. package/dist/core/command-handler.js +601 -50
  12. package/dist/core/command-handler.js.map +1 -1
  13. package/dist/core/dashboard-ipc-server.d.ts +2 -0
  14. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  15. package/dist/core/dashboard-ipc-server.js +170 -2
  16. package/dist/core/dashboard-ipc-server.js.map +1 -1
  17. package/dist/core/role-resolver.d.ts +17 -1
  18. package/dist/core/role-resolver.d.ts.map +1 -1
  19. package/dist/core/role-resolver.js +64 -10
  20. package/dist/core/role-resolver.js.map +1 -1
  21. package/dist/core/session-manager.d.ts +1 -1
  22. package/dist/core/session-manager.d.ts.map +1 -1
  23. package/dist/core/session-manager.js +24 -13
  24. package/dist/core/session-manager.js.map +1 -1
  25. package/dist/core/trigger-session.d.ts +9 -0
  26. package/dist/core/trigger-session.d.ts.map +1 -0
  27. package/dist/core/trigger-session.js +158 -0
  28. package/dist/core/trigger-session.js.map +1 -0
  29. package/dist/core/worker-pool.d.ts +105 -0
  30. package/dist/core/worker-pool.d.ts.map +1 -1
  31. package/dist/core/worker-pool.js +284 -4
  32. package/dist/core/worker-pool.js.map +1 -1
  33. package/dist/daemon.d.ts.map +1 -1
  34. package/dist/daemon.js +80 -45
  35. package/dist/daemon.js.map +1 -1
  36. package/dist/dashboard/connector-api.d.ts +3 -0
  37. package/dist/dashboard/connector-api.d.ts.map +1 -0
  38. package/dist/dashboard/connector-api.js +351 -0
  39. package/dist/dashboard/connector-api.js.map +1 -0
  40. package/dist/dashboard/federated-group-core.d.ts +54 -0
  41. package/dist/dashboard/federated-group-core.d.ts.map +1 -0
  42. package/dist/dashboard/federated-group-core.js +165 -0
  43. package/dist/dashboard/federated-group-core.js.map +1 -0
  44. package/dist/dashboard/federation-api.d.ts +42 -0
  45. package/dist/dashboard/federation-api.d.ts.map +1 -0
  46. package/dist/dashboard/federation-api.js +408 -0
  47. package/dist/dashboard/federation-api.js.map +1 -0
  48. package/dist/dashboard/federation-spoke-api.d.ts +76 -0
  49. package/dist/dashboard/federation-spoke-api.d.ts.map +1 -0
  50. package/dist/dashboard/federation-spoke-api.js +618 -0
  51. package/dist/dashboard/federation-spoke-api.js.map +1 -0
  52. package/dist/dashboard/team-group.d.ts +18 -0
  53. package/dist/dashboard/team-group.d.ts.map +1 -0
  54. package/dist/dashboard/team-group.js +7 -0
  55. package/dist/dashboard/team-group.js.map +1 -0
  56. package/dist/dashboard/trigger-api.d.ts +13 -0
  57. package/dist/dashboard/trigger-api.d.ts.map +1 -0
  58. package/dist/dashboard/trigger-api.js +77 -0
  59. package/dist/dashboard/trigger-api.js.map +1 -0
  60. package/dist/dashboard/web/app.js +8 -0
  61. package/dist/dashboard/web/app.js.map +1 -1
  62. package/dist/dashboard/web/connectors.d.ts +2 -0
  63. package/dist/dashboard/web/connectors.d.ts.map +1 -0
  64. package/dist/dashboard/web/connectors.js +187 -0
  65. package/dist/dashboard/web/connectors.js.map +1 -0
  66. package/dist/dashboard/web/team-federation.d.ts +3 -0
  67. package/dist/dashboard/web/team-federation.d.ts.map +1 -0
  68. package/dist/dashboard/web/team-federation.js +487 -0
  69. package/dist/dashboard/web/team-federation.js.map +1 -0
  70. package/dist/dashboard/webhook-routes.d.ts +19 -0
  71. package/dist/dashboard/webhook-routes.d.ts.map +1 -0
  72. package/dist/dashboard/webhook-routes.js +321 -0
  73. package/dist/dashboard/webhook-routes.js.map +1 -0
  74. package/dist/dashboard-web/app.js +509 -386
  75. package/dist/dashboard-web/index.html +2 -0
  76. package/dist/dashboard.js +152 -1
  77. package/dist/dashboard.js.map +1 -1
  78. package/dist/i18n/en.d.ts.map +1 -1
  79. package/dist/i18n/en.js +85 -8
  80. package/dist/i18n/en.js.map +1 -1
  81. package/dist/i18n/zh.d.ts.map +1 -1
  82. package/dist/i18n/zh.js +85 -8
  83. package/dist/i18n/zh.js.map +1 -1
  84. package/dist/im/lark/card-builder.d.ts +82 -0
  85. package/dist/im/lark/card-builder.d.ts.map +1 -1
  86. package/dist/im/lark/card-builder.js +315 -0
  87. package/dist/im/lark/card-builder.js.map +1 -1
  88. package/dist/im/lark/card-handler.d.ts.map +1 -1
  89. package/dist/im/lark/card-handler.js +195 -1
  90. package/dist/im/lark/card-handler.js.map +1 -1
  91. package/dist/im/lark/client.d.ts +45 -0
  92. package/dist/im/lark/client.d.ts.map +1 -1
  93. package/dist/im/lark/client.js +169 -18
  94. package/dist/im/lark/client.js.map +1 -1
  95. package/dist/im/lark/message-parser.d.ts.map +1 -1
  96. package/dist/im/lark/message-parser.js +1 -0
  97. package/dist/im/lark/message-parser.js.map +1 -1
  98. package/dist/services/bot-owner-store.d.ts +28 -0
  99. package/dist/services/bot-owner-store.d.ts.map +1 -0
  100. package/dist/services/bot-owner-store.js +82 -0
  101. package/dist/services/bot-owner-store.js.map +1 -0
  102. package/dist/services/bot-profile-store.d.ts +16 -0
  103. package/dist/services/bot-profile-store.d.ts.map +1 -0
  104. package/dist/services/bot-profile-store.js +98 -0
  105. package/dist/services/bot-profile-store.js.map +1 -0
  106. package/dist/services/connector-store.d.ts +58 -0
  107. package/dist/services/connector-store.d.ts.map +1 -0
  108. package/dist/services/connector-store.js +79 -0
  109. package/dist/services/connector-store.js.map +1 -0
  110. package/dist/services/deployment-identity.d.ts +22 -0
  111. package/dist/services/deployment-identity.d.ts.map +1 -0
  112. package/dist/services/deployment-identity.js +67 -0
  113. package/dist/services/deployment-identity.js.map +1 -0
  114. package/dist/services/federation-membership-store.d.ts +23 -0
  115. package/dist/services/federation-membership-store.d.ts.map +1 -0
  116. package/dist/services/federation-membership-store.js +66 -0
  117. package/dist/services/federation-membership-store.js.map +1 -0
  118. package/dist/services/federation-roster.d.ts +54 -0
  119. package/dist/services/federation-roster.d.ts.map +1 -0
  120. package/dist/services/federation-roster.js +51 -0
  121. package/dist/services/federation-roster.js.map +1 -0
  122. package/dist/services/federation-store.d.ts +76 -0
  123. package/dist/services/federation-store.d.ts.map +1 -0
  124. package/dist/services/federation-store.js +133 -0
  125. package/dist/services/federation-store.js.map +1 -0
  126. package/dist/services/group-creator.d.ts +6 -0
  127. package/dist/services/group-creator.d.ts.map +1 -1
  128. package/dist/services/group-creator.js +10 -1
  129. package/dist/services/group-creator.js.map +1 -1
  130. package/dist/services/groups-store.d.ts +11 -0
  131. package/dist/services/groups-store.d.ts.map +1 -1
  132. package/dist/services/groups-store.js +42 -0
  133. package/dist/services/groups-store.js.map +1 -1
  134. package/dist/services/invite-store.d.ts +28 -0
  135. package/dist/services/invite-store.d.ts.map +1 -0
  136. package/dist/services/invite-store.js +85 -0
  137. package/dist/services/invite-store.js.map +1 -0
  138. package/dist/services/pairing-store.d.ts +47 -0
  139. package/dist/services/pairing-store.d.ts.map +1 -0
  140. package/dist/services/pairing-store.js +132 -0
  141. package/dist/services/pairing-store.js.map +1 -0
  142. package/dist/services/relay-picker.d.ts +22 -0
  143. package/dist/services/relay-picker.d.ts.map +1 -0
  144. package/dist/services/relay-picker.js +62 -0
  145. package/dist/services/relay-picker.js.map +1 -0
  146. package/dist/services/team-roster.d.ts +38 -0
  147. package/dist/services/team-roster.d.ts.map +1 -0
  148. package/dist/services/team-roster.js +82 -0
  149. package/dist/services/team-roster.js.map +1 -0
  150. package/dist/services/team-store.d.ts +54 -0
  151. package/dist/services/team-store.d.ts.map +1 -0
  152. package/dist/services/team-store.js +156 -0
  153. package/dist/services/team-store.js.map +1 -0
  154. package/dist/services/trigger-log-store.d.ts +46 -0
  155. package/dist/services/trigger-log-store.d.ts.map +1 -0
  156. package/dist/services/trigger-log-store.js +132 -0
  157. package/dist/services/trigger-log-store.js.map +1 -0
  158. package/dist/services/trigger-types.d.ts +57 -0
  159. package/dist/services/trigger-types.d.ts.map +1 -0
  160. package/dist/services/trigger-types.js +28 -0
  161. package/dist/services/trigger-types.js.map +1 -0
  162. package/dist/services/webhook-key.d.ts +16 -0
  163. package/dist/services/webhook-key.d.ts.map +1 -0
  164. package/dist/services/webhook-key.js +123 -0
  165. package/dist/services/webhook-key.js.map +1 -0
  166. package/dist/services/webhook-lifecycle-extractors.d.ts +15 -0
  167. package/dist/services/webhook-lifecycle-extractors.d.ts.map +1 -0
  168. package/dist/services/webhook-lifecycle-extractors.js +59 -0
  169. package/dist/services/webhook-lifecycle-extractors.js.map +1 -0
  170. package/dist/services/webhook-lifecycle-store.d.ts +45 -0
  171. package/dist/services/webhook-lifecycle-store.d.ts.map +1 -0
  172. package/dist/services/webhook-lifecycle-store.js +159 -0
  173. package/dist/services/webhook-lifecycle-store.js.map +1 -0
  174. package/dist/setup/verify-permissions.d.ts.map +1 -1
  175. package/dist/setup/verify-permissions.js +4 -0
  176. package/dist/setup/verify-permissions.js.map +1 -1
  177. package/dist/skills/definitions.d.ts.map +1 -1
  178. package/dist/skills/definitions.js +64 -10
  179. package/dist/skills/definitions.js.map +1 -1
  180. package/dist/types.d.ts +14 -0
  181. package/dist/types.d.ts.map +1 -1
  182. package/dist/utils/daemon-discovery.d.ts +11 -0
  183. package/dist/utils/daemon-discovery.d.ts.map +1 -0
  184. package/dist/utils/daemon-discovery.js +59 -0
  185. package/dist/utils/daemon-discovery.js.map +1 -0
  186. package/dist/workflows/events/payloads.d.ts +2 -2
  187. package/dist/workflows/events/schema.d.ts +8 -8
  188. package/dist/workflows/trigger-from-envelope.d.ts +13 -0
  189. package/dist/workflows/trigger-from-envelope.d.ts.map +1 -0
  190. package/dist/workflows/trigger-from-envelope.js +67 -0
  191. package/dist/workflows/trigger-from-envelope.js.map +1 -0
  192. package/package.json +1 -1
package/dist/i18n/zh.js CHANGED
@@ -31,11 +31,13 @@ export const messages = {
31
31
  'card.status.retry_ready': '可重试',
32
32
  'card.status.executing': '正在执行…',
33
33
  'card.status.session_closed': '🛑 会话已关闭',
34
+ 'card.status.relay_frozen': '🔄 会话已搬迁',
34
35
  'card.status.selected': '已选择',
35
36
  'card.status.waiting_screenshot': '_(等待第一张截图…)_',
36
37
  'card.status.truncated_prefix': '… (已截断)',
37
38
  // ─── Card body text ──────────────────────────────────────────────────────
38
39
  'card.body.cli_terminated': '{cliName} 进程已终止。',
40
+ 'card.body.relay_frozen': '本会话已通过 /relay 搬到其他群继续,本卡片冻结作为存档;按钮已移除,避免误操作影响新群里活着的会话。',
39
41
  'card.body.click_resume_or_run': '点击「恢复会话」继续,或在终端执行:',
40
42
  'card.body.click_resume_only': '点击「恢复会话」继续。',
41
43
  'card.body.cli_no_cli_resume': '{cliName} 不支持从命令行精确恢复指定会话,可在飞书内 resume。',
@@ -49,7 +51,7 @@ export const messages = {
49
51
  'card.repo.placeholder_switch': '选择仓库并切换',
50
52
  'card.repo.current_active': '当前活跃项目:',
51
53
  'card.repo.current_marker': ' ← 当前',
52
- 'card.repo.note': '也可以回复 `/repo <编号>` 切换,例如:`/repo 1`',
54
+ 'card.repo.note': '也可以回复 `/repo <编号>` 切换(如 `/repo 1`),或直接 `/repo <路径|项目名>`(如 `/repo botmux`、`/repo ~/projects/foo`)跳过本卡片',
53
55
  // 群内授权卡片
54
56
  'card.grant.title': '🔑 使用授权',
55
57
  'card.grant.body_request': '用户 **{name}** 申请在本群使用我。<at id={owner}></at> 是否允许 ta 在本群与我对话?',
@@ -89,6 +91,37 @@ export const messages = {
89
91
  'card.adopt.title': '📡 选择要接入的 CLI 会话',
90
92
  'card.adopt.placeholder_select': '选择 CLI 会话',
91
93
  'card.adopt.uptime_unknown': '未知',
94
+ // ─── /relay picker card (pull mode) ─────────────────────────────────────
95
+ 'card.relay.title': '📋 选择要接力到本群的会话',
96
+ 'card.relay.empty': '当前没有可接力的会话。\n(picker 只列你作为 owner、同一机器人在其他群里的活跃会话。)',
97
+ 'card.relay.btn_pull': '接力到本群',
98
+ 'card.relay.btn_confirm': '确认接力到本群',
99
+ 'card.relay.selected_tag': '已选中',
100
+ 'card.relay.hint_pick_first': '点击上方任意会话以选中,然后再点确认按钮触发接力。',
101
+ 'card.relay.search_placeholder': '🔍 搜索会话(标题/群名/路径)',
102
+ 'card.relay.btn_search': '搜索',
103
+ 'card.relay.btn_prev_page': '← 上一页',
104
+ 'card.relay.btn_next_page': '下一页 →',
105
+ 'card.relay.page_indicator': '第 {current} / {total} 页',
106
+ 'card.relay.empty_filtered': '没有匹配「{query}」的会话,请换个关键词。',
107
+ 'card.relay.placeholder_select': '选择要接力的会话',
108
+ 'card.relay.type_group': '普通群',
109
+ 'card.relay.type_topic': '话题群',
110
+ 'card.relay.type_p2p': '单聊',
111
+ 'card.relay.field_type': '类型',
112
+ 'card.relay.field_location': '位置',
113
+ 'card.relay.field_time': '活跃',
114
+ 'card.relay.toast_adopt_not_relayable': '该会话是 /adopt 接入的外部 tmux,无法接力。',
115
+ 'card.relay.toast_not_found': '会话已不存在或已关闭。',
116
+ 'card.relay.toast_not_owner': '只有会话发起人能接力它。',
117
+ 'card.relay.toast_not_invoker': '这张菜单是别人召唤的,请自己发 /relay 召唤一张。',
118
+ 'card.relay.toast_worker_busy': '⚠️ 会话当前正在处理中,请等它空闲后再接力。',
119
+ 'card.relay.toast_not_started_yet': '⚠️ 会话还没选仓库、CLI 没起来,无法接力。请先回原会话把仓库选了。',
120
+ 'card.relay.toast_same_chat': '该会话已在本群里,无需接力。',
121
+ 'card.relay.toast_failed': '接力失败:{error}',
122
+ 'card.relay.toast_target_has_session': '本群已有该机器人的活跃会话,请先 /close 它再接力',
123
+ 'cmd.relay.target_has_session_msg': '⚠️ 本群已有该机器人的活跃会话「{title}」。请先用 /close 关掉那个会话,再接力新的过来。',
124
+ 'card.relay.toast_success': '✅ 已接力到本群',
92
125
  // ─── TUI prompt card ─────────────────────────────────────────────────────
93
126
  'card.tui.input_placeholder': '输入自定义回复…',
94
127
  // ─── Command responses ───────────────────────────────────────────────────
@@ -116,7 +149,6 @@ export const messages = {
116
149
  'cmd.repo.working_dir_not_exist': '❌ 配置的工作目录不存在或不是目录:{dirs}\n请检查 ~/.botmux/bots.json 中的 workingDir / workingDirs,或重新运行 `botmux setup` 修改为已存在的目录。',
117
150
  'cmd.repo.no_git_repos': '在 {dirs} 下未找到 git 仓库。',
118
151
  'cmd.skip.opened': '▶️ 已直接开启会话(工作目录:{cwd})',
119
- 'cmd.skip.no_pending': '当前没有待选择的仓库。',
120
152
  'cmd.status.running': '运行中',
121
153
  'cmd.status.waiting': '等待中',
122
154
  'cmd.status.fallback_no_session': '当前话题没有活跃的会话。\nDaemon active sessions: {count}\n{cliName}: v{version}',
@@ -156,6 +188,34 @@ export const messages = {
156
188
  'cmd.group.warn_bots_rejected': '⚠️ 部分机器人未能加入({bots}),可能不在当前机器人的 app scope 下。请到群里手动添加。',
157
189
  'cmd.group.warn_share_link_failed': '⚠️ 群分享链接获取失败,上面的链接仅群内成员可点开,非成员请群主手动邀请。',
158
190
  'cmd.group.resolve_failed': '⚠️ 无法解析被 @ 的机器人(可能群成员信息暂时拿不到),未建群。请稍后重试。',
191
+ // ─── /relay --create ────────────────────────────────────────────────────
192
+ 'cmd.relay.empty_group_name': '会话接力 {ts}',
193
+ 'cmd.relay.no_session': '⚠️ /relay 必须在已有会话的话题里发起。',
194
+ 'cmd.relay.target_has_session': '⚠️ 本群里这个机器人已经有一个活跃会话「{title}」。请先用 /close 关掉那个会话,再 /relay 接力新的过来。',
195
+ 'cmd.relay.no_sender': '⚠️ 无法获取发起人 open_id,/relay 取消。',
196
+ 'cmd.relay.no_mentions': '⚠️ /relay --create 必须 @ 至少一个机器人作为新群的协作伙伴。',
197
+ 'cmd.relay.not_owner': '⚠️ 只有会话发起人能用 /relay --create 把会话搬到新群。',
198
+ 'cmd.relay.adopt_not_relayable': '⚠️ 该会话是 /adopt 接入的外部 tmux 进程,CLI 在你电脑里跑,botmux 控不了 tmux 生命周期,无法接力。',
199
+ 'cmd.relay.not_started_yet': '⚠️ 会话还没选仓库、CLI 没起来,无法接力。请先在本会话里选仓库把 CLI 起起来。',
200
+ 'cmd.relay.worker_busy': '⚠️ 会话正在处理中(mid-turn),无法接力。请等当前回合结束(idle)后再发 /relay。',
201
+ 'cmd.relay.picker_p2p_unsupported': '⚠️ 单聊不支持接力会话。请在普通群里使用 /relay。',
202
+ 'cmd.relay.picker_topic_unsupported': '⚠️ 话题群不支持接力会话(话题群按话题路由,搬过来的会话没有 thread 锚点)。请在普通群里使用 /relay。',
203
+ 'cmd.relay.resolve_failed': '⚠️ 无法解析被 @ 的机器人,/relay 取消。请稍后重试。',
204
+ 'cmd.relay.m1_announce': '📋 已从「{sourceChat}」接力会话过来。\n⚠️ 飞书消息历史留在源群,AI 记忆已接续。\n@ 对应机器人继续对话即可。',
205
+ 'cmd.relay.m1_final_all_ok': '🚀 会话已接力到本群\n📋 来源:{sourceChat}\n✅ 已就绪:{successBots}\n⚠️ 飞书消息历史留在源群,AI 记忆已接续。@ 对应机器人继续对话。',
206
+ 'cmd.relay.m1_final_partial': '🚀 会话已接力到本群\n📋 来源:{sourceChat}\n✅ 已就绪:{successBots}\n⚠️ 未能迁移:{failedBots}\n→ 请在本群发 /relay,从菜单里把上述 bot 在源群的会话拉过来\n⚠️ 飞书消息历史留在源群,AI 记忆已接续。',
207
+ 'cmd.relay.m1_final_all_fresh': '🚀 新群已建好,机器人都已邀请。\n📋 来源:{sourceChat}\n本次没有可迁移的源会话——@ 任意机器人开始新对话即可。',
208
+ 'cmd.relay.created': '✅ 已创建群「{name}」并接力会话\n👉 {link}\n\n{report}',
209
+ 'cmd.relay.report_leader_ok': '• {bot}(当前会话)已接力',
210
+ 'cmd.relay.report_leader_no_session': '• {bot}(当前会话)— 跳过(无活跃会话)',
211
+ 'cmd.relay.report_leader_failed': '• {bot}(当前会话)— 接力失败:{error}',
212
+ 'cmd.relay.report_peer_ok': '• {bot} 已接力',
213
+ 'cmd.relay.report_peer_no_session': '• {bot} — 跳过(在源话题无会话)',
214
+ 'cmd.relay.report_peer_not_owner': '• {bot} — 跳过(会话不属于你)',
215
+ 'cmd.relay.report_peer_offline': '• {bot} — 跳过(守护进程离线)',
216
+ 'cmd.relay.report_peer_busy': '• {bot} — 跳过(会话繁忙,超时)',
217
+ 'cmd.relay.report_peer_failed': '• {bot} — 接力失败:{error}',
218
+ 'cmd.relay.failed': '⚠️ /relay --create 失败:{error}',
159
219
  // ─── /schedule ───────────────────────────────────────────────────────────
160
220
  'schedule.empty_with_examples': '暂无定时任务。\n\n用法示例:\n/schedule 每日17:50 帮我看看今天AI圈有什么新闻\n/schedule 工作日每天9:00 检查服务状态\n/schedule 每周一10:00 生成周报',
161
221
  'schedule.list_header': '定时任务列表 ({count}):',
@@ -173,7 +233,7 @@ export const messages = {
173
233
  'help.close': '/close - 关闭当前会话,终止 {cliName} 进程',
174
234
  'help.restart': '/restart - 重启 {cliName} 进程(保留 session)',
175
235
  'help.cd': '/cd <path> - 切换工作目录并重启 {cliName} 进程',
176
- 'help.repo_list': '/repo - 查看项目列表(交互式下拉 + 文本列表)',
236
+ 'help.repo_list': '/repo - 仓库待选时直接在默认目录开会话;会话中则弹项目选择卡片',
177
237
  'help.repo_n': '/repo <N> - 切换到第 N 个项目',
178
238
  'help.repo_path': '/repo <路径|项目名> - 直接指定路径或 workingDir 下的项目名,跳过选择卡片',
179
239
  'help.status': '/status - 查看当前会话状态(含终端链接)',
@@ -245,15 +305,32 @@ export const messages = {
245
305
  'ai.bridge.mentions_label': '[@提及]',
246
306
  'schedule.title_prefix': '[定时]',
247
307
  // ─── Role command ─────────────────────────────────────────────────────────
248
- 'role.current': '📋 当前群的 Role 配置:',
308
+ 'role.current': '📋 当前生效的 Role',
249
309
  'role.byte_count': '{bytes} / {max} 字节',
250
- 'role.empty': '当前群尚未配置 Role。\n\n用法:\n/role set <Markdown 内容> 设置角色\n/role — 查看当前角色\n/role delete删除角色',
251
- 'role.saved_via_cmd': '✅ Role 已更新({bytes} / {max} 字节)。下次消息生效。',
252
- 'role.deleted_via_cmd': '✅ Role 已删除。',
310
+ 'role.empty': '当前没有生效的 Role(团队级与本群均未配置)。\n\n用法:\n/role set <Markdown>设置本群 Role(覆盖团队级)\n/role team set <Markdown> 设置团队级 Role(本机器人跨群默认)\n/role cap set <一句话> 设置能力标签(花名册展示)',
311
+ 'role.saved_via_cmd': '✅ 本群 Role 已更新({bytes} / {max} 字节)。新会话生效。',
312
+ 'role.deleted_via_cmd': '✅ 本群 Role 已删除。',
253
313
  'role.nothing_to_delete': '当前群没有 Role 配置,无需删除。',
254
314
  'role.set_empty': 'Role 内容不能为空。用法:/role set <Markdown 内容>',
255
315
  'role.no_chat': '无法获取群信息,请稍后重试。',
256
- 'role.help': '/role 用法:\n• /role — 查看当前角色\n• /role set <Markdown 内容> — 设置角色\n• /role delete — 删除角色',
316
+ 'role.src_chat': '(来源:本群覆盖)',
317
+ 'role.src_team': '(来源:团队级默认)',
318
+ 'role.team_current': '📋 团队级 Role(本机器人,跨群默认):',
319
+ 'role.team_empty': '尚未设置团队级 Role。\n用法:/role team set <Markdown> — 设置;/role team delete — 删除',
320
+ 'role.team_saved': '✅ 团队级 Role 已更新({bytes} / {max} 字节)。未单独覆盖的群在新会话生效。',
321
+ 'role.team_deleted': '✅ 团队级 Role 已删除。',
322
+ 'role.team_nothing': '没有团队级 Role,无需删除。',
323
+ 'role.cap_current': '🏷️ 当前能力标签:{cap}',
324
+ 'role.cap_empty': '尚未设置能力标签。\n用法:/role cap set <一句话能力描述>',
325
+ 'role.cap_saved': '✅ 能力标签已更新:{cap}',
326
+ 'role.cap_cleared': '✅ 能力标签已清除。',
327
+ 'role.cap_set_empty': '能力标签不能为空。用法:/role cap set <描述>',
328
+ 'role.help': '/role 用法:\n• /role — 查看当前生效 Role\n• /role set <Markdown> — 设置本群 Role(覆盖团队级)\n• /role delete — 删除本群 Role\n• /role team [set <Markdown>|delete] — 团队级 Role(跨群默认)\n• /role cap [set <一句话>|clear] — 能力标签(花名册展示)',
329
+ 'pair.usage': '用法:/pair <配对码>(在团队平台网页点"登录"会显示配对码)。',
330
+ 'pair.ok': '✅ 登录配对成功,请回到网页继续。',
331
+ 'pair.expired': '配对码已过期,请在网页重新发起登录。',
332
+ 'pair.already': '该配对码已被使用,请在网页重新发起登录。',
333
+ 'pair.not_found': '配对码无效,请检查后重试(区分有效期,过期需重新发起)。',
257
334
  // ─── Card handler responses ──────────────────────────────────────────────
258
335
  'card.action.adopt_no_restart': '⚠️ adopt 模式不支持重启(不会触动你自己的 tmux pane / CLI 进程)',
259
336
  'card.action.restarted': '🔄 已重启 {cliName}',
@@ -1 +1 @@
1
- {"version":3,"file":"zh.js","sourceRoot":"","sources":["../../src/i18n/zh.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"zh.js","sourceRoot":"","sources":["../../src/i18n/zh.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,QAAQ,GAA2B;IAC9C,4EAA4E;IAC5E,wBAAwB,EAAE,UAAU;IACpC,iCAAiC,EAAE,aAAa;IAChD,yBAAyB,EAAE,WAAW;IACtC,6BAA6B,EAAE,wCAAwC;IACvE,sBAAsB,EAAE,iBAAiB;IACzC,qBAAqB,EAAE,MAAM;IAC7B,wBAAwB,EAAE,QAAQ;IAClC,yBAAyB,EAAE,SAAS;IACpC,sBAAsB,EAAE,SAAS;IACjC,sBAAsB,EAAE,SAAS;IACjC,sBAAsB,EAAE,SAAS;IACjC,kBAAkB,EAAE,OAAO;IAC3B,mBAAmB,EAAE,OAAO;IAC5B,oBAAoB,EAAE,WAAW;IACjC,uBAAuB,EAAE,OAAO;IAChC,yBAAyB,EAAE,OAAO;IAClC,sBAAsB,EAAE,YAAY;IACpC,0BAA0B,EAAE,YAAY;IAExC,4EAA4E;IAC5E,sBAAsB,EAAE,MAAM;IAC9B,qBAAqB,EAAE,KAAK;IAC5B,kBAAkB,EAAE,MAAM;IAC1B,uBAAuB,EAAE,OAAO;IAChC,qBAAqB,EAAE,MAAM;IAC7B,yBAAyB,EAAE,KAAK;IAChC,uBAAuB,EAAE,OAAO;IAChC,4BAA4B,EAAE,UAAU;IACxC,0BAA0B,EAAE,UAAU;IACtC,sBAAsB,EAAE,KAAK;IAC7B,gCAAgC,EAAE,cAAc;IAChD,8BAA8B,EAAE,SAAS;IAEzC,4EAA4E;IAC5E,0BAA0B,EAAE,kBAAkB;IAC9C,wBAAwB,EAAE,wDAAwD;IAClF,+BAA+B,EAAE,oBAAoB;IACrD,6BAA6B,EAAE,aAAa;IAC5C,6BAA6B,EAAE,yCAAyC;IACxE,uBAAuB,EAAE,UAAU;IACnC,wBAAwB,EAAE,KAAK;IAC/B,2BAA2B,EAAE,8CAA8C;IAC3E,8BAA8B,EAAE,0CAA0C;IAC1E,4BAA4B,EAAE,qCAAqC;IAEnE,4EAA4E;IAC5E,iBAAiB,EAAE,WAAW;IAC9B,8BAA8B,EAAE,SAAS;IACzC,0BAA0B,EAAE,SAAS;IACrC,0BAA0B,EAAE,OAAO;IACnC,gBAAgB,EAAE,uGAAuG;IAEzH,SAAS;IACT,kBAAkB,EAAE,SAAS;IAC7B,yBAAyB,EAAE,8DAA8D;IACzF,uBAAuB,EAAE,gDAAgD;IACzE,qBAAqB,EAAE,QAAQ;IAC/B,uBAAuB,EAAE,QAAQ;IACjC,qBAAqB,EAAE,IAAI;IAC3B,iBAAiB,EAAE,iEAAiE;IACpF,6BAA6B,EAAE,aAAa;IAC5C,0BAA0B,EAAE,UAAU;IACtC,+BAA+B,EAAE,OAAO;IACxC,yBAAyB,EAAE,eAAe;IAC1C,wBAAwB,EAAE,WAAW;IACrC,0BAA0B,EAAE,SAAS;IACrC,wBAAwB,EAAE,WAAW;IACrC,wBAAwB,EAAE,8BAA8B;IACxD,0BAA0B,EAAE,8BAA8B;IAE1D,sBAAsB;IACtB,sBAAsB,EAAE,qBAAqB;IAC7C,iBAAiB,EAAE,yFAAyF;IAC5G,qBAAqB,EAAE,8CAA8C;IACrE,wBAAwB,EAAE,qBAAqB;IAC/C,uBAAuB,EAAE,kBAAkB;IAC3C,uBAAuB,EAAE,sBAAsB;IAC/C,kBAAkB,EAAE,6DAA6D;IACjF,sBAAsB,EAAE,gBAAgB;IACxC,sBAAsB,EAAE,kBAAkB;IAC1C,wBAAwB,EAAE,kBAAkB;IAC5C,iBAAiB,EAAE,6BAA6B;IAChD,uBAAuB,EAAE,mDAAmD;IAC5E,mBAAmB,EAAE,kBAAkB;IACvC,uBAAuB,EAAE,KAAK;IAC9B,yBAAyB,EAAE,IAAI;IAC/B,8BAA8B,EAAE,OAAO;IACvC,uBAAuB,EAAE,GAAG;IAE5B,4EAA4E;IAC5E,kBAAkB,EAAE,kBAAkB;IACtC,+BAA+B,EAAE,WAAW;IAC5C,2BAA2B,EAAE,IAAI;IAEjC,2EAA2E;IAC3E,kBAAkB,EAAE,gBAAgB;IACpC,kBAAkB,EAAE,oDAAoD;IACxE,qBAAqB,EAAE,OAAO;IAC9B,wBAAwB,EAAE,SAAS;IACnC,yBAAyB,EAAE,KAAK;IAChC,4BAA4B,EAAE,2BAA2B;IACzD,+BAA+B,EAAE,mBAAmB;IACpD,uBAAuB,EAAE,IAAI;IAC7B,0BAA0B,EAAE,OAAO;IACnC,0BAA0B,EAAE,OAAO;IACnC,2BAA2B,EAAE,yBAAyB;IACtD,2BAA2B,EAAE,0BAA0B;IACvD,+BAA+B,EAAE,UAAU;IAC3C,uBAAuB,EAAE,KAAK;IAC9B,uBAAuB,EAAE,KAAK;IAC9B,qBAAqB,EAAE,IAAI;IAC3B,uBAAuB,EAAE,IAAI;IAC7B,2BAA2B,EAAE,IAAI;IACjC,uBAAuB,EAAE,IAAI;IAC7B,sCAAsC,EAAE,8BAA8B;IACtE,4BAA4B,EAAE,aAAa;IAC3C,4BAA4B,EAAE,cAAc;IAC5C,8BAA8B,EAAE,8BAA8B;IAC9D,8BAA8B,EAAE,yBAAyB;IACzD,kCAAkC,EAAE,sCAAsC;IAC1E,4BAA4B,EAAE,gBAAgB;IAC9C,yBAAyB,EAAE,cAAc;IACzC,qCAAqC,EAAE,8BAA8B;IACrE,kCAAkC,EAAE,sDAAsD;IAC1F,0BAA0B,EAAE,UAAU;IAEtC,4EAA4E;IAC5E,4BAA4B,EAAE,UAAU;IAExC,4EAA4E;IAC5E,uBAAuB,EAAE,cAAc;IACvC,oBAAoB,EAAE,yBAAyB;IAC/C,4BAA4B,EAAE,6BAA6B;IAC3D,4BAA4B,EAAE,oCAAoC;IAClE,8BAA8B,EAAE,8CAA8C;IAC9E,yBAAyB,EAAE,8CAA8C;IACzE,0BAA0B,EAAE,sCAAsC;IAClE,yBAAyB,EAAE,sBAAsB;IACjD,wBAAwB,EAAE,8BAA8B;IACxD,cAAc,EAAE,yCAAyC;IACzD,iBAAiB,EAAE,iCAAiC;IACpD,sBAAsB,EAAE,cAAc;IACtC,oBAAoB,EAAE,sBAAsB;IAC5C,wBAAwB,EAAE,eAAe;IACzC,wBAAwB,EAAE,oBAAoB;IAC9C,6BAA6B,EAAE,qBAAqB;IACpD,yBAAyB,EAAE,wDAAwD;IACnF,8BAA8B,EAAE,cAAc;IAC9C,sBAAsB,EAAE,gBAAgB;IACxC,0BAA0B,EAAE,qDAAqD;IACjF,6BAA6B,EAAE,uDAAuD;IACtF,gCAAgC,EAAE,+GAA+G;IACjJ,uBAAuB,EAAE,uBAAuB;IAChD,iBAAiB,EAAE,wBAAwB;IAC3C,oBAAoB,EAAE,KAAK;IAC3B,oBAAoB,EAAE,KAAK;IAC3B,gCAAgC,EAAE,sEAAsE;IACxG,0BAA0B,EAAE,YAAY;IACxC,iBAAiB,EAAE,WAAW;IAC9B,iBAAiB,EAAE,gBAAgB;IACnC,iBAAiB,EAAE,2BAA2B;IAC9C,iBAAiB,EAAE,2BAA2B;IAC9C,kBAAkB,EAAE,qBAAqB;IACzC,uBAAuB,EAAE,oBAAoB;IAC7C,2BAA2B,EAAE,0EAA0E;IACvG,uBAAuB,EAAE,gBAAgB;IACzC,0BAA0B,EAAE,sBAAsB;IAClD,yBAAyB,EAAE,iBAAiB;IAC5C,mBAAmB,EAAE,uCAAuC;IAC5D,uBAAuB,EAAE,0BAA0B;IACnD,sBAAsB,EAAE,uOAAuO;IAC/P,kBAAkB,EAAE,qFAAqF;IACzG,uBAAuB,EAAE,qEAAqE;IAC9F,+BAA+B,EAAE,4BAA4B;IAC7D,wBAAwB,EAAE,kBAAkB;IAC5C,yBAAyB,EAAE,+FAA+F;IAC1H,uBAAuB,EAAE,KAAK;IAC9B,yBAAyB,EAAE,KAAK;IAChC,0BAA0B,EAAE,kBAAkB;IAC9C,6BAA6B,EAAE,iDAAiD;IAChF,2BAA2B,EAAE,sCAAsC;IACnE,wBAAwB,EAAE,uEAAuE;IACjG,0BAA0B,EAAE,UAAU;IACtC,kBAAkB,EAAE,8BAA8B;IAClD,qBAAqB,EAAE,iCAAiC;IACxD,mBAAmB,EAAE,kEAAkE;IACvF,kBAAkB,EAAE,iBAAiB;IACrC,gCAAgC,EAAE,iDAAiD;IACnF,gCAAgC,EAAE,0CAA0C;IAC5E,wBAAwB,EAAE,iBAAiB;IAC3C,8BAA8B,EAAE,uDAAuD;IACvF,kCAAkC,EAAE,wCAAwC;IAC5E,0BAA0B,EAAE,0CAA0C;IAEtE,2EAA2E;IAC3E,4BAA4B,EAAE,WAAW;IACzC,sBAAsB,EAAE,0BAA0B;IAClD,8BAA8B,EAAE,kEAAkE;IAClG,qBAAqB,EAAE,+BAA+B;IACtD,uBAAuB,EAAE,2CAA2C;IACpE,qBAAqB,EAAE,uCAAuC;IAC9D,+BAA+B,EAAE,oEAAoE;IACrG,2BAA2B,EAAE,8CAA8C;IAC3E,uBAAuB,EAAE,qDAAqD;IAC9E,kCAAkC,EAAE,+BAA+B;IACnE,oCAAoC,EAAE,6DAA6D;IACnG,0BAA0B,EAAE,kCAAkC;IAC9D,uBAAuB,EAAE,qEAAqE;IAC9F,2BAA2B,EAAE,2FAA2F;IACxH,4BAA4B,EAAE,2IAA2I;IACzK,8BAA8B,EAAE,qEAAqE;IACrG,mBAAmB,EAAE,4CAA4C;IACjE,4BAA4B,EAAE,kBAAkB;IAChD,oCAAoC,EAAE,0BAA0B;IAChE,gCAAgC,EAAE,6BAA6B;IAC/D,0BAA0B,EAAE,aAAa;IACzC,kCAAkC,EAAE,uBAAuB;IAC3D,iCAAiC,EAAE,sBAAsB;IACzD,+BAA+B,EAAE,sBAAsB;IACvD,4BAA4B,EAAE,uBAAuB;IACrD,8BAA8B,EAAE,wBAAwB;IACxD,kBAAkB,EAAE,+BAA+B;IAEnD,4EAA4E;IAC5E,8BAA8B,EAAE,yGAAyG;IACzI,sBAAsB,EAAE,mBAAmB;IAC3C,qBAAqB,EAAE,eAAe;IACtC,qBAAqB,EAAE,eAAe;IACtC,kBAAkB,EAAE,cAAc;IAClC,oBAAoB,EAAE,YAAY;IAClC,kBAAkB,EAAE,cAAc;IAClC,mBAAmB,EAAE,cAAc;IACnC,wBAAwB,EAAE,mBAAmB;IAC7C,kBAAkB,EAAE,6FAA6F;IACjH,uBAAuB,EAAE,mVAAmV;IAE5W,4EAA4E;IAC5E,sBAAsB,EAAE,UAAU;IAClC,YAAY,EAAE,sCAAsC;IACpD,cAAc,EAAE,2CAA2C;IAC3D,SAAS,EAAE,sCAAsC;IACjD,gBAAgB,EAAE,2CAA2C;IAC7D,aAAa,EAAE,0BAA0B;IACzC,gBAAgB,EAAE,kDAAkD;IACpE,aAAa,EAAE,+BAA+B;IAC9C,WAAW,EAAE,sEAAsE;IACnF,0BAA0B,EAAE,yCAAyC;IACrE,uBAAuB,EAAE,SAAS;IAClC,sBAAsB,EAAE,4CAA4C;IACpE,oBAAoB,EAAE,+CAA+C;IACrE,sBAAsB,EAAE,2CAA2C;IACnE,sBAAsB,EAAE,8CAA8C;IACtE,mBAAmB,EAAE,6CAA6C;IAClE,uBAAuB,EAAE,wCAAwC;IACjE,oBAAoB,EAAE,UAAU;IAChC,YAAY,EAAE,wCAAwC;IACtD,iBAAiB,EAAE,wCAAwC;IAC3D,oBAAoB,EAAE,UAAU;IAChC,YAAY,EAAE,2CAA2C;IACzD,mBAAmB,EAAE,8BAA8B;IACnD,qBAAqB,EAAE,oBAAoB;IAC3C,kBAAkB,EAAE,4CAA4C;IAChE,oBAAoB,EAAE,8BAA8B;IACpD,oBAAoB,EAAE,yCAAyC;IAC/D,oBAAoB,EAAE,oBAAoB;IAC1C,YAAY,EAAE,qDAAqD;IACnE,aAAa,EAAE,kDAAkD;IACjE,oBAAoB,EAAE,aAAa;IACnC,YAAY,EAAE,kDAAkD;IAChE,WAAW,EAAE,qBAAqB;IAElC,4EAA4E;IAC5E,kBAAkB,EAAE,sCAAsC;IAC1D,4BAA4B,EAAE,8CAA8C;IAC5E,0BAA0B,EAAE,OAAO;IACnC,4BAA4B,EAAE,mDAAmD;IACjF,4BAA4B,EAAE,sCAAsC;IACpE,0BAA0B,EAAE,yEAAyE;IACrG,4BAA4B,EAAE,6DAA6D;IAC3F,yBAAyB,EAAE,uDAAuD;IAClF,wBAAwB,EAAE,sDAAsD;IAChF,0BAA0B,EAAE,qCAAqC;IACjE,4BAA4B,EAAE,gCAAgC;IAE9D,4EAA4E;IAC5E,qBAAqB,EAAE,MAAM;IAC7B,2BAA2B,EAAE,sEAAsE;IACnG,2BAA2B,EAAE,2BAA2B;IACxD,oCAAoC,EAAE,2BAA2B;IACjE,oCAAoC,EAAE,4DAA4D;IAClG,2BAA2B,EAAE,oEAAoE;IACjG,0BAA0B,EAAE,oFAAoF;IAChH,8BAA8B,EAAE,6EAA6E;IAC7G,2BAA2B,EAAE,0HAA0H;IACvJ,0BAA0B,EAAE,gPAAgP;IAC5Q,6BAA6B,EAAE,0DAA0D;IACzF,8BAA8B,EAAE,mEAAmE;IAEnG,4EAA4E;IAC5E,gBAAgB,EAAE,uCAAuC;IACzD,6BAA6B,EAAE,uIAAuI;IACtK,sBAAsB,EAAE,4FAA4F;IACpH,4BAA4B,EAAE,uEAAuE;IACrG,0BAA0B,EAAE,2DAA2D;IACvF,kBAAkB,EAAE,0JAA0J;IAC9K,uBAAuB,EAAE,qDAAqD;IAC9E,uBAAuB,EAAE,+PAA+P;IAExR,4EAA4E;IAC5E,gBAAgB,EAAE,4CAA4C;IAC9D,2BAA2B,EAAE,wEAAwE;IACrG,wBAAwB,EAAE,qGAAqG;IAC/H,sBAAsB,EAAE,4BAA4B;IACpD,6BAA6B,EAAE,MAAM;IACrC,0BAA0B,EAAE,OAAO;IACnC,uBAAuB,EAAE,MAAM;IAE/B,6EAA6E;IAC7E,cAAc,EAAE,gBAAgB;IAChC,iBAAiB,EAAE,oBAAoB;IACvC,YAAY,EAAE,wKAAwK;IACtL,oBAAoB,EAAE,0CAA0C;IAChE,sBAAsB,EAAE,gBAAgB;IACxC,wBAAwB,EAAE,qBAAqB;IAC/C,gBAAgB,EAAE,wCAAwC;IAC1D,cAAc,EAAE,gBAAgB;IAChC,eAAe,EAAE,WAAW;IAC5B,eAAe,EAAE,YAAY;IAC7B,mBAAmB,EAAE,yBAAyB;IAC9C,iBAAiB,EAAE,yEAAyE;IAC5F,iBAAiB,EAAE,mDAAmD;IACtE,mBAAmB,EAAE,iBAAiB;IACtC,mBAAmB,EAAE,kBAAkB;IACvC,kBAAkB,EAAE,kBAAkB;IACtC,gBAAgB,EAAE,uCAAuC;IACzD,gBAAgB,EAAE,iBAAiB;IACnC,kBAAkB,EAAE,YAAY;IAChC,oBAAoB,EAAE,gCAAgC;IACtD,WAAW,EAAE,6MAA6M;IAC1N,YAAY,EAAE,qCAAqC;IACnD,SAAS,EAAE,mBAAmB;IAC9B,cAAc,EAAE,oBAAoB;IACpC,cAAc,EAAE,sBAAsB;IACtC,gBAAgB,EAAE,8BAA8B;IAEhD,4EAA4E;IAC5E,8BAA8B,EAAE,+CAA+C;IAC/E,uBAAuB,EAAE,kBAAkB;IAC3C,6BAA6B,EAAE,oBAAoB;IACnD,uCAAuC,EAAE,wBAAwB;IACjE,4BAA4B,EAAE,+BAA+B;IAC7D,8BAA8B,EAAE,0BAA0B;IAC1D,+BAA+B,EAAE,gBAAgB;IACjD,oCAAoC,EAAE,+BAA+B;IACrE,kCAAkC,EAAE,eAAe;IACnD,sCAAsC,EAAE,0BAA0B;IAClE,0BAA0B,EAAE,oBAAoB;IAChD,8BAA8B,EAAE,yGAAyG;IACzI,gCAAgC,EAAE,kBAAkB;IACpD,uBAAuB,EAAE,WAAW;IACpC,8BAA8B,EAAE,gBAAgB;IAChD,8BAA8B,EAAE,cAAc;IAC9C,sBAAsB,EAAE,MAAM;IAC9B,yCAAyC,EAAE,gBAAgB;IAC3D,qCAAqC,EAAE,6BAA6B;IACpE,yCAAyC,EAAE,yBAAyB;IACpE,uCAAuC,EAAE,iCAAiC;IAE1E,4EAA4E;IAC5E,+BAA+B,EAAE,kBAAkB;IACnD,2BAA2B,EAAE,sDAAsD;IAEnF,4EAA4E;IAC5E,uBAAuB,EAAE,2CAA2C;IACpE,iCAAiC,EAAE,QAAQ;IAC3C,4BAA4B,EAAE,0BAA0B;IACxD,8BAA8B,EAAE,mCAAmC;IACnE,0BAA0B,EAAE,wBAAwB;IACpD,sBAAsB,EAAE,mBAAmB;IAC3C,2BAA2B,EAAE,uCAAuC;IACpE,0BAA0B,EAAE,wBAAwB;IACpD,sBAAsB,EAAE,sJAAsJ;IAC9K,yBAAyB,EAAE,eAAe;IAC1C,0BAA0B,EAAE,cAAc;IAC1C,4BAA4B,EAAE,mCAAmC;IACjE,mBAAmB,EAAE,sCAAsC;IAC3D,+BAA+B,EAAE,cAAc;IAC/C,2BAA2B,EAAE,YAAY;IACzC,2BAA2B,EAAE,cAAc;IAC3C,sBAAsB,EAAE,iBAAiB;IACzC,iBAAiB,EAAE,MAAM;IACzB,uBAAuB,EAAE,qBAAqB;IAC9C,yBAAyB,EAAE,0DAA0D;IACrF,sBAAsB,EAAE,kEAAkE;IAC1F,oBAAoB,EAAE,aAAa;IACnC,sBAAsB,EAAE,oBAAoB;IAC5C,sBAAsB,EAAE,UAAU;IAClC,oBAAoB,EAAE,gBAAgB;IACtC,kBAAkB,EAAE,cAAc;IAClC,gBAAgB,EAAE,cAAc;IAChC,+BAA+B,EAAE,mBAAmB;IACpD,mCAAmC,EAAE,qCAAqC;IAC1E,4BAA4B,EAAE,gBAAgB;IAC9C,iBAAiB,EAAE,8BAA8B;IACjD,mBAAmB,EAAE,iBAAiB;IACtC,+BAA+B,EAAE,oBAAoB;IACrD,gCAAgC,EAAE,mCAAmC;IACrE,yBAAyB,EAAE,uBAAuB;IAClD,wBAAwB,EAAE,uDAAuD;IACjF,mBAAmB,EAAE,0BAA0B;IAC/C,4BAA4B,EAAE,cAAc;IAE5C,iBAAiB,EAAE,WAAW;IAC9B,iBAAiB,EAAE,uBAAuB;IAC1C,sBAAsB,EAAE,sBAAsB;IAC9C,6BAA6B,EAAE,yBAAyB;IACxD,iBAAiB,EAAE,oBAAoB;IACvC,mBAAmB,EAAE,sBAAsB;IAC3C,wBAAwB,EAAE,yCAAyC;IAEnE,4EAA4E;IAC5E,6BAA6B,EAAE,mCAAmC;IAClE,+BAA+B,EAAE,8BAA8B;IAC/D,mCAAmC,EAAE,uDAAuD;IAC5F,mCAAmC,EAAE,2BAA2B;IAChE,6BAA6B,EAAE,iCAAiC;IAChE,gCAAgC,EAAE,gBAAgB;IAClD,0BAA0B,EAAE,gCAAgC;CAC7D,CAAC"}
@@ -27,6 +27,32 @@ export declare function buildSessionCard(sessionId: string, rootId: string, term
27
27
  * Lark bridge so future replies route back into this topic.
28
28
  */
29
29
  export declare function buildSessionClosedCard(sessionId: string, rootId: string, title: string, cliId?: CliId, workingDir?: string, cliResumeCommand?: string | null, locale?: Locale): string;
30
+ /**
31
+ * Build a frozen-snapshot card to PATCH onto the source-chat streaming card
32
+ * after `/relay` moves the session elsewhere.
33
+ *
34
+ * Why this exists: a live streaming card carries action buttons (close /
35
+ * toggle display / get write link). Those buttons identify their session by
36
+ * `session_id` in the value payload, so clicking them after relay still
37
+ * reaches the now-relocated session — closing it, toggling its display
38
+ * mode, etc. — but the visible feedback all lands on the NEW card in the
39
+ * target chat, not this one. The source-chat card then looks like a "live
40
+ * console" while actually being a footgun. PATCH it to an inert snapshot
41
+ * so the user sees clearly it's historical.
42
+ *
43
+ * Last-frame rendering:
44
+ * - imageKey present (session was in 'screenshot' / expanded mode at
45
+ * relay time) → embed the same img element the live card had.
46
+ * img_key is a Lark server resource independent of the card it lived
47
+ * on, so the PATCHed card can still reference it.
48
+ * - imageKey absent (hidden / collapsed mode) → render nothing extra.
49
+ * The header + body notice already convey the state; raw tmux pane
50
+ * text as a code-block is too long and noisy (王皓 caught this in
51
+ * testing).
52
+ *
53
+ * No action buttons are rendered in either case.
54
+ */
55
+ export declare function buildRelayedFrozenCard(title: string, cliId?: CliId, imageKey?: string, locale?: Locale): string;
30
56
  /**
31
57
  * Truncate content to fit within `maxBytes`, keeping the tail (most recent
32
58
  * output). Defaults to {@link MAX_CONTENT_BYTES}; callers that wrap the content
@@ -103,5 +129,61 @@ export declare function buildTuiPromptProcessingCard(selectedText: string, local
103
129
  * Build a resolved TUI prompt card — shows which option was selected.
104
130
  */
105
131
  export declare function buildTuiPromptResolvedCard(selectedText: string, locale?: Locale): string;
132
+ export interface RelayPickerEntry {
133
+ sessionId: string;
134
+ /** Short human label for the source chat — chat name if resolvable, else chatId. */
135
+ chatLabel: string;
136
+ /** First-turn title or current-turn topic — already truncated by the caller. */
137
+ title: string;
138
+ /** Absolute working dir, displayed verbatim. */
139
+ workingDir?: string;
140
+ /** CLI identifier, used to render a friendly name. */
141
+ cliId?: CliId;
142
+ /** Last activity timestamp, used to render a relative duration. */
143
+ lastMessageAt?: number;
144
+ /** Source chat's conversational topology. Drives the type tag in the
145
+ * picker. Caller supplies based on getChatNameAndMode lookup + the
146
+ * session's own chatType for the p2p case. */
147
+ chatMode?: 'group' | 'topic' | 'p2p';
148
+ }
149
+ export interface RelayPickerState {
150
+ /** Currently selected sessionId, if any (drives the highlight + confirm button). */
151
+ selectedSessionId?: string;
152
+ /** Case-insensitive substring filter applied to title / chatLabel / workingDir. */
153
+ searchQuery?: string;
154
+ /** 0-indexed page within the filtered list. Clamped to valid range at render time. */
155
+ page?: number;
156
+ }
157
+ /**
158
+ * Card listing the operator's relayable sessions, paginated 5 per page with
159
+ * a search box at the top and a confirm button at the bottom. Layout:
160
+ *
161
+ * ┌──────────────────────────────────────┐
162
+ * │ 📋 选择要接力的会话 │ header
163
+ * ├──────────────────────────────────────┤
164
+ * │ 🔍 [______________] [搜索] │ form: input + submit button
165
+ * ├──────────────────────────────────────┤
166
+ * │ [interactive_container 1] │ current page (≤5 cards),
167
+ * │ [interactive_container 2] │ each clickable for selection
168
+ * │ ... │
169
+ * ├──────────────────────────────────────┤
170
+ * │ [← 上一页] 1 / 4 [下一页 →] │ paginator row
171
+ * ├──────────────────────────────────────┤
172
+ * │ [确认接力到本群] │ primary button (only when
173
+ * │ │ a selected session is on
174
+ * │ │ the current filtered set)
175
+ * └──────────────────────────────────────┘
176
+ *
177
+ * State (search / page / selected) is propagated entirely via the value
178
+ * objects on each button and container — Lark cards are stateless, so any
179
+ * server-side re-render must reconstruct from what the click sent us.
180
+ * That's why every interactive value here carries `search`, `page`,
181
+ * `target_chat_id`, `root_id`.
182
+ *
183
+ * Note: typing into the search box without clicking 搜索 does NOT update
184
+ * the in-callback state — container/paginator clicks use whatever search
185
+ * was applied at card-render time. To apply a new filter, click 搜索.
186
+ */
187
+ export declare function buildRelayPickerCard(entries: RelayPickerEntry[], targetChatId: string, targetRootMessageId: string, invokerOpenId: string, locale?: Locale, state?: RelayPickerState): string;
106
188
  export declare function buildAdoptSelectCard(sessions: AdoptableSession[], rootMessageId?: string, locale?: Locale): string;
107
189
  //# sourceMappingURL=card-builder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"card-builder.d.ts","sourceRoot":"","sources":["../../../src/im/lark/card-builder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"card-builder.d.ts","sourceRoot":"","sources":["../../../src/im/lark/card-builder.ts"],"names":[],"mappings":"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"}
@@ -133,6 +133,57 @@ export function buildSessionClosedCard(sessionId, rootId, title, cliId, workingD
133
133
  };
134
134
  return JSON.stringify(card);
135
135
  }
136
+ /**
137
+ * Build a frozen-snapshot card to PATCH onto the source-chat streaming card
138
+ * after `/relay` moves the session elsewhere.
139
+ *
140
+ * Why this exists: a live streaming card carries action buttons (close /
141
+ * toggle display / get write link). Those buttons identify their session by
142
+ * `session_id` in the value payload, so clicking them after relay still
143
+ * reaches the now-relocated session — closing it, toggling its display
144
+ * mode, etc. — but the visible feedback all lands on the NEW card in the
145
+ * target chat, not this one. The source-chat card then looks like a "live
146
+ * console" while actually being a footgun. PATCH it to an inert snapshot
147
+ * so the user sees clearly it's historical.
148
+ *
149
+ * Last-frame rendering:
150
+ * - imageKey present (session was in 'screenshot' / expanded mode at
151
+ * relay time) → embed the same img element the live card had.
152
+ * img_key is a Lark server resource independent of the card it lived
153
+ * on, so the PATCHed card can still reference it.
154
+ * - imageKey absent (hidden / collapsed mode) → render nothing extra.
155
+ * The header + body notice already convey the state; raw tmux pane
156
+ * text as a code-block is too long and noisy (王皓 caught this in
157
+ * testing).
158
+ *
159
+ * No action buttons are rendered in either case.
160
+ */
161
+ export function buildRelayedFrozenCard(title, cliId, imageKey, locale) {
162
+ const cliName = getCliDisplayName(cliId ?? 'claude-code');
163
+ const body = `**${escapeMd(title || cliName)}**\n` +
164
+ `${t('card.body.relay_frozen', undefined, locale)}`;
165
+ const elements = [
166
+ { tag: 'markdown', content: body },
167
+ ];
168
+ if (imageKey) {
169
+ elements.push({
170
+ tag: 'img',
171
+ img_key: imageKey,
172
+ alt: { tag: 'plain_text', content: '' },
173
+ mode: 'fit_horizontal',
174
+ preview: true,
175
+ });
176
+ }
177
+ const card = {
178
+ config: { wide_screen_mode: true },
179
+ header: {
180
+ title: { tag: 'plain_text', content: t('card.status.relay_frozen', undefined, locale) },
181
+ template: 'grey',
182
+ },
183
+ elements,
184
+ };
185
+ return JSON.stringify(card);
186
+ }
136
187
  /**
137
188
  * Feishu card API rejects payloads exceeding ~109 KB (error 230025).
138
189
  * Cap markdown content byte size with headroom for card JSON overhead.
@@ -685,6 +736,270 @@ function formatDuration(ms) {
685
736
  const d = Math.floor(h / 24);
686
737
  return `${d}d${h % 24}h`;
687
738
  }
739
+ function relayPickerTypeTag(mode, locale) {
740
+ switch (mode) {
741
+ case 'p2p': return t('card.relay.type_p2p', undefined, locale);
742
+ case 'topic': return t('card.relay.type_topic', undefined, locale);
743
+ default: return t('card.relay.type_group', undefined, locale); // 'group' or undefined
744
+ }
745
+ }
746
+ const RELAY_PICKER_PAGE_SIZE = 5;
747
+ const RELAY_SEARCH_FIELD = 'search';
748
+ /**
749
+ * Match against title / chatLabel / workingDir / cliId. Case-insensitive
750
+ * substring. Empty / whitespace query matches everything.
751
+ */
752
+ function relayPickerFilter(entries, query) {
753
+ const q = (query ?? '').trim().toLowerCase();
754
+ if (!q)
755
+ return entries;
756
+ return entries.filter((e) => {
757
+ const haystack = [e.title, e.chatLabel, e.workingDir, e.cliId]
758
+ .filter(Boolean)
759
+ .join(' ')
760
+ .toLowerCase();
761
+ return haystack.includes(q);
762
+ });
763
+ }
764
+ /**
765
+ * Card listing the operator's relayable sessions, paginated 5 per page with
766
+ * a search box at the top and a confirm button at the bottom. Layout:
767
+ *
768
+ * ┌──────────────────────────────────────┐
769
+ * │ 📋 选择要接力的会话 │ header
770
+ * ├──────────────────────────────────────┤
771
+ * │ 🔍 [______________] [搜索] │ form: input + submit button
772
+ * ├──────────────────────────────────────┤
773
+ * │ [interactive_container 1] │ current page (≤5 cards),
774
+ * │ [interactive_container 2] │ each clickable for selection
775
+ * │ ... │
776
+ * ├──────────────────────────────────────┤
777
+ * │ [← 上一页] 1 / 4 [下一页 →] │ paginator row
778
+ * ├──────────────────────────────────────┤
779
+ * │ [确认接力到本群] │ primary button (only when
780
+ * │ │ a selected session is on
781
+ * │ │ the current filtered set)
782
+ * └──────────────────────────────────────┘
783
+ *
784
+ * State (search / page / selected) is propagated entirely via the value
785
+ * objects on each button and container — Lark cards are stateless, so any
786
+ * server-side re-render must reconstruct from what the click sent us.
787
+ * That's why every interactive value here carries `search`, `page`,
788
+ * `target_chat_id`, `root_id`.
789
+ *
790
+ * Note: typing into the search box without clicking 搜索 does NOT update
791
+ * the in-callback state — container/paginator clicks use whatever search
792
+ * was applied at card-render time. To apply a new filter, click 搜索.
793
+ */
794
+ export function buildRelayPickerCard(entries, targetChatId, targetRootMessageId, invokerOpenId, locale, state) {
795
+ const searchQuery = state?.searchQuery ?? '';
796
+ const requestedPage = state?.page ?? 0;
797
+ const selectedSessionId = state?.selectedSessionId;
798
+ const elements = [];
799
+ // ─── Filter & paginate ───────────────────────────────────────────────
800
+ const filtered = relayPickerFilter(entries, searchQuery);
801
+ const totalPages = Math.max(1, Math.ceil(filtered.length / RELAY_PICKER_PAGE_SIZE));
802
+ const page = Math.min(Math.max(0, requestedPage), totalPages - 1);
803
+ const start = page * RELAY_PICKER_PAGE_SIZE;
804
+ const visible = filtered.slice(start, start + RELAY_PICKER_PAGE_SIZE);
805
+ // Common state object carried by every interactive value so re-renders
806
+ // can reconstruct what the user was looking at. `invoker_open_id` pins the
807
+ // card to the user who originally summoned it — card-handler refuses
808
+ // re-render / confirm clicks from anyone else, so the menu doesn't get
809
+ // silently swapped to a passer-by's session list.
810
+ const stateValue = {
811
+ target_chat_id: targetChatId,
812
+ root_id: targetRootMessageId,
813
+ invoker_open_id: invokerOpenId,
814
+ search: searchQuery,
815
+ page,
816
+ selected: selectedSessionId ?? '',
817
+ };
818
+ // ─── Search box ─────────────────────────────────────────────────────
819
+ // v2 input supports `behaviors` natively — pressing Enter or clicking
820
+ // the built-in submit icon inside the input fires the callback. No
821
+ // separate 搜索 button needed (王皓 reported that button rendered as
822
+ // "..." due to cramped column width; the auto-submit input avoids the
823
+ // problem entirely AND removes the manual click).
824
+ //
825
+ // On submit the callback delivers `action.input_value` (the typed
826
+ // string) and `action.value` (our state object). card-handler reads
827
+ // input_value to update search, resets page to 0 and clears selection.
828
+ elements.push({
829
+ tag: 'input',
830
+ name: RELAY_SEARCH_FIELD,
831
+ placeholder: { tag: 'plain_text', content: t('card.relay.search_placeholder', undefined, locale) },
832
+ default_value: searchQuery,
833
+ width: 'fill',
834
+ behaviors: [
835
+ {
836
+ type: 'callback',
837
+ value: { action: 'relay_search', ...stateValue, selected: '' /* new search → reset selection */ },
838
+ },
839
+ ],
840
+ });
841
+ elements.push({ tag: 'hr' });
842
+ // ─── Empty / no-match notice ────────────────────────────────────────
843
+ if (entries.length === 0) {
844
+ elements.push({ tag: 'markdown', content: t('card.relay.empty', undefined, locale) });
845
+ return JSON.stringify(wrapCard(elements, locale));
846
+ }
847
+ if (filtered.length === 0) {
848
+ elements.push({
849
+ tag: 'markdown',
850
+ content: t('card.relay.empty_filtered', { query: searchQuery }, locale),
851
+ });
852
+ return JSON.stringify(wrapCard(elements, locale));
853
+ }
854
+ // ─── Session cards (current page) ───────────────────────────────────
855
+ const p2pLocationLabel = t('card.relay.type_p2p', undefined, locale);
856
+ const labelType = t('card.relay.field_type', undefined, locale);
857
+ const labelLocation = t('card.relay.field_location', undefined, locale);
858
+ const labelTime = t('card.relay.field_time', undefined, locale);
859
+ const selectedTag = t('card.relay.selected_tag', undefined, locale);
860
+ const hasValidSelection = !!selectedSessionId && filtered.some(e => e.sessionId === selectedSessionId);
861
+ visible.forEach((e) => {
862
+ const isSelected = e.sessionId === selectedSessionId;
863
+ const typeTag = relayPickerTypeTag(e.chatMode, locale);
864
+ const locationLine = e.chatMode === 'p2p' ? p2pLocationLabel : e.chatLabel;
865
+ const titleLine = isSelected
866
+ ? `**✅ ${escapeMd(e.title)}** \`${selectedTag}\``
867
+ : `**${escapeMd(e.title)}**`;
868
+ const lines = [
869
+ titleLine,
870
+ `${labelType}: ${typeTag}`,
871
+ `${labelLocation}: ${escapeMd(locationLine)}`,
872
+ ];
873
+ if (e.lastMessageAt) {
874
+ lines.push(`${labelTime}: ${formatDuration(Date.now() - e.lastMessageAt)}`);
875
+ }
876
+ elements.push({
877
+ tag: 'interactive_container',
878
+ width: 'fill',
879
+ padding: '8px 12px',
880
+ background_style: isSelected ? 'laser' : 'default',
881
+ has_border: true,
882
+ border_color: isSelected ? 'blue-500' : 'grey-200',
883
+ corner_radius: '8px',
884
+ behaviors: [
885
+ {
886
+ type: 'callback',
887
+ value: { action: 'relay_select', session_id: e.sessionId, ...stateValue },
888
+ },
889
+ ],
890
+ elements: [{ tag: 'markdown', content: lines.join('\n') }],
891
+ });
892
+ });
893
+ // ─── Paginator (only when more than one page) ───────────────────────
894
+ if (totalPages > 1) {
895
+ elements.push({
896
+ tag: 'column_set',
897
+ flex_mode: 'none',
898
+ horizontal_spacing: 'default',
899
+ columns: [
900
+ {
901
+ tag: 'column',
902
+ width: 'weighted',
903
+ weight: 1,
904
+ vertical_align: 'center',
905
+ elements: [
906
+ {
907
+ tag: 'button',
908
+ text: { tag: 'plain_text', content: t('card.relay.btn_prev_page', undefined, locale) },
909
+ type: 'default',
910
+ disabled: page === 0,
911
+ behaviors: [
912
+ {
913
+ type: 'callback',
914
+ value: { action: 'relay_page', ...stateValue, page: Math.max(0, page - 1) },
915
+ },
916
+ ],
917
+ },
918
+ ],
919
+ },
920
+ {
921
+ tag: 'column',
922
+ width: 'weighted',
923
+ weight: 2,
924
+ vertical_align: 'center',
925
+ elements: [
926
+ {
927
+ tag: 'markdown',
928
+ text_align: 'center',
929
+ content: t('card.relay.page_indicator', { current: page + 1, total: totalPages }, locale),
930
+ },
931
+ ],
932
+ },
933
+ {
934
+ tag: 'column',
935
+ width: 'weighted',
936
+ weight: 1,
937
+ vertical_align: 'center',
938
+ elements: [
939
+ {
940
+ tag: 'button',
941
+ text: { tag: 'plain_text', content: t('card.relay.btn_next_page', undefined, locale) },
942
+ type: 'default',
943
+ disabled: page === totalPages - 1,
944
+ behaviors: [
945
+ {
946
+ type: 'callback',
947
+ value: { action: 'relay_page', ...stateValue, page: Math.min(totalPages - 1, page + 1) },
948
+ },
949
+ ],
950
+ },
951
+ ],
952
+ },
953
+ ],
954
+ });
955
+ }
956
+ // ─── Confirm button or hint ─────────────────────────────────────────
957
+ elements.push({ tag: 'hr' });
958
+ if (hasValidSelection) {
959
+ elements.push({
960
+ tag: 'column_set',
961
+ flex_mode: 'none',
962
+ columns: [
963
+ {
964
+ tag: 'column',
965
+ width: 'weighted',
966
+ weight: 1,
967
+ elements: [
968
+ {
969
+ tag: 'button',
970
+ text: { tag: 'plain_text', content: t('card.relay.btn_confirm', undefined, locale) },
971
+ type: 'primary',
972
+ behaviors: [
973
+ {
974
+ type: 'callback',
975
+ value: { action: 'relay_confirm', session_id: selectedSessionId, ...stateValue },
976
+ },
977
+ ],
978
+ },
979
+ ],
980
+ },
981
+ ],
982
+ });
983
+ }
984
+ else {
985
+ elements.push({
986
+ tag: 'markdown',
987
+ content: `<font color='grey'>${t('card.relay.hint_pick_first', undefined, locale)}</font>`,
988
+ });
989
+ }
990
+ return JSON.stringify(wrapCard(elements, locale));
991
+ }
992
+ function wrapCard(elements, locale) {
993
+ return {
994
+ schema: '2.0',
995
+ config: { update_multi: true },
996
+ header: {
997
+ title: { tag: 'plain_text', content: t('card.relay.title', undefined, locale) },
998
+ template: 'blue',
999
+ },
1000
+ body: { direction: 'vertical', elements },
1001
+ };
1002
+ }
688
1003
  export function buildAdoptSelectCard(sessions, rootMessageId, locale) {
689
1004
  const unknownUptime = t('card.adopt.uptime_unknown', undefined, locale);
690
1005
  const options = sessions.map((s) => {