botmux 2.71.1 → 2.71.3

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 (43) hide show
  1. package/dist/core/command-handler.d.ts +1 -1
  2. package/dist/core/command-handler.d.ts.map +1 -1
  3. package/dist/core/command-handler.js +5 -1
  4. package/dist/core/command-handler.js.map +1 -1
  5. package/dist/core/reply-target.d.ts +10 -0
  6. package/dist/core/reply-target.d.ts.map +1 -1
  7. package/dist/core/reply-target.js +12 -0
  8. package/dist/core/reply-target.js.map +1 -1
  9. package/dist/core/worker-pool.d.ts.map +1 -1
  10. package/dist/core/worker-pool.js +6 -2
  11. package/dist/core/worker-pool.js.map +1 -1
  12. package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
  13. package/dist/dashboard/web/bot-defaults.js +3 -1
  14. package/dist/dashboard/web/bot-defaults.js.map +1 -1
  15. package/dist/dashboard/web/groups.d.ts.map +1 -1
  16. package/dist/dashboard/web/groups.js +18 -6
  17. package/dist/dashboard/web/groups.js.map +1 -1
  18. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  19. package/dist/dashboard/web/i18n.js +6 -0
  20. package/dist/dashboard/web/i18n.js.map +1 -1
  21. package/dist/dashboard/web/overview.d.ts.map +1 -1
  22. package/dist/dashboard/web/overview.js +70 -3
  23. package/dist/dashboard/web/overview.js.map +1 -1
  24. package/dist/dashboard/web/roles.d.ts.map +1 -1
  25. package/dist/dashboard/web/roles.js +5 -1
  26. package/dist/dashboard/web/roles.js.map +1 -1
  27. package/dist/dashboard/web/ui.d.ts +4 -0
  28. package/dist/dashboard/web/ui.d.ts.map +1 -1
  29. package/dist/dashboard/web/ui.js +19 -4
  30. package/dist/dashboard/web/ui.js.map +1 -1
  31. package/dist/dashboard-web/app.js +326 -322
  32. package/dist/dashboard-web/style.css +90 -1
  33. package/dist/im/lark/card-handler.d.ts +1 -1
  34. package/dist/im/lark/card-handler.d.ts.map +1 -1
  35. package/dist/im/lark/card-handler.js +10 -2
  36. package/dist/im/lark/card-handler.js.map +1 -1
  37. package/dist/services/claude-transcript.d.ts +17 -0
  38. package/dist/services/claude-transcript.d.ts.map +1 -1
  39. package/dist/services/claude-transcript.js +72 -0
  40. package/dist/services/claude-transcript.js.map +1 -1
  41. package/dist/worker.js +8 -2
  42. package/dist/worker.js.map +1 -1
  43. package/package.json +1 -1
@@ -1,16 +1,16 @@
1
- "use strict";(()=>{var Pt=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 Pt;async function $n(){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 l=JSON.parse(i.data);Q.applySse(a,l.body??l)}catch{}});o.onerror=()=>Q.setOnline(!1),o.onopen=()=>Q.setOnline(!0)}var qt="botmux.dashboard.locale",Ko={"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.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.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","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.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","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.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.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.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","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
- \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.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
1
+ "use strict";(()=>{var jt=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()}},ee=new jt;async function Ln(){let[e,n]=await Promise.all([fetch("/api/sessions").then(a=>a.json()),fetch("/api/schedules").then(a=>a.json())]);ee.upsertSessions(e.sessions??[]),ee.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 l=JSON.parse(i.data);ee.applySse(a,l.body??l)}catch{}});o.onerror=()=>ee.setOnline(!1),o.onopen=()=>ee.setOnline(!0)}var Ft="botmux.dashboard.locale",Zo={"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.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.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.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","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.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.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.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","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
+ \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
3
 
4
4
  {total} \u4E2A\u60AC\u6302\u9879\u4F1A\u7531 cancel recovery \u5904\u7406\u3002
5
5
  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
6
  "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"},Vo={"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.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.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","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.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","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.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.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.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","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
- 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.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}?
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"},ea={"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.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.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.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","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.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.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.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","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
+ 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
9
 
10
10
  {total} dangling item(s) will be handled by cancel-driven recovery.
11
11
  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
12
  "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"},Sn={zh:Ko,en:Vo};function ht(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 Yo(e=[]){for(let n of e){let o=ht(n);if(o)return o}return"zh"}function wt(e){return(n,o)=>{let s=Sn[e][n]??Sn.zh[n]??n;return o?s.replace(/\{(\w+)\}/g,(a,i)=>{let l=o[i];return l==null?`{${i}}`:String(l)}):s}}function Tn(e,n){return(e?ht(e.getItem(qt)):null)??Yo(n)}var Ut="botmux.dashboard.theme",Ln="botmux.dashboard.sessions.view";function Qo(e){return e==="system"||e==="light"||e==="dark"?e:null}function Xo(e){return e==="board"||e==="table"?e:null}function In(e,n){return e==="system"?n?"dark":"light":e}function Mn(e){return Qo(e?.getItem(Ut))??"dark"}function xn(e){return Xo(e?.getItem(Ln))??"board"}var En="botmux.dashboard.sessions.boardOrder",ot=["needs-you","starting","working","idle"];function Zo(e){if(!Array.isArray(e)||e.length!==ot.length)return null;let n=new Set(e);if(n.size!==e.length)return null;for(let o of ot)if(!n.has(o))return null;return e.slice()}function Hn(e){try{let n=e?.getItem(En);return n?Zo(JSON.parse(n))??[...ot]:[...ot]}catch{return[...ot]}}function jt(e,n){try{e?.setItem(En,JSON.stringify(n))}catch{}}function Cn(e,n){try{e?.setItem(Ln,n)}catch{}}var ea=["default","cyber","genshin","fallout","prts","bluearchive","zzz","dragonball","ikun"],Ft="botmux.dashboard.skin";function ta(e){return typeof e=="string"&&ea.includes(e)?e:null}function An(e){return ta(e?.getItem(Ft))??"default"}var na="\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF830123456789\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E$#%&@*+=<>/\\",Dn=["186 100% 60%","56 97% 60%","330 100% 64%","150 80% 58%"],zt=[{key:"shake",dur:280},{key:"rgb",dur:340},{key:"tear",dur:400},{key:"invert",dur:220},{key:"slice",dur:320},{key:"blackout",dur:260}],Rn=["ESTABLISHING NETLINK","BYPASSING ICE","DECRYPTING DATAFLOW","SYNCING BOTMUX TELEMETRY","ACCESS GRANTED"],On="0123456789ABCDEF#<>*/=+\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C",oa=3200,at=[],Ke=0,yt=0;function Jt(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function _t(e,n){let o="";for(let s=0;s<e;s++)o+=n[Math.floor(Math.random()*n.length)];return o}function aa(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=_t(28+Math.floor(Math.random()*22),na);let i=Dn[Math.floor(Math.random()*Dn.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 sa(){if(Jt())return;let e=document.body,n=()=>{let o=zt[Math.floor(Math.random()*zt.length)],s=`cp-fx-${o.key}`;e.classList.add(s),at.push(window.setTimeout(()=>e.classList.remove(s),o.dur)),at.push(window.setTimeout(n,2400+Math.random()*4200))};at.push(window.setTimeout(n,1800+Math.random()*2600))}function ia(){at.forEach(e=>window.clearTimeout(e)),at=[];for(let e of zt)document.body.classList.remove(`cp-fx-${e.key}`)}function ra(){if(Jt()||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;Ke=window.setInterval(()=>{let l=Rn[s];n&&(a<l.length?(a+=1,n.textContent=l.slice(0,a)+_t(l.length-a,On),n.classList.remove("done")):i<16?(i+=1,n.textContent=l,n.classList.add("done")):(s=(s+1)%Rn.length,a=0,i=0)),o&&(o.textContent=_t(26,On))},50),yt=window.setTimeout(()=>{window.clearInterval(Ke),Ke=0,e.remove()},oa)}function la(){Ke&&(window.clearInterval(Ke),Ke=0),yt&&(window.clearTimeout(yt),yt=0),document.getElementById("cyber-boot")?.remove()}var da=320,Bn=16,st=!0,Je=0,Gt=0,vt=!1,kt=[],Wt=[];function ca(){if(vt)return;vt=!0,st=!1,Je=0;let e=Jt(),n="";for(let s=0;s<Bn;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/Bn*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"),kt.push(window.setTimeout(()=>document.body.classList.remove("cyber-breach-quake"),760)),kt.push(window.setTimeout(()=>{o.remove(),vt=!1},e?2600:4200))}function ua(){st=!0,Je=0;let e=document.documentElement,n=()=>e.scrollHeight-(window.innerHeight+window.scrollY)<=4,o=w=>{w<=0||!n()||(Je+=w,Je>da&&st&&ca())},s=w=>o(w.deltaY),a=w=>{Gt=w.touches[0]?.clientY??0},i=w=>{let h=w.touches[0]?.clientY??0,y=Gt-h;Gt=h,o(y)},l=()=>{n()||(Je=0,st=!0)},c=(w,h)=>{window.addEventListener(w,h,{passive:!0}),Wt.push([w,h])};c("wheel",s),c("touchstart",a),c("touchmove",i),c("scroll",l)}function pa(){for(let[e,n]of Wt)window.removeEventListener(e,n);Wt=[],kt.forEach(e=>window.clearTimeout(e)),kt=[],document.body.classList.remove("cyber-breach-quake"),document.getElementById("cyber-breach")?.remove(),vt=!1,st=!0,Je=0}function Nn(e,n=!1){if(!(typeof document>"u")){if(!e){document.getElementById("cyber-fx")?.remove(),document.getElementById("cyber-hud")?.remove(),document.getElementById("cyber-glitch")?.remove(),ia(),la(),pa();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>',aa(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),sa(),ua()}n&&ra()}}var ma={genshin:2e3,zzz:1900,dragonball:1900,ikun:1900},fa='<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 ga(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 fa;default:return""}}function ba(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Pn(e){if(typeof document>"u"||ba())return;let n=ma[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=ga(e),document.body.appendChild(o),window.setTimeout(()=>o.remove(),n+80)}var Vt=class{locale="zh";themeMode="system";resolvedTheme="light";skin="default";authed=!0;listeners=new Set;translate=wt(this.locale);mediaQuery=null;init(){let n=typeof window<"u"?window:void 0;this.locale=Tn(n?.localStorage,wa()),this.translate=wt(this.locale),this.themeMode=Mn(n?.localStorage),this.skin=An(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=wt(n),window.localStorage.setItem(qt,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(Ut,this.themeMode)),a&&(this.skin=s,window.localStorage.setItem(Ft,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=In(this.themeMode,!!this.mediaQuery?.matches);let n=this.skin==="default"?this.resolvedTheme:ha[this.skin];document.documentElement.dataset.theme=n,document.documentElement.dataset.themeMode=this.themeMode}applySkin(n=!1){document.documentElement.dataset.skin=this.skin,Nn(this.skin==="cyber",n),n&&this.skin!=="cyber"&&this.skin!=="default"&&Pn(this.skin)}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}},ha={default:"light",cyber:"dark",genshin:"light",fallout:"dark",prts:"dark",bluearchive:"dark",zzz:"dark",dragonball:"light",ikun:"dark"};function wa(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var ce=new Vt;function t(e,n){return ce.t(e,n)}function r(e){return e.replace(/[&<>"']/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[n])}function Le(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 qn=[{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 Un(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}=qn[n%qn.length];return`--c1:${s};--c2:${a}`}var $t=new Map,St=new Map;function ya(e,n){return n?$t.get(n):e?St.get(String(e)):void 0}function ye(e){let n=e.name??"",o=e.avatarUrl??ya(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>`:"",l=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="${Un(n)}" aria-hidden="true">${l}${i}</span>`}function va(e){return e?Tt.get(e):void 0}function jn(e){let n=e.name??e.chatId??"",o=e.avatarUrl??va(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="${Un(n)}" aria-hidden="true">${i}</span>`}var Fn=new Map,Gn=new Map,Tt=new Map,Kt=null,zn="botmux.avatarCache.v1";function ka(){try{let e=typeof window<"u"?window.localStorage.getItem(zn):null;if(!e)return;let n=JSON.parse(e);for(let[o,s]of Object.entries(n.botByAppId??{}))$t.set(o,s);for(let[o,s]of Object.entries(n.botByName??{}))St.set(o,s);for(let[o,s]of Object.entries(n.chatById??{}))Tt.set(o,s)}catch{}}function $a(){try{if(typeof window>"u")return;window.localStorage.setItem(zn,JSON.stringify({botByAppId:Object.fromEntries($t),botByName:Object.fromEntries(St),chatById:Object.fromEntries(Tt)}))}catch{}}ka();function Ee(){return Kt??=(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&&Fn.set(o.larkAppId,String(o.botName)),o.botAvatarUrl&&(o.larkAppId&&$t.set(o.larkAppId,String(o.botAvatarUrl)),o.botName&&St.set(String(o.botName),String(o.botAvatarUrl)));for(let o of n.chats??[])o.chatId&&o.name&&Gn.set(o.chatId,String(o.name)),o.chatId&&o.avatar&&Tt.set(o.chatId,String(o.avatar));$a()}catch{Kt=null}})(),Kt}function He(e){let n=e.larkAppId?Fn.get(e.larkAppId):void 0;return n||(e.botName&&e.botName!==e.larkAppId?String(e.botName):String(e.botName??e.larkAppId??"-"))}function Ve(e){return e.chatId&&Gn.get(e.chatId)||null}function Oe(e){let n=String(e??"");return n.replace(/^(?:@\S+\s*)+/,"").trim()||n}function Pe(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 ue(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 _n={chats:[],bots:[]};async function Sa(){try{let e=await fetch("/api/groups");if(!e.ok)return;_n=await e.json()}catch{}}var Yt=new Set(["working","analyzing","active","starting"]);function Ta(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 _n.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 l=o(i);a.botName&&(l.botName===l.larkAppId||!l.botName)&&(l.botName=a.botName),l.sessions.push(a),a.cliId&&l.cliId==="unknown"&&(l.cliId=a.cliId),l.lastActiveAt=Math.max(l.lastActiveAt,Number(a.lastMessageAt??0)),a.status!=="closed"&&(l.active.push(a),Yt.has(a.status)&&l.busy.push(a),Pe(a)&&l.attention.push(a))}return[...n.values()].sort((a,i)=>{let l=c=>c.attention.length?0:c.busy.length?1:c.online||c.active.length?2:3;return l(a)!==l(i)?l(a)-l(i):i.lastActiveAt-a.lastActiveAt})}function La(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 c=[...e.attention].sort((w,h)=>ue(w)-ue(h))[0];i=`<b>${r((Oe(c.title)||c.sessionId).slice(0,60))}</b> \xB7 ${r(Pe(c)??"")}`}else if(s){let c=[...e.busy].sort((w,h)=>Number(h.lastMessageAt??0)-Number(w.lastMessageAt??0))[0];i=`<b>${r((Oe(c.title)||c.sessionId).slice(0,60))}</b>`}else n?i=r(t("overview.botOffline")):i=r(t("overview.botIdle"));let l=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":""}">
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"},In={zh:Zo,en:ea};function yt(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 ta(e=[]){for(let n of e){let o=yt(n);if(o)return o}return"zh"}function vt(e){return(n,o)=>{let s=In[e][n]??In.zh[n]??n;return o?s.replace(/\{(\w+)\}/g,(a,i)=>{let l=o[i];return l==null?`{${i}}`:String(l)}):s}}function Mn(e,n){return(e?yt(e.getItem(Ft)):null)??ta(n)}var Gt="botmux.dashboard.theme",xn="botmux.dashboard.sessions.view";function na(e){return e==="system"||e==="light"||e==="dark"?e:null}function oa(e){return e==="board"||e==="table"?e:null}function En(e,n){return e==="system"?n?"dark":"light":e}function Hn(e){return na(e?.getItem(Gt))??"dark"}function Cn(e){return oa(e?.getItem(xn))??"board"}var An="botmux.dashboard.sessions.boardOrder",at=["needs-you","starting","working","idle"];function aa(e){if(!Array.isArray(e)||e.length!==at.length)return null;let n=new Set(e);if(n.size!==e.length)return null;for(let o of at)if(!n.has(o))return null;return e.slice()}function Dn(e){try{let n=e?.getItem(An);return n?aa(JSON.parse(n))??[...at]:[...at]}catch{return[...at]}}function zt(e,n){try{e?.setItem(An,JSON.stringify(n))}catch{}}function Rn(e,n){try{e?.setItem(xn,n)}catch{}}var sa=["default","cyber","genshin","fallout","prts","bluearchive","zzz","dragonball","ikun"],_t="botmux.dashboard.skin";function ia(e){return typeof e=="string"&&sa.includes(e)?e:null}function On(e){return ia(e?.getItem(_t))??"default"}var ra="\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF830123456789\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E$#%&@*+=<>/\\",Bn=["186 100% 60%","56 97% 60%","330 100% 64%","150 80% 58%"],Jt=[{key:"shake",dur:280},{key:"rgb",dur:340},{key:"tear",dur:400},{key:"invert",dur:220},{key:"slice",dur:320},{key:"blackout",dur:260}],Nn=["ESTABLISHING NETLINK","BYPASSING ICE","DECRYPTING DATAFLOW","SYNCING BOTMUX TELEMETRY","ACCESS GRANTED"],Pn="0123456789ABCDEF#<>*/=+\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C",la=3200,st=[],Ke=0,kt=0;function Yt(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Kt(e,n){let o="";for(let s=0;s<e;s++)o+=n[Math.floor(Math.random()*n.length)];return o}function da(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=Kt(28+Math.floor(Math.random()*22),ra);let i=Bn[Math.floor(Math.random()*Bn.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 ca(){if(Yt())return;let e=document.body,n=()=>{let o=Jt[Math.floor(Math.random()*Jt.length)],s=`cp-fx-${o.key}`;e.classList.add(s),st.push(window.setTimeout(()=>e.classList.remove(s),o.dur)),st.push(window.setTimeout(n,2400+Math.random()*4200))};st.push(window.setTimeout(n,1800+Math.random()*2600))}function ua(){st.forEach(e=>window.clearTimeout(e)),st=[];for(let e of Jt)document.body.classList.remove(`cp-fx-${e.key}`)}function pa(){if(Yt()||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;Ke=window.setInterval(()=>{let l=Nn[s];n&&(a<l.length?(a+=1,n.textContent=l.slice(0,a)+Kt(l.length-a,Pn),n.classList.remove("done")):i<16?(i+=1,n.textContent=l,n.classList.add("done")):(s=(s+1)%Nn.length,a=0,i=0)),o&&(o.textContent=Kt(26,Pn))},50),kt=window.setTimeout(()=>{window.clearInterval(Ke),Ke=0,e.remove()},la)}function ma(){Ke&&(window.clearInterval(Ke),Ke=0),kt&&(window.clearTimeout(kt),kt=0),document.getElementById("cyber-boot")?.remove()}var fa=320,qn=16,it=!0,Je=0,Wt=0,$t=!1,St=[],Vt=[];function ga(){if($t)return;$t=!0,it=!1,Je=0;let e=Yt(),n="";for(let s=0;s<qn;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/qn*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"),St.push(window.setTimeout(()=>document.body.classList.remove("cyber-breach-quake"),760)),St.push(window.setTimeout(()=>{o.remove(),$t=!1},e?2600:4200))}function ba(){it=!0,Je=0;let e=document.documentElement,n=()=>e.scrollHeight-(window.innerHeight+window.scrollY)<=4,o=h=>{h<=0||!n()||(Je+=h,Je>fa&&it&&ga())},s=h=>o(h.deltaY),a=h=>{Wt=h.touches[0]?.clientY??0},i=h=>{let b=h.touches[0]?.clientY??0,v=Wt-b;Wt=b,o(v)},l=()=>{n()||(Je=0,it=!0)},c=(h,b)=>{window.addEventListener(h,b,{passive:!0}),Vt.push([h,b])};c("wheel",s),c("touchstart",a),c("touchmove",i),c("scroll",l)}function ha(){for(let[e,n]of Vt)window.removeEventListener(e,n);Vt=[],St.forEach(e=>window.clearTimeout(e)),St=[],document.body.classList.remove("cyber-breach-quake"),document.getElementById("cyber-breach")?.remove(),$t=!1,it=!0,Je=0}function Un(e,n=!1){if(!(typeof document>"u")){if(!e){document.getElementById("cyber-fx")?.remove(),document.getElementById("cyber-hud")?.remove(),document.getElementById("cyber-glitch")?.remove(),ua(),ma(),ha();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>',da(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),ca(),ba()}n&&pa()}}var wa={genshin:2e3,zzz:1900,dragonball:1900,ikun:1900},ya='<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 va(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 ya;default:return""}}function ka(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function jn(e){if(typeof document>"u"||ka())return;let n=wa[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=va(e),document.body.appendChild(o),window.setTimeout(()=>o.remove(),n+80)}var Xt=class{locale="zh";themeMode="system";resolvedTheme="light";skin="default";authed=!0;listeners=new Set;translate=vt(this.locale);mediaQuery=null;init(){let n=typeof window<"u"?window:void 0;this.locale=Mn(n?.localStorage,Sa()),this.translate=vt(this.locale),this.themeMode=Hn(n?.localStorage),this.skin=On(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=vt(n),window.localStorage.setItem(Ft,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(Gt,this.themeMode)),a&&(this.skin=s,window.localStorage.setItem(_t,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=En(this.themeMode,!!this.mediaQuery?.matches);let n=this.skin==="default"?this.resolvedTheme:$a[this.skin];document.documentElement.dataset.theme=n,document.documentElement.dataset.themeMode=this.themeMode}applySkin(n=!1){document.documentElement.dataset.skin=this.skin,Un(this.skin==="cyber",n),n&&this.skin!=="cyber"&&this.skin!=="default"&&jn(this.skin)}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}},$a={default:"light",cyber:"dark",genshin:"light",fallout:"dark",prts:"dark",bluearchive:"dark",zzz:"dark",dragonball:"light",ikun:"dark"};function Sa(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var ce=new Xt;function t(e,n){return ce.t(e,n)}function r(e){return e.replace(/[&<>"']/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[n])}function Le(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 Fn=[{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 Gn(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}=Fn[n%Fn.length];return`--c1:${s};--c2:${a}`}var Tt=new Map,Lt=new Map;function Ta(e,n){return n?Tt.get(n):e?Lt.get(String(e)):void 0}function ye(e){let n=e.name??"",o=e.avatarUrl??Ta(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>`:"",l=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="${Gn(n)}" aria-hidden="true">${l}${i}</span>`}function La(e){return e?Mt.get(e):void 0}function zn(e){let n=e.name??e.chatId??"",o=e.avatarUrl??La(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="${Gn(n)}" aria-hidden="true">${i}</span>`}var rt=new Map,It=new Map,Mt=new Map,Qt=null,_n="botmux.avatarCache.v1";function Ia(){try{let e=typeof window<"u"?window.localStorage.getItem(_n):null;if(!e)return;let n=JSON.parse(e);for(let[o,s]of Object.entries(n.botByAppId??{}))Tt.set(o,s);for(let[o,s]of Object.entries(n.botByName??{}))Lt.set(o,s);for(let[o,s]of Object.entries(n.chatById??{}))Mt.set(o,s);for(let[o,s]of Object.entries(n.nameByAppId??{}))rt.set(o,s);for(let[o,s]of Object.entries(n.chatNameById??{}))It.set(o,s)}catch{}}function Ma(){try{if(typeof window>"u")return;window.localStorage.setItem(_n,JSON.stringify({botByAppId:Object.fromEntries(Tt),botByName:Object.fromEntries(Lt),chatById:Object.fromEntries(Mt),nameByAppId:Object.fromEntries(rt),chatNameById:Object.fromEntries(It)}))}catch{}}Ia();function Ee(){return Qt??=(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&&rt.set(o.larkAppId,String(o.botName)),o.botAvatarUrl&&(o.larkAppId&&Tt.set(o.larkAppId,String(o.botAvatarUrl)),o.botName&&Lt.set(String(o.botName),String(o.botAvatarUrl)));for(let o of n.chats??[])o.chatId&&o.name&&It.set(o.chatId,String(o.name)),o.chatId&&o.avatar&&Mt.set(o.chatId,String(o.avatar));Ma()}catch{Qt=null}})(),Qt}function Wn(e){return e?rt.get(e):void 0}function He(e){let n=e.larkAppId?rt.get(e.larkAppId):void 0;return n||(e.botName&&e.botName!==e.larkAppId?String(e.botName):String(e.botName??e.larkAppId??"-"))}function Ve(e){return e.chatId&&It.get(e.chatId)||null}function Oe(e){let n=String(e??"");return n.replace(/^(?:@\S+\s*)+/,"").trim()||n}function Ye(e){return`<div class="page-loading" role="status"><i class="page-loading-spin" aria-hidden="true"></i>${r(e??t("common.loading"))}</div>`}function Pe(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 ue(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 Vn={chats:[],bots:[]};async function xa(){try{let e=await fetch("/api/groups");if(!e.ok)return;Vn=await e.json()}catch{}}var Zt=new Set(["working","analyzing","active","starting"]);function Ea(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 Vn.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 l=o(i);a.botName&&(l.botName===l.larkAppId||!l.botName)&&(l.botName=a.botName),l.sessions.push(a),a.cliId&&l.cliId==="unknown"&&(l.cliId=a.cliId),l.lastActiveAt=Math.max(l.lastActiveAt,Number(a.lastMessageAt??0)),a.status!=="closed"&&(l.active.push(a),Zt.has(a.status)&&l.busy.push(a),Pe(a)&&l.attention.push(a))}for(let a of n.values())if(a.botName===a.larkAppId){let i=Wn(a.larkAppId);i&&(a.botName=i)}return[...n.values()].sort((a,i)=>{let l=c=>c.attention.length?0:c.busy.length?1:c.online||c.active.length?2:3;return l(a)!==l(i)?l(a)-l(i):i.lastActiveAt-a.lastActiveAt})}var Yn="botmux.overview.teamExpanded",Ha=230,Jn=13,Kn=2;function Ca(e){let n=e.clientWidth;return n?Math.max(1,Math.floor((n+Jn)/(Ha+Jn)))*Kn:Kn*3}function Aa(){try{return window.localStorage.getItem(Yn)==="1"}catch{return!1}}function Da(e){try{window.localStorage.setItem(Yn,e?"1":"0")}catch{}}function Ra(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 c=[...e.attention].sort((h,b)=>ue(h)-ue(b))[0];i=`<b>${r((Oe(c.title)||c.sessionId).slice(0,60))}</b> \xB7 ${r(Pe(c)??"")}`}else if(s){let c=[...e.busy].sort((h,b)=>Number(b.lastMessageAt??0)-Number(h.lastMessageAt??0))[0];i=`<b>${r((Oe(c.title)||c.sessionId).slice(0,60))}</b>`}else n?i=r(t("overview.botOffline")):i=r(t("overview.botIdle"));let l=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":""}">
14
14
  <div class="mate-top">
15
15
  ${ye({name:e.botName,larkAppId:e.larkAppId,avatarUrl:e.botAvatarUrl,dot:a})}
16
16
  <div class="mate-id">
@@ -23,31 +23,31 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
23
23
  ${l}
24
24
  <span>${e.lastActiveAt?r(t("overview.lastActive",{time:Le(e.lastActiveAt)})):r(t("common.never"))}</span>
25
25
  </div>
26
- </article>`}function Ia(e){let n=He(e);return`<article class="qcard" data-id="${r(e.sessionId)}">
26
+ </article>`}function Oa(e){let n=He(e);return`<article class="qcard" data-id="${r(e.sessionId)}">
27
27
  ${ye({name:n,larkAppId:e.larkAppId,size:"sm"})}
28
28
  <div class="qcard-tx">
29
29
  <b>${r(n)} \xB7 ${r((Oe(e.title)||e.sessionId).slice(0,56))}</b>
30
30
  <span>${r(Pe(e)??"")} \xB7 ${Le(ue(e))}</span>
31
31
  </div>
32
32
  <a class="qcard-go" href="#/sessions">${r(t("strip.handle"))}</a>
33
- </article>`}function Ma(e){let n=He(e);return`<li class="sess-row">
33
+ </article>`}function Ba(e){let n=He(e);return`<li class="sess-row">
34
34
  ${ye({name:n,larkAppId:e.larkAppId,size:"sm"})}
35
35
  <div class="sess-tx">
36
36
  <b>${r((Oe(e.title)||e.sessionId).slice(0,64))}</b>
37
37
  <span>${r(n)} \xB7 ${r(Ve(e)??e.cliId??"unknown")} \xB7 ${Le(e.lastMessageAt)}</span>
38
38
  </div>
39
39
  <span class="status status-${r(e.status??"unknown")}">${r(e.status??"unknown")}</span>
40
- </li>`}function xa(e){let n=e.nextRunAt?new Date(e.nextRunAt).toLocaleString():"-";return`<li class="overview-list-row">
40
+ </li>`}function Na(e){let n=e.nextRunAt?new Date(e.nextRunAt).toLocaleString():"-";return`<li class="overview-list-row">
41
41
  <div>
42
42
  <strong>${r(e.name??e.id)}</strong>
43
43
  <span>${r(He(e))} \xB7 ${r(e.parsed?.display??"")}</span>
44
44
  </div>
45
45
  <span>${r(n)}</span>
46
- </li>`}function Ea(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>
46
+ </li>`}function Pa(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
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
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
49
  <div class="donut-center"><b>${s}</b><span>${r(t("overview.openSessions"))}</span></div>
50
- </div>`}async function Wn(e){e.innerHTML=`<section class="page hero-page">
50
+ </div>`}async function Qn(e){e.innerHTML=`<section class="page hero-page">
51
51
  <div class="page-heading">
52
52
  <div>
53
53
  <p class="eyebrow">${t("app.subtitle")}</p>
@@ -62,6 +62,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
62
62
  <a href="#/bot-defaults">${t("overview.viewAll")}</a>
63
63
  </div>
64
64
  <div class="team-grid" id="team-grid"></div>
65
+ <button type="button" class="team-toggle" id="team-toggle" hidden></button>
65
66
 
66
67
  <div class="sect-head" id="attention-head">
67
68
  <h2>${t("overview.attention")}</h2><span>${t("overview.attentionHint")}</span>
@@ -101,25 +102,25 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
101
102
  </section>
102
103
  </div>
103
104
  </div>
104
- </section>`;let n=e.querySelector("#overview-pills"),o=e.querySelector("#team-grid"),s=e.querySelector("#attention-list"),a=e.querySelector("#recent-sessions"),i=e.querySelector("#today-donut"),l=e.querySelector("#next-schedules");function c(){let w=[...Q.sessions.values()],h=w.filter(v=>v.status!=="closed"),y=h.filter(v=>Pe(v)).sort((v,d)=>ue(v)-ue(d)),k=h.filter(v=>Yt.has(v.status)&&!Pe(v)),p=h.length-y.length-k.length,E=Ta(w),O=E.filter(v=>v.online||v.active.length>0).length;n.innerHTML=`
105
- <span class="pill">${r(t("overview.workingSessions"))} <b>${k.length}</b></span>
106
- <span class="pill${y.length?" pill-hot":""}">${r(t("overview.attention"))} <b>${y.length}</b></span>
107
- <span class="pill">${r(t("overview.onlineBots"))} <b>${O}</b></span>`,o.innerHTML=E.length?E.map(La).join(""):`<div class="empty">${t("overview.noSessions")}</div>`,s.innerHTML=y.length?y.map(Ia).join(""):`<div class="qcard qcard-empty">${t("overview.noAttention")}</div>`;let T=h.filter(v=>Yt.has(v.status)||v.status==="idle").sort((v,d)=>Number(d.lastMessageAt??0)-Number(v.lastMessageAt??0)).slice(0,7);a.innerHTML=T.length?T.map(Ma).join(""):`<li class="empty">${t("overview.noSessions")}</li>`,i.innerHTML=`${Ea(k.length,y.length,Math.max(0,p))}
105
+ </section>`;let n=e.querySelector("#overview-pills"),o=e.querySelector("#team-grid"),s=e.querySelector("#team-toggle"),a=Aa();s.onclick=()=>{a=!a,Da(a),b()};let i=e.querySelector("#attention-list"),l=e.querySelector("#recent-sessions"),c=e.querySelector("#today-donut"),h=e.querySelector("#next-schedules");function b(){let k=[...ee.sessions.values()],m=k.filter(y=>y.status!=="closed"),D=m.filter(y=>Pe(y)).sort((y,H)=>ue(y)-ue(H)),E=m.filter(y=>Zt.has(y.status)&&!Pe(y)),C=m.length-D.length-E.length,w=Ea(k),$=w.filter(y=>y.online||y.active.length>0).length;n.innerHTML=`
106
+ <span class="pill">${r(t("overview.workingSessions"))} <b>${E.length}</b></span>
107
+ <span class="pill${D.length?" pill-hot":""}">${r(t("overview.attention"))} <b>${D.length}</b></span>
108
+ <span class="pill">${r(t("overview.onlineBots"))} <b>${$}</b></span>`;let d=Ca(o),g=a?w:w.slice(0,d);o.innerHTML=g.length?g.map(Ra).join(""):`<div class="empty">${t("overview.noSessions")}</div>`,w.length>d?(s.hidden=!1,s.textContent=a?t("overview.teamCollapse"):t("overview.teamExpand",{count:w.length})):s.hidden=!0,i.innerHTML=D.length?D.map(Oa).join(""):`<div class="qcard qcard-empty">${t("overview.noAttention")}</div>`;let M=m.filter(y=>Zt.has(y.status)||y.status==="idle").sort((y,H)=>Number(H.lastMessageAt??0)-Number(y.lastMessageAt??0)).slice(0,7);l.innerHTML=M.length?M.map(Ba).join(""):`<li class="empty">${t("overview.noSessions")}</li>`,c.innerHTML=`${Pa(E.length,D.length,Math.max(0,C))}
108
109
  <div class="donut-legend">
109
- <span><i style="background:var(--accent)"></i>${r(t("overview.workingSessions"))} ${k.length}</span>
110
- <span><i style="background:var(--warning)"></i>${r(t("overview.attention"))} ${y.length}</span>
111
- <span><i style="background:var(--success)"></i>${r(t("sessions.board.idle"))} ${Math.max(0,p)}</span>
112
- </div>`;let f=[...Q.schedules.values()].filter(v=>v.nextRunAt).sort((v,d)=>Date.parse(v.nextRunAt)-Date.parse(d.nextRunAt)).slice(0,5);l.innerHTML=f.length?f.map(xa).join(""):`<li class="empty">${t("overview.noSchedules")}</li>`}Q.on(c),c(),Sa().then(c),Ee().then(c)}function Ce(e,n){return`<th data-sort="${e}" data-label="${r(n)}">${r(n)}</th>`}function Xt(e){return typeof e=="number"&&Number.isFinite(e)?e:null}function Jn(e){let n=Xt(e);return n===null?"-":n.toLocaleString("en-US")}var Xn=["claude-code","seed","codex","codex-app","cursor","gemini","opencode","mtr","hermes","mira","pi","copilot","aiden","coco","oh-my-pi","unknown"],Kn=[{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"}];function Ha(e){return String(e??"unknown").toLowerCase().replace(/[^a-z0-9_-]/g,"-")}function Ca(e){let n=String(e??"").trim();return n?n.replace(/\\/g,"/").split("/").filter(Boolean).at(-1)??n:"-"}function Vn(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 Ye={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>'};function Qt(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 Yn(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"))}">${Ye.terminal}</a>`;if(!ce.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"))}">${Ye.key}</button>`;return`<span class="term-pill">${n}${o}</span>`}async function Qn(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 Aa(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 Da(){return`<details class="filter-cli">
110
+ <span><i style="background:var(--accent)"></i>${r(t("overview.workingSessions"))} ${E.length}</span>
111
+ <span><i style="background:var(--warning)"></i>${r(t("overview.attention"))} ${D.length}</span>
112
+ <span><i style="background:var(--success)"></i>${r(t("sessions.board.idle"))} ${Math.max(0,C)}</span>
113
+ </div>`;let L=[...ee.schedules.values()].filter(y=>y.nextRunAt).sort((y,H)=>Date.parse(y.nextRunAt)-Date.parse(H.nextRunAt)).slice(0,5);h.innerHTML=L.length?L.map(Na).join(""):`<li class="empty">${t("overview.noSchedules")}</li>`}let v=()=>{if(!document.body.contains(o)){window.removeEventListener("resize",v);return}a||b()};window.addEventListener("resize",v),ee.on(b),b(),xa().then(b),Ee().then(b)}function Ce(e,n){return`<th data-sort="${e}" data-label="${r(n)}">${r(n)}</th>`}function tn(e){return typeof e=="number"&&Number.isFinite(e)?e:null}function Xn(e){let n=tn(e);return n===null?"-":n.toLocaleString("en-US")}var oo=["claude-code","seed","codex","codex-app","cursor","gemini","opencode","mtr","hermes","mira","pi","copilot","aiden","coco","oh-my-pi","unknown"],Zn=[{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"}];function qa(e){return String(e??"unknown").toLowerCase().replace(/[^a-z0-9_-]/g,"-")}function Ua(e){let n=String(e??"").trim();return n?n.replace(/\\/g,"/").split("/").filter(Boolean).at(-1)??n:"-"}function eo(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 Qe={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>'};function en(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 to(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"))}">${Qe.terminal}</a>`;if(!ce.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"))}">${Qe.key}</button>`;return`<span class="term-pill">${n}${o}</span>`}async function no(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 ja(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 Fa(){return`<details class="filter-cli">
113
114
  <summary>${t("sessions.cli")} \xB7 <b id="cli-filter-count">${t("common.all")}</b></summary>
114
115
  <div class="filter-cli-pop" role="group" aria-label="${t("sessions.cli")}">
115
- ${Xn.map(e=>`
116
+ ${oo.map(e=>`
116
117
  <label class="filter-check">
117
118
  <input type="checkbox" name="cli" value="${r(e)}" checked>
118
119
  <span>${r(e)}</span>
119
120
  </label>
120
121
  `).join("")}
121
122
  </div>
122
- </details>`}function Ra(){return`<section class="page">
123
+ </details>`}function Ga(){return`<section class="page">
123
124
  <div class="page-heading">
124
125
  <div>
125
126
  <p class="eyebrow">${t("nav.sessions")}</p>
@@ -143,7 +144,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
143
144
  <option value="yes">${t("sessions.adoptYes")}</option>
144
145
  <option value="no">${t("sessions.adoptNo")}</option>
145
146
  </select>
146
- ${Da()}
147
+ ${Fa()}
147
148
  <label class="filter-toggle"><input type="checkbox" name="active" checked> <span>${t("sessions.activeOnly")}</span></label>
148
149
  </form>
149
150
  <div id="bulk-bar" class="bulk-bar" hidden>
@@ -170,30 +171,30 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
170
171
  </table>
171
172
  <div id="sessions-board" class="sessions-board" hidden></div>
172
173
  <dialog id="drawer"></dialog>
173
- </section>`}function Zn(e){e.innerHTML=Ra();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"),l=e.querySelector("#bulk-count"),c=e.querySelector("#bulk-close"),w=e.querySelector("#bulk-clear"),h=e.querySelector("#sessions-table"),y=e.querySelector("#sessions-board"),k=e.querySelectorAll("[data-view]"),p=new Set,E="lastMessageAt",O="desc",T=xn(window.localStorage),f=Hn(window.localStorage),v=null,d="",b="",x=!1;function H(){return f.map(u=>Kn.find(g=>g.id===u)).filter(u=>!!u)}function I(u,g){let S=f.indexOf(u),L=S+g;if(S<0||L<0||L>=f.length)return;let M=[...f];M.splice(S,1),M.splice(L,0,u),f=M,jt(window.localStorage,f),V()}function C(u,g){if(u===g)return;let S=f.indexOf(u),L=f.indexOf(g);if(S<0||L<0)return;let M=[...f];M.splice(S,1),M.splice(L,0,u),f=M,jt(window.localStorage,f),V()}function q(u){let g=u.status==="closed",S=p.has(u.sessionId)?"checked":"";return`<tr data-id="${r(u.sessionId)}">
174
- <td><input type="checkbox" class="row-select" ${S} ${g?"disabled":""}></td>
174
+ </section>`}function ao(e){e.innerHTML=Ga();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"),l=e.querySelector("#bulk-count"),c=e.querySelector("#bulk-close"),h=e.querySelector("#bulk-clear"),b=e.querySelector("#sessions-table"),v=e.querySelector("#sessions-board"),k=e.querySelectorAll("[data-view]"),m=new Set,D="lastMessageAt",E="desc",C=Cn(window.localStorage),w=Dn(window.localStorage),$=null,d="",g="",M=!1;function L(){return w.map(u=>Zn.find(f=>f.id===u)).filter(u=>!!u)}function y(u,f){let T=w.indexOf(u),I=T+f;if(T<0||I<0||I>=w.length)return;let x=[...w];x.splice(T,1),x.splice(I,0,u),w=x,zt(window.localStorage,w),X()}function H(u,f){if(u===f)return;let T=w.indexOf(u),I=w.indexOf(f);if(T<0||I<0)return;let x=[...w];x.splice(T,1),x.splice(I,0,u),w=x,zt(window.localStorage,w),X()}function A(u){let f=u.status==="closed",T=m.has(u.sessionId)?"checked":"";return`<tr data-id="${r(u.sessionId)}">
175
+ <td><input type="checkbox" class="row-select" ${T} ${f?"disabled":""}></td>
175
176
  <td>${r(He(u))}</td>
176
- <td><span class="badge cli-${Ha(u.cliId)}">${r(u.cliId??"unknown")}</span></td>
177
+ <td><span class="badge cli-${qa(u.cliId)}">${r(u.cliId??"unknown")}</span></td>
177
178
  <td><span class="status status-${r(u.status??"unknown")}">${r(u.status??"unknown")}</span></td>
178
- <td class="token-cell">${Jn(u.tokenUsage?.in)}</td>
179
- <td class="token-cell">${Jn(u.tokenUsage?.out)}</td>
179
+ <td class="token-cell">${Xn(u.tokenUsage?.in)}</td>
180
+ <td class="token-cell">${Xn(u.tokenUsage?.out)}</td>
180
181
  <td title="${r(String(u.title??""))}">${r(Oe(u.title??"").slice(0,48))}</td>
181
182
  <td title="${r(u.workingDir??"")}">${r((u.workingDir??"").slice(-34))}</td>
182
183
  <td>${Le(u.spawnedAt)}</td>
183
184
  <td>${Le(u.lastMessageAt)}</td>
184
185
  <td>${u.adopt?'<span class="badge">adopt</span>':""}</td>
185
186
  <td><button class="open" type="button">${t("sessions.details")}</button></td>
186
- </tr>`}function F(u){if(u.scope!=="chat"||!u.feishuChatLink)return null;let g=t("sessions.openChat");return`<a class="card-act" href="${r(u.feishuChatLink)}" target="_blank" rel="noopener" title="${r(g)}" aria-label="${r(g)}">${Ye.openChat}</a>`}function ie(u){return u.agentAttention?.reason?u.agentAttention.reason:u.agentAttention?t("sessions.board.signalAgent"):u.pendingRepo?t("sessions.board.signalRepo"):u.tuiPromptActive?t("sessions.board.signalPrompt"):u.status==="limited"?t("sessions.board.signalLimited"):""}function te(u){let g=p.has(u.sessionId),S=Oe(u.title)||u.sessionId,L=He(u),M=Ve(u),U=Vn(u),G=ie(u),X=Ca(u.workingDir);return`<article class="session-card${g?" selected":""}" data-id="${r(u.sessionId)}" aria-pressed="${g}">
187
+ </tr>`}function B(u){if(u.scope!=="chat"||!u.feishuChatLink)return null;let f=t("sessions.openChat");return`<a class="card-act" href="${r(u.feishuChatLink)}" target="_blank" rel="noopener" title="${r(f)}" aria-label="${r(f)}">${Qe.openChat}</a>`}function Y(u){return u.agentAttention?.reason?u.agentAttention.reason:u.agentAttention?t("sessions.board.signalAgent"):u.pendingRepo?t("sessions.board.signalRepo"):u.tuiPromptActive?t("sessions.board.signalPrompt"):u.status==="limited"?t("sessions.board.signalLimited"):""}function _(u){let f=m.has(u.sessionId),T=Oe(u.title)||u.sessionId,I=He(u),x=Ve(u),j=eo(u),G=Y(u),te=Ua(u.workingDir);return`<article class="session-card${f?" selected":""}" data-id="${r(u.sessionId)}" aria-pressed="${f}">
187
188
  <div class="session-card-top">
188
- ${ye({name:L,larkAppId:u.larkAppId,size:"sm"})}
189
+ ${ye({name:I,larkAppId:u.larkAppId,size:"sm"})}
189
190
  <div class="session-card-title">
190
- <strong title="${r(String(u.title??S))}">${r(String(S).slice(0,72))}</strong>
191
- <span>${r(L)} \xB7 ${r(M??u.cliId??"unknown")}</span>
191
+ <strong title="${r(String(u.title??T))}">${r(String(T).slice(0,72))}</strong>
192
+ <span>${r(I)} \xB7 ${r(x??u.cliId??"unknown")}</span>
192
193
  </div>
193
194
  <span class="status status-${r(u.status??"unknown")}">${r(u.status??"unknown")}</span>
194
195
  </div>
195
- ${X!=="-"||u.adopt?`<div class="session-card-meta">
196
- ${X!=="-"?`<span title="${r(u.workingDir??"")}">${r(X)}</span>`:""}
196
+ ${te!=="-"||u.adopt?`<div class="session-card-meta">
197
+ ${te!=="-"?`<span title="${r(u.workingDir??"")}">${r(te)}</span>`:""}
197
198
  ${u.adopt?'<span class="badge">adopt</span>':""}
198
199
  </div>`:""}
199
200
  <div class="session-card-time">
@@ -201,31 +202,31 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
201
202
  </div>
202
203
  ${G?`<div class="session-signal" title="${r(G)}">${r(G)}</div>`:""}
203
204
  <div class="session-card-actions">
204
- ${F(u)??Qt("locate",Ye.pin,t("sessions.locate"))}
205
- ${Qt("details",Ye.details,t("sessions.details"))}
206
- ${Yn(U)}
207
- ${Qt("close",Ye.close,t("sessions.close"),"danger")}
205
+ ${B(u)??en("locate",Qe.pin,t("sessions.locate"))}
206
+ ${en("details",Qe.details,t("sessions.details"))}
207
+ ${to(j)}
208
+ ${en("close",Qe.close,t("sessions.close"),"danger")}
208
209
  </div>
209
- </article>`}function he(u,g,S){let L=S==="needs-you"?ue(u):Number(u.lastMessageAt??0),M=S==="needs-you"?ue(g):Number(g.lastMessageAt??0);return L!==M?S==="needs-you"?L-M:M-L:String(u.title??u.sessionId).localeCompare(String(g.title??g.sessionId))}function ne(u){let g=new Map(Kn.map(M=>[M.id,[]]));for(let M of u){let U=Aa(M);U&&g.get(U).push(M)}let S=H(),L=S.map((M,U)=>{let G=(g.get(M.id)??[]).sort((X,z)=>he(X,z,M.id));return`<section class="session-board-column session-board-${M.id}" data-col="${M.id}">
210
+ </article>`}function me(u,f,T){let I=T==="needs-you"?ue(u):Number(u.lastMessageAt??0),x=T==="needs-you"?ue(f):Number(f.lastMessageAt??0);return I!==x?T==="needs-you"?I-x:x-I:String(u.title??u.sessionId).localeCompare(String(f.title??f.sessionId))}function $e(u){let f=new Map(Zn.map(x=>[x.id,[]]));for(let x of u){let j=ja(x);j&&f.get(j).push(x)}let T=L(),I=T.map((x,j)=>{let G=(f.get(x.id)??[]).sort((te,z)=>me(te,z,x.id));return`<section class="session-board-column session-board-${x.id}" data-col="${x.id}">
210
211
  <header draggable="true" title="${r(t("sessions.board.dragHint"))}">
211
212
  <div>
212
- <h2>${r(t(M.labelKey))}</h2>
213
- <p>${r(t(M.hintKey))}</p>
213
+ <h2>${r(t(x.labelKey))}</h2>
214
+ <p>${r(t(x.hintKey))}</p>
214
215
  </div>
215
216
  <span class="session-board-head-right">
216
217
  <span class="session-board-move">
217
- <button type="button" data-move-col="${M.id}" data-dir="-1"
218
- aria-label="${r(t("sessions.board.moveLeft"))}" ${U===0?"disabled":""}>\u2039</button>
219
- <button type="button" data-move-col="${M.id}" data-dir="1"
220
- aria-label="${r(t("sessions.board.moveRight"))}" ${U===S.length-1?"disabled":""}>\u203A</button>
218
+ <button type="button" data-move-col="${x.id}" data-dir="-1"
219
+ aria-label="${r(t("sessions.board.moveLeft"))}" ${j===0?"disabled":""}>\u2039</button>
220
+ <button type="button" data-move-col="${x.id}" data-dir="1"
221
+ aria-label="${r(t("sessions.board.moveRight"))}" ${j===T.length-1?"disabled":""}>\u203A</button>
221
222
  </span>
222
223
  <span class="session-board-count">${G.length}</span>
223
224
  </span>
224
225
  </header>
225
226
  <div class="session-board-list">
226
- ${G.length?G.map(te).join(""):`<div class="session-board-empty">${t("sessions.board.emptyColumn")}</div>`}
227
+ ${G.length?G.map(_).join(""):`<div class="session-board-empty">${t("sessions.board.emptyColumn")}</div>`}
227
228
  </div>
228
- </section>`}).join("");L!==d&&(d=L,y.innerHTML=L,y.classList.toggle("board-enter",!x),x=!0)}function le(){let u=new FormData(o),g=(u.get("q")??"").toLowerCase(),S=u.getAll("cli"),L=S.length>0&&S.length<Xn.length,M=u.get("status"),U=u.get("adopt"),G=!!u.get("active"),X=[...Q.sessions.values()].filter(z=>!L||S.includes(z.cliId??"unknown")).filter(z=>!M||z.status===M).filter(z=>!U||U==="yes"==!!z.adopt).filter(z=>!G||z.status!=="closed").filter(z=>!g||JSON.stringify(z).toLowerCase().includes(g));return X.sort($e),X}function me(u,g){return g==="spawnedAt"||g==="lastMessageAt"?Number(u[g]??0):g==="tokenIn"?Xt(u.tokenUsage?.in)??-1:g==="tokenOut"?Xt(u.tokenUsage?.out)??-1:g==="adopt"?!!u.adopt:String(u[g]??"").toLowerCase()}function $e(u,g){let S=me(u,E),L=me(g,E),M=0;return typeof S=="number"&&typeof L=="number"?M=S-L:typeof S=="boolean"&&typeof L=="boolean"?M=Number(S)-Number(L):M=String(S).localeCompare(String(L)),M===0&&(M=Number(u.lastMessageAt??0)-Number(g.lastMessageAt??0)),O==="asc"?M:-M}function Ne(){h.querySelectorAll("th[data-sort]").forEach(u=>{let g=u.dataset.sort===E;u.classList.toggle("sorted",g),u.setAttribute("aria-sort",g?O==="asc"?"ascending":"descending":"none");let S=u.dataset.label??u.textContent?.trim()??"";u.textContent=g?`${S} ${O==="asc"?"\u25B2":"\u25BC"}`:S})}function Se(u){i.hidden=p.size===0,l.textContent=t("sessions.selectedCount",{count:p.size});let g=u.filter(L=>L.status!=="closed");if(g.length===0){a.checked=!1,a.indeterminate=!1,a.disabled=!0;return}a.disabled=!1;let S=g.filter(L=>p.has(L.sessionId)).length;a.checked=S===g.length,a.indeterminate=S>0&&S<g.length}function ae(){k.forEach(u=>{let g=u.dataset.view===T;u.classList.toggle("active",g),u.setAttribute("aria-pressed",String(g))})}function re(){let u=o.querySelector("#cli-filter-count");if(!u)return;let g=[...o.querySelectorAll('input[name="cli"]')],S=g.filter(L=>L.checked).length;u.textContent=S===g.length?t("common.all"):`${S}/${g.length}`,u.classList.toggle("cli-filter-active",S!==g.length)}function V(){let u=le();for(let L of[...p]){let M=Q.sessions.get(L);(!M||M.status==="closed")&&p.delete(L)}let g=u.filter(L=>L.status!=="closed"),S=T==="board"?g:u;if(h.hidden=T!=="table",y.hidden=T!=="board",T==="table"){let L=u.length?u.map(q).join(""):`<tr><td colspan="12" class="empty">${t("sessions.empty")}</td></tr>`;L!==b&&(b=L,n.innerHTML=L)}else ne(g);ae(),Ne(),re(),Se(S)}async function Ie(u,g){g&&(g.disabled=!0,g.textContent=t("sessions.locating"));try{let S=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/locate`,{method:"POST"}),L=await S.json();if(L.ok){if(!g)return;let M=30;g.textContent=t("sessions.cooldown",{seconds:M});let U=setInterval(()=>{M-=1,M<=0?(clearInterval(U),g.disabled=!1,g.textContent=t("sessions.locate")):g.textContent=t("sessions.cooldown",{seconds:M})},1e3)}else alert(`Locate failed: ${L.error??S.status}`),g&&(g.disabled=!1,g.textContent=t("sessions.locate"))}catch(S){alert(`Locate error: ${S}`),g&&(g.disabled=!1,g.textContent=t("sessions.locate"))}}async function Me(u,g){if(!confirm(t("sessions.closeConfirm")))return!1;g&&(g.disabled=!0);try{let S=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/close`,{method:"POST"}),L=await S.json().catch(()=>({}));return!S.ok||L?.ok===!1?(S.status!==401&&alert(`Close failed: ${L?.error??S.status}`),!1):!0}catch(S){return alert(`Close error: ${S}`),!1}finally{g&&(g.disabled=!1)}}function se(u){let g=u.status==="closed",S=Vn(u);s.innerHTML=`<article>
229
+ </section>`}).join("");I!==d&&(d=I,v.innerHTML=I,v.classList.toggle("board-enter",!M),M=!0)}function re(){let u=new FormData(o),f=(u.get("q")??"").toLowerCase(),T=u.getAll("cli"),I=T.length>0&&T.length<oo.length,x=u.get("status"),j=u.get("adopt"),G=!!u.get("active"),te=[...ee.sessions.values()].filter(z=>!I||T.includes(z.cliId??"unknown")).filter(z=>!x||z.status===x).filter(z=>!j||j==="yes"==!!z.adopt).filter(z=>!G||z.status!=="closed").filter(z=>!f||JSON.stringify(z).toLowerCase().includes(f));return te.sort(fe),te}function Q(u,f){return f==="spawnedAt"||f==="lastMessageAt"?Number(u[f]??0):f==="tokenIn"?tn(u.tokenUsage?.in)??-1:f==="tokenOut"?tn(u.tokenUsage?.out)??-1:f==="adopt"?!!u.adopt:String(u[f]??"").toLowerCase()}function fe(u,f){let T=Q(u,D),I=Q(f,D),x=0;return typeof T=="number"&&typeof I=="number"?x=T-I:typeof T=="boolean"&&typeof I=="boolean"?x=Number(T)-Number(I):x=String(T).localeCompare(String(I)),x===0&&(x=Number(u.lastMessageAt??0)-Number(f.lastMessageAt??0)),E==="asc"?x:-x}function Ne(){b.querySelectorAll("th[data-sort]").forEach(u=>{let f=u.dataset.sort===D;u.classList.toggle("sorted",f),u.setAttribute("aria-sort",f?E==="asc"?"ascending":"descending":"none");let T=u.dataset.label??u.textContent?.trim()??"";u.textContent=f?`${T} ${E==="asc"?"\u25B2":"\u25BC"}`:T})}function Se(u){i.hidden=m.size===0,l.textContent=t("sessions.selectedCount",{count:m.size});let f=u.filter(I=>I.status!=="closed");if(f.length===0){a.checked=!1,a.indeterminate=!1,a.disabled=!0;return}a.disabled=!1;let T=f.filter(I=>m.has(I.sessionId)).length;a.checked=T===f.length,a.indeterminate=T>0&&T<f.length}function se(){k.forEach(u=>{let f=u.dataset.view===C;u.classList.toggle("active",f),u.setAttribute("aria-pressed",String(f))})}function le(){let u=o.querySelector("#cli-filter-count");if(!u)return;let f=[...o.querySelectorAll('input[name="cli"]')],T=f.filter(I=>I.checked).length;u.textContent=T===f.length?t("common.all"):`${T}/${f.length}`,u.classList.toggle("cli-filter-active",T!==f.length)}function X(){let u=re();for(let I of[...m]){let x=ee.sessions.get(I);(!x||x.status==="closed")&&m.delete(I)}let f=u.filter(I=>I.status!=="closed"),T=C==="board"?f:u;if(b.hidden=C!=="table",v.hidden=C!=="board",C==="table"){let I=u.length?u.map(A).join(""):`<tr><td colspan="12" class="empty">${t("sessions.empty")}</td></tr>`;I!==g&&(g=I,n.innerHTML=I)}else $e(f);se(),Ne(),le(),Se(T)}async function Ie(u,f){f&&(f.disabled=!0,f.textContent=t("sessions.locating"));try{let T=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/locate`,{method:"POST"}),I=await T.json();if(I.ok){if(!f)return;let x=30;f.textContent=t("sessions.cooldown",{seconds:x});let j=setInterval(()=>{x-=1,x<=0?(clearInterval(j),f.disabled=!1,f.textContent=t("sessions.locate")):f.textContent=t("sessions.cooldown",{seconds:x})},1e3)}else alert(`Locate failed: ${I.error??T.status}`),f&&(f.disabled=!1,f.textContent=t("sessions.locate"))}catch(T){alert(`Locate error: ${T}`),f&&(f.disabled=!1,f.textContent=t("sessions.locate"))}}async function Me(u,f){if(!confirm(t("sessions.closeConfirm")))return!1;f&&(f.disabled=!0);try{let T=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/close`,{method:"POST"}),I=await T.json().catch(()=>({}));return!T.ok||I?.ok===!1?(T.status!==401&&alert(`Close failed: ${I?.error??T.status}`),!1):!0}catch(T){return alert(`Close error: ${T}`),!1}finally{f&&(f.disabled=!1)}}function ie(u){let f=u.status==="closed",T=eo(u);s.innerHTML=`<article>
229
230
  <header>
230
231
  <h3>${r(Oe(u.title)||u.sessionId)}</h3>
231
232
  <span class="status status-${r(u.status??"unknown")}">${r(u.status??"unknown")}</span>
@@ -238,22 +239,22 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
238
239
  ${u.threadId?`<p><b>threadId:</b> <code>${r(u.threadId)}</code></p>`:""}
239
240
  <p><b>${t("sessions.workingDir")}:</b> ${r(u.workingDir??"-")}</p>
240
241
  <div class="actions">
241
- ${F(u)??`<button id="locate-btn" type="button">${t("sessions.locate")}</button>`}
242
- ${Yn(S)}
243
- ${g?`<button id="resume-btn" type="button" class="primary">${t("sessions.resume")}</button>`:""}
244
- ${g?"":`<button id="close-btn" type="button" class="contrast">${t("sessions.close")}</button>`}
242
+ ${B(u)??`<button id="locate-btn" type="button">${t("sessions.locate")}</button>`}
243
+ ${to(T)}
244
+ ${f?`<button id="resume-btn" type="button" class="primary">${t("sessions.resume")}</button>`:""}
245
+ ${f?"":`<button id="close-btn" type="button" class="contrast">${t("sessions.close")}</button>`}
245
246
  <button id="land-btn" type="button">${t("sessions.land")}</button>
246
247
  </div>
247
248
  <div id="land-area"></div>
248
249
  <form method="dialog"><button>${t("sessions.dismiss")}</button></form>
249
- </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 L=s.querySelector("#locate-btn");L&&(L.onclick=()=>{Ie(u,L)});let M=s.querySelector(".term-write");M&&(M.onclick=()=>{Qn(u,M)});let U=s.querySelector("#resume-btn");U&&(U.onclick=async()=>{U.disabled=!0;try{let ee=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/resume`,{method:"POST"}),oe=await ee.json().catch(()=>({}));if(!ee.ok||oe.ok===!1){alert(`${t("sessions.resumeFailed")}: ${oe?.error??ee.status}`),U.disabled=!1;return}s.close()}catch(ee){alert(`${t("sessions.resumeFailed")}: ${ee}`),U.disabled=!1}});let G=s.querySelector("#close-btn");G&&(G.onclick=async()=>{await Me(u,G)&&s.close()});let X=s.querySelector("#land-btn"),z=s.querySelector("#land-area");X&&z&&(X.onclick=async()=>{X.disabled=!0,z.innerHTML=`<p>${t("sessions.landLoading")}</p>`;try{let ee=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/sandbox-diff`),oe=await ee.json().catch(()=>({}));if(!oe.ok){z.innerHTML=`<p>${t("sessions.landUnavailable")}: ${r(oe.error??String(ee.status))}</p>`,X.disabled=!1;return}if(oe.empty){z.innerHTML=`<p>${t("sessions.landEmpty")}</p>`,X.disabled=!1;return}let W=String(oe.patch??""),xe=W.slice(0,2e4)+(W.length>2e4?`
250
+ </article>`,s.querySelectorAll("[data-copy]").forEach(oe=>{oe.onclick=()=>{navigator.clipboard.writeText(oe.dataset.copy??""),oe.textContent=t("sessions.copied"),setTimeout(()=>{oe.textContent=t("sessions.copy")},800)}});let I=s.querySelector("#locate-btn");I&&(I.onclick=()=>{Ie(u,I)});let x=s.querySelector(".term-write");x&&(x.onclick=()=>{no(u,x)});let j=s.querySelector("#resume-btn");j&&(j.onclick=async()=>{j.disabled=!0;try{let oe=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/resume`,{method:"POST"}),ae=await oe.json().catch(()=>({}));if(!oe.ok||ae.ok===!1){alert(`${t("sessions.resumeFailed")}: ${ae?.error??oe.status}`),j.disabled=!1;return}s.close()}catch(oe){alert(`${t("sessions.resumeFailed")}: ${oe}`),j.disabled=!1}});let G=s.querySelector("#close-btn");G&&(G.onclick=async()=>{await Me(u,G)&&s.close()});let te=s.querySelector("#land-btn"),z=s.querySelector("#land-area");te&&z&&(te.onclick=async()=>{te.disabled=!0,z.innerHTML=`<p>${t("sessions.landLoading")}</p>`;try{let oe=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/sandbox-diff`),ae=await oe.json().catch(()=>({}));if(!ae.ok){z.innerHTML=`<p>${t("sessions.landUnavailable")}: ${r(ae.error??String(oe.status))}</p>`,te.disabled=!1;return}if(ae.empty){z.innerHTML=`<p>${t("sessions.landEmpty")}</p>`,te.disabled=!1;return}let J=String(ae.patch??""),xe=J.slice(0,2e4)+(J.length>2e4?`
250
251
  \u2026(truncated)`:"");z.innerHTML=`
251
- <p><b>${oe.files}</b> files (+${oe.insertions}/-${oe.deletions}) \u2192 <code>${r(String(oe.workingDir??""))}</code></p>
252
+ <p><b>${ae.files}</b> files (+${ae.insertions}/-${ae.deletions}) \u2192 <code>${r(String(ae.workingDir??""))}</code></p>
252
253
  <pre style="max-height:320px;overflow:auto;white-space:pre-wrap">${r(xe)}</pre>
253
254
  <div class="actions">
254
255
  <button id="land-apply" type="button" class="primary">${t("sessions.landApply")}</button>
255
256
  <button id="land-discard" type="button" class="contrast">${t("sessions.landDiscard")}</button>
256
- </div>`;let we=z.querySelector("#land-apply"),$=z.querySelector("#land-discard");we.onclick=async()=>{we.disabled=!0,$.disabled=!0;let Z=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/sandbox-land/apply`,{method:"POST"}),A=await Z.json().catch(()=>({}));z.innerHTML=A.ok?`<p>\u2705 ${t("sessions.landApplied")}: ${A.files} files (+${A.insertions}/-${A.deletions}) \u2192 <code>${r(String(A.workingDir??""))}</code></p>`:`<p>\u274C ${t("sessions.landFailed")}: ${r(A.error??String(Z.status))}</p>`},$.onclick=async()=>{await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/sandbox-land/discard`,{method:"POST"}),z.innerHTML=`<p>\u{1F5D1} ${t("sessions.landDiscarded")}</p>`}}catch(ee){z.innerHTML=`<p>${t("sessions.landUnavailable")}: ${r(String(ee))}</p>`,X.disabled=!1}}),s.showModal()}n.addEventListener("click",u=>{let g=u.target;if(g.classList.contains("row-select")){let U=g.closest("tr[data-id]");if(!U)return;g.checked?p.add(U.dataset.id):p.delete(U.dataset.id),Se(le());return}let S=g.closest("td");if(S&&S.querySelector(".row-select"))return;let L=g.closest("tr[data-id]");if(!L)return;let M=Q.sessions.get(L.dataset.id);M&&se(M)}),y.addEventListener("click",u=>{let g=u.target,S=g.closest("button[data-move-col]");if(S){I(S.dataset.moveCol,Number(S.dataset.dir));return}let L=g.closest(".session-card[data-id]");if(!L)return;let M=Q.sessions.get(L.dataset.id);if(!M)return;let U=g.closest("button[data-action]");if(U){let G=U.dataset.action;G==="details"?se(M):G==="write-link"?Qn(M,U):G==="locate"?Ie(M,U):G==="close"&&Me(M,U).then(X=>{X&&(p.delete(M.sessionId),V())});return}g.closest("a, button, input, label")||(p.has(M.sessionId)?p.delete(M.sessionId):p.add(M.sessionId),L.classList.toggle("selected",p.has(M.sessionId)),L.setAttribute("aria-pressed",String(p.has(M.sessionId))),Se(le().filter(G=>G.status!=="closed")))}),y.addEventListener("dragstart",u=>{let S=u.target.closest(".session-board-column > header[draggable]")?.closest(".session-board-column");S?.dataset.col&&(v=S.dataset.col,S.classList.add("dragging"),u.dataTransfer&&(u.dataTransfer.effectAllowed="move",u.dataTransfer.setData("text/plain",v)))}),y.addEventListener("dragover",u=>{if(!v)return;u.preventDefault(),u.dataTransfer&&(u.dataTransfer.dropEffect="move");let g=u.target.closest(".session-board-column");y.querySelectorAll(".drag-over").forEach(S=>S.classList.remove("drag-over")),g&&g.dataset.col!==v&&g.classList.add("drag-over")}),y.addEventListener("drop",u=>{if(!v)return;u.preventDefault();let g=u.target.closest(".session-board-column"),S=v;v=null,g?.dataset.col&&C(S,g.dataset.col)}),y.addEventListener("dragend",()=>{v=null,y.querySelectorAll(".drag-over, .dragging").forEach(u=>u.classList.remove("drag-over","dragging"))}),k.forEach(u=>{u.addEventListener("click",()=>{let g=u.dataset.view==="table"?"table":"board";g!==T&&(T=g,Cn(window.localStorage,T),V())})}),a.addEventListener("change",()=>{let u=le().filter(g=>g.status!=="closed");for(let g of u)a.checked?p.add(g.sessionId):p.delete(g.sessionId);V()}),w.addEventListener("click",()=>{p.clear(),V()}),c.addEventListener("click",async()=>{let u=[...p];if(u.length===0||!confirm(t("sessions.closeBulkConfirm",{count:u.length})))return;c.disabled=!0,w.disabled=!0;let g=c.textContent,S=0,L=0,M=[...u];c.textContent=`0/${u.length}`;async function U(){for(;M.length;){let G=M.shift();try{let X=await fetch(`/api/sessions/${encodeURIComponent(G)}/close`,{method:"POST"}),z=await X.json().catch(()=>({}));(!X.ok||z?.ok===!1)&&(L+=1)}catch{L+=1}finally{S+=1,c.textContent=`${S}/${u.length}`}}}await Promise.all(Array.from({length:Math.min(6,u.length)},()=>U())),c.textContent=g,c.disabled=!1,w.disabled=!1,p.clear(),V(),L>0&&alert(`Failed: ${L}/${u.length}`)}),h.querySelectorAll("th[data-sort]").forEach(u=>{u.addEventListener("click",()=>{let g=u.dataset.sort;E===g?O=O==="asc"?"desc":"asc":(E=g,O=g==="spawnedAt"||g==="lastMessageAt"?"desc":"asc"),V()})}),o.addEventListener("input",V),Q.on(V),V(),Ee().then(V)}function Oa(){return`<section class="page">
257
+ </div>`;let we=z.querySelector("#land-apply"),S=z.querySelector("#land-discard");we.onclick=async()=>{we.disabled=!0,S.disabled=!0;let ne=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/sandbox-land/apply`,{method:"POST"}),R=await ne.json().catch(()=>({}));z.innerHTML=R.ok?`<p>\u2705 ${t("sessions.landApplied")}: ${R.files} files (+${R.insertions}/-${R.deletions}) \u2192 <code>${r(String(R.workingDir??""))}</code></p>`:`<p>\u274C ${t("sessions.landFailed")}: ${r(R.error??String(ne.status))}</p>`},S.onclick=async()=>{await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/sandbox-land/discard`,{method:"POST"}),z.innerHTML=`<p>\u{1F5D1} ${t("sessions.landDiscarded")}</p>`}}catch(oe){z.innerHTML=`<p>${t("sessions.landUnavailable")}: ${r(String(oe))}</p>`,te.disabled=!1}}),s.showModal()}n.addEventListener("click",u=>{let f=u.target;if(f.classList.contains("row-select")){let j=f.closest("tr[data-id]");if(!j)return;f.checked?m.add(j.dataset.id):m.delete(j.dataset.id),Se(re());return}let T=f.closest("td");if(T&&T.querySelector(".row-select"))return;let I=f.closest("tr[data-id]");if(!I)return;let x=ee.sessions.get(I.dataset.id);x&&ie(x)}),v.addEventListener("click",u=>{let f=u.target,T=f.closest("button[data-move-col]");if(T){y(T.dataset.moveCol,Number(T.dataset.dir));return}let I=f.closest(".session-card[data-id]");if(!I)return;let x=ee.sessions.get(I.dataset.id);if(!x)return;let j=f.closest("button[data-action]");if(j){let G=j.dataset.action;G==="details"?ie(x):G==="write-link"?no(x,j):G==="locate"?Ie(x,j):G==="close"&&Me(x,j).then(te=>{te&&(m.delete(x.sessionId),X())});return}f.closest("a, button, input, label")||(m.has(x.sessionId)?m.delete(x.sessionId):m.add(x.sessionId),I.classList.toggle("selected",m.has(x.sessionId)),I.setAttribute("aria-pressed",String(m.has(x.sessionId))),Se(re().filter(G=>G.status!=="closed")))}),v.addEventListener("dragstart",u=>{let T=u.target.closest(".session-board-column > header[draggable]")?.closest(".session-board-column");T?.dataset.col&&($=T.dataset.col,T.classList.add("dragging"),u.dataTransfer&&(u.dataTransfer.effectAllowed="move",u.dataTransfer.setData("text/plain",$)))}),v.addEventListener("dragover",u=>{if(!$)return;u.preventDefault(),u.dataTransfer&&(u.dataTransfer.dropEffect="move");let f=u.target.closest(".session-board-column");v.querySelectorAll(".drag-over").forEach(T=>T.classList.remove("drag-over")),f&&f.dataset.col!==$&&f.classList.add("drag-over")}),v.addEventListener("drop",u=>{if(!$)return;u.preventDefault();let f=u.target.closest(".session-board-column"),T=$;$=null,f?.dataset.col&&H(T,f.dataset.col)}),v.addEventListener("dragend",()=>{$=null,v.querySelectorAll(".drag-over, .dragging").forEach(u=>u.classList.remove("drag-over","dragging"))}),k.forEach(u=>{u.addEventListener("click",()=>{let f=u.dataset.view==="table"?"table":"board";f!==C&&(C=f,Rn(window.localStorage,C),X())})}),a.addEventListener("change",()=>{let u=re().filter(f=>f.status!=="closed");for(let f of u)a.checked?m.add(f.sessionId):m.delete(f.sessionId);X()}),h.addEventListener("click",()=>{m.clear(),X()}),c.addEventListener("click",async()=>{let u=[...m];if(u.length===0||!confirm(t("sessions.closeBulkConfirm",{count:u.length})))return;c.disabled=!0,h.disabled=!0;let f=c.textContent,T=0,I=0,x=[...u];c.textContent=`0/${u.length}`;async function j(){for(;x.length;){let G=x.shift();try{let te=await fetch(`/api/sessions/${encodeURIComponent(G)}/close`,{method:"POST"}),z=await te.json().catch(()=>({}));(!te.ok||z?.ok===!1)&&(I+=1)}catch{I+=1}finally{T+=1,c.textContent=`${T}/${u.length}`}}}await Promise.all(Array.from({length:Math.min(6,u.length)},()=>j())),c.textContent=f,c.disabled=!1,h.disabled=!1,m.clear(),X(),I>0&&alert(`Failed: ${I}/${u.length}`)}),b.querySelectorAll("th[data-sort]").forEach(u=>{u.addEventListener("click",()=>{let f=u.dataset.sort;D===f?E=E==="asc"?"desc":"asc":(D=f,E=f==="spawnedAt"||f==="lastMessageAt"?"desc":"asc"),X()})}),o.addEventListener("input",X),ee.on(X),X(),Ee().then(X)}function za(){return`<section class="page">
257
258
  <div class="page-heading">
258
259
  <div>
259
260
  <p class="eyebrow">${t("nav.schedules")}</p>
@@ -278,19 +279,19 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
278
279
  </tr></thead>
279
280
  <tbody id="schedules-tbody"></tbody>
280
281
  </table>
281
- </section>`}function eo(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function to(e){e.innerHTML=Oa();let n=e.querySelector("#schedules-tbody"),o=e.querySelector("#sched-filters");function s(){let i=new FormData(o),l=(i.get("q")??"").toLowerCase(),c=i.get("kind"),w=!!i.get("enabled");return[...Q.schedules.values()].filter(h=>!c||h.parsed?.kind===c).filter(h=>!w||h.enabled).filter(h=>!l||JSON.stringify(h).toLowerCase().includes(l)).sort((h,y)=>{if(h.enabled!==y.enabled)return h.enabled?-1:1;let k=h.nextRunAt?Date.parse(h.nextRunAt):1/0,p=y.nextRunAt?Date.parse(y.nextRunAt):1/0;return k-p})}function a(){n.innerHTML=s().map(i=>`<tr data-id="${r(i.id)}">
282
+ </section>`}function so(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function io(e){e.innerHTML=za();let n=e.querySelector("#schedules-tbody"),o=e.querySelector("#sched-filters");function s(){let i=new FormData(o),l=(i.get("q")??"").toLowerCase(),c=i.get("kind"),h=!!i.get("enabled");return[...ee.schedules.values()].filter(b=>!c||b.parsed?.kind===c).filter(b=>!h||b.enabled).filter(b=>!l||JSON.stringify(b).toLowerCase().includes(l)).sort((b,v)=>{if(b.enabled!==v.enabled)return b.enabled?-1:1;let k=b.nextRunAt?Date.parse(b.nextRunAt):1/0,m=v.nextRunAt?Date.parse(v.nextRunAt):1/0;return k-m})}function a(){n.innerHTML=s().map(i=>`<tr data-id="${r(i.id)}">
282
283
  <td>${r(i.name??i.id)}</td>
283
284
  <td>${r(i.botName??i.larkAppId??"-")}</td>
284
285
  <td><code>${r(i.parsed?.display??"?")}</code></td>
285
- <td>${eo(i.nextRunAt)}</td>
286
- <td>${eo(i.lastRunAt)} ${i.lastStatus==="error"?"\u26A0\uFE0F":""}</td>
286
+ <td>${so(i.nextRunAt)}</td>
287
+ <td>${so(i.lastRunAt)} ${i.lastStatus==="error"?"\u26A0\uFE0F":""}</td>
287
288
  <td>${i.repeat?`${i.repeat.completed}/${i.repeat.times??"\u221E"}`:"\u2014"}</td>
288
289
  <td>${i.enabled?"\u2713":"\u2717"}</td>
289
290
  <td class="actions-cell">
290
291
  <button data-op="run" type="button">${t("schedules.runNow")}</button>
291
292
  ${i.enabled?`<button data-op="pause" type="button">${t("schedules.pause")}</button>`:`<button data-op="resume" type="button">${t("schedules.resume")}</button>`}
292
293
  </td>
293
- </tr>`).join("")||`<tr><td colspan="8" class="empty">${t("schedules.empty")}</td></tr>`}n.addEventListener("click",async i=>{let l=i.target.closest("button[data-op]");if(!l)return;let c=l.closest("tr[data-id]");if(!c)return;let w=c.dataset.id,h=l.dataset.op;l.disabled=!0;let y=l.textContent;l.textContent="...";try{let k=await fetch(`/api/schedules/${encodeURIComponent(w)}/${h}`,{method:"POST"}),p=await k.json().catch(()=>({}));(!k.ok||p.ok===!1)&&alert(`Failed: ${k.status} ${p?.error??""}`.trim())}catch(k){alert("Network error: "+k)}finally{l.disabled=!1,l.textContent=y}}),o.addEventListener("input",a),Q.on(a),a()}var pe={chats:[],bots:[]};function Ba(){return`<section class="page">
294
+ </tr>`).join("")||`<tr><td colspan="8" class="empty">${t("schedules.empty")}</td></tr>`}n.addEventListener("click",async i=>{let l=i.target.closest("button[data-op]");if(!l)return;let c=l.closest("tr[data-id]");if(!c)return;let h=c.dataset.id,b=l.dataset.op;l.disabled=!0;let v=l.textContent;l.textContent="...";try{let k=await fetch(`/api/schedules/${encodeURIComponent(h)}/${b}`,{method:"POST"}),m=await k.json().catch(()=>({}));(!k.ok||m.ok===!1)&&alert(`Failed: ${k.status} ${m?.error??""}`.trim())}catch(k){alert("Network error: "+k)}finally{l.disabled=!1,l.textContent=v}}),o.addEventListener("input",a),ee.on(a),a()}var pe={chats:[],bots:[]};function _a(){return`<section class="page">
294
295
  <div class="page-heading">
295
296
  <div>
296
297
  <p class="eyebrow">${t("nav.groups")}</p>
@@ -304,17 +305,20 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
304
305
  <button type="button" id="g-refresh">${t("groups.refresh")}</button>
305
306
  <button type="button" id="g-create" class="primary">${t("groups.create")}</button>
306
307
  </form>
307
- <table>
308
- <thead id="g-head"></thead>
309
- <tbody id="g-body"></tbody>
310
- </table>
308
+ <div id="g-loading">${Ye()}</div>
309
+ <div class="table-scroll matrix-scroll" id="g-table-wrap" hidden>
310
+ <table>
311
+ <thead id="g-head"></thead>
312
+ <tbody id="g-body"></tbody>
313
+ </table>
314
+ </div>
311
315
  <dialog id="g-drawer"></dialog>
312
- </section>`}async function Qe(){pe=await(await fetch("/api/groups")).json()}async function Na(){return(await fetch("/api/groups")).json()}function Pa(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 no(e,n){return e.filter(o=>!n||!n.has(o.larkAppId)).map(o=>`
316
+ </section>`}async function Xe(){pe=await(await fetch("/api/groups")).json()}async function Wa(){return(await fetch("/api/groups")).json()}function Ja(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 ro(e,n){return e.filter(o=>!n||!n.has(o.larkAppId)).map(o=>`
313
317
  <label class="checkbox-row">
314
318
  <input type="checkbox" name="bot" value="${r(o.larkAppId)}">
315
319
  ${r(o.botName??o.larkAppId)} <small>(${r(o.larkAppId)})</small>
316
320
  </label>
317
- `).join("")}async function oo(e){e.innerHTML=Ba();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 Qe(),y()}finally{a.disabled=!1}};let l=e.querySelector("#g-create");l.onclick=()=>c(),await Qe();function c(){let p=pe.bots;if(p.length===0){alert(t("groups.noBotsOnline"));return}i.innerHTML=`
321
+ `).join("")}async function lo(e){e.innerHTML=_a();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 Xe(),m()}finally{a.disabled=!1}};let l=e.querySelector("#g-create");l.onclick=()=>b();let c=e.querySelector("#g-loading"),h=e.querySelector("#g-table-wrap");try{await Xe()}finally{c.remove(),h.hidden=!1}function b(){let E=pe.bots;if(E.length===0){alert(t("groups.noBotsOnline"));return}i.innerHTML=`
318
322
  <article>
319
323
  <header><h3>${t("groups.createTitle")}</h3></header>
320
324
  <p>${t("groups.createHelp")}</p>
@@ -330,75 +334,75 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
330
334
  </label>
331
335
  <fieldset>
332
336
  <legend>${t("groups.botPicker")}</legend>
333
- ${no(p)}
337
+ ${ro(E)}
334
338
  </fieldset>
335
339
  <div class="actions">
336
340
  <button type="submit" class="primary">${t("groups.createSubmit")}</button>
337
341
  <button type="button" id="g-create-cancel">${t("groups.cancel")}</button>
338
342
  </div>
339
343
  </form>
340
- </article>`,i.showModal(),i.querySelector("#g-create-cancel").onclick=()=>i.close(),i.querySelector("#g-createform").onsubmit=async T=>{T.preventDefault();let f=new FormData(T.target),v=(f.get("name")??"").trim(),d=(f.get("bindWorkingDir")??"").trim(),b=f.getAll("bot");if(b.length===0){alert("Pick at least one bot.");return}let x=T.target.querySelector("button[type=submit]");x&&(x.disabled=!0,x.textContent="Creating...");try{let H=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:v||void 0,larkAppIds:b,bindWorkingDir:d||void 0})}),I=await H.json();if(I.ok&&I.chatId){w(I);let C=Array.isArray(I.invalidBotIds)?I.invalidBotIds:[],q=b.filter(ie=>!C.includes(ie)),F=new Set(q);typeof I.creator=="string"&&I.creator&&F.add(I.creator),E(I.chatId,v||I.chatId,q,I.creator),y(),O(I.chatId,F).catch(()=>{})}else alert(`Failed: ${I.error??H.status}`),i.close()}catch(H){alert("Network error: "+H),i.close()}};function E(T,f,v,d){let b=new Set(v);d&&b.add(d);let x=pe.bots.map(I=>({larkAppId:I.larkAppId,botName:I.botName,inChat:b.has(I.larkAppId),oncallChat:null})),H={chatId:T,name:f,ownerId:d??null,memberBots:x};pe.chats=[H,...pe.chats.filter(I=>I.chatId!==T)]}async function O(T,f){let v=[600,1200,1200,1200,1200,1200];for(let d of v){await new Promise(H=>setTimeout(H,d));let b;try{b=await Na()}catch{continue}let x=(b.chats??[]).find(H=>H.chatId===T);if(x&&Pa(x,f)){pe=b,y();return}}}}function w(p){let E=String(p.chatId),O=typeof p.shareLink=="string"&&p.shareLink?p.shareLink:`https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(E)}`,T=p.invalidBotIds??[],f=p.invalidUserIds??[],v=p.autoInvitedOpenId,d=!!p.autoInviteRejected,b=p.ownerTransferredTo,x=p.transferError,H=p.notifyMessageId,I=p.notifyError,C=Array.isArray(p.oncallBindings)?p.oncallBindings:[],q=C.filter(ne=>ne?.ok).length,F=C.filter(ne=>!ne?.ok),ie=C.length>0?F.length===0?`<p class="hint-ok">\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1A<code>${r(p.bindResolvedPath??"")}</code>\uFF08${q}/${C.length} bots\uFF09</p>`:`<p class="hint-warn">\u76EE\u5F55\u7ED1\u5B9A\u90E8\u5206\u5931\u8D25\uFF1A\u6210\u529F ${q}/${C.length}\u3002${F.map(ne=>`<br><code>${r(ne.larkAppId??"?")}</code>: ${r(ne.error??"unknown")}`).join("")}</p>`:"",te;if(v){let ne=b?"<br><small>\u7FA4\u4E3B\u5DF2\u4ECE\u673A\u5668\u4EBA\u8F6C\u8BA9\u7ED9\u4F60\u3002</small>":x?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08${r(x)}\uFF09\uFF0C\u4F60\u73B0\u5728\u662F\u6210\u5458\u4F46\u7FA4\u4E3B\u4ECD\u662F\u673A\u5668\u4EBA\u3002</small>`:"",le=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>`:I?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8 @ \u901A\u77E5\u5931\u8D25\uFF08${r(I)}\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>`:"";te=`<p class="hint-ok">\u5DF2\u81EA\u52A8\u9080\u8BF7\u4F60\uFF08<code>${r(v)}</code>\uFF09\u4F5C\u4E3A\u6210\u5458\u3002${ne}${le}</p>`}else d?te='<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>':te='<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 he=[T.length?`<li>\u65E0\u6548 bot id: <code>${T.map(r).join(", ")}</code></li>`:"",f.length?`<li>\u65E0\u6548\u7528\u6237 open_id: <code>${f.map(r).join(", ")}</code></li>`:""].filter(Boolean).join("");i.innerHTML=`
344
+ </article>`,i.showModal(),i.querySelector("#g-create-cancel").onclick=()=>i.close(),i.querySelector("#g-createform").onsubmit=async $=>{$.preventDefault();let d=new FormData($.target),g=(d.get("name")??"").trim(),M=(d.get("bindWorkingDir")??"").trim(),L=d.getAll("bot");if(L.length===0){alert("Pick at least one bot.");return}let y=$.target.querySelector("button[type=submit]");y&&(y.disabled=!0,y.textContent="Creating...");try{let H=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:g||void 0,larkAppIds:L,bindWorkingDir:M||void 0})}),A=await H.json();if(A.ok&&A.chatId){v(A);let B=Array.isArray(A.invalidBotIds)?A.invalidBotIds:[],Y=L.filter(me=>!B.includes(me)),_=new Set(Y);typeof A.creator=="string"&&A.creator&&_.add(A.creator),C(A.chatId,g||A.chatId,Y,A.creator),m(),w(A.chatId,_).catch(()=>{})}else alert(`Failed: ${A.error??H.status}`),i.close()}catch(H){alert("Network error: "+H),i.close()}};function C($,d,g,M){let L=new Set(g);M&&L.add(M);let y=pe.bots.map(A=>({larkAppId:A.larkAppId,botName:A.botName,inChat:L.has(A.larkAppId),oncallChat:null})),H={chatId:$,name:d,ownerId:M??null,memberBots:y};pe.chats=[H,...pe.chats.filter(A=>A.chatId!==$)]}async function w($,d){let g=[600,1200,1200,1200,1200,1200];for(let M of g){await new Promise(H=>setTimeout(H,M));let L;try{L=await Wa()}catch{continue}let y=(L.chats??[]).find(H=>H.chatId===$);if(y&&Ja(y,d)){pe=L,m();return}}}}function v(E){let C=String(E.chatId),w=typeof E.shareLink=="string"&&E.shareLink?E.shareLink:`https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(C)}`,$=E.invalidBotIds??[],d=E.invalidUserIds??[],g=E.autoInvitedOpenId,M=!!E.autoInviteRejected,L=E.ownerTransferredTo,y=E.transferError,H=E.notifyMessageId,A=E.notifyError,B=Array.isArray(E.oncallBindings)?E.oncallBindings:[],Y=B.filter(Q=>Q?.ok).length,_=B.filter(Q=>!Q?.ok),me=B.length>0?_.length===0?`<p class="hint-ok">\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1A<code>${r(E.bindResolvedPath??"")}</code>\uFF08${Y}/${B.length} bots\uFF09</p>`:`<p class="hint-warn">\u76EE\u5F55\u7ED1\u5B9A\u90E8\u5206\u5931\u8D25\uFF1A\u6210\u529F ${Y}/${B.length}\u3002${_.map(Q=>`<br><code>${r(Q.larkAppId??"?")}</code>: ${r(Q.error??"unknown")}`).join("")}</p>`:"",$e;if(g){let Q=L?"<br><small>\u7FA4\u4E3B\u5DF2\u4ECE\u673A\u5668\u4EBA\u8F6C\u8BA9\u7ED9\u4F60\u3002</small>":y?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08${r(y)}\uFF09\uFF0C\u4F60\u73B0\u5728\u662F\u6210\u5458\u4F46\u7FA4\u4E3B\u4ECD\u662F\u673A\u5668\u4EBA\u3002</small>`:"",fe=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>`:A?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8 @ \u901A\u77E5\u5931\u8D25\uFF08${r(A)}\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>`:"";$e=`<p class="hint-ok">\u5DF2\u81EA\u52A8\u9080\u8BF7\u4F60\uFF08<code>${r(g)}</code>\uFF09\u4F5C\u4E3A\u6210\u5458\u3002${Q}${fe}</p>`}else M?$e='<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>':$e='<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 re=[$.length?`<li>\u65E0\u6548 bot id: <code>${$.map(r).join(", ")}</code></li>`:"",d.length?`<li>\u65E0\u6548\u7528\u6237 open_id: <code>${d.map(r).join(", ")}</code></li>`:""].filter(Boolean).join("");i.innerHTML=`
341
345
  <article>
342
346
  <header><h3>${t("groups.successTitle")}</h3></header>
343
- <p><b>chatId:</b> <code>${r(E)}</code> <button type="button" data-copy="${r(E)}">${t("sessions.copy")}</button></p>
344
- <p><b>\u521B\u5EFA\u8005:</b> <code>${r(p.creator??"?")}</code></p>
345
- ${te}
346
- ${ie}
347
- ${he?`<ul>${he}</ul>`:""}
347
+ <p><b>chatId:</b> <code>${r(C)}</code> <button type="button" data-copy="${r(C)}">${t("sessions.copy")}</button></p>
348
+ <p><b>\u521B\u5EFA\u8005:</b> <code>${r(E.creator??"?")}</code></p>
349
+ ${$e}
350
+ ${me}
351
+ ${re?`<ul>${re}</ul>`:""}
348
352
  <div class="actions">
349
- <a class="btn-link primary" href="${O}" target="_blank" rel="noopener">${t("groups.openGroup")}</a>
353
+ <a class="btn-link primary" href="${w}" target="_blank" rel="noopener">${t("groups.openGroup")}</a>
350
354
  <button type="button" id="g-create-close">${t("sessions.dismiss")}</button>
351
355
  </div>
352
- </article>`,i.querySelectorAll("[data-copy]").forEach(ne=>{ne.onclick=()=>{navigator.clipboard.writeText(ne.dataset.copy??""),ne.textContent=t("sessions.copied"),setTimeout(()=>{ne.textContent=t("sessions.copy")},800)}}),i.querySelector("#g-create-close").onclick=()=>i.close()}function h(){n.innerHTML=`<tr>
356
+ </article>`,i.querySelectorAll("[data-copy]").forEach(Q=>{Q.onclick=()=>{navigator.clipboard.writeText(Q.dataset.copy??""),Q.textContent=t("sessions.copied"),setTimeout(()=>{Q.textContent=t("sessions.copy")},800)}}),i.querySelector("#g-create-close").onclick=()=>i.close()}function k(){n.innerHTML=`<tr>
353
357
  <th>${t("groups.chat")}</th>
354
- ${pe.bots.map(p=>`<th>${r(p.botName??p.larkAppId)}</th>`).join("")}
358
+ ${pe.bots.map(E=>`<th>${r(E.botName??E.larkAppId)}</th>`).join("")}
355
359
  <th>${t("groups.actions")}</th>
356
- </tr>`}function y(){h();let p=new FormData(s),E=(p.get("q")??"").toLowerCase(),O=!!p.get("missing"),T=pe.chats.filter(f=>!E||(f.name??"").toLowerCase().includes(E)||f.chatId.toLowerCase().includes(E)||(f.ownerId??"").toLowerCase().includes(E)).filter(f=>!O||f.memberBots.some(v=>!v.inChat));if(T.length===0){o.innerHTML=`<tr><td colspan="${pe.bots.length+2}" class="empty">${t("groups.empty")}</td></tr>`;return}o.innerHTML=T.map(f=>`<tr data-chat="${r(f.chatId)}">
360
+ </tr>`}function m(){k();let E=new FormData(s),C=(E.get("q")??"").toLowerCase(),w=!!E.get("missing"),$=pe.chats.filter(d=>!C||(d.name??"").toLowerCase().includes(C)||d.chatId.toLowerCase().includes(C)||(d.ownerId??"").toLowerCase().includes(C)).filter(d=>!w||d.memberBots.some(g=>!g.inChat));if($.length===0){o.innerHTML=`<tr><td colspan="${pe.bots.length+2}" class="empty">${t("groups.empty")}</td></tr>`;return}o.innerHTML=$.map(d=>`<tr data-chat="${r(d.chatId)}">
357
361
  <td>
358
362
  <div class="g-chat-cell">
359
- ${jn({chatId:f.chatId,name:f.name,avatarUrl:f.avatar,size:"sm"})}
363
+ ${zn({chatId:d.chatId,name:d.name,avatarUrl:d.avatar,size:"sm"})}
360
364
  <div class="g-chat-meta">
361
- <strong>${r(f.name??f.chatId)}</strong><br>
362
- <small><code>${r(f.chatId)}</code></small>
365
+ <strong>${r(d.name??d.chatId)}</strong><br>
366
+ <small><code>${r(d.chatId)}</code></small>
363
367
  </div>
364
368
  </div>
365
369
  </td>
366
- ${pe.bots.map(v=>{let d=f.memberBots.find(H=>H.larkAppId===v.larkAppId),b=d?d.error?"!":d.inChat?"\u2713":"\u2717":"?";return`<td class="${d?d.error?"cell-error":d.inChat?"cell-in":"cell-out":"cell-unknown"}" title="${r(d?.error??"")}">${b}</td>`}).join("")}
370
+ ${pe.bots.map(g=>{let M=d.memberBots.find(H=>H.larkAppId===g.larkAppId),L=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??"")}">${L}</td>`}).join("")}
367
371
  <td>
368
372
  <button class="add-bots" type="button">${t("groups.addBots")}</button>
369
373
  <button class="manage-chat" type="button">${t("groups.manage")}</button>
370
374
  </td>
371
- </tr>`).join("")}y(),o.addEventListener("click",async p=>{let E=p.target.closest("button.add-bots");if(!E)return;let T=E.closest("tr[data-chat]").dataset.chat,f=pe.chats.find(b=>b.chatId===T);if(!f)return;let v=new Set(f.memberBots.filter(b=>b.inChat).map(b=>b.larkAppId));if(!pe.bots.filter(b=>!v.has(b.larkAppId)).length){alert("All configured bots are already in this chat.");return}i.innerHTML=`
375
+ </tr>`).join("")}m(),o.addEventListener("click",async E=>{let C=E.target.closest("button.add-bots");if(!C)return;let $=C.closest("tr[data-chat]").dataset.chat,d=pe.chats.find(L=>L.chatId===$);if(!d)return;let g=new Set(d.memberBots.filter(L=>L.inChat).map(L=>L.larkAppId));if(!pe.bots.filter(L=>!g.has(L.larkAppId)).length){alert("All configured bots are already in this chat.");return}i.innerHTML=`
372
376
  <article>
373
- <header><h3>${t("groups.addBots")} \xB7 ${r(f.name??f.chatId)}</h3></header>
377
+ <header><h3>${t("groups.addBots")} \xB7 ${r(d.name??d.chatId)}</h3></header>
374
378
  <p>${t("groups.createHelp")}</p>
375
379
  <form id="g-addform">
376
- ${no(pe.bots,v)}
380
+ ${ro(pe.bots,g)}
377
381
  <div class="actions">
378
382
  <button type="submit" class="primary">${t("groups.addBots")}</button>
379
383
  <button type="button" id="g-cancel">${t("groups.cancel")}</button>
380
384
  </div>
381
385
  </form>
382
- </article>`,i.showModal(),i.querySelector("#g-cancel").onclick=()=>i.close(),i.querySelector("#g-addform").onsubmit=async b=>{b.preventDefault();let H=new FormData(b.target).getAll("bot");if(H.length===0){alert("Pick at least one bot.");return}try{let C=await(await fetch(`/api/groups/${encodeURIComponent(T)}/add-bots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:H})})).json();if(C.error==="no_proxy_bot")alert("No bot is currently in this chat \u2014 add one manually in Feishu first, then retry.");else if(C.result){let q=C.result.map(F=>`${F.id}: ${F.ok?"OK":`failed (${F.error??"unknown"})`}`).join(`
383
- `);alert(q),await Qe(),y()}else alert(`Unexpected response: ${JSON.stringify(C)}`)}catch(I){alert("Network error: "+I)}finally{i.close()}}}),o.addEventListener("click",async p=>{let E=p.target.closest("button.manage-chat");if(!E)return;let T=E.closest("tr[data-chat]").dataset.chat,f=pe.chats.find(v=>v.chatId===T);f&&k(f)});function k(p){let E=p.memberBots.filter(T=>T.inChat),O=typeof p.ownerId=="string"?p.ownerId:"";i.innerHTML=`
386
+ </article>`,i.showModal(),i.querySelector("#g-cancel").onclick=()=>i.close(),i.querySelector("#g-addform").onsubmit=async L=>{L.preventDefault();let H=new FormData(L.target).getAll("bot");if(H.length===0){alert("Pick at least one bot.");return}try{let B=await(await fetch(`/api/groups/${encodeURIComponent($)}/add-bots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:H})})).json();if(B.error==="no_proxy_bot")alert("No bot is currently in this chat \u2014 add one manually in Feishu first, then retry.");else if(B.result){let Y=B.result.map(_=>`${_.id}: ${_.ok?"OK":`failed (${_.error??"unknown"})`}`).join(`
387
+ `);alert(Y),await Xe(),m()}else alert(`Unexpected response: ${JSON.stringify(B)}`)}catch(A){alert("Network error: "+A)}finally{i.close()}}}),o.addEventListener("click",async E=>{let C=E.target.closest("button.manage-chat");if(!C)return;let $=C.closest("tr[data-chat]").dataset.chat,d=pe.chats.find(g=>g.chatId===$);d&&D(d)});function D(E){let C=E.memberBots.filter($=>$.inChat),w=typeof E.ownerId=="string"?E.ownerId:"";i.innerHTML=`
384
388
  <article>
385
- <header><h3>${t("groups.manageTitle",{name:p.name??p.chatId})}</h3></header>
386
- <p><b>chatId:</b> <code>${r(p.chatId)}</code></p>
387
- <p><b>${t("groups.owner")}:</b> <code>${r(p.ownerId??t("common.unknown"))}</code></p>
389
+ <header><h3>${t("groups.manageTitle",{name:E.name??E.chatId})}</h3></header>
390
+ <p><b>chatId:</b> <code>${r(E.chatId)}</code></p>
391
+ <p><b>${t("groups.owner")}:</b> <code>${r(E.ownerId??t("common.unknown"))}</code></p>
388
392
 
389
393
  <fieldset>
390
394
  <legend>${t("groups.oncall")}</legend>
391
395
  <p><small>${t("groups.oncallHelp")}</small></p>
392
- ${E.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':E.map(T=>{let f=!!T.oncallChat,v=T.oncallChat?.workingDir??"";return`
393
- <div class="oncall-row" data-bot="${r(T.larkAppId)}">
396
+ ${C.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':C.map($=>{let d=!!$.oncallChat,g=$.oncallChat?.workingDir??"";return`
397
+ <div class="oncall-row" data-bot="${r($.larkAppId)}">
394
398
  <label class="checkbox-row">
395
- <input type="checkbox" data-action="toggle" ${f?"checked":""}>
396
- <strong>${r(T.botName??T.larkAppId)}</strong>
397
- <small>(${r(T.larkAppId)})</small>
399
+ <input type="checkbox" data-action="toggle" ${d?"checked":""}>
400
+ <strong>${r($.botName??$.larkAppId)}</strong>
401
+ <small>(${r($.larkAppId)})</small>
398
402
  </label>
399
403
  <div class="oncall-row-body">
400
404
  <input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
401
- value="${r(v)}" ${f?"":"disabled"}>
405
+ value="${r(g)}" ${d?"":"disabled"}>
402
406
  <button type="button" data-action="save">${t("groups.save")}</button>
403
407
  <span class="oncall-status" data-status></span>
404
408
  </div>
@@ -408,29 +412,29 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
408
412
 
409
413
  <fieldset>
410
414
  <legend>${t("groups.leaveTitle")}</legend>
411
- ${E.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':E.map(T=>`
415
+ ${C.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':C.map($=>`
412
416
  <label class="checkbox-row">
413
- <input type="checkbox" name="leave-bot" value="${r(T.larkAppId)}">
414
- ${r(T.botName??T.larkAppId)}
415
- <small>${T.larkAppId===O?"\xB7 \u7FA4\u4E3B":""}</small>
417
+ <input type="checkbox" name="leave-bot" value="${r($.larkAppId)}">
418
+ ${r($.botName??$.larkAppId)}
419
+ <small>${$.larkAppId===w?"\xB7 \u7FA4\u4E3B":""}</small>
416
420
  </label>
417
421
  `).join("")}
418
422
  </fieldset>
419
423
 
420
424
  <div class="actions">
421
- <button id="g-leave-btn" type="button" ${E.length===0?"disabled":""}>${t("groups.leaveSelected")}</button>
422
- <button id="g-disband-btn" type="button" class="contrast" ${E.length===0?"disabled":""}>${t("groups.disband")}</button>
425
+ <button id="g-leave-btn" type="button" ${C.length===0?"disabled":""}>${t("groups.leaveSelected")}</button>
426
+ <button id="g-disband-btn" type="button" class="contrast" ${C.length===0?"disabled":""}>${t("groups.disband")}</button>
423
427
  </div>
424
428
  <p class="hint-warn"><small>${t("groups.dangerHint")}</small></p>
425
429
  <form method="dialog"><button>${t("sessions.dismiss")}</button></form>
426
- </article>`,i.showModal(),i.querySelectorAll(".oncall-row").forEach(T=>{let f=T.dataset.bot,v=T.querySelector("input[data-action=toggle]"),d=T.querySelector("input[data-input=workingDir]"),b=T.querySelector("button[data-action=save]"),x=T.querySelector("[data-status]");v.addEventListener("change",()=>{d.disabled=!v.checked,v.checked&&d.focus()}),b.addEventListener("click",async()=>{x.textContent="",x.className="oncall-status";let H=v.checked,I=d.value.trim();if(H&&!I){x.textContent=t("groups.needWorkingDir"),x.classList.add("hint-warn-inline");return}b.disabled=!0;try{let C=`/api/groups/${encodeURIComponent(p.chatId)}/oncall/${encodeURIComponent(f)}`,q=H?await fetch(C,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({workingDir:I})}):await fetch(C,{method:"DELETE"}),F=await q.json().catch(()=>({}));if(q.ok&&F.ok){x.textContent=H?`\u2713 \u5DF2\u7ED1\u5B9A \u2192 ${F.resolvedPath??I}`:"\u2713 \u5DF2\u89E3\u7ED1",x.classList.add("hint-ok");try{await Qe(),y()}catch{}}else x.textContent=`\u2717 ${F.error??q.status}`,x.classList.add("hint-warn-inline")}catch(C){x.textContent=`\u2717 ${C?.message??C}`,x.classList.add("hint-warn-inline")}finally{b.disabled=!1}})}),i.querySelector("#g-leave-btn").onclick=async()=>{let T=[...i.querySelectorAll("input[name=leave-bot]:checked")].map(f=>f.value);if(T.length===0){alert("\u81F3\u5C11\u9009\u4E00\u4E2A\u673A\u5668\u4EBA");return}if(confirm(`\u786E\u5B9A\u8BA9 ${T.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 v=await(await fetch(`/api/groups/${encodeURIComponent(p.chatId)}/leave`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:T})})).json(),d=(v.result??[]).map(b=>{if(!b.ok)return`${b.larkAppId}: \u5931\u8D25 (${b.error??"unknown"})`;let x=b.closedSessions??[],H=x.filter(q=>!q.ok).length,I=x.length-H,C=x.length===0?"":H===0?`\uFF08\u5173\u95ED ${I} \u4E2A\u4F1A\u8BDD\uFF09`:`\uFF08\u5173\u95ED ${I} \u4E2A\uFF0C${H} \u4E2A\u5931\u8D25\uFF09`;return`${b.larkAppId}: OK${C}`}).join(`
427
- `);alert(d||`Unexpected: ${JSON.stringify(v)}`),await Qe(),y()}catch(f){alert("Network error: "+f)}finally{i.close()}},i.querySelector("#g-disband-btn").onclick=async()=>{if(E.length===0||!confirm(`\u786E\u5B9A\u89E3\u6563\u7FA4\u804A\u300C${p.name??p.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 T=[...E].sort((v,d)=>(d.larkAppId===O?1:0)-(v.larkAppId===O?1:0)),f=[];for(let v of T)try{let d=await fetch(`/api/groups/${encodeURIComponent(p.chatId)}/disband`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppId:v.larkAppId})}),b=await d.json();if(b.ok){let x=b.closedSessions??[],H=x.filter(q=>!q.ok).length,I=x.length-H,C=x.length===0?"":H===0?`
428
- \u5173\u95ED\u4E86 ${I} \u4E2A\u4F1A\u8BDD\u3002`:`
429
- \u5173\u95ED\u4E86 ${I} \u4E2A\u4F1A\u8BDD\uFF0C${H} \u4E2A\u4F1A\u8BDD\u5173\u95ED\u5931\u8D25\u3002`;alert(`\u5DF2\u89E3\u6563\uFF08\u7531 ${v.botName??v.larkAppId} \u6267\u884C\uFF09${C}`),await Qe(),y(),i.close();return}f.push(`${v.botName??v.larkAppId}: ${b.error??d.status}`)}catch(d){f.push(`${v.botName??v.larkAppId}: ${d}`)}alert(`\u6240\u6709\u5728\u7FA4\u673A\u5668\u4EBA\u5747\u65E0\u6CD5\u89E3\u6563\uFF1A
430
- ${f.join(`
430
+ </article>`,i.showModal(),i.querySelectorAll(".oncall-row").forEach($=>{let d=$.dataset.bot,g=$.querySelector("input[data-action=toggle]"),M=$.querySelector("input[data-input=workingDir]"),L=$.querySelector("button[data-action=save]"),y=$.querySelector("[data-status]");g.addEventListener("change",()=>{M.disabled=!g.checked,g.checked&&M.focus()}),L.addEventListener("click",async()=>{y.textContent="",y.className="oncall-status";let H=g.checked,A=M.value.trim();if(H&&!A){y.textContent=t("groups.needWorkingDir"),y.classList.add("hint-warn-inline");return}L.disabled=!0;try{let B=`/api/groups/${encodeURIComponent(E.chatId)}/oncall/${encodeURIComponent(d)}`,Y=H?await fetch(B,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({workingDir:A})}):await fetch(B,{method:"DELETE"}),_=await Y.json().catch(()=>({}));if(Y.ok&&_.ok){y.textContent=H?`\u2713 \u5DF2\u7ED1\u5B9A \u2192 ${_.resolvedPath??A}`:"\u2713 \u5DF2\u89E3\u7ED1",y.classList.add("hint-ok");try{await Xe(),m()}catch{}}else y.textContent=`\u2717 ${_.error??Y.status}`,y.classList.add("hint-warn-inline")}catch(B){y.textContent=`\u2717 ${B?.message??B}`,y.classList.add("hint-warn-inline")}finally{L.disabled=!1}})}),i.querySelector("#g-leave-btn").onclick=async()=>{let $=[...i.querySelectorAll("input[name=leave-bot]:checked")].map(d=>d.value);if($.length===0){alert("\u81F3\u5C11\u9009\u4E00\u4E2A\u673A\u5668\u4EBA");return}if(confirm(`\u786E\u5B9A\u8BA9 ${$.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 g=await(await fetch(`/api/groups/${encodeURIComponent(E.chatId)}/leave`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:$})})).json(),M=(g.result??[]).map(L=>{if(!L.ok)return`${L.larkAppId}: \u5931\u8D25 (${L.error??"unknown"})`;let y=L.closedSessions??[],H=y.filter(Y=>!Y.ok).length,A=y.length-H,B=y.length===0?"":H===0?`\uFF08\u5173\u95ED ${A} \u4E2A\u4F1A\u8BDD\uFF09`:`\uFF08\u5173\u95ED ${A} \u4E2A\uFF0C${H} \u4E2A\u5931\u8D25\uFF09`;return`${L.larkAppId}: OK${B}`}).join(`
431
+ `);alert(M||`Unexpected: ${JSON.stringify(g)}`),await Xe(),m()}catch(d){alert("Network error: "+d)}finally{i.close()}},i.querySelector("#g-disband-btn").onclick=async()=>{if(C.length===0||!confirm(`\u786E\u5B9A\u89E3\u6563\u7FA4\u804A\u300C${E.name??E.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 $=[...C].sort((g,M)=>(M.larkAppId===w?1:0)-(g.larkAppId===w?1:0)),d=[];for(let g of $)try{let M=await fetch(`/api/groups/${encodeURIComponent(E.chatId)}/disband`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppId:g.larkAppId})}),L=await M.json();if(L.ok){let y=L.closedSessions??[],H=y.filter(Y=>!Y.ok).length,A=y.length-H,B=y.length===0?"":H===0?`
432
+ \u5173\u95ED\u4E86 ${A} \u4E2A\u4F1A\u8BDD\u3002`:`
433
+ \u5173\u95ED\u4E86 ${A} \u4E2A\u4F1A\u8BDD\uFF0C${H} \u4E2A\u4F1A\u8BDD\u5173\u95ED\u5931\u8D25\u3002`;alert(`\u5DF2\u89E3\u6563\uFF08\u7531 ${g.botName??g.larkAppId} \u6267\u884C\uFF09${B}`),await Xe(),m(),i.close();return}d.push(`${g.botName??g.larkAppId}: ${L.error??M.status}`)}catch(M){d.push(`${g.botName??g.larkAppId}: ${M}`)}alert(`\u6240\u6709\u5728\u7FA4\u673A\u5668\u4EBA\u5747\u65E0\u6CD5\u89E3\u6563\uFF1A
434
+ ${d.join(`
431
435
  `)}
432
436
 
433
- \u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",y)}var ve={bots:[]},Ze=null,Xe=null;function ao(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 qa(){return`<section class="page">
437
+ \u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",m)}var ve={bots:[]},et=null,Ze=null;function co(e){let n=null;for(let o of ee.sessions.values())o.larkAppId!==e||!o.cliId||(!n||Number(o.lastMessageAt??0)>Number(n.lastMessageAt??0))&&(n=o);return n?.cliId??""}function Ka(){return`<section class="page">
434
438
  <div class="page-heading">
435
439
  <div>
436
440
  <p class="eyebrow">${t("nav.botDefaults")}</p>
@@ -446,13 +450,13 @@ ${f.join(`
446
450
  <aside id="bd-roster" class="bd-roster"></aside>
447
451
  <div id="bd-list" class="bd-detail"></div>
448
452
  </div>
449
- </section>`}async function so(){try{let e=await fetch("/api/bots"),n=await e.json().catch(()=>({}));if(!e.ok){Ze=n?.error?`HTTP ${e.status}: ${n.error}${n.path?` (${n.path})`:""}`:`HTTP ${e.status}`,ve={bots:[]};return}if(!n||!Array.isArray(n.bots)){Ze="unexpected response shape (no `bots` array)",ve={bots:[]};return}Ze=null,ve=n}catch(e){Ze=e?.message??String(e),ve={bots:[]}}}function io(e){if(!e)return"\u2014";let n=new Date(e);return Number.isNaN(n.getTime())?"\u2014":n.toLocaleString()}async function ro(e){e.innerHTML=qa();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 so(),i()}finally{a.disabled=!1}},n.addEventListener("click",d=>{let b=d.target.closest(".toggle-tx small, small.bd-help");b&&(d.preventDefault(),b.classList.toggle("open"))}),await so();function i(){let b=(new FormData(s).get("q")??"").toLowerCase(),x=ve.bots.filter(I=>!b||(I.botName??"").toLowerCase().includes(b)||(I.larkAppId??"").toLowerCase().includes(b));if(Ze){o.innerHTML="",n.innerHTML=`<p class="hint-warn">\u65E0\u6CD5\u52A0\u8F7D bot \u5217\u8868\uFF1A${r(Ze)}<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(x.length===0){o.innerHTML="",n.innerHTML=`<p class="empty">${t("botDefaults.empty")}</p>`;return}(!Xe||!x.some(I=>I.larkAppId===Xe))&&(Xe=x[0].larkAppId),o.innerHTML=x.map(l).join(""),o.querySelectorAll(".bd-roster-item").forEach(I=>{I.onclick=()=>{Xe=I.dataset.appid,i()}});let H=x.find(I=>I.larkAppId===Xe);n.innerHTML=c(H),v()}function l(d){let b=d.botName??d.larkAppId,x=ao(d.larkAppId),H=d.defaultOncall?.enabled?'<span class="bd-roster-flag">oncall</span>':"";return`<div class="bd-roster-item${d.larkAppId===Xe?" on":""}" data-appid="${r(d.larkAppId)}" role="button" tabindex="0">
450
- ${ye({name:b,larkAppId:d.larkAppId,size:"sm"})}
453
+ </section>`}async function uo(){try{let e=await fetch("/api/bots"),n=await e.json().catch(()=>({}));if(!e.ok){et=n?.error?`HTTP ${e.status}: ${n.error}${n.path?` (${n.path})`:""}`:`HTTP ${e.status}`,ve={bots:[]};return}if(!n||!Array.isArray(n.bots)){et="unexpected response shape (no `bots` array)",ve={bots:[]};return}et=null,ve=n}catch(e){et=e?.message??String(e),ve={bots:[]}}}function po(e){if(!e)return"\u2014";let n=new Date(e);return Number.isNaN(n.getTime())?"\u2014":n.toLocaleString()}async function mo(e){e.innerHTML=Ka();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 uo(),i()}finally{a.disabled=!1}},n.addEventListener("click",d=>{let g=d.target.closest(".toggle-tx small, small.bd-help");g&&(d.preventDefault(),g.classList.toggle("open"))}),n.innerHTML=Ye(),await uo();function i(){let g=(new FormData(s).get("q")??"").toLowerCase(),M=ve.bots.filter(y=>!g||(y.botName??"").toLowerCase().includes(g)||(y.larkAppId??"").toLowerCase().includes(g));if(et){o.innerHTML="",n.innerHTML=`<p class="hint-warn">\u65E0\u6CD5\u52A0\u8F7D bot \u5217\u8868\uFF1A${r(et)}<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(M.length===0){o.innerHTML="",n.innerHTML=`<p class="empty">${t("botDefaults.empty")}</p>`;return}(!Ze||!M.some(y=>y.larkAppId===Ze))&&(Ze=M[0].larkAppId),o.innerHTML=M.map(l).join(""),o.querySelectorAll(".bd-roster-item").forEach(y=>{y.onclick=()=>{Ze=y.dataset.appid,i()}});let L=M.find(y=>y.larkAppId===Ze);n.innerHTML=c(L),$()}function l(d){let g=d.botName??d.larkAppId,M=co(d.larkAppId),L=d.defaultOncall?.enabled?'<span class="bd-roster-flag">oncall</span>':"";return`<div class="bd-roster-item${d.larkAppId===Ze?" on":""}" data-appid="${r(d.larkAppId)}" role="button" tabindex="0">
454
+ ${ye({name:g,larkAppId:d.larkAppId,size:"sm"})}
451
455
  <div class="bd-roster-tx">
452
- <b>${r(b)}</b>
453
- <span>${r(x||d.larkAppId.slice(0,14))}</span>
456
+ <b>${r(g)}</b>
457
+ <span>${r(M||d.larkAppId.slice(0,14))}</span>
454
458
  </div>
455
- ${H}
459
+ ${L}
456
460
  </div>`}function c(d){if(d.error)return`<article class="bd-card bd-profile" data-appid="${r(d.larkAppId)}">
457
461
  <header class="bd-profile-head">
458
462
  ${ye({name:d.botName??d.larkAppId,larkAppId:d.larkAppId})}
@@ -460,17 +464,17 @@ ${f.join(`
460
464
  <code>${r(d.larkAppId)}</code></div>
461
465
  </header>
462
466
  <p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${r(d.error)}</p>
463
- </article>`;let b=d.defaultOncall??{enabled:!1,workingDir:"",since:0},x=!!b.enabled,H=d.botName??d.larkAppId,I=ao(d.larkAppId);return`<article class="bd-card bd-profile" data-appid="${r(d.larkAppId)}">
467
+ </article>`;let g=d.defaultOncall??{enabled:!1,workingDir:"",since:0},M=!!g.enabled,L=d.botName??d.larkAppId,y=co(d.larkAppId);return`<article class="bd-card bd-profile" data-appid="${r(d.larkAppId)}">
464
468
  <header class="bd-profile-head">
465
- ${ye({name:H,larkAppId:d.larkAppId,dot:"ok"})}
469
+ ${ye({name:L,larkAppId:d.larkAppId,dot:"ok"})}
466
470
  <div class="bd-profile-id">
467
- <strong>${r(H)}</strong>
468
- ${I?`<span class="mate-role">${r(I)}</span>`:""}
471
+ <strong>${r(L)}</strong>
472
+ ${y?`<span class="mate-role">${r(y)}</span>`:""}
469
473
  <code>${r(d.larkAppId)}</code>
470
474
  </div>
471
475
  <div class="bd-profile-meta bd-meta">
472
476
  <small class="bd-meta-ok">\u25CF ${t("botDefaults.metaOnline")}</small>
473
- <small data-oncall-since>${t("botDefaults.lastEnabled")}: ${r(io(b.since??0))}</small>
477
+ <small data-oncall-since>${t("botDefaults.lastEnabled")}: ${r(po(g.since??0))}</small>
474
478
  <small>${t("botDefaults.autobound",{count:d.autoboundChatCount??0})}</small>
475
479
  </div>
476
480
  </header>
@@ -479,7 +483,7 @@ ${f.join(`
479
483
  <section class="bd-section">
480
484
  <h3 class="bd-section-title">${t("botDefaults.sectionOncall")}</h3>
481
485
  <label class="toggle-row">
482
- <input type="checkbox" data-action="toggle" ${x?"checked":""}>
486
+ <input type="checkbox" data-action="toggle" ${M?"checked":""}>
483
487
  <span class="switch" aria-hidden="true"></span>
484
488
  <span class="toggle-tx"><strong>${t("botDefaults.defaultOncall")}</strong>
485
489
  <small>${t("botDefaults.defaultOncallHelp")}\u3002${t("botDefaults.warning")}</small></span>
@@ -488,43 +492,43 @@ ${f.join(`
488
492
  <label>
489
493
  <span>${t("botDefaults.workingDir")}</span>
490
494
  <input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
491
- value="${r(b.workingDir??"")}" ${x?"":"disabled"}>
495
+ value="${r(g.workingDir??"")}" ${M?"":"disabled"}>
492
496
  </label>
493
497
  </div>
494
498
  <div class="actions">
495
499
  <button type="button" class="primary" data-action="save">${t("botDefaults.save")}</button>
496
500
  <span class="oncall-status" data-status></span>
497
501
  </div>
498
- ${f(d)}
502
+ ${w(d)}
499
503
  </section>
500
- ${E(d)}
504
+ ${D(d)}
501
505
  </section>
502
- <section class="bd-tile">${w(d)}</section>
503
- <section class="bd-tile">${p(d)}</section>
504
- <section class="bd-tile">${k(d)}${y(d)}</section>
505
- <section class="bd-tile">${T(d)}</section>
506
+ <section class="bd-tile">${h(d)}</section>
507
+ <section class="bd-tile">${m(d)}</section>
508
+ <section class="bd-tile">${k(d)}${v(d)}</section>
509
+ <section class="bd-tile">${C(d)}</section>
506
510
  </div>
507
- </article>`}function w(d){let b=typeof d.teamRole=="string";return`<section class="bd-section">
511
+ </article>`}function h(d){let g=typeof d.teamRole=="string";return`<section class="bd-section">
508
512
  <h3 class="bd-section-title">${t("botDefaults.sectionRole")}</h3>
509
513
  <p class="bd-section-note">${t("botDefaults.roleHelp")}</p>
510
514
  <textarea data-input="teamRole" rows="6"
511
515
  placeholder="${r(t("botDefaults.rolePlaceholder"))}"
512
- style="width:100%;box-sizing:border-box;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px"${b?"":" disabled"}>${b?r(d.teamRole):""}</textarea>
516
+ style="width:100%;box-sizing:border-box;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px"${g?"":" disabled"}>${g?r(d.teamRole):""}</textarea>
513
517
  <div class="actions">
514
- <button type="button" class="primary" data-action="save-role"${b?"":" disabled"}>${t("botDefaults.roleSave")}</button>
515
- <button type="button" data-action="delete-role"${b?"":" disabled"}>${t("botDefaults.roleDelete")}</button>
518
+ <button type="button" class="primary" data-action="save-role"${g?"":" disabled"}>${t("botDefaults.roleSave")}</button>
519
+ <button type="button" data-action="delete-role"${g?"":" disabled"}>${t("botDefaults.roleDelete")}</button>
516
520
  <span class="oncall-status" data-role-status></span>
517
521
  </div>
518
- </section>`}function h(d){return d==null?t("botDefaults.brandStateDefault"):d.trim()===""?t("botDefaults.brandStateOff"):t("botDefaults.brandStateCustom")}function y(d){let b=d.brandLabel??null;return`<section class="bd-section">
522
+ </section>`}function b(d){return d==null?t("botDefaults.brandStateDefault"):d.trim()===""?t("botDefaults.brandStateOff"):t("botDefaults.brandStateCustom")}function v(d){let g=d.brandLabel??null;return`<section class="bd-section">
519
523
  <h3 class="bd-section-title">${t("botDefaults.sectionBrand")}</h3>
520
524
  <div class="bd-row bd-brand">
521
525
  <label>
522
526
  <span>${t("botDefaults.brandLabel")}</span>
523
527
  <input type="text" data-input="brandLabel"
524
528
  placeholder="${r(t("botDefaults.brandLabelPlaceholder"))}"
525
- value="${r(b??"")}">
529
+ value="${r(g??"")}">
526
530
  </label>
527
- <small data-brand-state>${r(h(b))}</small>
531
+ <small data-brand-state>${r(b(g))}</small>
528
532
  <small class="bd-help">${t("botDefaults.brandLabelHelp")}</small>
529
533
  <div class="actions">
530
534
  <button type="button" class="primary" data-action="save-brand">${t("botDefaults.brandSave")}</button>
@@ -532,38 +536,38 @@ ${f.join(`
532
536
  <span class="oncall-status" data-brand-status></span>
533
537
  </div>
534
538
  </div>
535
- </section>`}function k(d){let b=d.disableStreamingCard===!0,x=d.writableTerminalLinkInCard===!0,H=d.privateCard===!0;return`<section class="bd-section">
539
+ </section>`}function k(d){let g=d.disableStreamingCard===!0,M=d.writableTerminalLinkInCard===!0,L=d.privateCard===!0;return`<section class="bd-section">
536
540
  <h3 class="bd-section-title">${t("botDefaults.sectionCard")}</h3>
537
541
  <label class="toggle-row">
538
- <input type="checkbox" data-action="toggle-disable-streaming" ${b?"checked":""}>
542
+ <input type="checkbox" data-action="toggle-disable-streaming" ${g?"checked":""}>
539
543
  <span class="switch" aria-hidden="true"></span>
540
544
  <span class="toggle-tx"><strong>${t("botDefaults.disableStreaming")}</strong>
541
545
  <small>${t("botDefaults.disableStreamingHelp")}</small></span>
542
546
  </label>
543
547
  <label class="toggle-row">
544
- <input type="checkbox" data-action="toggle-writable-link" ${x?"checked":""} ${b?"disabled":""}>
548
+ <input type="checkbox" data-action="toggle-writable-link" ${M?"checked":""} ${g?"disabled":""}>
545
549
  <span class="switch" aria-hidden="true"></span>
546
550
  <span class="toggle-tx"><strong>${t("botDefaults.writableLink")}</strong>
547
551
  <small>${t("botDefaults.writableLinkHelp")}</small></span>
548
552
  </label>
549
553
  <label class="toggle-row">
550
- <input type="checkbox" data-action="toggle-private-card" ${H?"checked":""}>
554
+ <input type="checkbox" data-action="toggle-private-card" ${L?"checked":""}>
551
555
  <span class="switch" aria-hidden="true"></span>
552
556
  <span class="toggle-tx"><strong>${t("botDefaults.privateCard")}</strong>
553
557
  <small>${t("botDefaults.privateCardHelp")}</small></span>
554
558
  </label>
555
559
  <div class="actions">
556
- <small data-card-pref-moot class="hint-warn-inline" ${b?"":"hidden"}>${t("botDefaults.writableLinkMoot")}</small>
560
+ <small data-card-pref-moot class="hint-warn-inline" ${g?"":"hidden"}>${t("botDefaults.writableLinkMoot")}</small>
557
561
  <span class="oncall-status" data-card-pref-status></span>
558
562
  </div>
559
- </section>`}function p(d){let b=d.p2pMode==="chat"?"chat":"thread",x=d.regularGroupReplyMode==="new-topic"||d.regularGroupReplyMode==="shared"?d.regularGroupReplyMode:"chat",H=d.regularGroupMentionMode==="topic"||d.regularGroupMentionMode==="never"?d.regularGroupMentionMode:"always",I=(q,F)=>`<option value="${q}" ${x===q?"selected":""}>${r(F)}</option>`,C=(q,F)=>`<option value="${q}" ${H===q?"selected":""}>${r(F)}</option>`;return`<section class="bd-section">
563
+ </section>`}function m(d){let g=d.p2pMode==="chat"?"chat":"thread",M=d.regularGroupReplyMode==="new-topic"||d.regularGroupReplyMode==="shared"?d.regularGroupReplyMode:"chat",L=d.regularGroupMentionMode==="topic"||d.regularGroupMentionMode==="never"?d.regularGroupMentionMode:"always",y=(A,B)=>`<option value="${A}" ${M===A?"selected":""}>${r(B)}</option>`,H=(A,B)=>`<option value="${A}" ${L===A?"selected":""}>${r(B)}</option>`;return`<section class="bd-section">
560
564
  <h3 class="bd-section-title">${t("botDefaults.sectionSessionMode")}</h3>
561
565
  <div class="bd-row">
562
566
  <label>
563
567
  <span>${t("botDefaults.p2pMode")}</span>
564
568
  <select data-input="p2pMode">
565
- <option value="thread" ${b==="chat"?"":"selected"}>${r(t("botDefaults.p2pThread"))}</option>
566
- <option value="chat" ${b==="chat"?"selected":""}>${r(t("botDefaults.p2pChat"))}</option>
569
+ <option value="thread" ${g==="chat"?"":"selected"}>${r(t("botDefaults.p2pThread"))}</option>
570
+ <option value="chat" ${g==="chat"?"selected":""}>${r(t("botDefaults.p2pChat"))}</option>
567
571
  </select>
568
572
  </label>
569
573
  <small class="bd-help">${t("botDefaults.p2pHelp")}</small>
@@ -575,9 +579,9 @@ ${f.join(`
575
579
  <label>
576
580
  <span>${t("botDefaults.regularGroupMode")}</span>
577
581
  <select data-input="regularGroupMode">
578
- ${I("chat",t("botDefaults.regularGroupModeChat"))}
579
- ${I("new-topic",t("botDefaults.regularGroupModeNewTopic"))}
580
- ${I("shared",t("botDefaults.regularGroupModeShared"))}
582
+ ${y("chat",t("botDefaults.regularGroupModeChat"))}
583
+ ${y("new-topic",t("botDefaults.regularGroupModeNewTopic"))}
584
+ ${y("shared",t("botDefaults.regularGroupModeShared"))}
581
585
  </select>
582
586
  </label>
583
587
  <small class="bd-help">${t("botDefaults.regularGroupModeHelp")}</small>
@@ -589,9 +593,9 @@ ${f.join(`
589
593
  <label>
590
594
  <span>${t("botDefaults.mentionMode")}</span>
591
595
  <select data-input="regularGroupMentionMode">
592
- ${C("always",t("botDefaults.mentionModeAlways"))}
593
- ${C("topic",t("botDefaults.mentionModeTopic"))}
594
- ${C("never",t("botDefaults.mentionModeNever"))}
596
+ ${H("always",t("botDefaults.mentionModeAlways"))}
597
+ ${H("topic",t("botDefaults.mentionModeTopic"))}
598
+ ${H("never",t("botDefaults.mentionModeNever"))}
595
599
  </select>
596
600
  </label>
597
601
  <small class="bd-help">${t("botDefaults.mentionModeHelp")}</small>
@@ -599,10 +603,10 @@ ${f.join(`
599
603
  <span class="oncall-status" data-mention-mode-status></span>
600
604
  </div>
601
605
  </div>
602
- </section>`}function E(d){let b=d.sandbox===!0;return`<section class="bd-section">
606
+ </section>`}function D(d){let g=d.sandbox===!0;return`<section class="bd-section">
603
607
  <h3 class="bd-section-title">${t("botDefaults.sectionSandbox")}</h3>
604
608
  <label class="toggle-row">
605
- <input type="checkbox" data-action="toggle-sandbox" ${b?"checked":""}>
609
+ <input type="checkbox" data-action="toggle-sandbox" ${g?"checked":""}>
606
610
  <span class="switch" aria-hidden="true"></span>
607
611
  <span class="toggle-tx"><strong>${t("botDefaults.sandboxToggle")}</strong>
608
612
  <small>${t("botDefaults.sandboxHelp")}</small></span>
@@ -610,10 +614,10 @@ ${f.join(`
610
614
  <div class="actions">
611
615
  <span class="oncall-status" data-sandbox-status></span>
612
616
  </div>
613
- </section>`}function O(d){return d==null?t("botDefaults.quotaStateOff"):t("botDefaults.quotaStateOn",{count:d})}function T(d){let b=d.restrictGrantCommands===!0,x=typeof d.messageQuotaDefaultLimit=="number"?d.messageQuotaDefaultLimit:null;return`<section class="bd-section">
617
+ </section>`}function E(d){return d==null?t("botDefaults.quotaStateOff"):t("botDefaults.quotaStateOn",{count:d})}function C(d){let g=d.restrictGrantCommands===!0,M=typeof d.messageQuotaDefaultLimit=="number"?d.messageQuotaDefaultLimit:null;return`<section class="bd-section">
614
618
  <h3 class="bd-section-title">${t("botDefaults.sectionGrant")}</h3>
615
619
  <label class="toggle-row">
616
- <input type="checkbox" data-action="toggle-restrict-grant" ${b?"checked":""}>
620
+ <input type="checkbox" data-action="toggle-restrict-grant" ${g?"checked":""}>
617
621
  <span class="switch" aria-hidden="true"></span>
618
622
  <span class="toggle-tx"><strong>${t("botDefaults.restrictGrant")}</strong>
619
623
  <small>${t("botDefaults.restrictGrantHelp")}</small></span>
@@ -623,9 +627,9 @@ ${f.join(`
623
627
  <span>${t("botDefaults.quotaDefault")}</span>
624
628
  <input type="number" min="1" step="1" data-input="quotaLimit"
625
629
  placeholder="${r(t("botDefaults.quotaPlaceholder"))}"
626
- value="${x??""}">
630
+ value="${M??""}">
627
631
  </label>
628
- <small data-quota-state>${r(O(x))}</small>
632
+ <small data-quota-state>${r(E(M))}</small>
629
633
  <small class="bd-help">${t("botDefaults.quotaHelp")}</small>
630
634
  <div class="actions">
631
635
  <button type="button" class="primary" data-action="save-quota">${t("botDefaults.quotaSave")}</button>
@@ -633,10 +637,10 @@ ${f.join(`
633
637
  <span class="oncall-status" data-grant-status></span>
634
638
  </div>
635
639
  </div>
636
- </section>`}function f(d){let b=d.autoStartOnGroupJoin===!0,x=d.autoStartOnNewTopic===!0,H=typeof d.autoStartOnGroupJoinPrompt=="string"?d.autoStartOnGroupJoinPrompt:"";return`<div class="bd-subsection">
640
+ </section>`}function w(d){let g=d.autoStartOnGroupJoin===!0,M=d.autoStartOnNewTopic===!0,L=typeof d.autoStartOnGroupJoinPrompt=="string"?d.autoStartOnGroupJoinPrompt:"";return`<div class="bd-subsection">
637
641
  <h4 class="bd-subsection-title">${t("botDefaults.sectionAutoStart")}</h4>
638
642
  <label class="toggle-row">
639
- <input type="checkbox" data-action="toggle-auto-join" ${b?"checked":""}>
643
+ <input type="checkbox" data-action="toggle-auto-join" ${g?"checked":""}>
640
644
  <span class="switch" aria-hidden="true"></span>
641
645
  <span class="toggle-tx"><strong>${t("botDefaults.autoStartJoin")}</strong>
642
646
  <small>${t("botDefaults.autoStartJoinHelp")}</small></span>
@@ -645,14 +649,14 @@ ${f.join(`
645
649
  <label>
646
650
  <span>${t("botDefaults.autoStartJoinPrompt")}</span>
647
651
  <textarea data-input="autoJoinPrompt" rows="3"
648
- placeholder="${r(t("botDefaults.autoStartJoinPromptPlaceholder"))}">${r(H)}</textarea>
652
+ placeholder="${r(t("botDefaults.autoStartJoinPromptPlaceholder"))}">${r(L)}</textarea>
649
653
  </label>
650
654
  <div class="actions">
651
655
  <button type="button" class="primary" data-action="save-auto-join-prompt">${t("botDefaults.autoStartJoinPromptSave")}</button>
652
656
  </div>
653
657
  </div>
654
658
  <label class="toggle-row">
655
- <input type="checkbox" data-action="toggle-auto-topic" ${x?"checked":""}>
659
+ <input type="checkbox" data-action="toggle-auto-topic" ${M?"checked":""}>
656
660
  <span class="switch" aria-hidden="true"></span>
657
661
  <span class="toggle-tx"><strong>${t("botDefaults.autoStartTopic")}</strong>
658
662
  <small>${t("botDefaults.autoStartTopicHelp")}</small></span>
@@ -660,7 +664,7 @@ ${f.join(`
660
664
  <div class="actions">
661
665
  <span class="oncall-status" data-auto-start-status></span>
662
666
  </div>
663
- </div>`}function v(){n.querySelectorAll(".bd-card").forEach(d=>{let b=d.dataset.appid,x=d.querySelector("input[data-action=toggle]"),H=d.querySelector("input[data-input=workingDir]"),I=d.querySelector("button[data-action=save]"),C=d.querySelector("[data-status]");if(!x||!H||!I||!C)return;x.addEventListener("change",()=>{H.disabled=!x.checked,x.checked&&H.focus()}),I.addEventListener("click",async()=>{C.textContent="",C.className="oncall-status";let Y=x.checked,N=H.value.trim();if(Y&&!N){C.textContent=t("botDefaults.required"),C.classList.add("hint-warn-inline");return}I.disabled=!0;try{let R=await fetch(`/api/bots/${encodeURIComponent(b)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:Y,workingDir:N})}),j=await R.json().catch(()=>({}));if(R.ok&&j.ok){let P=j.resolvedPath?` \u2192 ${j.resolvedPath}`:"";C.textContent=Y?`\u2713 \u5DF2\u5F00\u542F${P}\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",C.classList.add("hint-ok");let _=ve.bots.find(Te=>Te.larkAppId===b);_&&j.defaultOncall&&(_.defaultOncall=j.defaultOncall);let de=d.querySelector("[data-oncall-since]");de&&j.defaultOncall?.since!=null&&(de.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${io(j.defaultOncall.since)}`)}else C.textContent=`\u2717 ${j.error??R.status}`,C.classList.add("hint-warn-inline")}catch(R){C.textContent=`\u2717 ${R?.message??R}`,C.classList.add("hint-warn-inline")}finally{I.disabled=!1}});let q=d.querySelector("input[data-input=brandLabel]"),F=d.querySelector("button[data-action=save-brand]"),ie=d.querySelector("button[data-action=reset-brand]"),te=d.querySelector("[data-brand-status]"),he=d.querySelector("[data-brand-state]");async function ne(Y,N){if(te){te.textContent="",te.className="oncall-status",N.disabled=!0;try{let R=await fetch(`/api/bots/${encodeURIComponent(b)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:Y})}),j=await R.json().catch(()=>({}));if(R.ok&&j.ok){let P=j.brandLabel??null;te.textContent="\u2713",te.classList.add("hint-ok"),q&&(q.value=P??""),he&&(he.textContent=h(P));let _=ve.bots.find(de=>de.larkAppId===b);_&&(_.brandLabel=P)}else te.textContent=`\u2717 ${j.error??R.status}`,te.classList.add("hint-warn-inline")}catch(R){te.textContent=`\u2717 ${R?.message??R}`,te.classList.add("hint-warn-inline")}finally{N.disabled=!1}}}q&&F&&F.addEventListener("click",()=>ne(q.value,F)),ie&&ie.addEventListener("click",()=>ne(null,ie));let le=d.querySelector("input[data-action=toggle-disable-streaming]"),me=d.querySelector("input[data-action=toggle-writable-link]"),$e=d.querySelector("input[data-action=toggle-private-card]"),Ne=d.querySelector("[data-card-pref-status]"),Se=d.querySelector("[data-card-pref-moot]");async function ae(Y,N,R=Ne){if(R){R.textContent="",R.className="oncall-status",N.disabled=!0;try{let j=await fetch(`/api/bots/${encodeURIComponent(b)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(Y)}),P=await j.json().catch(()=>({}));if(j.ok&&P.ok){R.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,R.classList.add("hint-ok");let _=ve.bots.find(de=>de.larkAppId===b);_&&(_.disableStreamingCard=P.disableStreamingCard,_.writableTerminalLinkInCard=P.writableTerminalLinkInCard,_.privateCard=P.privateCard,_.autoStartOnGroupJoin=P.autoStartOnGroupJoin,_.autoStartOnGroupJoinPrompt=P.autoStartOnGroupJoinPrompt,_.autoStartOnNewTopic=P.autoStartOnNewTopic,_.regularGroupReplyMode=P.regularGroupReplyMode,_.regularGroupMentionMode=P.regularGroupMentionMode)}else R.textContent=`\u2717 ${P.error??j.status}`,R.classList.add("hint-warn-inline")}catch(j){R.textContent=`\u2717 ${j?.message??j}`,R.classList.add("hint-warn-inline")}finally{N===me?N.disabled=!!le?.checked:N.disabled=!1}}}le&&le.addEventListener("change",()=>{let Y=le.checked;me&&(me.disabled=Y),Se&&(Se.hidden=!Y),ae({disableStreamingCard:Y},le)}),me&&me.addEventListener("change",()=>{ae({writableTerminalLinkInCard:me.checked},me)}),$e&&$e.addEventListener("change",()=>{ae({privateCard:$e.checked},$e)});let re=d.querySelector("input[data-action=toggle-sandbox]"),V=d.querySelector("[data-sandbox-status]");re&&re.addEventListener("change",async()=>{let Y=re.checked;V&&(V.textContent="",V.className="oncall-status"),re.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(b)}/sandbox`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:Y})}),R=await N.json().catch(()=>({}));if(N.ok&&R.ok){V&&(V.textContent=`\u2713 ${t("botDefaults.sandboxSaved")}`,V.classList.add("hint-ok"));let j=ve.bots.find(P=>P.larkAppId===b);j&&(j.sandbox=R.sandbox===!0)}else V&&(V.textContent=`\u2717 ${R.error??N.status}`,V.classList.add("hint-warn-inline")),re.checked=!Y}catch(N){V&&(V.textContent=`\u2717 ${N?.message??N}`,V.classList.add("hint-warn-inline")),re.checked=!Y}finally{re.disabled=!1}});let Ie=d.querySelector("input[data-action=toggle-auto-join]"),Me=d.querySelector("input[data-action=toggle-auto-topic]"),se=d.querySelector("textarea[data-input=autoJoinPrompt]"),u=d.querySelector("button[data-action=save-auto-join-prompt]"),g=d.querySelector("[data-auto-start-status]");Ie&&Ie.addEventListener("change",()=>{ae({autoStartOnGroupJoin:Ie.checked},Ie,g)}),Me&&Me.addEventListener("change",()=>{ae({autoStartOnNewTopic:Me.checked},Me,g)}),se&&u&&u.addEventListener("click",()=>{ae({autoStartOnGroupJoinPrompt:se.value},u,g)});let S=d.querySelector("select[data-input=p2pMode]"),L=d.querySelector("[data-p2p-status]");S&&L&&S.addEventListener("change",async()=>{let Y=S.value==="chat"?"chat":"thread";L.textContent="",L.className="oncall-status",S.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(b)}/p2p-mode`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({p2pMode:Y})}),R=await N.json().catch(()=>({}));if(N.ok&&R.ok){L.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,L.classList.add("hint-ok");let j=ve.bots.find(P=>P.larkAppId===b);j&&(j.p2pMode=R.p2pMode==="chat"?"chat":"thread")}else L.textContent=`\u2717 ${R.error??N.status}`,L.classList.add("hint-warn-inline")}catch(N){L.textContent=`\u2717 ${N?.message??N}`,L.classList.add("hint-warn-inline")}finally{S.disabled=!1}});let M=d.querySelector("select[data-input=regularGroupMode]"),U=d.querySelector("[data-regular-group-status]");M&&M.addEventListener("change",()=>{ae({regularGroupReplyMode:M.value},M,U)});let G=d.querySelector("select[data-input=regularGroupMentionMode]"),X=d.querySelector("[data-mention-mode-status]");G&&G.addEventListener("change",()=>{ae({regularGroupMentionMode:G.value},G,X)});let z=d.querySelector("textarea[data-input=teamRole]"),ee=d.querySelector("button[data-action=save-role]"),oe=d.querySelector("button[data-action=delete-role]"),W=d.querySelector("[data-role-status]");if(z&&ee&&oe&&W){let R=function(P){let _=n.querySelector(`.bd-card[data-appid="${CSS.escape(b)}"]`);if(!_)return;let de=_.querySelector("textarea[data-input=teamRole]"),Te=_.querySelector("button[data-action=save-role]"),nt=_.querySelector("button[data-action=delete-role]");de&&(de.value=P,de.disabled=!1),Te&&(Te.disabled=!1),nt&&(nt.disabled=!1)};var bt=R;let Y=`/api/team/local-bots/${encodeURIComponent(b)}/role`,N=ve.bots.find(P=>P.larkAppId===b);N&&typeof N.teamRole!="string"&&!N.teamRoleLoading&&(N.teamRoleLoading=!0,(async()=>{try{let P=await fetch(Y),_=await P.json().catch(()=>({}));P.ok&&_.ok?(N.teamRole=_.role??"",R(N.teamRole)):(W.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${_.error??P.status}`,W.classList.add("hint-warn-inline"))}catch(P){W.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${P?.message??P}`,W.classList.add("hint-warn-inline")}finally{N.teamRoleLoading=!1}})());async function j(P,_,de){if(W&&!(!N||typeof N.teamRole!="string")){W.textContent="",W.className="oncall-status",ee.disabled=!0,oe.disabled=!0;try{let Te=await fetch(Y,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({role:P})}),nt=await Te.json().catch(()=>({}));Te.ok&&nt.ok?(N&&(N.teamRole=P.trim()),W.textContent=`\u2713 ${de?t("botDefaults.roleDeleted"):t("botDefaults.roleSaved")}`,W.classList.add("hint-ok")):(W.textContent=`\u2717 ${nt.error??Te.status}`,W.classList.add("hint-warn-inline"))}catch(Te){W.textContent=`\u2717 ${Te?.message??Te}`,W.classList.add("hint-warn-inline")}finally{ee.disabled=!1,oe.disabled=!1}}}ee.addEventListener("click",()=>j(z.value,ee,!1)),oe.addEventListener("click",()=>{z.value="",j("",oe,!0)})}let xe=d.querySelector("input[data-action=toggle-restrict-grant]"),we=d.querySelector("input[data-input=quotaLimit]"),$=d.querySelector("button[data-action=save-quota]"),Z=d.querySelector("button[data-action=off-quota]"),A=d.querySelector("[data-grant-status]"),B=d.querySelector("[data-quota-state]");async function fe(Y,N){if(A){A.textContent="",A.className="oncall-status",N.disabled=!0;try{let R=await fetch(`/api/bots/${encodeURIComponent(b)}/grant-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(Y)}),j=await R.json().catch(()=>({}));if(R.ok&&j.ok){A.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,A.classList.add("hint-ok");let P=typeof j.messageQuotaDefaultLimit=="number"?j.messageQuotaDefaultLimit:null,_=ve.bots.find(de=>de.larkAppId===b);_&&(_.restrictGrantCommands=j.restrictGrantCommands===!0,_.messageQuotaDefaultLimit=P),B&&(B.textContent=O(P)),we&&"messageQuotaDefaultLimit"in Y&&(we.value=P==null?"":String(P))}else A.textContent=`\u2717 ${j.error??R.status}`,A.classList.add("hint-warn-inline")}catch(R){A.textContent=`\u2717 ${R?.message??R}`,A.classList.add("hint-warn-inline")}finally{N.disabled=!1}}}xe&&xe.addEventListener("change",()=>{fe({restrictGrantCommands:xe.checked},xe)}),we&&$&&$.addEventListener("click",()=>{let Y=we.value.trim();if(Y===""){fe({messageQuotaDefaultLimit:null},$);return}if(!/^[1-9]\d*$/.test(Y)){A&&(A.textContent=`\u2717 ${t("botDefaults.quotaInvalid")}`,A.className="oncall-status hint-warn-inline");return}fe({messageQuotaDefaultLimit:Number(Y)},$)}),we&&Z&&Z.addEventListener("click",()=>{we.value="",fe({messageQuotaDefaultLimit:null},Z)})})}i(),Ee().then(i),s.addEventListener("input",i)}var Zt=4096,It=[],Ae=null,De=null,ke="",et=new Set;function Ua(){return`<section class="page roles-page">
667
+ </div>`}function $(){n.querySelectorAll(".bd-card").forEach(d=>{let g=d.dataset.appid,M=d.querySelector("input[data-action=toggle]"),L=d.querySelector("input[data-input=workingDir]"),y=d.querySelector("button[data-action=save]"),H=d.querySelector("[data-status]");if(!M||!L||!y||!H)return;M.addEventListener("change",()=>{L.disabled=!M.checked,M.checked&&L.focus()}),y.addEventListener("click",async()=>{H.textContent="",H.className="oncall-status";let Z=M.checked,q=L.value.trim();if(Z&&!q){H.textContent=t("botDefaults.required"),H.classList.add("hint-warn-inline");return}y.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(g)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:Z,workingDir:q})}),F=await N.json().catch(()=>({}));if(N.ok&&F.ok){let U=F.resolvedPath?` \u2192 ${F.resolvedPath}`:"";H.textContent=Z?`\u2713 \u5DF2\u5F00\u542F${U}\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",H.classList.add("hint-ok");let W=ve.bots.find(Te=>Te.larkAppId===g);W&&F.defaultOncall&&(W.defaultOncall=F.defaultOncall);let de=d.querySelector("[data-oncall-since]");de&&F.defaultOncall?.since!=null&&(de.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${po(F.defaultOncall.since)}`)}else H.textContent=`\u2717 ${F.error??N.status}`,H.classList.add("hint-warn-inline")}catch(N){H.textContent=`\u2717 ${N?.message??N}`,H.classList.add("hint-warn-inline")}finally{y.disabled=!1}});let A=d.querySelector("input[data-input=brandLabel]"),B=d.querySelector("button[data-action=save-brand]"),Y=d.querySelector("button[data-action=reset-brand]"),_=d.querySelector("[data-brand-status]"),me=d.querySelector("[data-brand-state]");async function $e(Z,q){if(_){_.textContent="",_.className="oncall-status",q.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(g)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:Z})}),F=await N.json().catch(()=>({}));if(N.ok&&F.ok){let U=F.brandLabel??null;_.textContent="\u2713",_.classList.add("hint-ok"),A&&(A.value=U??""),me&&(me.textContent=b(U));let W=ve.bots.find(de=>de.larkAppId===g);W&&(W.brandLabel=U)}else _.textContent=`\u2717 ${F.error??N.status}`,_.classList.add("hint-warn-inline")}catch(N){_.textContent=`\u2717 ${N?.message??N}`,_.classList.add("hint-warn-inline")}finally{q.disabled=!1}}}A&&B&&B.addEventListener("click",()=>$e(A.value,B)),Y&&Y.addEventListener("click",()=>$e(null,Y));let re=d.querySelector("input[data-action=toggle-disable-streaming]"),Q=d.querySelector("input[data-action=toggle-writable-link]"),fe=d.querySelector("input[data-action=toggle-private-card]"),Ne=d.querySelector("[data-card-pref-status]"),Se=d.querySelector("[data-card-pref-moot]");async function se(Z,q,N=Ne){if(N){N.textContent="",N.className="oncall-status",q.disabled=!0;try{let F=await fetch(`/api/bots/${encodeURIComponent(g)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(Z)}),U=await F.json().catch(()=>({}));if(F.ok&&U.ok){N.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,N.classList.add("hint-ok");let W=ve.bots.find(de=>de.larkAppId===g);W&&(W.disableStreamingCard=U.disableStreamingCard,W.writableTerminalLinkInCard=U.writableTerminalLinkInCard,W.privateCard=U.privateCard,W.autoStartOnGroupJoin=U.autoStartOnGroupJoin,W.autoStartOnGroupJoinPrompt=U.autoStartOnGroupJoinPrompt,W.autoStartOnNewTopic=U.autoStartOnNewTopic,W.regularGroupReplyMode=U.regularGroupReplyMode,W.regularGroupMentionMode=U.regularGroupMentionMode)}else N.textContent=`\u2717 ${U.error??F.status}`,N.classList.add("hint-warn-inline")}catch(F){N.textContent=`\u2717 ${F?.message??F}`,N.classList.add("hint-warn-inline")}finally{q===Q?q.disabled=!!re?.checked:q.disabled=!1}}}re&&re.addEventListener("change",()=>{let Z=re.checked;Q&&(Q.disabled=Z),Se&&(Se.hidden=!Z),se({disableStreamingCard:Z},re)}),Q&&Q.addEventListener("change",()=>{se({writableTerminalLinkInCard:Q.checked},Q)}),fe&&fe.addEventListener("change",()=>{se({privateCard:fe.checked},fe)});let le=d.querySelector("input[data-action=toggle-sandbox]"),X=d.querySelector("[data-sandbox-status]");le&&le.addEventListener("change",async()=>{let Z=le.checked;X&&(X.textContent="",X.className="oncall-status"),le.disabled=!0;try{let q=await fetch(`/api/bots/${encodeURIComponent(g)}/sandbox`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:Z})}),N=await q.json().catch(()=>({}));if(q.ok&&N.ok){X&&(X.textContent=`\u2713 ${t("botDefaults.sandboxSaved")}`,X.classList.add("hint-ok"));let F=ve.bots.find(U=>U.larkAppId===g);F&&(F.sandbox=N.sandbox===!0)}else X&&(X.textContent=`\u2717 ${N.error??q.status}`,X.classList.add("hint-warn-inline")),le.checked=!Z}catch(q){X&&(X.textContent=`\u2717 ${q?.message??q}`,X.classList.add("hint-warn-inline")),le.checked=!Z}finally{le.disabled=!1}});let Ie=d.querySelector("input[data-action=toggle-auto-join]"),Me=d.querySelector("input[data-action=toggle-auto-topic]"),ie=d.querySelector("textarea[data-input=autoJoinPrompt]"),u=d.querySelector("button[data-action=save-auto-join-prompt]"),f=d.querySelector("[data-auto-start-status]");Ie&&Ie.addEventListener("change",()=>{se({autoStartOnGroupJoin:Ie.checked},Ie,f)}),Me&&Me.addEventListener("change",()=>{se({autoStartOnNewTopic:Me.checked},Me,f)}),ie&&u&&u.addEventListener("click",()=>{se({autoStartOnGroupJoinPrompt:ie.value},u,f)});let T=d.querySelector("select[data-input=p2pMode]"),I=d.querySelector("[data-p2p-status]");T&&I&&T.addEventListener("change",async()=>{let Z=T.value==="chat"?"chat":"thread";I.textContent="",I.className="oncall-status",T.disabled=!0;try{let q=await fetch(`/api/bots/${encodeURIComponent(g)}/p2p-mode`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({p2pMode:Z})}),N=await q.json().catch(()=>({}));if(q.ok&&N.ok){I.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,I.classList.add("hint-ok");let F=ve.bots.find(U=>U.larkAppId===g);F&&(F.p2pMode=N.p2pMode==="chat"?"chat":"thread")}else I.textContent=`\u2717 ${N.error??q.status}`,I.classList.add("hint-warn-inline")}catch(q){I.textContent=`\u2717 ${q?.message??q}`,I.classList.add("hint-warn-inline")}finally{T.disabled=!1}});let x=d.querySelector("select[data-input=regularGroupMode]"),j=d.querySelector("[data-regular-group-status]");x&&x.addEventListener("change",()=>{se({regularGroupReplyMode:x.value},x,j)});let G=d.querySelector("select[data-input=regularGroupMentionMode]"),te=d.querySelector("[data-mention-mode-status]");G&&G.addEventListener("change",()=>{se({regularGroupMentionMode:G.value},G,te)});let z=d.querySelector("textarea[data-input=teamRole]"),oe=d.querySelector("button[data-action=save-role]"),ae=d.querySelector("button[data-action=delete-role]"),J=d.querySelector("[data-role-status]");if(z&&oe&&ae&&J){let N=function(U){let W=n.querySelector(`.bd-card[data-appid="${CSS.escape(g)}"]`);if(!W)return;let de=W.querySelector("textarea[data-input=teamRole]"),Te=W.querySelector("button[data-action=save-role]"),ot=W.querySelector("button[data-action=delete-role]");de&&(de.value=U,de.disabled=!1),Te&&(Te.disabled=!1),ot&&(ot.disabled=!1)};var wt=N;let Z=`/api/team/local-bots/${encodeURIComponent(g)}/role`,q=ve.bots.find(U=>U.larkAppId===g);q&&typeof q.teamRole!="string"&&!q.teamRoleLoading&&(q.teamRoleLoading=!0,(async()=>{try{let U=await fetch(Z),W=await U.json().catch(()=>({}));U.ok&&W.ok?(q.teamRole=W.role??"",N(q.teamRole)):(J.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${W.error??U.status}`,J.classList.add("hint-warn-inline"))}catch(U){J.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${U?.message??U}`,J.classList.add("hint-warn-inline")}finally{q.teamRoleLoading=!1}})());async function F(U,W,de){if(J&&!(!q||typeof q.teamRole!="string")){J.textContent="",J.className="oncall-status",oe.disabled=!0,ae.disabled=!0;try{let Te=await fetch(Z,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({role:U})}),ot=await Te.json().catch(()=>({}));Te.ok&&ot.ok?(q&&(q.teamRole=U.trim()),J.textContent=`\u2713 ${de?t("botDefaults.roleDeleted"):t("botDefaults.roleSaved")}`,J.classList.add("hint-ok")):(J.textContent=`\u2717 ${ot.error??Te.status}`,J.classList.add("hint-warn-inline"))}catch(Te){J.textContent=`\u2717 ${Te?.message??Te}`,J.classList.add("hint-warn-inline")}finally{oe.disabled=!1,ae.disabled=!1}}}oe.addEventListener("click",()=>F(z.value,oe,!1)),ae.addEventListener("click",()=>{z.value="",F("",ae,!0)})}let xe=d.querySelector("input[data-action=toggle-restrict-grant]"),we=d.querySelector("input[data-input=quotaLimit]"),S=d.querySelector("button[data-action=save-quota]"),ne=d.querySelector("button[data-action=off-quota]"),R=d.querySelector("[data-grant-status]"),P=d.querySelector("[data-quota-state]");async function ge(Z,q){if(R){R.textContent="",R.className="oncall-status",q.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(g)}/grant-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(Z)}),F=await N.json().catch(()=>({}));if(N.ok&&F.ok){R.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,R.classList.add("hint-ok");let U=typeof F.messageQuotaDefaultLimit=="number"?F.messageQuotaDefaultLimit:null,W=ve.bots.find(de=>de.larkAppId===g);W&&(W.restrictGrantCommands=F.restrictGrantCommands===!0,W.messageQuotaDefaultLimit=U),P&&(P.textContent=E(U)),we&&"messageQuotaDefaultLimit"in Z&&(we.value=U==null?"":String(U))}else R.textContent=`\u2717 ${F.error??N.status}`,R.classList.add("hint-warn-inline")}catch(N){R.textContent=`\u2717 ${N?.message??N}`,R.classList.add("hint-warn-inline")}finally{q.disabled=!1}}}xe&&xe.addEventListener("change",()=>{ge({restrictGrantCommands:xe.checked},xe)}),we&&S&&S.addEventListener("click",()=>{let Z=we.value.trim();if(Z===""){ge({messageQuotaDefaultLimit:null},S);return}if(!/^[1-9]\d*$/.test(Z)){R&&(R.textContent=`\u2717 ${t("botDefaults.quotaInvalid")}`,R.className="oncall-status hint-warn-inline");return}ge({messageQuotaDefaultLimit:Number(Z)},S)}),we&&ne&&ne.addEventListener("click",()=>{we.value="",ge({messageQuotaDefaultLimit:null},ne)})})}i(),Ee().then(i),s.addEventListener("input",i)}var nn=4096,Et=[],Ae=null,De=null,ke="",tt=new Set;function Va(){return`<section class="page roles-page">
664
668
  <div class="page-heading">
665
669
  <div>
666
670
  <p class="eyebrow">${t("nav.roles")}</p>
@@ -699,7 +703,7 @@ ${f.join(`
699
703
  </div>
700
704
  </div>
701
705
  </div>
702
- </section>`}async function Lt(){It=((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 co(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`)).json()}async function ja(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 Fa(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`,{method:"DELETE"})).ok}function uo(e){return e.memberBots.filter(n=>n.inChat&&n.hasRole).length}function Ga(e){return e.memberBots.filter(n=>n.inChat).length}function je(e=""){let n=document.getElementById("roles-tree");if(!n)return;let o=e.toLowerCase(),s=It.filter(a=>{if(!o)return!0;let i=a.chatId.toLowerCase().includes(o)||(a.name??"").toLowerCase().includes(o),l=a.memberBots.some(c=>c.larkAppId.toLowerCase().includes(o)||(c.botName??"").toLowerCase().includes(o));return i||l});if(s.length===0){n.innerHTML=`<div class="roles-empty">${t("roles.noChats")}</div>`;return}n.innerHTML=s.map(a=>{let i=et.has(a.chatId),l=a.memberBots.filter(k=>k.inChat),c=i?"\u25BE":"\u25B8",w=uo(a),h=Ga(a),y=i?l.map(k=>`
706
+ </section>`}async function xt(){Et=((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 go(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`)).json()}async function Ya(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 Qa(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`,{method:"DELETE"})).ok}function bo(e){return e.memberBots.filter(n=>n.inChat&&n.hasRole).length}function Xa(e){return e.memberBots.filter(n=>n.inChat).length}function je(e=""){let n=document.getElementById("roles-tree");if(!n)return;let o=e.toLowerCase(),s=Et.filter(a=>{if(!o)return!0;let i=a.chatId.toLowerCase().includes(o)||(a.name??"").toLowerCase().includes(o),l=a.memberBots.some(c=>c.larkAppId.toLowerCase().includes(o)||(c.botName??"").toLowerCase().includes(o));return i||l});if(s.length===0){n.innerHTML=`<div class="roles-empty">${t("roles.noChats")}</div>`;return}n.innerHTML=s.map(a=>{let i=tt.has(a.chatId),l=a.memberBots.filter(k=>k.inChat),c=i?"\u25BE":"\u25B8",h=bo(a),b=Xa(a),v=i?l.map(k=>`
703
707
  <div class="roles-bot-row ${Ae===a.chatId&&De===k.larkAppId?"selected":""}"
704
708
  data-group-id="${r(a.chatId)}"
705
709
  data-bot-id="${r(k.larkAppId)}">
@@ -721,18 +725,18 @@ ${f.join(`
721
725
  <div class="roles-group-info">
722
726
  <div class="roles-group-name">${r(a.name??a.chatId)}</div>
723
727
  <div class="roles-group-meta">
724
- ${w}/${h} ${t("roles.botsWithRoles")}
728
+ ${h}/${b} ${t("roles.botsWithRoles")}
725
729
  </div>
726
730
  </div>
727
731
  <span class="roles-group-chevron"></span>
728
732
  </div>
729
- <div class="roles-bot-list">${y}</div>
730
- </div>`}).join(""),n.querySelectorAll(".roles-group-row").forEach(a=>{a.addEventListener("click",()=>{let i=a.dataset.groupId;i&&(et.has(i)?et.delete(i):et.add(i),je(document.getElementById("roles-search")?.value??""))})}),n.querySelectorAll(".roles-bot-row").forEach(a=>{a.addEventListener("click",i=>{i.stopPropagation();let l=a.dataset.groupId,c=a.dataset.botId;l&&c&&za(l,c)})})}async function za(e,n){Ae=e,De=n;let o=await co(n,e),s=document.getElementById("roles-editor-empty"),a=document.getElementById("roles-editor-form"),i=document.getElementById("roles-editor-textarea"),l=document.getElementById("roles-editor-group-name"),c=document.getElementById("roles-editor-bot-name"),w=document.getElementById("roles-editor-chat-id");s&&(s.style.display="none"),a&&(a.style.display="");let h=It.find(p=>p.chatId===e),y=h?.memberBots.find(p=>p.larkAppId===n);l&&(l.textContent=h?.name??e),c&&(c.textContent=y?.botName??n),w&&(w.textContent=`${e} \xB7 ${n}`),ke=o.content??"",i&&(i.value=ke,i.focus()),en(),tn(),je(document.getElementById("roles-search")?.value??"");let k=document.getElementById("roles-delete");k&&(k.style.display=o.hasRole?"":"none")}function en(){let e=document.getElementById("roles-editor-bytecount");if(!e)return;let n=new TextEncoder().encode(ke).length;e.textContent=`${n} / ${Zt} bytes`,e.className=`roles-bytecount ${n>3800?"warn":""} ${n>Zt?"over":""}`,_a(n)}function _a(e){let n=document.getElementById("roles-save");if(!n)return;let o=e??new TextEncoder().encode(ke).length;n.disabled=o>Zt||ke.trim().length===0}function tn(){let e=document.getElementById("roles-preview");e&&(ke.trim()?e.innerHTML=`<strong>${t("roles.preview")}</strong><pre>${r(ke)}</pre>`:e.innerHTML=`<small>${t("roles.previewEmpty")}</small>`)}function lo(){Ae=null,De=null,ke="";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 po(e){e.innerHTML=Ua(),et.clear(),lo(),await Lt(),await Ee();for(let n of It)uo(n)>0&&et.add(n.chatId);je(),document.getElementById("roles-search")?.addEventListener("input",n=>{je(n.target.value)}),document.getElementById("roles-refresh")?.addEventListener("click",async()=>{if(await Lt(),je(document.getElementById("roles-search")?.value??""),Ae&&De){let n=await co(De,Ae),o=document.getElementById("roles-editor-textarea");o&&(o.value=n.content??""),ke=n.content??"",en(),tn();let s=document.getElementById("roles-delete");s&&(s.style.display=n.hasRole?"":"none")}}),document.getElementById("roles-save")?.addEventListener("click",async function(){if(!(!Ae||!De)){this.disabled=!0,this.textContent="...";try{if(await ja(De,Ae,ke)){await Lt(),je(document.getElementById("roles-search")?.value??"");let o=document.getElementById("roles-delete");o&&(o.style.display="");let s=document.createElement("span");s.className="roles-saved-flash",s.textContent=` ${t("roles.saved")}`,document.querySelector(".roles-editor-footer")?.appendChild(s),setTimeout(()=>s.remove(),2e3)}else{let o=document.createElement("span");o.className="roles-saved-flash roles-save-error",o.textContent=ke.trim().length===0?` ${t("roles.emptyError")}`:` ${t("roles.saveFailed")}`,document.querySelector(".roles-editor-footer")?.appendChild(o),setTimeout(()=>o.remove(),3e3)}}finally{this.disabled=!1,this.textContent=t("roles.save")}}}),document.getElementById("roles-delete")?.addEventListener("click",async function(){if(!(!Ae||!De)&&confirm(t("roles.confirmDelete"))){this.disabled=!0,this.textContent="...";try{await Fa(De,Ae)&&(await Lt(),lo(),je(document.getElementById("roles-search")?.value??""))}finally{this.disabled=!1,this.textContent=t("roles.delete")}}}),document.getElementById("roles-editor-textarea")?.addEventListener("input",n=>{ke=n.target.value,en(),tn()})}async function Et(e){let n=await fetch(e);return{status:n.status,body:await n.json().catch(()=>({}))}}async function Ht(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 Ge=(e,n)=>Ht("POST",e,n),Wa=(e,n)=>Ht("PUT",e,n),nn=[],mo=[],fo="",Mt="",on=new Map,xt=new Map,it=new Set,rt=new Set;function J(e){return document.getElementById(e)}function Ct(){return[...nn,...mo]}function Fe(e){let n=on.get(e);return n||(n=new Set,on.set(e,n)),n}function Ja(e){return Ct().find(n=>n.key===e)}function go(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 Ka(){return`<section class="page">
733
+ <div class="roles-bot-list">${v}</div>
734
+ </div>`}).join(""),n.querySelectorAll(".roles-group-row").forEach(a=>{a.addEventListener("click",()=>{let i=a.dataset.groupId;i&&(tt.has(i)?tt.delete(i):tt.add(i),je(document.getElementById("roles-search")?.value??""))})}),n.querySelectorAll(".roles-bot-row").forEach(a=>{a.addEventListener("click",i=>{i.stopPropagation();let l=a.dataset.groupId,c=a.dataset.botId;l&&c&&Za(l,c)})})}async function Za(e,n){Ae=e,De=n;let o=await go(n,e),s=document.getElementById("roles-editor-empty"),a=document.getElementById("roles-editor-form"),i=document.getElementById("roles-editor-textarea"),l=document.getElementById("roles-editor-group-name"),c=document.getElementById("roles-editor-bot-name"),h=document.getElementById("roles-editor-chat-id");s&&(s.style.display="none"),a&&(a.style.display="");let b=Et.find(m=>m.chatId===e),v=b?.memberBots.find(m=>m.larkAppId===n);l&&(l.textContent=b?.name??e),c&&(c.textContent=v?.botName??n),h&&(h.textContent=`${e} \xB7 ${n}`),ke=o.content??"",i&&(i.value=ke,i.focus()),on(),an(),je(document.getElementById("roles-search")?.value??"");let k=document.getElementById("roles-delete");k&&(k.style.display=o.hasRole?"":"none")}function on(){let e=document.getElementById("roles-editor-bytecount");if(!e)return;let n=new TextEncoder().encode(ke).length;e.textContent=`${n} / ${nn} bytes`,e.className=`roles-bytecount ${n>3800?"warn":""} ${n>nn?"over":""}`,es(n)}function es(e){let n=document.getElementById("roles-save");if(!n)return;let o=e??new TextEncoder().encode(ke).length;n.disabled=o>nn||ke.trim().length===0}function an(){let e=document.getElementById("roles-preview");e&&(ke.trim()?e.innerHTML=`<strong>${t("roles.preview")}</strong><pre>${r(ke)}</pre>`:e.innerHTML=`<small>${t("roles.previewEmpty")}</small>`)}function fo(){Ae=null,De=null,ke="";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 ho(e){e.innerHTML=Va(),tt.clear(),fo();let n=document.getElementById("roles-tree");n&&(n.innerHTML=Ye()),await xt(),await Ee();for(let o of Et)bo(o)>0&&tt.add(o.chatId);je(),document.getElementById("roles-search")?.addEventListener("input",o=>{je(o.target.value)}),document.getElementById("roles-refresh")?.addEventListener("click",async()=>{if(await xt(),je(document.getElementById("roles-search")?.value??""),Ae&&De){let o=await go(De,Ae),s=document.getElementById("roles-editor-textarea");s&&(s.value=o.content??""),ke=o.content??"",on(),an();let a=document.getElementById("roles-delete");a&&(a.style.display=o.hasRole?"":"none")}}),document.getElementById("roles-save")?.addEventListener("click",async function(){if(!(!Ae||!De)){this.disabled=!0,this.textContent="...";try{if(await Ya(De,Ae,ke)){await xt(),je(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=ke.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(!(!Ae||!De)&&confirm(t("roles.confirmDelete"))){this.disabled=!0,this.textContent="...";try{await Qa(De,Ae)&&(await xt(),fo(),je(document.getElementById("roles-search")?.value??""))}finally{this.disabled=!1,this.textContent=t("roles.delete")}}}),document.getElementById("roles-editor-textarea")?.addEventListener("input",o=>{ke=o.target.value,on(),an()})}async function At(e){let n=await fetch(e);return{status:n.status,body:await n.json().catch(()=>({}))}}async function Dt(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 Ge=(e,n)=>Dt("POST",e,n),ts=(e,n)=>Dt("PUT",e,n),sn=[],wo=[],yo="",Ht="",rn=new Map,Ct=new Map,lt=new Set,dt=new Set;function K(e){return document.getElementById(e)}function Rt(){return[...sn,...wo]}function Fe(e){let n=rn.get(e);return n||(n=new Set,rn.set(e,n)),n}function ns(e){return Rt().find(n=>n.key===e)}function vo(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 os(){return`<section class="page">
731
735
  <div class="page-heading"><div>
732
736
  <p class="eyebrow">${t("team.eyebrow")}</p><h1>${t("team.homeTitle")}</h1>
733
737
  <p class="tf-lede">${t("team.homeLede")}</p>
734
738
  </div></div>
735
- ${go("home")}
739
+ ${vo("home")}
736
740
  <div class="card" style="margin-bottom:16px">
737
741
  <h2 style="margin-top:0">${t("team.localDeployTitle")}</h2>
738
742
  <p>${t("team.myIdentity")}<b id="tf-owner">${t("team.unbound")}</b>
@@ -761,12 +765,12 @@ ${go("home")}
761
765
  </div>
762
766
  </div>
763
767
  </div>
764
- </section>`}function Va(e){let n=(J("tf-search").value||"").trim().toLowerCase();if(n&&!((e.name||"")+" "+(e.cliId||"")+" "+(e.capability||"")).toLowerCase().includes(n))return!1;let o=J("tf-cli").value;return!(o&&e.cliId!==o||J("tf-fcap").checked&&!e.capability||J("tf-frole").checked&&!e.hasTeamRole)}function Ya(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(p=>p.deployment.id===a.id);if(!i.length)continue;let l=a.id===fo,c=l?t("team.tagLocal"):a.stale?t("team.tagRemoteStale"):t("team.tagRemote"),w=e.kind==="local"&&!l?` <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>`:"",h=`${e.key}::${a.id}`,y=rt.has(h),k=i.filter(p=>Fe(e.key).has(p.larkAppId)).length;if(s+=`<div class="tf-dep-h" data-dk="${r(h)}" style="cursor:pointer;margin:10px 0 2px"><b>${y?"\u25BE":"\u25B8"} ${r(a.name)}</b> <span class="muted" style="font-size:12px">${t("team.depTag",{tag:c})} \xB7 ${t("team.depCount",{count:i.length})}${k?t("team.depSelected",{n:k}):""}</span>${w}</div>`,!!y){s+='<table style="width:100%;border-collapse:collapse;font-size:14px"><tbody>';for(let p of i){let E=r(p.larkAppId),O=Fe(e.key).has(p.larkAppId)?" checked":"",T=p.deployment.stale?"opacity:.55":"",f=l?`<input class="tf-cap" data-app="${E}" value="${r(p.capability||"")}" placeholder="${t("team.capPh")}" style="width:92%;padding:3px 6px">`:p.capability?r(p.capability):'<span class="muted">\u2014</span>',v=p.hasTeamRole?l?`<button class="tf-role" data-app="${E}" data-name="${r(p.name)}">${t("team.viewRole")}</button>`:t("team.hasRoleShort"):'<span class="muted">\u2014</span>';s+=`<tr style="${T}"><td style="padding:4px 8px"><input type="checkbox" class="tf-pick" data-tk="${r(e.key)}" data-app="${E}"${O}></td><td style="padding:4px 8px">${r(p.name)}</td><td style="padding:4px 8px" class="muted">${r(p.cliId)}</td><td style="padding:4px 8px">${f}</td><td style="padding:4px 8px">${v}</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(xt.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 qe(){let e=J("tf-teams"),n=Ct();if(!n.length){e.innerHTML=`<p class="muted">${t("team.noTeams")}</p>`,J("tf-count").textContent="";return}let o="",s=new Set,a=new Set;for(let c of n){let w=c.bots.filter(Va);w.forEach(p=>s.add(p.larkAppId)),c.bots.forEach(p=>a.add(p.larkAppId));let h=new Set(w.map(p=>p.larkAppId));[...Fe(c.key)].forEach(p=>{h.has(p)||Fe(c.key).delete(p)});let y=!it.has(c.key),k=c.kind==="remote"?c.ok?` <span class="ok" style="font-size:12px">${t("team.connected")}</span>`:` <span class="err" style="font-size:12px">${t("team.connectFail",{error:r(c.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(c.key)}" style="cursor:pointer;display:flex;align-items:center;gap:8px;flex-wrap:wrap"><b style="font-size:15px">${y?"\u25B8":"\u25BE"} ${r(c.label)}</b>`+(c.sub?` <span class="muted" style="font-size:12px">${r(c.sub)}</span>`:"")+k+` <span class="muted" style="font-size:12px">\xB7 ${t("team.teamMeta",{deps:c.deployments.length,bots:c.bots.length})}</span></div>`,y||(o+=c.kind==="remote"&&!c.ok?`<p class="muted" style="margin:8px 0 0">${t("team.rosterFail")}</p>`:Ya(c,w)),o+="</div>"}e.innerHTML=o;let i=n.length>1?t("team.acrossTeams",{n:n.length}):"",l=s.size===a.size?`${a.size}`:`${s.size} / ${a.size}`;J("tf-count").textContent=`\xB7 ${l} ${t("team.botsWord")}${i}`,Qa()}function Qa(){let e=J("tf-teams");e.querySelectorAll(".tf-team-h").forEach(n=>{n.onclick=()=>{let o=n.dataset.tk;it.has(o)?it.delete(o):it.add(o),qe()}}),e.querySelectorAll(".tf-dep-h").forEach(n=>{n.onclick=()=>{let o=n.dataset.dk;rt.has(o)?rt.delete(o):rt.add(o),qe()}}),e.querySelectorAll(".tf-pick").forEach(n=>{n.onchange=()=>{let o=Fe(n.dataset.tk);n.checked?o.add(n.dataset.app):o.delete(n.dataset.app)}}),e.querySelectorAll(".tf-gname").forEach(n=>{n.oninput=()=>{xt.set(n.dataset.tk,n.value)}}),e.querySelectorAll(".tf-cap").forEach(n=>{n.onchange=async()=>{let o=n.dataset.app,s=n.value;await Wa("/api/team/local-bots/"+encodeURIComponent(o)+"/capability",{capability:s}),Ct().forEach(a=>{let i=a.bots.find(l=>l.larkAppId===o);i&&(i.capability=s.trim()||null)})}}),e.querySelectorAll(".tf-role").forEach(n=>{n.onclick=()=>Za(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 Ht("DELETE",`/api/team/hosted/${encodeURIComponent(n.dataset.team)}/members/${encodeURIComponent(n.dataset.dep)}`),lt())}}),e.querySelectorAll(".tf-grp").forEach(n=>{n.onclick=async()=>{let o=n.dataset.tk,s=Ja(o);if(!s)return;let a=[...Fe(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 l=(e.querySelector(`.tf-gname[data-tk="${CSS.escape(o)}"]`)?.value||"").trim()||t("team.defaultGroupName");i.innerHTML=`<span class="muted">${t("team.creatingGroup")}</span>`;let c=s.kind==="local"?await Ge("/api/team/federated-group",{name:l,larkAppIds:a,teamId:s.teamId}):await Ge("/api/team/remote-group",{hubUrl:s.hubUrl,teamId:s.teamId,name:l,larkAppIds:a});if(Xa(i,c.body,c.status),c.body?.ok){Fe(o).clear(),xt.delete(o);let w=i.innerHTML,h=()=>{let y=e.querySelector(`.tf-gout[data-tk="${CSS.escape(o)}"]`);y&&(y.innerHTML=w)};s.kind==="local"?lt().then(h):(qe(),h())}}})}function Xa(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>`:"",l=n.missingOperatorIdentity?`<span class="err"> \xB7 ${t("team.missingIdentity")}</span>`:"",c=(n.skippedNoOwner||[]).length?`<span class="err"> \xB7 ${t("team.skippedNoOwner",{n:(n.skippedNoOwner||[]).length})}</span>`:"",w=n.delegatedTo?t("team.delegatedBy",{name:r(n.delegatedTo)}):"";e.innerHTML=`<span class="ok">${t("team.groupCreated")}</span>${w} \xB7 <a href="${r(s)}" target="_blank">${t("team.openInLark")}</a>${a}${i}${l}${c}`}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 Za(e,n){let o=await Et("/api/team/local-bots/"+encodeURIComponent(e)+"/role");J("tf-modal-title").textContent=t("team.roleModalTitleName",{name:n}),J("tf-modal-text").value=o.body?.role||"",J("tf-modal").dataset.app=e,J("tf-modal").style.display="flex"}function bo(){let e=Array.from(new Set(Ct().flatMap(s=>s.bots.map(a=>a.cliId)).filter(Boolean))).sort(),n=J("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 lt(){let n=(await Et("/api/team/hosted")).body;if(!n?.ok){nn=[],qe();return}fo=n.deployment.deploymentId,Mt=n.suggestedHubUrl||"",J("tf-owner").textContent=n.deployment.ownerName||(n.deployment.ownerUnionId?t("team.bound"):t("team.unbound")),nn=(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||[]})),bo(),qe()}async function es(){mo=((await Et("/api/team/remote-roster")).body?.memberships||[]).map(o=>{let s=o.roster?.deployments||[],a=s.find(l=>l.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||[]}}),bo(),qe()}function ho(e){e.innerHTML=Ka(),on.clear(),xt.clear(),it.clear(),rt.clear(),["tf-search","tf-cli","tf-fcap","tf-frole"].forEach(n=>{let o=J(n);o.oninput=qe,o.onchange=qe}),J("tf-modal-cancel").onclick=()=>{J("tf-modal").style.display="none"},ns(),lt(),es()}function ts(){return`<section class="page">
768
+ </section>`}function as(e){let n=(K("tf-search").value||"").trim().toLowerCase();if(n&&!((e.name||"")+" "+(e.cliId||"")+" "+(e.capability||"")).toLowerCase().includes(n))return!1;let o=K("tf-cli").value;return!(o&&e.cliId!==o||K("tf-fcap").checked&&!e.capability||K("tf-frole").checked&&!e.hasTeamRole)}function ss(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(m=>m.deployment.id===a.id);if(!i.length)continue;let l=a.id===yo,c=l?t("team.tagLocal"):a.stale?t("team.tagRemoteStale"):t("team.tagRemote"),h=e.kind==="local"&&!l?` <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>`:"",b=`${e.key}::${a.id}`,v=dt.has(b),k=i.filter(m=>Fe(e.key).has(m.larkAppId)).length;if(s+=`<div class="tf-dep-h" data-dk="${r(b)}" style="cursor:pointer;margin:10px 0 2px"><b>${v?"\u25BE":"\u25B8"} ${r(a.name)}</b> <span class="muted" style="font-size:12px">${t("team.depTag",{tag:c})} \xB7 ${t("team.depCount",{count:i.length})}${k?t("team.depSelected",{n:k}):""}</span>${h}</div>`,!!v){s+='<table style="width:100%;border-collapse:collapse;font-size:14px"><tbody>';for(let m of i){let D=r(m.larkAppId),E=Fe(e.key).has(m.larkAppId)?" checked":"",C=m.deployment.stale?"opacity:.55":"",w=l?`<input class="tf-cap" data-app="${D}" value="${r(m.capability||"")}" placeholder="${t("team.capPh")}" style="width:92%;padding:3px 6px">`:m.capability?r(m.capability):'<span class="muted">\u2014</span>',$=m.hasTeamRole?l?`<button class="tf-role" data-app="${D}" data-name="${r(m.name)}">${t("team.viewRole")}</button>`:t("team.hasRoleShort"):'<span class="muted">\u2014</span>';s+=`<tr style="${C}"><td style="padding:4px 8px"><input type="checkbox" class="tf-pick" data-tk="${r(e.key)}" data-app="${D}"${E}></td><td style="padding:4px 8px">${r(m.name)}</td><td style="padding:4px 8px" class="muted">${r(m.cliId)}</td><td style="padding:4px 8px">${w}</td><td style="padding:4px 8px">${$}</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(Ct.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 qe(){let e=K("tf-teams"),n=Rt();if(!n.length){e.innerHTML=`<p class="muted">${t("team.noTeams")}</p>`,K("tf-count").textContent="";return}let o="",s=new Set,a=new Set;for(let c of n){let h=c.bots.filter(as);h.forEach(m=>s.add(m.larkAppId)),c.bots.forEach(m=>a.add(m.larkAppId));let b=new Set(h.map(m=>m.larkAppId));[...Fe(c.key)].forEach(m=>{b.has(m)||Fe(c.key).delete(m)});let v=!lt.has(c.key),k=c.kind==="remote"?c.ok?` <span class="ok" style="font-size:12px">${t("team.connected")}</span>`:` <span class="err" style="font-size:12px">${t("team.connectFail",{error:r(c.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(c.key)}" style="cursor:pointer;display:flex;align-items:center;gap:8px;flex-wrap:wrap"><b style="font-size:15px">${v?"\u25B8":"\u25BE"} ${r(c.label)}</b>`+(c.sub?` <span class="muted" style="font-size:12px">${r(c.sub)}</span>`:"")+k+` <span class="muted" style="font-size:12px">\xB7 ${t("team.teamMeta",{deps:c.deployments.length,bots:c.bots.length})}</span></div>`,v||(o+=c.kind==="remote"&&!c.ok?`<p class="muted" style="margin:8px 0 0">${t("team.rosterFail")}</p>`:ss(c,h)),o+="</div>"}e.innerHTML=o;let i=n.length>1?t("team.acrossTeams",{n:n.length}):"",l=s.size===a.size?`${a.size}`:`${s.size} / ${a.size}`;K("tf-count").textContent=`\xB7 ${l} ${t("team.botsWord")}${i}`,is()}function is(){let e=K("tf-teams");e.querySelectorAll(".tf-team-h").forEach(n=>{n.onclick=()=>{let o=n.dataset.tk;lt.has(o)?lt.delete(o):lt.add(o),qe()}}),e.querySelectorAll(".tf-dep-h").forEach(n=>{n.onclick=()=>{let o=n.dataset.dk;dt.has(o)?dt.delete(o):dt.add(o),qe()}}),e.querySelectorAll(".tf-pick").forEach(n=>{n.onchange=()=>{let o=Fe(n.dataset.tk);n.checked?o.add(n.dataset.app):o.delete(n.dataset.app)}}),e.querySelectorAll(".tf-gname").forEach(n=>{n.oninput=()=>{Ct.set(n.dataset.tk,n.value)}}),e.querySelectorAll(".tf-cap").forEach(n=>{n.onchange=async()=>{let o=n.dataset.app,s=n.value;await ts("/api/team/local-bots/"+encodeURIComponent(o)+"/capability",{capability:s}),Rt().forEach(a=>{let i=a.bots.find(l=>l.larkAppId===o);i&&(i.capability=s.trim()||null)})}}),e.querySelectorAll(".tf-role").forEach(n=>{n.onclick=()=>ls(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 Dt("DELETE",`/api/team/hosted/${encodeURIComponent(n.dataset.team)}/members/${encodeURIComponent(n.dataset.dep)}`),ct())}}),e.querySelectorAll(".tf-grp").forEach(n=>{n.onclick=async()=>{let o=n.dataset.tk,s=ns(o);if(!s)return;let a=[...Fe(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 l=(e.querySelector(`.tf-gname[data-tk="${CSS.escape(o)}"]`)?.value||"").trim()||t("team.defaultGroupName");i.innerHTML=`<span class="muted">${t("team.creatingGroup")}</span>`;let c=s.kind==="local"?await Ge("/api/team/federated-group",{name:l,larkAppIds:a,teamId:s.teamId}):await Ge("/api/team/remote-group",{hubUrl:s.hubUrl,teamId:s.teamId,name:l,larkAppIds:a});if(rs(i,c.body,c.status),c.body?.ok){Fe(o).clear(),Ct.delete(o);let h=i.innerHTML,b=()=>{let v=e.querySelector(`.tf-gout[data-tk="${CSS.escape(o)}"]`);v&&(v.innerHTML=h)};s.kind==="local"?ct().then(b):(qe(),b())}}})}function rs(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>`:"",l=n.missingOperatorIdentity?`<span class="err"> \xB7 ${t("team.missingIdentity")}</span>`:"",c=(n.skippedNoOwner||[]).length?`<span class="err"> \xB7 ${t("team.skippedNoOwner",{n:(n.skippedNoOwner||[]).length})}</span>`:"",h=n.delegatedTo?t("team.delegatedBy",{name:r(n.delegatedTo)}):"";e.innerHTML=`<span class="ok">${t("team.groupCreated")}</span>${h} \xB7 <a href="${r(s)}" target="_blank">${t("team.openInLark")}</a>${a}${i}${l}${c}`}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 ls(e,n){let o=await At("/api/team/local-bots/"+encodeURIComponent(e)+"/role");K("tf-modal-title").textContent=t("team.roleModalTitleName",{name:n}),K("tf-modal-text").value=o.body?.role||"",K("tf-modal").dataset.app=e,K("tf-modal").style.display="flex"}function ko(){let e=Array.from(new Set(Rt().flatMap(s=>s.bots.map(a=>a.cliId)).filter(Boolean))).sort(),n=K("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 ct(){let n=(await At("/api/team/hosted")).body;if(!n?.ok){sn=[],qe();return}yo=n.deployment.deploymentId,Ht=n.suggestedHubUrl||"",K("tf-owner").textContent=n.deployment.ownerName||(n.deployment.ownerUnionId?t("team.bound"):t("team.unbound")),sn=(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||[]})),ko(),qe()}async function ds(){wo=((await At("/api/team/remote-roster")).body?.memberships||[]).map(o=>{let s=o.roster?.deployments||[],a=s.find(l=>l.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||[]}}),ko(),qe()}function $o(e){e.innerHTML=os(),rn.clear(),Ct.clear(),lt.clear(),dt.clear(),["tf-search","tf-cli","tf-fcap","tf-frole"].forEach(n=>{let o=K(n);o.oninput=qe,o.onchange=qe}),K("tf-modal-cancel").onclick=()=>{K("tf-modal").style.display="none"},us(),ct(),ds()}function cs(){return`<section class="page">
765
769
  <div class="page-heading"><div>
766
770
  <p class="eyebrow">${t("team.eyebrow")}</p><h1>${t("team.manageTitle")}</h1>
767
771
  <p class="tf-lede">${t("team.manageLede")}</p>
768
772
  </div></div>
769
- ${go("manage")}
773
+ ${vo("manage")}
770
774
  <div class="card" style="margin-bottom:16px">
771
775
  <h2 style="margin-top:0">${t("team.hostedTitle")}</h2>
772
776
  <p style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:6px">
@@ -785,7 +789,7 @@ ${go("manage")}
785
789
  </p>
786
790
  <div id="tm-join-out" style="display:none;margin-top:6px"></div>
787
791
  </div>
788
- </section>`}async function an(){let n=(await Et("/api/team/hosted")).body,o=J("tm-list");Mt=n?.suggestedHubUrl||Mt;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(l=>!l.local).length;return`<div class="card" style="margin:0 0 8px;padding:10px 14px;background:var(--bg-soft,#f6f7f9)">
792
+ </section>`}async function ln(){let n=(await At("/api/team/hosted")).body,o=K("tm-list");Ht=n?.suggestedHubUrl||Ht;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(l=>!l.local).length;return`<div class="card" style="margin:0 0 8px;padding:10px 14px;background:var(--bg-soft,#f6f7f9)">
789
793
  <div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
790
794
  <b>${r(a.name)}</b>${a.isDefault?` <span class="muted" style="font-size:12px">${t("team.default")}</span>`:""}
791
795
  <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>
@@ -794,7 +798,7 @@ ${go("manage")}
794
798
  ${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>`}
795
799
  </span>
796
800
  </div>
797
- <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,l=o.querySelector(`.tm-inv-out[data-team="${CSS.escape(i)}"]`);l.style.display="",l.innerHTML=`<span class="muted">${t("team.generating")}</span>`;let c=await Ge("/api/team/local-invite",{teamId:i});c.body?.code?l.innerHTML=`${t("team.inviteResultLede")}<br>${t("team.inviteHub")}<code>${r(Mt)}</code><br>${t("team.inviteCode")}<code style="font-size:15px">${r(c.body.code)}</code>`:l.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 Ht("DELETE","/api/team/hosted/"+encodeURIComponent(a.dataset.team)),an())}})}function wo(e){e.innerHTML=ts(),J("tm-create").onclick=async()=>{let n=J("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 Ge("/api/team/hosted",{name:n});s.body?.ok?(o.innerHTML=`<span class="ok">${t("team.created")}</span>`,J("tm-newname").value="",an()):o.innerHTML=`<span class="err">${t("team.createFail",{error:r(String(s.body?.error||s.status))})}</span>`},J("tm-join").onclick=async()=>{let n=J("tm-hub").value.trim(),o=J("tm-code").value.trim(),s=J("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 Ge("/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>`,J("tm-code").value="";else{let i=a.body?.error||a.status,l=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(l))}</span>`}},an()}function ns(){J("tf-autobind").onclick=async()=>{let e=J("tf-bind-out");e.style.display="",e.innerHTML=`<span class="muted">${t("team.identifying")}</span>`;let o=(await Ge("/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>`,lt();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 l=(await Ge("/api/team/identity/auto-bind",{unionId:a.dataset.union})).body;l?.ok&&l.owner?(e.innerHTML=`<span class="ok">${t("team.bound2",{name:r(l.owner.name||l.owner.unionId)})}</span>`,lt()):e.innerHTML=`<span class="err">${t("team.bindFail",{error:r(String(l?.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 sn(e){let n=await fetch(e);return{status:n.status,body:await n.json().catch(()=>({}))}}async function ln(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 K(e){return document.getElementById(e)}function ze(e){return(K(e).value||"").trim()}var dn=[],un=[];function os(){return`<section class="page">
801
+ <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,l=o.querySelector(`.tm-inv-out[data-team="${CSS.escape(i)}"]`);l.style.display="",l.innerHTML=`<span class="muted">${t("team.generating")}</span>`;let c=await Ge("/api/team/local-invite",{teamId:i});c.body?.code?l.innerHTML=`${t("team.inviteResultLede")}<br>${t("team.inviteHub")}<code>${r(Ht)}</code><br>${t("team.inviteCode")}<code style="font-size:15px">${r(c.body.code)}</code>`:l.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 Dt("DELETE","/api/team/hosted/"+encodeURIComponent(a.dataset.team)),ln())}})}function So(e){e.innerHTML=cs(),K("tm-create").onclick=async()=>{let n=K("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 Ge("/api/team/hosted",{name:n});s.body?.ok?(o.innerHTML=`<span class="ok">${t("team.created")}</span>`,K("tm-newname").value="",ln()):o.innerHTML=`<span class="err">${t("team.createFail",{error:r(String(s.body?.error||s.status))})}</span>`},K("tm-join").onclick=async()=>{let n=K("tm-hub").value.trim(),o=K("tm-code").value.trim(),s=K("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 Ge("/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>`,K("tm-code").value="";else{let i=a.body?.error||a.status,l=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(l))}</span>`}},ln()}function us(){K("tf-autobind").onclick=async()=>{let e=K("tf-bind-out");e.style.display="",e.innerHTML=`<span class="muted">${t("team.identifying")}</span>`;let o=(await Ge("/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>`,ct();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 l=(await Ge("/api/team/identity/auto-bind",{unionId:a.dataset.union})).body;l?.ok&&l.owner?(e.innerHTML=`<span class="ok">${t("team.bound2",{name:r(l.owner.name||l.owner.unionId)})}</span>`,ct()):e.innerHTML=`<span class="err">${t("team.bindFail",{error:r(String(l?.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 dn(e){let n=await fetch(e);return{status:n.status,body:await n.json().catch(()=>({}))}}async function un(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 V(e){return document.getElementById(e)}function ze(e){return(V(e).value||"").trim()}var pn=[],fn=[];function ps(){return`<section class="page">
798
802
  <div class="page-heading">
799
803
  <div>
800
804
  <p class="eyebrow">Webhook</p>
@@ -856,11 +860,11 @@ ${go("manage")}
856
860
  <h2 style="margin-top:0">${t("connectors.listTitle")} <span class="muted" id="cn-count" style="font-size:13px"></span></h2>
857
861
  <div id="cn-list">${t("connectors.loading")}</div>
858
862
  </div>
859
- </section>`}function rn(){let e=K("cn-kind").value,n=K("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 yo(e){return`${location.origin}/webhook/${encodeURIComponent(e)}`}function as(e){return e==="fixed"?t("connectors.modeLabelFixed"):e==="new-group"?t("connectors.modeLabelNewGroup"):t("connectors.modeLabelDynamic")}function ss(e){return e==="workflow"?t("connectors.kindLabelWorkflow"):t("connectors.kindLabelTurn")}function cn(e){return un.find(o=>o.chatId===e)?.name||e}function is(e){return un.filter(n=>n.bots.includes(e))}function vo(){let e=K("cn-bot").value,n=is(e),o=c=>`<option value="${r(c.chatId)}">${r(c.name||c.chatId)}</option>`,s=K("cn-chat-sel"),a=s.value;s.innerHTML=n.length?n.map(o).join(""):`<option value="">${t("connectors.noBotGroups")}</option>`,a&&n.some(c=>c.chatId===a)&&(s.value=a);let i=K("cn-allow-sel"),l=new Set(Array.from(i.selectedOptions).map(c=>c.value));i.innerHTML=n.map(o).join(""),Array.from(i.options).forEach(c=>{l.has(c.value)&&(c.selected=!0)})}function rs(e){let n=K("cn-list");if(K("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=dn.find(w=>w.larkAppId===o.target.botId),a=yo(o.id),i=(o.verify?.type??"token")==="token",l=i?t("connectors.badgeToken"):t("connectors.badgeSign"),c=o.target.mode==="fixed"&&o.target.chatId?` \xB7 ${t("connectors.dest",{name:r(cn(o.target.chatId))})}`:"";return`<div class="card" style="margin:0 0 10px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
863
+ </section>`}function cn(){let e=V("cn-kind").value,n=V("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 To(e){return`${location.origin}/webhook/${encodeURIComponent(e)}`}function ms(e){return e==="fixed"?t("connectors.modeLabelFixed"):e==="new-group"?t("connectors.modeLabelNewGroup"):t("connectors.modeLabelDynamic")}function fs(e){return e==="workflow"?t("connectors.kindLabelWorkflow"):t("connectors.kindLabelTurn")}function mn(e){return fn.find(o=>o.chatId===e)?.name||e}function gs(e){return fn.filter(n=>n.bots.includes(e))}function Lo(){let e=V("cn-bot").value,n=gs(e),o=c=>`<option value="${r(c.chatId)}">${r(c.name||c.chatId)}</option>`,s=V("cn-chat-sel"),a=s.value;s.innerHTML=n.length?n.map(o).join(""):`<option value="">${t("connectors.noBotGroups")}</option>`,a&&n.some(c=>c.chatId===a)&&(s.value=a);let i=V("cn-allow-sel"),l=new Set(Array.from(i.selectedOptions).map(c=>c.value));i.innerHTML=n.map(o).join(""),Array.from(i.options).forEach(c=>{l.has(c.value)&&(c.selected=!0)})}function bs(e){let n=V("cn-list");if(V("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=pn.find(h=>h.larkAppId===o.target.botId),a=To(o.id),i=(o.verify?.type??"token")==="token",l=i?t("connectors.badgeToken"):t("connectors.badgeSign"),c=o.target.mode==="fixed"&&o.target.chatId?` \xB7 ${t("connectors.dest",{name:r(mn(o.target.chatId))})}`:"";return`<div class="card" style="margin:0 0 10px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
860
864
  <div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
861
865
  <b style="font-size:15px">${r(o.name)}</b>
862
866
  <span class="${o.enabled?"ok":"muted"}" style="font-size:12px">${o.enabled?t("connectors.enabled"):t("connectors.disabled")}</span>
863
- <span class="muted" style="font-size:12px">\xB7 ${r(s?.botName||o.target.botId)} \xB7 ${ss(o.target.kind)} \xB7 ${as(o.target.mode)}${c} \xB7 ${l}</span>
867
+ <span class="muted" style="font-size:12px">\xB7 ${r(s?.botName||o.target.botId)} \xB7 ${fs(o.target.kind)} \xB7 ${ms(o.target.mode)}${c} \xB7 ${l}</span>
864
868
  <span style="margin-left:auto;display:flex;gap:6px">
865
869
  <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>
866
870
  <button class="cn-del ghost" data-id="${r(o.id)}" style="font-size:12px">${t("connectors.btnDel")}</button>
@@ -869,15 +873,15 @@ ${go("manage")}
869
873
  <div style="margin-top:6px;font-size:13px;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
870
874
  <span class="muted">${t("connectors.webhookUrl")}</span><code style="font-size:12px;word-break:break-all">${r(a)}${i?"/&lt;token&gt;":""}</code>
871
875
  <button class="cn-copy ghost" data-url="${r(a)}" style="font-size:12px">${t("connectors.copy")}</button>
872
- </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 ln("PATCH","/api/connectors/"+encodeURIComponent(o.dataset.id),{enabled:o.dataset.on!=="true"}),At()}}),n.querySelectorAll(".cn-del").forEach(o=>{o.onclick=async()=>{confirm(t("connectors.delConfirm"))&&(await ln("DELETE","/api/connectors/"+encodeURIComponent(o.dataset.id)),At())}})}async function At(){let[e,n,o]=await Promise.all([sn("/api/bots"),sn("/api/connectors"),sn("/api/groups")]);dn=(e.body?.bots||[]).map(i=>({larkAppId:i.larkAppId,botName:i.botName||i.larkAppId})),un=(o.body?.chats||[]).map(i=>({chatId:i.chatId,name:i.name||"",bots:(i.memberBots||[]).filter(l=>l.inChat).map(l=>l.larkAppId)}));let s=K("cn-bot"),a=s.value;s.innerHTML=dn.map(i=>`<option value="${r(i.larkAppId)}">${r(i.botName)}</option>`).join("")||`<option value="">${t("connectors.noOnlineBots")}</option>`,a&&(s.value=a),vo(),rs(n.body?.connectors||[])}function ko(e){e.innerHTML=os(),K("cn-kind").onchange=rn,K("cn-mode").onchange=rn,K("cn-bot").onchange=vo,K("cn-chat-manual").onclick=n=>{n.preventDefault();let o=K("cn-chat"),s=K("cn-chat-sel"),a=o.style.display==="none";o.style.display=a?"":"none",s.style.display=a?"none":"",K("cn-chat-manual").textContent=a?t("connectors.chatListLink"):t("connectors.chatManualLink")},rn(),K("cn-create").onclick=async()=>{let n=K("cn-create-out"),o=ze("cn-name"),s=K("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=K("cn-kind").value,i=K("cn-mode").value,l={name:o,enabled:!0,target:{kind:a,mode:i,botId:s},promptEnvelope:{sourceName:o}},c=ze("cn-instruction");if(c&&(l.promptEnvelope.instruction=c),a==="workflow"){if(!ze("cn-wf")){n.innerHTML=`<span class="err">${t("connectors.errWf")}</span>`;return}l.target.workflowId=ze("cn-wf")}if(i==="fixed"){let k=K("cn-chat").style.display!=="none"?ze("cn-chat"):K("cn-chat-sel").value;if(!k){n.innerHTML=`<span class="err">${t("connectors.errChat")}</span>`;return}l.target.chatId=k}else{let y=Array.from(K("cn-allow-sel").selectedOptions).map(k=>k.value).filter(Boolean);y.length&&(l.target.allowChats=y)}if(i==="new-group"){let y=ze("cn-dedup");l.lifecycleExtractors=y?{dedupKey:y}:null}l.verify={type:K("cn-verify").value};let w=ze("cn-secret");w&&(l.secret=w),n.innerHTML=`<span class="muted">${t("connectors.creating")}</span>`;let h=await ln("POST","/api/connectors",l);if(h.status===201&&h.body?.ok){n.innerHTML="";let y=K("cn-created");y.style.display="";let k=h.body.webhookUrl||yo(h.body.connector.id),p=h.body.secret,E=(h.body.connector?.verify?.type??"token")==="token",O=i==="dynamic",T=O?l.target.allowChats?.[0]||"<chatId>":"",f=O?`${r(k)}?chatId=${r(T)}`:r(k),v;if(E&&O){let d=T!=="<chatId>"?`\uFF08${r(cn(l.target.allowChats[0]))}\uFF09`:"";v=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicLede",{gn:d})}</p>
873
- <pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${f}' -H 'content-type: application/json' -d '{}'</code></pre>
874
- <p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicNote")}</p>`}else E?v=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageTokenLede")}</p>
875
- <pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${f}' -H 'content-type: application/json' -d '{}'</code></pre>
876
- <p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageTokenNote")}</p>`:v=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageHmac")}${O?t("connectors.usageHmacDynamic"):""}</p>`;y.innerHTML=`<div class="card" style="padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
877
- <p class="ok" style="margin:0 0 6px">${t("connectors.createdPrefix",{name:r(o)})}${i==="fixed"&&l.target.chatId?`<span class="muted" style="font-weight:400;font-size:13px"> \xB7 ${t("connectors.createdDest",{name:r(cn(l.target.chatId))})}</span>`:""}</p>
876
+ </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 un("PATCH","/api/connectors/"+encodeURIComponent(o.dataset.id),{enabled:o.dataset.on!=="true"}),Ot()}}),n.querySelectorAll(".cn-del").forEach(o=>{o.onclick=async()=>{confirm(t("connectors.delConfirm"))&&(await un("DELETE","/api/connectors/"+encodeURIComponent(o.dataset.id)),Ot())}})}async function Ot(){let[e,n,o]=await Promise.all([dn("/api/bots"),dn("/api/connectors"),dn("/api/groups")]);pn=(e.body?.bots||[]).map(i=>({larkAppId:i.larkAppId,botName:i.botName||i.larkAppId})),fn=(o.body?.chats||[]).map(i=>({chatId:i.chatId,name:i.name||"",bots:(i.memberBots||[]).filter(l=>l.inChat).map(l=>l.larkAppId)}));let s=V("cn-bot"),a=s.value;s.innerHTML=pn.map(i=>`<option value="${r(i.larkAppId)}">${r(i.botName)}</option>`).join("")||`<option value="">${t("connectors.noOnlineBots")}</option>`,a&&(s.value=a),Lo(),bs(n.body?.connectors||[])}function Io(e){e.innerHTML=ps(),V("cn-kind").onchange=cn,V("cn-mode").onchange=cn,V("cn-bot").onchange=Lo,V("cn-chat-manual").onclick=n=>{n.preventDefault();let o=V("cn-chat"),s=V("cn-chat-sel"),a=o.style.display==="none";o.style.display=a?"":"none",s.style.display=a?"none":"",V("cn-chat-manual").textContent=a?t("connectors.chatListLink"):t("connectors.chatManualLink")},cn(),V("cn-create").onclick=async()=>{let n=V("cn-create-out"),o=ze("cn-name"),s=V("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=V("cn-kind").value,i=V("cn-mode").value,l={name:o,enabled:!0,target:{kind:a,mode:i,botId:s},promptEnvelope:{sourceName:o}},c=ze("cn-instruction");if(c&&(l.promptEnvelope.instruction=c),a==="workflow"){if(!ze("cn-wf")){n.innerHTML=`<span class="err">${t("connectors.errWf")}</span>`;return}l.target.workflowId=ze("cn-wf")}if(i==="fixed"){let k=V("cn-chat").style.display!=="none"?ze("cn-chat"):V("cn-chat-sel").value;if(!k){n.innerHTML=`<span class="err">${t("connectors.errChat")}</span>`;return}l.target.chatId=k}else{let v=Array.from(V("cn-allow-sel").selectedOptions).map(k=>k.value).filter(Boolean);v.length&&(l.target.allowChats=v)}if(i==="new-group"){let v=ze("cn-dedup");l.lifecycleExtractors=v?{dedupKey:v}:null}l.verify={type:V("cn-verify").value};let h=ze("cn-secret");h&&(l.secret=h),n.innerHTML=`<span class="muted">${t("connectors.creating")}</span>`;let b=await un("POST","/api/connectors",l);if(b.status===201&&b.body?.ok){n.innerHTML="";let v=V("cn-created");v.style.display="";let k=b.body.webhookUrl||To(b.body.connector.id),m=b.body.secret,D=(b.body.connector?.verify?.type??"token")==="token",E=i==="dynamic",C=E?l.target.allowChats?.[0]||"<chatId>":"",w=E?`${r(k)}?chatId=${r(C)}`:r(k),$;if(D&&E){let d=C!=="<chatId>"?`\uFF08${r(mn(l.target.allowChats[0]))}\uFF09`:"";$=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicLede",{gn:d})}</p>
877
+ <pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${w}' -H 'content-type: application/json' -d '{}'</code></pre>
878
+ <p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicNote")}</p>`}else D?$=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageTokenLede")}</p>
879
+ <pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${w}' -H 'content-type: application/json' -d '{}'</code></pre>
880
+ <p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageTokenNote")}</p>`:$=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageHmac")}${E?t("connectors.usageHmacDynamic"):""}</p>`;v.innerHTML=`<div class="card" style="padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
881
+ <p class="ok" style="margin:0 0 6px">${t("connectors.createdPrefix",{name:r(o)})}${i==="fixed"&&l.target.chatId?`<span class="muted" style="font-weight:400;font-size:13px"> \xB7 ${t("connectors.createdDest",{name:r(mn(l.target.chatId))})}</span>`:""}</p>
878
882
  <p style="margin:4px 0;font-size:13px"><span class="muted">${t("connectors.webhookUrl")}</span><code style="word-break:break-all">${r(k)}</code></p>
879
- ${p?`<p style="margin:4px 0;font-size:13px"><span class="muted">${E?t("connectors.tokenLabel"):t("connectors.signLabel")}${t("connectors.secretOnce")}</span><code>${r(p)}</code></p>`:""}
880
- ${v}</div>`,["cn-name","cn-wf","cn-chat","cn-dedup","cn-secret","cn-instruction"].forEach(d=>{K(d).value=""}),K("cn-allow-sel").selectedIndex=-1,At()}else{let y=h.body?.error||h.status;n.innerHTML=`<span class="err">${t("connectors.createFailed",{error:r(String(y))})}</span>`}},At()}var ge=null,ct=null,dt=!0;function $o(e){return{publicReadOnly:e?.publicReadOnly===!0,openTerminalInFeishu:e?.openTerminalInFeishu===!0,maintenance:e?.maintenance&&typeof e.maintenance=="object"?e.maintenance:{},localDevInstall:e?.localDevInstall===!0}}function ls(e,n){let o=e?.[n]??{};return{enabled:o.enabled===!0,time:typeof o.time=="string"?o.time:"04:00"}}function ds(){return`<section class="page">
883
+ ${m?`<p style="margin:4px 0;font-size:13px"><span class="muted">${D?t("connectors.tokenLabel"):t("connectors.signLabel")}${t("connectors.secretOnce")}</span><code>${r(m)}</code></p>`:""}
884
+ ${$}</div>`,["cn-name","cn-wf","cn-chat","cn-dedup","cn-secret","cn-instruction"].forEach(d=>{V(d).value=""}),V("cn-allow-sel").selectedIndex=-1,Ot()}else{let v=b.body?.error||b.status;n.innerHTML=`<span class="err">${t("connectors.createFailed",{error:r(String(v))})}</span>`}},Ot()}var be=null,pt=null,ut=!0;function Mo(e){return{publicReadOnly:e?.publicReadOnly===!0,openTerminalInFeishu:e?.openTerminalInFeishu===!0,maintenance:e?.maintenance&&typeof e.maintenance=="object"?e.maintenance:{},localDevInstall:e?.localDevInstall===!0}}function hs(e,n){let o=e?.[n]??{};return{enabled:o.enabled===!0,time:typeof o.time=="string"?o.time:"04:00"}}function ws(){return`<section class="page">
881
885
  <div class="page-heading">
882
886
  <div>
883
887
  <p class="eyebrow">${t("nav.settings")}</p>
@@ -886,7 +890,7 @@ ${go("manage")}
886
890
  </div>
887
891
  </div>
888
892
  <div id="settings-body"></div>
889
- </section>`}function cs(e){let{enabled:n,time:o}=ls(ge.maintenance,"autoUpdate"),s=e?"disabled":"";return`<label class="toggle-row">
893
+ </section>`}function ys(e){let{enabled:n,time:o}=hs(be.maintenance,"autoUpdate"),s=e?"disabled":"";return`<label class="toggle-row">
890
894
  <input type="checkbox" data-maint="autoUpdate" ${n?"checked":""} ${s}>
891
895
  <span class="switch" aria-hidden="true"></span>
892
896
  <span class="toggle-tx"><strong>${t("settings.autoUpdate")}</strong>
@@ -896,18 +900,18 @@ ${go("manage")}
896
900
  <label>${t("settings.maintenanceTime")}
897
901
  <input type="time" data-maint-time="autoUpdate" value="${r(o)}" ${s}>
898
902
  </label>
899
- </div>`}function us(e){return`<label class="toggle-row">
900
- <input type="checkbox" data-maint="autoRestart" ${ge.maintenance.autoRestart?.enabled===!0?"checked":""} ${e?"disabled":""}>
903
+ </div>`}function vs(e){return`<label class="toggle-row">
904
+ <input type="checkbox" data-maint="autoRestart" ${be.maintenance.autoRestart?.enabled===!0?"checked":""} ${e?"disabled":""}>
901
905
  <span class="switch" aria-hidden="true"></span>
902
906
  <span class="toggle-tx"><strong>${t("settings.autoRestart")}</strong>
903
907
  <small>${t("settings.autoRestartHelp")}</small></span>
904
- </label>`}function ps(){if(ct)return`<p class="hint-warn">${t("settings.loadFailed")}: ${r(ct)}</p>`;if(!ge)return`<p class="empty">${t("settings.loading")}</p>`;let e=dt?"":"disabled",n=!dt||ge.localDevInstall;return`<div class="settings-grid">
908
+ </label>`}function ks(){if(pt)return`<p class="hint-warn">${t("settings.loadFailed")}: ${r(pt)}</p>`;if(!be)return`<p class="empty">${t("settings.loading")}</p>`;let e=ut?"":"disabled",n=!ut||be.localDevInstall;return`<div class="settings-grid">
905
909
  <article class="bd-card settings-card">
906
- ${dt?"":`<p class="hint-warn">${t("settings.readOnlyVisitor")}</p>`}
910
+ ${ut?"":`<p class="hint-warn">${t("settings.readOnlyVisitor")}</p>`}
907
911
  <section class="bd-section">
908
912
  <h3 class="bd-section-title">${t("settings.sectionAccess")}</h3>
909
913
  <label class="toggle-row">
910
- <input type="checkbox" data-setting="publicReadOnly" ${ge.publicReadOnly?"checked":""} ${e}>
914
+ <input type="checkbox" data-setting="publicReadOnly" ${be.publicReadOnly?"checked":""} ${e}>
911
915
  <span class="switch" aria-hidden="true"></span>
912
916
  <span class="toggle-tx"><strong>${t("settings.publicReadOnly")}</strong>
913
917
  <small>${t("settings.publicReadOnlyHelp")}</small></span>
@@ -916,7 +920,7 @@ ${go("manage")}
916
920
  <section class="bd-section">
917
921
  <h3 class="bd-section-title">${t("settings.sectionCards")}</h3>
918
922
  <label class="toggle-row">
919
- <input type="checkbox" data-setting="openTerminalInFeishu" ${ge.openTerminalInFeishu?"checked":""} ${e}>
923
+ <input type="checkbox" data-setting="openTerminalInFeishu" ${be.openTerminalInFeishu?"checked":""} ${e}>
920
924
  <span class="switch" aria-hidden="true"></span>
921
925
  <span class="toggle-tx"><strong>${t("settings.openTerminalInFeishu")}</strong>
922
926
  <small>${t("settings.openTerminalInFeishuHelp")}</small></span>
@@ -924,50 +928,50 @@ ${go("manage")}
924
928
  </section>
925
929
  <section class="bd-section">
926
930
  <h3 class="bd-section-title">${t("settings.sectionMaintenance")}</h3>
927
- ${cs(n)}
928
- ${ge.localDevInstall?`<p class="hint-warn">${t("settings.autoUpdateLocalDev")}</p>`:""}
929
- ${us(!dt||ge.maintenance.autoUpdate?.enabled!==!0)}
931
+ ${ys(n)}
932
+ ${be.localDevInstall?`<p class="hint-warn">${t("settings.autoUpdateLocalDev")}</p>`:""}
933
+ ${vs(!ut||be.maintenance.autoUpdate?.enabled!==!0)}
930
934
  </section>
931
935
  <div class="actions settings-actions">
932
936
  <span class="oncall-status" data-settings-status></span>
933
937
  </div>
934
938
  </article>
935
- </div>`}async function ms(){try{let e=await fetch("/api/settings"),n=await e.json().catch(()=>({}));if(!e.ok){ge=null,ct=n?.error??`HTTP ${e.status}`;return}ge=$o(n.settings),dt=n.authed===!0,ct=null}catch(e){ge=null,ct=e?.message??String(e)}}async function So(e){e.innerHTML=ds();let n=e.querySelector("#settings-body");function o(){n.innerHTML=ps(),i()}function s(){return n.querySelector("[data-settings-status]")}async function a(l,c,w){if(!ge)return;w.disabled=!0;let h=s();h&&(h.textContent=t("settings.saving"),h.className="oncall-status");try{let y=await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(l)}),k=await y.json().catch(()=>({}));if(!y.ok||k.ok===!1)throw new Error(k?.error??`HTTP ${y.status}`);ge=$o(k.settings),h&&(h.textContent=t("settings.saved"),h.classList.add("hint-ok"))}catch(y){c(),h&&(h.textContent=`${t("settings.saveFailed")}: ${y?.message??y}`,h.classList.add("hint-warn-inline"))}finally{w.disabled=!1}}function i(){n.querySelectorAll("input[data-setting]").forEach(c=>{c.addEventListener("change",()=>{let w=c.dataset.setting,h=!c.checked;a({[w]:c.checked},()=>{c.checked=h},c)})});let l=(c,w,h)=>{let k=n.querySelector(`input[data-maint="${c}"]`)?.checked??!1,p;if(c==="autoUpdate"){let E=n.querySelector('input[data-maint-time="autoUpdate"]');p={enabled:k,time:E?.value||"04:00"}}else p={enabled:k};a({maintenance:{[c]:p}},h,w).then(()=>o())};n.querySelectorAll("input[data-maint]").forEach(c=>{c.addEventListener("change",()=>{let w=c.dataset.maint,h=!c.checked;l(w,c,()=>{c.checked=h})})}),n.querySelectorAll("input[data-maint-time]").forEach(c=>{c.addEventListener("change",()=>{let w=c.dataset.maintTime,h=c.defaultValue;l(w,c,()=>{c.value=h})})})}o(),await ms(),o()}function fs(){let e=[["",t("workflow.filter.nonTerminal")],["all",t("workflow.filter.all")],["pending",Ue("pending")],["running",Ue("running")],["waiting",Ue("waiting")],["succeeded",Ue("succeeded")],["failed",Ue("failed")],["cancelled",Ue("cancelled")]];return`
939
+ </div>`}async function $s(){try{let e=await fetch("/api/settings"),n=await e.json().catch(()=>({}));if(!e.ok){be=null,pt=n?.error??`HTTP ${e.status}`;return}be=Mo(n.settings),ut=n.authed===!0,pt=null}catch(e){be=null,pt=e?.message??String(e)}}async function xo(e){e.innerHTML=ws();let n=e.querySelector("#settings-body");function o(){n.innerHTML=ks(),i()}function s(){return n.querySelector("[data-settings-status]")}async function a(l,c,h){if(!be)return;h.disabled=!0;let b=s();b&&(b.textContent=t("settings.saving"),b.className="oncall-status");try{let v=await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(l)}),k=await v.json().catch(()=>({}));if(!v.ok||k.ok===!1)throw new Error(k?.error??`HTTP ${v.status}`);be=Mo(k.settings),b&&(b.textContent=t("settings.saved"),b.classList.add("hint-ok"))}catch(v){c(),b&&(b.textContent=`${t("settings.saveFailed")}: ${v?.message??v}`,b.classList.add("hint-warn-inline"))}finally{h.disabled=!1}}function i(){n.querySelectorAll("input[data-setting]").forEach(c=>{c.addEventListener("change",()=>{let h=c.dataset.setting,b=!c.checked;a({[h]:c.checked},()=>{c.checked=b},c)})});let l=(c,h,b)=>{let k=n.querySelector(`input[data-maint="${c}"]`)?.checked??!1,m;if(c==="autoUpdate"){let D=n.querySelector('input[data-maint-time="autoUpdate"]');m={enabled:k,time:D?.value||"04:00"}}else m={enabled:k};a({maintenance:{[c]:m}},b,h).then(()=>o())};n.querySelectorAll("input[data-maint]").forEach(c=>{c.addEventListener("change",()=>{let h=c.dataset.maint,b=!c.checked;l(h,c,()=>{c.checked=b})})}),n.querySelectorAll("input[data-maint-time]").forEach(c=>{c.addEventListener("change",()=>{let h=c.dataset.maintTime,b=c.defaultValue;l(h,c,()=>{c.value=b})})})}o(),await $s(),o()}function Ss(){let e=[["",t("workflow.filter.nonTerminal")],["all",t("workflow.filter.all")],["pending",Ue("pending")],["running",Ue("running")],["waiting",Ue("waiting")],["succeeded",Ue("succeeded")],["failed",Ue("failed")],["cancelled",Ue("cancelled")]];return`
936
940
  <nav class="wf-subnav">
937
- <a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${m(t("workflow.subnav.runs"))}</a>
938
- <a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${m(t("workflow.subnav.catalog"))}</a>
941
+ <a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${p(t("workflow.subnav.runs"))}</a>
942
+ <a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${p(t("workflow.subnav.catalog"))}</a>
939
943
  </nav>
940
944
  <form id="wf-filters" class="filters">
941
- <input type="search" name="q" placeholder="${m(t("workflow.searchPlaceholder"))}" />
945
+ <input type="search" name="q" placeholder="${p(t("workflow.searchPlaceholder"))}" />
942
946
  <select name="status">
943
- ${e.map(([n,o])=>`<option value="${m(n)}">${m(o)}</option>`).join("")}
947
+ ${e.map(([n,o])=>`<option value="${p(n)}">${p(o)}</option>`).join("")}
944
948
  </select>
945
949
  <span id="wf-last-load" class="muted"></span>
946
950
  </form>
947
951
  <table>
948
952
  <thead><tr>
949
- <th>${m(t("workflow.table.run"))}</th><th>${m(t("workflow.table.workflow"))}</th><th>${m(t("workflow.table.status"))}</th>
950
- <th>${m(t("workflow.table.lastSeq"))}</th><th>${m(t("workflow.table.dangling"))}</th><th>${m(t("workflow.table.updated"))}</th>
951
- <th>${m(t("workflow.table.chatApp"))}</th>
953
+ <th>${p(t("workflow.table.run"))}</th><th>${p(t("workflow.table.workflow"))}</th><th>${p(t("workflow.table.status"))}</th>
954
+ <th>${p(t("workflow.table.lastSeq"))}</th><th>${p(t("workflow.table.dangling"))}</th><th>${p(t("workflow.table.updated"))}</th>
955
+ <th>${p(t("workflow.table.chatApp"))}</th>
952
956
  </tr></thead>
953
957
  <tbody id="wf-tbody"></tbody>
954
958
  </table>
955
- `}var gs=5e3,bs=2e3,ut=new Set(["succeeded","failed","cancelled"]);function m(e){return e.replace(/[&<>"']/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[n])}function hs(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 Be(e){return`<span class="${ut.has(e)?"wf-status terminal":"wf-status live"} wf-status-${m(e)}">${m(Ue(e))}</span>`}function Ue(e){let n=`workflow.status.${e}`,o=t(n);return o===n?e:o}function Mo(e){let n=location.hash.match(/^#\/workflows\/([^?#]+)(?:\?([^#]*))?$/);if(n){let o=new URLSearchParams(n[2]??"");return ys(e,decodeURIComponent(n[1]),{focusAttemptId:o.get("attempt")??void 0})}return ws(e)}function ws(e){e.innerHTML=fs();let n=e.querySelector("#wf-tbody"),o=e.querySelector("#wf-filters"),s=e.querySelector("#wf-last-load"),a=[],i=null,l=!1,c=null,w=!1;function h(T){let v=(new FormData(o).get("q")??"").trim().toLowerCase();return v?T.filter(d=>d.runId.toLowerCase().includes(v)||d.workflowId.toLowerCase().includes(v)||(d.chatId??"").toLowerCase().includes(v)):T}function y(){let T=h(a);if(T.length===0){n.innerHTML=`<tr><td colspan="7" class="empty">${c?m(t("workflow.list.failedLoad",{error:c})):a.length===0?m(t("workflow.list.noRuns")):m(t("workflow.list.noFilterMatch"))}</td></tr>`;return}n.innerHTML=T.map(f=>{let v=`${f.dEf}/${f.dAct}/${f.dWait}`,d=f.dEf+f.dAct+f.dWait>0?"wf-dangling has":"wf-dangling none",b=[];f.chatId&&b.push(m(f.chatId)),f.larkAppId&&b.push(`<span class="muted">${m(f.larkAppId)}</span>`);let x=b.length>0?b.join("<br/>"):"\u2014",H=ks(f);return`<tr data-runid="${m(f.runId)}">
956
- <td><a href="#/workflows/${encodeURIComponent(f.runId)}"><code>${m(f.runId)}</code></a></td>
957
- <td>${m(f.workflowId)}</td>
958
- <td>${Be(f.status)}${f.failedNodeId?` <span class="muted">(${m(f.failedNodeId)})</span>`:""}${H}</td>
959
- <td>${f.lastSeq}</td>
960
- <td class="${d}">${v}</td>
961
- <td title="${m(new Date(f.updatedAt).toISOString())}">${hs(f.updatedAt)}</td>
962
- <td>${x}</td>
963
- </tr>`}).join("")}function k(){c?(s.textContent=t("workflow.list.error",{error:c}),s.classList.add("error")):(s.textContent=t("workflow.list.loaded",{count:a.length,time:new Date().toLocaleTimeString()}),s.classList.remove("error"))}async function p(){if(!(w||l)&&!document.hidden){l=!0;try{let T=o.elements.namedItem("status")?.value??"",f=new URLSearchParams;T==="all"?f.set("all","1"):T&&f.set("status",T);let v="/api/workflows/runs"+(f.toString()?`?${f}`:""),d=await fetch(v);d.ok?(a=(await d.json()).runs??[],c=null):(c=`HTTP ${d.status}`,a=[])}catch(T){c=T?.message??String(T),a=[]}finally{l=!1,w||(y(),k())}}}function E(){i!==null&&window.clearTimeout(i),i=window.setTimeout(async()=>{await p(),w||E()},gs)}function O(){document.hidden||p()}return o.addEventListener("input",()=>{y()}),o.addEventListener("change",T=>{T.target.getAttribute("name")==="status"&&p()}),document.addEventListener("visibilitychange",O),p().then(()=>{w||E()}),()=>{w=!0,i!==null&&window.clearTimeout(i),document.removeEventListener("visibilitychange",O)}}function ys(e,n,o={}){e.innerHTML=`
959
+ `}var Ts=5e3,Ls=2e3,mt=new Set(["succeeded","failed","cancelled"]);function p(e){return e.replace(/[&<>"']/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[n])}function Is(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 Be(e){return`<span class="${mt.has(e)?"wf-status terminal":"wf-status live"} wf-status-${p(e)}">${p(Ue(e))}</span>`}function Ue(e){let n=`workflow.status.${e}`,o=t(n);return o===n?e:o}function Ao(e){let n=location.hash.match(/^#\/workflows\/([^?#]+)(?:\?([^#]*))?$/);if(n){let o=new URLSearchParams(n[2]??"");return xs(e,decodeURIComponent(n[1]),{focusAttemptId:o.get("attempt")??void 0})}return Ms(e)}function Ms(e){e.innerHTML=Ss();let n=e.querySelector("#wf-tbody"),o=e.querySelector("#wf-filters"),s=e.querySelector("#wf-last-load"),a=[],i=null,l=!1,c=null,h=!1;function b(C){let $=(new FormData(o).get("q")??"").trim().toLowerCase();return $?C.filter(d=>d.runId.toLowerCase().includes($)||d.workflowId.toLowerCase().includes($)||(d.chatId??"").toLowerCase().includes($)):C}function v(){let C=b(a);if(C.length===0){n.innerHTML=`<tr><td colspan="7" class="empty">${c?p(t("workflow.list.failedLoad",{error:c})):a.length===0?p(t("workflow.list.noRuns")):p(t("workflow.list.noFilterMatch"))}</td></tr>`;return}n.innerHTML=C.map(w=>{let $=`${w.dEf}/${w.dAct}/${w.dWait}`,d=w.dEf+w.dAct+w.dWait>0?"wf-dangling has":"wf-dangling none",g=[];w.chatId&&g.push(p(w.chatId)),w.larkAppId&&g.push(`<span class="muted">${p(w.larkAppId)}</span>`);let M=g.length>0?g.join("<br/>"):"\u2014",L=Hs(w);return`<tr data-runid="${p(w.runId)}">
960
+ <td><a href="#/workflows/${encodeURIComponent(w.runId)}"><code>${p(w.runId)}</code></a></td>
961
+ <td>${p(w.workflowId)}</td>
962
+ <td>${Be(w.status)}${w.failedNodeId?` <span class="muted">(${p(w.failedNodeId)})</span>`:""}${L}</td>
963
+ <td>${w.lastSeq}</td>
964
+ <td class="${d}">${$}</td>
965
+ <td title="${p(new Date(w.updatedAt).toISOString())}">${Is(w.updatedAt)}</td>
966
+ <td>${M}</td>
967
+ </tr>`}).join("")}function k(){c?(s.textContent=t("workflow.list.error",{error:c}),s.classList.add("error")):(s.textContent=t("workflow.list.loaded",{count:a.length,time:new Date().toLocaleTimeString()}),s.classList.remove("error"))}async function m(){if(!(h||l)&&!document.hidden){l=!0;try{let C=o.elements.namedItem("status")?.value??"",w=new URLSearchParams;C==="all"?w.set("all","1"):C&&w.set("status",C);let $="/api/workflows/runs"+(w.toString()?`?${w}`:""),d=await fetch($);d.ok?(a=(await d.json()).runs??[],c=null):(c=`HTTP ${d.status}`,a=[])}catch(C){c=C?.message??String(C),a=[]}finally{l=!1,h||(v(),k())}}}function D(){i!==null&&window.clearTimeout(i),i=window.setTimeout(async()=>{await m(),h||D()},Ts)}function E(){document.hidden||m()}return o.addEventListener("input",()=>{v()}),o.addEventListener("change",C=>{C.target.getAttribute("name")==="status"&&m()}),document.addEventListener("visibilitychange",E),m().then(()=>{h||D()}),()=>{h=!0,i!==null&&window.clearTimeout(i),document.removeEventListener("visibilitychange",E)}}function xs(e,n,o={}){e.innerHTML=`
964
968
  <div class="wf-detail-head">
965
- <a class="btn-link" href="#/workflows">${m(t("workflow.detail.back"))}</a>
969
+ <a class="btn-link" href="#/workflows">${p(t("workflow.detail.back"))}</a>
966
970
  <div>
967
- <h2><code>${m(n)}</code></h2>
968
- <div id="wf-detail-subtitle" class="muted">${m(t("workflow.detail.loading"))}</div>
971
+ <h2><code>${p(n)}</code></h2>
972
+ <div id="wf-detail-subtitle" class="muted">${p(t("workflow.detail.loading"))}</div>
969
973
  </div>
970
- <button id="wf-cancel-run" type="button" class="contrast" hidden>${m(t("workflow.detail.cancel"))}</button>
974
+ <button id="wf-cancel-run" type="button" class="contrast" hidden>${p(t("workflow.detail.cancel"))}</button>
971
975
  <span id="wf-detail-refresh" class="muted"></span>
972
976
  </div>
973
977
  <section id="wf-detail-error" class="hint-warn" hidden></section>
@@ -976,20 +980,20 @@ ${go("manage")}
976
980
  <section id="wf-dangling-panel"></section>
977
981
  <section class="wf-panel">
978
982
  <div class="wf-panel-title">
979
- <h3>${m(t("workflow.detail.parallel"))}</h3>
983
+ <h3>${p(t("workflow.detail.parallel"))}</h3>
980
984
  <span id="wf-parallel-meta" class="muted"></span>
981
985
  </div>
982
986
  <div id="wf-parallel-view"></div>
983
987
  </section>
984
988
  <section class="wf-panel">
985
989
  <div class="wf-panel-title">
986
- <h3>${m(t("workflow.detail.nodes"))}</h3>
990
+ <h3>${p(t("workflow.detail.nodes"))}</h3>
987
991
  </div>
988
992
  <div class="wf-table-scroll">
989
993
  <table>
990
994
  <thead><tr>
991
- <th>${m(t("workflow.detail.node"))}</th><th>${m(t("workflow.detail.nodeStatus"))}</th><th>${m(t("workflow.detail.activity"))}</th><th>${m(t("workflow.detail.activityStatus"))}</th>
992
- <th>${m(t("workflow.detail.attempts"))}</th><th>${m(t("workflow.detail.current"))}</th><th>${m(t("workflow.detail.detail"))}</th>
995
+ <th>${p(t("workflow.detail.node"))}</th><th>${p(t("workflow.detail.nodeStatus"))}</th><th>${p(t("workflow.detail.activity"))}</th><th>${p(t("workflow.detail.activityStatus"))}</th>
996
+ <th>${p(t("workflow.detail.attempts"))}</th><th>${p(t("workflow.detail.current"))}</th><th>${p(t("workflow.detail.detail"))}</th>
993
997
  </tr></thead>
994
998
  <tbody id="wf-node-tbody"></tbody>
995
999
  </table>
@@ -997,95 +1001,95 @@ ${go("manage")}
997
1001
  </section>
998
1002
  <section class="wf-panel">
999
1003
  <div class="wf-panel-title">
1000
- <h3>${m(t("workflow.detail.nodeIO"))}</h3>
1004
+ <h3>${p(t("workflow.detail.nodeIO"))}</h3>
1001
1005
  </div>
1002
1006
  <div id="wf-io-list" class="wf-io-list"></div>
1003
1007
  </section>
1004
1008
  <section class="wf-panel">
1005
1009
  <div class="wf-panel-title">
1006
- <h3>${m(t("workflow.detail.timeline"))}</h3>
1007
- <button id="wf-load-older" type="button" hidden>${m(t("workflow.detail.loadOlder"))}</button>
1010
+ <h3>${p(t("workflow.detail.timeline"))}</h3>
1011
+ <button id="wf-load-older" type="button" hidden>${p(t("workflow.detail.loadOlder"))}</button>
1008
1012
  </div>
1009
1013
  <div class="wf-table-scroll wf-timeline-scroll">
1010
1014
  <table>
1011
1015
  <thead><tr>
1012
- <th>${m(t("workflow.detail.seq"))}</th><th>${m(t("workflow.detail.event"))}</th><th>${m(t("workflow.detail.actor"))}</th><th>${m(t("workflow.detail.node"))}</th><th>${m(t("workflow.detail.activity"))}</th><th>${m(t("workflow.detail.error"))}</th><th>${m(t("workflow.detail.time"))}</th>
1016
+ <th>${p(t("workflow.detail.seq"))}</th><th>${p(t("workflow.detail.event"))}</th><th>${p(t("workflow.detail.actor"))}</th><th>${p(t("workflow.detail.node"))}</th><th>${p(t("workflow.detail.activity"))}</th><th>${p(t("workflow.detail.error"))}</th><th>${p(t("workflow.detail.time"))}</th>
1013
1017
  </tr></thead>
1014
1018
  <tbody id="wf-event-tbody"></tbody>
1015
1019
  </table>
1016
1020
  </div>
1017
1021
  <div id="wf-event-meta" class="muted"></div>
1018
1022
  </section>
1019
- `;let s=e.querySelector("#wf-detail-subtitle"),a=e.querySelector("#wf-detail-refresh"),i=e.querySelector("#wf-detail-error"),l=e.querySelector("#wf-cancel-status"),c=e.querySelector("#wf-summary"),w=e.querySelector("#wf-dangling-panel"),h=e.querySelector("#wf-parallel-view"),y=e.querySelector("#wf-parallel-meta"),k=e.querySelector("#wf-node-tbody"),p=e.querySelector("#wf-io-list"),E=e.querySelector(".wf-timeline-scroll"),O=e.querySelector("#wf-event-tbody"),T=e.querySelector("#wf-event-meta"),f=e.querySelector("#wf-cancel-run"),v=e.querySelector("#wf-load-older"),d=null,b=[],x=new Set,H=null,I=null,C=!1,q=0,F=null,ie=!1,te=!1,he=!1,ne=new Set,le=new Map,me=new Map,$e=new Map,Ne=new Set,Se=new Map,ae=new Set,re=new Map,V=new Map,Ie=0,Me=o.focusAttemptId;function se($){if(!$){i.hidden=!0,i.textContent="";return}i.hidden=!1,i.textContent=$}function u($){if(!$){l.hidden=!0,l.textContent="";return}l.hidden=!1,l.textContent=$}async function g(){let $=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/snapshot`);if($.status===404)throw new Error(t("workflow.detail.unknownRun"));if(!$.ok)throw new Error(t("workflow.detail.snapshotHttp",{status:$.status}));d=await $.json()}async function S($){let Z=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/events?${$}`);if(Z.status===404)throw new Error(t("workflow.detail.unknownRun"));if(!Z.ok)throw new Error(t("workflow.detail.eventsHttp",{status:Z.status}));return await Z.json()}function L($,Z){let A=$.filter(B=>x.has(B.eventId)?!1:(x.add(B.eventId),!0));A.length!==0&&(b=Z==="prepend"?[...A,...b]:[...b,...A],b.sort((B,fe)=>pt(B.eventId)-pt(fe.eventId)))}async function M(){await g();let $=await S(new URLSearchParams({tail:"100"}));b=[],x=new Set,L($.events,"append"),H=$.oldestSeq,I=$.newestSeq,C=$.hasOlder,q=$.totalCount,W()}async function U(){if(!(ie||te||document.hidden)){te=!0;try{if(await g(),I!==null){let $=await S(new URLSearchParams({afterSeq:String(I),limit:"200"}));L($.events,"append"),$.newestSeq!==null&&(I=$.newestSeq),H===null&&$.oldestSeq!==null&&(H=$.oldestSeq),q=$.totalCount}else{let $=await S(new URLSearchParams({tail:"1"}));L($.events,"append"),H=$.oldestSeq,I=$.newestSeq,C=$.hasOlder,q=$.totalCount}se(null),W()}catch($){se($?.message??String($))}finally{te=!1}}}async function G(){if(!(H===null||!C)){v.disabled=!0;try{let $=await S(new URLSearchParams({beforeSeq:String(H),limit:"100"}));L($.events,"prepend"),$.oldestSeq!==null&&(H=$.oldestSeq),C=$.hasOlder,q=$.totalCount,se(null),W()}catch($){se($?.message??String($))}finally{v.disabled=!1}}}async function X(){if(!d||ut.has(d.run.status)||he)return;if(!d.chatBinding?.larkAppId){se(t("workflow.detail.cancelUnavailable",{runId:n}));return}let $=$s(d),Z=t("workflow.detail.cancelConfirm",{runId:n,...$});if(window.confirm(Z)){he=!0,f.disabled=!0;try{let A=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/cancel`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"cancelled via dashboard"})});if(A.status===401)throw new Error(t("workflow.detail.writeAccessCancel"));let B=await A.json().catch(()=>({}));if(!A.ok||!B.ok)throw new Error(B.hint??B.error??t("workflow.detail.cancelHttp",{status:A.status}));u(B.pending?t("workflow.detail.cancelPending"):null),se(null),await U()}catch(A){se(A?.message??String(A))}finally{he=!1,f.disabled=!1,W()}}}async function z($,Z){if(!ae.has($)){ae.add($),re.delete($),W();try{let A=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/attempts/${encodeURIComponent(Z)}/${encodeURIComponent($)}/resume`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});if(A.status===401)throw new Error(t("workflow.detail.writeAccessResume"));let B=await A.json().catch(()=>({}));if(!A.ok||!B.ok||!B.resumeId||!B.url)throw new Error(B.hint??B.message??B.error??t("workflow.detail.resumeStartFailed",{status:A.status}));Se.set($,{resumeId:B.resumeId,url:B.url})}catch(A){let B=A?.message??String(A);re.set($,B)}finally{ae.delete($),W()}}}async function ee($,Z){if(!ae.has($)){ae.add($),re.delete($),W();try{let A=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/attempts/${encodeURIComponent(Z)}/${encodeURIComponent($)}/resume/end`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"ended_by_dashboard"})});if(A.status===401)throw new Error(t("workflow.detail.writeAccessResume"));let B=await A.json().catch(()=>({}));if(!A.ok||!B.ok)if(B.error==="resume_not_running")Se.delete($);else throw new Error(B.hint??B.message??B.error??t("workflow.detail.resumeEndFailed",{status:A.status}));else Se.delete($)}catch(A){let B=A?.message??String(A);re.set($,B)}finally{ae.delete($),W()}}}async function oe($,Z){if(!Ne.has($)){Ne.add($),$e.delete($),W();try{let A=me.get($)?.trim()||void 0,B=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/${Z}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({comment:A})});if(B.status===401)throw new Error(t("workflow.detail.writeAccessApproval"));let fe=await B.json().catch(()=>({}));if(!B.ok||!fe.ok)throw new Error(fe.hint??fe.message??fe.error??t("workflow.detail.actionHttp",{action:Z,status:B.status}));let bt=Z==="approve"?t("workflow.detail.approved"):t("workflow.detail.rejected");$e.set($,{kind:"ok",text:fe.alreadyTerminal?t("workflow.detail.alreadyTerminal",{label:bt}):fe.pending?t("workflow.detail.workflowContinue",{label:bt}):t("workflow.detail.workflowRefreshing",{label:bt})}),se(null),await U()}catch(A){let B=A?.message??String(A);$e.set($,{kind:"error",text:B}),se(B)}finally{Ne.delete($),W()}}}function W(){if(!d)return;Ie=E.scrollTop;let $=d.run;ut.has($.status)&&u(null),s.innerHTML=`${m($.workflowId??"?")} \xB7 ${Be($.status)} \xB7 lastSeq ${d.lastSeq}`,a.textContent=t("workflow.detail.refreshed",{time:new Date().toLocaleTimeString()}),f.hidden=ut.has($.status),f.disabled=he||!d.chatBinding?.larkAppId,f.textContent=d.chatBinding?.larkAppId?t("workflow.detail.cancel"):t("workflow.detail.cliCancelOnly"),f.title=d.chatBinding?.larkAppId?t("workflow.detail.cancelTitle"):t("workflow.detail.cliCancelTitle",{runId:n}),vs(c,d),Ss(w,d),Ts(h,y,d,b),Hs(k,d),Cs(p,d,ne,le,{comments:me,statuses:$e,resolving:Ne,onResolve:oe},{sessions:Se,pending:ae,errors:re,onStart:z,onEnd:ee},Me,V)&&(Me=void 0),oi(O,b),E.scrollTop=Ie,v.hidden=!C,T.textContent=t("workflow.detail.eventsLoaded",{loaded:b.length,total:q})}function xe(){if(F!==null&&window.clearTimeout(F),d&&ut.has(d.run.status)){F=null;return}F=window.setTimeout(async()=>{await U(),ie||xe()},bs)}function we(){document.hidden||U().then(()=>{!ie&&F===null&&xe()})}return v.addEventListener("click",()=>{G()}),f.addEventListener("click",()=>{X()}),document.addEventListener("visibilitychange",we),M().then(()=>{se(null),ie||xe()}).catch($=>{se($?.message??String($)),s.textContent=t("workflow.detail.loadFailed")}),()=>{ie=!0,F!==null&&window.clearTimeout(F),document.removeEventListener("visibilitychange",we)}}function vs(e,n){let o=n.run,s=[[t("workflow.summary.workflow"),m(o.workflowId??"?")],[t("workflow.summary.status"),Be(o.status)],[t("workflow.summary.lastSeq"),String(n.lastSeq)],[t("workflow.summary.updated"),m(new Date(n.updatedAt).toLocaleString())],[t("workflow.summary.revision"),m(Ot(o.revisionId))],[t("workflow.summary.initiator"),m(o.initiator??"-")]];o.failedNodeId&&s.push([t("workflow.summary.failedNode"),m(o.failedNodeId)]),o.cancelOriginEventId&&s.push([t("workflow.summary.cancelOrigin"),m(o.cancelOriginEventId)]),n.chatBinding&&(s.push([t("workflow.summary.chat"),`<code>${m(n.chatBinding.chatId)}</code>`]),s.push([t("workflow.summary.app"),`<code>${m(n.chatBinding.larkAppId)}</code>`])),e.innerHTML=s.map(([a,i])=>`<div class="wf-summary-item"><span>${a}</span><strong>${i}</strong></div>`).join("")}function ks(e){if(!e.errorCode)return"";let n=e.errorMessage?` \u2014 ${ri(e.errorMessage,96)}`:"";return`<div class="wf-run-error">
1020
- <span class="muted error">${m(e.errorCode)}</span>${m(n)}
1021
- </div>`}function $s(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 Ss(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>${m(t("workflow.detail.dangling"))}</h3></div><div class="muted">${m(t("workflow.detail.noDangling"))}</div>`;return}e.innerHTML=`<div class="wf-panel-title"><h3>${m(t("workflow.detail.dangling"))}</h3><span class="wf-dangling has">${a}</span></div>
1023
+ `;let s=e.querySelector("#wf-detail-subtitle"),a=e.querySelector("#wf-detail-refresh"),i=e.querySelector("#wf-detail-error"),l=e.querySelector("#wf-cancel-status"),c=e.querySelector("#wf-summary"),h=e.querySelector("#wf-dangling-panel"),b=e.querySelector("#wf-parallel-view"),v=e.querySelector("#wf-parallel-meta"),k=e.querySelector("#wf-node-tbody"),m=e.querySelector("#wf-io-list"),D=e.querySelector(".wf-timeline-scroll"),E=e.querySelector("#wf-event-tbody"),C=e.querySelector("#wf-event-meta"),w=e.querySelector("#wf-cancel-run"),$=e.querySelector("#wf-load-older"),d=null,g=[],M=new Set,L=null,y=null,H=!1,A=0,B=null,Y=!1,_=!1,me=!1,$e=new Set,re=new Map,Q=new Map,fe=new Map,Ne=new Set,Se=new Map,se=new Set,le=new Map,X=new Map,Ie=0,Me=o.focusAttemptId;function ie(S){if(!S){i.hidden=!0,i.textContent="";return}i.hidden=!1,i.textContent=S}function u(S){if(!S){l.hidden=!0,l.textContent="";return}l.hidden=!1,l.textContent=S}async function f(){let S=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/snapshot`);if(S.status===404)throw new Error(t("workflow.detail.unknownRun"));if(!S.ok)throw new Error(t("workflow.detail.snapshotHttp",{status:S.status}));d=await S.json()}async function T(S){let ne=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/events?${S}`);if(ne.status===404)throw new Error(t("workflow.detail.unknownRun"));if(!ne.ok)throw new Error(t("workflow.detail.eventsHttp",{status:ne.status}));return await ne.json()}function I(S,ne){let R=S.filter(P=>M.has(P.eventId)?!1:(M.add(P.eventId),!0));R.length!==0&&(g=ne==="prepend"?[...R,...g]:[...g,...R],g.sort((P,ge)=>ft(P.eventId)-ft(ge.eventId)))}async function x(){await f();let S=await T(new URLSearchParams({tail:"100"}));g=[],M=new Set,I(S.events,"append"),L=S.oldestSeq,y=S.newestSeq,H=S.hasOlder,A=S.totalCount,J()}async function j(){if(!(Y||_||document.hidden)){_=!0;try{if(await f(),y!==null){let S=await T(new URLSearchParams({afterSeq:String(y),limit:"200"}));I(S.events,"append"),S.newestSeq!==null&&(y=S.newestSeq),L===null&&S.oldestSeq!==null&&(L=S.oldestSeq),A=S.totalCount}else{let S=await T(new URLSearchParams({tail:"1"}));I(S.events,"append"),L=S.oldestSeq,y=S.newestSeq,H=S.hasOlder,A=S.totalCount}ie(null),J()}catch(S){ie(S?.message??String(S))}finally{_=!1}}}async function G(){if(!(L===null||!H)){$.disabled=!0;try{let S=await T(new URLSearchParams({beforeSeq:String(L),limit:"100"}));I(S.events,"prepend"),S.oldestSeq!==null&&(L=S.oldestSeq),H=S.hasOlder,A=S.totalCount,ie(null),J()}catch(S){ie(S?.message??String(S))}finally{$.disabled=!1}}}async function te(){if(!d||mt.has(d.run.status)||me)return;if(!d.chatBinding?.larkAppId){ie(t("workflow.detail.cancelUnavailable",{runId:n}));return}let S=Cs(d),ne=t("workflow.detail.cancelConfirm",{runId:n,...S});if(window.confirm(ne)){me=!0,w.disabled=!0;try{let R=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/cancel`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"cancelled via dashboard"})});if(R.status===401)throw new Error(t("workflow.detail.writeAccessCancel"));let P=await R.json().catch(()=>({}));if(!R.ok||!P.ok)throw new Error(P.hint??P.error??t("workflow.detail.cancelHttp",{status:R.status}));u(P.pending?t("workflow.detail.cancelPending"):null),ie(null),await j()}catch(R){ie(R?.message??String(R))}finally{me=!1,w.disabled=!1,J()}}}async function z(S,ne){if(!se.has(S)){se.add(S),le.delete(S),J();try{let R=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/attempts/${encodeURIComponent(ne)}/${encodeURIComponent(S)}/resume`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});if(R.status===401)throw new Error(t("workflow.detail.writeAccessResume"));let P=await R.json().catch(()=>({}));if(!R.ok||!P.ok||!P.resumeId||!P.url)throw new Error(P.hint??P.message??P.error??t("workflow.detail.resumeStartFailed",{status:R.status}));Se.set(S,{resumeId:P.resumeId,url:P.url})}catch(R){let P=R?.message??String(R);le.set(S,P)}finally{se.delete(S),J()}}}async function oe(S,ne){if(!se.has(S)){se.add(S),le.delete(S),J();try{let R=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/attempts/${encodeURIComponent(ne)}/${encodeURIComponent(S)}/resume/end`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"ended_by_dashboard"})});if(R.status===401)throw new Error(t("workflow.detail.writeAccessResume"));let P=await R.json().catch(()=>({}));if(!R.ok||!P.ok)if(P.error==="resume_not_running")Se.delete(S);else throw new Error(P.hint??P.message??P.error??t("workflow.detail.resumeEndFailed",{status:R.status}));else Se.delete(S)}catch(R){let P=R?.message??String(R);le.set(S,P)}finally{se.delete(S),J()}}}async function ae(S,ne){if(!Ne.has(S)){Ne.add(S),fe.delete(S),J();try{let R=Q.get(S)?.trim()||void 0,P=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/${ne}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({comment:R})});if(P.status===401)throw new Error(t("workflow.detail.writeAccessApproval"));let ge=await P.json().catch(()=>({}));if(!P.ok||!ge.ok)throw new Error(ge.hint??ge.message??ge.error??t("workflow.detail.actionHttp",{action:ne,status:P.status}));let wt=ne==="approve"?t("workflow.detail.approved"):t("workflow.detail.rejected");fe.set(S,{kind:"ok",text:ge.alreadyTerminal?t("workflow.detail.alreadyTerminal",{label:wt}):ge.pending?t("workflow.detail.workflowContinue",{label:wt}):t("workflow.detail.workflowRefreshing",{label:wt})}),ie(null),await j()}catch(R){let P=R?.message??String(R);fe.set(S,{kind:"error",text:P}),ie(P)}finally{Ne.delete(S),J()}}}function J(){if(!d)return;Ie=D.scrollTop;let S=d.run;mt.has(S.status)&&u(null),s.innerHTML=`${p(S.workflowId??"?")} \xB7 ${Be(S.status)} \xB7 lastSeq ${d.lastSeq}`,a.textContent=t("workflow.detail.refreshed",{time:new Date().toLocaleTimeString()}),w.hidden=mt.has(S.status),w.disabled=me||!d.chatBinding?.larkAppId,w.textContent=d.chatBinding?.larkAppId?t("workflow.detail.cancel"):t("workflow.detail.cliCancelOnly"),w.title=d.chatBinding?.larkAppId?t("workflow.detail.cancelTitle"):t("workflow.detail.cliCancelTitle",{runId:n}),Es(c,d),As(h,d),Ds(b,v,d,g),qs(k,d),Us(m,d,$e,re,{comments:Q,statuses:fe,resolving:Ne,onResolve:ae},{sessions:Se,pending:se,errors:le,onStart:z,onEnd:oe},Me,X)&&(Me=void 0),pi(E,g),D.scrollTop=Ie,$.hidden=!H,C.textContent=t("workflow.detail.eventsLoaded",{loaded:g.length,total:A})}function xe(){if(B!==null&&window.clearTimeout(B),d&&mt.has(d.run.status)){B=null;return}B=window.setTimeout(async()=>{await j(),Y||xe()},Ls)}function we(){document.hidden||j().then(()=>{!Y&&B===null&&xe()})}return $.addEventListener("click",()=>{G()}),w.addEventListener("click",()=>{te()}),document.addEventListener("visibilitychange",we),x().then(()=>{ie(null),Y||xe()}).catch(S=>{ie(S?.message??String(S)),s.textContent=t("workflow.detail.loadFailed")}),()=>{Y=!0,B!==null&&window.clearTimeout(B),document.removeEventListener("visibilitychange",we)}}function Es(e,n){let o=n.run,s=[[t("workflow.summary.workflow"),p(o.workflowId??"?")],[t("workflow.summary.status"),Be(o.status)],[t("workflow.summary.lastSeq"),String(n.lastSeq)],[t("workflow.summary.updated"),p(new Date(n.updatedAt).toLocaleString())],[t("workflow.summary.revision"),p(Pt(o.revisionId))],[t("workflow.summary.initiator"),p(o.initiator??"-")]];o.failedNodeId&&s.push([t("workflow.summary.failedNode"),p(o.failedNodeId)]),o.cancelOriginEventId&&s.push([t("workflow.summary.cancelOrigin"),p(o.cancelOriginEventId)]),n.chatBinding&&(s.push([t("workflow.summary.chat"),`<code>${p(n.chatBinding.chatId)}</code>`]),s.push([t("workflow.summary.app"),`<code>${p(n.chatBinding.larkAppId)}</code>`])),e.innerHTML=s.map(([a,i])=>`<div class="wf-summary-item"><span>${a}</span><strong>${i}</strong></div>`).join("")}function Hs(e){if(!e.errorCode)return"";let n=e.errorMessage?` \u2014 ${bi(e.errorMessage,96)}`:"";return`<div class="wf-run-error">
1024
+ <span class="muted error">${p(e.errorCode)}</span>${p(n)}
1025
+ </div>`}function Cs(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 As(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>${p(t("workflow.detail.dangling"))}</h3></div><div class="muted">${p(t("workflow.detail.noDangling"))}</div>`;return}e.innerHTML=`<div class="wf-panel-title"><h3>${p(t("workflow.detail.dangling"))}</h3><span class="wf-dangling has">${a}</span></div>
1022
1026
  <div class="wf-dangling-grid">
1023
- ${s.map(([i,l])=>`<div><strong>${i}</strong>${l.length===0?`<div class="muted">${m(t("workflow.detail.none"))}</div>`:`<ul>${l.map(c=>`<li><code>${m(c)}</code></li>`).join("")}</ul>`}</div>`).join("")}
1024
- </div>`}function Ts(e,n,o,s){let a=Ls(s,o);if(a.length===0){n.textContent="",e.innerHTML=`<div class="empty">${m(t("workflow.detail.noParallelData"))}</div>`;return}let i=Date.now(),l=Math.min(...a.map(p=>p.startedAt)),c=Math.max(...a.map(p=>p.endedAt??i),l+1e3),w=Math.max(1,c-l),h=Ms(a,i),y=a.filter(p=>!p.endedAt&&(p.status==="running"||p.status==="effectAttempting")).length;n.textContent=t("workflow.detail.parallelMeta",{count:a.length,max:h,running:y});let k=a.sort((p,E)=>p.startedAt-E.startedAt||p.activityId.localeCompare(E.activityId)).map(p=>Is(p,l,w,i)).join("");e.innerHTML=`<div class="wf-parallel-axis">
1025
- <span title="${m(new Date(l).toISOString())}">${m(Rt(l))}</span>
1026
- <span title="${m(new Date(c).toISOString())}">${m(Rt(c))}</span>
1027
+ ${s.map(([i,l])=>`<div><strong>${i}</strong>${l.length===0?`<div class="muted">${p(t("workflow.detail.none"))}</div>`:`<ul>${l.map(c=>`<li><code>${p(c)}</code></li>`).join("")}</ul>`}</div>`).join("")}
1028
+ </div>`}function Ds(e,n,o,s){let a=Rs(s,o);if(a.length===0){n.textContent="",e.innerHTML=`<div class="empty">${p(t("workflow.detail.noParallelData"))}</div>`;return}let i=Date.now(),l=Math.min(...a.map(m=>m.startedAt)),c=Math.max(...a.map(m=>m.endedAt??i),l+1e3),h=Math.max(1,c-l),b=Bs(a,i),v=a.filter(m=>!m.endedAt&&(m.status==="running"||m.status==="effectAttempting")).length;n.textContent=t("workflow.detail.parallelMeta",{count:a.length,max:b,running:v});let k=a.sort((m,D)=>m.startedAt-D.startedAt||m.activityId.localeCompare(D.activityId)).map(m=>Os(m,l,h,i)).join("");e.innerHTML=`<div class="wf-parallel-axis">
1029
+ <span title="${p(new Date(l).toISOString())}">${p(Nt(l))}</span>
1030
+ <span title="${p(new Date(c).toISOString())}">${p(Nt(c))}</span>
1027
1031
  </div>
1028
- <div class="wf-parallel-list">${k}</div>`}function Ls(e,n){let o=new Map,s=new Map(n.activities.map(a=>[a.activityId,a.ownerNodeId]));for(let a of[...e].sort((i,l)=>pt(i.eventId)-pt(l.eventId))){let i=ii(a);if(!i)continue;let l=typeof i.activityId=="string"?i.activityId:void 0,c=typeof i.attemptId=="string"?i.attemptId:void 0;if(!l||!c)continue;let w=o.get(c);if(a.type==="attemptCreated"){let h=typeof i.attemptNumber=="number"?i.attemptNumber:void 0;w={nodeId:typeof i.nodeId=="string"?i.nodeId:s.get(l),activityId:l,attemptId:c,attemptNumber:h,status:"pending",startedAt:a.timestamp},o.set(c,w);continue}w||(w={nodeId:s.get(l),activityId:l,attemptId:c,status:"pending",startedAt:a.timestamp},o.set(c,w)),a.type==="activityRunning"?(w.status="running",w.runningAt=a.timestamp):a.type==="effectAttempted"?w.status="effectAttempting":a.type==="activityWaiting"||a.type==="waitCreated"?w.status="waiting":xs(a.type)&&(w.status=Es(a.type),w.endedAt=a.timestamp,w.endType=a.type)}return[...o.values()]}function Is(e,n,o,s){let a=e.endedAt??s,i=Io((e.startedAt-n)/o*100,0,100),l=Io((Math.max(a,e.startedAt+1)-e.startedAt)/o*100,.7,100-i),c=e.nodeId??e.activityId,w=e.attemptNumber!==void 0?`#${e.attemptNumber}`:Ot(e.attemptId),h=[`${c} ${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(`
1032
+ <div class="wf-parallel-list">${k}</div>`}function Rs(e,n){let o=new Map,s=new Map(n.activities.map(a=>[a.activityId,a.ownerNodeId]));for(let a of[...e].sort((i,l)=>ft(i.eventId)-ft(l.eventId))){let i=gi(a);if(!i)continue;let l=typeof i.activityId=="string"?i.activityId:void 0,c=typeof i.attemptId=="string"?i.attemptId:void 0;if(!l||!c)continue;let h=o.get(c);if(a.type==="attemptCreated"){let b=typeof i.attemptNumber=="number"?i.attemptNumber:void 0;h={nodeId:typeof i.nodeId=="string"?i.nodeId:s.get(l),activityId:l,attemptId:c,attemptNumber:b,status:"pending",startedAt:a.timestamp},o.set(c,h);continue}h||(h={nodeId:s.get(l),activityId:l,attemptId:c,status:"pending",startedAt:a.timestamp},o.set(c,h)),a.type==="activityRunning"?(h.status="running",h.runningAt=a.timestamp):a.type==="effectAttempted"?h.status="effectAttempting":a.type==="activityWaiting"||a.type==="waitCreated"?h.status="waiting":Ns(a.type)&&(h.status=Ps(a.type),h.endedAt=a.timestamp,h.endType=a.type)}return[...o.values()]}function Os(e,n,o,s){let a=e.endedAt??s,i=Co((e.startedAt-n)/o*100,0,100),l=Co((Math.max(a,e.startedAt+1)-e.startedAt)/o*100,.7,100-i),c=e.nodeId??e.activityId,h=e.attemptNumber!==void 0?`#${e.attemptNumber}`:Pt(e.attemptId),b=[`${c} ${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(`
1029
1033
  `);return`<div class="wf-parallel-row">
1030
1034
  <div class="wf-parallel-label">
1031
- <code>${m(c)}</code>
1032
- <span class="muted">${m(e.activityId)} \xB7 ${m(w)}</span>
1035
+ <code>${p(c)}</code>
1036
+ <span class="muted">${p(e.activityId)} \xB7 ${p(h)}</span>
1033
1037
  </div>
1034
1038
  <div class="wf-parallel-track">
1035
- <div class="wf-parallel-bar wf-parallel-${m(e.status)}" style="left:${i.toFixed(3)}%;width:${l.toFixed(3)}%;" title="${m(h)}">
1036
- <span>${m(Ue(e.status))}</span>
1039
+ <div class="wf-parallel-bar wf-parallel-${p(e.status)}" style="left:${i.toFixed(3)}%;width:${l.toFixed(3)}%;" title="${p(b)}">
1040
+ <span>${p(Ue(e.status))}</span>
1037
1041
  </div>
1038
1042
  </div>
1039
- </div>`}function Ms(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,l)=>i.time-l.time||l.delta-i.delta);let s=0,a=0;for(let i of o)s+=i.delta,a=Math.max(a,s);return a}function xs(e){return e==="activitySucceeded"||e==="activityFailed"||e==="activityTimedOut"||e==="activityCanceled"}function Es(e){return e==="activitySucceeded"?"succeeded":e==="activityCanceled"?"cancelled":e==="activityTimedOut"?"timedOut":"failed"}function Hs(e,n){let o=new Map(n.activities.map(i=>[i.activityId,i])),s=new Set,a=[];for(let i of n.nodes){let l=(i.activityId?o.get(i.activityId):void 0)??n.activities.find(c=>c.ownerNodeId===i.nodeId);l&&s.add(l.activityId),a.push(To(i,l))}for(let i of n.activities)s.has(i.activityId)||a.push(To(void 0,i));e.innerHTML=a.length>0?a.join(""):`<tr><td colspan="7" class="empty">${m(t("workflow.detail.noNodes"))}</td></tr>`}function To(e,n){let o=n?.attempts[n.attempts.length-1];return`<tr>
1040
- <td>${e?`<code>${m(e.nodeId)}</code>`:'<span class="muted">-</span>'}</td>
1043
+ </div>`}function Bs(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,l)=>i.time-l.time||l.delta-i.delta);let s=0,a=0;for(let i of o)s+=i.delta,a=Math.max(a,s);return a}function Ns(e){return e==="activitySucceeded"||e==="activityFailed"||e==="activityTimedOut"||e==="activityCanceled"}function Ps(e){return e==="activitySucceeded"?"succeeded":e==="activityCanceled"?"cancelled":e==="activityTimedOut"?"timedOut":"failed"}function qs(e,n){let o=new Map(n.activities.map(i=>[i.activityId,i])),s=new Set,a=[];for(let i of n.nodes){let l=(i.activityId?o.get(i.activityId):void 0)??n.activities.find(c=>c.ownerNodeId===i.nodeId);l&&s.add(l.activityId),a.push(Eo(i,l))}for(let i of n.activities)s.has(i.activityId)||a.push(Eo(void 0,i));e.innerHTML=a.length>0?a.join(""):`<tr><td colspan="7" class="empty">${p(t("workflow.detail.noNodes"))}</td></tr>`}function Eo(e,n){let o=n?.attempts[n.attempts.length-1];return`<tr>
1044
+ <td>${e?`<code>${p(e.nodeId)}</code>`:'<span class="muted">-</span>'}</td>
1041
1045
  <td>${e?Be(e.status):'<span class="muted">-</span>'}</td>
1042
- <td>${n?`<code>${m(n.activityId)}</code>`:'<span class="muted">-</span>'}</td>
1046
+ <td>${n?`<code>${p(n.activityId)}</code>`:'<span class="muted">-</span>'}</td>
1043
1047
  <td>${n?Be(n.status):'<span class="muted">-</span>'}</td>
1044
1048
  <td>${n?.attempts.length??0}</td>
1045
- <td>${o?`<code>${m(o.attemptId)}</code>`:'<span class="muted">-</span>'}</td>
1046
- <td>${o?ni(o):`<span class="muted">${m(t("workflow.detail.idle"))}</span>`}</td>
1047
- </tr>`}function Cs(e,n,o,s,a,i,l,c){Ys(e,o,s),Ws(e,a.comments);let w=!!(l&&n.attemptIO?.[l]?.terminal);w&&l&&o.add(pn(l,t("workflow.detail.liveTerminal")));let h=As(n),y=new Set;if(c){for(let p of h){y.add(p.key);let E=c.get(p.key);E||(E=Ds(p.key),c.set(p.key,E),e.appendChild(E.article)),Rs(E,p,o,a,i,l)}for(let[p,E]of Array.from(c))y.has(p)||(E.article.remove(),c.delete(p));if(h.length===0){if(!e.querySelector(".wf-io-empty-placeholder")){let p=document.createElement("div");p.className="empty wf-io-empty-placeholder",p.textContent=t("workflow.detail.noNodeIO"),e.appendChild(p)}}else e.querySelector(".wf-io-empty-placeholder")?.remove()}else{let p=[];for(let E of h)p.push(qs(E,o,a,i,l));e.innerHTML=p.length>0?p.join(""):`<div class="empty">${m(t("workflow.detail.noNodeIO"))}</div>`}Xs(e,s);let k=Vs(e,l);return Qs(e,o),Zs(e,s),Ks(e,a),Bo(e,i),k&&w}function As(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(l=>l.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?.[Dt(i)?.attemptId??""]})}for(let a of e.activities)o.has(a.activityId)||s.push({key:`activity:${a.activityId}`,activity:a,io:e.attemptIO?.[Dt(a)?.attemptId??""]});return s}function Ds(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 Rs(e,n,o,s,a,i){let l=Dt(n.activity),c=n.node?.nodeId??n.activity?.ownerNodeId??n.activity?.activityId??"unknown",w=!!(l&&l.attemptId===i);e.article.classList.toggle("is-focused",w),l?e.article.dataset.wfAttemptCard=l.attemptId:delete e.article.dataset.wfAttemptCard;let h=Oo(l,s);e.head.innerHTML=`
1049
+ <td>${o?`<code>${p(o.attemptId)}</code>`:'<span class="muted">-</span>'}</td>
1050
+ <td>${o?ui(o):`<span class="muted">${p(t("workflow.detail.idle"))}</span>`}</td>
1051
+ </tr>`}function Us(e,n,o,s,a,i,l,c){si(e,o,s),ti(e,a.comments);let h=!!(l&&n.attemptIO?.[l]?.terminal);h&&l&&o.add(gn(l,t("workflow.detail.liveTerminal")));let b=js(n),v=new Set;if(c){for(let m of b){v.add(m.key);let D=c.get(m.key);D||(D=Fs(m.key),c.set(m.key,D),e.appendChild(D.article)),Gs(D,m,o,a,i,l)}for(let[m,D]of Array.from(c))v.has(m)||(D.article.remove(),c.delete(m));if(b.length===0){if(!e.querySelector(".wf-io-empty-placeholder")){let m=document.createElement("div");m.className="empty wf-io-empty-placeholder",m.textContent=t("workflow.detail.noNodeIO"),e.appendChild(m)}}else e.querySelector(".wf-io-empty-placeholder")?.remove()}else{let m=[];for(let D of b)m.push(Ks(D,o,a,i,l));e.innerHTML=m.length>0?m.join(""):`<div class="empty">${p(t("workflow.detail.noNodeIO"))}</div>`}ri(e,s);let k=ai(e,l);return ii(e,o),li(e,s),oi(e,a),jo(e,i),k&&h}function js(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(l=>l.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?.[Bt(i)?.attemptId??""]})}for(let a of e.activities)o.has(a.activityId)||s.push({key:`activity:${a.activityId}`,activity:a,io:e.attemptIO?.[Bt(a)?.attemptId??""]});return s}function Fs(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 Gs(e,n,o,s,a,i){let l=Bt(n.activity),c=n.node?.nodeId??n.activity?.ownerNodeId??n.activity?.activityId??"unknown",h=!!(l&&l.attemptId===i);e.article.classList.toggle("is-focused",h),l?e.article.dataset.wfAttemptCard=l.attemptId:delete e.article.dataset.wfAttemptCard;let b=Uo(l,s);e.head.innerHTML=`
1048
1052
  <header>
1049
1053
  <div>
1050
- <strong><code>${m(c)}</code></strong>
1051
- <span class="muted">${n.activity?m(n.activity.activityId):m(t("workflow.detail.notDispatched"))}</span>
1054
+ <strong><code>${p(c)}</code></strong>
1055
+ <span class="muted">${n.activity?p(n.activity.activityId):p(t("workflow.detail.notDispatched"))}</span>
1052
1056
  </div>
1053
1057
  <div>${n.node?Be(n.node.status):""} ${n.activity?Be(n.activity.status):""}</div>
1054
1058
  </header>
1055
1059
  <div class="wf-io-meta">
1056
- ${l?`${m(t("workflow.detail.attempt"))} <code>${m(l.attemptId)}</code>`:m(t("workflow.detail.noAttempt"))}
1060
+ ${l?`${p(t("workflow.detail.attempt"))} <code>${p(l.attemptId)}</code>`:p(t("workflow.detail.noAttempt"))}
1057
1061
  </div>
1058
- ${h}
1059
- `;let y=xo(l,n.activity,n.io?.terminal,a),k=y?.url??null;if(k!==e.currentTerminalUrl)y===null?e.terminalSlot.innerHTML="":e.terminalSlot.innerHTML=Eo(n.key,l,n.activity,n.io?.terminal,y,o,a),e.currentTerminalUrl=k;else if(y!==null&&n.io?.terminal){let E=e.terminalSlot.querySelector("details.wf-terminal-block > summary");if(E){let O=Ho(y.kind);E.innerHTML=`${m(O)} ${Ro(l,n.io.terminal)}`}l&&Js(e.terminalSlot,l,n.activity,n.io.terminal,y,a)}let p=l?.attemptId??n.activity?.activityId??n.node?.nodeId??"unknown";e.grid.innerHTML=`
1060
- ${Re(p,t("workflow.detail.authoredInput"),n.io?.input,o)}
1061
- ${Re(p,t("workflow.detail.resolvedInput"),n.io?.resolvedInput,o)}
1062
- ${Re(p,t("workflow.detail.output"),n.io?.output,o)}
1063
- ${Re(p,t("workflow.detail.executionLog"),n.io?.log,o)}
1064
- ${n.io?.waitPrompt?Re(p,t("workflow.detail.waitPrompt"),n.io.waitPrompt,o):""}
1065
- `}function xo(e,n,o,s){if(!o||o.error)return null;if(Us(e,o))return{kind:"live",url:Fs(o)};if(!e||!n||!js(e,o))return null;let a=zs();if(!a)return null;let i=s?.sessions.get(e.attemptId);return i?{kind:"resume",url:i.url,resumeId:i.resumeId,downloadUrl:Lo(a,n.activityId,e.attemptId)}:{kind:"replay",url:Gs(a,n.activityId,e.attemptId,!!o.hasPtyLog),downloadUrl:Lo(a,n.activityId,e.attemptId)}}function Eo(e,n,o,s,a,i,l){if(!s)return"";let c=Ho(a.kind),w=pn(e,c),h=Ro(n,s),y=Os(a.kind),k=a.kind==="replay"||a.kind==="resume"?`<a class="btn-link" href="${m(a.downloadUrl)}" download>${m(t("workflow.detail.downloadFullLog"))}</a>`:"",p=n?Ao(n,o,s,a,l):"",E=n?Do(n.attemptId,l):"";return`<details class="wf-io-block wf-terminal-block" data-io-key="${m(w)}"${i.has(w)?" open":""}>
1066
- <summary>${m(c)} ${h}</summary>
1062
+ ${b}
1063
+ `;let v=Do(l,n.activity,n.io?.terminal,a),k=v?.url??null;if(k!==e.currentTerminalUrl)v===null?e.terminalSlot.innerHTML="":e.terminalSlot.innerHTML=Ro(n.key,l,n.activity,n.io?.terminal,v,o,a),e.currentTerminalUrl=k;else if(v!==null&&n.io?.terminal){let D=e.terminalSlot.querySelector("details.wf-terminal-block > summary");if(D){let E=Oo(v.kind);D.innerHTML=`${p(E)} ${qo(l,n.io.terminal)}`}l&&ni(e.terminalSlot,l,n.activity,n.io.terminal,v,a)}let m=l?.attemptId??n.activity?.activityId??n.node?.nodeId??"unknown";e.grid.innerHTML=`
1064
+ ${Re(m,t("workflow.detail.authoredInput"),n.io?.input,o)}
1065
+ ${Re(m,t("workflow.detail.resolvedInput"),n.io?.resolvedInput,o)}
1066
+ ${Re(m,t("workflow.detail.output"),n.io?.output,o)}
1067
+ ${Re(m,t("workflow.detail.executionLog"),n.io?.log,o)}
1068
+ ${n.io?.waitPrompt?Re(m,t("workflow.detail.waitPrompt"),n.io.waitPrompt,o):""}
1069
+ `}function Do(e,n,o,s){if(!o||o.error)return null;if(Vs(e,o))return{kind:"live",url:Qs(o)};if(!e||!n||!Ys(e,o))return null;let a=Zs();if(!a)return null;let i=s?.sessions.get(e.attemptId);return i?{kind:"resume",url:i.url,resumeId:i.resumeId,downloadUrl:Ho(a,n.activityId,e.attemptId)}:{kind:"replay",url:Xs(a,n.activityId,e.attemptId,!!o.hasPtyLog),downloadUrl:Ho(a,n.activityId,e.attemptId)}}function Ro(e,n,o,s,a,i,l){if(!s)return"";let c=Oo(a.kind),h=gn(e,c),b=qo(n,s),v=zs(a.kind),k=a.kind==="replay"||a.kind==="resume"?`<a class="btn-link" href="${p(a.downloadUrl)}" download>${p(t("workflow.detail.downloadFullLog"))}</a>`:"",m=n?No(n,o,s,a,l):"",D=n?Po(n.attemptId,l):"";return`<details class="wf-io-block wf-terminal-block" data-io-key="${p(h)}"${i.has(h)?" open":""}>
1070
+ <summary>${p(c)} ${b}</summary>
1067
1071
  <div class="wf-terminal-actions">
1068
- <a class="btn-link" href="${m(a.url)}" target="_blank" rel="noreferrer">${m(y)}</a>
1072
+ <a class="btn-link" href="${p(a.url)}" target="_blank" rel="noreferrer">${p(v)}</a>
1069
1073
  ${k}
1070
- ${p}
1074
+ ${m}
1071
1075
  </div>
1072
- ${E}
1073
- <iframe class="wf-terminal-frame" src="${m(a.url)}" title="${m(c)}" loading="lazy"></iframe>
1074
- </details>`}function Ho(e){return e==="live"?t("workflow.detail.liveTerminal"):e==="resume"?t("workflow.detail.terminalResume"):t("workflow.detail.terminalReplay")}function Os(e){return e==="live"?t("workflow.detail.openTerminalNewTab"):e==="resume"?t("workflow.detail.openResumeNewTab"):t("workflow.detail.openReplayNewTab")}var Co=new Set(["antigravity","codex-app","cursor","mira"]),Bs=new Set(["aiden","coco","claude-code","seed","codex","mtr","hermes","pi"]);function Ns(e){return!!e&&(Bs.has(e)||Co.has(e))}function Ps(e){return!!e&&Co.has(e)}function Ao(e,n,o,s,a){if(!a||s.kind==="live"||!n)return"";let i=s.kind==="resume",l=a.pending.has(e.attemptId),c=`data-wf-resume-attempt="${m(e.attemptId)}" data-wf-resume-activity="${m(n.activityId)}"`;return i?`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="end" ${c}${l?" disabled":""}>${m(l?t("workflow.detail.resumeEnding"):t("workflow.detail.endResumeSession"))}</button>`:Ns(o.cliId)?Ps(o.cliId)&&!o.cliSessionId?`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${m(t("workflow.detail.resumeMissingCliSession"))}">${m(t("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="start" ${c}${l?" disabled":""}>${m(l?t("workflow.detail.resumeStarting"):t("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${m(t("workflow.detail.resumeUnsupportedCli",{cliId:o.cliId??"?"}))}">${m(t("workflow.detail.resumeSession"))}</button>`}function Do(e,n){if(!n)return"";let o=n.errors.get(e);return o?`<div class="hint-warn wf-resume-status" data-wf-resume-status="${m(e)}">${m(o)}</div>`:""}function qs(e,n,o,s,a){let i=Dt(e.activity),l=e.node?.nodeId??e.activity?.ownerNodeId??e.activity?.activityId??"unknown",c=i?.attemptId??e.activity?.activityId??e.node?.nodeId??"unknown",w=Oo(i,o),h=i?.attemptId===a?" is-focused":"",y=i?` data-wf-attempt-card="${m(i.attemptId)}"`:"",k=xo(i,e.activity,e.io?.terminal,s),p=k?Eo(c,i,e.activity,e.io?.terminal,k,n,s):"";return`<article class="wf-io-card${h}" data-wf-card-key="${m(e.key)}"${y}>
1076
+ ${D}
1077
+ <iframe class="wf-terminal-frame" src="${p(a.url)}" title="${p(c)}" loading="lazy"></iframe>
1078
+ </details>`}function Oo(e){return e==="live"?t("workflow.detail.liveTerminal"):e==="resume"?t("workflow.detail.terminalResume"):t("workflow.detail.terminalReplay")}function zs(e){return e==="live"?t("workflow.detail.openTerminalNewTab"):e==="resume"?t("workflow.detail.openResumeNewTab"):t("workflow.detail.openReplayNewTab")}var Bo=new Set(["antigravity","codex-app","cursor","mira"]),_s=new Set(["aiden","coco","claude-code","seed","codex","mtr","hermes","pi"]);function Ws(e){return!!e&&(_s.has(e)||Bo.has(e))}function Js(e){return!!e&&Bo.has(e)}function No(e,n,o,s,a){if(!a||s.kind==="live"||!n)return"";let i=s.kind==="resume",l=a.pending.has(e.attemptId),c=`data-wf-resume-attempt="${p(e.attemptId)}" data-wf-resume-activity="${p(n.activityId)}"`;return i?`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="end" ${c}${l?" disabled":""}>${p(l?t("workflow.detail.resumeEnding"):t("workflow.detail.endResumeSession"))}</button>`:Ws(o.cliId)?Js(o.cliId)&&!o.cliSessionId?`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${p(t("workflow.detail.resumeMissingCliSession"))}">${p(t("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="start" ${c}${l?" disabled":""}>${p(l?t("workflow.detail.resumeStarting"):t("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${p(t("workflow.detail.resumeUnsupportedCli",{cliId:o.cliId??"?"}))}">${p(t("workflow.detail.resumeSession"))}</button>`}function Po(e,n){if(!n)return"";let o=n.errors.get(e);return o?`<div class="hint-warn wf-resume-status" data-wf-resume-status="${p(e)}">${p(o)}</div>`:""}function Ks(e,n,o,s,a){let i=Bt(e.activity),l=e.node?.nodeId??e.activity?.ownerNodeId??e.activity?.activityId??"unknown",c=i?.attemptId??e.activity?.activityId??e.node?.nodeId??"unknown",h=Uo(i,o),b=i?.attemptId===a?" is-focused":"",v=i?` data-wf-attempt-card="${p(i.attemptId)}"`:"",k=Do(i,e.activity,e.io?.terminal,s),m=k?Ro(c,i,e.activity,e.io?.terminal,k,n,s):"";return`<article class="wf-io-card${b}" data-wf-card-key="${p(e.key)}"${v}>
1075
1079
  <div class="wf-io-card-head">
1076
1080
  <header>
1077
1081
  <div>
1078
- <strong><code>${m(l)}</code></strong>
1079
- <span class="muted">${e.activity?m(e.activity.activityId):m(t("workflow.detail.notDispatched"))}</span>
1082
+ <strong><code>${p(l)}</code></strong>
1083
+ <span class="muted">${e.activity?p(e.activity.activityId):p(t("workflow.detail.notDispatched"))}</span>
1080
1084
  </div>
1081
1085
  <div>${e.node?Be(e.node.status):""} ${e.activity?Be(e.activity.status):""}</div>
1082
1086
  </header>
1083
1087
  <div class="wf-io-meta">
1084
- ${i?`${m(t("workflow.detail.attempt"))} <code>${m(i.attemptId)}</code>`:m(t("workflow.detail.noAttempt"))}
1088
+ ${i?`${p(t("workflow.detail.attempt"))} <code>${p(i.attemptId)}</code>`:p(t("workflow.detail.noAttempt"))}
1085
1089
  </div>
1086
- ${w}
1090
+ ${h}
1087
1091
  </div>
1088
- <div class="wf-io-terminal-slot">${p}</div>
1092
+ <div class="wf-io-terminal-slot">${m}</div>
1089
1093
  <div class="wf-io-grid">
1090
1094
  ${Re(c,t("workflow.detail.authoredInput"),e.io?.input,n)}
1091
1095
  ${Re(c,t("workflow.detail.resolvedInput"),e.io?.resolvedInput,n)}
@@ -1093,131 +1097,131 @@ ${go("manage")}
1093
1097
  ${Re(c,t("workflow.detail.executionLog"),e.io?.log,n)}
1094
1098
  ${e.io?.waitPrompt?Re(c,t("workflow.detail.waitPrompt"),e.io.waitPrompt,n):""}
1095
1099
  </div>
1096
- </article>`}function Dt(e){return e?.attempts[e.attempts.length-1]}function Ro(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">${m(o.join(" \xB7 "))}</span>`}function Us(e,n){return n.status==="live"&&n.webPort>0&&(e?.status==="pending"||e?.status==="running"||e?.status==="effectAttempting")}function js(e,n){return e.status==="succeeded"||e.status==="failed"||e.status==="cancelled"||e.status==="timedOut"?!!(n.sessionId||n.startedAt):!1}function Fs(e){return`http://${window.location.hostname||"127.0.0.1"}:${e.webPort}`}function Gs(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 Lo(e,n,o){return`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(n)}/${encodeURIComponent(o)}/terminal-log/raw?download=1`}function zs(){let e=window.location.hash.match(/^#\/workflows\/([^/?#]+)/);if(!e)return null;try{return decodeURIComponent(e[1])}catch{return null}}function Oo(e,n){if(!_s(e))return"";let o=e.attemptId,s=n.comments.get(o)??"",a=n.resolving.has(o),i=n.statuses.get(o),l=i?.kind==="error"?"hint-warn":"hint-ok";return`<div class="wf-approval-box" data-wf-approval="${m(o)}">
1100
+ </article>`}function Bt(e){return e?.attempts[e.attempts.length-1]}function qo(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">${p(o.join(" \xB7 "))}</span>`}function Vs(e,n){return n.status==="live"&&n.webPort>0&&(e?.status==="pending"||e?.status==="running"||e?.status==="effectAttempting")}function Ys(e,n){return e.status==="succeeded"||e.status==="failed"||e.status==="cancelled"||e.status==="timedOut"?!!(n.sessionId||n.startedAt):!1}function Qs(e){return`http://${window.location.hostname||"127.0.0.1"}:${e.webPort}`}function Xs(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 Ho(e,n,o){return`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(n)}/${encodeURIComponent(o)}/terminal-log/raw?download=1`}function Zs(){let e=window.location.hash.match(/^#\/workflows\/([^/?#]+)/);if(!e)return null;try{return decodeURIComponent(e[1])}catch{return null}}function Uo(e,n){if(!ei(e))return"";let o=e.attemptId,s=n.comments.get(o)??"",a=n.resolving.has(o),i=n.statuses.get(o),l=i?.kind==="error"?"hint-warn":"hint-ok";return`<div class="wf-approval-box" data-wf-approval="${p(o)}">
1097
1101
  <label>
1098
- <span>${m(t("workflow.detail.approvalComment"))}</span>
1099
- <textarea class="wf-approval-comment" data-wf-approval-comment="${m(o)}" rows="2" placeholder="${m(t("workflow.detail.optionalComment"))}"${a?" disabled":""}>${m(s)}</textarea>
1102
+ <span>${p(t("workflow.detail.approvalComment"))}</span>
1103
+ <textarea class="wf-approval-comment" data-wf-approval-comment="${p(o)}" rows="2" placeholder="${p(t("workflow.detail.optionalComment"))}"${a?" disabled":""}>${p(s)}</textarea>
1100
1104
  </label>
1101
1105
  <div class="wf-approval-actions">
1102
- <button type="button" class="primary" data-wf-approval-action="approve" data-wf-attempt-id="${m(o)}"${a?" disabled":""}>${m(t("workflow.detail.approve"))}</button>
1103
- <button type="button" data-wf-approval-action="reject" data-wf-attempt-id="${m(o)}"${a?" disabled":""}>${m(t("workflow.detail.reject"))}</button>
1104
- ${a?`<span class="muted">${m(t("workflow.detail.submitting"))}</span>`:""}
1106
+ <button type="button" class="primary" data-wf-approval-action="approve" data-wf-attempt-id="${p(o)}"${a?" disabled":""}>${p(t("workflow.detail.approve"))}</button>
1107
+ <button type="button" data-wf-approval-action="reject" data-wf-attempt-id="${p(o)}"${a?" disabled":""}>${p(t("workflow.detail.reject"))}</button>
1108
+ ${a?`<span class="muted">${p(t("workflow.detail.submitting"))}</span>`:""}
1105
1109
  </div>
1106
- ${i?`<div class="${l} wf-approval-status">${m(i.text)}</div>`:""}
1107
- </div>`}function _s(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function Ws(e,n){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(o=>{let s=o.dataset.wfApprovalComment;s&&n.set(s,o.value)})}function Bo(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 Js(e,n,o,s,a,i){let l=e.querySelector(".wf-terminal-actions");if(!l)return;let c=l.querySelector('button[data-wf-resume-button="1"]'),w=Ao(n,o,s,a,i);c?c.outerHTML=w:w&&l.insertAdjacentHTML("beforeend",w);let h=e.querySelector("details.wf-terminal-block");if(h){let y=h.querySelector(".wf-resume-status"),k=Do(n.attemptId,i);y?y.outerHTML=k:k&&l.insertAdjacentHTML("afterend",k)}Bo(e,i)}function Ks(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 Re(e,n,o,s){let a=pn(e,n);return`<details class="wf-io-block" data-io-key="${m(a)}"${s.has(a)?" open":""}>
1108
- <summary>${m(n)} ${ei(o)}</summary>
1109
- ${ti(o)}
1110
- </details>`}function pn(e,n){return`${e}:${n}`}function Vs(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 Ys(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 Qs(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 Xs(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 Zs(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 ei(e){if(!e)return`<span class="muted">${m(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(Ot(e.outputHash)),n.length?`<span class="muted">${m(n.join(" \xB7 "))}</span>`:""}function ti(e){if(!e)return`<div class="muted wf-io-empty">${m(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">${m(e.error)}</div>`:"";return n?`${o}<pre class="wf-io-pre">${m(n)}</pre>`:`${o}<div class="muted wf-io-empty">${m(t("workflow.detail.noPreview"))}</div>`}function ni(e){let n=[];if(e.effectAttempted&&n.push(`${m(t("workflow.detail.effect"))} ${m(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(`${m(t("workflow.detail.wait"))} ${m(e.wait.waitKind)} ${m(o)}`),e.wait.deadlineAt!==void 0&&n.push(`${m(t("workflow.detail.deadline"))} ${m(Rt(e.wait.deadlineAt))}`)}if(e.error){let o=`${e.error.errorCode}${e.error.errorClass?` \xB7 ${e.error.errorClass}`:""}`;n.push(`<span class="muted error">${m(o)}</span>`),e.error.errorMessage&&n.push(`<span class="error wf-error-msg">${m(e.error.errorMessage)}</span>`)}return e.output&&n.push(`${m(t("workflow.detail.output"))} ${m(Ot(e.output.outputHash))}`),e.runningMs!==void 0&&n.push(`${e.runningMs}ms`),n.length>0?n.join("<br/>"):'<span class="muted">-</span>'}function oi(e,n){e.innerHTML=n.length>0?n.map(ai).join(""):`<tr><td colspan="7" class="empty">${m(t("workflow.detail.noEvents"))}</td></tr>`}function ai(e){let n=si(e.payload);return`<tr>
1111
- <td>${pt(e.eventId)}</td>
1112
- <td><code>${m(e.type)}</code></td>
1113
- <td>${m(e.actor)}</td>
1114
- <td>${n.nodeId?`<code>${m(n.nodeId)}</code>`:"-"}</td>
1115
- <td>${n.activityId?`<code>${m(n.activityId)}</code>`:"-"}</td>
1116
- <td>${n.errorCode?`<span class="muted error">${m(n.errorCode)}</span>`:"-"}</td>
1117
- <td title="${m(new Date(e.timestamp).toISOString())}">${m(Rt(e.timestamp))}</td>
1118
- </tr>`}function pt(e){let n=e.lastIndexOf("-");if(n<0)return 0;let o=Number(e.slice(n+1));return Number.isFinite(o)?o:0}function si(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 ii(e){return!e.payload||typeof e.payload!="object"||"ref"in e.payload?null:e.payload}function Io(e,n,o){return Math.min(o,Math.max(n,e))}function Ot(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function ri(e,n){return e.length>n?e.slice(0,n-1)+"\u2026":e}function Rt(e){return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}function D(e){return e.replace(/[&<>"']/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[n])}function No(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function Po(e){let n=location.hash.match(/^#\/(?:workflows\/catalog|workflows-catalog)\/([^/?#]+)$/);return n?di(e,decodeURIComponent(n[1])):li(e)}function li(e){e.innerHTML=`
1110
+ ${i?`<div class="${l} wf-approval-status">${p(i.text)}</div>`:""}
1111
+ </div>`}function ei(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function ti(e,n){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(o=>{let s=o.dataset.wfApprovalComment;s&&n.set(s,o.value)})}function jo(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 ni(e,n,o,s,a,i){let l=e.querySelector(".wf-terminal-actions");if(!l)return;let c=l.querySelector('button[data-wf-resume-button="1"]'),h=No(n,o,s,a,i);c?c.outerHTML=h:h&&l.insertAdjacentHTML("beforeend",h);let b=e.querySelector("details.wf-terminal-block");if(b){let v=b.querySelector(".wf-resume-status"),k=Po(n.attemptId,i);v?v.outerHTML=k:k&&l.insertAdjacentHTML("afterend",k)}jo(e,i)}function oi(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 Re(e,n,o,s){let a=gn(e,n);return`<details class="wf-io-block" data-io-key="${p(a)}"${s.has(a)?" open":""}>
1112
+ <summary>${p(n)} ${di(o)}</summary>
1113
+ ${ci(o)}
1114
+ </details>`}function gn(e,n){return`${e}:${n}`}function ai(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 si(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 ii(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 ri(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 li(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 di(e){if(!e)return`<span class="muted">${p(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(Pt(e.outputHash)),n.length?`<span class="muted">${p(n.join(" \xB7 "))}</span>`:""}function ci(e){if(!e)return`<div class="muted wf-io-empty">${p(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">${p(e.error)}</div>`:"";return n?`${o}<pre class="wf-io-pre">${p(n)}</pre>`:`${o}<div class="muted wf-io-empty">${p(t("workflow.detail.noPreview"))}</div>`}function ui(e){let n=[];if(e.effectAttempted&&n.push(`${p(t("workflow.detail.effect"))} ${p(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(`${p(t("workflow.detail.wait"))} ${p(e.wait.waitKind)} ${p(o)}`),e.wait.deadlineAt!==void 0&&n.push(`${p(t("workflow.detail.deadline"))} ${p(Nt(e.wait.deadlineAt))}`)}if(e.error){let o=`${e.error.errorCode}${e.error.errorClass?` \xB7 ${e.error.errorClass}`:""}`;n.push(`<span class="muted error">${p(o)}</span>`),e.error.errorMessage&&n.push(`<span class="error wf-error-msg">${p(e.error.errorMessage)}</span>`)}return e.output&&n.push(`${p(t("workflow.detail.output"))} ${p(Pt(e.output.outputHash))}`),e.runningMs!==void 0&&n.push(`${e.runningMs}ms`),n.length>0?n.join("<br/>"):'<span class="muted">-</span>'}function pi(e,n){e.innerHTML=n.length>0?n.map(mi).join(""):`<tr><td colspan="7" class="empty">${p(t("workflow.detail.noEvents"))}</td></tr>`}function mi(e){let n=fi(e.payload);return`<tr>
1115
+ <td>${ft(e.eventId)}</td>
1116
+ <td><code>${p(e.type)}</code></td>
1117
+ <td>${p(e.actor)}</td>
1118
+ <td>${n.nodeId?`<code>${p(n.nodeId)}</code>`:"-"}</td>
1119
+ <td>${n.activityId?`<code>${p(n.activityId)}</code>`:"-"}</td>
1120
+ <td>${n.errorCode?`<span class="muted error">${p(n.errorCode)}</span>`:"-"}</td>
1121
+ <td title="${p(new Date(e.timestamp).toISOString())}">${p(Nt(e.timestamp))}</td>
1122
+ </tr>`}function ft(e){let n=e.lastIndexOf("-");if(n<0)return 0;let o=Number(e.slice(n+1));return Number.isFinite(o)?o:0}function fi(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 gi(e){return!e.payload||typeof e.payload!="object"||"ref"in e.payload?null:e.payload}function Co(e,n,o){return Math.min(o,Math.max(n,e))}function Pt(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function bi(e,n){return e.length>n?e.slice(0,n-1)+"\u2026":e}function Nt(e){return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}function O(e){return e.replace(/[&<>"']/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[n])}function Fo(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function Go(e){let n=location.hash.match(/^#\/(?:workflows\/catalog|workflows-catalog)\/([^/?#]+)$/);return n?wi(e,decodeURIComponent(n[1])):hi(e)}function hi(e){e.innerHTML=`
1119
1123
  <nav class="wf-subnav">
1120
- <a href="#/workflows" data-i18n="workflow.subnav.runs">${D(t("workflow.subnav.runs"))}</a>
1121
- <a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${D(t("workflow.subnav.catalog"))}</a>
1124
+ <a href="#/workflows" data-i18n="workflow.subnav.runs">${O(t("workflow.subnav.runs"))}</a>
1125
+ <a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${O(t("workflow.subnav.catalog"))}</a>
1122
1126
  </nav>
1123
1127
  <section class="catalog-head">
1124
1128
  <div>
1125
- <h2>${D(t("catalog.title"))}</h2>
1126
- <p class="muted">${D(t("catalog.subtitle"))}</p>
1129
+ <h2>${O(t("catalog.title"))}</h2>
1130
+ <p class="muted">${O(t("catalog.subtitle"))}</p>
1127
1131
  </div>
1128
- <button id="catalog-refresh" type="button">${D(t("catalog.refresh"))}</button>
1132
+ <button id="catalog-refresh" type="button">${O(t("catalog.refresh"))}</button>
1129
1133
  </section>
1130
1134
  <form id="catalog-filters" class="filters">
1131
- <input type="search" name="q" placeholder="${D(t("catalog.searchPlaceholder"))}" />
1135
+ <input type="search" name="q" placeholder="${O(t("catalog.searchPlaceholder"))}" />
1132
1136
  <span id="catalog-status" class="muted"></span>
1133
1137
  </form>
1134
1138
  <div class="wf-table-scroll">
1135
1139
  <table>
1136
1140
  <thead><tr>
1137
- <th>${D(t("catalog.table.workflow"))}</th>
1138
- <th>${D(t("catalog.table.version"))}</th>
1139
- <th>${D(t("catalog.table.params"))}</th>
1140
- <th>${D(t("catalog.table.nodes"))}</th>
1141
- <th>${D(t("catalog.table.revision"))}</th>
1142
- <th>${D(t("catalog.table.path"))}</th>
1141
+ <th>${O(t("catalog.table.workflow"))}</th>
1142
+ <th>${O(t("catalog.table.version"))}</th>
1143
+ <th>${O(t("catalog.table.params"))}</th>
1144
+ <th>${O(t("catalog.table.nodes"))}</th>
1145
+ <th>${O(t("catalog.table.revision"))}</th>
1146
+ <th>${O(t("catalog.table.path"))}</th>
1143
1147
  </tr></thead>
1144
1148
  <tbody id="catalog-tbody"></tbody>
1145
1149
  </table>
1146
1150
  </div>
1147
- `;let n=e.querySelector("#catalog-tbody"),o=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),a=e.querySelector("#catalog-refresh"),i=[],l=null,c=!1;function w(){let k=(new FormData(s).get("q")??"").trim().toLowerCase();return k?i.filter(p=>p.workflowId.toLowerCase().includes(k)||p.path.toLowerCase().includes(k)):i}function h(){l?(o.textContent=t("catalog.loadFailed",{error:l}),o.classList.add("error")):(o.textContent=`${i.length}`,o.classList.remove("error"));let k=w();if(k.length===0){n.innerHTML=`<tr><td colspan="6" class="empty">${i.length===0?D(t("catalog.noDefinitions")):D(t("catalog.noFilterMatch"))}</td></tr>`;return}n.innerHTML=k.map(p=>`
1151
+ `;let n=e.querySelector("#catalog-tbody"),o=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),a=e.querySelector("#catalog-refresh"),i=[],l=null,c=!1;function h(){let k=(new FormData(s).get("q")??"").trim().toLowerCase();return k?i.filter(m=>m.workflowId.toLowerCase().includes(k)||m.path.toLowerCase().includes(k)):i}function b(){l?(o.textContent=t("catalog.loadFailed",{error:l}),o.classList.add("error")):(o.textContent=`${i.length}`,o.classList.remove("error"));let k=h();if(k.length===0){n.innerHTML=`<tr><td colspan="6" class="empty">${i.length===0?O(t("catalog.noDefinitions")):O(t("catalog.noFilterMatch"))}</td></tr>`;return}n.innerHTML=k.map(m=>`
1148
1152
  <tr>
1149
- <td><a href="#/workflows/catalog/${encodeURIComponent(p.workflowId)}"><code>${D(p.workflowId)}</code></a></td>
1150
- <td>${p.version}</td>
1151
- <td>${D(t("catalog.paramSummary",{required:p.requiredParamCount,total:p.paramCount}))}</td>
1152
- <td>${p.nodeCount}</td>
1153
- <td><code>${D(No(p.revisionId))}</code></td>
1154
- <td><code>${D(p.path)}</code></td>
1153
+ <td><a href="#/workflows/catalog/${encodeURIComponent(m.workflowId)}"><code>${O(m.workflowId)}</code></a></td>
1154
+ <td>${m.version}</td>
1155
+ <td>${O(t("catalog.paramSummary",{required:m.requiredParamCount,total:m.paramCount}))}</td>
1156
+ <td>${m.nodeCount}</td>
1157
+ <td><code>${O(Fo(m.revisionId))}</code></td>
1158
+ <td><code>${O(m.path)}</code></td>
1155
1159
  </tr>
1156
- `).join("")}async function y(){a.disabled=!0,o.textContent=t("catalog.loading");try{let k=await fetch("/api/workflows/definitions");if(!k.ok)throw new Error(`HTTP ${k.status}`);i=(await k.json()).definitions??[],l=null}catch(k){l=k?.message??String(k),i=[]}finally{a.disabled=!1,c||h()}}return s.addEventListener("input",h),a.addEventListener("click",()=>{y()}),y(),()=>{c=!0}}function di(e,n){e.innerHTML=`
1160
+ `).join("")}async function v(){a.disabled=!0,o.textContent=t("catalog.loading");try{let k=await fetch("/api/workflows/definitions");if(!k.ok)throw new Error(`HTTP ${k.status}`);i=(await k.json()).definitions??[],l=null}catch(k){l=k?.message??String(k),i=[]}finally{a.disabled=!1,c||b()}}return s.addEventListener("input",b),a.addEventListener("click",()=>{v()}),v(),()=>{c=!0}}function wi(e,n){e.innerHTML=`
1157
1161
  <div class="catalog-detail-head">
1158
- <a class="btn-link" href="#/workflows/catalog">${D(t("catalog.back"))}</a>
1162
+ <a class="btn-link" href="#/workflows/catalog">${O(t("catalog.back"))}</a>
1159
1163
  <div>
1160
- <h2><code>${D(n)}</code></h2>
1161
- <div id="catalog-detail-subtitle" class="muted">${D(t("workflow.detail.loading"))}</div>
1164
+ <h2><code>${O(n)}</code></h2>
1165
+ <div id="catalog-detail-subtitle" class="muted">${O(t("workflow.detail.loading"))}</div>
1162
1166
  </div>
1163
1167
  </div>
1164
1168
  <section id="catalog-error" class="hint-warn" hidden></section>
1165
1169
  <section id="catalog-run-status" class="hint-ok" hidden></section>
1166
1170
  <div id="catalog-detail-body"></div>
1167
- `;let o=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),a=e.querySelector("#catalog-run-status"),i=e.querySelector("#catalog-detail-body"),l=null,c=!1,w=!1;function h(f){s.hidden=!f,s.textContent=f??""}function y(f){a.hidden=!f,a.textContent=f??""}function k(f){let v={};for(let[d,b]of Object.entries(f??{}))"default"in b&&(v[d]=b.default);return v}function p(){if(!l)return;let f=l.definition;o.textContent=`${t("catalog.revision")} ${No(l.revisionId)} \xB7 ${l.path}`;let v=JSON.stringify(k(f.params),null,2);i.innerHTML=`
1171
+ `;let o=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),a=e.querySelector("#catalog-run-status"),i=e.querySelector("#catalog-detail-body"),l=null,c=!1,h=!1;function b(w){s.hidden=!w,s.textContent=w??""}function v(w){a.hidden=!w,a.textContent=w??""}function k(w){let $={};for(let[d,g]of Object.entries(w??{}))"default"in g&&($[d]=g.default);return $}function m(){if(!l)return;let w=l.definition;o.textContent=`${t("catalog.revision")} ${Fo(l.revisionId)} \xB7 ${l.path}`;let $=JSON.stringify(k(w.params),null,2);i.innerHTML=`
1168
1172
  <section class="wf-panel">
1169
- <div class="wf-panel-title"><h3>${D(t("catalog.summary"))}</h3></div>
1173
+ <div class="wf-panel-title"><h3>${O(t("catalog.summary"))}</h3></div>
1170
1174
  <div class="wf-summary-grid">
1171
- <div class="wf-summary-item"><span>${D(t("catalog.table.workflow"))}</span><strong><code>${D(f.workflowId)}</code></strong></div>
1172
- <div class="wf-summary-item"><span>${D(t("catalog.table.version"))}</span><strong>${f.version}</strong></div>
1173
- <div class="wf-summary-item"><span>${D(t("catalog.nodeCount"))}</span><strong>${Object.keys(f.nodes).length}</strong></div>
1174
- <div class="wf-summary-item"><span>${D(t("catalog.path"))}</span><strong><code>${D(l.path)}</code></strong></div>
1175
+ <div class="wf-summary-item"><span>${O(t("catalog.table.workflow"))}</span><strong><code>${O(w.workflowId)}</code></strong></div>
1176
+ <div class="wf-summary-item"><span>${O(t("catalog.table.version"))}</span><strong>${w.version}</strong></div>
1177
+ <div class="wf-summary-item"><span>${O(t("catalog.nodeCount"))}</span><strong>${Object.keys(w.nodes).length}</strong></div>
1178
+ <div class="wf-summary-item"><span>${O(t("catalog.path"))}</span><strong><code>${O(l.path)}</code></strong></div>
1175
1179
  </div>
1176
1180
  </section>
1177
1181
 
1178
1182
  <section class="wf-panel">
1179
- <div class="wf-panel-title"><h3>${D(t("catalog.runPanel"))}</h3></div>
1183
+ <div class="wf-panel-title"><h3>${O(t("catalog.runPanel"))}</h3></div>
1180
1184
  <form id="catalog-run-form" class="catalog-run-form">
1181
1185
  <label>
1182
- <span>${D(t("catalog.paramsJson"))}</span>
1183
- <textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${D(t("catalog.paramsPlaceholder"))}">${D(v)}</textarea>
1186
+ <span>${O(t("catalog.paramsJson"))}</span>
1187
+ <textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${O(t("catalog.paramsPlaceholder"))}">${O($)}</textarea>
1184
1188
  </label>
1185
1189
  <div class="catalog-chat-grid">
1186
1190
  <label>
1187
- <span>${D(t("catalog.chatId"))}</span>
1191
+ <span>${O(t("catalog.chatId"))}</span>
1188
1192
  <input id="catalog-chat-id" type="text" autocomplete="off" />
1189
1193
  </label>
1190
1194
  <label>
1191
- <span>${D(t("catalog.larkAppId"))}</span>
1195
+ <span>${O(t("catalog.larkAppId"))}</span>
1192
1196
  <input id="catalog-lark-app-id" type="text" autocomplete="off" />
1193
1197
  </label>
1194
1198
  </div>
1195
- <div class="muted">${D(t("catalog.chatBindingHint"))}</div>
1199
+ <div class="muted">${O(t("catalog.chatBindingHint"))}</div>
1196
1200
  <div id="catalog-param-errors" class="catalog-param-errors" hidden></div>
1197
- <button id="catalog-run-btn" type="submit" class="primary">${D(t("catalog.run"))}</button>
1201
+ <button id="catalog-run-btn" type="submit" class="primary">${O(t("catalog.run"))}</button>
1198
1202
  </form>
1199
1203
  </section>
1200
1204
 
1201
1205
  <section class="wf-panel">
1202
- <div class="wf-panel-title"><h3>${D(t("catalog.paramsSchema"))}</h3></div>
1203
- ${ci(f.params)}
1206
+ <div class="wf-panel-title"><h3>${O(t("catalog.paramsSchema"))}</h3></div>
1207
+ ${yi(w.params)}
1204
1208
  </section>
1205
1209
 
1206
1210
  <section class="wf-panel">
1207
- <div class="wf-panel-title"><h3>${D(t("catalog.definitionJson"))}</h3></div>
1208
- <pre class="wf-io-pre">${D(JSON.stringify(f,null,2))}</pre>
1211
+ <div class="wf-panel-title"><h3>${O(t("catalog.definitionJson"))}</h3></div>
1212
+ <pre class="wf-io-pre">${O(JSON.stringify(w,null,2))}</pre>
1209
1213
  </section>
1210
- `,O()}async function E(){if(!l||w)return;let f=i.querySelector("#catalog-params"),v=i.querySelector("#catalog-chat-id"),d=i.querySelector("#catalog-lark-app-id"),b=i.querySelector("#catalog-run-btn"),x=i.querySelector("#catalog-param-errors"),H;try{if(H=JSON.parse(f.value||"{}"),!H||typeof H!="object"||Array.isArray(H))throw new Error(t("catalog.badParamsJson"))}catch(I){x.hidden=!1,x.innerHTML=`<div class="muted error">${D(I?.message??String(I))}</div>`;return}w=!0,b.disabled=!0,b.textContent=t("catalog.running"),x.hidden=!0,h(null),y(null);try{let I=await fetch(`/api/workflows/definitions/${encodeURIComponent(l.definition.workflowId)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({params:H,chatBinding:{chatId:v.value.trim(),larkAppId:d.value.trim()}})});if(I.status===401)throw new Error(t("catalog.writeAccess"));let C=await I.json().catch(()=>({}));if(!I.ok||!C.ok)throw C.issues?.length&&(x.hidden=!1,x.innerHTML=`<strong>${D(t("catalog.invalidParams"))}</strong><ul>${C.issues.map(q=>`<li>${D(t("catalog.issue",{path:q.path.length?q.path.join("."):"(root)",message:q.message}))}</li>`).join("")}</ul>`),new Error(C.hint??C.message??C.error??t("catalog.runHttp",{status:I.status}));y(t("catalog.runStarted")),C.runId&&(location.hash=`#/workflows/${encodeURIComponent(C.runId)}`)}catch(I){h(I?.message??String(I))}finally{w=!1,b.disabled=!1,b.textContent=t("catalog.run")}}function O(){i.querySelector("#catalog-run-form")?.addEventListener("submit",v=>{v.preventDefault(),E()})}async function T(){try{let f=await fetch(`/api/workflows/definitions/${encodeURIComponent(n)}`);if(f.status===404)throw new Error("unknown_workflow");if(!f.ok)throw new Error(`HTTP ${f.status}`);l=await f.json(),h(null),p()}catch(f){h(t("catalog.definitionLoadFailed",{error:f?.message??String(f)})),o.textContent=t("workflow.detail.loadFailed")}}return T().then(()=>{}),()=>{c=!0}}function ci(e){let n=Object.entries(e??{});return n.length===0?`<div class="muted">${D(t("catalog.noParams"))}</div>`:`<div class="catalog-param-list">${n.map(([o,s])=>`
1214
+ `,E()}async function D(){if(!l||h)return;let w=i.querySelector("#catalog-params"),$=i.querySelector("#catalog-chat-id"),d=i.querySelector("#catalog-lark-app-id"),g=i.querySelector("#catalog-run-btn"),M=i.querySelector("#catalog-param-errors"),L;try{if(L=JSON.parse(w.value||"{}"),!L||typeof L!="object"||Array.isArray(L))throw new Error(t("catalog.badParamsJson"))}catch(y){M.hidden=!1,M.innerHTML=`<div class="muted error">${O(y?.message??String(y))}</div>`;return}h=!0,g.disabled=!0,g.textContent=t("catalog.running"),M.hidden=!0,b(null),v(null);try{let y=await fetch(`/api/workflows/definitions/${encodeURIComponent(l.definition.workflowId)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({params:L,chatBinding:{chatId:$.value.trim(),larkAppId:d.value.trim()}})});if(y.status===401)throw new Error(t("catalog.writeAccess"));let H=await y.json().catch(()=>({}));if(!y.ok||!H.ok)throw H.issues?.length&&(M.hidden=!1,M.innerHTML=`<strong>${O(t("catalog.invalidParams"))}</strong><ul>${H.issues.map(A=>`<li>${O(t("catalog.issue",{path:A.path.length?A.path.join("."):"(root)",message:A.message}))}</li>`).join("")}</ul>`),new Error(H.hint??H.message??H.error??t("catalog.runHttp",{status:y.status}));v(t("catalog.runStarted")),H.runId&&(location.hash=`#/workflows/${encodeURIComponent(H.runId)}`)}catch(y){b(y?.message??String(y))}finally{h=!1,g.disabled=!1,g.textContent=t("catalog.run")}}function E(){i.querySelector("#catalog-run-form")?.addEventListener("submit",$=>{$.preventDefault(),D()})}async function C(){try{let w=await fetch(`/api/workflows/definitions/${encodeURIComponent(n)}`);if(w.status===404)throw new Error("unknown_workflow");if(!w.ok)throw new Error(`HTTP ${w.status}`);l=await w.json(),b(null),m()}catch(w){b(t("catalog.definitionLoadFailed",{error:w?.message??String(w)})),o.textContent=t("workflow.detail.loadFailed")}}return C().then(()=>{}),()=>{c=!0}}function yi(e){let n=Object.entries(e??{});return n.length===0?`<div class="muted">${O(t("catalog.noParams"))}</div>`:`<div class="catalog-param-list">${n.map(([o,s])=>`
1211
1215
  <article class="catalog-param">
1212
1216
  <header>
1213
- <code>${D(o)}</code>
1214
- <span class="wf-status">${D(s.required?t("catalog.required"):t("catalog.optional"))}</span>
1215
- <span class="muted">${D(s.type)}${s.format?` \xB7 ${D(s.format)}`:""}</span>
1217
+ <code>${O(o)}</code>
1218
+ <span class="wf-status">${O(s.required?t("catalog.required"):t("catalog.optional"))}</span>
1219
+ <span class="muted">${O(s.type)}${s.format?` \xB7 ${O(s.format)}`:""}</span>
1216
1220
  </header>
1217
- ${s.description?`<div class="muted">${D(t("catalog.description"))}: ${D(s.description)}</div>`:""}
1218
- ${"default"in s?`<pre class="wf-io-pre">${D(`${t("catalog.default")}: ${JSON.stringify(s.default,null,2)}`)}</pre>`:""}
1221
+ ${s.description?`<div class="muted">${O(t("catalog.description"))}: ${O(s.description)}</div>`:""}
1222
+ ${"default"in s?`<pre class="wf-io-pre">${O(`${t("catalog.default")}: ${JSON.stringify(s.default,null,2)}`)}</pre>`:""}
1219
1223
  </article>
1220
- `).join("")}</div>`}var _e=null,Bt=null;function ft(){Bt!==null&&(window.clearInterval(Bt),Bt=null)}function fn(){return _e||(_e=document.createElement("dialog"),_e.className="onboarding-dialog",document.body.appendChild(_e),_e.addEventListener("close",ft),_e)}function ui(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 pi(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 mt(e){let n=fn(),o=e.status==="waiting_for_scan"&&e.qrDataUrl?`<div class="qr-card">
1224
+ `).join("")}</div>`}var _e=null,qt=null;function bt(){qt!==null&&(window.clearInterval(qt),qt=null)}function hn(){return _e||(_e=document.createElement("dialog"),_e.className="onboarding-dialog",document.body.appendChild(_e),_e.addEventListener("close",bt),_e)}function vi(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 ki(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 gt(e){let n=hn(),o=e.status==="waiting_for_scan"&&e.qrDataUrl?`<div class="qr-card">
1221
1225
  <img class="qr-image" src="${e.qrDataUrl}" alt="${t("botOnboarding.qrAlt")}">
1222
1226
  ${e.qrUrl?`<a class="onboarding-link" href="${r(e.qrUrl)}" target="_blank" rel="noopener">${t("botOnboarding.openLink")}</a>`:""}
1223
1227
  </div>`:"",s=e.status==="waiting_for_platform_scan"&&e.platformQrDataUrl?`<div class="qr-card">
@@ -1227,14 +1231,14 @@ ${go("manage")}
1227
1231
  <h3>${t("botOnboarding.title")}</h3>
1228
1232
  <p>${t("botOnboarding.intro")}</p>
1229
1233
  </header>
1230
- <p class="onboarding-status status-${e.status}">${ui(e)}</p>
1234
+ <p class="onboarding-status status-${e.status}">${vi(e)}</p>
1231
1235
  ${o}
1232
1236
  ${s}
1233
1237
  ${a}
1234
- ${pi(e)}
1238
+ ${ki(e)}
1235
1239
  ${i}
1236
1240
  <form method="dialog"><button>${t("botOnboarding.close")}</button></form>
1237
- </article>`}async function mi(){try{let e=await fetch("/api/cli-options"),n=await e.json();if(e.ok&&Array.isArray(n?.options))return n.options}catch{}return[{id:"claude-code",label:"Claude"}]}function mn(e,n){let o=fn(),s=e.map(c=>`<option value="${r(c.id)}">${r(c.label)}\uFF08${r(c.id)}\uFF09</option>`).join(""),a=n?`<p class="form-error">${r(n)}</p>`:"";o.innerHTML=`<article>
1241
+ </article>`}async function $i(){try{let e=await fetch("/api/cli-options"),n=await e.json();if(e.ok&&Array.isArray(n?.options))return n.options}catch{}return[{id:"claude-code",label:"Claude"}]}function bn(e,n){let o=hn(),s=e.map(c=>`<option value="${r(c.id)}">${r(c.label)}\uFF08${r(c.id)}\uFF09</option>`).join(""),a=n?`<p class="form-error">${r(n)}</p>`:"";o.innerHTML=`<article>
1238
1242
  <header>
1239
1243
  <h3>${t("botOnboarding.title")}</h3>
1240
1244
  <p>${t("botOnboarding.intro")}</p>
@@ -1258,8 +1262,8 @@ ${go("manage")}
1258
1262
  <button type="submit" class="primary">${t("botOnboarding.startScan")}</button>
1259
1263
  </menu>
1260
1264
  </form>
1261
- </article>`;let i=o.querySelector("#onboarding-form");o.querySelector("#ob-cancel")?.addEventListener("click",()=>o.close()),i?.addEventListener("submit",c=>{c.preventDefault();let w=o.querySelector("#ob-cli")?.value??"",h=o.querySelector("#ob-dir")?.value??"",y=o.querySelector("#ob-model")?.value??"";fi({cliId:w,workingDir:h,model:y},e)})}async function fi(e,n){ft(),mt({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){mn(n,s?.message??s?.error??"invalid_input");return}if(!o.ok||!s?.job?.id)throw new Error(s?.error??`http_${o.status}`);mt(s.job),Bt=window.setInterval(()=>{gi(s.job.id).catch(a=>{ft(),mt({id:s.job.id,status:"failed",message:a instanceof Error?a.message:String(a)})})},1200)}catch(o){mt({id:"",status:"failed",message:o instanceof Error?o.message:String(o)})}}async function gi(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}`);mt(o.job),(o.job.status==="completed"||o.job.status==="failed")&&ft()}async function bi(){ft();let e=fn();mn([{id:"claude-code",label:"Claude"}]),e.open||e.showModal();let n=await mi();e.open&&e.querySelector("#onboarding-form")&&mn(n)}function qo(){let e=document.getElementById("add-bot-btn");e&&(e.onclick=()=>{bi()})}var hi={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"/>'},jo=[{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"}]}],Uo=jo.flatMap(e=>e.options),We=!1;function gn(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">${hi[e]??""}</svg>`}function wi(e){return e.replace(/[&<>"]/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"})[n])}function Fo(){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=jo.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">${gn(i.icon)}</span><span class="tm-label" data-label-key="${i.labelKey}"></span></button>`).join("")).join("");let s=a=>{We=a,o.hidden=!We,n.setAttribute("aria-expanded",String(We)),e.classList.toggle("open",We)};n.addEventListener("click",a=>{a.stopPropagation(),s(!We)}),o.addEventListener("click",a=>{let i=a.target.closest(".tm-item");i&&(ce.setTheme(i.dataset.value??"system"),s(!1))}),document.addEventListener("click",a=>{We&&!e.contains(a.target)&&s(!1)}),document.addEventListener("keydown",a=>{a.key==="Escape"&&We&&s(!1)}),bn()}function bn(){let e=document.getElementById("theme-menu-btn");if(!e)return;let n=Uo.find(o=>o.value===ce.theme)??Uo[0];e.innerHTML=`<span class="tm-ic">${gn(n.icon)}</span><span class="tm-current">${wi(t(n.labelKey))}</span><span class="tm-chev">${gn("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===ce.theme)})}var be=document.getElementById("root"),tt=!0,_o=!1,Wo=["roles","bot-defaults","team","connectors"],hn=!1;function yi(){if(hn)return;hn=!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(),hn=!1};e.querySelector("#auth-expired-dismiss")?.addEventListener("click",n),e.addEventListener("click",o=>{o.target===e&&n()})}var wn;function vi(){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",wn&&window.clearTimeout(wn),wn=window.setTimeout(()=>{e.style.display="none"},4e3)}var ki=window.fetch.bind(window);window.fetch=async function(...n){let o=await ki(...n);if(o.status===401){let s=(n[1]?.method??"GET").toUpperCase();(s==="GET"||s==="HEAD")&&!_o?yi():vi()}return o};var yn="";function Nt(){let e=document.getElementById("attention-strip");if(!e)return;let n=[...Q.sessions.values()].map(a=>({s:a,reason:Pe(a)})).filter(a=>!!a.reason).sort((a,i)=>ue(a.s)-ue(i.s));if(n.length===0){e.hidden=!0,e.innerHTML="",yn="";return}let o=n[0],s=`
1265
+ </article>`;let i=o.querySelector("#onboarding-form");o.querySelector("#ob-cancel")?.addEventListener("click",()=>o.close()),i?.addEventListener("submit",c=>{c.preventDefault();let h=o.querySelector("#ob-cli")?.value??"",b=o.querySelector("#ob-dir")?.value??"",v=o.querySelector("#ob-model")?.value??"";Si({cliId:h,workingDir:b,model:v},e)})}async function Si(e,n){bt(),gt({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){bn(n,s?.message??s?.error??"invalid_input");return}if(!o.ok||!s?.job?.id)throw new Error(s?.error??`http_${o.status}`);gt(s.job),qt=window.setInterval(()=>{Ti(s.job.id).catch(a=>{bt(),gt({id:s.job.id,status:"failed",message:a instanceof Error?a.message:String(a)})})},1200)}catch(o){gt({id:"",status:"failed",message:o instanceof Error?o.message:String(o)})}}async function Ti(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}`);gt(o.job),(o.job.status==="completed"||o.job.status==="failed")&&bt()}async function Li(){bt();let e=hn();bn([{id:"claude-code",label:"Claude"}]),e.open||e.showModal();let n=await $i();e.open&&e.querySelector("#onboarding-form")&&bn(n)}function zo(){let e=document.getElementById("add-bot-btn");e&&(e.onclick=()=>{Li()})}var Ii={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"/>'},Wo=[{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"}]}],_o=Wo.flatMap(e=>e.options),We=!1;function wn(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">${Ii[e]??""}</svg>`}function Mi(e){return e.replace(/[&<>"]/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"})[n])}function Jo(){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=Wo.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">${wn(i.icon)}</span><span class="tm-label" data-label-key="${i.labelKey}"></span></button>`).join("")).join("");let s=a=>{We=a,o.hidden=!We,n.setAttribute("aria-expanded",String(We)),e.classList.toggle("open",We)};n.addEventListener("click",a=>{a.stopPropagation(),s(!We)}),o.addEventListener("click",a=>{let i=a.target.closest(".tm-item");i&&(ce.setTheme(i.dataset.value??"system"),s(!1))}),document.addEventListener("click",a=>{We&&!e.contains(a.target)&&s(!1)}),document.addEventListener("keydown",a=>{a.key==="Escape"&&We&&s(!1)}),yn()}function yn(){let e=document.getElementById("theme-menu-btn");if(!e)return;let n=_o.find(o=>o.value===ce.theme)??_o[0];e.innerHTML=`<span class="tm-ic">${wn(n.icon)}</span><span class="tm-current">${Mi(t(n.labelKey))}</span><span class="tm-chev">${wn("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===ce.theme)})}var he=document.getElementById("root"),nt=!0,Yo=!1,Qo=["roles","bot-defaults","team","connectors"],vn=!1;function xi(){if(vn)return;vn=!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(),vn=!1};e.querySelector("#auth-expired-dismiss")?.addEventListener("click",n),e.addEventListener("click",o=>{o.target===e&&n()})}var kn;function Ei(){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",kn&&window.clearTimeout(kn),kn=window.setTimeout(()=>{e.style.display="none"},4e3)}var Hi=window.fetch.bind(window);window.fetch=async function(...n){let o=await Hi(...n);if(o.status===401){let s=(n[1]?.method??"GET").toUpperCase();(s==="GET"||s==="HEAD")&&!Yo?xi():Ei()}return o};var $n="";function Ut(){let e=document.getElementById("attention-strip");if(!e)return;let n=[...ee.sessions.values()].map(a=>({s:a,reason:Pe(a)})).filter(a=>!!a.reason).sort((a,i)=>ue(a.s)-ue(i.s));if(n.length===0){e.hidden=!0,e.innerHTML="",$n="";return}let o=n[0],s=`
1262
1266
  <span class="attention-strip-ic" aria-hidden="true">!</span>
1263
1267
  <b>${r(t("strip.pending",{count:n.length}))}</b>
1264
1268
  <span class="attention-strip-longest">${r(t("strip.longest",{time:Le(ue(o.s)),bot:He(o.s),reason:o.reason}))}</span>
1265
- <a class="attention-strip-go" href="#/sessions">${r(t("strip.handle"))}</a>`;e.hidden=!1,s!==yn&&(yn=s,e.innerHTML=s)}Q.on(Nt);Ee().then(Nt);async function $i(){try{let e=await fetch("/api/settings");if(e.ok){let n=await e.json();tt=!!n.authed,ce.authed=tt,_o=!!(n.settings&&n.settings.publicReadOnly);let o=ht(n.lang);o&&ce.setLocale(o)}}catch{}}async function Si(e){if(tt)try{await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({lang:e})})}catch{}}function Ti(){for(let n of Wo){let o=document.querySelector(`.sidebar-nav a[data-route="${n}"]`);o&&(o.style.display=tt?"":"none")}let e=document.getElementById("add-bot-btn");e&&(e.style.display=tt?"":"none")}function Li(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 gt=null;function Go(e){for(let n of document.querySelectorAll(".sidebar-nav a")){let o=n.getAttribute("href")??"#/";n.classList.toggle("active",o===(e||"#/"))}}function vn(){gt&&(gt(),gt=null);let e=location.hash||"#/";if(!tt&&Wo.some(n=>e.startsWith("#/"+n))){Li(be),Go(e);return}e.startsWith("#/workflows/catalog")||e.startsWith("#/workflows-catalog")?gt=Po(be):e.startsWith("#/workflows")?gt=Mo(be):e.startsWith("#/groups")?oo(be):e.startsWith("#/settings")?So(be):e.startsWith("#/bot-defaults")?ro(be):e.startsWith("#/connectors")?ko(be):e.startsWith("#/team/manage")?wo(be):e.startsWith("#/team")?ho(be):e.startsWith("#/roles")?po(be):e.startsWith("#/schedules")?to(be):e.startsWith("#/sessions")?Zn(be):Wn(be),Go(e)}var kn=document.getElementById("status");function Jo(){kn&&(kn.textContent=Q.online?t("status.live"):t("status.disconnected"),kn.className="connection-status "+(Q.online?"online":"offline"))}Q.on(Jo);function zo(){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===ce.locale)}),bn(),Jo()}function Ii(){document.querySelectorAll("[data-locale]").forEach(e=>{e.onclick=()=>{let n=e.dataset.locale;ce.setLocale(n),Si(n)}}),Fo()}(async()=>{ce.init(),Ii(),qo(),ce.on(()=>{zo(),Nt(),vn()}),zo(),Nt(),await $i(),Ti();try{await $n()}catch(e){console.error("botmux dashboard bootstrap failed",e),Q.setOnline(!1)}window.addEventListener("hashchange",vn),vn()})();})();
1269
+ <a class="attention-strip-go" href="#/sessions">${r(t("strip.handle"))}</a>`;e.hidden=!1,s!==$n&&($n=s,e.innerHTML=s)}ee.on(Ut);Ee().then(Ut);async function Ci(){try{let e=await fetch("/api/settings");if(e.ok){let n=await e.json();nt=!!n.authed,ce.authed=nt,Yo=!!(n.settings&&n.settings.publicReadOnly);let o=yt(n.lang);o&&ce.setLocale(o)}}catch{}}async function Ai(e){if(nt)try{await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({lang:e})})}catch{}}function Di(){for(let n of Qo){let o=document.querySelector(`.sidebar-nav a[data-route="${n}"]`);o&&(o.style.display=nt?"":"none")}let e=document.getElementById("add-bot-btn");e&&(e.style.display=nt?"":"none")}function Ri(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 ht=null;function Ko(e){for(let n of document.querySelectorAll(".sidebar-nav a")){let o=n.getAttribute("href")??"#/";n.classList.toggle("active",o===(e||"#/"))}}function Sn(){ht&&(ht(),ht=null);let e=location.hash||"#/";if(!nt&&Qo.some(n=>e.startsWith("#/"+n))){Ri(he),Ko(e);return}e.startsWith("#/workflows/catalog")||e.startsWith("#/workflows-catalog")?ht=Go(he):e.startsWith("#/workflows")?ht=Ao(he):e.startsWith("#/groups")?lo(he):e.startsWith("#/settings")?xo(he):e.startsWith("#/bot-defaults")?mo(he):e.startsWith("#/connectors")?Io(he):e.startsWith("#/team/manage")?So(he):e.startsWith("#/team")?$o(he):e.startsWith("#/roles")?ho(he):e.startsWith("#/schedules")?io(he):e.startsWith("#/sessions")?ao(he):Qn(he),Ko(e)}var Tn=document.getElementById("status");function Xo(){Tn&&(Tn.textContent=ee.online?t("status.live"):t("status.disconnected"),Tn.className="connection-status "+(ee.online?"online":"offline"))}ee.on(Xo);function Vo(){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===ce.locale)}),yn(),Xo()}function Oi(){document.querySelectorAll("[data-locale]").forEach(e=>{e.onclick=()=>{let n=e.dataset.locale;ce.setLocale(n),Ai(n)}}),Jo()}(async()=>{ce.init(),Oi(),zo(),ce.on(()=>{Vo(),Ut(),Sn()}),Vo(),Ut(),await Ci(),Di();try{await Ln()}catch(e){console.error("botmux dashboard bootstrap failed",e),ee.setOnline(!1)}window.addEventListener("hashchange",Sn),Sn()})();})();