botmux 2.84.0 → 2.84.1

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 (179) hide show
  1. package/README.md +4 -0
  2. package/dist/adapters/backend/sandbox.d.ts +4 -0
  3. package/dist/adapters/backend/sandbox.d.ts.map +1 -1
  4. package/dist/adapters/backend/sandbox.js +14 -0
  5. package/dist/adapters/backend/sandbox.js.map +1 -1
  6. package/dist/adapters/cli/claude-code.d.ts.map +1 -1
  7. package/dist/adapters/cli/claude-code.js +4 -1
  8. package/dist/adapters/cli/claude-code.js.map +1 -1
  9. package/dist/adapters/cli/types.d.ts +11 -0
  10. package/dist/adapters/cli/types.d.ts.map +1 -1
  11. package/dist/bot-registry.d.ts +7 -0
  12. package/dist/bot-registry.d.ts.map +1 -1
  13. package/dist/bot-registry.js +27 -0
  14. package/dist/bot-registry.js.map +1 -1
  15. package/dist/cli.d.ts.map +1 -1
  16. package/dist/cli.js +30 -65
  17. package/dist/cli.js.map +1 -1
  18. package/dist/core/command-handler.d.ts.map +1 -1
  19. package/dist/core/command-handler.js +42 -1
  20. package/dist/core/command-handler.js.map +1 -1
  21. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  22. package/dist/core/dashboard-ipc-server.js +58 -1
  23. package/dist/core/dashboard-ipc-server.js.map +1 -1
  24. package/dist/core/passthrough-commands.d.ts.map +1 -1
  25. package/dist/core/passthrough-commands.js +1 -1
  26. package/dist/core/passthrough-commands.js.map +1 -1
  27. package/dist/core/pending-response.d.ts +2 -39
  28. package/dist/core/pending-response.d.ts.map +1 -1
  29. package/dist/core/pending-response.js +5 -99
  30. package/dist/core/pending-response.js.map +1 -1
  31. package/dist/core/session-manager.d.ts.map +1 -1
  32. package/dist/core/session-manager.js +4 -16
  33. package/dist/core/session-manager.js.map +1 -1
  34. package/dist/core/skills/claude-plugin-delivery.d.ts +6 -0
  35. package/dist/core/skills/claude-plugin-delivery.d.ts.map +1 -0
  36. package/dist/core/skills/claude-plugin-delivery.js +21 -0
  37. package/dist/core/skills/claude-plugin-delivery.js.map +1 -0
  38. package/dist/core/skills/cli-admin-command.d.ts +7 -0
  39. package/dist/core/skills/cli-admin-command.d.ts.map +1 -0
  40. package/dist/core/skills/cli-admin-command.js +243 -0
  41. package/dist/core/skills/cli-admin-command.js.map +1 -0
  42. package/dist/core/skills/cli-session-command.d.ts +7 -0
  43. package/dist/core/skills/cli-session-command.d.ts.map +1 -0
  44. package/dist/core/skills/cli-session-command.js +45 -0
  45. package/dist/core/skills/cli-session-command.js.map +1 -0
  46. package/dist/core/skills/delivery.d.ts +11 -0
  47. package/dist/core/skills/delivery.d.ts.map +1 -0
  48. package/dist/core/skills/delivery.js +22 -0
  49. package/dist/core/skills/delivery.js.map +1 -0
  50. package/dist/core/skills/discovery.d.ts +3 -0
  51. package/dist/core/skills/discovery.d.ts.map +1 -0
  52. package/dist/core/skills/discovery.js +34 -0
  53. package/dist/core/skills/discovery.js.map +1 -0
  54. package/dist/core/skills/frontmatter.d.ts +9 -0
  55. package/dist/core/skills/frontmatter.d.ts.map +1 -0
  56. package/dist/core/skills/frontmatter.js +42 -0
  57. package/dist/core/skills/frontmatter.js.map +1 -0
  58. package/dist/core/skills/im-command.d.ts +9 -0
  59. package/dist/core/skills/im-command.d.ts.map +1 -0
  60. package/dist/core/skills/im-command.js +107 -0
  61. package/dist/core/skills/im-command.js.map +1 -0
  62. package/dist/core/skills/manifest-store.d.ts +4 -0
  63. package/dist/core/skills/manifest-store.d.ts.map +1 -0
  64. package/dist/core/skills/manifest-store.js +26 -0
  65. package/dist/core/skills/manifest-store.js.map +1 -0
  66. package/dist/core/skills/package.d.ts +13 -0
  67. package/dist/core/skills/package.d.ts.map +1 -0
  68. package/dist/core/skills/package.js +35 -0
  69. package/dist/core/skills/package.js.map +1 -0
  70. package/dist/core/skills/policy.d.ts +18 -0
  71. package/dist/core/skills/policy.d.ts.map +1 -0
  72. package/dist/core/skills/policy.js +69 -0
  73. package/dist/core/skills/policy.js.map +1 -0
  74. package/dist/core/skills/prompt.d.ts +3 -0
  75. package/dist/core/skills/prompt.d.ts.map +1 -0
  76. package/dist/core/skills/prompt.js +25 -0
  77. package/dist/core/skills/prompt.js.map +1 -0
  78. package/dist/core/skills/references.d.ts +21 -0
  79. package/dist/core/skills/references.d.ts.map +1 -0
  80. package/dist/core/skills/references.js +27 -0
  81. package/dist/core/skills/references.js.map +1 -0
  82. package/dist/core/skills/registry-paths.d.ts +5 -0
  83. package/dist/core/skills/registry-paths.d.ts.map +1 -0
  84. package/dist/core/skills/registry-paths.js +15 -0
  85. package/dist/core/skills/registry-paths.js.map +1 -0
  86. package/dist/core/skills/resource-reader.d.ts +9 -0
  87. package/dist/core/skills/resource-reader.d.ts.map +1 -0
  88. package/dist/core/skills/resource-reader.js +97 -0
  89. package/dist/core/skills/resource-reader.js.map +1 -0
  90. package/dist/core/skills/session-resolver.d.ts +14 -0
  91. package/dist/core/skills/session-resolver.d.ts.map +1 -0
  92. package/dist/core/skills/session-resolver.js +24 -0
  93. package/dist/core/skills/session-resolver.js.map +1 -0
  94. package/dist/core/skills/session-runtime.d.ts +14 -0
  95. package/dist/core/skills/session-runtime.d.ts.map +1 -0
  96. package/dist/core/skills/session-runtime.js +32 -0
  97. package/dist/core/skills/session-runtime.js.map +1 -0
  98. package/dist/core/skills/sources.d.ts +21 -0
  99. package/dist/core/skills/sources.d.ts.map +1 -0
  100. package/dist/core/skills/sources.js +155 -0
  101. package/dist/core/skills/sources.js.map +1 -0
  102. package/dist/core/skills/types.d.ts +71 -0
  103. package/dist/core/skills/types.d.ts.map +1 -0
  104. package/dist/core/skills/types.js +2 -0
  105. package/dist/core/skills/types.js.map +1 -0
  106. package/dist/core/types.d.ts +10 -3
  107. package/dist/core/types.d.ts.map +1 -1
  108. package/dist/core/types.js.map +1 -1
  109. package/dist/core/worker-pool.d.ts +14 -1
  110. package/dist/core/worker-pool.d.ts.map +1 -1
  111. package/dist/core/worker-pool.js +89 -62
  112. package/dist/core/worker-pool.js.map +1 -1
  113. package/dist/daemon.d.ts +2 -2
  114. package/dist/daemon.d.ts.map +1 -1
  115. package/dist/daemon.js +49 -52
  116. package/dist/daemon.js.map +1 -1
  117. package/dist/dashboard/skill-install-request.d.ts +21 -0
  118. package/dist/dashboard/skill-install-request.d.ts.map +1 -0
  119. package/dist/dashboard/skill-install-request.js +62 -0
  120. package/dist/dashboard/skill-install-request.js.map +1 -0
  121. package/dist/dashboard/web/app.d.ts.map +1 -1
  122. package/dist/dashboard/web/app.js +4 -1
  123. package/dist/dashboard/web/app.js.map +1 -1
  124. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  125. package/dist/dashboard/web/i18n.js +138 -0
  126. package/dist/dashboard/web/i18n.js.map +1 -1
  127. package/dist/dashboard/web/skills.d.ts +2 -0
  128. package/dist/dashboard/web/skills.d.ts.map +1 -0
  129. package/dist/dashboard/web/skills.js +539 -0
  130. package/dist/dashboard/web/skills.js.map +1 -0
  131. package/dist/dashboard-web/app.js +594 -451
  132. package/dist/dashboard-web/index.html +1 -0
  133. package/dist/dashboard-web/style.css +793 -0
  134. package/dist/dashboard.js +231 -0
  135. package/dist/dashboard.js.map +1 -1
  136. package/dist/global-config.d.ts +7 -0
  137. package/dist/global-config.d.ts.map +1 -1
  138. package/dist/global-config.js +16 -0
  139. package/dist/global-config.js.map +1 -1
  140. package/dist/i18n/en.d.ts.map +1 -1
  141. package/dist/i18n/en.js +2 -5
  142. package/dist/i18n/en.js.map +1 -1
  143. package/dist/i18n/zh.d.ts.map +1 -1
  144. package/dist/i18n/zh.js +2 -5
  145. package/dist/i18n/zh.js.map +1 -1
  146. package/dist/im/lark/card-builder.d.ts +0 -3
  147. package/dist/im/lark/card-builder.d.ts.map +1 -1
  148. package/dist/im/lark/card-builder.js +0 -33
  149. package/dist/im/lark/card-builder.js.map +1 -1
  150. package/dist/services/bot-config-store.d.ts +4 -4
  151. package/dist/services/bot-config-store.d.ts.map +1 -1
  152. package/dist/services/bot-config-store.js +24 -1
  153. package/dist/services/bot-config-store.js.map +1 -1
  154. package/dist/services/session-store.d.ts +1 -0
  155. package/dist/services/session-store.d.ts.map +1 -1
  156. package/dist/services/session-store.js +12 -5
  157. package/dist/services/session-store.js.map +1 -1
  158. package/dist/services/skill-registry-store.d.ts +42 -0
  159. package/dist/services/skill-registry-store.d.ts.map +1 -0
  160. package/dist/services/skill-registry-store.js +343 -0
  161. package/dist/services/skill-registry-store.js.map +1 -0
  162. package/dist/skills/installer.d.ts.map +1 -1
  163. package/dist/skills/installer.js +3 -0
  164. package/dist/skills/installer.js.map +1 -1
  165. package/dist/types.d.ts +2 -5
  166. package/dist/types.d.ts.map +1 -1
  167. package/dist/utils/file-lock.d.ts +1 -0
  168. package/dist/utils/file-lock.d.ts.map +1 -1
  169. package/dist/utils/file-lock.js +87 -1
  170. package/dist/utils/file-lock.js.map +1 -1
  171. package/dist/worker.js +2 -0
  172. package/dist/worker.js.map +1 -1
  173. package/dist/workflows/definition.d.ts +16 -16
  174. package/dist/workflows/events/schema.d.ts +280 -280
  175. package/package.json +1 -1
  176. package/dist/services/pending-response-transaction-store.d.ts +0 -12
  177. package/dist/services/pending-response-transaction-store.d.ts.map +0 -1
  178. package/dist/services/pending-response-transaction-store.js +0 -52
  179. package/dist/services/pending-response-transaction-store.js.map +0 -1
@@ -1,53 +1,59 @@
1
- "use strict";(()=>{var Ln=class{sessions=new Map;schedules=new Map;online=!0;listeners=new Set;upsertSessions(n){for(let o of n)this.sessions.set(o.sessionId,o);this.emit()}upsertSchedules(n){for(let o of n)this.schedules.set(o.id,o);this.emit()}applySse(n,o){if(n==="session.spawned")this.sessions.set(o.session.sessionId,o.session);else if(n==="session.update"){let s=this.sessions.get(o.sessionId);s&&this.sessions.set(o.sessionId,{...s,...o.patch})}else if(n==="session.exited"){let s=this.sessions.get(o.sessionId);s&&this.sessions.set(o.sessionId,{...s,status:"closed"})}else if(n==="schedule.created")this.schedules.set(o.schedule.id,o.schedule);else if(n==="schedule.updated"){let s=this.schedules.get(o.id);s&&this.schedules.set(o.id,{...s,...o.patch})}else if(n==="schedule.deleted")this.schedules.delete(o.id);else return;this.emit()}setOnline(n){this.online!==n&&(this.online=n,this.emit())}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}},Q=new Ln;async function wo(){let[e,n]=await Promise.all([fetch("/api/sessions").then(a=>a.json()),fetch("/api/schedules").then(a=>a.json())]);Q.upsertSessions(e.sessions??[]),Q.upsertSchedules(n.schedules??[]);let o=new EventSource("/events"),s=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let a of s)o.addEventListener(a,i=>{try{let d=JSON.parse(i.data);Q.applySse(a,d.body??d)}catch{}});o.onerror=()=>Q.setOnline(!1),o.onopen=()=>Q.setOnline(!0)}var In="botmux.dashboard.locale",cs={"app.name":"botmux","app.subtitle":"\u98DE\u4E66 AI CLI \u63A7\u5236\u53F0","time.secondsAgo":"{value} \u79D2\u524D","time.minutesAgo":"{value} \u5206\u949F\u524D","time.hoursAgo":"{value} \u5C0F\u65F6\u524D","nav.overview":"\u603B\u89C8","nav.sessions":"\u4F1A\u8BDD","nav.sidebarCollapse":"\u6536\u8D77\u83DC\u5355\u680F","nav.sidebarExpand":"\u5C55\u5F00\u83DC\u5355\u680F","nav.groups":"\u7FA4\u7EC4","nav.schedules":"\u5B9A\u65F6","nav.settings":"\u8BBE\u7F6E","nav.botDefaults":"Bot \u914D\u7F6E","status.live":"\u5B9E\u65F6\u8FDE\u63A5","status.disconnected":"\u8FDE\u63A5\u65AD\u5F00","status.system":"\u7CFB\u7EDF","status.light":"\u6D45\u8272","status.dark":"\u6697\u9ED1","status.language":"\u8BED\u8A00","status.theme":"\u4E3B\u9898","theme.base":"\u57FA\u7840","theme.skins":"\u4E3B\u9898\u76AE\u80A4","skin.cyber":"2077","skin.genshin":"\u539F\u795E","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"\u851A\u84DD\u6863\u6848","skin.zzz":"\u7EDD\u533A\u96F6","skin.dragonball":"\u4E03\u9F99\u73E0","skin.ikun":"ikun","botOnboarding.add":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.title":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.intro":"\u9009\u62E9 CLI \u4E0E\u5DE5\u4F5C\u76EE\u5F55\uFF0C\u626B\u7801\u521B\u5EFA PersonalAgent \u5E94\u7528\u540E\u5199\u5165\u672C\u673A bots.json\uFF0C\u5E76\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u3002","botOnboarding.cliLabel":"CLI \u9002\u914D\u5668","botOnboarding.dirLabel":"\u5DE5\u4F5C\u76EE\u5F55","botOnboarding.dirPlaceholder":"\u9ED8\u8BA4 ~\uFF08\u5BB6\u76EE\u5F55\uFF09\uFF0C\u9700\u4E3A daemon \u4E3B\u673A\u4E0A\u5DF2\u5B58\u5728\u7684\u76EE\u5F55","botOnboarding.modelLabel":"\u6A21\u578B\uFF08\u53EF\u9009\uFF09","botOnboarding.modelPlaceholder":"\u7559\u7A7A\u4F7F\u7528\u8BE5 CLI \u7684\u9ED8\u8BA4\u6A21\u578B","botOnboarding.modelTtadkPlaceholder":"ttadk \u7F51\u5173\u6A21\u578B\uFF0C\u9ED8\u8BA4 {model}\uFF0C\u53EF\u6539\uFF08\u968F\u65F6\u5728\u6B64\u8C03\u6574\uFF09","botOnboarding.modelTtadkCocoPlaceholder":"CoCo \u65E0\u9700\u6307\u5B9A\u6A21\u578B","botOnboarding.startScan":"\u5F00\u59CB\u626B\u7801","botOnboarding.cancel":"\u53D6\u6D88","botOnboarding.starting":"\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...","botOnboarding.waiting":"\u8BF7\u7528\u98DE\u4E66 App \u626B\u7801\u786E\u8BA4\u521B\u5EFA\u5E94\u7528\u3002","botOnboarding.verifying":"\u626B\u7801\u6210\u529F\uFF0C\u6B63\u5728\u6821\u9A8C\u51ED\u8BC1...","botOnboarding.configuringPermissions":"\u6B63\u5728\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u2026","botOnboarding.platformScanHint":"\u8BF7\u7528\u98DE\u4E66 App \u518D\u626B\u4E00\u6B21\u7801\u767B\u5F55\u5F00\u653E\u5E73\u53F0\uFF08\u7528\u4E8E\u81EA\u52A8\u5BFC\u5165\u6743\u9650\u3001\u914D\u7F6E\u56DE\u8C03\u3001\u63D0\u4EA4\u7248\u672C\uFF09\u3002","botOnboarding.platformQrAlt":"\u5F00\u653E\u5E73\u53F0\u767B\u5F55\u4E8C\u7EF4\u7801","botOnboarding.completed":"\u673A\u5668\u4EBA\u5DF2\u6DFB\u52A0\u3002","botOnboarding.permissionOk":"\u5DF2\u81EA\u52A8\u5BFC\u5165 {count} \u9879\u6743\u9650\u3002","botOnboarding.permissionSkipped":"\uFF08\u8DF3\u8FC7 {count} \u9879\u5F53\u524D\u79DF\u6237\u76EE\u5F55\u4E2D\u6CA1\u6709\u7684\u6743\u9650\uFF09","botOnboarding.permissionVersion":"\u5DF2\u63D0\u4EA4\u53D1\u5E03\u7248\u672C {version}\u3002","botOnboarding.permissionManual":"\u6743\u9650\u672A\u80FD\u81EA\u52A8\u914D\u7F6E\uFF0C\u8BF7\u624B\u52A8\u5B8C\u6210\u4EE5\u4E0B\u6B65\u9AA4\uFF1A","botOnboarding.metaDir":"\u76EE\u5F55","botOnboarding.failed":"\u6DFB\u52A0\u5931\u8D25","botOnboarding.openLink":"\u6253\u4E0D\u5F00\u626B\u7801\uFF1F\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00","botOnboarding.close":"\u5173\u95ED","botOnboarding.restartHint":"\u5DF2\u5199\u5165 bots.json\u3002\u6267\u884C pnpm daemon:restart \u540E\u65B0\u673A\u5668\u4EBA\u751F\u6548\u3002","botOnboarding.qrAlt":"\u98DE\u4E66\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA\u4E8C\u7EF4\u7801","overview.title":"\u5DE5\u4F5C\u53F0","overview.subtitle":"\u6570\u5B57\u5458\u5DE5\u5B9E\u65F6\u72B6\u6001 \xB7 \u540C\u6B65\u98DE\u4E66\u8BDD\u9898","overview.team":"AI \u56E2\u961F","overview.teamHint":"\u6BCF\u4F4D\u6570\u5B57\u5458\u5DE5\u7684\u5B9E\u65F6\u72B6\u6001","overview.attention":"\u9700\u8981\u4F60\u5904\u7406","overview.attentionHint":"\u5361\u4F4F\u7684\u4EFB\u52A1\uFF0C\u56DE\u4E2A\u8BDD\u5C31\u80FD\u7EE7\u7EED\u8DD1","overview.activeSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.activeSessionsHint":"\u6B63\u5728\u8FD0\u8F6C\u7684\u4F1A\u8BDD","overview.today":"\u6B64\u523B\u6982\u89C8","overview.todayHint":"\u6D3B\u8DC3\u4F1A\u8BDD\u5206\u5E03","overview.viewAll":"\u67E5\u770B\u5168\u90E8 \u2192","overview.botIdle":"\u5F85\u547D\u4E2D\uFF0C\u968F\u65F6\u53EF\u63A5\u65B0\u4EFB\u52A1","overview.botOffline":"\u79BB\u7EBF \u2014 daemon \u672A\u4E0A\u7EBF","overview.botBusy":"\u6267\u884C\u4E2D \xB7 {count} \u4F1A\u8BDD","overview.botNeedsYou":"\u7B49\u4F60\u56DE\u590D","overview.botReady":"\u5C31\u7EEA","overview.botOff":"\u79BB\u7EBF","overview.sessionsCount":"{count} \u4F1A\u8BDD","overview.lastActive":"{time}\u524D\u6D3B\u8DC3","overview.noAttention":"\u6CA1\u6709\u7B49\u4F60\u5904\u7406\u7684\u4E8B\u9879","overview.teamExpand":"\u5C55\u5F00\u5168\u90E8 {count} \u4F4D \u25BE","overview.teamCollapse":"\u6536\u8D77 \u25B4","strip.pending":"{count} \u4EF6\u5F85\u5904\u7406","strip.longest":"\u6700\u4E45\u5DF2\u7B49 {time} \u2014 {bot} {reason}","strip.handle":"\u7ACB\u5373\u5904\u7406","overview.openSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.workingSessions":"\u5DE5\u4F5C\u4E2D","overview.onlineBots":"\u5728\u7EBF Bot","overview.schedules":"\u5B9A\u65F6\u4EFB\u52A1","overview.groups":"\u7FA4\u804A\u8986\u76D6","overview.enabledSchedules":"\u5DF2\u542F\u7528","overview.total":"\u603B\u8BA1","overview.active":"\u6D3B\u8DC3","overview.daemonRegistry":"daemon \u6CE8\u518C\u8868","overview.chatMatrix":"\u7FA4\u804A\u77E9\u9635","overview.recentSessions":"\u6700\u8FD1\u4F1A\u8BDD","overview.nextSchedules":"\u5373\u5C06\u6267\u884C","overview.noSessions":"\u6682\u65E0\u4F1A\u8BDD\u3002","overview.noSchedules":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","sessions.title":"\u4F1A\u8BDD\u63A7\u5236","sessions.subtitle":"\u5B9A\u4F4D\u98DE\u4E66\u8BDD\u9898\u3001\u6253\u5F00 Web Terminal\u3001\u5173\u95ED\u6216\u6062\u590D CLI \u4F1A\u8BDD\u3002","sessions.search":"\u641C\u7D22\u5DE5\u4F5C\u76EE\u5F55 / \u6807\u9898 / ID","sessions.anyStatus":"\u5168\u90E8\u72B6\u6001","sessions.adoptAny":"adopt: \u5168\u90E8","sessions.adoptYes":"adopt: \u662F","sessions.adoptNo":"adopt: \u5426","sessions.activeOnly":"\u4EC5\u6D3B\u8DC3","sessions.closeSelected":"\u5173\u95ED\u9009\u4E2D","sessions.clearSelection":"\u53D6\u6D88\u9009\u62E9","sessions.selectedCount":"\u5DF2\u9009 {count} \u4E2A\u4F1A\u8BDD","sessions.bot":"bot","sessions.cli":"CLI","sessions.chat":"\u7FA4\u804A","sessions.openChat":"\u6253\u5F00\u7FA4\u804A","sessions.status":"\u72B6\u6001","sessions.tokenIn":"Token In","sessions.tokenOut":"Token Out","sessions.titleCol":"\u6807\u9898","sessions.workingDir":"\u5DE5\u4F5C\u76EE\u5F55","sessions.created":"\u521B\u5EFA","sessions.last":"\u6700\u8FD1","sessions.adopt":"\u63A5\u5165","sessions.actions":"\u64CD\u4F5C","sessions.details":"\u8BE6\u60C5","sessions.copy":"\u590D\u5236","sessions.copied":"\u5DF2\u590D\u5236","sessions.locate":"\u5B9A\u4F4D\u8BDD\u9898","sessions.locating":"\u53D1\u9001\u4E2D...","sessions.cooldown":"\u51B7\u5374 {seconds}s","sessions.openTerminal":"\u7EC8\u7AEF","sessions.writeLink":"\u64CD\u4F5C\u94FE\u63A5","sessions.writeLinkHint":"\u83B7\u53D6\u53EF\u64CD\u4F5C\u7EC8\u7AEF\u94FE\u63A5\uFF08\u5E26\u5199\u6743\u9650 token\uFF0C\u65B0\u6807\u7B7E\u6253\u5F00\uFF09","sessions.writeLinkFail":"\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u5931\u8D25","sessions.close":"\u5173\u95ED\u4F1A\u8BDD","sessions.resume":"\u6062\u590D\u4F1A\u8BDD","sessions.dismiss":"\u5173\u95ED","sessions.closeConfirm":"\u5173\u95ED\u8FD9\u4E2A\u4F1A\u8BDD\uFF1F","sessions.resumeFailed":"\u6062\u590D\u5931\u8D25","sessions.land":"\u843D\u76D8","sessions.landLoading":"\u52A0\u8F7D\u6C99\u76D2 diff\u2026","sessions.landUnavailable":"\u65E0\u6CD5\u843D\u76D8","sessions.landEmpty":"\u6C99\u76D2\u526F\u672C\u6CA1\u6709\u6539\u52A8\u3002","sessions.landApply":"\u5E94\u7528\u5230\u78C1\u76D8","sessions.landDiscard":"\u4E22\u5F03","sessions.landApplied":"\u5DF2\u843D\u76D8","sessions.landFailed":"\u843D\u76D8\u5931\u8D25","sessions.landDiscarded":"\u5DF2\u4E22\u5F03\uFF08\u6C99\u76D2\u526F\u672C\u672A\u5E94\u7528\uFF09\u3002","connectors.lede":"\u8BA9\u5916\u90E8\u7CFB\u7EDF\uFF08\u76D1\u63A7\u544A\u8B66\u3001CI\u3001\u5DE5\u5355\u2026\uFF09\u901A\u8FC7\u4E00\u4E2A webhook \u89E6\u53D1\u673A\u5668\u4EBA\u5728\u7FA4\u91CC\u8BF4\u8BDD\u6216\u8DD1\u5DE5\u4F5C\u6D41\u3002","connectors.createTitle":"\u65B0\u5EFA Webhook","connectors.fName":"\u540D\u79F0","connectors.fNamePh":"\u5982\uFF1A\u7EBF\u4E0A\u544A\u8B66","connectors.fBot":"\u89E6\u53D1\u7684\u673A\u5668\u4EBA","connectors.fKind":"\u89E6\u53D1\u65B9\u5F0F","connectors.kindTurn":"\u5355\u8F6E\u5BF9\u8BDD\uFF08\u8BA9\u673A\u5668\u4EBA\u56DE\u5E94\u4E00\u6B21\uFF09","connectors.kindWorkflow":"\u5DE5\u4F5C\u6D41","connectors.fWf":"\u5DE5\u4F5C\u6D41 ID","connectors.fMode":"\u6295\u9012\u5230\u54EA\u4E2A\u7FA4","connectors.modeDynamic":"\u7531\u8BF7\u6C42\u6307\u5B9A\uFF08\u7FA4\u968F\u8BF7\u6C42\u4F20\u5165\uFF09","connectors.modeFixed":"\u56FA\u5B9A\u7FA4","connectors.modeNewGroup":"\u6BCF\u6B21\u65B0\u5EFA\u7FA4","connectors.fFixedChat":"\u6295\u9012\u5230\u7684\u7FA4","connectors.fChatManualPh":"\u624B\u52A8\u586B\u7FA4 ID\uFF1Aoc_\u2026","connectors.chatManualLink":"\u627E\u4E0D\u5230\u7FA4\uFF1F\u624B\u52A8\u586B ID \u2192","connectors.chatListLink":"\u4ECE\u7FA4\u5217\u8868\u9009\u62E9 \u2190","connectors.fAllow":"\u5141\u8BB8\u7684\u7FA4","connectors.optional":"\uFF08\u53EF\u9009\uFF09","connectors.allowHint":"\u6309\u4F4F Ctrl/\u2318 \u591A\u9009\uFF1B\u7559\u7A7A = \u4E0D\u9650\u3002\u53EA\u7528\u4E8E\u6821\u9A8C\u8BF7\u6C42\u4F20\u5165\u7684\u7FA4\u662F\u5426\u88AB\u5141\u8BB8\u3002","connectors.dynamicHint":'<b>\u52A8\u6001\u6A21\u5F0F</b>\uFF1A\u7FA4 ID \u968F\u6BCF\u6B21\u8BF7\u6C42\u4F20\u5165\uFF0C\u4E09\u9009\u4E00 \u2014\u2014 \u67E5\u8BE2\u53C2\u6570 <code>?chatId=&lt;\u7FA4ID&gt;</code> \xB7 \u8BF7\u6C42\u5934 <code>x-botmux-chat-id: &lt;\u7FA4ID&gt;</code> \xB7 \u8BF7\u6C42\u4F53 <code>{"chatId":"&lt;\u7FA4ID&gt;"}</code>\u3002<br>\u60F3"\u4E00\u4E2A URL \u76F4\u63A5\u89E6\u53D1\u3001\u4E0D\u5E26\u53C2\u6570"\uFF0C\u8BF7\u6539\u9009\u300C\u56FA\u5B9A\u7FA4\u300D\u3002',"connectors.fDedup":"\u53BB\u91CD\u5B57\u6BB5","connectors.fDedupPh":"\u5982 alert.id\uFF08\u4ECE\u4E8B\u4EF6 body \u53D6\u503C\uFF09","connectors.dedupHint":"\u586B\u4E86\uFF1A\u547D\u4E2D\u76F8\u540C\u503C\u7684\u4E8B\u4EF6\u90FD\u6295\u5230<b>\u540C\u4E00\u4E2A\u7FA4</b>\u3002\u7559\u7A7A\uFF1A\u6BCF\u4E2A\u4E8B\u4EF6<b>\u65B0\u5EFA\u4E00\u4E2A\u7FA4</b>\u3002","connectors.fInstruction":"\u5904\u7406\u6307\u4EE4","connectors.fInstructionPh":"\u4E8B\u4EF6\u89E6\u53D1\u65F6\u8BA9\u673A\u5668\u4EBA\u505A\u4EC0\u4E48\u3002\u5982\uFF1A\u603B\u7ED3\u8FD9\u6761\u544A\u8B66\u7684\u4E25\u91CD\u7A0B\u5EA6\uFF0C@\u76F8\u5173 oncall\uFF0C\u7ED9\u51FA\u6392\u67E5\u5EFA\u8BAE\u3002\u7559\u7A7A = \u53EA\u628A\u4E8B\u4EF6\u539F\u6837\u4EA4\u7ED9\u6A21\u578B\u81EA\u7531\u53D1\u6325\u3002","connectors.fVerify":"\u6821\u9A8C\u65B9\u5F0F","connectors.verifyToken":"\u4EE4\u724C\uFF08\u7B80\u5355\uFF1A\u5BC6\u94A5\u653E\u8FDB URL\uFF0C\u4E00\u6761 curl \u5C31\u80FD\u89E6\u53D1\uFF09","connectors.verifyHmac":"HMAC \u7B7E\u540D\uFF08\u9AD8\u7EA7\uFF1A\u66F4\u5B89\u5168\uFF0C\u9700\u81EA\u884C\u5BF9\u8BF7\u6C42\u7B7E\u540D\uFF09","connectors.fSecret":"\u5BC6\u94A5 / \u4EE4\u724C","connectors.fSecretPh":"\u7559\u7A7A\u81EA\u52A8\u751F\u6210\uFF08\u53EA\u663E\u793A\u4E00\u6B21\uFF09","connectors.btnCreate":"\u521B\u5EFA","connectors.listTitle":"\u5DF2\u6709 Webhook","connectors.loading":"\u52A0\u8F7D\u4E2D\u2026","connectors.noBotGroups":"\uFF08\u8BE5\u673A\u5668\u4EBA\u6682\u65E0\u53EF\u89C1\u7FA4\uFF0C\u70B9\u53F3\u4FA7\u624B\u52A8\u586B ID\uFF09","connectors.modeLabelFixed":"\u56FA\u5B9A\u7FA4","connectors.modeLabelNewGroup":"\u6BCF\u6B21\u65B0\u5EFA\u7FA4","connectors.modeLabelDynamic":"\u8BF7\u6C42\u6307\u5B9A\u7FA4","connectors.kindLabelWorkflow":"\u5DE5\u4F5C\u6D41","connectors.kindLabelTurn":"\u5355\u8F6E","connectors.count":"\xB7 {count} \u4E2A","connectors.empty":"\u8FD8\u6CA1\u6709 Webhook\u3002\u7528\u4E0A\u9762\u7684\u8868\u5355\u521B\u5EFA\u4E00\u4E2A\u3002","connectors.enabled":"\u5DF2\u542F\u7528","connectors.disabled":"\u5DF2\u505C\u7528","connectors.badgeToken":"\u4EE4\u724C","connectors.badgeSign":"\u7B7E\u540D","connectors.dest":"\u6295\u9012\u300C{name}\u300D","connectors.btnDisable":"\u505C\u7528","connectors.btnEnable":"\u542F\u7528","connectors.btnDel":"\u5220\u9664","connectors.webhookUrl":"Webhook URL\uFF1A","connectors.copy":"\u590D\u5236","connectors.copied":"\u5DF2\u590D\u5236","connectors.tokenHint":"\u4EE4\u724C\u6A21\u5F0F\uFF1A\u8C03\u7528\u65F6\u5728 URL \u672B\u5C3E\u8FFD\u52A0 <code>/&lt;\u4EE4\u724C&gt;</code>\uFF08\u4EE4\u724C\u4EC5\u521B\u5EFA/\u8F6E\u6362\u65F6\u663E\u793A\u4E00\u6B21\uFF09\u3002","connectors.dynamicReqHint":'\u52A8\u6001\u6A21\u5F0F\uFF1A\u8BF7\u6C42\u9700\u5E26\u76EE\u6807\u7FA4 \u2014\u2014 <code>?chatId=&lt;\u7FA4ID&gt;</code> \u6216\u5934 <code>x-botmux-chat-id</code> \u6216 body <code>{"chatId":"\u2026"}</code>\u3002',"connectors.instructionPrefix":"\u5904\u7406\u6307\u4EE4\uFF1A","connectors.delConfirm":"\u5220\u9664\u8FD9\u4E2A Webhook\uFF1F\u5B83\u7684 URL \u4F1A\u7ACB\u5373\u5931\u6548\u3002","connectors.errName":"\u8BF7\u586B\u540D\u79F0","connectors.errBot":"\u8BF7\u9009\u673A\u5668\u4EBA","connectors.errWf":"\u8BF7\u586B\u5DE5\u4F5C\u6D41 ID","connectors.errChat":"\u8BF7\u9009\u62E9\uFF08\u6216\u624B\u52A8\u586B\uFF09\u6295\u9012\u7684\u7FA4","connectors.creating":"\u521B\u5EFA\u4E2D\u2026","connectors.usageDynamicLede":"\u52A8\u6001\u6A21\u5F0F\uFF1AURL \u5DF2\u542B\u4EE4\u724C\uFF0C\u8C03\u7528\u65F6\u518D\u5E26\u4E0A\u76EE\u6807\u7FA4 ID{gn}\uFF1A","connectors.usageDynamicNote":'\u7FA4\u4E5F\u53EF\u653E\u8BF7\u6C42\u5934 <code>x-botmux-chat-id</code> \u6216 body <code>{"chatId":"\u2026"}</code>\u3002\u26A0\uFE0F URL \u5373\u51ED\u8BC1\uFF0C\u52FF\u6CC4\u6F0F\u3002',"connectors.usageTokenLede":"\u6B64 URL \u5DF2\u542B\u4EE4\u724C\u3001\u4E14\u56FA\u5B9A\u6295\u9012\u5230\u6240\u9009\u7FA4\uFF0C\u76F4\u63A5 POST \u5373\u53EF\u89E6\u53D1\uFF1A","connectors.usageTokenNote":"\u26A0\uFE0F URL \u5373\u51ED\u8BC1\uFF0C\u8BF7\u52FF\u516C\u5F00\u6CC4\u6F0F\uFF1B\u53EF\u5728\u4E0B\u65B9\u5217\u8868\u5220\u9664\u6216\u8F6E\u6362\u3002","connectors.usageHmac":"\u5916\u90E8\u7CFB\u7EDF\u9700\u5BF9 <code>timestamp.body</code> \u505A HMAC-SHA256 \u7B7E\u540D\uFF0C\u5E76\u5E26\u4E0A <code>x-botmux-timestamp</code> / <code>x-botmux-nonce</code> / <code>x-botmux-signature</code> \u5934\u8C03\u7528","connectors.usageHmacDynamic":"\uFF0C\u540C\u65F6\u6309\u4E0A\u9762\u65B9\u5F0F\u5E26\u76EE\u6807\u7FA4 ID","connectors.createdPrefix":"\u5DF2\u521B\u5EFA\u300C{name}\u300D","connectors.createdDest":"\u6295\u9012\u5230\u300C{name}\u300D","connectors.tokenLabel":"\u8BBF\u95EE\u4EE4\u724C","connectors.signLabel":"\u7B7E\u540D\u5BC6\u94A5","connectors.secretOnce":"\uFF08\u53EA\u663E\u793A\u8FD9\u4E00\u6B21\uFF0C\u8BF7\u4FDD\u5B58\uFF09\uFF1A","connectors.createFailed":"\u521B\u5EFA\u5931\u8D25\uFF1A{error}","connectors.noOnlineBots":"\uFF08\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF09","team.navHome":"\u6211\u7684\u56E2\u961F","team.navManage":"\u56E2\u961F\u7BA1\u7406","team.eyebrow":"\u56E2\u961F","team.homeTitle":"\u56E2\u961F\u534F\u4F5C\uFF08\u8DE8\u90E8\u7F72\uFF09","team.homeLede":"\u628A\u522B\u7684\u90E8\u7F72\uFF08\u540C\u4E8B\u81EA\u5DF1\u8DD1\u7684 botmux\uFF09\u9080\u8BF7\u8FDB\u540C\u4E00\u4E2A\u56E2\u961F\uFF0C\u4E92\u76F8\u53D1\u73B0\u673A\u5668\u4EBA\u3001\u534F\u4F5C\u62C9\u7FA4\u3002","team.localDeployTitle":"\u672C\u90E8\u7F72","team.myIdentity":"\u6211\u7684\u98DE\u4E66\u8EAB\u4EFD\uFF1A","team.unbound":"\u672A\u7ED1\u5B9A","team.bindBtn":"\u7ED1\u5B9A","team.bindHint":"\uFF08\u7528\u673A\u5668\u4EBA\u51ED\u8BC1\u81EA\u52A8\u8BC6\u522B\u4F60\uFF1B\u7ED1\u5B9A\u540E\u62C9\u7FA4\u4F1A\u628A\u4F60\u62C9\u8FDB\u7FA4\u3001\u673A\u5668\u4EBA\u4E5F\u5F52\u5230\u4F60\u540D\u4E0B\uFF09","team.myTeams":"\u6211\u7684\u56E2\u961F","team.searchPh":"\u641C\u7D22 \u540D\u79F0/\u80FD\u529B/CLI\u2026","team.allCli":"\u5168\u90E8 CLI","team.hasCap":"\u6709\u80FD\u529B\u6807\u7B7E","team.hasRole":"\u6709\u9ED8\u8BA4\u89D2\u8272","team.teamsHint":"\u6BCF\u4E2A\u56E2\u961F\u91CC\u52FE\u9009\u673A\u5668\u4EBA\u5373\u53EF\u5355\u72EC\u62C9\u7FA4\uFF08\u81EA\u52A8\u5E26\u4E0A\u5404\u81EA\u8D1F\u8D23\u4EBA\uFF09\u3002\u8981\u65B0\u5EFA\u56E2\u961F / \u751F\u6210\u9080\u8BF7\u7801 / \u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\uFF0C\u53BB\u300C\u56E2\u961F\u7BA1\u7406\u300D\u3002","team.loading":"\u52A0\u8F7D\u4E2D\u2026","team.roleModalTitle":"\u9ED8\u8BA4\u89D2\u8272","team.roleModalHint":"\u8BE5\u673A\u5668\u4EBA\u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF08\u8DE8\u7FA4\u751F\u6548\uFF09\uFF0C\u6B64\u5904\u53EA\u8BFB\u3002\u5982\u9700\u4FEE\u6539\uFF0C\u8BF7\u5230\u300CBot \u914D\u7F6E\u300D\u9875\u3002","team.close":"\u5173\u95ED","team.tagLocal":"\u672C\u90E8\u7F72","team.tagRemoteStale":"\u8FDC\u7AEF\xB7\u79BB\u7EBF\uFF1F","team.tagRemote":"\u8FDC\u7AEF","team.removeMember":"\u79FB\u9664","team.depTag":"\uFF08{tag}\uFF09","team.depCount":"{count} \u4E2A","team.depSelected":"\uFF0C\u5DF2\u9009 {n}","team.capPh":"\u80FD\u529B\u6807\u7B7E\u2026","team.viewRole":"\u67E5\u770B","team.hasRoleShort":"\u6709\u89D2\u8272","team.noMatch":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u673A\u5668\u4EBA\u3002","team.gnamePh":"\u7FA4\u540D\uFF08\u5982\uFF1A\u8DE8\u56E2\u961F\u6392\u969C\uFF09","team.pullGroupBtn":"\u628A\u52FE\u9009\u7684\u673A\u5668\u4EBA\u62C9\u4E00\u4E2A\u7FA4","team.pullGroupHint":"\u52FE\u9009\u673A\u5668\u4EBA \u2192 \u62C9\u5230\u4E00\u4E2A\u98DE\u4E66\u7FA4\uFF08\u81EA\u52A8\u542B owner\uFF09","team.noTeams":"\u8FD8\u6CA1\u6709\u56E2\u961F\u3002\u53BB\u300C\u56E2\u961F\u7BA1\u7406\u300D\u751F\u6210\u9080\u8BF7\u7801\u8BA9\u522B\u4EBA\u52A0\u5165\u4F60\uFF0C\u6216\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\u3002","team.connected":"\u5DF2\u8FDE\u63A5","team.connectFail":"\u8FDE\u63A5\u5931\u8D25\uFF1A{error}","team.iHost":"\u6211\u6258\u7BA1","team.teamMeta":"{deps} \u4E2A\u90E8\u7F72 \xB7 {bots} \u4E2A\u673A\u5668\u4EBA","team.rosterFail":"\u65E0\u6CD5\u83B7\u53D6\u8BE5\u56E2\u961F\u82B1\u540D\u518C\u3002","team.acrossTeams":"\uFF08\u8DE8 {n} \u4E2A\u56E2\u961F\uFF0C\u53BB\u91CD\uFF09","team.botsWord":"\u4E2A\u673A\u5668\u4EBA","team.groupCreated":"\u7FA4\u5DF2\u521B\u5EFA","team.delegatedBy":"\uFF08\u7531\u300C{name}\u300D\u5EFA\u7FA4\uFF09","team.openInLark":"\u5728\u98DE\u4E66\u6253\u5F00","team.invalidBots":"\u672A\u52A0\u5165\u7684\u673A\u5668\u4EBA\uFF1A{ids}","team.invalidOwners":"{n} \u4E2A owner \u672A\u80FD\u62C9\u8FDB","team.missingIdentity":"\u4F60\u672A\u7ED1\u5B9A\u98DE\u4E66\u8EAB\u4EFD\uFF0C\u6CA1\u628A\u4F60\u81EA\u5DF1\u62C9\u8FDB\u7FA4\uFF08\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u7ED1\u5B9A\uFF09","team.skippedNoOwner":"{n} \u4E2A\u673A\u5668\u4EBA\u56E0\u8D1F\u8D23\u4EBA\u672A\u7ED1\u5B9A\u8EAB\u4EFD\u88AB\u8DF3\u8FC7\uFF08\u672A\u52A0\u5165\u7FA4\uFF09","team.errNoLocalBot":"\u8BF7\u81F3\u5C11\u52FE\u9009\u4E00\u4E2A\u4F60\u81EA\u5DF1\uFF08\u672C\u90E8\u7F72\uFF09\u7684\u5728\u7EBF\u673A\u5668\u4EBA\u2014\u2014\u7FA4\u8981\u7531\u5B83\u521B\u5EFA\u5E76\u628A\u4F60\uFF08\u53D1\u8D77\u4EBA\uFF09\u62C9\u8FDB\u7FA4\u3002","team.errAllSkipped":"\u6240\u9009\u673A\u5668\u4EBA\u7684\u8D1F\u8D23\u4EBA\u90FD\u6CA1\u7ED1\u5B9A\u8EAB\u4EFD\uFF0C\u65E0\u6CD5\u62C9\u7FA4\uFF08\u673A\u5668\u4EBA\u4E0D\u80FD\u8FDB\u4E00\u4E2A owner \u4E0D\u5728\u7684\u7FA4\uFF09\u3002\u8BF7\u8BA9\u5BF9\u5E94\u90E8\u7F72\u5148\u7ED1\u5B9A\u8EAB\u4EFD\u3002","team.errNoCreator":"\u6CA1\u6709\u53EF\u7528\u7684\u5EFA\u7FA4\u53D1\u8D77\u65B9\uFF08\u76F8\u5173\u90E8\u7F72\u90FD\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF0C\u6216\u4E0D\u53EF\u8FBE\uFF09","team.errDelegationTimeout":"\u59D4\u6258\u5BF9\u65B9\u90E8\u7F72\u5EFA\u7FA4\u8D85\u65F6\uFF08\u53EF\u80FD\u5DF2\u5EFA\uFF0C\u53BB\u98DE\u4E66\u786E\u8BA4\uFF0C\u52FF\u91CD\u590D\u70B9\uFF09","team.errGroupCreate":"\u5EFA\u7FA4\u5931\u8D25\uFF1A{error}","team.roleModalTitleName":"\u9ED8\u8BA4\u89D2\u8272 \xB7 {name}","team.bound":"\u5DF2\u7ED1\u5B9A","team.myHostedTeam":"\u6211\u6258\u7BA1\u7684\u56E2\u961F","team.remoteTeamLabel":"{name} \u7684\u56E2\u961F","team.manageTitle":"\u56E2\u961F\u7BA1\u7406","team.manageLede":"\u521B\u5EFA\u591A\u4E2A\u56E2\u961F\u3001\u7ED9\u6BCF\u4E2A\u56E2\u961F\u751F\u6210\u9080\u8BF7\u7801\u3001\u6216\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\u3002\u4E00\u4E2A\u56E2\u961F = \u4F60\u672C\u90E8\u7F72\u7684\u673A\u5668\u4EBA + \u52A0\u5165\u8BE5\u56E2\u961F\u7684\u5176\u5B83\u90E8\u7F72\u3002","team.hostedTitle":"\u6211\u6258\u7BA1\u7684\u56E2\u961F","team.newTeamPh":"\u65B0\u56E2\u961F\u540D\u79F0","team.createTeamBtn":"\u521B\u5EFA\u56E2\u961F","team.joinTitle":"\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F","team.hubPh":"Hub \u5730\u5740\uFF0C\u5982 http://10.0.0.5:7891","team.codePh":"\u9080\u8BF7\u7801","team.joinBtn":"\u52A0\u5165","team.noTeamsShort":"\u8FD8\u6CA1\u6709\u56E2\u961F\u3002","team.default":"\u9ED8\u8BA4","team.manageMetaDeps":"{count} \u4E2A\u90E8\u7F72","team.manageMetaRemote":"\uFF08\u542B {r} \u8FDC\u7AEF\uFF09","team.manageMetaBots":"{count} \u4E2A\u673A\u5668\u4EBA","team.genInvite":"\u751F\u6210\u9080\u8BF7\u7801","team.delBtn":"\u5220\u9664","team.generating":"\u751F\u6210\u4E2D\u2026","team.inviteResultLede":"\u628A\u4E0B\u9762\u4E24\u9879\u53D1\u7ED9\u522B\u7684\u90E8\u7F72\u7684\u4EBA\uFF0824 \u5C0F\u65F6\u5185\u3001\u5355\u6B21\u6709\u6548\uFF09\uFF1A","team.inviteHub":"Hub \u5730\u5740\uFF1A","team.inviteCode":"\u9080\u8BF7\u7801\uFF1A","team.genFail":"\u751F\u6210\u5931\u8D25\u3002","team.delConfirm":"\u5220\u9664\u56E2\u961F\u300C{name}\u300D\uFF1F\u5DF2\u52A0\u5165\u5B83\u7684\u90E8\u7F72\u4F1A\u88AB\u79FB\u9664\uFF08\u4E0D\u5F71\u54CD\u4ED6\u4EEC\u81EA\u5DF1\u7684\u90E8\u7F72\uFF09\u3002","team.errName":"\u8BF7\u586B\u56E2\u961F\u540D\u79F0","team.creating":"\u521B\u5EFA\u4E2D\u2026","team.created":"\u5DF2\u521B\u5EFA","team.createFail":"\u521B\u5EFA\u5931\u8D25\uFF1A{error}","team.errHubCode":"\u8BF7\u586B Hub \u5730\u5740\u548C\u9080\u8BF7\u7801\u3002","team.joining":"\u52A0\u5165\u4E2D\u2026","team.joined":"\u5DF2\u52A0\u5165\u300C{name}\u300D\uFF0C\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u67E5\u770B\u3002","team.joinErrSelf":"\u8FD9\u662F\u4F60\u81EA\u5DF1\u7684\u90E8\u7F72\uFF0C\u4E0D\u80FD\u52A0\u5165\u81EA\u5DF1\uFF08\u9080\u8BF7\u7801\u8981\u53D1\u7ED9\u522B\u7684\u90E8\u7F72\u7684\u4EBA\u7528\uFF09","team.joinErrAlready":"\u4F60\u7684\u90E8\u7F72\u5DF2\u7ECF\u52A0\u5165\u8FC7\u8FD9\u4E2A\u56E2\u961F\u4E86","team.joinErrUnreachable":"\u8FDE\u4E0D\u4E0A\u5BF9\u65B9 Hub\uFF08\u68C0\u67E5\u5730\u5740/\u7F51\u7EDC\uFF09","team.joinErrTimeout":"\u5BF9\u65B9 Hub \u54CD\u5E94\u8D85\u65F6","team.joinErrGeneric":"\u52A0\u5165\u5931\u8D25\uFF1A{error}","team.identifying":"\u8BC6\u522B\u4E2D\u2026","team.bound2":"\u5DF2\u7ED1\u5B9A\uFF1A{name}","team.multiCandidate":"\u8BC6\u522B\u5230\u591A\u4E2A\u5019\u9009\uFF0C\u70B9\u4F60\u81EA\u5DF1\uFF1A","team.binding":"\u7ED1\u5B9A\u4E2D\u2026","team.bindFail":"\u7ED1\u5B9A\u5931\u8D25\uFF1A{error}","team.noCandidates":"\u6CA1\u8BC6\u522B\u5230\u8EAB\u4EFD\uFF1A\u8BF7\u786E\u8BA4\u673A\u5668\u4EBA\u914D\u7F6E\u4E86 allowedUsers\uFF08\u5141\u8BB8\u4F7F\u7528\u8005\uFF09\uFF0C\u4E14\u673A\u5668\u4EBA\u6709\u901A\u8BAF\u5F55\u6743\u9650\u3002","team.removeMemberConfirm":"\u628A\u300C{name}\u300D\u79FB\u51FA\u8FD9\u4E2A\u56E2\u961F\uFF1F\u5B83\u7684\u673A\u5668\u4EBA\u5C06\u4ECE\u672C\u56E2\u961F\u82B1\u540D\u518C\u6D88\u5931\uFF08\u4E0D\u5F71\u54CD\u5BF9\u65B9\u81EA\u5DF1\u7684\u90E8\u7F72\uFF09\u3002","team.creatingGroup":"\u5EFA\u7FA4\u4E2D\u2026","team.defaultGroupName":"\u534F\u4F5C\u7FA4","team.errPickBot":"\u8BF7\u5148\u52FE\u9009\u81F3\u5C11\u4E00\u4E2A\u673A\u5668\u4EBA","sessions.closeBulkConfirm":"\u5173\u95ED\u9009\u4E2D\u7684 {count} \u4E2A\u4F1A\u8BDD\uFF1F","sessions.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u4F1A\u8BDD\u3002","sessions.viewMode":"\u4F1A\u8BDD\u89C6\u56FE","sessions.viewKanban":"\u770B\u677F","sessions.viewBoard":"\u72B6\u6001\u677F","sessions.viewTable":"\u8868\u683C","sessions.selectSession":"\u9009\u62E9\u4F1A\u8BDD","sessions.board.needsYou":"\u9700\u8981\u4F60","sessions.board.needsYouHint":"\u7B49\u5F85\u4ED3\u5E93\u3001TUI \u9009\u62E9\u6216\u989D\u5EA6\u5904\u7406","sessions.board.starting":"\u542F\u52A8\u4E2D","sessions.board.startingHint":"CLI \u6B63\u5728\u521B\u5EFA\u6216\u6062\u590D","sessions.board.working":"\u5E72\u6D3B\u4E2D","sessions.board.workingHint":"\u6B63\u5728\u8F93\u51FA\u3001\u5206\u6790\u6216\u6267\u884C\u5DE5\u5177","sessions.board.idle":"\u7A7A\u95F2","sessions.board.idleHint":"\u53EF\u7EE7\u7EED\u5BF9\u8BDD\u6216\u63A5\u65B0\u4EFB\u52A1","sessions.board.emptyColumn":"\u6682\u65E0\u4F1A\u8BDD","sessions.board.signalRepo":"\u5F85\u9009\u4ED3\u5E93","sessions.board.signalPrompt":"\u7B49\u5F85 TUI \u9009\u62E9","sessions.board.signalLimited":"\u989D\u5EA6\u53D7\u9650","sessions.board.signalAgent":"\u9700\u8981\u4EBA\u5DE5\u4ECB\u5165","sessions.board.waiting":"\u7B49\u5F85","sessions.board.dragHint":"\u62D6\u52A8\u5217\u5934\u8C03\u6574\u5217\u987A\u5E8F","sessions.board.moveLeft":"\u5DE6\u79FB\u6B64\u5217","sessions.board.moveRight":"\u53F3\u79FB\u6B64\u5217","sessions.kanban.backlog":"\u5F85\u529E\u6C60","sessions.kanban.todo":"\u5F85\u529E","sessions.kanban.inProgress":"\u8FDB\u884C\u4E2D","sessions.kanban.inReview":"\u5F85\u786E\u8BA4","sessions.kanban.done":"\u5DF2\u5B8C\u6210","sessions.kanban.updated":"\u66F4\u65B0\u4E8E {time}","sessions.kanban.moreHidden":"\u8FD8\u6709 {count} \u4E2A\u672A\u663E\u793A","sessions.kanban.openTab":"\u65B0\u6807\u7B7E\u9875\u6253\u5F00","sessions.kanban.openFeishu":"\u6253\u5F00\u98DE\u4E66","sessions.kanban.terminalLoading":"\u6B63\u5728\u6253\u5F00\u7EC8\u7AEF\u2026","sessions.kanban.rename":"\u91CD\u547D\u540D\uFF08\u53CC\u51FB\u6807\u9898\u4E5F\u53EF\uFF09","sessions.kanban.renameFail":"\u91CD\u547D\u540D\u5931\u8D25","sessions.kanban.moveFail":"\u79FB\u52A8\u5931\u8D25","sessions.kanban.groupBy":"\u5206\u7EC4\u7EF4\u5EA6","sessions.kanban.groupFlow":"\u5DE5\u4F5C\u6D41","sessions.kanban.groupTeam":"\u56E2\u961F","sessions.kanban.groupBot":"\u673A\u5668\u4EBA","sessions.kanban.teamLoading":"\u6B63\u5728\u52A0\u8F7D\u56E2\u961F\u2026","sessions.kanban.noTeam":"\u6682\u65E0\u56E2\u961F","sessions.kanban.teamScope":"{chats} \u4E2A\u534F\u4F5C\u7FA4 \xB7 {sessions} \u4E2A\u4F1A\u8BDD","sessions.kanban.remoteHint":"\u6765\u81EA {name} \u90E8\u7F72\u7684\u4F1A\u8BDD\uFF08\u5FEB\u7167\uFF0C\u7EC8\u7AEF/\u5386\u53F2\u5728\u5BF9\u65B9\u673A\u5668\u4E0A\uFF09","sessions.kanban.clusterDragHint":"\u62D6\u52A8\u6807\u9898\u6574\u7EC4\u79FB\u52A8","sessions.history.title":"\u4F1A\u8BDD\u5386\u53F2","sessions.history.loading":"\u6B63\u5728\u62C9\u53D6\u98DE\u4E66\u6D88\u606F\u2026","sessions.history.fail":"\u5386\u53F2\u62C9\u53D6\u5931\u8D25","sessions.history.empty":"\u6CA1\u6709\u6D88\u606F","sessions.history.user":"\u7528\u6237","sessions.history.owner":"\u521B\u5EFA\u8005","sessions.history.staleHint":"dashboard \u6216 daemon \u8FDB\u7A0B\u53EF\u80FD\u8FD8\u5728\u8DD1\u65E7\u7248\u672C\uFF0Cbotmux restart \u540E\u91CD\u8BD5","groups.title":"\u7FA4\u7EC4\u4E0E Bot","groups.subtitle":"\u67E5\u770B chat x bot \u8986\u76D6\u77E9\u9635\uFF0C\u7BA1\u7406\u62C9\u7FA4\u3001oncall\u3001\u9000\u7FA4\u548C\u89E3\u6563\u3002","groups.search":"\u641C\u7D22\u7FA4\u540D / ID / owner","groups.missingOnly":"\u4EC5\u7F3A bot","groups.refresh":"\u5237\u65B0","groups.create":"\u65B0\u5EFA\u7FA4","groups.chat":"\u7FA4\u804A","groups.actions":"\u64CD\u4F5C","groups.addBots":"\u6DFB\u52A0 bot","groups.manage":"\u7BA1\u7406","groups.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u7FA4\u804A\u3002","groups.createTitle":"\u65B0\u5EFA\u7FA4\u804A","groups.createHelp":"\u9009\u62E9\u8981\u9080\u8BF7\u7684 bot\u3002dashboard \u4F1A\u81EA\u52A8\u9009\u62E9\u5728\u7EBF daemon \u4F5C\u4E3A\u521B\u5EFA\u8005\u3002","groups.name":"\u7FA4\u540D","groups.namePlaceholder":"\u4F8B\u5982 AI ChangeLog","groups.bindDir":"\u7ED1\u5B9A\u76EE\u5F55","groups.bindDirHelp":"\u65B0\u8BDD\u9898\u76F4\u63A5\u7528\u8BE5\u76EE\u5F55\u542F\u52A8 CLI\uFF0C\u8DF3\u8FC7 repo \u9009\u62E9\u3002","groups.botPicker":"Bot","groups.createSubmit":"\u521B\u5EFA","groups.cancel":"\u53D6\u6D88","groups.successTitle":"\u7FA4\u521B\u5EFA\u6210\u529F","groups.openGroup":"\u6253\u5F00\u65B0\u7FA4","groups.manageTitle":"\u7BA1\u7406 {name}","groups.owner":"\u7FA4\u4E3B","groups.oncall":"Oncall \u6A21\u5F0F","groups.oncallHelp":"\u5F00\u542F\u540E\uFF0C\u7FA4\u5185\u6210\u5458\u53EF @ \u673A\u5668\u4EBA\uFF1B\u65B0\u8BDD\u9898\u76F4\u63A5\u4F7F\u7528\u7ED1\u5B9A\u76EE\u5F55\u3002","groups.leaveTitle":"\u9009\u62E9\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.leaveSelected":"\u9009\u4E2D\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.disband":"\u89E3\u6563\u7FA4\u804A","groups.dangerHint":"\u89E3\u6563\u4EC5\u5F53\u5728\u7FA4\u673A\u5668\u4EBA\u662F\u7FA4\u4E3B\u65F6\u624D\u4F1A\u6210\u529F\uFF0C\u5426\u5219\u5EFA\u8BAE\u4F7F\u7528\u9000\u51FA\u7FA4\u804A\u3002","groups.save":"\u4FDD\u5B58","groups.needWorkingDir":"\u8BF7\u586B\u5DE5\u4F5C\u76EE\u5F55","groups.noBotsOnline":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u8BF7\u5148\u91CD\u542F daemon\u3002","schedules.title":"\u5B9A\u65F6\u4EFB\u52A1","schedules.subtitle":"\u8DE8 daemon \u67E5\u770B\u3001\u6682\u505C\u3001\u6062\u590D\u548C\u7ACB\u5373\u89E6\u53D1\u5B9A\u65F6\u4EFB\u52A1\u3002","schedules.search":"\u641C\u7D22\u540D\u79F0 / prompt / \u5DE5\u4F5C\u76EE\u5F55","schedules.anyKind":"\u5168\u90E8\u7C7B\u578B","schedules.enabledOnly":"\u4EC5\u542F\u7528","schedules.name":"\u540D\u79F0","schedules.bot":"bot","schedules.schedule":"\u89C4\u5219","schedules.next":"\u4E0B\u6B21","schedules.last":"\u4E0A\u6B21","schedules.repeat":"\u91CD\u590D","schedules.enabled":"\u542F\u7528","schedules.actions":"\u64CD\u4F5C","schedules.runNow":"\u7ACB\u5373\u8FD0\u884C","schedules.pause":"\u6682\u505C","schedules.resume":"\u6062\u590D","schedules.delivery":"\u6295\u9012","schedules.deliveryOrigin":"\u539F\u8BDD\u9898","schedules.deliveryNewTopic":"\u6BCF\u6B21\u65B0\u8BDD\u9898","schedules.deliveryLocal":"\u4EC5\u8BB0\u5F55","schedules.useNewTopic":"\u6539\u4E3A\u6BCF\u6B21\u65B0\u8BDD\u9898","schedules.useOrigin":"\u6539\u4E3A\u539F\u8BDD\u9898","schedules.empty":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","settings.title":"\u5168\u5C40\u8BBE\u7F6E","settings.subtitle":"\u7BA1\u7406\u672C\u673A botmux dashboard \u4E0E\u6240\u6709 bot \u5171\u4EAB\u7684\u5168\u5C40\u884C\u4E3A\u3002","settings.loading":"\u6B63\u5728\u52A0\u8F7D\u8BBE\u7F6E\u2026","settings.loadFailed":"\u8BBE\u7F6E\u52A0\u8F7D\u5931\u8D25","settings.readOnlyVisitor":"\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u4FEE\u6539\u8BBE\u7F6E\u9700\u8981\u6388\u6743\u94FE\u63A5\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09","settings.sectionAccess":"\u8BBF\u95EE\u6743\u9650","settings.publicReadOnly":"\u5141\u8BB8\u65E0 token \u53EA\u8BFB\u8BBF\u95EE dashboard","settings.publicReadOnlyHelp":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 token \u7684\u8BBF\u95EE\u8005\u53EF\u4EE5\u67E5\u770B dashboard\u3001\u4F1A\u8BDD\u3001\u5B9A\u65F6\u4EFB\u52A1\u548C SSE\uFF1B\u5173\u95ED\u3001\u6682\u505C\u3001\u5BA1\u6279\u7B49\u5199\u64CD\u4F5C\u4ECD\u5FC5\u987B\u901A\u8FC7 token \u9274\u6743\u3002\u654F\u611F\u7EC8\u7AEF\u539F\u59CB\u65E5\u5FD7\u59CB\u7EC8\u9700\u8981 token\u3002","settings.sectionCards":"\u98DE\u4E66\u5361\u7247","settings.openTerminalInFeishu":"\u6D41\u5F0F\u5361\u7247\u7EC8\u7AEF\u6309\u94AE\u5728\u98DE\u4E66\u4FA7\u680F\u6253\u5F00","settings.openTerminalInFeishuHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF1A\u7EC8\u7AEF\u6309\u94AE\u76F4\u63A5\u6253\u5F00 Web Terminal URL\u3002\u5F00\u542F\u540E\u4F7F\u7528\u98DE\u4E66 web_url/open \u5305\u88C5\uFF0C\u5728\u98DE\u4E66 PC \u4FA7\u680F\u91CC\u6253\u5F00\uFF1B\u5199\u6743\u9650\u4ECD\u7531\u7EC8\u7AEF token \u63A7\u5236\u3002","settings.sectionRepoPicker":"\u4ED3\u5E93\u9009\u62E9","settings.repoPickerMode":"\u4ED3\u5E93\u9009\u62E9\u5361\u6A21\u5F0F","settings.repoPickerModeAll":"\u4ED3\u5E93 + worktree","settings.repoPickerModeRepos":"\u4EC5\u4E3B\u4ED3\u5E93","settings.repoPickerModeHelp":"\u9ED8\u8BA4\u663E\u793A\u4ED3\u5E93\u548C linked worktree\u3002\u9009\u62E9\u300C\u4EC5\u4E3B\u4ED3\u5E93\u300D\u540E\uFF0C\u521D\u59CB\u5316\u548C\u88F8 /repo \u7684\u9009\u62E9\u5361\u53EA\u5217\u4E3B\u4ED3\u5E93\uFF1B\u663E\u5F0F /repo /abs/path/to/worktree \u4ECD\u53EF\u76F4\u8FBE worktree\u3002","settings.saving":"\u4FDD\u5B58\u4E2D\u2026","settings.saved":"\u5DF2\u4FDD\u5B58","settings.saveFailed":"\u4FDD\u5B58\u5931\u8D25","settings.sectionMaintenance":"\u81EA\u52A8\u7EF4\u62A4","settings.autoUpdate":"\u81EA\u52A8\u66F4\u65B0","settings.autoUpdateHelp":"\u9ED8\u8BA4\u5173\u95ED\u3002\u5230\u70B9\u6267\u884C npm install -g botmux@latest \u5B89\u88C5\u6700\u65B0\u7248\u672C\uFF08\u53EA\u4E0B\u8F7D\u5B89\u88C5\u3001\u672C\u8EAB\u4E0D\u91CD\u542F\uFF09\u3002\u4EC5 npm \u5168\u5C40\u5B89\u88C5\u53EF\u7528\u3002","settings.autoRestart":"\u81EA\u52A8\u91CD\u542F","settings.autoRestartHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF0C\u9700\u5148\u5F00\u542F\u81EA\u52A8\u66F4\u65B0\u3002\u81EA\u52A8\u66F4\u65B0\u88C5\u5230\u65B0\u7248\u672C\u540E\uFF0C\u82E5\u6CA1\u6709\u8FDB\u884C\u4E2D\u7684\u4F1A\u8BDD\u5219\u81EA\u52A8\u91CD\u542F\u4EE5\u751F\u6548\uFF08\u649E\u4E0A\u5FD9\u788C\u4F1A\u8BDD\u5219\u8DF3\u5230\u6B21\u65E5\uFF09\u3002","settings.autoUpdateLocalDev":"\u5F53\u524D\u4E3A\u672C\u5730\u5F00\u53D1\u5B89\u88C5\uFF08\u4ECE\u6E90\u7801\u8FD0\u884C\uFF09\uFF0C\u81EA\u52A8\u66F4\u65B0\u4E0D\u53EF\u7528\u3002","settings.maintenanceTime":"\u65F6\u95F4","botDefaults.title":"\u6570\u5B57\u5458\u5DE5\u6863\u6848","botDefaults.subtitle":"\u6BCF\u4F4D\u5458\u5DE5\u7684\u9ED8\u8BA4\u884C\u4E3A\uFF1Aoncall\u3001\u4E3B\u52A8\u5F00\u5DE5\u3001\u4EBA\u8BBE\u89D2\u8272\u3001\u5361\u7247\u4E0E\u6388\u6743\u3002","botDefaults.metaOnline":"\u5728\u7EBF \xB7 daemon \u6B63\u5E38","botDefaults.search":"\u641C\u7D22 bot \u540D / app id","botDefaults.refresh":"\u5237\u65B0","botDefaults.sectionOncall":"\u65B0\u7FA4 Oncall","botDefaults.sectionBrand":"\u5361\u7247\u7B7E\u540D","botDefaults.warning":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 oncall binding \u7684\u7FA4\u4F1A\u5728\u4E0B\u6B21\u5F00\u65B0\u8BDD\u9898\u65F6\u81EA\u52A8\u7ED1\u5B9A\u5230\u8BE5\u76EE\u5F55\uFF1B\u624B\u52A8\u7ED1\u5B9A\u6216\u624B\u52A8\u89E3\u7ED1\u8FC7\u7684\u7FA4\u4E0D\u4F1A\u88AB\u8986\u76D6\u3002","botDefaults.empty":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u5148 botmux restart \u8BA9 daemon \u4E0A\u7EBF\u3002","botDefaults.defaultOncall":"\u9ED8\u8BA4\u8FDB\u5165 oncall \u6A21\u5F0F","botDefaults.defaultOncallHelp":"\u6240\u6709\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8\u7ED1\u5B9A","botDefaults.workingDir":"\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55","botDefaults.lastEnabled":"\u4E0A\u6B21\u542F\u7528\u65F6\u95F4","botDefaults.autobound":"\u5DF2\u81EA\u52A8\u7ED1\u5B9A {count} \u4E2A\u7FA4","botDefaults.save":"\u4FDD\u5B58","botDefaults.required":"\u5F00\u542F\u65F6\u5FC5\u987B\u586B\u5DE5\u4F5C\u76EE\u5F55","botDefaults.brandLabel":"\u4E2A\u6027\u7B7E\u540D\uFF08\u5361\u7247\u9875\u811A\uFF09","botDefaults.brandLabelHelp":"\u8BE5 bot \u53D1\u51FA\u7684\u5361\u7247\u9875\u811A\u7B7E\u540D\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u4E0D\u663E\u793A\uFF1B\u586B\u5199\uFF1D\u81EA\u5B9A\u4E49\uFF08\u652F\u6301 markdown\uFF0C\u5982 [Acme](https://\u2026)\uFF09\uFF1B\u6062\u590D\u9ED8\u8BA4\uFF1D\u663E\u793A botmux\u3002","botDefaults.brandLabelPlaceholder":"\u9ED8\u8BA4\uFF1Abotmux\uFF08\u7559\u7A7A\u5219\u4E0D\u663E\u793A\uFF09","botDefaults.sectionSandbox":"\u6587\u4EF6\u6C99\u76D2\uFF08oncall\uFF09","botDefaults.sandboxToggle":"\u5F00\u542F\u6587\u4EF6\u6C99\u76D2","botDefaults.sandboxHelp":"\u5F00\u542F\u540E\uFF0C\u8BE5 bot \u7684\u6BCF\u4E2A\u4F1A\u8BDD\u90FD\u8DD1\u5728\u6309\u4F1A\u8BDD\u9694\u79BB\u7684\u6C99\u76D2\u91CC\uFF1A\u53EA\u770B\u5F97\u5230\u4E00\u4EFD\u9879\u76EE\u526F\u672C\uFF0C\u78B0\u4E0D\u5230\u4F60\u78C1\u76D8\u4E0A\u7684\u771F\u5B9E\u6587\u4EF6\u3001\u5BC6\u94A5\u3001\u522B\u7684\u4F1A\u8BDD\u6570\u636E\u3002\u9002\u5408\u628A\u673A\u5668\u4EBA\u5206\u4EAB\u7ED9\u534A\u53D7\u4FE1\u4EFB\u7684\u4EBA\uFF08oncall\uFF09\u3002\u4EC5 Linux \u751F\u6548\uFF0C\u4E0B\u4E2A\u65B0\u4F1A\u8BDD\u8D77\u6548\u3002","botDefaults.sandboxSaved":"\u5DF2\u4FDD\u5B58\uFF08\u4E0B\u4E2A\u65B0\u4F1A\u8BDD\u751F\u6548\uFF09","botDefaults.brandSave":"\u4FDD\u5B58\u7B7E\u540D","botDefaults.brandReset":"\u6062\u590D\u9ED8\u8BA4","botDefaults.brandStateDefault":"\u5F53\u524D\uFF1A\u9ED8\u8BA4 botmux","botDefaults.brandStateOff":"\u5F53\u524D\uFF1A\u5DF2\u5173\u95ED","botDefaults.brandStateCustom":"\u5F53\u524D\uFF1A\u81EA\u5B9A\u4E49","botDefaults.sectionCard":"\u5361\u7247\u884C\u4E3A","botDefaults.disableStreaming":"\u5173\u95ED\u98DE\u4E66\u6D41\u5F0F\u5361\u7247","botDefaults.disableStreamingHelp":"\u4E0D\u518D\u53D1\u5B9E\u65F6\u5237\u65B0\u7684\u4F1A\u8BDD\u72B6\u6001\u5361\uFF08\u542B\u300C\u6253\u5F00\u7EC8\u7AEF\u300D\u5165\u53E3\uFF09\uFF1B\u4EFB\u52A1\u6700\u7EC8\u7ED3\u679C\u4ECD\u901A\u8FC7\u6D88\u606F\u9001\u8FBE\u3002\u9002\u5408\u5ACC\u6D41\u5F0F\u5361\u7247\u70E6\u7684\u573A\u666F\u3002","botDefaults.writableLink":"\u5361\u7247\u4E0A\u76F4\u63A5\u7ED9\u53EF\u64CD\u4F5C\uFF08\u53EF\u5199\uFF09\u7EC8\u7AEF\u94FE\u63A5","botDefaults.writableLinkHelp":"\u26A0\uFE0F \u5728\u6D41\u5F0F\u5361\u7247\u6B63\u6587\u76F4\u63A5\u8D34\u51FA\u53EF\u5199\u7EC8\u7AEF\u94FE\u63A5\uFF0C\u7FA4\u5185\u4EFB\u4F55\u4EBA\u90FD\u80FD\u70B9\u5F00\u5E76\u64CD\u63A7\u7EC8\u7AEF\u3002\u4E0D\u52FE\uFF1D\u4FDD\u6301\u73B0\u72B6\uFF08\u8D70\u300C\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u300D\u6309\u94AE\u79C1\u804A\u53D1\u7ED9\u70B9\u51FB\u8005\uFF09\u3002","botDefaults.writableLinkMoot":"\u5DF2\u5173\u95ED\u6D41\u5F0F\u5361\u7247","botDefaults.privateCard":"/card \u53D1\u79C1\u5BC6\u5361\u7247\uFF08\u4EC5\u6388\u6743\u4EBA\u53EF\u89C1\uFF09","botDefaults.privateCardHelp":"\u5F00\u542F\u540E /card \u6539\u7528\u300C\u4EC5\u7279\u5B9A\u4EBA\u53EF\u89C1\u300D\u7684\u4E34\u65F6\u5361\u7247\uFF1A\u53EA\u53D1\u7ED9 owner\uFF08allowedUsers\uFF09\uFF0C/grant \u6388\u6743\u5BF9\u8BDD\u7684\u4EBA\u548C\u7FA4\u91CC\u5176\u4ED6\u4EBA\u90FD\u770B\u4E0D\u5230\u3002\u4EE3\u4EF7\uFF1A\u662F\u9759\u6001\u5FEB\u7167\u3001\u4E0D\u4F1A\u5B9E\u65F6\u5237\u65B0\uFF1B\u4E14\u4EC5\u666E\u901A\u7FA4\u53EF\u7528\uFF08\u8BDD\u9898\u7FA4 / \u5355\u804A\u4F1A\u5931\u8D25\uFF0C\u4E0D\u964D\u7EA7\uFF09\u3002\u53EA\u5F71\u54CD /card \u547D\u4EE4\uFF0C\u81EA\u52A8\u6D41\u5F0F\u5361\u4E0D\u53D8\u3002","botDefaults.cardPrefSaved":"\u5DF2\u4FDD\u5B58","botDefaults.sectionRole":"\u9ED8\u8BA4\u89D2\u8272","botDefaults.roleHelp":"\u8BE5 bot \u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF08\u8DE8\u7FA4\u751F\u6548\uFF09\uFF0C\u4F1A\u6CE8\u5165\u5230\u8BE5 bot \u5728\u5404\u7FA4\u7684\u4F1A\u8BDD\u91CC\uFF1B\u5355\u4E2A\u7FA4\u53EF\u5728\u300C\u89D2\u8272\u300D\u9875\u5355\u72EC\u8986\u76D6\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u5220\u9664\u3002","botDefaults.rolePlaceholder":"\u4F8B\u5982\uFF1A\u4F60\u662F\u540E\u7AEF\u6392\u969C\u52A9\u624B\uFF0C\u56DE\u7B54\u7B80\u6D01\u3001\u4F18\u5148\u7ED9\u53EF\u6267\u884C\u547D\u4EE4\u2026","botDefaults.roleSave":"\u4FDD\u5B58\u89D2\u8272","botDefaults.roleDelete":"\u5220\u9664","botDefaults.roleSaved":"\u5DF2\u4FDD\u5B58","botDefaults.roleDeleted":"\u5DF2\u5220\u9664","botDefaults.roleLoadErr":"\u89D2\u8272\u52A0\u8F7D\u5931\u8D25","botDefaults.sectionAutoStart":"\u4E3B\u52A8\u5F00\u5DE5","botDefaults.autoStartJoin":"\u88AB\u62C9\u8FDB\u65B0\u7FA4\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartJoinHelp":"\u5F00\u542F\u540E\uFF0C\u673A\u5668\u4EBA\u4E00\u88AB\u62C9\u8FDB\u65B0\u7FA4\uFF08\u7FA4\u91CC\u6709\u6388\u6743\u7528\u6237 allowedUsers \u65F6\uFF09\u5C31\u81EA\u52A8\u5F00\u4E00\u4E2A\u4F1A\u8BDD\u5F00\u59CB\u5DE5\u4F5C\uFF0C\u65E0\u9700 @\u3002\u5728\u673A\u5668\u4EBA\u7684\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55\u542F\u52A8\uFF1B\u672A\u914D\u7F6E\u9ED8\u8BA4\u76EE\u5F55\u65F6\u5148\u5F39\u4ED3\u5E93\u9009\u62E9\u5361\u8BA9\u4F60\u9009\u3002\u524D\u63D0\uFF1A\u9700\u5728\u98DE\u4E66\u5F00\u653E\u5E73\u53F0\u4E3A\u672C\u5E94\u7528\u8BA2\u9605\u300C\u673A\u5668\u4EBA\u8FDB\u7FA4\u300D\u4E8B\u4EF6 im.chat.member.bot.added_v1\uFF0C\u5E76\u5F00\u901A\u7FA4\u6210\u5458\u8BFB\u53D6\u6743\u9650\u3002","botDefaults.autoStartJoinPrompt":"\u5165\u7FA4\u9996\u8F6E prompt\uFF08\u53EF\u9009\uFF09","botDefaults.autoStartJoinPromptPlaceholder":"\u586B\u4E86\uFF1D\u4F5C\u4E3A\u5165\u7FA4\u540E\u7684\u7B2C\u4E00\u6761\u4EFB\u52A1\uFF1B\u7559\u7A7A\uFF1D\u673A\u5668\u4EBA\u81EA\u5DF1\u770B\u7FA4\u91CC\u4FE1\u606F\u51B3\u5B9A\u505A\u4EC0\u4E48","botDefaults.autoStartJoinPromptSave":"\u4FDD\u5B58 prompt","botDefaults.autoStartTopic":"\u8BDD\u9898\u7FA4\u65B0\u8BDD\u9898\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartTopicHelp":"\u5F00\u542F\u540E\uFF0C\u5728\u8BDD\u9898\u7FA4\u91CC\u6BCF\u5F53\u6709\u4EBA\u65B0\u5F00\u4E00\u4E2A\u8BDD\u9898\uFF0C\u673A\u5668\u4EBA\u5C31\u4F1A\u81EA\u52A8\u63A5\u5165\u8BE5\u8BDD\u9898\u3001\u628A\u9996\u6761\u6D88\u606F\u5F53\u4F5C\u4EFB\u52A1\u5F00\u59CB\u5904\u7406\uFF0C\u65E0\u9700 @\u3002\u4EC5\u5BF9\u8BDD\u9898\u7FA4\u751F\u6548\uFF0C\u666E\u901A\u7FA4\u4E0D\u53D7\u5F71\u54CD\u3002","botDefaults.sectionSessionMode":"\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.p2pMode":"\u79C1\u804A\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.p2pThread":"thread\uFF08\u6BCF\u6761 DM \u72EC\u7ACB\u4F1A\u8BDD\uFF09","botDefaults.p2pChat":"chat\uFF08\u6241\u5E73\u8FDE\u7EED\u5355\u804A\u4F1A\u8BDD\uFF09","botDefaults.p2pHelp":"\u79C1\u804A\uFF081:1 DM\uFF09\u7684\u4F1A\u8BDD\u65B9\u5F0F\uFF1Athread = \u6BCF\u6761\u9876\u5C42\u6D88\u606F\u5404\u81EA\u8D77\u72EC\u7ACB\u4F1A\u8BDD\uFF08\u907F\u514D\u628A\u5BF9\u8BDD\u5806\u8FDB\u540C\u4E00\u4E2A CLI \u8FDB\u7A0B\uFF09\uFF1Bchat = \u6574\u6BB5 DM \u5171\u7528\u4E00\u4E2A\u8FDE\u7EED\u4F1A\u8BDD\u3001\u5171\u4EAB\u4E0A\u4E0B\u6587\uFF08\u7C7B Hermes\uFF09\u3002\u6539\u540E\u7ACB\u5373\u751F\u6548\u3002","botDefaults.regularGroupMode":"\u666E\u901A\u7FA4\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.regularGroupModeChat":"chat\uFF08\u6241\u5E73\u8FDE\u7EED\u5355\u804A\u4F1A\u8BDD\uFF0C\u9ED8\u8BA4\uFF09","botDefaults.regularGroupModeNewTopic":"new-topic\uFF08\u6BCF\u6761\u9876\u5C42 @ \u5404\u5F00\u72EC\u7ACB\u8BDD\u9898\u4E0E\u4F1A\u8BDD\uFF09","botDefaults.regularGroupModeShared":"shared\uFF08\u8BDD\u9898\u6A21\u5F0F\u4F46\u590D\u7528\u540C\u4E00\u4E2A session\uFF09","botDefaults.regularGroupModeHelp":"\u666E\u901A\u7FA4\uFF08\u975E\u8BDD\u9898\u7FA4\uFF09\u91CC @ \u8BE5 bot \u7684\u65B0\u9876\u5C42\u6D88\u606F\u600E\u4E48\u5F00\u4F1A\u8BDD\uFF1Achat = \u6574\u7FA4\u5171\u7528\u4E00\u4E2A\u8FDE\u7EED\u4F1A\u8BDD\uFF08\u9ED8\u8BA4\uFF09\uFF1Bnew-topic = \u6BCF\u6761\u9876\u5C42 @ \u5728\u539F\u6D88\u606F\u4E0B\u5F00\u72EC\u7ACB\u8BDD\u9898\u3001\u5404\u81EA\u72EC\u7ACB\u4F1A\u8BDD\uFF1Bshared = \u8BDD\u9898\u6A21\u5F0F\u4F46\u590D\u7528\u540C\u4E00\u4E2A session\uFF08\u56DE\u590D\u843D\u5728\u8BDD\u9898\u91CC\u3001\u4F46\u5171\u7528\u672C\u7FA4\u4F1A\u8BDD\u4E0E\u4E0A\u4E0B\u6587\uFF09\u3002\u8FD9\u662F per-bot \u9ED8\u8BA4\uFF0C\u5177\u4F53\u67D0\u4E2A\u7FA4\u53EF\u7528 /reply-mode \u5355\u72EC\u8986\u76D6\u3002\u6539\u540E\u7ACB\u5373\u751F\u6548\u3002","botDefaults.mentionMode":"\u7FA4\u804A @ \u7B56\u7565","botDefaults.mentionModeAlways":"\u90FD\u9700\u8981 @\uFF08\u9ED8\u8BA4\uFF09","botDefaults.mentionModeTopic":"\u4EC5\u8BDD\u9898\u5185\u4E0D\u9700\u8981 @","botDefaults.mentionModeNever":"\u6240\u6709\u6D88\u606F\u90FD\u4E0D\u9700\u8981 @","botDefaults.mentionModeHelp":"\u8BE5 bot \u5168\u5C40\u751F\u6548\uFF0C\u51B3\u5B9A\u7FA4\u91CC\u8981\u4E0D\u8981 @ \u624D\u56DE\uFF1A\u300C\u90FD\u9700\u8981 @\u300D= \u4EFB\u4F55\u6D88\u606F\u90FD\u5F97 @\uFF08\u9ED8\u8BA4\uFF0C\u6700\u5B89\u5168\uFF1B\u591A\u4EBA\u7FA4\u91CC\u8BDD\u9898\u5185\u4E5F\u8981 @\uFF09\uFF1B\u300C\u4EC5\u8BDD\u9898\u5185\u4E0D\u9700\u8981 @\u300D= \u8D77\u65B0\u5BF9\u8BDD / \u9876\u5C42\u4ECD\u8981 @\uFF0C\u4F46\u5728\u8BE5 bot \u5DF2\u5F00\u7684\u4EFB\u4F55\u8BDD\u9898\u91CC\uFF08new-topic / shared / \u8BDD\u9898\u7FA4\uFF09\u540E\u7EED\u6D88\u606F\u514D @ \u7EED\u804A\uFF1B\u300C\u6240\u6709\u6D88\u606F\u90FD\u4E0D\u9700\u8981 @\u300D= \u8BE5 bot \u6709\u5BF9\u8BDD\u6743\u9650\u7684\u7FA4\u91CC\u975E @ \u6D88\u606F\u4E5F\u56DE\uFF08\u542B\u5168\u65B0\u6D88\u606F\u51B7\u542F\u52A8\uFF0C\u4EC5\u9002\u5408\u4E13\u7528 / \u503C\u73ED\u5C0F\u7FA4\uFF0C\u591A\u4EBA\u7FA4\u91CC\u4F1A\u89C1\u6D88\u606F\u5C31\u56DE\uFF09\u3002\u6CE8\uFF1A\u7FA4\u91CC\u53EA\u6709\u4F60\u548C\u8BE5 bot\uFF081 \u5BF9 1\uFF09\u65F6\u4E00\u76F4\u514D @\uFF0C\u4E0E\u672C\u8BBE\u7F6E\u65E0\u5173\u3002","botDefaults.docSubscribeMode":"\u6587\u6863\u8BA2\u9605\u89E6\u53D1\u8303\u56F4\uFF08\u9ED8\u8BA4\uFF09","botDefaults.docSubscribeModeMention":"\u4EC5\u8BC4\u8BBA @ \u6211\u624D\u89E6\u53D1","botDefaults.docSubscribeModeAll":"\u6240\u6709\u65B0\u8BC4\u8BBA\u90FD\u89E6\u53D1","botDefaults.docSubscribeModeHelp":"\u7528 /subscribe-lark-doc \u8BA2\u9605\u98DE\u4E66\u6587\u6863\u540E\uFF0C\u6587\u6863\u8BC4\u8BBA\u4F1A\u5582\u8FDB\u4F1A\u8BDD\u3001bot \u56DE\u590D\u53D1\u56DE\u8BC4\u8BBA\u3002\u8FD9\u91CC\u8BBE\u65B0\u8BA2\u9605\u7684\u9ED8\u8BA4\u89E6\u53D1\u8303\u56F4\uFF1A\u300C\u4EC5\u8BC4\u8BBA @ \u6211\u300D\u6700\u5B89\u5168\uFF08\u9632\u5237\u5C4F\uFF09\uFF1B\u300C\u6240\u6709\u65B0\u8BC4\u8BBA\u300D\u9002\u5408\u4E13\u7528\u6587\u6863\u3002","botDefaults.sectionGrant":"\u6388\u6743\u4E0E\u989D\u5EA6","botDefaults.restrictGrant":"\u9650\u5236\u88AB\u6388\u6743\u4EBA\u53EA\u80FD\u7EAF\u5BF9\u8BDD","botDefaults.restrictGrantHelp":"\u5F00\u542F\u540E\uFF0C\u88AB /grant \u6388\u6743\u7684\u4EBA\uFF08owner \u81EA\u5DF1\u4E0D\u53D7\u9650\uFF09\u53EA\u80FD\u53D1\u666E\u901A\u5BF9\u8BDD\uFF0C\u6240\u6709 slash \u547D\u4EE4\u4E00\u5F8B\u62E6\u622A\uFF1Abotmux \u81EA\u5E26\u547D\u4EE4\u3001\u900F\u4F20\u547D\u4EE4\u3001/workflow\u3001/introduce\u3001/t \u4EE5\u53CA CLI \u539F\u751F\u547D\u4EE4\uFF08/help \u7B49\uFF09\u3002\u5F62\u5982 /path/to/file \u7684\u5185\u5BB9\u4E0D\u4F1A\u88AB\u8BEF\u5224\u3002","botDefaults.quotaDefault":"\u9ED8\u8BA4\u6D88\u606F\u989D\u5EA6","botDefaults.quotaPlaceholder":"\u7559\u7A7A\uFF1D\u4E0D\u914D\u7F6E\u9ED8\u8BA4\u989D\u5EA6","botDefaults.quotaHelp":"\u4E0D\u5E26\u6570\u5B57\u7684 /grant @x \u9ED8\u8BA4\u7ED9\u7684\u6D88\u606F\u6761\u6570\u3002\u7559\u7A7A\u6216\u70B9\u300C\u5173\u95ED\u300D\u53EA\u662F\u4E0D\u518D\u7ED9\u88F8 /grant \u5957\u9ED8\u8BA4\u989D\u5EA6\uFF0C\u4E0D\u4F1A\u6E05\u6389\u5DF2\u6709\u7684\u989D\u5EA6\u8BA1\u6570\uFF0C\u4E5F\u4E0D\u5F71\u54CD\u663E\u5F0F /grant @x N\u2014\u2014\u5B83\u4EEC\u7167\u5E38\u7EE7\u7EED enforce\u3002\u989D\u5EA6\u7528\u5C3D\u4F1A\u81EA\u52A8\u64A4\u9500\u8BE5\u4EBA\u6388\u6743\u3002","botDefaults.quotaSave":"\u4FDD\u5B58\u989D\u5EA6","botDefaults.quotaOff":"\u5173\u95ED","botDefaults.quotaInvalid":"\u989D\u5EA6\u5FC5\u987B\u662F\u6B63\u6574\u6570","botDefaults.quotaStateOff":"\u5F53\u524D\uFF1A\u672A\u914D\u7F6E\u9ED8\u8BA4\u989D\u5EA6","botDefaults.quotaStateOn":"\u5F53\u524D\uFF1A\u6BCF\u4EBA {count} \u6761","botDefaults.sectionSessionCap":"\u4F1A\u8BDD\u6570\u4E0A\u9650","botDefaults.maxLiveWorkers":"\u6700\u5927\u540C\u65F6\u6D3B\u8DC3\u4F1A\u8BDD\u6570","botDefaults.maxLiveWorkersPlaceholder":"\u7559\u7A7A\uFF1D\u9ED8\u8BA4 30","botDefaults.maxLiveWorkersHelp":"\u672C Bot \u540C\u65F6\u4FDD\u6D3B\u7684\u4F1A\u8BDD\u6570\u4E0A\u9650\uFF0C\u7528\u4E8E\u63A7\u5236\u5185\u5B58\u3002\u8D85\u8FC7\u540E\u6700\u4E45\u672A\u7528\u7684\u4F1A\u8BDD\u81EA\u52A8\u4F11\u7720\uFF1Aworker \u548C CLI \u8FDB\u7A0B\u4E00\u8D77\u6740\u6389\u3001\u56DE\u6536\u5168\u90E8\u5185\u5B58\uFF0C\u4E0B\u6761\u6D88\u606F\u65F6\u4ECE\u78C1\u76D8 transcript \u51B7\u6062\u590D\uFF08--resume \u91CD\u5EFA\u4E0A\u4E0B\u6587\uFF0C\u51E0\u79D2\uFF0C\u4E0D\u518D\u5E38\u9A7B\u5360\u5185\u5B58\uFF09\u3002\u7559\u7A7A\uFF1D\u7528\u9ED8\u8BA4 30\uFF1B\u586B\u6570\u5B57\uFF1D\u672C Bot \u81EA\u5B9A\u4E49\uFF08\u60F3\u8981\u66F4\u591A\u5C31\u586B\u5927\u6570\u5B57\uFF09\u3002\u6CE8\u610F\uFF1A\u4F11\u7720\u53EA\u5BF9\u53EF\u6062\u590D\u540E\u7AEF\uFF08tmux/herdr/zellij\uFF09\u751F\u6548\uFF0C\u7EAF PTY \u4F1A\u8BDD\u4E0D\u53D7\u5F71\u54CD\uFF1B\u6B63\u5728\u51FA\u7B54\u6848\u7684\u4F1A\u8BDD\u4E0D\u4F1A\u88AB\u6253\u65AD\u3002","botDefaults.maxLiveWorkersSave":"\u4FDD\u5B58\u4E0A\u9650","botDefaults.maxLiveWorkersOff":"\u6062\u590D\u9ED8\u8BA4","botDefaults.maxLiveWorkersInvalid":"\u4E0A\u9650\u5FC5\u987B\u662F\u6B63\u6574\u6570","botDefaults.maxLiveWorkersStateDefault":"\u5F53\u524D\uFF1A\u9ED8\u8BA4 30 \u4E2A\u6D3B\u8DC3\u4F1A\u8BDD","botDefaults.maxLiveWorkersStateOn":"\u5F53\u524D\uFF1A\u6700\u591A {count} \u4E2A\u6D3B\u8DC3\u4F1A\u8BDD","nav.roles":"\u89D2\u8272\u7BA1\u7406","roles.title":"\u89D2\u8272\u7BA1\u7406","roles.subtitle":"\u4E3A\u6BCF\u4E2A\u7FA4\u7EC4\u7684\u6BCF\u4E2A Bot \u5355\u72EC\u8BBE\u7F6E\u89D2\u8272\u63D0\u793A\u8BCD\uFF0CBot \u5728\u8BE5\u7FA4\u4E2D\u4F1A\u4EE5\u6B64\u89D2\u8272\u884C\u4E8B\u3002","roles.search":"\u641C\u7D22\u7FA4\u540D/Bot/ID","roles.refresh":"\u5237\u65B0","roles.selectHint":"\u2190 \u5C55\u5F00\u7FA4\u7EC4\uFF0C\u9009\u62E9\u4E00\u4E2A Bot \u6765\u7F16\u8F91\u89D2\u8272","roles.editorPlaceholder":`\u8F93\u5165\u89D2\u8272\u63CF\u8FF0\uFF0C\u4F8B\u5982\uFF1A
1
+ "use strict";(()=>{var Cn=class{sessions=new Map;schedules=new Map;online=!0;listeners=new Set;upsertSessions(n){for(let a of n)this.sessions.set(a.sessionId,a);this.emit()}upsertSchedules(n){for(let a of n)this.schedules.set(a.id,a);this.emit()}applySse(n,a){if(n==="session.spawned")this.sessions.set(a.session.sessionId,a.session);else if(n==="session.update"){let s=this.sessions.get(a.sessionId);s&&this.sessions.set(a.sessionId,{...s,...a.patch})}else if(n==="session.exited"){let s=this.sessions.get(a.sessionId);s&&this.sessions.set(a.sessionId,{...s,status:"closed"})}else if(n==="schedule.created")this.schedules.set(a.schedule.id,a.schedule);else if(n==="schedule.updated"){let s=this.schedules.get(a.id);s&&this.schedules.set(a.id,{...s,...a.patch})}else if(n==="schedule.deleted")this.schedules.delete(a.id);else return;this.emit()}setOnline(n){this.online!==n&&(this.online=n,this.emit())}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}},Q=new Cn;async function Sa(){let[e,n]=await Promise.all([fetch("/api/sessions").then(o=>o.json()),fetch("/api/schedules").then(o=>o.json())]);Q.upsertSessions(e.sessions??[]),Q.upsertSchedules(n.schedules??[]);let a=new EventSource("/events"),s=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let o of s)a.addEventListener(o,r=>{try{let d=JSON.parse(r.data);Q.applySse(o,d.body??d)}catch{}});a.onerror=()=>Q.setOnline(!1),a.onopen=()=>Q.setOnline(!0)}var An="botmux.dashboard.locale",ys={"app.name":"botmux","app.subtitle":"\u98DE\u4E66 AI CLI \u63A7\u5236\u53F0","time.secondsAgo":"{value} \u79D2\u524D","time.minutesAgo":"{value} \u5206\u949F\u524D","time.hoursAgo":"{value} \u5C0F\u65F6\u524D","nav.overview":"\u603B\u89C8","nav.sessions":"\u4F1A\u8BDD","nav.sidebarCollapse":"\u6536\u8D77\u83DC\u5355\u680F","nav.sidebarExpand":"\u5C55\u5F00\u83DC\u5355\u680F","nav.groups":"\u7FA4\u7EC4","nav.schedules":"\u5B9A\u65F6","nav.settings":"\u8BBE\u7F6E","nav.botDefaults":"Bot \u914D\u7F6E","nav.skills":"Skills","status.live":"\u5B9E\u65F6\u8FDE\u63A5","status.disconnected":"\u8FDE\u63A5\u65AD\u5F00","status.system":"\u7CFB\u7EDF","status.light":"\u6D45\u8272","status.dark":"\u6697\u9ED1","status.language":"\u8BED\u8A00","status.theme":"\u4E3B\u9898","theme.base":"\u57FA\u7840","theme.skins":"\u4E3B\u9898\u76AE\u80A4","skin.cyber":"2077","skin.genshin":"\u539F\u795E","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"\u851A\u84DD\u6863\u6848","skin.zzz":"\u7EDD\u533A\u96F6","skin.dragonball":"\u4E03\u9F99\u73E0","skin.ikun":"ikun","botOnboarding.add":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.title":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.intro":"\u9009\u62E9 CLI \u4E0E\u5DE5\u4F5C\u76EE\u5F55\uFF0C\u626B\u7801\u521B\u5EFA PersonalAgent \u5E94\u7528\u540E\u5199\u5165\u672C\u673A bots.json\uFF0C\u5E76\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u3002","botOnboarding.cliLabel":"CLI \u9002\u914D\u5668","botOnboarding.dirLabel":"\u5DE5\u4F5C\u76EE\u5F55","botOnboarding.dirPlaceholder":"\u9ED8\u8BA4 ~\uFF08\u5BB6\u76EE\u5F55\uFF09\uFF0C\u9700\u4E3A daemon \u4E3B\u673A\u4E0A\u5DF2\u5B58\u5728\u7684\u76EE\u5F55","botOnboarding.modelLabel":"\u6A21\u578B\uFF08\u53EF\u9009\uFF09","botOnboarding.modelPlaceholder":"\u7559\u7A7A\u4F7F\u7528\u8BE5 CLI \u7684\u9ED8\u8BA4\u6A21\u578B","botOnboarding.modelTtadkPlaceholder":"ttadk \u7F51\u5173\u6A21\u578B\uFF0C\u9ED8\u8BA4 {model}\uFF0C\u53EF\u6539\uFF08\u968F\u65F6\u5728\u6B64\u8C03\u6574\uFF09","botOnboarding.modelTtadkCocoPlaceholder":"CoCo \u65E0\u9700\u6307\u5B9A\u6A21\u578B","botOnboarding.startScan":"\u5F00\u59CB\u626B\u7801","botOnboarding.cancel":"\u53D6\u6D88","botOnboarding.starting":"\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...","botOnboarding.waiting":"\u8BF7\u7528\u98DE\u4E66 App \u626B\u7801\u786E\u8BA4\u521B\u5EFA\u5E94\u7528\u3002","botOnboarding.verifying":"\u626B\u7801\u6210\u529F\uFF0C\u6B63\u5728\u6821\u9A8C\u51ED\u8BC1...","botOnboarding.configuringPermissions":"\u6B63\u5728\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u2026","botOnboarding.platformScanHint":"\u8BF7\u7528\u98DE\u4E66 App \u518D\u626B\u4E00\u6B21\u7801\u767B\u5F55\u5F00\u653E\u5E73\u53F0\uFF08\u7528\u4E8E\u81EA\u52A8\u5BFC\u5165\u6743\u9650\u3001\u914D\u7F6E\u56DE\u8C03\u3001\u63D0\u4EA4\u7248\u672C\uFF09\u3002","botOnboarding.platformQrAlt":"\u5F00\u653E\u5E73\u53F0\u767B\u5F55\u4E8C\u7EF4\u7801","botOnboarding.completed":"\u673A\u5668\u4EBA\u5DF2\u6DFB\u52A0\u3002","botOnboarding.permissionOk":"\u5DF2\u81EA\u52A8\u5BFC\u5165 {count} \u9879\u6743\u9650\u3002","botOnboarding.permissionSkipped":"\uFF08\u8DF3\u8FC7 {count} \u9879\u5F53\u524D\u79DF\u6237\u76EE\u5F55\u4E2D\u6CA1\u6709\u7684\u6743\u9650\uFF09","botOnboarding.permissionVersion":"\u5DF2\u63D0\u4EA4\u53D1\u5E03\u7248\u672C {version}\u3002","botOnboarding.permissionManual":"\u6743\u9650\u672A\u80FD\u81EA\u52A8\u914D\u7F6E\uFF0C\u8BF7\u624B\u52A8\u5B8C\u6210\u4EE5\u4E0B\u6B65\u9AA4\uFF1A","botOnboarding.metaDir":"\u76EE\u5F55","botOnboarding.failed":"\u6DFB\u52A0\u5931\u8D25","botOnboarding.openLink":"\u6253\u4E0D\u5F00\u626B\u7801\uFF1F\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00","botOnboarding.close":"\u5173\u95ED","botOnboarding.restartHint":"\u5DF2\u5199\u5165 bots.json\u3002\u6267\u884C pnpm daemon:restart \u540E\u65B0\u673A\u5668\u4EBA\u751F\u6548\u3002","botOnboarding.qrAlt":"\u98DE\u4E66\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA\u4E8C\u7EF4\u7801","overview.title":"\u5DE5\u4F5C\u53F0","overview.subtitle":"\u6570\u5B57\u5458\u5DE5\u5B9E\u65F6\u72B6\u6001 \xB7 \u540C\u6B65\u98DE\u4E66\u8BDD\u9898","overview.team":"AI \u56E2\u961F","overview.teamHint":"\u6BCF\u4F4D\u6570\u5B57\u5458\u5DE5\u7684\u5B9E\u65F6\u72B6\u6001","overview.attention":"\u9700\u8981\u4F60\u5904\u7406","overview.attentionHint":"\u5361\u4F4F\u7684\u4EFB\u52A1\uFF0C\u56DE\u4E2A\u8BDD\u5C31\u80FD\u7EE7\u7EED\u8DD1","overview.activeSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.activeSessionsHint":"\u6B63\u5728\u8FD0\u8F6C\u7684\u4F1A\u8BDD","overview.today":"\u6B64\u523B\u6982\u89C8","overview.todayHint":"\u6D3B\u8DC3\u4F1A\u8BDD\u5206\u5E03","overview.viewAll":"\u67E5\u770B\u5168\u90E8 \u2192","overview.botIdle":"\u5F85\u547D\u4E2D\uFF0C\u968F\u65F6\u53EF\u63A5\u65B0\u4EFB\u52A1","overview.botOffline":"\u79BB\u7EBF \u2014 daemon \u672A\u4E0A\u7EBF","overview.botBusy":"\u6267\u884C\u4E2D \xB7 {count} \u4F1A\u8BDD","overview.botNeedsYou":"\u7B49\u4F60\u56DE\u590D","overview.botReady":"\u5C31\u7EEA","overview.botOff":"\u79BB\u7EBF","overview.sessionsCount":"{count} \u4F1A\u8BDD","overview.lastActive":"{time}\u524D\u6D3B\u8DC3","overview.noAttention":"\u6CA1\u6709\u7B49\u4F60\u5904\u7406\u7684\u4E8B\u9879","overview.teamExpand":"\u5C55\u5F00\u5168\u90E8 {count} \u4F4D \u25BE","overview.teamCollapse":"\u6536\u8D77 \u25B4","strip.pending":"{count} \u4EF6\u5F85\u5904\u7406","strip.longest":"\u6700\u4E45\u5DF2\u7B49 {time} \u2014 {bot} {reason}","strip.handle":"\u7ACB\u5373\u5904\u7406","overview.openSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.workingSessions":"\u5DE5\u4F5C\u4E2D","overview.onlineBots":"\u5728\u7EBF Bot","overview.schedules":"\u5B9A\u65F6\u4EFB\u52A1","overview.groups":"\u7FA4\u804A\u8986\u76D6","overview.enabledSchedules":"\u5DF2\u542F\u7528","overview.total":"\u603B\u8BA1","overview.active":"\u6D3B\u8DC3","overview.daemonRegistry":"daemon \u6CE8\u518C\u8868","overview.chatMatrix":"\u7FA4\u804A\u77E9\u9635","overview.recentSessions":"\u6700\u8FD1\u4F1A\u8BDD","overview.nextSchedules":"\u5373\u5C06\u6267\u884C","overview.noSessions":"\u6682\u65E0\u4F1A\u8BDD\u3002","overview.noSchedules":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","sessions.title":"\u4F1A\u8BDD\u63A7\u5236","sessions.subtitle":"\u5B9A\u4F4D\u98DE\u4E66\u8BDD\u9898\u3001\u6253\u5F00 Web Terminal\u3001\u5173\u95ED\u6216\u6062\u590D CLI \u4F1A\u8BDD\u3002","sessions.search":"\u641C\u7D22\u5DE5\u4F5C\u76EE\u5F55 / \u6807\u9898 / ID","sessions.anyStatus":"\u5168\u90E8\u72B6\u6001","sessions.adoptAny":"adopt: \u5168\u90E8","sessions.adoptYes":"adopt: \u662F","sessions.adoptNo":"adopt: \u5426","sessions.activeOnly":"\u4EC5\u6D3B\u8DC3","sessions.closeSelected":"\u5173\u95ED\u9009\u4E2D","sessions.clearSelection":"\u53D6\u6D88\u9009\u62E9","sessions.selectedCount":"\u5DF2\u9009 {count} \u4E2A\u4F1A\u8BDD","sessions.bot":"bot","sessions.cli":"CLI","sessions.chat":"\u7FA4\u804A","sessions.openChat":"\u6253\u5F00\u7FA4\u804A","sessions.status":"\u72B6\u6001","sessions.tokenIn":"Token In","sessions.tokenOut":"Token Out","sessions.titleCol":"\u6807\u9898","sessions.workingDir":"\u5DE5\u4F5C\u76EE\u5F55","sessions.created":"\u521B\u5EFA","sessions.last":"\u6700\u8FD1","sessions.adopt":"\u63A5\u5165","sessions.actions":"\u64CD\u4F5C","sessions.details":"\u8BE6\u60C5","sessions.copy":"\u590D\u5236","sessions.copied":"\u5DF2\u590D\u5236","sessions.locate":"\u5B9A\u4F4D\u8BDD\u9898","sessions.locating":"\u53D1\u9001\u4E2D...","sessions.cooldown":"\u51B7\u5374 {seconds}s","sessions.openTerminal":"\u7EC8\u7AEF","sessions.writeLink":"\u64CD\u4F5C\u94FE\u63A5","sessions.writeLinkHint":"\u83B7\u53D6\u53EF\u64CD\u4F5C\u7EC8\u7AEF\u94FE\u63A5\uFF08\u5E26\u5199\u6743\u9650 token\uFF0C\u65B0\u6807\u7B7E\u6253\u5F00\uFF09","sessions.writeLinkFail":"\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u5931\u8D25","sessions.close":"\u5173\u95ED\u4F1A\u8BDD","sessions.resume":"\u6062\u590D\u4F1A\u8BDD","sessions.dismiss":"\u5173\u95ED","sessions.closeConfirm":"\u5173\u95ED\u8FD9\u4E2A\u4F1A\u8BDD\uFF1F","sessions.resumeFailed":"\u6062\u590D\u5931\u8D25","sessions.land":"\u843D\u76D8","sessions.landLoading":"\u52A0\u8F7D\u6C99\u76D2 diff\u2026","sessions.landUnavailable":"\u65E0\u6CD5\u843D\u76D8","sessions.landEmpty":"\u6C99\u76D2\u526F\u672C\u6CA1\u6709\u6539\u52A8\u3002","sessions.landApply":"\u5E94\u7528\u5230\u78C1\u76D8","sessions.landDiscard":"\u4E22\u5F03","sessions.landApplied":"\u5DF2\u843D\u76D8","sessions.landFailed":"\u843D\u76D8\u5931\u8D25","sessions.landDiscarded":"\u5DF2\u4E22\u5F03\uFF08\u6C99\u76D2\u526F\u672C\u672A\u5E94\u7528\uFF09\u3002","connectors.lede":"\u8BA9\u5916\u90E8\u7CFB\u7EDF\uFF08\u76D1\u63A7\u544A\u8B66\u3001CI\u3001\u5DE5\u5355\u2026\uFF09\u901A\u8FC7\u4E00\u4E2A webhook \u89E6\u53D1\u673A\u5668\u4EBA\u5728\u7FA4\u91CC\u8BF4\u8BDD\u6216\u8DD1\u5DE5\u4F5C\u6D41\u3002","connectors.createTitle":"\u65B0\u5EFA Webhook","connectors.fName":"\u540D\u79F0","connectors.fNamePh":"\u5982\uFF1A\u7EBF\u4E0A\u544A\u8B66","connectors.fBot":"\u89E6\u53D1\u7684\u673A\u5668\u4EBA","connectors.fKind":"\u89E6\u53D1\u65B9\u5F0F","connectors.kindTurn":"\u5355\u8F6E\u5BF9\u8BDD\uFF08\u8BA9\u673A\u5668\u4EBA\u56DE\u5E94\u4E00\u6B21\uFF09","connectors.kindWorkflow":"\u5DE5\u4F5C\u6D41","connectors.fWf":"\u5DE5\u4F5C\u6D41 ID","connectors.fMode":"\u6295\u9012\u5230\u54EA\u4E2A\u7FA4","connectors.modeDynamic":"\u7531\u8BF7\u6C42\u6307\u5B9A\uFF08\u7FA4\u968F\u8BF7\u6C42\u4F20\u5165\uFF09","connectors.modeFixed":"\u56FA\u5B9A\u7FA4","connectors.modeNewGroup":"\u6BCF\u6B21\u65B0\u5EFA\u7FA4","connectors.fFixedChat":"\u6295\u9012\u5230\u7684\u7FA4","connectors.fChatManualPh":"\u624B\u52A8\u586B\u7FA4 ID\uFF1Aoc_\u2026","connectors.chatManualLink":"\u627E\u4E0D\u5230\u7FA4\uFF1F\u624B\u52A8\u586B ID \u2192","connectors.chatListLink":"\u4ECE\u7FA4\u5217\u8868\u9009\u62E9 \u2190","connectors.fAllow":"\u5141\u8BB8\u7684\u7FA4","connectors.optional":"\uFF08\u53EF\u9009\uFF09","connectors.allowHint":"\u6309\u4F4F Ctrl/\u2318 \u591A\u9009\uFF1B\u7559\u7A7A = \u4E0D\u9650\u3002\u53EA\u7528\u4E8E\u6821\u9A8C\u8BF7\u6C42\u4F20\u5165\u7684\u7FA4\u662F\u5426\u88AB\u5141\u8BB8\u3002","connectors.dynamicHint":'<b>\u52A8\u6001\u6A21\u5F0F</b>\uFF1A\u7FA4 ID \u968F\u6BCF\u6B21\u8BF7\u6C42\u4F20\u5165\uFF0C\u4E09\u9009\u4E00 \u2014\u2014 \u67E5\u8BE2\u53C2\u6570 <code>?chatId=&lt;\u7FA4ID&gt;</code> \xB7 \u8BF7\u6C42\u5934 <code>x-botmux-chat-id: &lt;\u7FA4ID&gt;</code> \xB7 \u8BF7\u6C42\u4F53 <code>{"chatId":"&lt;\u7FA4ID&gt;"}</code>\u3002<br>\u60F3"\u4E00\u4E2A URL \u76F4\u63A5\u89E6\u53D1\u3001\u4E0D\u5E26\u53C2\u6570"\uFF0C\u8BF7\u6539\u9009\u300C\u56FA\u5B9A\u7FA4\u300D\u3002',"connectors.fDedup":"\u53BB\u91CD\u5B57\u6BB5","connectors.fDedupPh":"\u5982 alert.id\uFF08\u4ECE\u4E8B\u4EF6 body \u53D6\u503C\uFF09","connectors.dedupHint":"\u586B\u4E86\uFF1A\u547D\u4E2D\u76F8\u540C\u503C\u7684\u4E8B\u4EF6\u90FD\u6295\u5230<b>\u540C\u4E00\u4E2A\u7FA4</b>\u3002\u7559\u7A7A\uFF1A\u6BCF\u4E2A\u4E8B\u4EF6<b>\u65B0\u5EFA\u4E00\u4E2A\u7FA4</b>\u3002","connectors.fInstruction":"\u5904\u7406\u6307\u4EE4","connectors.fInstructionPh":"\u4E8B\u4EF6\u89E6\u53D1\u65F6\u8BA9\u673A\u5668\u4EBA\u505A\u4EC0\u4E48\u3002\u5982\uFF1A\u603B\u7ED3\u8FD9\u6761\u544A\u8B66\u7684\u4E25\u91CD\u7A0B\u5EA6\uFF0C@\u76F8\u5173 oncall\uFF0C\u7ED9\u51FA\u6392\u67E5\u5EFA\u8BAE\u3002\u7559\u7A7A = \u53EA\u628A\u4E8B\u4EF6\u539F\u6837\u4EA4\u7ED9\u6A21\u578B\u81EA\u7531\u53D1\u6325\u3002","connectors.fVerify":"\u6821\u9A8C\u65B9\u5F0F","connectors.verifyToken":"\u4EE4\u724C\uFF08\u7B80\u5355\uFF1A\u5BC6\u94A5\u653E\u8FDB URL\uFF0C\u4E00\u6761 curl \u5C31\u80FD\u89E6\u53D1\uFF09","connectors.verifyHmac":"HMAC \u7B7E\u540D\uFF08\u9AD8\u7EA7\uFF1A\u66F4\u5B89\u5168\uFF0C\u9700\u81EA\u884C\u5BF9\u8BF7\u6C42\u7B7E\u540D\uFF09","connectors.fSecret":"\u5BC6\u94A5 / \u4EE4\u724C","connectors.fSecretPh":"\u7559\u7A7A\u81EA\u52A8\u751F\u6210\uFF08\u53EA\u663E\u793A\u4E00\u6B21\uFF09","connectors.btnCreate":"\u521B\u5EFA","connectors.listTitle":"\u5DF2\u6709 Webhook","connectors.loading":"\u52A0\u8F7D\u4E2D\u2026","connectors.noBotGroups":"\uFF08\u8BE5\u673A\u5668\u4EBA\u6682\u65E0\u53EF\u89C1\u7FA4\uFF0C\u70B9\u53F3\u4FA7\u624B\u52A8\u586B ID\uFF09","connectors.modeLabelFixed":"\u56FA\u5B9A\u7FA4","connectors.modeLabelNewGroup":"\u6BCF\u6B21\u65B0\u5EFA\u7FA4","connectors.modeLabelDynamic":"\u8BF7\u6C42\u6307\u5B9A\u7FA4","connectors.kindLabelWorkflow":"\u5DE5\u4F5C\u6D41","connectors.kindLabelTurn":"\u5355\u8F6E","connectors.count":"\xB7 {count} \u4E2A","connectors.empty":"\u8FD8\u6CA1\u6709 Webhook\u3002\u7528\u4E0A\u9762\u7684\u8868\u5355\u521B\u5EFA\u4E00\u4E2A\u3002","connectors.enabled":"\u5DF2\u542F\u7528","connectors.disabled":"\u5DF2\u505C\u7528","connectors.badgeToken":"\u4EE4\u724C","connectors.badgeSign":"\u7B7E\u540D","connectors.dest":"\u6295\u9012\u300C{name}\u300D","connectors.btnDisable":"\u505C\u7528","connectors.btnEnable":"\u542F\u7528","connectors.btnDel":"\u5220\u9664","connectors.webhookUrl":"Webhook URL\uFF1A","connectors.copy":"\u590D\u5236","connectors.copied":"\u5DF2\u590D\u5236","connectors.tokenHint":"\u4EE4\u724C\u6A21\u5F0F\uFF1A\u8C03\u7528\u65F6\u5728 URL \u672B\u5C3E\u8FFD\u52A0 <code>/&lt;\u4EE4\u724C&gt;</code>\uFF08\u4EE4\u724C\u4EC5\u521B\u5EFA/\u8F6E\u6362\u65F6\u663E\u793A\u4E00\u6B21\uFF09\u3002","connectors.dynamicReqHint":'\u52A8\u6001\u6A21\u5F0F\uFF1A\u8BF7\u6C42\u9700\u5E26\u76EE\u6807\u7FA4 \u2014\u2014 <code>?chatId=&lt;\u7FA4ID&gt;</code> \u6216\u5934 <code>x-botmux-chat-id</code> \u6216 body <code>{"chatId":"\u2026"}</code>\u3002',"connectors.instructionPrefix":"\u5904\u7406\u6307\u4EE4\uFF1A","connectors.delConfirm":"\u5220\u9664\u8FD9\u4E2A Webhook\uFF1F\u5B83\u7684 URL \u4F1A\u7ACB\u5373\u5931\u6548\u3002","connectors.errName":"\u8BF7\u586B\u540D\u79F0","connectors.errBot":"\u8BF7\u9009\u673A\u5668\u4EBA","connectors.errWf":"\u8BF7\u586B\u5DE5\u4F5C\u6D41 ID","connectors.errChat":"\u8BF7\u9009\u62E9\uFF08\u6216\u624B\u52A8\u586B\uFF09\u6295\u9012\u7684\u7FA4","connectors.creating":"\u521B\u5EFA\u4E2D\u2026","connectors.usageDynamicLede":"\u52A8\u6001\u6A21\u5F0F\uFF1AURL \u5DF2\u542B\u4EE4\u724C\uFF0C\u8C03\u7528\u65F6\u518D\u5E26\u4E0A\u76EE\u6807\u7FA4 ID{gn}\uFF1A","connectors.usageDynamicNote":'\u7FA4\u4E5F\u53EF\u653E\u8BF7\u6C42\u5934 <code>x-botmux-chat-id</code> \u6216 body <code>{"chatId":"\u2026"}</code>\u3002\u26A0\uFE0F URL \u5373\u51ED\u8BC1\uFF0C\u52FF\u6CC4\u6F0F\u3002',"connectors.usageTokenLede":"\u6B64 URL \u5DF2\u542B\u4EE4\u724C\u3001\u4E14\u56FA\u5B9A\u6295\u9012\u5230\u6240\u9009\u7FA4\uFF0C\u76F4\u63A5 POST \u5373\u53EF\u89E6\u53D1\uFF1A","connectors.usageTokenNote":"\u26A0\uFE0F URL \u5373\u51ED\u8BC1\uFF0C\u8BF7\u52FF\u516C\u5F00\u6CC4\u6F0F\uFF1B\u53EF\u5728\u4E0B\u65B9\u5217\u8868\u5220\u9664\u6216\u8F6E\u6362\u3002","connectors.usageHmac":"\u5916\u90E8\u7CFB\u7EDF\u9700\u5BF9 <code>timestamp.body</code> \u505A HMAC-SHA256 \u7B7E\u540D\uFF0C\u5E76\u5E26\u4E0A <code>x-botmux-timestamp</code> / <code>x-botmux-nonce</code> / <code>x-botmux-signature</code> \u5934\u8C03\u7528","connectors.usageHmacDynamic":"\uFF0C\u540C\u65F6\u6309\u4E0A\u9762\u65B9\u5F0F\u5E26\u76EE\u6807\u7FA4 ID","connectors.createdPrefix":"\u5DF2\u521B\u5EFA\u300C{name}\u300D","connectors.createdDest":"\u6295\u9012\u5230\u300C{name}\u300D","connectors.tokenLabel":"\u8BBF\u95EE\u4EE4\u724C","connectors.signLabel":"\u7B7E\u540D\u5BC6\u94A5","connectors.secretOnce":"\uFF08\u53EA\u663E\u793A\u8FD9\u4E00\u6B21\uFF0C\u8BF7\u4FDD\u5B58\uFF09\uFF1A","connectors.createFailed":"\u521B\u5EFA\u5931\u8D25\uFF1A{error}","connectors.noOnlineBots":"\uFF08\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF09","team.navHome":"\u6211\u7684\u56E2\u961F","team.navManage":"\u56E2\u961F\u7BA1\u7406","team.eyebrow":"\u56E2\u961F","team.homeTitle":"\u56E2\u961F\u534F\u4F5C\uFF08\u8DE8\u90E8\u7F72\uFF09","team.homeLede":"\u628A\u522B\u7684\u90E8\u7F72\uFF08\u540C\u4E8B\u81EA\u5DF1\u8DD1\u7684 botmux\uFF09\u9080\u8BF7\u8FDB\u540C\u4E00\u4E2A\u56E2\u961F\uFF0C\u4E92\u76F8\u53D1\u73B0\u673A\u5668\u4EBA\u3001\u534F\u4F5C\u62C9\u7FA4\u3002","team.localDeployTitle":"\u672C\u90E8\u7F72","team.myIdentity":"\u6211\u7684\u98DE\u4E66\u8EAB\u4EFD\uFF1A","team.unbound":"\u672A\u7ED1\u5B9A","team.bindBtn":"\u7ED1\u5B9A","team.bindHint":"\uFF08\u7528\u673A\u5668\u4EBA\u51ED\u8BC1\u81EA\u52A8\u8BC6\u522B\u4F60\uFF1B\u7ED1\u5B9A\u540E\u62C9\u7FA4\u4F1A\u628A\u4F60\u62C9\u8FDB\u7FA4\u3001\u673A\u5668\u4EBA\u4E5F\u5F52\u5230\u4F60\u540D\u4E0B\uFF09","team.myTeams":"\u6211\u7684\u56E2\u961F","team.searchPh":"\u641C\u7D22 \u540D\u79F0/\u80FD\u529B/CLI\u2026","team.allCli":"\u5168\u90E8 CLI","team.hasCap":"\u6709\u80FD\u529B\u6807\u7B7E","team.hasRole":"\u6709\u9ED8\u8BA4\u89D2\u8272","team.teamsHint":"\u6BCF\u4E2A\u56E2\u961F\u91CC\u52FE\u9009\u673A\u5668\u4EBA\u5373\u53EF\u5355\u72EC\u62C9\u7FA4\uFF08\u81EA\u52A8\u5E26\u4E0A\u5404\u81EA\u8D1F\u8D23\u4EBA\uFF09\u3002\u8981\u65B0\u5EFA\u56E2\u961F / \u751F\u6210\u9080\u8BF7\u7801 / \u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\uFF0C\u53BB\u300C\u56E2\u961F\u7BA1\u7406\u300D\u3002","team.loading":"\u52A0\u8F7D\u4E2D\u2026","team.roleModalTitle":"\u9ED8\u8BA4\u89D2\u8272","team.roleModalHint":"\u8BE5\u673A\u5668\u4EBA\u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF08\u8DE8\u7FA4\u751F\u6548\uFF09\uFF0C\u6B64\u5904\u53EA\u8BFB\u3002\u5982\u9700\u4FEE\u6539\uFF0C\u8BF7\u5230\u300CBot \u914D\u7F6E\u300D\u9875\u3002","team.close":"\u5173\u95ED","team.tagLocal":"\u672C\u90E8\u7F72","team.tagRemoteStale":"\u8FDC\u7AEF\xB7\u79BB\u7EBF\uFF1F","team.tagRemote":"\u8FDC\u7AEF","team.removeMember":"\u79FB\u9664","team.depTag":"\uFF08{tag}\uFF09","team.depCount":"{count} \u4E2A","team.depSelected":"\uFF0C\u5DF2\u9009 {n}","team.capPh":"\u80FD\u529B\u6807\u7B7E\u2026","team.viewRole":"\u67E5\u770B","team.hasRoleShort":"\u6709\u89D2\u8272","team.noMatch":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u673A\u5668\u4EBA\u3002","team.gnamePh":"\u7FA4\u540D\uFF08\u5982\uFF1A\u8DE8\u56E2\u961F\u6392\u969C\uFF09","team.pullGroupBtn":"\u628A\u52FE\u9009\u7684\u673A\u5668\u4EBA\u62C9\u4E00\u4E2A\u7FA4","team.pullGroupHint":"\u52FE\u9009\u673A\u5668\u4EBA \u2192 \u62C9\u5230\u4E00\u4E2A\u98DE\u4E66\u7FA4\uFF08\u81EA\u52A8\u542B owner\uFF09","team.noTeams":"\u8FD8\u6CA1\u6709\u56E2\u961F\u3002\u53BB\u300C\u56E2\u961F\u7BA1\u7406\u300D\u751F\u6210\u9080\u8BF7\u7801\u8BA9\u522B\u4EBA\u52A0\u5165\u4F60\uFF0C\u6216\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\u3002","team.connected":"\u5DF2\u8FDE\u63A5","team.connectFail":"\u8FDE\u63A5\u5931\u8D25\uFF1A{error}","team.iHost":"\u6211\u6258\u7BA1","team.teamMeta":"{deps} \u4E2A\u90E8\u7F72 \xB7 {bots} \u4E2A\u673A\u5668\u4EBA","team.rosterFail":"\u65E0\u6CD5\u83B7\u53D6\u8BE5\u56E2\u961F\u82B1\u540D\u518C\u3002","team.acrossTeams":"\uFF08\u8DE8 {n} \u4E2A\u56E2\u961F\uFF0C\u53BB\u91CD\uFF09","team.botsWord":"\u4E2A\u673A\u5668\u4EBA","team.groupCreated":"\u7FA4\u5DF2\u521B\u5EFA","team.delegatedBy":"\uFF08\u7531\u300C{name}\u300D\u5EFA\u7FA4\uFF09","team.openInLark":"\u5728\u98DE\u4E66\u6253\u5F00","team.invalidBots":"\u672A\u52A0\u5165\u7684\u673A\u5668\u4EBA\uFF1A{ids}","team.invalidOwners":"{n} \u4E2A owner \u672A\u80FD\u62C9\u8FDB","team.missingIdentity":"\u4F60\u672A\u7ED1\u5B9A\u98DE\u4E66\u8EAB\u4EFD\uFF0C\u6CA1\u628A\u4F60\u81EA\u5DF1\u62C9\u8FDB\u7FA4\uFF08\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u7ED1\u5B9A\uFF09","team.skippedNoOwner":"{n} \u4E2A\u673A\u5668\u4EBA\u56E0\u8D1F\u8D23\u4EBA\u672A\u7ED1\u5B9A\u8EAB\u4EFD\u88AB\u8DF3\u8FC7\uFF08\u672A\u52A0\u5165\u7FA4\uFF09","team.errNoLocalBot":"\u8BF7\u81F3\u5C11\u52FE\u9009\u4E00\u4E2A\u4F60\u81EA\u5DF1\uFF08\u672C\u90E8\u7F72\uFF09\u7684\u5728\u7EBF\u673A\u5668\u4EBA\u2014\u2014\u7FA4\u8981\u7531\u5B83\u521B\u5EFA\u5E76\u628A\u4F60\uFF08\u53D1\u8D77\u4EBA\uFF09\u62C9\u8FDB\u7FA4\u3002","team.errAllSkipped":"\u6240\u9009\u673A\u5668\u4EBA\u7684\u8D1F\u8D23\u4EBA\u90FD\u6CA1\u7ED1\u5B9A\u8EAB\u4EFD\uFF0C\u65E0\u6CD5\u62C9\u7FA4\uFF08\u673A\u5668\u4EBA\u4E0D\u80FD\u8FDB\u4E00\u4E2A owner \u4E0D\u5728\u7684\u7FA4\uFF09\u3002\u8BF7\u8BA9\u5BF9\u5E94\u90E8\u7F72\u5148\u7ED1\u5B9A\u8EAB\u4EFD\u3002","team.errNoCreator":"\u6CA1\u6709\u53EF\u7528\u7684\u5EFA\u7FA4\u53D1\u8D77\u65B9\uFF08\u76F8\u5173\u90E8\u7F72\u90FD\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF0C\u6216\u4E0D\u53EF\u8FBE\uFF09","team.errDelegationTimeout":"\u59D4\u6258\u5BF9\u65B9\u90E8\u7F72\u5EFA\u7FA4\u8D85\u65F6\uFF08\u53EF\u80FD\u5DF2\u5EFA\uFF0C\u53BB\u98DE\u4E66\u786E\u8BA4\uFF0C\u52FF\u91CD\u590D\u70B9\uFF09","team.errGroupCreate":"\u5EFA\u7FA4\u5931\u8D25\uFF1A{error}","team.roleModalTitleName":"\u9ED8\u8BA4\u89D2\u8272 \xB7 {name}","team.bound":"\u5DF2\u7ED1\u5B9A","team.myHostedTeam":"\u6211\u6258\u7BA1\u7684\u56E2\u961F","team.remoteTeamLabel":"{name} \u7684\u56E2\u961F","team.manageTitle":"\u56E2\u961F\u7BA1\u7406","team.manageLede":"\u521B\u5EFA\u591A\u4E2A\u56E2\u961F\u3001\u7ED9\u6BCF\u4E2A\u56E2\u961F\u751F\u6210\u9080\u8BF7\u7801\u3001\u6216\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\u3002\u4E00\u4E2A\u56E2\u961F = \u4F60\u672C\u90E8\u7F72\u7684\u673A\u5668\u4EBA + \u52A0\u5165\u8BE5\u56E2\u961F\u7684\u5176\u5B83\u90E8\u7F72\u3002","team.hostedTitle":"\u6211\u6258\u7BA1\u7684\u56E2\u961F","team.newTeamPh":"\u65B0\u56E2\u961F\u540D\u79F0","team.createTeamBtn":"\u521B\u5EFA\u56E2\u961F","team.joinTitle":"\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F","team.hubPh":"Hub \u5730\u5740\uFF0C\u5982 http://10.0.0.5:7891","team.codePh":"\u9080\u8BF7\u7801","team.joinBtn":"\u52A0\u5165","team.noTeamsShort":"\u8FD8\u6CA1\u6709\u56E2\u961F\u3002","team.default":"\u9ED8\u8BA4","team.manageMetaDeps":"{count} \u4E2A\u90E8\u7F72","team.manageMetaRemote":"\uFF08\u542B {r} \u8FDC\u7AEF\uFF09","team.manageMetaBots":"{count} \u4E2A\u673A\u5668\u4EBA","team.genInvite":"\u751F\u6210\u9080\u8BF7\u7801","team.delBtn":"\u5220\u9664","team.generating":"\u751F\u6210\u4E2D\u2026","team.inviteResultLede":"\u628A\u4E0B\u9762\u4E24\u9879\u53D1\u7ED9\u522B\u7684\u90E8\u7F72\u7684\u4EBA\uFF0824 \u5C0F\u65F6\u5185\u3001\u5355\u6B21\u6709\u6548\uFF09\uFF1A","team.inviteHub":"Hub \u5730\u5740\uFF1A","team.inviteCode":"\u9080\u8BF7\u7801\uFF1A","team.genFail":"\u751F\u6210\u5931\u8D25\u3002","team.delConfirm":"\u5220\u9664\u56E2\u961F\u300C{name}\u300D\uFF1F\u5DF2\u52A0\u5165\u5B83\u7684\u90E8\u7F72\u4F1A\u88AB\u79FB\u9664\uFF08\u4E0D\u5F71\u54CD\u4ED6\u4EEC\u81EA\u5DF1\u7684\u90E8\u7F72\uFF09\u3002","team.errName":"\u8BF7\u586B\u56E2\u961F\u540D\u79F0","team.creating":"\u521B\u5EFA\u4E2D\u2026","team.created":"\u5DF2\u521B\u5EFA","team.createFail":"\u521B\u5EFA\u5931\u8D25\uFF1A{error}","team.errHubCode":"\u8BF7\u586B Hub \u5730\u5740\u548C\u9080\u8BF7\u7801\u3002","team.joining":"\u52A0\u5165\u4E2D\u2026","team.joined":"\u5DF2\u52A0\u5165\u300C{name}\u300D\uFF0C\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u67E5\u770B\u3002","team.joinErrSelf":"\u8FD9\u662F\u4F60\u81EA\u5DF1\u7684\u90E8\u7F72\uFF0C\u4E0D\u80FD\u52A0\u5165\u81EA\u5DF1\uFF08\u9080\u8BF7\u7801\u8981\u53D1\u7ED9\u522B\u7684\u90E8\u7F72\u7684\u4EBA\u7528\uFF09","team.joinErrAlready":"\u4F60\u7684\u90E8\u7F72\u5DF2\u7ECF\u52A0\u5165\u8FC7\u8FD9\u4E2A\u56E2\u961F\u4E86","team.joinErrUnreachable":"\u8FDE\u4E0D\u4E0A\u5BF9\u65B9 Hub\uFF08\u68C0\u67E5\u5730\u5740/\u7F51\u7EDC\uFF09","team.joinErrTimeout":"\u5BF9\u65B9 Hub \u54CD\u5E94\u8D85\u65F6","team.joinErrGeneric":"\u52A0\u5165\u5931\u8D25\uFF1A{error}","team.identifying":"\u8BC6\u522B\u4E2D\u2026","team.bound2":"\u5DF2\u7ED1\u5B9A\uFF1A{name}","team.multiCandidate":"\u8BC6\u522B\u5230\u591A\u4E2A\u5019\u9009\uFF0C\u70B9\u4F60\u81EA\u5DF1\uFF1A","team.binding":"\u7ED1\u5B9A\u4E2D\u2026","team.bindFail":"\u7ED1\u5B9A\u5931\u8D25\uFF1A{error}","team.noCandidates":"\u6CA1\u8BC6\u522B\u5230\u8EAB\u4EFD\uFF1A\u8BF7\u786E\u8BA4\u673A\u5668\u4EBA\u914D\u7F6E\u4E86 allowedUsers\uFF08\u5141\u8BB8\u4F7F\u7528\u8005\uFF09\uFF0C\u4E14\u673A\u5668\u4EBA\u6709\u901A\u8BAF\u5F55\u6743\u9650\u3002","team.removeMemberConfirm":"\u628A\u300C{name}\u300D\u79FB\u51FA\u8FD9\u4E2A\u56E2\u961F\uFF1F\u5B83\u7684\u673A\u5668\u4EBA\u5C06\u4ECE\u672C\u56E2\u961F\u82B1\u540D\u518C\u6D88\u5931\uFF08\u4E0D\u5F71\u54CD\u5BF9\u65B9\u81EA\u5DF1\u7684\u90E8\u7F72\uFF09\u3002","team.creatingGroup":"\u5EFA\u7FA4\u4E2D\u2026","team.defaultGroupName":"\u534F\u4F5C\u7FA4","team.errPickBot":"\u8BF7\u5148\u52FE\u9009\u81F3\u5C11\u4E00\u4E2A\u673A\u5668\u4EBA","sessions.closeBulkConfirm":"\u5173\u95ED\u9009\u4E2D\u7684 {count} \u4E2A\u4F1A\u8BDD\uFF1F","sessions.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u4F1A\u8BDD\u3002","sessions.viewMode":"\u4F1A\u8BDD\u89C6\u56FE","sessions.viewKanban":"\u770B\u677F","sessions.viewBoard":"\u72B6\u6001\u677F","sessions.viewTable":"\u8868\u683C","sessions.selectSession":"\u9009\u62E9\u4F1A\u8BDD","sessions.board.needsYou":"\u9700\u8981\u4F60","sessions.board.needsYouHint":"\u7B49\u5F85\u4ED3\u5E93\u3001TUI \u9009\u62E9\u6216\u989D\u5EA6\u5904\u7406","sessions.board.starting":"\u542F\u52A8\u4E2D","sessions.board.startingHint":"CLI \u6B63\u5728\u521B\u5EFA\u6216\u6062\u590D","sessions.board.working":"\u5E72\u6D3B\u4E2D","sessions.board.workingHint":"\u6B63\u5728\u8F93\u51FA\u3001\u5206\u6790\u6216\u6267\u884C\u5DE5\u5177","sessions.board.idle":"\u7A7A\u95F2","sessions.board.idleHint":"\u53EF\u7EE7\u7EED\u5BF9\u8BDD\u6216\u63A5\u65B0\u4EFB\u52A1","sessions.board.emptyColumn":"\u6682\u65E0\u4F1A\u8BDD","sessions.board.signalRepo":"\u5F85\u9009\u4ED3\u5E93","sessions.board.signalPrompt":"\u7B49\u5F85 TUI \u9009\u62E9","sessions.board.signalLimited":"\u989D\u5EA6\u53D7\u9650","sessions.board.signalAgent":"\u9700\u8981\u4EBA\u5DE5\u4ECB\u5165","sessions.board.waiting":"\u7B49\u5F85","sessions.board.dragHint":"\u62D6\u52A8\u5217\u5934\u8C03\u6574\u5217\u987A\u5E8F","sessions.board.moveLeft":"\u5DE6\u79FB\u6B64\u5217","sessions.board.moveRight":"\u53F3\u79FB\u6B64\u5217","sessions.kanban.backlog":"\u5F85\u529E\u6C60","sessions.kanban.todo":"\u5F85\u529E","sessions.kanban.inProgress":"\u8FDB\u884C\u4E2D","sessions.kanban.inReview":"\u5F85\u786E\u8BA4","sessions.kanban.done":"\u5DF2\u5B8C\u6210","sessions.kanban.updated":"\u66F4\u65B0\u4E8E {time}","sessions.kanban.moreHidden":"\u8FD8\u6709 {count} \u4E2A\u672A\u663E\u793A","sessions.kanban.openTab":"\u65B0\u6807\u7B7E\u9875\u6253\u5F00","sessions.kanban.openFeishu":"\u6253\u5F00\u98DE\u4E66","sessions.kanban.terminalLoading":"\u6B63\u5728\u6253\u5F00\u7EC8\u7AEF\u2026","sessions.kanban.rename":"\u91CD\u547D\u540D\uFF08\u53CC\u51FB\u6807\u9898\u4E5F\u53EF\uFF09","sessions.kanban.renameFail":"\u91CD\u547D\u540D\u5931\u8D25","sessions.kanban.moveFail":"\u79FB\u52A8\u5931\u8D25","sessions.kanban.groupBy":"\u5206\u7EC4\u7EF4\u5EA6","sessions.kanban.groupFlow":"\u5DE5\u4F5C\u6D41","sessions.kanban.groupTeam":"\u56E2\u961F","sessions.kanban.groupBot":"\u673A\u5668\u4EBA","sessions.kanban.teamLoading":"\u6B63\u5728\u52A0\u8F7D\u56E2\u961F\u2026","sessions.kanban.noTeam":"\u6682\u65E0\u56E2\u961F","sessions.kanban.teamScope":"{chats} \u4E2A\u534F\u4F5C\u7FA4 \xB7 {sessions} \u4E2A\u4F1A\u8BDD","sessions.kanban.remoteHint":"\u6765\u81EA {name} \u90E8\u7F72\u7684\u4F1A\u8BDD\uFF08\u5FEB\u7167\uFF0C\u7EC8\u7AEF/\u5386\u53F2\u5728\u5BF9\u65B9\u673A\u5668\u4E0A\uFF09","sessions.kanban.clusterDragHint":"\u62D6\u52A8\u6807\u9898\u6574\u7EC4\u79FB\u52A8","sessions.history.title":"\u4F1A\u8BDD\u5386\u53F2","sessions.history.loading":"\u6B63\u5728\u62C9\u53D6\u98DE\u4E66\u6D88\u606F\u2026","sessions.history.fail":"\u5386\u53F2\u62C9\u53D6\u5931\u8D25","sessions.history.empty":"\u6CA1\u6709\u6D88\u606F","sessions.history.user":"\u7528\u6237","sessions.history.owner":"\u521B\u5EFA\u8005","sessions.history.staleHint":"dashboard \u6216 daemon \u8FDB\u7A0B\u53EF\u80FD\u8FD8\u5728\u8DD1\u65E7\u7248\u672C\uFF0Cbotmux restart \u540E\u91CD\u8BD5","groups.title":"\u7FA4\u7EC4\u4E0E Bot","groups.subtitle":"\u67E5\u770B chat x bot \u8986\u76D6\u77E9\u9635\uFF0C\u7BA1\u7406\u62C9\u7FA4\u3001oncall\u3001\u9000\u7FA4\u548C\u89E3\u6563\u3002","groups.search":"\u641C\u7D22\u7FA4\u540D / ID / owner","groups.missingOnly":"\u4EC5\u7F3A bot","groups.refresh":"\u5237\u65B0","groups.create":"\u65B0\u5EFA\u7FA4","groups.chat":"\u7FA4\u804A","groups.actions":"\u64CD\u4F5C","groups.addBots":"\u6DFB\u52A0 bot","groups.manage":"\u7BA1\u7406","groups.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u7FA4\u804A\u3002","groups.createTitle":"\u65B0\u5EFA\u7FA4\u804A","groups.createHelp":"\u9009\u62E9\u8981\u9080\u8BF7\u7684 bot\u3002dashboard \u4F1A\u81EA\u52A8\u9009\u62E9\u5728\u7EBF daemon \u4F5C\u4E3A\u521B\u5EFA\u8005\u3002","groups.name":"\u7FA4\u540D","groups.namePlaceholder":"\u4F8B\u5982 AI ChangeLog","groups.bindDir":"\u7ED1\u5B9A\u76EE\u5F55","groups.bindDirHelp":"\u65B0\u8BDD\u9898\u76F4\u63A5\u7528\u8BE5\u76EE\u5F55\u542F\u52A8 CLI\uFF0C\u8DF3\u8FC7 repo \u9009\u62E9\u3002","groups.botPicker":"Bot","groups.createSubmit":"\u521B\u5EFA","groups.cancel":"\u53D6\u6D88","groups.successTitle":"\u7FA4\u521B\u5EFA\u6210\u529F","groups.openGroup":"\u6253\u5F00\u65B0\u7FA4","groups.manageTitle":"\u7BA1\u7406 {name}","groups.owner":"\u7FA4\u4E3B","groups.oncall":"Oncall \u6A21\u5F0F","groups.oncallHelp":"\u5F00\u542F\u540E\uFF0C\u7FA4\u5185\u6210\u5458\u53EF @ \u673A\u5668\u4EBA\uFF1B\u65B0\u8BDD\u9898\u76F4\u63A5\u4F7F\u7528\u7ED1\u5B9A\u76EE\u5F55\u3002","groups.leaveTitle":"\u9009\u62E9\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.leaveSelected":"\u9009\u4E2D\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.disband":"\u89E3\u6563\u7FA4\u804A","groups.dangerHint":"\u89E3\u6563\u4EC5\u5F53\u5728\u7FA4\u673A\u5668\u4EBA\u662F\u7FA4\u4E3B\u65F6\u624D\u4F1A\u6210\u529F\uFF0C\u5426\u5219\u5EFA\u8BAE\u4F7F\u7528\u9000\u51FA\u7FA4\u804A\u3002","groups.save":"\u4FDD\u5B58","groups.needWorkingDir":"\u8BF7\u586B\u5DE5\u4F5C\u76EE\u5F55","groups.noBotsOnline":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u8BF7\u5148\u91CD\u542F daemon\u3002","schedules.title":"\u5B9A\u65F6\u4EFB\u52A1","schedules.subtitle":"\u8DE8 daemon \u67E5\u770B\u3001\u6682\u505C\u3001\u6062\u590D\u548C\u7ACB\u5373\u89E6\u53D1\u5B9A\u65F6\u4EFB\u52A1\u3002","schedules.search":"\u641C\u7D22\u540D\u79F0 / prompt / \u5DE5\u4F5C\u76EE\u5F55","schedules.anyKind":"\u5168\u90E8\u7C7B\u578B","schedules.enabledOnly":"\u4EC5\u542F\u7528","schedules.name":"\u540D\u79F0","schedules.bot":"bot","schedules.schedule":"\u89C4\u5219","schedules.next":"\u4E0B\u6B21","schedules.last":"\u4E0A\u6B21","schedules.repeat":"\u91CD\u590D","schedules.enabled":"\u542F\u7528","schedules.actions":"\u64CD\u4F5C","schedules.runNow":"\u7ACB\u5373\u8FD0\u884C","schedules.pause":"\u6682\u505C","schedules.resume":"\u6062\u590D","schedules.delivery":"\u6295\u9012","schedules.deliveryOrigin":"\u539F\u8BDD\u9898","schedules.deliveryNewTopic":"\u6BCF\u6B21\u65B0\u8BDD\u9898","schedules.deliveryLocal":"\u4EC5\u8BB0\u5F55","schedules.useNewTopic":"\u6539\u4E3A\u6BCF\u6B21\u65B0\u8BDD\u9898","schedules.useOrigin":"\u6539\u4E3A\u539F\u8BDD\u9898","schedules.empty":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","settings.title":"\u5168\u5C40\u8BBE\u7F6E","settings.subtitle":"\u7BA1\u7406\u672C\u673A botmux dashboard \u4E0E\u6240\u6709 bot \u5171\u4EAB\u7684\u5168\u5C40\u884C\u4E3A\u3002","settings.loading":"\u6B63\u5728\u52A0\u8F7D\u8BBE\u7F6E\u2026","settings.loadFailed":"\u8BBE\u7F6E\u52A0\u8F7D\u5931\u8D25","settings.readOnlyVisitor":"\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u4FEE\u6539\u8BBE\u7F6E\u9700\u8981\u6388\u6743\u94FE\u63A5\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09","settings.sectionAccess":"\u8BBF\u95EE\u6743\u9650","settings.publicReadOnly":"\u5141\u8BB8\u65E0 token \u53EA\u8BFB\u8BBF\u95EE dashboard","settings.publicReadOnlyHelp":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 token \u7684\u8BBF\u95EE\u8005\u53EF\u4EE5\u67E5\u770B dashboard\u3001\u4F1A\u8BDD\u3001\u5B9A\u65F6\u4EFB\u52A1\u548C SSE\uFF1B\u5173\u95ED\u3001\u6682\u505C\u3001\u5BA1\u6279\u7B49\u5199\u64CD\u4F5C\u4ECD\u5FC5\u987B\u901A\u8FC7 token \u9274\u6743\u3002\u654F\u611F\u7EC8\u7AEF\u539F\u59CB\u65E5\u5FD7\u59CB\u7EC8\u9700\u8981 token\u3002","settings.sectionCards":"\u98DE\u4E66\u5361\u7247","settings.openTerminalInFeishu":"\u6D41\u5F0F\u5361\u7247\u7EC8\u7AEF\u6309\u94AE\u5728\u98DE\u4E66\u4FA7\u680F\u6253\u5F00","settings.openTerminalInFeishuHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF1A\u7EC8\u7AEF\u6309\u94AE\u76F4\u63A5\u6253\u5F00 Web Terminal URL\u3002\u5F00\u542F\u540E\u4F7F\u7528\u98DE\u4E66 web_url/open \u5305\u88C5\uFF0C\u5728\u98DE\u4E66 PC \u4FA7\u680F\u91CC\u6253\u5F00\uFF1B\u5199\u6743\u9650\u4ECD\u7531\u7EC8\u7AEF token \u63A7\u5236\u3002","settings.sectionRepoPicker":"\u4ED3\u5E93\u9009\u62E9","settings.repoPickerMode":"\u4ED3\u5E93\u9009\u62E9\u5361\u6A21\u5F0F","settings.repoPickerModeAll":"\u4ED3\u5E93 + worktree","settings.repoPickerModeRepos":"\u4EC5\u4E3B\u4ED3\u5E93","settings.repoPickerModeHelp":"\u9ED8\u8BA4\u663E\u793A\u4ED3\u5E93\u548C linked worktree\u3002\u9009\u62E9\u300C\u4EC5\u4E3B\u4ED3\u5E93\u300D\u540E\uFF0C\u521D\u59CB\u5316\u548C\u88F8 /repo \u7684\u9009\u62E9\u5361\u53EA\u5217\u4E3B\u4ED3\u5E93\uFF1B\u663E\u5F0F /repo /abs/path/to/worktree \u4ECD\u53EF\u76F4\u8FBE worktree\u3002","settings.saving":"\u4FDD\u5B58\u4E2D\u2026","settings.saved":"\u5DF2\u4FDD\u5B58","settings.saveFailed":"\u4FDD\u5B58\u5931\u8D25","settings.sectionMaintenance":"\u81EA\u52A8\u7EF4\u62A4","settings.autoUpdate":"\u81EA\u52A8\u66F4\u65B0","settings.autoUpdateHelp":"\u9ED8\u8BA4\u5173\u95ED\u3002\u5230\u70B9\u6267\u884C npm install -g botmux@latest \u5B89\u88C5\u6700\u65B0\u7248\u672C\uFF08\u53EA\u4E0B\u8F7D\u5B89\u88C5\u3001\u672C\u8EAB\u4E0D\u91CD\u542F\uFF09\u3002\u4EC5 npm \u5168\u5C40\u5B89\u88C5\u53EF\u7528\u3002","settings.autoRestart":"\u81EA\u52A8\u91CD\u542F","settings.autoRestartHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF0C\u9700\u5148\u5F00\u542F\u81EA\u52A8\u66F4\u65B0\u3002\u81EA\u52A8\u66F4\u65B0\u88C5\u5230\u65B0\u7248\u672C\u540E\uFF0C\u82E5\u6CA1\u6709\u8FDB\u884C\u4E2D\u7684\u4F1A\u8BDD\u5219\u81EA\u52A8\u91CD\u542F\u4EE5\u751F\u6548\uFF08\u649E\u4E0A\u5FD9\u788C\u4F1A\u8BDD\u5219\u8DF3\u5230\u6B21\u65E5\uFF09\u3002","settings.autoUpdateLocalDev":"\u5F53\u524D\u4E3A\u672C\u5730\u5F00\u53D1\u5B89\u88C5\uFF08\u4ECE\u6E90\u7801\u8FD0\u884C\uFF09\uFF0C\u81EA\u52A8\u66F4\u65B0\u4E0D\u53EF\u7528\u3002","settings.maintenanceTime":"\u65F6\u95F4","skills.title":"Skill \u7BA1\u7406","skills.subtitle":"\u7BA1\u7406 botmux \u7684 CLI \u65E0\u5173 Skill \u8D44\u4EA7\uFF0C\u5E76\u6309 bot \u9009\u62E9\u4F18\u5148\u62AB\u9732\u3002","skills.installed":"\u5DF2\u5B89\u88C5 Skills","skills.installedHelp":"\u672C\u673A registry \u4E2D\u53EF\u88AB bot \u4F18\u5148\u62AB\u9732\u7684 Skill \u8D44\u4EA7\u3002","skills.overviewTitle":"\u6309 Bot \u7EC4\u7EC7 Skill \u8D44\u4EA7","skills.overviewBody":"\u5168\u5C40 Skill \u6CE8\u5165\u914D\u7F6E\u63A7\u5236\u4F1A\u8BDD\u6CE8\u5165\u7B56\u7565\uFF1B\u6BCF\u4E2A bot \u53EA\u7EF4\u62A4\u81EA\u5DF1\u7684\u4F18\u5148\u62AB\u9732\u5217\u8868\u3002","skills.metricInstalled":"\u5DF2\u5B89\u88C5 Skills","skills.metricBots":"\u5DF2\u914D\u7F6E Bot","skills.metricAttached":"\u4F18\u5148\u5F15\u7528","skills.install":"\u5B89\u88C5 Skill","skills.installInfoLabel":"\u5B89\u88C5\u4F4D\u7F6E\u8BF4\u660E","skills.installInfo":`\u6CE8\u518C: ~/.botmux/skills/registry.json
2
+ \u5B89\u88C5: ~/.botmux/skills/store/\u6280\u80FD\u540D\uFF1BGit \u7F13\u5B58: ~/.botmux/skills/sources
3
+ \u9694\u79BB: \u4E0D\u5199\u5165 Codex/Claude \u5168\u5C40\u76EE\u5F55\uFF1B\u672C\u673A CLI Skill \u76F4\u63A5\u5F15\u7528\u539F\u5730\u5740`,"skills.source":"\u5BFC\u5165\u5730\u5740","skills.sourcePlaceholder":"\u7C98\u8D34 GitHub Skill \u9875\u9762\u3001Git URL \u6216\u672C\u673A Skill \u76EE\u5F55","skills.sourceHelpRemoteLabel":"GitHub / Git: ","skills.sourceHelpRemote":"\u53EF\u7C98\u8D34 Skill \u76EE\u5F55\u9875\u9762\u6216\u4ED3\u5E93\u5730\u5740\uFF1B\u4ED3\u5E93\u5730\u5740\u9700\u586B\u5199\u4ED3\u5E93\u5185\u8DEF\u5F84\u3002","skills.sourceHelpLocalLabel":"\u672C\u673A CLI Skill \u76EE\u5F55: ","skills.sourceHelpLocal":"\u76F4\u63A5\u5F15\u7528\u539F\u5730\u5740\uFF0C\u4E0D\u590D\u5236\u5230 botmux store\u3002","skills.path":"\u4ED3\u5E93\u5185\u8DEF\u5F84\uFF08\u53EF\u9009\uFF09","skills.pathPlaceholder":"\u7559\u7A7A\u5219\u4F7F\u7528 GitHub URL \u4E2D\u7684\u8DEF\u5F84","skills.ref":"Ref\uFF08\u53EF\u9009\uFF09","skills.refPlaceholder":"\u7559\u7A7A\u5219\u4F7F\u7528 GitHub URL \u4E2D\u7684\u5206\u652F\u6216\u9ED8\u8BA4 HEAD","skills.link":"\u672C\u5730\u94FE\u63A5\uFF08\u4E0D\u590D\u5236\uFF09","skills.installSubmit":"\u5B89\u88C5","skills.update":"\u66F4\u65B0","skills.remove":"\u5220\u9664","skills.pageStatus":"{page} / {pages}","skills.prevPage":"\u4E0A\u4E00\u9875","skills.nextPage":"\u4E0B\u4E00\u9875","skills.empty":"\u6682\u65E0\u5DF2\u5B89\u88C5 skill\u3002\u53EF\u4EE5\u4ECE\u672C\u673A\u76EE\u5F55\u3001Git \u6216 GitHub \u5B89\u88C5\u3002","skills.globalDefaults":"\u5168\u5C40 Skill \u6CE8\u5165\u914D\u7F6E","skills.globalProject":"\u5DE5\u4F5C\u533A Skill","skills.globalProjectOff":"\u5FFD\u7565\u5DE5\u4F5C\u533A Skill","skills.globalProjectOffHelp":"\u4EC5\u8BFB\u53D6\u5168\u5C40 CLI Skill \u548C botmux Skill","skills.globalProjectAll":"\u8BFB\u53D6\u5DE5\u4F5C\u533A Skill","skills.globalProjectAllHelp":`\u8BFB\u53D6 .agents/skills \u4E0E
4
+ .botmux/skills`,"skills.globalDelivery":"Skill \u6CE8\u5165\u65B9\u5F0F","skills.bots":"Bot Skill \u914D\u7F6E","skills.botsHelp":"\u4E3A\u6BCF\u4E2A bot \u9009\u62E9\u6700\u9700\u8981\u4F18\u5148\u62AB\u9732\u7684 Skill\u3002","skills.botCount":"{count} \u4E2A Bot","skills.scrollBotsPrev":"\u5411\u5DE6\u67E5\u770B Bot","skills.scrollBotsNext":"\u5411\u53F3\u67E5\u770B Bot","skills.skillCount":"{count} \u4E2A Skill","skills.attach":"\u52A0\u5165\u4F18\u5148\u62AB\u9732","skills.detach":"\u79FB\u9664","skills.detachNamed":"\u79FB\u9664 {skill}","skills.delivery":"\u6CE8\u5165\u65B9\u5F0F","skills.deliveryAuto":"\u81EA\u52A8","skills.deliveryAutoHelp":"\u4F18\u5148\u7528 CLI \u539F\u751F\u901A\u9053\uFF1B\u4E0D\u652F\u6301\u65F6\u81EA\u52A8\u6539\u7528\u63D0\u793A\u8BCD\u6CE8\u5165","skills.deliveryPrompt":"\u63D0\u793A\u8BCD","skills.deliveryPromptHelp":"\u628A Skill \u6E05\u5355\u5199\u5165\u4F1A\u8BDD\u63D0\u793A\u8BCD\uFF0C\u517C\u5BB9\u6240\u6709 CLI","skills.deliveryNative":"\u539F\u751F","skills.deliveryNativeHelp":"\u53EA\u4EA4\u7ED9 CLI \u81EA\u5DF1\u7684 Skill \u673A\u5236\uFF0C\u4E0D\u505A\u63D0\u793A\u8BCD\u515C\u5E95","skills.projectMode":"\u5DE5\u4F5C\u533A Skills","skills.projectDefault":"\u8DDF\u968F\u5168\u5C40","skills.projectDefaultHelp":"\u4F7F\u7528\u5DE6\u4FA7\u9879\u76EE Skill \u9ED8\u8BA4\u503C","skills.projectOff":"\u4E0D\u8BFB\u53D6","skills.projectOffHelp":"\u8FD9\u4E2A bot \u4E0D\u8BFB\u53D6\u5DE5\u4F5C\u533A skill","skills.projectAll":"\u8BFB\u53D6","skills.projectAllHelp":"\u8FD9\u4E2A bot \u52A0\u5165\u5DE5\u4F5C\u533A skill \u5019\u9009","skills.priority":"\u4F18\u5148 skills","skills.noPriority":"\u672A\u914D\u7F6E\uFF0C\u4FDD\u6301 CLI \u9ED8\u8BA4\u884C\u4E3A","skills.dangling":"\u672A\u5B89\u88C5","skills.removeInUse":'Skill "{skill}" \u4ECD\u88AB\u4EE5\u4E0B\u914D\u7F6E\u5F15\u7528\uFF1A{refs}\u3002\u5220\u9664\u53EA\u4F1A\u79FB\u9664 registry \u6587\u4EF6\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u6E05\u7406\u5F15\u7528\u3002\u7EE7\u7EED\u5220\u9664\uFF1F',"skills.saved":"\u5DF2\u4FDD\u5B58","skills.failed":"\u5931\u8D25","skills.jobRunning":"\u5904\u7406\u4E2D...","skills.refresh":"\u5237\u65B0","botDefaults.title":"\u6570\u5B57\u5458\u5DE5\u6863\u6848","botDefaults.subtitle":"\u6BCF\u4F4D\u5458\u5DE5\u7684\u9ED8\u8BA4\u884C\u4E3A\uFF1Aoncall\u3001\u4E3B\u52A8\u5F00\u5DE5\u3001\u4EBA\u8BBE\u89D2\u8272\u3001\u5361\u7247\u4E0E\u6388\u6743\u3002","botDefaults.metaOnline":"\u5728\u7EBF \xB7 daemon \u6B63\u5E38","botDefaults.search":"\u641C\u7D22 bot \u540D / app id","botDefaults.refresh":"\u5237\u65B0","botDefaults.sectionOncall":"\u65B0\u7FA4 Oncall","botDefaults.sectionBrand":"\u5361\u7247\u7B7E\u540D","botDefaults.warning":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 oncall binding \u7684\u7FA4\u4F1A\u5728\u4E0B\u6B21\u5F00\u65B0\u8BDD\u9898\u65F6\u81EA\u52A8\u7ED1\u5B9A\u5230\u8BE5\u76EE\u5F55\uFF1B\u624B\u52A8\u7ED1\u5B9A\u6216\u624B\u52A8\u89E3\u7ED1\u8FC7\u7684\u7FA4\u4E0D\u4F1A\u88AB\u8986\u76D6\u3002","botDefaults.empty":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u5148 botmux restart \u8BA9 daemon \u4E0A\u7EBF\u3002","botDefaults.defaultOncall":"\u9ED8\u8BA4\u8FDB\u5165 oncall \u6A21\u5F0F","botDefaults.defaultOncallHelp":"\u6240\u6709\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8\u7ED1\u5B9A","botDefaults.workingDir":"\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55","botDefaults.lastEnabled":"\u4E0A\u6B21\u542F\u7528\u65F6\u95F4","botDefaults.autobound":"\u5DF2\u81EA\u52A8\u7ED1\u5B9A {count} \u4E2A\u7FA4","botDefaults.save":"\u4FDD\u5B58","botDefaults.required":"\u5F00\u542F\u65F6\u5FC5\u987B\u586B\u5DE5\u4F5C\u76EE\u5F55","botDefaults.brandLabel":"\u4E2A\u6027\u7B7E\u540D\uFF08\u5361\u7247\u9875\u811A\uFF09","botDefaults.brandLabelHelp":"\u8BE5 bot \u53D1\u51FA\u7684\u5361\u7247\u9875\u811A\u7B7E\u540D\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u4E0D\u663E\u793A\uFF1B\u586B\u5199\uFF1D\u81EA\u5B9A\u4E49\uFF08\u652F\u6301 markdown\uFF0C\u5982 [Acme](https://\u2026)\uFF09\uFF1B\u6062\u590D\u9ED8\u8BA4\uFF1D\u663E\u793A botmux\u3002","botDefaults.brandLabelPlaceholder":"\u9ED8\u8BA4\uFF1Abotmux\uFF08\u7559\u7A7A\u5219\u4E0D\u663E\u793A\uFF09","botDefaults.sectionSandbox":"\u6587\u4EF6\u6C99\u76D2\uFF08oncall\uFF09","botDefaults.sandboxToggle":"\u5F00\u542F\u6587\u4EF6\u6C99\u76D2","botDefaults.sandboxHelp":"\u5F00\u542F\u540E\uFF0C\u8BE5 bot \u7684\u6BCF\u4E2A\u4F1A\u8BDD\u90FD\u8DD1\u5728\u6309\u4F1A\u8BDD\u9694\u79BB\u7684\u6C99\u76D2\u91CC\uFF1A\u53EA\u770B\u5F97\u5230\u4E00\u4EFD\u9879\u76EE\u526F\u672C\uFF0C\u78B0\u4E0D\u5230\u4F60\u78C1\u76D8\u4E0A\u7684\u771F\u5B9E\u6587\u4EF6\u3001\u5BC6\u94A5\u3001\u522B\u7684\u4F1A\u8BDD\u6570\u636E\u3002\u9002\u5408\u628A\u673A\u5668\u4EBA\u5206\u4EAB\u7ED9\u534A\u53D7\u4FE1\u4EFB\u7684\u4EBA\uFF08oncall\uFF09\u3002\u4EC5 Linux \u751F\u6548\uFF0C\u4E0B\u4E2A\u65B0\u4F1A\u8BDD\u8D77\u6548\u3002","botDefaults.sandboxSaved":"\u5DF2\u4FDD\u5B58\uFF08\u4E0B\u4E2A\u65B0\u4F1A\u8BDD\u751F\u6548\uFF09","botDefaults.brandSave":"\u4FDD\u5B58\u7B7E\u540D","botDefaults.brandReset":"\u6062\u590D\u9ED8\u8BA4","botDefaults.brandStateDefault":"\u5F53\u524D\uFF1A\u9ED8\u8BA4 botmux","botDefaults.brandStateOff":"\u5F53\u524D\uFF1A\u5DF2\u5173\u95ED","botDefaults.brandStateCustom":"\u5F53\u524D\uFF1A\u81EA\u5B9A\u4E49","botDefaults.sectionCard":"\u5361\u7247\u884C\u4E3A","botDefaults.disableStreaming":"\u5173\u95ED\u98DE\u4E66\u6D41\u5F0F\u5361\u7247","botDefaults.disableStreamingHelp":"\u4E0D\u518D\u53D1\u5B9E\u65F6\u5237\u65B0\u7684\u4F1A\u8BDD\u72B6\u6001\u5361\uFF08\u542B\u300C\u6253\u5F00\u7EC8\u7AEF\u300D\u5165\u53E3\uFF09\uFF1B\u4EFB\u52A1\u6700\u7EC8\u7ED3\u679C\u4ECD\u901A\u8FC7\u6D88\u606F\u9001\u8FBE\u3002\u9002\u5408\u5ACC\u6D41\u5F0F\u5361\u7247\u70E6\u7684\u573A\u666F\u3002","botDefaults.writableLink":"\u5361\u7247\u4E0A\u76F4\u63A5\u7ED9\u53EF\u64CD\u4F5C\uFF08\u53EF\u5199\uFF09\u7EC8\u7AEF\u94FE\u63A5","botDefaults.writableLinkHelp":"\u26A0\uFE0F \u5728\u6D41\u5F0F\u5361\u7247\u6B63\u6587\u76F4\u63A5\u8D34\u51FA\u53EF\u5199\u7EC8\u7AEF\u94FE\u63A5\uFF0C\u7FA4\u5185\u4EFB\u4F55\u4EBA\u90FD\u80FD\u70B9\u5F00\u5E76\u64CD\u63A7\u7EC8\u7AEF\u3002\u4E0D\u52FE\uFF1D\u4FDD\u6301\u73B0\u72B6\uFF08\u8D70\u300C\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u300D\u6309\u94AE\u79C1\u804A\u53D1\u7ED9\u70B9\u51FB\u8005\uFF09\u3002","botDefaults.writableLinkMoot":"\u5DF2\u5173\u95ED\u6D41\u5F0F\u5361\u7247","botDefaults.privateCard":"/card \u53D1\u79C1\u5BC6\u5361\u7247\uFF08\u4EC5\u6388\u6743\u4EBA\u53EF\u89C1\uFF09","botDefaults.privateCardHelp":"\u5F00\u542F\u540E /card \u6539\u7528\u300C\u4EC5\u7279\u5B9A\u4EBA\u53EF\u89C1\u300D\u7684\u4E34\u65F6\u5361\u7247\uFF1A\u53EA\u53D1\u7ED9 owner\uFF08allowedUsers\uFF09\uFF0C/grant \u6388\u6743\u5BF9\u8BDD\u7684\u4EBA\u548C\u7FA4\u91CC\u5176\u4ED6\u4EBA\u90FD\u770B\u4E0D\u5230\u3002\u4EE3\u4EF7\uFF1A\u662F\u9759\u6001\u5FEB\u7167\u3001\u4E0D\u4F1A\u5B9E\u65F6\u5237\u65B0\uFF1B\u4E14\u4EC5\u666E\u901A\u7FA4\u53EF\u7528\uFF08\u8BDD\u9898\u7FA4 / \u5355\u804A\u4F1A\u5931\u8D25\uFF0C\u4E0D\u964D\u7EA7\uFF09\u3002\u53EA\u5F71\u54CD /card \u547D\u4EE4\uFF0C\u81EA\u52A8\u6D41\u5F0F\u5361\u4E0D\u53D8\u3002","botDefaults.cardPrefSaved":"\u5DF2\u4FDD\u5B58","botDefaults.sectionRole":"\u9ED8\u8BA4\u89D2\u8272","botDefaults.roleHelp":"\u8BE5 bot \u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF08\u8DE8\u7FA4\u751F\u6548\uFF09\uFF0C\u4F1A\u6CE8\u5165\u5230\u8BE5 bot \u5728\u5404\u7FA4\u7684\u4F1A\u8BDD\u91CC\uFF1B\u5355\u4E2A\u7FA4\u53EF\u5728\u300C\u89D2\u8272\u300D\u9875\u5355\u72EC\u8986\u76D6\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u5220\u9664\u3002","botDefaults.rolePlaceholder":"\u4F8B\u5982\uFF1A\u4F60\u662F\u540E\u7AEF\u6392\u969C\u52A9\u624B\uFF0C\u56DE\u7B54\u7B80\u6D01\u3001\u4F18\u5148\u7ED9\u53EF\u6267\u884C\u547D\u4EE4\u2026","botDefaults.roleSave":"\u4FDD\u5B58\u89D2\u8272","botDefaults.roleDelete":"\u5220\u9664","botDefaults.roleSaved":"\u5DF2\u4FDD\u5B58","botDefaults.roleDeleted":"\u5DF2\u5220\u9664","botDefaults.roleLoadErr":"\u89D2\u8272\u52A0\u8F7D\u5931\u8D25","botDefaults.sectionAutoStart":"\u4E3B\u52A8\u5F00\u5DE5","botDefaults.autoStartJoin":"\u88AB\u62C9\u8FDB\u65B0\u7FA4\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartJoinHelp":"\u5F00\u542F\u540E\uFF0C\u673A\u5668\u4EBA\u4E00\u88AB\u62C9\u8FDB\u65B0\u7FA4\uFF08\u7FA4\u91CC\u6709\u6388\u6743\u7528\u6237 allowedUsers \u65F6\uFF09\u5C31\u81EA\u52A8\u5F00\u4E00\u4E2A\u4F1A\u8BDD\u5F00\u59CB\u5DE5\u4F5C\uFF0C\u65E0\u9700 @\u3002\u5728\u673A\u5668\u4EBA\u7684\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55\u542F\u52A8\uFF1B\u672A\u914D\u7F6E\u9ED8\u8BA4\u76EE\u5F55\u65F6\u5148\u5F39\u4ED3\u5E93\u9009\u62E9\u5361\u8BA9\u4F60\u9009\u3002\u524D\u63D0\uFF1A\u9700\u5728\u98DE\u4E66\u5F00\u653E\u5E73\u53F0\u4E3A\u672C\u5E94\u7528\u8BA2\u9605\u300C\u673A\u5668\u4EBA\u8FDB\u7FA4\u300D\u4E8B\u4EF6 im.chat.member.bot.added_v1\uFF0C\u5E76\u5F00\u901A\u7FA4\u6210\u5458\u8BFB\u53D6\u6743\u9650\u3002","botDefaults.autoStartJoinPrompt":"\u5165\u7FA4\u9996\u8F6E prompt\uFF08\u53EF\u9009\uFF09","botDefaults.autoStartJoinPromptPlaceholder":"\u586B\u4E86\uFF1D\u4F5C\u4E3A\u5165\u7FA4\u540E\u7684\u7B2C\u4E00\u6761\u4EFB\u52A1\uFF1B\u7559\u7A7A\uFF1D\u673A\u5668\u4EBA\u81EA\u5DF1\u770B\u7FA4\u91CC\u4FE1\u606F\u51B3\u5B9A\u505A\u4EC0\u4E48","botDefaults.autoStartJoinPromptSave":"\u4FDD\u5B58 prompt","botDefaults.autoStartTopic":"\u8BDD\u9898\u7FA4\u65B0\u8BDD\u9898\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartTopicHelp":"\u5F00\u542F\u540E\uFF0C\u5728\u8BDD\u9898\u7FA4\u91CC\u6BCF\u5F53\u6709\u4EBA\u65B0\u5F00\u4E00\u4E2A\u8BDD\u9898\uFF0C\u673A\u5668\u4EBA\u5C31\u4F1A\u81EA\u52A8\u63A5\u5165\u8BE5\u8BDD\u9898\u3001\u628A\u9996\u6761\u6D88\u606F\u5F53\u4F5C\u4EFB\u52A1\u5F00\u59CB\u5904\u7406\uFF0C\u65E0\u9700 @\u3002\u4EC5\u5BF9\u8BDD\u9898\u7FA4\u751F\u6548\uFF0C\u666E\u901A\u7FA4\u4E0D\u53D7\u5F71\u54CD\u3002","botDefaults.sectionSessionMode":"\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.p2pMode":"\u79C1\u804A\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.p2pThread":"thread\uFF08\u6BCF\u6761 DM \u72EC\u7ACB\u4F1A\u8BDD\uFF09","botDefaults.p2pChat":"chat\uFF08\u6241\u5E73\u8FDE\u7EED\u5355\u804A\u4F1A\u8BDD\uFF09","botDefaults.p2pHelp":"\u79C1\u804A\uFF081:1 DM\uFF09\u7684\u4F1A\u8BDD\u65B9\u5F0F\uFF1Athread = \u6BCF\u6761\u9876\u5C42\u6D88\u606F\u5404\u81EA\u8D77\u72EC\u7ACB\u4F1A\u8BDD\uFF08\u907F\u514D\u628A\u5BF9\u8BDD\u5806\u8FDB\u540C\u4E00\u4E2A CLI \u8FDB\u7A0B\uFF09\uFF1Bchat = \u6574\u6BB5 DM \u5171\u7528\u4E00\u4E2A\u8FDE\u7EED\u4F1A\u8BDD\u3001\u5171\u4EAB\u4E0A\u4E0B\u6587\uFF08\u7C7B Hermes\uFF09\u3002\u6539\u540E\u7ACB\u5373\u751F\u6548\u3002","botDefaults.regularGroupMode":"\u666E\u901A\u7FA4\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.regularGroupModeChat":"chat\uFF08\u6241\u5E73\u8FDE\u7EED\u5355\u804A\u4F1A\u8BDD\uFF0C\u9ED8\u8BA4\uFF09","botDefaults.regularGroupModeNewTopic":"new-topic\uFF08\u6BCF\u6761\u9876\u5C42 @ \u5404\u5F00\u72EC\u7ACB\u8BDD\u9898\u4E0E\u4F1A\u8BDD\uFF09","botDefaults.regularGroupModeShared":"shared\uFF08\u8BDD\u9898\u6A21\u5F0F\u4F46\u590D\u7528\u540C\u4E00\u4E2A session\uFF09","botDefaults.regularGroupModeHelp":"\u666E\u901A\u7FA4\uFF08\u975E\u8BDD\u9898\u7FA4\uFF09\u91CC @ \u8BE5 bot \u7684\u65B0\u9876\u5C42\u6D88\u606F\u600E\u4E48\u5F00\u4F1A\u8BDD\uFF1Achat = \u6574\u7FA4\u5171\u7528\u4E00\u4E2A\u8FDE\u7EED\u4F1A\u8BDD\uFF08\u9ED8\u8BA4\uFF09\uFF1Bnew-topic = \u6BCF\u6761\u9876\u5C42 @ \u5728\u539F\u6D88\u606F\u4E0B\u5F00\u72EC\u7ACB\u8BDD\u9898\u3001\u5404\u81EA\u72EC\u7ACB\u4F1A\u8BDD\uFF1Bshared = \u8BDD\u9898\u6A21\u5F0F\u4F46\u590D\u7528\u540C\u4E00\u4E2A session\uFF08\u56DE\u590D\u843D\u5728\u8BDD\u9898\u91CC\u3001\u4F46\u5171\u7528\u672C\u7FA4\u4F1A\u8BDD\u4E0E\u4E0A\u4E0B\u6587\uFF09\u3002\u8FD9\u662F per-bot \u9ED8\u8BA4\uFF0C\u5177\u4F53\u67D0\u4E2A\u7FA4\u53EF\u7528 /reply-mode \u5355\u72EC\u8986\u76D6\u3002\u6539\u540E\u7ACB\u5373\u751F\u6548\u3002","botDefaults.mentionMode":"\u7FA4\u804A @ \u7B56\u7565","botDefaults.mentionModeAlways":"\u90FD\u9700\u8981 @\uFF08\u9ED8\u8BA4\uFF09","botDefaults.mentionModeTopic":"\u4EC5\u8BDD\u9898\u5185\u4E0D\u9700\u8981 @","botDefaults.mentionModeNever":"\u6240\u6709\u6D88\u606F\u90FD\u4E0D\u9700\u8981 @","botDefaults.mentionModeHelp":"\u8BE5 bot \u5168\u5C40\u751F\u6548\uFF0C\u51B3\u5B9A\u7FA4\u91CC\u8981\u4E0D\u8981 @ \u624D\u56DE\uFF1A\u300C\u90FD\u9700\u8981 @\u300D= \u4EFB\u4F55\u6D88\u606F\u90FD\u5F97 @\uFF08\u9ED8\u8BA4\uFF0C\u6700\u5B89\u5168\uFF1B\u591A\u4EBA\u7FA4\u91CC\u8BDD\u9898\u5185\u4E5F\u8981 @\uFF09\uFF1B\u300C\u4EC5\u8BDD\u9898\u5185\u4E0D\u9700\u8981 @\u300D= \u8D77\u65B0\u5BF9\u8BDD / \u9876\u5C42\u4ECD\u8981 @\uFF0C\u4F46\u5728\u8BE5 bot \u5DF2\u5F00\u7684\u4EFB\u4F55\u8BDD\u9898\u91CC\uFF08new-topic / shared / \u8BDD\u9898\u7FA4\uFF09\u540E\u7EED\u6D88\u606F\u514D @ \u7EED\u804A\uFF1B\u300C\u6240\u6709\u6D88\u606F\u90FD\u4E0D\u9700\u8981 @\u300D= \u8BE5 bot \u6709\u5BF9\u8BDD\u6743\u9650\u7684\u7FA4\u91CC\u975E @ \u6D88\u606F\u4E5F\u56DE\uFF08\u542B\u5168\u65B0\u6D88\u606F\u51B7\u542F\u52A8\uFF0C\u4EC5\u9002\u5408\u4E13\u7528 / \u503C\u73ED\u5C0F\u7FA4\uFF0C\u591A\u4EBA\u7FA4\u91CC\u4F1A\u89C1\u6D88\u606F\u5C31\u56DE\uFF09\u3002\u6CE8\uFF1A\u7FA4\u91CC\u53EA\u6709\u4F60\u548C\u8BE5 bot\uFF081 \u5BF9 1\uFF09\u65F6\u4E00\u76F4\u514D @\uFF0C\u4E0E\u672C\u8BBE\u7F6E\u65E0\u5173\u3002","botDefaults.docSubscribeMode":"\u6587\u6863\u8BA2\u9605\u89E6\u53D1\u8303\u56F4\uFF08\u9ED8\u8BA4\uFF09","botDefaults.docSubscribeModeMention":"\u4EC5\u8BC4\u8BBA @ \u6211\u624D\u89E6\u53D1","botDefaults.docSubscribeModeAll":"\u6240\u6709\u65B0\u8BC4\u8BBA\u90FD\u89E6\u53D1","botDefaults.docSubscribeModeHelp":"\u7528 /subscribe-lark-doc \u8BA2\u9605\u98DE\u4E66\u6587\u6863\u540E\uFF0C\u6587\u6863\u8BC4\u8BBA\u4F1A\u5582\u8FDB\u4F1A\u8BDD\u3001bot \u56DE\u590D\u53D1\u56DE\u8BC4\u8BBA\u3002\u8FD9\u91CC\u8BBE\u65B0\u8BA2\u9605\u7684\u9ED8\u8BA4\u89E6\u53D1\u8303\u56F4\uFF1A\u300C\u4EC5\u8BC4\u8BBA @ \u6211\u300D\u6700\u5B89\u5168\uFF08\u9632\u5237\u5C4F\uFF09\uFF1B\u300C\u6240\u6709\u65B0\u8BC4\u8BBA\u300D\u9002\u5408\u4E13\u7528\u6587\u6863\u3002","botDefaults.sectionGrant":"\u6388\u6743\u4E0E\u989D\u5EA6","botDefaults.restrictGrant":"\u9650\u5236\u88AB\u6388\u6743\u4EBA\u53EA\u80FD\u7EAF\u5BF9\u8BDD","botDefaults.restrictGrantHelp":"\u5F00\u542F\u540E\uFF0C\u88AB /grant \u6388\u6743\u7684\u4EBA\uFF08owner \u81EA\u5DF1\u4E0D\u53D7\u9650\uFF09\u53EA\u80FD\u53D1\u666E\u901A\u5BF9\u8BDD\uFF0C\u6240\u6709 slash \u547D\u4EE4\u4E00\u5F8B\u62E6\u622A\uFF1Abotmux \u81EA\u5E26\u547D\u4EE4\u3001\u900F\u4F20\u547D\u4EE4\u3001/workflow\u3001/introduce\u3001/t \u4EE5\u53CA CLI \u539F\u751F\u547D\u4EE4\uFF08/help \u7B49\uFF09\u3002\u5F62\u5982 /path/to/file \u7684\u5185\u5BB9\u4E0D\u4F1A\u88AB\u8BEF\u5224\u3002","botDefaults.quotaDefault":"\u9ED8\u8BA4\u6D88\u606F\u989D\u5EA6","botDefaults.quotaPlaceholder":"\u7559\u7A7A\uFF1D\u4E0D\u914D\u7F6E\u9ED8\u8BA4\u989D\u5EA6","botDefaults.quotaHelp":"\u4E0D\u5E26\u6570\u5B57\u7684 /grant @x \u9ED8\u8BA4\u7ED9\u7684\u6D88\u606F\u6761\u6570\u3002\u7559\u7A7A\u6216\u70B9\u300C\u5173\u95ED\u300D\u53EA\u662F\u4E0D\u518D\u7ED9\u88F8 /grant \u5957\u9ED8\u8BA4\u989D\u5EA6\uFF0C\u4E0D\u4F1A\u6E05\u6389\u5DF2\u6709\u7684\u989D\u5EA6\u8BA1\u6570\uFF0C\u4E5F\u4E0D\u5F71\u54CD\u663E\u5F0F /grant @x N\u2014\u2014\u5B83\u4EEC\u7167\u5E38\u7EE7\u7EED enforce\u3002\u989D\u5EA6\u7528\u5C3D\u4F1A\u81EA\u52A8\u64A4\u9500\u8BE5\u4EBA\u6388\u6743\u3002","botDefaults.quotaSave":"\u4FDD\u5B58\u989D\u5EA6","botDefaults.quotaOff":"\u5173\u95ED","botDefaults.quotaInvalid":"\u989D\u5EA6\u5FC5\u987B\u662F\u6B63\u6574\u6570","botDefaults.quotaStateOff":"\u5F53\u524D\uFF1A\u672A\u914D\u7F6E\u9ED8\u8BA4\u989D\u5EA6","botDefaults.quotaStateOn":"\u5F53\u524D\uFF1A\u6BCF\u4EBA {count} \u6761","botDefaults.sectionSessionCap":"\u4F1A\u8BDD\u6570\u4E0A\u9650","botDefaults.maxLiveWorkers":"\u6700\u5927\u540C\u65F6\u6D3B\u8DC3\u4F1A\u8BDD\u6570","botDefaults.maxLiveWorkersPlaceholder":"\u7559\u7A7A\uFF1D\u9ED8\u8BA4 30","botDefaults.maxLiveWorkersHelp":"\u672C Bot \u540C\u65F6\u4FDD\u6D3B\u7684\u4F1A\u8BDD\u6570\u4E0A\u9650\uFF0C\u7528\u4E8E\u63A7\u5236\u5185\u5B58\u3002\u8D85\u8FC7\u540E\u6700\u4E45\u672A\u7528\u7684\u4F1A\u8BDD\u81EA\u52A8\u4F11\u7720\uFF1Aworker \u548C CLI \u8FDB\u7A0B\u4E00\u8D77\u6740\u6389\u3001\u56DE\u6536\u5168\u90E8\u5185\u5B58\uFF0C\u4E0B\u6761\u6D88\u606F\u65F6\u4ECE\u78C1\u76D8 transcript \u51B7\u6062\u590D\uFF08--resume \u91CD\u5EFA\u4E0A\u4E0B\u6587\uFF0C\u51E0\u79D2\uFF0C\u4E0D\u518D\u5E38\u9A7B\u5360\u5185\u5B58\uFF09\u3002\u7559\u7A7A\uFF1D\u7528\u9ED8\u8BA4 30\uFF1B\u586B\u6570\u5B57\uFF1D\u672C Bot \u81EA\u5B9A\u4E49\uFF08\u60F3\u8981\u66F4\u591A\u5C31\u586B\u5927\u6570\u5B57\uFF09\u3002\u6CE8\u610F\uFF1A\u4F11\u7720\u53EA\u5BF9\u53EF\u6062\u590D\u540E\u7AEF\uFF08tmux/herdr/zellij\uFF09\u751F\u6548\uFF0C\u7EAF PTY \u4F1A\u8BDD\u4E0D\u53D7\u5F71\u54CD\uFF1B\u6B63\u5728\u51FA\u7B54\u6848\u7684\u4F1A\u8BDD\u4E0D\u4F1A\u88AB\u6253\u65AD\u3002","botDefaults.maxLiveWorkersSave":"\u4FDD\u5B58\u4E0A\u9650","botDefaults.maxLiveWorkersOff":"\u6062\u590D\u9ED8\u8BA4","botDefaults.maxLiveWorkersInvalid":"\u4E0A\u9650\u5FC5\u987B\u662F\u6B63\u6574\u6570","botDefaults.maxLiveWorkersStateDefault":"\u5F53\u524D\uFF1A\u9ED8\u8BA4 30 \u4E2A\u6D3B\u8DC3\u4F1A\u8BDD","botDefaults.maxLiveWorkersStateOn":"\u5F53\u524D\uFF1A\u6700\u591A {count} \u4E2A\u6D3B\u8DC3\u4F1A\u8BDD","nav.roles":"\u89D2\u8272\u7BA1\u7406","roles.title":"\u89D2\u8272\u7BA1\u7406","roles.subtitle":"\u4E3A\u6BCF\u4E2A\u7FA4\u7EC4\u7684\u6BCF\u4E2A Bot \u5355\u72EC\u8BBE\u7F6E\u89D2\u8272\u63D0\u793A\u8BCD\uFF0CBot \u5728\u8BE5\u7FA4\u4E2D\u4F1A\u4EE5\u6B64\u89D2\u8272\u884C\u4E8B\u3002","roles.search":"\u641C\u7D22\u7FA4\u540D/Bot/ID","roles.refresh":"\u5237\u65B0","roles.selectHint":"\u2190 \u5C55\u5F00\u7FA4\u7EC4\uFF0C\u9009\u62E9\u4E00\u4E2A Bot \u6765\u7F16\u8F91\u89D2\u8272","roles.editorPlaceholder":`\u8F93\u5165\u89D2\u8272\u63CF\u8FF0\uFF0C\u4F8B\u5982\uFF1A
2
5
  \u4F60\u662F\u672C\u7FA4\u7684\u6280\u672F\u987E\u95EE\uFF0C\u8D1F\u8D23\u56DE\u7B54\u6240\u6709\u6280\u672F\u95EE\u9898...`,"roles.configured":"\u5DF2\u914D\u7F6E","roles.unconfigured":"\u672A\u914D\u7F6E","roles.noChats":"\u6682\u65E0\u7FA4\u7EC4","roles.preview":"\u9884\u89C8","roles.previewEmpty":"\uFF08\u7A7A\u5185\u5BB9\uFF09","roles.saved":"\u5DF2\u4FDD\u5B58","roles.delete":"\u5220\u9664","roles.save":"\u4FDD\u5B58","roles.confirmDelete":"\u786E\u8BA4\u5220\u9664\u8BE5 Bot \u5728\u6B64\u7FA4\u7684\u89D2\u8272\u914D\u7F6E\uFF1F","roles.botsWithRoles":"\u4E2A Bot \u5DF2\u914D\u7F6E\u89D2\u8272","roles.emptyError":"\u89D2\u8272\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u8BF7\u5148\u8F93\u5165\u5185\u5BB9","roles.saveFailed":"\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5","common.none":"\u65E0","common.loading":"\u52A0\u8F7D\u4E2D\u2026","common.unknown":"\u672A\u77E5","common.now":"\u521A\u521A","common.never":"\u4ECE\u672A","common.all":"\u5168\u90E8","nav.workflows":"\u5DE5\u4F5C\u6D41(beta)","nav.workflowCatalog":"\u76EE\u5F55","workflow.subnav.runs":"\u8FD0\u884C","workflow.subnav.catalog":"\u76EE\u5F55","workflow.searchPlaceholder":"\u641C\u7D22 runId / workflowId / chatId","workflow.filter.nonTerminal":"\u975E\u7EC8\u6001","workflow.filter.all":"\u5168\u90E8","workflow.status.pending":"\u5F85\u5F00\u59CB","workflow.status.running":"\u8FD0\u884C\u4E2D","workflow.status.waiting":"\u7B49\u5F85\u4E2D","workflow.status.effectAttempting":"\u526F\u4F5C\u7528\u4E2D","workflow.status.timedOut":"\u5DF2\u8D85\u65F6","workflow.status.succeeded":"\u6210\u529F","workflow.status.failed":"\u5931\u8D25","workflow.status.cancelled":"\u5DF2\u53D6\u6D88","workflow.table.run":"\u8FD0\u884C","workflow.table.workflow":"\u5DE5\u4F5C\u6D41","workflow.table.status":"\u72B6\u6001","workflow.table.lastSeq":"\u6700\u540E\u5E8F\u53F7","workflow.table.dangling":"\u60AC\u6302 dEf/dAct/dWait","workflow.table.updated":"\u66F4\u65B0\u65F6\u95F4","workflow.table.chatApp":"\u7FA4\u804A / \u5E94\u7528","workflow.list.failedLoad":"\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","workflow.list.noRuns":"\u6CA1\u6709\u5339\u914D\u7684\u8FD0\u884C\u3002","workflow.list.noFilterMatch":"\u6CA1\u6709\u7B26\u5408\u7B5B\u9009\u6761\u4EF6\u7684\u8FD0\u884C\u3002","workflow.list.loaded":"{count} \u4E2A\u8FD0\u884C \xB7 \u5237\u65B0\u4E8E {time}","workflow.list.error":"\u9519\u8BEF\uFF1A{error}","workflow.detail.back":"\u8FD4\u56DE","workflow.detail.loading":"\u52A0\u8F7D\u4E2D...","workflow.detail.loadFailed":"\u52A0\u8F7D\u5931\u8D25","workflow.detail.cancel":"\u53D6\u6D88","workflow.detail.cliCancelOnly":"\u4EC5 CLI \u53EF\u53D6\u6D88","workflow.detail.cancelTitle":"\u53D6\u6D88\u8FD9\u4E2A\u5DE5\u4F5C\u6D41\u8FD0\u884C","workflow.detail.cliCancelTitle":"\u65E0\u6CD5\u5728\u9875\u9762\u53D6\u6D88\uFF1A\u8BF7\u4F7F\u7528 botmux workflow cancel {runId}","workflow.detail.nodes":"\u8282\u70B9 / Activity","workflow.detail.parallel":"\u5E76\u53D1\u6267\u884C","workflow.detail.parallelMeta":"{count} \u6B21\u5C1D\u8BD5 \xB7 \u6700\u9AD8\u5E76\u53D1 {max} \xB7 \u8FD0\u884C\u4E2D {running}","workflow.detail.noParallelData":"\u8FD8\u6CA1\u6709 attempt \u65F6\u95F4\u6570\u636E\u3002","workflow.detail.parallelNow":"\u73B0\u5728","workflow.detail.node":"\u8282\u70B9","workflow.detail.nodeStatus":"\u8282\u70B9\u72B6\u6001","workflow.detail.activity":"Activity","workflow.detail.activityStatus":"Activity \u72B6\u6001","workflow.detail.attempts":"\u5C1D\u8BD5\u6B21\u6570","workflow.detail.current":"\u5F53\u524D\u5C1D\u8BD5","workflow.detail.detail":"\u8BE6\u60C5","workflow.detail.nodeIO":"\u8282\u70B9\u8F93\u5165\u8F93\u51FA","workflow.detail.timeline":"\u65F6\u95F4\u7EBF","workflow.detail.loadOlder":"\u52A0\u8F7D\u66F4\u65E9\u4E8B\u4EF6","workflow.detail.seq":"\u5E8F\u53F7","workflow.detail.actor":"\u6267\u884C\u8005","workflow.detail.error":"\u9519\u8BEF","workflow.detail.event":"\u4E8B\u4EF6","workflow.detail.time":"\u65F6\u95F4","workflow.detail.refreshed":"\u5237\u65B0\u4E8E {time}","workflow.detail.unknownRun":"\u672A\u77E5\u8FD0\u884C","workflow.detail.snapshotHttp":"snapshot HTTP {status}","workflow.detail.eventsHttp":"events HTTP {status}","workflow.detail.cancelUnavailable":"\u65E0\u6CD5\u53D6\u6D88\uFF1A\u8BF7\u4F7F\u7528 botmux workflow cancel {runId}","workflow.detail.cancelConfirm":`\u786E\u8BA4\u53D6\u6D88\u5DE5\u4F5C\u6D41\u8FD0\u884C {runId}\uFF1F
3
6
 
4
7
  {total} \u4E2A\u60AC\u6302\u9879\u4F1A\u7531 cancel recovery \u5904\u7406\u3002
5
8
  effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"workflow.detail.writeAccessCancel":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u70B9\u51FB\u53D6\u6D88\u3002","workflow.detail.cancelHttp":"cancel HTTP {status}","workflow.detail.cancelPending":"\u53D6\u6D88\u5DF2\u63D0\u4EA4\uFF1B\u7B49\u5F85\u8FD0\u884C\u4E2D\u7684 activity \u6536\u655B","workflow.detail.writeAccessApproval":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u5BA1\u6279\u3002","workflow.detail.actionHttp":"{action} HTTP {status}","workflow.detail.approved":"\u5DF2\u901A\u8FC7","workflow.detail.rejected":"\u5DF2\u62D2\u7EDD","workflow.detail.alreadyTerminal":"\u8FD0\u884C\u5DF2\u7EC8\u6001\uFF1B\u672A\u5E94\u7528\u201C{label}\u201D\u3002","workflow.detail.workflowContinue":"{label}\uFF1B\u7B49\u5F85\u5DE5\u4F5C\u6D41\u7EE7\u7EED\u6267\u884C\u3002","workflow.detail.workflowRefreshing":"{label}\uFF1B\u6B63\u5728\u5237\u65B0\u5DE5\u4F5C\u6D41\u72B6\u6001\u3002","workflow.detail.eventsLoaded":"\u5DF2\u52A0\u8F7D {loaded}/{total} \u4E2A\u4E8B\u4EF6","workflow.detail.dangling":"\u60AC\u6302\u9879","workflow.detail.noDangling":"\u6CA1\u6709\u60AC\u6302\u5DE5\u4F5C\u3002","workflow.detail.none":"\u65E0","workflow.detail.noNodes":"\u8FD8\u6CA1\u6709\u8282\u70B9\u3002","workflow.detail.idle":"\u7A7A\u95F2","workflow.detail.noNodeIO":"\u8FD8\u6CA1\u6709\u8282\u70B9\u8F93\u5165\u8F93\u51FA\u3002","workflow.detail.notDispatched":"\u5C1A\u672A\u6D3E\u53D1","workflow.detail.noAttempt":"\u8FD8\u6CA1\u6709\u5C1D\u8BD5","workflow.detail.attempt":"\u5C1D\u8BD5","workflow.detail.authoredInput":"\u539F\u59CB\u8F93\u5165","workflow.detail.resolvedInput":"\u89E3\u6790\u540E\u8F93\u5165","workflow.detail.output":"\u8F93\u51FA","workflow.detail.executionLog":"\u6267\u884C\u65E5\u5FD7","workflow.detail.liveTerminal":"\u5B9E\u65F6\u7EC8\u7AEF","workflow.detail.terminalLive":"\u5728\u7EBF","workflow.detail.terminalClosedShort":"\u5DF2\u5173\u95ED","workflow.detail.terminalClosed":"\u7EC8\u7AEF\u5DF2\u5173\u95ED\u3002\u8BF7\u67E5\u770B\u4E0B\u65B9\u6267\u884C\u65E5\u5FD7\u83B7\u53D6\u6700\u7EC8\u8BB0\u5F55\u3002","workflow.detail.openTerminalNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u7EC8\u7AEF","workflow.detail.terminalReplay":"\u7EC8\u7AEF\u56DE\u653E","workflow.detail.openReplayNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u56DE\u653E","workflow.detail.downloadFullLog":"\u4E0B\u8F7D\u5B8C\u6574\u65E5\u5FD7","workflow.detail.terminalResume":"\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.openResumeNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.resumeSession":"\u7EE7\u7EED\u4F1A\u8BDD","workflow.detail.resumeStarting":"\u6B63\u5728\u542F\u52A8\u2026","workflow.detail.endResumeSession":"\u7ED3\u675F\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.resumeEnding":"\u7ED3\u675F\u4E2D\u2026","workflow.detail.resumeUnsupportedCli":"{cliId} CLI \u4E0D\u652F\u6301 resume","workflow.detail.resumeMissingCliSession":"\u7F3A\u5C11 cliSessionId\uFF0C\u65E0\u6CD5 resume","workflow.detail.resumeStartFailed":"\u542F\u52A8\u8C03\u8BD5\u4F1A\u8BDD\u5931\u8D25 (HTTP {status})","workflow.detail.resumeEndFailed":"\u7ED3\u675F\u8C03\u8BD5\u4F1A\u8BDD\u5931\u8D25 (HTTP {status})","workflow.detail.writeAccessResume":"\u9700\u8981\u5199\u5165\u6743\u9650\u624D\u80FD resume \u4F1A\u8BDD\u3002","workflow.detail.waitPrompt":"\u7B49\u5F85\u63D0\u793A","workflow.detail.approvalComment":"\u5BA1\u6279\u5907\u6CE8","workflow.detail.optionalComment":"\u53EF\u9009\u5907\u6CE8","workflow.detail.approve":"\u901A\u8FC7","workflow.detail.reject":"\u62D2\u7EDD","workflow.detail.submitting":"\u63D0\u4EA4\u4E2D...","workflow.detail.empty":"\u7A7A","workflow.detail.truncated":"\u5DF2\u622A\u65AD","workflow.detail.noData":"\u6CA1\u6709\u6570\u636E\u3002","workflow.detail.noPreview":"\u6CA1\u6709\u9884\u89C8\u3002","workflow.detail.open":"\u6253\u5F00","workflow.detail.deadline":"\u622A\u6B62","workflow.detail.effect":"\u526F\u4F5C\u7528","workflow.detail.wait":"\u7B49\u5F85","workflow.detail.noEvents":"\u8FD8\u6CA1\u6709\u4E8B\u4EF6\u3002","workflow.summary.workflow":"\u5DE5\u4F5C\u6D41","workflow.summary.status":"\u72B6\u6001","workflow.summary.lastSeq":"\u6700\u540E\u5E8F\u53F7","workflow.summary.updated":"\u66F4\u65B0\u65F6\u95F4","workflow.summary.revision":"\u4FEE\u8BA2","workflow.summary.initiator":"\u53D1\u8D77\u4EBA","workflow.summary.failedNode":"\u5931\u8D25\u8282\u70B9","workflow.summary.cancelOrigin":"\u53D6\u6D88\u6765\u6E90","workflow.summary.chat":"\u7FA4\u804A","workflow.summary.app":"\u5E94\u7528","workflow.dangling.activities":"Activities","workflow.dangling.effects":"Effects","workflow.dangling.waits":"Waits","workflow.dangling.cancels":"Cancels","catalog.title":"\u5DE5\u4F5C\u6D41\u76EE\u5F55","catalog.subtitle":"\u4ECE\u5DF2\u4FDD\u5B58\u7684 workflow \u5B9A\u4E49\u521B\u5EFA\u4E00\u6B21\u8FD0\u884C\u3002","catalog.searchPlaceholder":"\u641C\u7D22 workflowId / \u8DEF\u5F84","catalog.refresh":"\u5237\u65B0","catalog.loading":"\u6B63\u5728\u52A0\u8F7D\u76EE\u5F55...","catalog.loadFailed":"\u76EE\u5F55\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","catalog.noDefinitions":"\u6CA1\u6709\u627E\u5230 workflow \u5B9A\u4E49\u3002","catalog.noFilterMatch":"\u6CA1\u6709\u7B26\u5408\u7B5B\u9009\u6761\u4EF6\u7684\u5B9A\u4E49\u3002","catalog.table.workflow":"\u5DE5\u4F5C\u6D41","catalog.table.version":"\u7248\u672C","catalog.table.params":"\u53C2\u6570","catalog.table.nodes":"\u8282\u70B9","catalog.table.revision":"\u4FEE\u8BA2","catalog.table.path":"\u8DEF\u5F84","catalog.paramSummary":"{required}/{total} \u5FC5\u586B","catalog.back":"\u8FD4\u56DE\u76EE\u5F55","catalog.detailTitle":"\u5DE5\u4F5C\u6D41\u5B9A\u4E49","catalog.definitionLoadFailed":"\u5B9A\u4E49\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","catalog.summary":"\u6458\u8981","catalog.paramsSchema":"\u53C2\u6570 Schema","catalog.definitionJson":"\u5B9A\u4E49 JSON","catalog.runPanel":"\u8FD0\u884C\u5DE5\u4F5C\u6D41","catalog.paramsJson":"\u53C2\u6570 JSON","catalog.paramsPlaceholder":`{
6
9
  "city": "\u5317\u4EAC"
7
- }`,"catalog.chatId":"\u7FA4\u804A ID","catalog.larkAppId":"\u98DE\u4E66\u5E94\u7528 ID","catalog.chatBindingHint":"\u5FC5\u586B\uFF0C\u7528\u4E8E\u786E\u5B9A humanGate \u5361\u7247\u53D1\u9001\u5230\u54EA\u4E2A\u98DE\u4E66\u7FA4\uFF0C\u4EE5\u53CA\u53D6\u6D88\u8DEF\u7531\u5F52\u5C5E\u3002","catalog.run":"\u8FD0\u884C","catalog.running":"\u542F\u52A8\u4E2D...","catalog.badParamsJson":"\u53C2\u6570\u5FC5\u987B\u662F JSON object\u3002","catalog.writeAccess":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u8FD0\u884C\u3002","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"\u8FD0\u884C\u5DF2\u542F\u52A8\uFF1B\u6B63\u5728\u6253\u5F00\u8BE6\u60C5\u9875...","catalog.invalidParams":"\u53C2\u6570\u65E0\u6548","catalog.issue":"{path}: {message}","catalog.noParams":"\u6CA1\u6709\u58F0\u660E\u53C2\u6570\u3002","catalog.required":"\u5FC5\u586B","catalog.optional":"\u53EF\u9009","catalog.default":"\u9ED8\u8BA4\u503C","catalog.description":"\u8BF4\u660E","catalog.path":"\u8DEF\u5F84","catalog.revision":"\u4FEE\u8BA2","catalog.nodeCount":"\u8282\u70B9\u6570"},us={"app.name":"botmux","app.subtitle":"Feishu AI CLI Control","time.secondsAgo":"{value}s ago","time.minutesAgo":"{value}m ago","time.hoursAgo":"{value}h ago","nav.overview":"Overview","nav.sessions":"Sessions","nav.sidebarCollapse":"Collapse sidebar","nav.sidebarExpand":"Expand sidebar","nav.groups":"Groups","nav.schedules":"Schedules","nav.settings":"Settings","nav.botDefaults":"Bot Defaults","status.live":"Live","status.disconnected":"Disconnected","status.system":"System","status.light":"Light","status.dark":"Dark","status.language":"Language","status.theme":"Theme","theme.base":"Basic","theme.skins":"Skins","skin.cyber":"2077","skin.genshin":"Genshin","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"Blue Archive","skin.zzz":"ZZZ","skin.dragonball":"Dragon Ball","skin.ikun":"ikun","botOnboarding.add":"Add Bot","botOnboarding.title":"Add Bot","botOnboarding.intro":"Pick a CLI and working directory, scan to create a PersonalAgent app \u2014 the dashboard writes it to local bots.json and auto-configures Open Platform permissions.","botOnboarding.cliLabel":"CLI adapter","botOnboarding.dirLabel":"Working directory","botOnboarding.dirPlaceholder":"Default ~ (home); must exist on the daemon host","botOnboarding.modelLabel":"Model (optional)","botOnboarding.modelPlaceholder":"Leave empty for the CLI default model","botOnboarding.modelTtadkPlaceholder":"ttadk gateway model, default {model}, editable anytime","botOnboarding.modelTtadkCocoPlaceholder":"CoCo needs no model","botOnboarding.startScan":"Start scan","botOnboarding.cancel":"Cancel","botOnboarding.starting":"Generating QR code...","botOnboarding.waiting":"Scan with the Feishu app to create the app.","botOnboarding.verifying":"Scan accepted. Verifying credentials...","botOnboarding.configuringPermissions":"Auto-configuring Open Platform permissions\u2026","botOnboarding.platformScanHint":"Scan once more with the Feishu app to sign in to the Open Platform (to auto-import permissions, set the callback, and submit a version).","botOnboarding.platformQrAlt":"Open Platform login QR code","botOnboarding.completed":"Bot added.","botOnboarding.permissionOk":"Auto-imported {count} permissions.","botOnboarding.permissionSkipped":"({count} skipped \u2014 not in the tenant catalog)","botOnboarding.permissionVersion":"Submitted version {version}.","botOnboarding.permissionManual":"Permissions could not be auto-configured. Complete these steps manually:","botOnboarding.metaDir":"Dir","botOnboarding.failed":"Add failed","botOnboarding.openLink":"Open scan link in browser","botOnboarding.close":"Close","botOnboarding.restartHint":"bots.json has been updated. Run pnpm daemon:restart for the new bot to take effect.","botOnboarding.qrAlt":"Feishu bot onboarding QR code","overview.title":"Workbench","overview.subtitle":"Live status of your AI teammates \xB7 synced with Feishu topics","overview.team":"AI Team","overview.teamHint":"Live status of every digital teammate","overview.attention":"Needs You","overview.attentionHint":"Blocked tasks \u2014 one reply gets them moving again","overview.activeSessions":"Active Sessions","overview.activeSessionsHint":"Sessions currently running","overview.today":"Right Now","overview.todayHint":"Active session distribution","overview.viewAll":"View all \u2192","overview.botIdle":"Standing by, ready for new tasks","overview.botOffline":"Offline \u2014 daemon not running","overview.botBusy":"Working \xB7 {count} sessions","overview.botNeedsYou":"Waiting on you","overview.botReady":"Ready","overview.botOff":"Offline","overview.sessionsCount":"{count} sessions","overview.lastActive":"active {time} ago","overview.noAttention":"Nothing waiting on you","overview.teamExpand":"Show all {count} \u25BE","overview.teamCollapse":"Collapse \u25B4","strip.pending":"{count} pending","strip.longest":"waiting {time} \u2014 {bot} {reason}","strip.handle":"Handle now","overview.openSessions":"Active Sessions","overview.workingSessions":"Working","overview.onlineBots":"Online Bots","overview.schedules":"Schedules","overview.groups":"Groups Seen","overview.enabledSchedules":"Enabled","overview.total":"total","overview.active":"active","overview.daemonRegistry":"daemon registry","overview.chatMatrix":"chat matrix","overview.recentSessions":"Recent Sessions","overview.nextSchedules":"Next Runs","overview.noSessions":"No sessions yet.","overview.noSchedules":"No schedules yet.","sessions.title":"Session Control","sessions.subtitle":"Locate Feishu topics, open Web Terminal, close or resume CLI sessions.","sessions.search":"Search working dir / title / IDs","sessions.anyStatus":"Any status","sessions.adoptAny":"adopt: any","sessions.adoptYes":"adopt: yes","sessions.adoptNo":"adopt: no","sessions.activeOnly":"Active only","sessions.closeSelected":"Close selected","sessions.clearSelection":"Clear","sessions.selectedCount":"{count} sessions selected","sessions.bot":"Bot","sessions.cli":"CLI","sessions.chat":"Chat","sessions.openChat":"Open chat","sessions.status":"Status","sessions.tokenIn":"Token In","sessions.tokenOut":"Token Out","sessions.titleCol":"Title","sessions.workingDir":"Working Dir","sessions.created":"Created","sessions.last":"Last","sessions.adopt":"Adopt","sessions.actions":"Actions","sessions.details":"Details","sessions.copy":"Copy","sessions.copied":"Copied","sessions.locate":"Locate Topic","sessions.locating":"Sending...","sessions.cooldown":"Cooldown {seconds}s","sessions.openTerminal":"Terminal","sessions.writeLink":"Write Link","sessions.writeLinkHint":"Get a writable terminal link (carries a write-access token; opens in a new tab)","sessions.writeLinkFail":"Failed to get write link","sessions.close":"Close Session","sessions.resume":"Resume Session","sessions.dismiss":"Close","sessions.closeConfirm":"Close this session?","sessions.resumeFailed":"Resume failed","sessions.land":"Land","sessions.landLoading":"Loading sandbox diff\u2026","sessions.landUnavailable":"Cannot land","sessions.landEmpty":"No changes in the sandbox clone.","sessions.landApply":"Apply to disk","sessions.landDiscard":"Discard","sessions.landApplied":"Landed","sessions.landFailed":"Land failed","sessions.landDiscarded":"Discarded (sandbox clone not applied).","connectors.lede":"Let external systems (alerts, CI, tickets\u2026) trigger a bot to speak in a group or run a workflow via one webhook.","connectors.createTitle":"New Webhook","connectors.fName":"Name","connectors.fNamePh":"e.g. Prod alerts","connectors.fBot":"Trigger bot","connectors.fKind":"Trigger type","connectors.kindTurn":"Single turn (bot responds once)","connectors.kindWorkflow":"Workflow","connectors.fWf":"Workflow ID","connectors.fMode":"Deliver to which group","connectors.modeDynamic":"Specified per request (chat passed in)","connectors.modeFixed":"Fixed group","connectors.modeNewGroup":"New group each time","connectors.fFixedChat":"Target group","connectors.fChatManualPh":"Enter chat ID manually: oc_\u2026","connectors.chatManualLink":"Group not listed? Enter ID manually \u2192","connectors.chatListLink":"\u2190 Pick from group list","connectors.fAllow":"Allowed groups","connectors.optional":" (optional)","connectors.allowHint":"Hold Ctrl/\u2318 to multi-select; empty = unrestricted. Only validates the chat passed in the request.","connectors.dynamicHint":'<b>Dynamic mode</b>: the chat ID is passed per request, one of three ways \u2014 query <code>?chatId=&lt;chatId&gt;</code> \xB7 header <code>x-botmux-chat-id: &lt;chatId&gt;</code> \xB7 body <code>{"chatId":"&lt;chatId&gt;"}</code>.<br>For "one URL triggers directly, no params", choose Fixed group instead.',"connectors.fDedup":"Dedup field","connectors.fDedupPh":"e.g. alert.id (read from event body)","connectors.dedupHint":"Set: events with the same value go to the <b>same group</b>. Empty: each event <b>creates a new group</b>.","connectors.fInstruction":"Instruction","connectors.fInstructionPh":"What the bot should do on the event. e.g. Summarize the severity, @ the oncall, suggest next steps. Empty = hand the raw event to the model.","connectors.fVerify":"Verification","connectors.verifyToken":"Token (simple: secret in the URL, one curl triggers it)","connectors.verifyHmac":"HMAC signature (advanced: more secure, sign the request yourself)","connectors.fSecret":"Secret / token","connectors.fSecretPh":"Leave empty to auto-generate (shown once)","connectors.btnCreate":"Create","connectors.listTitle":"Existing Webhooks","connectors.loading":"Loading\u2026","connectors.noBotGroups":"(This bot has no visible groups; enter an ID manually on the right)","connectors.modeLabelFixed":"Fixed group","connectors.modeLabelNewGroup":"New group each time","connectors.modeLabelDynamic":"Per-request group","connectors.kindLabelWorkflow":"Workflow","connectors.kindLabelTurn":"Single turn","connectors.count":"\xB7 {count}","connectors.empty":"No webhooks yet. Create one with the form above.","connectors.enabled":"Enabled","connectors.disabled":"Disabled","connectors.badgeToken":"Token","connectors.badgeSign":"Signed","connectors.dest":'to "{name}"',"connectors.btnDisable":"Disable","connectors.btnEnable":"Enable","connectors.btnDel":"Delete","connectors.webhookUrl":"Webhook URL: ","connectors.copy":"Copy","connectors.copied":"Copied","connectors.tokenHint":"Token mode: append <code>/&lt;token&gt;</code> to the URL when calling (the token is shown only on create/rotate).","connectors.dynamicReqHint":'Dynamic mode: the request must carry the target chat \u2014 <code>?chatId=&lt;chatId&gt;</code> or header <code>x-botmux-chat-id</code> or body <code>{"chatId":"\u2026"}</code>.',"connectors.instructionPrefix":"Instruction: ","connectors.delConfirm":"Delete this webhook? Its URL stops working immediately.","connectors.errName":"Enter a name","connectors.errBot":"Pick a bot","connectors.errWf":"Enter a workflow ID","connectors.errChat":"Pick (or enter) a target group","connectors.creating":"Creating\u2026","connectors.usageDynamicLede":"Dynamic mode: the URL already has the token; pass the target chat ID when calling{gn}:","connectors.usageDynamicNote":'The chat can also go in header <code>x-botmux-chat-id</code> or body <code>{"chatId":"\u2026"}</code>. \u26A0\uFE0F The URL is the credential \u2014 keep it secret.',"connectors.usageTokenLede":"This URL already has the token and a fixed target group; just POST to trigger:","connectors.usageTokenNote":"\u26A0\uFE0F The URL is the credential \u2014 keep it private; delete or rotate it in the list below.","connectors.usageHmac":"The external system must HMAC-SHA256-sign <code>timestamp.body</code> and call with <code>x-botmux-timestamp</code> / <code>x-botmux-nonce</code> / <code>x-botmux-signature</code> headers","connectors.usageHmacDynamic":", and also pass the target chat ID as above","connectors.createdPrefix":'Created "{name}"',"connectors.createdDest":'to "{name}"',"connectors.tokenLabel":"Access token","connectors.signLabel":"Signing secret","connectors.secretOnce":" (shown once \u2014 save it): ","connectors.createFailed":"Create failed: {error}","connectors.noOnlineBots":"(No online bots)","team.navHome":"My team","team.navManage":"Team management","team.eyebrow":"Team","team.homeTitle":"Team collaboration (cross-deployment)","team.homeLede":"Invite other deployments (botmux instances teammates run) into one team to discover bots across deployments and pull collaborative groups.","team.localDeployTitle":"This deployment","team.myIdentity":"My Lark identity: ","team.unbound":"Not bound","team.bindBtn":"Bind","team.bindHint":" (auto-identifies you via the bot credentials; once bound, pulling a group adds you and attributes the bots to you)","team.myTeams":"My teams","team.searchPh":"Search name / capability / CLI\u2026","team.allCli":"All CLIs","team.hasCap":"Has capability tag","team.hasRole":"Has default role","team.teamsHint":"Tick bots in any team to pull them into a group (each with its owner). To create a team / generate an invite code / join another team, go to Team management.","team.loading":"Loading\u2026","team.roleModalTitle":"Default role","team.roleModalHint":"The bot default persona (applies across groups), read-only here. To edit, go to the Bot Defaults page.","team.close":"Close","team.tagLocal":"This deployment","team.tagRemoteStale":"Remote \xB7 offline?","team.tagRemote":"Remote","team.removeMember":"Remove","team.depTag":"({tag})","team.depCount":"{count}","team.depSelected":", {n} selected","team.capPh":"Capability tag\u2026","team.viewRole":"View","team.hasRoleShort":"Has role","team.noMatch":"No bots match the filters.","team.gnamePh":"Group name (e.g. cross-team triage)","team.pullGroupBtn":"Pull ticked bots into a group","team.pullGroupHint":"Tick bots \u2192 pull into a Lark group (owner included automatically)","team.noTeams":"No teams yet. Go to Team management to generate an invite code for others to join you, or join another team.","team.connected":"Connected","team.connectFail":"Connection failed: {error}","team.iHost":"I host","team.teamMeta":"{deps} deployments \xB7 {bots} bots","team.rosterFail":"Could not fetch this team roster.","team.acrossTeams":" (across {n} teams, deduped)","team.botsWord":"bots","team.groupCreated":"Group created","team.delegatedBy":' (created by "{name}")',"team.openInLark":"Open in Lark","team.invalidBots":"Bots not added: {ids}","team.invalidOwners":"{n} owner(s) could not be added","team.missingIdentity":"You have not bound a Lark identity, so you were not added to the group (bind it in My team)","team.skippedNoOwner":"{n} bot(s) skipped because their owner has no bound identity (not added)","team.errNoLocalBot":"Tick at least one of your own (this deployment) online bots \u2014 the group is created by it and adds you (the initiator).","team.errAllSkipped":"None of the selected bot owners have a bound identity, so the group cannot be pulled (a bot cannot join a group without its owner). Have those deployments bind an identity first.","team.errNoCreator":"No available group creator (the relevant deployments have no online bot, or are unreachable)","team.errDelegationTimeout":"Timed out delegating group creation to the other deployment (it may have succeeded \u2014 check Lark, do not retry)","team.errGroupCreate":"Group creation failed: {error}","team.roleModalTitleName":"Default role \xB7 {name}","team.bound":"Bound","team.myHostedTeam":"My hosted team","team.remoteTeamLabel":"{name} team","team.manageTitle":"Team management","team.manageLede":"Create multiple teams, generate an invite code per team, or join another team. A team = this deployment bots + the other deployments that joined it.","team.hostedTitle":"Teams I host","team.newTeamPh":"New team name","team.createTeamBtn":"Create team","team.joinTitle":"Join another team","team.hubPh":"Hub address, e.g. http://10.0.0.5:7891","team.codePh":"Invite code","team.joinBtn":"Join","team.noTeamsShort":"No teams yet.","team.default":"Default","team.manageMetaDeps":"{count} deployments","team.manageMetaRemote":" (incl. {r} remote)","team.manageMetaBots":"{count} bots","team.genInvite":"Generate invite code","team.delBtn":"Delete","team.generating":"Generating\u2026","team.inviteResultLede":"Send the two items below to someone on another deployment (valid once, within 24h):","team.inviteHub":"Hub address: ","team.inviteCode":"Invite code: ","team.genFail":"Generation failed.","team.delConfirm":'Delete team "{name}"? Deployments that joined it will be removed (their own deployments are unaffected).',"team.errName":"Enter a team name","team.creating":"Creating\u2026","team.created":"Created","team.createFail":"Create failed: {error}","team.errHubCode":"Enter the hub address and invite code.","team.joining":"Joining\u2026","team.joined":'Joined "{name}" \u2014 see it in My team.',"team.joinErrSelf":"This is your own deployment; you cannot join yourself (the invite code is for someone on another deployment).","team.joinErrAlready":"Your deployment already joined this team.","team.joinErrUnreachable":"Cannot reach the hub (check the address/network).","team.joinErrTimeout":"The hub timed out.","team.joinErrGeneric":"Join failed: {error}","team.identifying":"Identifying\u2026","team.bound2":"Bound: {name}","team.multiCandidate":"Multiple candidates found \u2014 click yourself:","team.binding":"Binding\u2026","team.bindFail":"Bind failed: {error}","team.noCandidates":"No identity found: make sure the bot has allowedUsers configured and contacts permission.","team.removeMemberConfirm":'Remove "{name}" from this team? Its bots disappear from this team roster (their own deployment is unaffected).',"team.creatingGroup":"Creating group\u2026","team.defaultGroupName":"Collaboration group","team.errPickBot":"Tick at least one bot first","sessions.closeBulkConfirm":"Close {count} selected sessions?","sessions.empty":"No sessions match the filters.","sessions.viewMode":"Session view","sessions.viewKanban":"Kanban","sessions.viewBoard":"Board","sessions.viewTable":"Table","sessions.selectSession":"Select session","sessions.board.needsYou":"Needs You","sessions.board.needsYouHint":"Repo, TUI, or usage limit waiting","sessions.board.starting":"Starting","sessions.board.startingHint":"CLI is spawning or resuming","sessions.board.working":"Working","sessions.board.workingHint":"Streaming, analyzing, or using tools","sessions.board.idle":"Idle","sessions.board.idleHint":"Ready for the next message","sessions.board.emptyColumn":"No sessions","sessions.board.signalRepo":"Repo needed","sessions.board.signalPrompt":"TUI choice needed","sessions.board.signalLimited":"Usage limited","sessions.board.signalAgent":"Needs human input","sessions.board.waiting":"Waiting","sessions.board.dragHint":"Drag header to reorder columns","sessions.board.moveLeft":"Move column left","sessions.board.moveRight":"Move column right","sessions.kanban.backlog":"Backlog","sessions.kanban.todo":"Todo","sessions.kanban.inProgress":"In Progress","sessions.kanban.inReview":"In Review","sessions.kanban.done":"Done","sessions.kanban.updated":"Updated {time}","sessions.kanban.moreHidden":"{count} more hidden","sessions.kanban.openTab":"Open in new tab","sessions.kanban.openFeishu":"Open in Feishu","sessions.kanban.terminalLoading":"Opening terminal\u2026","sessions.kanban.rename":"Rename (double-click title works too)","sessions.kanban.renameFail":"Rename failed","sessions.kanban.moveFail":"Move failed","sessions.kanban.groupBy":"Group by","sessions.kanban.groupFlow":"Workflow","sessions.kanban.groupTeam":"Team","sessions.kanban.groupBot":"Bots","sessions.kanban.teamLoading":"Loading teams\u2026","sessions.kanban.noTeam":"No teams","sessions.kanban.teamScope":"{chats} collab chats \xB7 {sessions} sessions","sessions.kanban.remoteHint":"Session from the {name} deployment (snapshot; terminal/history live on their machine)","sessions.kanban.clusterDragHint":"Drag header to move the whole group","sessions.history.title":"History","sessions.history.loading":"Fetching Feishu messages\u2026","sessions.history.fail":"Failed to load history","sessions.history.empty":"No messages","sessions.history.user":"User","sessions.history.owner":"Owner","sessions.history.staleHint":"The dashboard or daemon process may still run an old build \u2014 botmux restart and retry","groups.title":"Groups & Bots","groups.subtitle":"Inspect the chat x bot matrix and manage group creation, oncall, leave, and disband flows.","groups.search":"Search chat name / ID / owner","groups.missingOnly":"Missing bot only","groups.refresh":"Refresh","groups.create":"New Group","groups.chat":"Chat","groups.actions":"Actions","groups.addBots":"Add Bots","groups.manage":"Manage","groups.empty":"No chats match the filters.","groups.createTitle":"Create New Group","groups.createHelp":"Pick bots to invite. The dashboard chooses an online daemon as creator.","groups.name":"Group Name","groups.namePlaceholder":"e.g. AI ChangeLog","groups.bindDir":"Bind Directory","groups.bindDirHelp":"New topics start the CLI here and skip repo selection.","groups.botPicker":"Bots","groups.createSubmit":"Create","groups.cancel":"Cancel","groups.successTitle":"Group Created","groups.openGroup":"Open Group","groups.manageTitle":"Manage {name}","groups.owner":"Owner","groups.oncall":"Oncall Mode","groups.oncallHelp":"When enabled, group members can @ the bot; new topics use the bound directory.","groups.leaveTitle":"Select Bots to Leave","groups.leaveSelected":"Selected Bots Leave","groups.disband":"Disband Group","groups.dangerHint":"Disband only works when an in-chat bot is the owner. Otherwise prefer leaving the chat.","groups.save":"Save","groups.needWorkingDir":"Working directory is required","groups.noBotsOnline":"No bots online. Restart the daemon first.","schedules.title":"Schedules","schedules.subtitle":"View, pause, resume, and run scheduled tasks across daemons.","schedules.search":"Search name / prompt / working dir","schedules.anyKind":"Any kind","schedules.enabledOnly":"Enabled only","schedules.name":"Name","schedules.bot":"Bot","schedules.schedule":"Schedule","schedules.next":"Next","schedules.last":"Last","schedules.repeat":"Repeat","schedules.enabled":"Enabled","schedules.actions":"Actions","schedules.runNow":"Run Now","schedules.pause":"Pause","schedules.resume":"Resume","schedules.delivery":"Delivery","schedules.deliveryOrigin":"Original thread","schedules.deliveryNewTopic":"New topic each run","schedules.deliveryLocal":"Log only","schedules.useNewTopic":"Switch to new-topic","schedules.useOrigin":"Switch to original","schedules.empty":"No schedules.","settings.title":"Global Settings","settings.subtitle":"Manage machine-wide botmux dashboard behavior shared by every bot.","settings.loading":"Loading settings\u2026","settings.loadFailed":"Failed to load settings","settings.readOnlyVisitor":"Read-only access \u2014 changing settings requires an authorized link (run botmux dashboard).","settings.sectionAccess":"Access","settings.publicReadOnly":"Allow tokenless read-only dashboard access","settings.publicReadOnlyHelp":"When enabled, visitors without a token can view the dashboard, sessions, schedules, and SSE. Writes such as close, pause, and approvals still require token auth. Sensitive raw terminal logs always require a token.","settings.sectionCards":"Feishu Cards","settings.openTerminalInFeishu":"Open streaming-card terminals in the Feishu sidebar","settings.openTerminalInFeishuHelp":"Off by default: terminal buttons open the Web Terminal URL directly. When enabled, botmux wraps the URL with Feishu web_url/open so Feishu PC opens it in a sidebar. Terminal write access is still controlled by its token.","settings.sectionRepoPicker":"Repo Picker","settings.repoPickerMode":"Repo picker card mode","settings.repoPickerModeAll":"Repos + worktrees","settings.repoPickerModeRepos":"Main repos only","settings.repoPickerModeHelp":"Default shows repositories and linked worktrees. Main repos only hides linked worktrees from initialization and bare /repo cards; explicit /repo /abs/path/to/worktree still works.","settings.saving":"Saving\u2026","settings.saved":"Saved","settings.saveFailed":"Save failed","settings.sectionMaintenance":"Auto Maintenance","settings.autoUpdate":"Auto update","settings.autoUpdateHelp":"Off by default. At the set time, runs npm install -g botmux@latest to install the latest version (download/install only \u2014 no restart). npm-global installs only.","settings.autoRestart":"Auto restart","settings.autoRestartHelp":"Off by default; requires auto-update. After auto-update installs a newer version, restart to apply it if no session is in progress (busy \u21D2 slips to the next day).","settings.autoUpdateLocalDev":"This is a local-dev install (running from source); auto-update is unavailable.","settings.maintenanceTime":"Time","botDefaults.title":"Bot Profiles","botDefaults.subtitle":"Per-bot defaults: oncall, proactive start, persona role, cards and grants.","botDefaults.metaOnline":"Online \xB7 daemon healthy","botDefaults.search":"Search bot name / app id","botDefaults.refresh":"Refresh","botDefaults.sectionOncall":"New-chat Oncall","botDefaults.sectionBrand":"Card Signature","botDefaults.warning":"When enabled, chats without an oncall binding auto-bind to this directory on their next new topic. Manually bound or unbound chats are preserved.","botDefaults.empty":"No bots online. Run botmux restart first.","botDefaults.defaultOncall":"Default to oncall mode","botDefaults.defaultOncallHelp":"Unbound chats auto-bind on the next new topic","botDefaults.workingDir":"Default Working Directory","botDefaults.lastEnabled":"Last Enabled","botDefaults.autobound":"{count} chats auto-bound","botDefaults.save":"Save","botDefaults.required":"Working directory is required when enabled","botDefaults.brandLabel":"Signature (card footer)","botDefaults.brandLabelHelp":"Footer signature on cards this bot sends. Save empty = hide; fill in = custom (markdown ok, e.g. [Acme](https://\u2026)); Reset = show botmux.","botDefaults.brandLabelPlaceholder":"Default: botmux (empty = hidden)","botDefaults.sectionSandbox":"File sandbox (oncall)","botDefaults.sandboxToggle":"Enable file sandbox","botDefaults.sandboxHelp":"When on, every session of this bot runs in a per-session sandbox: only a project copy is visible \u2014 your real files, secrets, and other sessions are not. For sharing the bot with semi-trusted users (oncall). Linux only; applies to the next new session.","botDefaults.sandboxSaved":"Saved (applies to the next new session)","botDefaults.brandSave":"Save Signature","botDefaults.brandReset":"Reset to default","botDefaults.brandStateDefault":"Current: default botmux","botDefaults.brandStateOff":"Current: off","botDefaults.brandStateCustom":"Current: custom","botDefaults.sectionCard":"Card Behavior","botDefaults.disableStreaming":"Disable streaming card","botDefaults.disableStreamingHelp":"Stop posting the live session status card (and its Open Terminal entry). The task's final result still arrives as a message. For those who find the live card noisy.","botDefaults.writableLink":"Put a writable terminal link on the card","botDefaults.writableLinkHelp":'\u26A0\uFE0F Embeds a writable terminal link in the streaming card body \u2014 anyone in the chat can open and drive the terminal. Off = current behavior (private DM via the "Get Write Link" button).',"botDefaults.writableLinkMoot":"Streaming card disabled \u2014 this has no effect","botDefaults.privateCard":"/card sends a private card (authorized users only)","botDefaults.privateCardHelp":'Makes /card send an ephemeral "visible-to-specific-people" card: delivered only to the owner (allowedUsers); /grant-authorized talk users and everyone else in the chat cannot see it. Trade-off: it is a static snapshot (no live updates) and only works in regular group chats (topic groups / DMs fail, with no fallback). Affects only the /card command; the auto streaming card is unchanged.',"botDefaults.cardPrefSaved":"Saved","botDefaults.sectionRole":"Default Role","botDefaults.roleHelp":"This bot's default persona (applies across all chats), injected into the bot's sessions in every chat; a single group can override it on the Roles page. Save empty = delete.","botDefaults.rolePlaceholder":"e.g. You are a backend triage assistant; answer concisely, prefer runnable commands\u2026","botDefaults.roleSave":"Save role","botDefaults.roleDelete":"Delete","botDefaults.roleSaved":"Saved","botDefaults.roleDeleted":"Deleted","botDefaults.roleLoadErr":"Failed to load role","botDefaults.sectionAutoStart":"Proactive Start","botDefaults.autoStartJoin":"Auto-start when added to a new chat","botDefaults.autoStartJoinHelp":'When enabled, the bot auto-starts a session and gets to work the moment it is added to a new chat (when an authorized user / allowedUsers is a member), no @ needed. It launches in the bot default working dir; if none is configured it shows a repo-select card first. Prerequisite: subscribe the "bot joined chat" event im.chat.member.bot.added_v1 for this app and grant the member-read scope in the Feishu console.',"botDefaults.autoStartJoinPrompt":"First-turn prompt on join (optional)","botDefaults.autoStartJoinPromptPlaceholder":"Filled = used as the first task after joining; blank = the bot reads the chat and decides what to do","botDefaults.autoStartJoinPromptSave":"Save prompt","botDefaults.autoStartTopic":"Auto-start on new topics in topic groups","botDefaults.autoStartTopicHelp":"When enabled, in a topic group the bot automatically joins each newly opened topic and starts working on its first message, no @ needed. Topic groups only \u2014 regular groups are unaffected.","botDefaults.sectionSessionMode":"Session mode","botDefaults.p2pMode":"Private chat session mode","botDefaults.p2pThread":"thread (separate session per DM)","botDefaults.p2pChat":"chat (flat continuous session)","botDefaults.p2pHelp":"How 1:1 DMs are sessioned: thread = each top-level message starts its own session (keeps chatter out of one CLI process); chat = the whole DM shares one continuous session and context (Hermes-like). Takes effect immediately.","botDefaults.regularGroupMode":"Regular group session mode","botDefaults.regularGroupModeChat":"chat (flat continuous session, default)","botDefaults.regularGroupModeNewTopic":"new-topic (each top-level @ opens its own topic & session)","botDefaults.regularGroupModeShared":"shared (topic display, reusing one session)","botDefaults.regularGroupModeHelp":"How new top-level @mentions in regular (non-topic) groups are sessioned: chat = the whole group shares one continuous session (default); new-topic = each top-level @ opens its own topic with a separate session; shared = topic display but reuse the same session (replies fold into a topic yet share the group session & context). This is the per-bot default; a specific group can override it via /reply-mode. Takes effect immediately.","botDefaults.mentionMode":"Group @ policy","botDefaults.mentionModeAlways":"Always require @ (default)","botDefaults.mentionModeTopic":"No @ needed inside topics","botDefaults.mentionModeNever":"Never require @","botDefaults.mentionModeHelp":'Bot-global: controls when an @ is required to get a reply in groups. "Always require @" = every message needs an @ (default, safest; inside topics too, in multi-person groups); "No @ needed inside topics" = starting a new conversation / top-level still needs @, but follow-ups inside ANY topic this bot already drives (new-topic / shared / topic-group) continue without @; "Never require @" = non-@ messages are answered too wherever the bot has talk access (including cold-starting on a brand-new message \u2014 only suitable for dedicated / on-call small groups; in busy multi-person groups it replies to everything). Note: when you are alone with this bot (1:1) replies never need an @, independent of this setting.',"botDefaults.docSubscribeMode":"Doc subscription trigger (default)","botDefaults.docSubscribeModeMention":"Only when a comment @s me","botDefaults.docSubscribeModeAll":"Every new comment","botDefaults.docSubscribeModeHelp":'After subscribing to a Feishu doc with /subscribe-lark-doc, its comments feed into the session and the bot replies back into the comment. This sets the default trigger range for new subscriptions: "only when a comment @s me" is safest (avoids noise); "every new comment" suits dedicated docs.',"botDefaults.sectionGrant":"Authorization & Quota","botDefaults.restrictGrant":"Restrict grantees to plain conversation","botDefaults.restrictGrantHelp":"When enabled, /grant-authorized users (the owner is exempt) can only send plain messages; every slash command is blocked: botmux built-in commands, passthrough commands, /workflow, /introduce, /t, and CLI-native commands (/help, etc.). Text like /path/to/file is not misclassified.","botDefaults.quotaDefault":"Default message quota","botDefaults.quotaPlaceholder":"Empty = no default quota","botDefaults.quotaHelp":'Message count a bare /grant @x (no number) hands out. Empty or "Turn off" merely stops applying a default to bare /grant \u2014 it does NOT clear existing quota counters, nor affect an explicit /grant @x N; those keep being enforced. Authorization is auto-revoked once a quota runs out.',"botDefaults.quotaSave":"Save quota","botDefaults.quotaOff":"Turn off","botDefaults.quotaInvalid":"Quota must be a positive integer","botDefaults.quotaStateOff":"Current: no default quota","botDefaults.quotaStateOn":"Current: {count} per grantee","botDefaults.sectionSessionCap":"Session limit","botDefaults.maxLiveWorkers":"Max live sessions","botDefaults.maxLiveWorkersPlaceholder":"Empty = default 30","botDefaults.maxLiveWorkersHelp":"Cap on this bot's simultaneously-live sessions, to bound memory. Beyond it, the least-recently-used sessions are suspended: both the worker AND the CLI process are killed to reclaim all their memory, and the session cold-resumes from its on-disk transcript on the next message (--resume rebuilds context in a few seconds \u2014 nothing stays resident). Empty = use the default of 30; a number = a per-bot override (set a larger number if you want more). Note: suspension only applies to resumable backends (tmux/herdr/zellij), never plain PTY; a session that is mid-reply is never interrupted.","botDefaults.maxLiveWorkersSave":"Save limit","botDefaults.maxLiveWorkersOff":"Reset to default","botDefaults.maxLiveWorkersInvalid":"Limit must be a positive integer","botDefaults.maxLiveWorkersStateDefault":"Current: default 30 live sessions","botDefaults.maxLiveWorkersStateOn":"Current: up to {count} live sessions","nav.roles":"Roles","roles.title":"Role Management","roles.subtitle":"Set per-bot role prompts for each group. Each bot adopts its own persona in the selected group.","roles.search":"Search group / bot / ID","roles.refresh":"Refresh","roles.selectHint":"\u2190 Expand a group and select a bot to edit its role","roles.editorPlaceholder":`Enter role description, e.g.:
10
+ }`,"catalog.chatId":"\u7FA4\u804A ID","catalog.larkAppId":"\u98DE\u4E66\u5E94\u7528 ID","catalog.chatBindingHint":"\u5FC5\u586B\uFF0C\u7528\u4E8E\u786E\u5B9A humanGate \u5361\u7247\u53D1\u9001\u5230\u54EA\u4E2A\u98DE\u4E66\u7FA4\uFF0C\u4EE5\u53CA\u53D6\u6D88\u8DEF\u7531\u5F52\u5C5E\u3002","catalog.run":"\u8FD0\u884C","catalog.running":"\u542F\u52A8\u4E2D...","catalog.badParamsJson":"\u53C2\u6570\u5FC5\u987B\u662F JSON object\u3002","catalog.writeAccess":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u8FD0\u884C\u3002","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"\u8FD0\u884C\u5DF2\u542F\u52A8\uFF1B\u6B63\u5728\u6253\u5F00\u8BE6\u60C5\u9875...","catalog.invalidParams":"\u53C2\u6570\u65E0\u6548","catalog.issue":"{path}: {message}","catalog.noParams":"\u6CA1\u6709\u58F0\u660E\u53C2\u6570\u3002","catalog.required":"\u5FC5\u586B","catalog.optional":"\u53EF\u9009","catalog.default":"\u9ED8\u8BA4\u503C","catalog.description":"\u8BF4\u660E","catalog.path":"\u8DEF\u5F84","catalog.revision":"\u4FEE\u8BA2","catalog.nodeCount":"\u8282\u70B9\u6570"},vs={"app.name":"botmux","app.subtitle":"Feishu AI CLI Control","time.secondsAgo":"{value}s ago","time.minutesAgo":"{value}m ago","time.hoursAgo":"{value}h ago","nav.overview":"Overview","nav.sessions":"Sessions","nav.sidebarCollapse":"Collapse sidebar","nav.sidebarExpand":"Expand sidebar","nav.groups":"Groups","nav.schedules":"Schedules","nav.settings":"Settings","nav.botDefaults":"Bot Defaults","nav.skills":"Skills","status.live":"Live","status.disconnected":"Disconnected","status.system":"System","status.light":"Light","status.dark":"Dark","status.language":"Language","status.theme":"Theme","theme.base":"Basic","theme.skins":"Skins","skin.cyber":"2077","skin.genshin":"Genshin","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"Blue Archive","skin.zzz":"ZZZ","skin.dragonball":"Dragon Ball","skin.ikun":"ikun","botOnboarding.add":"Add Bot","botOnboarding.title":"Add Bot","botOnboarding.intro":"Pick a CLI and working directory, scan to create a PersonalAgent app \u2014 the dashboard writes it to local bots.json and auto-configures Open Platform permissions.","botOnboarding.cliLabel":"CLI adapter","botOnboarding.dirLabel":"Working directory","botOnboarding.dirPlaceholder":"Default ~ (home); must exist on the daemon host","botOnboarding.modelLabel":"Model (optional)","botOnboarding.modelPlaceholder":"Leave empty for the CLI default model","botOnboarding.modelTtadkPlaceholder":"ttadk gateway model, default {model}, editable anytime","botOnboarding.modelTtadkCocoPlaceholder":"CoCo needs no model","botOnboarding.startScan":"Start scan","botOnboarding.cancel":"Cancel","botOnboarding.starting":"Generating QR code...","botOnboarding.waiting":"Scan with the Feishu app to create the app.","botOnboarding.verifying":"Scan accepted. Verifying credentials...","botOnboarding.configuringPermissions":"Auto-configuring Open Platform permissions\u2026","botOnboarding.platformScanHint":"Scan once more with the Feishu app to sign in to the Open Platform (to auto-import permissions, set the callback, and submit a version).","botOnboarding.platformQrAlt":"Open Platform login QR code","botOnboarding.completed":"Bot added.","botOnboarding.permissionOk":"Auto-imported {count} permissions.","botOnboarding.permissionSkipped":"({count} skipped \u2014 not in the tenant catalog)","botOnboarding.permissionVersion":"Submitted version {version}.","botOnboarding.permissionManual":"Permissions could not be auto-configured. Complete these steps manually:","botOnboarding.metaDir":"Dir","botOnboarding.failed":"Add failed","botOnboarding.openLink":"Open scan link in browser","botOnboarding.close":"Close","botOnboarding.restartHint":"bots.json has been updated. Run pnpm daemon:restart for the new bot to take effect.","botOnboarding.qrAlt":"Feishu bot onboarding QR code","overview.title":"Workbench","overview.subtitle":"Live status of your AI teammates \xB7 synced with Feishu topics","overview.team":"AI Team","overview.teamHint":"Live status of every digital teammate","overview.attention":"Needs You","overview.attentionHint":"Blocked tasks \u2014 one reply gets them moving again","overview.activeSessions":"Active Sessions","overview.activeSessionsHint":"Sessions currently running","overview.today":"Right Now","overview.todayHint":"Active session distribution","overview.viewAll":"View all \u2192","overview.botIdle":"Standing by, ready for new tasks","overview.botOffline":"Offline \u2014 daemon not running","overview.botBusy":"Working \xB7 {count} sessions","overview.botNeedsYou":"Waiting on you","overview.botReady":"Ready","overview.botOff":"Offline","overview.sessionsCount":"{count} sessions","overview.lastActive":"active {time} ago","overview.noAttention":"Nothing waiting on you","overview.teamExpand":"Show all {count} \u25BE","overview.teamCollapse":"Collapse \u25B4","strip.pending":"{count} pending","strip.longest":"waiting {time} \u2014 {bot} {reason}","strip.handle":"Handle now","overview.openSessions":"Active Sessions","overview.workingSessions":"Working","overview.onlineBots":"Online Bots","overview.schedules":"Schedules","overview.groups":"Groups Seen","overview.enabledSchedules":"Enabled","overview.total":"total","overview.active":"active","overview.daemonRegistry":"daemon registry","overview.chatMatrix":"chat matrix","overview.recentSessions":"Recent Sessions","overview.nextSchedules":"Next Runs","overview.noSessions":"No sessions yet.","overview.noSchedules":"No schedules yet.","sessions.title":"Session Control","sessions.subtitle":"Locate Feishu topics, open Web Terminal, close or resume CLI sessions.","sessions.search":"Search working dir / title / IDs","sessions.anyStatus":"Any status","sessions.adoptAny":"adopt: any","sessions.adoptYes":"adopt: yes","sessions.adoptNo":"adopt: no","sessions.activeOnly":"Active only","sessions.closeSelected":"Close selected","sessions.clearSelection":"Clear","sessions.selectedCount":"{count} sessions selected","sessions.bot":"Bot","sessions.cli":"CLI","sessions.chat":"Chat","sessions.openChat":"Open chat","sessions.status":"Status","sessions.tokenIn":"Token In","sessions.tokenOut":"Token Out","sessions.titleCol":"Title","sessions.workingDir":"Working Dir","sessions.created":"Created","sessions.last":"Last","sessions.adopt":"Adopt","sessions.actions":"Actions","sessions.details":"Details","sessions.copy":"Copy","sessions.copied":"Copied","sessions.locate":"Locate Topic","sessions.locating":"Sending...","sessions.cooldown":"Cooldown {seconds}s","sessions.openTerminal":"Terminal","sessions.writeLink":"Write Link","sessions.writeLinkHint":"Get a writable terminal link (carries a write-access token; opens in a new tab)","sessions.writeLinkFail":"Failed to get write link","sessions.close":"Close Session","sessions.resume":"Resume Session","sessions.dismiss":"Close","sessions.closeConfirm":"Close this session?","sessions.resumeFailed":"Resume failed","sessions.land":"Land","sessions.landLoading":"Loading sandbox diff\u2026","sessions.landUnavailable":"Cannot land","sessions.landEmpty":"No changes in the sandbox clone.","sessions.landApply":"Apply to disk","sessions.landDiscard":"Discard","sessions.landApplied":"Landed","sessions.landFailed":"Land failed","sessions.landDiscarded":"Discarded (sandbox clone not applied).","connectors.lede":"Let external systems (alerts, CI, tickets\u2026) trigger a bot to speak in a group or run a workflow via one webhook.","connectors.createTitle":"New Webhook","connectors.fName":"Name","connectors.fNamePh":"e.g. Prod alerts","connectors.fBot":"Trigger bot","connectors.fKind":"Trigger type","connectors.kindTurn":"Single turn (bot responds once)","connectors.kindWorkflow":"Workflow","connectors.fWf":"Workflow ID","connectors.fMode":"Deliver to which group","connectors.modeDynamic":"Specified per request (chat passed in)","connectors.modeFixed":"Fixed group","connectors.modeNewGroup":"New group each time","connectors.fFixedChat":"Target group","connectors.fChatManualPh":"Enter chat ID manually: oc_\u2026","connectors.chatManualLink":"Group not listed? Enter ID manually \u2192","connectors.chatListLink":"\u2190 Pick from group list","connectors.fAllow":"Allowed groups","connectors.optional":" (optional)","connectors.allowHint":"Hold Ctrl/\u2318 to multi-select; empty = unrestricted. Only validates the chat passed in the request.","connectors.dynamicHint":'<b>Dynamic mode</b>: the chat ID is passed per request, one of three ways \u2014 query <code>?chatId=&lt;chatId&gt;</code> \xB7 header <code>x-botmux-chat-id: &lt;chatId&gt;</code> \xB7 body <code>{"chatId":"&lt;chatId&gt;"}</code>.<br>For "one URL triggers directly, no params", choose Fixed group instead.',"connectors.fDedup":"Dedup field","connectors.fDedupPh":"e.g. alert.id (read from event body)","connectors.dedupHint":"Set: events with the same value go to the <b>same group</b>. Empty: each event <b>creates a new group</b>.","connectors.fInstruction":"Instruction","connectors.fInstructionPh":"What the bot should do on the event. e.g. Summarize the severity, @ the oncall, suggest next steps. Empty = hand the raw event to the model.","connectors.fVerify":"Verification","connectors.verifyToken":"Token (simple: secret in the URL, one curl triggers it)","connectors.verifyHmac":"HMAC signature (advanced: more secure, sign the request yourself)","connectors.fSecret":"Secret / token","connectors.fSecretPh":"Leave empty to auto-generate (shown once)","connectors.btnCreate":"Create","connectors.listTitle":"Existing Webhooks","connectors.loading":"Loading\u2026","connectors.noBotGroups":"(This bot has no visible groups; enter an ID manually on the right)","connectors.modeLabelFixed":"Fixed group","connectors.modeLabelNewGroup":"New group each time","connectors.modeLabelDynamic":"Per-request group","connectors.kindLabelWorkflow":"Workflow","connectors.kindLabelTurn":"Single turn","connectors.count":"\xB7 {count}","connectors.empty":"No webhooks yet. Create one with the form above.","connectors.enabled":"Enabled","connectors.disabled":"Disabled","connectors.badgeToken":"Token","connectors.badgeSign":"Signed","connectors.dest":'to "{name}"',"connectors.btnDisable":"Disable","connectors.btnEnable":"Enable","connectors.btnDel":"Delete","connectors.webhookUrl":"Webhook URL: ","connectors.copy":"Copy","connectors.copied":"Copied","connectors.tokenHint":"Token mode: append <code>/&lt;token&gt;</code> to the URL when calling (the token is shown only on create/rotate).","connectors.dynamicReqHint":'Dynamic mode: the request must carry the target chat \u2014 <code>?chatId=&lt;chatId&gt;</code> or header <code>x-botmux-chat-id</code> or body <code>{"chatId":"\u2026"}</code>.',"connectors.instructionPrefix":"Instruction: ","connectors.delConfirm":"Delete this webhook? Its URL stops working immediately.","connectors.errName":"Enter a name","connectors.errBot":"Pick a bot","connectors.errWf":"Enter a workflow ID","connectors.errChat":"Pick (or enter) a target group","connectors.creating":"Creating\u2026","connectors.usageDynamicLede":"Dynamic mode: the URL already has the token; pass the target chat ID when calling{gn}:","connectors.usageDynamicNote":'The chat can also go in header <code>x-botmux-chat-id</code> or body <code>{"chatId":"\u2026"}</code>. \u26A0\uFE0F The URL is the credential \u2014 keep it secret.',"connectors.usageTokenLede":"This URL already has the token and a fixed target group; just POST to trigger:","connectors.usageTokenNote":"\u26A0\uFE0F The URL is the credential \u2014 keep it private; delete or rotate it in the list below.","connectors.usageHmac":"The external system must HMAC-SHA256-sign <code>timestamp.body</code> and call with <code>x-botmux-timestamp</code> / <code>x-botmux-nonce</code> / <code>x-botmux-signature</code> headers","connectors.usageHmacDynamic":", and also pass the target chat ID as above","connectors.createdPrefix":'Created "{name}"',"connectors.createdDest":'to "{name}"',"connectors.tokenLabel":"Access token","connectors.signLabel":"Signing secret","connectors.secretOnce":" (shown once \u2014 save it): ","connectors.createFailed":"Create failed: {error}","connectors.noOnlineBots":"(No online bots)","team.navHome":"My team","team.navManage":"Team management","team.eyebrow":"Team","team.homeTitle":"Team collaboration (cross-deployment)","team.homeLede":"Invite other deployments (botmux instances teammates run) into one team to discover bots across deployments and pull collaborative groups.","team.localDeployTitle":"This deployment","team.myIdentity":"My Lark identity: ","team.unbound":"Not bound","team.bindBtn":"Bind","team.bindHint":" (auto-identifies you via the bot credentials; once bound, pulling a group adds you and attributes the bots to you)","team.myTeams":"My teams","team.searchPh":"Search name / capability / CLI\u2026","team.allCli":"All CLIs","team.hasCap":"Has capability tag","team.hasRole":"Has default role","team.teamsHint":"Tick bots in any team to pull them into a group (each with its owner). To create a team / generate an invite code / join another team, go to Team management.","team.loading":"Loading\u2026","team.roleModalTitle":"Default role","team.roleModalHint":"The bot default persona (applies across groups), read-only here. To edit, go to the Bot Defaults page.","team.close":"Close","team.tagLocal":"This deployment","team.tagRemoteStale":"Remote \xB7 offline?","team.tagRemote":"Remote","team.removeMember":"Remove","team.depTag":"({tag})","team.depCount":"{count}","team.depSelected":", {n} selected","team.capPh":"Capability tag\u2026","team.viewRole":"View","team.hasRoleShort":"Has role","team.noMatch":"No bots match the filters.","team.gnamePh":"Group name (e.g. cross-team triage)","team.pullGroupBtn":"Pull ticked bots into a group","team.pullGroupHint":"Tick bots \u2192 pull into a Lark group (owner included automatically)","team.noTeams":"No teams yet. Go to Team management to generate an invite code for others to join you, or join another team.","team.connected":"Connected","team.connectFail":"Connection failed: {error}","team.iHost":"I host","team.teamMeta":"{deps} deployments \xB7 {bots} bots","team.rosterFail":"Could not fetch this team roster.","team.acrossTeams":" (across {n} teams, deduped)","team.botsWord":"bots","team.groupCreated":"Group created","team.delegatedBy":' (created by "{name}")',"team.openInLark":"Open in Lark","team.invalidBots":"Bots not added: {ids}","team.invalidOwners":"{n} owner(s) could not be added","team.missingIdentity":"You have not bound a Lark identity, so you were not added to the group (bind it in My team)","team.skippedNoOwner":"{n} bot(s) skipped because their owner has no bound identity (not added)","team.errNoLocalBot":"Tick at least one of your own (this deployment) online bots \u2014 the group is created by it and adds you (the initiator).","team.errAllSkipped":"None of the selected bot owners have a bound identity, so the group cannot be pulled (a bot cannot join a group without its owner). Have those deployments bind an identity first.","team.errNoCreator":"No available group creator (the relevant deployments have no online bot, or are unreachable)","team.errDelegationTimeout":"Timed out delegating group creation to the other deployment (it may have succeeded \u2014 check Lark, do not retry)","team.errGroupCreate":"Group creation failed: {error}","team.roleModalTitleName":"Default role \xB7 {name}","team.bound":"Bound","team.myHostedTeam":"My hosted team","team.remoteTeamLabel":"{name} team","team.manageTitle":"Team management","team.manageLede":"Create multiple teams, generate an invite code per team, or join another team. A team = this deployment bots + the other deployments that joined it.","team.hostedTitle":"Teams I host","team.newTeamPh":"New team name","team.createTeamBtn":"Create team","team.joinTitle":"Join another team","team.hubPh":"Hub address, e.g. http://10.0.0.5:7891","team.codePh":"Invite code","team.joinBtn":"Join","team.noTeamsShort":"No teams yet.","team.default":"Default","team.manageMetaDeps":"{count} deployments","team.manageMetaRemote":" (incl. {r} remote)","team.manageMetaBots":"{count} bots","team.genInvite":"Generate invite code","team.delBtn":"Delete","team.generating":"Generating\u2026","team.inviteResultLede":"Send the two items below to someone on another deployment (valid once, within 24h):","team.inviteHub":"Hub address: ","team.inviteCode":"Invite code: ","team.genFail":"Generation failed.","team.delConfirm":'Delete team "{name}"? Deployments that joined it will be removed (their own deployments are unaffected).',"team.errName":"Enter a team name","team.creating":"Creating\u2026","team.created":"Created","team.createFail":"Create failed: {error}","team.errHubCode":"Enter the hub address and invite code.","team.joining":"Joining\u2026","team.joined":'Joined "{name}" \u2014 see it in My team.',"team.joinErrSelf":"This is your own deployment; you cannot join yourself (the invite code is for someone on another deployment).","team.joinErrAlready":"Your deployment already joined this team.","team.joinErrUnreachable":"Cannot reach the hub (check the address/network).","team.joinErrTimeout":"The hub timed out.","team.joinErrGeneric":"Join failed: {error}","team.identifying":"Identifying\u2026","team.bound2":"Bound: {name}","team.multiCandidate":"Multiple candidates found \u2014 click yourself:","team.binding":"Binding\u2026","team.bindFail":"Bind failed: {error}","team.noCandidates":"No identity found: make sure the bot has allowedUsers configured and contacts permission.","team.removeMemberConfirm":'Remove "{name}" from this team? Its bots disappear from this team roster (their own deployment is unaffected).',"team.creatingGroup":"Creating group\u2026","team.defaultGroupName":"Collaboration group","team.errPickBot":"Tick at least one bot first","sessions.closeBulkConfirm":"Close {count} selected sessions?","sessions.empty":"No sessions match the filters.","sessions.viewMode":"Session view","sessions.viewKanban":"Kanban","sessions.viewBoard":"Board","sessions.viewTable":"Table","sessions.selectSession":"Select session","sessions.board.needsYou":"Needs You","sessions.board.needsYouHint":"Repo, TUI, or usage limit waiting","sessions.board.starting":"Starting","sessions.board.startingHint":"CLI is spawning or resuming","sessions.board.working":"Working","sessions.board.workingHint":"Streaming, analyzing, or using tools","sessions.board.idle":"Idle","sessions.board.idleHint":"Ready for the next message","sessions.board.emptyColumn":"No sessions","sessions.board.signalRepo":"Repo needed","sessions.board.signalPrompt":"TUI choice needed","sessions.board.signalLimited":"Usage limited","sessions.board.signalAgent":"Needs human input","sessions.board.waiting":"Waiting","sessions.board.dragHint":"Drag header to reorder columns","sessions.board.moveLeft":"Move column left","sessions.board.moveRight":"Move column right","sessions.kanban.backlog":"Backlog","sessions.kanban.todo":"Todo","sessions.kanban.inProgress":"In Progress","sessions.kanban.inReview":"In Review","sessions.kanban.done":"Done","sessions.kanban.updated":"Updated {time}","sessions.kanban.moreHidden":"{count} more hidden","sessions.kanban.openTab":"Open in new tab","sessions.kanban.openFeishu":"Open in Feishu","sessions.kanban.terminalLoading":"Opening terminal\u2026","sessions.kanban.rename":"Rename (double-click title works too)","sessions.kanban.renameFail":"Rename failed","sessions.kanban.moveFail":"Move failed","sessions.kanban.groupBy":"Group by","sessions.kanban.groupFlow":"Workflow","sessions.kanban.groupTeam":"Team","sessions.kanban.groupBot":"Bots","sessions.kanban.teamLoading":"Loading teams\u2026","sessions.kanban.noTeam":"No teams","sessions.kanban.teamScope":"{chats} collab chats \xB7 {sessions} sessions","sessions.kanban.remoteHint":"Session from the {name} deployment (snapshot; terminal/history live on their machine)","sessions.kanban.clusterDragHint":"Drag header to move the whole group","sessions.history.title":"History","sessions.history.loading":"Fetching Feishu messages\u2026","sessions.history.fail":"Failed to load history","sessions.history.empty":"No messages","sessions.history.user":"User","sessions.history.owner":"Owner","sessions.history.staleHint":"The dashboard or daemon process may still run an old build \u2014 botmux restart and retry","groups.title":"Groups & Bots","groups.subtitle":"Inspect the chat x bot matrix and manage group creation, oncall, leave, and disband flows.","groups.search":"Search chat name / ID / owner","groups.missingOnly":"Missing bot only","groups.refresh":"Refresh","groups.create":"New Group","groups.chat":"Chat","groups.actions":"Actions","groups.addBots":"Add Bots","groups.manage":"Manage","groups.empty":"No chats match the filters.","groups.createTitle":"Create New Group","groups.createHelp":"Pick bots to invite. The dashboard chooses an online daemon as creator.","groups.name":"Group Name","groups.namePlaceholder":"e.g. AI ChangeLog","groups.bindDir":"Bind Directory","groups.bindDirHelp":"New topics start the CLI here and skip repo selection.","groups.botPicker":"Bots","groups.createSubmit":"Create","groups.cancel":"Cancel","groups.successTitle":"Group Created","groups.openGroup":"Open Group","groups.manageTitle":"Manage {name}","groups.owner":"Owner","groups.oncall":"Oncall Mode","groups.oncallHelp":"When enabled, group members can @ the bot; new topics use the bound directory.","groups.leaveTitle":"Select Bots to Leave","groups.leaveSelected":"Selected Bots Leave","groups.disband":"Disband Group","groups.dangerHint":"Disband only works when an in-chat bot is the owner. Otherwise prefer leaving the chat.","groups.save":"Save","groups.needWorkingDir":"Working directory is required","groups.noBotsOnline":"No bots online. Restart the daemon first.","schedules.title":"Schedules","schedules.subtitle":"View, pause, resume, and run scheduled tasks across daemons.","schedules.search":"Search name / prompt / working dir","schedules.anyKind":"Any kind","schedules.enabledOnly":"Enabled only","schedules.name":"Name","schedules.bot":"Bot","schedules.schedule":"Schedule","schedules.next":"Next","schedules.last":"Last","schedules.repeat":"Repeat","schedules.enabled":"Enabled","schedules.actions":"Actions","schedules.runNow":"Run Now","schedules.pause":"Pause","schedules.resume":"Resume","schedules.delivery":"Delivery","schedules.deliveryOrigin":"Original thread","schedules.deliveryNewTopic":"New topic each run","schedules.deliveryLocal":"Log only","schedules.useNewTopic":"Switch to new-topic","schedules.useOrigin":"Switch to original","schedules.empty":"No schedules.","settings.title":"Global Settings","settings.subtitle":"Manage machine-wide botmux dashboard behavior shared by every bot.","settings.loading":"Loading settings\u2026","settings.loadFailed":"Failed to load settings","settings.readOnlyVisitor":"Read-only access \u2014 changing settings requires an authorized link (run botmux dashboard).","settings.sectionAccess":"Access","settings.publicReadOnly":"Allow tokenless read-only dashboard access","settings.publicReadOnlyHelp":"When enabled, visitors without a token can view the dashboard, sessions, schedules, and SSE. Writes such as close, pause, and approvals still require token auth. Sensitive raw terminal logs always require a token.","settings.sectionCards":"Feishu Cards","settings.openTerminalInFeishu":"Open streaming-card terminals in the Feishu sidebar","settings.openTerminalInFeishuHelp":"Off by default: terminal buttons open the Web Terminal URL directly. When enabled, botmux wraps the URL with Feishu web_url/open so Feishu PC opens it in a sidebar. Terminal write access is still controlled by its token.","settings.sectionRepoPicker":"Repo Picker","settings.repoPickerMode":"Repo picker card mode","settings.repoPickerModeAll":"Repos + worktrees","settings.repoPickerModeRepos":"Main repos only","settings.repoPickerModeHelp":"Default shows repositories and linked worktrees. Main repos only hides linked worktrees from initialization and bare /repo cards; explicit /repo /abs/path/to/worktree still works.","settings.saving":"Saving\u2026","settings.saved":"Saved","settings.saveFailed":"Save failed","settings.sectionMaintenance":"Auto Maintenance","settings.autoUpdate":"Auto update","settings.autoUpdateHelp":"Off by default. At the set time, runs npm install -g botmux@latest to install the latest version (download/install only \u2014 no restart). npm-global installs only.","settings.autoRestart":"Auto restart","settings.autoRestartHelp":"Off by default; requires auto-update. After auto-update installs a newer version, restart to apply it if no session is in progress (busy \u21D2 slips to the next day).","settings.autoUpdateLocalDev":"This is a local-dev install (running from source); auto-update is unavailable.","settings.maintenanceTime":"Time","skills.title":"Skill Management","skills.subtitle":"Manage CLI-neutral botmux Skill assets and choose priority disclosure per bot.","skills.installed":"Installed Skills","skills.installedHelp":"Skill assets in the local registry that bots can disclose first.","skills.overviewTitle":"Organize Skill assets by bot","skills.overviewBody":"Global Skill delivery settings control session injection; each bot only manages its priority disclosure list.","skills.metricInstalled":"Installed Skills","skills.metricBots":"Configured Bots","skills.metricAttached":"Priority refs","skills.install":"Install Skill","skills.installInfoLabel":"Install location details","skills.installInfo":`Registry: ~/.botmux/skills/registry.json
11
+ Install: ~/.botmux/skills/store/skill-name; Git cache: ~/.botmux/skills/sources
12
+ Isolation: Codex/Claude global directories are not modified; local CLI Skills are referenced in place`,"skills.source":"Import Address","skills.sourcePlaceholder":"Paste a GitHub Skill page, Git URL, or local Skill directory","skills.sourceHelpRemoteLabel":"GitHub / Git: ","skills.sourceHelpRemote":"Paste a Skill directory page or repository URL; repository URLs need a repo path.","skills.sourceHelpLocalLabel":"Local CLI Skill directory: ","skills.sourceHelpLocal":"Referenced in place without copying into the botmux store.","skills.path":"Repo Path (optional)","skills.pathPlaceholder":"Blank uses the path from the GitHub URL","skills.ref":"Ref (optional)","skills.refPlaceholder":"Blank uses the GitHub URL ref or default HEAD","skills.link":"Local link (no copy)","skills.installSubmit":"Install","skills.update":"Update","skills.remove":"Remove","skills.pageStatus":"{page} / {pages}","skills.prevPage":"Previous page","skills.nextPage":"Next page","skills.empty":"No installed skills yet. Install from a local directory, Git, or GitHub.","skills.globalDefaults":"Global Skill Delivery","skills.globalProject":"Workspace Skills","skills.globalProjectOff":"Ignore workspace Skills","skills.globalProjectOffHelp":"Read global CLI Skills and botmux Skills only","skills.globalProjectAll":"Read workspace Skills","skills.globalProjectAllHelp":`Read .agents/skills and
13
+ .botmux/skills`,"skills.globalDelivery":"Skill Delivery","skills.bots":"Bot Skill Settings","skills.botsHelp":"Choose the Skills each bot should disclose first.","skills.botCount":"{count} Bots","skills.scrollBotsPrev":"Scroll bots left","skills.scrollBotsNext":"Scroll bots right","skills.skillCount":"{count} Skills","skills.attach":"Add to priority","skills.detach":"Remove","skills.detachNamed":"Remove {skill}","skills.delivery":"Injection","skills.deliveryAuto":"Auto","skills.deliveryAutoHelp":"Use native CLI delivery first; fall back to Prompt when unsupported","skills.deliveryPrompt":"Prompt","skills.deliveryPromptHelp":"Inject the Skill catalog into the session prompt; works with every CLI","skills.deliveryNative":"Native","skills.deliveryNativeHelp":"Use only the CLI native Skill mechanism; no Prompt fallback","skills.projectMode":"Workspace Skills","skills.projectDefault":"Follow global","skills.projectDefaultHelp":"Use the project default on the left","skills.projectOff":"Do not read","skills.projectOffHelp":"This bot ignores workspace skills","skills.projectAll":"Read","skills.projectAllHelp":"This bot includes workspace skill candidates","skills.priority":"Priority skills","skills.noPriority":"Not configured, keeping CLI default behavior","skills.dangling":"Not installed","skills.removeInUse":'Skill "{skill}" is still referenced by: {refs}. Removing it deletes the registry package but does not automatically clean references. Continue?',"skills.saved":"Saved","skills.failed":"Failed","skills.jobRunning":"Working...","skills.refresh":"Refresh","botDefaults.title":"Bot Profiles","botDefaults.subtitle":"Per-bot defaults: oncall, proactive start, persona role, cards and grants.","botDefaults.metaOnline":"Online \xB7 daemon healthy","botDefaults.search":"Search bot name / app id","botDefaults.refresh":"Refresh","botDefaults.sectionOncall":"New-chat Oncall","botDefaults.sectionBrand":"Card Signature","botDefaults.warning":"When enabled, chats without an oncall binding auto-bind to this directory on their next new topic. Manually bound or unbound chats are preserved.","botDefaults.empty":"No bots online. Run botmux restart first.","botDefaults.defaultOncall":"Default to oncall mode","botDefaults.defaultOncallHelp":"Unbound chats auto-bind on the next new topic","botDefaults.workingDir":"Default Working Directory","botDefaults.lastEnabled":"Last Enabled","botDefaults.autobound":"{count} chats auto-bound","botDefaults.save":"Save","botDefaults.required":"Working directory is required when enabled","botDefaults.brandLabel":"Signature (card footer)","botDefaults.brandLabelHelp":"Footer signature on cards this bot sends. Save empty = hide; fill in = custom (markdown ok, e.g. [Acme](https://\u2026)); Reset = show botmux.","botDefaults.brandLabelPlaceholder":"Default: botmux (empty = hidden)","botDefaults.sectionSandbox":"File sandbox (oncall)","botDefaults.sandboxToggle":"Enable file sandbox","botDefaults.sandboxHelp":"When on, every session of this bot runs in a per-session sandbox: only a project copy is visible \u2014 your real files, secrets, and other sessions are not. For sharing the bot with semi-trusted users (oncall). Linux only; applies to the next new session.","botDefaults.sandboxSaved":"Saved (applies to the next new session)","botDefaults.brandSave":"Save Signature","botDefaults.brandReset":"Reset to default","botDefaults.brandStateDefault":"Current: default botmux","botDefaults.brandStateOff":"Current: off","botDefaults.brandStateCustom":"Current: custom","botDefaults.sectionCard":"Card Behavior","botDefaults.disableStreaming":"Disable streaming card","botDefaults.disableStreamingHelp":"Stop posting the live session status card (and its Open Terminal entry). The task's final result still arrives as a message. For those who find the live card noisy.","botDefaults.writableLink":"Put a writable terminal link on the card","botDefaults.writableLinkHelp":'\u26A0\uFE0F Embeds a writable terminal link in the streaming card body \u2014 anyone in the chat can open and drive the terminal. Off = current behavior (private DM via the "Get Write Link" button).',"botDefaults.writableLinkMoot":"Streaming card disabled \u2014 this has no effect","botDefaults.privateCard":"/card sends a private card (authorized users only)","botDefaults.privateCardHelp":'Makes /card send an ephemeral "visible-to-specific-people" card: delivered only to the owner (allowedUsers); /grant-authorized talk users and everyone else in the chat cannot see it. Trade-off: it is a static snapshot (no live updates) and only works in regular group chats (topic groups / DMs fail, with no fallback). Affects only the /card command; the auto streaming card is unchanged.',"botDefaults.cardPrefSaved":"Saved","botDefaults.sectionRole":"Default Role","botDefaults.roleHelp":"This bot's default persona (applies across all chats), injected into the bot's sessions in every chat; a single group can override it on the Roles page. Save empty = delete.","botDefaults.rolePlaceholder":"e.g. You are a backend triage assistant; answer concisely, prefer runnable commands\u2026","botDefaults.roleSave":"Save role","botDefaults.roleDelete":"Delete","botDefaults.roleSaved":"Saved","botDefaults.roleDeleted":"Deleted","botDefaults.roleLoadErr":"Failed to load role","botDefaults.sectionAutoStart":"Proactive Start","botDefaults.autoStartJoin":"Auto-start when added to a new chat","botDefaults.autoStartJoinHelp":'When enabled, the bot auto-starts a session and gets to work the moment it is added to a new chat (when an authorized user / allowedUsers is a member), no @ needed. It launches in the bot default working dir; if none is configured it shows a repo-select card first. Prerequisite: subscribe the "bot joined chat" event im.chat.member.bot.added_v1 for this app and grant the member-read scope in the Feishu console.',"botDefaults.autoStartJoinPrompt":"First-turn prompt on join (optional)","botDefaults.autoStartJoinPromptPlaceholder":"Filled = used as the first task after joining; blank = the bot reads the chat and decides what to do","botDefaults.autoStartJoinPromptSave":"Save prompt","botDefaults.autoStartTopic":"Auto-start on new topics in topic groups","botDefaults.autoStartTopicHelp":"When enabled, in a topic group the bot automatically joins each newly opened topic and starts working on its first message, no @ needed. Topic groups only \u2014 regular groups are unaffected.","botDefaults.sectionSessionMode":"Session mode","botDefaults.p2pMode":"Private chat session mode","botDefaults.p2pThread":"thread (separate session per DM)","botDefaults.p2pChat":"chat (flat continuous session)","botDefaults.p2pHelp":"How 1:1 DMs are sessioned: thread = each top-level message starts its own session (keeps chatter out of one CLI process); chat = the whole DM shares one continuous session and context (Hermes-like). Takes effect immediately.","botDefaults.regularGroupMode":"Regular group session mode","botDefaults.regularGroupModeChat":"chat (flat continuous session, default)","botDefaults.regularGroupModeNewTopic":"new-topic (each top-level @ opens its own topic & session)","botDefaults.regularGroupModeShared":"shared (topic display, reusing one session)","botDefaults.regularGroupModeHelp":"How new top-level @mentions in regular (non-topic) groups are sessioned: chat = the whole group shares one continuous session (default); new-topic = each top-level @ opens its own topic with a separate session; shared = topic display but reuse the same session (replies fold into a topic yet share the group session & context). This is the per-bot default; a specific group can override it via /reply-mode. Takes effect immediately.","botDefaults.mentionMode":"Group @ policy","botDefaults.mentionModeAlways":"Always require @ (default)","botDefaults.mentionModeTopic":"No @ needed inside topics","botDefaults.mentionModeNever":"Never require @","botDefaults.mentionModeHelp":'Bot-global: controls when an @ is required to get a reply in groups. "Always require @" = every message needs an @ (default, safest; inside topics too, in multi-person groups); "No @ needed inside topics" = starting a new conversation / top-level still needs @, but follow-ups inside ANY topic this bot already drives (new-topic / shared / topic-group) continue without @; "Never require @" = non-@ messages are answered too wherever the bot has talk access (including cold-starting on a brand-new message \u2014 only suitable for dedicated / on-call small groups; in busy multi-person groups it replies to everything). Note: when you are alone with this bot (1:1) replies never need an @, independent of this setting.',"botDefaults.docSubscribeMode":"Doc subscription trigger (default)","botDefaults.docSubscribeModeMention":"Only when a comment @s me","botDefaults.docSubscribeModeAll":"Every new comment","botDefaults.docSubscribeModeHelp":'After subscribing to a Feishu doc with /subscribe-lark-doc, its comments feed into the session and the bot replies back into the comment. This sets the default trigger range for new subscriptions: "only when a comment @s me" is safest (avoids noise); "every new comment" suits dedicated docs.',"botDefaults.sectionGrant":"Authorization & Quota","botDefaults.restrictGrant":"Restrict grantees to plain conversation","botDefaults.restrictGrantHelp":"When enabled, /grant-authorized users (the owner is exempt) can only send plain messages; every slash command is blocked: botmux built-in commands, passthrough commands, /workflow, /introduce, /t, and CLI-native commands (/help, etc.). Text like /path/to/file is not misclassified.","botDefaults.quotaDefault":"Default message quota","botDefaults.quotaPlaceholder":"Empty = no default quota","botDefaults.quotaHelp":'Message count a bare /grant @x (no number) hands out. Empty or "Turn off" merely stops applying a default to bare /grant \u2014 it does NOT clear existing quota counters, nor affect an explicit /grant @x N; those keep being enforced. Authorization is auto-revoked once a quota runs out.',"botDefaults.quotaSave":"Save quota","botDefaults.quotaOff":"Turn off","botDefaults.quotaInvalid":"Quota must be a positive integer","botDefaults.quotaStateOff":"Current: no default quota","botDefaults.quotaStateOn":"Current: {count} per grantee","botDefaults.sectionSessionCap":"Session limit","botDefaults.maxLiveWorkers":"Max live sessions","botDefaults.maxLiveWorkersPlaceholder":"Empty = default 30","botDefaults.maxLiveWorkersHelp":"Cap on this bot's simultaneously-live sessions, to bound memory. Beyond it, the least-recently-used sessions are suspended: both the worker AND the CLI process are killed to reclaim all their memory, and the session cold-resumes from its on-disk transcript on the next message (--resume rebuilds context in a few seconds \u2014 nothing stays resident). Empty = use the default of 30; a number = a per-bot override (set a larger number if you want more). Note: suspension only applies to resumable backends (tmux/herdr/zellij), never plain PTY; a session that is mid-reply is never interrupted.","botDefaults.maxLiveWorkersSave":"Save limit","botDefaults.maxLiveWorkersOff":"Reset to default","botDefaults.maxLiveWorkersInvalid":"Limit must be a positive integer","botDefaults.maxLiveWorkersStateDefault":"Current: default 30 live sessions","botDefaults.maxLiveWorkersStateOn":"Current: up to {count} live sessions","nav.roles":"Roles","roles.title":"Role Management","roles.subtitle":"Set per-bot role prompts for each group. Each bot adopts its own persona in the selected group.","roles.search":"Search group / bot / ID","roles.refresh":"Refresh","roles.selectHint":"\u2190 Expand a group and select a bot to edit its role","roles.editorPlaceholder":`Enter role description, e.g.:
8
14
  You are a code reviewer for this group...`,"roles.configured":"Configured","roles.unconfigured":"None","roles.noChats":"No groups","roles.preview":"Preview","roles.previewEmpty":"(empty)","roles.saved":"Saved","roles.delete":"Delete","roles.save":"Save","roles.confirmDelete":"Delete this bot's role config for this group?","roles.botsWithRoles":"bots configured","roles.emptyError":"Role content cannot be empty","roles.saveFailed":"Save failed, please retry","common.none":"None","common.loading":"Loading\u2026","common.unknown":"Unknown","common.now":"now","common.never":"never","common.all":"All","nav.workflows":"Workflows (beta)","nav.workflowCatalog":"Catalog","workflow.subnav.runs":"Runs","workflow.subnav.catalog":"Catalog","workflow.searchPlaceholder":"search runId / workflowId / chatId","workflow.filter.nonTerminal":"non-terminal","workflow.filter.all":"all","workflow.status.pending":"pending","workflow.status.running":"running","workflow.status.waiting":"waiting","workflow.status.effectAttempting":"effect","workflow.status.timedOut":"timed out","workflow.status.succeeded":"succeeded","workflow.status.failed":"failed","workflow.status.cancelled":"cancelled","workflow.table.run":"run","workflow.table.workflow":"workflow","workflow.table.status":"status","workflow.table.lastSeq":"lastSeq","workflow.table.dangling":"dEf/dAct/dWait","workflow.table.updated":"updated","workflow.table.chatApp":"chat / app","workflow.list.failedLoad":"Failed to load: {error}","workflow.list.noRuns":"No runs match.","workflow.list.noFilterMatch":"No runs match this filter.","workflow.list.loaded":"{count} runs \xB7 refreshed {time}","workflow.list.error":"error: {error}","workflow.detail.back":"Back","workflow.detail.loading":"Loading...","workflow.detail.loadFailed":"Load failed","workflow.detail.cancel":"Cancel","workflow.detail.cliCancelOnly":"CLI cancel only","workflow.detail.cancelTitle":"Cancel this workflow run","workflow.detail.cliCancelTitle":"Cancel unavailable: use botmux workflow cancel {runId}","workflow.detail.nodes":"Nodes / Activities","workflow.detail.parallel":"Parallel execution","workflow.detail.parallelMeta":"{count} attempt(s) \xB7 max parallel {max} \xB7 running {running}","workflow.detail.noParallelData":"No attempt timing data yet.","workflow.detail.parallelNow":"now","workflow.detail.node":"node","workflow.detail.nodeStatus":"node status","workflow.detail.activity":"activity","workflow.detail.activityStatus":"activity status","workflow.detail.attempts":"attempts","workflow.detail.current":"current","workflow.detail.detail":"detail","workflow.detail.nodeIO":"Node I/O","workflow.detail.timeline":"Timeline","workflow.detail.loadOlder":"Load older","workflow.detail.seq":"seq","workflow.detail.actor":"actor","workflow.detail.error":"error","workflow.detail.event":"event","workflow.detail.time":"time","workflow.detail.refreshed":"refreshed {time}","workflow.detail.unknownRun":"unknown run","workflow.detail.snapshotHttp":"snapshot HTTP {status}","workflow.detail.eventsHttp":"events HTTP {status}","workflow.detail.cancelUnavailable":"cancel unavailable: use botmux workflow cancel {runId}","workflow.detail.cancelConfirm":`Cancel workflow run {runId}?
9
15
 
10
16
  {total} dangling item(s) will be handled by cancel-driven recovery.
11
17
  effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"workflow.detail.writeAccessCancel":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and click cancel again.","workflow.detail.cancelHttp":"cancel HTTP {status}","workflow.detail.cancelPending":"cancel pending; waiting for running activity to drain","workflow.detail.writeAccessApproval":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and approve/reject again.","workflow.detail.actionHttp":"{action} HTTP {status}","workflow.detail.approved":"approved","workflow.detail.rejected":"rejected","workflow.detail.alreadyTerminal":"Run already terminal; {label} was not applied.","workflow.detail.workflowContinue":"{label}; waiting for workflow to continue.","workflow.detail.workflowRefreshing":"{label}; refreshing workflow state.","workflow.detail.eventsLoaded":"{loaded}/{total} events loaded","workflow.detail.dangling":"Dangling","workflow.detail.noDangling":"No dangling work.","workflow.detail.none":"none","workflow.detail.noNodes":"No nodes yet.","workflow.detail.idle":"idle","workflow.detail.noNodeIO":"No node I/O yet.","workflow.detail.notDispatched":"not dispatched","workflow.detail.noAttempt":"No attempt yet","workflow.detail.attempt":"attempt","workflow.detail.authoredInput":"Authored input","workflow.detail.resolvedInput":"Resolved input","workflow.detail.output":"Output","workflow.detail.executionLog":"Execution log","workflow.detail.liveTerminal":"Live terminal","workflow.detail.terminalLive":"live","workflow.detail.terminalClosedShort":"closed","workflow.detail.terminalClosed":"Terminal is closed. Use the execution log below for the final transcript.","workflow.detail.openTerminalNewTab":"Open terminal in new tab","workflow.detail.terminalReplay":"Terminal replay","workflow.detail.openReplayNewTab":"Open replay in new tab","workflow.detail.downloadFullLog":"Download full log","workflow.detail.terminalResume":"Debug session","workflow.detail.openResumeNewTab":"Open debug session in new tab","workflow.detail.resumeSession":"Resume session","workflow.detail.resumeStarting":"Starting\u2026","workflow.detail.endResumeSession":"End debug session","workflow.detail.resumeEnding":"Ending\u2026","workflow.detail.resumeUnsupportedCli":'CLI "{cliId}" does not support resume',"workflow.detail.resumeMissingCliSession":"Missing cliSessionId \u2014 cannot resume","workflow.detail.resumeStartFailed":"Failed to start debug session (HTTP {status})","workflow.detail.resumeEndFailed":"Failed to end debug session (HTTP {status})","workflow.detail.writeAccessResume":"Resume requires dashboard write access.","workflow.detail.waitPrompt":"Wait prompt","workflow.detail.approvalComment":"Approval comment","workflow.detail.optionalComment":"Optional comment","workflow.detail.approve":"Approve","workflow.detail.reject":"Reject","workflow.detail.submitting":"Submitting...","workflow.detail.empty":"empty","workflow.detail.truncated":"truncated","workflow.detail.noData":"No data.","workflow.detail.noPreview":"No preview.","workflow.detail.open":"open","workflow.detail.deadline":"deadline","workflow.detail.effect":"effect","workflow.detail.wait":"wait","workflow.detail.noEvents":"No events.","workflow.summary.workflow":"workflow","workflow.summary.status":"status","workflow.summary.lastSeq":"lastSeq","workflow.summary.updated":"updated","workflow.summary.revision":"revision","workflow.summary.initiator":"initiator","workflow.summary.failedNode":"failedNode","workflow.summary.cancelOrigin":"cancelOrigin","workflow.summary.chat":"chat","workflow.summary.app":"app","workflow.dangling.activities":"activities","workflow.dangling.effects":"effects","workflow.dangling.waits":"waits","workflow.dangling.cancels":"cancels","catalog.title":"Workflow catalog","catalog.subtitle":"Create a workflow run from a saved workflow definition.","catalog.searchPlaceholder":"search workflowId / path","catalog.refresh":"Refresh","catalog.loading":"Loading catalog...","catalog.loadFailed":"Failed to load catalog: {error}","catalog.noDefinitions":"No workflow definitions found.","catalog.noFilterMatch":"No definitions match this filter.","catalog.table.workflow":"workflow","catalog.table.version":"version","catalog.table.params":"params","catalog.table.nodes":"nodes","catalog.table.revision":"revision","catalog.table.path":"path","catalog.paramSummary":"{required}/{total} required","catalog.back":"Back to catalog","catalog.detailTitle":"Workflow definition","catalog.definitionLoadFailed":"Failed to load definition: {error}","catalog.summary":"Summary","catalog.paramsSchema":"Params schema","catalog.definitionJson":"Definition JSON","catalog.runPanel":"Run workflow","catalog.paramsJson":"Params JSON","catalog.paramsPlaceholder":`{
12
18
  "city": "\u5317\u4EAC"
13
- }`,"catalog.chatId":"Chat ID","catalog.larkAppId":"Lark app ID","catalog.chatBindingHint":"Required so humanGate cards and cancel routing know which Lark chat owns the run.","catalog.run":"Run","catalog.running":"Starting...","catalog.badParamsJson":"Params must be a JSON object.","catalog.writeAccess":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and run again.","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"Run started; opening detail page...","catalog.invalidParams":"Invalid params","catalog.issue":"{path}: {message}","catalog.noParams":"No params declared.","catalog.required":"required","catalog.optional":"optional","catalog.default":"default","catalog.description":"description","catalog.path":"path","catalog.revision":"revision","catalog.nodeCount":"nodes"},yo={zh:cs,en:us};function Vt(e){if(typeof e!="string")return null;let n=e.trim().toLowerCase();return n==="zh"||n.startsWith("zh-")?"zh":n==="en"||n.startsWith("en-")?"en":null}function ps(e=[]){for(let n of e){let o=Vt(n);if(o)return o}return"zh"}function Qt(e){return(n,o)=>{let s=yo[e][n]??yo.zh[n]??n;return o?s.replace(/\{(\w+)\}/g,(a,i)=>{let d=o[i];return d==null?`{${i}}`:String(d)}):s}}function vo(e,n){return(e?Vt(e.getItem(In)):null)??ps(n)}var Mn="botmux.dashboard.theme",ko="botmux.dashboard.sessions.view";function ms(e){return e==="system"||e==="light"||e==="dark"?e:null}function xn(e){return e==="kanban"||e==="board"||e==="table"?e:null}function $o(e,n){return e==="system"?n?"dark":"light":e}function So(e){return ms(e?.getItem(Mn))??"dark"}function To(e){return xn(e?.getItem(ko))??"board"}var Lo="botmux.dashboard.sessions.boardOrder",Dt=["needs-you","starting","working","idle"];function fs(e){if(!Array.isArray(e)||e.length!==Dt.length)return null;let n=new Set(e);if(n.size!==e.length)return null;for(let o of Dt)if(!n.has(o))return null;return e.slice()}function Io(e){try{let n=e?.getItem(Lo);return n?fs(JSON.parse(n))??[...Dt]:[...Dt]}catch{return[...Dt]}}function En(e,n){try{e?.setItem(Lo,JSON.stringify(n))}catch{}}function Mo(e,n){try{e?.setItem(ko,n)}catch{}}var xo="botmux.dashboard.sessions.kanbanGroupBy",Hn="botmux.dashboard.sessions.kanbanTeam";function gs(e){return e==="flow"||e==="team"||e==="bot"?e:null}function Eo(e){return gs(e?.getItem(xo))??"flow"}function Ho(e,n){try{e?.setItem(xo,n)}catch{}}var Co="botmux.dashboard.sidebar";function bs(e){return e==="expanded"||e==="collapsed"?e:null}function Ao(e){return bs(e?.getItem(Co))??"expanded"}function Do(e,n){try{e?.setItem(Co,n)}catch{}}var hs=["default","cyber","genshin","fallout","prts","bluearchive","zzz","dragonball","ikun"],Cn="botmux.dashboard.skin";function ws(e){return typeof e=="string"&&hs.includes(e)?e:null}function Ro(e){return ws(e?.getItem(Cn))??"default"}var ys="\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF830123456789\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E$#%&@*+=<>/\\",Oo=["186 100% 60%","56 97% 60%","330 100% 64%","150 80% 58%"],Dn=[{key:"shake",dur:280},{key:"rgb",dur:340},{key:"tear",dur:400},{key:"invert",dur:220},{key:"slice",dur:320},{key:"blackout",dur:260}],Bo=["ESTABLISHING NETLINK","BYPASSING ICE","DECRYPTING DATAFLOW","SYNCING BOTMUX TELEMETRY","ACCESS GRANTED"],No="0123456789ABCDEF#<>*/=+\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C",vs=3200,Rt=[],$t=0,Xt=0;function Bn(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Rn(e,n){let o="";for(let s=0;s<e;s++)o+=n[Math.floor(Math.random()*n.length)];return o}function ks(e){let n=document.createElement("div");n.className="cyber-rain";let o=Math.max(10,Math.min(26,Math.round(window.innerWidth/70)));for(let s=0;s<o;s++){let a=document.createElement("span");a.className="cyber-rain-col",a.textContent=Rn(28+Math.floor(Math.random()*22),ys);let i=Oo[Math.floor(Math.random()*Oo.length)];a.style.cssText=`left:${(s+.5)/o*100}%;--rc:${i};--sz:${10+Math.floor(Math.random()*9)}px;--op:${(.25+Math.random()*.45).toFixed(2)};--dur:${(6+Math.random()*9).toFixed(1)}s;--delay:${(-Math.random()*12).toFixed(1)}s;`,n.appendChild(a)}e.appendChild(n)}function $s(){if(Bn())return;let e=document.body,n=()=>{let o=Dn[Math.floor(Math.random()*Dn.length)],s=`cp-fx-${o.key}`;e.classList.add(s),Rt.push(window.setTimeout(()=>e.classList.remove(s),o.dur)),Rt.push(window.setTimeout(n,2400+Math.random()*4200))};Rt.push(window.setTimeout(n,1800+Math.random()*2600))}function Ss(){Rt.forEach(e=>window.clearTimeout(e)),Rt=[];for(let e of Dn)document.body.classList.remove(`cp-fx-${e.key}`)}function Ts(){if(Bn()||document.getElementById("cyber-boot"))return;let e=document.createElement("div");e.id="cyber-boot",e.className="cyber-boot",e.setAttribute("aria-hidden","true"),e.innerHTML='<div class="cyber-boot-grid"></div><div class="cyber-loader"><div class="cyber-loader-frame"><div class="cyber-loader-head"><span>KIROSHI NETLINK</span><span class="cyber-loader-jp">\u4FB5\u5165\u4E2D</span></div><div class="cyber-loader-line"><span class="cyber-loader-prompt">&gt;</span><span class="cyber-loader-text"></span><span class="cyber-loader-cursor">_</span></div><div class="cyber-loader-stream"></div></div></div>',document.body.appendChild(e);let n=e.querySelector(".cyber-loader-text"),o=e.querySelector(".cyber-loader-stream"),s=0,a=0,i=0;$t=window.setInterval(()=>{let d=Bo[s];n&&(a<d.length?(a+=1,n.textContent=d.slice(0,a)+Rn(d.length-a,No),n.classList.remove("done")):i<16?(i+=1,n.textContent=d,n.classList.add("done")):(s=(s+1)%Bo.length,a=0,i=0)),o&&(o.textContent=Rn(26,No))},50),Xt=window.setTimeout(()=>{window.clearInterval($t),$t=0,e.remove()},vs)}function Ls(){$t&&(window.clearInterval($t),$t=0),Xt&&(window.clearTimeout(Xt),Xt=0),document.getElementById("cyber-boot")?.remove()}var Is=320,Po=16,Ot=!0,kt=0,An=0,Zt=!1,en=[],On=[];function Ms(){if(Zt)return;Zt=!0,Ot=!1,kt=0;let e=Bn(),n="";for(let s=0;s<Po;s++){let a=s%3===0?"186 100% 52%":s%3===1?"330 100% 58%":"56 97% 52%",i=(s%2===0?1:-1)*(8+s%5*7);n+=`<span class="cyber-breach-shard" style="top:${s/Po*100}%;height:${2+s%4*3}%;--shift:${i}px;--delay:${s%8*.09}s;--dur:${(.36+s%5*.12).toFixed(2)}s;--hue:${a}"></span>`}let o=document.createElement("div");o.id="cyber-breach",o.className="cyber-breach",o.setAttribute("aria-hidden","true"),o.innerHTML=`<span class="cyber-breach-flash"></span><span class="cyber-breach-grid"></span><div class="cyber-breach-shards">${n}</div><div class="cyber-breach-banner"><span class="cyber-breach-tag">// BREACH PROTOCOL \u2014 SYSTEM OVERRIDE</span><span class="cyber-breach-caption" data-text="SYSTEM BREACH">SYSTEM BREACH</span><span class="cyber-breach-sub" data-text="NETWATCH OVERRIDE ENGAGED">NETWATCH OVERRIDE ENGAGED</span></div>`,document.body.appendChild(o),e||document.body.classList.add("cyber-breach-quake"),en.push(window.setTimeout(()=>document.body.classList.remove("cyber-breach-quake"),760)),en.push(window.setTimeout(()=>{o.remove(),Zt=!1},e?2600:4200))}function xs(){Ot=!0,kt=0;let e=document.documentElement,n=()=>e.scrollHeight-(window.innerHeight+window.scrollY)<=4,o=v=>{v<=0||!n()||(kt+=v,kt>Is&&Ot&&Ms())},s=v=>o(v.deltaY),a=v=>{An=v.touches[0]?.clientY??0},i=v=>{let k=v.touches[0]?.clientY??0,I=An-k;An=k,o(I)},d=()=>{n()||(kt=0,Ot=!0)},p=(v,k)=>{window.addEventListener(v,k,{passive:!0}),On.push([v,k])};p("wheel",s),p("touchstart",a),p("touchmove",i),p("scroll",d)}function Es(){for(let[e,n]of On)window.removeEventListener(e,n);On=[],en.forEach(e=>window.clearTimeout(e)),en=[],document.body.classList.remove("cyber-breach-quake"),document.getElementById("cyber-breach")?.remove(),Zt=!1,Ot=!0,kt=0}function qo(e,n=!1){if(!(typeof document>"u")){if(!e){document.getElementById("cyber-fx")?.remove(),document.getElementById("cyber-hud")?.remove(),document.getElementById("cyber-glitch")?.remove(),Ss(),Ls(),Es();return}if(!document.getElementById("cyber-fx")){let o=document.createElement("div");o.id="cyber-fx",o.className="cyber-fx",o.setAttribute("aria-hidden","true"),o.innerHTML='<div class="cyber-fx-grid"></div><div class="cyber-fx-scan"></div><span class="cyber-flicker"></span><span class="cyber-rollline"></span>',ks(o),document.body.appendChild(o);let s=document.createElement("div");s.id="cyber-hud",s.className="cyber-hud",s.setAttribute("aria-hidden","true"),s.innerHTML='<span class="cyber-hud-corner tl"></span><span class="cyber-hud-corner tr"></span><span class="cyber-hud-corner bl"></span><span class="cyber-hud-corner br"></span><span class="cyber-hud-tag">NIGHT CITY // NETWATCH</span>',document.body.appendChild(s);let a=document.createElement("div");a.id="cyber-glitch",a.className="cyber-glitch",a.setAttribute("aria-hidden","true"),document.body.appendChild(a),$s(),xs()}n&&Ts()}}var Hs={genshin:2e3,zzz:1900,dragonball:1900,ikun:1900},Cs='<span class="si-bball" aria-hidden="true"><span class="si-bball-seams"><svg viewBox="0 0 100 100"><g fill="none" stroke="#3a1d08" stroke-width="3.4" stroke-linecap="round"><path d="M50 4V96"/><path d="M4 50H96"/><path d="M50 4 Q14 50 50 96"/><path d="M50 4 Q86 50 50 96"/></g></svg></span></span>';function As(e){switch(e){case"genshin":return'<span class="si-gi-shine" aria-hidden="true"></span><span class="si-gi-text">\u539F\u795E\uFF0C\u542F\u52A8</span>';case"zzz":return'<span class="si-static" aria-hidden="true"></span><span class="si-roll" aria-hidden="true"></span><span class="si-now">NOW&nbsp;LOADING</span>';case"dragonball":return'<span class="si-speed" aria-hidden="true"></span><img class="si-cloud" src="/assets/skins/dragonball-wukong.webp" alt="">';case"ikun":return Cs;default:return""}}function Ds(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Uo(e){if(typeof document>"u"||Ds())return;let n=Hs[e];if(!n)return;document.getElementById("skin-intro")?.remove();let o=document.createElement("div");o.id="skin-intro",o.className=`skin-intro si-${e}`,o.setAttribute("aria-hidden","true"),o.style.setProperty("--si-dur",`${n}ms`),o.innerHTML=As(e),document.body.appendChild(o),window.setTimeout(()=>o.remove(),n+80)}var Pn=class{locale="zh";themeMode="system";resolvedTheme="light";skin="default";authed=!0;listeners=new Set;translate=Qt(this.locale);mediaQuery=null;init(){let n=typeof window<"u"?window:void 0;this.locale=vo(n?.localStorage,Os()),this.translate=Qt(this.locale),this.themeMode=So(n?.localStorage),this.skin=Ro(n?.localStorage),this.mediaQuery=n?.matchMedia?.("(prefers-color-scheme: dark)")??null,this.mediaQuery?.addEventListener("change",()=>{this.applyTheme(),this.emit()}),this.applyTheme(),this.applySkin(),this.applyLocale()}t(n,o){return this.translate(n,o)}setLocale(n){this.locale!==n&&(this.locale=n,this.translate=Qt(n),window.localStorage.setItem(In,n),this.applyLocale(),this.emit())}get theme(){return this.skin==="default"?this.themeMode:this.skin}setTheme(n){let o=n==="system"||n==="light"||n==="dark",s=o?"default":n,a=s!==this.skin;o&&this.themeMode!==n&&(this.themeMode=n,window.localStorage.setItem(Mn,this.themeMode)),a&&(this.skin=s,window.localStorage.setItem(Cn,this.skin)),this.applyTheme(),this.applySkin(a),this.emit()}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}applyTheme(){this.resolvedTheme=$o(this.themeMode,!!this.mediaQuery?.matches);let n=this.skin==="default"?this.resolvedTheme:Rs[this.skin];document.documentElement.dataset.theme=n,document.documentElement.dataset.themeMode=this.themeMode}applySkin(n=!1){document.documentElement.dataset.skin=this.skin,qo(this.skin==="cyber",n),n&&this.skin!=="cyber"&&this.skin!=="default"&&Uo(this.skin)}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}},Rs={default:"light",cyber:"dark",genshin:"light",fallout:"dark",prts:"dark",bluearchive:"dark",zzz:"dark",dragonball:"light",ikun:"dark"};function Os(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var Te=new Pn;function t(e,n){return Te.t(e,n)}function r(e){return e.replace(/[&<>"']/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[n])}function qe(e){if(!e)return"-";let n=Date.now()-e;return n<6e4?t("common.now"):n<36e5?Math.floor(n/6e4)+"m":n<864e5?Math.floor(n/36e5)+"h":Math.floor(n/864e5)+"d"}var jo=[{c1:"#5be3ff",c2:"#4f8bff"},{c1:"#b89bff",c2:"#6b4df0"},{c1:"#7ce0c3",c2:"#2e9e8f"},{c1:"#8fb4ff",c2:"#3b62d8"},{c1:"#ffd28f",c2:"#d8783b"},{c1:"#7df0a8",c2:"#1f9e63"},{c1:"#9fd0ff",c2:"#4878c8"},{c1:"#ff9fb8",c2:"#d84a78"}];function Fo(e){let n=0,o=String(e??"");for(let i=0;i<o.length;i++)n=n*31+o.charCodeAt(i)>>>0;let{c1:s,c2:a}=jo[n%jo.length];return`--c1:${s};--c2:${a}`}var tn=new Map,nn=new Map;function Bs(e,n){return n?tn.get(n):e?nn.get(String(e)):void 0}function fe(e){let n=e.name??"",o=e.avatarUrl??Bs(e.name,e.larkAppId),s=e.size==="sm"?" orb-avatar-sm":"",a=o?" orb-has-img":"",i=e.dot?`<i class="orb-dot orb-dot-${e.dot}"></i>`:"",d=o?`<img class="orb-img" src="${r(o)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar${s}${a}" style="${Fo(n)}" aria-hidden="true">${d}${i}</span>`}function Ns(e){return e?sn.get(e):void 0}function on(e){let n=e.name??e.chatId??"",o=e.avatarUrl??Ns(e.chatId),s=e.size==="sm"?" orb-avatar-sm":"",a=o?" orb-has-img":"",i=o?`<img class="orb-img" src="${r(o)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar orb-square${s}${a}" style="${Fo(n)}" aria-hidden="true">${i}</span>`}var Bt=new Map,an=new Map,sn=new Map,Nn=null,Go="botmux.avatarCache.v1";function Ps(){try{let e=typeof window<"u"?window.localStorage.getItem(Go):null;if(!e)return;let n=JSON.parse(e);for(let[o,s]of Object.entries(n.botByAppId??{}))tn.set(o,s);for(let[o,s]of Object.entries(n.botByName??{}))nn.set(o,s);for(let[o,s]of Object.entries(n.chatById??{}))sn.set(o,s);for(let[o,s]of Object.entries(n.nameByAppId??{}))Bt.set(o,s);for(let[o,s]of Object.entries(n.chatNameById??{}))an.set(o,s)}catch{}}function qs(){try{if(typeof window>"u")return;window.localStorage.setItem(Go,JSON.stringify({botByAppId:Object.fromEntries(tn),botByName:Object.fromEntries(nn),chatById:Object.fromEntries(sn),nameByAppId:Object.fromEntries(Bt),chatNameById:Object.fromEntries(an)}))}catch{}}Ps();function Ke(){return Nn??=(async()=>{try{let e=await fetch("/api/groups");if(!e.ok)throw new Error(`HTTP ${e.status}`);let n=await e.json();for(let o of n.bots??[])o.larkAppId&&o.botName&&o.botName!==o.larkAppId&&Bt.set(o.larkAppId,String(o.botName)),o.botAvatarUrl&&(o.larkAppId&&tn.set(o.larkAppId,String(o.botAvatarUrl)),o.botName&&nn.set(String(o.botName),String(o.botAvatarUrl)));for(let o of n.chats??[])o.chatId&&o.name&&an.set(o.chatId,String(o.name)),o.chatId&&o.avatar&&sn.set(o.chatId,String(o.avatar));qs()}catch{Nn=null}})(),Nn}function _o(e){return e?Bt.get(e):void 0}function ye(e){let n=e.larkAppId?Bt.get(e.larkAppId):void 0;return n||(e.botName&&e.botName!==e.larkAppId?String(e.botName):String(e.botName??e.larkAppId??"-"))}function st(e){return e.chatId&&an.get(e.chatId)||null}function ve(e){let n=String(e??"");return n.replace(/^(?:@\S+\s*)+/,"").trim()||n}function St(e){return`<div class="page-loading" role="status"><i class="page-loading-spin" aria-hidden="true"></i>${r(e??t("common.loading"))}</div>`}function it(e){return e.status==="closed"?null:e.agentAttention?.reason?e.agentAttention.reason:e.agentAttention?t("sessions.board.signalAgent"):e.pendingRepo?t("sessions.board.signalRepo"):e.tuiPromptActive?t("sessions.board.signalPrompt"):e.status==="limited"?t("sessions.board.signalLimited"):null}function xe(e){let n=Number(e.agentAttention?.at??e.lastMessageAt??0);if(Number.isFinite(n))return n;let o=Number(e.lastMessageAt??0);return Number.isFinite(o)?o:0}var Ko={chats:[],bots:[]};async function Us(){try{let e=await fetch("/api/groups");if(!e.ok)return;Ko=await e.json()}catch{}}var qn=new Set(["working","analyzing","active","starting"]);function js(e){let n=new Map,o=a=>{let i=n.get(a);return i||(i={botName:a,larkAppId:a,cliId:"unknown",online:!1,sessions:[],active:[],busy:[],attention:[],lastActiveAt:0},n.set(a,i)),i};for(let a of Ko.bots??[]){let i=o(a.larkAppId??a.botName??"-");i.online=!0,a.botName&&(i.botName=a.botName),a.botAvatarUrl&&(i.botAvatarUrl=a.botAvatarUrl)}let s=[...e].sort((a,i)=>+(a.status==="closed")-+(i.status==="closed"));for(let a of s){let i=a.larkAppId??a.botName??"-";if(a.status==="closed"&&!n.has(i))continue;let d=o(i);a.botName&&(d.botName===d.larkAppId||!d.botName)&&(d.botName=a.botName),d.sessions.push(a),a.cliId&&d.cliId==="unknown"&&(d.cliId=a.cliId),d.lastActiveAt=Math.max(d.lastActiveAt,Number(a.lastMessageAt??0)),a.status!=="closed"&&(d.active.push(a),qn.has(a.status)&&d.busy.push(a),it(a)&&d.attention.push(a))}for(let a of n.values())if(a.botName===a.larkAppId){let i=_o(a.larkAppId);i&&(a.botName=i)}return[...n.values()].sort((a,i)=>{let d=p=>p.attention.length?0:p.busy.length?1:p.online||p.active.length?2:3;return d(a)!==d(i)?d(a)-d(i):i.lastActiveAt-a.lastActiveAt})}var Jo="botmux.overview.teamExpanded",Fs=230,zo=13,Wo=2;function Gs(e){let n=e.clientWidth;return n?Math.max(1,Math.floor((n+zo)/(Fs+zo)))*Wo:Wo*3}function _s(){try{return window.localStorage.getItem(Jo)==="1"}catch{return!1}}function zs(e){try{window.localStorage.setItem(Jo,e?"1":"0")}catch{}}function Ws(e){let n=!e.online&&e.active.length===0,o=e.attention.length>0,s=e.busy.length>0,a=o?"warn":s?"busy":n?"off":"ok",i;if(o){let p=[...e.attention].sort((v,k)=>xe(v)-xe(k))[0];i=`<b>${r((ve(p.title)||p.sessionId).slice(0,60))}</b> \xB7 ${r(it(p)??"")}`}else if(s){let p=[...e.busy].sort((v,k)=>Number(k.lastMessageAt??0)-Number(v.lastMessageAt??0))[0];i=`<b>${r((ve(p.title)||p.sessionId).slice(0,60))}</b>`}else n?i=r(t("overview.botOffline")):i=r(t("overview.botIdle"));let d=o?`<span class="tag tag-warn">${r(t("overview.botNeedsYou"))}</span>`:s?`<span class="tag tag-run">${r(t("overview.botBusy",{count:e.busy.length}))}</span>`:n?`<span class="tag tag-off">${r(t("overview.botOff"))}</span>`:`<span class="tag tag-ok">${r(t("overview.botReady"))}</span>`;return`<article class="mate${o?" mate-attn":""}${n?" mate-off":""}">
19
+ }`,"catalog.chatId":"Chat ID","catalog.larkAppId":"Lark app ID","catalog.chatBindingHint":"Required so humanGate cards and cancel routing know which Lark chat owns the run.","catalog.run":"Run","catalog.running":"Starting...","catalog.badParamsJson":"Params must be a JSON object.","catalog.writeAccess":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and run again.","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"Run started; opening detail page...","catalog.invalidParams":"Invalid params","catalog.issue":"{path}: {message}","catalog.noParams":"No params declared.","catalog.required":"required","catalog.optional":"optional","catalog.default":"default","catalog.description":"description","catalog.path":"path","catalog.revision":"revision","catalog.nodeCount":"nodes"},La={zh:ys,en:vs};function en(e){if(typeof e!="string")return null;let n=e.trim().toLowerCase();return n==="zh"||n.startsWith("zh-")?"zh":n==="en"||n.startsWith("en-")?"en":null}function ks(e=[]){for(let n of e){let a=en(n);if(a)return a}return"zh"}function tn(e){return(n,a)=>{let s=La[e][n]??La.zh[n]??n;return a?s.replace(/\{(\w+)\}/g,(o,r)=>{let d=a[r];return d==null?`{${r}}`:String(d)}):s}}function Ta(e,n){return(e?en(e.getItem(An)):null)??ks(n)}var Dn="botmux.dashboard.theme",Ia="botmux.dashboard.sessions.view";function $s(e){return e==="system"||e==="light"||e==="dark"?e:null}function Rn(e){return e==="kanban"||e==="board"||e==="table"?e:null}function Ma(e,n){return e==="system"?n?"dark":"light":e}function Ea(e){return $s(e?.getItem(Dn))??"dark"}function xa(e){return Rn(e?.getItem(Ia))??"board"}var Ha="botmux.dashboard.sessions.boardOrder",Bt=["needs-you","starting","working","idle"];function Ss(e){if(!Array.isArray(e)||e.length!==Bt.length)return null;let n=new Set(e);if(n.size!==e.length)return null;for(let a of Bt)if(!n.has(a))return null;return e.slice()}function Ca(e){try{let n=e?.getItem(Ha);return n?Ss(JSON.parse(n))??[...Bt]:[...Bt]}catch{return[...Bt]}}function Pn(e,n){try{e?.setItem(Ha,JSON.stringify(n))}catch{}}function Aa(e,n){try{e?.setItem(Ia,n)}catch{}}var Da="botmux.dashboard.sessions.kanbanGroupBy",Bn="botmux.dashboard.sessions.kanbanTeam";function Ls(e){return e==="flow"||e==="team"||e==="bot"?e:null}function Ra(e){return Ls(e?.getItem(Da))??"flow"}function Pa(e,n){try{e?.setItem(Da,n)}catch{}}var Ba="botmux.dashboard.sidebar";function Ts(e){return e==="expanded"||e==="collapsed"?e:null}function Oa(e){return Ts(e?.getItem(Ba))??"expanded"}function Na(e,n){try{e?.setItem(Ba,n)}catch{}}var Is=["default","cyber","genshin","fallout","prts","bluearchive","zzz","dragonball","ikun"],On="botmux.dashboard.skin";function Ms(e){return typeof e=="string"&&Is.includes(e)?e:null}function qa(e){return Ms(e?.getItem(On))??"default"}var Es="\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF830123456789\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E$#%&@*+=<>/\\",ja=["186 100% 60%","56 97% 60%","330 100% 64%","150 80% 58%"],qn=[{key:"shake",dur:280},{key:"rgb",dur:340},{key:"tear",dur:400},{key:"invert",dur:220},{key:"slice",dur:320},{key:"blackout",dur:260}],Ua=["ESTABLISHING NETLINK","BYPASSING ICE","DECRYPTING DATAFLOW","SYNCING BOTMUX TELEMETRY","ACCESS GRANTED"],Fa="0123456789ABCDEF#<>*/=+\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C",xs=3200,Ot=[],It=0,nn=0;function Fn(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function jn(e,n){let a="";for(let s=0;s<e;s++)a+=n[Math.floor(Math.random()*n.length)];return a}function Hs(e){let n=document.createElement("div");n.className="cyber-rain";let a=Math.max(10,Math.min(26,Math.round(window.innerWidth/70)));for(let s=0;s<a;s++){let o=document.createElement("span");o.className="cyber-rain-col",o.textContent=jn(28+Math.floor(Math.random()*22),Es);let r=ja[Math.floor(Math.random()*ja.length)];o.style.cssText=`left:${(s+.5)/a*100}%;--rc:${r};--sz:${10+Math.floor(Math.random()*9)}px;--op:${(.25+Math.random()*.45).toFixed(2)};--dur:${(6+Math.random()*9).toFixed(1)}s;--delay:${(-Math.random()*12).toFixed(1)}s;`,n.appendChild(o)}e.appendChild(n)}function Cs(){if(Fn())return;let e=document.body,n=()=>{let a=qn[Math.floor(Math.random()*qn.length)],s=`cp-fx-${a.key}`;e.classList.add(s),Ot.push(window.setTimeout(()=>e.classList.remove(s),a.dur)),Ot.push(window.setTimeout(n,2400+Math.random()*4200))};Ot.push(window.setTimeout(n,1800+Math.random()*2600))}function As(){Ot.forEach(e=>window.clearTimeout(e)),Ot=[];for(let e of qn)document.body.classList.remove(`cp-fx-${e.key}`)}function Ds(){if(Fn()||document.getElementById("cyber-boot"))return;let e=document.createElement("div");e.id="cyber-boot",e.className="cyber-boot",e.setAttribute("aria-hidden","true"),e.innerHTML='<div class="cyber-boot-grid"></div><div class="cyber-loader"><div class="cyber-loader-frame"><div class="cyber-loader-head"><span>KIROSHI NETLINK</span><span class="cyber-loader-jp">\u4FB5\u5165\u4E2D</span></div><div class="cyber-loader-line"><span class="cyber-loader-prompt">&gt;</span><span class="cyber-loader-text"></span><span class="cyber-loader-cursor">_</span></div><div class="cyber-loader-stream"></div></div></div>',document.body.appendChild(e);let n=e.querySelector(".cyber-loader-text"),a=e.querySelector(".cyber-loader-stream"),s=0,o=0,r=0;It=window.setInterval(()=>{let d=Ua[s];n&&(o<d.length?(o+=1,n.textContent=d.slice(0,o)+jn(d.length-o,Fa),n.classList.remove("done")):r<16?(r+=1,n.textContent=d,n.classList.add("done")):(s=(s+1)%Ua.length,o=0,r=0)),a&&(a.textContent=jn(26,Fa))},50),nn=window.setTimeout(()=>{window.clearInterval(It),It=0,e.remove()},xs)}function Rs(){It&&(window.clearInterval(It),It=0),nn&&(window.clearTimeout(nn),nn=0),document.getElementById("cyber-boot")?.remove()}var Ps=320,Ga=16,Nt=!0,Tt=0,Nn=0,an=!1,on=[],Un=[];function Bs(){if(an)return;an=!0,Nt=!1,Tt=0;let e=Fn(),n="";for(let s=0;s<Ga;s++){let o=s%3===0?"186 100% 52%":s%3===1?"330 100% 58%":"56 97% 52%",r=(s%2===0?1:-1)*(8+s%5*7);n+=`<span class="cyber-breach-shard" style="top:${s/Ga*100}%;height:${2+s%4*3}%;--shift:${r}px;--delay:${s%8*.09}s;--dur:${(.36+s%5*.12).toFixed(2)}s;--hue:${o}"></span>`}let a=document.createElement("div");a.id="cyber-breach",a.className="cyber-breach",a.setAttribute("aria-hidden","true"),a.innerHTML=`<span class="cyber-breach-flash"></span><span class="cyber-breach-grid"></span><div class="cyber-breach-shards">${n}</div><div class="cyber-breach-banner"><span class="cyber-breach-tag">// BREACH PROTOCOL \u2014 SYSTEM OVERRIDE</span><span class="cyber-breach-caption" data-text="SYSTEM BREACH">SYSTEM BREACH</span><span class="cyber-breach-sub" data-text="NETWATCH OVERRIDE ENGAGED">NETWATCH OVERRIDE ENGAGED</span></div>`,document.body.appendChild(a),e||document.body.classList.add("cyber-breach-quake"),on.push(window.setTimeout(()=>document.body.classList.remove("cyber-breach-quake"),760)),on.push(window.setTimeout(()=>{a.remove(),an=!1},e?2600:4200))}function Os(){Nt=!0,Tt=0;let e=document.documentElement,n=()=>e.scrollHeight-(window.innerHeight+window.scrollY)<=4,a=k=>{k<=0||!n()||(Tt+=k,Tt>Ps&&Nt&&Bs())},s=k=>a(k.deltaY),o=k=>{Nn=k.touches[0]?.clientY??0},r=k=>{let $=k.touches[0]?.clientY??0,E=Nn-$;Nn=$,a(E)},d=()=>{n()||(Tt=0,Nt=!0)},p=(k,$)=>{window.addEventListener(k,$,{passive:!0}),Un.push([k,$])};p("wheel",s),p("touchstart",o),p("touchmove",r),p("scroll",d)}function Ns(){for(let[e,n]of Un)window.removeEventListener(e,n);Un=[],on.forEach(e=>window.clearTimeout(e)),on=[],document.body.classList.remove("cyber-breach-quake"),document.getElementById("cyber-breach")?.remove(),an=!1,Nt=!0,Tt=0}function _a(e,n=!1){if(!(typeof document>"u")){if(!e){document.getElementById("cyber-fx")?.remove(),document.getElementById("cyber-hud")?.remove(),document.getElementById("cyber-glitch")?.remove(),As(),Rs(),Ns();return}if(!document.getElementById("cyber-fx")){let a=document.createElement("div");a.id="cyber-fx",a.className="cyber-fx",a.setAttribute("aria-hidden","true"),a.innerHTML='<div class="cyber-fx-grid"></div><div class="cyber-fx-scan"></div><span class="cyber-flicker"></span><span class="cyber-rollline"></span>',Hs(a),document.body.appendChild(a);let s=document.createElement("div");s.id="cyber-hud",s.className="cyber-hud",s.setAttribute("aria-hidden","true"),s.innerHTML='<span class="cyber-hud-corner tl"></span><span class="cyber-hud-corner tr"></span><span class="cyber-hud-corner bl"></span><span class="cyber-hud-corner br"></span><span class="cyber-hud-tag">NIGHT CITY // NETWATCH</span>',document.body.appendChild(s);let o=document.createElement("div");o.id="cyber-glitch",o.className="cyber-glitch",o.setAttribute("aria-hidden","true"),document.body.appendChild(o),Cs(),Os()}n&&Ds()}}var qs={genshin:2e3,zzz:1900,dragonball:1900,ikun:1900},js='<span class="si-bball" aria-hidden="true"><span class="si-bball-seams"><svg viewBox="0 0 100 100"><g fill="none" stroke="#3a1d08" stroke-width="3.4" stroke-linecap="round"><path d="M50 4V96"/><path d="M4 50H96"/><path d="M50 4 Q14 50 50 96"/><path d="M50 4 Q86 50 50 96"/></g></svg></span></span>';function Us(e){switch(e){case"genshin":return'<span class="si-gi-shine" aria-hidden="true"></span><span class="si-gi-text">\u539F\u795E\uFF0C\u542F\u52A8</span>';case"zzz":return'<span class="si-static" aria-hidden="true"></span><span class="si-roll" aria-hidden="true"></span><span class="si-now">NOW&nbsp;LOADING</span>';case"dragonball":return'<span class="si-speed" aria-hidden="true"></span><img class="si-cloud" src="/assets/skins/dragonball-wukong.webp" alt="">';case"ikun":return js;default:return""}}function Fs(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Wa(e){if(typeof document>"u"||Fs())return;let n=qs[e];if(!n)return;document.getElementById("skin-intro")?.remove();let a=document.createElement("div");a.id="skin-intro",a.className=`skin-intro si-${e}`,a.setAttribute("aria-hidden","true"),a.style.setProperty("--si-dur",`${n}ms`),a.innerHTML=Us(e),document.body.appendChild(a),window.setTimeout(()=>a.remove(),n+80)}var _n=class{locale="zh";themeMode="system";resolvedTheme="light";skin="default";authed=!0;listeners=new Set;translate=tn(this.locale);mediaQuery=null;init(){let n=typeof window<"u"?window:void 0;this.locale=Ta(n?.localStorage,_s()),this.translate=tn(this.locale),this.themeMode=Ea(n?.localStorage),this.skin=qa(n?.localStorage),this.mediaQuery=n?.matchMedia?.("(prefers-color-scheme: dark)")??null,this.mediaQuery?.addEventListener("change",()=>{this.applyTheme(),this.emit()}),this.applyTheme(),this.applySkin(),this.applyLocale()}t(n,a){return this.translate(n,a)}setLocale(n){this.locale!==n&&(this.locale=n,this.translate=tn(n),window.localStorage.setItem(An,n),this.applyLocale(),this.emit())}get theme(){return this.skin==="default"?this.themeMode:this.skin}setTheme(n){let a=n==="system"||n==="light"||n==="dark",s=a?"default":n,o=s!==this.skin;a&&this.themeMode!==n&&(this.themeMode=n,window.localStorage.setItem(Dn,this.themeMode)),o&&(this.skin=s,window.localStorage.setItem(On,this.skin)),this.applyTheme(),this.applySkin(o),this.emit()}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}applyTheme(){this.resolvedTheme=Ma(this.themeMode,!!this.mediaQuery?.matches);let n=this.skin==="default"?this.resolvedTheme:Gs[this.skin];document.documentElement.dataset.theme=n,document.documentElement.dataset.themeMode=this.themeMode}applySkin(n=!1){document.documentElement.dataset.skin=this.skin,_a(this.skin==="cyber",n),n&&this.skin!=="cyber"&&this.skin!=="default"&&Wa(this.skin)}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}},Gs={default:"light",cyber:"dark",genshin:"light",fallout:"dark",prts:"dark",bluearchive:"dark",zzz:"dark",dragonball:"light",ikun:"dark"};function _s(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var Te=new _n;function t(e,n){return Te.t(e,n)}function i(e){return e.replace(/[&<>"']/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[n])}function je(e){if(!e)return"-";let n=Date.now()-e;return n<6e4?t("common.now"):n<36e5?Math.floor(n/6e4)+"m":n<864e5?Math.floor(n/36e5)+"h":Math.floor(n/864e5)+"d"}var za=[{c1:"#5be3ff",c2:"#4f8bff"},{c1:"#b89bff",c2:"#6b4df0"},{c1:"#7ce0c3",c2:"#2e9e8f"},{c1:"#8fb4ff",c2:"#3b62d8"},{c1:"#ffd28f",c2:"#d8783b"},{c1:"#7df0a8",c2:"#1f9e63"},{c1:"#9fd0ff",c2:"#4878c8"},{c1:"#ff9fb8",c2:"#d84a78"}];function Ka(e){let n=0,a=String(e??"");for(let r=0;r<a.length;r++)n=n*31+a.charCodeAt(r)>>>0;let{c1:s,c2:o}=za[n%za.length];return`--c1:${s};--c2:${o}`}var sn=new Map,rn=new Map;function Ws(e,n){return n?sn.get(n):e?rn.get(String(e)):void 0}function me(e){let n=e.name??"",a=e.avatarUrl??Ws(e.name,e.larkAppId),s=e.size==="sm"?" orb-avatar-sm":"",o=a?" orb-has-img":"",r=e.dot?`<i class="orb-dot orb-dot-${e.dot}"></i>`:"",d=a?`<img class="orb-img" src="${i(a)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar${s}${o}" style="${Ka(n)}" aria-hidden="true">${d}${r}</span>`}function zs(e){return e?cn.get(e):void 0}function ln(e){let n=e.name??e.chatId??"",a=e.avatarUrl??zs(e.chatId),s=e.size==="sm"?" orb-avatar-sm":"",o=a?" orb-has-img":"",r=a?`<img class="orb-img" src="${i(a)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar orb-square${s}${o}" style="${Ka(n)}" aria-hidden="true">${r}</span>`}var qt=new Map,dn=new Map,cn=new Map,Gn=null,Ja="botmux.avatarCache.v1";function Ks(){try{let e=typeof window<"u"?window.localStorage.getItem(Ja):null;if(!e)return;let n=JSON.parse(e);for(let[a,s]of Object.entries(n.botByAppId??{}))sn.set(a,s);for(let[a,s]of Object.entries(n.botByName??{}))rn.set(a,s);for(let[a,s]of Object.entries(n.chatById??{}))cn.set(a,s);for(let[a,s]of Object.entries(n.nameByAppId??{}))qt.set(a,s);for(let[a,s]of Object.entries(n.chatNameById??{}))dn.set(a,s)}catch{}}function Js(){try{if(typeof window>"u")return;window.localStorage.setItem(Ja,JSON.stringify({botByAppId:Object.fromEntries(sn),botByName:Object.fromEntries(rn),chatById:Object.fromEntries(cn),nameByAppId:Object.fromEntries(qt),chatNameById:Object.fromEntries(dn)}))}catch{}}Ks();function Je(){return Gn??=(async()=>{try{let e=await fetch("/api/groups");if(!e.ok)throw new Error(`HTTP ${e.status}`);let n=await e.json();for(let a of n.bots??[])a.larkAppId&&a.botName&&a.botName!==a.larkAppId&&qt.set(a.larkAppId,String(a.botName)),a.botAvatarUrl&&(a.larkAppId&&sn.set(a.larkAppId,String(a.botAvatarUrl)),a.botName&&rn.set(String(a.botName),String(a.botAvatarUrl)));for(let a of n.chats??[])a.chatId&&a.name&&dn.set(a.chatId,String(a.name)),a.chatId&&a.avatar&&cn.set(a.chatId,String(a.avatar));Js()}catch{Gn=null}})(),Gn}function Va(e){return e?qt.get(e):void 0}function ve(e){let n=e.larkAppId?qt.get(e.larkAppId):void 0;return n||(e.botName&&e.botName!==e.larkAppId?String(e.botName):String(e.botName??e.larkAppId??"-"))}function rt(e){return e.chatId&&dn.get(e.chatId)||null}function ke(e){let n=String(e??"");return n.replace(/^(?:@\S+\s*)+/,"").trim()||n}function lt(e){return`<div class="page-loading" role="status"><i class="page-loading-spin" aria-hidden="true"></i>${i(e??t("common.loading"))}</div>`}function dt(e){return e.status==="closed"?null:e.agentAttention?.reason?e.agentAttention.reason:e.agentAttention?t("sessions.board.signalAgent"):e.pendingRepo?t("sessions.board.signalRepo"):e.tuiPromptActive?t("sessions.board.signalPrompt"):e.status==="limited"?t("sessions.board.signalLimited"):null}function He(e){let n=Number(e.agentAttention?.at??e.lastMessageAt??0);if(Number.isFinite(n))return n;let a=Number(e.lastMessageAt??0);return Number.isFinite(a)?a:0}var Xa={chats:[],bots:[]};async function Vs(){try{let e=await fetch("/api/groups");if(!e.ok)return;Xa=await e.json()}catch{}}var Wn=new Set(["working","analyzing","active","starting"]);function Ys(e){let n=new Map,a=o=>{let r=n.get(o);return r||(r={botName:o,larkAppId:o,cliId:"unknown",online:!1,sessions:[],active:[],busy:[],attention:[],lastActiveAt:0},n.set(o,r)),r};for(let o of Xa.bots??[]){let r=a(o.larkAppId??o.botName??"-");r.online=!0,o.botName&&(r.botName=o.botName),o.botAvatarUrl&&(r.botAvatarUrl=o.botAvatarUrl)}let s=[...e].sort((o,r)=>+(o.status==="closed")-+(r.status==="closed"));for(let o of s){let r=o.larkAppId??o.botName??"-";if(o.status==="closed"&&!n.has(r))continue;let d=a(r);o.botName&&(d.botName===d.larkAppId||!d.botName)&&(d.botName=o.botName),d.sessions.push(o),o.cliId&&d.cliId==="unknown"&&(d.cliId=o.cliId),d.lastActiveAt=Math.max(d.lastActiveAt,Number(o.lastMessageAt??0)),o.status!=="closed"&&(d.active.push(o),Wn.has(o.status)&&d.busy.push(o),dt(o)&&d.attention.push(o))}for(let o of n.values())if(o.botName===o.larkAppId){let r=Va(o.larkAppId);r&&(o.botName=r)}return[...n.values()].sort((o,r)=>{let d=p=>p.attention.length?0:p.busy.length?1:p.online||p.active.length?2:3;return d(o)!==d(r)?d(o)-d(r):r.lastActiveAt-o.lastActiveAt})}var Za="botmux.overview.teamExpanded",Qs=230,Ya=13,Qa=2;function Xs(e){let n=e.clientWidth;return n?Math.max(1,Math.floor((n+Ya)/(Qs+Ya)))*Qa:Qa*3}function Zs(){try{return window.localStorage.getItem(Za)==="1"}catch{return!1}}function ei(e){try{window.localStorage.setItem(Za,e?"1":"0")}catch{}}function ti(e){let n=!e.online&&e.active.length===0,a=e.attention.length>0,s=e.busy.length>0,o=a?"warn":s?"busy":n?"off":"ok",r;if(a){let p=[...e.attention].sort((k,$)=>He(k)-He($))[0];r=`<b>${i((ke(p.title)||p.sessionId).slice(0,60))}</b> \xB7 ${i(dt(p)??"")}`}else if(s){let p=[...e.busy].sort((k,$)=>Number($.lastMessageAt??0)-Number(k.lastMessageAt??0))[0];r=`<b>${i((ke(p.title)||p.sessionId).slice(0,60))}</b>`}else n?r=i(t("overview.botOffline")):r=i(t("overview.botIdle"));let d=a?`<span class="tag tag-warn">${i(t("overview.botNeedsYou"))}</span>`:s?`<span class="tag tag-run">${i(t("overview.botBusy",{count:e.busy.length}))}</span>`:n?`<span class="tag tag-off">${i(t("overview.botOff"))}</span>`:`<span class="tag tag-ok">${i(t("overview.botReady"))}</span>`;return`<article class="mate${a?" mate-attn":""}${n?" mate-off":""}">
14
20
  <div class="mate-top">
15
- ${fe({name:e.botName,larkAppId:e.larkAppId,avatarUrl:e.botAvatarUrl,dot:a})}
21
+ ${me({name:e.botName,larkAppId:e.larkAppId,avatarUrl:e.botAvatarUrl,dot:o})}
16
22
  <div class="mate-id">
17
- <b>${r(e.botName)}</b>
18
- <span class="mate-role">${r(e.cliId)}</span>
23
+ <b>${i(e.botName)}</b>
24
+ <span class="mate-role">${i(e.cliId)}</span>
19
25
  </div>
20
26
  </div>
21
- <div class="mate-task">${i}</div>
27
+ <div class="mate-task">${r}</div>
22
28
  <div class="mate-foot">
23
29
  ${d}
24
- <span>${e.lastActiveAt?r(t("overview.lastActive",{time:qe(e.lastActiveAt)})):r(t("common.never"))}</span>
30
+ <span>${e.lastActiveAt?i(t("overview.lastActive",{time:je(e.lastActiveAt)})):i(t("common.never"))}</span>
25
31
  </div>
26
- </article>`}function Ks(e){let n=ye(e);return`<article class="qcard" data-id="${r(e.sessionId)}">
27
- ${fe({name:n,larkAppId:e.larkAppId,size:"sm"})}
32
+ </article>`}function ni(e){let n=ve(e);return`<article class="qcard" data-id="${i(e.sessionId)}">
33
+ ${me({name:n,larkAppId:e.larkAppId,size:"sm"})}
28
34
  <div class="qcard-tx">
29
- <b>${r(n)} \xB7 ${r((ve(e.title)||e.sessionId).slice(0,56))}</b>
30
- <span>${r(it(e)??"")} \xB7 ${qe(xe(e))}</span>
35
+ <b>${i(n)} \xB7 ${i((ke(e.title)||e.sessionId).slice(0,56))}</b>
36
+ <span>${i(dt(e)??"")} \xB7 ${je(He(e))}</span>
31
37
  </div>
32
- <a class="qcard-go" href="#/sessions">${r(t("strip.handle"))}</a>
33
- </article>`}function Js(e){let n=ye(e);return`<li class="sess-row">
34
- ${fe({name:n,larkAppId:e.larkAppId,size:"sm"})}
38
+ <a class="qcard-go" href="#/sessions">${i(t("strip.handle"))}</a>
39
+ </article>`}function ai(e){let n=ve(e);return`<li class="sess-row">
40
+ ${me({name:n,larkAppId:e.larkAppId,size:"sm"})}
35
41
  <div class="sess-tx">
36
- <b>${r((ve(e.title)||e.sessionId).slice(0,64))}</b>
37
- <span>${r(n)} \xB7 ${r(st(e)??e.cliId??"unknown")} \xB7 ${qe(e.lastMessageAt)}</span>
42
+ <b>${i((ke(e.title)||e.sessionId).slice(0,64))}</b>
43
+ <span>${i(n)} \xB7 ${i(rt(e)??e.cliId??"unknown")} \xB7 ${je(e.lastMessageAt)}</span>
38
44
  </div>
39
- <span class="status status-${r(e.status??"unknown")}">${r(e.status??"unknown")}</span>
40
- </li>`}function Ys(e){let n=e.nextRunAt?new Date(e.nextRunAt).toLocaleString():"-";return`<li class="overview-list-row">
45
+ <span class="status status-${i(e.status??"unknown")}">${i(e.status??"unknown")}</span>
46
+ </li>`}function oi(e){let n=e.nextRunAt?new Date(e.nextRunAt).toLocaleString():"-";return`<li class="overview-list-row">
41
47
  <div>
42
- <strong>${r(e.name??e.id)}</strong>
43
- <span>${r(ye(e))} \xB7 ${r(e.parsed?.display??"")}</span>
48
+ <strong>${i(e.name??e.id)}</strong>
49
+ <span>${i(ve(e))} \xB7 ${i(e.parsed?.display??"")}</span>
44
50
  </div>
45
- <span>${r(n)}</span>
46
- </li>`}function Vs(e,n,o){let s=e+n+o;if(s===0)return`<div class="donut-wrap"><div class="donut" style="background:conic-gradient(var(--border) 0 360deg)"></div>
47
- <div class="donut-center"><b>0</b><span>${r(t("overview.openSessions"))}</span></div></div>`;let a=e/s*360,i=a+n/s*360;return`<div class="donut-wrap">
48
- <div class="donut" style="background:conic-gradient(var(--accent) 0 ${a}deg, var(--warning) ${a}deg ${i}deg, var(--success) ${i}deg 360deg)"></div>
49
- <div class="donut-center"><b>${s}</b><span>${r(t("overview.openSessions"))}</span></div>
50
- </div>`}async function Yo(e){e.innerHTML=`<section class="page hero-page">
51
+ <span>${i(n)}</span>
52
+ </li>`}function si(e,n,a){let s=e+n+a;if(s===0)return`<div class="donut-wrap"><div class="donut" style="background:conic-gradient(var(--border) 0 360deg)"></div>
53
+ <div class="donut-center"><b>0</b><span>${i(t("overview.openSessions"))}</span></div></div>`;let o=e/s*360,r=o+n/s*360;return`<div class="donut-wrap">
54
+ <div class="donut" style="background:conic-gradient(var(--accent) 0 ${o}deg, var(--warning) ${o}deg ${r}deg, var(--success) ${r}deg 360deg)"></div>
55
+ <div class="donut-center"><b>${s}</b><span>${i(t("overview.openSessions"))}</span></div>
56
+ </div>`}async function eo(e){e.innerHTML=`<section class="page hero-page">
51
57
  <div class="page-heading">
52
58
  <div>
53
59
  <p class="eyebrow">${t("app.subtitle")}</p>
@@ -102,25 +108,25 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
102
108
  </section>
103
109
  </div>
104
110
  </div>
105
- </section>`;let n=e.querySelector("#overview-pills"),o=e.querySelector("#team-grid"),s=e.querySelector("#team-toggle"),a=_s();s.onclick=()=>{a=!a,zs(a),k()};let i=e.querySelector("#attention-list"),d=e.querySelector("#recent-sessions"),p=e.querySelector("#today-donut"),v=e.querySelector("#next-schedules");function k(){let T=[...Q.sessions.values()],g=T.filter(S=>S.status!=="closed"),R=g.filter(S=>it(S)).sort((S,H)=>xe(S)-xe(H)),A=g.filter(S=>qn.has(S.status)&&!it(S)),O=g.length-R.length-A.length,M=js(T),E=M.filter(S=>S.online||S.active.length>0).length;n.innerHTML=`
106
- <span class="pill">${r(t("overview.workingSessions"))} <b>${A.length}</b></span>
107
- <span class="pill${R.length?" pill-hot":""}">${r(t("overview.attention"))} <b>${R.length}</b></span>
108
- <span class="pill">${r(t("overview.onlineBots"))} <b>${E}</b></span>`;let $=Gs(o),D=a?M:M.slice(0,$);o.innerHTML=D.length?D.map(Ws).join(""):`<div class="empty">${t("overview.noSessions")}</div>`,M.length>$?(s.hidden=!1,s.textContent=a?t("overview.teamCollapse"):t("overview.teamExpand",{count:M.length})):s.hidden=!0,i.innerHTML=R.length?R.map(Ks).join(""):`<div class="qcard qcard-empty">${t("overview.noAttention")}</div>`;let m=g.filter(S=>qn.has(S.status)||S.status==="idle").sort((S,H)=>Number(H.lastMessageAt??0)-Number(S.lastMessageAt??0)).slice(0,7);d.innerHTML=m.length?m.map(Js).join(""):`<li class="empty">${t("overview.noSessions")}</li>`,p.innerHTML=`${Vs(A.length,R.length,Math.max(0,O))}
111
+ </section>`;let n=e.querySelector("#overview-pills"),a=e.querySelector("#team-grid"),s=e.querySelector("#team-toggle"),o=Zs();s.onclick=()=>{o=!o,ei(o),$()};let r=e.querySelector("#attention-list"),d=e.querySelector("#recent-sessions"),p=e.querySelector("#today-donut"),k=e.querySelector("#next-schedules");function $(){let w=[...Q.sessions.values()],u=w.filter(I=>I.status!=="closed"),S=u.filter(I=>dt(I)).sort((I,D)=>He(I)-He(D)),x=u.filter(I=>Wn.has(I.status)&&!dt(I)),A=u.length-S.length-x.length,L=Ys(w),H=L.filter(I=>I.online||I.active.length>0).length;n.innerHTML=`
112
+ <span class="pill">${i(t("overview.workingSessions"))} <b>${x.length}</b></span>
113
+ <span class="pill${S.length?" pill-hot":""}">${i(t("overview.attention"))} <b>${S.length}</b></span>
114
+ <span class="pill">${i(t("overview.onlineBots"))} <b>${H}</b></span>`;let T=Xs(a),P=o?L:L.slice(0,T);a.innerHTML=P.length?P.map(ti).join(""):`<div class="empty">${t("overview.noSessions")}</div>`,L.length>T?(s.hidden=!1,s.textContent=o?t("overview.teamCollapse"):t("overview.teamExpand",{count:L.length})):s.hidden=!0,r.innerHTML=S.length?S.map(ni).join(""):`<div class="qcard qcard-empty">${t("overview.noAttention")}</div>`;let f=u.filter(I=>Wn.has(I.status)||I.status==="idle").sort((I,D)=>Number(D.lastMessageAt??0)-Number(I.lastMessageAt??0)).slice(0,7);d.innerHTML=f.length?f.map(ai).join(""):`<li class="empty">${t("overview.noSessions")}</li>`,p.innerHTML=`${si(x.length,S.length,Math.max(0,A))}
109
115
  <div class="donut-legend">
110
- <span><i style="background:var(--accent)"></i>${r(t("overview.workingSessions"))} ${A.length}</span>
111
- <span><i style="background:var(--warning)"></i>${r(t("overview.attention"))} ${R.length}</span>
112
- <span><i style="background:var(--success)"></i>${r(t("sessions.board.idle"))} ${Math.max(0,O)}</span>
113
- </div>`;let y=[...Q.schedules.values()].filter(S=>S.nextRunAt).sort((S,H)=>Date.parse(S.nextRunAt)-Date.parse(H.nextRunAt)).slice(0,5);v.innerHTML=y.length?y.map(Ys).join(""):`<li class="empty">${t("overview.noSchedules")}</li>`}let I=()=>{if(!document.body.contains(o)){window.removeEventListener("resize",I);return}a||k()};window.addEventListener("resize",I),Q.on(k),k(),Us().then(k),Ke().then(k)}var Vo=["backlog","todo","in_progress","in_review","done"];function Qo(e){return typeof e=="string"&&Vo.includes(e)?e:null}function Xo(e){if(e.status==="closed")return"done";let n=Qo(e.kanbanColumn);return n||(e.pendingRepo||e.tuiPromptActive||e.agentAttention||e.status==="limited"?"in_review":e.status==="starting"||e.status==="working"||e.status==="analyzing"||e.status==="active"?"in_progress":"todo")}var Qs=1e15;function pt(e){if(typeof e.kanbanPosition=="number"&&Number.isFinite(e.kanbanPosition))return e.kanbanPosition;let n=typeof e.lastMessageAt=="number"&&Number.isFinite(e.lastMessageAt)?e.lastMessageAt:0;return Qs-n}function Un(e,n){return e!==null&&n!==null?(e+n)/2:e!==null?e+1024:n!==null?n-1024:1024}function Je(e,n){return`<th data-sort="${e}" data-label="${r(n)}">${r(n)}</th>`}function _n(e){return typeof e=="number"&&Number.isFinite(e)?e:null}function Zo(e){let n=_n(e);return n===null?"-":n.toLocaleString("en-US")}var ia=["claude-code","seed","relay","codex","codex-app","cursor","gemini","opencode","mtr","hermes","mira","pi","copilot","aiden","coco","oh-my-pi","unknown"],ea=[{id:"needs-you",labelKey:"sessions.board.needsYou",hintKey:"sessions.board.needsYouHint"},{id:"starting",labelKey:"sessions.board.starting",hintKey:"sessions.board.startingHint"},{id:"working",labelKey:"sessions.board.working",hintKey:"sessions.board.workingHint"},{id:"idle",labelKey:"sessions.board.idle",hintKey:"sessions.board.idleHint"}],ta=[{id:"backlog",labelKey:"sessions.kanban.backlog"},{id:"todo",labelKey:"sessions.kanban.todo"},{id:"in_progress",labelKey:"sessions.kanban.inProgress"},{id:"in_review",labelKey:"sessions.kanban.inReview"},{id:"done",labelKey:"sessions.kanban.done"}],jn=50;function Xs(e){let n=(o="")=>`<svg viewBox="0 0 14 14" aria-hidden="true"><circle cx="7" cy="7" r="5.4" fill="none" stroke="currentColor" stroke-width="1.6"${o}/>`;switch(e){case"backlog":return`${n(' stroke-dasharray="1.6 2.1"')}</svg>`;case"in_progress":return`${n()}<path d="M7,7 L7,3.6 A3.4,3.4 0 0 1 7,10.4 Z" fill="currentColor"/></svg>`;case"in_review":return`${n()}<path d="M7,7 L7,3.6 A3.4,3.4 0 1 1 3.6,7 Z" fill="currentColor"/></svg>`;case"done":return'<svg viewBox="0 0 14 14" aria-hidden="true"><circle cx="7" cy="7" r="6.2" fill="currentColor"/><path d="M4.4 7.2 6.2 9 9.7 5.4" fill="none" stroke="var(--surface)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>';default:return`${n()}</svg>`}}function na(e){return String(e??"unknown").toLowerCase().replace(/[^a-z0-9_-]/g,"-")}function oa(e){let n=String(e??"").trim();return n?n.replace(/\\/g,"/").split("/").filter(Boolean).at(-1)??n:"-"}function Fn(e){if(!e.webPort)return null;let n=e.proxyPort??e.webPort,o=e.proxyPort?`/s/${encodeURIComponent(e.sessionId)}`:"";return`http://${location.hostname}:${n}${o}`}var Ee={pin:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M8 14.3s4.2-3.9 4.2-7.3A4.2 4.2 0 0 0 8 2.9a4.2 4.2 0 0 0-4.2 4.1C3.8 10.4 8 14.3 8 14.3z"/><circle cx="8" cy="6.9" r="1.5"/></svg>',openChat:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M9.4 2.8h3.8v3.8"/><path d="M13.2 2.8 7.3 8.7"/><path d="M11.5 9.3v2.9a1.2 1.2 0 0 1-1.2 1.2H3.8a1.2 1.2 0 0 1-1.2-1.2V5.7a1.2 1.2 0 0 1 1.2-1.2h2.9"/></svg>',details:'<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="2.2" y="2.9" width="11.6" height="10.2" rx="1.8"/><path d="M9.9 2.9v10.2"/></svg>',terminal:'<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="1.7" y="2.7" width="12.6" height="10.6" rx="2"/><path d="M4.4 6.3 6.4 8.1 4.4 9.9"/><path d="M8.2 10.2h3.4"/></svg>',key:'<svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="6" cy="6.1" r="3"/><path d="M8.1 8.2 13 13.1"/><path d="M11.3 11.4 12.6 10.1"/><path d="M12.7 12.8 13.7 11.8"/></svg>',close:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M4.2 4.2 11.8 11.8"/><path d="M11.8 4.2 4.2 11.8"/></svg>',edit:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M10.7 3.3 12.7 5.3 6.3 11.7 3.7 12.3 4.3 9.7 10.7 3.3z"/></svg>',history:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M2.2 4.8a2 2 0 0 1 2-2h7.6a2 2 0 0 1 2 2v4.6a2 2 0 0 1-2 2H6.6l-2.9 2.4v-2.4h-.5a2 2 0 0 1-2-2z"/><path d="M5.2 6.2h5.6M5.2 8.4h3.6"/></svg>',feishu:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M2.6 4.4C6.4 4 10.4 5.4 13.4 8.2 9.8 7 6.4 6.6 3.4 7.4"/><path d="M13.4 8.2C9.6 8.7 6 10 2.9 12 5.6 9 8.8 7.6 13.4 8.2"/></svg>'};function Gn(e,n,o,s=""){return`<button type="button" class="card-act${s?" "+s:""}" data-action="${e}" title="${r(o)}" aria-label="${r(o)}">${n}</button>`}function aa(e){if(!e)return"";let n=`<a class="term-btn term-open" href="${r(e)}" target="_blank" rel="noopener" title="${r(t("sessions.openTerminal"))}" aria-label="${r(t("sessions.openTerminal"))}">${Ee.terminal}</a>`;if(!Te.authed)return`<span class="term-pill solo">${n}</span>`;let o=`<button type="button" class="term-btn term-write" data-action="write-link" title="${r(t("sessions.writeLinkHint"))}" aria-label="${r(t("sessions.writeLink"))}">${Ee.key}</button>`;return`<span class="term-pill">${n}${o}</span>`}async function sa(e,n){let o=window.open("about:blank","_blank");o&&(o.opener=null),n&&(n.disabled=!0);try{let s=await fetch(`/api/sessions/${encodeURIComponent(e.sessionId)}/write-link`),a=await s.json().catch(()=>({}));if(!s.ok||a?.ok===!1||!a?.url){o?.close(),s.status!==401&&alert(`${t("sessions.writeLinkFail")}: ${a?.error??s.status}`);return}o?o.location.href=a.url:window.open(a.url,"_blank","noopener")}catch(s){o?.close(),alert(`${t("sessions.writeLinkFail")}: ${s}`)}finally{n&&(n.disabled=!1)}}function Zs(e){return e.status==="closed"?null:e.pendingRepo||e.tuiPromptActive||e.agentAttention||e.status==="limited"?"needs-you":e.status==="starting"?"starting":e.status==="working"||e.status==="analyzing"||e.status==="active"?"working":"idle"}function ei(){return`<details class="filter-cli">
116
+ <span><i style="background:var(--accent)"></i>${i(t("overview.workingSessions"))} ${x.length}</span>
117
+ <span><i style="background:var(--warning)"></i>${i(t("overview.attention"))} ${S.length}</span>
118
+ <span><i style="background:var(--success)"></i>${i(t("sessions.board.idle"))} ${Math.max(0,A)}</span>
119
+ </div>`;let v=[...Q.schedules.values()].filter(I=>I.nextRunAt).sort((I,D)=>Date.parse(I.nextRunAt)-Date.parse(D.nextRunAt)).slice(0,5);k.innerHTML=v.length?v.map(oi).join(""):`<li class="empty">${t("overview.noSchedules")}</li>`}let E=()=>{if(!document.body.contains(a)){window.removeEventListener("resize",E);return}o||$()};window.addEventListener("resize",E),Q.on($),$(),Vs().then($),Je().then($)}var to=["backlog","todo","in_progress","in_review","done"];function no(e){return typeof e=="string"&&to.includes(e)?e:null}function ao(e){if(e.status==="closed")return"done";let n=no(e.kanbanColumn);return n||(e.pendingRepo||e.tuiPromptActive||e.agentAttention||e.status==="limited"?"in_review":e.status==="starting"||e.status==="working"||e.status==="analyzing"||e.status==="active"?"in_progress":"todo")}var ii=1e15;function gt(e){if(typeof e.kanbanPosition=="number"&&Number.isFinite(e.kanbanPosition))return e.kanbanPosition;let n=typeof e.lastMessageAt=="number"&&Number.isFinite(e.lastMessageAt)?e.lastMessageAt:0;return ii-n}function zn(e,n){return e!==null&&n!==null?(e+n)/2:e!==null?e+1024:n!==null?n-1024:1024}function Ve(e,n){return`<th data-sort="${e}" data-label="${i(n)}">${i(n)}</th>`}function Yn(e){return typeof e=="number"&&Number.isFinite(e)?e:null}function oo(e){let n=Yn(e);return n===null?"-":n.toLocaleString("en-US")}var po=["claude-code","seed","relay","codex","codex-app","cursor","gemini","opencode","mtr","hermes","mira","pi","copilot","aiden","coco","oh-my-pi","unknown"],so=[{id:"needs-you",labelKey:"sessions.board.needsYou",hintKey:"sessions.board.needsYouHint"},{id:"starting",labelKey:"sessions.board.starting",hintKey:"sessions.board.startingHint"},{id:"working",labelKey:"sessions.board.working",hintKey:"sessions.board.workingHint"},{id:"idle",labelKey:"sessions.board.idle",hintKey:"sessions.board.idleHint"}],io=[{id:"backlog",labelKey:"sessions.kanban.backlog"},{id:"todo",labelKey:"sessions.kanban.todo"},{id:"in_progress",labelKey:"sessions.kanban.inProgress"},{id:"in_review",labelKey:"sessions.kanban.inReview"},{id:"done",labelKey:"sessions.kanban.done"}],Kn=50;function ri(e){let n=(a="")=>`<svg viewBox="0 0 14 14" aria-hidden="true"><circle cx="7" cy="7" r="5.4" fill="none" stroke="currentColor" stroke-width="1.6"${a}/>`;switch(e){case"backlog":return`${n(' stroke-dasharray="1.6 2.1"')}</svg>`;case"in_progress":return`${n()}<path d="M7,7 L7,3.6 A3.4,3.4 0 0 1 7,10.4 Z" fill="currentColor"/></svg>`;case"in_review":return`${n()}<path d="M7,7 L7,3.6 A3.4,3.4 0 1 1 3.6,7 Z" fill="currentColor"/></svg>`;case"done":return'<svg viewBox="0 0 14 14" aria-hidden="true"><circle cx="7" cy="7" r="6.2" fill="currentColor"/><path d="M4.4 7.2 6.2 9 9.7 5.4" fill="none" stroke="var(--surface)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>';default:return`${n()}</svg>`}}function ro(e){return String(e??"unknown").toLowerCase().replace(/[^a-z0-9_-]/g,"-")}function lo(e){let n=String(e??"").trim();return n?n.replace(/\\/g,"/").split("/").filter(Boolean).at(-1)??n:"-"}function Jn(e){if(!e.webPort)return null;let n=e.proxyPort??e.webPort,a=e.proxyPort?`/s/${encodeURIComponent(e.sessionId)}`:"";return`http://${location.hostname}:${n}${a}`}var Ce={pin:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M8 14.3s4.2-3.9 4.2-7.3A4.2 4.2 0 0 0 8 2.9a4.2 4.2 0 0 0-4.2 4.1C3.8 10.4 8 14.3 8 14.3z"/><circle cx="8" cy="6.9" r="1.5"/></svg>',openChat:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M9.4 2.8h3.8v3.8"/><path d="M13.2 2.8 7.3 8.7"/><path d="M11.5 9.3v2.9a1.2 1.2 0 0 1-1.2 1.2H3.8a1.2 1.2 0 0 1-1.2-1.2V5.7a1.2 1.2 0 0 1 1.2-1.2h2.9"/></svg>',details:'<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="2.2" y="2.9" width="11.6" height="10.2" rx="1.8"/><path d="M9.9 2.9v10.2"/></svg>',terminal:'<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="1.7" y="2.7" width="12.6" height="10.6" rx="2"/><path d="M4.4 6.3 6.4 8.1 4.4 9.9"/><path d="M8.2 10.2h3.4"/></svg>',key:'<svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="6" cy="6.1" r="3"/><path d="M8.1 8.2 13 13.1"/><path d="M11.3 11.4 12.6 10.1"/><path d="M12.7 12.8 13.7 11.8"/></svg>',close:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M4.2 4.2 11.8 11.8"/><path d="M11.8 4.2 4.2 11.8"/></svg>',edit:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M10.7 3.3 12.7 5.3 6.3 11.7 3.7 12.3 4.3 9.7 10.7 3.3z"/></svg>',history:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M2.2 4.8a2 2 0 0 1 2-2h7.6a2 2 0 0 1 2 2v4.6a2 2 0 0 1-2 2H6.6l-2.9 2.4v-2.4h-.5a2 2 0 0 1-2-2z"/><path d="M5.2 6.2h5.6M5.2 8.4h3.6"/></svg>',feishu:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M2.6 4.4C6.4 4 10.4 5.4 13.4 8.2 9.8 7 6.4 6.6 3.4 7.4"/><path d="M13.4 8.2C9.6 8.7 6 10 2.9 12 5.6 9 8.8 7.6 13.4 8.2"/></svg>'};function Vn(e,n,a,s=""){return`<button type="button" class="card-act${s?" "+s:""}" data-action="${e}" title="${i(a)}" aria-label="${i(a)}">${n}</button>`}function co(e){if(!e)return"";let n=`<a class="term-btn term-open" href="${i(e)}" target="_blank" rel="noopener" title="${i(t("sessions.openTerminal"))}" aria-label="${i(t("sessions.openTerminal"))}">${Ce.terminal}</a>`;if(!Te.authed)return`<span class="term-pill solo">${n}</span>`;let a=`<button type="button" class="term-btn term-write" data-action="write-link" title="${i(t("sessions.writeLinkHint"))}" aria-label="${i(t("sessions.writeLink"))}">${Ce.key}</button>`;return`<span class="term-pill">${n}${a}</span>`}async function uo(e,n){let a=window.open("about:blank","_blank");a&&(a.opener=null),n&&(n.disabled=!0);try{let s=await fetch(`/api/sessions/${encodeURIComponent(e.sessionId)}/write-link`),o=await s.json().catch(()=>({}));if(!s.ok||o?.ok===!1||!o?.url){a?.close(),s.status!==401&&alert(`${t("sessions.writeLinkFail")}: ${o?.error??s.status}`);return}a?a.location.href=o.url:window.open(o.url,"_blank","noopener")}catch(s){a?.close(),alert(`${t("sessions.writeLinkFail")}: ${s}`)}finally{n&&(n.disabled=!1)}}function li(e){return e.status==="closed"?null:e.pendingRepo||e.tuiPromptActive||e.agentAttention||e.status==="limited"?"needs-you":e.status==="starting"?"starting":e.status==="working"||e.status==="analyzing"||e.status==="active"?"working":"idle"}function di(){return`<details class="filter-cli">
114
120
  <summary>${t("sessions.cli")} \xB7 <b id="cli-filter-count">${t("common.all")}</b></summary>
115
121
  <div class="filter-cli-pop" role="group" aria-label="${t("sessions.cli")}">
116
- ${ia.map(e=>`
122
+ ${po.map(e=>`
117
123
  <label class="filter-check">
118
- <input type="checkbox" name="cli" value="${r(e)}" checked>
119
- <span>${r(e)}</span>
124
+ <input type="checkbox" name="cli" value="${i(e)}" checked>
125
+ <span>${i(e)}</span>
120
126
  </label>
121
127
  `).join("")}
122
128
  </div>
123
- </details>`}function ti(){return`<section class="page">
129
+ </details>`}function ci(){return`<section class="page">
124
130
  <div class="page-heading">
125
131
  <div>
126
132
  <p class="eyebrow">${t("nav.sessions")}</p>
@@ -154,7 +160,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
154
160
  <option value="yes">${t("sessions.adoptYes")}</option>
155
161
  <option value="no">${t("sessions.adoptNo")}</option>
156
162
  </select>
157
- ${ei()}
163
+ ${di()}
158
164
  <label class="filter-toggle"><input type="checkbox" name="active" checked> <span>${t("sessions.activeOnly")}</span></label>
159
165
  </form>
160
166
  <div id="bulk-bar" class="bulk-bar" hidden>
@@ -165,16 +171,16 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
165
171
  <table id="sessions-table">
166
172
  <thead><tr>
167
173
  <th><input type="checkbox" id="select-all" title="${t("sessions.activeOnly")}"></th>
168
- ${Je("botName",t("sessions.bot"))}
169
- ${Je("cliId",t("sessions.cli"))}
170
- ${Je("status",t("sessions.status"))}
171
- ${Je("tokenIn",t("sessions.tokenIn"))}
172
- ${Je("tokenOut",t("sessions.tokenOut"))}
173
- ${Je("title",t("sessions.titleCol"))}
174
- ${Je("workingDir",t("sessions.workingDir"))}
175
- ${Je("spawnedAt",t("sessions.created"))}
176
- ${Je("lastMessageAt",t("sessions.last"))}
177
- ${Je("adopt",t("sessions.adopt"))}
174
+ ${Ve("botName",t("sessions.bot"))}
175
+ ${Ve("cliId",t("sessions.cli"))}
176
+ ${Ve("status",t("sessions.status"))}
177
+ ${Ve("tokenIn",t("sessions.tokenIn"))}
178
+ ${Ve("tokenOut",t("sessions.tokenOut"))}
179
+ ${Ve("title",t("sessions.titleCol"))}
180
+ ${Ve("workingDir",t("sessions.workingDir"))}
181
+ ${Ve("spawnedAt",t("sessions.created"))}
182
+ ${Ve("lastMessageAt",t("sessions.last"))}
183
+ ${Ve("adopt",t("sessions.adopt"))}
178
184
  <th>${t("sessions.actions")}</th>
179
185
  </tr></thead>
180
186
  <tbody></tbody>
@@ -184,163 +190,163 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
184
190
  <dialog id="drawer"></dialog>
185
191
  <dialog id="term-modal" class="term-modal"></dialog>
186
192
  <dialog id="history-modal" class="history-modal"></dialog>
187
- </section>`}function ra(e){e.innerHTML=ti();let n=e.querySelector("#sessions-table tbody"),o=e.querySelector("#filters"),s=e.querySelector("#drawer"),a=e.querySelector("#select-all"),i=e.querySelector("#bulk-bar"),d=e.querySelector("#bulk-count"),p=e.querySelector("#bulk-close"),v=e.querySelector("#bulk-clear"),k=e.querySelector("#sessions-table"),I=e.querySelector("#sessions-board"),T=e.querySelector("#sessions-kanban"),g=e.querySelector("#term-modal"),R=e.querySelector("#history-modal"),A=e.querySelector("#kanban-groupby"),O=e.querySelector("#kanban-team"),M=e.querySelector("#kanban-team-stats"),E=e.querySelectorAll(".sessions-view-toggle [data-view]"),$=new Set,D="lastMessageAt",m="desc",y=To(window.localStorage),S=Io(window.localStorage),H=null,B="",j="",q="",oe=!1,X=null,ae=!1,Ae=null,se=new Map,ie=Eo(window.localStorage),ce=null,Le=null,de=[],Be=null,ge=!1,Ie=!1,re=(()=>{try{return window.localStorage.getItem(Hn)??""}catch{return""}})();async function pe(){if(!(Ie||ge)){Ie=!0;try{let[l,c,f]=await Promise.all([fetch("/api/team/hosted").then(w=>w.json()).catch(()=>null),fetch("/api/team/remote-roster").then(w=>w.json()).catch(()=>null),fetch("/api/groups").then(w=>w.json()).catch(()=>null)]);Array.isArray(f?.chats)&&(Be=new Map(f.chats.map(w=>[String(w.chatId),{botIds:new Set((w.memberBots??[]).filter(L=>L.inChat).map(L=>String(L.larkAppId))),observedNames:new Set((w.observedBotNames??[]).map(L=>String(L)))}])));let u=w=>({ids:new Set(w.map(L=>String(L.larkAppId))),names:new Set(w.map(L=>String(L.name??"")).filter(Boolean))}),b=[];for(let w of l?.teams??[]){let{ids:L,names:C}=u(w.bots??[]);b.push({key:`local:${w.teamId}`,label:w.isDefault?t("team.myHostedTeam"):String(w.name??w.teamId),botIds:L,botNames:C,groupChats:new Set((w.groupChatIds??[]).map(F=>String(F)))})}for(let w of c?.memberships??[]){let{ids:L,names:C}=u(w.roster?.bots??[]);b.push({key:`${w.hubUrl}::${w.teamId}`,label:String(w.teamName??w.teamId??w.hubUrl),botIds:L,botNames:C,groupChats:new Set})}de=b}finally{ge=!0,Ie=!1}de.length&&!de.some(l=>l.key===re)&&(re=de[0].key),delete O.dataset.loading,O.disabled=de.length===0,O.innerHTML=de.length?de.map(l=>`<option value="${r(l.key)}"${l.key===re?" selected":""}>${r(l.label)}</option>`).join(""):`<option value="">${r(t("sessions.kanban.noTeam"))}</option>`,q="",Z()}}let le=null,Ne="",je=0,Pe=!1,Fe=new Map;async function be(l){let c=Ne===l.key&&Date.now()-je<3e4;if(!(Pe||c)){Pe=!0;try{let u=l.key.startsWith("local:")?`/api/team/board/local/${encodeURIComponent(l.key.slice(6))}`:`/api/team/remote-board?key=${encodeURIComponent(l.key)}`,b=await fetch(u),w=await b.json().catch(()=>({}));if(!b.ok||w?.ok===!1)return;let L=typeof w.deploymentId=="string"?w.deploymentId:null,C=[];Fe=new Map;for(let F of Array.isArray(w.reports)?w.reports:[])if(!(L&&F.deploymentId===L))for(let N of Array.isArray(F.sessions)?F.sessions:[]){let ee={...N,remoteDeployment:F.deploymentName||F.deploymentId};C.push(ee),Fe.set(String(N.sessionId),ee)}le={board:w.board&&typeof w.board=="object"?w.board:{},remoteRows:C},Ne=l.key,je=Date.now(),q="",Z()}catch{}finally{Pe=!1}}}async function nt(l,c,f,u,b){try{let L=l.startsWith("local:")?await fetch(`/api/team/board/local/${encodeURIComponent(l.slice(6))}/move`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({sessionId:c,column:f,position:u})}):await fetch("/api/team/remote-board-move",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({key:l,sessionId:c,column:f,position:u})}),C=await L.json().catch(()=>({}));(!L.ok||C?.ok===!1)&&(le&&(b?le.board[c]=b:delete le.board[c]),q="",Z(),L.status!==401&&alert(`${t("sessions.kanban.moveFail")}: ${C?.error??L.status}`))}catch(w){le&&(b?le.board[c]=b:delete le.board[c]),q="",Z(),alert(`${t("sessions.kanban.moveFail")}: ${w}`)}}function wt(l,c,f){let u=de.find(w=>w.key===re)??de[0];if(!u)return;(!le||Ne!==u.key)&&(le={board:{},remoteRows:le?.remoteRows??[]},Ne=u.key);let b=le.board[l];le.board[l]={column:c,position:f},nt(u.key,l,c,f,b)}function ot(){return S.map(l=>ea.find(c=>c.id===l)).filter(l=>!!l)}function Ht(l,c){let f=S.indexOf(l),u=f+c;if(f<0||u<0||u>=S.length)return;let b=[...S];b.splice(f,1),b.splice(u,0,l),S=b,En(window.localStorage,S),Z()}function at(l,c){if(l===c)return;let f=S.indexOf(l),u=S.indexOf(c);if(f<0||u<0)return;let b=[...S];b.splice(f,1),b.splice(u,0,l),S=b,En(window.localStorage,S),Z()}function Me(l){let c=l.status==="closed",f=$.has(l.sessionId)?"checked":"";return`<tr data-id="${r(l.sessionId)}">
188
- <td><input type="checkbox" class="row-select" ${f} ${c?"disabled":""}></td>
189
- <td>${r(ye(l))}</td>
190
- <td><span class="badge cli-${na(l.cliId)}">${r(l.cliId??"unknown")}</span></td>
191
- <td><span class="status status-${r(l.status??"unknown")}">${r(l.status??"unknown")}</span></td>
192
- <td class="token-cell">${Zo(l.tokenUsage?.in)}</td>
193
- <td class="token-cell">${Zo(l.tokenUsage?.out)}</td>
194
- <td title="${r(String(l.title??""))}">${r(ve(l.title??"").slice(0,48))}</td>
195
- <td title="${r(l.workingDir??"")}">${r((l.workingDir??"").slice(-34))}</td>
196
- <td>${qe(l.spawnedAt)}</td>
197
- <td>${qe(l.lastMessageAt)}</td>
193
+ </section>`}function mo(e){e.innerHTML=ci();let n=e.querySelector("#sessions-table tbody"),a=e.querySelector("#filters"),s=e.querySelector("#drawer"),o=e.querySelector("#select-all"),r=e.querySelector("#bulk-bar"),d=e.querySelector("#bulk-count"),p=e.querySelector("#bulk-close"),k=e.querySelector("#bulk-clear"),$=e.querySelector("#sessions-table"),E=e.querySelector("#sessions-board"),w=e.querySelector("#sessions-kanban"),u=e.querySelector("#term-modal"),S=e.querySelector("#history-modal"),x=e.querySelector("#kanban-groupby"),A=e.querySelector("#kanban-team"),L=e.querySelector("#kanban-team-stats"),H=e.querySelectorAll(".sessions-view-toggle [data-view]"),T=new Set,P="lastMessageAt",f="desc",v=xa(window.localStorage),I=Ca(window.localStorage),D=null,B="",U="",q="",ae=!1,X=null,oe=!1,De=null,se=new Map,re=Ra(window.localStorage),ue=null,Me=null,ce=[],Oe=null,be=!1,Ee=!1,le=(()=>{try{return window.localStorage.getItem(Bn)??""}catch{return""}})();async function fe(){if(!(Ee||be)){Ee=!0;try{let[l,c,g]=await Promise.all([fetch("/api/team/hosted").then(y=>y.json()).catch(()=>null),fetch("/api/team/remote-roster").then(y=>y.json()).catch(()=>null),fetch("/api/groups").then(y=>y.json()).catch(()=>null)]);Array.isArray(g?.chats)&&(Oe=new Map(g.chats.map(y=>[String(y.chatId),{botIds:new Set((y.memberBots??[]).filter(M=>M.inChat).map(M=>String(M.larkAppId))),observedNames:new Set((y.observedBotNames??[]).map(M=>String(M)))}])));let m=y=>({ids:new Set(y.map(M=>String(M.larkAppId))),names:new Set(y.map(M=>String(M.name??"")).filter(Boolean))}),b=[];for(let y of l?.teams??[]){let{ids:M,names:R}=m(y.bots??[]);b.push({key:`local:${y.teamId}`,label:y.isDefault?t("team.myHostedTeam"):String(y.name??y.teamId),botIds:M,botNames:R,groupChats:new Set((y.groupChatIds??[]).map(F=>String(F)))})}for(let y of c?.memberships??[]){let{ids:M,names:R}=m(y.roster?.bots??[]);b.push({key:`${y.hubUrl}::${y.teamId}`,label:String(y.teamName??y.teamId??y.hubUrl),botIds:M,botNames:R,groupChats:new Set})}ce=b}finally{be=!0,Ee=!1}ce.length&&!ce.some(l=>l.key===le)&&(le=ce[0].key),delete A.dataset.loading,A.disabled=ce.length===0,A.innerHTML=ce.length?ce.map(l=>`<option value="${i(l.key)}"${l.key===le?" selected":""}>${i(l.label)}</option>`).join(""):`<option value="">${i(t("sessions.kanban.noTeam"))}</option>`,q="",Z()}}let de=null,Ne="",Fe=0,qe=!1,Ge=new Map;async function he(l){let c=Ne===l.key&&Date.now()-Fe<3e4;if(!(qe||c)){qe=!0;try{let m=l.key.startsWith("local:")?`/api/team/board/local/${encodeURIComponent(l.key.slice(6))}`:`/api/team/remote-board?key=${encodeURIComponent(l.key)}`,b=await fetch(m),y=await b.json().catch(()=>({}));if(!b.ok||y?.ok===!1)return;let M=typeof y.deploymentId=="string"?y.deploymentId:null,R=[];Ge=new Map;for(let F of Array.isArray(y.reports)?y.reports:[])if(!(M&&F.deploymentId===M))for(let O of Array.isArray(F.sessions)?F.sessions:[]){let ee={...O,remoteDeployment:F.deploymentName||F.deploymentId};R.push(ee),Ge.set(String(O.sessionId),ee)}de={board:y.board&&typeof y.board=="object"?y.board:{},remoteRows:R},Ne=l.key,Fe=Date.now(),q="",Z()}catch{}finally{qe=!1}}}async function ot(l,c,g,m,b){try{let M=l.startsWith("local:")?await fetch(`/api/team/board/local/${encodeURIComponent(l.slice(6))}/move`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({sessionId:c,column:g,position:m})}):await fetch("/api/team/remote-board-move",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({key:l,sessionId:c,column:g,position:m})}),R=await M.json().catch(()=>({}));(!M.ok||R?.ok===!1)&&(de&&(b?de.board[c]=b:delete de.board[c]),q="",Z(),M.status!==401&&alert(`${t("sessions.kanban.moveFail")}: ${R?.error??M.status}`))}catch(y){de&&(b?de.board[c]=b:delete de.board[c]),q="",Z(),alert(`${t("sessions.kanban.moveFail")}: ${y}`)}}function $t(l,c,g){let m=ce.find(y=>y.key===le)??ce[0];if(!m)return;(!de||Ne!==m.key)&&(de={board:{},remoteRows:de?.remoteRows??[]},Ne=m.key);let b=de.board[l];de.board[l]={column:c,position:g},ot(m.key,l,c,g,b)}function st(){return I.map(l=>so.find(c=>c.id===l)).filter(l=>!!l)}function Dt(l,c){let g=I.indexOf(l),m=g+c;if(g<0||m<0||m>=I.length)return;let b=[...I];b.splice(g,1),b.splice(m,0,l),I=b,Pn(window.localStorage,I),Z()}function it(l,c){if(l===c)return;let g=I.indexOf(l),m=I.indexOf(c);if(g<0||m<0)return;let b=[...I];b.splice(g,1),b.splice(m,0,l),I=b,Pn(window.localStorage,I),Z()}function xe(l){let c=l.status==="closed",g=T.has(l.sessionId)?"checked":"";return`<tr data-id="${i(l.sessionId)}">
194
+ <td><input type="checkbox" class="row-select" ${g} ${c?"disabled":""}></td>
195
+ <td>${i(ve(l))}</td>
196
+ <td><span class="badge cli-${ro(l.cliId)}">${i(l.cliId??"unknown")}</span></td>
197
+ <td><span class="status status-${i(l.status??"unknown")}">${i(l.status??"unknown")}</span></td>
198
+ <td class="token-cell">${oo(l.tokenUsage?.in)}</td>
199
+ <td class="token-cell">${oo(l.tokenUsage?.out)}</td>
200
+ <td title="${i(String(l.title??""))}">${i(ke(l.title??"").slice(0,48))}</td>
201
+ <td title="${i(l.workingDir??"")}">${i((l.workingDir??"").slice(-34))}</td>
202
+ <td>${je(l.spawnedAt)}</td>
203
+ <td>${je(l.lastMessageAt)}</td>
198
204
  <td>${l.adopt?'<span class="badge">adopt</span>':""}</td>
199
205
  <td><button class="open" type="button">${t("sessions.details")}</button></td>
200
- </tr>`}function _e(l){if(l.scope!=="chat"||!l.feishuChatLink)return null;let c=t("sessions.openChat");return`<a class="card-act" href="${r(l.feishuChatLink)}" target="_blank" rel="noopener" title="${r(c)}" aria-label="${r(c)}">${Ee.feishu}</a>`}function Ge(l){return l.agentAttention?.reason?l.agentAttention.reason:l.agentAttention?t("sessions.board.signalAgent"):l.pendingRepo?t("sessions.board.signalRepo"):l.tuiPromptActive?t("sessions.board.signalPrompt"):l.status==="limited"?t("sessions.board.signalLimited"):""}function x(l){let c=$.has(l.sessionId),f=ve(l.title)||l.sessionId,u=ye(l),b=st(l),w=Fn(l),L=Ge(l),C=oa(l.workingDir);return`<article class="session-card${c?" selected":""}" data-id="${r(l.sessionId)}" aria-pressed="${c}">
206
+ </tr>`}function We(l){if(l.scope!=="chat"||!l.feishuChatLink)return null;let c=t("sessions.openChat");return`<a class="card-act" href="${i(l.feishuChatLink)}" target="_blank" rel="noopener" title="${i(c)}" aria-label="${i(c)}">${Ce.feishu}</a>`}function _e(l){return l.agentAttention?.reason?l.agentAttention.reason:l.agentAttention?t("sessions.board.signalAgent"):l.pendingRepo?t("sessions.board.signalRepo"):l.tuiPromptActive?t("sessions.board.signalPrompt"):l.status==="limited"?t("sessions.board.signalLimited"):""}function C(l){let c=T.has(l.sessionId),g=ke(l.title)||l.sessionId,m=ve(l),b=rt(l),y=Jn(l),M=_e(l),R=lo(l.workingDir);return`<article class="session-card${c?" selected":""}" data-id="${i(l.sessionId)}" aria-pressed="${c}">
201
207
  <div class="session-card-top">
202
- ${fe({name:u,larkAppId:l.larkAppId,size:"sm"})}
208
+ ${me({name:m,larkAppId:l.larkAppId,size:"sm"})}
203
209
  <div class="session-card-title">
204
- <strong title="${r(String(l.title??f))}">${r(String(f).slice(0,72))}</strong>
205
- <span>${r(u)} \xB7 ${r(b??l.cliId??"unknown")}</span>
210
+ <strong title="${i(String(l.title??g))}">${i(String(g).slice(0,72))}</strong>
211
+ <span>${i(m)} \xB7 ${i(b??l.cliId??"unknown")}</span>
206
212
  </div>
207
- <span class="status status-${r(l.status??"unknown")}">${r(l.status??"unknown")}</span>
213
+ <span class="status status-${i(l.status??"unknown")}">${i(l.status??"unknown")}</span>
208
214
  </div>
209
- ${C!=="-"||l.adopt?`<div class="session-card-meta">
210
- ${C!=="-"?`<span title="${r(l.workingDir??"")}">${r(C)}</span>`:""}
215
+ ${R!=="-"||l.adopt?`<div class="session-card-meta">
216
+ ${R!=="-"?`<span title="${i(l.workingDir??"")}">${i(R)}</span>`:""}
211
217
  ${l.adopt?'<span class="badge">adopt</span>':""}
212
218
  </div>`:""}
213
219
  <div class="session-card-time">
214
- <span>${l.agentAttention?.at?`${r(t("sessions.board.waiting"))} ${qe(xe(l))}`:`${r(t("sessions.last"))}: ${qe(l.lastMessageAt)}`}</span>
220
+ <span>${l.agentAttention?.at?`${i(t("sessions.board.waiting"))} ${je(He(l))}`:`${i(t("sessions.last"))}: ${je(l.lastMessageAt)}`}</span>
215
221
  </div>
216
- ${L?`<div class="session-signal" title="${r(L)}">${r(L)}</div>`:""}
222
+ ${M?`<div class="session-signal" title="${i(M)}">${i(M)}</div>`:""}
217
223
  <div class="session-card-actions">
218
- ${_e(l)??Gn("locate",Ee.pin,t("sessions.locate"))}
219
- ${Gn("details",Ee.details,t("sessions.details"))}
220
- ${aa(w)}
221
- ${Gn("close",Ee.close,t("sessions.close"),"danger")}
224
+ ${We(l)??Vn("locate",Ce.pin,t("sessions.locate"))}
225
+ ${Vn("details",Ce.details,t("sessions.details"))}
226
+ ${co(y)}
227
+ ${Vn("close",Ce.close,t("sessions.close"),"danger")}
222
228
  </div>
223
- </article>`}function V(l,c,f){let u=f==="needs-you"?xe(l):Number(l.lastMessageAt??0),b=f==="needs-you"?xe(c):Number(c.lastMessageAt??0);return u!==b?f==="needs-you"?u-b:b-u:String(l.title??l.sessionId).localeCompare(String(c.title??c.sessionId))}function K(l){let c=new Map(ea.map(b=>[b.id,[]]));for(let b of l){let w=Zs(b);w&&c.get(w).push(b)}let f=ot(),u=f.map((b,w)=>{let L=(c.get(b.id)??[]).sort((C,F)=>V(C,F,b.id));return`<section class="session-board-column session-board-${b.id}" data-col="${b.id}">
224
- <header draggable="true" title="${r(t("sessions.board.dragHint"))}">
229
+ </article>`}function Y(l,c,g){let m=g==="needs-you"?He(l):Number(l.lastMessageAt??0),b=g==="needs-you"?He(c):Number(c.lastMessageAt??0);return m!==b?g==="needs-you"?m-b:b-m:String(l.title??l.sessionId).localeCompare(String(c.title??c.sessionId))}function K(l){let c=new Map(so.map(b=>[b.id,[]]));for(let b of l){let y=li(b);y&&c.get(y).push(b)}let g=st(),m=g.map((b,y)=>{let M=(c.get(b.id)??[]).sort((R,F)=>Y(R,F,b.id));return`<section class="session-board-column session-board-${b.id}" data-col="${b.id}">
230
+ <header draggable="true" title="${i(t("sessions.board.dragHint"))}">
225
231
  <div>
226
- <h2>${r(t(b.labelKey))}</h2>
227
- <p>${r(t(b.hintKey))}</p>
232
+ <h2>${i(t(b.labelKey))}</h2>
233
+ <p>${i(t(b.hintKey))}</p>
228
234
  </div>
229
235
  <span class="session-board-head-right">
230
236
  <span class="session-board-move">
231
237
  <button type="button" data-move-col="${b.id}" data-dir="-1"
232
- aria-label="${r(t("sessions.board.moveLeft"))}" ${w===0?"disabled":""}>\u2039</button>
238
+ aria-label="${i(t("sessions.board.moveLeft"))}" ${y===0?"disabled":""}>\u2039</button>
233
239
  <button type="button" data-move-col="${b.id}" data-dir="1"
234
- aria-label="${r(t("sessions.board.moveRight"))}" ${w===f.length-1?"disabled":""}>\u203A</button>
240
+ aria-label="${i(t("sessions.board.moveRight"))}" ${y===g.length-1?"disabled":""}>\u203A</button>
235
241
  </span>
236
- <span class="session-board-count">${L.length}</span>
242
+ <span class="session-board-count">${M.length}</span>
237
243
  </span>
238
244
  </header>
239
245
  <div class="session-board-list">
240
- ${L.length?L.map(x).join(""):`<div class="session-board-empty">${t("sessions.board.emptyColumn")}</div>`}
246
+ ${M.length?M.map(C).join(""):`<div class="session-board-empty">${t("sessions.board.emptyColumn")}</div>`}
241
247
  </div>
242
- </section>`}).join("");u!==B&&(B=u,I.innerHTML=u,I.classList.toggle("board-enter",!oe),oe=!0)}function _(l){let c=ve(l.title)||l.sessionId,f=ye(l),u=st(l),b=oa(l.workingDir),w=Ge(l),L=[u,b!=="-"?b:null].filter(Boolean).join(" \xB7 "),C=String(l.status??"unknown"),F=typeof l.remoteDeployment=="string"?l.remoteDeployment:"";return`<article class="kanban-card${F?" kanban-card-remote":""}" data-id="${r(l.sessionId)}" tabindex="0" role="button" draggable="true">
248
+ </section>`}).join("");m!==B&&(B=m,E.innerHTML=m,E.classList.toggle("board-enter",!ae),ae=!0)}function _(l){let c=ke(l.title)||l.sessionId,g=ve(l),m=rt(l),b=lo(l.workingDir),y=_e(l),M=[m,b!=="-"?b:null].filter(Boolean).join(" \xB7 "),R=String(l.status??"unknown"),F=typeof l.remoteDeployment=="string"?l.remoteDeployment:"";return`<article class="kanban-card${F?" kanban-card-remote":""}" data-id="${i(l.sessionId)}" tabindex="0" role="button" draggable="true">
243
249
  <div class="kanban-card-top">
244
- <span class="badge cli-${na(l.cliId)}">${r(l.cliId??"unknown")}</span>
250
+ <span class="badge cli-${ro(l.cliId)}">${i(l.cliId??"unknown")}</span>
245
251
  ${l.adopt?'<span class="badge">adopt</span>':""}
246
- ${F?`<span class="badge kanban-remote-badge" title="${r(t("sessions.kanban.remoteHint",{name:F}))}">${r(F)}</span>`:""}
252
+ ${F?`<span class="badge kanban-remote-badge" title="${i(t("sessions.kanban.remoteHint",{name:F}))}">${i(F)}</span>`:""}
247
253
  <span class="kanban-card-top-right">
248
- <span class="kanban-card-dot" data-status="${r(C)}" title="${r(C)}"></span>
249
- ${F?"":`<button type="button" class="card-act kanban-card-act" data-action="history" title="${r(t("sessions.history.title"))}" aria-label="${r(t("sessions.history.title"))}">${Ee.history}</button>
250
- ${l.feishuChatLink?`<a class="card-act kanban-card-act" href="${r(l.feishuChatLink)}" target="_blank" rel="noopener" title="${r(t("sessions.kanban.openFeishu"))}" aria-label="${r(t("sessions.kanban.openFeishu"))}">${Ee.feishu}</a>`:""}
251
- <button type="button" class="card-act kanban-card-act" data-action="details" title="${r(t("sessions.details"))}" aria-label="${r(t("sessions.details"))}">${Ee.details}</button>`}
254
+ <span class="kanban-card-dot" data-status="${i(R)}" title="${i(R)}"></span>
255
+ ${F?"":`<button type="button" class="card-act kanban-card-act" data-action="history" title="${i(t("sessions.history.title"))}" aria-label="${i(t("sessions.history.title"))}">${Ce.history}</button>
256
+ ${l.feishuChatLink?`<a class="card-act kanban-card-act" href="${i(l.feishuChatLink)}" target="_blank" rel="noopener" title="${i(t("sessions.kanban.openFeishu"))}" aria-label="${i(t("sessions.kanban.openFeishu"))}">${Ce.feishu}</a>`:""}
257
+ <button type="button" class="card-act kanban-card-act" data-action="details" title="${i(t("sessions.details"))}" aria-label="${i(t("sessions.details"))}">${Ce.details}</button>`}
252
258
  </span>
253
259
  </div>
254
- <p class="kanban-card-title" title="${r(String(l.title??c))}">${r(String(c).slice(0,140))}</p>
255
- ${L?`<p class="kanban-card-desc" title="${r(L)}">${r(L)}</p>`:""}
256
- ${w?`<div class="session-signal" title="${r(w)}">${r(w)}</div>`:""}
260
+ <p class="kanban-card-title" title="${i(String(l.title??c))}">${i(String(c).slice(0,140))}</p>
261
+ ${M?`<p class="kanban-card-desc" title="${i(M)}">${i(M)}</p>`:""}
262
+ ${y?`<div class="session-signal" title="${i(y)}">${i(y)}</div>`:""}
257
263
  <div class="kanban-card-foot">
258
- <span class="kanban-card-owner">${fe({name:f,larkAppId:l.larkAppId,size:"sm"})}<span>${r(f)}</span></span>
259
- <span class="kanban-card-updated">${r(t("sessions.kanban.updated",{time:qe(l.lastMessageAt)}))}</span>
264
+ <span class="kanban-card-owner">${me({name:g,larkAppId:l.larkAppId,size:"sm"})}<span>${i(g)}</span></span>
265
+ <span class="kanban-card-updated">${i(t("sessions.kanban.updated",{time:je(l.lastMessageAt)}))}</span>
260
266
  </div>
261
- </article>`}function he(l){let c=[],f=new Map;for(let w of l){let L=String(w.chatId??w.sessionId),C=f.get(L);C||(C={chatId:L,rows:[]},f.set(L,C),c.push(C)),C.rows.push(w)}let u=[];return{html:c.map(w=>{if(u.push(...w.rows),w.rows.length<2)return _(w.rows[0]);let L=st(w.rows[0])??w.chatId;return`<div class="kanban-cluster" data-chat="${r(w.chatId)}">
262
- <header draggable="true" title="${r(L)} \xB7 ${r(t("sessions.kanban.clusterDragHint"))}">
263
- ${on({chatId:w.chatId,name:L,size:"sm"})}
264
- <span class="kanban-cluster-name">${r(L)}</span>
265
- <span class="kanban-cluster-count">${w.rows.length}</span>
267
+ </article>`}function we(l){let c=[],g=new Map;for(let y of l){let M=String(y.chatId??y.sessionId),R=g.get(M);R||(R={chatId:M,rows:[]},g.set(M,R),c.push(R)),R.rows.push(y)}let m=[];return{html:c.map(y=>{if(m.push(...y.rows),y.rows.length<2)return _(y.rows[0]);let M=rt(y.rows[0])??y.chatId;return`<div class="kanban-cluster" data-chat="${i(y.chatId)}">
268
+ <header draggable="true" title="${i(M)} \xB7 ${i(t("sessions.kanban.clusterDragHint"))}">
269
+ ${ln({chatId:y.chatId,name:M,size:"sm"})}
270
+ <span class="kanban-cluster-name">${i(M)}</span>
271
+ <span class="kanban-cluster-count">${y.rows.length}</span>
266
272
  </header>
267
- ${w.rows.map(_).join("")}
268
- </div>`}).join(""),flat:u}}function Xe(l){let c=new Map;for(let u of l){if(u.status==="closed")continue;let b=String(u.larkAppId||u.botName||"unknown"),w=c.get(b);w||(w={name:ye(u),larkAppId:u.larkAppId,rows:[]},c.set(b,w)),w.rows.push(u)}let f=[...c.values()].sort((u,b)=>u.name.localeCompare(b.name));return f.length?f.map(u=>{let b=u.rows.sort((L,C)=>Number(C.lastMessageAt??0)-Number(L.lastMessageAt??0)),{html:w}=he(b);return`<section class="kanban-column kanban-bot-col" data-bot="${r(u.larkAppId??u.name)}">
273
+ ${y.rows.map(_).join("")}
274
+ </div>`}).join(""),flat:m}}function Ze(l){let c=new Map;for(let m of l){if(m.status==="closed")continue;let b=String(m.larkAppId||m.botName||"unknown"),y=c.get(b);y||(y={name:ve(m),larkAppId:m.larkAppId,rows:[]},c.set(b,y)),y.rows.push(m)}let g=[...c.values()].sort((m,b)=>m.name.localeCompare(b.name));return g.length?g.map(m=>{let b=m.rows.sort((M,R)=>Number(R.lastMessageAt??0)-Number(M.lastMessageAt??0)),{html:y}=we(b);return`<section class="kanban-column kanban-bot-col" data-bot="${i(m.larkAppId??m.name)}">
269
275
  <header>
270
- <span class="kanban-col-avatar">${fe({name:u.name,larkAppId:u.larkAppId,size:"sm"})}</span>
271
- <h2>${r(u.name)}</h2>
276
+ <span class="kanban-col-avatar">${me({name:m.name,larkAppId:m.larkAppId,size:"sm"})}</span>
277
+ <h2>${i(m.name)}</h2>
272
278
  <span class="kanban-col-count">${b.length}</span>
273
279
  </header>
274
- <div class="kanban-col-list">${w}</div>
275
- </section>`}).join(""):`<div class="kanban-col-empty">${t("sessions.board.emptyColumn")}</div>`}function $e(l){let c=new Map(ta.map(u=>[u.id,[]]));for(let u of l)c.get(Xo(u)).push(u);let f=ta.map(u=>{let b=(c.get(u.id)??[]).sort((F,N)=>pt(F)-pt(N)),w=0;u.id==="done"&&b.length>jn&&(w=b.length-jn,b=b.slice(0,jn));let{html:L,flat:C}=he(b);return c.set(u.id,C),`<section class="kanban-column kanban-${u.id}" data-col="${u.id}">
280
+ <div class="kanban-col-list">${y}</div>
281
+ </section>`}).join(""):`<div class="kanban-col-empty">${t("sessions.board.emptyColumn")}</div>`}function Se(l){let c=new Map(io.map(m=>[m.id,[]]));for(let m of l)c.get(ao(m)).push(m);let g=io.map(m=>{let b=(c.get(m.id)??[]).sort((F,O)=>gt(F)-gt(O)),y=0;m.id==="done"&&b.length>Kn&&(y=b.length-Kn,b=b.slice(0,Kn));let{html:M,flat:R}=we(b);return c.set(m.id,R),`<section class="kanban-column kanban-${m.id}" data-col="${m.id}">
276
282
  <header>
277
- <span class="kanban-col-icon">${Xs(u.id)}</span>
278
- <h2>${r(t(u.labelKey))}</h2>
279
- <span class="kanban-col-count">${b.length+w}</span>
283
+ <span class="kanban-col-icon">${ri(m.id)}</span>
284
+ <h2>${i(t(m.labelKey))}</h2>
285
+ <span class="kanban-col-count">${b.length+y}</span>
280
286
  </header>
281
287
  <div class="kanban-col-list">
282
- ${b.length?L:`<div class="kanban-col-empty">${t("sessions.board.emptyColumn")}</div>`}
283
- ${w?`<div class="kanban-col-more">${r(t("sessions.kanban.moreHidden",{count:w}))}</div>`:""}
288
+ ${b.length?M:`<div class="kanban-col-empty">${t("sessions.board.emptyColumn")}</div>`}
289
+ ${y?`<div class="kanban-col-more">${i(t("sessions.kanban.moreHidden",{count:y}))}</div>`:""}
284
290
  </div>
285
- </section>`}).join("");return se=c,f}function Wt(l){if(X||ce||ae)return;T.classList.toggle("kanban-mode-bot",ie==="bot");let c;if(ie==="bot")c=Xe(l),se=new Map;else if(ie==="team")if(!ge)c=`<div class="kanban-loading">${t("sessions.kanban.teamLoading")}</div>`,se=new Map,O.dataset.loading||(O.dataset.loading="1",O.disabled=!0,O.innerHTML=`<option>${r(t("sessions.kanban.teamLoading"))}</option>`),pe();else{let u=de.find(N=>N.key===re)??de[0],b=[],w=new Set;if(u){for(let N of u.groupChats)w.add(N);if(Be)for(let[N,ee]of Be){if(w.has(N))continue;let me=!1;for(let ze of u.botIds)if(ee.botIds.has(ze)){me=!0;break}if(me){for(let ze of ee.observedNames)if(u.botNames.has(ze)){w.add(N);break}}}b=l.filter(N=>w.has(String(N.chatId)))}u&&be(u);let L=(Ne===u?.key?le?.board:null)??{},C=(Ne===u?.key?le?.remoteRows:null)??[],F=[...b,...C].map(N=>{let ee=L[N.sessionId];return ee?{...N,kanbanColumn:ee.column,kanbanPosition:ee.position}:N});M.textContent=t("sessions.kanban.teamScope",{chats:w.size,sessions:F.length}),c=$e(F)}else c=$e(l);if(c===q)return;q=c;let f=new Map;T.querySelectorAll(".kanban-col-list").forEach(u=>{let b=u.closest(".kanban-column")?.dataset.col;b&&u.scrollTop&&f.set(b,u.scrollTop)}),T.innerHTML=c,f.size&&T.querySelectorAll(".kanban-col-list").forEach(u=>{let b=u.closest(".kanban-column")?.dataset.col,w=b?f.get(b):void 0;w&&(u.scrollTop=w)})}async function ct(l,c,f,u){try{let b=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/board`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({column:c,position:f})}),w=await b.json().catch(()=>({}));(!b.ok||w?.ok===!1)&&(l.kanbanColumn=u.column,l.kanbanPosition=u.position,q="",Z(),b.status!==401&&alert(`${t("sessions.kanban.moveFail")}: ${w?.error??b.status}`))}catch(b){l.kanbanColumn=u.column,l.kanbanPosition=u.position,q="",Z(),alert(`${t("sessions.kanban.moveFail")}: ${b}`)}}async function Ze(l,c){let f=l.title;l.title=c,q="",Z();try{let u=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/rename`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({title:c})}),b=await u.json().catch(()=>({}));(!u.ok||b?.ok===!1)&&(l.title=f,q="",Z(),u.status!==401&&alert(`${t("sessions.kanban.renameFail")}: ${b?.error??u.status}`))}catch(u){l.title=f,q="",Z(),alert(`${t("sessions.kanban.renameFail")}: ${u}`)}}function yt(l){if(l==null||l==="")return"";let c=Number(l),f=Number.isFinite(c)&&c>0?new Date(c):new Date(String(l));return Number.isNaN(f.getTime())?"":f.toLocaleString()}function Ct(l,c,f){let u=c.senderType==="user",b=u?c.senderName||(f&&c.senderId===f?t("sessions.history.owner"):t("sessions.history.user")):ye(l),w=yt(c.createTime),L=String(c.content??"").trim()||`[${c.msgType??"message"}]`,C=u?c.senderAvatar?`<img class="history-avatar-img" src="${r(String(c.senderAvatar))}" alt="" decoding="async" referrerpolicy="no-referrer">`:`<span class="history-avatar-user" aria-hidden="true">${r(String(b).slice(0,1))}</span>`:fe({name:ye(l),larkAppId:l.larkAppId,size:"sm"});return`<div class="history-msg${u?" mine":""}">
286
- ${C}
291
+ </section>`}).join("");return se=c,g}function Yt(l){if(X||ue||oe)return;w.classList.toggle("kanban-mode-bot",re==="bot");let c;if(re==="bot")c=Ze(l),se=new Map;else if(re==="team")if(!be)c=`<div class="kanban-loading">${t("sessions.kanban.teamLoading")}</div>`,se=new Map,A.dataset.loading||(A.dataset.loading="1",A.disabled=!0,A.innerHTML=`<option>${i(t("sessions.kanban.teamLoading"))}</option>`),fe();else{let m=ce.find(O=>O.key===le)??ce[0],b=[],y=new Set;if(m){for(let O of m.groupChats)y.add(O);if(Oe)for(let[O,ee]of Oe){if(y.has(O))continue;let ge=!1;for(let ze of m.botIds)if(ee.botIds.has(ze)){ge=!0;break}if(ge){for(let ze of ee.observedNames)if(m.botNames.has(ze)){y.add(O);break}}}b=l.filter(O=>y.has(String(O.chatId)))}m&&he(m);let M=(Ne===m?.key?de?.board:null)??{},R=(Ne===m?.key?de?.remoteRows:null)??[],F=[...b,...R].map(O=>{let ee=M[O.sessionId];return ee?{...O,kanbanColumn:ee.column,kanbanPosition:ee.position}:O});L.textContent=t("sessions.kanban.teamScope",{chats:y.size,sessions:F.length}),c=Se(F)}else c=Se(l);if(c===q)return;q=c;let g=new Map;w.querySelectorAll(".kanban-col-list").forEach(m=>{let b=m.closest(".kanban-column")?.dataset.col;b&&m.scrollTop&&g.set(b,m.scrollTop)}),w.innerHTML=c,g.size&&w.querySelectorAll(".kanban-col-list").forEach(m=>{let b=m.closest(".kanban-column")?.dataset.col,y=b?g.get(b):void 0;y&&(m.scrollTop=y)})}async function mt(l,c,g,m){try{let b=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/board`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({column:c,position:g})}),y=await b.json().catch(()=>({}));(!b.ok||y?.ok===!1)&&(l.kanbanColumn=m.column,l.kanbanPosition=m.position,q="",Z(),b.status!==401&&alert(`${t("sessions.kanban.moveFail")}: ${y?.error??b.status}`))}catch(b){l.kanbanColumn=m.column,l.kanbanPosition=m.position,q="",Z(),alert(`${t("sessions.kanban.moveFail")}: ${b}`)}}async function et(l,c){let g=l.title;l.title=c,q="",Z();try{let m=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/rename`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({title:c})}),b=await m.json().catch(()=>({}));(!m.ok||b?.ok===!1)&&(l.title=g,q="",Z(),m.status!==401&&alert(`${t("sessions.kanban.renameFail")}: ${b?.error??m.status}`))}catch(m){l.title=g,q="",Z(),alert(`${t("sessions.kanban.renameFail")}: ${m}`)}}function St(l){if(l==null||l==="")return"";let c=Number(l),g=Number.isFinite(c)&&c>0?new Date(c):new Date(String(l));return Number.isNaN(g.getTime())?"":g.toLocaleString()}function Rt(l,c,g){let m=c.senderType==="user",b=m?c.senderName||(g&&c.senderId===g?t("sessions.history.owner"):t("sessions.history.user")):ve(l),y=St(c.createTime),M=String(c.content??"").trim()||`[${c.msgType??"message"}]`,R=m?c.senderAvatar?`<img class="history-avatar-img" src="${i(String(c.senderAvatar))}" alt="" decoding="async" referrerpolicy="no-referrer">`:`<span class="history-avatar-user" aria-hidden="true">${i(String(b).slice(0,1))}</span>`:me({name:ve(l),larkAppId:l.larkAppId,size:"sm"});return`<div class="history-msg${m?" mine":""}">
292
+ ${R}
287
293
  <div class="history-msg-main">
288
- <div class="history-msg-meta"><span>${r(b)}</span><time>${r(w)}</time></div>
289
- <div class="history-bubble">${r(L)}</div>
294
+ <div class="history-msg-meta"><span>${i(b)}</span><time>${i(y)}</time></div>
295
+ <div class="history-bubble">${i(M)}</div>
290
296
  </div>
291
- </div>`}async function Se(l){let c=ye(l);R.innerHTML=`<div class="term-modal-head">
297
+ </div>`}async function Le(l){let c=ve(l);S.innerHTML=`<div class="term-modal-head">
292
298
  <span class="term-modal-title">
293
- ${fe({name:c,larkAppId:l.larkAppId,size:"sm"})}
294
- <strong title="${r(String(l.title??""))}">${r((ve(l.title)||l.sessionId).slice(0,60))}</strong>
295
- <span class="history-scope-tag">${r(t("sessions.history.title"))}</span>
299
+ ${me({name:c,larkAppId:l.larkAppId,size:"sm"})}
300
+ <strong title="${i(String(l.title??""))}">${i((ke(l.title)||l.sessionId).slice(0,60))}</strong>
301
+ <span class="history-scope-tag">${i(t("sessions.history.title"))}</span>
296
302
  </span>
297
303
  <span class="term-modal-actions">
298
- <button type="button" id="history-close" class="card-act" title="${r(t("sessions.dismiss"))}" aria-label="${r(t("sessions.dismiss"))}">${Ee.close}</button>
304
+ <button type="button" id="history-close" class="card-act" title="${i(t("sessions.dismiss"))}" aria-label="${i(t("sessions.dismiss"))}">${Ce.close}</button>
299
305
  </span>
300
306
  </div>
301
- <div class="history-body"><div class="term-modal-loading">${t("sessions.history.loading")}</div></div>`,R.showModal(),R.querySelector("#history-close").onclick=()=>R.close();try{let f=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/history?limit=80`),u=await f.json().catch(()=>({}));if(!R.open)return;let b=R.querySelector(".history-body");if(!f.ok||u?.ok===!1){let L=String(u?.error??f.status),C=L==="not_found_yet"||L==="not_found";b.innerHTML=`<div class="history-error">${r(t("sessions.history.fail"))}: ${r(L)}${C?`<br><span>${r(t("sessions.history.staleHint"))}</span>`:""}</div>`;return}let w=Array.isArray(u.messages)?u.messages:[];if(!w.length){b.innerHTML=`<div class="history-error">${t("sessions.history.empty")}</div>`;return}b.innerHTML=`<div class="history-list">${w.map(L=>Ct(l,L,u.ownerOpenId)).join("")}</div>`,b.scrollTop=b.scrollHeight}catch(f){if(!R.open)return;let u=R.querySelector(".history-body");u&&(u.innerHTML=`<div class="history-error">${r(t("sessions.history.fail"))}: ${r(String(f))}</div>`)}}function At(l,c){let f=l.querySelector(".kanban-card-title");if(!f||l.querySelector(".kanban-rename-input"))return;ae=!0;let u=document.createElement("input");u.type="text",u.className="kanban-rename-input",u.maxLength=200,u.value=ve(c.title)||"",f.replaceWith(u),u.focus(),u.select();let b=!1,w=L=>{if(b)return;b=!0,ae=!1;let C=u.value.trim();L&&C&&C!==(ve(c.title)||"")?Ze(c,C):(q="",Z())};u.addEventListener("keydown",L=>{L.stopPropagation(),L.key==="Enter"?(L.preventDefault(),w(!0)):L.key==="Escape"&&(L.preventDefault(),w(!1))}),u.addEventListener("blur",()=>w(!0)),u.addEventListener("click",L=>L.stopPropagation())}function vt(l,c){for(let f of l.querySelectorAll(".kanban-card:not(.dragging)")){if(f.closest(".kanban-cluster.dragging"))continue;let u=f.getBoundingClientRect();if(c<u.top+u.height/2)return f}return null}function $n(){T.querySelectorAll(".drag-over, .dragging, .drop-before").forEach(l=>l.classList.remove("drag-over","dragging","drop-before"))}function J(l){let c=g.querySelector(".term-modal-name");if(!c||g.querySelector(".term-modal-name-input"))return;let f=document.createElement("input");f.type="text",f.className="term-modal-name-input",f.maxLength=200,f.value=ve(l.title)||"",c.replaceWith(f);let u=()=>{let L=getComputedStyle(f),C=document.createElement("span");C.style.cssText="position:absolute;visibility:hidden;white-space:pre",C.style.fontSize=L.fontSize,C.style.fontFamily=L.fontFamily,C.style.fontWeight=L.fontWeight,C.style.letterSpacing=L.letterSpacing,C.textContent=f.value||" ",document.body.appendChild(C);let F=C.offsetWidth;C.remove();let N=Math.round(window.innerWidth*.6);f.style.width=`${Math.min(Math.max(F+22,80),N)}px`};u(),f.addEventListener("input",u),f.focus(),f.select();let b=!1,w=L=>{if(b)return;b=!0;let C=f.value.trim(),F=ve(l.title)||"";if(L&&C&&C!==F){l.title=C;let N=document.createElement("strong");N.className="term-modal-name",N.title=C,N.textContent=C.slice(0,60),f.replaceWith(N),Ze(l,C)}else{let N=document.createElement("strong");N.className="term-modal-name",N.title=String(l.title??F),N.textContent=F.slice(0,60),f.replaceWith(N)}};f.addEventListener("keydown",L=>{L.stopPropagation(),L.key==="Enter"?(L.preventDefault(),w(!0)):L.key==="Escape"&&(L.preventDefault(),w(!1))}),f.addEventListener("blur",()=>w(!0))}async function z(l){let c=Fn(l);if(!c){Kt(l);return}let f=ve(l.title)||l.sessionId,u=l.feishuChatLink?`<a class="card-act" href="${r(l.feishuChatLink)}" target="_blank" rel="noopener" title="${r(t("sessions.kanban.openFeishu"))}" aria-label="${r(t("sessions.kanban.openFeishu"))}">${Ee.feishu}</a>`:"";g.innerHTML=`<div class="term-modal-head">
307
+ <div class="history-body"><div class="term-modal-loading">${t("sessions.history.loading")}</div></div>`,S.showModal(),S.querySelector("#history-close").onclick=()=>S.close();try{let g=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/history?limit=80`),m=await g.json().catch(()=>({}));if(!S.open)return;let b=S.querySelector(".history-body");if(!g.ok||m?.ok===!1){let M=String(m?.error??g.status),R=M==="not_found_yet"||M==="not_found";b.innerHTML=`<div class="history-error">${i(t("sessions.history.fail"))}: ${i(M)}${R?`<br><span>${i(t("sessions.history.staleHint"))}</span>`:""}</div>`;return}let y=Array.isArray(m.messages)?m.messages:[];if(!y.length){b.innerHTML=`<div class="history-error">${t("sessions.history.empty")}</div>`;return}b.innerHTML=`<div class="history-list">${y.map(M=>Rt(l,M,m.ownerOpenId)).join("")}</div>`,b.scrollTop=b.scrollHeight}catch(g){if(!S.open)return;let m=S.querySelector(".history-body");m&&(m.innerHTML=`<div class="history-error">${i(t("sessions.history.fail"))}: ${i(String(g))}</div>`)}}function Pt(l,c){let g=l.querySelector(".kanban-card-title");if(!g||l.querySelector(".kanban-rename-input"))return;oe=!0;let m=document.createElement("input");m.type="text",m.className="kanban-rename-input",m.maxLength=200,m.value=ke(c.title)||"",g.replaceWith(m),m.focus(),m.select();let b=!1,y=M=>{if(b)return;b=!0,oe=!1;let R=m.value.trim();M&&R&&R!==(ke(c.title)||"")?et(c,R):(q="",Z())};m.addEventListener("keydown",M=>{M.stopPropagation(),M.key==="Enter"?(M.preventDefault(),y(!0)):M.key==="Escape"&&(M.preventDefault(),y(!1))}),m.addEventListener("blur",()=>y(!0)),m.addEventListener("click",M=>M.stopPropagation())}function Lt(l,c){for(let g of l.querySelectorAll(".kanban-card:not(.dragging)")){if(g.closest(".kanban-cluster.dragging"))continue;let m=g.getBoundingClientRect();if(c<m.top+m.height/2)return g}return null}function En(){w.querySelectorAll(".drag-over, .dragging, .drop-before").forEach(l=>l.classList.remove("drag-over","dragging","drop-before"))}function J(l){let c=u.querySelector(".term-modal-name");if(!c||u.querySelector(".term-modal-name-input"))return;let g=document.createElement("input");g.type="text",g.className="term-modal-name-input",g.maxLength=200,g.value=ke(l.title)||"",c.replaceWith(g);let m=()=>{let M=getComputedStyle(g),R=document.createElement("span");R.style.cssText="position:absolute;visibility:hidden;white-space:pre",R.style.fontSize=M.fontSize,R.style.fontFamily=M.fontFamily,R.style.fontWeight=M.fontWeight,R.style.letterSpacing=M.letterSpacing,R.textContent=g.value||" ",document.body.appendChild(R);let F=R.offsetWidth;R.remove();let O=Math.round(window.innerWidth*.6);g.style.width=`${Math.min(Math.max(F+22,80),O)}px`};m(),g.addEventListener("input",m),g.focus(),g.select();let b=!1,y=M=>{if(b)return;b=!0;let R=g.value.trim(),F=ke(l.title)||"";if(M&&R&&R!==F){l.title=R;let O=document.createElement("strong");O.className="term-modal-name",O.title=R,O.textContent=R.slice(0,60),g.replaceWith(O),et(l,R)}else{let O=document.createElement("strong");O.className="term-modal-name",O.title=String(l.title??F),O.textContent=F.slice(0,60),g.replaceWith(O)}};g.addEventListener("keydown",M=>{M.stopPropagation(),M.key==="Enter"?(M.preventDefault(),y(!0)):M.key==="Escape"&&(M.preventDefault(),y(!1))}),g.addEventListener("blur",()=>y(!0))}async function W(l){let c=Jn(l);if(!c){Qt(l);return}let g=ke(l.title)||l.sessionId,m=l.feishuChatLink?`<a class="card-act" href="${i(l.feishuChatLink)}" target="_blank" rel="noopener" title="${i(t("sessions.kanban.openFeishu"))}" aria-label="${i(t("sessions.kanban.openFeishu"))}">${Ce.feishu}</a>`:"";u.innerHTML=`<div class="term-modal-head">
302
308
  <span class="term-modal-title">
303
- ${fe({name:ye(l),larkAppId:l.larkAppId,size:"sm"})}
304
- <strong class="term-modal-name" title="${r(String(l.title??f))}">${r(String(f).slice(0,60))}</strong>
305
- <button type="button" id="term-modal-edit" class="card-act" title="${r(t("sessions.kanban.rename"))}" aria-label="${r(t("sessions.kanban.rename"))}">${Ee.edit}</button>
306
- <span class="status status-${r(l.status??"unknown")}">${r(l.status??"unknown")}</span>
309
+ ${me({name:ve(l),larkAppId:l.larkAppId,size:"sm"})}
310
+ <strong class="term-modal-name" title="${i(String(l.title??g))}">${i(String(g).slice(0,60))}</strong>
311
+ <button type="button" id="term-modal-edit" class="card-act" title="${i(t("sessions.kanban.rename"))}" aria-label="${i(t("sessions.kanban.rename"))}">${Ce.edit}</button>
312
+ <span class="status status-${i(l.status??"unknown")}">${i(l.status??"unknown")}</span>
307
313
  </span>
308
314
  <span class="term-modal-actions">
309
- ${u}
310
- <a id="term-modal-tab" class="card-act" href="${r(c)}" target="_blank" rel="noopener" title="${r(t("sessions.kanban.openTab"))}" aria-label="${r(t("sessions.kanban.openTab"))}">${Ee.terminal}</a>
311
- <button type="button" id="term-modal-close" class="card-act" title="${r(t("sessions.dismiss"))}" aria-label="${r(t("sessions.dismiss"))}">${Ee.close}</button>
315
+ ${m}
316
+ <a id="term-modal-tab" class="card-act" href="${i(c)}" target="_blank" rel="noopener" title="${i(t("sessions.kanban.openTab"))}" aria-label="${i(t("sessions.kanban.openTab"))}">${Ce.terminal}</a>
317
+ <button type="button" id="term-modal-close" class="card-act" title="${i(t("sessions.dismiss"))}" aria-label="${i(t("sessions.dismiss"))}">${Ce.close}</button>
312
318
  </span>
313
319
  </div>
314
- <div class="term-modal-body"><div class="term-modal-loading">${t("sessions.kanban.terminalLoading")}</div></div>`,g.showModal(),g.querySelector("#term-modal-close").onclick=()=>g.close(),g.querySelector("#term-modal-edit").onclick=()=>J(l);let b=c;if(Te.authed)try{let C=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/write-link`),F=await C.json().catch(()=>({}));C.ok&&F?.ok!==!1&&F?.url&&(b=F.url)}catch{}if(!g.open)return;let w=g.querySelector(".term-modal-body");w.innerHTML=`<iframe class="term-modal-frame" src="${r(b)}" allow="clipboard-read; clipboard-write"></iframe>`;let L=g.querySelector("#term-modal-tab");L&&(L.href=b)}function P(){let l=new FormData(o),c=(l.get("q")??"").toLowerCase(),f=l.getAll("cli"),u=f.length>0&&f.length<ia.length,b=l.get("status"),w=l.get("adopt"),L=!!l.get("active"),C=y==="kanban",F=[...Q.sessions.values()].filter(N=>!u||f.includes(N.cliId??"unknown")).filter(N=>!b||N.status===b).filter(N=>!w||w==="yes"==!!N.adopt).filter(N=>!L||C||N.status!=="closed").filter(N=>!c||JSON.stringify(N).toLowerCase().includes(c));return F.sort(G),F}function W(l,c){return c==="spawnedAt"||c==="lastMessageAt"?Number(l[c]??0):c==="tokenIn"?_n(l.tokenUsage?.in)??-1:c==="tokenOut"?_n(l.tokenUsage?.out)??-1:c==="adopt"?!!l.adopt:String(l[c]??"").toLowerCase()}function G(l,c){let f=W(l,D),u=W(c,D),b=0;return typeof f=="number"&&typeof u=="number"?b=f-u:typeof f=="boolean"&&typeof u=="boolean"?b=Number(f)-Number(u):b=String(f).localeCompare(String(u)),b===0&&(b=Number(l.lastMessageAt??0)-Number(c.lastMessageAt??0)),m==="asc"?b:-b}function Y(){k.querySelectorAll("th[data-sort]").forEach(l=>{let c=l.dataset.sort===D;l.classList.toggle("sorted",c),l.setAttribute("aria-sort",c?m==="asc"?"ascending":"descending":"none");let f=l.dataset.label??l.textContent?.trim()??"";l.textContent=c?`${f} ${m==="asc"?"\u25B2":"\u25BC"}`:f})}function ue(l){i.hidden=$.size===0,d.textContent=t("sessions.selectedCount",{count:$.size});let c=l.filter(u=>u.status!=="closed");if(c.length===0){a.checked=!1,a.indeterminate=!1,a.disabled=!0;return}a.disabled=!1;let f=c.filter(u=>$.has(u.sessionId)).length;a.checked=f===c.length,a.indeterminate=f>0&&f<c.length}function De(){E.forEach(l=>{let c=l.dataset.view===y;l.classList.toggle("active",c),l.setAttribute("aria-pressed",String(c))}),A.hidden=y!=="kanban",O.hidden=!(y==="kanban"&&ie==="team"),M.hidden=O.hidden||!ge,A.querySelectorAll("[data-groupby]").forEach(l=>{let c=l.dataset.groupby===ie;l.classList.toggle("active",c),l.setAttribute("aria-pressed",String(c))})}function ut(){let l=o.querySelector("#cli-filter-count");if(!l)return;let c=[...o.querySelectorAll('input[name="cli"]')],f=c.filter(u=>u.checked).length;l.textContent=f===c.length?t("common.all"):`${f}/${c.length}`,l.classList.toggle("cli-filter-active",f!==c.length)}function Z(){let l=P();for(let u of[...$]){let b=Q.sessions.get(u);(!b||b.status==="closed")&&$.delete(u)}let c=l.filter(u=>u.status!=="closed"),f=y==="table"?l:c;if(k.hidden=y!=="table",I.hidden=y!=="board",T.hidden=y!=="kanban",y==="table"){let u=l.length?l.map(Me).join(""):`<tr><td colspan="12" class="empty">${t("sessions.empty")}</td></tr>`;u!==j&&(j=u,n.innerHTML=u)}else y==="kanban"?Wt(l):K(c);De(),Y(),ut(),ue(f)}async function fo(l,c){c&&(c.disabled=!0,c.textContent=t("sessions.locating"));try{let f=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/locate`,{method:"POST"}),u=await f.json();if(u.ok){if(!c)return;let b=30;c.textContent=t("sessions.cooldown",{seconds:b});let w=setInterval(()=>{b-=1,b<=0?(clearInterval(w),c.disabled=!1,c.textContent=t("sessions.locate")):c.textContent=t("sessions.cooldown",{seconds:b})},1e3)}else alert(`Locate failed: ${u.error??f.status}`),c&&(c.disabled=!1,c.textContent=t("sessions.locate"))}catch(f){alert(`Locate error: ${f}`),c&&(c.disabled=!1,c.textContent=t("sessions.locate"))}}async function go(l,c){if(!confirm(t("sessions.closeConfirm")))return!1;c&&(c.disabled=!0);try{let f=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/close`,{method:"POST"}),u=await f.json().catch(()=>({}));return!f.ok||u?.ok===!1?(f.status!==401&&alert(`Close failed: ${u?.error??f.status}`),!1):!0}catch(f){return alert(`Close error: ${f}`),!1}finally{c&&(c.disabled=!1)}}function Kt(l){let c=l.status==="closed",f=Fn(l);s.innerHTML=`<article>
320
+ <div class="term-modal-body"><div class="term-modal-loading">${t("sessions.kanban.terminalLoading")}</div></div>`,u.showModal(),u.querySelector("#term-modal-close").onclick=()=>u.close(),u.querySelector("#term-modal-edit").onclick=()=>J(l);let b=c;if(Te.authed)try{let R=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/write-link`),F=await R.json().catch(()=>({}));R.ok&&F?.ok!==!1&&F?.url&&(b=F.url)}catch{}if(!u.open)return;let y=u.querySelector(".term-modal-body");y.innerHTML=`<iframe class="term-modal-frame" src="${i(b)}" allow="clipboard-read; clipboard-write"></iframe>`;let M=u.querySelector("#term-modal-tab");M&&(M.href=b)}function N(){let l=new FormData(a),c=(l.get("q")??"").toLowerCase(),g=l.getAll("cli"),m=g.length>0&&g.length<po.length,b=l.get("status"),y=l.get("adopt"),M=!!l.get("active"),R=v==="kanban",F=[...Q.sessions.values()].filter(O=>!m||g.includes(O.cliId??"unknown")).filter(O=>!b||O.status===b).filter(O=>!y||y==="yes"==!!O.adopt).filter(O=>!M||R||O.status!=="closed").filter(O=>!c||JSON.stringify(O).toLowerCase().includes(c));return F.sort(G),F}function z(l,c){return c==="spawnedAt"||c==="lastMessageAt"?Number(l[c]??0):c==="tokenIn"?Yn(l.tokenUsage?.in)??-1:c==="tokenOut"?Yn(l.tokenUsage?.out)??-1:c==="adopt"?!!l.adopt:String(l[c]??"").toLowerCase()}function G(l,c){let g=z(l,P),m=z(c,P),b=0;return typeof g=="number"&&typeof m=="number"?b=g-m:typeof g=="boolean"&&typeof m=="boolean"?b=Number(g)-Number(m):b=String(g).localeCompare(String(m)),b===0&&(b=Number(l.lastMessageAt??0)-Number(c.lastMessageAt??0)),f==="asc"?b:-b}function V(){$.querySelectorAll("th[data-sort]").forEach(l=>{let c=l.dataset.sort===P;l.classList.toggle("sorted",c),l.setAttribute("aria-sort",c?f==="asc"?"ascending":"descending":"none");let g=l.dataset.label??l.textContent?.trim()??"";l.textContent=c?`${g} ${f==="asc"?"\u25B2":"\u25BC"}`:g})}function pe(l){r.hidden=T.size===0,d.textContent=t("sessions.selectedCount",{count:T.size});let c=l.filter(m=>m.status!=="closed");if(c.length===0){o.checked=!1,o.indeterminate=!1,o.disabled=!0;return}o.disabled=!1;let g=c.filter(m=>T.has(m.sessionId)).length;o.checked=g===c.length,o.indeterminate=g>0&&g<c.length}function Re(){H.forEach(l=>{let c=l.dataset.view===v;l.classList.toggle("active",c),l.setAttribute("aria-pressed",String(c))}),x.hidden=v!=="kanban",A.hidden=!(v==="kanban"&&re==="team"),L.hidden=A.hidden||!be,x.querySelectorAll("[data-groupby]").forEach(l=>{let c=l.dataset.groupby===re;l.classList.toggle("active",c),l.setAttribute("aria-pressed",String(c))})}function ft(){let l=a.querySelector("#cli-filter-count");if(!l)return;let c=[...a.querySelectorAll('input[name="cli"]')],g=c.filter(m=>m.checked).length;l.textContent=g===c.length?t("common.all"):`${g}/${c.length}`,l.classList.toggle("cli-filter-active",g!==c.length)}function Z(){let l=N();for(let m of[...T]){let b=Q.sessions.get(m);(!b||b.status==="closed")&&T.delete(m)}let c=l.filter(m=>m.status!=="closed"),g=v==="table"?l:c;if($.hidden=v!=="table",E.hidden=v!=="board",w.hidden=v!=="kanban",v==="table"){let m=l.length?l.map(xe).join(""):`<tr><td colspan="12" class="empty">${t("sessions.empty")}</td></tr>`;m!==U&&(U=m,n.innerHTML=m)}else v==="kanban"?Yt(l):K(c);Re(),V(),ft(),pe(g)}async function ya(l,c){c&&(c.disabled=!0,c.textContent=t("sessions.locating"));try{let g=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/locate`,{method:"POST"}),m=await g.json();if(m.ok){if(!c)return;let b=30;c.textContent=t("sessions.cooldown",{seconds:b});let y=setInterval(()=>{b-=1,b<=0?(clearInterval(y),c.disabled=!1,c.textContent=t("sessions.locate")):c.textContent=t("sessions.cooldown",{seconds:b})},1e3)}else alert(`Locate failed: ${m.error??g.status}`),c&&(c.disabled=!1,c.textContent=t("sessions.locate"))}catch(g){alert(`Locate error: ${g}`),c&&(c.disabled=!1,c.textContent=t("sessions.locate"))}}async function va(l,c){if(!confirm(t("sessions.closeConfirm")))return!1;c&&(c.disabled=!0);try{let g=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/close`,{method:"POST"}),m=await g.json().catch(()=>({}));return!g.ok||m?.ok===!1?(g.status!==401&&alert(`Close failed: ${m?.error??g.status}`),!1):!0}catch(g){return alert(`Close error: ${g}`),!1}finally{c&&(c.disabled=!1)}}function Qt(l){let c=l.status==="closed",g=Jn(l);s.innerHTML=`<article>
315
321
  <header>
316
- <h3>${r(ve(l.title)||l.sessionId)}</h3>
317
- <span class="status status-${r(l.status??"unknown")}">${r(l.status??"unknown")}</span>
318
- <p><code>${r(l.sessionId)}</code> <button data-copy="${r(l.sessionId)}">${t("sessions.copy")}</button></p>
322
+ <h3>${i(ke(l.title)||l.sessionId)}</h3>
323
+ <span class="status status-${i(l.status??"unknown")}">${i(l.status??"unknown")}</span>
324
+ <p><code>${i(l.sessionId)}</code> <button data-copy="${i(l.sessionId)}">${t("sessions.copy")}</button></p>
319
325
  </header>
320
- <p><b>${t("sessions.bot")}:</b> ${r(ye(l))} \xB7 <b>${t("sessions.cli")}:</b> ${r(l.cliId??"?")}</p>
321
- ${st(l)?`<p><b>${t("sessions.chat")}:</b> ${r(st(l))}</p>`:""}
322
- <p><b>chatId:</b> <code>${r(l.chatId??"")}</code> <button data-copy="${r(l.chatId??"")}">${t("sessions.copy")}</button></p>
323
- <p><b>rootMessageId:</b> <code>${r(l.rootMessageId??"")}</code> <button data-copy="${r(l.rootMessageId??"")}">${t("sessions.copy")}</button></p>
324
- ${l.threadId?`<p><b>threadId:</b> <code>${r(l.threadId)}</code></p>`:""}
325
- <p><b>${t("sessions.workingDir")}:</b> ${r(l.workingDir??"-")}</p>
326
+ <p><b>${t("sessions.bot")}:</b> ${i(ve(l))} \xB7 <b>${t("sessions.cli")}:</b> ${i(l.cliId??"?")}</p>
327
+ ${rt(l)?`<p><b>${t("sessions.chat")}:</b> ${i(rt(l))}</p>`:""}
328
+ <p><b>chatId:</b> <code>${i(l.chatId??"")}</code> <button data-copy="${i(l.chatId??"")}">${t("sessions.copy")}</button></p>
329
+ <p><b>rootMessageId:</b> <code>${i(l.rootMessageId??"")}</code> <button data-copy="${i(l.rootMessageId??"")}">${t("sessions.copy")}</button></p>
330
+ ${l.threadId?`<p><b>threadId:</b> <code>${i(l.threadId)}</code></p>`:""}
331
+ <p><b>${t("sessions.workingDir")}:</b> ${i(l.workingDir??"-")}</p>
326
332
  <div class="actions">
327
- ${_e(l)??`<button id="locate-btn" type="button">${t("sessions.locate")}</button>`}
333
+ ${We(l)??`<button id="locate-btn" type="button">${t("sessions.locate")}</button>`}
328
334
  <button id="history-drawer-btn" type="button">${t("sessions.history.title")}</button>
329
- ${aa(f)}
335
+ ${co(g)}
330
336
  ${c?`<button id="resume-btn" type="button" class="primary">${t("sessions.resume")}</button>`:""}
331
337
  ${c?"":`<button id="close-btn" type="button" class="contrast">${t("sessions.close")}</button>`}
332
338
  <button id="land-btn" type="button">${t("sessions.land")}</button>
333
339
  </div>
334
340
  <div id="land-area"></div>
335
341
  <form method="dialog"><button>${t("sessions.dismiss")}</button></form>
336
- </article>`,s.querySelectorAll("[data-copy]").forEach(ee=>{ee.onclick=()=>{navigator.clipboard.writeText(ee.dataset.copy??""),ee.textContent=t("sessions.copied"),setTimeout(()=>{ee.textContent=t("sessions.copy")},800)}});let u=s.querySelector("#locate-btn");u&&(u.onclick=()=>{fo(l,u)});let b=s.querySelector("#history-drawer-btn");b&&(b.onclick=()=>{Se(l)});let w=s.querySelector(".term-write");w&&(w.onclick=()=>{sa(l,w)});let L=s.querySelector("#resume-btn");L&&(L.onclick=async()=>{L.disabled=!0;try{let ee=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/resume`,{method:"POST"}),me=await ee.json().catch(()=>({}));if(!ee.ok||me.ok===!1){alert(`${t("sessions.resumeFailed")}: ${me?.error??ee.status}`),L.disabled=!1;return}s.close()}catch(ee){alert(`${t("sessions.resumeFailed")}: ${ee}`),L.disabled=!1}});let C=s.querySelector("#close-btn");C&&(C.onclick=async()=>{await go(l,C)&&s.close()});let F=s.querySelector("#land-btn"),N=s.querySelector("#land-area");F&&N&&(F.onclick=async()=>{F.disabled=!0,N.innerHTML=`<p>${t("sessions.landLoading")}</p>`;try{let ee=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/sandbox-diff`),me=await ee.json().catch(()=>({}));if(!me.ok){N.innerHTML=`<p>${t("sessions.landUnavailable")}: ${r(me.error??String(ee.status))}</p>`,F.disabled=!1;return}if(me.empty){N.innerHTML=`<p>${t("sessions.landEmpty")}</p>`,F.disabled=!1;return}let ze=String(me.patch??""),Sn=ze.slice(0,2e4)+(ze.length>2e4?`
337
- \u2026(truncated)`:"");N.innerHTML=`
338
- <p><b>${me.files}</b> files (+${me.insertions}/-${me.deletions}) \u2192 <code>${r(String(me.workingDir??""))}</code></p>
339
- <pre style="max-height:320px;overflow:auto;white-space:pre-wrap">${r(Sn)}</pre>
342
+ </article>`,s.querySelectorAll("[data-copy]").forEach(ee=>{ee.onclick=()=>{navigator.clipboard.writeText(ee.dataset.copy??""),ee.textContent=t("sessions.copied"),setTimeout(()=>{ee.textContent=t("sessions.copy")},800)}});let m=s.querySelector("#locate-btn");m&&(m.onclick=()=>{ya(l,m)});let b=s.querySelector("#history-drawer-btn");b&&(b.onclick=()=>{Le(l)});let y=s.querySelector(".term-write");y&&(y.onclick=()=>{uo(l,y)});let M=s.querySelector("#resume-btn");M&&(M.onclick=async()=>{M.disabled=!0;try{let ee=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/resume`,{method:"POST"}),ge=await ee.json().catch(()=>({}));if(!ee.ok||ge.ok===!1){alert(`${t("sessions.resumeFailed")}: ${ge?.error??ee.status}`),M.disabled=!1;return}s.close()}catch(ee){alert(`${t("sessions.resumeFailed")}: ${ee}`),M.disabled=!1}});let R=s.querySelector("#close-btn");R&&(R.onclick=async()=>{await va(l,R)&&s.close()});let F=s.querySelector("#land-btn"),O=s.querySelector("#land-area");F&&O&&(F.onclick=async()=>{F.disabled=!0,O.innerHTML=`<p>${t("sessions.landLoading")}</p>`;try{let ee=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/sandbox-diff`),ge=await ee.json().catch(()=>({}));if(!ge.ok){O.innerHTML=`<p>${t("sessions.landUnavailable")}: ${i(ge.error??String(ee.status))}</p>`,F.disabled=!1;return}if(ge.empty){O.innerHTML=`<p>${t("sessions.landEmpty")}</p>`,F.disabled=!1;return}let ze=String(ge.patch??""),xn=ze.slice(0,2e4)+(ze.length>2e4?`
343
+ \u2026(truncated)`:"");O.innerHTML=`
344
+ <p><b>${ge.files}</b> files (+${ge.insertions}/-${ge.deletions}) \u2192 <code>${i(String(ge.workingDir??""))}</code></p>
345
+ <pre style="max-height:320px;overflow:auto;white-space:pre-wrap">${i(xn)}</pre>
340
346
  <div class="actions">
341
347
  <button id="land-apply" type="button" class="primary">${t("sessions.landApply")}</button>
342
348
  <button id="land-discard" type="button" class="contrast">${t("sessions.landDiscard")}</button>
343
- </div>`;let We=N.querySelector("#land-apply"),Yt=N.querySelector("#land-discard");We.onclick=async()=>{We.disabled=!0,Yt.disabled=!0;let et=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/sandbox-land/apply`,{method:"POST"}),Re=await et.json().catch(()=>({}));N.innerHTML=Re.ok?`<p>\u2705 ${t("sessions.landApplied")}: ${Re.files} files (+${Re.insertions}/-${Re.deletions}) \u2192 <code>${r(String(Re.workingDir??""))}</code></p>`:`<p>\u274C ${t("sessions.landFailed")}: ${r(Re.error??String(et.status))}</p>`},Yt.onclick=async()=>{await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/sandbox-land/discard`,{method:"POST"}),N.innerHTML=`<p>\u{1F5D1} ${t("sessions.landDiscarded")}</p>`}}catch(ee){N.innerHTML=`<p>${t("sessions.landUnavailable")}: ${r(String(ee))}</p>`,F.disabled=!1}}),s.showModal()}n.addEventListener("click",l=>{let c=l.target;if(c.classList.contains("row-select")){let w=c.closest("tr[data-id]");if(!w)return;c.checked?$.add(w.dataset.id):$.delete(w.dataset.id),ue(P());return}let f=c.closest("td");if(f&&f.querySelector(".row-select"))return;let u=c.closest("tr[data-id]");if(!u)return;let b=Q.sessions.get(u.dataset.id);b&&Kt(b)}),I.addEventListener("click",l=>{let c=l.target,f=c.closest("button[data-move-col]");if(f){Ht(f.dataset.moveCol,Number(f.dataset.dir));return}let u=c.closest(".session-card[data-id]");if(!u)return;let b=Q.sessions.get(u.dataset.id);if(!b)return;let w=c.closest("button[data-action]");if(w){let L=w.dataset.action;L==="details"?Kt(b):L==="write-link"?sa(b,w):L==="locate"?fo(b,w):L==="close"&&go(b,w).then(C=>{C&&($.delete(b.sessionId),Z())});return}c.closest("a, button, input, label")||($.has(b.sessionId)?$.delete(b.sessionId):$.add(b.sessionId),u.classList.toggle("selected",$.has(b.sessionId)),u.setAttribute("aria-pressed",String($.has(b.sessionId))),ue(P().filter(L=>L.status!=="closed")))}),I.addEventListener("dragstart",l=>{let f=l.target.closest(".session-board-column > header[draggable]")?.closest(".session-board-column");f?.dataset.col&&(H=f.dataset.col,f.classList.add("dragging"),l.dataTransfer&&(l.dataTransfer.effectAllowed="move",l.dataTransfer.setData("text/plain",H)))}),I.addEventListener("dragover",l=>{if(!H)return;l.preventDefault(),l.dataTransfer&&(l.dataTransfer.dropEffect="move");let c=l.target.closest(".session-board-column");I.querySelectorAll(".drag-over").forEach(f=>f.classList.remove("drag-over")),c&&c.dataset.col!==H&&c.classList.add("drag-over")}),I.addEventListener("drop",l=>{if(!H)return;l.preventDefault();let c=l.target.closest(".session-board-column"),f=H;H=null,c?.dataset.col&&at(f,c.dataset.col)}),I.addEventListener("dragend",()=>{H=null,I.querySelectorAll(".drag-over, .dragging").forEach(l=>l.classList.remove("drag-over","dragging"))}),E.forEach(l=>{l.addEventListener("click",()=>{let c=xn(l.dataset.view)??"board";c!==y&&(y=c,Mo(window.localStorage,y),Z())})}),A.querySelectorAll("[data-groupby]").forEach(l=>{l.addEventListener("click",()=>{let c=l.dataset.groupby,f=c==="bot"?"bot":c==="team"?"team":"flow";f!==ie&&(ie=f,Ho(window.localStorage,f),q="",Z())})}),O.addEventListener("change",()=>{re=O.value;try{window.localStorage.setItem(Hn,re)}catch{}q="",Z()});function Jt(){Ae!==null&&(clearTimeout(Ae),Ae=null)}T.addEventListener("click",l=>{let c=l.target,f=c.closest(".kanban-card[data-id]");if(!f)return;let u=Q.sessions.get(f.dataset.id);if(!u)return;let b=c.closest("button[data-action]");if(b){b.dataset.action==="details"?Kt(u):b.dataset.action==="rename"?At(f,u):b.dataset.action==="history"&&Se(u);return}c.closest("a, button, input, label")||(Jt(),Ae=setTimeout(()=>{Ae=null,z(u)},220))}),T.addEventListener("dblclick",l=>{let c=l.target,f=c.closest(".kanban-card-title"),u=c.closest(".kanban-card[data-id]");if(!f||!u)return;Jt();let b=Q.sessions.get(u.dataset.id);b&&At(u,b)}),T.addEventListener("keydown",l=>{if(l.key!=="Enter"&&l.key!==" ")return;let c=l.target;if(!c.classList?.contains("kanban-card"))return;l.preventDefault();let f=Q.sessions.get(c.dataset.id);f&&z(f)}),T.addEventListener("dragstart",l=>{if(ie==="bot")return;let c=l.target,f=c.closest(".kanban-cluster > header[draggable]");if(f){let b=f.closest(".kanban-cluster"),w=b.closest(".kanban-column")?.dataset.col;if(!b.dataset.chat||!w)return;Jt(),ce=b.dataset.chat,Le=w,b.classList.add("dragging"),l.dataTransfer&&(l.dataTransfer.effectAllowed="move",l.dataTransfer.setData("text/plain",`cluster:${ce}`));return}let u=c.closest(".kanban-card[data-id]");u&&(Jt(),X=u.dataset.id,u.classList.add("dragging"),l.dataTransfer&&(l.dataTransfer.effectAllowed="move",l.dataTransfer.setData("text/plain",X)))}),T.addEventListener("dragover",l=>{if(!X&&!ce)return;l.preventDefault(),l.dataTransfer&&(l.dataTransfer.dropEffect="move");let c=l.target.closest(".kanban-column");T.querySelectorAll(".drag-over").forEach(f=>f.classList.remove("drag-over")),T.querySelectorAll(".drop-before").forEach(f=>f.classList.remove("drop-before")),c&&(c.classList.add("drag-over"),vt(c,l.clientY)?.classList.add("drop-before"))}),T.addEventListener("drop",l=>{let c=ce,f=Le,u=X;if(!u&&!c)return;l.preventDefault(),X=null,ce=null,Le=null,$n();let b=l.target.closest(".kanban-column"),w=b?.dataset.col;if(!b||!w)return;let L=vt(b,l.clientY);if(c&&f){let We=(se.get(f)??[]).filter(we=>String(we.chatId)===c).filter(we=>!(we.status==="closed"&&w!=="done"));if(!We.length)return;let Yt=new Set(We.map(we=>we.sessionId)),et=(se.get(w)??[]).filter(we=>!Yt.has(we.sessionId)),Re=L?et.findIndex(we=>we.sessionId===L.dataset.id):et.length;Re<0&&(Re=et.length);let bo=Re>0?et[Re-1]:null,ho=Re<et.length?et[Re]:null,rs=Un(bo?pt(bo):null,ho?pt(ho):null);We.forEach((we,ls)=>{let Tn=rs+ls*.001;if(ie==="team")wt(String(we.sessionId),w,Tn);else{let ds={column:we.kanbanColumn,position:we.kanbanPosition};we.kanbanColumn=w,we.kanbanPosition=Tn,ct(we,w,Tn,ds)}}),q="",Z();return}let C=Q.sessions.get(u)??Fe.get(u);if(!C||C.status==="closed"&&w!=="done")return;let F=(se.get(w)??[]).filter(We=>We.sessionId!==u),N=L?F.findIndex(We=>We.sessionId===L.dataset.id):F.length;N<0&&(N=F.length);let ee=N>0?F[N-1]:null,me=N<F.length?F[N]:null,ze=Un(ee?pt(ee):null,me?pt(me):null);if(ie==="team"){wt(String(C.sessionId),w,ze),q="",Z();return}let Sn={column:C.kanbanColumn,position:C.kanbanPosition};C.kanbanColumn=w,C.kanbanPosition=ze,q="",Z(),ct(C,w,ze,Sn)}),T.addEventListener("dragend",()=>{X=null,ce=null,Le=null,$n(),q="",Z()}),g.addEventListener("click",l=>{l.target===g&&g.close()}),g.addEventListener("close",()=>{g.innerHTML=""}),R.addEventListener("click",l=>{l.target===R&&R.close()}),R.addEventListener("close",()=>{R.innerHTML=""}),a.addEventListener("change",()=>{let l=P().filter(c=>c.status!=="closed");for(let c of l)a.checked?$.add(c.sessionId):$.delete(c.sessionId);Z()}),v.addEventListener("click",()=>{$.clear(),Z()}),p.addEventListener("click",async()=>{let l=[...$];if(l.length===0||!confirm(t("sessions.closeBulkConfirm",{count:l.length})))return;p.disabled=!0,v.disabled=!0;let c=p.textContent,f=0,u=0,b=[...l];p.textContent=`0/${l.length}`;async function w(){for(;b.length;){let L=b.shift();try{let C=await fetch(`/api/sessions/${encodeURIComponent(L)}/close`,{method:"POST"}),F=await C.json().catch(()=>({}));(!C.ok||F?.ok===!1)&&(u+=1)}catch{u+=1}finally{f+=1,p.textContent=`${f}/${l.length}`}}}await Promise.all(Array.from({length:Math.min(6,l.length)},()=>w())),p.textContent=c,p.disabled=!1,v.disabled=!1,$.clear(),Z(),u>0&&alert(`Failed: ${u}/${l.length}`)}),k.querySelectorAll("th[data-sort]").forEach(l=>{l.addEventListener("click",()=>{let c=l.dataset.sort;D===c?m=m==="asc"?"desc":"asc":(D=c,m=c==="spawnedAt"||c==="lastMessageAt"?"desc":"asc"),Z()})}),o.addEventListener("input",Z),Q.on(Z);let is=setInterval(()=>{if(!document.body.contains(T)){clearInterval(is);return}y==="kanban"&&ie==="team"&&(q="",Z())},3e4);Z(),Ke().then(Z)}function ni(){return`<section class="page">
349
+ </div>`;let Ke=O.querySelector("#land-apply"),Zt=O.querySelector("#land-discard");Ke.onclick=async()=>{Ke.disabled=!0,Zt.disabled=!0;let tt=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/sandbox-land/apply`,{method:"POST"}),Pe=await tt.json().catch(()=>({}));O.innerHTML=Pe.ok?`<p>\u2705 ${t("sessions.landApplied")}: ${Pe.files} files (+${Pe.insertions}/-${Pe.deletions}) \u2192 <code>${i(String(Pe.workingDir??""))}</code></p>`:`<p>\u274C ${t("sessions.landFailed")}: ${i(Pe.error??String(tt.status))}</p>`},Zt.onclick=async()=>{await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/sandbox-land/discard`,{method:"POST"}),O.innerHTML=`<p>\u{1F5D1} ${t("sessions.landDiscarded")}</p>`}}catch(ee){O.innerHTML=`<p>${t("sessions.landUnavailable")}: ${i(String(ee))}</p>`,F.disabled=!1}}),s.showModal()}n.addEventListener("click",l=>{let c=l.target;if(c.classList.contains("row-select")){let y=c.closest("tr[data-id]");if(!y)return;c.checked?T.add(y.dataset.id):T.delete(y.dataset.id),pe(N());return}let g=c.closest("td");if(g&&g.querySelector(".row-select"))return;let m=c.closest("tr[data-id]");if(!m)return;let b=Q.sessions.get(m.dataset.id);b&&Qt(b)}),E.addEventListener("click",l=>{let c=l.target,g=c.closest("button[data-move-col]");if(g){Dt(g.dataset.moveCol,Number(g.dataset.dir));return}let m=c.closest(".session-card[data-id]");if(!m)return;let b=Q.sessions.get(m.dataset.id);if(!b)return;let y=c.closest("button[data-action]");if(y){let M=y.dataset.action;M==="details"?Qt(b):M==="write-link"?uo(b,y):M==="locate"?ya(b,y):M==="close"&&va(b,y).then(R=>{R&&(T.delete(b.sessionId),Z())});return}c.closest("a, button, input, label")||(T.has(b.sessionId)?T.delete(b.sessionId):T.add(b.sessionId),m.classList.toggle("selected",T.has(b.sessionId)),m.setAttribute("aria-pressed",String(T.has(b.sessionId))),pe(N().filter(M=>M.status!=="closed")))}),E.addEventListener("dragstart",l=>{let g=l.target.closest(".session-board-column > header[draggable]")?.closest(".session-board-column");g?.dataset.col&&(D=g.dataset.col,g.classList.add("dragging"),l.dataTransfer&&(l.dataTransfer.effectAllowed="move",l.dataTransfer.setData("text/plain",D)))}),E.addEventListener("dragover",l=>{if(!D)return;l.preventDefault(),l.dataTransfer&&(l.dataTransfer.dropEffect="move");let c=l.target.closest(".session-board-column");E.querySelectorAll(".drag-over").forEach(g=>g.classList.remove("drag-over")),c&&c.dataset.col!==D&&c.classList.add("drag-over")}),E.addEventListener("drop",l=>{if(!D)return;l.preventDefault();let c=l.target.closest(".session-board-column"),g=D;D=null,c?.dataset.col&&it(g,c.dataset.col)}),E.addEventListener("dragend",()=>{D=null,E.querySelectorAll(".drag-over, .dragging").forEach(l=>l.classList.remove("drag-over","dragging"))}),H.forEach(l=>{l.addEventListener("click",()=>{let c=Rn(l.dataset.view)??"board";c!==v&&(v=c,Aa(window.localStorage,v),Z())})}),x.querySelectorAll("[data-groupby]").forEach(l=>{l.addEventListener("click",()=>{let c=l.dataset.groupby,g=c==="bot"?"bot":c==="team"?"team":"flow";g!==re&&(re=g,Pa(window.localStorage,g),q="",Z())})}),A.addEventListener("change",()=>{le=A.value;try{window.localStorage.setItem(Bn,le)}catch{}q="",Z()});function Xt(){De!==null&&(clearTimeout(De),De=null)}w.addEventListener("click",l=>{let c=l.target,g=c.closest(".kanban-card[data-id]");if(!g)return;let m=Q.sessions.get(g.dataset.id);if(!m)return;let b=c.closest("button[data-action]");if(b){b.dataset.action==="details"?Qt(m):b.dataset.action==="rename"?Pt(g,m):b.dataset.action==="history"&&Le(m);return}c.closest("a, button, input, label")||(Xt(),De=setTimeout(()=>{De=null,W(m)},220))}),w.addEventListener("dblclick",l=>{let c=l.target,g=c.closest(".kanban-card-title"),m=c.closest(".kanban-card[data-id]");if(!g||!m)return;Xt();let b=Q.sessions.get(m.dataset.id);b&&Pt(m,b)}),w.addEventListener("keydown",l=>{if(l.key!=="Enter"&&l.key!==" ")return;let c=l.target;if(!c.classList?.contains("kanban-card"))return;l.preventDefault();let g=Q.sessions.get(c.dataset.id);g&&W(g)}),w.addEventListener("dragstart",l=>{if(re==="bot")return;let c=l.target,g=c.closest(".kanban-cluster > header[draggable]");if(g){let b=g.closest(".kanban-cluster"),y=b.closest(".kanban-column")?.dataset.col;if(!b.dataset.chat||!y)return;Xt(),ue=b.dataset.chat,Me=y,b.classList.add("dragging"),l.dataTransfer&&(l.dataTransfer.effectAllowed="move",l.dataTransfer.setData("text/plain",`cluster:${ue}`));return}let m=c.closest(".kanban-card[data-id]");m&&(Xt(),X=m.dataset.id,m.classList.add("dragging"),l.dataTransfer&&(l.dataTransfer.effectAllowed="move",l.dataTransfer.setData("text/plain",X)))}),w.addEventListener("dragover",l=>{if(!X&&!ue)return;l.preventDefault(),l.dataTransfer&&(l.dataTransfer.dropEffect="move");let c=l.target.closest(".kanban-column");w.querySelectorAll(".drag-over").forEach(g=>g.classList.remove("drag-over")),w.querySelectorAll(".drop-before").forEach(g=>g.classList.remove("drop-before")),c&&(c.classList.add("drag-over"),Lt(c,l.clientY)?.classList.add("drop-before"))}),w.addEventListener("drop",l=>{let c=ue,g=Me,m=X;if(!m&&!c)return;l.preventDefault(),X=null,ue=null,Me=null,En();let b=l.target.closest(".kanban-column"),y=b?.dataset.col;if(!b||!y)return;let M=Lt(b,l.clientY);if(c&&g){let Ke=(se.get(g)??[]).filter(ye=>String(ye.chatId)===c).filter(ye=>!(ye.status==="closed"&&y!=="done"));if(!Ke.length)return;let Zt=new Set(Ke.map(ye=>ye.sessionId)),tt=(se.get(y)??[]).filter(ye=>!Zt.has(ye.sessionId)),Pe=M?tt.findIndex(ye=>ye.sessionId===M.dataset.id):tt.length;Pe<0&&(Pe=tt.length);let ka=Pe>0?tt[Pe-1]:null,$a=Pe<tt.length?tt[Pe]:null,bs=zn(ka?gt(ka):null,$a?gt($a):null);Ke.forEach((ye,hs)=>{let Hn=bs+hs*.001;if(re==="team")$t(String(ye.sessionId),y,Hn);else{let ws={column:ye.kanbanColumn,position:ye.kanbanPosition};ye.kanbanColumn=y,ye.kanbanPosition=Hn,mt(ye,y,Hn,ws)}}),q="",Z();return}let R=Q.sessions.get(m)??Ge.get(m);if(!R||R.status==="closed"&&y!=="done")return;let F=(se.get(y)??[]).filter(Ke=>Ke.sessionId!==m),O=M?F.findIndex(Ke=>Ke.sessionId===M.dataset.id):F.length;O<0&&(O=F.length);let ee=O>0?F[O-1]:null,ge=O<F.length?F[O]:null,ze=zn(ee?gt(ee):null,ge?gt(ge):null);if(re==="team"){$t(String(R.sessionId),y,ze),q="",Z();return}let xn={column:R.kanbanColumn,position:R.kanbanPosition};R.kanbanColumn=y,R.kanbanPosition=ze,q="",Z(),mt(R,y,ze,xn)}),w.addEventListener("dragend",()=>{X=null,ue=null,Me=null,En(),q="",Z()}),u.addEventListener("click",l=>{l.target===u&&u.close()}),u.addEventListener("close",()=>{u.innerHTML=""}),S.addEventListener("click",l=>{l.target===S&&S.close()}),S.addEventListener("close",()=>{S.innerHTML=""}),o.addEventListener("change",()=>{let l=N().filter(c=>c.status!=="closed");for(let c of l)o.checked?T.add(c.sessionId):T.delete(c.sessionId);Z()}),k.addEventListener("click",()=>{T.clear(),Z()}),p.addEventListener("click",async()=>{let l=[...T];if(l.length===0||!confirm(t("sessions.closeBulkConfirm",{count:l.length})))return;p.disabled=!0,k.disabled=!0;let c=p.textContent,g=0,m=0,b=[...l];p.textContent=`0/${l.length}`;async function y(){for(;b.length;){let M=b.shift();try{let R=await fetch(`/api/sessions/${encodeURIComponent(M)}/close`,{method:"POST"}),F=await R.json().catch(()=>({}));(!R.ok||F?.ok===!1)&&(m+=1)}catch{m+=1}finally{g+=1,p.textContent=`${g}/${l.length}`}}}await Promise.all(Array.from({length:Math.min(6,l.length)},()=>y())),p.textContent=c,p.disabled=!1,k.disabled=!1,T.clear(),Z(),m>0&&alert(`Failed: ${m}/${l.length}`)}),$.querySelectorAll("th[data-sort]").forEach(l=>{l.addEventListener("click",()=>{let c=l.dataset.sort;P===c?f=f==="asc"?"desc":"asc":(P=c,f=c==="spawnedAt"||c==="lastMessageAt"?"desc":"asc"),Z()})}),a.addEventListener("input",Z),Q.on(Z);let gs=setInterval(()=>{if(!document.body.contains(w)){clearInterval(gs);return}v==="kanban"&&re==="team"&&(q="",Z())},3e4);Z(),Je().then(Z)}function ui(){return`<section class="page">
344
350
  <div class="page-heading">
345
351
  <div>
346
352
  <p class="eyebrow">${t("nav.schedules")}</p>
@@ -365,21 +371,21 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
365
371
  </tr></thead>
366
372
  <tbody id="schedules-tbody"></tbody>
367
373
  </table>
368
- </section>`}function la(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function da(e){e.innerHTML=ni();let n=e.querySelector("#schedules-tbody"),o=e.querySelector("#sched-filters");function s(){let i=new FormData(o),d=(i.get("q")??"").toLowerCase(),p=i.get("kind"),v=!!i.get("enabled");return[...Q.schedules.values()].filter(k=>!p||k.parsed?.kind===p).filter(k=>!v||k.enabled).filter(k=>!d||JSON.stringify(k).toLowerCase().includes(d)).sort((k,I)=>{if(k.enabled!==I.enabled)return k.enabled?-1:1;let T=k.nextRunAt?Date.parse(k.nextRunAt):1/0,g=I.nextRunAt?Date.parse(I.nextRunAt):1/0;return T-g})}function a(){n.innerHTML=s().map(i=>`<tr data-id="${r(i.id)}">
369
- <td>${r(i.name??i.id)}</td>
370
- <td>${r(i.botName??i.larkAppId??"-")}</td>
371
- <td><code>${r(i.parsed?.display??"?")}</code></td>
372
- <td>${i.deliver==="new-topic"?`\u{1F195} ${t("schedules.deliveryNewTopic")}`:i.deliver==="local"?`\u{1F515} ${t("schedules.deliveryLocal")}`:t("schedules.deliveryOrigin")}</td>
373
- <td>${la(i.nextRunAt)}</td>
374
- <td>${la(i.lastRunAt)} ${i.lastStatus==="error"?"\u26A0\uFE0F":""}</td>
375
- <td>${i.repeat?`${i.repeat.completed}/${i.repeat.times??"\u221E"}`:"\u2014"}</td>
376
- <td>${i.enabled?"\u2713":"\u2717"}</td>
374
+ </section>`}function fo(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function go(e){e.innerHTML=ui();let n=e.querySelector("#schedules-tbody"),a=e.querySelector("#sched-filters");function s(){let r=new FormData(a),d=(r.get("q")??"").toLowerCase(),p=r.get("kind"),k=!!r.get("enabled");return[...Q.schedules.values()].filter($=>!p||$.parsed?.kind===p).filter($=>!k||$.enabled).filter($=>!d||JSON.stringify($).toLowerCase().includes(d)).sort(($,E)=>{if($.enabled!==E.enabled)return $.enabled?-1:1;let w=$.nextRunAt?Date.parse($.nextRunAt):1/0,u=E.nextRunAt?Date.parse(E.nextRunAt):1/0;return w-u})}function o(){n.innerHTML=s().map(r=>`<tr data-id="${i(r.id)}">
375
+ <td>${i(r.name??r.id)}</td>
376
+ <td>${i(r.botName??r.larkAppId??"-")}</td>
377
+ <td><code>${i(r.parsed?.display??"?")}</code></td>
378
+ <td>${r.deliver==="new-topic"?`\u{1F195} ${t("schedules.deliveryNewTopic")}`:r.deliver==="local"?`\u{1F515} ${t("schedules.deliveryLocal")}`:t("schedules.deliveryOrigin")}</td>
379
+ <td>${fo(r.nextRunAt)}</td>
380
+ <td>${fo(r.lastRunAt)} ${r.lastStatus==="error"?"\u26A0\uFE0F":""}</td>
381
+ <td>${r.repeat?`${r.repeat.completed}/${r.repeat.times??"\u221E"}`:"\u2014"}</td>
382
+ <td>${r.enabled?"\u2713":"\u2717"}</td>
377
383
  <td class="actions-cell">
378
384
  <button data-op="run" type="button">${t("schedules.runNow")}</button>
379
- ${i.enabled?`<button data-op="pause" type="button">${t("schedules.pause")}</button>`:`<button data-op="resume" type="button">${t("schedules.resume")}</button>`}
380
- ${i.deliver==="local"?"":`<button data-op="delivery" type="button">${i.deliver==="new-topic"?t("schedules.useOrigin"):t("schedules.useNewTopic")}</button>`}
385
+ ${r.enabled?`<button data-op="pause" type="button">${t("schedules.pause")}</button>`:`<button data-op="resume" type="button">${t("schedules.resume")}</button>`}
386
+ ${r.deliver==="local"?"":`<button data-op="delivery" type="button">${r.deliver==="new-topic"?t("schedules.useOrigin"):t("schedules.useNewTopic")}</button>`}
381
387
  </td>
382
- </tr>`).join("")||`<tr><td colspan="9" class="empty">${t("schedules.empty")}</td></tr>`}n.addEventListener("click",async i=>{let d=i.target.closest("button[data-op]");if(!d)return;let p=d.closest("tr[data-id]");if(!p)return;let v=p.dataset.id,k=d.dataset.op;d.disabled=!0;let I=d.textContent;d.textContent="...";try{let T=await fetch(`/api/schedules/${encodeURIComponent(v)}/${k}`,{method:"POST"}),g=await T.json().catch(()=>({}));(!T.ok||g.ok===!1)&&alert(`Failed: ${T.status} ${g?.error??""}`.trim())}catch(T){alert("Network error: "+T)}finally{d.disabled=!1,d.textContent=I}}),o.addEventListener("input",a),Q.on(a),a()}var He={chats:[],bots:[]};function oi(){return`<section class="page">
388
+ </tr>`).join("")||`<tr><td colspan="9" class="empty">${t("schedules.empty")}</td></tr>`}n.addEventListener("click",async r=>{let d=r.target.closest("button[data-op]");if(!d)return;let p=d.closest("tr[data-id]");if(!p)return;let k=p.dataset.id,$=d.dataset.op;d.disabled=!0;let E=d.textContent;d.textContent="...";try{let w=await fetch(`/api/schedules/${encodeURIComponent(k)}/${$}`,{method:"POST"}),u=await w.json().catch(()=>({}));(!w.ok||u.ok===!1)&&alert(`Failed: ${w.status} ${u?.error??""}`.trim())}catch(w){alert("Network error: "+w)}finally{d.disabled=!1,d.textContent=E}}),a.addEventListener("input",o),Q.on(o),o()}var Ae={chats:[],bots:[]};function pi(){return`<section class="page">
383
389
  <div class="page-heading">
384
390
  <div>
385
391
  <p class="eyebrow">${t("nav.groups")}</p>
@@ -393,7 +399,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
393
399
  <button type="button" id="g-refresh">${t("groups.refresh")}</button>
394
400
  <button type="button" id="g-create" class="primary">${t("groups.create")}</button>
395
401
  </form>
396
- <div id="g-loading">${St()}</div>
402
+ <div id="g-loading">${lt()}</div>
397
403
  <div class="table-scroll matrix-scroll" id="g-table-wrap" hidden>
398
404
  <table>
399
405
  <thead id="g-head"></thead>
@@ -401,12 +407,12 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
401
407
  </table>
402
408
  </div>
403
409
  <dialog id="g-drawer"></dialog>
404
- </section>`}async function Tt(){He=await(await fetch("/api/groups")).json()}async function ai(){return(await fetch("/api/groups")).json()}function si(e,n){if(n.size===0)return!0;let o=e?.memberBots??[];for(let s of n)if(!o.some(a=>a.larkAppId===s&&a.inChat))return!1;return!0}function ca(e,n){return e.filter(o=>!n||!n.has(o.larkAppId)).map(o=>`
410
+ </section>`}async function Mt(){Ae=await(await fetch("/api/groups")).json()}async function mi(){return(await fetch("/api/groups")).json()}function fi(e,n){if(n.size===0)return!0;let a=e?.memberBots??[];for(let s of n)if(!a.some(o=>o.larkAppId===s&&o.inChat))return!1;return!0}function bo(e,n){return e.filter(a=>!n||!n.has(a.larkAppId)).map(a=>`
405
411
  <label class="checkbox-row">
406
- <input type="checkbox" name="bot" value="${r(o.larkAppId)}">
407
- ${r(o.botName??o.larkAppId)} <small>(${r(o.larkAppId)})</small>
412
+ <input type="checkbox" name="bot" value="${i(a.larkAppId)}">
413
+ ${i(a.botName??a.larkAppId)} <small>(${i(a.larkAppId)})</small>
408
414
  </label>
409
- `).join("")}async function ua(e){e.innerHTML=oi();let n=e.querySelector("#g-head"),o=e.querySelector("#g-body"),s=e.querySelector("#g-filters"),a=e.querySelector("#g-refresh"),i=e.querySelector("#g-drawer");a.onclick=async()=>{a.disabled=!0;try{await Tt(),g()}finally{a.disabled=!1}};let d=e.querySelector("#g-create");d.onclick=()=>k();let p=e.querySelector("#g-loading"),v=e.querySelector("#g-table-wrap");try{await Tt()}finally{p.remove(),v.hidden=!1}function k(){let A=He.bots;if(A.length===0){alert(t("groups.noBotsOnline"));return}i.innerHTML=`
415
+ `).join("")}async function ho(e){e.innerHTML=pi();let n=e.querySelector("#g-head"),a=e.querySelector("#g-body"),s=e.querySelector("#g-filters"),o=e.querySelector("#g-refresh"),r=e.querySelector("#g-drawer");o.onclick=async()=>{o.disabled=!0;try{await Mt(),u()}finally{o.disabled=!1}};let d=e.querySelector("#g-create");d.onclick=()=>$();let p=e.querySelector("#g-loading"),k=e.querySelector("#g-table-wrap");try{await Mt()}finally{p.remove(),k.hidden=!1}function $(){let x=Ae.bots;if(x.length===0){alert(t("groups.noBotsOnline"));return}r.innerHTML=`
410
416
  <article>
411
417
  <header><h3>${t("groups.createTitle")}</h3></header>
412
418
  <p>${t("groups.createHelp")}</p>
@@ -422,75 +428,75 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
422
428
  </label>
423
429
  <fieldset>
424
430
  <legend>${t("groups.botPicker")}</legend>
425
- ${ca(A)}
431
+ ${bo(x)}
426
432
  </fieldset>
427
433
  <div class="actions">
428
434
  <button type="submit" class="primary">${t("groups.createSubmit")}</button>
429
435
  <button type="button" id="g-create-cancel">${t("groups.cancel")}</button>
430
436
  </div>
431
437
  </form>
432
- </article>`,i.showModal(),i.querySelector("#g-create-cancel").onclick=()=>i.close(),i.querySelector("#g-createform").onsubmit=async E=>{E.preventDefault();let $=new FormData(E.target),D=($.get("name")??"").trim(),m=($.get("bindWorkingDir")??"").trim(),y=$.getAll("bot");if(y.length===0){alert("Pick at least one bot.");return}let S=E.target.querySelector("button[type=submit]");S&&(S.disabled=!0,S.textContent="Creating...");try{let H=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:D||void 0,larkAppIds:y,bindWorkingDir:m||void 0})}),B=await H.json();if(B.ok&&B.chatId){I(B);let j=Array.isArray(B.invalidBotIds)?B.invalidBotIds:[],q=y.filter(X=>!j.includes(X)),oe=new Set(q);typeof B.creator=="string"&&B.creator&&oe.add(B.creator),O(B.chatId,D||B.chatId,q,B.creator),g(),M(B.chatId,oe).catch(()=>{})}else alert(`Failed: ${B.error??H.status}`),i.close()}catch(H){alert("Network error: "+H),i.close()}};function O(E,$,D,m){let y=new Set(D);m&&y.add(m);let S=He.bots.map(B=>({larkAppId:B.larkAppId,botName:B.botName,inChat:y.has(B.larkAppId),oncallChat:null})),H={chatId:E,name:$,ownerId:m??null,memberBots:S};He.chats=[H,...He.chats.filter(B=>B.chatId!==E)]}async function M(E,$){let D=[600,1200,1200,1200,1200,1200];for(let m of D){await new Promise(H=>setTimeout(H,m));let y;try{y=await ai()}catch{continue}let S=(y.chats??[]).find(H=>H.chatId===E);if(S&&si(S,$)){He=y,g();return}}}}function I(A){let O=String(A.chatId),M=typeof A.shareLink=="string"&&A.shareLink?A.shareLink:`https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(O)}`,E=A.invalidBotIds??[],$=A.invalidUserIds??[],D=A.autoInvitedOpenId,m=!!A.autoInviteRejected,y=A.ownerTransferredTo,S=A.transferError,H=A.notifyMessageId,B=A.notifyError,j=Array.isArray(A.oncallBindings)?A.oncallBindings:[],q=j.filter(se=>se?.ok).length,oe=j.filter(se=>!se?.ok),X=j.length>0?oe.length===0?`<p class="hint-ok">\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1A<code>${r(A.bindResolvedPath??"")}</code>\uFF08${q}/${j.length} bots\uFF09</p>`:`<p class="hint-warn">\u76EE\u5F55\u7ED1\u5B9A\u90E8\u5206\u5931\u8D25\uFF1A\u6210\u529F ${q}/${j.length}\u3002${oe.map(se=>`<br><code>${r(se.larkAppId??"?")}</code>: ${r(se.error??"unknown")}`).join("")}</p>`:"",ae;if(D){let se=y?"<br><small>\u7FA4\u4E3B\u5DF2\u4ECE\u673A\u5668\u4EBA\u8F6C\u8BA9\u7ED9\u4F60\u3002</small>":S?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08${r(S)}\uFF09\uFF0C\u4F60\u73B0\u5728\u662F\u6210\u5458\u4F46\u7FA4\u4E3B\u4ECD\u662F\u673A\u5668\u4EBA\u3002</small>`:"",ie=H?`<br><small>\u673A\u5668\u4EBA\u5DF2\u5728\u7FA4\u91CC @ \u4E86\u4F60\uFF08\u6D88\u606F id <code>${r(H)}</code>\uFF09\uFF0C\u770B\u98DE\u4E66\u901A\u77E5\u5C31\u80FD\u8FDB\u7FA4\u3002</small>`:B?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8 @ \u901A\u77E5\u5931\u8D25\uFF08${r(B)}\uFF09\uFF0C\u65B0\u7FA4\u53EF\u80FD\u4E0D\u4F1A\u4E3B\u52A8\u51FA\u73B0\u5728\u4F60\u4FA7\u8FB9\u680F\uFF0C\u5EFA\u8BAE\u4ECE\u4E0B\u9762\u6309\u94AE\u8DF3\u8FDB\u53BB\u3002</small>`:"";ae=`<p class="hint-ok">\u5DF2\u81EA\u52A8\u9080\u8BF7\u4F60\uFF08<code>${r(D)}</code>\uFF09\u4F5C\u4E3A\u6210\u5458\u3002${se}${ie}</p>`}else m?ae='<p class="hint-warn">\u98DE\u4E66\u62D2\u7EDD\u4E86\u81EA\u52A8\u9080\u8BF7\uFF08\u4F60\u7684 open_id \u5728\u521B\u5EFA\u8005 bot \u7684 scope \u4E0B\u4E0D\u53EF\u7528\uFF09\u3002<strong>\u4F60\u76EE\u524D\u4E0D\u662F\u65B0\u7FA4\u6210\u5458</strong>\uFF0C\u9700\u8981\u8BA9\u7FA4\u91CC\u7684\u67D0\u4E2A\u673A\u5668\u4EBA\u624B\u52A8\u628A\u4F60\u52A0\u8FDB\u6765\u3002</p>':ae='<p class="hint-warn">\u6CA1\u5728 dashboard \u7F13\u5B58\u91CC\u627E\u5230 ownerOpenId\uFF0C<strong>\u6CA1\u6709\u81EA\u52A8\u9080\u8BF7\u4F60</strong>\u3002\u70B9\u5F00\u4E0B\u9762\u94FE\u63A5\u524D\uFF0C\u5148\u8BA9\u7FA4\u91CC\u4EFB\u4E00\u673A\u5668\u4EBA\u624B\u52A8\u628A\u4F60\u52A0\u8FDB\u53BB\u3002</p>';let Ae=[E.length?`<li>\u65E0\u6548 bot id: <code>${E.map(r).join(", ")}</code></li>`:"",$.length?`<li>\u65E0\u6548\u7528\u6237 open_id: <code>${$.map(r).join(", ")}</code></li>`:""].filter(Boolean).join("");i.innerHTML=`
438
+ </article>`,r.showModal(),r.querySelector("#g-create-cancel").onclick=()=>r.close(),r.querySelector("#g-createform").onsubmit=async H=>{H.preventDefault();let T=new FormData(H.target),P=(T.get("name")??"").trim(),f=(T.get("bindWorkingDir")??"").trim(),v=T.getAll("bot");if(v.length===0){alert("Pick at least one bot.");return}let I=H.target.querySelector("button[type=submit]");I&&(I.disabled=!0,I.textContent="Creating...");try{let D=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:P||void 0,larkAppIds:v,bindWorkingDir:f||void 0})}),B=await D.json();if(B.ok&&B.chatId){E(B);let U=Array.isArray(B.invalidBotIds)?B.invalidBotIds:[],q=v.filter(X=>!U.includes(X)),ae=new Set(q);typeof B.creator=="string"&&B.creator&&ae.add(B.creator),A(B.chatId,P||B.chatId,q,B.creator),u(),L(B.chatId,ae).catch(()=>{})}else alert(`Failed: ${B.error??D.status}`),r.close()}catch(D){alert("Network error: "+D),r.close()}};function A(H,T,P,f){let v=new Set(P);f&&v.add(f);let I=Ae.bots.map(B=>({larkAppId:B.larkAppId,botName:B.botName,inChat:v.has(B.larkAppId),oncallChat:null})),D={chatId:H,name:T,ownerId:f??null,memberBots:I};Ae.chats=[D,...Ae.chats.filter(B=>B.chatId!==H)]}async function L(H,T){let P=[600,1200,1200,1200,1200,1200];for(let f of P){await new Promise(D=>setTimeout(D,f));let v;try{v=await mi()}catch{continue}let I=(v.chats??[]).find(D=>D.chatId===H);if(I&&fi(I,T)){Ae=v,u();return}}}}function E(x){let A=String(x.chatId),L=typeof x.shareLink=="string"&&x.shareLink?x.shareLink:`https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(A)}`,H=x.invalidBotIds??[],T=x.invalidUserIds??[],P=x.autoInvitedOpenId,f=!!x.autoInviteRejected,v=x.ownerTransferredTo,I=x.transferError,D=x.notifyMessageId,B=x.notifyError,U=Array.isArray(x.oncallBindings)?x.oncallBindings:[],q=U.filter(se=>se?.ok).length,ae=U.filter(se=>!se?.ok),X=U.length>0?ae.length===0?`<p class="hint-ok">\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1A<code>${i(x.bindResolvedPath??"")}</code>\uFF08${q}/${U.length} bots\uFF09</p>`:`<p class="hint-warn">\u76EE\u5F55\u7ED1\u5B9A\u90E8\u5206\u5931\u8D25\uFF1A\u6210\u529F ${q}/${U.length}\u3002${ae.map(se=>`<br><code>${i(se.larkAppId??"?")}</code>: ${i(se.error??"unknown")}`).join("")}</p>`:"",oe;if(P){let se=v?"<br><small>\u7FA4\u4E3B\u5DF2\u4ECE\u673A\u5668\u4EBA\u8F6C\u8BA9\u7ED9\u4F60\u3002</small>":I?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08${i(I)}\uFF09\uFF0C\u4F60\u73B0\u5728\u662F\u6210\u5458\u4F46\u7FA4\u4E3B\u4ECD\u662F\u673A\u5668\u4EBA\u3002</small>`:"",re=D?`<br><small>\u673A\u5668\u4EBA\u5DF2\u5728\u7FA4\u91CC @ \u4E86\u4F60\uFF08\u6D88\u606F id <code>${i(D)}</code>\uFF09\uFF0C\u770B\u98DE\u4E66\u901A\u77E5\u5C31\u80FD\u8FDB\u7FA4\u3002</small>`:B?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8 @ \u901A\u77E5\u5931\u8D25\uFF08${i(B)}\uFF09\uFF0C\u65B0\u7FA4\u53EF\u80FD\u4E0D\u4F1A\u4E3B\u52A8\u51FA\u73B0\u5728\u4F60\u4FA7\u8FB9\u680F\uFF0C\u5EFA\u8BAE\u4ECE\u4E0B\u9762\u6309\u94AE\u8DF3\u8FDB\u53BB\u3002</small>`:"";oe=`<p class="hint-ok">\u5DF2\u81EA\u52A8\u9080\u8BF7\u4F60\uFF08<code>${i(P)}</code>\uFF09\u4F5C\u4E3A\u6210\u5458\u3002${se}${re}</p>`}else f?oe='<p class="hint-warn">\u98DE\u4E66\u62D2\u7EDD\u4E86\u81EA\u52A8\u9080\u8BF7\uFF08\u4F60\u7684 open_id \u5728\u521B\u5EFA\u8005 bot \u7684 scope \u4E0B\u4E0D\u53EF\u7528\uFF09\u3002<strong>\u4F60\u76EE\u524D\u4E0D\u662F\u65B0\u7FA4\u6210\u5458</strong>\uFF0C\u9700\u8981\u8BA9\u7FA4\u91CC\u7684\u67D0\u4E2A\u673A\u5668\u4EBA\u624B\u52A8\u628A\u4F60\u52A0\u8FDB\u6765\u3002</p>':oe='<p class="hint-warn">\u6CA1\u5728 dashboard \u7F13\u5B58\u91CC\u627E\u5230 ownerOpenId\uFF0C<strong>\u6CA1\u6709\u81EA\u52A8\u9080\u8BF7\u4F60</strong>\u3002\u70B9\u5F00\u4E0B\u9762\u94FE\u63A5\u524D\uFF0C\u5148\u8BA9\u7FA4\u91CC\u4EFB\u4E00\u673A\u5668\u4EBA\u624B\u52A8\u628A\u4F60\u52A0\u8FDB\u53BB\u3002</p>';let De=[H.length?`<li>\u65E0\u6548 bot id: <code>${H.map(i).join(", ")}</code></li>`:"",T.length?`<li>\u65E0\u6548\u7528\u6237 open_id: <code>${T.map(i).join(", ")}</code></li>`:""].filter(Boolean).join("");r.innerHTML=`
433
439
  <article>
434
440
  <header><h3>${t("groups.successTitle")}</h3></header>
435
- <p><b>chatId:</b> <code>${r(O)}</code> <button type="button" data-copy="${r(O)}">${t("sessions.copy")}</button></p>
436
- <p><b>\u521B\u5EFA\u8005:</b> <code>${r(A.creator??"?")}</code></p>
437
- ${ae}
441
+ <p><b>chatId:</b> <code>${i(A)}</code> <button type="button" data-copy="${i(A)}">${t("sessions.copy")}</button></p>
442
+ <p><b>\u521B\u5EFA\u8005:</b> <code>${i(x.creator??"?")}</code></p>
443
+ ${oe}
438
444
  ${X}
439
- ${Ae?`<ul>${Ae}</ul>`:""}
445
+ ${De?`<ul>${De}</ul>`:""}
440
446
  <div class="actions">
441
- <a class="btn-link primary" href="${M}" target="_blank" rel="noopener">${t("groups.openGroup")}</a>
447
+ <a class="btn-link primary" href="${L}" target="_blank" rel="noopener">${t("groups.openGroup")}</a>
442
448
  <button type="button" id="g-create-close">${t("sessions.dismiss")}</button>
443
449
  </div>
444
- </article>`,i.querySelectorAll("[data-copy]").forEach(se=>{se.onclick=()=>{navigator.clipboard.writeText(se.dataset.copy??""),se.textContent=t("sessions.copied"),setTimeout(()=>{se.textContent=t("sessions.copy")},800)}}),i.querySelector("#g-create-close").onclick=()=>i.close()}function T(){n.innerHTML=`<tr>
450
+ </article>`,r.querySelectorAll("[data-copy]").forEach(se=>{se.onclick=()=>{navigator.clipboard.writeText(se.dataset.copy??""),se.textContent=t("sessions.copied"),setTimeout(()=>{se.textContent=t("sessions.copy")},800)}}),r.querySelector("#g-create-close").onclick=()=>r.close()}function w(){n.innerHTML=`<tr>
445
451
  <th>${t("groups.chat")}</th>
446
- ${He.bots.map(A=>`<th>${r(A.botName??A.larkAppId)}</th>`).join("")}
452
+ ${Ae.bots.map(x=>`<th>${i(x.botName??x.larkAppId)}</th>`).join("")}
447
453
  <th>${t("groups.actions")}</th>
448
- </tr>`}function g(){T();let A=new FormData(s),O=(A.get("q")??"").toLowerCase(),M=!!A.get("missing"),E=He.chats.filter($=>!O||($.name??"").toLowerCase().includes(O)||$.chatId.toLowerCase().includes(O)||($.ownerId??"").toLowerCase().includes(O)).filter($=>!M||$.memberBots.some(D=>!D.inChat));if(E.length===0){o.innerHTML=`<tr><td colspan="${He.bots.length+2}" class="empty">${t("groups.empty")}</td></tr>`;return}o.innerHTML=E.map($=>`<tr data-chat="${r($.chatId)}">
454
+ </tr>`}function u(){w();let x=new FormData(s),A=(x.get("q")??"").toLowerCase(),L=!!x.get("missing"),H=Ae.chats.filter(T=>!A||(T.name??"").toLowerCase().includes(A)||T.chatId.toLowerCase().includes(A)||(T.ownerId??"").toLowerCase().includes(A)).filter(T=>!L||T.memberBots.some(P=>!P.inChat));if(H.length===0){a.innerHTML=`<tr><td colspan="${Ae.bots.length+2}" class="empty">${t("groups.empty")}</td></tr>`;return}a.innerHTML=H.map(T=>`<tr data-chat="${i(T.chatId)}">
449
455
  <td>
450
456
  <div class="g-chat-cell">
451
- ${on({chatId:$.chatId,name:$.name,avatarUrl:$.avatar,size:"sm"})}
457
+ ${ln({chatId:T.chatId,name:T.name,avatarUrl:T.avatar,size:"sm"})}
452
458
  <div class="g-chat-meta">
453
- <strong>${r($.name??$.chatId)}</strong><br>
454
- <small><code>${r($.chatId)}</code></small>
459
+ <strong>${i(T.name??T.chatId)}</strong><br>
460
+ <small><code>${i(T.chatId)}</code></small>
455
461
  </div>
456
462
  </div>
457
463
  </td>
458
- ${He.bots.map(D=>{let m=$.memberBots.find(H=>H.larkAppId===D.larkAppId),y=m?m.error?"!":m.inChat?"\u2713":"\u2717":"?";return`<td class="${m?m.error?"cell-error":m.inChat?"cell-in":"cell-out":"cell-unknown"}" title="${r(m?.error??"")}">${y}</td>`}).join("")}
464
+ ${Ae.bots.map(P=>{let f=T.memberBots.find(D=>D.larkAppId===P.larkAppId),v=f?f.error?"!":f.inChat?"\u2713":"\u2717":"?";return`<td class="${f?f.error?"cell-error":f.inChat?"cell-in":"cell-out":"cell-unknown"}" title="${i(f?.error??"")}">${v}</td>`}).join("")}
459
465
  <td>
460
466
  <button class="add-bots" type="button">${t("groups.addBots")}</button>
461
467
  <button class="manage-chat" type="button">${t("groups.manage")}</button>
462
468
  </td>
463
- </tr>`).join("")}g(),o.addEventListener("click",async A=>{let O=A.target.closest("button.add-bots");if(!O)return;let E=O.closest("tr[data-chat]").dataset.chat,$=He.chats.find(y=>y.chatId===E);if(!$)return;let D=new Set($.memberBots.filter(y=>y.inChat).map(y=>y.larkAppId));if(!He.bots.filter(y=>!D.has(y.larkAppId)).length){alert("All configured bots are already in this chat.");return}i.innerHTML=`
469
+ </tr>`).join("")}u(),a.addEventListener("click",async x=>{let A=x.target.closest("button.add-bots");if(!A)return;let H=A.closest("tr[data-chat]").dataset.chat,T=Ae.chats.find(v=>v.chatId===H);if(!T)return;let P=new Set(T.memberBots.filter(v=>v.inChat).map(v=>v.larkAppId));if(!Ae.bots.filter(v=>!P.has(v.larkAppId)).length){alert("All configured bots are already in this chat.");return}r.innerHTML=`
464
470
  <article>
465
- <header><h3>${t("groups.addBots")} \xB7 ${r($.name??$.chatId)}</h3></header>
471
+ <header><h3>${t("groups.addBots")} \xB7 ${i(T.name??T.chatId)}</h3></header>
466
472
  <p>${t("groups.createHelp")}</p>
467
473
  <form id="g-addform">
468
- ${ca(He.bots,D)}
474
+ ${bo(Ae.bots,P)}
469
475
  <div class="actions">
470
476
  <button type="submit" class="primary">${t("groups.addBots")}</button>
471
477
  <button type="button" id="g-cancel">${t("groups.cancel")}</button>
472
478
  </div>
473
479
  </form>
474
- </article>`,i.showModal(),i.querySelector("#g-cancel").onclick=()=>i.close(),i.querySelector("#g-addform").onsubmit=async y=>{y.preventDefault();let H=new FormData(y.target).getAll("bot");if(H.length===0){alert("Pick at least one bot.");return}try{let j=await(await fetch(`/api/groups/${encodeURIComponent(E)}/add-bots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:H})})).json();if(j.error==="no_proxy_bot")alert("No bot is currently in this chat \u2014 add one manually in Feishu first, then retry.");else if(j.result){let q=j.result.map(oe=>`${oe.id}: ${oe.ok?"OK":`failed (${oe.error??"unknown"})`}`).join(`
475
- `);alert(q),await Tt(),g()}else alert(`Unexpected response: ${JSON.stringify(j)}`)}catch(B){alert("Network error: "+B)}finally{i.close()}}}),o.addEventListener("click",async A=>{let O=A.target.closest("button.manage-chat");if(!O)return;let E=O.closest("tr[data-chat]").dataset.chat,$=He.chats.find(D=>D.chatId===E);$&&R($)});function R(A){let O=A.memberBots.filter(E=>E.inChat),M=typeof A.ownerId=="string"?A.ownerId:"";i.innerHTML=`
480
+ </article>`,r.showModal(),r.querySelector("#g-cancel").onclick=()=>r.close(),r.querySelector("#g-addform").onsubmit=async v=>{v.preventDefault();let D=new FormData(v.target).getAll("bot");if(D.length===0){alert("Pick at least one bot.");return}try{let U=await(await fetch(`/api/groups/${encodeURIComponent(H)}/add-bots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:D})})).json();if(U.error==="no_proxy_bot")alert("No bot is currently in this chat \u2014 add one manually in Feishu first, then retry.");else if(U.result){let q=U.result.map(ae=>`${ae.id}: ${ae.ok?"OK":`failed (${ae.error??"unknown"})`}`).join(`
481
+ `);alert(q),await Mt(),u()}else alert(`Unexpected response: ${JSON.stringify(U)}`)}catch(B){alert("Network error: "+B)}finally{r.close()}}}),a.addEventListener("click",async x=>{let A=x.target.closest("button.manage-chat");if(!A)return;let H=A.closest("tr[data-chat]").dataset.chat,T=Ae.chats.find(P=>P.chatId===H);T&&S(T)});function S(x){let A=x.memberBots.filter(H=>H.inChat),L=typeof x.ownerId=="string"?x.ownerId:"";r.innerHTML=`
476
482
  <article>
477
- <header><h3>${t("groups.manageTitle",{name:A.name??A.chatId})}</h3></header>
478
- <p><b>chatId:</b> <code>${r(A.chatId)}</code></p>
479
- <p><b>${t("groups.owner")}:</b> <code>${r(A.ownerId??t("common.unknown"))}</code></p>
483
+ <header><h3>${t("groups.manageTitle",{name:x.name??x.chatId})}</h3></header>
484
+ <p><b>chatId:</b> <code>${i(x.chatId)}</code></p>
485
+ <p><b>${t("groups.owner")}:</b> <code>${i(x.ownerId??t("common.unknown"))}</code></p>
480
486
 
481
487
  <fieldset>
482
488
  <legend>${t("groups.oncall")}</legend>
483
489
  <p><small>${t("groups.oncallHelp")}</small></p>
484
- ${O.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':O.map(E=>{let $=!!E.oncallChat,D=E.oncallChat?.workingDir??"";return`
485
- <div class="oncall-row" data-bot="${r(E.larkAppId)}">
490
+ ${A.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':A.map(H=>{let T=!!H.oncallChat,P=H.oncallChat?.workingDir??"";return`
491
+ <div class="oncall-row" data-bot="${i(H.larkAppId)}">
486
492
  <label class="checkbox-row">
487
- <input type="checkbox" data-action="toggle" ${$?"checked":""}>
488
- <strong>${r(E.botName??E.larkAppId)}</strong>
489
- <small>(${r(E.larkAppId)})</small>
493
+ <input type="checkbox" data-action="toggle" ${T?"checked":""}>
494
+ <strong>${i(H.botName??H.larkAppId)}</strong>
495
+ <small>(${i(H.larkAppId)})</small>
490
496
  </label>
491
497
  <div class="oncall-row-body">
492
498
  <input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
493
- value="${r(D)}" ${$?"":"disabled"}>
499
+ value="${i(P)}" ${T?"":"disabled"}>
494
500
  <button type="button" data-action="save">${t("groups.save")}</button>
495
501
  <span class="oncall-status" data-status></span>
496
502
  </div>
@@ -500,29 +506,29 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
500
506
 
501
507
  <fieldset>
502
508
  <legend>${t("groups.leaveTitle")}</legend>
503
- ${O.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':O.map(E=>`
509
+ ${A.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':A.map(H=>`
504
510
  <label class="checkbox-row">
505
- <input type="checkbox" name="leave-bot" value="${r(E.larkAppId)}">
506
- ${r(E.botName??E.larkAppId)}
507
- <small>${E.larkAppId===M?"\xB7 \u7FA4\u4E3B":""}</small>
511
+ <input type="checkbox" name="leave-bot" value="${i(H.larkAppId)}">
512
+ ${i(H.botName??H.larkAppId)}
513
+ <small>${H.larkAppId===L?"\xB7 \u7FA4\u4E3B":""}</small>
508
514
  </label>
509
515
  `).join("")}
510
516
  </fieldset>
511
517
 
512
518
  <div class="actions">
513
- <button id="g-leave-btn" type="button" ${O.length===0?"disabled":""}>${t("groups.leaveSelected")}</button>
514
- <button id="g-disband-btn" type="button" class="contrast" ${O.length===0?"disabled":""}>${t("groups.disband")}</button>
519
+ <button id="g-leave-btn" type="button" ${A.length===0?"disabled":""}>${t("groups.leaveSelected")}</button>
520
+ <button id="g-disband-btn" type="button" class="contrast" ${A.length===0?"disabled":""}>${t("groups.disband")}</button>
515
521
  </div>
516
522
  <p class="hint-warn"><small>${t("groups.dangerHint")}</small></p>
517
523
  <form method="dialog"><button>${t("sessions.dismiss")}</button></form>
518
- </article>`,i.showModal(),i.querySelectorAll(".oncall-row").forEach(E=>{let $=E.dataset.bot,D=E.querySelector("input[data-action=toggle]"),m=E.querySelector("input[data-input=workingDir]"),y=E.querySelector("button[data-action=save]"),S=E.querySelector("[data-status]");D.addEventListener("change",()=>{m.disabled=!D.checked,D.checked&&m.focus()}),y.addEventListener("click",async()=>{S.textContent="",S.className="oncall-status";let H=D.checked,B=m.value.trim();if(H&&!B){S.textContent=t("groups.needWorkingDir"),S.classList.add("hint-warn-inline");return}y.disabled=!0;try{let j=`/api/groups/${encodeURIComponent(A.chatId)}/oncall/${encodeURIComponent($)}`,q=H?await fetch(j,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({workingDir:B})}):await fetch(j,{method:"DELETE"}),oe=await q.json().catch(()=>({}));if(q.ok&&oe.ok){S.textContent=H?`\u2713 \u5DF2\u7ED1\u5B9A \u2192 ${oe.resolvedPath??B}`:"\u2713 \u5DF2\u89E3\u7ED1",S.classList.add("hint-ok");try{await Tt(),g()}catch{}}else S.textContent=`\u2717 ${oe.error??q.status}`,S.classList.add("hint-warn-inline")}catch(j){S.textContent=`\u2717 ${j?.message??j}`,S.classList.add("hint-warn-inline")}finally{y.disabled=!1}})}),i.querySelector("#g-leave-btn").onclick=async()=>{let E=[...i.querySelectorAll("input[name=leave-bot]:checked")].map($=>$.value);if(E.length===0){alert("\u81F3\u5C11\u9009\u4E00\u4E2A\u673A\u5668\u4EBA");return}if(confirm(`\u786E\u5B9A\u8BA9 ${E.length} \u4E2A\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A\uFF1F\u8BE5 bot \u5728\u6B64\u7FA4\u7684\u4F1A\u8BDD\u4F1A\u4E00\u5E76\u5173\u95ED\u3002`))try{let D=await(await fetch(`/api/groups/${encodeURIComponent(A.chatId)}/leave`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:E})})).json(),m=(D.result??[]).map(y=>{if(!y.ok)return`${y.larkAppId}: \u5931\u8D25 (${y.error??"unknown"})`;let S=y.closedSessions??[],H=S.filter(q=>!q.ok).length,B=S.length-H,j=S.length===0?"":H===0?`\uFF08\u5173\u95ED ${B} \u4E2A\u4F1A\u8BDD\uFF09`:`\uFF08\u5173\u95ED ${B} \u4E2A\uFF0C${H} \u4E2A\u5931\u8D25\uFF09`;return`${y.larkAppId}: OK${j}`}).join(`
519
- `);alert(m||`Unexpected: ${JSON.stringify(D)}`),await Tt(),g()}catch($){alert("Network error: "+$)}finally{i.close()}},i.querySelector("#g-disband-btn").onclick=async()=>{if(O.length===0||!confirm(`\u786E\u5B9A\u89E3\u6563\u7FA4\u804A\u300C${A.name??A.chatId}\u300D\uFF1F\u6B64\u64CD\u4F5C\u4E0D\u53EF\u6062\u590D\uFF0C\u672C\u7FA4\u6240\u6709\u673A\u5668\u4EBA\u4F1A\u8BDD\u4E5F\u4F1A\u4E00\u5E76\u5173\u95ED\u3002`))return;let E=[...O].sort((D,m)=>(m.larkAppId===M?1:0)-(D.larkAppId===M?1:0)),$=[];for(let D of E)try{let m=await fetch(`/api/groups/${encodeURIComponent(A.chatId)}/disband`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppId:D.larkAppId})}),y=await m.json();if(y.ok){let S=y.closedSessions??[],H=S.filter(q=>!q.ok).length,B=S.length-H,j=S.length===0?"":H===0?`
524
+ </article>`,r.showModal(),r.querySelectorAll(".oncall-row").forEach(H=>{let T=H.dataset.bot,P=H.querySelector("input[data-action=toggle]"),f=H.querySelector("input[data-input=workingDir]"),v=H.querySelector("button[data-action=save]"),I=H.querySelector("[data-status]");P.addEventListener("change",()=>{f.disabled=!P.checked,P.checked&&f.focus()}),v.addEventListener("click",async()=>{I.textContent="",I.className="oncall-status";let D=P.checked,B=f.value.trim();if(D&&!B){I.textContent=t("groups.needWorkingDir"),I.classList.add("hint-warn-inline");return}v.disabled=!0;try{let U=`/api/groups/${encodeURIComponent(x.chatId)}/oncall/${encodeURIComponent(T)}`,q=D?await fetch(U,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({workingDir:B})}):await fetch(U,{method:"DELETE"}),ae=await q.json().catch(()=>({}));if(q.ok&&ae.ok){I.textContent=D?`\u2713 \u5DF2\u7ED1\u5B9A \u2192 ${ae.resolvedPath??B}`:"\u2713 \u5DF2\u89E3\u7ED1",I.classList.add("hint-ok");try{await Mt(),u()}catch{}}else I.textContent=`\u2717 ${ae.error??q.status}`,I.classList.add("hint-warn-inline")}catch(U){I.textContent=`\u2717 ${U?.message??U}`,I.classList.add("hint-warn-inline")}finally{v.disabled=!1}})}),r.querySelector("#g-leave-btn").onclick=async()=>{let H=[...r.querySelectorAll("input[name=leave-bot]:checked")].map(T=>T.value);if(H.length===0){alert("\u81F3\u5C11\u9009\u4E00\u4E2A\u673A\u5668\u4EBA");return}if(confirm(`\u786E\u5B9A\u8BA9 ${H.length} \u4E2A\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A\uFF1F\u8BE5 bot \u5728\u6B64\u7FA4\u7684\u4F1A\u8BDD\u4F1A\u4E00\u5E76\u5173\u95ED\u3002`))try{let P=await(await fetch(`/api/groups/${encodeURIComponent(x.chatId)}/leave`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:H})})).json(),f=(P.result??[]).map(v=>{if(!v.ok)return`${v.larkAppId}: \u5931\u8D25 (${v.error??"unknown"})`;let I=v.closedSessions??[],D=I.filter(q=>!q.ok).length,B=I.length-D,U=I.length===0?"":D===0?`\uFF08\u5173\u95ED ${B} \u4E2A\u4F1A\u8BDD\uFF09`:`\uFF08\u5173\u95ED ${B} \u4E2A\uFF0C${D} \u4E2A\u5931\u8D25\uFF09`;return`${v.larkAppId}: OK${U}`}).join(`
525
+ `);alert(f||`Unexpected: ${JSON.stringify(P)}`),await Mt(),u()}catch(T){alert("Network error: "+T)}finally{r.close()}},r.querySelector("#g-disband-btn").onclick=async()=>{if(A.length===0||!confirm(`\u786E\u5B9A\u89E3\u6563\u7FA4\u804A\u300C${x.name??x.chatId}\u300D\uFF1F\u6B64\u64CD\u4F5C\u4E0D\u53EF\u6062\u590D\uFF0C\u672C\u7FA4\u6240\u6709\u673A\u5668\u4EBA\u4F1A\u8BDD\u4E5F\u4F1A\u4E00\u5E76\u5173\u95ED\u3002`))return;let H=[...A].sort((P,f)=>(f.larkAppId===L?1:0)-(P.larkAppId===L?1:0)),T=[];for(let P of H)try{let f=await fetch(`/api/groups/${encodeURIComponent(x.chatId)}/disband`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppId:P.larkAppId})}),v=await f.json();if(v.ok){let I=v.closedSessions??[],D=I.filter(q=>!q.ok).length,B=I.length-D,U=I.length===0?"":D===0?`
520
526
  \u5173\u95ED\u4E86 ${B} \u4E2A\u4F1A\u8BDD\u3002`:`
521
- \u5173\u95ED\u4E86 ${B} \u4E2A\u4F1A\u8BDD\uFF0C${H} \u4E2A\u4F1A\u8BDD\u5173\u95ED\u5931\u8D25\u3002`;alert(`\u5DF2\u89E3\u6563\uFF08\u7531 ${D.botName??D.larkAppId} \u6267\u884C\uFF09${j}`),await Tt(),g(),i.close();return}$.push(`${D.botName??D.larkAppId}: ${y.error??m.status}`)}catch(m){$.push(`${D.botName??D.larkAppId}: ${m}`)}alert(`\u6240\u6709\u5728\u7FA4\u673A\u5668\u4EBA\u5747\u65E0\u6CD5\u89E3\u6563\uFF1A
522
- ${$.join(`
527
+ \u5173\u95ED\u4E86 ${B} \u4E2A\u4F1A\u8BDD\uFF0C${D} \u4E2A\u4F1A\u8BDD\u5173\u95ED\u5931\u8D25\u3002`;alert(`\u5DF2\u89E3\u6563\uFF08\u7531 ${P.botName??P.larkAppId} \u6267\u884C\uFF09${U}`),await Mt(),u(),r.close();return}T.push(`${P.botName??P.larkAppId}: ${v.error??f.status}`)}catch(f){T.push(`${P.botName??P.larkAppId}: ${f}`)}alert(`\u6240\u6709\u5728\u7FA4\u673A\u5668\u4EBA\u5747\u65E0\u6CD5\u89E3\u6563\uFF1A
528
+ ${T.join(`
523
529
  `)}
524
530
 
525
- \u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",g)}var Oe={bots:[]},It=null,Lt=null;function pa(e){let n=null;for(let o of Q.sessions.values())o.larkAppId!==e||!o.cliId||(!n||Number(o.lastMessageAt??0)>Number(n.lastMessageAt??0))&&(n=o);return n?.cliId??""}function ii(){return`<section class="page">
531
+ \u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",u)}var Be={bots:[]},xt=null,Et=null;function wo(e){let n=null;for(let a of Q.sessions.values())a.larkAppId!==e||!a.cliId||(!n||Number(a.lastMessageAt??0)>Number(n.lastMessageAt??0))&&(n=a);return n?.cliId??""}function gi(){return`<section class="page">
526
532
  <div class="page-heading">
527
533
  <div>
528
534
  <p class="eyebrow">${t("nav.botDefaults")}</p>
@@ -538,32 +544,32 @@ ${$.join(`
538
544
  <aside id="bd-roster" class="bd-roster"></aside>
539
545
  <div id="bd-list" class="bd-detail"></div>
540
546
  </div>
541
- </section>`}async function ma(){try{let e=await fetch("/api/bots"),n=await e.json().catch(()=>({}));if(!e.ok){It=n?.error?`HTTP ${e.status}: ${n.error}${n.path?` (${n.path})`:""}`:`HTTP ${e.status}`,Oe={bots:[]};return}if(!n||!Array.isArray(n.bots)){It="unexpected response shape (no `bots` array)",Oe={bots:[]};return}It=null,Oe=n}catch(e){It=e?.message??String(e),Oe={bots:[]}}}function fa(e){if(!e)return"\u2014";let n=new Date(e);return Number.isNaN(n.getTime())?"\u2014":n.toLocaleString()}async function ga(e){e.innerHTML=ii();let n=e.querySelector("#bd-list"),o=e.querySelector("#bd-roster"),s=e.querySelector("#bd-filters"),a=e.querySelector("#bd-refresh");a.onclick=async()=>{a.disabled=!0;try{await ma(),i()}finally{a.disabled=!1}},n.addEventListener("click",m=>{let y=m.target.closest(".toggle-tx small, small.bd-help");y&&(m.preventDefault(),y.classList.toggle("open"))}),n.innerHTML=St(),await ma();function i(){let y=(new FormData(s).get("q")??"").toLowerCase(),S=Oe.bots.filter(B=>!y||(B.botName??"").toLowerCase().includes(y)||(B.larkAppId??"").toLowerCase().includes(y));if(It){o.innerHTML="",n.innerHTML=`<p class="hint-warn">\u65E0\u6CD5\u52A0\u8F7D bot \u5217\u8868\uFF1A${r(It)}<br>\u5E38\u89C1\u539F\u56E0\uFF1Adashboard / daemon \u8FDB\u7A0B\u8FD8\u5728\u8DD1\u65E7\u4EE3\u7801\uFF0C\u6267\u884C <code>botmux restart</code> \u540E\u5237\u65B0\u3002</p>`;return}if(S.length===0){o.innerHTML="",n.innerHTML=`<p class="empty">${t("botDefaults.empty")}</p>`;return}(!Lt||!S.some(B=>B.larkAppId===Lt))&&(Lt=S[0].larkAppId),o.innerHTML=S.map(d).join(""),o.querySelectorAll(".bd-roster-item").forEach(B=>{B.onclick=()=>{Lt=B.dataset.appid,i()}});let H=S.find(B=>B.larkAppId===Lt);n.innerHTML=p(H),D()}function d(m){let y=m.botName??m.larkAppId,S=pa(m.larkAppId),H=m.defaultOncall?.enabled?'<span class="bd-roster-flag">oncall</span>':"";return`<div class="bd-roster-item${m.larkAppId===Lt?" on":""}" data-appid="${r(m.larkAppId)}" role="button" tabindex="0">
542
- ${fe({name:y,larkAppId:m.larkAppId,size:"sm"})}
547
+ </section>`}async function yo(){try{let e=await fetch("/api/bots"),n=await e.json().catch(()=>({}));if(!e.ok){xt=n?.error?`HTTP ${e.status}: ${n.error}${n.path?` (${n.path})`:""}`:`HTTP ${e.status}`,Be={bots:[]};return}if(!n||!Array.isArray(n.bots)){xt="unexpected response shape (no `bots` array)",Be={bots:[]};return}xt=null,Be=n}catch(e){xt=e?.message??String(e),Be={bots:[]}}}function vo(e){if(!e)return"\u2014";let n=new Date(e);return Number.isNaN(n.getTime())?"\u2014":n.toLocaleString()}async function ko(e){e.innerHTML=gi();let n=e.querySelector("#bd-list"),a=e.querySelector("#bd-roster"),s=e.querySelector("#bd-filters"),o=e.querySelector("#bd-refresh");o.onclick=async()=>{o.disabled=!0;try{await yo(),r()}finally{o.disabled=!1}},n.addEventListener("click",f=>{let v=f.target.closest(".toggle-tx small, small.bd-help");v&&(f.preventDefault(),v.classList.toggle("open"))}),n.innerHTML=lt(),await yo();function r(){let v=(new FormData(s).get("q")??"").toLowerCase(),I=Be.bots.filter(B=>!v||(B.botName??"").toLowerCase().includes(v)||(B.larkAppId??"").toLowerCase().includes(v));if(xt){a.innerHTML="",n.innerHTML=`<p class="hint-warn">\u65E0\u6CD5\u52A0\u8F7D bot \u5217\u8868\uFF1A${i(xt)}<br>\u5E38\u89C1\u539F\u56E0\uFF1Adashboard / daemon \u8FDB\u7A0B\u8FD8\u5728\u8DD1\u65E7\u4EE3\u7801\uFF0C\u6267\u884C <code>botmux restart</code> \u540E\u5237\u65B0\u3002</p>`;return}if(I.length===0){a.innerHTML="",n.innerHTML=`<p class="empty">${t("botDefaults.empty")}</p>`;return}(!Et||!I.some(B=>B.larkAppId===Et))&&(Et=I[0].larkAppId),a.innerHTML=I.map(d).join(""),a.querySelectorAll(".bd-roster-item").forEach(B=>{B.onclick=()=>{Et=B.dataset.appid,r()}});let D=I.find(B=>B.larkAppId===Et);n.innerHTML=p(D),P()}function d(f){let v=f.botName??f.larkAppId,I=wo(f.larkAppId),D=f.defaultOncall?.enabled?'<span class="bd-roster-flag">oncall</span>':"";return`<div class="bd-roster-item${f.larkAppId===Et?" on":""}" data-appid="${i(f.larkAppId)}" role="button" tabindex="0">
548
+ ${me({name:v,larkAppId:f.larkAppId,size:"sm"})}
543
549
  <div class="bd-roster-tx">
544
- <b>${r(y)}</b>
545
- <span>${r(S||m.larkAppId.slice(0,14))}</span>
550
+ <b>${i(v)}</b>
551
+ <span>${i(I||f.larkAppId.slice(0,14))}</span>
546
552
  </div>
547
- ${H}
548
- </div>`}function p(m){if(m.error)return`<article class="bd-card bd-profile" data-appid="${r(m.larkAppId)}">
553
+ ${D}
554
+ </div>`}function p(f){if(f.error)return`<article class="bd-card bd-profile" data-appid="${i(f.larkAppId)}">
549
555
  <header class="bd-profile-head">
550
- ${fe({name:m.botName??m.larkAppId,larkAppId:m.larkAppId})}
551
- <div class="bd-profile-id"><strong>${r(m.botName??m.larkAppId)}</strong>
552
- <code>${r(m.larkAppId)}</code></div>
556
+ ${me({name:f.botName??f.larkAppId,larkAppId:f.larkAppId})}
557
+ <div class="bd-profile-id"><strong>${i(f.botName??f.larkAppId)}</strong>
558
+ <code>${i(f.larkAppId)}</code></div>
553
559
  </header>
554
- <p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${r(m.error)}</p>
555
- </article>`;let y=m.defaultOncall??{enabled:!1,workingDir:"",since:0},S=!!y.enabled,H=m.botName??m.larkAppId,B=pa(m.larkAppId);return`<article class="bd-card bd-profile" data-appid="${r(m.larkAppId)}">
560
+ <p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${i(f.error)}</p>
561
+ </article>`;let v=f.defaultOncall??{enabled:!1,workingDir:"",since:0},I=!!v.enabled,D=f.botName??f.larkAppId,B=wo(f.larkAppId);return`<article class="bd-card bd-profile" data-appid="${i(f.larkAppId)}">
556
562
  <header class="bd-profile-head">
557
- ${fe({name:H,larkAppId:m.larkAppId,dot:"ok"})}
563
+ ${me({name:D,larkAppId:f.larkAppId,dot:"ok"})}
558
564
  <div class="bd-profile-id">
559
- <strong>${r(H)}</strong>
560
- ${B?`<span class="mate-role">${r(B)}</span>`:""}
561
- <code>${r(m.larkAppId)}</code>
565
+ <strong>${i(D)}</strong>
566
+ ${B?`<span class="mate-role">${i(B)}</span>`:""}
567
+ <code>${i(f.larkAppId)}</code>
562
568
  </div>
563
569
  <div class="bd-profile-meta bd-meta">
564
570
  <small class="bd-meta-ok">\u25CF ${t("botDefaults.metaOnline")}</small>
565
- <small data-oncall-since>${t("botDefaults.lastEnabled")}: ${r(fa(y.since??0))}</small>
566
- <small>${t("botDefaults.autobound",{count:m.autoboundChatCount??0})}</small>
571
+ <small data-oncall-since>${t("botDefaults.lastEnabled")}: ${i(vo(v.since??0))}</small>
572
+ <small>${t("botDefaults.autobound",{count:f.autoboundChatCount??0})}</small>
567
573
  </div>
568
574
  </header>
569
575
  <div class="bd-body bd-grid">
@@ -571,7 +577,7 @@ ${$.join(`
571
577
  <section class="bd-section">
572
578
  <h3 class="bd-section-title">${t("botDefaults.sectionOncall")}</h3>
573
579
  <label class="toggle-row">
574
- <input type="checkbox" data-action="toggle" ${S?"checked":""}>
580
+ <input type="checkbox" data-action="toggle" ${I?"checked":""}>
575
581
  <span class="switch" aria-hidden="true"></span>
576
582
  <span class="toggle-tx"><strong>${t("botDefaults.defaultOncall")}</strong>
577
583
  <small>${t("botDefaults.defaultOncallHelp")}\u3002${t("botDefaults.warning")}</small></span>
@@ -580,43 +586,43 @@ ${$.join(`
580
586
  <label>
581
587
  <span>${t("botDefaults.workingDir")}</span>
582
588
  <input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
583
- value="${r(y.workingDir??"")}" ${S?"":"disabled"}>
589
+ value="${i(v.workingDir??"")}" ${I?"":"disabled"}>
584
590
  </label>
585
591
  </div>
586
592
  <div class="actions">
587
593
  <button type="button" class="primary" data-action="save">${t("botDefaults.save")}</button>
588
594
  <span class="oncall-status" data-status></span>
589
595
  </div>
590
- ${$(m)}
596
+ ${T(f)}
591
597
  </section>
592
- ${O(m)}
598
+ ${A(f)}
593
599
  </section>
594
- <section class="bd-tile">${v(m)}</section>
595
- <section class="bd-tile">${g(m)}${A(m)}</section>
596
- <section class="bd-tile">${T(m)}${I(m)}</section>
597
- <section class="bd-tile">${E(m)}</section>
600
+ <section class="bd-tile">${k(f)}</section>
601
+ <section class="bd-tile">${u(f)}${x(f)}</section>
602
+ <section class="bd-tile">${w(f)}${E(f)}</section>
603
+ <section class="bd-tile">${H(f)}</section>
598
604
  </div>
599
- </article>`}function v(m){let y=typeof m.teamRole=="string";return`<section class="bd-section">
605
+ </article>`}function k(f){let v=typeof f.teamRole=="string";return`<section class="bd-section">
600
606
  <h3 class="bd-section-title">${t("botDefaults.sectionRole")}</h3>
601
607
  <p class="bd-section-note">${t("botDefaults.roleHelp")}</p>
602
608
  <textarea data-input="teamRole" rows="6"
603
- placeholder="${r(t("botDefaults.rolePlaceholder"))}"
604
- style="width:100%;box-sizing:border-box;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px"${y?"":" disabled"}>${y?r(m.teamRole):""}</textarea>
609
+ placeholder="${i(t("botDefaults.rolePlaceholder"))}"
610
+ style="width:100%;box-sizing:border-box;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px"${v?"":" disabled"}>${v?i(f.teamRole):""}</textarea>
605
611
  <div class="actions">
606
- <button type="button" class="primary" data-action="save-role"${y?"":" disabled"}>${t("botDefaults.roleSave")}</button>
607
- <button type="button" data-action="delete-role"${y?"":" disabled"}>${t("botDefaults.roleDelete")}</button>
612
+ <button type="button" class="primary" data-action="save-role"${v?"":" disabled"}>${t("botDefaults.roleSave")}</button>
613
+ <button type="button" data-action="delete-role"${v?"":" disabled"}>${t("botDefaults.roleDelete")}</button>
608
614
  <span class="oncall-status" data-role-status></span>
609
615
  </div>
610
- </section>`}function k(m){return m==null?t("botDefaults.brandStateDefault"):m.trim()===""?t("botDefaults.brandStateOff"):t("botDefaults.brandStateCustom")}function I(m){let y=m.brandLabel??null;return`<section class="bd-section">
616
+ </section>`}function $(f){return f==null?t("botDefaults.brandStateDefault"):f.trim()===""?t("botDefaults.brandStateOff"):t("botDefaults.brandStateCustom")}function E(f){let v=f.brandLabel??null;return`<section class="bd-section">
611
617
  <h3 class="bd-section-title">${t("botDefaults.sectionBrand")}</h3>
612
618
  <div class="bd-row bd-brand">
613
619
  <label>
614
620
  <span>${t("botDefaults.brandLabel")}</span>
615
621
  <input type="text" data-input="brandLabel"
616
- placeholder="${r(t("botDefaults.brandLabelPlaceholder"))}"
617
- value="${r(y??"")}">
622
+ placeholder="${i(t("botDefaults.brandLabelPlaceholder"))}"
623
+ value="${i(v??"")}">
618
624
  </label>
619
- <small data-brand-state>${r(k(y))}</small>
625
+ <small data-brand-state>${i($(v))}</small>
620
626
  <small class="bd-help">${t("botDefaults.brandLabelHelp")}</small>
621
627
  <div class="actions">
622
628
  <button type="button" class="primary" data-action="save-brand">${t("botDefaults.brandSave")}</button>
@@ -624,38 +630,38 @@ ${$.join(`
624
630
  <span class="oncall-status" data-brand-status></span>
625
631
  </div>
626
632
  </div>
627
- </section>`}function T(m){let y=m.disableStreamingCard===!0,S=m.writableTerminalLinkInCard===!0,H=m.privateCard===!0;return`<section class="bd-section">
633
+ </section>`}function w(f){let v=f.disableStreamingCard===!0,I=f.writableTerminalLinkInCard===!0,D=f.privateCard===!0;return`<section class="bd-section">
628
634
  <h3 class="bd-section-title">${t("botDefaults.sectionCard")}</h3>
629
635
  <label class="toggle-row">
630
- <input type="checkbox" data-action="toggle-disable-streaming" ${y?"checked":""}>
636
+ <input type="checkbox" data-action="toggle-disable-streaming" ${v?"checked":""}>
631
637
  <span class="switch" aria-hidden="true"></span>
632
638
  <span class="toggle-tx"><strong>${t("botDefaults.disableStreaming")}</strong>
633
639
  <small>${t("botDefaults.disableStreamingHelp")}</small></span>
634
640
  </label>
635
641
  <label class="toggle-row">
636
- <input type="checkbox" data-action="toggle-writable-link" ${S?"checked":""} ${y?"disabled":""}>
642
+ <input type="checkbox" data-action="toggle-writable-link" ${I?"checked":""} ${v?"disabled":""}>
637
643
  <span class="switch" aria-hidden="true"></span>
638
644
  <span class="toggle-tx"><strong>${t("botDefaults.writableLink")}</strong>
639
645
  <small>${t("botDefaults.writableLinkHelp")}</small></span>
640
646
  </label>
641
647
  <label class="toggle-row">
642
- <input type="checkbox" data-action="toggle-private-card" ${H?"checked":""}>
648
+ <input type="checkbox" data-action="toggle-private-card" ${D?"checked":""}>
643
649
  <span class="switch" aria-hidden="true"></span>
644
650
  <span class="toggle-tx"><strong>${t("botDefaults.privateCard")}</strong>
645
651
  <small>${t("botDefaults.privateCardHelp")}</small></span>
646
652
  </label>
647
653
  <div class="actions">
648
- <small data-card-pref-moot class="hint-warn-inline" ${y?"":"hidden"}>${t("botDefaults.writableLinkMoot")}</small>
654
+ <small data-card-pref-moot class="hint-warn-inline" ${v?"":"hidden"}>${t("botDefaults.writableLinkMoot")}</small>
649
655
  <span class="oncall-status" data-card-pref-status></span>
650
656
  </div>
651
- </section>`}function g(m){let y=m.p2pMode==="chat"?"chat":"thread",S=m.regularGroupReplyMode==="new-topic"||m.regularGroupReplyMode==="shared"?m.regularGroupReplyMode:"chat",H=m.regularGroupMentionMode==="topic"||m.regularGroupMentionMode==="never"?m.regularGroupMentionMode:"always",B=m.docSubscribeDefaultMode==="all"?"all":"mention-only",j=(X,ae)=>`<option value="${X}" ${S===X?"selected":""}>${r(ae)}</option>`,q=(X,ae)=>`<option value="${X}" ${H===X?"selected":""}>${r(ae)}</option>`,oe=(X,ae)=>`<option value="${X}" ${B===X?"selected":""}>${r(ae)}</option>`;return`<section class="bd-section">
657
+ </section>`}function u(f){let v=f.p2pMode==="chat"?"chat":"thread",I=f.regularGroupReplyMode==="new-topic"||f.regularGroupReplyMode==="shared"?f.regularGroupReplyMode:"chat",D=f.regularGroupMentionMode==="topic"||f.regularGroupMentionMode==="never"?f.regularGroupMentionMode:"always",B=f.docSubscribeDefaultMode==="all"?"all":"mention-only",U=(X,oe)=>`<option value="${X}" ${I===X?"selected":""}>${i(oe)}</option>`,q=(X,oe)=>`<option value="${X}" ${D===X?"selected":""}>${i(oe)}</option>`,ae=(X,oe)=>`<option value="${X}" ${B===X?"selected":""}>${i(oe)}</option>`;return`<section class="bd-section">
652
658
  <h3 class="bd-section-title">${t("botDefaults.sectionSessionMode")}</h3>
653
659
  <div class="bd-row">
654
660
  <label>
655
661
  <span>${t("botDefaults.p2pMode")}</span>
656
662
  <select data-input="p2pMode">
657
- <option value="thread" ${y==="chat"?"":"selected"}>${r(t("botDefaults.p2pThread"))}</option>
658
- <option value="chat" ${y==="chat"?"selected":""}>${r(t("botDefaults.p2pChat"))}</option>
663
+ <option value="thread" ${v==="chat"?"":"selected"}>${i(t("botDefaults.p2pThread"))}</option>
664
+ <option value="chat" ${v==="chat"?"selected":""}>${i(t("botDefaults.p2pChat"))}</option>
659
665
  </select>
660
666
  </label>
661
667
  <small class="bd-help">${t("botDefaults.p2pHelp")}</small>
@@ -667,9 +673,9 @@ ${$.join(`
667
673
  <label>
668
674
  <span>${t("botDefaults.regularGroupMode")}</span>
669
675
  <select data-input="regularGroupMode">
670
- ${j("chat",t("botDefaults.regularGroupModeChat"))}
671
- ${j("new-topic",t("botDefaults.regularGroupModeNewTopic"))}
672
- ${j("shared",t("botDefaults.regularGroupModeShared"))}
676
+ ${U("chat",t("botDefaults.regularGroupModeChat"))}
677
+ ${U("new-topic",t("botDefaults.regularGroupModeNewTopic"))}
678
+ ${U("shared",t("botDefaults.regularGroupModeShared"))}
673
679
  </select>
674
680
  </label>
675
681
  <small class="bd-help">${t("botDefaults.regularGroupModeHelp")}</small>
@@ -695,8 +701,8 @@ ${$.join(`
695
701
  <label>
696
702
  <span>${t("botDefaults.docSubscribeMode")}</span>
697
703
  <select data-input="docSubscribeDefaultMode">
698
- ${oe("mention-only",t("botDefaults.docSubscribeModeMention"))}
699
- ${oe("all",t("botDefaults.docSubscribeModeAll"))}
704
+ ${ae("mention-only",t("botDefaults.docSubscribeModeMention"))}
705
+ ${ae("all",t("botDefaults.docSubscribeModeAll"))}
700
706
  </select>
701
707
  </label>
702
708
  <small class="bd-help">${t("botDefaults.docSubscribeModeHelp")}</small>
@@ -704,16 +710,16 @@ ${$.join(`
704
710
  <span class="oncall-status" data-doc-subscribe-mode-status></span>
705
711
  </div>
706
712
  </div>
707
- </section>`}function R(m){return m==null?t("botDefaults.maxLiveWorkersStateDefault"):t("botDefaults.maxLiveWorkersStateOn",{count:m})}function A(m){let y=typeof m.maxLiveWorkers=="number"?m.maxLiveWorkers:null;return`<div class="bd-subsection">
713
+ </section>`}function S(f){return f==null?t("botDefaults.maxLiveWorkersStateDefault"):t("botDefaults.maxLiveWorkersStateOn",{count:f})}function x(f){let v=typeof f.maxLiveWorkers=="number"?f.maxLiveWorkers:null;return`<div class="bd-subsection">
708
714
  <h4 class="bd-subsection-title">${t("botDefaults.sectionSessionCap")}</h4>
709
715
  <div class="bd-row bd-quota">
710
716
  <label>
711
717
  <span>${t("botDefaults.maxLiveWorkers")}</span>
712
718
  <input type="number" min="1" step="1" data-input="maxLiveWorkers"
713
- placeholder="${r(t("botDefaults.maxLiveWorkersPlaceholder"))}"
714
- value="${y??""}">
719
+ placeholder="${i(t("botDefaults.maxLiveWorkersPlaceholder"))}"
720
+ value="${v??""}">
715
721
  </label>
716
- <small data-session-cap-state>${r(R(y))}</small>
722
+ <small data-session-cap-state>${i(S(v))}</small>
717
723
  <small class="bd-help">${t("botDefaults.maxLiveWorkersHelp")}</small>
718
724
  <div class="actions">
719
725
  <button type="button" class="primary" data-action="save-session-cap">${t("botDefaults.maxLiveWorkersSave")}</button>
@@ -721,10 +727,10 @@ ${$.join(`
721
727
  <span class="oncall-status" data-session-cap-status></span>
722
728
  </div>
723
729
  </div>
724
- </div>`}function O(m){let y=m.sandbox===!0;return`<section class="bd-section">
730
+ </div>`}function A(f){let v=f.sandbox===!0;return`<section class="bd-section">
725
731
  <h3 class="bd-section-title">${t("botDefaults.sectionSandbox")}</h3>
726
732
  <label class="toggle-row">
727
- <input type="checkbox" data-action="toggle-sandbox" ${y?"checked":""}>
733
+ <input type="checkbox" data-action="toggle-sandbox" ${v?"checked":""}>
728
734
  <span class="switch" aria-hidden="true"></span>
729
735
  <span class="toggle-tx"><strong>${t("botDefaults.sandboxToggle")}</strong>
730
736
  <small>${t("botDefaults.sandboxHelp")}</small></span>
@@ -732,10 +738,10 @@ ${$.join(`
732
738
  <div class="actions">
733
739
  <span class="oncall-status" data-sandbox-status></span>
734
740
  </div>
735
- </section>`}function M(m){return m==null?t("botDefaults.quotaStateOff"):t("botDefaults.quotaStateOn",{count:m})}function E(m){let y=m.restrictGrantCommands===!0,S=typeof m.messageQuotaDefaultLimit=="number"?m.messageQuotaDefaultLimit:null;return`<section class="bd-section">
741
+ </section>`}function L(f){return f==null?t("botDefaults.quotaStateOff"):t("botDefaults.quotaStateOn",{count:f})}function H(f){let v=f.restrictGrantCommands===!0,I=typeof f.messageQuotaDefaultLimit=="number"?f.messageQuotaDefaultLimit:null;return`<section class="bd-section">
736
742
  <h3 class="bd-section-title">${t("botDefaults.sectionGrant")}</h3>
737
743
  <label class="toggle-row">
738
- <input type="checkbox" data-action="toggle-restrict-grant" ${y?"checked":""}>
744
+ <input type="checkbox" data-action="toggle-restrict-grant" ${v?"checked":""}>
739
745
  <span class="switch" aria-hidden="true"></span>
740
746
  <span class="toggle-tx"><strong>${t("botDefaults.restrictGrant")}</strong>
741
747
  <small>${t("botDefaults.restrictGrantHelp")}</small></span>
@@ -744,10 +750,10 @@ ${$.join(`
744
750
  <label>
745
751
  <span>${t("botDefaults.quotaDefault")}</span>
746
752
  <input type="number" min="1" step="1" data-input="quotaLimit"
747
- placeholder="${r(t("botDefaults.quotaPlaceholder"))}"
748
- value="${S??""}">
753
+ placeholder="${i(t("botDefaults.quotaPlaceholder"))}"
754
+ value="${I??""}">
749
755
  </label>
750
- <small data-quota-state>${r(M(S))}</small>
756
+ <small data-quota-state>${i(L(I))}</small>
751
757
  <small class="bd-help">${t("botDefaults.quotaHelp")}</small>
752
758
  <div class="actions">
753
759
  <button type="button" class="primary" data-action="save-quota">${t("botDefaults.quotaSave")}</button>
@@ -755,10 +761,10 @@ ${$.join(`
755
761
  <span class="oncall-status" data-grant-status></span>
756
762
  </div>
757
763
  </div>
758
- </section>`}function $(m){let y=m.autoStartOnGroupJoin===!0,S=m.autoStartOnNewTopic===!0,H=typeof m.autoStartOnGroupJoinPrompt=="string"?m.autoStartOnGroupJoinPrompt:"";return`<div class="bd-subsection">
764
+ </section>`}function T(f){let v=f.autoStartOnGroupJoin===!0,I=f.autoStartOnNewTopic===!0,D=typeof f.autoStartOnGroupJoinPrompt=="string"?f.autoStartOnGroupJoinPrompt:"";return`<div class="bd-subsection">
759
765
  <h4 class="bd-subsection-title">${t("botDefaults.sectionAutoStart")}</h4>
760
766
  <label class="toggle-row">
761
- <input type="checkbox" data-action="toggle-auto-join" ${y?"checked":""}>
767
+ <input type="checkbox" data-action="toggle-auto-join" ${v?"checked":""}>
762
768
  <span class="switch" aria-hidden="true"></span>
763
769
  <span class="toggle-tx"><strong>${t("botDefaults.autoStartJoin")}</strong>
764
770
  <small>${t("botDefaults.autoStartJoinHelp")}</small></span>
@@ -767,14 +773,14 @@ ${$.join(`
767
773
  <label>
768
774
  <span>${t("botDefaults.autoStartJoinPrompt")}</span>
769
775
  <textarea data-input="autoJoinPrompt" rows="3"
770
- placeholder="${r(t("botDefaults.autoStartJoinPromptPlaceholder"))}">${r(H)}</textarea>
776
+ placeholder="${i(t("botDefaults.autoStartJoinPromptPlaceholder"))}">${i(D)}</textarea>
771
777
  </label>
772
778
  <div class="actions">
773
779
  <button type="button" class="primary" data-action="save-auto-join-prompt">${t("botDefaults.autoStartJoinPromptSave")}</button>
774
780
  </div>
775
781
  </div>
776
782
  <label class="toggle-row">
777
- <input type="checkbox" data-action="toggle-auto-topic" ${S?"checked":""}>
783
+ <input type="checkbox" data-action="toggle-auto-topic" ${I?"checked":""}>
778
784
  <span class="switch" aria-hidden="true"></span>
779
785
  <span class="toggle-tx"><strong>${t("botDefaults.autoStartTopic")}</strong>
780
786
  <small>${t("botDefaults.autoStartTopicHelp")}</small></span>
@@ -782,7 +788,144 @@ ${$.join(`
782
788
  <div class="actions">
783
789
  <span class="oncall-status" data-auto-start-status></span>
784
790
  </div>
785
- </div>`}function D(){n.querySelectorAll(".bd-card").forEach(m=>{let y=m.dataset.appid,S=m.querySelector("input[data-action=toggle]"),H=m.querySelector("input[data-input=workingDir]"),B=m.querySelector("button[data-action=save]"),j=m.querySelector("[data-status]");if(!S||!H||!B||!j)return;S.addEventListener("change",()=>{H.disabled=!S.checked,S.checked&&H.focus()}),B.addEventListener("click",async()=>{j.textContent="",j.className="oncall-status";let J=S.checked,z=H.value.trim();if(J&&!z){j.textContent=t("botDefaults.required"),j.classList.add("hint-warn-inline");return}B.disabled=!0;try{let P=await fetch(`/api/bots/${encodeURIComponent(y)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:J,workingDir:z})}),W=await P.json().catch(()=>({}));if(P.ok&&W.ok){let G=W.resolvedPath?` \u2192 ${W.resolvedPath}`:"";j.textContent=J?`\u2713 \u5DF2\u5F00\u542F${G}\uFF08\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8 oncall\uFF09`:"\u2713 \u5DF2\u5173\u95ED\uFF08\u5DF2\u7ED1\u5B9A\u7684\u7FA4\u4E0D\u52A8\uFF09",j.classList.add("hint-ok");let Y=Oe.bots.find(De=>De.larkAppId===y);Y&&W.defaultOncall&&(Y.defaultOncall=W.defaultOncall);let ue=m.querySelector("[data-oncall-since]");ue&&W.defaultOncall?.since!=null&&(ue.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${fa(W.defaultOncall.since)}`)}else j.textContent=`\u2717 ${W.error??P.status}`,j.classList.add("hint-warn-inline")}catch(P){j.textContent=`\u2717 ${P?.message??P}`,j.classList.add("hint-warn-inline")}finally{B.disabled=!1}});let q=m.querySelector("input[data-input=brandLabel]"),oe=m.querySelector("button[data-action=save-brand]"),X=m.querySelector("button[data-action=reset-brand]"),ae=m.querySelector("[data-brand-status]"),Ae=m.querySelector("[data-brand-state]");async function se(J,z){if(ae){ae.textContent="",ae.className="oncall-status",z.disabled=!0;try{let P=await fetch(`/api/bots/${encodeURIComponent(y)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:J})}),W=await P.json().catch(()=>({}));if(P.ok&&W.ok){let G=W.brandLabel??null;ae.textContent="\u2713",ae.classList.add("hint-ok"),q&&(q.value=G??""),Ae&&(Ae.textContent=k(G));let Y=Oe.bots.find(ue=>ue.larkAppId===y);Y&&(Y.brandLabel=G)}else ae.textContent=`\u2717 ${W.error??P.status}`,ae.classList.add("hint-warn-inline")}catch(P){ae.textContent=`\u2717 ${P?.message??P}`,ae.classList.add("hint-warn-inline")}finally{z.disabled=!1}}}q&&oe&&oe.addEventListener("click",()=>se(q.value,oe)),X&&X.addEventListener("click",()=>se(null,X));let ie=m.querySelector("input[data-action=toggle-disable-streaming]"),ce=m.querySelector("input[data-action=toggle-writable-link]"),Le=m.querySelector("input[data-action=toggle-private-card]"),de=m.querySelector("[data-card-pref-status]"),Be=m.querySelector("[data-card-pref-moot]");async function ge(J,z,P=de){if(P){P.textContent="",P.className="oncall-status",z.disabled=!0;try{let W=await fetch(`/api/bots/${encodeURIComponent(y)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(J)}),G=await W.json().catch(()=>({}));if(W.ok&&G.ok){P.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,P.classList.add("hint-ok");let Y=Oe.bots.find(ue=>ue.larkAppId===y);Y&&(Y.disableStreamingCard=G.disableStreamingCard,Y.writableTerminalLinkInCard=G.writableTerminalLinkInCard,Y.privateCard=G.privateCard,Y.autoStartOnGroupJoin=G.autoStartOnGroupJoin,Y.autoStartOnGroupJoinPrompt=G.autoStartOnGroupJoinPrompt,Y.autoStartOnNewTopic=G.autoStartOnNewTopic,Y.regularGroupReplyMode=G.regularGroupReplyMode,Y.regularGroupMentionMode=G.regularGroupMentionMode,Y.docSubscribeDefaultMode=G.docSubscribeDefaultMode)}else P.textContent=`\u2717 ${G.error??W.status}`,P.classList.add("hint-warn-inline")}catch(W){P.textContent=`\u2717 ${W?.message??W}`,P.classList.add("hint-warn-inline")}finally{z===ce?z.disabled=!!ie?.checked:z.disabled=!1}}}ie&&ie.addEventListener("change",()=>{let J=ie.checked;ce&&(ce.disabled=J),Be&&(Be.hidden=!J),ge({disableStreamingCard:J},ie)}),ce&&ce.addEventListener("change",()=>{ge({writableTerminalLinkInCard:ce.checked},ce)}),Le&&Le.addEventListener("change",()=>{ge({privateCard:Le.checked},Le)});let Ie=m.querySelector("input[data-action=toggle-sandbox]"),re=m.querySelector("[data-sandbox-status]");Ie&&Ie.addEventListener("change",async()=>{let J=Ie.checked;re&&(re.textContent="",re.className="oncall-status"),Ie.disabled=!0;try{let z=await fetch(`/api/bots/${encodeURIComponent(y)}/sandbox`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:J})}),P=await z.json().catch(()=>({}));if(z.ok&&P.ok){re&&(re.textContent=`\u2713 ${t("botDefaults.sandboxSaved")}`,re.classList.add("hint-ok"));let W=Oe.bots.find(G=>G.larkAppId===y);W&&(W.sandbox=P.sandbox===!0)}else re&&(re.textContent=`\u2717 ${P.error??z.status}`,re.classList.add("hint-warn-inline")),Ie.checked=!J}catch(z){re&&(re.textContent=`\u2717 ${z?.message??z}`,re.classList.add("hint-warn-inline")),Ie.checked=!J}finally{Ie.disabled=!1}});let pe=m.querySelector("input[data-action=toggle-auto-join]"),le=m.querySelector("input[data-action=toggle-auto-topic]"),Ne=m.querySelector("textarea[data-input=autoJoinPrompt]"),je=m.querySelector("button[data-action=save-auto-join-prompt]"),Pe=m.querySelector("[data-auto-start-status]");pe&&pe.addEventListener("change",()=>{ge({autoStartOnGroupJoin:pe.checked},pe,Pe)}),le&&le.addEventListener("change",()=>{ge({autoStartOnNewTopic:le.checked},le,Pe)}),Ne&&je&&je.addEventListener("click",()=>{ge({autoStartOnGroupJoinPrompt:Ne.value},je,Pe)});let Fe=m.querySelector("select[data-input=p2pMode]"),be=m.querySelector("[data-p2p-status]");Fe&&be&&Fe.addEventListener("change",async()=>{let J=Fe.value==="chat"?"chat":"thread";be.textContent="",be.className="oncall-status",Fe.disabled=!0;try{let z=await fetch(`/api/bots/${encodeURIComponent(y)}/p2p-mode`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({p2pMode:J})}),P=await z.json().catch(()=>({}));if(z.ok&&P.ok){be.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,be.classList.add("hint-ok");let W=Oe.bots.find(G=>G.larkAppId===y);W&&(W.p2pMode=P.p2pMode==="chat"?"chat":"thread")}else be.textContent=`\u2717 ${P.error??z.status}`,be.classList.add("hint-warn-inline")}catch(z){be.textContent=`\u2717 ${z?.message??z}`,be.classList.add("hint-warn-inline")}finally{Fe.disabled=!1}});let nt=m.querySelector("select[data-input=regularGroupMode]"),wt=m.querySelector("[data-regular-group-status]");nt&&nt.addEventListener("change",()=>{ge({regularGroupReplyMode:nt.value},nt,wt)});let ot=m.querySelector("select[data-input=regularGroupMentionMode]"),Ht=m.querySelector("[data-mention-mode-status]");ot&&ot.addEventListener("change",()=>{ge({regularGroupMentionMode:ot.value},ot,Ht)});let at=m.querySelector("select[data-input=docSubscribeDefaultMode]"),Me=m.querySelector("[data-doc-subscribe-mode-status]");at&&at.addEventListener("change",()=>{ge({docSubscribeDefaultMode:at.value},at,Me)});let _e=m.querySelector("textarea[data-input=teamRole]"),Ge=m.querySelector("button[data-action=save-role]"),x=m.querySelector("button[data-action=delete-role]"),V=m.querySelector("[data-role-status]");if(_e&&Ge&&x&&V){let P=function(G){let Y=n.querySelector(`.bd-card[data-appid="${CSS.escape(y)}"]`);if(!Y)return;let ue=Y.querySelector("textarea[data-input=teamRole]"),De=Y.querySelector("button[data-action=save-role]"),ut=Y.querySelector("button[data-action=delete-role]");ue&&(ue.value=G,ue.disabled=!1),De&&(De.disabled=!1),ut&&(ut.disabled=!1)};var $n=P;let J=`/api/team/local-bots/${encodeURIComponent(y)}/role`,z=Oe.bots.find(G=>G.larkAppId===y);z&&typeof z.teamRole!="string"&&!z.teamRoleLoading&&(z.teamRoleLoading=!0,(async()=>{try{let G=await fetch(J),Y=await G.json().catch(()=>({}));G.ok&&Y.ok?(z.teamRole=Y.role??"",P(z.teamRole)):(V.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${Y.error??G.status}`,V.classList.add("hint-warn-inline"))}catch(G){V.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${G?.message??G}`,V.classList.add("hint-warn-inline")}finally{z.teamRoleLoading=!1}})());async function W(G,Y,ue){if(V&&!(!z||typeof z.teamRole!="string")){V.textContent="",V.className="oncall-status",Ge.disabled=!0,x.disabled=!0;try{let De=await fetch(J,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({role:G})}),ut=await De.json().catch(()=>({}));De.ok&&ut.ok?(z&&(z.teamRole=G.trim()),V.textContent=`\u2713 ${ue?t("botDefaults.roleDeleted"):t("botDefaults.roleSaved")}`,V.classList.add("hint-ok")):(V.textContent=`\u2717 ${ut.error??De.status}`,V.classList.add("hint-warn-inline"))}catch(De){V.textContent=`\u2717 ${De?.message??De}`,V.classList.add("hint-warn-inline")}finally{Ge.disabled=!1,x.disabled=!1}}}Ge.addEventListener("click",()=>W(_e.value,Ge,!1)),x.addEventListener("click",()=>{_e.value="",W("",x,!0)})}let K=m.querySelector("input[data-action=toggle-restrict-grant]"),_=m.querySelector("input[data-input=quotaLimit]"),he=m.querySelector("button[data-action=save-quota]"),Xe=m.querySelector("button[data-action=off-quota]"),$e=m.querySelector("[data-grant-status]"),Wt=m.querySelector("[data-quota-state]");async function ct(J,z){if($e){$e.textContent="",$e.className="oncall-status",z.disabled=!0;try{let P=await fetch(`/api/bots/${encodeURIComponent(y)}/grant-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(J)}),W=await P.json().catch(()=>({}));if(P.ok&&W.ok){$e.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,$e.classList.add("hint-ok");let G=typeof W.messageQuotaDefaultLimit=="number"?W.messageQuotaDefaultLimit:null,Y=Oe.bots.find(ue=>ue.larkAppId===y);Y&&(Y.restrictGrantCommands=W.restrictGrantCommands===!0,Y.messageQuotaDefaultLimit=G),Wt&&(Wt.textContent=M(G)),_&&"messageQuotaDefaultLimit"in J&&(_.value=G==null?"":String(G))}else $e.textContent=`\u2717 ${W.error??P.status}`,$e.classList.add("hint-warn-inline")}catch(P){$e.textContent=`\u2717 ${P?.message??P}`,$e.classList.add("hint-warn-inline")}finally{z.disabled=!1}}}K&&K.addEventListener("change",()=>{ct({restrictGrantCommands:K.checked},K)}),_&&he&&he.addEventListener("click",()=>{let J=_.value.trim();if(J===""){ct({messageQuotaDefaultLimit:null},he);return}if(!/^[1-9]\d*$/.test(J)){$e&&($e.textContent=`\u2717 ${t("botDefaults.quotaInvalid")}`,$e.className="oncall-status hint-warn-inline");return}ct({messageQuotaDefaultLimit:Number(J)},he)}),_&&Xe&&Xe.addEventListener("click",()=>{_.value="",ct({messageQuotaDefaultLimit:null},Xe)});let Ze=m.querySelector("input[data-input=maxLiveWorkers]"),yt=m.querySelector("button[data-action=save-session-cap]"),Ct=m.querySelector("button[data-action=off-session-cap]"),Se=m.querySelector("[data-session-cap-status]"),At=m.querySelector("[data-session-cap-state]");async function vt(J,z){if(Se){Se.textContent="",Se.className="oncall-status",z.disabled=!0;try{let P=await fetch(`/api/bots/${encodeURIComponent(y)}/max-live-workers`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({maxLiveWorkers:J})}),W=await P.json().catch(()=>({}));if(P.ok&&W.ok){Se.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,Se.classList.add("hint-ok");let G=typeof W.maxLiveWorkers=="number"?W.maxLiveWorkers:null,Y=Oe.bots.find(ue=>ue.larkAppId===y);Y&&(Y.maxLiveWorkers=G),At&&(At.textContent=R(G)),Ze&&(Ze.value=G==null?"":String(G))}else Se.textContent=`\u2717 ${W.error??P.status}`,Se.classList.add("hint-warn-inline")}catch(P){Se.textContent=`\u2717 ${P?.message??P}`,Se.classList.add("hint-warn-inline")}finally{z.disabled=!1}}}Ze&&yt&&yt.addEventListener("click",()=>{let J=Ze.value.trim();if(J===""){vt(null,yt);return}if(!/^[1-9]\d*$/.test(J)){Se&&(Se.textContent=`\u2717 ${t("botDefaults.maxLiveWorkersInvalid")}`,Se.className="oncall-status hint-warn-inline");return}vt(Number(J),yt)}),Ze&&Ct&&Ct.addEventListener("click",()=>{Ze.value="",vt(null,Ct)})})}i(),Ke().then(i),s.addEventListener("input",i)}var zn=4096,ln=[],Ye=null,Ve=null,Ue="",Mt=new Set;function ri(){return`<section class="page roles-page">
791
+ </div>`}function P(){n.querySelectorAll(".bd-card").forEach(f=>{let v=f.dataset.appid,I=f.querySelector("input[data-action=toggle]"),D=f.querySelector("input[data-input=workingDir]"),B=f.querySelector("button[data-action=save]"),U=f.querySelector("[data-status]");if(!I||!D||!B||!U)return;I.addEventListener("change",()=>{D.disabled=!I.checked,I.checked&&D.focus()}),B.addEventListener("click",async()=>{U.textContent="",U.className="oncall-status";let J=I.checked,W=D.value.trim();if(J&&!W){U.textContent=t("botDefaults.required"),U.classList.add("hint-warn-inline");return}B.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(v)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:J,workingDir:W})}),z=await N.json().catch(()=>({}));if(N.ok&&z.ok){let G=z.resolvedPath?` \u2192 ${z.resolvedPath}`:"";U.textContent=J?`\u2713 \u5DF2\u5F00\u542F${G}\uFF08\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8 oncall\uFF09`:"\u2713 \u5DF2\u5173\u95ED\uFF08\u5DF2\u7ED1\u5B9A\u7684\u7FA4\u4E0D\u52A8\uFF09",U.classList.add("hint-ok");let V=Be.bots.find(Re=>Re.larkAppId===v);V&&z.defaultOncall&&(V.defaultOncall=z.defaultOncall);let pe=f.querySelector("[data-oncall-since]");pe&&z.defaultOncall?.since!=null&&(pe.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${vo(z.defaultOncall.since)}`)}else U.textContent=`\u2717 ${z.error??N.status}`,U.classList.add("hint-warn-inline")}catch(N){U.textContent=`\u2717 ${N?.message??N}`,U.classList.add("hint-warn-inline")}finally{B.disabled=!1}});let q=f.querySelector("input[data-input=brandLabel]"),ae=f.querySelector("button[data-action=save-brand]"),X=f.querySelector("button[data-action=reset-brand]"),oe=f.querySelector("[data-brand-status]"),De=f.querySelector("[data-brand-state]");async function se(J,W){if(oe){oe.textContent="",oe.className="oncall-status",W.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(v)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:J})}),z=await N.json().catch(()=>({}));if(N.ok&&z.ok){let G=z.brandLabel??null;oe.textContent="\u2713",oe.classList.add("hint-ok"),q&&(q.value=G??""),De&&(De.textContent=$(G));let V=Be.bots.find(pe=>pe.larkAppId===v);V&&(V.brandLabel=G)}else oe.textContent=`\u2717 ${z.error??N.status}`,oe.classList.add("hint-warn-inline")}catch(N){oe.textContent=`\u2717 ${N?.message??N}`,oe.classList.add("hint-warn-inline")}finally{W.disabled=!1}}}q&&ae&&ae.addEventListener("click",()=>se(q.value,ae)),X&&X.addEventListener("click",()=>se(null,X));let re=f.querySelector("input[data-action=toggle-disable-streaming]"),ue=f.querySelector("input[data-action=toggle-writable-link]"),Me=f.querySelector("input[data-action=toggle-private-card]"),ce=f.querySelector("[data-card-pref-status]"),Oe=f.querySelector("[data-card-pref-moot]");async function be(J,W,N=ce){if(N){N.textContent="",N.className="oncall-status",W.disabled=!0;try{let z=await fetch(`/api/bots/${encodeURIComponent(v)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(J)}),G=await z.json().catch(()=>({}));if(z.ok&&G.ok){N.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,N.classList.add("hint-ok");let V=Be.bots.find(pe=>pe.larkAppId===v);V&&(V.disableStreamingCard=G.disableStreamingCard,V.writableTerminalLinkInCard=G.writableTerminalLinkInCard,V.privateCard=G.privateCard,V.autoStartOnGroupJoin=G.autoStartOnGroupJoin,V.autoStartOnGroupJoinPrompt=G.autoStartOnGroupJoinPrompt,V.autoStartOnNewTopic=G.autoStartOnNewTopic,V.regularGroupReplyMode=G.regularGroupReplyMode,V.regularGroupMentionMode=G.regularGroupMentionMode,V.docSubscribeDefaultMode=G.docSubscribeDefaultMode)}else N.textContent=`\u2717 ${G.error??z.status}`,N.classList.add("hint-warn-inline")}catch(z){N.textContent=`\u2717 ${z?.message??z}`,N.classList.add("hint-warn-inline")}finally{W===ue?W.disabled=!!re?.checked:W.disabled=!1}}}re&&re.addEventListener("change",()=>{let J=re.checked;ue&&(ue.disabled=J),Oe&&(Oe.hidden=!J),be({disableStreamingCard:J},re)}),ue&&ue.addEventListener("change",()=>{be({writableTerminalLinkInCard:ue.checked},ue)}),Me&&Me.addEventListener("change",()=>{be({privateCard:Me.checked},Me)});let Ee=f.querySelector("input[data-action=toggle-sandbox]"),le=f.querySelector("[data-sandbox-status]");Ee&&Ee.addEventListener("change",async()=>{let J=Ee.checked;le&&(le.textContent="",le.className="oncall-status"),Ee.disabled=!0;try{let W=await fetch(`/api/bots/${encodeURIComponent(v)}/sandbox`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:J})}),N=await W.json().catch(()=>({}));if(W.ok&&N.ok){le&&(le.textContent=`\u2713 ${t("botDefaults.sandboxSaved")}`,le.classList.add("hint-ok"));let z=Be.bots.find(G=>G.larkAppId===v);z&&(z.sandbox=N.sandbox===!0)}else le&&(le.textContent=`\u2717 ${N.error??W.status}`,le.classList.add("hint-warn-inline")),Ee.checked=!J}catch(W){le&&(le.textContent=`\u2717 ${W?.message??W}`,le.classList.add("hint-warn-inline")),Ee.checked=!J}finally{Ee.disabled=!1}});let fe=f.querySelector("input[data-action=toggle-auto-join]"),de=f.querySelector("input[data-action=toggle-auto-topic]"),Ne=f.querySelector("textarea[data-input=autoJoinPrompt]"),Fe=f.querySelector("button[data-action=save-auto-join-prompt]"),qe=f.querySelector("[data-auto-start-status]");fe&&fe.addEventListener("change",()=>{be({autoStartOnGroupJoin:fe.checked},fe,qe)}),de&&de.addEventListener("change",()=>{be({autoStartOnNewTopic:de.checked},de,qe)}),Ne&&Fe&&Fe.addEventListener("click",()=>{be({autoStartOnGroupJoinPrompt:Ne.value},Fe,qe)});let Ge=f.querySelector("select[data-input=p2pMode]"),he=f.querySelector("[data-p2p-status]");Ge&&he&&Ge.addEventListener("change",async()=>{let J=Ge.value==="chat"?"chat":"thread";he.textContent="",he.className="oncall-status",Ge.disabled=!0;try{let W=await fetch(`/api/bots/${encodeURIComponent(v)}/p2p-mode`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({p2pMode:J})}),N=await W.json().catch(()=>({}));if(W.ok&&N.ok){he.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,he.classList.add("hint-ok");let z=Be.bots.find(G=>G.larkAppId===v);z&&(z.p2pMode=N.p2pMode==="chat"?"chat":"thread")}else he.textContent=`\u2717 ${N.error??W.status}`,he.classList.add("hint-warn-inline")}catch(W){he.textContent=`\u2717 ${W?.message??W}`,he.classList.add("hint-warn-inline")}finally{Ge.disabled=!1}});let ot=f.querySelector("select[data-input=regularGroupMode]"),$t=f.querySelector("[data-regular-group-status]");ot&&ot.addEventListener("change",()=>{be({regularGroupReplyMode:ot.value},ot,$t)});let st=f.querySelector("select[data-input=regularGroupMentionMode]"),Dt=f.querySelector("[data-mention-mode-status]");st&&st.addEventListener("change",()=>{be({regularGroupMentionMode:st.value},st,Dt)});let it=f.querySelector("select[data-input=docSubscribeDefaultMode]"),xe=f.querySelector("[data-doc-subscribe-mode-status]");it&&it.addEventListener("change",()=>{be({docSubscribeDefaultMode:it.value},it,xe)});let We=f.querySelector("textarea[data-input=teamRole]"),_e=f.querySelector("button[data-action=save-role]"),C=f.querySelector("button[data-action=delete-role]"),Y=f.querySelector("[data-role-status]");if(We&&_e&&C&&Y){let N=function(G){let V=n.querySelector(`.bd-card[data-appid="${CSS.escape(v)}"]`);if(!V)return;let pe=V.querySelector("textarea[data-input=teamRole]"),Re=V.querySelector("button[data-action=save-role]"),ft=V.querySelector("button[data-action=delete-role]");pe&&(pe.value=G,pe.disabled=!1),Re&&(Re.disabled=!1),ft&&(ft.disabled=!1)};var En=N;let J=`/api/team/local-bots/${encodeURIComponent(v)}/role`,W=Be.bots.find(G=>G.larkAppId===v);W&&typeof W.teamRole!="string"&&!W.teamRoleLoading&&(W.teamRoleLoading=!0,(async()=>{try{let G=await fetch(J),V=await G.json().catch(()=>({}));G.ok&&V.ok?(W.teamRole=V.role??"",N(W.teamRole)):(Y.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${V.error??G.status}`,Y.classList.add("hint-warn-inline"))}catch(G){Y.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${G?.message??G}`,Y.classList.add("hint-warn-inline")}finally{W.teamRoleLoading=!1}})());async function z(G,V,pe){if(Y&&!(!W||typeof W.teamRole!="string")){Y.textContent="",Y.className="oncall-status",_e.disabled=!0,C.disabled=!0;try{let Re=await fetch(J,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({role:G})}),ft=await Re.json().catch(()=>({}));Re.ok&&ft.ok?(W&&(W.teamRole=G.trim()),Y.textContent=`\u2713 ${pe?t("botDefaults.roleDeleted"):t("botDefaults.roleSaved")}`,Y.classList.add("hint-ok")):(Y.textContent=`\u2717 ${ft.error??Re.status}`,Y.classList.add("hint-warn-inline"))}catch(Re){Y.textContent=`\u2717 ${Re?.message??Re}`,Y.classList.add("hint-warn-inline")}finally{_e.disabled=!1,C.disabled=!1}}}_e.addEventListener("click",()=>z(We.value,_e,!1)),C.addEventListener("click",()=>{We.value="",z("",C,!0)})}let K=f.querySelector("input[data-action=toggle-restrict-grant]"),_=f.querySelector("input[data-input=quotaLimit]"),we=f.querySelector("button[data-action=save-quota]"),Ze=f.querySelector("button[data-action=off-quota]"),Se=f.querySelector("[data-grant-status]"),Yt=f.querySelector("[data-quota-state]");async function mt(J,W){if(Se){Se.textContent="",Se.className="oncall-status",W.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(v)}/grant-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(J)}),z=await N.json().catch(()=>({}));if(N.ok&&z.ok){Se.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,Se.classList.add("hint-ok");let G=typeof z.messageQuotaDefaultLimit=="number"?z.messageQuotaDefaultLimit:null,V=Be.bots.find(pe=>pe.larkAppId===v);V&&(V.restrictGrantCommands=z.restrictGrantCommands===!0,V.messageQuotaDefaultLimit=G),Yt&&(Yt.textContent=L(G)),_&&"messageQuotaDefaultLimit"in J&&(_.value=G==null?"":String(G))}else Se.textContent=`\u2717 ${z.error??N.status}`,Se.classList.add("hint-warn-inline")}catch(N){Se.textContent=`\u2717 ${N?.message??N}`,Se.classList.add("hint-warn-inline")}finally{W.disabled=!1}}}K&&K.addEventListener("change",()=>{mt({restrictGrantCommands:K.checked},K)}),_&&we&&we.addEventListener("click",()=>{let J=_.value.trim();if(J===""){mt({messageQuotaDefaultLimit:null},we);return}if(!/^[1-9]\d*$/.test(J)){Se&&(Se.textContent=`\u2717 ${t("botDefaults.quotaInvalid")}`,Se.className="oncall-status hint-warn-inline");return}mt({messageQuotaDefaultLimit:Number(J)},we)}),_&&Ze&&Ze.addEventListener("click",()=>{_.value="",mt({messageQuotaDefaultLimit:null},Ze)});let et=f.querySelector("input[data-input=maxLiveWorkers]"),St=f.querySelector("button[data-action=save-session-cap]"),Rt=f.querySelector("button[data-action=off-session-cap]"),Le=f.querySelector("[data-session-cap-status]"),Pt=f.querySelector("[data-session-cap-state]");async function Lt(J,W){if(Le){Le.textContent="",Le.className="oncall-status",W.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(v)}/max-live-workers`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({maxLiveWorkers:J})}),z=await N.json().catch(()=>({}));if(N.ok&&z.ok){Le.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,Le.classList.add("hint-ok");let G=typeof z.maxLiveWorkers=="number"?z.maxLiveWorkers:null,V=Be.bots.find(pe=>pe.larkAppId===v);V&&(V.maxLiveWorkers=G),Pt&&(Pt.textContent=S(G)),et&&(et.value=G==null?"":String(G))}else Le.textContent=`\u2717 ${z.error??N.status}`,Le.classList.add("hint-warn-inline")}catch(N){Le.textContent=`\u2717 ${N?.message??N}`,Le.classList.add("hint-warn-inline")}finally{W.disabled=!1}}}et&&St&&St.addEventListener("click",()=>{let J=et.value.trim();if(J===""){Lt(null,St);return}if(!/^[1-9]\d*$/.test(J)){Le&&(Le.textContent=`\u2717 ${t("botDefaults.maxLiveWorkersInvalid")}`,Le.className="oncall-status hint-warn-inline");return}Lt(Number(J),St)}),et&&Rt&&Rt.addEventListener("click",()=>{et.value="",Lt(null,Rt)})})}r(),Je().then(r),s.addEventListener("input",r)}var ie={skills:[],bots:[],trustProjectSkills:"off",delivery:"auto"},un=null,bi=2,bt=0;function hi(){return`<section class="page">
792
+ <div class="page-heading">
793
+ <div>
794
+ <p class="eyebrow">${t("nav.skills")}</p>
795
+ <h1>${t("skills.title")}</h1>
796
+ <p>${t("skills.subtitle")}</p>
797
+ </div>
798
+ <button type="button" id="skills-refresh">${t("skills.refresh")}</button>
799
+ </div>
800
+ <div id="skills-body"></div>
801
+ </section>`}function wi(e){let n=e.source??{};return n.type==="github"?`github:${n.owner}/${n.repo}/${n.path??""}`:n.type==="git"?`${n.url??"git"}#${n.path??""}`:n.type==="local-link"?"local-link":n.type==="local-copy"?"local-copy":String(n.type??"unknown")}function jt(e){return(e?.include??[]).filter(n=>n.startsWith("skill:")).map(n=>n.slice(6))}function yi(e){return jt(e).length}function vi(e){return jt(e).length>0}function ki(){return new Set(ie.skills.map(e=>e.name))}function $i(e){return ie.bots.filter(n=>jt(n.skills).includes(e)).map(n=>n.botName??n.larkAppId)}function Si(){return`<article class="bd-card skills-install-panel">
802
+ <div class="skills-install-title">
803
+ <h3 class="bd-section-title">${t("skills.install")}</h3>
804
+ <span class="skills-help-tip">
805
+ <button type="button" class="skills-help-button" aria-label="${t("skills.installInfoLabel")}">?</button>
806
+ <span class="skills-help-popover" role="tooltip">${t("skills.installInfo")}</span>
807
+ </span>
808
+ </div>
809
+ <div class="skills-install-grid">
810
+ <label><span>${t("skills.source")}</span>
811
+ <input type="text" data-install="source" placeholder="${t("skills.sourcePlaceholder")}">
812
+ </label>
813
+ <div class="bd-section-note skills-install-note">
814
+ <span><strong>${t("skills.sourceHelpRemoteLabel")}</strong>${t("skills.sourceHelpRemote")}</span>
815
+ <span><strong>${t("skills.sourceHelpLocalLabel")}</strong>${t("skills.sourceHelpLocal")}</span>
816
+ </div>
817
+ <label class="skills-install-field-wide"><span>${t("skills.path")}</span>
818
+ <input type="text" data-install="path" placeholder="${t("skills.pathPlaceholder")}">
819
+ </label>
820
+ <label class="skills-install-field-wide"><span>${t("skills.ref")}</span>
821
+ <input type="text" data-install="ref" placeholder="${t("skills.refPlaceholder")}">
822
+ </label>
823
+ </div>
824
+ <div class="actions">
825
+ <button type="button" class="primary" data-action="install">${t("skills.installSubmit")}</button>
826
+ <span class="oncall-status" data-skills-status></span>
827
+ </div>
828
+ </article>`}function Li(){if(ie.skills.length===0)return`<p class="empty">${t("skills.empty")}</p>`;pn();let e=$o(),n=bt*e;return`<div class="skills-list">${ie.skills.slice(n,n+e).map(s=>`
829
+ <article class="skills-row skills-installed-card" data-skill="${i(s.name)}">
830
+ <div class="skills-row-body">
831
+ <strong>${i(s.name)}</strong>
832
+ ${s.description?`<p>${i(s.description)}</p>`:""}
833
+ <small>${i(wi(s))}</small>
834
+ </div>
835
+ <div class="skills-card-actions">
836
+ <button type="button" data-action="update-skill">${t("skills.update")}</button>
837
+ <button type="button" data-action="remove-skill">${t("skills.remove")}</button>
838
+ </div>
839
+ </article>`).join("")}</div>`}function Ti(){let e=typeof window>"u"?1440:window.innerWidth;return e>=1600?4:e<=620?1:e<=980?2:3}function $o(){return Ti()*bi}function So(){return Math.max(1,Math.ceil(ie.skills.length/$o()))}function pn(){bt=Math.min(Math.max(0,bt),So()-1)}function Ii(){pn();let e=`<span class="skills-count-pill">${t("skills.skillCount",{count:ie.skills.length})}</span>`,n=So();return n<=1?e:`<div class="skills-installed-toolbar">
840
+ ${e}
841
+ <div class="skills-pager">
842
+ <button type="button" class="skills-pager-button" data-action="page-installed-skills" data-dir="-1" aria-label="${t("skills.prevPage")}" title="${t("skills.prevPage")}" ${bt===0?"disabled":""}>&lsaquo;</button>
843
+ <span>${t("skills.pageStatus",{page:bt+1,pages:n})}</span>
844
+ <button type="button" class="skills-pager-button" data-action="page-installed-skills" data-dir="1" aria-label="${t("skills.nextPage")}" title="${t("skills.nextPage")}" ${bt>=n-1?"disabled":""}>&rsaquo;</button>
845
+ </div>
846
+ </div>`}function Mi(){let e=[["auto",t("skills.deliveryAuto"),t("skills.deliveryAutoHelp")],["prompt",t("skills.deliveryPrompt"),t("skills.deliveryPromptHelp")],["native",t("skills.deliveryNative"),t("skills.deliveryNativeHelp")]];return`<article class="bd-card skills-defaults-panel">
847
+ <h3 class="bd-section-title">${t("skills.globalDefaults")}</h3>
848
+ <div class="skills-control-block">
849
+ <span class="skills-control-label">${t("skills.globalProject")}</span>
850
+ <div class="skills-choice-group skills-choice-group-compact skills-project-group">
851
+ ${[["off",t("skills.globalProjectOff"),t("skills.globalProjectOffHelp")],["all",t("skills.globalProjectAll"),t("skills.globalProjectAllHelp")]].map(([n,a,s])=>`<button type="button" class="skills-choice${ie.trustProjectSkills===n?" selected":""}" data-global-project-value="${n}" aria-pressed="${ie.trustProjectSkills===n?"true":"false"}">
852
+ <strong>${a}</strong><small>${s}</small>
853
+ </button>`).join("")}
854
+ </div>
855
+ </div>
856
+ <div class="skills-control-block">
857
+ <span class="skills-control-label">${t("skills.globalDelivery")}</span>
858
+ <div class="skills-choice-group skills-delivery-group">
859
+ ${e.map(([n,a,s])=>`<button type="button" class="skills-choice${ie.delivery===n?" selected":""}" data-global-delivery-value="${n}" aria-pressed="${ie.delivery===n?"true":"false"}">
860
+ <strong>${a}</strong><small>${s}</small>
861
+ </button>`).join("")}
862
+ </div>
863
+ </div>
864
+ </article>`}function Ei(e){let n=new Set(jt(e.skills)),a=ie.skills.filter(s=>!n.has(s.name));return a.length===0?`<button type="button" disabled>${t("skills.attach")}</button>`:`<select data-attach-picker>
865
+ ${a.map(s=>`<option value="${i(s.name)}">${i(s.name)}</option>`).join("")}
866
+ </select>
867
+ <button type="button" data-action="attach-skill">${t("skills.attach")}</button>`}function xi(e){if(e.error)return`<article class="bd-card skills-bot-card" data-appid="${i(e.larkAppId)}">
868
+ <header>${me({name:e.botName??e.larkAppId,larkAppId:e.larkAppId,size:"sm"})}
869
+ <strong>${i(e.botName??e.larkAppId)}</strong></header>
870
+ <p class="hint-warn-inline">${i(e.error)}</p>
871
+ </article>`;let n=jt(e.skills),a=ki();return`<article class="bd-card skills-bot-card" data-appid="${i(e.larkAppId)}">
872
+ <header class="skills-bot-head">
873
+ ${me({name:e.botName??e.larkAppId,larkAppId:e.larkAppId,size:"sm",dot:"ok"})}
874
+ <div><strong>${i(e.botName??e.larkAppId)}</strong><code>${i(e.larkAppId)}</code></div>
875
+ <span class="skills-count-pill">${t("skills.skillCount",{count:n.length})}</span>
876
+ </header>
877
+ <section class="bd-section">
878
+ <h3 class="bd-section-title">${t("skills.priority")}</h3>
879
+ ${n.length===0?`<p class="bd-section-note">${t("skills.noPriority")}</p>`:`<div class="skills-chip-list">${n.map(s=>{let o=!a.has(s);return`<span class="skills-priority-row${o?" skills-priority-dangling":""}" title="${o?i(t("skills.dangling")):""}">
880
+ <span class="skills-priority-name">${i(s)}${o?`<small>${t("skills.dangling")}</small>`:""}</span>
881
+ <button type="button" class="skills-priority-remove" data-action="detach-skill" data-name="${i(s)}" aria-label="${i(t("skills.detachNamed",{skill:s}))}">&times;</button>
882
+ </span>`}).join("")}</div>`}
883
+ <div class="actions skills-attach-row">${Ei(e)}</div>
884
+ </section>
885
+ <span class="oncall-status" data-bot-status></span>
886
+ </article>`}function Hi(){return ie.bots.reduce((e,n)=>e+yi(n.skills),0)}function Ci(){return ie.bots.filter(e=>vi(e.skills)).length}function Ai(){return`<section class="skills-overview">
887
+ <div class="skills-overview-copy">
888
+ <h2>${t("skills.overviewTitle")}</h2>
889
+ <p>${t("skills.overviewBody")}</p>
890
+ </div>
891
+ <div class="skills-metric-strip">
892
+ <span><small>${t("skills.metricInstalled")}</small><strong>${ie.skills.length}</strong></span>
893
+ <span><small>${t("skills.metricBots")}</small><strong>${Ci()}/${ie.bots.length}</strong></span>
894
+ <span><small>${t("skills.metricAttached")}</small><strong>${Hi()}</strong></span>
895
+ </div>
896
+ </section>`}function Di(){let e=`<span class="skills-count-pill">${t("skills.botCount",{count:ie.bots.length})}</span>`;return ie.bots.length<=3?e:`<div class="skills-bot-rail-actions">
897
+ <button type="button" class="skills-rail-button" data-action="scroll-bots" data-dir="-1" aria-label="${t("skills.scrollBotsPrev")}" title="${t("skills.scrollBotsPrev")}">&lsaquo;</button>
898
+ ${e}
899
+ <button type="button" class="skills-rail-button" data-action="scroll-bots" data-dir="1" aria-label="${t("skills.scrollBotsNext")}" title="${t("skills.scrollBotsNext")}">&rsaquo;</button>
900
+ </div>`}function Ri(){return un?`<p class="hint-warn">${i(un)}</p>`:`<div class="skills-page-grid">
901
+ <aside class="skills-side-rail">
902
+ ${Mi()}
903
+ ${Si()}
904
+ </aside>
905
+ <section class="skills-main-panel">
906
+ ${Ai()}
907
+ <section class="skills-bots-panel">
908
+ <div class="skills-section-head skills-section-head-row">
909
+ <div>
910
+ <h2>${t("skills.bots")}</h2>
911
+ <p>${t("skills.botsHelp")}</p>
912
+ </div>
913
+ ${Di()}
914
+ </div>
915
+ <div class="skills-bot-grid">${ie.bots.map(xi).join("")}</div>
916
+ </section>
917
+ <section class="bd-card skills-installed-panel">
918
+ <div class="skills-section-head skills-section-head-row">
919
+ <div>
920
+ <h2>${t("skills.installed")}</h2>
921
+ <p>${t("skills.installedHelp")}</p>
922
+ </div>
923
+ ${Ii()}
924
+ </div>
925
+ ${Li()}
926
+ </section>
927
+ </section>
928
+ </div>`}async function Pi(){try{let[e,n]=await Promise.all([fetch("/api/skills"),fetch("/api/bots")]),a=await e.json().catch(()=>({})),s=await n.json().catch(()=>({}));if(!e.ok)throw new Error(a?.error??`skills HTTP ${e.status}`);if(!n.ok)throw new Error(s?.error??`bots HTTP ${n.status}`);ie={skills:Array.isArray(a.skills)?a.skills:[],bots:Array.isArray(s.bots)?s.bots:[],trustProjectSkills:a.trustProjectSkills==="all"?"all":"off",delivery:a.delivery==="prompt"||a.delivery==="native"?a.delivery:"auto"},pn(),un=null}catch(e){un=e?.message??String(e)}}async function nt(e,n){let a=await fetch(e,{...n,headers:{"content-type":"application/json",...n.headers??{}}}),s=await a.json().catch(()=>({}));if(!a.ok||s.ok===!1){let o=new Error(s?.error??`HTTP ${a.status}`);throw o.status=a.status,o.body=s,o}return s}function Bi(e){return new Promise(n=>setTimeout(n,e))}async function Lo(e){e.innerHTML=hi();let n=e.querySelector("#skills-body"),a=e.querySelector("#skills-refresh");async function s(){n.innerHTML=lt(),await Pi(),k()}function o(w){return w?.querySelector("[data-skills-status], [data-bot-status]")??null}function r(w,u,S){w&&(w.textContent=u,w.className=`oncall-status ${S?"hint-ok":"hint-warn-inline"}`)}function d(w,u){n.querySelectorAll(w).forEach(S=>{S.disabled=u})}function p(w,u,S){n.querySelectorAll(w).forEach(x=>{let A=x.dataset[u]===S;x.classList.toggle("selected",A),x.setAttribute("aria-pressed",A?"true":"false")})}function k(){n.innerHTML=Ri(),E()}async function $(w,u){let S=w;for(r(u,t("skills.jobRunning"),!0);;){if(S.status==="succeeded"){r(u,t("skills.saved"),!0),await s();return}if(S.status==="failed")throw new Error(S.error??"job_failed");await Bi(800),S=(await nt(`/api/skills/jobs/${encodeURIComponent(S.id)}`,{method:"GET"})).job}}function E(){n.querySelector('[data-action="install"]')?.addEventListener("click",async()=>{let w=n.querySelector(".skills-install-panel"),u=o(w),S=n.querySelector('[data-action="install"]'),x=n.querySelector('[data-install="source"]')?.value.trim()??"",A=n.querySelector('[data-install="path"]')?.value.trim()??"",L=n.querySelector('[data-install="ref"]')?.value.trim()??"";try{S&&(S.disabled=!0);let H=await nt("/api/skills/install",{method:"POST",body:JSON.stringify({source:x,path:A||void 0,ref:L||void 0})});await $(H.job,u)}catch(H){r(u,`${t("skills.failed")}: ${H?.message??H}`,!1)}finally{S&&(S.disabled=!1)}}),n.querySelectorAll("[data-global-project-value]").forEach(w=>w.addEventListener("click",async()=>{let u=w.dataset.globalProjectValue==="all"?"all":"off";if(ie.trustProjectSkills!==u)try{d("[data-global-project-value]",!0);let S=await nt("/api/skills/global",{method:"PUT",body:JSON.stringify({trustProjectSkills:u})});ie.trustProjectSkills=S.trustProjectSkills==="all"?"all":u,p("[data-global-project-value]","globalProjectValue",ie.trustProjectSkills)}catch(S){window.alert(`${t("skills.failed")}: ${S?.message??S}`)}finally{d("[data-global-project-value]",!1)}})),n.querySelectorAll("[data-global-delivery-value]").forEach(w=>w.addEventListener("click",async()=>{let u=w.dataset.globalDeliveryValue==="prompt"||w.dataset.globalDeliveryValue==="native"?w.dataset.globalDeliveryValue:"auto";if(ie.delivery!==u)try{d("[data-global-delivery-value]",!0);let S=await nt("/api/skills/global",{method:"PUT",body:JSON.stringify({delivery:u})});ie.delivery=S.delivery==="prompt"||S.delivery==="native"?S.delivery:u,p("[data-global-delivery-value]","globalDeliveryValue",ie.delivery)}catch(S){window.alert(`${t("skills.failed")}: ${S?.message??S}`)}finally{d("[data-global-delivery-value]",!1)}})),n.querySelectorAll('[data-action="scroll-bots"]').forEach(w=>w.addEventListener("click",()=>{let u=n.querySelector(".skills-bot-grid"),S=u?.querySelector(".skills-bot-card");if(!u||!S)return;let x=window.getComputedStyle(u),A=Number.parseFloat(x.columnGap||x.gap||"0")||0,L=w.dataset.dir==="-1"?-1:1;u.scrollBy({left:L*(S.getBoundingClientRect().width+A),behavior:"smooth"})})),n.querySelectorAll('[data-action="page-installed-skills"]').forEach(w=>w.addEventListener("click",()=>{let u=w.dataset.dir==="-1"?-1:1;bt+=u,pn(),k()})),n.querySelectorAll(".skills-row").forEach(w=>{let u=w.dataset.skill??"";w.querySelector('[data-action="update-skill"]')?.addEventListener("click",async()=>{let S=w.querySelector('[data-action="update-skill"]'),x=n.querySelector(".skills-install-panel"),A=o(x);try{S&&(S.disabled=!0);let L=await nt(`/api/skills/${encodeURIComponent(u)}/update`,{method:"POST",body:"{}"});await $(L.job,A)}catch(L){window.alert(`${t("skills.failed")}: ${L?.message??L}`)}finally{S&&(S.disabled=!1)}}),w.querySelector('[data-action="remove-skill"]')?.addEventListener("click",async()=>{if(window.confirm(`${t("skills.remove")} ${u}?`))try{await nt(`/api/skills/${encodeURIComponent(u)}`,{method:"DELETE",body:"{}"}),await s()}catch(S){if(S?.status===409&&S?.body?.error==="skill_in_use"){let x=Array.isArray(S.body.affectedBots)?S.body.affectedBots.map(L=>{let H=L?.botName||L?.larkAppId;return H?`${H}`:""}).filter(Boolean):$i(u),A=[x.length?`Bot: ${x.join(", ")}`:""].filter(Boolean).join("; ")||"-";if(!window.confirm(t("skills.removeInUse",{skill:u,refs:A})))return;try{await nt(`/api/skills/${encodeURIComponent(u)}?force=1`,{method:"DELETE",body:"{}"}),await s();return}catch(L){window.alert(`${t("skills.failed")}: ${L?.message??L}`);return}}window.alert(`${t("skills.failed")}: ${S?.message??S}`)}})}),n.querySelectorAll(".skills-bot-card").forEach(w=>{let u=w.dataset.appid??"",S=ie.bots.find(x=>x.larkAppId===u);S&&(w.querySelector('[data-action="attach-skill"]')?.addEventListener("click",async()=>{let x=w.querySelector("[data-attach-picker]")?.value;if(x)try{let A=await nt(`/api/bots/${encodeURIComponent(u)}/skills`,{method:"PUT",body:JSON.stringify({action:"attach",name:x})});S.skills=A.skills??null,k()}catch(A){r(o(w),`${t("skills.failed")}: ${A?.message??A}`,!1)}}),w.querySelectorAll('[data-action="detach-skill"]').forEach(x=>{x.addEventListener("click",async()=>{let A=x.dataset.name;if(A)try{let L=await nt(`/api/bots/${encodeURIComponent(u)}/skills`,{method:"PUT",body:JSON.stringify({action:"detach",name:A})});S.skills=L.skills??null,k()}catch(L){r(o(w),`${t("skills.failed")}: ${L?.message??L}`,!1)}})}))})}a.onclick=()=>{s()},await s()}var Qn=4096,fn=[],Ye=null,Qe=null,Ue="",Ht=new Set;function Oi(){return`<section class="page roles-page">
786
929
  <div class="page-heading">
787
930
  <div>
788
931
  <p class="eyebrow">${t("nav.roles")}</p>
@@ -821,40 +964,40 @@ ${$.join(`
821
964
  </div>
822
965
  </div>
823
966
  </div>
824
- </section>`}async function rn(){ln=((await(await fetch("/api/groups")).json()).chats??[]).map(o=>({chatId:o.chatId,name:o.name??o.chatId,memberBots:(o.memberBots??[]).map(s=>({larkAppId:s.larkAppId,botName:s.botName??s.larkAppId,inChat:s.inChat??!1,hasRole:s.hasRole??!1,oncallChat:s.oncallChat??null}))}))}async function ha(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`)).json()}async function li(e,n,o){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({content:o})})).ok}async function di(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`,{method:"DELETE"})).ok}function wa(e){return e.memberBots.filter(n=>n.inChat&&n.hasRole).length}function ci(e){return e.memberBots.filter(n=>n.inChat).length}function mt(e=""){let n=document.getElementById("roles-tree");if(!n)return;let o=e.toLowerCase(),s=ln.filter(a=>{if(!o)return!0;let i=a.chatId.toLowerCase().includes(o)||(a.name??"").toLowerCase().includes(o),d=a.memberBots.some(p=>p.larkAppId.toLowerCase().includes(o)||(p.botName??"").toLowerCase().includes(o));return i||d});if(s.length===0){n.innerHTML=`<div class="roles-empty">${t("roles.noChats")}</div>`;return}n.innerHTML=s.map(a=>{let i=Mt.has(a.chatId),d=a.memberBots.filter(T=>T.inChat),p=i?"\u25BE":"\u25B8",v=wa(a),k=ci(a),I=i?d.map(T=>`
825
- <div class="roles-bot-row ${Ye===a.chatId&&Ve===T.larkAppId?"selected":""}"
826
- data-group-id="${r(a.chatId)}"
827
- data-bot-id="${r(T.larkAppId)}">
967
+ </section>`}async function mn(){fn=((await(await fetch("/api/groups")).json()).chats??[]).map(a=>({chatId:a.chatId,name:a.name??a.chatId,memberBots:(a.memberBots??[]).map(s=>({larkAppId:s.larkAppId,botName:s.botName??s.larkAppId,inChat:s.inChat??!1,hasRole:s.hasRole??!1,oncallChat:s.oncallChat??null}))}))}async function Io(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`)).json()}async function Ni(e,n,a){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({content:a})})).ok}async function qi(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`,{method:"DELETE"})).ok}function Mo(e){return e.memberBots.filter(n=>n.inChat&&n.hasRole).length}function ji(e){return e.memberBots.filter(n=>n.inChat).length}function ht(e=""){let n=document.getElementById("roles-tree");if(!n)return;let a=e.toLowerCase(),s=fn.filter(o=>{if(!a)return!0;let r=o.chatId.toLowerCase().includes(a)||(o.name??"").toLowerCase().includes(a),d=o.memberBots.some(p=>p.larkAppId.toLowerCase().includes(a)||(p.botName??"").toLowerCase().includes(a));return r||d});if(s.length===0){n.innerHTML=`<div class="roles-empty">${t("roles.noChats")}</div>`;return}n.innerHTML=s.map(o=>{let r=Ht.has(o.chatId),d=o.memberBots.filter(w=>w.inChat),p=r?"\u25BE":"\u25B8",k=Mo(o),$=ji(o),E=r?d.map(w=>`
968
+ <div class="roles-bot-row ${Ye===o.chatId&&Qe===w.larkAppId?"selected":""}"
969
+ data-group-id="${i(o.chatId)}"
970
+ data-bot-id="${i(w.larkAppId)}">
828
971
  <span class="roles-bot-indent"></span>
829
- ${fe({name:T.botName,larkAppId:T.larkAppId,size:"sm"})}
972
+ ${me({name:w.botName,larkAppId:w.larkAppId,size:"sm"})}
830
973
  <div class="roles-bot-info">
831
- <div class="roles-bot-name">${r(T.botName)}</div>
832
- <div class="roles-bot-id">${r(T.larkAppId)}</div>
974
+ <div class="roles-bot-name">${i(w.botName)}</div>
975
+ <div class="roles-bot-id">${i(w.larkAppId)}</div>
833
976
  </div>
834
- <span class="roles-badge ${T.hasRole?"has-role":"no-role"}">
835
- ${T.hasRole?t("roles.configured"):t("roles.unconfigured")}
977
+ <span class="roles-badge ${w.hasRole?"has-role":"no-role"}">
978
+ ${w.hasRole?t("roles.configured"):t("roles.unconfigured")}
836
979
  </span>
837
980
  </div>`).join(""):"";return`
838
981
  <div class="roles-group-section">
839
- <div class="roles-group-row ${i?"expanded":""} ${Ye===a.chatId&&!Ve?"selected":""}"
840
- data-group-id="${r(a.chatId)}">
982
+ <div class="roles-group-row ${r?"expanded":""} ${Ye===o.chatId&&!Qe?"selected":""}"
983
+ data-group-id="${i(o.chatId)}">
841
984
  <span class="roles-group-arrow">${p}</span>
842
985
  <span class="roles-group-icon" aria-hidden="true"><svg viewBox="0 0 16 16"><circle cx="5.6" cy="5.8" r="2.4"/><path d="M1.8 13.2c.5-2.4 2-3.6 3.8-3.6s3.3 1.2 3.8 3.6"/><circle cx="11" cy="6.8" r="1.9"/><path d="M9.8 12.6c.4-1.7 1.5-2.6 2.8-2.6 1 0 1.9.5 2.4 1.6"/></svg></span>
843
986
  <div class="roles-group-info">
844
- <div class="roles-group-name">${r(a.name??a.chatId)}</div>
987
+ <div class="roles-group-name">${i(o.name??o.chatId)}</div>
845
988
  <div class="roles-group-meta">
846
- ${v}/${k} ${t("roles.botsWithRoles")}
989
+ ${k}/${$} ${t("roles.botsWithRoles")}
847
990
  </div>
848
991
  </div>
849
992
  <span class="roles-group-chevron"></span>
850
993
  </div>
851
- <div class="roles-bot-list">${I}</div>
852
- </div>`}).join(""),n.querySelectorAll(".roles-group-row").forEach(a=>{a.addEventListener("click",()=>{let i=a.dataset.groupId;i&&(Mt.has(i)?Mt.delete(i):Mt.add(i),mt(document.getElementById("roles-search")?.value??""))})}),n.querySelectorAll(".roles-bot-row").forEach(a=>{a.addEventListener("click",i=>{i.stopPropagation();let d=a.dataset.groupId,p=a.dataset.botId;d&&p&&ui(d,p)})})}async function ui(e,n){Ye=e,Ve=n;let o=await ha(n,e),s=document.getElementById("roles-editor-empty"),a=document.getElementById("roles-editor-form"),i=document.getElementById("roles-editor-textarea"),d=document.getElementById("roles-editor-group-name"),p=document.getElementById("roles-editor-bot-name"),v=document.getElementById("roles-editor-chat-id");s&&(s.style.display="none"),a&&(a.style.display="");let k=ln.find(g=>g.chatId===e),I=k?.memberBots.find(g=>g.larkAppId===n);d&&(d.textContent=k?.name??e),p&&(p.textContent=I?.botName??n),v&&(v.textContent=`${e} \xB7 ${n}`),Ue=o.content??"",i&&(i.value=Ue,i.focus()),Wn(),Kn(),mt(document.getElementById("roles-search")?.value??"");let T=document.getElementById("roles-delete");T&&(T.style.display=o.hasRole?"":"none")}function Wn(){let e=document.getElementById("roles-editor-bytecount");if(!e)return;let n=new TextEncoder().encode(Ue).length;e.textContent=`${n} / ${zn} bytes`,e.className=`roles-bytecount ${n>3800?"warn":""} ${n>zn?"over":""}`,pi(n)}function pi(e){let n=document.getElementById("roles-save");if(!n)return;let o=e??new TextEncoder().encode(Ue).length;n.disabled=o>zn||Ue.trim().length===0}function Kn(){let e=document.getElementById("roles-preview");e&&(Ue.trim()?e.innerHTML=`<strong>${t("roles.preview")}</strong><pre>${r(Ue)}</pre>`:e.innerHTML=`<small>${t("roles.previewEmpty")}</small>`)}function ba(){Ye=null,Ve=null,Ue="";let e=document.getElementById("roles-editor-empty"),n=document.getElementById("roles-editor-form"),o=document.getElementById("roles-editor-textarea"),s=document.getElementById("roles-delete");e&&(e.style.display=""),n&&(n.style.display="none"),o&&(o.value=""),s&&(s.style.display="none")}async function ya(e){e.innerHTML=ri(),Mt.clear(),ba();let n=document.getElementById("roles-tree");n&&(n.innerHTML=St()),await rn(),await Ke();for(let o of ln)wa(o)>0&&Mt.add(o.chatId);mt(),document.getElementById("roles-search")?.addEventListener("input",o=>{mt(o.target.value)}),document.getElementById("roles-refresh")?.addEventListener("click",async()=>{if(await rn(),mt(document.getElementById("roles-search")?.value??""),Ye&&Ve){let o=await ha(Ve,Ye),s=document.getElementById("roles-editor-textarea");s&&(s.value=o.content??""),Ue=o.content??"",Wn(),Kn();let a=document.getElementById("roles-delete");a&&(a.style.display=o.hasRole?"":"none")}}),document.getElementById("roles-save")?.addEventListener("click",async function(){if(!(!Ye||!Ve)){this.disabled=!0,this.textContent="...";try{if(await li(Ve,Ye,Ue)){await rn(),mt(document.getElementById("roles-search")?.value??"");let s=document.getElementById("roles-delete");s&&(s.style.display="");let a=document.createElement("span");a.className="roles-saved-flash",a.textContent=` ${t("roles.saved")}`,document.querySelector(".roles-editor-footer")?.appendChild(a),setTimeout(()=>a.remove(),2e3)}else{let s=document.createElement("span");s.className="roles-saved-flash roles-save-error",s.textContent=Ue.trim().length===0?` ${t("roles.emptyError")}`:` ${t("roles.saveFailed")}`,document.querySelector(".roles-editor-footer")?.appendChild(s),setTimeout(()=>s.remove(),3e3)}}finally{this.disabled=!1,this.textContent=t("roles.save")}}}),document.getElementById("roles-delete")?.addEventListener("click",async function(){if(!(!Ye||!Ve)&&confirm(t("roles.confirmDelete"))){this.disabled=!0,this.textContent="...";try{await di(Ve,Ye)&&(await rn(),ba(),mt(document.getElementById("roles-search")?.value??""))}finally{this.disabled=!1,this.textContent=t("roles.delete")}}}),document.getElementById("roles-editor-textarea")?.addEventListener("input",o=>{Ue=o.target.value,Wn(),Kn()})}async function un(e){let n=await fetch(e);return{status:n.status,body:await n.json().catch(()=>({}))}}async function pn(e,n,o){let s=await fetch(n,{method:e,headers:{"content-type":"application/json"},body:o?JSON.stringify(o):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}var gt=(e,n)=>pn("POST",e,n),mi=(e,n)=>pn("PUT",e,n),Jn=[],va=[],ka="",dn="",Yn=new Map,cn=new Map,Nt=new Set,Pt=new Set;function te(e){return document.getElementById(e)}function mn(){return[...Jn,...va]}function ft(e){let n=Yn.get(e);return n||(n=new Set,Yn.set(e,n)),n}function fi(e){return mn().find(n=>n.key===e)}function $a(e){let n=(o,s,a)=>`<a href="${o}" style="padding:6px 14px;border-radius:8px;text-decoration:none;font-size:14px;font-weight:600;${a?"background:var(--accent);color:var(--on-accent)":"color:var(--muted);background:var(--surface-muted)"}">${s}</a>`;return`<div style="display:flex;gap:8px;margin-bottom:14px">${n("#/team",t("team.navHome"),e==="home")}${n("#/team/manage",t("team.navManage"),e==="manage")}</div>`}function gi(){return`<section class="page">
994
+ <div class="roles-bot-list">${E}</div>
995
+ </div>`}).join(""),n.querySelectorAll(".roles-group-row").forEach(o=>{o.addEventListener("click",()=>{let r=o.dataset.groupId;r&&(Ht.has(r)?Ht.delete(r):Ht.add(r),ht(document.getElementById("roles-search")?.value??""))})}),n.querySelectorAll(".roles-bot-row").forEach(o=>{o.addEventListener("click",r=>{r.stopPropagation();let d=o.dataset.groupId,p=o.dataset.botId;d&&p&&Ui(d,p)})})}async function Ui(e,n){Ye=e,Qe=n;let a=await Io(n,e),s=document.getElementById("roles-editor-empty"),o=document.getElementById("roles-editor-form"),r=document.getElementById("roles-editor-textarea"),d=document.getElementById("roles-editor-group-name"),p=document.getElementById("roles-editor-bot-name"),k=document.getElementById("roles-editor-chat-id");s&&(s.style.display="none"),o&&(o.style.display="");let $=fn.find(u=>u.chatId===e),E=$?.memberBots.find(u=>u.larkAppId===n);d&&(d.textContent=$?.name??e),p&&(p.textContent=E?.botName??n),k&&(k.textContent=`${e} \xB7 ${n}`),Ue=a.content??"",r&&(r.value=Ue,r.focus()),Xn(),Zn(),ht(document.getElementById("roles-search")?.value??"");let w=document.getElementById("roles-delete");w&&(w.style.display=a.hasRole?"":"none")}function Xn(){let e=document.getElementById("roles-editor-bytecount");if(!e)return;let n=new TextEncoder().encode(Ue).length;e.textContent=`${n} / ${Qn} bytes`,e.className=`roles-bytecount ${n>3800?"warn":""} ${n>Qn?"over":""}`,Fi(n)}function Fi(e){let n=document.getElementById("roles-save");if(!n)return;let a=e??new TextEncoder().encode(Ue).length;n.disabled=a>Qn||Ue.trim().length===0}function Zn(){let e=document.getElementById("roles-preview");e&&(Ue.trim()?e.innerHTML=`<strong>${t("roles.preview")}</strong><pre>${i(Ue)}</pre>`:e.innerHTML=`<small>${t("roles.previewEmpty")}</small>`)}function To(){Ye=null,Qe=null,Ue="";let e=document.getElementById("roles-editor-empty"),n=document.getElementById("roles-editor-form"),a=document.getElementById("roles-editor-textarea"),s=document.getElementById("roles-delete");e&&(e.style.display=""),n&&(n.style.display="none"),a&&(a.value=""),s&&(s.style.display="none")}async function Eo(e){e.innerHTML=Oi(),Ht.clear(),To();let n=document.getElementById("roles-tree");n&&(n.innerHTML=lt()),await mn(),await Je();for(let a of fn)Mo(a)>0&&Ht.add(a.chatId);ht(),document.getElementById("roles-search")?.addEventListener("input",a=>{ht(a.target.value)}),document.getElementById("roles-refresh")?.addEventListener("click",async()=>{if(await mn(),ht(document.getElementById("roles-search")?.value??""),Ye&&Qe){let a=await Io(Qe,Ye),s=document.getElementById("roles-editor-textarea");s&&(s.value=a.content??""),Ue=a.content??"",Xn(),Zn();let o=document.getElementById("roles-delete");o&&(o.style.display=a.hasRole?"":"none")}}),document.getElementById("roles-save")?.addEventListener("click",async function(){if(!(!Ye||!Qe)){this.disabled=!0,this.textContent="...";try{if(await Ni(Qe,Ye,Ue)){await mn(),ht(document.getElementById("roles-search")?.value??"");let s=document.getElementById("roles-delete");s&&(s.style.display="");let o=document.createElement("span");o.className="roles-saved-flash",o.textContent=` ${t("roles.saved")}`,document.querySelector(".roles-editor-footer")?.appendChild(o),setTimeout(()=>o.remove(),2e3)}else{let s=document.createElement("span");s.className="roles-saved-flash roles-save-error",s.textContent=Ue.trim().length===0?` ${t("roles.emptyError")}`:` ${t("roles.saveFailed")}`,document.querySelector(".roles-editor-footer")?.appendChild(s),setTimeout(()=>s.remove(),3e3)}}finally{this.disabled=!1,this.textContent=t("roles.save")}}}),document.getElementById("roles-delete")?.addEventListener("click",async function(){if(!(!Ye||!Qe)&&confirm(t("roles.confirmDelete"))){this.disabled=!0,this.textContent="...";try{await qi(Qe,Ye)&&(await mn(),To(),ht(document.getElementById("roles-search")?.value??""))}finally{this.disabled=!1,this.textContent=t("roles.delete")}}}),document.getElementById("roles-editor-textarea")?.addEventListener("input",a=>{Ue=a.target.value,Xn(),Zn()})}async function hn(e){let n=await fetch(e);return{status:n.status,body:await n.json().catch(()=>({}))}}async function wn(e,n,a){let s=await fetch(n,{method:e,headers:{"content-type":"application/json"},body:a?JSON.stringify(a):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}var yt=(e,n)=>wn("POST",e,n),Gi=(e,n)=>wn("PUT",e,n),ea=[],xo=[],Ho="",gn="",ta=new Map,bn=new Map,Ut=new Set,Ft=new Set;function te(e){return document.getElementById(e)}function yn(){return[...ea,...xo]}function wt(e){let n=ta.get(e);return n||(n=new Set,ta.set(e,n)),n}function _i(e){return yn().find(n=>n.key===e)}function Co(e){let n=(a,s,o)=>`<a href="${a}" style="padding:6px 14px;border-radius:8px;text-decoration:none;font-size:14px;font-weight:600;${o?"background:var(--accent);color:var(--on-accent)":"color:var(--muted);background:var(--surface-muted)"}">${s}</a>`;return`<div style="display:flex;gap:8px;margin-bottom:14px">${n("#/team",t("team.navHome"),e==="home")}${n("#/team/manage",t("team.navManage"),e==="manage")}</div>`}function Wi(){return`<section class="page">
853
996
  <div class="page-heading"><div>
854
997
  <p class="eyebrow">${t("team.eyebrow")}</p><h1>${t("team.homeTitle")}</h1>
855
998
  <p class="tf-lede">${t("team.homeLede")}</p>
856
999
  </div></div>
857
- ${$a("home")}
1000
+ ${Co("home")}
858
1001
  <div class="card" style="margin-bottom:16px">
859
1002
  <h2 style="margin-top:0">${t("team.localDeployTitle")}</h2>
860
1003
  <p>${t("team.myIdentity")}<b id="tf-owner">${t("team.unbound")}</b>
@@ -883,12 +1026,12 @@ ${$a("home")}
883
1026
  </div>
884
1027
  </div>
885
1028
  </div>
886
- </section>`}function bi(e){let n=(te("tf-search").value||"").trim().toLowerCase();if(n&&!((e.name||"")+" "+(e.cliId||"")+" "+(e.capability||"")).toLowerCase().includes(n))return!1;let o=te("tf-cli").value;return!(o&&e.cliId!==o||te("tf-fcap").checked&&!e.capability||te("tf-frole").checked&&!e.hasTeamRole)}function hi(e,n){let o=[...e.deployments].sort((a,i)=>a.local===i.local?0:a.local?-1:1),s="";for(let a of o){let i=n.filter(g=>g.deployment.id===a.id);if(!i.length)continue;let d=a.id===ka,p=d?t("team.tagLocal"):a.stale?t("team.tagRemoteStale"):t("team.tagRemote"),v=e.kind==="local"&&!d?` <button class="tf-rmmember ghost" data-team="${r(e.teamId)}" data-dep="${r(a.id)}" data-name="${r(a.name)}" style="font-size:12px">${t("team.removeMember")}</button>`:"",k=`${e.key}::${a.id}`,I=Pt.has(k),T=i.filter(g=>ft(e.key).has(g.larkAppId)).length;if(s+=`<div class="tf-dep-h" data-dk="${r(k)}" style="cursor:pointer;margin:10px 0 2px"><b>${I?"\u25BE":"\u25B8"} ${r(a.name)}</b> <span class="muted" style="font-size:12px">${t("team.depTag",{tag:p})} \xB7 ${t("team.depCount",{count:i.length})}${T?t("team.depSelected",{n:T}):""}</span>${v}</div>`,!!I){s+='<table style="width:100%;border-collapse:collapse;font-size:14px"><tbody>';for(let g of i){let R=r(g.larkAppId),A=ft(e.key).has(g.larkAppId)?" checked":"",O=g.deployment.stale?"opacity:.55":"",M=d?`<input class="tf-cap" data-app="${R}" value="${r(g.capability||"")}" placeholder="${t("team.capPh")}" style="width:92%;padding:3px 6px">`:g.capability?r(g.capability):'<span class="muted">\u2014</span>',E=g.hasTeamRole?d?`<button class="tf-role" data-app="${R}" data-name="${r(g.name)}">${t("team.viewRole")}</button>`:t("team.hasRoleShort"):'<span class="muted">\u2014</span>';s+=`<tr style="${O}"><td style="padding:4px 8px"><input type="checkbox" class="tf-pick" data-tk="${r(e.key)}" data-app="${R}"${A}></td><td style="padding:4px 8px">${r(g.name)}</td><td style="padding:4px 8px" class="muted">${r(g.cliId)}</td><td style="padding:4px 8px">${M}</td><td style="padding:4px 8px">${E}</td></tr>`}s+="</tbody></table>"}}return s||(s=`<p class="muted" style="margin:8px 0 0">${t("team.noMatch")}</p>`),s+=`<div style="margin-top:12px;display:flex;gap:8px;flex-wrap:wrap;align-items:center"><input class="tf-gname" data-tk="${r(e.key)}" value="${r(cn.get(e.key)||"")}" placeholder="${t("team.gnamePh")}" style="min-width:200px"><button class="tf-grp primary" data-tk="${r(e.key)}">${t("team.pullGroupBtn")}</button><span class="muted" style="font-size:13px">${t("team.pullGroupHint")}</span><span class="tf-gout" data-tk="${r(e.key)}" style="font-size:13px;display:block;flex-basis:100%"></span></div>`,s}function rt(){let e=te("tf-teams"),n=mn();if(!n.length){e.innerHTML=`<p class="muted">${t("team.noTeams")}</p>`,te("tf-count").textContent="";return}let o="",s=new Set,a=new Set;for(let p of n){let v=p.bots.filter(bi);v.forEach(g=>s.add(g.larkAppId)),p.bots.forEach(g=>a.add(g.larkAppId));let k=new Set(v.map(g=>g.larkAppId));[...ft(p.key)].forEach(g=>{k.has(g)||ft(p.key).delete(g)});let I=!Nt.has(p.key),T=p.kind==="remote"?p.ok?` <span class="ok" style="font-size:12px">${t("team.connected")}</span>`:` <span class="err" style="font-size:12px">${t("team.connectFail",{error:r(p.error||"")})}</span>`:` <span class="muted" style="font-size:12px">${t("team.iHost")}</span>`;o+=`<div class="card" style="margin:0 0 12px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)"><div class="tf-team-h" data-tk="${r(p.key)}" style="cursor:pointer;display:flex;align-items:center;gap:8px;flex-wrap:wrap"><b style="font-size:15px">${I?"\u25B8":"\u25BE"} ${r(p.label)}</b>`+(p.sub?` <span class="muted" style="font-size:12px">${r(p.sub)}</span>`:"")+T+` <span class="muted" style="font-size:12px">\xB7 ${t("team.teamMeta",{deps:p.deployments.length,bots:p.bots.length})}</span></div>`,I||(o+=p.kind==="remote"&&!p.ok?`<p class="muted" style="margin:8px 0 0">${t("team.rosterFail")}</p>`:hi(p,v)),o+="</div>"}e.innerHTML=o;let i=n.length>1?t("team.acrossTeams",{n:n.length}):"",d=s.size===a.size?`${a.size}`:`${s.size} / ${a.size}`;te("tf-count").textContent=`\xB7 ${d} ${t("team.botsWord")}${i}`,wi()}function wi(){let e=te("tf-teams");e.querySelectorAll(".tf-team-h").forEach(n=>{n.onclick=()=>{let o=n.dataset.tk;Nt.has(o)?Nt.delete(o):Nt.add(o),rt()}}),e.querySelectorAll(".tf-dep-h").forEach(n=>{n.onclick=()=>{let o=n.dataset.dk;Pt.has(o)?Pt.delete(o):Pt.add(o),rt()}}),e.querySelectorAll(".tf-pick").forEach(n=>{n.onchange=()=>{let o=ft(n.dataset.tk);n.checked?o.add(n.dataset.app):o.delete(n.dataset.app)}}),e.querySelectorAll(".tf-gname").forEach(n=>{n.oninput=()=>{cn.set(n.dataset.tk,n.value)}}),e.querySelectorAll(".tf-cap").forEach(n=>{n.onchange=async()=>{let o=n.dataset.app,s=n.value;await mi("/api/team/local-bots/"+encodeURIComponent(o)+"/capability",{capability:s}),mn().forEach(a=>{let i=a.bots.find(d=>d.larkAppId===o);i&&(i.capability=s.trim()||null)})}}),e.querySelectorAll(".tf-role").forEach(n=>{n.onclick=()=>vi(n.dataset.app,n.dataset.name||"")}),e.querySelectorAll(".tf-rmmember").forEach(n=>{n.onclick=async o=>{o.stopPropagation(),confirm(t("team.removeMemberConfirm",{name:n.dataset.name||""}))&&(await pn("DELETE",`/api/team/hosted/${encodeURIComponent(n.dataset.team)}/members/${encodeURIComponent(n.dataset.dep)}`),qt())}}),e.querySelectorAll(".tf-grp").forEach(n=>{n.onclick=async()=>{let o=n.dataset.tk,s=fi(o);if(!s)return;let a=[...ft(o)],i=e.querySelector(`.tf-gout[data-tk="${CSS.escape(o)}"]`);if(!a.length){i.innerHTML=`<span class="err">${t("team.errPickBot")}</span>`;return}let d=(e.querySelector(`.tf-gname[data-tk="${CSS.escape(o)}"]`)?.value||"").trim()||t("team.defaultGroupName");i.innerHTML=`<span class="muted">${t("team.creatingGroup")}</span>`;let p=s.kind==="local"?await gt("/api/team/federated-group",{name:d,larkAppIds:a,teamId:s.teamId}):await gt("/api/team/remote-group",{hubUrl:s.hubUrl,teamId:s.teamId,name:d,larkAppIds:a});if(yi(i,p.body,p.status),p.body?.ok){ft(o).clear(),cn.delete(o);let v=i.innerHTML,k=()=>{let I=e.querySelector(`.tf-gout[data-tk="${CSS.escape(o)}"]`);I&&(I.innerHTML=v)};s.kind==="local"?qt().then(k):(rt(),k())}}})}function yi(e,n,o){if(n?.ok&&n.chatId){let s=n.shareLink||"https://applink.feishu.cn/client/chat/open?openChatId="+encodeURIComponent(n.chatId),a=(n.invalidBotIds||[]).length?` <span class="err"> \xB7 ${t("team.invalidBots",{ids:r((n.invalidBotIds||[]).join(", "))})}</span>`:"",i=(n.invalidOwnerUnionIds||[]).length?`<span class="err"> \xB7 ${t("team.invalidOwners",{n:(n.invalidOwnerUnionIds||[]).length})}</span>`:"",d=n.missingOperatorIdentity?`<span class="err"> \xB7 ${t("team.missingIdentity")}</span>`:"",p=(n.skippedNoOwner||[]).length?`<span class="err"> \xB7 ${t("team.skippedNoOwner",{n:(n.skippedNoOwner||[]).length})}</span>`:"",v=n.delegatedTo?t("team.delegatedBy",{name:r(n.delegatedTo)}):"";e.innerHTML=`<span class="ok">${t("team.groupCreated")}</span>${v} \xB7 <a href="${r(s)}" target="_blank">${t("team.openInLark")}</a>${a}${i}${d}${p}`}else{let s=n?.error||o,a=s==="no_local_online_bot"?t("team.errNoLocalBot"):s==="all_bots_skipped_no_owner"?t("team.errAllSkipped"):s==="no_creator_available"?t("team.errNoCreator"):s==="delegation_timeout"?t("team.errDelegationTimeout"):t("team.errGroupCreate",{error:String(s)});e.innerHTML=`<span class="err">${r(String(a))}</span>`}}async function vi(e,n){let o=await un("/api/team/local-bots/"+encodeURIComponent(e)+"/role");te("tf-modal-title").textContent=t("team.roleModalTitleName",{name:n}),te("tf-modal-text").value=o.body?.role||"",te("tf-modal").dataset.app=e,te("tf-modal").style.display="flex"}function Sa(){let e=Array.from(new Set(mn().flatMap(s=>s.bots.map(a=>a.cliId)).filter(Boolean))).sort(),n=te("tf-cli"),o=n.value;n.innerHTML=`<option value="">${t("team.allCli")}</option>`+e.map(s=>`<option value="${r(s)}">${r(s)}</option>`).join(""),n.value=o}async function qt(){let n=(await un("/api/team/hosted")).body;if(!n?.ok){Jn=[],rt();return}ka=n.deployment.deploymentId,dn=n.suggestedHubUrl||"",te("tf-owner").textContent=n.deployment.ownerName||(n.deployment.ownerUnionId?t("team.bound"):t("team.unbound")),Jn=(n.teams||[]).map(o=>({kind:"local",key:`local:${o.teamId}`,teamId:o.teamId,label:o.isDefault?t("team.myHostedTeam"):o.name,sub:"",ok:!0,deployments:o.deployments||[],bots:o.bots||[]})),Sa(),rt()}async function ki(){va=((await un("/api/team/remote-roster")).body?.memberships||[]).map(o=>{let s=o.roster?.deployments||[],a=s.find(d=>d.local),i=a?.name?t("team.remoteTeamLabel",{name:a.name}):o.teamName||o.teamId;return{kind:"remote",key:`${o.hubUrl}::${o.teamId}`,teamId:o.teamId,label:i,sub:o.hubUrl,ok:!!o.ok,error:o.error,hubUrl:o.hubUrl,deployments:s,bots:o.roster?.bots||[]}}),Sa(),rt()}function Ta(e){e.innerHTML=gi(),Yn.clear(),cn.clear(),Nt.clear(),Pt.clear(),["tf-search","tf-cli","tf-fcap","tf-frole"].forEach(n=>{let o=te(n);o.oninput=rt,o.onchange=rt}),te("tf-modal-cancel").onclick=()=>{te("tf-modal").style.display="none"},Si(),qt(),ki()}function $i(){return`<section class="page">
1029
+ </section>`}function zi(e){let n=(te("tf-search").value||"").trim().toLowerCase();if(n&&!((e.name||"")+" "+(e.cliId||"")+" "+(e.capability||"")).toLowerCase().includes(n))return!1;let a=te("tf-cli").value;return!(a&&e.cliId!==a||te("tf-fcap").checked&&!e.capability||te("tf-frole").checked&&!e.hasTeamRole)}function Ki(e,n){let a=[...e.deployments].sort((o,r)=>o.local===r.local?0:o.local?-1:1),s="";for(let o of a){let r=n.filter(u=>u.deployment.id===o.id);if(!r.length)continue;let d=o.id===Ho,p=d?t("team.tagLocal"):o.stale?t("team.tagRemoteStale"):t("team.tagRemote"),k=e.kind==="local"&&!d?` <button class="tf-rmmember ghost" data-team="${i(e.teamId)}" data-dep="${i(o.id)}" data-name="${i(o.name)}" style="font-size:12px">${t("team.removeMember")}</button>`:"",$=`${e.key}::${o.id}`,E=Ft.has($),w=r.filter(u=>wt(e.key).has(u.larkAppId)).length;if(s+=`<div class="tf-dep-h" data-dk="${i($)}" style="cursor:pointer;margin:10px 0 2px"><b>${E?"\u25BE":"\u25B8"} ${i(o.name)}</b> <span class="muted" style="font-size:12px">${t("team.depTag",{tag:p})} \xB7 ${t("team.depCount",{count:r.length})}${w?t("team.depSelected",{n:w}):""}</span>${k}</div>`,!!E){s+='<table style="width:100%;border-collapse:collapse;font-size:14px"><tbody>';for(let u of r){let S=i(u.larkAppId),x=wt(e.key).has(u.larkAppId)?" checked":"",A=u.deployment.stale?"opacity:.55":"",L=d?`<input class="tf-cap" data-app="${S}" value="${i(u.capability||"")}" placeholder="${t("team.capPh")}" style="width:92%;padding:3px 6px">`:u.capability?i(u.capability):'<span class="muted">\u2014</span>',H=u.hasTeamRole?d?`<button class="tf-role" data-app="${S}" data-name="${i(u.name)}">${t("team.viewRole")}</button>`:t("team.hasRoleShort"):'<span class="muted">\u2014</span>';s+=`<tr style="${A}"><td style="padding:4px 8px"><input type="checkbox" class="tf-pick" data-tk="${i(e.key)}" data-app="${S}"${x}></td><td style="padding:4px 8px">${i(u.name)}</td><td style="padding:4px 8px" class="muted">${i(u.cliId)}</td><td style="padding:4px 8px">${L}</td><td style="padding:4px 8px">${H}</td></tr>`}s+="</tbody></table>"}}return s||(s=`<p class="muted" style="margin:8px 0 0">${t("team.noMatch")}</p>`),s+=`<div style="margin-top:12px;display:flex;gap:8px;flex-wrap:wrap;align-items:center"><input class="tf-gname" data-tk="${i(e.key)}" value="${i(bn.get(e.key)||"")}" placeholder="${t("team.gnamePh")}" style="min-width:200px"><button class="tf-grp primary" data-tk="${i(e.key)}">${t("team.pullGroupBtn")}</button><span class="muted" style="font-size:13px">${t("team.pullGroupHint")}</span><span class="tf-gout" data-tk="${i(e.key)}" style="font-size:13px;display:block;flex-basis:100%"></span></div>`,s}function ct(){let e=te("tf-teams"),n=yn();if(!n.length){e.innerHTML=`<p class="muted">${t("team.noTeams")}</p>`,te("tf-count").textContent="";return}let a="",s=new Set,o=new Set;for(let p of n){let k=p.bots.filter(zi);k.forEach(u=>s.add(u.larkAppId)),p.bots.forEach(u=>o.add(u.larkAppId));let $=new Set(k.map(u=>u.larkAppId));[...wt(p.key)].forEach(u=>{$.has(u)||wt(p.key).delete(u)});let E=!Ut.has(p.key),w=p.kind==="remote"?p.ok?` <span class="ok" style="font-size:12px">${t("team.connected")}</span>`:` <span class="err" style="font-size:12px">${t("team.connectFail",{error:i(p.error||"")})}</span>`:` <span class="muted" style="font-size:12px">${t("team.iHost")}</span>`;a+=`<div class="card" style="margin:0 0 12px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)"><div class="tf-team-h" data-tk="${i(p.key)}" style="cursor:pointer;display:flex;align-items:center;gap:8px;flex-wrap:wrap"><b style="font-size:15px">${E?"\u25B8":"\u25BE"} ${i(p.label)}</b>`+(p.sub?` <span class="muted" style="font-size:12px">${i(p.sub)}</span>`:"")+w+` <span class="muted" style="font-size:12px">\xB7 ${t("team.teamMeta",{deps:p.deployments.length,bots:p.bots.length})}</span></div>`,E||(a+=p.kind==="remote"&&!p.ok?`<p class="muted" style="margin:8px 0 0">${t("team.rosterFail")}</p>`:Ki(p,k)),a+="</div>"}e.innerHTML=a;let r=n.length>1?t("team.acrossTeams",{n:n.length}):"",d=s.size===o.size?`${o.size}`:`${s.size} / ${o.size}`;te("tf-count").textContent=`\xB7 ${d} ${t("team.botsWord")}${r}`,Ji()}function Ji(){let e=te("tf-teams");e.querySelectorAll(".tf-team-h").forEach(n=>{n.onclick=()=>{let a=n.dataset.tk;Ut.has(a)?Ut.delete(a):Ut.add(a),ct()}}),e.querySelectorAll(".tf-dep-h").forEach(n=>{n.onclick=()=>{let a=n.dataset.dk;Ft.has(a)?Ft.delete(a):Ft.add(a),ct()}}),e.querySelectorAll(".tf-pick").forEach(n=>{n.onchange=()=>{let a=wt(n.dataset.tk);n.checked?a.add(n.dataset.app):a.delete(n.dataset.app)}}),e.querySelectorAll(".tf-gname").forEach(n=>{n.oninput=()=>{bn.set(n.dataset.tk,n.value)}}),e.querySelectorAll(".tf-cap").forEach(n=>{n.onchange=async()=>{let a=n.dataset.app,s=n.value;await Gi("/api/team/local-bots/"+encodeURIComponent(a)+"/capability",{capability:s}),yn().forEach(o=>{let r=o.bots.find(d=>d.larkAppId===a);r&&(r.capability=s.trim()||null)})}}),e.querySelectorAll(".tf-role").forEach(n=>{n.onclick=()=>Yi(n.dataset.app,n.dataset.name||"")}),e.querySelectorAll(".tf-rmmember").forEach(n=>{n.onclick=async a=>{a.stopPropagation(),confirm(t("team.removeMemberConfirm",{name:n.dataset.name||""}))&&(await wn("DELETE",`/api/team/hosted/${encodeURIComponent(n.dataset.team)}/members/${encodeURIComponent(n.dataset.dep)}`),Gt())}}),e.querySelectorAll(".tf-grp").forEach(n=>{n.onclick=async()=>{let a=n.dataset.tk,s=_i(a);if(!s)return;let o=[...wt(a)],r=e.querySelector(`.tf-gout[data-tk="${CSS.escape(a)}"]`);if(!o.length){r.innerHTML=`<span class="err">${t("team.errPickBot")}</span>`;return}let d=(e.querySelector(`.tf-gname[data-tk="${CSS.escape(a)}"]`)?.value||"").trim()||t("team.defaultGroupName");r.innerHTML=`<span class="muted">${t("team.creatingGroup")}</span>`;let p=s.kind==="local"?await yt("/api/team/federated-group",{name:d,larkAppIds:o,teamId:s.teamId}):await yt("/api/team/remote-group",{hubUrl:s.hubUrl,teamId:s.teamId,name:d,larkAppIds:o});if(Vi(r,p.body,p.status),p.body?.ok){wt(a).clear(),bn.delete(a);let k=r.innerHTML,$=()=>{let E=e.querySelector(`.tf-gout[data-tk="${CSS.escape(a)}"]`);E&&(E.innerHTML=k)};s.kind==="local"?Gt().then($):(ct(),$())}}})}function Vi(e,n,a){if(n?.ok&&n.chatId){let s=n.shareLink||"https://applink.feishu.cn/client/chat/open?openChatId="+encodeURIComponent(n.chatId),o=(n.invalidBotIds||[]).length?` <span class="err"> \xB7 ${t("team.invalidBots",{ids:i((n.invalidBotIds||[]).join(", "))})}</span>`:"",r=(n.invalidOwnerUnionIds||[]).length?`<span class="err"> \xB7 ${t("team.invalidOwners",{n:(n.invalidOwnerUnionIds||[]).length})}</span>`:"",d=n.missingOperatorIdentity?`<span class="err"> \xB7 ${t("team.missingIdentity")}</span>`:"",p=(n.skippedNoOwner||[]).length?`<span class="err"> \xB7 ${t("team.skippedNoOwner",{n:(n.skippedNoOwner||[]).length})}</span>`:"",k=n.delegatedTo?t("team.delegatedBy",{name:i(n.delegatedTo)}):"";e.innerHTML=`<span class="ok">${t("team.groupCreated")}</span>${k} \xB7 <a href="${i(s)}" target="_blank">${t("team.openInLark")}</a>${o}${r}${d}${p}`}else{let s=n?.error||a,o=s==="no_local_online_bot"?t("team.errNoLocalBot"):s==="all_bots_skipped_no_owner"?t("team.errAllSkipped"):s==="no_creator_available"?t("team.errNoCreator"):s==="delegation_timeout"?t("team.errDelegationTimeout"):t("team.errGroupCreate",{error:String(s)});e.innerHTML=`<span class="err">${i(String(o))}</span>`}}async function Yi(e,n){let a=await hn("/api/team/local-bots/"+encodeURIComponent(e)+"/role");te("tf-modal-title").textContent=t("team.roleModalTitleName",{name:n}),te("tf-modal-text").value=a.body?.role||"",te("tf-modal").dataset.app=e,te("tf-modal").style.display="flex"}function Ao(){let e=Array.from(new Set(yn().flatMap(s=>s.bots.map(o=>o.cliId)).filter(Boolean))).sort(),n=te("tf-cli"),a=n.value;n.innerHTML=`<option value="">${t("team.allCli")}</option>`+e.map(s=>`<option value="${i(s)}">${i(s)}</option>`).join(""),n.value=a}async function Gt(){let n=(await hn("/api/team/hosted")).body;if(!n?.ok){ea=[],ct();return}Ho=n.deployment.deploymentId,gn=n.suggestedHubUrl||"",te("tf-owner").textContent=n.deployment.ownerName||(n.deployment.ownerUnionId?t("team.bound"):t("team.unbound")),ea=(n.teams||[]).map(a=>({kind:"local",key:`local:${a.teamId}`,teamId:a.teamId,label:a.isDefault?t("team.myHostedTeam"):a.name,sub:"",ok:!0,deployments:a.deployments||[],bots:a.bots||[]})),Ao(),ct()}async function Qi(){xo=((await hn("/api/team/remote-roster")).body?.memberships||[]).map(a=>{let s=a.roster?.deployments||[],o=s.find(d=>d.local),r=o?.name?t("team.remoteTeamLabel",{name:o.name}):a.teamName||a.teamId;return{kind:"remote",key:`${a.hubUrl}::${a.teamId}`,teamId:a.teamId,label:r,sub:a.hubUrl,ok:!!a.ok,error:a.error,hubUrl:a.hubUrl,deployments:s,bots:a.roster?.bots||[]}}),Ao(),ct()}function Do(e){e.innerHTML=Wi(),ta.clear(),bn.clear(),Ut.clear(),Ft.clear(),["tf-search","tf-cli","tf-fcap","tf-frole"].forEach(n=>{let a=te(n);a.oninput=ct,a.onchange=ct}),te("tf-modal-cancel").onclick=()=>{te("tf-modal").style.display="none"},Zi(),Gt(),Qi()}function Xi(){return`<section class="page">
887
1030
  <div class="page-heading"><div>
888
1031
  <p class="eyebrow">${t("team.eyebrow")}</p><h1>${t("team.manageTitle")}</h1>
889
1032
  <p class="tf-lede">${t("team.manageLede")}</p>
890
1033
  </div></div>
891
- ${$a("manage")}
1034
+ ${Co("manage")}
892
1035
  <div class="card" style="margin-bottom:16px">
893
1036
  <h2 style="margin-top:0">${t("team.hostedTitle")}</h2>
894
1037
  <p style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:6px">
@@ -907,16 +1050,16 @@ ${$a("manage")}
907
1050
  </p>
908
1051
  <div id="tm-join-out" style="display:none;margin-top:6px"></div>
909
1052
  </div>
910
- </section>`}async function Vn(){let n=(await un("/api/team/hosted")).body,o=te("tm-list");dn=n?.suggestedHubUrl||dn;let s=n?.teams||[];if(!s.length){o.innerHTML=`<p class="muted">${t("team.noTeamsShort")}</p>`;return}o.innerHTML=s.map(a=>{let i=(a.deployments||[]).filter(d=>!d.local).length;return`<div class="card" style="margin:0 0 8px;padding:10px 14px;background:var(--bg-soft,#f6f7f9)">
1053
+ </section>`}async function na(){let n=(await hn("/api/team/hosted")).body,a=te("tm-list");gn=n?.suggestedHubUrl||gn;let s=n?.teams||[];if(!s.length){a.innerHTML=`<p class="muted">${t("team.noTeamsShort")}</p>`;return}a.innerHTML=s.map(o=>{let r=(o.deployments||[]).filter(d=>!d.local).length;return`<div class="card" style="margin:0 0 8px;padding:10px 14px;background:var(--bg-soft,#f6f7f9)">
911
1054
  <div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
912
- <b>${r(a.name)}</b>${a.isDefault?` <span class="muted" style="font-size:12px">${t("team.default")}</span>`:""}
913
- <span class="muted" style="font-size:12px">\xB7 ${t("team.manageMetaDeps",{count:(a.deployments||[]).length})}${i?t("team.manageMetaRemote",{r:i}):""} \xB7 ${t("team.manageMetaBots",{count:(a.bots||[]).length})}</span>
1055
+ <b>${i(o.name)}</b>${o.isDefault?` <span class="muted" style="font-size:12px">${t("team.default")}</span>`:""}
1056
+ <span class="muted" style="font-size:12px">\xB7 ${t("team.manageMetaDeps",{count:(o.deployments||[]).length})}${r?t("team.manageMetaRemote",{r}):""} \xB7 ${t("team.manageMetaBots",{count:(o.bots||[]).length})}</span>
914
1057
  <span style="margin-left:auto;display:flex;gap:6px">
915
- <button class="tm-invite ghost" data-team="${r(a.teamId)}" style="font-size:12px">${t("team.genInvite")}</button>
916
- ${a.isDefault?"":`<button class="tm-del ghost" data-team="${r(a.teamId)}" data-name="${r(a.name)}" style="font-size:12px">${t("team.delBtn")}</button>`}
1058
+ <button class="tm-invite ghost" data-team="${i(o.teamId)}" style="font-size:12px">${t("team.genInvite")}</button>
1059
+ ${o.isDefault?"":`<button class="tm-del ghost" data-team="${i(o.teamId)}" data-name="${i(o.name)}" style="font-size:12px">${t("team.delBtn")}</button>`}
917
1060
  </span>
918
1061
  </div>
919
- <div class="tm-inv-out" data-team="${r(a.teamId)}" style="display:none;margin-top:6px;font-size:13px"></div></div>`}).join(""),o.querySelectorAll(".tm-invite").forEach(a=>{a.onclick=async()=>{let i=a.dataset.team,d=o.querySelector(`.tm-inv-out[data-team="${CSS.escape(i)}"]`);d.style.display="",d.innerHTML=`<span class="muted">${t("team.generating")}</span>`;let p=await gt("/api/team/local-invite",{teamId:i});p.body?.code?d.innerHTML=`${t("team.inviteResultLede")}<br>${t("team.inviteHub")}<code>${r(dn)}</code><br>${t("team.inviteCode")}<code style="font-size:15px">${r(p.body.code)}</code>`:d.innerHTML=`<span class="err">${t("team.genFail")}</span>`}}),o.querySelectorAll(".tm-del").forEach(a=>{a.onclick=async()=>{confirm(t("team.delConfirm",{name:a.dataset.name||""}))&&(await pn("DELETE","/api/team/hosted/"+encodeURIComponent(a.dataset.team)),Vn())}})}function La(e){e.innerHTML=$i(),te("tm-create").onclick=async()=>{let n=te("tm-newname").value.trim(),o=e.querySelector(".tm-cout");if(!n){o.innerHTML=`<span class="err">${t("team.errName")}</span>`;return}o.innerHTML=`<span class="muted">${t("team.creating")}</span>`;let s=await gt("/api/team/hosted",{name:n});s.body?.ok?(o.innerHTML=`<span class="ok">${t("team.created")}</span>`,te("tm-newname").value="",Vn()):o.innerHTML=`<span class="err">${t("team.createFail",{error:r(String(s.body?.error||s.status))})}</span>`},te("tm-join").onclick=async()=>{let n=te("tm-hub").value.trim(),o=te("tm-code").value.trim(),s=te("tm-join-out");if(s.style.display="",!n||!o){s.innerHTML=`<span class="err">${t("team.errHubCode")}</span>`;return}s.innerHTML=`<span class="muted">${t("team.joining")}</span>`;let a=await gt("/api/team/join-remote",{hubUrl:n,inviteCode:o});if(a.body?.ok)s.innerHTML=`<span class="ok">${t("team.joined",{name:r(a.body.teamName||"")})}</span>`,te("tm-code").value="";else{let i=a.body?.error||a.status,d=i==="cannot_join_self"?t("team.joinErrSelf"):i==="deployment_already_joined"?t("team.joinErrAlready"):i==="hub_unreachable"?t("team.joinErrUnreachable"):i==="hub_timeout"?t("team.joinErrTimeout"):t("team.joinErrGeneric",{error:String(i)});s.innerHTML=`<span class="err">${r(String(d))}</span>`}},Vn()}function Si(){te("tf-autobind").onclick=async()=>{let e=te("tf-bind-out");e.style.display="",e.innerHTML=`<span class="muted">${t("team.identifying")}</span>`;let o=(await gt("/api/team/identity/auto-bind")).body;if(o?.ok&&o.owner){e.innerHTML=`<span class="ok">${t("team.bound2",{name:r(o.owner.name||o.owner.unionId)})}</span>`,qt();return}if(o?.ok&&o.needChoice&&Array.isArray(o.candidates)){let s=o.candidates.map(a=>`<button class="tf-pickowner ghost" data-union="${r(a.unionId)}" style="margin:2px">${r(a.name||a.unionId)}</button>`).join(" ");e.innerHTML=`${t("team.multiCandidate")}<br>${s}`,e.querySelectorAll(".tf-pickowner").forEach(a=>{a.onclick=async()=>{e.innerHTML=`<span class="muted">${t("team.binding")}</span>`;let d=(await gt("/api/team/identity/auto-bind",{unionId:a.dataset.union})).body;d?.ok&&d.owner?(e.innerHTML=`<span class="ok">${t("team.bound2",{name:r(d.owner.name||d.owner.unionId)})}</span>`,qt()):e.innerHTML=`<span class="err">${t("team.bindFail",{error:r(String(d?.error||"unknown"))})}</span>`}});return}if(o?.error==="no_candidates"){e.innerHTML=`<span class="err">${t("team.noCandidates")}</span>`;return}e.innerHTML=`<span class="err">${t("team.bindFail",{error:r(String(o?.error||"unknown"))})}</span>`}}async function Qn(e){let n=await fetch(e);return{status:n.status,body:await n.json().catch(()=>({}))}}async function Zn(e,n,o){let s=await fetch(n,{method:e,headers:{"content-type":"application/json"},body:o?JSON.stringify(o):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}function ne(e){return document.getElementById(e)}function bt(e){return(ne(e).value||"").trim()}var eo=[],no=[];function Ti(){return`<section class="page">
1062
+ <div class="tm-inv-out" data-team="${i(o.teamId)}" style="display:none;margin-top:6px;font-size:13px"></div></div>`}).join(""),a.querySelectorAll(".tm-invite").forEach(o=>{o.onclick=async()=>{let r=o.dataset.team,d=a.querySelector(`.tm-inv-out[data-team="${CSS.escape(r)}"]`);d.style.display="",d.innerHTML=`<span class="muted">${t("team.generating")}</span>`;let p=await yt("/api/team/local-invite",{teamId:r});p.body?.code?d.innerHTML=`${t("team.inviteResultLede")}<br>${t("team.inviteHub")}<code>${i(gn)}</code><br>${t("team.inviteCode")}<code style="font-size:15px">${i(p.body.code)}</code>`:d.innerHTML=`<span class="err">${t("team.genFail")}</span>`}}),a.querySelectorAll(".tm-del").forEach(o=>{o.onclick=async()=>{confirm(t("team.delConfirm",{name:o.dataset.name||""}))&&(await wn("DELETE","/api/team/hosted/"+encodeURIComponent(o.dataset.team)),na())}})}function Ro(e){e.innerHTML=Xi(),te("tm-create").onclick=async()=>{let n=te("tm-newname").value.trim(),a=e.querySelector(".tm-cout");if(!n){a.innerHTML=`<span class="err">${t("team.errName")}</span>`;return}a.innerHTML=`<span class="muted">${t("team.creating")}</span>`;let s=await yt("/api/team/hosted",{name:n});s.body?.ok?(a.innerHTML=`<span class="ok">${t("team.created")}</span>`,te("tm-newname").value="",na()):a.innerHTML=`<span class="err">${t("team.createFail",{error:i(String(s.body?.error||s.status))})}</span>`},te("tm-join").onclick=async()=>{let n=te("tm-hub").value.trim(),a=te("tm-code").value.trim(),s=te("tm-join-out");if(s.style.display="",!n||!a){s.innerHTML=`<span class="err">${t("team.errHubCode")}</span>`;return}s.innerHTML=`<span class="muted">${t("team.joining")}</span>`;let o=await yt("/api/team/join-remote",{hubUrl:n,inviteCode:a});if(o.body?.ok)s.innerHTML=`<span class="ok">${t("team.joined",{name:i(o.body.teamName||"")})}</span>`,te("tm-code").value="";else{let r=o.body?.error||o.status,d=r==="cannot_join_self"?t("team.joinErrSelf"):r==="deployment_already_joined"?t("team.joinErrAlready"):r==="hub_unreachable"?t("team.joinErrUnreachable"):r==="hub_timeout"?t("team.joinErrTimeout"):t("team.joinErrGeneric",{error:String(r)});s.innerHTML=`<span class="err">${i(String(d))}</span>`}},na()}function Zi(){te("tf-autobind").onclick=async()=>{let e=te("tf-bind-out");e.style.display="",e.innerHTML=`<span class="muted">${t("team.identifying")}</span>`;let a=(await yt("/api/team/identity/auto-bind")).body;if(a?.ok&&a.owner){e.innerHTML=`<span class="ok">${t("team.bound2",{name:i(a.owner.name||a.owner.unionId)})}</span>`,Gt();return}if(a?.ok&&a.needChoice&&Array.isArray(a.candidates)){let s=a.candidates.map(o=>`<button class="tf-pickowner ghost" data-union="${i(o.unionId)}" style="margin:2px">${i(o.name||o.unionId)}</button>`).join(" ");e.innerHTML=`${t("team.multiCandidate")}<br>${s}`,e.querySelectorAll(".tf-pickowner").forEach(o=>{o.onclick=async()=>{e.innerHTML=`<span class="muted">${t("team.binding")}</span>`;let d=(await yt("/api/team/identity/auto-bind",{unionId:o.dataset.union})).body;d?.ok&&d.owner?(e.innerHTML=`<span class="ok">${t("team.bound2",{name:i(d.owner.name||d.owner.unionId)})}</span>`,Gt()):e.innerHTML=`<span class="err">${t("team.bindFail",{error:i(String(d?.error||"unknown"))})}</span>`}});return}if(a?.error==="no_candidates"){e.innerHTML=`<span class="err">${t("team.noCandidates")}</span>`;return}e.innerHTML=`<span class="err">${t("team.bindFail",{error:i(String(a?.error||"unknown"))})}</span>`}}async function aa(e){let n=await fetch(e);return{status:n.status,body:await n.json().catch(()=>({}))}}async function sa(e,n,a){let s=await fetch(n,{method:e,headers:{"content-type":"application/json"},body:a?JSON.stringify(a):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}function ne(e){return document.getElementById(e)}function vt(e){return(ne(e).value||"").trim()}var ia=[],la=[];function er(){return`<section class="page">
920
1063
  <div class="page-heading">
921
1064
  <div>
922
1065
  <p class="eyebrow">Webhook</p>
@@ -978,28 +1121,28 @@ ${$a("manage")}
978
1121
  <h2 style="margin-top:0">${t("connectors.listTitle")} <span class="muted" id="cn-count" style="font-size:13px"></span></h2>
979
1122
  <div id="cn-list">${t("connectors.loading")}</div>
980
1123
  </div>
981
- </section>`}function Xn(){let e=ne("cn-kind").value,n=ne("cn-mode").value;document.querySelectorAll(".cn-wf").forEach(o=>{o.style.display=e==="workflow"?"":"none"}),document.querySelectorAll(".cn-fixed").forEach(o=>{o.style.display=n==="fixed"?"":"none"}),document.querySelectorAll(".cn-allow").forEach(o=>{o.style.display=n==="fixed"?"none":""}),document.querySelectorAll(".cn-dyn").forEach(o=>{o.style.display=n==="dynamic"?"":"none"}),document.querySelectorAll(".cn-life").forEach(o=>{o.style.display=n==="new-group"?"":"none"})}function Ia(e){return`${location.origin}/webhook/${encodeURIComponent(e)}`}function Li(e){return e==="fixed"?t("connectors.modeLabelFixed"):e==="new-group"?t("connectors.modeLabelNewGroup"):t("connectors.modeLabelDynamic")}function Ii(e){return e==="workflow"?t("connectors.kindLabelWorkflow"):t("connectors.kindLabelTurn")}function to(e){return no.find(o=>o.chatId===e)?.name||e}function Mi(e){return no.filter(n=>n.bots.includes(e))}function Ma(){let e=ne("cn-bot").value,n=Mi(e),o=p=>`<option value="${r(p.chatId)}">${r(p.name||p.chatId)}</option>`,s=ne("cn-chat-sel"),a=s.value;s.innerHTML=n.length?n.map(o).join(""):`<option value="">${t("connectors.noBotGroups")}</option>`,a&&n.some(p=>p.chatId===a)&&(s.value=a);let i=ne("cn-allow-sel"),d=new Set(Array.from(i.selectedOptions).map(p=>p.value));i.innerHTML=n.map(o).join(""),Array.from(i.options).forEach(p=>{d.has(p.value)&&(p.selected=!0)})}function xi(e){let n=ne("cn-list");if(ne("cn-count").textContent=e.length?t("connectors.count",{count:e.length}):"",!e.length){n.innerHTML=`<p class="muted">${t("connectors.empty")}</p>`;return}n.innerHTML=e.map(o=>{let s=eo.find(v=>v.larkAppId===o.target.botId),a=Ia(o.id),i=(o.verify?.type??"token")==="token",d=i?t("connectors.badgeToken"):t("connectors.badgeSign"),p=o.target.mode==="fixed"&&o.target.chatId?` \xB7 ${t("connectors.dest",{name:r(to(o.target.chatId))})}`:"";return`<div class="card" style="margin:0 0 10px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
1124
+ </section>`}function oa(){let e=ne("cn-kind").value,n=ne("cn-mode").value;document.querySelectorAll(".cn-wf").forEach(a=>{a.style.display=e==="workflow"?"":"none"}),document.querySelectorAll(".cn-fixed").forEach(a=>{a.style.display=n==="fixed"?"":"none"}),document.querySelectorAll(".cn-allow").forEach(a=>{a.style.display=n==="fixed"?"none":""}),document.querySelectorAll(".cn-dyn").forEach(a=>{a.style.display=n==="dynamic"?"":"none"}),document.querySelectorAll(".cn-life").forEach(a=>{a.style.display=n==="new-group"?"":"none"})}function Po(e){return`${location.origin}/webhook/${encodeURIComponent(e)}`}function tr(e){return e==="fixed"?t("connectors.modeLabelFixed"):e==="new-group"?t("connectors.modeLabelNewGroup"):t("connectors.modeLabelDynamic")}function nr(e){return e==="workflow"?t("connectors.kindLabelWorkflow"):t("connectors.kindLabelTurn")}function ra(e){return la.find(a=>a.chatId===e)?.name||e}function ar(e){return la.filter(n=>n.bots.includes(e))}function Bo(){let e=ne("cn-bot").value,n=ar(e),a=p=>`<option value="${i(p.chatId)}">${i(p.name||p.chatId)}</option>`,s=ne("cn-chat-sel"),o=s.value;s.innerHTML=n.length?n.map(a).join(""):`<option value="">${t("connectors.noBotGroups")}</option>`,o&&n.some(p=>p.chatId===o)&&(s.value=o);let r=ne("cn-allow-sel"),d=new Set(Array.from(r.selectedOptions).map(p=>p.value));r.innerHTML=n.map(a).join(""),Array.from(r.options).forEach(p=>{d.has(p.value)&&(p.selected=!0)})}function or(e){let n=ne("cn-list");if(ne("cn-count").textContent=e.length?t("connectors.count",{count:e.length}):"",!e.length){n.innerHTML=`<p class="muted">${t("connectors.empty")}</p>`;return}n.innerHTML=e.map(a=>{let s=ia.find(k=>k.larkAppId===a.target.botId),o=Po(a.id),r=(a.verify?.type??"token")==="token",d=r?t("connectors.badgeToken"):t("connectors.badgeSign"),p=a.target.mode==="fixed"&&a.target.chatId?` \xB7 ${t("connectors.dest",{name:i(ra(a.target.chatId))})}`:"";return`<div class="card" style="margin:0 0 10px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
982
1125
  <div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
983
- <b style="font-size:15px">${r(o.name)}</b>
984
- <span class="${o.enabled?"ok":"muted"}" style="font-size:12px">${o.enabled?t("connectors.enabled"):t("connectors.disabled")}</span>
985
- <span class="muted" style="font-size:12px">\xB7 ${r(s?.botName||o.target.botId)} \xB7 ${Ii(o.target.kind)} \xB7 ${Li(o.target.mode)}${p} \xB7 ${d}</span>
1126
+ <b style="font-size:15px">${i(a.name)}</b>
1127
+ <span class="${a.enabled?"ok":"muted"}" style="font-size:12px">${a.enabled?t("connectors.enabled"):t("connectors.disabled")}</span>
1128
+ <span class="muted" style="font-size:12px">\xB7 ${i(s?.botName||a.target.botId)} \xB7 ${nr(a.target.kind)} \xB7 ${tr(a.target.mode)}${p} \xB7 ${d}</span>
986
1129
  <span style="margin-left:auto;display:flex;gap:6px">
987
- <button class="cn-toggle ghost" data-id="${r(o.id)}" data-on="${o.enabled}" style="font-size:12px">${o.enabled?t("connectors.btnDisable"):t("connectors.btnEnable")}</button>
988
- <button class="cn-del ghost" data-id="${r(o.id)}" style="font-size:12px">${t("connectors.btnDel")}</button>
1130
+ <button class="cn-toggle ghost" data-id="${i(a.id)}" data-on="${a.enabled}" style="font-size:12px">${a.enabled?t("connectors.btnDisable"):t("connectors.btnEnable")}</button>
1131
+ <button class="cn-del ghost" data-id="${i(a.id)}" style="font-size:12px">${t("connectors.btnDel")}</button>
989
1132
  </span>
990
1133
  </div>
991
1134
  <div style="margin-top:6px;font-size:13px;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
992
- <span class="muted">${t("connectors.webhookUrl")}</span><code style="font-size:12px;word-break:break-all">${r(a)}${i?"/&lt;token&gt;":""}</code>
993
- <button class="cn-copy ghost" data-url="${r(a)}" style="font-size:12px">${t("connectors.copy")}</button>
994
- </div>${i?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.tokenHint")}</div>`:""}${o.target.mode==="dynamic"?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.dynamicReqHint")}</div>`:""}${o.promptEnvelope?.instruction?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.instructionPrefix")}${r(o.promptEnvelope.instruction)}</div>`:""}</div>`}).join(""),n.querySelectorAll(".cn-copy").forEach(o=>{o.onclick=()=>{navigator.clipboard?.writeText(o.dataset.url),o.textContent=t("connectors.copied"),setTimeout(()=>o.textContent=t("connectors.copy"),1200)}}),n.querySelectorAll(".cn-toggle").forEach(o=>{o.onclick=async()=>{await Zn("PATCH","/api/connectors/"+encodeURIComponent(o.dataset.id),{enabled:o.dataset.on!=="true"}),fn()}}),n.querySelectorAll(".cn-del").forEach(o=>{o.onclick=async()=>{confirm(t("connectors.delConfirm"))&&(await Zn("DELETE","/api/connectors/"+encodeURIComponent(o.dataset.id)),fn())}})}async function fn(){let[e,n,o]=await Promise.all([Qn("/api/bots"),Qn("/api/connectors"),Qn("/api/groups")]);eo=(e.body?.bots||[]).map(i=>({larkAppId:i.larkAppId,botName:i.botName||i.larkAppId})),no=(o.body?.chats||[]).map(i=>({chatId:i.chatId,name:i.name||"",bots:(i.memberBots||[]).filter(d=>d.inChat).map(d=>d.larkAppId)}));let s=ne("cn-bot"),a=s.value;s.innerHTML=eo.map(i=>`<option value="${r(i.larkAppId)}">${r(i.botName)}</option>`).join("")||`<option value="">${t("connectors.noOnlineBots")}</option>`,a&&(s.value=a),Ma(),xi(n.body?.connectors||[])}function xa(e){e.innerHTML=Ti(),ne("cn-kind").onchange=Xn,ne("cn-mode").onchange=Xn,ne("cn-bot").onchange=Ma,ne("cn-chat-manual").onclick=n=>{n.preventDefault();let o=ne("cn-chat"),s=ne("cn-chat-sel"),a=o.style.display==="none";o.style.display=a?"":"none",s.style.display=a?"none":"",ne("cn-chat-manual").textContent=a?t("connectors.chatListLink"):t("connectors.chatManualLink")},Xn(),ne("cn-create").onclick=async()=>{let n=ne("cn-create-out"),o=bt("cn-name"),s=ne("cn-bot").value;if(!o){n.innerHTML=`<span class="err">${t("connectors.errName")}</span>`;return}if(!s){n.innerHTML=`<span class="err">${t("connectors.errBot")}</span>`;return}let a=ne("cn-kind").value,i=ne("cn-mode").value,d={name:o,enabled:!0,target:{kind:a,mode:i,botId:s},promptEnvelope:{sourceName:o}},p=bt("cn-instruction");if(p&&(d.promptEnvelope.instruction=p),a==="workflow"){if(!bt("cn-wf")){n.innerHTML=`<span class="err">${t("connectors.errWf")}</span>`;return}d.target.workflowId=bt("cn-wf")}if(i==="fixed"){let T=ne("cn-chat").style.display!=="none"?bt("cn-chat"):ne("cn-chat-sel").value;if(!T){n.innerHTML=`<span class="err">${t("connectors.errChat")}</span>`;return}d.target.chatId=T}else{let I=Array.from(ne("cn-allow-sel").selectedOptions).map(T=>T.value).filter(Boolean);I.length&&(d.target.allowChats=I)}if(i==="new-group"){let I=bt("cn-dedup");d.lifecycleExtractors=I?{dedupKey:I}:null}d.verify={type:ne("cn-verify").value};let v=bt("cn-secret");v&&(d.secret=v),n.innerHTML=`<span class="muted">${t("connectors.creating")}</span>`;let k=await Zn("POST","/api/connectors",d);if(k.status===201&&k.body?.ok){n.innerHTML="";let I=ne("cn-created");I.style.display="";let T=k.body.webhookUrl||Ia(k.body.connector.id),g=k.body.secret,R=(k.body.connector?.verify?.type??"token")==="token",A=i==="dynamic",O=A?d.target.allowChats?.[0]||"<chatId>":"",M=A?`${r(T)}?chatId=${r(O)}`:r(T),E;if(R&&A){let $=O!=="<chatId>"?`\uFF08${r(to(d.target.allowChats[0]))}\uFF09`:"";E=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicLede",{gn:$})}</p>
995
- <pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${M}' -H 'content-type: application/json' -d '{}'</code></pre>
996
- <p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicNote")}</p>`}else R?E=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageTokenLede")}</p>
997
- <pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${M}' -H 'content-type: application/json' -d '{}'</code></pre>
998
- <p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageTokenNote")}</p>`:E=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageHmac")}${A?t("connectors.usageHmacDynamic"):""}</p>`;I.innerHTML=`<div class="card" style="padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
999
- <p class="ok" style="margin:0 0 6px">${t("connectors.createdPrefix",{name:r(o)})}${i==="fixed"&&d.target.chatId?`<span class="muted" style="font-weight:400;font-size:13px"> \xB7 ${t("connectors.createdDest",{name:r(to(d.target.chatId))})}</span>`:""}</p>
1000
- <p style="margin:4px 0;font-size:13px"><span class="muted">${t("connectors.webhookUrl")}</span><code style="word-break:break-all">${r(T)}</code></p>
1001
- ${g?`<p style="margin:4px 0;font-size:13px"><span class="muted">${R?t("connectors.tokenLabel"):t("connectors.signLabel")}${t("connectors.secretOnce")}</span><code>${r(g)}</code></p>`:""}
1002
- ${E}</div>`,["cn-name","cn-wf","cn-chat","cn-dedup","cn-secret","cn-instruction"].forEach($=>{ne($).value=""}),ne("cn-allow-sel").selectedIndex=-1,fn()}else{let I=k.body?.error||k.status;n.innerHTML=`<span class="err">${t("connectors.createFailed",{error:r(String(I))})}</span>`}},fn()}var ke=null,jt=null,Ut=!0;function Ea(e){return{publicReadOnly:e?.publicReadOnly===!0,openTerminalInFeishu:e?.openTerminalInFeishu===!0,repoPickerMode:e?.repoPickerMode==="repos"?"repos":"all",maintenance:e?.maintenance&&typeof e.maintenance=="object"?e.maintenance:{},localDevInstall:e?.localDevInstall===!0}}function Ei(e,n){let o=e?.[n]??{};return{enabled:o.enabled===!0,time:typeof o.time=="string"?o.time:"04:00"}}function Hi(){return`<section class="page">
1135
+ <span class="muted">${t("connectors.webhookUrl")}</span><code style="font-size:12px;word-break:break-all">${i(o)}${r?"/&lt;token&gt;":""}</code>
1136
+ <button class="cn-copy ghost" data-url="${i(o)}" style="font-size:12px">${t("connectors.copy")}</button>
1137
+ </div>${r?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.tokenHint")}</div>`:""}${a.target.mode==="dynamic"?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.dynamicReqHint")}</div>`:""}${a.promptEnvelope?.instruction?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.instructionPrefix")}${i(a.promptEnvelope.instruction)}</div>`:""}</div>`}).join(""),n.querySelectorAll(".cn-copy").forEach(a=>{a.onclick=()=>{navigator.clipboard?.writeText(a.dataset.url),a.textContent=t("connectors.copied"),setTimeout(()=>a.textContent=t("connectors.copy"),1200)}}),n.querySelectorAll(".cn-toggle").forEach(a=>{a.onclick=async()=>{await sa("PATCH","/api/connectors/"+encodeURIComponent(a.dataset.id),{enabled:a.dataset.on!=="true"}),vn()}}),n.querySelectorAll(".cn-del").forEach(a=>{a.onclick=async()=>{confirm(t("connectors.delConfirm"))&&(await sa("DELETE","/api/connectors/"+encodeURIComponent(a.dataset.id)),vn())}})}async function vn(){let[e,n,a]=await Promise.all([aa("/api/bots"),aa("/api/connectors"),aa("/api/groups")]);ia=(e.body?.bots||[]).map(r=>({larkAppId:r.larkAppId,botName:r.botName||r.larkAppId})),la=(a.body?.chats||[]).map(r=>({chatId:r.chatId,name:r.name||"",bots:(r.memberBots||[]).filter(d=>d.inChat).map(d=>d.larkAppId)}));let s=ne("cn-bot"),o=s.value;s.innerHTML=ia.map(r=>`<option value="${i(r.larkAppId)}">${i(r.botName)}</option>`).join("")||`<option value="">${t("connectors.noOnlineBots")}</option>`,o&&(s.value=o),Bo(),or(n.body?.connectors||[])}function Oo(e){e.innerHTML=er(),ne("cn-kind").onchange=oa,ne("cn-mode").onchange=oa,ne("cn-bot").onchange=Bo,ne("cn-chat-manual").onclick=n=>{n.preventDefault();let a=ne("cn-chat"),s=ne("cn-chat-sel"),o=a.style.display==="none";a.style.display=o?"":"none",s.style.display=o?"none":"",ne("cn-chat-manual").textContent=o?t("connectors.chatListLink"):t("connectors.chatManualLink")},oa(),ne("cn-create").onclick=async()=>{let n=ne("cn-create-out"),a=vt("cn-name"),s=ne("cn-bot").value;if(!a){n.innerHTML=`<span class="err">${t("connectors.errName")}</span>`;return}if(!s){n.innerHTML=`<span class="err">${t("connectors.errBot")}</span>`;return}let o=ne("cn-kind").value,r=ne("cn-mode").value,d={name:a,enabled:!0,target:{kind:o,mode:r,botId:s},promptEnvelope:{sourceName:a}},p=vt("cn-instruction");if(p&&(d.promptEnvelope.instruction=p),o==="workflow"){if(!vt("cn-wf")){n.innerHTML=`<span class="err">${t("connectors.errWf")}</span>`;return}d.target.workflowId=vt("cn-wf")}if(r==="fixed"){let w=ne("cn-chat").style.display!=="none"?vt("cn-chat"):ne("cn-chat-sel").value;if(!w){n.innerHTML=`<span class="err">${t("connectors.errChat")}</span>`;return}d.target.chatId=w}else{let E=Array.from(ne("cn-allow-sel").selectedOptions).map(w=>w.value).filter(Boolean);E.length&&(d.target.allowChats=E)}if(r==="new-group"){let E=vt("cn-dedup");d.lifecycleExtractors=E?{dedupKey:E}:null}d.verify={type:ne("cn-verify").value};let k=vt("cn-secret");k&&(d.secret=k),n.innerHTML=`<span class="muted">${t("connectors.creating")}</span>`;let $=await sa("POST","/api/connectors",d);if($.status===201&&$.body?.ok){n.innerHTML="";let E=ne("cn-created");E.style.display="";let w=$.body.webhookUrl||Po($.body.connector.id),u=$.body.secret,S=($.body.connector?.verify?.type??"token")==="token",x=r==="dynamic",A=x?d.target.allowChats?.[0]||"<chatId>":"",L=x?`${i(w)}?chatId=${i(A)}`:i(w),H;if(S&&x){let T=A!=="<chatId>"?`\uFF08${i(ra(d.target.allowChats[0]))}\uFF09`:"";H=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicLede",{gn:T})}</p>
1138
+ <pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${L}' -H 'content-type: application/json' -d '{}'</code></pre>
1139
+ <p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicNote")}</p>`}else S?H=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageTokenLede")}</p>
1140
+ <pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${L}' -H 'content-type: application/json' -d '{}'</code></pre>
1141
+ <p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageTokenNote")}</p>`:H=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageHmac")}${x?t("connectors.usageHmacDynamic"):""}</p>`;E.innerHTML=`<div class="card" style="padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
1142
+ <p class="ok" style="margin:0 0 6px">${t("connectors.createdPrefix",{name:i(a)})}${r==="fixed"&&d.target.chatId?`<span class="muted" style="font-weight:400;font-size:13px"> \xB7 ${t("connectors.createdDest",{name:i(ra(d.target.chatId))})}</span>`:""}</p>
1143
+ <p style="margin:4px 0;font-size:13px"><span class="muted">${t("connectors.webhookUrl")}</span><code style="word-break:break-all">${i(w)}</code></p>
1144
+ ${u?`<p style="margin:4px 0;font-size:13px"><span class="muted">${S?t("connectors.tokenLabel"):t("connectors.signLabel")}${t("connectors.secretOnce")}</span><code>${i(u)}</code></p>`:""}
1145
+ ${H}</div>`,["cn-name","cn-wf","cn-chat","cn-dedup","cn-secret","cn-instruction"].forEach(T=>{ne(T).value=""}),ne("cn-allow-sel").selectedIndex=-1,vn()}else{let E=$.body?.error||$.status;n.innerHTML=`<span class="err">${t("connectors.createFailed",{error:i(String(E))})}</span>`}},vn()}var $e=null,Wt=null,_t=!0;function No(e){return{publicReadOnly:e?.publicReadOnly===!0,openTerminalInFeishu:e?.openTerminalInFeishu===!0,repoPickerMode:e?.repoPickerMode==="repos"?"repos":"all",maintenance:e?.maintenance&&typeof e.maintenance=="object"?e.maintenance:{},localDevInstall:e?.localDevInstall===!0}}function sr(e,n){let a=e?.[n]??{};return{enabled:a.enabled===!0,time:typeof a.time=="string"?a.time:"04:00"}}function ir(){return`<section class="page">
1003
1146
  <div class="page-heading">
1004
1147
  <div>
1005
1148
  <p class="eyebrow">${t("nav.settings")}</p>
@@ -1008,7 +1151,7 @@ ${$a("manage")}
1008
1151
  </div>
1009
1152
  </div>
1010
1153
  <div id="settings-body"></div>
1011
- </section>`}function Ci(e){let{enabled:n,time:o}=Ei(ke.maintenance,"autoUpdate"),s=e?"disabled":"";return`<label class="toggle-row">
1154
+ </section>`}function rr(e){let{enabled:n,time:a}=sr($e.maintenance,"autoUpdate"),s=e?"disabled":"";return`<label class="toggle-row">
1012
1155
  <input type="checkbox" data-maint="autoUpdate" ${n?"checked":""} ${s}>
1013
1156
  <span class="switch" aria-hidden="true"></span>
1014
1157
  <span class="toggle-tx"><strong>${t("settings.autoUpdate")}</strong>
@@ -1016,20 +1159,20 @@ ${$a("manage")}
1016
1159
  </label>
1017
1160
  <div class="maint-time">
1018
1161
  <label>${t("settings.maintenanceTime")}
1019
- <input type="time" data-maint-time="autoUpdate" value="${r(o)}" ${s}>
1162
+ <input type="time" data-maint-time="autoUpdate" value="${i(a)}" ${s}>
1020
1163
  </label>
1021
- </div>`}function Ai(e){return`<label class="toggle-row">
1022
- <input type="checkbox" data-maint="autoRestart" ${ke.maintenance.autoRestart?.enabled===!0?"checked":""} ${e?"disabled":""}>
1164
+ </div>`}function lr(e){return`<label class="toggle-row">
1165
+ <input type="checkbox" data-maint="autoRestart" ${$e.maintenance.autoRestart?.enabled===!0?"checked":""} ${e?"disabled":""}>
1023
1166
  <span class="switch" aria-hidden="true"></span>
1024
1167
  <span class="toggle-tx"><strong>${t("settings.autoRestart")}</strong>
1025
1168
  <small>${t("settings.autoRestartHelp")}</small></span>
1026
- </label>`}function Di(){if(jt)return`<p class="hint-warn">${t("settings.loadFailed")}: ${r(jt)}</p>`;if(!ke)return`<p class="empty">${t("settings.loading")}</p>`;let e=Ut?"":"disabled",n=!Ut||ke.localDevInstall;return`<div class="settings-grid">
1169
+ </label>`}function dr(){if(Wt)return`<p class="hint-warn">${t("settings.loadFailed")}: ${i(Wt)}</p>`;if(!$e)return`<p class="empty">${t("settings.loading")}</p>`;let e=_t?"":"disabled",n=!_t||$e.localDevInstall;return`<div class="settings-grid">
1027
1170
  <article class="bd-card settings-card">
1028
- ${Ut?"":`<p class="hint-warn">${t("settings.readOnlyVisitor")}</p>`}
1171
+ ${_t?"":`<p class="hint-warn">${t("settings.readOnlyVisitor")}</p>`}
1029
1172
  <section class="bd-section">
1030
1173
  <h3 class="bd-section-title">${t("settings.sectionAccess")}</h3>
1031
1174
  <label class="toggle-row">
1032
- <input type="checkbox" data-setting="publicReadOnly" ${ke.publicReadOnly?"checked":""} ${e}>
1175
+ <input type="checkbox" data-setting="publicReadOnly" ${$e.publicReadOnly?"checked":""} ${e}>
1033
1176
  <span class="switch" aria-hidden="true"></span>
1034
1177
  <span class="toggle-tx"><strong>${t("settings.publicReadOnly")}</strong>
1035
1178
  <small>${t("settings.publicReadOnlyHelp")}</small></span>
@@ -1038,7 +1181,7 @@ ${$a("manage")}
1038
1181
  <section class="bd-section">
1039
1182
  <h3 class="bd-section-title">${t("settings.sectionCards")}</h3>
1040
1183
  <label class="toggle-row">
1041
- <input type="checkbox" data-setting="openTerminalInFeishu" ${ke.openTerminalInFeishu?"checked":""} ${e}>
1184
+ <input type="checkbox" data-setting="openTerminalInFeishu" ${$e.openTerminalInFeishu?"checked":""} ${e}>
1042
1185
  <span class="switch" aria-hidden="true"></span>
1043
1186
  <span class="toggle-tx"><strong>${t("settings.openTerminalInFeishu")}</strong>
1044
1187
  <small>${t("settings.openTerminalInFeishuHelp")}</small></span>
@@ -1049,23 +1192,23 @@ ${$a("manage")}
1049
1192
  <label class="form-row">
1050
1193
  <span>${t("settings.repoPickerMode")}</span>
1051
1194
  <select data-select-setting="repoPickerMode" ${e}>
1052
- <option value="all" ${ke.repoPickerMode==="all"?"selected":""}>${t("settings.repoPickerModeAll")}</option>
1053
- <option value="repos" ${ke.repoPickerMode==="repos"?"selected":""}>${t("settings.repoPickerModeRepos")}</option>
1195
+ <option value="all" ${$e.repoPickerMode==="all"?"selected":""}>${t("settings.repoPickerModeAll")}</option>
1196
+ <option value="repos" ${$e.repoPickerMode==="repos"?"selected":""}>${t("settings.repoPickerModeRepos")}</option>
1054
1197
  </select>
1055
1198
  <small>${t("settings.repoPickerModeHelp")}</small>
1056
1199
  </label>
1057
1200
  </section>
1058
1201
  <section class="bd-section">
1059
1202
  <h3 class="bd-section-title">${t("settings.sectionMaintenance")}</h3>
1060
- ${Ci(n)}
1061
- ${ke.localDevInstall?`<p class="hint-warn">${t("settings.autoUpdateLocalDev")}</p>`:""}
1062
- ${Ai(!Ut||ke.maintenance.autoUpdate?.enabled!==!0)}
1203
+ ${rr(n)}
1204
+ ${$e.localDevInstall?`<p class="hint-warn">${t("settings.autoUpdateLocalDev")}</p>`:""}
1205
+ ${lr(!_t||$e.maintenance.autoUpdate?.enabled!==!0)}
1063
1206
  </section>
1064
1207
  <div class="actions settings-actions">
1065
1208
  <span class="oncall-status" data-settings-status></span>
1066
1209
  </div>
1067
1210
  </article>
1068
- </div>`}async function Ri(){try{let e=await fetch("/api/settings"),n=await e.json().catch(()=>({}));if(!e.ok){ke=null,jt=n?.error??`HTTP ${e.status}`;return}ke=Ea(n.settings),Ut=n.authed===!0,jt=null}catch(e){ke=null,jt=e?.message??String(e)}}async function Ha(e){e.innerHTML=Hi();let n=e.querySelector("#settings-body");function o(){n.innerHTML=Di(),i()}function s(){return n.querySelector("[data-settings-status]")}async function a(d,p,v){if(!ke)return;v.disabled=!0;let k=s();k&&(k.textContent=t("settings.saving"),k.className="oncall-status");try{let I=await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(d)}),T=await I.json().catch(()=>({}));if(!I.ok||T.ok===!1)throw new Error(T?.error??`HTTP ${I.status}`);ke=Ea(T.settings),k&&(k.textContent=t("settings.saved"),k.classList.add("hint-ok"))}catch(I){p(),k&&(k.textContent=`${t("settings.saveFailed")}: ${I?.message??I}`,k.classList.add("hint-warn-inline"))}finally{v.disabled=!1}}function i(){n.querySelectorAll("input[data-setting]").forEach(p=>{p.addEventListener("change",()=>{let v=p.dataset.setting,k=!p.checked;a({[v]:p.checked},()=>{p.checked=k},p)})}),n.querySelectorAll("select[data-select-setting]").forEach(p=>{p.addEventListener("change",()=>{let v=p.dataset.selectSetting,k=ke?.[v]??"all";a({[v]:p.value},()=>{p.value=k},p)})});let d=(p,v,k)=>{let T=n.querySelector(`input[data-maint="${p}"]`)?.checked??!1,g;if(p==="autoUpdate"){let R=n.querySelector('input[data-maint-time="autoUpdate"]');g={enabled:T,time:R?.value||"04:00"}}else g={enabled:T};a({maintenance:{[p]:g}},k,v).then(()=>o())};n.querySelectorAll("input[data-maint]").forEach(p=>{p.addEventListener("change",()=>{let v=p.dataset.maint,k=!p.checked;d(v,p,()=>{p.checked=k})})}),n.querySelectorAll("input[data-maint-time]").forEach(p=>{p.addEventListener("change",()=>{let v=p.dataset.maintTime,k=p.defaultValue;d(v,p,()=>{p.value=k})})})}o(),await Ri(),o()}function Oi(){let e=[["",t("workflow.filter.nonTerminal")],["all",t("workflow.filter.all")],["pending",lt("pending")],["running",lt("running")],["waiting",lt("waiting")],["succeeded",lt("succeeded")],["failed",lt("failed")],["cancelled",lt("cancelled")]];return`
1211
+ </div>`}async function cr(){try{let e=await fetch("/api/settings"),n=await e.json().catch(()=>({}));if(!e.ok){$e=null,Wt=n?.error??`HTTP ${e.status}`;return}$e=No(n.settings),_t=n.authed===!0,Wt=null}catch(e){$e=null,Wt=e?.message??String(e)}}async function qo(e){e.innerHTML=ir();let n=e.querySelector("#settings-body");function a(){n.innerHTML=dr(),r()}function s(){return n.querySelector("[data-settings-status]")}async function o(d,p,k){if(!$e)return;k.disabled=!0;let $=s();$&&($.textContent=t("settings.saving"),$.className="oncall-status");try{let E=await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(d)}),w=await E.json().catch(()=>({}));if(!E.ok||w.ok===!1)throw new Error(w?.error??`HTTP ${E.status}`);$e=No(w.settings),$&&($.textContent=t("settings.saved"),$.classList.add("hint-ok"))}catch(E){p(),$&&($.textContent=`${t("settings.saveFailed")}: ${E?.message??E}`,$.classList.add("hint-warn-inline"))}finally{k.disabled=!1}}function r(){n.querySelectorAll("input[data-setting]").forEach(p=>{p.addEventListener("change",()=>{let k=p.dataset.setting,$=!p.checked;o({[k]:p.checked},()=>{p.checked=$},p)})}),n.querySelectorAll("select[data-select-setting]").forEach(p=>{p.addEventListener("change",()=>{let k=p.dataset.selectSetting,$=$e?.[k]??"all";o({[k]:p.value},()=>{p.value=$},p)})});let d=(p,k,$)=>{let w=n.querySelector(`input[data-maint="${p}"]`)?.checked??!1,u;if(p==="autoUpdate"){let S=n.querySelector('input[data-maint-time="autoUpdate"]');u={enabled:w,time:S?.value||"04:00"}}else u={enabled:w};o({maintenance:{[p]:u}},$,k).then(()=>a())};n.querySelectorAll("input[data-maint]").forEach(p=>{p.addEventListener("change",()=>{let k=p.dataset.maint,$=!p.checked;d(k,p,()=>{p.checked=$})})}),n.querySelectorAll("input[data-maint-time]").forEach(p=>{p.addEventListener("change",()=>{let k=p.dataset.maintTime,$=p.defaultValue;d(k,p,()=>{p.value=$})})})}a(),await cr(),a()}function ur(){let e=[["",t("workflow.filter.nonTerminal")],["all",t("workflow.filter.all")],["pending",ut("pending")],["running",ut("running")],["waiting",ut("waiting")],["succeeded",ut("succeeded")],["failed",ut("failed")],["cancelled",ut("cancelled")]];return`
1069
1212
  <nav class="wf-subnav">
1070
1213
  <a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${h(t("workflow.subnav.runs"))}</a>
1071
1214
  <a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${h(t("workflow.subnav.catalog"))}</a>
@@ -1073,7 +1216,7 @@ ${$a("manage")}
1073
1216
  <form id="wf-filters" class="filters">
1074
1217
  <input type="search" name="q" placeholder="${h(t("workflow.searchPlaceholder"))}" />
1075
1218
  <select name="status">
1076
- ${e.map(([n,o])=>`<option value="${h(n)}">${h(o)}</option>`).join("")}
1219
+ ${e.map(([n,a])=>`<option value="${h(n)}">${h(a)}</option>`).join("")}
1077
1220
  </select>
1078
1221
  <span id="wf-last-load" class="muted"></span>
1079
1222
  </form>
@@ -1085,15 +1228,15 @@ ${$a("manage")}
1085
1228
  </tr></thead>
1086
1229
  <tbody id="wf-tbody"></tbody>
1087
1230
  </table>
1088
- `}var Bi=5e3,Ni=2e3,Ft=new Set(["succeeded","failed","cancelled"]);function h(e){return e.replace(/[&<>"']/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[n])}function Pi(e){let n=new Date(e),s=Date.now()-e;return s<6e4?t("time.secondsAgo",{value:Math.max(1,Math.floor(s/1e3))}):s<36e5?t("time.minutesAgo",{value:Math.floor(s/6e4)}):s<864e5?t("time.hoursAgo",{value:Math.floor(s/36e5)}):n.toISOString().slice(0,19).replace("T"," ")}function tt(e){return`<span class="${Ft.has(e)?"wf-status terminal":"wf-status live"} wf-status-${h(e)}">${h(lt(e))}</span>`}function lt(e){let n=`workflow.status.${e}`,o=t(n);return o===n?e:o}function Ra(e){let n=location.hash.match(/^#\/workflows\/([^?#]+)(?:\?([^#]*))?$/);if(n){let o=new URLSearchParams(n[2]??"");return Ui(e,decodeURIComponent(n[1]),{focusAttemptId:o.get("attempt")??void 0})}return qi(e)}function qi(e){e.innerHTML=Oi();let n=e.querySelector("#wf-tbody"),o=e.querySelector("#wf-filters"),s=e.querySelector("#wf-last-load"),a=[],i=null,d=!1,p=null,v=!1;function k(O){let E=(new FormData(o).get("q")??"").trim().toLowerCase();return E?O.filter($=>$.runId.toLowerCase().includes(E)||$.workflowId.toLowerCase().includes(E)||($.chatId??"").toLowerCase().includes(E)):O}function I(){let O=k(a);if(O.length===0){n.innerHTML=`<tr><td colspan="7" class="empty">${p?h(t("workflow.list.failedLoad",{error:p})):a.length===0?h(t("workflow.list.noRuns")):h(t("workflow.list.noFilterMatch"))}</td></tr>`;return}n.innerHTML=O.map(M=>{let E=`${M.dEf}/${M.dAct}/${M.dWait}`,$=M.dEf+M.dAct+M.dWait>0?"wf-dangling has":"wf-dangling none",D=[];M.chatId&&D.push(h(M.chatId)),M.larkAppId&&D.push(`<span class="muted">${h(M.larkAppId)}</span>`);let m=D.length>0?D.join("<br/>"):"\u2014",y=Fi(M);return`<tr data-runid="${h(M.runId)}">
1089
- <td><a href="#/workflows/${encodeURIComponent(M.runId)}"><code>${h(M.runId)}</code></a></td>
1090
- <td>${h(M.workflowId)}</td>
1091
- <td>${tt(M.status)}${M.failedNodeId?` <span class="muted">(${h(M.failedNodeId)})</span>`:""}${y}</td>
1092
- <td>${M.lastSeq}</td>
1093
- <td class="${$}">${E}</td>
1094
- <td title="${h(new Date(M.updatedAt).toISOString())}">${Pi(M.updatedAt)}</td>
1095
- <td>${m}</td>
1096
- </tr>`}).join("")}function T(){p?(s.textContent=t("workflow.list.error",{error:p}),s.classList.add("error")):(s.textContent=t("workflow.list.loaded",{count:a.length,time:new Date().toLocaleTimeString()}),s.classList.remove("error"))}async function g(){if(!(v||d)&&!document.hidden){d=!0;try{let O=o.elements.namedItem("status")?.value??"",M=new URLSearchParams;O==="all"?M.set("all","1"):O&&M.set("status",O);let E="/api/workflows/runs"+(M.toString()?`?${M}`:""),$=await fetch(E);$.ok?(a=(await $.json()).runs??[],p=null):(p=`HTTP ${$.status}`,a=[])}catch(O){p=O?.message??String(O),a=[]}finally{d=!1,v||(I(),T())}}}function R(){i!==null&&window.clearTimeout(i),i=window.setTimeout(async()=>{await g(),v||R()},Bi)}function A(){document.hidden||g()}return o.addEventListener("input",()=>{I()}),o.addEventListener("change",O=>{O.target.getAttribute("name")==="status"&&g()}),document.addEventListener("visibilitychange",A),g().then(()=>{v||R()}),()=>{v=!0,i!==null&&window.clearTimeout(i),document.removeEventListener("visibilitychange",A)}}function Ui(e,n,o={}){e.innerHTML=`
1231
+ `}var pr=5e3,mr=2e3,zt=new Set(["succeeded","failed","cancelled"]);function h(e){return e.replace(/[&<>"']/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[n])}function fr(e){let n=new Date(e),s=Date.now()-e;return s<6e4?t("time.secondsAgo",{value:Math.max(1,Math.floor(s/1e3))}):s<36e5?t("time.minutesAgo",{value:Math.floor(s/6e4)}):s<864e5?t("time.hoursAgo",{value:Math.floor(s/36e5)}):n.toISOString().slice(0,19).replace("T"," ")}function at(e){return`<span class="${zt.has(e)?"wf-status terminal":"wf-status live"} wf-status-${h(e)}">${h(ut(e))}</span>`}function ut(e){let n=`workflow.status.${e}`,a=t(n);return a===n?e:a}function Go(e){let n=location.hash.match(/^#\/workflows\/([^?#]+)(?:\?([^#]*))?$/);if(n){let a=new URLSearchParams(n[2]??"");return br(e,decodeURIComponent(n[1]),{focusAttemptId:a.get("attempt")??void 0})}return gr(e)}function gr(e){e.innerHTML=ur();let n=e.querySelector("#wf-tbody"),a=e.querySelector("#wf-filters"),s=e.querySelector("#wf-last-load"),o=[],r=null,d=!1,p=null,k=!1;function $(A){let H=(new FormData(a).get("q")??"").trim().toLowerCase();return H?A.filter(T=>T.runId.toLowerCase().includes(H)||T.workflowId.toLowerCase().includes(H)||(T.chatId??"").toLowerCase().includes(H)):A}function E(){let A=$(o);if(A.length===0){n.innerHTML=`<tr><td colspan="7" class="empty">${p?h(t("workflow.list.failedLoad",{error:p})):o.length===0?h(t("workflow.list.noRuns")):h(t("workflow.list.noFilterMatch"))}</td></tr>`;return}n.innerHTML=A.map(L=>{let H=`${L.dEf}/${L.dAct}/${L.dWait}`,T=L.dEf+L.dAct+L.dWait>0?"wf-dangling has":"wf-dangling none",P=[];L.chatId&&P.push(h(L.chatId)),L.larkAppId&&P.push(`<span class="muted">${h(L.larkAppId)}</span>`);let f=P.length>0?P.join("<br/>"):"\u2014",v=wr(L);return`<tr data-runid="${h(L.runId)}">
1232
+ <td><a href="#/workflows/${encodeURIComponent(L.runId)}"><code>${h(L.runId)}</code></a></td>
1233
+ <td>${h(L.workflowId)}</td>
1234
+ <td>${at(L.status)}${L.failedNodeId?` <span class="muted">(${h(L.failedNodeId)})</span>`:""}${v}</td>
1235
+ <td>${L.lastSeq}</td>
1236
+ <td class="${T}">${H}</td>
1237
+ <td title="${h(new Date(L.updatedAt).toISOString())}">${fr(L.updatedAt)}</td>
1238
+ <td>${f}</td>
1239
+ </tr>`}).join("")}function w(){p?(s.textContent=t("workflow.list.error",{error:p}),s.classList.add("error")):(s.textContent=t("workflow.list.loaded",{count:o.length,time:new Date().toLocaleTimeString()}),s.classList.remove("error"))}async function u(){if(!(k||d)&&!document.hidden){d=!0;try{let A=a.elements.namedItem("status")?.value??"",L=new URLSearchParams;A==="all"?L.set("all","1"):A&&L.set("status",A);let H="/api/workflows/runs"+(L.toString()?`?${L}`:""),T=await fetch(H);T.ok?(o=(await T.json()).runs??[],p=null):(p=`HTTP ${T.status}`,o=[])}catch(A){p=A?.message??String(A),o=[]}finally{d=!1,k||(E(),w())}}}function S(){r!==null&&window.clearTimeout(r),r=window.setTimeout(async()=>{await u(),k||S()},pr)}function x(){document.hidden||u()}return a.addEventListener("input",()=>{E()}),a.addEventListener("change",A=>{A.target.getAttribute("name")==="status"&&u()}),document.addEventListener("visibilitychange",x),u().then(()=>{k||S()}),()=>{k=!0,r!==null&&window.clearTimeout(r),document.removeEventListener("visibilitychange",x)}}function br(e,n,a={}){e.innerHTML=`
1097
1240
  <div class="wf-detail-head">
1098
1241
  <a class="btn-link" href="#/workflows">${h(t("workflow.detail.back"))}</a>
1099
1242
  <div>
@@ -1149,253 +1292,253 @@ ${$a("manage")}
1149
1292
  </div>
1150
1293
  <div id="wf-event-meta" class="muted"></div>
1151
1294
  </section>
1152
- `;let s=e.querySelector("#wf-detail-subtitle"),a=e.querySelector("#wf-detail-refresh"),i=e.querySelector("#wf-detail-error"),d=e.querySelector("#wf-cancel-status"),p=e.querySelector("#wf-summary"),v=e.querySelector("#wf-dangling-panel"),k=e.querySelector("#wf-parallel-view"),I=e.querySelector("#wf-parallel-meta"),T=e.querySelector("#wf-node-tbody"),g=e.querySelector("#wf-io-list"),R=e.querySelector(".wf-timeline-scroll"),A=e.querySelector("#wf-event-tbody"),O=e.querySelector("#wf-event-meta"),M=e.querySelector("#wf-cancel-run"),E=e.querySelector("#wf-load-older"),$=null,D=[],m=new Set,y=null,S=null,H=!1,B=0,j=null,q=!1,oe=!1,X=!1,ae=new Set,Ae=new Map,se=new Map,ie=new Map,ce=new Set,Le=new Map,de=new Set,Be=new Map,ge=new Map,Ie=0,re=o.focusAttemptId;function pe(x){if(!x){i.hidden=!0,i.textContent="";return}i.hidden=!1,i.textContent=x}function le(x){if(!x){d.hidden=!0,d.textContent="";return}d.hidden=!1,d.textContent=x}async function Ne(){let x=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/snapshot`);if(x.status===404)throw new Error(t("workflow.detail.unknownRun"));if(!x.ok)throw new Error(t("workflow.detail.snapshotHttp",{status:x.status}));$=await x.json()}async function je(x){let V=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/events?${x}`);if(V.status===404)throw new Error(t("workflow.detail.unknownRun"));if(!V.ok)throw new Error(t("workflow.detail.eventsHttp",{status:V.status}));return await V.json()}function Pe(x,V){let K=x.filter(_=>m.has(_.eventId)?!1:(m.add(_.eventId),!0));K.length!==0&&(D=V==="prepend"?[...K,...D]:[...D,...K],D.sort((_,he)=>Gt(_.eventId)-Gt(he.eventId)))}async function Fe(){await Ne();let x=await je(new URLSearchParams({tail:"100"}));D=[],m=new Set,Pe(x.events,"append"),y=x.oldestSeq,S=x.newestSeq,H=x.hasOlder,B=x.totalCount,Me()}async function be(){if(!(q||oe||document.hidden)){oe=!0;try{if(await Ne(),S!==null){let x=await je(new URLSearchParams({afterSeq:String(S),limit:"200"}));Pe(x.events,"append"),x.newestSeq!==null&&(S=x.newestSeq),y===null&&x.oldestSeq!==null&&(y=x.oldestSeq),B=x.totalCount}else{let x=await je(new URLSearchParams({tail:"1"}));Pe(x.events,"append"),y=x.oldestSeq,S=x.newestSeq,H=x.hasOlder,B=x.totalCount}pe(null),Me()}catch(x){pe(x?.message??String(x))}finally{oe=!1}}}async function nt(){if(!(y===null||!H)){E.disabled=!0;try{let x=await je(new URLSearchParams({beforeSeq:String(y),limit:"100"}));Pe(x.events,"prepend"),x.oldestSeq!==null&&(y=x.oldestSeq),H=x.hasOlder,B=x.totalCount,pe(null),Me()}catch(x){pe(x?.message??String(x))}finally{E.disabled=!1}}}async function wt(){if(!$||Ft.has($.run.status)||X)return;if(!$.chatBinding?.larkAppId){pe(t("workflow.detail.cancelUnavailable",{runId:n}));return}let x=Gi($),V=t("workflow.detail.cancelConfirm",{runId:n,...x});if(window.confirm(V)){X=!0,M.disabled=!0;try{let K=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/cancel`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"cancelled via dashboard"})});if(K.status===401)throw new Error(t("workflow.detail.writeAccessCancel"));let _=await K.json().catch(()=>({}));if(!K.ok||!_.ok)throw new Error(_.hint??_.error??t("workflow.detail.cancelHttp",{status:K.status}));le(_.pending?t("workflow.detail.cancelPending"):null),pe(null),await be()}catch(K){pe(K?.message??String(K))}finally{X=!1,M.disabled=!1,Me()}}}async function ot(x,V){if(!de.has(x)){de.add(x),Be.delete(x),Me();try{let K=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/attempts/${encodeURIComponent(V)}/${encodeURIComponent(x)}/resume`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});if(K.status===401)throw new Error(t("workflow.detail.writeAccessResume"));let _=await K.json().catch(()=>({}));if(!K.ok||!_.ok||!_.resumeId||!_.url)throw new Error(_.hint??_.message??_.error??t("workflow.detail.resumeStartFailed",{status:K.status}));Le.set(x,{resumeId:_.resumeId,url:_.url})}catch(K){let _=K?.message??String(K);Be.set(x,_)}finally{de.delete(x),Me()}}}async function Ht(x,V){if(!de.has(x)){de.add(x),Be.delete(x),Me();try{let K=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/attempts/${encodeURIComponent(V)}/${encodeURIComponent(x)}/resume/end`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"ended_by_dashboard"})});if(K.status===401)throw new Error(t("workflow.detail.writeAccessResume"));let _=await K.json().catch(()=>({}));if(!K.ok||!_.ok)if(_.error==="resume_not_running")Le.delete(x);else throw new Error(_.hint??_.message??_.error??t("workflow.detail.resumeEndFailed",{status:K.status}));else Le.delete(x)}catch(K){let _=K?.message??String(K);Be.set(x,_)}finally{de.delete(x),Me()}}}async function at(x,V){if(!ce.has(x)){ce.add(x),ie.delete(x),Me();try{let K=se.get(x)?.trim()||void 0,_=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/${V}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({comment:K})});if(_.status===401)throw new Error(t("workflow.detail.writeAccessApproval"));let he=await _.json().catch(()=>({}));if(!_.ok||!he.ok)throw new Error(he.hint??he.message??he.error??t("workflow.detail.actionHttp",{action:V,status:_.status}));let Xe=V==="approve"?t("workflow.detail.approved"):t("workflow.detail.rejected");ie.set(x,{kind:"ok",text:he.alreadyTerminal?t("workflow.detail.alreadyTerminal",{label:Xe}):he.pending?t("workflow.detail.workflowContinue",{label:Xe}):t("workflow.detail.workflowRefreshing",{label:Xe})}),pe(null),await be()}catch(K){let _=K?.message??String(K);ie.set(x,{kind:"error",text:_}),pe(_)}finally{ce.delete(x),Me()}}}function Me(){if(!$)return;Ie=R.scrollTop;let x=$.run;Ft.has(x.status)&&le(null),s.innerHTML=`${h(x.workflowId??"?")} \xB7 ${tt(x.status)} \xB7 lastSeq ${$.lastSeq}`,a.textContent=t("workflow.detail.refreshed",{time:new Date().toLocaleTimeString()}),M.hidden=Ft.has(x.status),M.disabled=X||!$.chatBinding?.larkAppId,M.textContent=$.chatBinding?.larkAppId?t("workflow.detail.cancel"):t("workflow.detail.cliCancelOnly"),M.title=$.chatBinding?.larkAppId?t("workflow.detail.cancelTitle"):t("workflow.detail.cliCancelTitle",{runId:n}),ji(p,$),_i(v,$),zi(k,I,$,D),Qi(T,$),Xi(g,$,ae,Ae,{comments:se,statuses:ie,resolving:ce,onResolve:at},{sessions:Le,pending:de,errors:Be,onStart:ot,onEnd:Ht},re,ge)&&(re=void 0),Tr(A,D),R.scrollTop=Ie,E.hidden=!H,O.textContent=t("workflow.detail.eventsLoaded",{loaded:D.length,total:B})}function _e(){if(j!==null&&window.clearTimeout(j),$&&Ft.has($.run.status)){j=null;return}j=window.setTimeout(async()=>{await be(),q||_e()},Ni)}function Ge(){document.hidden||be().then(()=>{!q&&j===null&&_e()})}return E.addEventListener("click",()=>{nt()}),M.addEventListener("click",()=>{wt()}),document.addEventListener("visibilitychange",Ge),Fe().then(()=>{pe(null),q||_e()}).catch(x=>{pe(x?.message??String(x)),s.textContent=t("workflow.detail.loadFailed")}),()=>{q=!0,j!==null&&window.clearTimeout(j),document.removeEventListener("visibilitychange",Ge)}}function ji(e,n){let o=n.run,s=[[t("workflow.summary.workflow"),h(o.workflowId??"?")],[t("workflow.summary.status"),tt(o.status)],[t("workflow.summary.lastSeq"),String(n.lastSeq)],[t("workflow.summary.updated"),h(new Date(n.updatedAt).toLocaleString())],[t("workflow.summary.revision"),h(hn(o.revisionId))],[t("workflow.summary.initiator"),h(o.initiator??"-")]];o.failedNodeId&&s.push([t("workflow.summary.failedNode"),h(o.failedNodeId)]),o.cancelOriginEventId&&s.push([t("workflow.summary.cancelOrigin"),h(o.cancelOriginEventId)]),n.chatBinding&&(s.push([t("workflow.summary.chat"),`<code>${h(n.chatBinding.chatId)}</code>`]),s.push([t("workflow.summary.app"),`<code>${h(n.chatBinding.larkAppId)}</code>`])),e.innerHTML=s.map(([a,i])=>`<div class="wf-summary-item"><span>${a}</span><strong>${i}</strong></div>`).join("")}function Fi(e){if(!e.errorCode)return"";let n=e.errorMessage?` \u2014 ${xr(e.errorMessage,96)}`:"";return`<div class="wf-run-error">
1295
+ `;let s=e.querySelector("#wf-detail-subtitle"),o=e.querySelector("#wf-detail-refresh"),r=e.querySelector("#wf-detail-error"),d=e.querySelector("#wf-cancel-status"),p=e.querySelector("#wf-summary"),k=e.querySelector("#wf-dangling-panel"),$=e.querySelector("#wf-parallel-view"),E=e.querySelector("#wf-parallel-meta"),w=e.querySelector("#wf-node-tbody"),u=e.querySelector("#wf-io-list"),S=e.querySelector(".wf-timeline-scroll"),x=e.querySelector("#wf-event-tbody"),A=e.querySelector("#wf-event-meta"),L=e.querySelector("#wf-cancel-run"),H=e.querySelector("#wf-load-older"),T=null,P=[],f=new Set,v=null,I=null,D=!1,B=0,U=null,q=!1,ae=!1,X=!1,oe=new Set,De=new Map,se=new Map,re=new Map,ue=new Set,Me=new Map,ce=new Set,Oe=new Map,be=new Map,Ee=0,le=a.focusAttemptId;function fe(C){if(!C){r.hidden=!0,r.textContent="";return}r.hidden=!1,r.textContent=C}function de(C){if(!C){d.hidden=!0,d.textContent="";return}d.hidden=!1,d.textContent=C}async function Ne(){let C=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/snapshot`);if(C.status===404)throw new Error(t("workflow.detail.unknownRun"));if(!C.ok)throw new Error(t("workflow.detail.snapshotHttp",{status:C.status}));T=await C.json()}async function Fe(C){let Y=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/events?${C}`);if(Y.status===404)throw new Error(t("workflow.detail.unknownRun"));if(!Y.ok)throw new Error(t("workflow.detail.eventsHttp",{status:Y.status}));return await Y.json()}function qe(C,Y){let K=C.filter(_=>f.has(_.eventId)?!1:(f.add(_.eventId),!0));K.length!==0&&(P=Y==="prepend"?[...K,...P]:[...P,...K],P.sort((_,we)=>Kt(_.eventId)-Kt(we.eventId)))}async function Ge(){await Ne();let C=await Fe(new URLSearchParams({tail:"100"}));P=[],f=new Set,qe(C.events,"append"),v=C.oldestSeq,I=C.newestSeq,D=C.hasOlder,B=C.totalCount,xe()}async function he(){if(!(q||ae||document.hidden)){ae=!0;try{if(await Ne(),I!==null){let C=await Fe(new URLSearchParams({afterSeq:String(I),limit:"200"}));qe(C.events,"append"),C.newestSeq!==null&&(I=C.newestSeq),v===null&&C.oldestSeq!==null&&(v=C.oldestSeq),B=C.totalCount}else{let C=await Fe(new URLSearchParams({tail:"1"}));qe(C.events,"append"),v=C.oldestSeq,I=C.newestSeq,D=C.hasOlder,B=C.totalCount}fe(null),xe()}catch(C){fe(C?.message??String(C))}finally{ae=!1}}}async function ot(){if(!(v===null||!D)){H.disabled=!0;try{let C=await Fe(new URLSearchParams({beforeSeq:String(v),limit:"100"}));qe(C.events,"prepend"),C.oldestSeq!==null&&(v=C.oldestSeq),D=C.hasOlder,B=C.totalCount,fe(null),xe()}catch(C){fe(C?.message??String(C))}finally{H.disabled=!1}}}async function $t(){if(!T||zt.has(T.run.status)||X)return;if(!T.chatBinding?.larkAppId){fe(t("workflow.detail.cancelUnavailable",{runId:n}));return}let C=yr(T),Y=t("workflow.detail.cancelConfirm",{runId:n,...C});if(window.confirm(Y)){X=!0,L.disabled=!0;try{let K=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/cancel`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"cancelled via dashboard"})});if(K.status===401)throw new Error(t("workflow.detail.writeAccessCancel"));let _=await K.json().catch(()=>({}));if(!K.ok||!_.ok)throw new Error(_.hint??_.error??t("workflow.detail.cancelHttp",{status:K.status}));de(_.pending?t("workflow.detail.cancelPending"):null),fe(null),await he()}catch(K){fe(K?.message??String(K))}finally{X=!1,L.disabled=!1,xe()}}}async function st(C,Y){if(!ce.has(C)){ce.add(C),Oe.delete(C),xe();try{let K=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/attempts/${encodeURIComponent(Y)}/${encodeURIComponent(C)}/resume`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});if(K.status===401)throw new Error(t("workflow.detail.writeAccessResume"));let _=await K.json().catch(()=>({}));if(!K.ok||!_.ok||!_.resumeId||!_.url)throw new Error(_.hint??_.message??_.error??t("workflow.detail.resumeStartFailed",{status:K.status}));Me.set(C,{resumeId:_.resumeId,url:_.url})}catch(K){let _=K?.message??String(K);Oe.set(C,_)}finally{ce.delete(C),xe()}}}async function Dt(C,Y){if(!ce.has(C)){ce.add(C),Oe.delete(C),xe();try{let K=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/attempts/${encodeURIComponent(Y)}/${encodeURIComponent(C)}/resume/end`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"ended_by_dashboard"})});if(K.status===401)throw new Error(t("workflow.detail.writeAccessResume"));let _=await K.json().catch(()=>({}));if(!K.ok||!_.ok)if(_.error==="resume_not_running")Me.delete(C);else throw new Error(_.hint??_.message??_.error??t("workflow.detail.resumeEndFailed",{status:K.status}));else Me.delete(C)}catch(K){let _=K?.message??String(K);Oe.set(C,_)}finally{ce.delete(C),xe()}}}async function it(C,Y){if(!ue.has(C)){ue.add(C),re.delete(C),xe();try{let K=se.get(C)?.trim()||void 0,_=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/${Y}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({comment:K})});if(_.status===401)throw new Error(t("workflow.detail.writeAccessApproval"));let we=await _.json().catch(()=>({}));if(!_.ok||!we.ok)throw new Error(we.hint??we.message??we.error??t("workflow.detail.actionHttp",{action:Y,status:_.status}));let Ze=Y==="approve"?t("workflow.detail.approved"):t("workflow.detail.rejected");re.set(C,{kind:"ok",text:we.alreadyTerminal?t("workflow.detail.alreadyTerminal",{label:Ze}):we.pending?t("workflow.detail.workflowContinue",{label:Ze}):t("workflow.detail.workflowRefreshing",{label:Ze})}),fe(null),await he()}catch(K){let _=K?.message??String(K);re.set(C,{kind:"error",text:_}),fe(_)}finally{ue.delete(C),xe()}}}function xe(){if(!T)return;Ee=S.scrollTop;let C=T.run;zt.has(C.status)&&de(null),s.innerHTML=`${h(C.workflowId??"?")} \xB7 ${at(C.status)} \xB7 lastSeq ${T.lastSeq}`,o.textContent=t("workflow.detail.refreshed",{time:new Date().toLocaleTimeString()}),L.hidden=zt.has(C.status),L.disabled=X||!T.chatBinding?.larkAppId,L.textContent=T.chatBinding?.larkAppId?t("workflow.detail.cancel"):t("workflow.detail.cliCancelOnly"),L.title=T.chatBinding?.larkAppId?t("workflow.detail.cancelTitle"):t("workflow.detail.cliCancelTitle",{runId:n}),hr(p,T),vr(k,T),kr($,E,T,P),Mr(w,T),Er(u,T,oe,De,{comments:se,statuses:re,resolving:ue,onResolve:it},{sessions:Me,pending:ce,errors:Oe,onStart:st,onEnd:Dt},le,be)&&(le=void 0),el(x,P),S.scrollTop=Ee,H.hidden=!D,A.textContent=t("workflow.detail.eventsLoaded",{loaded:P.length,total:B})}function We(){if(U!==null&&window.clearTimeout(U),T&&zt.has(T.run.status)){U=null;return}U=window.setTimeout(async()=>{await he(),q||We()},mr)}function _e(){document.hidden||he().then(()=>{!q&&U===null&&We()})}return H.addEventListener("click",()=>{ot()}),L.addEventListener("click",()=>{$t()}),document.addEventListener("visibilitychange",_e),Ge().then(()=>{fe(null),q||We()}).catch(C=>{fe(C?.message??String(C)),s.textContent=t("workflow.detail.loadFailed")}),()=>{q=!0,U!==null&&window.clearTimeout(U),document.removeEventListener("visibilitychange",_e)}}function hr(e,n){let a=n.run,s=[[t("workflow.summary.workflow"),h(a.workflowId??"?")],[t("workflow.summary.status"),at(a.status)],[t("workflow.summary.lastSeq"),String(n.lastSeq)],[t("workflow.summary.updated"),h(new Date(n.updatedAt).toLocaleString())],[t("workflow.summary.revision"),h(Sn(a.revisionId))],[t("workflow.summary.initiator"),h(a.initiator??"-")]];a.failedNodeId&&s.push([t("workflow.summary.failedNode"),h(a.failedNodeId)]),a.cancelOriginEventId&&s.push([t("workflow.summary.cancelOrigin"),h(a.cancelOriginEventId)]),n.chatBinding&&(s.push([t("workflow.summary.chat"),`<code>${h(n.chatBinding.chatId)}</code>`]),s.push([t("workflow.summary.app"),`<code>${h(n.chatBinding.larkAppId)}</code>`])),e.innerHTML=s.map(([o,r])=>`<div class="wf-summary-item"><span>${o}</span><strong>${r}</strong></div>`).join("")}function wr(e){if(!e.errorCode)return"";let n=e.errorMessage?` \u2014 ${ol(e.errorMessage,96)}`:"";return`<div class="wf-run-error">
1153
1296
  <span class="muted error">${h(e.errorCode)}</span>${h(n)}
1154
- </div>`}function Gi(e){let n=e.dangling;return{total:new Set([...n.activities,...n.effectAttempted,...n.waits,...n.cancels]).size,effects:n.effectAttempted.length,activities:n.activities.length,waits:n.waits.length,cancels:n.cancels.length}}function _i(e,n){let o=n.dangling,s=[[t("workflow.dangling.activities"),o.activities],[t("workflow.dangling.effects"),o.effectAttempted],[t("workflow.dangling.waits"),o.waits],[t("workflow.dangling.cancels"),o.cancels]],a=new Set(s.flatMap(([,i])=>i)).size;if(e.className=a>0?"wf-panel wf-dangling-panel has":"wf-panel wf-dangling-panel",a===0){e.innerHTML=`<div class="wf-panel-title"><h3>${h(t("workflow.detail.dangling"))}</h3></div><div class="muted">${h(t("workflow.detail.noDangling"))}</div>`;return}e.innerHTML=`<div class="wf-panel-title"><h3>${h(t("workflow.detail.dangling"))}</h3><span class="wf-dangling has">${a}</span></div>
1297
+ </div>`}function yr(e){let n=e.dangling;return{total:new Set([...n.activities,...n.effectAttempted,...n.waits,...n.cancels]).size,effects:n.effectAttempted.length,activities:n.activities.length,waits:n.waits.length,cancels:n.cancels.length}}function vr(e,n){let a=n.dangling,s=[[t("workflow.dangling.activities"),a.activities],[t("workflow.dangling.effects"),a.effectAttempted],[t("workflow.dangling.waits"),a.waits],[t("workflow.dangling.cancels"),a.cancels]],o=new Set(s.flatMap(([,r])=>r)).size;if(e.className=o>0?"wf-panel wf-dangling-panel has":"wf-panel wf-dangling-panel",o===0){e.innerHTML=`<div class="wf-panel-title"><h3>${h(t("workflow.detail.dangling"))}</h3></div><div class="muted">${h(t("workflow.detail.noDangling"))}</div>`;return}e.innerHTML=`<div class="wf-panel-title"><h3>${h(t("workflow.detail.dangling"))}</h3><span class="wf-dangling has">${o}</span></div>
1155
1298
  <div class="wf-dangling-grid">
1156
- ${s.map(([i,d])=>`<div><strong>${i}</strong>${d.length===0?`<div class="muted">${h(t("workflow.detail.none"))}</div>`:`<ul>${d.map(p=>`<li><code>${h(p)}</code></li>`).join("")}</ul>`}</div>`).join("")}
1157
- </div>`}function zi(e,n,o,s){let a=Wi(s,o);if(a.length===0){n.textContent="",e.innerHTML=`<div class="empty">${h(t("workflow.detail.noParallelData"))}</div>`;return}let i=Date.now(),d=Math.min(...a.map(g=>g.startedAt)),p=Math.max(...a.map(g=>g.endedAt??i),d+1e3),v=Math.max(1,p-d),k=Ji(a,i),I=a.filter(g=>!g.endedAt&&(g.status==="running"||g.status==="effectAttempting")).length;n.textContent=t("workflow.detail.parallelMeta",{count:a.length,max:k,running:I});let T=a.sort((g,R)=>g.startedAt-R.startedAt||g.activityId.localeCompare(R.activityId)).map(g=>Ki(g,d,v,i)).join("");e.innerHTML=`<div class="wf-parallel-axis">
1158
- <span title="${h(new Date(d).toISOString())}">${h(bn(d))}</span>
1159
- <span title="${h(new Date(p).toISOString())}">${h(bn(p))}</span>
1299
+ ${s.map(([r,d])=>`<div><strong>${r}</strong>${d.length===0?`<div class="muted">${h(t("workflow.detail.none"))}</div>`:`<ul>${d.map(p=>`<li><code>${h(p)}</code></li>`).join("")}</ul>`}</div>`).join("")}
1300
+ </div>`}function kr(e,n,a,s){let o=$r(s,a);if(o.length===0){n.textContent="",e.innerHTML=`<div class="empty">${h(t("workflow.detail.noParallelData"))}</div>`;return}let r=Date.now(),d=Math.min(...o.map(u=>u.startedAt)),p=Math.max(...o.map(u=>u.endedAt??r),d+1e3),k=Math.max(1,p-d),$=Lr(o,r),E=o.filter(u=>!u.endedAt&&(u.status==="running"||u.status==="effectAttempting")).length;n.textContent=t("workflow.detail.parallelMeta",{count:o.length,max:$,running:E});let w=o.sort((u,S)=>u.startedAt-S.startedAt||u.activityId.localeCompare(S.activityId)).map(u=>Sr(u,d,k,r)).join("");e.innerHTML=`<div class="wf-parallel-axis">
1301
+ <span title="${h(new Date(d).toISOString())}">${h($n(d))}</span>
1302
+ <span title="${h(new Date(p).toISOString())}">${h($n(p))}</span>
1160
1303
  </div>
1161
- <div class="wf-parallel-list">${T}</div>`}function Wi(e,n){let o=new Map,s=new Map(n.activities.map(a=>[a.activityId,a.ownerNodeId]));for(let a of[...e].sort((i,d)=>Gt(i.eventId)-Gt(d.eventId))){let i=Mr(a);if(!i)continue;let d=typeof i.activityId=="string"?i.activityId:void 0,p=typeof i.attemptId=="string"?i.attemptId:void 0;if(!d||!p)continue;let v=o.get(p);if(a.type==="attemptCreated"){let k=typeof i.attemptNumber=="number"?i.attemptNumber:void 0;v={nodeId:typeof i.nodeId=="string"?i.nodeId:s.get(d),activityId:d,attemptId:p,attemptNumber:k,status:"pending",startedAt:a.timestamp},o.set(p,v);continue}v||(v={nodeId:s.get(d),activityId:d,attemptId:p,status:"pending",startedAt:a.timestamp},o.set(p,v)),a.type==="activityRunning"?(v.status="running",v.runningAt=a.timestamp):a.type==="effectAttempted"?v.status="effectAttempting":a.type==="activityWaiting"||a.type==="waitCreated"?v.status="waiting":Yi(a.type)&&(v.status=Vi(a.type),v.endedAt=a.timestamp,v.endType=a.type)}return[...o.values()]}function Ki(e,n,o,s){let a=e.endedAt??s,i=Da((e.startedAt-n)/o*100,0,100),d=Da((Math.max(a,e.startedAt+1)-e.startedAt)/o*100,.7,100-i),p=e.nodeId??e.activityId,v=e.attemptNumber!==void 0?`#${e.attemptNumber}`:hn(e.attemptId),k=[`${p} ${e.status}`,`${new Date(e.startedAt).toISOString()} \u2192 ${e.endedAt?new Date(e.endedAt).toISOString():t("workflow.detail.parallelNow")}`,e.endType?`end: ${e.endType}`:void 0].filter(Boolean).join(`
1304
+ <div class="wf-parallel-list">${w}</div>`}function $r(e,n){let a=new Map,s=new Map(n.activities.map(o=>[o.activityId,o.ownerNodeId]));for(let o of[...e].sort((r,d)=>Kt(r.eventId)-Kt(d.eventId))){let r=al(o);if(!r)continue;let d=typeof r.activityId=="string"?r.activityId:void 0,p=typeof r.attemptId=="string"?r.attemptId:void 0;if(!d||!p)continue;let k=a.get(p);if(o.type==="attemptCreated"){let $=typeof r.attemptNumber=="number"?r.attemptNumber:void 0;k={nodeId:typeof r.nodeId=="string"?r.nodeId:s.get(d),activityId:d,attemptId:p,attemptNumber:$,status:"pending",startedAt:o.timestamp},a.set(p,k);continue}k||(k={nodeId:s.get(d),activityId:d,attemptId:p,status:"pending",startedAt:o.timestamp},a.set(p,k)),o.type==="activityRunning"?(k.status="running",k.runningAt=o.timestamp):o.type==="effectAttempted"?k.status="effectAttempting":o.type==="activityWaiting"||o.type==="waitCreated"?k.status="waiting":Tr(o.type)&&(k.status=Ir(o.type),k.endedAt=o.timestamp,k.endType=o.type)}return[...a.values()]}function Sr(e,n,a,s){let o=e.endedAt??s,r=Fo((e.startedAt-n)/a*100,0,100),d=Fo((Math.max(o,e.startedAt+1)-e.startedAt)/a*100,.7,100-r),p=e.nodeId??e.activityId,k=e.attemptNumber!==void 0?`#${e.attemptNumber}`:Sn(e.attemptId),$=[`${p} ${e.status}`,`${new Date(e.startedAt).toISOString()} \u2192 ${e.endedAt?new Date(e.endedAt).toISOString():t("workflow.detail.parallelNow")}`,e.endType?`end: ${e.endType}`:void 0].filter(Boolean).join(`
1162
1305
  `);return`<div class="wf-parallel-row">
1163
1306
  <div class="wf-parallel-label">
1164
1307
  <code>${h(p)}</code>
1165
- <span class="muted">${h(e.activityId)} \xB7 ${h(v)}</span>
1308
+ <span class="muted">${h(e.activityId)} \xB7 ${h(k)}</span>
1166
1309
  </div>
1167
1310
  <div class="wf-parallel-track">
1168
- <div class="wf-parallel-bar wf-parallel-${h(e.status)}" style="left:${i.toFixed(3)}%;width:${d.toFixed(3)}%;" title="${h(k)}">
1169
- <span>${h(lt(e.status))}</span>
1311
+ <div class="wf-parallel-bar wf-parallel-${h(e.status)}" style="left:${r.toFixed(3)}%;width:${d.toFixed(3)}%;" title="${h($)}">
1312
+ <span>${h(ut(e.status))}</span>
1170
1313
  </div>
1171
1314
  </div>
1172
- </div>`}function Ji(e,n){let o=[];for(let i of e)o.push({time:i.startedAt,delta:1}),o.push({time:i.endedAt??n,delta:-1});o.sort((i,d)=>i.time-d.time||d.delta-i.delta);let s=0,a=0;for(let i of o)s+=i.delta,a=Math.max(a,s);return a}function Yi(e){return e==="activitySucceeded"||e==="activityFailed"||e==="activityTimedOut"||e==="activityCanceled"}function Vi(e){return e==="activitySucceeded"?"succeeded":e==="activityCanceled"?"cancelled":e==="activityTimedOut"?"timedOut":"failed"}function Qi(e,n){let o=new Map(n.activities.map(i=>[i.activityId,i])),s=new Set,a=[];for(let i of n.nodes){let d=(i.activityId?o.get(i.activityId):void 0)??n.activities.find(p=>p.ownerNodeId===i.nodeId);d&&s.add(d.activityId),a.push(Ca(i,d))}for(let i of n.activities)s.has(i.activityId)||a.push(Ca(void 0,i));e.innerHTML=a.length>0?a.join(""):`<tr><td colspan="7" class="empty">${h(t("workflow.detail.noNodes"))}</td></tr>`}function Ca(e,n){let o=n?.attempts[n.attempts.length-1];return`<tr>
1315
+ </div>`}function Lr(e,n){let a=[];for(let r of e)a.push({time:r.startedAt,delta:1}),a.push({time:r.endedAt??n,delta:-1});a.sort((r,d)=>r.time-d.time||d.delta-r.delta);let s=0,o=0;for(let r of a)s+=r.delta,o=Math.max(o,s);return o}function Tr(e){return e==="activitySucceeded"||e==="activityFailed"||e==="activityTimedOut"||e==="activityCanceled"}function Ir(e){return e==="activitySucceeded"?"succeeded":e==="activityCanceled"?"cancelled":e==="activityTimedOut"?"timedOut":"failed"}function Mr(e,n){let a=new Map(n.activities.map(r=>[r.activityId,r])),s=new Set,o=[];for(let r of n.nodes){let d=(r.activityId?a.get(r.activityId):void 0)??n.activities.find(p=>p.ownerNodeId===r.nodeId);d&&s.add(d.activityId),o.push(jo(r,d))}for(let r of n.activities)s.has(r.activityId)||o.push(jo(void 0,r));e.innerHTML=o.length>0?o.join(""):`<tr><td colspan="7" class="empty">${h(t("workflow.detail.noNodes"))}</td></tr>`}function jo(e,n){let a=n?.attempts[n.attempts.length-1];return`<tr>
1173
1316
  <td>${e?`<code>${h(e.nodeId)}</code>`:'<span class="muted">-</span>'}</td>
1174
- <td>${e?tt(e.status):'<span class="muted">-</span>'}</td>
1317
+ <td>${e?at(e.status):'<span class="muted">-</span>'}</td>
1175
1318
  <td>${n?`<code>${h(n.activityId)}</code>`:'<span class="muted">-</span>'}</td>
1176
- <td>${n?tt(n.status):'<span class="muted">-</span>'}</td>
1319
+ <td>${n?at(n.status):'<span class="muted">-</span>'}</td>
1177
1320
  <td>${n?.attempts.length??0}</td>
1178
- <td>${o?`<code>${h(o.attemptId)}</code>`:'<span class="muted">-</span>'}</td>
1179
- <td>${o?Sr(o):`<span class="muted">${h(t("workflow.detail.idle"))}</span>`}</td>
1180
- </tr>`}function Xi(e,n,o,s,a,i,d,p){hr(e,o,s),mr(e,a.comments);let v=!!(d&&n.attemptIO?.[d]?.terminal);v&&d&&o.add(oo(d,t("workflow.detail.liveTerminal")));let k=Zi(n),I=new Set;if(p){for(let g of k){I.add(g.key);let R=p.get(g.key);R||(R=er(g.key),p.set(g.key,R),e.appendChild(R.article)),tr(R,g,o,a,i,d)}for(let[g,R]of Array.from(p))I.has(g)||(R.article.remove(),p.delete(g));if(k.length===0){if(!e.querySelector(".wf-io-empty-placeholder")){let g=document.createElement("div");g.className="empty wf-io-empty-placeholder",g.textContent=t("workflow.detail.noNodeIO"),e.appendChild(g)}}else e.querySelector(".wf-io-empty-placeholder")?.remove()}else{let g=[];for(let R of k)g.push(ir(R,o,a,i,d));e.innerHTML=g.length>0?g.join(""):`<div class="empty">${h(t("workflow.detail.noNodeIO"))}</div>`}yr(e,s);let T=br(e,d);return wr(e,o),vr(e,s),gr(e,a),Ga(e,i),T&&v}function Zi(e){let n=new Map(e.activities.map(a=>[a.activityId,a])),o=new Set,s=[];for(let a of e.nodes){let i=(a.activityId?n.get(a.activityId):void 0)??e.activities.find(d=>d.ownerNodeId===a.nodeId);if(!i){s.push({key:`node:${a.nodeId}`,node:a});continue}o.add(i.activityId),s.push({key:`activity:${i.activityId}`,node:a,activity:i,io:e.attemptIO?.[gn(i)?.attemptId??""]})}for(let a of e.activities)o.has(a.activityId)||s.push({key:`activity:${a.activityId}`,activity:a,io:e.attemptIO?.[gn(a)?.attemptId??""]});return s}function er(e){let n=document.createElement("article");n.className="wf-io-card",n.dataset.wfCardKey=e;let o=document.createElement("div");o.className="wf-io-card-head";let s=document.createElement("div");s.className="wf-io-terminal-slot";let a=document.createElement("div");return a.className="wf-io-grid",n.appendChild(o),n.appendChild(s),n.appendChild(a),{article:n,head:o,terminalSlot:s,grid:a,currentTerminalUrl:null}}function tr(e,n,o,s,a,i){let d=gn(n.activity),p=n.node?.nodeId??n.activity?.ownerNodeId??n.activity?.activityId??"unknown",v=!!(d&&d.attemptId===i);e.article.classList.toggle("is-focused",v),d?e.article.dataset.wfAttemptCard=d.attemptId:delete e.article.dataset.wfAttemptCard;let k=Fa(d,s);e.head.innerHTML=`
1321
+ <td>${a?`<code>${h(a.attemptId)}</code>`:'<span class="muted">-</span>'}</td>
1322
+ <td>${a?Zr(a):`<span class="muted">${h(t("workflow.detail.idle"))}</span>`}</td>
1323
+ </tr>`}function Er(e,n,a,s,o,r,d,p){Kr(e,a,s),Gr(e,o.comments);let k=!!(d&&n.attemptIO?.[d]?.terminal);k&&d&&a.add(da(d,t("workflow.detail.liveTerminal")));let $=xr(n),E=new Set;if(p){for(let u of $){E.add(u.key);let S=p.get(u.key);S||(S=Hr(u.key),p.set(u.key,S),e.appendChild(S.article)),Cr(S,u,a,o,r,d)}for(let[u,S]of Array.from(p))E.has(u)||(S.article.remove(),p.delete(u));if($.length===0){if(!e.querySelector(".wf-io-empty-placeholder")){let u=document.createElement("div");u.className="empty wf-io-empty-placeholder",u.textContent=t("workflow.detail.noNodeIO"),e.appendChild(u)}}else e.querySelector(".wf-io-empty-placeholder")?.remove()}else{let u=[];for(let S of $)u.push(Br(S,a,o,r,d));e.innerHTML=u.length>0?u.join(""):`<div class="empty">${h(t("workflow.detail.noNodeIO"))}</div>`}Vr(e,s);let w=zr(e,d);return Jr(e,a),Yr(e,s),Wr(e,o),Xo(e,r),w&&k}function xr(e){let n=new Map(e.activities.map(o=>[o.activityId,o])),a=new Set,s=[];for(let o of e.nodes){let r=(o.activityId?n.get(o.activityId):void 0)??e.activities.find(d=>d.ownerNodeId===o.nodeId);if(!r){s.push({key:`node:${o.nodeId}`,node:o});continue}a.add(r.activityId),s.push({key:`activity:${r.activityId}`,node:o,activity:r,io:e.attemptIO?.[kn(r)?.attemptId??""]})}for(let o of e.activities)a.has(o.activityId)||s.push({key:`activity:${o.activityId}`,activity:o,io:e.attemptIO?.[kn(o)?.attemptId??""]});return s}function Hr(e){let n=document.createElement("article");n.className="wf-io-card",n.dataset.wfCardKey=e;let a=document.createElement("div");a.className="wf-io-card-head";let s=document.createElement("div");s.className="wf-io-terminal-slot";let o=document.createElement("div");return o.className="wf-io-grid",n.appendChild(a),n.appendChild(s),n.appendChild(o),{article:n,head:a,terminalSlot:s,grid:o,currentTerminalUrl:null}}function Cr(e,n,a,s,o,r){let d=kn(n.activity),p=n.node?.nodeId??n.activity?.ownerNodeId??n.activity?.activityId??"unknown",k=!!(d&&d.attemptId===r);e.article.classList.toggle("is-focused",k),d?e.article.dataset.wfAttemptCard=d.attemptId:delete e.article.dataset.wfAttemptCard;let $=Qo(d,s);e.head.innerHTML=`
1181
1324
  <header>
1182
1325
  <div>
1183
1326
  <strong><code>${h(p)}</code></strong>
1184
1327
  <span class="muted">${n.activity?h(n.activity.activityId):h(t("workflow.detail.notDispatched"))}</span>
1185
1328
  </div>
1186
- <div>${n.node?tt(n.node.status):""} ${n.activity?tt(n.activity.status):""}</div>
1329
+ <div>${n.node?at(n.node.status):""} ${n.activity?at(n.activity.status):""}</div>
1187
1330
  </header>
1188
1331
  <div class="wf-io-meta">
1189
1332
  ${d?`${h(t("workflow.detail.attempt"))} <code>${h(d.attemptId)}</code>`:h(t("workflow.detail.noAttempt"))}
1190
1333
  </div>
1191
- ${k}
1192
- `;let I=Oa(d,n.activity,n.io?.terminal,a),T=I?.url??null;if(T!==e.currentTerminalUrl)I===null?e.terminalSlot.innerHTML="":e.terminalSlot.innerHTML=Ba(n.key,d,n.activity,n.io?.terminal,I,o,a),e.currentTerminalUrl=T;else if(I!==null&&n.io?.terminal){let R=e.terminalSlot.querySelector("details.wf-terminal-block > summary");if(R){let A=Na(I.kind);R.innerHTML=`${h(A)} ${ja(d,n.io.terminal)}`}d&&fr(e.terminalSlot,d,n.activity,n.io.terminal,I,a)}let g=d?.attemptId??n.activity?.activityId??n.node?.nodeId??"unknown";e.grid.innerHTML=`
1193
- ${Qe(g,t("workflow.detail.authoredInput"),n.io?.input,o)}
1194
- ${Qe(g,t("workflow.detail.resolvedInput"),n.io?.resolvedInput,o)}
1195
- ${Qe(g,t("workflow.detail.output"),n.io?.output,o)}
1196
- ${Qe(g,t("workflow.detail.executionLog"),n.io?.log,o)}
1197
- ${n.io?.waitPrompt?Qe(g,t("workflow.detail.waitPrompt"),n.io.waitPrompt,o):""}
1198
- `}function Oa(e,n,o,s){if(!o||o.error)return null;if(rr(e,o))return{kind:"live",url:dr(o)};if(!e||!n||!lr(e,o))return null;let a=ur();if(!a)return null;let i=s?.sessions.get(e.attemptId);return i?{kind:"resume",url:i.url,resumeId:i.resumeId,downloadUrl:Aa(a,n.activityId,e.attemptId)}:{kind:"replay",url:cr(a,n.activityId,e.attemptId,!!o.hasPtyLog),downloadUrl:Aa(a,n.activityId,e.attemptId)}}function Ba(e,n,o,s,a,i,d){if(!s)return"";let p=Na(a.kind),v=oo(e,p),k=ja(n,s),I=nr(a.kind),T=a.kind==="replay"||a.kind==="resume"?`<a class="btn-link" href="${h(a.downloadUrl)}" download>${h(t("workflow.detail.downloadFullLog"))}</a>`:"",g=n?qa(n,o,s,a,d):"",R=n?Ua(n.attemptId,d):"";return`<details class="wf-io-block wf-terminal-block" data-io-key="${h(v)}"${i.has(v)?" open":""}>
1199
- <summary>${h(p)} ${k}</summary>
1334
+ ${$}
1335
+ `;let E=_o(d,n.activity,n.io?.terminal,o),w=E?.url??null;if(w!==e.currentTerminalUrl)E===null?e.terminalSlot.innerHTML="":e.terminalSlot.innerHTML=Wo(n.key,d,n.activity,n.io?.terminal,E,a,o),e.currentTerminalUrl=w;else if(E!==null&&n.io?.terminal){let S=e.terminalSlot.querySelector("details.wf-terminal-block > summary");if(S){let x=zo(E.kind);S.innerHTML=`${h(x)} ${Yo(d,n.io.terminal)}`}d&&_r(e.terminalSlot,d,n.activity,n.io.terminal,E,o)}let u=d?.attemptId??n.activity?.activityId??n.node?.nodeId??"unknown";e.grid.innerHTML=`
1336
+ ${Xe(u,t("workflow.detail.authoredInput"),n.io?.input,a)}
1337
+ ${Xe(u,t("workflow.detail.resolvedInput"),n.io?.resolvedInput,a)}
1338
+ ${Xe(u,t("workflow.detail.output"),n.io?.output,a)}
1339
+ ${Xe(u,t("workflow.detail.executionLog"),n.io?.log,a)}
1340
+ ${n.io?.waitPrompt?Xe(u,t("workflow.detail.waitPrompt"),n.io.waitPrompt,a):""}
1341
+ `}function _o(e,n,a,s){if(!a||a.error)return null;if(Or(e,a))return{kind:"live",url:qr(a)};if(!e||!n||!Nr(e,a))return null;let o=Ur();if(!o)return null;let r=s?.sessions.get(e.attemptId);return r?{kind:"resume",url:r.url,resumeId:r.resumeId,downloadUrl:Uo(o,n.activityId,e.attemptId)}:{kind:"replay",url:jr(o,n.activityId,e.attemptId,!!a.hasPtyLog),downloadUrl:Uo(o,n.activityId,e.attemptId)}}function Wo(e,n,a,s,o,r,d){if(!s)return"";let p=zo(o.kind),k=da(e,p),$=Yo(n,s),E=Ar(o.kind),w=o.kind==="replay"||o.kind==="resume"?`<a class="btn-link" href="${h(o.downloadUrl)}" download>${h(t("workflow.detail.downloadFullLog"))}</a>`:"",u=n?Jo(n,a,s,o,d):"",S=n?Vo(n.attemptId,d):"";return`<details class="wf-io-block wf-terminal-block" data-io-key="${h(k)}"${r.has(k)?" open":""}>
1342
+ <summary>${h(p)} ${$}</summary>
1200
1343
  <div class="wf-terminal-actions">
1201
- <a class="btn-link" href="${h(a.url)}" target="_blank" rel="noreferrer">${h(I)}</a>
1202
- ${T}
1203
- ${g}
1344
+ <a class="btn-link" href="${h(o.url)}" target="_blank" rel="noreferrer">${h(E)}</a>
1345
+ ${w}
1346
+ ${u}
1204
1347
  </div>
1205
- ${R}
1206
- <iframe class="wf-terminal-frame" src="${h(a.url)}" title="${h(p)}" loading="lazy"></iframe>
1207
- </details>`}function Na(e){return e==="live"?t("workflow.detail.liveTerminal"):e==="resume"?t("workflow.detail.terminalResume"):t("workflow.detail.terminalReplay")}function nr(e){return e==="live"?t("workflow.detail.openTerminalNewTab"):e==="resume"?t("workflow.detail.openResumeNewTab"):t("workflow.detail.openReplayNewTab")}var Pa=new Set(["antigravity","codex-app","cursor","mira"]),or=new Set(["aiden","coco","claude-code","seed","relay","codex","mtr","hermes","pi","mir"]);function ar(e){return!!e&&(or.has(e)||Pa.has(e))}function sr(e){return!!e&&Pa.has(e)}function qa(e,n,o,s,a){if(!a||s.kind==="live"||!n)return"";let i=s.kind==="resume",d=a.pending.has(e.attemptId),p=`data-wf-resume-attempt="${h(e.attemptId)}" data-wf-resume-activity="${h(n.activityId)}"`;return i?`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="end" ${p}${d?" disabled":""}>${h(d?t("workflow.detail.resumeEnding"):t("workflow.detail.endResumeSession"))}</button>`:ar(o.cliId)?sr(o.cliId)&&!o.cliSessionId?`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${h(t("workflow.detail.resumeMissingCliSession"))}">${h(t("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="start" ${p}${d?" disabled":""}>${h(d?t("workflow.detail.resumeStarting"):t("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${h(t("workflow.detail.resumeUnsupportedCli",{cliId:o.cliId??"?"}))}">${h(t("workflow.detail.resumeSession"))}</button>`}function Ua(e,n){if(!n)return"";let o=n.errors.get(e);return o?`<div class="hint-warn wf-resume-status" data-wf-resume-status="${h(e)}">${h(o)}</div>`:""}function ir(e,n,o,s,a){let i=gn(e.activity),d=e.node?.nodeId??e.activity?.ownerNodeId??e.activity?.activityId??"unknown",p=i?.attemptId??e.activity?.activityId??e.node?.nodeId??"unknown",v=Fa(i,o),k=i?.attemptId===a?" is-focused":"",I=i?` data-wf-attempt-card="${h(i.attemptId)}"`:"",T=Oa(i,e.activity,e.io?.terminal,s),g=T?Ba(p,i,e.activity,e.io?.terminal,T,n,s):"";return`<article class="wf-io-card${k}" data-wf-card-key="${h(e.key)}"${I}>
1348
+ ${S}
1349
+ <iframe class="wf-terminal-frame" src="${h(o.url)}" title="${h(p)}" loading="lazy"></iframe>
1350
+ </details>`}function zo(e){return e==="live"?t("workflow.detail.liveTerminal"):e==="resume"?t("workflow.detail.terminalResume"):t("workflow.detail.terminalReplay")}function Ar(e){return e==="live"?t("workflow.detail.openTerminalNewTab"):e==="resume"?t("workflow.detail.openResumeNewTab"):t("workflow.detail.openReplayNewTab")}var Ko=new Set(["antigravity","codex-app","cursor","mira"]),Dr=new Set(["aiden","coco","claude-code","seed","relay","codex","mtr","hermes","pi","mir"]);function Rr(e){return!!e&&(Dr.has(e)||Ko.has(e))}function Pr(e){return!!e&&Ko.has(e)}function Jo(e,n,a,s,o){if(!o||s.kind==="live"||!n)return"";let r=s.kind==="resume",d=o.pending.has(e.attemptId),p=`data-wf-resume-attempt="${h(e.attemptId)}" data-wf-resume-activity="${h(n.activityId)}"`;return r?`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="end" ${p}${d?" disabled":""}>${h(d?t("workflow.detail.resumeEnding"):t("workflow.detail.endResumeSession"))}</button>`:Rr(a.cliId)?Pr(a.cliId)&&!a.cliSessionId?`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${h(t("workflow.detail.resumeMissingCliSession"))}">${h(t("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="start" ${p}${d?" disabled":""}>${h(d?t("workflow.detail.resumeStarting"):t("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${h(t("workflow.detail.resumeUnsupportedCli",{cliId:a.cliId??"?"}))}">${h(t("workflow.detail.resumeSession"))}</button>`}function Vo(e,n){if(!n)return"";let a=n.errors.get(e);return a?`<div class="hint-warn wf-resume-status" data-wf-resume-status="${h(e)}">${h(a)}</div>`:""}function Br(e,n,a,s,o){let r=kn(e.activity),d=e.node?.nodeId??e.activity?.ownerNodeId??e.activity?.activityId??"unknown",p=r?.attemptId??e.activity?.activityId??e.node?.nodeId??"unknown",k=Qo(r,a),$=r?.attemptId===o?" is-focused":"",E=r?` data-wf-attempt-card="${h(r.attemptId)}"`:"",w=_o(r,e.activity,e.io?.terminal,s),u=w?Wo(p,r,e.activity,e.io?.terminal,w,n,s):"";return`<article class="wf-io-card${$}" data-wf-card-key="${h(e.key)}"${E}>
1208
1351
  <div class="wf-io-card-head">
1209
1352
  <header>
1210
1353
  <div>
1211
1354
  <strong><code>${h(d)}</code></strong>
1212
1355
  <span class="muted">${e.activity?h(e.activity.activityId):h(t("workflow.detail.notDispatched"))}</span>
1213
1356
  </div>
1214
- <div>${e.node?tt(e.node.status):""} ${e.activity?tt(e.activity.status):""}</div>
1357
+ <div>${e.node?at(e.node.status):""} ${e.activity?at(e.activity.status):""}</div>
1215
1358
  </header>
1216
1359
  <div class="wf-io-meta">
1217
- ${i?`${h(t("workflow.detail.attempt"))} <code>${h(i.attemptId)}</code>`:h(t("workflow.detail.noAttempt"))}
1360
+ ${r?`${h(t("workflow.detail.attempt"))} <code>${h(r.attemptId)}</code>`:h(t("workflow.detail.noAttempt"))}
1218
1361
  </div>
1219
- ${v}
1362
+ ${k}
1220
1363
  </div>
1221
- <div class="wf-io-terminal-slot">${g}</div>
1364
+ <div class="wf-io-terminal-slot">${u}</div>
1222
1365
  <div class="wf-io-grid">
1223
- ${Qe(p,t("workflow.detail.authoredInput"),e.io?.input,n)}
1224
- ${Qe(p,t("workflow.detail.resolvedInput"),e.io?.resolvedInput,n)}
1225
- ${Qe(p,t("workflow.detail.output"),e.io?.output,n)}
1226
- ${Qe(p,t("workflow.detail.executionLog"),e.io?.log,n)}
1227
- ${e.io?.waitPrompt?Qe(p,t("workflow.detail.waitPrompt"),e.io.waitPrompt,n):""}
1366
+ ${Xe(p,t("workflow.detail.authoredInput"),e.io?.input,n)}
1367
+ ${Xe(p,t("workflow.detail.resolvedInput"),e.io?.resolvedInput,n)}
1368
+ ${Xe(p,t("workflow.detail.output"),e.io?.output,n)}
1369
+ ${Xe(p,t("workflow.detail.executionLog"),e.io?.log,n)}
1370
+ ${e.io?.waitPrompt?Xe(p,t("workflow.detail.waitPrompt"),e.io.waitPrompt,n):""}
1228
1371
  </div>
1229
- </article>`}function gn(e){return e?.attempts[e.attempts.length-1]}function ja(e,n){let o=[];return n.error?o.push(t("workflow.detail.error")):o.push(n.status==="live"?t("workflow.detail.terminalLive"):t("workflow.detail.terminalClosedShort")),e?.status&&o.push(e.status),n.webPort>0&&o.push(`:${n.webPort}`),`<span class="muted">${h(o.join(" \xB7 "))}</span>`}function rr(e,n){return n.status==="live"&&n.webPort>0&&(e?.status==="pending"||e?.status==="running"||e?.status==="effectAttempting")}function lr(e,n){return e.status==="succeeded"||e.status==="failed"||e.status==="cancelled"||e.status==="timedOut"?!!(n.sessionId||n.startedAt):!1}function dr(e){return`http://${window.location.hostname||"127.0.0.1"}:${e.webPort}`}function cr(e,n,o,s){let a=new URLSearchParams({runId:e,activityId:n,attemptId:o});return s&&a.set("hasPtyLog","1"),`/assets/terminal-replay.html?${a.toString()}`}function Aa(e,n,o){return`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(n)}/${encodeURIComponent(o)}/terminal-log/raw?download=1`}function ur(){let e=window.location.hash.match(/^#\/workflows\/([^/?#]+)/);if(!e)return null;try{return decodeURIComponent(e[1])}catch{return null}}function Fa(e,n){if(!pr(e))return"";let o=e.attemptId,s=n.comments.get(o)??"",a=n.resolving.has(o),i=n.statuses.get(o),d=i?.kind==="error"?"hint-warn":"hint-ok";return`<div class="wf-approval-box" data-wf-approval="${h(o)}">
1372
+ </article>`}function kn(e){return e?.attempts[e.attempts.length-1]}function Yo(e,n){let a=[];return n.error?a.push(t("workflow.detail.error")):a.push(n.status==="live"?t("workflow.detail.terminalLive"):t("workflow.detail.terminalClosedShort")),e?.status&&a.push(e.status),n.webPort>0&&a.push(`:${n.webPort}`),`<span class="muted">${h(a.join(" \xB7 "))}</span>`}function Or(e,n){return n.status==="live"&&n.webPort>0&&(e?.status==="pending"||e?.status==="running"||e?.status==="effectAttempting")}function Nr(e,n){return e.status==="succeeded"||e.status==="failed"||e.status==="cancelled"||e.status==="timedOut"?!!(n.sessionId||n.startedAt):!1}function qr(e){return`http://${window.location.hostname||"127.0.0.1"}:${e.webPort}`}function jr(e,n,a,s){let o=new URLSearchParams({runId:e,activityId:n,attemptId:a});return s&&o.set("hasPtyLog","1"),`/assets/terminal-replay.html?${o.toString()}`}function Uo(e,n,a){return`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(n)}/${encodeURIComponent(a)}/terminal-log/raw?download=1`}function Ur(){let e=window.location.hash.match(/^#\/workflows\/([^/?#]+)/);if(!e)return null;try{return decodeURIComponent(e[1])}catch{return null}}function Qo(e,n){if(!Fr(e))return"";let a=e.attemptId,s=n.comments.get(a)??"",o=n.resolving.has(a),r=n.statuses.get(a),d=r?.kind==="error"?"hint-warn":"hint-ok";return`<div class="wf-approval-box" data-wf-approval="${h(a)}">
1230
1373
  <label>
1231
1374
  <span>${h(t("workflow.detail.approvalComment"))}</span>
1232
- <textarea class="wf-approval-comment" data-wf-approval-comment="${h(o)}" rows="2" placeholder="${h(t("workflow.detail.optionalComment"))}"${a?" disabled":""}>${h(s)}</textarea>
1375
+ <textarea class="wf-approval-comment" data-wf-approval-comment="${h(a)}" rows="2" placeholder="${h(t("workflow.detail.optionalComment"))}"${o?" disabled":""}>${h(s)}</textarea>
1233
1376
  </label>
1234
1377
  <div class="wf-approval-actions">
1235
- <button type="button" class="primary" data-wf-approval-action="approve" data-wf-attempt-id="${h(o)}"${a?" disabled":""}>${h(t("workflow.detail.approve"))}</button>
1236
- <button type="button" data-wf-approval-action="reject" data-wf-attempt-id="${h(o)}"${a?" disabled":""}>${h(t("workflow.detail.reject"))}</button>
1237
- ${a?`<span class="muted">${h(t("workflow.detail.submitting"))}</span>`:""}
1378
+ <button type="button" class="primary" data-wf-approval-action="approve" data-wf-attempt-id="${h(a)}"${o?" disabled":""}>${h(t("workflow.detail.approve"))}</button>
1379
+ <button type="button" data-wf-approval-action="reject" data-wf-attempt-id="${h(a)}"${o?" disabled":""}>${h(t("workflow.detail.reject"))}</button>
1380
+ ${o?`<span class="muted">${h(t("workflow.detail.submitting"))}</span>`:""}
1238
1381
  </div>
1239
- ${i?`<div class="${d} wf-approval-status">${h(i.text)}</div>`:""}
1240
- </div>`}function pr(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function mr(e,n){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(o=>{let s=o.dataset.wfApprovalComment;s&&n.set(s,o.value)})}function Ga(e,n){e.querySelectorAll("button[data-wf-resume-action][data-wf-resume-attempt][data-wf-resume-activity]").forEach(o=>{o.dataset.wfResumeBound!=="1"&&(o.dataset.wfResumeBound="1",o.addEventListener("click",()=>{let s=o.dataset.wfResumeAttempt,a=o.dataset.wfResumeActivity,i=o.dataset.wfResumeAction;!s||!a||(i==="start"?n.onStart(s,a):i==="end"&&n.onEnd(s,a))}))})}function fr(e,n,o,s,a,i){let d=e.querySelector(".wf-terminal-actions");if(!d)return;let p=d.querySelector('button[data-wf-resume-button="1"]'),v=qa(n,o,s,a,i);p?p.outerHTML=v:v&&d.insertAdjacentHTML("beforeend",v);let k=e.querySelector("details.wf-terminal-block");if(k){let I=k.querySelector(".wf-resume-status"),T=Ua(n.attemptId,i);I?I.outerHTML=T:T&&d.insertAdjacentHTML("afterend",T)}Ga(e,i)}function gr(e,n){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(o=>{let s=o.dataset.wfApprovalComment;s&&o.addEventListener("input",()=>{n.comments.set(s,o.value)})}),e.querySelectorAll("button[data-wf-approval-action][data-wf-attempt-id]").forEach(o=>{o.addEventListener("click",()=>{let s=o.dataset.wfAttemptId,a=o.dataset.wfApprovalAction;!s||a!=="approve"&&a!=="reject"||n.onResolve(s,a)})})}function Qe(e,n,o,s){let a=oo(e,n);return`<details class="wf-io-block" data-io-key="${h(a)}"${s.has(a)?" open":""}>
1241
- <summary>${h(n)} ${kr(o)}</summary>
1242
- ${$r(o)}
1243
- </details>`}function oo(e,n){return`${e}:${n}`}function br(e,n){if(!n)return!1;for(let o of e.querySelectorAll("[data-wf-attempt-card]"))if(o.dataset.wfAttemptCard===n)return o.scrollIntoView({block:"center"}),!0;return!1}function hr(e,n,o){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(s=>{let a=s.dataset.ioKey;if(!a)return;s.open?n.add(a):n.delete(a);let i=s.querySelector(".wf-io-pre");i&&o.set(a,i.scrollTop)})}function wr(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(o=>{o.dataset.ioToggleBound!=="1"&&(o.dataset.ioToggleBound="1",o.addEventListener("toggle",()=>{let s=o.dataset.ioKey;s&&(o.open?n.add(s):n.delete(s))}))})}function yr(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(o=>{let s=o.dataset.ioKey;if(!s)return;let a=n.get(s);if(a===void 0)return;let i=o.querySelector(".wf-io-pre");i&&(i.scrollTop=a)})}function vr(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(o=>{let s=o.dataset.ioKey;if(!s)return;let a=o.querySelector(".wf-io-pre");a&&a.dataset.ioScrollBound!=="1"&&(a.dataset.ioScrollBound="1",a.addEventListener("scroll",()=>{n.set(s,a.scrollTop)}))})}function kr(e){if(!e)return`<span class="muted">${h(t("workflow.detail.empty"))}</span>`;let n=[];return e.outputBytes!==void 0&&n.push(`${e.outputBytes}B`),e.truncated&&n.push(t("workflow.detail.truncated")),e.error&&n.push(t("workflow.detail.error")),e.outputHash&&n.push(hn(e.outputHash)),n.length?`<span class="muted">${h(n.join(" \xB7 "))}</span>`:""}function $r(e){if(!e)return`<div class="muted wf-io-empty">${h(t("workflow.detail.noData"))}</div>`;let n=e.value!==void 0?JSON.stringify(e.value,null,2):e.text??"",o=e.error?`<div class="muted error">${h(e.error)}</div>`:"";return n?`${o}<pre class="wf-io-pre">${h(n)}</pre>`:`${o}<div class="muted wf-io-empty">${h(t("workflow.detail.noPreview"))}</div>`}function Sr(e){let n=[];if(e.effectAttempted&&n.push(`${h(t("workflow.detail.effect"))} ${h(e.effectAttempted.provider)}`),e.wait){let o=e.wait.resolution?`${e.wait.resolution.kind}${e.wait.resolution.resolution?":"+e.wait.resolution.resolution:""}`:t("workflow.detail.open");n.push(`${h(t("workflow.detail.wait"))} ${h(e.wait.waitKind)} ${h(o)}`),e.wait.deadlineAt!==void 0&&n.push(`${h(t("workflow.detail.deadline"))} ${h(bn(e.wait.deadlineAt))}`)}if(e.error){let o=`${e.error.errorCode}${e.error.errorClass?` \xB7 ${e.error.errorClass}`:""}`;n.push(`<span class="muted error">${h(o)}</span>`),e.error.errorMessage&&n.push(`<span class="error wf-error-msg">${h(e.error.errorMessage)}</span>`)}return e.output&&n.push(`${h(t("workflow.detail.output"))} ${h(hn(e.output.outputHash))}`),e.runningMs!==void 0&&n.push(`${e.runningMs}ms`),n.length>0?n.join("<br/>"):'<span class="muted">-</span>'}function Tr(e,n){e.innerHTML=n.length>0?n.map(Lr).join(""):`<tr><td colspan="7" class="empty">${h(t("workflow.detail.noEvents"))}</td></tr>`}function Lr(e){let n=Ir(e.payload);return`<tr>
1244
- <td>${Gt(e.eventId)}</td>
1382
+ ${r?`<div class="${d} wf-approval-status">${h(r.text)}</div>`:""}
1383
+ </div>`}function Fr(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function Gr(e,n){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(a=>{let s=a.dataset.wfApprovalComment;s&&n.set(s,a.value)})}function Xo(e,n){e.querySelectorAll("button[data-wf-resume-action][data-wf-resume-attempt][data-wf-resume-activity]").forEach(a=>{a.dataset.wfResumeBound!=="1"&&(a.dataset.wfResumeBound="1",a.addEventListener("click",()=>{let s=a.dataset.wfResumeAttempt,o=a.dataset.wfResumeActivity,r=a.dataset.wfResumeAction;!s||!o||(r==="start"?n.onStart(s,o):r==="end"&&n.onEnd(s,o))}))})}function _r(e,n,a,s,o,r){let d=e.querySelector(".wf-terminal-actions");if(!d)return;let p=d.querySelector('button[data-wf-resume-button="1"]'),k=Jo(n,a,s,o,r);p?p.outerHTML=k:k&&d.insertAdjacentHTML("beforeend",k);let $=e.querySelector("details.wf-terminal-block");if($){let E=$.querySelector(".wf-resume-status"),w=Vo(n.attemptId,r);E?E.outerHTML=w:w&&d.insertAdjacentHTML("afterend",w)}Xo(e,r)}function Wr(e,n){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(a=>{let s=a.dataset.wfApprovalComment;s&&a.addEventListener("input",()=>{n.comments.set(s,a.value)})}),e.querySelectorAll("button[data-wf-approval-action][data-wf-attempt-id]").forEach(a=>{a.addEventListener("click",()=>{let s=a.dataset.wfAttemptId,o=a.dataset.wfApprovalAction;!s||o!=="approve"&&o!=="reject"||n.onResolve(s,o)})})}function Xe(e,n,a,s){let o=da(e,n);return`<details class="wf-io-block" data-io-key="${h(o)}"${s.has(o)?" open":""}>
1384
+ <summary>${h(n)} ${Qr(a)}</summary>
1385
+ ${Xr(a)}
1386
+ </details>`}function da(e,n){return`${e}:${n}`}function zr(e,n){if(!n)return!1;for(let a of e.querySelectorAll("[data-wf-attempt-card]"))if(a.dataset.wfAttemptCard===n)return a.scrollIntoView({block:"center"}),!0;return!1}function Kr(e,n,a){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(s=>{let o=s.dataset.ioKey;if(!o)return;s.open?n.add(o):n.delete(o);let r=s.querySelector(".wf-io-pre");r&&a.set(o,r.scrollTop)})}function Jr(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(a=>{a.dataset.ioToggleBound!=="1"&&(a.dataset.ioToggleBound="1",a.addEventListener("toggle",()=>{let s=a.dataset.ioKey;s&&(a.open?n.add(s):n.delete(s))}))})}function Vr(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(a=>{let s=a.dataset.ioKey;if(!s)return;let o=n.get(s);if(o===void 0)return;let r=a.querySelector(".wf-io-pre");r&&(r.scrollTop=o)})}function Yr(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(a=>{let s=a.dataset.ioKey;if(!s)return;let o=a.querySelector(".wf-io-pre");o&&o.dataset.ioScrollBound!=="1"&&(o.dataset.ioScrollBound="1",o.addEventListener("scroll",()=>{n.set(s,o.scrollTop)}))})}function Qr(e){if(!e)return`<span class="muted">${h(t("workflow.detail.empty"))}</span>`;let n=[];return e.outputBytes!==void 0&&n.push(`${e.outputBytes}B`),e.truncated&&n.push(t("workflow.detail.truncated")),e.error&&n.push(t("workflow.detail.error")),e.outputHash&&n.push(Sn(e.outputHash)),n.length?`<span class="muted">${h(n.join(" \xB7 "))}</span>`:""}function Xr(e){if(!e)return`<div class="muted wf-io-empty">${h(t("workflow.detail.noData"))}</div>`;let n=e.value!==void 0?JSON.stringify(e.value,null,2):e.text??"",a=e.error?`<div class="muted error">${h(e.error)}</div>`:"";return n?`${a}<pre class="wf-io-pre">${h(n)}</pre>`:`${a}<div class="muted wf-io-empty">${h(t("workflow.detail.noPreview"))}</div>`}function Zr(e){let n=[];if(e.effectAttempted&&n.push(`${h(t("workflow.detail.effect"))} ${h(e.effectAttempted.provider)}`),e.wait){let a=e.wait.resolution?`${e.wait.resolution.kind}${e.wait.resolution.resolution?":"+e.wait.resolution.resolution:""}`:t("workflow.detail.open");n.push(`${h(t("workflow.detail.wait"))} ${h(e.wait.waitKind)} ${h(a)}`),e.wait.deadlineAt!==void 0&&n.push(`${h(t("workflow.detail.deadline"))} ${h($n(e.wait.deadlineAt))}`)}if(e.error){let a=`${e.error.errorCode}${e.error.errorClass?` \xB7 ${e.error.errorClass}`:""}`;n.push(`<span class="muted error">${h(a)}</span>`),e.error.errorMessage&&n.push(`<span class="error wf-error-msg">${h(e.error.errorMessage)}</span>`)}return e.output&&n.push(`${h(t("workflow.detail.output"))} ${h(Sn(e.output.outputHash))}`),e.runningMs!==void 0&&n.push(`${e.runningMs}ms`),n.length>0?n.join("<br/>"):'<span class="muted">-</span>'}function el(e,n){e.innerHTML=n.length>0?n.map(tl).join(""):`<tr><td colspan="7" class="empty">${h(t("workflow.detail.noEvents"))}</td></tr>`}function tl(e){let n=nl(e.payload);return`<tr>
1387
+ <td>${Kt(e.eventId)}</td>
1245
1388
  <td><code>${h(e.type)}</code></td>
1246
1389
  <td>${h(e.actor)}</td>
1247
1390
  <td>${n.nodeId?`<code>${h(n.nodeId)}</code>`:"-"}</td>
1248
1391
  <td>${n.activityId?`<code>${h(n.activityId)}</code>`:"-"}</td>
1249
1392
  <td>${n.errorCode?`<span class="muted error">${h(n.errorCode)}</span>`:"-"}</td>
1250
- <td title="${h(new Date(e.timestamp).toISOString())}">${h(bn(e.timestamp))}</td>
1251
- </tr>`}function Gt(e){let n=e.lastIndexOf("-");if(n<0)return 0;let o=Number(e.slice(n+1));return Number.isFinite(o)?o:0}function Ir(e){if(!e||typeof e!="object"||"ref"in e)return{};let n=e,o={};typeof n.nodeId=="string"&&(o.nodeId=n.nodeId),typeof n.activityId=="string"&&(o.activityId=n.activityId),typeof n.failedNodeId=="string"&&(o.nodeId=n.failedNodeId);let s=n.error;return s&&typeof s=="object"&&"errorCode"in s&&(o.errorCode=String(s.errorCode)),o}function Mr(e){return!e.payload||typeof e.payload!="object"||"ref"in e.payload?null:e.payload}function Da(e,n,o){return Math.min(o,Math.max(n,e))}function hn(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function xr(e,n){return e.length>n?e.slice(0,n-1)+"\u2026":e}function bn(e){return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}function U(e){return e.replace(/[&<>"']/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[n])}function _a(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function za(e){let n=location.hash.match(/^#\/(?:workflows\/catalog|workflows-catalog)\/([^/?#]+)$/);return n?Hr(e,decodeURIComponent(n[1])):Er(e)}function Er(e){e.innerHTML=`
1393
+ <td title="${h(new Date(e.timestamp).toISOString())}">${h($n(e.timestamp))}</td>
1394
+ </tr>`}function Kt(e){let n=e.lastIndexOf("-");if(n<0)return 0;let a=Number(e.slice(n+1));return Number.isFinite(a)?a:0}function nl(e){if(!e||typeof e!="object"||"ref"in e)return{};let n=e,a={};typeof n.nodeId=="string"&&(a.nodeId=n.nodeId),typeof n.activityId=="string"&&(a.activityId=n.activityId),typeof n.failedNodeId=="string"&&(a.nodeId=n.failedNodeId);let s=n.error;return s&&typeof s=="object"&&"errorCode"in s&&(a.errorCode=String(s.errorCode)),a}function al(e){return!e.payload||typeof e.payload!="object"||"ref"in e.payload?null:e.payload}function Fo(e,n,a){return Math.min(a,Math.max(n,e))}function Sn(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function ol(e,n){return e.length>n?e.slice(0,n-1)+"\u2026":e}function $n(e){return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}function j(e){return e.replace(/[&<>"']/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[n])}function Zo(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function es(e){let n=location.hash.match(/^#\/(?:workflows\/catalog|workflows-catalog)\/([^/?#]+)$/);return n?il(e,decodeURIComponent(n[1])):sl(e)}function sl(e){e.innerHTML=`
1252
1395
  <nav class="wf-subnav">
1253
- <a href="#/workflows" data-i18n="workflow.subnav.runs">${U(t("workflow.subnav.runs"))}</a>
1254
- <a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${U(t("workflow.subnav.catalog"))}</a>
1396
+ <a href="#/workflows" data-i18n="workflow.subnav.runs">${j(t("workflow.subnav.runs"))}</a>
1397
+ <a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${j(t("workflow.subnav.catalog"))}</a>
1255
1398
  </nav>
1256
1399
  <section class="catalog-head">
1257
1400
  <div>
1258
- <h2>${U(t("catalog.title"))}</h2>
1259
- <p class="muted">${U(t("catalog.subtitle"))}</p>
1401
+ <h2>${j(t("catalog.title"))}</h2>
1402
+ <p class="muted">${j(t("catalog.subtitle"))}</p>
1260
1403
  </div>
1261
- <button id="catalog-refresh" type="button">${U(t("catalog.refresh"))}</button>
1404
+ <button id="catalog-refresh" type="button">${j(t("catalog.refresh"))}</button>
1262
1405
  </section>
1263
1406
  <form id="catalog-filters" class="filters">
1264
- <input type="search" name="q" placeholder="${U(t("catalog.searchPlaceholder"))}" />
1407
+ <input type="search" name="q" placeholder="${j(t("catalog.searchPlaceholder"))}" />
1265
1408
  <span id="catalog-status" class="muted"></span>
1266
1409
  </form>
1267
1410
  <div class="wf-table-scroll">
1268
1411
  <table>
1269
1412
  <thead><tr>
1270
- <th>${U(t("catalog.table.workflow"))}</th>
1271
- <th>${U(t("catalog.table.version"))}</th>
1272
- <th>${U(t("catalog.table.params"))}</th>
1273
- <th>${U(t("catalog.table.nodes"))}</th>
1274
- <th>${U(t("catalog.table.revision"))}</th>
1275
- <th>${U(t("catalog.table.path"))}</th>
1413
+ <th>${j(t("catalog.table.workflow"))}</th>
1414
+ <th>${j(t("catalog.table.version"))}</th>
1415
+ <th>${j(t("catalog.table.params"))}</th>
1416
+ <th>${j(t("catalog.table.nodes"))}</th>
1417
+ <th>${j(t("catalog.table.revision"))}</th>
1418
+ <th>${j(t("catalog.table.path"))}</th>
1276
1419
  </tr></thead>
1277
1420
  <tbody id="catalog-tbody"></tbody>
1278
1421
  </table>
1279
1422
  </div>
1280
- `;let n=e.querySelector("#catalog-tbody"),o=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),a=e.querySelector("#catalog-refresh"),i=[],d=null,p=!1;function v(){let T=(new FormData(s).get("q")??"").trim().toLowerCase();return T?i.filter(g=>g.workflowId.toLowerCase().includes(T)||g.path.toLowerCase().includes(T)):i}function k(){d?(o.textContent=t("catalog.loadFailed",{error:d}),o.classList.add("error")):(o.textContent=`${i.length}`,o.classList.remove("error"));let T=v();if(T.length===0){n.innerHTML=`<tr><td colspan="6" class="empty">${i.length===0?U(t("catalog.noDefinitions")):U(t("catalog.noFilterMatch"))}</td></tr>`;return}n.innerHTML=T.map(g=>`
1423
+ `;let n=e.querySelector("#catalog-tbody"),a=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),o=e.querySelector("#catalog-refresh"),r=[],d=null,p=!1;function k(){let w=(new FormData(s).get("q")??"").trim().toLowerCase();return w?r.filter(u=>u.workflowId.toLowerCase().includes(w)||u.path.toLowerCase().includes(w)):r}function $(){d?(a.textContent=t("catalog.loadFailed",{error:d}),a.classList.add("error")):(a.textContent=`${r.length}`,a.classList.remove("error"));let w=k();if(w.length===0){n.innerHTML=`<tr><td colspan="6" class="empty">${r.length===0?j(t("catalog.noDefinitions")):j(t("catalog.noFilterMatch"))}</td></tr>`;return}n.innerHTML=w.map(u=>`
1281
1424
  <tr>
1282
- <td><a href="#/workflows/catalog/${encodeURIComponent(g.workflowId)}"><code>${U(g.workflowId)}</code></a></td>
1283
- <td>${g.version}</td>
1284
- <td>${U(t("catalog.paramSummary",{required:g.requiredParamCount,total:g.paramCount}))}</td>
1285
- <td>${g.nodeCount}</td>
1286
- <td><code>${U(_a(g.revisionId))}</code></td>
1287
- <td><code>${U(g.path)}</code></td>
1425
+ <td><a href="#/workflows/catalog/${encodeURIComponent(u.workflowId)}"><code>${j(u.workflowId)}</code></a></td>
1426
+ <td>${u.version}</td>
1427
+ <td>${j(t("catalog.paramSummary",{required:u.requiredParamCount,total:u.paramCount}))}</td>
1428
+ <td>${u.nodeCount}</td>
1429
+ <td><code>${j(Zo(u.revisionId))}</code></td>
1430
+ <td><code>${j(u.path)}</code></td>
1288
1431
  </tr>
1289
- `).join("")}async function I(){a.disabled=!0,o.textContent=t("catalog.loading");try{let T=await fetch("/api/workflows/definitions");if(!T.ok)throw new Error(`HTTP ${T.status}`);i=(await T.json()).definitions??[],d=null}catch(T){d=T?.message??String(T),i=[]}finally{a.disabled=!1,p||k()}}return s.addEventListener("input",k),a.addEventListener("click",()=>{I()}),I(),()=>{p=!0}}function Hr(e,n){e.innerHTML=`
1432
+ `).join("")}async function E(){o.disabled=!0,a.textContent=t("catalog.loading");try{let w=await fetch("/api/workflows/definitions");if(!w.ok)throw new Error(`HTTP ${w.status}`);r=(await w.json()).definitions??[],d=null}catch(w){d=w?.message??String(w),r=[]}finally{o.disabled=!1,p||$()}}return s.addEventListener("input",$),o.addEventListener("click",()=>{E()}),E(),()=>{p=!0}}function il(e,n){e.innerHTML=`
1290
1433
  <div class="catalog-detail-head">
1291
- <a class="btn-link" href="#/workflows/catalog">${U(t("catalog.back"))}</a>
1434
+ <a class="btn-link" href="#/workflows/catalog">${j(t("catalog.back"))}</a>
1292
1435
  <div>
1293
- <h2><code>${U(n)}</code></h2>
1294
- <div id="catalog-detail-subtitle" class="muted">${U(t("workflow.detail.loading"))}</div>
1436
+ <h2><code>${j(n)}</code></h2>
1437
+ <div id="catalog-detail-subtitle" class="muted">${j(t("workflow.detail.loading"))}</div>
1295
1438
  </div>
1296
1439
  </div>
1297
1440
  <section id="catalog-error" class="hint-warn" hidden></section>
1298
1441
  <section id="catalog-run-status" class="hint-ok" hidden></section>
1299
1442
  <div id="catalog-detail-body"></div>
1300
- `;let o=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),a=e.querySelector("#catalog-run-status"),i=e.querySelector("#catalog-detail-body"),d=null,p=!1,v=!1;function k(M){s.hidden=!M,s.textContent=M??""}function I(M){a.hidden=!M,a.textContent=M??""}function T(M){let E={};for(let[$,D]of Object.entries(M??{}))"default"in D&&(E[$]=D.default);return E}function g(){if(!d)return;let M=d.definition;o.textContent=`${t("catalog.revision")} ${_a(d.revisionId)} \xB7 ${d.path}`;let E=JSON.stringify(T(M.params),null,2);i.innerHTML=`
1443
+ `;let a=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),o=e.querySelector("#catalog-run-status"),r=e.querySelector("#catalog-detail-body"),d=null,p=!1,k=!1;function $(L){s.hidden=!L,s.textContent=L??""}function E(L){o.hidden=!L,o.textContent=L??""}function w(L){let H={};for(let[T,P]of Object.entries(L??{}))"default"in P&&(H[T]=P.default);return H}function u(){if(!d)return;let L=d.definition;a.textContent=`${t("catalog.revision")} ${Zo(d.revisionId)} \xB7 ${d.path}`;let H=JSON.stringify(w(L.params),null,2);r.innerHTML=`
1301
1444
  <section class="wf-panel">
1302
- <div class="wf-panel-title"><h3>${U(t("catalog.summary"))}</h3></div>
1445
+ <div class="wf-panel-title"><h3>${j(t("catalog.summary"))}</h3></div>
1303
1446
  <div class="wf-summary-grid">
1304
- <div class="wf-summary-item"><span>${U(t("catalog.table.workflow"))}</span><strong><code>${U(M.workflowId)}</code></strong></div>
1305
- <div class="wf-summary-item"><span>${U(t("catalog.table.version"))}</span><strong>${M.version}</strong></div>
1306
- <div class="wf-summary-item"><span>${U(t("catalog.nodeCount"))}</span><strong>${Object.keys(M.nodes).length}</strong></div>
1307
- <div class="wf-summary-item"><span>${U(t("catalog.path"))}</span><strong><code>${U(d.path)}</code></strong></div>
1447
+ <div class="wf-summary-item"><span>${j(t("catalog.table.workflow"))}</span><strong><code>${j(L.workflowId)}</code></strong></div>
1448
+ <div class="wf-summary-item"><span>${j(t("catalog.table.version"))}</span><strong>${L.version}</strong></div>
1449
+ <div class="wf-summary-item"><span>${j(t("catalog.nodeCount"))}</span><strong>${Object.keys(L.nodes).length}</strong></div>
1450
+ <div class="wf-summary-item"><span>${j(t("catalog.path"))}</span><strong><code>${j(d.path)}</code></strong></div>
1308
1451
  </div>
1309
1452
  </section>
1310
1453
 
1311
1454
  <section class="wf-panel">
1312
- <div class="wf-panel-title"><h3>${U(t("catalog.runPanel"))}</h3></div>
1455
+ <div class="wf-panel-title"><h3>${j(t("catalog.runPanel"))}</h3></div>
1313
1456
  <form id="catalog-run-form" class="catalog-run-form">
1314
1457
  <label>
1315
- <span>${U(t("catalog.paramsJson"))}</span>
1316
- <textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${U(t("catalog.paramsPlaceholder"))}">${U(E)}</textarea>
1458
+ <span>${j(t("catalog.paramsJson"))}</span>
1459
+ <textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${j(t("catalog.paramsPlaceholder"))}">${j(H)}</textarea>
1317
1460
  </label>
1318
1461
  <div class="catalog-chat-grid">
1319
1462
  <label>
1320
- <span>${U(t("catalog.chatId"))}</span>
1463
+ <span>${j(t("catalog.chatId"))}</span>
1321
1464
  <input id="catalog-chat-id" type="text" autocomplete="off" />
1322
1465
  </label>
1323
1466
  <label>
1324
- <span>${U(t("catalog.larkAppId"))}</span>
1467
+ <span>${j(t("catalog.larkAppId"))}</span>
1325
1468
  <input id="catalog-lark-app-id" type="text" autocomplete="off" />
1326
1469
  </label>
1327
1470
  </div>
1328
- <div class="muted">${U(t("catalog.chatBindingHint"))}</div>
1471
+ <div class="muted">${j(t("catalog.chatBindingHint"))}</div>
1329
1472
  <div id="catalog-param-errors" class="catalog-param-errors" hidden></div>
1330
- <button id="catalog-run-btn" type="submit" class="primary">${U(t("catalog.run"))}</button>
1473
+ <button id="catalog-run-btn" type="submit" class="primary">${j(t("catalog.run"))}</button>
1331
1474
  </form>
1332
1475
  </section>
1333
1476
 
1334
1477
  <section class="wf-panel">
1335
- <div class="wf-panel-title"><h3>${U(t("catalog.paramsSchema"))}</h3></div>
1336
- ${Cr(M.params)}
1478
+ <div class="wf-panel-title"><h3>${j(t("catalog.paramsSchema"))}</h3></div>
1479
+ ${rl(L.params)}
1337
1480
  </section>
1338
1481
 
1339
1482
  <section class="wf-panel">
1340
- <div class="wf-panel-title"><h3>${U(t("catalog.definitionJson"))}</h3></div>
1341
- <pre class="wf-io-pre">${U(JSON.stringify(M,null,2))}</pre>
1483
+ <div class="wf-panel-title"><h3>${j(t("catalog.definitionJson"))}</h3></div>
1484
+ <pre class="wf-io-pre">${j(JSON.stringify(L,null,2))}</pre>
1342
1485
  </section>
1343
- `,A()}async function R(){if(!d||v)return;let M=i.querySelector("#catalog-params"),E=i.querySelector("#catalog-chat-id"),$=i.querySelector("#catalog-lark-app-id"),D=i.querySelector("#catalog-run-btn"),m=i.querySelector("#catalog-param-errors"),y;try{if(y=JSON.parse(M.value||"{}"),!y||typeof y!="object"||Array.isArray(y))throw new Error(t("catalog.badParamsJson"))}catch(S){m.hidden=!1,m.innerHTML=`<div class="muted error">${U(S?.message??String(S))}</div>`;return}v=!0,D.disabled=!0,D.textContent=t("catalog.running"),m.hidden=!0,k(null),I(null);try{let S=await fetch(`/api/workflows/definitions/${encodeURIComponent(d.definition.workflowId)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({params:y,chatBinding:{chatId:E.value.trim(),larkAppId:$.value.trim()}})});if(S.status===401)throw new Error(t("catalog.writeAccess"));let H=await S.json().catch(()=>({}));if(!S.ok||!H.ok)throw H.issues?.length&&(m.hidden=!1,m.innerHTML=`<strong>${U(t("catalog.invalidParams"))}</strong><ul>${H.issues.map(B=>`<li>${U(t("catalog.issue",{path:B.path.length?B.path.join("."):"(root)",message:B.message}))}</li>`).join("")}</ul>`),new Error(H.hint??H.message??H.error??t("catalog.runHttp",{status:S.status}));I(t("catalog.runStarted")),H.runId&&(location.hash=`#/workflows/${encodeURIComponent(H.runId)}`)}catch(S){k(S?.message??String(S))}finally{v=!1,D.disabled=!1,D.textContent=t("catalog.run")}}function A(){i.querySelector("#catalog-run-form")?.addEventListener("submit",E=>{E.preventDefault(),R()})}async function O(){try{let M=await fetch(`/api/workflows/definitions/${encodeURIComponent(n)}`);if(M.status===404)throw new Error("unknown_workflow");if(!M.ok)throw new Error(`HTTP ${M.status}`);d=await M.json(),k(null),g()}catch(M){k(t("catalog.definitionLoadFailed",{error:M?.message??String(M)})),o.textContent=t("workflow.detail.loadFailed")}}return O().then(()=>{}),()=>{p=!0}}function Cr(e){let n=Object.entries(e??{});return n.length===0?`<div class="muted">${U(t("catalog.noParams"))}</div>`:`<div class="catalog-param-list">${n.map(([o,s])=>`
1486
+ `,x()}async function S(){if(!d||k)return;let L=r.querySelector("#catalog-params"),H=r.querySelector("#catalog-chat-id"),T=r.querySelector("#catalog-lark-app-id"),P=r.querySelector("#catalog-run-btn"),f=r.querySelector("#catalog-param-errors"),v;try{if(v=JSON.parse(L.value||"{}"),!v||typeof v!="object"||Array.isArray(v))throw new Error(t("catalog.badParamsJson"))}catch(I){f.hidden=!1,f.innerHTML=`<div class="muted error">${j(I?.message??String(I))}</div>`;return}k=!0,P.disabled=!0,P.textContent=t("catalog.running"),f.hidden=!0,$(null),E(null);try{let I=await fetch(`/api/workflows/definitions/${encodeURIComponent(d.definition.workflowId)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({params:v,chatBinding:{chatId:H.value.trim(),larkAppId:T.value.trim()}})});if(I.status===401)throw new Error(t("catalog.writeAccess"));let D=await I.json().catch(()=>({}));if(!I.ok||!D.ok)throw D.issues?.length&&(f.hidden=!1,f.innerHTML=`<strong>${j(t("catalog.invalidParams"))}</strong><ul>${D.issues.map(B=>`<li>${j(t("catalog.issue",{path:B.path.length?B.path.join("."):"(root)",message:B.message}))}</li>`).join("")}</ul>`),new Error(D.hint??D.message??D.error??t("catalog.runHttp",{status:I.status}));E(t("catalog.runStarted")),D.runId&&(location.hash=`#/workflows/${encodeURIComponent(D.runId)}`)}catch(I){$(I?.message??String(I))}finally{k=!1,P.disabled=!1,P.textContent=t("catalog.run")}}function x(){r.querySelector("#catalog-run-form")?.addEventListener("submit",H=>{H.preventDefault(),S()})}async function A(){try{let L=await fetch(`/api/workflows/definitions/${encodeURIComponent(n)}`);if(L.status===404)throw new Error("unknown_workflow");if(!L.ok)throw new Error(`HTTP ${L.status}`);d=await L.json(),$(null),u()}catch(L){$(t("catalog.definitionLoadFailed",{error:L?.message??String(L)})),a.textContent=t("workflow.detail.loadFailed")}}return A().then(()=>{}),()=>{p=!0}}function rl(e){let n=Object.entries(e??{});return n.length===0?`<div class="muted">${j(t("catalog.noParams"))}</div>`:`<div class="catalog-param-list">${n.map(([a,s])=>`
1344
1487
  <article class="catalog-param">
1345
1488
  <header>
1346
- <code>${U(o)}</code>
1347
- <span class="wf-status">${U(s.required?t("catalog.required"):t("catalog.optional"))}</span>
1348
- <span class="muted">${U(s.type)}${s.format?` \xB7 ${U(s.format)}`:""}</span>
1489
+ <code>${j(a)}</code>
1490
+ <span class="wf-status">${j(s.required?t("catalog.required"):t("catalog.optional"))}</span>
1491
+ <span class="muted">${j(s.type)}${s.format?` \xB7 ${j(s.format)}`:""}</span>
1349
1492
  </header>
1350
- ${s.description?`<div class="muted">${U(t("catalog.description"))}: ${U(s.description)}</div>`:""}
1351
- ${"default"in s?`<pre class="wf-io-pre">${U(`${t("catalog.default")}: ${JSON.stringify(s.default,null,2)}`)}</pre>`:""}
1493
+ ${s.description?`<div class="muted">${j(t("catalog.description"))}: ${j(s.description)}</div>`:""}
1494
+ ${"default"in s?`<pre class="wf-io-pre">${j(`${t("catalog.default")}: ${JSON.stringify(s.default,null,2)}`)}</pre>`:""}
1352
1495
  </article>
1353
- `).join("")}</div>`}var wn=78222186;function Wa(e){let n={maxWidth:e.style.maxWidth,padding:e.style.padding,flex:e.style.flex,minHeight:e.style.minHeight,display:e.style.display};e.style.maxWidth="none",e.style.padding="0",e.style.flex="1 1 auto",e.style.minHeight="0",e.style.display="flex";let o=!1,s,a="",i=g=>(g/1048576).toFixed(0);function d(){s&&(clearTimeout(s),s=void 0)}function p(){d(),e.innerHTML=`
1496
+ `).join("")}</div>`}var Ln=78222186;function ts(e){let n={maxWidth:e.style.maxWidth,padding:e.style.padding,flex:e.style.flex,minHeight:e.style.minHeight,display:e.style.display};e.style.maxWidth="none",e.style.padding="0",e.style.flex="1 1 auto",e.style.minHeight="0",e.style.display="flex";let a=!1,s,o="",r=u=>(u/1048576).toFixed(0);function d(){s&&(clearTimeout(s),s=void 0)}function p(){d(),e.innerHTML=`
1354
1497
  <iframe
1355
1498
  src="/game/index.html"
1356
1499
  title="HD2D Office"
1357
1500
  style="flex:1;width:100%;min-height:0;border:none;display:block;background:#0b0d12;"
1358
1501
  allow="autoplay"
1359
- ></iframe>`}function v(g){let R=g.total||wn,A=R?Math.min(100,Math.round(g.received/R*100)):0,O=g.state==="downloading",M=g.state==="error";e.innerHTML=`
1502
+ ></iframe>`}function k(u){let S=u.total||Ln,x=S?Math.min(100,Math.round(u.received/S*100)):0,A=u.state==="downloading",L=u.state==="error";e.innerHTML=`
1360
1503
  <div style="margin:auto;text-align:center;max-width:440px;padding:32px;color:var(--fg,#e6e6e6);">
1361
1504
  <div style="font-size:18px;font-weight:600;margin-bottom:8px;">HD2D \u529E\u516C\u5BA4</div>
1362
1505
  <div style="font-size:13px;opacity:.7;line-height:1.7;margin-bottom:20px;">
1363
1506
  \u628A\u6BCF\u4E2A\u4F1A\u8BDD\u53D8\u6210\u529E\u516C\u5BA4\u91CC\u7684\u4E00\u4E2A\u673A\u5668\u4EBA\uFF0C\u5B9E\u65F6\u6620\u5C04\u5C4F\u5E55\u72B6\u6001\u3002<br>
1364
- \u9996\u6B21\u8FDB\u5165\u9700\u4E0B\u8F7D\u7EA6 ${i(R)} MB \u6E38\u620F\u8D44\u6E90\uFF08\u4EC5\u4E00\u6B21\uFF0C\u4E4B\u540E\u672C\u5730\u7F13\u5B58\uFF09\u3002
1507
+ \u9996\u6B21\u8FDB\u5165\u9700\u4E0B\u8F7D\u7EA6 ${r(S)} MB \u6E38\u620F\u8D44\u6E90\uFF08\u4EC5\u4E00\u6B21\uFF0C\u4E4B\u540E\u672C\u5730\u7F13\u5B58\uFF09\u3002
1365
1508
  </div>
1366
- ${M?`<div style="color:#e06c75;font-size:12px;margin-bottom:14px;">\u4E0A\u6B21\u4E0B\u8F7D\u5931\u8D25\uFF1A${r(g.error??"\u672A\u77E5\u9519\u8BEF")}<br><span style="opacity:.7;">\u586B\u4EE3\u7406\u540E\u70B9\u91CD\u8BD5</span></div>`:""}
1367
- ${O?`
1509
+ ${L?`<div style="color:#e06c75;font-size:12px;margin-bottom:14px;">\u4E0A\u6B21\u4E0B\u8F7D\u5931\u8D25\uFF1A${i(u.error??"\u672A\u77E5\u9519\u8BEF")}<br><span style="opacity:.7;">\u586B\u4EE3\u7406\u540E\u70B9\u91CD\u8BD5</span></div>`:""}
1510
+ ${A?`
1368
1511
  <div style="background:rgba(127,127,127,.2);border-radius:6px;height:10px;overflow:hidden;margin-bottom:10px;">
1369
- <div style="height:100%;width:${A}%;background:#4a9eff;transition:width .3s;"></div>
1512
+ <div style="height:100%;width:${x}%;background:#4a9eff;transition:width .3s;"></div>
1370
1513
  </div>
1371
- <div style="font-size:12px;opacity:.7;">\u4E0B\u8F7D\u4E2D\u2026 ${i(g.received)} / ${i(R)} MB\uFF08${A}%\uFF09</div>
1514
+ <div style="font-size:12px;opacity:.7;">\u4E0B\u8F7D\u4E2D\u2026 ${r(u.received)} / ${r(S)} MB\uFF08${x}%\uFF09</div>
1372
1515
  `:`
1373
- <input id="hd2d-proxy" type="text" value="${r(a)}"
1516
+ <input id="hd2d-proxy" type="text" value="${i(o)}"
1374
1517
  placeholder="HTTP \u4EE3\u7406\uFF08\u53EF\u9009\uFF0C\u5982 http://127.0.0.1:7890\uFF09"
1375
1518
  style="width:100%;box-sizing:border-box;margin-bottom:12px;padding:8px 10px;border-radius:6px;border:1px solid rgba(127,127,127,.4);background:transparent;color:inherit;font-size:12px;" />
1376
1519
  <div style="font-size:11px;opacity:.5;margin-bottom:14px;text-align:left;">\u8FDE\u4E0D\u4E0A GitHub \u65F6\u586B\u4EE3\u7406\uFF08\u4EC5\u7528\u4E8E\u4E0B\u8F7D\u672C\u8D44\u6E90\uFF0C\u4F1A\u8BB0\u4F4F\uFF09\u3002\u7559\u7A7A\u8D70\u76F4\u8FDE/\u7CFB\u7EDF\u4EE3\u7406\u73AF\u5883\u53D8\u91CF\u3002</div>
1377
1520
  <button id="hd2d-load" style="cursor:pointer;border:none;border-radius:8px;padding:10px 22px;font-size:14px;font-weight:600;background:#4a9eff;color:#fff;">
1378
- ${M?"\u91CD\u8BD5":"\u52A0\u8F7D\u529E\u516C\u5BA4"}\uFF08\u7EA6 ${i(R)} MB\uFF09
1521
+ ${L?"\u91CD\u8BD5":"\u52A0\u8F7D\u529E\u516C\u5BA4"}\uFF08\u7EA6 ${r(S)} MB\uFF09
1379
1522
  </button>
1380
1523
  `}
1381
- </div>`;let E=e.querySelector("#hd2d-load");E&&(E.onclick=()=>{a=e.querySelector("#hd2d-proxy")?.value.trim()??"",I()})}function k(g){if(!o){if(typeof g.proxy=="string"&&(a=g.proxy),g.state==="ready"){p();return}v(g),g.state==="downloading"&&(s=setTimeout(()=>{T()},700))}}async function I(){v({state:"downloading",received:0,total:wn});try{let g=await fetch("/api/game/download",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({proxy:a})});if(!g.ok)throw new Error(`HTTP ${g.status}`);k(await g.json())}catch(g){v({state:"error",received:0,total:wn,error:g instanceof Error?g.message:String(g)})}}async function T(){if(!o)try{let g=await fetch("/api/game/status");if(!g.ok){v({state:"absent",received:0,total:wn});return}k(await g.json())}catch{o||(s=setTimeout(()=>{T()},1500))}}return T(),()=>{o=!0,d(),e.innerHTML="",e.style.maxWidth=n.maxWidth,e.style.padding=n.padding,e.style.flex=n.flex,e.style.minHeight=n.minHeight,e.style.display=n.display}}var dt=null,yn=null,vn="glm-5.1",Ja=[];function zt(){yn!==null&&(window.clearInterval(yn),yn=null)}function so(){return dt||(dt=document.createElement("dialog"),dt.className="onboarding-dialog",document.body.appendChild(dt),dt.addEventListener("close",zt),dt)}function Ar(e){return e.status==="waiting_for_scan"?t("botOnboarding.waiting"):e.status==="verifying"?t("botOnboarding.verifying"):e.status==="configuring_permissions"?e.permissionStatusMsg?`${t("botOnboarding.configuringPermissions")} ${e.permissionStatusMsg}`:t("botOnboarding.configuringPermissions"):e.status==="waiting_for_platform_scan"?t("botOnboarding.platformScanHint"):e.status==="completed"?t("botOnboarding.completed"):e.status==="failed"?`${t("botOnboarding.failed")}: ${r(e.message??e.error??"unknown")}`:t("botOnboarding.starting")}function Dr(e){if(e.status!=="completed"||!e.permission)return"";let n=e.permission;if(n.ok){let s=[t("botOnboarding.permissionOk",{count:n.scopeCount??0})];n.skippedScopeCount&&n.skippedScopeCount>0&&s.push(t("botOnboarding.permissionSkipped",{count:n.skippedScopeCount})),n.versionId&&s.push(t("botOnboarding.permissionVersion",{version:r(n.versionId)}));let a=`<p class="hint-ok">\u2705 ${s.join(" ")}</p>`;return n.scopeWarning&&(a+=`<p class="hint-warn">\u26A0\uFE0F ${r(n.scopeWarning)}</p>`),a}let o=(e.remainingSteps??[]).map(s=>`<li><a href="${r(s.url)}" target="_blank" rel="noopener">${r(s.title)}</a></li>`).join("");return`<p class="hint-warn">\u26A0\uFE0F ${t("botOnboarding.permissionManual")}${n.message?`\uFF08${r(n.message)}\uFF09`:""}</p>`+(o?`<ol class="onboarding-steps">${o}</ol>`:"")}function _t(e){let n=so(),o=e.status==="waiting_for_scan"&&e.qrDataUrl?`<div class="qr-card">
1524
+ </div>`;let H=e.querySelector("#hd2d-load");H&&(H.onclick=()=>{o=e.querySelector("#hd2d-proxy")?.value.trim()??"",E()})}function $(u){if(!a){if(typeof u.proxy=="string"&&(o=u.proxy),u.state==="ready"){p();return}k(u),u.state==="downloading"&&(s=setTimeout(()=>{w()},700))}}async function E(){k({state:"downloading",received:0,total:Ln});try{let u=await fetch("/api/game/download",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({proxy:o})});if(!u.ok)throw new Error(`HTTP ${u.status}`);$(await u.json())}catch(u){k({state:"error",received:0,total:Ln,error:u instanceof Error?u.message:String(u)})}}async function w(){if(!a)try{let u=await fetch("/api/game/status");if(!u.ok){k({state:"absent",received:0,total:Ln});return}$(await u.json())}catch{a||(s=setTimeout(()=>{w()},1500))}}return w(),()=>{a=!0,d(),e.innerHTML="",e.style.maxWidth=n.maxWidth,e.style.padding=n.padding,e.style.flex=n.flex,e.style.minHeight=n.minHeight,e.style.display=n.display}}var pt=null,Tn=null,In="glm-5.1",as=[];function Vt(){Tn!==null&&(window.clearInterval(Tn),Tn=null)}function ua(){return pt||(pt=document.createElement("dialog"),pt.className="onboarding-dialog",document.body.appendChild(pt),pt.addEventListener("close",Vt),pt)}function ll(e){return e.status==="waiting_for_scan"?t("botOnboarding.waiting"):e.status==="verifying"?t("botOnboarding.verifying"):e.status==="configuring_permissions"?e.permissionStatusMsg?`${t("botOnboarding.configuringPermissions")} ${e.permissionStatusMsg}`:t("botOnboarding.configuringPermissions"):e.status==="waiting_for_platform_scan"?t("botOnboarding.platformScanHint"):e.status==="completed"?t("botOnboarding.completed"):e.status==="failed"?`${t("botOnboarding.failed")}: ${i(e.message??e.error??"unknown")}`:t("botOnboarding.starting")}function dl(e){if(e.status!=="completed"||!e.permission)return"";let n=e.permission;if(n.ok){let s=[t("botOnboarding.permissionOk",{count:n.scopeCount??0})];n.skippedScopeCount&&n.skippedScopeCount>0&&s.push(t("botOnboarding.permissionSkipped",{count:n.skippedScopeCount})),n.versionId&&s.push(t("botOnboarding.permissionVersion",{version:i(n.versionId)}));let o=`<p class="hint-ok">\u2705 ${s.join(" ")}</p>`;return n.scopeWarning&&(o+=`<p class="hint-warn">\u26A0\uFE0F ${i(n.scopeWarning)}</p>`),o}let a=(e.remainingSteps??[]).map(s=>`<li><a href="${i(s.url)}" target="_blank" rel="noopener">${i(s.title)}</a></li>`).join("");return`<p class="hint-warn">\u26A0\uFE0F ${t("botOnboarding.permissionManual")}${n.message?`\uFF08${i(n.message)}\uFF09`:""}</p>`+(a?`<ol class="onboarding-steps">${a}</ol>`:"")}function Jt(e){let n=ua(),a=e.status==="waiting_for_scan"&&e.qrDataUrl?`<div class="qr-card">
1382
1525
  <img class="qr-image" src="${e.qrDataUrl}" alt="${t("botOnboarding.qrAlt")}">
1383
- ${e.qrUrl?`<a class="onboarding-link" href="${r(e.qrUrl)}" target="_blank" rel="noopener">${t("botOnboarding.openLink")}</a>`:""}
1526
+ ${e.qrUrl?`<a class="onboarding-link" href="${i(e.qrUrl)}" target="_blank" rel="noopener">${t("botOnboarding.openLink")}</a>`:""}
1384
1527
  </div>`:"",s=e.status==="waiting_for_platform_scan"&&e.platformQrDataUrl?`<div class="qr-card">
1385
1528
  <img class="qr-image" src="${e.platformQrDataUrl}" alt="${t("botOnboarding.platformQrAlt")}">
1386
- </div>`:"",a=e.appId?`<p><b>App ID:</b> <code>${r(e.appId)}</code>`+(e.cliId?` \uFF5C <b>CLI:</b> <code>${r(e.cliId)}</code>`:"")+(e.workingDir?` \uFF5C <b>${t("botOnboarding.metaDir")}:</b> <code>${r(e.workingDir)}</code>`:"")+"</p>":"",i=e.status==="completed"?`<p class="hint-ok">${t("botOnboarding.restartHint")}</p>`:"";n.innerHTML=`<article>
1529
+ </div>`:"",o=e.appId?`<p><b>App ID:</b> <code>${i(e.appId)}</code>`+(e.cliId?` \uFF5C <b>CLI:</b> <code>${i(e.cliId)}</code>`:"")+(e.workingDir?` \uFF5C <b>${t("botOnboarding.metaDir")}:</b> <code>${i(e.workingDir)}</code>`:"")+"</p>":"",r=e.status==="completed"?`<p class="hint-ok">${t("botOnboarding.restartHint")}</p>`:"";n.innerHTML=`<article>
1387
1530
  <header>
1388
1531
  <h3>${t("botOnboarding.title")}</h3>
1389
1532
  <p>${t("botOnboarding.intro")}</p>
1390
1533
  </header>
1391
- <p class="onboarding-status status-${e.status}">${Ar(e)}</p>
1392
- ${o}
1393
- ${s}
1534
+ <p class="onboarding-status status-${e.status}">${ll(e)}</p>
1394
1535
  ${a}
1395
- ${Dr(e)}
1396
- ${i}
1536
+ ${s}
1537
+ ${o}
1538
+ ${dl(e)}
1539
+ ${r}
1397
1540
  <form method="dialog"><button>${t("botOnboarding.close")}</button></form>
1398
- </article>`}async function Rr(){try{let e=await fetch("/api/cli-options"),n=await e.json();if(e.ok&&Array.isArray(n?.options))return typeof n.ttadkModelDefault=="string"&&n.ttadkModelDefault.trim()&&(vn=n.ttadkModelDefault.trim()),Array.isArray(n.ttadkModelSuggestions)&&(Ja=n.ttadkModelSuggestions.filter(o=>typeof o=="string")),n.options}catch{}return[{id:"claude-code",label:"Claude"}]}function Ka(e){let n=dt;if(!n)return;let o=n.querySelector("#ob-cli"),s=n.querySelector("#ob-model"),a=n.querySelector("#ob-model-suggestions");if(!o||!s)return;let i=e.find(v=>v.id===o.value),d=i?.gateway==="ttadk",p=d&&i?.acceptsModel!==!1;if(d&&!p){s.value="",s.disabled=!0,s.placeholder=t("botOnboarding.modelTtadkCocoPlaceholder");return}s.disabled=!1,p?(a&&(a.innerHTML=Ja.map(v=>`<option value="${r(v)}"></option>`).join("")),s.placeholder=t("botOnboarding.modelTtadkPlaceholder").replace("{model}",vn),s.value.trim()||(s.value=vn)):(a&&(a.innerHTML=""),s.placeholder=t("botOnboarding.modelPlaceholder"),s.value.trim()===vn&&(s.value=""))}function ao(e,n){let o=so(),s=e.map(v=>`<option value="${r(v.id)}">${r(v.label)}\uFF08${r(v.id)}\uFF09</option>`).join(""),a=n?`<p class="form-error">${r(n)}</p>`:"";o.innerHTML=`<article>
1541
+ </article>`}async function cl(){try{let e=await fetch("/api/cli-options"),n=await e.json();if(e.ok&&Array.isArray(n?.options))return typeof n.ttadkModelDefault=="string"&&n.ttadkModelDefault.trim()&&(In=n.ttadkModelDefault.trim()),Array.isArray(n.ttadkModelSuggestions)&&(as=n.ttadkModelSuggestions.filter(a=>typeof a=="string")),n.options}catch{}return[{id:"claude-code",label:"Claude"}]}function ns(e){let n=pt;if(!n)return;let a=n.querySelector("#ob-cli"),s=n.querySelector("#ob-model"),o=n.querySelector("#ob-model-suggestions");if(!a||!s)return;let r=e.find(k=>k.id===a.value),d=r?.gateway==="ttadk",p=d&&r?.acceptsModel!==!1;if(d&&!p){s.value="",s.disabled=!0,s.placeholder=t("botOnboarding.modelTtadkCocoPlaceholder");return}s.disabled=!1,p?(o&&(o.innerHTML=as.map(k=>`<option value="${i(k)}"></option>`).join("")),s.placeholder=t("botOnboarding.modelTtadkPlaceholder").replace("{model}",In),s.value.trim()||(s.value=In)):(o&&(o.innerHTML=""),s.placeholder=t("botOnboarding.modelPlaceholder"),s.value.trim()===In&&(s.value=""))}function ca(e,n){let a=ua(),s=e.map(k=>`<option value="${i(k.id)}">${i(k.label)}\uFF08${i(k.id)}\uFF09</option>`).join(""),o=n?`<p class="form-error">${i(n)}</p>`:"";a.innerHTML=`<article>
1399
1542
  <header>
1400
1543
  <h3>${t("botOnboarding.title")}</h3>
1401
1544
  <p>${t("botOnboarding.intro")}</p>
@@ -1414,14 +1557,14 @@ ${$a("manage")}
1414
1557
  <input id="ob-model" type="text" list="ob-model-suggestions" placeholder="${t("botOnboarding.modelPlaceholder")}" autocomplete="off" spellcheck="false">
1415
1558
  <datalist id="ob-model-suggestions"></datalist>
1416
1559
  </label>
1417
- ${a}
1560
+ ${o}
1418
1561
  <menu class="onboarding-actions">
1419
1562
  <button type="button" id="ob-cancel">${t("botOnboarding.cancel")}</button>
1420
1563
  <button type="submit" class="primary">${t("botOnboarding.startScan")}</button>
1421
1564
  </menu>
1422
1565
  </form>
1423
- </article>`;let i=o.querySelector("#onboarding-form");o.querySelector("#ob-cancel")?.addEventListener("click",()=>o.close()),o.querySelector("#ob-cli")?.addEventListener("change",()=>Ka(e)),Ka(e),i?.addEventListener("submit",v=>{v.preventDefault();let k=o.querySelector("#ob-cli")?.value??"",I=o.querySelector("#ob-dir")?.value??"",T=o.querySelector("#ob-model")?.value??"";Or({cliId:k,workingDir:I,model:T},e)})}async function Or(e,n){zt(),_t({id:"",status:"starting"});try{let o=await fetch("/api/bot-onboarding/start",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({cliId:e.cliId,workingDir:e.workingDir.trim(),model:e.model.trim()||void 0})}),s=await o.json();if(o.status===400){ao(n,s?.message??s?.error??"invalid_input");return}if(!o.ok||!s?.job?.id)throw new Error(s?.error??`http_${o.status}`);_t(s.job),yn=window.setInterval(()=>{Br(s.job.id).catch(a=>{zt(),_t({id:s.job.id,status:"failed",message:a instanceof Error?a.message:String(a)})})},1200)}catch(o){_t({id:"",status:"failed",message:o instanceof Error?o.message:String(o)})}}async function Br(e){let n=await fetch(`/api/bot-onboarding/${encodeURIComponent(e)}`),o=await n.json();if(!n.ok||!o?.job)throw new Error(o?.error??`http_${n.status}`);_t(o.job),(o.job.status==="completed"||o.job.status==="failed")&&zt()}async function Nr(){zt();let e=so();ao([{id:"claude-code",label:"Claude"}]),e.open||e.showModal();let n=await Rr();e.open&&e.querySelector("#onboarding-form")&&ao(n)}function Ya(){let e=document.getElementById("add-bot-btn");e&&(e.onclick=()=>{Nr()})}var Pr={monitor:'<rect width="20" height="14" x="2" y="3" rx="2"/><line x1="8" x2="16" y1="21" y2="21"/><line x1="12" x2="12" y1="17" y2="21"/>',sun:'<circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/>',moon:'<path d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"/>',cpu:'<path d="M12 20v2"/><path d="M12 2v2"/><path d="M17 20v2"/><path d="M17 2v2"/><path d="M2 12h2"/><path d="M2 17h2"/><path d="M2 7h2"/><path d="M20 12h2"/><path d="M20 17h2"/><path d="M20 7h2"/><path d="M7 20v2"/><path d="M7 2v2"/><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="8" y="8" width="8" height="8" rx="1"/>',sparkles:'<path d="M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z"/><path d="M20 2v4"/><path d="M22 4h-4"/><circle cx="4" cy="20" r="2"/>',zap:'<path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z"/>',terminal:'<path d="M12 19h8"/><path d="m4 17 6-6-6-6"/>',keyRound:'<path d="M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z"/><circle cx="16.5" cy="7.5" r=".5" fill="currentColor"/>',network:'<rect x="16" y="16" width="6" height="6" rx="1"/><rect x="2" y="16" width="6" height="6" rx="1"/><rect x="9" y="2" width="6" height="6" rx="1"/><path d="M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3"/><path d="M12 12V8"/>',swords:'<polyline points="14.5 17.5 3 6 3 3 6 3 17.5 14.5"/><line x1="13" x2="19" y1="19" y2="13"/><line x1="16" x2="20" y1="16" y2="20"/><line x1="19" x2="21" y1="21" y2="19"/><polyline points="14.5 6.5 18 3 21 3 21 6 17.5 9.5"/><line x1="5" x2="9" y1="14" y2="18"/><line x1="7" x2="4" y1="17" y2="20"/><line x1="3" x2="5" y1="19" y2="21"/>',flame:'<path d="M12 3q1 4 4 6.5t3 5.5a1 1 0 0 1-14 0 5 5 0 0 1 1-3 1 1 0 0 0 5 0c0-2-1.5-3-1.5-5q0-2 2.5-4"/>',ball:'<path d="M11 7a16 16 20 0 1 10.98 4.362"/><path d="M12 12a13 13 0 0 1-8.66 5"/><path d="M16.83 13.634a16 16 0 0 1-9.267 7.328"/><path d="M20.66 17A13 13 0 0 0 12 12a13 13 0 0 1 0-10"/><path d="M8.17 15.366a16 16 0 0 1-1.713-11.69"/><circle cx="12" cy="12" r="10"/>',chevron:'<path d="m6 9 6 6 6-6"/>'},Qa=[{labelKey:"theme.base",options:[{value:"system",labelKey:"status.system",icon:"monitor"},{value:"light",labelKey:"status.light",icon:"sun"},{value:"dark",labelKey:"status.dark",icon:"moon"}]},{labelKey:"theme.skins",options:[{value:"cyber",labelKey:"skin.cyber",icon:"cpu"},{value:"genshin",labelKey:"skin.genshin",icon:"sparkles"},{value:"fallout",labelKey:"skin.fallout",icon:"zap"},{value:"prts",labelKey:"skin.prts",icon:"terminal"},{value:"bluearchive",labelKey:"skin.bluearchive",icon:"keyRound"},{value:"zzz",labelKey:"skin.zzz",icon:"network"},{value:"dragonball",labelKey:"skin.dragonball",icon:"flame"},{value:"ikun",labelKey:"skin.ikun",icon:"ball"}]}],Va=Qa.flatMap(e=>e.options),ht=!1;function io(e){return`<svg class="tm-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${Pr[e]??""}</svg>`}function qr(e){return e.replace(/[&<>"]/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"})[n])}function Xa(){let e=document.getElementById("theme-menu"),n=document.getElementById("theme-menu-btn"),o=document.getElementById("theme-menu-pop");if(!e||!n||!o)return;o.innerHTML=Qa.map(a=>`<div class="tm-group" data-label-key="${a.labelKey}"></div>`+a.options.map(i=>`<button type="button" class="tm-item" role="option" data-value="${i.value}"><span class="tm-ic">${io(i.icon)}</span><span class="tm-label" data-label-key="${i.labelKey}"></span></button>`).join("")).join("");let s=a=>{ht=a,o.hidden=!ht,n.setAttribute("aria-expanded",String(ht)),e.classList.toggle("open",ht)};n.addEventListener("click",a=>{a.stopPropagation(),s(!ht)}),o.addEventListener("click",a=>{let i=a.target.closest(".tm-item");i&&(Te.setTheme(i.dataset.value??"system"),s(!1))}),document.addEventListener("click",a=>{ht&&!e.contains(a.target)&&s(!1)}),document.addEventListener("keydown",a=>{a.key==="Escape"&&ht&&s(!1)}),ro()}function ro(){let e=document.getElementById("theme-menu-btn");if(!e)return;let n=Va.find(o=>o.value===Te.theme)??Va[0];e.innerHTML=`<span class="tm-ic">${io(n.icon)}</span><span class="tm-current">${qr(t(n.labelKey))}</span><span class="tm-chev">${io("chevron")}</span>`,document.querySelectorAll("#theme-menu-pop [data-label-key]").forEach(o=>{o.textContent=t(o.dataset.labelKey??"")}),document.querySelectorAll("#theme-menu-pop .tm-item").forEach(o=>{o.classList.toggle("active",o.dataset.value===Te.theme)})}var Ce=document.getElementById("root"),Et=!0,os=!1,as=["roles","bot-defaults","team","connectors"],lo=!1;function Ur(){if(lo)return;lo=!0;let e=document.createElement("div");e.id="auth-expired-overlay",e.style.cssText="position:fixed;inset:0;background:rgba(0,0,0,.65);display:flex;align-items:center;justify-content:center;z-index:9999",e.innerHTML='<div style="background:var(--surface);color:var(--fg);border:1px solid var(--border);border-radius:12px;padding:36px 40px;max-width:460px;width:90vw;text-align:center;box-shadow:0 12px 40px rgba(0,0,0,.35)"><h2 style="margin:0 0 14px;font-size:19px;color:var(--fg)">\u8BBF\u95EE\u94FE\u63A5\u5DF2\u5931\u6548</h2><p style="margin:0 0 24px;line-height:1.7;color:var(--muted,#8f959e);font-size:14px">\u5F53\u524D\u94FE\u63A5/\u8BBF\u95EE\u5DF2\u5931\u6548\uFF0C\u8BF7\u4F7F\u7528\u6700\u65B0\u6388\u6743\u94FE\u63A5\u91CD\u65B0\u8FDB\u5165\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09\u3002</p><button id="auth-expired-dismiss" type="button" style="padding:8px 22px;background:var(--accent);color:var(--on-accent);border:none;border-radius:8px;cursor:pointer;font-size:14px">\u77E5\u9053\u4E86</button></div>',document.body.appendChild(e);let n=()=>{e.remove(),lo=!1};e.querySelector("#auth-expired-dismiss")?.addEventListener("click",n),e.addEventListener("click",o=>{o.target===e&&n()})}var co;function jr(){let e=document.getElementById("readonly-toast");e||(e=document.createElement("div"),e.id="readonly-toast",e.style.cssText="position:fixed;left:50%;bottom:28px;transform:translateX(-50%);z-index:9999;background:var(--fg,#1f2329);color:var(--bg,#fff);padding:10px 18px;border-radius:8px;font-size:13px;box-shadow:0 8px 24px rgba(0,0,0,.25)",document.body.appendChild(e)),e.textContent="\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u6B64\u64CD\u4F5C\u9700\u8981\u6388\u6743\u94FE\u63A5\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09",e.style.display="block",co&&window.clearTimeout(co),co=window.setTimeout(()=>{e.style.display="none"},4e3)}var Fr=window.fetch.bind(window);window.fetch=async function(...n){let o=await Fr(...n);if(o.status===401){let s=(n[1]?.method??"GET").toUpperCase();(s==="GET"||s==="HEAD")&&!os?Ur():jr()}return o};var uo="";function kn(){let e=document.getElementById("attention-strip");if(!e)return;let n=[...Q.sessions.values()].map(a=>({s:a,reason:it(a)})).filter(a=>!!a.reason).sort((a,i)=>xe(a.s)-xe(i.s));if(n.length===0){e.hidden=!0,e.innerHTML="",uo="";return}let o=n[0],s=`
1566
+ </article>`;let r=a.querySelector("#onboarding-form");a.querySelector("#ob-cancel")?.addEventListener("click",()=>a.close()),a.querySelector("#ob-cli")?.addEventListener("change",()=>ns(e)),ns(e),r?.addEventListener("submit",k=>{k.preventDefault();let $=a.querySelector("#ob-cli")?.value??"",E=a.querySelector("#ob-dir")?.value??"",w=a.querySelector("#ob-model")?.value??"";ul({cliId:$,workingDir:E,model:w},e)})}async function ul(e,n){Vt(),Jt({id:"",status:"starting"});try{let a=await fetch("/api/bot-onboarding/start",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({cliId:e.cliId,workingDir:e.workingDir.trim(),model:e.model.trim()||void 0})}),s=await a.json();if(a.status===400){ca(n,s?.message??s?.error??"invalid_input");return}if(!a.ok||!s?.job?.id)throw new Error(s?.error??`http_${a.status}`);Jt(s.job),Tn=window.setInterval(()=>{pl(s.job.id).catch(o=>{Vt(),Jt({id:s.job.id,status:"failed",message:o instanceof Error?o.message:String(o)})})},1200)}catch(a){Jt({id:"",status:"failed",message:a instanceof Error?a.message:String(a)})}}async function pl(e){let n=await fetch(`/api/bot-onboarding/${encodeURIComponent(e)}`),a=await n.json();if(!n.ok||!a?.job)throw new Error(a?.error??`http_${n.status}`);Jt(a.job),(a.job.status==="completed"||a.job.status==="failed")&&Vt()}async function ml(){Vt();let e=ua();ca([{id:"claude-code",label:"Claude"}]),e.open||e.showModal();let n=await cl();e.open&&e.querySelector("#onboarding-form")&&ca(n)}function os(){let e=document.getElementById("add-bot-btn");e&&(e.onclick=()=>{ml()})}var fl={monitor:'<rect width="20" height="14" x="2" y="3" rx="2"/><line x1="8" x2="16" y1="21" y2="21"/><line x1="12" x2="12" y1="17" y2="21"/>',sun:'<circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/>',moon:'<path d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"/>',cpu:'<path d="M12 20v2"/><path d="M12 2v2"/><path d="M17 20v2"/><path d="M17 2v2"/><path d="M2 12h2"/><path d="M2 17h2"/><path d="M2 7h2"/><path d="M20 12h2"/><path d="M20 17h2"/><path d="M20 7h2"/><path d="M7 20v2"/><path d="M7 2v2"/><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="8" y="8" width="8" height="8" rx="1"/>',sparkles:'<path d="M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z"/><path d="M20 2v4"/><path d="M22 4h-4"/><circle cx="4" cy="20" r="2"/>',zap:'<path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z"/>',terminal:'<path d="M12 19h8"/><path d="m4 17 6-6-6-6"/>',keyRound:'<path d="M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z"/><circle cx="16.5" cy="7.5" r=".5" fill="currentColor"/>',network:'<rect x="16" y="16" width="6" height="6" rx="1"/><rect x="2" y="16" width="6" height="6" rx="1"/><rect x="9" y="2" width="6" height="6" rx="1"/><path d="M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3"/><path d="M12 12V8"/>',swords:'<polyline points="14.5 17.5 3 6 3 3 6 3 17.5 14.5"/><line x1="13" x2="19" y1="19" y2="13"/><line x1="16" x2="20" y1="16" y2="20"/><line x1="19" x2="21" y1="21" y2="19"/><polyline points="14.5 6.5 18 3 21 3 21 6 17.5 9.5"/><line x1="5" x2="9" y1="14" y2="18"/><line x1="7" x2="4" y1="17" y2="20"/><line x1="3" x2="5" y1="19" y2="21"/>',flame:'<path d="M12 3q1 4 4 6.5t3 5.5a1 1 0 0 1-14 0 5 5 0 0 1 1-3 1 1 0 0 0 5 0c0-2-1.5-3-1.5-5q0-2 2.5-4"/>',ball:'<path d="M11 7a16 16 20 0 1 10.98 4.362"/><path d="M12 12a13 13 0 0 1-8.66 5"/><path d="M16.83 13.634a16 16 0 0 1-9.267 7.328"/><path d="M20.66 17A13 13 0 0 0 12 12a13 13 0 0 1 0-10"/><path d="M8.17 15.366a16 16 0 0 1-1.713-11.69"/><circle cx="12" cy="12" r="10"/>',chevron:'<path d="m6 9 6 6 6-6"/>'},is=[{labelKey:"theme.base",options:[{value:"system",labelKey:"status.system",icon:"monitor"},{value:"light",labelKey:"status.light",icon:"sun"},{value:"dark",labelKey:"status.dark",icon:"moon"}]},{labelKey:"theme.skins",options:[{value:"cyber",labelKey:"skin.cyber",icon:"cpu"},{value:"genshin",labelKey:"skin.genshin",icon:"sparkles"},{value:"fallout",labelKey:"skin.fallout",icon:"zap"},{value:"prts",labelKey:"skin.prts",icon:"terminal"},{value:"bluearchive",labelKey:"skin.bluearchive",icon:"keyRound"},{value:"zzz",labelKey:"skin.zzz",icon:"network"},{value:"dragonball",labelKey:"skin.dragonball",icon:"flame"},{value:"ikun",labelKey:"skin.ikun",icon:"ball"}]}],ss=is.flatMap(e=>e.options),kt=!1;function pa(e){return`<svg class="tm-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${fl[e]??""}</svg>`}function gl(e){return e.replace(/[&<>"]/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"})[n])}function rs(){let e=document.getElementById("theme-menu"),n=document.getElementById("theme-menu-btn"),a=document.getElementById("theme-menu-pop");if(!e||!n||!a)return;a.innerHTML=is.map(o=>`<div class="tm-group" data-label-key="${o.labelKey}"></div>`+o.options.map(r=>`<button type="button" class="tm-item" role="option" data-value="${r.value}"><span class="tm-ic">${pa(r.icon)}</span><span class="tm-label" data-label-key="${r.labelKey}"></span></button>`).join("")).join("");let s=o=>{kt=o,a.hidden=!kt,n.setAttribute("aria-expanded",String(kt)),e.classList.toggle("open",kt)};n.addEventListener("click",o=>{o.stopPropagation(),s(!kt)}),a.addEventListener("click",o=>{let r=o.target.closest(".tm-item");r&&(Te.setTheme(r.dataset.value??"system"),s(!1))}),document.addEventListener("click",o=>{kt&&!e.contains(o.target)&&s(!1)}),document.addEventListener("keydown",o=>{o.key==="Escape"&&kt&&s(!1)}),ma()}function ma(){let e=document.getElementById("theme-menu-btn");if(!e)return;let n=ss.find(a=>a.value===Te.theme)??ss[0];e.innerHTML=`<span class="tm-ic">${pa(n.icon)}</span><span class="tm-current">${gl(t(n.labelKey))}</span><span class="tm-chev">${pa("chevron")}</span>`,document.querySelectorAll("#theme-menu-pop [data-label-key]").forEach(a=>{a.textContent=t(a.dataset.labelKey??"")}),document.querySelectorAll("#theme-menu-pop .tm-item").forEach(a=>{a.classList.toggle("active",a.dataset.value===Te.theme)})}var Ie=document.getElementById("root"),At=!0,ps=!1,ms=["roles","bot-defaults","skills","team","connectors"],fa=!1;function bl(){if(fa)return;fa=!0;let e=document.createElement("div");e.id="auth-expired-overlay",e.style.cssText="position:fixed;inset:0;background:rgba(0,0,0,.65);display:flex;align-items:center;justify-content:center;z-index:9999",e.innerHTML='<div style="background:var(--surface);color:var(--fg);border:1px solid var(--border);border-radius:12px;padding:36px 40px;max-width:460px;width:90vw;text-align:center;box-shadow:0 12px 40px rgba(0,0,0,.35)"><h2 style="margin:0 0 14px;font-size:19px;color:var(--fg)">\u8BBF\u95EE\u94FE\u63A5\u5DF2\u5931\u6548</h2><p style="margin:0 0 24px;line-height:1.7;color:var(--muted,#8f959e);font-size:14px">\u5F53\u524D\u94FE\u63A5/\u8BBF\u95EE\u5DF2\u5931\u6548\uFF0C\u8BF7\u4F7F\u7528\u6700\u65B0\u6388\u6743\u94FE\u63A5\u91CD\u65B0\u8FDB\u5165\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09\u3002</p><button id="auth-expired-dismiss" type="button" style="padding:8px 22px;background:var(--accent);color:var(--on-accent);border:none;border-radius:8px;cursor:pointer;font-size:14px">\u77E5\u9053\u4E86</button></div>',document.body.appendChild(e);let n=()=>{e.remove(),fa=!1};e.querySelector("#auth-expired-dismiss")?.addEventListener("click",n),e.addEventListener("click",a=>{a.target===e&&n()})}var ga;function hl(){let e=document.getElementById("readonly-toast");e||(e=document.createElement("div"),e.id="readonly-toast",e.style.cssText="position:fixed;left:50%;bottom:28px;transform:translateX(-50%);z-index:9999;background:var(--fg,#1f2329);color:var(--bg,#fff);padding:10px 18px;border-radius:8px;font-size:13px;box-shadow:0 8px 24px rgba(0,0,0,.25)",document.body.appendChild(e)),e.textContent="\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u6B64\u64CD\u4F5C\u9700\u8981\u6388\u6743\u94FE\u63A5\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09",e.style.display="block",ga&&window.clearTimeout(ga),ga=window.setTimeout(()=>{e.style.display="none"},4e3)}var wl=window.fetch.bind(window);window.fetch=async function(...n){let a=await wl(...n);if(a.status===401){let s=(n[1]?.method??"GET").toUpperCase();(s==="GET"||s==="HEAD")&&!ps?bl():hl()}return a};var ba="";function Mn(){let e=document.getElementById("attention-strip");if(!e)return;let n=[...Q.sessions.values()].map(o=>({s:o,reason:dt(o)})).filter(o=>!!o.reason).sort((o,r)=>He(o.s)-He(r.s));if(n.length===0){e.hidden=!0,e.innerHTML="",ba="";return}let a=n[0],s=`
1424
1567
  <span class="attention-strip-ic" aria-hidden="true">!</span>
1425
- <b>${r(t("strip.pending",{count:n.length}))}</b>
1426
- <span class="attention-strip-longest">${r(t("strip.longest",{time:qe(xe(o.s)),bot:ye(o.s),reason:o.reason}))}</span>
1427
- <a class="attention-strip-go" href="#/sessions">${r(t("strip.handle"))}</a>`;e.hidden=!1,s!==uo&&(uo=s,e.innerHTML=s)}Q.on(kn);Ke().then(kn);async function Gr(){try{let e=await fetch("/api/settings");if(e.ok){let n=await e.json();Et=!!n.authed,Te.authed=Et,os=!!(n.settings&&n.settings.publicReadOnly);let o=Vt(n.lang);o&&Te.setLocale(o)}}catch{}}async function _r(e){if(Et)try{await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({lang:e})})}catch{}}function zr(){for(let n of as){let o=document.querySelector(`.sidebar-nav a[data-route="${n}"]`);o&&(o.style.display=Et?"":"none")}let e=document.getElementById("add-bot-btn");e&&(e.style.display=Et?"":"none")}function Wr(e){e.innerHTML='<section class="auth-required" style="max-width:520px;margin:64px auto;text-align:center;background:var(--surface);color:var(--fg);border:1px solid var(--border);border-radius:14px;padding:40px 36px;box-shadow:0 8px 28px rgba(0,0,0,.12)"><h2 style="margin:0 0 12px;font-size:20px;color:var(--fg)">\u6B64\u9875\u9700\u8981\u6388\u6743\u94FE\u63A5</h2><p style="margin:0 0 24px;line-height:1.7;color:var(--muted);font-size:14px">\u4F60\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u7BA1\u7406\u9875\uFF08\u89D2\u8272 / Bot \u914D\u7F6E / \u56E2\u961F / Webhook\uFF09\u9700\u8981\u6388\u6743\u94FE\u63A5\u3002\u8FD0\u884C <code>botmux dashboard</code> \u83B7\u53D6\u6700\u65B0\u94FE\u63A5\u540E\u5373\u53EF\u7BA1\u7406\u3002</p><a href="#/" style="display:inline-block;padding:8px 22px;background:var(--accent);color:var(--on-accent);border-radius:8px;text-decoration:none;font-size:14px">\u8FD4\u56DE\u603B\u89C8</a></section>'}var xt=null;function Za(e){for(let n of document.querySelectorAll(".sidebar-nav a")){let o=n.getAttribute("href")??"#/";n.classList.toggle("active",o===(e||"#/"))}}function po(){xt&&(xt(),xt=null);let e=location.hash||"#/";if(!Et&&as.some(n=>e.startsWith("#/"+n))){Wr(Ce),Za(e);return}e.startsWith("#/workflows/catalog")||e.startsWith("#/workflows-catalog")?xt=za(Ce):e.startsWith("#/workflows")?xt=Ra(Ce):e.startsWith("#/groups")?ua(Ce):e.startsWith("#/settings")?Ha(Ce):e.startsWith("#/bot-defaults")?ga(Ce):e.startsWith("#/connectors")?xa(Ce):e.startsWith("#/team/manage")?La(Ce):e.startsWith("#/team")?Ta(Ce):e.startsWith("#/roles")?ya(Ce):e.startsWith("#/schedules")?da(Ce):e.startsWith("#/sessions")?ra(Ce):e.startsWith("#/office")?xt=Wa(Ce)??null:Yo(Ce),Za(e)}var mo=document.getElementById("status");function ss(){mo&&(mo.textContent=Q.online?t("status.live"):t("status.disconnected"),mo.className="connection-status "+(Q.online?"online":"offline"))}Q.on(ss);function es(){document.querySelectorAll("[data-i18n]").forEach(e=>{e.textContent=t(e.dataset.i18n??"")}),document.querySelectorAll("[data-locale]").forEach(e=>{e.classList.toggle("active",e.dataset.locale===Te.locale)}),ro(),ss()}function Kr(){document.querySelectorAll("[data-locale]").forEach(e=>{e.onclick=()=>{let n=e.dataset.locale;Te.setLocale(n),_r(n)}}),Xa(),Yr()}var ts="botmux.ownerAvatar.v1";function ns(e,n){let o=document.querySelector(".brand-mark");!o||!e||(o.innerHTML=`<img class="brand-owner-img" src="${r(e)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.remove()">`,n&&(o.title=n))}function Jr(){try{let e=JSON.parse(window.localStorage.getItem(ts)??"null");e?.avatarUrl&&ns(String(e.avatarUrl),e.name?String(e.name):void 0)}catch{}fetch("/api/owner-profile").then(e=>e.ok?e.json():null).then(e=>{if(!(!e?.ok||!e.avatarUrl)){ns(String(e.avatarUrl),e.name?String(e.name):void 0);try{window.localStorage.setItem(ts,JSON.stringify({avatarUrl:e.avatarUrl,name:e.name??""}))}catch{}}}).catch(()=>{})}function Yr(){let e=document.getElementById("sidebar-toggle");if(!e)return;let n=Ao(window.localStorage),o=()=>{document.documentElement.dataset.sidebar=n,e.title=t(n==="collapsed"?"nav.sidebarExpand":"nav.sidebarCollapse")};o(),e.addEventListener("click",()=>{n=n==="collapsed"?"expanded":"collapsed",Do(window.localStorage,n),o()})}(async()=>{Te.init(),Kr(),Ya(),Te.on(()=>{es(),kn(),po()}),es(),kn(),await Gr(),zr(),Jr();try{await wo()}catch(e){console.error("botmux dashboard bootstrap failed",e),Q.setOnline(!1)}window.addEventListener("hashchange",po),po()})();})();
1568
+ <b>${i(t("strip.pending",{count:n.length}))}</b>
1569
+ <span class="attention-strip-longest">${i(t("strip.longest",{time:je(He(a.s)),bot:ve(a.s),reason:a.reason}))}</span>
1570
+ <a class="attention-strip-go" href="#/sessions">${i(t("strip.handle"))}</a>`;e.hidden=!1,s!==ba&&(ba=s,e.innerHTML=s)}Q.on(Mn);Je().then(Mn);async function yl(){try{let e=await fetch("/api/settings");if(e.ok){let n=await e.json();At=!!n.authed,Te.authed=At,ps=!!(n.settings&&n.settings.publicReadOnly);let a=en(n.lang);a&&Te.setLocale(a)}}catch{}}async function vl(e){if(At)try{await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({lang:e})})}catch{}}function kl(){for(let n of ms){let a=document.querySelector(`.sidebar-nav a[data-route="${n}"]`);a&&(a.style.display=At?"":"none")}let e=document.getElementById("add-bot-btn");e&&(e.style.display=At?"":"none")}function $l(e){e.innerHTML='<section class="auth-required" style="max-width:520px;margin:64px auto;text-align:center;background:var(--surface);color:var(--fg);border:1px solid var(--border);border-radius:14px;padding:40px 36px;box-shadow:0 8px 28px rgba(0,0,0,.12)"><h2 style="margin:0 0 12px;font-size:20px;color:var(--fg)">\u6B64\u9875\u9700\u8981\u6388\u6743\u94FE\u63A5</h2><p style="margin:0 0 24px;line-height:1.7;color:var(--muted);font-size:14px">\u4F60\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u7BA1\u7406\u9875\uFF08\u89D2\u8272 / Bot \u914D\u7F6E / \u56E2\u961F / Webhook\uFF09\u9700\u8981\u6388\u6743\u94FE\u63A5\u3002\u8FD0\u884C <code>botmux dashboard</code> \u83B7\u53D6\u6700\u65B0\u94FE\u63A5\u540E\u5373\u53EF\u7BA1\u7406\u3002</p><a href="#/" style="display:inline-block;padding:8px 22px;background:var(--accent);color:var(--on-accent);border-radius:8px;text-decoration:none;font-size:14px">\u8FD4\u56DE\u603B\u89C8</a></section>'}var Ct=null;function ls(e){for(let n of document.querySelectorAll(".sidebar-nav a")){let a=n.getAttribute("href")??"#/";n.classList.toggle("active",a===(e||"#/"))}}function ha(){Ct&&(Ct(),Ct=null);let e=location.hash||"#/";if(!At&&ms.some(n=>e.startsWith("#/"+n))){$l(Ie),ls(e);return}e.startsWith("#/workflows/catalog")||e.startsWith("#/workflows-catalog")?Ct=es(Ie):e.startsWith("#/workflows")?Ct=Go(Ie):e.startsWith("#/groups")?ho(Ie):e.startsWith("#/settings")?qo(Ie):e.startsWith("#/bot-defaults")?ko(Ie):e.startsWith("#/skills")?Lo(Ie):e.startsWith("#/connectors")?Oo(Ie):e.startsWith("#/team/manage")?Ro(Ie):e.startsWith("#/team")?Do(Ie):e.startsWith("#/roles")?Eo(Ie):e.startsWith("#/schedules")?go(Ie):e.startsWith("#/sessions")?mo(Ie):e.startsWith("#/office")?Ct=ts(Ie)??null:eo(Ie),ls(e)}var wa=document.getElementById("status");function fs(){wa&&(wa.textContent=Q.online?t("status.live"):t("status.disconnected"),wa.className="connection-status "+(Q.online?"online":"offline"))}Q.on(fs);function ds(){document.querySelectorAll("[data-i18n]").forEach(e=>{e.textContent=t(e.dataset.i18n??"")}),document.querySelectorAll("[data-locale]").forEach(e=>{e.classList.toggle("active",e.dataset.locale===Te.locale)}),ma(),fs()}function Sl(){document.querySelectorAll("[data-locale]").forEach(e=>{e.onclick=()=>{let n=e.dataset.locale;Te.setLocale(n),vl(n)}}),rs(),Tl()}var cs="botmux.ownerAvatar.v1";function us(e,n){let a=document.querySelector(".brand-mark");!a||!e||(a.innerHTML=`<img class="brand-owner-img" src="${i(e)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.remove()">`,n&&(a.title=n))}function Ll(){try{let e=JSON.parse(window.localStorage.getItem(cs)??"null");e?.avatarUrl&&us(String(e.avatarUrl),e.name?String(e.name):void 0)}catch{}fetch("/api/owner-profile").then(e=>e.ok?e.json():null).then(e=>{if(!(!e?.ok||!e.avatarUrl)){us(String(e.avatarUrl),e.name?String(e.name):void 0);try{window.localStorage.setItem(cs,JSON.stringify({avatarUrl:e.avatarUrl,name:e.name??""}))}catch{}}}).catch(()=>{})}function Tl(){let e=document.getElementById("sidebar-toggle");if(!e)return;let n=Oa(window.localStorage),a=()=>{document.documentElement.dataset.sidebar=n,e.title=t(n==="collapsed"?"nav.sidebarExpand":"nav.sidebarCollapse")};a(),e.addEventListener("click",()=>{n=n==="collapsed"?"expanded":"collapsed",Na(window.localStorage,n),a()})}(async()=>{Te.init(),Sl(),os(),Te.on(()=>{ds(),Mn(),ha()}),ds(),Mn(),await yl(),kl(),Ll();try{await Sa()}catch(e){console.error("botmux dashboard bootstrap failed",e),Q.setOnline(!1)}window.addEventListener("hashchange",ha),ha()})();})();