botmux 2.48.2 → 2.48.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.
@@ -1,28 +1,28 @@
1
- "use strict";(()=>{var ze=class{sessions=new Map;schedules=new Map;online=!0;listeners=new Set;upsertSessions(t){for(let n of t)this.sessions.set(n.sessionId,n);this.emit()}upsertSchedules(t){for(let n of t)this.schedules.set(n.id,n);this.emit()}applySse(t,n){if(t==="session.spawned")this.sessions.set(n.session.sessionId,n.session);else if(t==="session.update"){let s=this.sessions.get(n.sessionId);s&&this.sessions.set(n.sessionId,{...s,...n.patch})}else if(t==="session.exited"){let s=this.sessions.get(n.sessionId);s&&this.sessions.set(n.sessionId,{...s,status:"closed"})}else if(t==="schedule.created")this.schedules.set(n.schedule.id,n.schedule);else if(t==="schedule.updated"){let s=this.schedules.get(n.id);s&&this.schedules.set(n.id,{...s,...n.patch})}else if(t==="schedule.deleted")this.schedules.delete(n.id);else return;this.emit()}setOnline(t){this.online!==t&&(this.online=t,this.emit())}on(t){return this.listeners.add(t),()=>this.listeners.delete(t)}emit(){for(let t of this.listeners)t()}},N=new ze;async function pt(){let[e,t]=await Promise.all([fetch("/api/sessions").then(a=>a.json()),fetch("/api/schedules").then(a=>a.json())]);N.upsertSessions(e.sessions??[]),N.upsertSchedules(t.schedules??[]);let n=new EventSource("/events"),s=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let a of s)n.addEventListener(a,r=>{try{let i=JSON.parse(r.data);N.applySse(a,i.body??i)}catch{}});n.onerror=()=>N.setOnline(!1),n.onopen=()=>N.setOnline(!0)}var We="botmux.dashboard.locale",gn={"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.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","botOnboarding.add":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.title":"\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.intro":"\u7528\u98DE\u4E66 App \u626B\u7801\u521B\u5EFA PersonalAgent \u5E94\u7528\uFF0C\u6210\u529F\u540E\u4F1A\u5199\u5165\u672C\u673A bots.json\u3002","botOnboarding.starting":"\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...","botOnboarding.waiting":"\u8BF7\u7528\u98DE\u4E66 App \u626B\u7801\u786E\u8BA4\u3002","botOnboarding.verifying":"\u626B\u7801\u6210\u529F\uFF0C\u6B63\u5728\u6821\u9A8C\u51ED\u8BC1...","botOnboarding.completed":"\u673A\u5668\u4EBA\u5DF2\u6DFB\u52A0\u3002","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":"\u63A7\u5236\u53F0\u603B\u89C8","overview.subtitle":"\u8DE8 bot\u3001\u7FA4\u804A\u3001\u4F1A\u8BDD\u548C\u5B9A\u65F6\u4EFB\u52A1\u7684\u5B9E\u65F6\u7BA1\u63A7\u9762\u3002","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.status":"\u72B6\u6001","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.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.closeBulkConfirm":"\u5173\u95ED\u9009\u4E2D\u7684 {count} \u4E2A\u4F1A\u8BDD\uFF1F","sessions.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u4F1A\u8BDD\u3002","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","botDefaults.title":"Bot \u9ED8\u8BA4\u914D\u7F6E","botDefaults.subtitle":"\u7BA1\u7406\u6BCF\u4E2A bot \u7684\u9ED8\u8BA4\u884C\u4E3A\uFF1A\u65B0\u7FA4 oncall \u81EA\u52A8\u7ED1\u5B9A\u3001\u5361\u7247\u7B7E\u540D\u7B49\u3002","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.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\uFF0C\u672C\u9879\u4E0D\u751F\u6548","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","nav.roles":"\u89D2\u8272\u7BA1\u7406","roles.title":"\u89D2\u8272\u7BA1\u7406","roles.subtitle":"\u4E3A\u6BCF\u4E2A\u7FA4\u7EC4\u7684\u6BCF\u4E2A Bot \u5355\u72EC\u8BBE\u7F6E\u89D2\u8272\u63D0\u793A\u8BCD\uFF0CBot \u5728\u8BE5\u7FA4\u4E2D\u4F1A\u4EE5\u6B64\u89D2\u8272\u884C\u4E8B\u3002","roles.search":"\u641C\u7D22\u7FA4\u540D/Bot/ID","roles.refresh":"\u5237\u65B0","roles.selectHint":"\u2190 \u5C55\u5F00\u7FA4\u7EC4\uFF0C\u9009\u62E9\u4E00\u4E2A Bot \u6765\u7F16\u8F91\u89D2\u8272","roles.editorPlaceholder":`\u8F93\u5165\u89D2\u8272\u63CF\u8FF0\uFF0C\u4F8B\u5982\uFF1A
1
+ "use strict";(()=>{var Ve=class{sessions=new Map;schedules=new Map;online=!0;listeners=new Set;upsertSessions(t){for(let n of t)this.sessions.set(n.sessionId,n);this.emit()}upsertSchedules(t){for(let n of t)this.schedules.set(n.id,n);this.emit()}applySse(t,n){if(t==="session.spawned")this.sessions.set(n.session.sessionId,n.session);else if(t==="session.update"){let s=this.sessions.get(n.sessionId);s&&this.sessions.set(n.sessionId,{...s,...n.patch})}else if(t==="session.exited"){let s=this.sessions.get(n.sessionId);s&&this.sessions.set(n.sessionId,{...s,status:"closed"})}else if(t==="schedule.created")this.schedules.set(n.schedule.id,n.schedule);else if(t==="schedule.updated"){let s=this.schedules.get(n.id);s&&this.schedules.set(n.id,{...s,...n.patch})}else if(t==="schedule.deleted")this.schedules.delete(n.id);else return;this.emit()}setOnline(t){this.online!==t&&(this.online=t,this.emit())}on(t){return this.listeners.add(t),()=>this.listeners.delete(t)}emit(){for(let t of this.listeners)t()}},_=new Ve;async function ft(){let[e,t]=await Promise.all([fetch("/api/sessions").then(a=>a.json()),fetch("/api/schedules").then(a=>a.json())]);_.upsertSessions(e.sessions??[]),_.upsertSchedules(t.schedules??[]);let n=new EventSource("/events"),s=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let a of s)n.addEventListener(a,r=>{try{let i=JSON.parse(r.data);_.applySse(a,i.body??i)}catch{}});n.onerror=()=>_.setOnline(!1),n.onopen=()=>_.setOnline(!0)}var Ye="botmux.dashboard.locale",wn={"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.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","botOnboarding.add":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.title":"\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.intro":"\u7528\u98DE\u4E66 App \u626B\u7801\u521B\u5EFA PersonalAgent \u5E94\u7528\uFF0C\u6210\u529F\u540E\u4F1A\u5199\u5165\u672C\u673A bots.json\u3002","botOnboarding.starting":"\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...","botOnboarding.waiting":"\u8BF7\u7528\u98DE\u4E66 App \u626B\u7801\u786E\u8BA4\u3002","botOnboarding.verifying":"\u626B\u7801\u6210\u529F\uFF0C\u6B63\u5728\u6821\u9A8C\u51ED\u8BC1...","botOnboarding.completed":"\u673A\u5668\u4EBA\u5DF2\u6DFB\u52A0\u3002","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":"\u63A7\u5236\u53F0\u603B\u89C8","overview.subtitle":"\u8DE8 bot\u3001\u7FA4\u804A\u3001\u4F1A\u8BDD\u548C\u5B9A\u65F6\u4EFB\u52A1\u7684\u5B9E\u65F6\u7BA1\u63A7\u9762\u3002","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.status":"\u72B6\u6001","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.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.closeBulkConfirm":"\u5173\u95ED\u9009\u4E2D\u7684 {count} \u4E2A\u4F1A\u8BDD\uFF1F","sessions.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u4F1A\u8BDD\u3002","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","botDefaults.title":"Bot \u9ED8\u8BA4\u914D\u7F6E","botDefaults.subtitle":"\u7BA1\u7406\u6BCF\u4E2A bot \u7684\u9ED8\u8BA4\u884C\u4E3A\uFF1A\u65B0\u7FA4 oncall \u81EA\u52A8\u7ED1\u5B9A\u3001\u5361\u7247\u7B7E\u540D\u7B49\u3002","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.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\uFF0C\u672C\u9879\u4E0D\u751F\u6548","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":"\u56E2\u961F\u89D2\u8272","botDefaults.roleHelp":"\u8BE5 bot \u8DE8\u7FA4\u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF08\u56E2\u961F\u7EA7\u89D2\u8272\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","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
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","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"},hn={"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.botDefaults":"Bot Defaults","status.live":"Live","status.disconnected":"Disconnected","status.system":"System","status.light":"Light","status.dark":"Dark","status.language":"Language","status.theme":"Theme","botOnboarding.add":"Add Bot","botOnboarding.title":"Scan to Add Bot","botOnboarding.intro":"Scan with the Feishu app to create a PersonalAgent app. The dashboard writes it to local bots.json after success.","botOnboarding.starting":"Generating QR code...","botOnboarding.waiting":"Scan with the Feishu app to continue.","botOnboarding.verifying":"Scan accepted. Verifying credentials...","botOnboarding.completed":"Bot added.","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":"Control Overview","overview.subtitle":"A realtime control plane across bots, chats, CLI sessions, and schedules.","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.status":"Status","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.close":"Close Session","sessions.resume":"Resume Session","sessions.dismiss":"Close","sessions.closeConfirm":"Close this session?","sessions.resumeFailed":"Resume failed","sessions.closeBulkConfirm":"Close {count} selected sessions?","sessions.empty":"No sessions match the filters.","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.","botDefaults.title":"Bot Defaults","botDefaults.subtitle":"Manage each bot's defaults: new-chat oncall auto-binding, card signature, and more.","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.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","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.:
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"},gn={"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.botDefaults":"Bot Defaults","status.live":"Live","status.disconnected":"Disconnected","status.system":"System","status.light":"Light","status.dark":"Dark","status.language":"Language","status.theme":"Theme","botOnboarding.add":"Add Bot","botOnboarding.title":"Scan to Add Bot","botOnboarding.intro":"Scan with the Feishu app to create a PersonalAgent app. The dashboard writes it to local bots.json after success.","botOnboarding.starting":"Generating QR code...","botOnboarding.waiting":"Scan with the Feishu app to continue.","botOnboarding.verifying":"Scan accepted. Verifying credentials...","botOnboarding.completed":"Bot added.","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":"Control Overview","overview.subtitle":"A realtime control plane across bots, chats, CLI sessions, and schedules.","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.status":"Status","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.close":"Close Session","sessions.resume":"Resume Session","sessions.dismiss":"Close","sessions.closeConfirm":"Close this session?","sessions.resumeFailed":"Resume failed","sessions.closeBulkConfirm":"Close {count} selected sessions?","sessions.empty":"No sessions match the filters.","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.","botDefaults.title":"Bot Defaults","botDefaults.subtitle":"Manage each bot's defaults: new-chat oncall auto-binding, card signature, and more.","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.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":"Team Role","botDefaults.roleHelp":"This bot's cross-chat default persona (team-level role), 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","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
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","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"},ft={zh:gn,en:hn};function mt(e){if(typeof e!="string")return null;let t=e.trim().toLowerCase();return t==="zh"||t.startsWith("zh-")?"zh":t==="en"||t.startsWith("en-")?"en":null}function bn(e=[]){for(let t of e){let n=mt(t);if(n)return n}return"zh"}function Me(e){return(t,n)=>{let s=ft[e][t]??ft.zh[t]??t;return n?s.replace(/\{(\w+)\}/g,(a,r)=>{let i=n[r];return i==null?`{${r}}`:String(i)}):s}}function wt(e,t){return(e?mt(e.getItem(We)):null)??bn(t)}var Je="botmux.dashboard.theme";function yn(e){return e==="system"||e==="light"||e==="dark"?e:null}function gt(e,t){return e==="system"?t?"dark":"light":e}function ht(e){return yn(e?.getItem(Je))??"system"}var Ge=class{locale="zh";themeMode="system";resolvedTheme="light";listeners=new Set;translate=Me(this.locale);mediaQuery=null;init(){let t=typeof window<"u"?window:void 0;this.locale=wt(t?.localStorage,vn()),this.translate=Me(this.locale),this.themeMode=ht(t?.localStorage),this.mediaQuery=t?.matchMedia?.("(prefers-color-scheme: dark)")??null,this.mediaQuery?.addEventListener("change",()=>{this.applyTheme(),this.emit()}),this.applyTheme(),this.applyLocale()}t(t,n){return this.translate(t,n)}setLocale(t){this.locale!==t&&(this.locale=t,this.translate=Me(t),window.localStorage.setItem(We,t),this.applyLocale(),this.emit())}setThemeMode(t){this.themeMode!==t&&(this.themeMode=t,window.localStorage.setItem(Je,t),this.applyTheme(),this.emit())}on(t){return this.listeners.add(t),()=>this.listeners.delete(t)}emit(){for(let t of this.listeners)t()}applyTheme(){this.resolvedTheme=gt(this.themeMode,!!this.mediaQuery?.matches),document.documentElement.dataset.theme=this.resolvedTheme,document.documentElement.dataset.themeMode=this.themeMode}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}};function vn(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var ae=new Ge;function o(e,t){return ae.t(e,t)}function d(e){return e.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}function be(e){if(!e)return"-";let t=Date.now()-e;return t<6e4?o("common.now"):t<36e5?Math.floor(t/6e4)+"m":t<864e5?Math.floor(t/36e5)+"h":Math.floor(t/864e5)+"d"}var Ke={chats:[],bots:[]};async function kn(){try{let e=await fetch("/api/groups");if(!e.ok)return;Ke=await e.json()}catch{}}function $n(e){return`status status-${d(e||"unknown")}`}function Sn(e){return`<li class="overview-list-row">
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"},mt={zh:wn,en:gn};function wt(e){if(typeof e!="string")return null;let t=e.trim().toLowerCase();return t==="zh"||t.startsWith("zh-")?"zh":t==="en"||t.startsWith("en-")?"en":null}function hn(e=[]){for(let t of e){let n=wt(t);if(n)return n}return"zh"}function Re(e){return(t,n)=>{let s=mt[e][t]??mt.zh[t]??t;return n?s.replace(/\{(\w+)\}/g,(a,r)=>{let i=n[r];return i==null?`{${r}}`:String(i)}):s}}function gt(e,t){return(e?wt(e.getItem(Ye)):null)??hn(t)}var Qe="botmux.dashboard.theme";function bn(e){return e==="system"||e==="light"||e==="dark"?e:null}function ht(e,t){return e==="system"?t?"dark":"light":e}function bt(e){return bn(e?.getItem(Qe))??"system"}var Xe=class{locale="zh";themeMode="system";resolvedTheme="light";listeners=new Set;translate=Re(this.locale);mediaQuery=null;init(){let t=typeof window<"u"?window:void 0;this.locale=gt(t?.localStorage,yn()),this.translate=Re(this.locale),this.themeMode=bt(t?.localStorage),this.mediaQuery=t?.matchMedia?.("(prefers-color-scheme: dark)")??null,this.mediaQuery?.addEventListener("change",()=>{this.applyTheme(),this.emit()}),this.applyTheme(),this.applyLocale()}t(t,n){return this.translate(t,n)}setLocale(t){this.locale!==t&&(this.locale=t,this.translate=Re(t),window.localStorage.setItem(Ye,t),this.applyLocale(),this.emit())}setThemeMode(t){this.themeMode!==t&&(this.themeMode=t,window.localStorage.setItem(Qe,t),this.applyTheme(),this.emit())}on(t){return this.listeners.add(t),()=>this.listeners.delete(t)}emit(){for(let t of this.listeners)t()}applyTheme(){this.resolvedTheme=ht(this.themeMode,!!this.mediaQuery?.matches),document.documentElement.dataset.theme=this.resolvedTheme,document.documentElement.dataset.themeMode=this.themeMode}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}};function yn(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var ce=new Xe;function o(e,t){return ce.t(e,t)}function d(e){return e.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}function $e(e){if(!e)return"-";let t=Date.now()-e;return t<6e4?o("common.now"):t<36e5?Math.floor(t/6e4)+"m":t<864e5?Math.floor(t/36e5)+"h":Math.floor(t/864e5)+"d"}var Ze={chats:[],bots:[]};async function vn(){try{let e=await fetch("/api/groups");if(!e.ok)return;Ze=await e.json()}catch{}}function kn(e){return`status status-${d(e||"unknown")}`}function $n(e){return`<li class="overview-list-row">
14
14
  <div>
15
15
  <strong>${d(e.title??e.sessionId)}</strong>
16
16
  <span>${d(e.botName??"")} \xB7 ${d(e.cliId??"unknown")}</span>
17
17
  </div>
18
- <span class="${$n(e.status)}">${d(e.status??"unknown")}</span>
19
- </li>`}function In(e){let t=e.nextRunAt?new Date(e.nextRunAt).toLocaleString():"-";return`<li class="overview-list-row">
18
+ <span class="${kn(e.status)}">${d(e.status??"unknown")}</span>
19
+ </li>`}function Sn(e){let t=e.nextRunAt?new Date(e.nextRunAt).toLocaleString():"-";return`<li class="overview-list-row">
20
20
  <div>
21
21
  <strong>${d(e.name??e.id)}</strong>
22
22
  <span>${d(e.botName??e.larkAppId??"")} \xB7 ${d(e.parsed?.display??"")}</span>
23
23
  </div>
24
24
  <span>${d(t)}</span>
25
- </li>`}async function bt(e){e.innerHTML=`<section class="page hero-page">
25
+ </li>`}async function yt(e){e.innerHTML=`<section class="page hero-page">
26
26
  <div class="page-heading">
27
27
  <div>
28
28
  <p class="eyebrow">${o("app.subtitle")}</p>
@@ -53,19 +53,19 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
53
53
  <ul class="overview-list" id="next-schedules"></ul>
54
54
  </section>
55
55
  </div>
56
- </section>`;let t=e.querySelector("#overview-metrics"),n=e.querySelector("#recent-sessions"),s=e.querySelector("#next-schedules");function a(){let r=[...N.sessions.values()],i=[...N.schedules.values()],m=r.filter(L=>L.status!=="closed"),k=r.filter(L=>L.status==="working"||L.status==="analyzing"||L.status==="starting"),$=i.filter(L=>L.enabled),p=Ke.bots?.length||new Set(r.map(L=>L.larkAppId).filter(Boolean)).size,g=[{label:o("overview.openSessions"),value:m.length,meta:`${r.length} ${o("overview.total")}`},{label:o("overview.workingSessions"),value:k.length,meta:`${m.length} ${o("overview.active")}`},{label:o("overview.onlineBots"),value:p,meta:o("overview.daemonRegistry")},{label:o("overview.schedules"),value:i.length,meta:`${$.length} ${o("overview.enabledSchedules")}`},{label:o("overview.groups"),value:Ke.chats?.length??0,meta:o("overview.chatMatrix")}];t.innerHTML=g.map(L=>`<article class="metric-card">
56
+ </section>`;let t=e.querySelector("#overview-metrics"),n=e.querySelector("#recent-sessions"),s=e.querySelector("#next-schedules");function a(){let r=[..._.sessions.values()],i=[..._.schedules.values()],m=r.filter(L=>L.status!=="closed"),y=r.filter(L=>L.status==="working"||L.status==="analyzing"||L.status==="starting"),k=i.filter(L=>L.enabled),h=Ze.bots?.length||new Set(r.map(L=>L.larkAppId).filter(Boolean)).size,u=[{label:o("overview.openSessions"),value:m.length,meta:`${r.length} ${o("overview.total")}`},{label:o("overview.workingSessions"),value:y.length,meta:`${m.length} ${o("overview.active")}`},{label:o("overview.onlineBots"),value:h,meta:o("overview.daemonRegistry")},{label:o("overview.schedules"),value:i.length,meta:`${k.length} ${o("overview.enabledSchedules")}`},{label:o("overview.groups"),value:Ze.chats?.length??0,meta:o("overview.chatMatrix")}];t.innerHTML=u.map(L=>`<article class="metric-card">
57
57
  <span>${d(L.label)}</span>
58
58
  <strong>${L.value}</strong>
59
59
  <small>${d(L.meta)}</small>
60
- </article>`).join("");let l=r.sort((L,b)=>Number(b.lastMessageAt??0)-Number(L.lastMessageAt??0)).slice(0,6);n.innerHTML=l.length?l.map(L=>Sn({...L,title:L.title??`${be(L.lastMessageAt)} \xB7 ${L.sessionId}`})).join(""):`<li class="empty">${o("overview.noSessions")}</li>`;let I=i.filter(L=>L.nextRunAt).sort((L,b)=>Date.parse(L.nextRunAt)-Date.parse(b.nextRunAt)).slice(0,6);s.innerHTML=I.length?I.map(In).join(""):`<li class="empty">${o("overview.noSchedules")}</li>`}N.on(a),a(),kn().then(a)}function se(e,t){return`<th data-sort="${e}" data-label="${d(t)}">${d(t)}</th>`}var yt=["claude-code","codex","codex-app","cursor","gemini","opencode","mtr","hermes","mira","aiden","coco","unknown"];function Tn(){return`<div class="filter-check-group" role="group" aria-label="${o("sessions.cli")}">
60
+ </article>`).join("");let l=r.sort((L,v)=>Number(v.lastMessageAt??0)-Number(L.lastMessageAt??0)).slice(0,6);n.innerHTML=l.length?l.map(L=>$n({...L,title:L.title??`${$e(L.lastMessageAt)} \xB7 ${L.sessionId}`})).join(""):`<li class="empty">${o("overview.noSessions")}</li>`;let $=i.filter(L=>L.nextRunAt).sort((L,v)=>Date.parse(L.nextRunAt)-Date.parse(v.nextRunAt)).slice(0,6);s.innerHTML=$.length?$.map(Sn).join(""):`<li class="empty">${o("overview.noSchedules")}</li>`}_.on(a),a(),vn().then(a)}function ue(e,t){return`<th data-sort="${e}" data-label="${d(t)}">${d(t)}</th>`}var vt=["claude-code","codex","codex-app","cursor","gemini","opencode","mtr","hermes","mira","aiden","coco","unknown"];function Tn(){return`<div class="filter-check-group" role="group" aria-label="${o("sessions.cli")}">
61
61
  <span class="filter-check-label">${o("sessions.cli")}</span>
62
- ${yt.map(e=>`
62
+ ${vt.map(e=>`
63
63
  <label class="filter-check">
64
64
  <input type="checkbox" name="cli" value="${d(e)}" checked>
65
65
  <span>${d(e)}</span>
66
66
  </label>
67
67
  `).join("")}
68
- </div>`}function Ln(){return`<section class="page">
68
+ </div>`}function In(){return`<section class="page">
69
69
  <div class="page-heading">
70
70
  <div>
71
71
  <p class="eyebrow">${o("nav.sessions")}</p>
@@ -96,49 +96,49 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
96
96
  <table id="sessions-table">
97
97
  <thead><tr>
98
98
  <th><input type="checkbox" id="select-all" title="${o("sessions.activeOnly")}"></th>
99
- ${se("botName",o("sessions.bot"))}
100
- ${se("cliId",o("sessions.cli"))}
101
- ${se("status",o("sessions.status"))}
102
- ${se("title",o("sessions.titleCol"))}
103
- ${se("workingDir",o("sessions.workingDir"))}
104
- ${se("spawnedAt",o("sessions.created"))}
105
- ${se("lastMessageAt",o("sessions.last"))}
106
- ${se("adopt",o("sessions.adopt"))}
99
+ ${ue("botName",o("sessions.bot"))}
100
+ ${ue("cliId",o("sessions.cli"))}
101
+ ${ue("status",o("sessions.status"))}
102
+ ${ue("title",o("sessions.titleCol"))}
103
+ ${ue("workingDir",o("sessions.workingDir"))}
104
+ ${ue("spawnedAt",o("sessions.created"))}
105
+ ${ue("lastMessageAt",o("sessions.last"))}
106
+ ${ue("adopt",o("sessions.adopt"))}
107
107
  <th>${o("sessions.actions")}</th>
108
108
  </tr></thead>
109
109
  <tbody></tbody>
110
110
  </table>
111
111
  <dialog id="drawer"></dialog>
112
- </section>`}function vt(e){e.innerHTML=Ln();let t=e.querySelector("#sessions-table tbody"),n=e.querySelector("#filters"),s=e.querySelector("#drawer"),a=e.querySelector("#select-all"),r=e.querySelector("#bulk-bar"),i=e.querySelector("#bulk-count"),m=e.querySelector("#bulk-close"),k=e.querySelector("#bulk-clear"),$=e.querySelector("#sessions-table"),p=new Set,g="lastMessageAt",l="desc";function I(u){let w=u.status==="closed",h=p.has(u.sessionId)?"checked":"";return`<tr data-id="${d(u.sessionId)}">
113
- <td><input type="checkbox" class="row-select" ${h} ${w?"disabled":""}></td>
114
- <td>${d(u.botName??"")}</td>
115
- <td><span class="badge cli-${d(u.cliId??"unknown")}">${d(u.cliId??"unknown")}</span></td>
116
- <td><span class="status status-${d(u.status??"unknown")}">${d(u.status??"unknown")}</span></td>
117
- <td>${d((u.title??"").slice(0,48))}</td>
118
- <td title="${d(u.workingDir??"")}">${d((u.workingDir??"").slice(-34))}</td>
119
- <td>${be(u.spawnedAt)}</td>
120
- <td>${be(u.lastMessageAt)}</td>
121
- <td>${u.adopt?'<span class="badge">adopt</span>':""}</td>
112
+ </section>`}function kt(e){e.innerHTML=In();let t=e.querySelector("#sessions-table tbody"),n=e.querySelector("#filters"),s=e.querySelector("#drawer"),a=e.querySelector("#select-all"),r=e.querySelector("#bulk-bar"),i=e.querySelector("#bulk-count"),m=e.querySelector("#bulk-close"),y=e.querySelector("#bulk-clear"),k=e.querySelector("#sessions-table"),h=new Set,u="lastMessageAt",l="desc";function $(p){let w=p.status==="closed",g=h.has(p.sessionId)?"checked":"";return`<tr data-id="${d(p.sessionId)}">
113
+ <td><input type="checkbox" class="row-select" ${g} ${w?"disabled":""}></td>
114
+ <td>${d(p.botName??"")}</td>
115
+ <td><span class="badge cli-${d(p.cliId??"unknown")}">${d(p.cliId??"unknown")}</span></td>
116
+ <td><span class="status status-${d(p.status??"unknown")}">${d(p.status??"unknown")}</span></td>
117
+ <td>${d((p.title??"").slice(0,48))}</td>
118
+ <td title="${d(p.workingDir??"")}">${d((p.workingDir??"").slice(-34))}</td>
119
+ <td>${$e(p.spawnedAt)}</td>
120
+ <td>${$e(p.lastMessageAt)}</td>
121
+ <td>${p.adopt?'<span class="badge">adopt</span>':""}</td>
122
122
  <td><button class="open" type="button">${o("sessions.details")}</button></td>
123
- </tr>`}function L(){let u=new FormData(n),w=(u.get("q")??"").toLowerCase(),h=u.getAll("cli"),E=h.length>0&&h.length<yt.length,M=u.get("status"),A=u.get("adopt"),P=!!u.get("active"),O=[...N.sessions.values()].filter(H=>!E||h.includes(H.cliId??"unknown")).filter(H=>!M||H.status===M).filter(H=>!A||A==="yes"==!!H.adopt).filter(H=>!P||H.status!=="closed").filter(H=>!w||JSON.stringify(H).toLowerCase().includes(w));return O.sort(f),O}function b(u,w){return w==="spawnedAt"||w==="lastMessageAt"?Number(u[w]??0):w==="adopt"?!!u.adopt:String(u[w]??"").toLowerCase()}function f(u,w){let h=b(u,g),E=b(w,g),M=0;return typeof h=="number"&&typeof E=="number"?M=h-E:typeof h=="boolean"&&typeof E=="boolean"?M=Number(h)-Number(E):M=String(h).localeCompare(String(E)),M===0&&(M=Number(u.lastMessageAt??0)-Number(w.lastMessageAt??0)),l==="asc"?M:-M}function T(){$.querySelectorAll("th[data-sort]").forEach(u=>{let w=u.dataset.sort===g;u.classList.toggle("sorted",w),u.setAttribute("aria-sort",w?l==="asc"?"ascending":"descending":"none");let h=u.dataset.label??u.textContent?.trim()??"";u.textContent=w?`${h} ${l==="asc"?"\u25B2":"\u25BC"}`:h})}function S(u){r.hidden=p.size===0,i.textContent=o("sessions.selectedCount",{count:p.size});let w=u.filter(E=>E.status!=="closed");if(w.length===0){a.checked=!1,a.indeterminate=!1,a.disabled=!0;return}a.disabled=!1;let h=w.filter(E=>p.has(E.sessionId)).length;a.checked=h===w.length,a.indeterminate=h>0&&h<w.length}function y(){let u=L();for(let w of[...p]){let h=N.sessions.get(w);(!h||h.status==="closed")&&p.delete(w)}t.innerHTML=u.length?u.map(I).join(""):`<tr><td colspan="10" class="empty">${o("sessions.empty")}</td></tr>`,T(),S(u)}function C(u){let w=u.status==="closed";s.innerHTML=`<article>
123
+ </tr>`}function L(){let p=new FormData(n),w=(p.get("q")??"").toLowerCase(),g=p.getAll("cli"),E=g.length>0&&g.length<vt.length,H=p.get("status"),C=p.get("adopt"),j=!!p.get("active"),U=[..._.sessions.values()].filter(R=>!E||g.includes(R.cliId??"unknown")).filter(R=>!H||R.status===H).filter(R=>!C||C==="yes"==!!R.adopt).filter(R=>!j||R.status!=="closed").filter(R=>!w||JSON.stringify(R).toLowerCase().includes(w));return U.sort(f),U}function v(p,w){return w==="spawnedAt"||w==="lastMessageAt"?Number(p[w]??0):w==="adopt"?!!p.adopt:String(p[w]??"").toLowerCase()}function f(p,w){let g=v(p,u),E=v(w,u),H=0;return typeof g=="number"&&typeof E=="number"?H=g-E:typeof g=="boolean"&&typeof E=="boolean"?H=Number(g)-Number(E):H=String(g).localeCompare(String(E)),H===0&&(H=Number(p.lastMessageAt??0)-Number(w.lastMessageAt??0)),l==="asc"?H:-H}function I(){k.querySelectorAll("th[data-sort]").forEach(p=>{let w=p.dataset.sort===u;p.classList.toggle("sorted",w),p.setAttribute("aria-sort",w?l==="asc"?"ascending":"descending":"none");let g=p.dataset.label??p.textContent?.trim()??"";p.textContent=w?`${g} ${l==="asc"?"\u25B2":"\u25BC"}`:g})}function T(p){r.hidden=h.size===0,i.textContent=o("sessions.selectedCount",{count:h.size});let w=p.filter(E=>E.status!=="closed");if(w.length===0){a.checked=!1,a.indeterminate=!1,a.disabled=!0;return}a.disabled=!1;let g=w.filter(E=>h.has(E.sessionId)).length;a.checked=g===w.length,a.indeterminate=g>0&&g<w.length}function S(){let p=L();for(let w of[...h]){let g=_.sessions.get(w);(!g||g.status==="closed")&&h.delete(w)}t.innerHTML=p.length?p.map($).join(""):`<tr><td colspan="10" class="empty">${o("sessions.empty")}</td></tr>`,I(),T(p)}function M(p){let w=p.status==="closed";s.innerHTML=`<article>
124
124
  <header>
125
- <h3>${d(u.title??u.sessionId)}</h3>
126
- <span class="status status-${d(u.status??"unknown")}">${d(u.status??"unknown")}</span>
127
- <p><code>${d(u.sessionId)}</code> <button data-copy="${d(u.sessionId)}">${o("sessions.copy")}</button></p>
125
+ <h3>${d(p.title??p.sessionId)}</h3>
126
+ <span class="status status-${d(p.status??"unknown")}">${d(p.status??"unknown")}</span>
127
+ <p><code>${d(p.sessionId)}</code> <button data-copy="${d(p.sessionId)}">${o("sessions.copy")}</button></p>
128
128
  </header>
129
- <p><b>${o("sessions.bot")}:</b> ${d(u.botName??"-")} \xB7 <b>${o("sessions.cli")}:</b> ${d(u.cliId??"?")}</p>
130
- <p><b>chatId:</b> <code>${d(u.chatId??"")}</code> <button data-copy="${d(u.chatId??"")}">${o("sessions.copy")}</button></p>
131
- <p><b>rootMessageId:</b> <code>${d(u.rootMessageId??"")}</code> <button data-copy="${d(u.rootMessageId??"")}">${o("sessions.copy")}</button></p>
132
- ${u.threadId?`<p><b>threadId:</b> <code>${d(u.threadId)}</code></p>`:""}
133
- <p><b>${o("sessions.workingDir")}:</b> ${d(u.workingDir??"-")}</p>
129
+ <p><b>${o("sessions.bot")}:</b> ${d(p.botName??"-")} \xB7 <b>${o("sessions.cli")}:</b> ${d(p.cliId??"?")}</p>
130
+ <p><b>chatId:</b> <code>${d(p.chatId??"")}</code> <button data-copy="${d(p.chatId??"")}">${o("sessions.copy")}</button></p>
131
+ <p><b>rootMessageId:</b> <code>${d(p.rootMessageId??"")}</code> <button data-copy="${d(p.rootMessageId??"")}">${o("sessions.copy")}</button></p>
132
+ ${p.threadId?`<p><b>threadId:</b> <code>${d(p.threadId)}</code></p>`:""}
133
+ <p><b>${o("sessions.workingDir")}:</b> ${d(p.workingDir??"-")}</p>
134
134
  <div class="actions">
135
135
  <button id="locate-btn" type="button">${o("sessions.locate")}</button>
136
- ${u.webPort?`<a class="btn-link primary" href="http://${d(location.hostname)}:${u.proxyPort??u.webPort}${u.proxyPort?`/s/${encodeURIComponent(u.sessionId)}`:""}" target="_blank" rel="noopener">${o("sessions.openTerminal")}</a>`:""}
136
+ ${p.webPort?`<a class="btn-link primary" href="http://${d(location.hostname)}:${p.proxyPort??p.webPort}${p.proxyPort?`/s/${encodeURIComponent(p.sessionId)}`:""}" target="_blank" rel="noopener">${o("sessions.openTerminal")}</a>`:""}
137
137
  ${w?`<button id="resume-btn" type="button" class="primary">${o("sessions.resume")}</button>`:""}
138
138
  ${w?"":`<button id="close-btn" type="button" class="contrast">${o("sessions.close")}</button>`}
139
139
  </div>
140
140
  <form method="dialog"><button>${o("sessions.dismiss")}</button></form>
141
- </article>`,s.querySelectorAll("[data-copy]").forEach(A=>{A.onclick=()=>{navigator.clipboard.writeText(A.dataset.copy??""),A.textContent=o("sessions.copied"),setTimeout(()=>{A.textContent=o("sessions.copy")},800)}});let h=s.querySelector("#locate-btn");h&&(h.onclick=async()=>{h.disabled=!0,h.textContent=o("sessions.locating");try{let A=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/locate`,{method:"POST"}),P=await A.json();if(P.ok){let O=30;h.textContent=o("sessions.cooldown",{seconds:O});let H=setInterval(()=>{O-=1,O<=0?(clearInterval(H),h.disabled=!1,h.textContent=o("sessions.locate")):h.textContent=o("sessions.cooldown",{seconds:O})},1e3)}else alert(`Locate failed: ${P.error??A.status}`),h.disabled=!1,h.textContent=o("sessions.locate")}catch(A){alert(`Locate error: ${A}`),h.disabled=!1,h.textContent=o("sessions.locate")}});let E=s.querySelector("#resume-btn");E&&(E.onclick=async()=>{E.disabled=!0;try{let A=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/resume`,{method:"POST"}),P=await A.json().catch(()=>({}));if(!A.ok||P.ok===!1){alert(`${o("sessions.resumeFailed")}: ${P?.error??A.status}`),E.disabled=!1;return}s.close()}catch(A){alert(`${o("sessions.resumeFailed")}: ${A}`),E.disabled=!1}});let M=s.querySelector("#close-btn");M&&(M.onclick=async()=>{if(confirm(o("sessions.closeConfirm"))){M.disabled=!0;try{await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/close`,{method:"POST"})}finally{s.close()}}}),s.showModal()}t.addEventListener("click",u=>{let w=u.target;if(w.classList.contains("row-select")){let A=w.closest("tr[data-id]");if(!A)return;w.checked?p.add(A.dataset.id):p.delete(A.dataset.id),S(L());return}let h=w.closest("td");if(h&&h.querySelector(".row-select"))return;let E=w.closest("tr[data-id]");if(!E)return;let M=N.sessions.get(E.dataset.id);M&&C(M)}),a.addEventListener("change",()=>{let u=L().filter(w=>w.status!=="closed");for(let w of u)a.checked?p.add(w.sessionId):p.delete(w.sessionId);y()}),k.addEventListener("click",()=>{p.clear(),y()}),m.addEventListener("click",async()=>{let u=[...p];if(u.length===0||!confirm(o("sessions.closeBulkConfirm",{count:u.length})))return;m.disabled=!0,k.disabled=!0;let w=m.textContent,h=0,E=0,M=[...u];m.textContent=`0/${u.length}`;async function A(){for(;M.length;){let P=M.shift();try{let O=await fetch(`/api/sessions/${encodeURIComponent(P)}/close`,{method:"POST"}),H=await O.json().catch(()=>({}));(!O.ok||H?.ok===!1)&&(E+=1)}catch{E+=1}finally{h+=1,m.textContent=`${h}/${u.length}`}}}await Promise.all(Array.from({length:Math.min(6,u.length)},()=>A())),m.textContent=w,m.disabled=!1,k.disabled=!1,p.clear(),y(),E>0&&alert(`Failed: ${E}/${u.length}`)}),$.querySelectorAll("th[data-sort]").forEach(u=>{u.addEventListener("click",()=>{let w=u.dataset.sort;g===w?l=l==="asc"?"desc":"asc":(g=w,l=w==="spawnedAt"||w==="lastMessageAt"?"desc":"asc"),y()})}),n.addEventListener("input",y),N.on(y),y()}function En(){return`<section class="page">
141
+ </article>`,s.querySelectorAll("[data-copy]").forEach(C=>{C.onclick=()=>{navigator.clipboard.writeText(C.dataset.copy??""),C.textContent=o("sessions.copied"),setTimeout(()=>{C.textContent=o("sessions.copy")},800)}});let g=s.querySelector("#locate-btn");g&&(g.onclick=async()=>{g.disabled=!0,g.textContent=o("sessions.locating");try{let C=await fetch(`/api/sessions/${encodeURIComponent(p.sessionId)}/locate`,{method:"POST"}),j=await C.json();if(j.ok){let U=30;g.textContent=o("sessions.cooldown",{seconds:U});let R=setInterval(()=>{U-=1,U<=0?(clearInterval(R),g.disabled=!1,g.textContent=o("sessions.locate")):g.textContent=o("sessions.cooldown",{seconds:U})},1e3)}else alert(`Locate failed: ${j.error??C.status}`),g.disabled=!1,g.textContent=o("sessions.locate")}catch(C){alert(`Locate error: ${C}`),g.disabled=!1,g.textContent=o("sessions.locate")}});let E=s.querySelector("#resume-btn");E&&(E.onclick=async()=>{E.disabled=!0;try{let C=await fetch(`/api/sessions/${encodeURIComponent(p.sessionId)}/resume`,{method:"POST"}),j=await C.json().catch(()=>({}));if(!C.ok||j.ok===!1){alert(`${o("sessions.resumeFailed")}: ${j?.error??C.status}`),E.disabled=!1;return}s.close()}catch(C){alert(`${o("sessions.resumeFailed")}: ${C}`),E.disabled=!1}});let H=s.querySelector("#close-btn");H&&(H.onclick=async()=>{if(confirm(o("sessions.closeConfirm"))){H.disabled=!0;try{await fetch(`/api/sessions/${encodeURIComponent(p.sessionId)}/close`,{method:"POST"})}finally{s.close()}}}),s.showModal()}t.addEventListener("click",p=>{let w=p.target;if(w.classList.contains("row-select")){let C=w.closest("tr[data-id]");if(!C)return;w.checked?h.add(C.dataset.id):h.delete(C.dataset.id),T(L());return}let g=w.closest("td");if(g&&g.querySelector(".row-select"))return;let E=w.closest("tr[data-id]");if(!E)return;let H=_.sessions.get(E.dataset.id);H&&M(H)}),a.addEventListener("change",()=>{let p=L().filter(w=>w.status!=="closed");for(let w of p)a.checked?h.add(w.sessionId):h.delete(w.sessionId);S()}),y.addEventListener("click",()=>{h.clear(),S()}),m.addEventListener("click",async()=>{let p=[...h];if(p.length===0||!confirm(o("sessions.closeBulkConfirm",{count:p.length})))return;m.disabled=!0,y.disabled=!0;let w=m.textContent,g=0,E=0,H=[...p];m.textContent=`0/${p.length}`;async function C(){for(;H.length;){let j=H.shift();try{let U=await fetch(`/api/sessions/${encodeURIComponent(j)}/close`,{method:"POST"}),R=await U.json().catch(()=>({}));(!U.ok||R?.ok===!1)&&(E+=1)}catch{E+=1}finally{g+=1,m.textContent=`${g}/${p.length}`}}}await Promise.all(Array.from({length:Math.min(6,p.length)},()=>C())),m.textContent=w,m.disabled=!1,y.disabled=!1,h.clear(),S(),E>0&&alert(`Failed: ${E}/${p.length}`)}),k.querySelectorAll("th[data-sort]").forEach(p=>{p.addEventListener("click",()=>{let w=p.dataset.sort;u===w?l=l==="asc"?"desc":"asc":(u=w,l=w==="spawnedAt"||w==="lastMessageAt"?"desc":"asc"),S()})}),n.addEventListener("input",S),_.on(S),S()}function Ln(){return`<section class="page">
142
142
  <div class="page-heading">
143
143
  <div>
144
144
  <p class="eyebrow">${o("nav.schedules")}</p>
@@ -163,19 +163,19 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
163
163
  </tr></thead>
164
164
  <tbody id="schedules-tbody"></tbody>
165
165
  </table>
166
- </section>`}function kt(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function $t(e){e.innerHTML=En();let t=e.querySelector("#schedules-tbody"),n=e.querySelector("#sched-filters");function s(){let r=new FormData(n),i=(r.get("q")??"").toLowerCase(),m=r.get("kind"),k=!!r.get("enabled");return[...N.schedules.values()].filter($=>!m||$.parsed?.kind===m).filter($=>!k||$.enabled).filter($=>!i||JSON.stringify($).toLowerCase().includes(i)).sort(($,p)=>{if($.enabled!==p.enabled)return $.enabled?-1:1;let g=$.nextRunAt?Date.parse($.nextRunAt):1/0,l=p.nextRunAt?Date.parse(p.nextRunAt):1/0;return g-l})}function a(){t.innerHTML=s().map(r=>`<tr data-id="${d(r.id)}">
166
+ </section>`}function $t(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function St(e){e.innerHTML=Ln();let t=e.querySelector("#schedules-tbody"),n=e.querySelector("#sched-filters");function s(){let r=new FormData(n),i=(r.get("q")??"").toLowerCase(),m=r.get("kind"),y=!!r.get("enabled");return[..._.schedules.values()].filter(k=>!m||k.parsed?.kind===m).filter(k=>!y||k.enabled).filter(k=>!i||JSON.stringify(k).toLowerCase().includes(i)).sort((k,h)=>{if(k.enabled!==h.enabled)return k.enabled?-1:1;let u=k.nextRunAt?Date.parse(k.nextRunAt):1/0,l=h.nextRunAt?Date.parse(h.nextRunAt):1/0;return u-l})}function a(){t.innerHTML=s().map(r=>`<tr data-id="${d(r.id)}">
167
167
  <td>${d(r.name??r.id)}</td>
168
168
  <td>${d(r.botName??r.larkAppId??"-")}</td>
169
169
  <td><code>${d(r.parsed?.display??"?")}</code></td>
170
- <td>${kt(r.nextRunAt)}</td>
171
- <td>${kt(r.lastRunAt)} ${r.lastStatus==="error"?"\u26A0\uFE0F":""}</td>
170
+ <td>${$t(r.nextRunAt)}</td>
171
+ <td>${$t(r.lastRunAt)} ${r.lastStatus==="error"?"\u26A0\uFE0F":""}</td>
172
172
  <td>${r.repeat?`${r.repeat.completed}/${r.repeat.times??"\u221E"}`:"\u2014"}</td>
173
173
  <td>${r.enabled?"\u2713":"\u2717"}</td>
174
174
  <td class="actions-cell">
175
175
  <button data-op="run" type="button">${o("schedules.runNow")}</button>
176
176
  ${r.enabled?`<button data-op="pause" type="button">${o("schedules.pause")}</button>`:`<button data-op="resume" type="button">${o("schedules.resume")}</button>`}
177
177
  </td>
178
- </tr>`).join("")||`<tr><td colspan="8" class="empty">${o("schedules.empty")}</td></tr>`}t.addEventListener("click",async r=>{let i=r.target.closest("button[data-op]");if(!i)return;let m=i.closest("tr[data-id]");if(!m)return;let k=m.dataset.id,$=i.dataset.op;i.disabled=!0;let p=i.textContent;i.textContent="...";try{let g=await fetch(`/api/schedules/${encodeURIComponent(k)}/${$}`,{method:"POST"}),l=await g.json().catch(()=>({}));(!g.ok||l.ok===!1)&&alert(`Failed: ${g.status} ${l?.error??""}`.trim())}catch(g){alert("Network error: "+g)}finally{i.disabled=!1,i.textContent=p}}),n.addEventListener("input",a),N.on(a),a()}var z={chats:[],bots:[]};function Mn(){return`<section class="page">
178
+ </tr>`).join("")||`<tr><td colspan="8" class="empty">${o("schedules.empty")}</td></tr>`}t.addEventListener("click",async r=>{let i=r.target.closest("button[data-op]");if(!i)return;let m=i.closest("tr[data-id]");if(!m)return;let y=m.dataset.id,k=i.dataset.op;i.disabled=!0;let h=i.textContent;i.textContent="...";try{let u=await fetch(`/api/schedules/${encodeURIComponent(y)}/${k}`,{method:"POST"}),l=await u.json().catch(()=>({}));(!u.ok||l.ok===!1)&&alert(`Failed: ${u.status} ${l?.error??""}`.trim())}catch(u){alert("Network error: "+u)}finally{i.disabled=!1,i.textContent=h}}),n.addEventListener("input",a),_.on(a),a()}var Y={chats:[],bots:[]};function En(){return`<section class="page">
179
179
  <div class="page-heading">
180
180
  <div>
181
181
  <p class="eyebrow">${o("nav.groups")}</p>
@@ -194,12 +194,12 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
194
194
  <tbody id="g-body"></tbody>
195
195
  </table>
196
196
  <dialog id="g-drawer"></dialog>
197
- </section>`}async function fe(){z=await(await fetch("/api/groups")).json()}async function xn(){return(await fetch("/api/groups")).json()}function Cn(e,t){if(t.size===0)return!0;let n=e?.memberBots??[];for(let s of t)if(!n.some(a=>a.larkAppId===s&&a.inChat))return!1;return!0}function St(e,t){return e.filter(n=>!t||!t.has(n.larkAppId)).map(n=>`
197
+ </section>`}async function be(){Y=await(await fetch("/api/groups")).json()}async function Mn(){return(await fetch("/api/groups")).json()}function xn(e,t){if(t.size===0)return!0;let n=e?.memberBots??[];for(let s of t)if(!n.some(a=>a.larkAppId===s&&a.inChat))return!1;return!0}function Tt(e,t){return e.filter(n=>!t||!t.has(n.larkAppId)).map(n=>`
198
198
  <label class="checkbox-row">
199
199
  <input type="checkbox" name="bot" value="${d(n.larkAppId)}">
200
200
  ${d(n.botName??n.larkAppId)} <small>(${d(n.larkAppId)})</small>
201
201
  </label>
202
- `).join("")}async function It(e){e.innerHTML=Mn();let t=e.querySelector("#g-head"),n=e.querySelector("#g-body"),s=e.querySelector("#g-filters"),a=e.querySelector("#g-refresh"),r=e.querySelector("#g-drawer");a.onclick=async()=>{a.disabled=!0;try{await fe(),p()}finally{a.disabled=!1}};let i=e.querySelector("#g-create");i.onclick=()=>m(),await fe();function m(){let l=z.bots;if(l.length===0){alert(o("groups.noBotsOnline"));return}r.innerHTML=`
202
+ `).join("")}async function It(e){e.innerHTML=En();let t=e.querySelector("#g-head"),n=e.querySelector("#g-body"),s=e.querySelector("#g-filters"),a=e.querySelector("#g-refresh"),r=e.querySelector("#g-drawer");a.onclick=async()=>{a.disabled=!0;try{await be(),h()}finally{a.disabled=!1}};let i=e.querySelector("#g-create");i.onclick=()=>m(),await be();function m(){let l=Y.bots;if(l.length===0){alert(o("groups.noBotsOnline"));return}r.innerHTML=`
203
203
  <article>
204
204
  <header><h3>${o("groups.createTitle")}</h3></header>
205
205
  <p>${o("groups.createHelp")}</p>
@@ -215,52 +215,52 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
215
215
  </label>
216
216
  <fieldset>
217
217
  <legend>${o("groups.botPicker")}</legend>
218
- ${St(l)}
218
+ ${Tt(l)}
219
219
  </fieldset>
220
220
  <div class="actions">
221
221
  <button type="submit" class="primary">${o("groups.createSubmit")}</button>
222
222
  <button type="button" id="g-create-cancel">${o("groups.cancel")}</button>
223
223
  </div>
224
224
  </form>
225
- </article>`,r.showModal(),r.querySelector("#g-create-cancel").onclick=()=>r.close(),r.querySelector("#g-createform").onsubmit=async b=>{b.preventDefault();let f=new FormData(b.target),T=(f.get("name")??"").trim(),S=(f.get("bindWorkingDir")??"").trim(),y=f.getAll("bot");if(y.length===0){alert("Pick at least one bot.");return}let C=b.target.querySelector("button[type=submit]");C&&(C.disabled=!0,C.textContent="Creating...");try{let u=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:T||void 0,larkAppIds:y,bindWorkingDir:S||void 0})}),w=await u.json();if(w.ok&&w.chatId){k(w);let h=Array.isArray(w.invalidBotIds)?w.invalidBotIds:[],E=y.filter(A=>!h.includes(A)),M=new Set(E);typeof w.creator=="string"&&w.creator&&M.add(w.creator),I(w.chatId,T||w.chatId,E,w.creator),p(),L(w.chatId,M).catch(()=>{})}else alert(`Failed: ${w.error??u.status}`),r.close()}catch(u){alert("Network error: "+u),r.close()}};function I(b,f,T,S){let y=new Set(T);S&&y.add(S);let C=z.bots.map(w=>({larkAppId:w.larkAppId,botName:w.botName,inChat:y.has(w.larkAppId),oncallChat:null})),u={chatId:b,name:f,ownerId:S??null,memberBots:C};z.chats=[u,...z.chats.filter(w=>w.chatId!==b)]}async function L(b,f){let T=[600,1200,1200,1200,1200,1200];for(let S of T){await new Promise(u=>setTimeout(u,S));let y;try{y=await xn()}catch{continue}let C=(y.chats??[]).find(u=>u.chatId===b);if(C&&Cn(C,f)){z=y,p();return}}}}function k(l){let I=String(l.chatId),L=`https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(I)}`,b=l.invalidBotIds??[],f=l.invalidUserIds??[],T=l.autoInvitedOpenId,S=!!l.autoInviteRejected,y=l.ownerTransferredTo,C=l.transferError,u=l.notifyMessageId,w=l.notifyError,h=Array.isArray(l.oncallBindings)?l.oncallBindings:[],E=h.filter(H=>H?.ok).length,M=h.filter(H=>!H?.ok),A=h.length>0?M.length===0?`<p class="hint-ok">\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1A<code>${d(l.bindResolvedPath??"")}</code>\uFF08${E}/${h.length} bots\uFF09</p>`:`<p class="hint-warn">\u76EE\u5F55\u7ED1\u5B9A\u90E8\u5206\u5931\u8D25\uFF1A\u6210\u529F ${E}/${h.length}\u3002${M.map(H=>`<br><code>${d(H.larkAppId??"?")}</code>: ${d(H.error??"unknown")}`).join("")}</p>`:"",P;if(T){let H=y?"<br><small>\u7FA4\u4E3B\u5DF2\u4ECE\u673A\u5668\u4EBA\u8F6C\u8BA9\u7ED9\u4F60\u3002</small>":C?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08${d(C)}\uFF09\uFF0C\u4F60\u73B0\u5728\u662F\u6210\u5458\u4F46\u7FA4\u4E3B\u4ECD\u662F\u673A\u5668\u4EBA\u3002</small>`:"",q=u?`<br><small>\u673A\u5668\u4EBA\u5DF2\u5728\u7FA4\u91CC @ \u4E86\u4F60\uFF08\u6D88\u606F id <code>${d(u)}</code>\uFF09\uFF0C\u770B\u98DE\u4E66\u901A\u77E5\u5C31\u80FD\u8FDB\u7FA4\u3002</small>`:w?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8 @ \u901A\u77E5\u5931\u8D25\uFF08${d(w)}\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>`:"";P=`<p class="hint-ok">\u5DF2\u81EA\u52A8\u9080\u8BF7\u4F60\uFF08<code>${d(T)}</code>\uFF09\u4F5C\u4E3A\u6210\u5458\u3002${H}${q}</p>`}else S?P='<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>':P='<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 O=[b.length?`<li>\u65E0\u6548 bot id: <code>${b.map(d).join(", ")}</code></li>`:"",f.length?`<li>\u65E0\u6548\u7528\u6237 open_id: <code>${f.map(d).join(", ")}</code></li>`:""].filter(Boolean).join("");r.innerHTML=`
225
+ </article>`,r.showModal(),r.querySelector("#g-create-cancel").onclick=()=>r.close(),r.querySelector("#g-createform").onsubmit=async v=>{v.preventDefault();let f=new FormData(v.target),I=(f.get("name")??"").trim(),T=(f.get("bindWorkingDir")??"").trim(),S=f.getAll("bot");if(S.length===0){alert("Pick at least one bot.");return}let M=v.target.querySelector("button[type=submit]");M&&(M.disabled=!0,M.textContent="Creating...");try{let p=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:I||void 0,larkAppIds:S,bindWorkingDir:T||void 0})}),w=await p.json();if(w.ok&&w.chatId){y(w);let g=Array.isArray(w.invalidBotIds)?w.invalidBotIds:[],E=S.filter(C=>!g.includes(C)),H=new Set(E);typeof w.creator=="string"&&w.creator&&H.add(w.creator),$(w.chatId,I||w.chatId,E,w.creator),h(),L(w.chatId,H).catch(()=>{})}else alert(`Failed: ${w.error??p.status}`),r.close()}catch(p){alert("Network error: "+p),r.close()}};function $(v,f,I,T){let S=new Set(I);T&&S.add(T);let M=Y.bots.map(w=>({larkAppId:w.larkAppId,botName:w.botName,inChat:S.has(w.larkAppId),oncallChat:null})),p={chatId:v,name:f,ownerId:T??null,memberBots:M};Y.chats=[p,...Y.chats.filter(w=>w.chatId!==v)]}async function L(v,f){let I=[600,1200,1200,1200,1200,1200];for(let T of I){await new Promise(p=>setTimeout(p,T));let S;try{S=await Mn()}catch{continue}let M=(S.chats??[]).find(p=>p.chatId===v);if(M&&xn(M,f)){Y=S,h();return}}}}function y(l){let $=String(l.chatId),L=`https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent($)}`,v=l.invalidBotIds??[],f=l.invalidUserIds??[],I=l.autoInvitedOpenId,T=!!l.autoInviteRejected,S=l.ownerTransferredTo,M=l.transferError,p=l.notifyMessageId,w=l.notifyError,g=Array.isArray(l.oncallBindings)?l.oncallBindings:[],E=g.filter(R=>R?.ok).length,H=g.filter(R=>!R?.ok),C=g.length>0?H.length===0?`<p class="hint-ok">\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1A<code>${d(l.bindResolvedPath??"")}</code>\uFF08${E}/${g.length} bots\uFF09</p>`:`<p class="hint-warn">\u76EE\u5F55\u7ED1\u5B9A\u90E8\u5206\u5931\u8D25\uFF1A\u6210\u529F ${E}/${g.length}\u3002${H.map(R=>`<br><code>${d(R.larkAppId??"?")}</code>: ${d(R.error??"unknown")}`).join("")}</p>`:"",j;if(I){let R=S?"<br><small>\u7FA4\u4E3B\u5DF2\u4ECE\u673A\u5668\u4EBA\u8F6C\u8BA9\u7ED9\u4F60\u3002</small>":M?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08${d(M)}\uFF09\uFF0C\u4F60\u73B0\u5728\u662F\u6210\u5458\u4F46\u7FA4\u4E3B\u4ECD\u662F\u673A\u5668\u4EBA\u3002</small>`:"",ae=p?`<br><small>\u673A\u5668\u4EBA\u5DF2\u5728\u7FA4\u91CC @ \u4E86\u4F60\uFF08\u6D88\u606F id <code>${d(p)}</code>\uFF09\uFF0C\u770B\u98DE\u4E66\u901A\u77E5\u5C31\u80FD\u8FDB\u7FA4\u3002</small>`:w?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8 @ \u901A\u77E5\u5931\u8D25\uFF08${d(w)}\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>`:"";j=`<p class="hint-ok">\u5DF2\u81EA\u52A8\u9080\u8BF7\u4F60\uFF08<code>${d(I)}</code>\uFF09\u4F5C\u4E3A\u6210\u5458\u3002${R}${ae}</p>`}else T?j='<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>':j='<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 U=[v.length?`<li>\u65E0\u6548 bot id: <code>${v.map(d).join(", ")}</code></li>`:"",f.length?`<li>\u65E0\u6548\u7528\u6237 open_id: <code>${f.map(d).join(", ")}</code></li>`:""].filter(Boolean).join("");r.innerHTML=`
226
226
  <article>
227
227
  <header><h3>${o("groups.successTitle")}</h3></header>
228
- <p><b>chatId:</b> <code>${d(I)}</code> <button type="button" data-copy="${d(I)}">${o("sessions.copy")}</button></p>
228
+ <p><b>chatId:</b> <code>${d($)}</code> <button type="button" data-copy="${d($)}">${o("sessions.copy")}</button></p>
229
229
  <p><b>\u521B\u5EFA\u8005:</b> <code>${d(l.creator??"?")}</code></p>
230
- ${P}
231
- ${A}
232
- ${O?`<ul>${O}</ul>`:""}
230
+ ${j}
231
+ ${C}
232
+ ${U?`<ul>${U}</ul>`:""}
233
233
  <div class="actions">
234
234
  <a class="btn-link primary" href="${L}" target="_blank" rel="noopener">${o("groups.openGroup")}</a>
235
235
  <button type="button" id="g-create-close">${o("sessions.dismiss")}</button>
236
236
  </div>
237
- </article>`,r.querySelectorAll("[data-copy]").forEach(H=>{H.onclick=()=>{navigator.clipboard.writeText(H.dataset.copy??""),H.textContent=o("sessions.copied"),setTimeout(()=>{H.textContent=o("sessions.copy")},800)}}),r.querySelector("#g-create-close").onclick=()=>r.close()}function $(){t.innerHTML=`<tr>
237
+ </article>`,r.querySelectorAll("[data-copy]").forEach(R=>{R.onclick=()=>{navigator.clipboard.writeText(R.dataset.copy??""),R.textContent=o("sessions.copied"),setTimeout(()=>{R.textContent=o("sessions.copy")},800)}}),r.querySelector("#g-create-close").onclick=()=>r.close()}function k(){t.innerHTML=`<tr>
238
238
  <th>${o("groups.chat")}</th>
239
- ${z.bots.map(l=>`<th>${d(l.botName??l.larkAppId)}</th>`).join("")}
239
+ ${Y.bots.map(l=>`<th>${d(l.botName??l.larkAppId)}</th>`).join("")}
240
240
  <th>${o("groups.actions")}</th>
241
- </tr>`}function p(){$();let l=new FormData(s),I=(l.get("q")??"").toLowerCase(),L=!!l.get("missing"),b=z.chats.filter(f=>!I||(f.name??"").toLowerCase().includes(I)||f.chatId.toLowerCase().includes(I)||(f.ownerId??"").toLowerCase().includes(I)).filter(f=>!L||f.memberBots.some(T=>!T.inChat));if(b.length===0){n.innerHTML=`<tr><td colspan="${z.bots.length+2}" class="empty">${o("groups.empty")}</td></tr>`;return}n.innerHTML=b.map(f=>`<tr data-chat="${d(f.chatId)}">
241
+ </tr>`}function h(){k();let l=new FormData(s),$=(l.get("q")??"").toLowerCase(),L=!!l.get("missing"),v=Y.chats.filter(f=>!$||(f.name??"").toLowerCase().includes($)||f.chatId.toLowerCase().includes($)||(f.ownerId??"").toLowerCase().includes($)).filter(f=>!L||f.memberBots.some(I=>!I.inChat));if(v.length===0){n.innerHTML=`<tr><td colspan="${Y.bots.length+2}" class="empty">${o("groups.empty")}</td></tr>`;return}n.innerHTML=v.map(f=>`<tr data-chat="${d(f.chatId)}">
242
242
  <td>
243
243
  <strong>${d(f.name??f.chatId)}</strong><br>
244
244
  <small><code>${d(f.chatId)}</code></small>
245
245
  </td>
246
- ${z.bots.map(T=>{let S=f.memberBots.find(u=>u.larkAppId===T.larkAppId),y=S?S.error?"!":S.inChat?"\u2713":"\u2717":"?";return`<td class="${S?S.error?"cell-error":S.inChat?"cell-in":"cell-out":"cell-unknown"}" title="${d(S?.error??"")}">${y}</td>`}).join("")}
246
+ ${Y.bots.map(I=>{let T=f.memberBots.find(p=>p.larkAppId===I.larkAppId),S=T?T.error?"!":T.inChat?"\u2713":"\u2717":"?";return`<td class="${T?T.error?"cell-error":T.inChat?"cell-in":"cell-out":"cell-unknown"}" title="${d(T?.error??"")}">${S}</td>`}).join("")}
247
247
  <td>
248
248
  <button class="add-bots" type="button">${o("groups.addBots")}</button>
249
249
  <button class="manage-chat" type="button">${o("groups.manage")}</button>
250
250
  </td>
251
- </tr>`).join("")}p(),n.addEventListener("click",async l=>{let I=l.target.closest("button.add-bots");if(!I)return;let b=I.closest("tr[data-chat]").dataset.chat,f=z.chats.find(y=>y.chatId===b);if(!f)return;let T=new Set(f.memberBots.filter(y=>y.inChat).map(y=>y.larkAppId));if(!z.bots.filter(y=>!T.has(y.larkAppId)).length){alert("All configured bots are already in this chat.");return}r.innerHTML=`
251
+ </tr>`).join("")}h(),n.addEventListener("click",async l=>{let $=l.target.closest("button.add-bots");if(!$)return;let v=$.closest("tr[data-chat]").dataset.chat,f=Y.chats.find(S=>S.chatId===v);if(!f)return;let I=new Set(f.memberBots.filter(S=>S.inChat).map(S=>S.larkAppId));if(!Y.bots.filter(S=>!I.has(S.larkAppId)).length){alert("All configured bots are already in this chat.");return}r.innerHTML=`
252
252
  <article>
253
253
  <header><h3>${o("groups.addBots")} \xB7 ${d(f.name??f.chatId)}</h3></header>
254
254
  <p>${o("groups.createHelp")}</p>
255
255
  <form id="g-addform">
256
- ${St(z.bots,T)}
256
+ ${Tt(Y.bots,I)}
257
257
  <div class="actions">
258
258
  <button type="submit" class="primary">${o("groups.addBots")}</button>
259
259
  <button type="button" id="g-cancel">${o("groups.cancel")}</button>
260
260
  </div>
261
261
  </form>
262
- </article>`,r.showModal(),r.querySelector("#g-cancel").onclick=()=>r.close(),r.querySelector("#g-addform").onsubmit=async y=>{y.preventDefault();let u=new FormData(y.target).getAll("bot");if(u.length===0){alert("Pick at least one bot.");return}try{let h=await(await fetch(`/api/groups/${encodeURIComponent(b)}/add-bots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:u})})).json();if(h.error==="no_proxy_bot")alert("No bot is currently in this chat \u2014 add one manually in Feishu first, then retry.");else if(h.result){let E=h.result.map(M=>`${M.id}: ${M.ok?"OK":`failed (${M.error??"unknown"})`}`).join(`
263
- `);alert(E),await fe(),p()}else alert(`Unexpected response: ${JSON.stringify(h)}`)}catch(w){alert("Network error: "+w)}finally{r.close()}}}),n.addEventListener("click",async l=>{let I=l.target.closest("button.manage-chat");if(!I)return;let b=I.closest("tr[data-chat]").dataset.chat,f=z.chats.find(T=>T.chatId===b);f&&g(f)});function g(l){let I=l.memberBots.filter(b=>b.inChat),L=typeof l.ownerId=="string"?l.ownerId:"";r.innerHTML=`
262
+ </article>`,r.showModal(),r.querySelector("#g-cancel").onclick=()=>r.close(),r.querySelector("#g-addform").onsubmit=async S=>{S.preventDefault();let p=new FormData(S.target).getAll("bot");if(p.length===0){alert("Pick at least one bot.");return}try{let g=await(await fetch(`/api/groups/${encodeURIComponent(v)}/add-bots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:p})})).json();if(g.error==="no_proxy_bot")alert("No bot is currently in this chat \u2014 add one manually in Feishu first, then retry.");else if(g.result){let E=g.result.map(H=>`${H.id}: ${H.ok?"OK":`failed (${H.error??"unknown"})`}`).join(`
263
+ `);alert(E),await be(),h()}else alert(`Unexpected response: ${JSON.stringify(g)}`)}catch(w){alert("Network error: "+w)}finally{r.close()}}}),n.addEventListener("click",async l=>{let $=l.target.closest("button.manage-chat");if(!$)return;let v=$.closest("tr[data-chat]").dataset.chat,f=Y.chats.find(I=>I.chatId===v);f&&u(f)});function u(l){let $=l.memberBots.filter(v=>v.inChat),L=typeof l.ownerId=="string"?l.ownerId:"";r.innerHTML=`
264
264
  <article>
265
265
  <header><h3>${o("groups.manageTitle",{name:l.name??l.chatId})}</h3></header>
266
266
  <p><b>chatId:</b> <code>${d(l.chatId)}</code></p>
@@ -269,16 +269,16 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
269
269
  <fieldset>
270
270
  <legend>${o("groups.oncall")}</legend>
271
271
  <p><small>${o("groups.oncallHelp")}</small></p>
272
- ${I.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':I.map(b=>{let f=!!b.oncallChat,T=b.oncallChat?.workingDir??"";return`
273
- <div class="oncall-row" data-bot="${d(b.larkAppId)}">
272
+ ${$.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':$.map(v=>{let f=!!v.oncallChat,I=v.oncallChat?.workingDir??"";return`
273
+ <div class="oncall-row" data-bot="${d(v.larkAppId)}">
274
274
  <label class="checkbox-row">
275
275
  <input type="checkbox" data-action="toggle" ${f?"checked":""}>
276
- <strong>${d(b.botName??b.larkAppId)}</strong>
277
- <small>(${d(b.larkAppId)})</small>
276
+ <strong>${d(v.botName??v.larkAppId)}</strong>
277
+ <small>(${d(v.larkAppId)})</small>
278
278
  </label>
279
279
  <div class="oncall-row-body">
280
280
  <input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
281
- value="${d(T)}" ${f?"":"disabled"}>
281
+ value="${d(I)}" ${f?"":"disabled"}>
282
282
  <button type="button" data-action="save">${o("groups.save")}</button>
283
283
  <span class="oncall-status" data-status></span>
284
284
  </div>
@@ -288,29 +288,29 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
288
288
 
289
289
  <fieldset>
290
290
  <legend>${o("groups.leaveTitle")}</legend>
291
- ${I.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':I.map(b=>`
291
+ ${$.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':$.map(v=>`
292
292
  <label class="checkbox-row">
293
- <input type="checkbox" name="leave-bot" value="${d(b.larkAppId)}">
294
- ${d(b.botName??b.larkAppId)}
295
- <small>${b.larkAppId===L?"\xB7 \u7FA4\u4E3B":""}</small>
293
+ <input type="checkbox" name="leave-bot" value="${d(v.larkAppId)}">
294
+ ${d(v.botName??v.larkAppId)}
295
+ <small>${v.larkAppId===L?"\xB7 \u7FA4\u4E3B":""}</small>
296
296
  </label>
297
297
  `).join("")}
298
298
  </fieldset>
299
299
 
300
300
  <div class="actions">
301
- <button id="g-leave-btn" type="button" ${I.length===0?"disabled":""}>${o("groups.leaveSelected")}</button>
302
- <button id="g-disband-btn" type="button" class="contrast" ${I.length===0?"disabled":""}>${o("groups.disband")}</button>
301
+ <button id="g-leave-btn" type="button" ${$.length===0?"disabled":""}>${o("groups.leaveSelected")}</button>
302
+ <button id="g-disband-btn" type="button" class="contrast" ${$.length===0?"disabled":""}>${o("groups.disband")}</button>
303
303
  </div>
304
304
  <p class="hint-warn"><small>${o("groups.dangerHint")}</small></p>
305
305
  <form method="dialog"><button>${o("sessions.dismiss")}</button></form>
306
- </article>`,r.showModal(),r.querySelectorAll(".oncall-row").forEach(b=>{let f=b.dataset.bot,T=b.querySelector("input[data-action=toggle]"),S=b.querySelector("input[data-input=workingDir]"),y=b.querySelector("button[data-action=save]"),C=b.querySelector("[data-status]");T.addEventListener("change",()=>{S.disabled=!T.checked,T.checked&&S.focus()}),y.addEventListener("click",async()=>{C.textContent="",C.className="oncall-status";let u=T.checked,w=S.value.trim();if(u&&!w){C.textContent=o("groups.needWorkingDir"),C.classList.add("hint-warn-inline");return}y.disabled=!0;try{let h=`/api/groups/${encodeURIComponent(l.chatId)}/oncall/${encodeURIComponent(f)}`,E=u?await fetch(h,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({workingDir:w})}):await fetch(h,{method:"DELETE"}),M=await E.json().catch(()=>({}));if(E.ok&&M.ok){C.textContent=u?`\u2713 \u5DF2\u7ED1\u5B9A \u2192 ${M.resolvedPath??w}`:"\u2713 \u5DF2\u89E3\u7ED1",C.classList.add("hint-ok");try{await fe(),p()}catch{}}else C.textContent=`\u2717 ${M.error??E.status}`,C.classList.add("hint-warn-inline")}catch(h){C.textContent=`\u2717 ${h?.message??h}`,C.classList.add("hint-warn-inline")}finally{y.disabled=!1}})}),r.querySelector("#g-leave-btn").onclick=async()=>{let b=[...r.querySelectorAll("input[name=leave-bot]:checked")].map(f=>f.value);if(b.length===0){alert("\u81F3\u5C11\u9009\u4E00\u4E2A\u673A\u5668\u4EBA");return}if(confirm(`\u786E\u5B9A\u8BA9 ${b.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 T=await(await fetch(`/api/groups/${encodeURIComponent(l.chatId)}/leave`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:b})})).json(),S=(T.result??[]).map(y=>{if(!y.ok)return`${y.larkAppId}: \u5931\u8D25 (${y.error??"unknown"})`;let C=y.closedSessions??[],u=C.filter(E=>!E.ok).length,w=C.length-u,h=C.length===0?"":u===0?`\uFF08\u5173\u95ED ${w} \u4E2A\u4F1A\u8BDD\uFF09`:`\uFF08\u5173\u95ED ${w} \u4E2A\uFF0C${u} \u4E2A\u5931\u8D25\uFF09`;return`${y.larkAppId}: OK${h}`}).join(`
307
- `);alert(S||`Unexpected: ${JSON.stringify(T)}`),await fe(),p()}catch(f){alert("Network error: "+f)}finally{r.close()}},r.querySelector("#g-disband-btn").onclick=async()=>{if(I.length===0||!confirm(`\u786E\u5B9A\u89E3\u6563\u7FA4\u804A\u300C${l.name??l.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 b=[...I].sort((T,S)=>(S.larkAppId===L?1:0)-(T.larkAppId===L?1:0)),f=[];for(let T of b)try{let S=await fetch(`/api/groups/${encodeURIComponent(l.chatId)}/disband`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppId:T.larkAppId})}),y=await S.json();if(y.ok){let C=y.closedSessions??[],u=C.filter(E=>!E.ok).length,w=C.length-u,h=C.length===0?"":u===0?`
306
+ </article>`,r.showModal(),r.querySelectorAll(".oncall-row").forEach(v=>{let f=v.dataset.bot,I=v.querySelector("input[data-action=toggle]"),T=v.querySelector("input[data-input=workingDir]"),S=v.querySelector("button[data-action=save]"),M=v.querySelector("[data-status]");I.addEventListener("change",()=>{T.disabled=!I.checked,I.checked&&T.focus()}),S.addEventListener("click",async()=>{M.textContent="",M.className="oncall-status";let p=I.checked,w=T.value.trim();if(p&&!w){M.textContent=o("groups.needWorkingDir"),M.classList.add("hint-warn-inline");return}S.disabled=!0;try{let g=`/api/groups/${encodeURIComponent(l.chatId)}/oncall/${encodeURIComponent(f)}`,E=p?await fetch(g,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({workingDir:w})}):await fetch(g,{method:"DELETE"}),H=await E.json().catch(()=>({}));if(E.ok&&H.ok){M.textContent=p?`\u2713 \u5DF2\u7ED1\u5B9A \u2192 ${H.resolvedPath??w}`:"\u2713 \u5DF2\u89E3\u7ED1",M.classList.add("hint-ok");try{await be(),h()}catch{}}else M.textContent=`\u2717 ${H.error??E.status}`,M.classList.add("hint-warn-inline")}catch(g){M.textContent=`\u2717 ${g?.message??g}`,M.classList.add("hint-warn-inline")}finally{S.disabled=!1}})}),r.querySelector("#g-leave-btn").onclick=async()=>{let v=[...r.querySelectorAll("input[name=leave-bot]:checked")].map(f=>f.value);if(v.length===0){alert("\u81F3\u5C11\u9009\u4E00\u4E2A\u673A\u5668\u4EBA");return}if(confirm(`\u786E\u5B9A\u8BA9 ${v.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 I=await(await fetch(`/api/groups/${encodeURIComponent(l.chatId)}/leave`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:v})})).json(),T=(I.result??[]).map(S=>{if(!S.ok)return`${S.larkAppId}: \u5931\u8D25 (${S.error??"unknown"})`;let M=S.closedSessions??[],p=M.filter(E=>!E.ok).length,w=M.length-p,g=M.length===0?"":p===0?`\uFF08\u5173\u95ED ${w} \u4E2A\u4F1A\u8BDD\uFF09`:`\uFF08\u5173\u95ED ${w} \u4E2A\uFF0C${p} \u4E2A\u5931\u8D25\uFF09`;return`${S.larkAppId}: OK${g}`}).join(`
307
+ `);alert(T||`Unexpected: ${JSON.stringify(I)}`),await be(),h()}catch(f){alert("Network error: "+f)}finally{r.close()}},r.querySelector("#g-disband-btn").onclick=async()=>{if($.length===0||!confirm(`\u786E\u5B9A\u89E3\u6563\u7FA4\u804A\u300C${l.name??l.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 v=[...$].sort((I,T)=>(T.larkAppId===L?1:0)-(I.larkAppId===L?1:0)),f=[];for(let I of v)try{let T=await fetch(`/api/groups/${encodeURIComponent(l.chatId)}/disband`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppId:I.larkAppId})}),S=await T.json();if(S.ok){let M=S.closedSessions??[],p=M.filter(E=>!E.ok).length,w=M.length-p,g=M.length===0?"":p===0?`
308
308
  \u5173\u95ED\u4E86 ${w} \u4E2A\u4F1A\u8BDD\u3002`:`
309
- \u5173\u95ED\u4E86 ${w} \u4E2A\u4F1A\u8BDD\uFF0C${u} \u4E2A\u4F1A\u8BDD\u5173\u95ED\u5931\u8D25\u3002`;alert(`\u5DF2\u89E3\u6563\uFF08\u7531 ${T.botName??T.larkAppId} \u6267\u884C\uFF09${h}`),await fe(),p(),r.close();return}f.push(`${T.botName??T.larkAppId}: ${y.error??S.status}`)}catch(S){f.push(`${T.botName??T.larkAppId}: ${S}`)}alert(`\u6240\u6709\u5728\u7FA4\u673A\u5668\u4EBA\u5747\u65E0\u6CD5\u89E3\u6563\uFF1A
309
+ \u5173\u95ED\u4E86 ${w} \u4E2A\u4F1A\u8BDD\uFF0C${p} \u4E2A\u4F1A\u8BDD\u5173\u95ED\u5931\u8D25\u3002`;alert(`\u5DF2\u89E3\u6563\uFF08\u7531 ${I.botName??I.larkAppId} \u6267\u884C\uFF09${g}`),await be(),h(),r.close();return}f.push(`${I.botName??I.larkAppId}: ${S.error??T.status}`)}catch(T){f.push(`${I.botName??I.larkAppId}: ${T}`)}alert(`\u6240\u6709\u5728\u7FA4\u673A\u5668\u4EBA\u5747\u65E0\u6CD5\u89E3\u6563\uFF1A
310
310
  ${f.join(`
311
311
  `)}
312
312
 
313
- \u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",p)}var re={bots:[]},me=null;function Hn(){return`<section class="page">
313
+ \u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",h)}var se={bots:[]},ye=null;function Hn(){return`<section class="page">
314
314
  <div class="page-heading">
315
315
  <div>
316
316
  <p class="eyebrow">${o("nav.botDefaults")}</p>
@@ -323,20 +323,20 @@ ${f.join(`
323
323
  <button type="button" id="bd-refresh">${o("botDefaults.refresh")}</button>
324
324
  </form>
325
325
  <div id="bd-list"></div>
326
- </section>`}async function Tt(){try{let e=await fetch("/api/bots"),t=await e.json().catch(()=>({}));if(!e.ok){me=t?.error?`HTTP ${e.status}: ${t.error}${t.path?` (${t.path})`:""}`:`HTTP ${e.status}`,re={bots:[]};return}if(!t||!Array.isArray(t.bots)){me="unexpected response shape (no `bots` array)",re={bots:[]};return}me=null,re=t}catch(e){me=e?.message??String(e),re={bots:[]}}}function Lt(e){if(!e)return"\u2014";let t=new Date(e);return Number.isNaN(t.getTime())?"\u2014":t.toLocaleString()}async function Et(e){e.innerHTML=Hn();let t=e.querySelector("#bd-list"),n=e.querySelector("#bd-filters"),s=e.querySelector("#bd-refresh");s.onclick=async()=>{s.disabled=!0;try{await Tt(),a()}finally{s.disabled=!1}},await Tt();function a(){let g=(new FormData(n).get("q")??"").toLowerCase(),l=re.bots.filter(I=>!g||(I.botName??"").toLowerCase().includes(g)||(I.larkAppId??"").toLowerCase().includes(g));if(me){t.innerHTML=`<p class="hint-warn">\u65E0\u6CD5\u52A0\u8F7D bot \u5217\u8868\uFF1A${d(me)}<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(l.length===0){t.innerHTML=`<p class="empty">${o("botDefaults.empty")}</p>`;return}t.innerHTML=l.map(r).join(""),$()}function r(p){if(p.error)return`<article class="bd-card" data-appid="${d(p.larkAppId)}">
327
- <header><strong>${d(p.botName??p.larkAppId)}</strong>
328
- <small>${d(p.larkAppId)}</small></header>
329
- <p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${d(p.error)}</p>
330
- </article>`;let g=p.defaultOncall??{enabled:!1,workingDir:"",since:0},l=!!g.enabled;return`<article class="bd-card" data-appid="${d(p.larkAppId)}">
326
+ </section>`}async function Lt(){try{let e=await fetch("/api/bots"),t=await e.json().catch(()=>({}));if(!e.ok){ye=t?.error?`HTTP ${e.status}: ${t.error}${t.path?` (${t.path})`:""}`:`HTTP ${e.status}`,se={bots:[]};return}if(!t||!Array.isArray(t.bots)){ye="unexpected response shape (no `bots` array)",se={bots:[]};return}ye=null,se=t}catch(e){ye=e?.message??String(e),se={bots:[]}}}function Et(e){if(!e)return"\u2014";let t=new Date(e);return Number.isNaN(t.getTime())?"\u2014":t.toLocaleString()}async function Mt(e){e.innerHTML=Hn();let t=e.querySelector("#bd-list"),n=e.querySelector("#bd-filters"),s=e.querySelector("#bd-refresh");s.onclick=async()=>{s.disabled=!0;try{await Lt(),a()}finally{s.disabled=!1}},await Lt();function a(){let l=(new FormData(n).get("q")??"").toLowerCase(),$=se.bots.filter(L=>!l||(L.botName??"").toLowerCase().includes(l)||(L.larkAppId??"").toLowerCase().includes(l));if(ye){t.innerHTML=`<p class="hint-warn">\u65E0\u6CD5\u52A0\u8F7D bot \u5217\u8868\uFF1A${d(ye)}<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($.length===0){t.innerHTML=`<p class="empty">${o("botDefaults.empty")}</p>`;return}t.innerHTML=$.map(r).join(""),h()}function r(u){if(u.error)return`<article class="bd-card" data-appid="${d(u.larkAppId)}">
327
+ <header><strong>${d(u.botName??u.larkAppId)}</strong>
328
+ <small>${d(u.larkAppId)}</small></header>
329
+ <p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${d(u.error)}</p>
330
+ </article>`;let l=u.defaultOncall??{enabled:!1,workingDir:"",since:0},$=!!l.enabled;return`<article class="bd-card" data-appid="${d(u.larkAppId)}">
331
331
  <header>
332
- <strong>${d(p.botName??p.larkAppId)}</strong>
333
- <small>${d(p.larkAppId)}</small>
332
+ <strong>${d(u.botName??u.larkAppId)}</strong>
333
+ <small>${d(u.larkAppId)}</small>
334
334
  </header>
335
335
  <div class="bd-body">
336
336
  <section class="bd-section">
337
337
  <h3 class="bd-section-title">${o("botDefaults.sectionOncall")}</h3>
338
338
  <label class="checkbox-row">
339
- <input type="checkbox" data-action="toggle" ${l?"checked":""}>
339
+ <input type="checkbox" data-action="toggle" ${$?"checked":""}>
340
340
  <strong>${o("botDefaults.defaultOncall")}</strong>
341
341
  <small>${o("botDefaults.defaultOncallHelp")}</small>
342
342
  </label>
@@ -344,32 +344,44 @@ ${f.join(`
344
344
  <label>
345
345
  <span>${o("botDefaults.workingDir")}</span>
346
346
  <input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
347
- value="${d(g.workingDir??"")}" ${l?"":"disabled"}>
347
+ value="${d(l.workingDir??"")}" ${$?"":"disabled"}>
348
348
  </label>
349
349
  </div>
350
350
  <p class="bd-section-note">${o("botDefaults.warning")}</p>
351
351
  <div class="bd-meta">
352
- <small>${o("botDefaults.lastEnabled")}: ${d(Lt(g.since??0))}</small>
353
- <small>${o("botDefaults.autobound",{count:p.autoboundChatCount??0})}</small>
352
+ <small>${o("botDefaults.lastEnabled")}: ${d(Et(l.since??0))}</small>
353
+ <small>${o("botDefaults.autobound",{count:u.autoboundChatCount??0})}</small>
354
354
  </div>
355
355
  <div class="actions">
356
356
  <button type="button" data-action="save">${o("botDefaults.save")}</button>
357
357
  <span class="oncall-status" data-status></span>
358
358
  </div>
359
359
  </section>
360
- ${m(p)}
361
- ${k(p)}
360
+ ${i(u)}
361
+ ${y(u)}
362
+ ${k(u)}
362
363
  </div>
363
- </article>`}function i(p){return p==null?o("botDefaults.brandStateDefault"):p.trim()===""?o("botDefaults.brandStateOff"):o("botDefaults.brandStateCustom")}function m(p){let g=p.brandLabel??null;return`<section class="bd-section">
364
+ </article>`}function i(u){let l=typeof u.teamRole=="string";return`<section class="bd-section">
365
+ <h3 class="bd-section-title">${o("botDefaults.sectionRole")}</h3>
366
+ <p class="bd-section-note">${o("botDefaults.roleHelp")}</p>
367
+ <textarea data-input="teamRole" rows="6"
368
+ placeholder="${d(o("botDefaults.rolePlaceholder"))}"
369
+ style="width:100%;box-sizing:border-box;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px"${l?"":" disabled"}>${l?d(u.teamRole):""}</textarea>
370
+ <div class="actions">
371
+ <button type="button" data-action="save-role"${l?"":" disabled"}>${o("botDefaults.roleSave")}</button>
372
+ <button type="button" data-action="delete-role"${l?"":" disabled"}>${o("botDefaults.roleDelete")}</button>
373
+ <span class="oncall-status" data-role-status></span>
374
+ </div>
375
+ </section>`}function m(u){return u==null?o("botDefaults.brandStateDefault"):u.trim()===""?o("botDefaults.brandStateOff"):o("botDefaults.brandStateCustom")}function y(u){let l=u.brandLabel??null;return`<section class="bd-section">
364
376
  <h3 class="bd-section-title">${o("botDefaults.sectionBrand")}</h3>
365
377
  <div class="bd-row bd-brand">
366
378
  <label>
367
379
  <span>${o("botDefaults.brandLabel")}</span>
368
380
  <input type="text" data-input="brandLabel"
369
381
  placeholder="${d(o("botDefaults.brandLabelPlaceholder"))}"
370
- value="${d(g??"")}">
382
+ value="${d(l??"")}">
371
383
  </label>
372
- <small data-brand-state>${d(i(g))}</small>
384
+ <small data-brand-state>${d(m(l))}</small>
373
385
  <small>${o("botDefaults.brandLabelHelp")}</small>
374
386
  <div class="actions">
375
387
  <button type="button" data-action="save-brand">${o("botDefaults.brandSave")}</button>
@@ -377,28 +389,28 @@ ${f.join(`
377
389
  <span class="oncall-status" data-brand-status></span>
378
390
  </div>
379
391
  </div>
380
- </section>`}function k(p){let g=p.disableStreamingCard===!0,l=p.writableTerminalLinkInCard===!0,I=p.privateCard===!0;return`<section class="bd-section">
392
+ </section>`}function k(u){let l=u.disableStreamingCard===!0,$=u.writableTerminalLinkInCard===!0,L=u.privateCard===!0;return`<section class="bd-section">
381
393
  <h3 class="bd-section-title">${o("botDefaults.sectionCard")}</h3>
382
394
  <label class="checkbox-row">
383
- <input type="checkbox" data-action="toggle-disable-streaming" ${g?"checked":""}>
395
+ <input type="checkbox" data-action="toggle-disable-streaming" ${l?"checked":""}>
384
396
  <strong>${o("botDefaults.disableStreaming")}</strong>
385
397
  <small>${o("botDefaults.disableStreamingHelp")}</small>
386
398
  </label>
387
399
  <label class="checkbox-row">
388
- <input type="checkbox" data-action="toggle-writable-link" ${l?"checked":""} ${g?"disabled":""}>
400
+ <input type="checkbox" data-action="toggle-writable-link" ${$?"checked":""} ${l?"disabled":""}>
389
401
  <strong>${o("botDefaults.writableLink")}</strong>
390
402
  <small>${o("botDefaults.writableLinkHelp")}</small>
391
403
  </label>
392
404
  <label class="checkbox-row">
393
- <input type="checkbox" data-action="toggle-private-card" ${I?"checked":""}>
405
+ <input type="checkbox" data-action="toggle-private-card" ${L?"checked":""}>
394
406
  <strong>${o("botDefaults.privateCard")}</strong>
395
407
  <small>${o("botDefaults.privateCardHelp")}</small>
396
408
  </label>
397
409
  <div class="actions">
398
- <small data-card-pref-moot class="hint-warn-inline" ${g?"":"hidden"}>${o("botDefaults.writableLinkMoot")}</small>
410
+ <small data-card-pref-moot class="hint-warn-inline" ${l?"":"hidden"}>${o("botDefaults.writableLinkMoot")}</small>
399
411
  <span class="oncall-status" data-card-pref-status></span>
400
412
  </div>
401
- </section>`}function $(){t.querySelectorAll(".bd-card").forEach(p=>{let g=p.dataset.appid,l=p.querySelector("input[data-action=toggle]"),I=p.querySelector("input[data-input=workingDir]"),L=p.querySelector("button[data-action=save]"),b=p.querySelector("[data-status]");if(!l||!I||!L||!b)return;l.addEventListener("change",()=>{I.disabled=!l.checked,l.checked&&I.focus()}),L.addEventListener("click",async()=>{b.textContent="",b.className="oncall-status";let O=l.checked,H=I.value.trim();if(O&&!H){b.textContent=o("botDefaults.required"),b.classList.add("hint-warn-inline");return}L.disabled=!0;try{let q=await fetch(`/api/bots/${encodeURIComponent(g)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:O,workingDir:H})}),j=await q.json().catch(()=>({}));if(q.ok&&j.ok){let F=j.resolvedPath?` \u2192 ${j.resolvedPath}`:"";b.textContent=O?`\u2713 \u5DF2\u5F00\u542F${F}\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",b.classList.add("hint-ok");let W=re.bots.find(te=>te.larkAppId===g);W&&j.defaultOncall&&(W.defaultOncall=j.defaultOncall);let ee=p.querySelector(".bd-meta small:first-child");ee&&j.defaultOncall?.since!=null&&(ee.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${Lt(j.defaultOncall.since)}`)}else b.textContent=`\u2717 ${j.error??q.status}`,b.classList.add("hint-warn-inline")}catch(q){b.textContent=`\u2717 ${q?.message??q}`,b.classList.add("hint-warn-inline")}finally{L.disabled=!1}});let f=p.querySelector("input[data-input=brandLabel]"),T=p.querySelector("button[data-action=save-brand]"),S=p.querySelector("button[data-action=reset-brand]"),y=p.querySelector("[data-brand-status]"),C=p.querySelector("[data-brand-state]");async function u(O,H){if(y){y.textContent="",y.className="oncall-status",H.disabled=!0;try{let q=await fetch(`/api/bots/${encodeURIComponent(g)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:O})}),j=await q.json().catch(()=>({}));if(q.ok&&j.ok){let F=j.brandLabel??null;y.textContent="\u2713",y.classList.add("hint-ok"),f&&(f.value=F??""),C&&(C.textContent=i(F));let W=re.bots.find(ee=>ee.larkAppId===g);W&&(W.brandLabel=F)}else y.textContent=`\u2717 ${j.error??q.status}`,y.classList.add("hint-warn-inline")}catch(q){y.textContent=`\u2717 ${q?.message??q}`,y.classList.add("hint-warn-inline")}finally{H.disabled=!1}}}f&&T&&T.addEventListener("click",()=>u(f.value,T)),S&&S.addEventListener("click",()=>u(null,S));let w=p.querySelector("input[data-action=toggle-disable-streaming]"),h=p.querySelector("input[data-action=toggle-writable-link]"),E=p.querySelector("input[data-action=toggle-private-card]"),M=p.querySelector("[data-card-pref-status]"),A=p.querySelector("[data-card-pref-moot]");async function P(O,H){if(M){M.textContent="",M.className="oncall-status",H.disabled=!0;try{let q=await fetch(`/api/bots/${encodeURIComponent(g)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(O)}),j=await q.json().catch(()=>({}));if(q.ok&&j.ok){M.textContent=`\u2713 ${o("botDefaults.cardPrefSaved")}`,M.classList.add("hint-ok");let F=re.bots.find(W=>W.larkAppId===g);F&&(F.disableStreamingCard=j.disableStreamingCard,F.writableTerminalLinkInCard=j.writableTerminalLinkInCard,F.privateCard=j.privateCard)}else M.textContent=`\u2717 ${j.error??q.status}`,M.classList.add("hint-warn-inline")}catch(q){M.textContent=`\u2717 ${q?.message??q}`,M.classList.add("hint-warn-inline")}finally{H===h?H.disabled=!!w?.checked:H.disabled=!1}}}w&&w.addEventListener("change",()=>{let O=w.checked;h&&(h.disabled=O),A&&(A.hidden=!O),P({disableStreamingCard:O},w)}),h&&h.addEventListener("change",()=>{P({writableTerminalLinkInCard:h.checked},h)}),E&&E.addEventListener("change",()=>{P({privateCard:E.checked},E)})})}a(),n.addEventListener("input",a)}var Ve=4096,Ce=[],Q=null,X=null,J="",we=new Set;function An(){return`<section class="page roles-page">
413
+ </section>`}function h(){t.querySelectorAll(".bd-card").forEach(u=>{let l=u.dataset.appid,$=u.querySelector("input[data-action=toggle]"),L=u.querySelector("input[data-input=workingDir]"),v=u.querySelector("button[data-action=save]"),f=u.querySelector("[data-status]");if(!$||!L||!v||!f)return;$.addEventListener("change",()=>{L.disabled=!$.checked,$.checked&&L.focus()}),v.addEventListener("click",async()=>{f.textContent="",f.className="oncall-status";let J=$.checked,B=L.value.trim();if(J&&!B){f.textContent=o("botDefaults.required"),f.classList.add("hint-warn-inline");return}v.disabled=!0;try{let q=await fetch(`/api/bots/${encodeURIComponent(l)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:J,workingDir:B})}),N=await q.json().catch(()=>({}));if(q.ok&&N.ok){let P=N.resolvedPath?` \u2192 ${N.resolvedPath}`:"";f.textContent=J?`\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",f.classList.add("hint-ok");let z=se.bots.find(V=>V.larkAppId===l);z&&N.defaultOncall&&(z.defaultOncall=N.defaultOncall);let F=u.querySelector(".bd-meta small:first-child");F&&N.defaultOncall?.since!=null&&(F.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${Et(N.defaultOncall.since)}`)}else f.textContent=`\u2717 ${N.error??q.status}`,f.classList.add("hint-warn-inline")}catch(q){f.textContent=`\u2717 ${q?.message??q}`,f.classList.add("hint-warn-inline")}finally{v.disabled=!1}});let I=u.querySelector("input[data-input=brandLabel]"),T=u.querySelector("button[data-action=save-brand]"),S=u.querySelector("button[data-action=reset-brand]"),M=u.querySelector("[data-brand-status]"),p=u.querySelector("[data-brand-state]");async function w(J,B){if(M){M.textContent="",M.className="oncall-status",B.disabled=!0;try{let q=await fetch(`/api/bots/${encodeURIComponent(l)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:J})}),N=await q.json().catch(()=>({}));if(q.ok&&N.ok){let P=N.brandLabel??null;M.textContent="\u2713",M.classList.add("hint-ok"),I&&(I.value=P??""),p&&(p.textContent=m(P));let z=se.bots.find(F=>F.larkAppId===l);z&&(z.brandLabel=P)}else M.textContent=`\u2717 ${N.error??q.status}`,M.classList.add("hint-warn-inline")}catch(q){M.textContent=`\u2717 ${q?.message??q}`,M.classList.add("hint-warn-inline")}finally{B.disabled=!1}}}I&&T&&T.addEventListener("click",()=>w(I.value,T)),S&&S.addEventListener("click",()=>w(null,S));let g=u.querySelector("input[data-action=toggle-disable-streaming]"),E=u.querySelector("input[data-action=toggle-writable-link]"),H=u.querySelector("input[data-action=toggle-private-card]"),C=u.querySelector("[data-card-pref-status]"),j=u.querySelector("[data-card-pref-moot]");async function U(J,B){if(C){C.textContent="",C.className="oncall-status",B.disabled=!0;try{let q=await fetch(`/api/bots/${encodeURIComponent(l)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(J)}),N=await q.json().catch(()=>({}));if(q.ok&&N.ok){C.textContent=`\u2713 ${o("botDefaults.cardPrefSaved")}`,C.classList.add("hint-ok");let P=se.bots.find(z=>z.larkAppId===l);P&&(P.disableStreamingCard=N.disableStreamingCard,P.writableTerminalLinkInCard=N.writableTerminalLinkInCard,P.privateCard=N.privateCard)}else C.textContent=`\u2717 ${N.error??q.status}`,C.classList.add("hint-warn-inline")}catch(q){C.textContent=`\u2717 ${q?.message??q}`,C.classList.add("hint-warn-inline")}finally{B===E?B.disabled=!!g?.checked:B.disabled=!1}}}g&&g.addEventListener("change",()=>{let J=g.checked;E&&(E.disabled=J),j&&(j.hidden=!J),U({disableStreamingCard:J},g)}),E&&E.addEventListener("change",()=>{U({writableTerminalLinkInCard:E.checked},E)}),H&&H.addEventListener("change",()=>{U({privateCard:H.checked},H)});let R=u.querySelector("textarea[data-input=teamRole]"),ae=u.querySelector("button[data-action=save-role]"),ie=u.querySelector("button[data-action=delete-role]"),W=u.querySelector("[data-role-status]");if(R&&ae&&ie&&W){let q=function(P){let z=t.querySelector(`.bd-card[data-appid="${CSS.escape(l)}"]`);if(!z)return;let F=z.querySelector("textarea[data-input=teamRole]"),V=z.querySelector("button[data-action=save-role]"),le=z.querySelector("button[data-action=delete-role]");F&&(F.value=P,F.disabled=!1),V&&(V.disabled=!1),le&&(le.disabled=!1)};var ke=q;let J=`/api/team/local-bots/${encodeURIComponent(l)}/role`,B=se.bots.find(P=>P.larkAppId===l);B&&typeof B.teamRole!="string"&&!B.teamRoleLoading&&(B.teamRoleLoading=!0,(async()=>{try{let P=await fetch(J),z=await P.json().catch(()=>({}));P.ok&&z.ok?(B.teamRole=z.role??"",q(B.teamRole)):(W.textContent=`\u2717 ${o("botDefaults.roleLoadErr")}: ${z.error??P.status}`,W.classList.add("hint-warn-inline"))}catch(P){W.textContent=`\u2717 ${o("botDefaults.roleLoadErr")}: ${P?.message??P}`,W.classList.add("hint-warn-inline")}finally{B.teamRoleLoading=!1}})());async function N(P,z,F){if(W&&!(!B||typeof B.teamRole!="string")){W.textContent="",W.className="oncall-status",ae.disabled=!0,ie.disabled=!0;try{let V=await fetch(J,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({role:P})}),le=await V.json().catch(()=>({}));V.ok&&le.ok?(B&&(B.teamRole=P.trim()),W.textContent=`\u2713 ${F?o("botDefaults.roleDeleted"):o("botDefaults.roleSaved")}`,W.classList.add("hint-ok")):(W.textContent=`\u2717 ${le.error??V.status}`,W.classList.add("hint-warn-inline"))}catch(V){W.textContent=`\u2717 ${V?.message??V}`,W.classList.add("hint-warn-inline")}finally{ae.disabled=!1,ie.disabled=!1}}}ae.addEventListener("click",()=>N(R.value,ae,!1)),ie.addEventListener("click",()=>{R.value="",N("",ie,!0)})}})}a(),n.addEventListener("input",a)}var et=4096,Be=[],te=null,ne=null,Q="",ve=new Set;function Cn(){return`<section class="page roles-page">
402
414
  <div class="page-heading">
403
415
  <div>
404
416
  <p class="eyebrow">${o("nav.roles")}</p>
@@ -437,35 +449,35 @@ ${f.join(`
437
449
  </div>
438
450
  </div>
439
451
  </div>
440
- </section>`}async function xe(){Ce=((await(await fetch("/api/groups")).json()).chats??[]).map(n=>({chatId:n.chatId,name:n.name??n.chatId,memberBots:(n.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 xt(e,t){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)).json()}async function Rn(e,t,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({content:n})})).ok}async function Dn(e,t){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{method:"DELETE"})).ok}function Ct(e){return e.memberBots.filter(t=>t.inChat&&t.hasRole).length}function Bn(e){return e.memberBots.filter(t=>t.inChat).length}function de(e=""){let t=document.getElementById("roles-tree");if(!t)return;let n=e.toLowerCase(),s=Ce.filter(a=>{if(!n)return!0;let r=a.chatId.toLowerCase().includes(n)||(a.name??"").toLowerCase().includes(n),i=a.memberBots.some(m=>m.larkAppId.toLowerCase().includes(n)||(m.botName??"").toLowerCase().includes(n));return r||i});if(s.length===0){t.innerHTML=`<div class="roles-empty">${o("roles.noChats")}</div>`;return}t.innerHTML=s.map(a=>{let r=we.has(a.chatId),i=a.memberBots.filter(g=>g.inChat),m=r?"\u25BE":"\u25B8",k=Ct(a),$=Bn(a),p=r?i.map(g=>`
441
- <div class="roles-bot-row ${Q===a.chatId&&X===g.larkAppId?"selected":""}"
452
+ </section>`}async function De(){Be=((await(await fetch("/api/groups")).json()).chats??[]).map(n=>({chatId:n.chatId,name:n.name??n.chatId,memberBots:(n.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 Ht(e,t){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)).json()}async function An(e,t,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({content:n})})).ok}async function Rn(e,t){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{method:"DELETE"})).ok}function Ct(e){return e.memberBots.filter(t=>t.inChat&&t.hasRole).length}function Dn(e){return e.memberBots.filter(t=>t.inChat).length}function me(e=""){let t=document.getElementById("roles-tree");if(!t)return;let n=e.toLowerCase(),s=Be.filter(a=>{if(!n)return!0;let r=a.chatId.toLowerCase().includes(n)||(a.name??"").toLowerCase().includes(n),i=a.memberBots.some(m=>m.larkAppId.toLowerCase().includes(n)||(m.botName??"").toLowerCase().includes(n));return r||i});if(s.length===0){t.innerHTML=`<div class="roles-empty">${o("roles.noChats")}</div>`;return}t.innerHTML=s.map(a=>{let r=ve.has(a.chatId),i=a.memberBots.filter(u=>u.inChat),m=r?"\u25BE":"\u25B8",y=Ct(a),k=Dn(a),h=r?i.map(u=>`
453
+ <div class="roles-bot-row ${te===a.chatId&&ne===u.larkAppId?"selected":""}"
442
454
  data-group-id="${d(a.chatId)}"
443
- data-bot-id="${d(g.larkAppId)}">
455
+ data-bot-id="${d(u.larkAppId)}">
444
456
  <span class="roles-bot-indent"></span>
445
457
  <span class="roles-bot-icon">\u{1F916}</span>
446
458
  <div class="roles-bot-info">
447
- <div class="roles-bot-name">${d(g.botName)}</div>
448
- <div class="roles-bot-id">${d(g.larkAppId)}</div>
459
+ <div class="roles-bot-name">${d(u.botName)}</div>
460
+ <div class="roles-bot-id">${d(u.larkAppId)}</div>
449
461
  </div>
450
- <span class="roles-badge ${g.hasRole?"has-role":"no-role"}">
451
- ${g.hasRole?o("roles.configured"):o("roles.unconfigured")}
462
+ <span class="roles-badge ${u.hasRole?"has-role":"no-role"}">
463
+ ${u.hasRole?o("roles.configured"):o("roles.unconfigured")}
452
464
  </span>
453
465
  </div>`).join(""):"";return`
454
466
  <div class="roles-group-section">
455
- <div class="roles-group-row ${r?"expanded":""} ${Q===a.chatId&&!X?"selected":""}"
467
+ <div class="roles-group-row ${r?"expanded":""} ${te===a.chatId&&!ne?"selected":""}"
456
468
  data-group-id="${d(a.chatId)}">
457
469
  <span class="roles-group-arrow">${m}</span>
458
470
  <span class="roles-group-icon">\u{1F4C1}</span>
459
471
  <div class="roles-group-info">
460
472
  <div class="roles-group-name">${d(a.name??a.chatId)}</div>
461
473
  <div class="roles-group-meta">
462
- ${k}/${$} ${o("roles.botsWithRoles")}
474
+ ${y}/${k} ${o("roles.botsWithRoles")}
463
475
  </div>
464
476
  </div>
465
477
  <span class="roles-group-chevron"></span>
466
478
  </div>
467
- <div class="roles-bot-list">${p}</div>
468
- </div>`}).join(""),t.querySelectorAll(".roles-group-row").forEach(a=>{a.addEventListener("click",()=>{let r=a.dataset.groupId;r&&(we.has(r)?we.delete(r):we.add(r),de(document.getElementById("roles-search")?.value??""))})}),t.querySelectorAll(".roles-bot-row").forEach(a=>{a.addEventListener("click",r=>{r.stopPropagation();let i=a.dataset.groupId,m=a.dataset.botId;i&&m&&On(i,m)})})}async function On(e,t){Q=e,X=t;let n=await xt(t,e),s=document.getElementById("roles-editor-empty"),a=document.getElementById("roles-editor-form"),r=document.getElementById("roles-editor-textarea"),i=document.getElementById("roles-editor-group-name"),m=document.getElementById("roles-editor-bot-name"),k=document.getElementById("roles-editor-chat-id");s&&(s.style.display="none"),a&&(a.style.display="");let $=Ce.find(l=>l.chatId===e),p=$?.memberBots.find(l=>l.larkAppId===t);i&&(i.textContent=$?.name??e),m&&(m.textContent=p?.botName??t),k&&(k.textContent=`${e} \xB7 ${t}`),J=n.content??"",r&&(r.value=J,r.focus()),Ye(),Qe(),de(document.getElementById("roles-search")?.value??"");let g=document.getElementById("roles-delete");g&&(g.style.display=n.hasRole?"":"none")}function Ye(){let e=document.getElementById("roles-editor-bytecount");if(!e)return;let t=new TextEncoder().encode(J).length;e.textContent=`${t} / ${Ve} bytes`,e.className=`roles-bytecount ${t>3800?"warn":""} ${t>Ve?"over":""}`,qn(t)}function qn(e){let t=document.getElementById("roles-save");if(!t)return;let n=e??new TextEncoder().encode(J).length;t.disabled=n>Ve||J.trim().length===0}function Qe(){let e=document.getElementById("roles-preview");e&&(J.trim()?e.innerHTML=`<strong>${o("roles.preview")}</strong><pre>${d(J)}</pre>`:e.innerHTML=`<small>${o("roles.previewEmpty")}</small>`)}function Mt(){Q=null,X=null,J="";let e=document.getElementById("roles-editor-empty"),t=document.getElementById("roles-editor-form"),n=document.getElementById("roles-editor-textarea"),s=document.getElementById("roles-delete");e&&(e.style.display=""),t&&(t.style.display="none"),n&&(n.value=""),s&&(s.style.display="none")}async function Ht(e){e.innerHTML=An(),we.clear(),Mt(),await xe();for(let t of Ce)Ct(t)>0&&we.add(t.chatId);de(),document.getElementById("roles-search")?.addEventListener("input",t=>{de(t.target.value)}),document.getElementById("roles-refresh")?.addEventListener("click",async()=>{if(await xe(),de(document.getElementById("roles-search")?.value??""),Q&&X){let t=await xt(X,Q),n=document.getElementById("roles-editor-textarea");n&&(n.value=t.content??""),J=t.content??"",Ye(),Qe();let s=document.getElementById("roles-delete");s&&(s.style.display=t.hasRole?"":"none")}}),document.getElementById("roles-save")?.addEventListener("click",async function(){if(!(!Q||!X)){this.disabled=!0,this.textContent="...";try{if(await Rn(X,Q,J)){await xe(),de(document.getElementById("roles-search")?.value??"");let n=document.getElementById("roles-delete");n&&(n.style.display="");let s=document.createElement("span");s.className="roles-saved-flash",s.textContent=` ${o("roles.saved")}`,document.querySelector(".roles-editor-footer")?.appendChild(s),setTimeout(()=>s.remove(),2e3)}else{let n=document.createElement("span");n.className="roles-saved-flash roles-save-error",n.textContent=J.trim().length===0?` ${o("roles.emptyError")}`:` ${o("roles.saveFailed")}`,document.querySelector(".roles-editor-footer")?.appendChild(n),setTimeout(()=>n.remove(),3e3)}}finally{this.disabled=!1,this.textContent=o("roles.save")}}}),document.getElementById("roles-delete")?.addEventListener("click",async function(){if(!(!Q||!X)&&confirm(o("roles.confirmDelete"))){this.disabled=!0,this.textContent="...";try{await Dn(X,Q)&&(await xe(),Mt(),de(document.getElementById("roles-search")?.value??""))}finally{this.disabled=!1,this.textContent=o("roles.delete")}}}),document.getElementById("roles-editor-textarea")?.addEventListener("input",t=>{J=t.target.value,Ye(),Qe()})}async function Re(e){let t=await fetch(e);return{status:t.status,body:await t.json().catch(()=>({}))}}async function De(e,t,n){let s=await fetch(t,{method:e,headers:{"content-type":"application/json"},body:n?JSON.stringify(n):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}var ue=(e,t)=>De("POST",e,t),At=(e,t)=>De("PUT",e,t),Xe=[],Rt=[],Dt="",He="",Ze=new Map,Ae=new Map,ye=new Set,ve=new Set;function B(e){return document.getElementById(e)}function Be(){return[...Xe,...Rt]}function ce(e){let t=Ze.get(e);return t||(t=new Set,Ze.set(e,t)),t}function Pn(e){return Be().find(t=>t.key===e)}function Bt(e){let t=(n,s,a)=>`<a href="${n}" style="padding:6px 14px;border-radius:8px;text-decoration:none;font-size:14px;${a?"background:var(--accent,#3370ff);color:#fff":"color:var(--text,#1f2329)"}">${s}</a>`;return`<div style="display:flex;gap:8px;margin-bottom:14px">${t("#/team","\u6211\u7684\u56E2\u961F",e==="home")}${t("#/team/manage","\u56E2\u961F\u7BA1\u7406",e==="manage")}</div>`}function Nn(){return`<section class="page">
479
+ <div class="roles-bot-list">${h}</div>
480
+ </div>`}).join(""),t.querySelectorAll(".roles-group-row").forEach(a=>{a.addEventListener("click",()=>{let r=a.dataset.groupId;r&&(ve.has(r)?ve.delete(r):ve.add(r),me(document.getElementById("roles-search")?.value??""))})}),t.querySelectorAll(".roles-bot-row").forEach(a=>{a.addEventListener("click",r=>{r.stopPropagation();let i=a.dataset.groupId,m=a.dataset.botId;i&&m&&Bn(i,m)})})}async function Bn(e,t){te=e,ne=t;let n=await Ht(t,e),s=document.getElementById("roles-editor-empty"),a=document.getElementById("roles-editor-form"),r=document.getElementById("roles-editor-textarea"),i=document.getElementById("roles-editor-group-name"),m=document.getElementById("roles-editor-bot-name"),y=document.getElementById("roles-editor-chat-id");s&&(s.style.display="none"),a&&(a.style.display="");let k=Be.find(l=>l.chatId===e),h=k?.memberBots.find(l=>l.larkAppId===t);i&&(i.textContent=k?.name??e),m&&(m.textContent=h?.botName??t),y&&(y.textContent=`${e} \xB7 ${t}`),Q=n.content??"",r&&(r.value=Q,r.focus()),tt(),nt(),me(document.getElementById("roles-search")?.value??"");let u=document.getElementById("roles-delete");u&&(u.style.display=n.hasRole?"":"none")}function tt(){let e=document.getElementById("roles-editor-bytecount");if(!e)return;let t=new TextEncoder().encode(Q).length;e.textContent=`${t} / ${et} bytes`,e.className=`roles-bytecount ${t>3800?"warn":""} ${t>et?"over":""}`,qn(t)}function qn(e){let t=document.getElementById("roles-save");if(!t)return;let n=e??new TextEncoder().encode(Q).length;t.disabled=n>et||Q.trim().length===0}function nt(){let e=document.getElementById("roles-preview");e&&(Q.trim()?e.innerHTML=`<strong>${o("roles.preview")}</strong><pre>${d(Q)}</pre>`:e.innerHTML=`<small>${o("roles.previewEmpty")}</small>`)}function xt(){te=null,ne=null,Q="";let e=document.getElementById("roles-editor-empty"),t=document.getElementById("roles-editor-form"),n=document.getElementById("roles-editor-textarea"),s=document.getElementById("roles-delete");e&&(e.style.display=""),t&&(t.style.display="none"),n&&(n.value=""),s&&(s.style.display="none")}async function At(e){e.innerHTML=Cn(),ve.clear(),xt(),await De();for(let t of Be)Ct(t)>0&&ve.add(t.chatId);me(),document.getElementById("roles-search")?.addEventListener("input",t=>{me(t.target.value)}),document.getElementById("roles-refresh")?.addEventListener("click",async()=>{if(await De(),me(document.getElementById("roles-search")?.value??""),te&&ne){let t=await Ht(ne,te),n=document.getElementById("roles-editor-textarea");n&&(n.value=t.content??""),Q=t.content??"",tt(),nt();let s=document.getElementById("roles-delete");s&&(s.style.display=t.hasRole?"":"none")}}),document.getElementById("roles-save")?.addEventListener("click",async function(){if(!(!te||!ne)){this.disabled=!0,this.textContent="...";try{if(await An(ne,te,Q)){await De(),me(document.getElementById("roles-search")?.value??"");let n=document.getElementById("roles-delete");n&&(n.style.display="");let s=document.createElement("span");s.className="roles-saved-flash",s.textContent=` ${o("roles.saved")}`,document.querySelector(".roles-editor-footer")?.appendChild(s),setTimeout(()=>s.remove(),2e3)}else{let n=document.createElement("span");n.className="roles-saved-flash roles-save-error",n.textContent=Q.trim().length===0?` ${o("roles.emptyError")}`:` ${o("roles.saveFailed")}`,document.querySelector(".roles-editor-footer")?.appendChild(n),setTimeout(()=>n.remove(),3e3)}}finally{this.disabled=!1,this.textContent=o("roles.save")}}}),document.getElementById("roles-delete")?.addEventListener("click",async function(){if(!(!te||!ne)&&confirm(o("roles.confirmDelete"))){this.disabled=!0,this.textContent="...";try{await Rn(ne,te)&&(await De(),xt(),me(document.getElementById("roles-search")?.value??""))}finally{this.disabled=!1,this.textContent=o("roles.delete")}}}),document.getElementById("roles-editor-textarea")?.addEventListener("input",t=>{Q=t.target.value,tt(),nt()})}async function Pe(e){let t=await fetch(e);return{status:t.status,body:await t.json().catch(()=>({}))}}async function Ne(e,t,n){let s=await fetch(t,{method:e,headers:{"content-type":"application/json"},body:n?JSON.stringify(n):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}var ge=(e,t)=>Ne("POST",e,t),On=(e,t)=>Ne("PUT",e,t),ot=[],Rt=[],Dt="",qe="",at=new Map,Oe=new Map,Se=new Set,Te=new Set;function O(e){return document.getElementById(e)}function je(){return[...ot,...Rt]}function we(e){let t=at.get(e);return t||(t=new Set,at.set(e,t)),t}function Pn(e){return je().find(t=>t.key===e)}function Bt(e){let t=(n,s,a)=>`<a href="${n}" style="padding:6px 14px;border-radius:8px;text-decoration:none;font-size:14px;${a?"background:var(--accent,#3370ff);color:#fff":"color:var(--text,#1f2329)"}">${s}</a>`;return`<div style="display:flex;gap:8px;margin-bottom:14px">${t("#/team","\u6211\u7684\u56E2\u961F",e==="home")}${t("#/team/manage","\u56E2\u961F\u7BA1\u7406",e==="manage")}</div>`}function Nn(){return`<section class="page">
469
481
  <div class="page-heading"><div>
470
482
  <p class="eyebrow">\u56E2\u961F</p><h1>\u56E2\u961F\u534F\u4F5C\uFF08\u8DE8\u90E8\u7F72\uFF09</h1>
471
483
  <p>\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</p>
@@ -492,14 +504,14 @@ ${Bt("home")}
492
504
  <div id="tf-modal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);align-items:center;justify-content:center;z-index:50">
493
505
  <div style="background:var(--card,#fff);color:var(--text,#1f2329);border-radius:10px;padding:18px 20px;width:min(560px,92vw)">
494
506
  <h2 id="tf-modal-title" style="margin-top:0">\u56E2\u961F\u89D2\u8272</h2>
495
- <p class="muted" style="font-size:13px">\u56E2\u961F\u7EA7\u89D2\u8272\uFF08\u8BE5\u673A\u5668\u4EBA\u8DE8\u7FA4\u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF09\u3002\u7559\u7A7A\u4FDD\u5B58\u5373\u5220\u9664\u3002\u4EC5\u672C\u90E8\u7F72\u7684\u673A\u5668\u4EBA\u53EF\u7F16\u8F91\u3002</p>
496
- <textarea id="tf-modal-text" style="width:100%;min-height:200px;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px;box-sizing:border-box"></textarea>
507
+ <p class="muted" style="font-size:13px">\u56E2\u961F\u7EA7\u89D2\u8272\uFF08\u8BE5\u673A\u5668\u4EBA\u8DE8\u7FA4\u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF09\uFF0C\u6B64\u5904\u53EA\u8BFB\u3002\u5982\u9700\u4FEE\u6539\uFF0C\u8BF7\u5230\u300CBot \u914D\u7F6E\u300D\u9875\u3002</p>
508
+ <textarea id="tf-modal-text" readonly style="width:100%;min-height:200px;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px;box-sizing:border-box"></textarea>
497
509
  <div style="display:flex;justify-content:flex-end;gap:8px;margin-top:12px">
498
- <button id="tf-modal-cancel">\u53D6\u6D88</button><button id="tf-modal-save" class="primary">\u4FDD\u5B58</button>
510
+ <button id="tf-modal-cancel">\u5173\u95ED</button>
499
511
  </div>
500
512
  </div>
501
513
  </div>
502
- </section>`}function jn(e){let t=(B("tf-search").value||"").trim().toLowerCase();if(t&&!((e.name||"")+" "+(e.cliId||"")+" "+(e.capability||"")).toLowerCase().includes(t))return!1;let n=B("tf-cli").value;return!(n&&e.cliId!==n||B("tf-fcap").checked&&!e.capability||B("tf-frole").checked&&!e.hasTeamRole)}function Un(e,t){let n=[...e.deployments].sort((a,r)=>a.local===r.local?0:a.local?-1:1),s="";for(let a of n){let r=t.filter(l=>l.deployment.id===a.id);if(!r.length)continue;let i=a.id===Dt,m=i?"\u672C\u90E8\u7F72":a.stale?"\u8FDC\u7AEF\xB7\u79BB\u7EBF\uFF1F":"\u8FDC\u7AEF",k=e.kind==="local"&&!i?` <button class="tf-rmmember ghost" data-team="${d(e.teamId)}" data-dep="${d(a.id)}" data-name="${d(a.name)}" style="font-size:12px">\u79FB\u9664</button>`:"",$=`${e.key}::${a.id}`,p=ve.has($),g=r.filter(l=>ce(e.key).has(l.larkAppId)).length;if(s+=`<div class="tf-dep-h" data-dk="${d($)}" style="cursor:pointer;margin:10px 0 2px"><b>${p?"\u25BE":"\u25B8"} ${d(a.name)}</b> <span class="muted" style="font-size:12px">\uFF08${m}\uFF09\xB7 ${r.length} \u4E2A${g?`\uFF0C\u5DF2\u9009 ${g}`:""}</span>${k}</div>`,!!p){s+='<table style="width:100%;border-collapse:collapse;font-size:14px"><tbody>';for(let l of r){let I=d(l.larkAppId),L=ce(e.key).has(l.larkAppId)?" checked":"",b=l.deployment.stale?"opacity:.55":"",f=i?`<input class="tf-cap" data-app="${I}" value="${d(l.capability||"")}" placeholder="\u80FD\u529B\u6807\u7B7E\u2026" style="width:92%;padding:3px 6px">`:l.capability?d(l.capability):'<span class="muted">\u2014</span>',T=i?`<button class="tf-role" data-app="${I}" data-name="${d(l.name)}">${l.hasTeamRole?"\u5DF2\u8BBE\xB7\u6539":"\u8BBE\u7F6E"}</button>`:l.hasTeamRole?"\u6709\u89D2\u8272":'<span class="muted">\u2014</span>';s+=`<tr style="${b}"><td style="padding:4px 8px"><input type="checkbox" class="tf-pick" data-tk="${d(e.key)}" data-app="${I}"${L}></td><td style="padding:4px 8px">${d(l.name)}</td><td style="padding:4px 8px" class="muted">${d(l.cliId)}</td><td style="padding:4px 8px">${f}</td><td style="padding:4px 8px">${T}</td></tr>`}s+="</tbody></table>"}}return s||(s='<p class="muted" style="margin:8px 0 0">\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u673A\u5668\u4EBA\u3002</p>'),s+=`<div style="margin-top:12px;display:flex;gap:8px;flex-wrap:wrap;align-items:center"><input class="tf-gname" data-tk="${d(e.key)}" value="${d(Ae.get(e.key)||"")}" placeholder="\u7FA4\u540D\uFF08\u5982\uFF1A\u8DE8\u56E2\u961F\u6392\u969C\uFF09" style="min-width:200px"><button class="tf-grp primary" data-tk="${d(e.key)}">\u628A\u52FE\u9009\u7684\u673A\u5668\u4EBA\u62C9\u4E00\u4E2A\u7FA4</button><span class="muted" style="font-size:13px">\u52FE\u9009\u673A\u5668\u4EBA \u2192 \u62C9\u5230\u4E00\u4E2A\u98DE\u4E66\u7FA4\uFF08\u81EA\u52A8\u542B owner\uFF09</span><span class="tf-gout" data-tk="${d(e.key)}" style="font-size:13px;display:block;flex-basis:100%"></span></div>`,s}function ie(){let e=B("tf-teams"),t=Be();if(!t.length){e.innerHTML='<p class="muted">\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</p>',B("tf-count").textContent="";return}let n="",s=new Set,a=new Set;for(let i of t){let m=i.bots.filter(jn);m.forEach(g=>s.add(g.larkAppId)),i.bots.forEach(g=>a.add(g.larkAppId));let k=new Set(m.map(g=>g.larkAppId));[...ce(i.key)].forEach(g=>{k.has(g)||ce(i.key).delete(g)});let $=!ye.has(i.key),p=i.kind==="remote"?i.ok?' <span class="ok" style="font-size:12px">\u5DF2\u8FDE\u63A5</span>':` <span class="err" style="font-size:12px">\u8FDE\u63A5\u5931\u8D25\uFF1A${d(i.error||"")}</span>`:' <span class="muted" style="font-size:12px">\u6211\u6258\u7BA1</span>';n+=`<div class="card" style="margin:0 0 12px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)"><div class="tf-team-h" data-tk="${d(i.key)}" style="cursor:pointer;display:flex;align-items:center;gap:8px;flex-wrap:wrap"><b style="font-size:15px">${$?"\u25B8":"\u25BE"} ${d(i.label)}</b>`+(i.sub?` <span class="muted" style="font-size:12px">${d(i.sub)}</span>`:"")+p+` <span class="muted" style="font-size:12px">\xB7 ${i.deployments.length} \u4E2A\u90E8\u7F72 \xB7 ${i.bots.length} \u4E2A\u673A\u5668\u4EBA</span></div>`,$||(n+=i.kind==="remote"&&!i.ok?'<p class="muted" style="margin:8px 0 0">\u65E0\u6CD5\u83B7\u53D6\u8BE5\u56E2\u961F\u82B1\u540D\u518C\u3002</p>':Un(i,m)),n+="</div>"}e.innerHTML=n;let r=t.length>1?`\uFF08\u8DE8 ${t.length} \u4E2A\u56E2\u961F\uFF0C\u53BB\u91CD\uFF09`:"";B("tf-count").textContent=`\xB7 ${s.size===a.size?`${a.size}`:`${s.size} / ${a.size}`} \u4E2A\u673A\u5668\u4EBA${r}`,Fn()}function Fn(){let e=B("tf-teams");e.querySelectorAll(".tf-team-h").forEach(t=>{t.onclick=()=>{let n=t.dataset.tk;ye.has(n)?ye.delete(n):ye.add(n),ie()}}),e.querySelectorAll(".tf-dep-h").forEach(t=>{t.onclick=()=>{let n=t.dataset.dk;ve.has(n)?ve.delete(n):ve.add(n),ie()}}),e.querySelectorAll(".tf-pick").forEach(t=>{t.onchange=()=>{let n=ce(t.dataset.tk);t.checked?n.add(t.dataset.app):n.delete(t.dataset.app)}}),e.querySelectorAll(".tf-gname").forEach(t=>{t.oninput=()=>{Ae.set(t.dataset.tk,t.value)}}),e.querySelectorAll(".tf-cap").forEach(t=>{t.onchange=async()=>{let n=t.dataset.app,s=t.value;await At("/api/team/local-bots/"+encodeURIComponent(n)+"/capability",{capability:s}),Be().forEach(a=>{let r=a.bots.find(i=>i.larkAppId===n);r&&(r.capability=s.trim()||null)})}}),e.querySelectorAll(".tf-role").forEach(t=>{t.onclick=()=>zn(t.dataset.app,t.dataset.name||"")}),e.querySelectorAll(".tf-rmmember").forEach(t=>{t.onclick=async n=>{n.stopPropagation(),confirm(`\u628A\u300C${t.dataset.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`)&&(await De("DELETE",`/api/team/hosted/${encodeURIComponent(t.dataset.team)}/members/${encodeURIComponent(t.dataset.dep)}`),ge())}}),e.querySelectorAll(".tf-grp").forEach(t=>{t.onclick=async()=>{let n=t.dataset.tk,s=Pn(n);if(!s)return;let a=[...ce(n)],r=e.querySelector(`.tf-gout[data-tk="${CSS.escape(n)}"]`);if(!a.length){r.innerHTML='<span class="err">\u8BF7\u5148\u52FE\u9009\u81F3\u5C11\u4E00\u4E2A\u673A\u5668\u4EBA</span>';return}let i=(e.querySelector(`.tf-gname[data-tk="${CSS.escape(n)}"]`)?.value||"").trim()||"\u534F\u4F5C\u7FA4";r.innerHTML='<span class="muted">\u5EFA\u7FA4\u4E2D\u2026</span>';let m=s.kind==="local"?await ue("/api/team/federated-group",{name:i,larkAppIds:a,teamId:s.teamId}):await ue("/api/team/remote-group",{hubUrl:s.hubUrl,teamId:s.teamId,name:i,larkAppIds:a});if(_n(r,m.body,m.status),m.body?.ok){ce(n).clear(),Ae.delete(n);let k=r.innerHTML,$=()=>{let p=e.querySelector(`.tf-gout[data-tk="${CSS.escape(n)}"]`);p&&(p.innerHTML=k)};s.kind==="local"?ge().then($):(ie(),$())}}})}function _n(e,t,n){if(t?.ok&&t.chatId){let s=t.shareLink||"https://applink.feishu.cn/client/chat/open?openChatId="+encodeURIComponent(t.chatId),a=(t.invalidBotIds||[]).length?`<span class="err"> \xB7 \u672A\u52A0\u5165\u7684\u673A\u5668\u4EBA\uFF1A${d((t.invalidBotIds||[]).join(", "))}</span>`:"",r=(t.invalidOwnerUnionIds||[]).length?`<span class="err"> \xB7 ${(t.invalidOwnerUnionIds||[]).length} \u4E2A owner \u672A\u80FD\u62C9\u8FDB</span>`:"",i=t.missingOperatorIdentity?'<span class="err"> \xB7 \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</span>':"",m=(t.skippedNoOwner||[]).length?`<span class="err"> \xB7 ${(t.skippedNoOwner||[]).length} \u4E2A\u673A\u5668\u4EBA\u56E0\u8D1F\u8D23\u4EBA\u672A\u7ED1\u5B9A\u8EAB\u4EFD\u88AB\u8DF3\u8FC7\uFF08\u672A\u52A0\u5165\u7FA4\uFF09</span>`:"",k=t.delegatedTo?`\uFF08\u7531\u300C${d(t.delegatedTo)}\u300D\u5EFA\u7FA4\uFF09`:"";e.innerHTML=`<span class="ok">\u7FA4\u5DF2\u521B\u5EFA</span>${k} \xB7 <a href="${d(s)}" target="_blank">\u5728\u98DE\u4E66\u6253\u5F00</a>${a}${r}${i}${m}`}else{let s=t?.error||n,a=s==="no_local_online_bot"?"\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":s==="all_bots_skipped_no_owner"?"\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":s==="no_creator_available"?"\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":s==="delegation_timeout"?"\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":`\u5EFA\u7FA4\u5931\u8D25\uFF1A${s}`;e.innerHTML=`<span class="err">${d(String(a))}</span>`}}async function zn(e,t){let n=await Re("/api/team/local-bots/"+encodeURIComponent(e)+"/role");B("tf-modal-title").textContent="\u56E2\u961F\u89D2\u8272 \xB7 "+t,B("tf-modal-text").value=n.body?.role||"",B("tf-modal").dataset.app=e,B("tf-modal").style.display="flex"}function Ot(){let e=Array.from(new Set(Be().flatMap(s=>s.bots.map(a=>a.cliId)).filter(Boolean))).sort(),t=B("tf-cli"),n=t.value;t.innerHTML='<option value="">\u5168\u90E8 CLI</option>'+e.map(s=>`<option value="${d(s)}">${d(s)}</option>`).join(""),t.value=n}async function ge(){let t=(await Re("/api/team/hosted")).body;if(!t?.ok){Xe=[],ie();return}Dt=t.deployment.deploymentId,He=t.suggestedHubUrl||"",B("tf-owner").textContent=t.deployment.ownerName||(t.deployment.ownerUnionId?"\u5DF2\u7ED1\u5B9A":"\u672A\u7ED1\u5B9A"),Xe=(t.teams||[]).map(n=>({kind:"local",key:`local:${n.teamId}`,teamId:n.teamId,label:n.isDefault?"\u6211\u6258\u7BA1\u7684\u56E2\u961F":n.name,sub:"",ok:!0,deployments:n.deployments||[],bots:n.bots||[]})),Ot(),ie()}async function Wn(){Rt=((await Re("/api/team/remote-roster")).body?.memberships||[]).map(n=>{let s=n.roster?.deployments||[],a=s.find(i=>i.local),r=a?.name?`${a.name} \u7684\u56E2\u961F`:n.teamName||n.teamId;return{kind:"remote",key:`${n.hubUrl}::${n.teamId}`,teamId:n.teamId,label:r,sub:n.hubUrl,ok:!!n.ok,error:n.error,hubUrl:n.hubUrl,deployments:s,bots:n.roster?.bots||[]}}),Ot(),ie()}function qt(e){e.innerHTML=Nn(),Ze.clear(),Ae.clear(),ye.clear(),ve.clear(),["tf-search","tf-cli","tf-fcap","tf-frole"].forEach(t=>{let n=B(t);n.oninput=ie,n.onchange=ie}),B("tf-modal-cancel").onclick=()=>{B("tf-modal").style.display="none"},B("tf-modal-save").onclick=async()=>{let t=B("tf-modal").dataset.app;await At("/api/team/local-bots/"+encodeURIComponent(t)+"/role",{role:B("tf-modal-text").value}),B("tf-modal").style.display="none",ge()},Gn(),ge(),Wn()}function Jn(){return`<section class="page">
514
+ </section>`}function jn(e){let t=(O("tf-search").value||"").trim().toLowerCase();if(t&&!((e.name||"")+" "+(e.cliId||"")+" "+(e.capability||"")).toLowerCase().includes(t))return!1;let n=O("tf-cli").value;return!(n&&e.cliId!==n||O("tf-fcap").checked&&!e.capability||O("tf-frole").checked&&!e.hasTeamRole)}function Un(e,t){let n=[...e.deployments].sort((a,r)=>a.local===r.local?0:a.local?-1:1),s="";for(let a of n){let r=t.filter(l=>l.deployment.id===a.id);if(!r.length)continue;let i=a.id===Dt,m=i?"\u672C\u90E8\u7F72":a.stale?"\u8FDC\u7AEF\xB7\u79BB\u7EBF\uFF1F":"\u8FDC\u7AEF",y=e.kind==="local"&&!i?` <button class="tf-rmmember ghost" data-team="${d(e.teamId)}" data-dep="${d(a.id)}" data-name="${d(a.name)}" style="font-size:12px">\u79FB\u9664</button>`:"",k=`${e.key}::${a.id}`,h=Te.has(k),u=r.filter(l=>we(e.key).has(l.larkAppId)).length;if(s+=`<div class="tf-dep-h" data-dk="${d(k)}" style="cursor:pointer;margin:10px 0 2px"><b>${h?"\u25BE":"\u25B8"} ${d(a.name)}</b> <span class="muted" style="font-size:12px">\uFF08${m}\uFF09\xB7 ${r.length} \u4E2A${u?`\uFF0C\u5DF2\u9009 ${u}`:""}</span>${y}</div>`,!!h){s+='<table style="width:100%;border-collapse:collapse;font-size:14px"><tbody>';for(let l of r){let $=d(l.larkAppId),L=we(e.key).has(l.larkAppId)?" checked":"",v=l.deployment.stale?"opacity:.55":"",f=i?`<input class="tf-cap" data-app="${$}" value="${d(l.capability||"")}" placeholder="\u80FD\u529B\u6807\u7B7E\u2026" style="width:92%;padding:3px 6px">`:l.capability?d(l.capability):'<span class="muted">\u2014</span>',I=l.hasTeamRole?i?`<button class="tf-role" data-app="${$}" data-name="${d(l.name)}">\u67E5\u770B</button>`:"\u6709\u89D2\u8272":'<span class="muted">\u2014</span>';s+=`<tr style="${v}"><td style="padding:4px 8px"><input type="checkbox" class="tf-pick" data-tk="${d(e.key)}" data-app="${$}"${L}></td><td style="padding:4px 8px">${d(l.name)}</td><td style="padding:4px 8px" class="muted">${d(l.cliId)}</td><td style="padding:4px 8px">${f}</td><td style="padding:4px 8px">${I}</td></tr>`}s+="</tbody></table>"}}return s||(s='<p class="muted" style="margin:8px 0 0">\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u673A\u5668\u4EBA\u3002</p>'),s+=`<div style="margin-top:12px;display:flex;gap:8px;flex-wrap:wrap;align-items:center"><input class="tf-gname" data-tk="${d(e.key)}" value="${d(Oe.get(e.key)||"")}" placeholder="\u7FA4\u540D\uFF08\u5982\uFF1A\u8DE8\u56E2\u961F\u6392\u969C\uFF09" style="min-width:200px"><button class="tf-grp primary" data-tk="${d(e.key)}">\u628A\u52FE\u9009\u7684\u673A\u5668\u4EBA\u62C9\u4E00\u4E2A\u7FA4</button><span class="muted" style="font-size:13px">\u52FE\u9009\u673A\u5668\u4EBA \u2192 \u62C9\u5230\u4E00\u4E2A\u98DE\u4E66\u7FA4\uFF08\u81EA\u52A8\u542B owner\uFF09</span><span class="tf-gout" data-tk="${d(e.key)}" style="font-size:13px;display:block;flex-basis:100%"></span></div>`,s}function pe(){let e=O("tf-teams"),t=je();if(!t.length){e.innerHTML='<p class="muted">\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</p>',O("tf-count").textContent="";return}let n="",s=new Set,a=new Set;for(let i of t){let m=i.bots.filter(jn);m.forEach(u=>s.add(u.larkAppId)),i.bots.forEach(u=>a.add(u.larkAppId));let y=new Set(m.map(u=>u.larkAppId));[...we(i.key)].forEach(u=>{y.has(u)||we(i.key).delete(u)});let k=!Se.has(i.key),h=i.kind==="remote"?i.ok?' <span class="ok" style="font-size:12px">\u5DF2\u8FDE\u63A5</span>':` <span class="err" style="font-size:12px">\u8FDE\u63A5\u5931\u8D25\uFF1A${d(i.error||"")}</span>`:' <span class="muted" style="font-size:12px">\u6211\u6258\u7BA1</span>';n+=`<div class="card" style="margin:0 0 12px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)"><div class="tf-team-h" data-tk="${d(i.key)}" style="cursor:pointer;display:flex;align-items:center;gap:8px;flex-wrap:wrap"><b style="font-size:15px">${k?"\u25B8":"\u25BE"} ${d(i.label)}</b>`+(i.sub?` <span class="muted" style="font-size:12px">${d(i.sub)}</span>`:"")+h+` <span class="muted" style="font-size:12px">\xB7 ${i.deployments.length} \u4E2A\u90E8\u7F72 \xB7 ${i.bots.length} \u4E2A\u673A\u5668\u4EBA</span></div>`,k||(n+=i.kind==="remote"&&!i.ok?'<p class="muted" style="margin:8px 0 0">\u65E0\u6CD5\u83B7\u53D6\u8BE5\u56E2\u961F\u82B1\u540D\u518C\u3002</p>':Un(i,m)),n+="</div>"}e.innerHTML=n;let r=t.length>1?`\uFF08\u8DE8 ${t.length} \u4E2A\u56E2\u961F\uFF0C\u53BB\u91CD\uFF09`:"";O("tf-count").textContent=`\xB7 ${s.size===a.size?`${a.size}`:`${s.size} / ${a.size}`} \u4E2A\u673A\u5668\u4EBA${r}`,Fn()}function Fn(){let e=O("tf-teams");e.querySelectorAll(".tf-team-h").forEach(t=>{t.onclick=()=>{let n=t.dataset.tk;Se.has(n)?Se.delete(n):Se.add(n),pe()}}),e.querySelectorAll(".tf-dep-h").forEach(t=>{t.onclick=()=>{let n=t.dataset.dk;Te.has(n)?Te.delete(n):Te.add(n),pe()}}),e.querySelectorAll(".tf-pick").forEach(t=>{t.onchange=()=>{let n=we(t.dataset.tk);t.checked?n.add(t.dataset.app):n.delete(t.dataset.app)}}),e.querySelectorAll(".tf-gname").forEach(t=>{t.oninput=()=>{Oe.set(t.dataset.tk,t.value)}}),e.querySelectorAll(".tf-cap").forEach(t=>{t.onchange=async()=>{let n=t.dataset.app,s=t.value;await On("/api/team/local-bots/"+encodeURIComponent(n)+"/capability",{capability:s}),je().forEach(a=>{let r=a.bots.find(i=>i.larkAppId===n);r&&(r.capability=s.trim()||null)})}}),e.querySelectorAll(".tf-role").forEach(t=>{t.onclick=()=>zn(t.dataset.app,t.dataset.name||"")}),e.querySelectorAll(".tf-rmmember").forEach(t=>{t.onclick=async n=>{n.stopPropagation(),confirm(`\u628A\u300C${t.dataset.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`)&&(await Ne("DELETE",`/api/team/hosted/${encodeURIComponent(t.dataset.team)}/members/${encodeURIComponent(t.dataset.dep)}`),Ie())}}),e.querySelectorAll(".tf-grp").forEach(t=>{t.onclick=async()=>{let n=t.dataset.tk,s=Pn(n);if(!s)return;let a=[...we(n)],r=e.querySelector(`.tf-gout[data-tk="${CSS.escape(n)}"]`);if(!a.length){r.innerHTML='<span class="err">\u8BF7\u5148\u52FE\u9009\u81F3\u5C11\u4E00\u4E2A\u673A\u5668\u4EBA</span>';return}let i=(e.querySelector(`.tf-gname[data-tk="${CSS.escape(n)}"]`)?.value||"").trim()||"\u534F\u4F5C\u7FA4";r.innerHTML='<span class="muted">\u5EFA\u7FA4\u4E2D\u2026</span>';let m=s.kind==="local"?await ge("/api/team/federated-group",{name:i,larkAppIds:a,teamId:s.teamId}):await ge("/api/team/remote-group",{hubUrl:s.hubUrl,teamId:s.teamId,name:i,larkAppIds:a});if(_n(r,m.body,m.status),m.body?.ok){we(n).clear(),Oe.delete(n);let y=r.innerHTML,k=()=>{let h=e.querySelector(`.tf-gout[data-tk="${CSS.escape(n)}"]`);h&&(h.innerHTML=y)};s.kind==="local"?Ie().then(k):(pe(),k())}}})}function _n(e,t,n){if(t?.ok&&t.chatId){let s=t.shareLink||"https://applink.feishu.cn/client/chat/open?openChatId="+encodeURIComponent(t.chatId),a=(t.invalidBotIds||[]).length?`<span class="err"> \xB7 \u672A\u52A0\u5165\u7684\u673A\u5668\u4EBA\uFF1A${d((t.invalidBotIds||[]).join(", "))}</span>`:"",r=(t.invalidOwnerUnionIds||[]).length?`<span class="err"> \xB7 ${(t.invalidOwnerUnionIds||[]).length} \u4E2A owner \u672A\u80FD\u62C9\u8FDB</span>`:"",i=t.missingOperatorIdentity?'<span class="err"> \xB7 \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</span>':"",m=(t.skippedNoOwner||[]).length?`<span class="err"> \xB7 ${(t.skippedNoOwner||[]).length} \u4E2A\u673A\u5668\u4EBA\u56E0\u8D1F\u8D23\u4EBA\u672A\u7ED1\u5B9A\u8EAB\u4EFD\u88AB\u8DF3\u8FC7\uFF08\u672A\u52A0\u5165\u7FA4\uFF09</span>`:"",y=t.delegatedTo?`\uFF08\u7531\u300C${d(t.delegatedTo)}\u300D\u5EFA\u7FA4\uFF09`:"";e.innerHTML=`<span class="ok">\u7FA4\u5DF2\u521B\u5EFA</span>${y} \xB7 <a href="${d(s)}" target="_blank">\u5728\u98DE\u4E66\u6253\u5F00</a>${a}${r}${i}${m}`}else{let s=t?.error||n,a=s==="no_local_online_bot"?"\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":s==="all_bots_skipped_no_owner"?"\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":s==="no_creator_available"?"\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":s==="delegation_timeout"?"\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":`\u5EFA\u7FA4\u5931\u8D25\uFF1A${s}`;e.innerHTML=`<span class="err">${d(String(a))}</span>`}}async function zn(e,t){let n=await Pe("/api/team/local-bots/"+encodeURIComponent(e)+"/role");O("tf-modal-title").textContent="\u56E2\u961F\u89D2\u8272 \xB7 "+t,O("tf-modal-text").value=n.body?.role||"",O("tf-modal").dataset.app=e,O("tf-modal").style.display="flex"}function qt(){let e=Array.from(new Set(je().flatMap(s=>s.bots.map(a=>a.cliId)).filter(Boolean))).sort(),t=O("tf-cli"),n=t.value;t.innerHTML='<option value="">\u5168\u90E8 CLI</option>'+e.map(s=>`<option value="${d(s)}">${d(s)}</option>`).join(""),t.value=n}async function Ie(){let t=(await Pe("/api/team/hosted")).body;if(!t?.ok){ot=[],pe();return}Dt=t.deployment.deploymentId,qe=t.suggestedHubUrl||"",O("tf-owner").textContent=t.deployment.ownerName||(t.deployment.ownerUnionId?"\u5DF2\u7ED1\u5B9A":"\u672A\u7ED1\u5B9A"),ot=(t.teams||[]).map(n=>({kind:"local",key:`local:${n.teamId}`,teamId:n.teamId,label:n.isDefault?"\u6211\u6258\u7BA1\u7684\u56E2\u961F":n.name,sub:"",ok:!0,deployments:n.deployments||[],bots:n.bots||[]})),qt(),pe()}async function Wn(){Rt=((await Pe("/api/team/remote-roster")).body?.memberships||[]).map(n=>{let s=n.roster?.deployments||[],a=s.find(i=>i.local),r=a?.name?`${a.name} \u7684\u56E2\u961F`:n.teamName||n.teamId;return{kind:"remote",key:`${n.hubUrl}::${n.teamId}`,teamId:n.teamId,label:r,sub:n.hubUrl,ok:!!n.ok,error:n.error,hubUrl:n.hubUrl,deployments:s,bots:n.roster?.bots||[]}}),qt(),pe()}function Ot(e){e.innerHTML=Nn(),at.clear(),Oe.clear(),Se.clear(),Te.clear(),["tf-search","tf-cli","tf-fcap","tf-frole"].forEach(t=>{let n=O(t);n.oninput=pe,n.onchange=pe}),O("tf-modal-cancel").onclick=()=>{O("tf-modal").style.display="none"},Gn(),Ie(),Wn()}function Jn(){return`<section class="page">
503
515
  <div class="page-heading"><div>
504
516
  <p class="eyebrow">\u56E2\u961F</p><h1>\u56E2\u961F\u7BA1\u7406</h1>
505
517
  <p>\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</p>
@@ -523,7 +535,7 @@ ${Bt("manage")}
523
535
  </p>
524
536
  <div id="tm-join-out" style="display:none;margin-top:6px"></div>
525
537
  </div>
526
- </section>`}async function et(){let t=(await Re("/api/team/hosted")).body,n=B("tm-list");He=t?.suggestedHubUrl||He;let s=t?.teams||[];if(!s.length){n.innerHTML='<p class="muted">\u8FD8\u6CA1\u6709\u56E2\u961F\u3002</p>';return}n.innerHTML=s.map(a=>{let r=(a.deployments||[]).filter(i=>!i.local).length;return`<div class="card" style="margin:0 0 8px;padding:10px 14px;background:var(--bg-soft,#f6f7f9)">
538
+ </section>`}async function st(){let t=(await Pe("/api/team/hosted")).body,n=O("tm-list");qe=t?.suggestedHubUrl||qe;let s=t?.teams||[];if(!s.length){n.innerHTML='<p class="muted">\u8FD8\u6CA1\u6709\u56E2\u961F\u3002</p>';return}n.innerHTML=s.map(a=>{let r=(a.deployments||[]).filter(i=>!i.local).length;return`<div class="card" style="margin:0 0 8px;padding:10px 14px;background:var(--bg-soft,#f6f7f9)">
527
539
  <div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
528
540
  <b>${d(a.name)}</b>${a.isDefault?' <span class="muted" style="font-size:12px">\u9ED8\u8BA4</span>':""}
529
541
  <span class="muted" style="font-size:12px">\xB7 ${(a.deployments||[]).length} \u4E2A\u90E8\u7F72${r?`\uFF08\u542B ${r} \u8FDC\u7AEF\uFF09`:""} \xB7 ${(a.bots||[]).length} \u4E2A\u673A\u5668\u4EBA</span>
@@ -532,7 +544,7 @@ ${Bt("manage")}
532
544
  ${a.isDefault?"":`<button class="tm-del ghost" data-team="${d(a.teamId)}" data-name="${d(a.name)}" style="font-size:12px">\u5220\u9664</button>`}
533
545
  </span>
534
546
  </div>
535
- <div class="tm-inv-out" data-team="${d(a.teamId)}" style="display:none;margin-top:6px;font-size:13px"></div></div>`}).join(""),n.querySelectorAll(".tm-invite").forEach(a=>{a.onclick=async()=>{let r=a.dataset.team,i=n.querySelector(`.tm-inv-out[data-team="${CSS.escape(r)}"]`);i.style.display="",i.innerHTML='<span class="muted">\u751F\u6210\u4E2D\u2026</span>';let m=await ue("/api/team/local-invite",{teamId:r});m.body?.code?i.innerHTML=`\u628A\u4E0B\u9762\u4E24\u9879\u53D1\u7ED9<b>\u522B\u7684\u90E8\u7F72</b>\u7684\u4EBA\uFF0824 \u5C0F\u65F6\u5185\u3001\u5355\u6B21\u6709\u6548\uFF09\uFF1A<br>Hub \u5730\u5740\uFF1A<code>${d(He)}</code><br>\u9080\u8BF7\u7801\uFF1A<code style="font-size:15px">${d(m.body.code)}</code>`:i.innerHTML='<span class="err">\u751F\u6210\u5931\u8D25\u3002</span>'}}),n.querySelectorAll(".tm-del").forEach(a=>{a.onclick=async()=>{confirm(`\u5220\u9664\u56E2\u961F\u300C${a.dataset.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`)&&(await De("DELETE","/api/team/hosted/"+encodeURIComponent(a.dataset.team)),et())}})}function Pt(e){e.innerHTML=Jn(),B("tm-create").onclick=async()=>{let t=B("tm-newname").value.trim(),n=e.querySelector(".tm-cout");if(!t){n.innerHTML='<span class="err">\u8BF7\u586B\u56E2\u961F\u540D\u79F0</span>';return}n.innerHTML='<span class="muted">\u521B\u5EFA\u4E2D\u2026</span>';let s=await ue("/api/team/hosted",{name:t});s.body?.ok?(n.innerHTML='<span class="ok">\u5DF2\u521B\u5EFA</span>',B("tm-newname").value="",et()):n.innerHTML=`<span class="err">\u521B\u5EFA\u5931\u8D25\uFF1A${d(String(s.body?.error||s.status))}</span>`},B("tm-join").onclick=async()=>{let t=B("tm-hub").value.trim(),n=B("tm-code").value.trim(),s=B("tm-join-out");if(s.style.display="",!t||!n){s.innerHTML='<span class="err">\u8BF7\u586B Hub \u5730\u5740\u548C\u9080\u8BF7\u7801\u3002</span>';return}s.innerHTML='<span class="muted">\u52A0\u5165\u4E2D\u2026</span>';let a=await ue("/api/team/join-remote",{hubUrl:t,inviteCode:n});if(a.body?.ok)s.innerHTML=`<span class="ok">\u5DF2\u52A0\u5165\u300C${d(a.body.teamName||"")}\u300D\uFF0C\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u67E5\u770B\u3002</span>`,B("tm-code").value="";else{let r=a.body?.error||a.status,i=r==="cannot_join_self"?"\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":r==="deployment_already_joined"?"\u4F60\u7684\u90E8\u7F72\u5DF2\u7ECF\u52A0\u5165\u8FC7\u8FD9\u4E2A\u56E2\u961F\u4E86":r==="hub_unreachable"?"\u8FDE\u4E0D\u4E0A\u5BF9\u65B9 Hub\uFF08\u68C0\u67E5\u5730\u5740/\u7F51\u7EDC\uFF09":r==="hub_timeout"?"\u5BF9\u65B9 Hub \u54CD\u5E94\u8D85\u65F6":`\u52A0\u5165\u5931\u8D25\uFF1A${r}`;s.innerHTML=`<span class="err">${d(String(i))}</span>`}},et()}function Gn(){B("tf-autobind").onclick=async()=>{let e=B("tf-bind-out");e.style.display="",e.innerHTML='<span class="muted">\u8BC6\u522B\u4E2D\u2026</span>';let n=(await ue("/api/team/identity/auto-bind")).body;if(n?.ok&&n.owner){e.innerHTML=`<span class="ok">\u5DF2\u7ED1\u5B9A\uFF1A${d(n.owner.name||n.owner.unionId)}</span>`,ge();return}if(n?.ok&&n.needChoice&&Array.isArray(n.candidates)){let s=n.candidates.map(a=>`<button class="tf-pickowner ghost" data-union="${d(a.unionId)}" style="margin:2px">${d(a.name||a.unionId)}</button>`).join(" ");e.innerHTML=`\u8BC6\u522B\u5230\u591A\u4E2A\u5019\u9009\uFF0C\u70B9\u4F60\u81EA\u5DF1\uFF1A<br>${s}`,e.querySelectorAll(".tf-pickowner").forEach(a=>{a.onclick=async()=>{e.innerHTML='<span class="muted">\u7ED1\u5B9A\u4E2D\u2026</span>';let i=(await ue("/api/team/identity/auto-bind",{unionId:a.dataset.union})).body;i?.ok&&i.owner?(e.innerHTML=`<span class="ok">\u5DF2\u7ED1\u5B9A\uFF1A${d(i.owner.name||i.owner.unionId)}</span>`,ge()):e.innerHTML=`<span class="err">\u7ED1\u5B9A\u5931\u8D25\uFF1A${d(String(i?.error||"unknown"))}</span>`}});return}if(n?.error==="no_candidates"){e.innerHTML='<span class="err">\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</span>';return}e.innerHTML=`<span class="err">\u7ED1\u5B9A\u5931\u8D25\uFF1A${d(String(n?.error||"unknown"))}</span>`}}async function Nt(e){let t=await fetch(e);return{status:t.status,body:await t.json().catch(()=>({}))}}async function nt(e,t,n){let s=await fetch(t,{method:e,headers:{"content-type":"application/json"},body:n?JSON.stringify(n):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}function _(e){return document.getElementById(e)}function K(e){return(_(e).value||"").trim()}var ot=[];function Kn(){return`<section class="page">
547
+ <div class="tm-inv-out" data-team="${d(a.teamId)}" style="display:none;margin-top:6px;font-size:13px"></div></div>`}).join(""),n.querySelectorAll(".tm-invite").forEach(a=>{a.onclick=async()=>{let r=a.dataset.team,i=n.querySelector(`.tm-inv-out[data-team="${CSS.escape(r)}"]`);i.style.display="",i.innerHTML='<span class="muted">\u751F\u6210\u4E2D\u2026</span>';let m=await ge("/api/team/local-invite",{teamId:r});m.body?.code?i.innerHTML=`\u628A\u4E0B\u9762\u4E24\u9879\u53D1\u7ED9<b>\u522B\u7684\u90E8\u7F72</b>\u7684\u4EBA\uFF0824 \u5C0F\u65F6\u5185\u3001\u5355\u6B21\u6709\u6548\uFF09\uFF1A<br>Hub \u5730\u5740\uFF1A<code>${d(qe)}</code><br>\u9080\u8BF7\u7801\uFF1A<code style="font-size:15px">${d(m.body.code)}</code>`:i.innerHTML='<span class="err">\u751F\u6210\u5931\u8D25\u3002</span>'}}),n.querySelectorAll(".tm-del").forEach(a=>{a.onclick=async()=>{confirm(`\u5220\u9664\u56E2\u961F\u300C${a.dataset.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`)&&(await Ne("DELETE","/api/team/hosted/"+encodeURIComponent(a.dataset.team)),st())}})}function Pt(e){e.innerHTML=Jn(),O("tm-create").onclick=async()=>{let t=O("tm-newname").value.trim(),n=e.querySelector(".tm-cout");if(!t){n.innerHTML='<span class="err">\u8BF7\u586B\u56E2\u961F\u540D\u79F0</span>';return}n.innerHTML='<span class="muted">\u521B\u5EFA\u4E2D\u2026</span>';let s=await ge("/api/team/hosted",{name:t});s.body?.ok?(n.innerHTML='<span class="ok">\u5DF2\u521B\u5EFA</span>',O("tm-newname").value="",st()):n.innerHTML=`<span class="err">\u521B\u5EFA\u5931\u8D25\uFF1A${d(String(s.body?.error||s.status))}</span>`},O("tm-join").onclick=async()=>{let t=O("tm-hub").value.trim(),n=O("tm-code").value.trim(),s=O("tm-join-out");if(s.style.display="",!t||!n){s.innerHTML='<span class="err">\u8BF7\u586B Hub \u5730\u5740\u548C\u9080\u8BF7\u7801\u3002</span>';return}s.innerHTML='<span class="muted">\u52A0\u5165\u4E2D\u2026</span>';let a=await ge("/api/team/join-remote",{hubUrl:t,inviteCode:n});if(a.body?.ok)s.innerHTML=`<span class="ok">\u5DF2\u52A0\u5165\u300C${d(a.body.teamName||"")}\u300D\uFF0C\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u67E5\u770B\u3002</span>`,O("tm-code").value="";else{let r=a.body?.error||a.status,i=r==="cannot_join_self"?"\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":r==="deployment_already_joined"?"\u4F60\u7684\u90E8\u7F72\u5DF2\u7ECF\u52A0\u5165\u8FC7\u8FD9\u4E2A\u56E2\u961F\u4E86":r==="hub_unreachable"?"\u8FDE\u4E0D\u4E0A\u5BF9\u65B9 Hub\uFF08\u68C0\u67E5\u5730\u5740/\u7F51\u7EDC\uFF09":r==="hub_timeout"?"\u5BF9\u65B9 Hub \u54CD\u5E94\u8D85\u65F6":`\u52A0\u5165\u5931\u8D25\uFF1A${r}`;s.innerHTML=`<span class="err">${d(String(i))}</span>`}},st()}function Gn(){O("tf-autobind").onclick=async()=>{let e=O("tf-bind-out");e.style.display="",e.innerHTML='<span class="muted">\u8BC6\u522B\u4E2D\u2026</span>';let n=(await ge("/api/team/identity/auto-bind")).body;if(n?.ok&&n.owner){e.innerHTML=`<span class="ok">\u5DF2\u7ED1\u5B9A\uFF1A${d(n.owner.name||n.owner.unionId)}</span>`,Ie();return}if(n?.ok&&n.needChoice&&Array.isArray(n.candidates)){let s=n.candidates.map(a=>`<button class="tf-pickowner ghost" data-union="${d(a.unionId)}" style="margin:2px">${d(a.name||a.unionId)}</button>`).join(" ");e.innerHTML=`\u8BC6\u522B\u5230\u591A\u4E2A\u5019\u9009\uFF0C\u70B9\u4F60\u81EA\u5DF1\uFF1A<br>${s}`,e.querySelectorAll(".tf-pickowner").forEach(a=>{a.onclick=async()=>{e.innerHTML='<span class="muted">\u7ED1\u5B9A\u4E2D\u2026</span>';let i=(await ge("/api/team/identity/auto-bind",{unionId:a.dataset.union})).body;i?.ok&&i.owner?(e.innerHTML=`<span class="ok">\u5DF2\u7ED1\u5B9A\uFF1A${d(i.owner.name||i.owner.unionId)}</span>`,Ie()):e.innerHTML=`<span class="err">\u7ED1\u5B9A\u5931\u8D25\uFF1A${d(String(i?.error||"unknown"))}</span>`}});return}if(n?.error==="no_candidates"){e.innerHTML='<span class="err">\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</span>';return}e.innerHTML=`<span class="err">\u7ED1\u5B9A\u5931\u8D25\uFF1A${d(String(n?.error||"unknown"))}</span>`}}async function Nt(e){let t=await fetch(e);return{status:t.status,body:await t.json().catch(()=>({}))}}async function it(e,t,n){let s=await fetch(t,{method:e,headers:{"content-type":"application/json"},body:n?JSON.stringify(n):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}function K(e){return document.getElementById(e)}function X(e){return(K(e).value||"").trim()}var lt=[];function Kn(){return`<section class="page">
536
548
  <div class="page-heading">
537
549
  <div>
538
550
  <p class="eyebrow">\u63A5\u5165\u70B9 \xB7 beta</p>
@@ -571,7 +583,7 @@ ${Bt("manage")}
571
583
  <h2 style="margin-top:0">\u5DF2\u6709\u63A5\u5165\u70B9 <span class="muted" id="cn-count" style="font-size:13px"></span></h2>
572
584
  <div id="cn-list">\u52A0\u8F7D\u4E2D\u2026</div>
573
585
  </div>
574
- </section>`}function tt(){let e=_("cn-kind").value,t=_("cn-mode").value;document.querySelectorAll(".cn-wf").forEach(n=>{n.style.display=e==="workflow"?"":"none"}),document.querySelectorAll(".cn-fixed").forEach(n=>{n.style.display=t==="fixed"?"":"none"}),document.querySelectorAll(".cn-allow").forEach(n=>{n.style.display=t==="fixed"?"none":""}),document.querySelectorAll(".cn-life").forEach(n=>{n.style.display=t==="new-group"?"":"none"})}function jt(e){return`${location.origin}/webhook/${encodeURIComponent(e)}`}function Vn(e){return e==="fixed"?"\u56FA\u5B9A\u7FA4":e==="new-group"?"\u6BCF\u6B21\u65B0\u5EFA\u7FA4":"\u8BF7\u6C42\u6307\u5B9A\u7FA4"}function Yn(e){return e==="workflow"?"\u5DE5\u4F5C\u6D41":"\u5355\u8F6E"}function Qn(e){let t=_("cn-list");if(_("cn-count").textContent=e.length?`\xB7 ${e.length} \u4E2A`:"",!e.length){t.innerHTML='<p class="muted">\u8FD8\u6CA1\u6709\u63A5\u5165\u70B9\u3002\u7528\u4E0A\u9762\u7684\u8868\u5355\u521B\u5EFA\u4E00\u4E2A\u3002</p>';return}t.innerHTML=e.map(n=>{let s=ot.find(r=>r.larkAppId===n.target.botId),a=jt(n.id);return`<div class="card" style="margin:0 0 10px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
586
+ </section>`}function rt(){let e=K("cn-kind").value,t=K("cn-mode").value;document.querySelectorAll(".cn-wf").forEach(n=>{n.style.display=e==="workflow"?"":"none"}),document.querySelectorAll(".cn-fixed").forEach(n=>{n.style.display=t==="fixed"?"":"none"}),document.querySelectorAll(".cn-allow").forEach(n=>{n.style.display=t==="fixed"?"none":""}),document.querySelectorAll(".cn-life").forEach(n=>{n.style.display=t==="new-group"?"":"none"})}function jt(e){return`${location.origin}/webhook/${encodeURIComponent(e)}`}function Vn(e){return e==="fixed"?"\u56FA\u5B9A\u7FA4":e==="new-group"?"\u6BCF\u6B21\u65B0\u5EFA\u7FA4":"\u8BF7\u6C42\u6307\u5B9A\u7FA4"}function Yn(e){return e==="workflow"?"\u5DE5\u4F5C\u6D41":"\u5355\u8F6E"}function Qn(e){let t=K("cn-list");if(K("cn-count").textContent=e.length?`\xB7 ${e.length} \u4E2A`:"",!e.length){t.innerHTML='<p class="muted">\u8FD8\u6CA1\u6709\u63A5\u5165\u70B9\u3002\u7528\u4E0A\u9762\u7684\u8868\u5355\u521B\u5EFA\u4E00\u4E2A\u3002</p>';return}t.innerHTML=e.map(n=>{let s=lt.find(r=>r.larkAppId===n.target.botId),a=jt(n.id);return`<div class="card" style="margin:0 0 10px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
575
587
  <div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
576
588
  <b style="font-size:15px">${d(n.name)}</b>
577
589
  <span class="${n.enabled?"ok":"muted"}" style="font-size:12px">${n.enabled?"\u5DF2\u542F\u7528":"\u5DF2\u505C\u7528"}</span>
@@ -584,11 +596,11 @@ ${Bt("manage")}
584
596
  <div style="margin-top:6px;font-size:13px;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
585
597
  <span class="muted">Webhook URL\uFF1A</span><code style="font-size:12px;word-break:break-all">${d(a)}</code>
586
598
  <button class="cn-copy ghost" data-url="${d(a)}" style="font-size:12px">\u590D\u5236</button>
587
- </div></div>`}).join(""),t.querySelectorAll(".cn-copy").forEach(n=>{n.onclick=()=>{navigator.clipboard?.writeText(n.dataset.url),n.textContent="\u5DF2\u590D\u5236",setTimeout(()=>n.textContent="\u590D\u5236",1200)}}),t.querySelectorAll(".cn-toggle").forEach(n=>{n.onclick=async()=>{await nt("PATCH","/api/connectors/"+encodeURIComponent(n.dataset.id),{enabled:n.dataset.on!=="true"}),Oe()}}),t.querySelectorAll(".cn-del").forEach(n=>{n.onclick=async()=>{confirm("\u5220\u9664\u8FD9\u4E2A\u63A5\u5165\u70B9\uFF1F\u5B83\u7684 webhook URL \u4F1A\u7ACB\u5373\u5931\u6548\u3002")&&(await nt("DELETE","/api/connectors/"+encodeURIComponent(n.dataset.id)),Oe())}})}async function Oe(){let[e,t]=await Promise.all([Nt("/api/bots"),Nt("/api/connectors")]);ot=(e.body?.bots||[]).map(a=>({larkAppId:a.larkAppId,botName:a.botName||a.larkAppId}));let n=_("cn-bot"),s=n.value;n.innerHTML=ot.map(a=>`<option value="${d(a.larkAppId)}">${d(a.botName)}</option>`).join("")||'<option value="">\uFF08\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF09</option>',s&&(n.value=s),Qn(t.body?.connectors||[])}function Ut(e){e.innerHTML=Kn(),_("cn-kind").onchange=tt,_("cn-mode").onchange=tt,tt(),_("cn-create").onclick=async()=>{let t=_("cn-create-out"),n=K("cn-name"),s=_("cn-bot").value;if(!n){t.innerHTML='<span class="err">\u8BF7\u586B\u540D\u79F0</span>';return}if(!s){t.innerHTML='<span class="err">\u8BF7\u9009\u673A\u5668\u4EBA</span>';return}let a=_("cn-kind").value,r=_("cn-mode").value,i={name:n,enabled:!0,target:{kind:a,mode:r,botId:s},promptEnvelope:{sourceName:n}};if(a==="workflow"){if(!K("cn-wf")){t.innerHTML='<span class="err">\u8BF7\u586B\u5DE5\u4F5C\u6D41 ID</span>';return}i.target.workflowId=K("cn-wf")}if(r==="fixed"){if(!K("cn-chat")){t.innerHTML='<span class="err">\u56FA\u5B9A\u7FA4\u9700\u8981\u586B\u7FA4 ID</span>';return}i.target.chatId=K("cn-chat")}else{let $=K("cn-allow");$&&(i.target.allowChats=$.split(",").map(p=>p.trim()).filter(Boolean))}if(r==="new-group"){if(!K("cn-dedup")||!K("cn-status")){t.innerHTML='<span class="err">\u300C\u6BCF\u6B21\u65B0\u5EFA\u7FA4\u300D\u9700\u8981\u586B\u53BB\u91CD\u5B57\u6BB5\u548C\u72B6\u6001\u5B57\u6BB5</span>';return}i.lifecycleExtractors={dedupKey:K("cn-dedup"),status:K("cn-status")}}let m=K("cn-secret");m&&(i.secret=m),t.innerHTML='<span class="muted">\u521B\u5EFA\u4E2D\u2026</span>';let k=await nt("POST","/api/connectors",i);if(k.status===201&&k.body?.ok){t.innerHTML="";let $=_("cn-created");$.style.display="";let p=k.body.webhookUrl||jt(k.body.connector.id),g=k.body.secret;$.innerHTML=`<div class="card" style="padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
599
+ </div></div>`}).join(""),t.querySelectorAll(".cn-copy").forEach(n=>{n.onclick=()=>{navigator.clipboard?.writeText(n.dataset.url),n.textContent="\u5DF2\u590D\u5236",setTimeout(()=>n.textContent="\u590D\u5236",1200)}}),t.querySelectorAll(".cn-toggle").forEach(n=>{n.onclick=async()=>{await it("PATCH","/api/connectors/"+encodeURIComponent(n.dataset.id),{enabled:n.dataset.on!=="true"}),Ue()}}),t.querySelectorAll(".cn-del").forEach(n=>{n.onclick=async()=>{confirm("\u5220\u9664\u8FD9\u4E2A\u63A5\u5165\u70B9\uFF1F\u5B83\u7684 webhook URL \u4F1A\u7ACB\u5373\u5931\u6548\u3002")&&(await it("DELETE","/api/connectors/"+encodeURIComponent(n.dataset.id)),Ue())}})}async function Ue(){let[e,t]=await Promise.all([Nt("/api/bots"),Nt("/api/connectors")]);lt=(e.body?.bots||[]).map(a=>({larkAppId:a.larkAppId,botName:a.botName||a.larkAppId}));let n=K("cn-bot"),s=n.value;n.innerHTML=lt.map(a=>`<option value="${d(a.larkAppId)}">${d(a.botName)}</option>`).join("")||'<option value="">\uFF08\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF09</option>',s&&(n.value=s),Qn(t.body?.connectors||[])}function Ut(e){e.innerHTML=Kn(),K("cn-kind").onchange=rt,K("cn-mode").onchange=rt,rt(),K("cn-create").onclick=async()=>{let t=K("cn-create-out"),n=X("cn-name"),s=K("cn-bot").value;if(!n){t.innerHTML='<span class="err">\u8BF7\u586B\u540D\u79F0</span>';return}if(!s){t.innerHTML='<span class="err">\u8BF7\u9009\u673A\u5668\u4EBA</span>';return}let a=K("cn-kind").value,r=K("cn-mode").value,i={name:n,enabled:!0,target:{kind:a,mode:r,botId:s},promptEnvelope:{sourceName:n}};if(a==="workflow"){if(!X("cn-wf")){t.innerHTML='<span class="err">\u8BF7\u586B\u5DE5\u4F5C\u6D41 ID</span>';return}i.target.workflowId=X("cn-wf")}if(r==="fixed"){if(!X("cn-chat")){t.innerHTML='<span class="err">\u56FA\u5B9A\u7FA4\u9700\u8981\u586B\u7FA4 ID</span>';return}i.target.chatId=X("cn-chat")}else{let k=X("cn-allow");k&&(i.target.allowChats=k.split(",").map(h=>h.trim()).filter(Boolean))}if(r==="new-group"){if(!X("cn-dedup")||!X("cn-status")){t.innerHTML='<span class="err">\u300C\u6BCF\u6B21\u65B0\u5EFA\u7FA4\u300D\u9700\u8981\u586B\u53BB\u91CD\u5B57\u6BB5\u548C\u72B6\u6001\u5B57\u6BB5</span>';return}i.lifecycleExtractors={dedupKey:X("cn-dedup"),status:X("cn-status")}}let m=X("cn-secret");m&&(i.secret=m),t.innerHTML='<span class="muted">\u521B\u5EFA\u4E2D\u2026</span>';let y=await it("POST","/api/connectors",i);if(y.status===201&&y.body?.ok){t.innerHTML="";let k=K("cn-created");k.style.display="";let h=y.body.webhookUrl||jt(y.body.connector.id),u=y.body.secret;k.innerHTML=`<div class="card" style="padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
588
600
  <p class="ok" style="margin:0 0 6px">\u5DF2\u521B\u5EFA\u300C${d(n)}\u300D</p>
589
- <p style="margin:4px 0;font-size:13px"><span class="muted">Webhook URL\uFF1A</span><code style="word-break:break-all">${d(p)}</code></p>
590
- ${g?`<p style="margin:4px 0;font-size:13px"><span class="muted">\u7B7E\u540D\u5BC6\u94A5\uFF08\u53EA\u663E\u793A\u8FD9\u4E00\u6B21\uFF0C\u8BF7\u4FDD\u5B58\uFF09\uFF1A</span><code>${d(g)}</code></p>`:""}
591
- <p class="muted" style="font-size:12px;margin:6px 0 0">\u5916\u90E8\u7CFB\u7EDF\u7528\u6B64 URL + \u5BC6\u94A5\uFF08HMAC-SHA256 \u7B7E\u540D\uFF09\u8C03\u7528\u5373\u53EF\u89E6\u53D1\u3002</p></div>`,["cn-name","cn-wf","cn-chat","cn-allow","cn-dedup","cn-status","cn-secret"].forEach(l=>{_(l).value=""}),Oe()}else{let $=k.body?.error||k.status;t.innerHTML=`<span class="err">\u521B\u5EFA\u5931\u8D25\uFF1A${d(String($))}</span>`}},Oe()}function Xn(){let e=[["",o("workflow.filter.nonTerminal")],["all",o("workflow.filter.all")],["pending",le("pending")],["running",le("running")],["waiting",le("waiting")],["succeeded",le("succeeded")],["failed",le("failed")],["cancelled",le("cancelled")]];return`
601
+ <p style="margin:4px 0;font-size:13px"><span class="muted">Webhook URL\uFF1A</span><code style="word-break:break-all">${d(h)}</code></p>
602
+ ${u?`<p style="margin:4px 0;font-size:13px"><span class="muted">\u7B7E\u540D\u5BC6\u94A5\uFF08\u53EA\u663E\u793A\u8FD9\u4E00\u6B21\uFF0C\u8BF7\u4FDD\u5B58\uFF09\uFF1A</span><code>${d(u)}</code></p>`:""}
603
+ <p class="muted" style="font-size:12px;margin:6px 0 0">\u5916\u90E8\u7CFB\u7EDF\u7528\u6B64 URL + \u5BC6\u94A5\uFF08HMAC-SHA256 \u7B7E\u540D\uFF09\u8C03\u7528\u5373\u53EF\u89E6\u53D1\u3002</p></div>`,["cn-name","cn-wf","cn-chat","cn-allow","cn-dedup","cn-status","cn-secret"].forEach(l=>{K(l).value=""}),Ue()}else{let k=y.body?.error||y.status;t.innerHTML=`<span class="err">\u521B\u5EFA\u5931\u8D25\uFF1A${d(String(k))}</span>`}},Ue()}function Xn(){let e=[["",o("workflow.filter.nonTerminal")],["all",o("workflow.filter.all")],["pending",fe("pending")],["running",fe("running")],["waiting",fe("waiting")],["succeeded",fe("succeeded")],["failed",fe("failed")],["cancelled",fe("cancelled")]];return`
592
604
  <nav class="wf-subnav">
593
605
  <a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${c(o("workflow.subnav.runs"))}</a>
594
606
  <a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${c(o("workflow.subnav.catalog"))}</a>
@@ -608,15 +620,15 @@ ${Bt("manage")}
608
620
  </tr></thead>
609
621
  <tbody id="wf-tbody"></tbody>
610
622
  </table>
611
- `}var Zn=5e3,eo=2e3,ke=new Set(["succeeded","failed","cancelled"]);function c(e){return e.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}function to(e){let t=new Date(e),s=Date.now()-e;return s<6e4?o("time.secondsAgo",{value:Math.max(1,Math.floor(s/1e3))}):s<36e5?o("time.minutesAgo",{value:Math.floor(s/6e4)}):s<864e5?o("time.hoursAgo",{value:Math.floor(s/36e5)}):t.toISOString().slice(0,19).replace("T"," ")}function ne(e){return`<span class="${ke.has(e)?"wf-status terminal":"wf-status live"} wf-status-${c(e)}">${c(le(e))}</span>`}function le(e){let t=`workflow.status.${e}`,n=o(t);return n===t?e:n}function Wt(e){let t=location.hash.match(/^#\/workflows\/([^?#]+)(?:\?([^#]*))?$/);if(t){let n=new URLSearchParams(t[2]??"");return oo(e,decodeURIComponent(t[1]),{focusAttemptId:n.get("attempt")??void 0})}return no(e)}function no(e){e.innerHTML=Xn();let t=e.querySelector("#wf-tbody"),n=e.querySelector("#wf-filters"),s=e.querySelector("#wf-last-load"),a=[],r=null,i=!1,m=null,k=!1;function $(b){let T=(new FormData(n).get("q")??"").trim().toLowerCase();return T?b.filter(S=>S.runId.toLowerCase().includes(T)||S.workflowId.toLowerCase().includes(T)||(S.chatId??"").toLowerCase().includes(T)):b}function p(){let b=$(a);if(b.length===0){t.innerHTML=`<tr><td colspan="7" class="empty">${m?c(o("workflow.list.failedLoad",{error:m})):a.length===0?c(o("workflow.list.noRuns")):c(o("workflow.list.noFilterMatch"))}</td></tr>`;return}t.innerHTML=b.map(f=>{let T=`${f.dEf}/${f.dAct}/${f.dWait}`,S=f.dEf+f.dAct+f.dWait>0?"wf-dangling has":"wf-dangling none",y=[];f.chatId&&y.push(c(f.chatId)),f.larkAppId&&y.push(`<span class="muted">${c(f.larkAppId)}</span>`);let C=y.length>0?y.join("<br/>"):"\u2014",u=so(f);return`<tr data-runid="${c(f.runId)}">
623
+ `}var Zn=5e3,eo=2e3,Le=new Set(["succeeded","failed","cancelled"]);function c(e){return e.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}function to(e){let t=new Date(e),s=Date.now()-e;return s<6e4?o("time.secondsAgo",{value:Math.max(1,Math.floor(s/1e3))}):s<36e5?o("time.minutesAgo",{value:Math.floor(s/6e4)}):s<864e5?o("time.hoursAgo",{value:Math.floor(s/36e5)}):t.toISOString().slice(0,19).replace("T"," ")}function re(e){return`<span class="${Le.has(e)?"wf-status terminal":"wf-status live"} wf-status-${c(e)}">${c(fe(e))}</span>`}function fe(e){let t=`workflow.status.${e}`,n=o(t);return n===t?e:n}function Wt(e){let t=location.hash.match(/^#\/workflows\/([^?#]+)(?:\?([^#]*))?$/);if(t){let n=new URLSearchParams(t[2]??"");return oo(e,decodeURIComponent(t[1]),{focusAttemptId:n.get("attempt")??void 0})}return no(e)}function no(e){e.innerHTML=Xn();let t=e.querySelector("#wf-tbody"),n=e.querySelector("#wf-filters"),s=e.querySelector("#wf-last-load"),a=[],r=null,i=!1,m=null,y=!1;function k(v){let I=(new FormData(n).get("q")??"").trim().toLowerCase();return I?v.filter(T=>T.runId.toLowerCase().includes(I)||T.workflowId.toLowerCase().includes(I)||(T.chatId??"").toLowerCase().includes(I)):v}function h(){let v=k(a);if(v.length===0){t.innerHTML=`<tr><td colspan="7" class="empty">${m?c(o("workflow.list.failedLoad",{error:m})):a.length===0?c(o("workflow.list.noRuns")):c(o("workflow.list.noFilterMatch"))}</td></tr>`;return}t.innerHTML=v.map(f=>{let I=`${f.dEf}/${f.dAct}/${f.dWait}`,T=f.dEf+f.dAct+f.dWait>0?"wf-dangling has":"wf-dangling none",S=[];f.chatId&&S.push(c(f.chatId)),f.larkAppId&&S.push(`<span class="muted">${c(f.larkAppId)}</span>`);let M=S.length>0?S.join("<br/>"):"\u2014",p=so(f);return`<tr data-runid="${c(f.runId)}">
612
624
  <td><a href="#/workflows/${encodeURIComponent(f.runId)}"><code>${c(f.runId)}</code></a></td>
613
625
  <td>${c(f.workflowId)}</td>
614
- <td>${ne(f.status)}${f.failedNodeId?` <span class="muted">(${c(f.failedNodeId)})</span>`:""}${u}</td>
626
+ <td>${re(f.status)}${f.failedNodeId?` <span class="muted">(${c(f.failedNodeId)})</span>`:""}${p}</td>
615
627
  <td>${f.lastSeq}</td>
616
- <td class="${S}">${T}</td>
628
+ <td class="${T}">${I}</td>
617
629
  <td title="${c(new Date(f.updatedAt).toISOString())}">${to(f.updatedAt)}</td>
618
- <td>${C}</td>
619
- </tr>`}).join("")}function g(){m?(s.textContent=o("workflow.list.error",{error:m}),s.classList.add("error")):(s.textContent=o("workflow.list.loaded",{count:a.length,time:new Date().toLocaleTimeString()}),s.classList.remove("error"))}async function l(){if(!(k||i)&&!document.hidden){i=!0;try{let b=n.elements.namedItem("status")?.value??"",f=new URLSearchParams;b==="all"?f.set("all","1"):b&&f.set("status",b);let T="/api/workflows/runs"+(f.toString()?`?${f}`:""),S=await fetch(T);S.ok?(a=(await S.json()).runs??[],m=null):(m=`HTTP ${S.status}`,a=[])}catch(b){m=b?.message??String(b),a=[]}finally{i=!1,k||(p(),g())}}}function I(){r!==null&&window.clearTimeout(r),r=window.setTimeout(async()=>{await l(),k||I()},Zn)}function L(){document.hidden||l()}return n.addEventListener("input",()=>{p()}),n.addEventListener("change",b=>{b.target.getAttribute("name")==="status"&&l()}),document.addEventListener("visibilitychange",L),l().then(()=>{k||I()}),()=>{k=!0,r!==null&&window.clearTimeout(r),document.removeEventListener("visibilitychange",L)}}function oo(e,t,n={}){e.innerHTML=`
630
+ <td>${M}</td>
631
+ </tr>`}).join("")}function u(){m?(s.textContent=o("workflow.list.error",{error:m}),s.classList.add("error")):(s.textContent=o("workflow.list.loaded",{count:a.length,time:new Date().toLocaleTimeString()}),s.classList.remove("error"))}async function l(){if(!(y||i)&&!document.hidden){i=!0;try{let v=n.elements.namedItem("status")?.value??"",f=new URLSearchParams;v==="all"?f.set("all","1"):v&&f.set("status",v);let I="/api/workflows/runs"+(f.toString()?`?${f}`:""),T=await fetch(I);T.ok?(a=(await T.json()).runs??[],m=null):(m=`HTTP ${T.status}`,a=[])}catch(v){m=v?.message??String(v),a=[]}finally{i=!1,y||(h(),u())}}}function $(){r!==null&&window.clearTimeout(r),r=window.setTimeout(async()=>{await l(),y||$()},Zn)}function L(){document.hidden||l()}return n.addEventListener("input",()=>{h()}),n.addEventListener("change",v=>{v.target.getAttribute("name")==="status"&&l()}),document.addEventListener("visibilitychange",L),l().then(()=>{y||$()}),()=>{y=!0,r!==null&&window.clearTimeout(r),document.removeEventListener("visibilitychange",L)}}function oo(e,t,n={}){e.innerHTML=`
620
632
  <div class="wf-detail-head">
621
633
  <a class="btn-link" href="#/workflows">${c(o("workflow.detail.back"))}</a>
622
634
  <div>
@@ -672,84 +684,84 @@ ${Bt("manage")}
672
684
  </div>
673
685
  <div id="wf-event-meta" class="muted"></div>
674
686
  </section>
675
- `;let s=e.querySelector("#wf-detail-subtitle"),a=e.querySelector("#wf-detail-refresh"),r=e.querySelector("#wf-detail-error"),i=e.querySelector("#wf-cancel-status"),m=e.querySelector("#wf-summary"),k=e.querySelector("#wf-dangling-panel"),$=e.querySelector("#wf-parallel-view"),p=e.querySelector("#wf-parallel-meta"),g=e.querySelector("#wf-node-tbody"),l=e.querySelector("#wf-io-list"),I=e.querySelector(".wf-timeline-scroll"),L=e.querySelector("#wf-event-tbody"),b=e.querySelector("#wf-event-meta"),f=e.querySelector("#wf-cancel-run"),T=e.querySelector("#wf-load-older"),S=null,y=[],C=new Set,u=null,w=null,h=!1,E=0,M=null,A=!1,P=!1,O=!1,H=new Set,q=new Map,j=new Map,F=new Map,W=new Set,ee=new Map,te=new Set,he=new Map,dn=new Map,it=0,lt=n.focusAttemptId;function G(v){if(!v){r.hidden=!0,r.textContent="";return}r.hidden=!1,r.textContent=v}function dt(v){if(!v){i.hidden=!0,i.textContent="";return}i.hidden=!1,i.textContent=v}async function ct(){let v=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/snapshot`);if(v.status===404)throw new Error(o("workflow.detail.unknownRun"));if(!v.ok)throw new Error(o("workflow.detail.snapshotHttp",{status:v.status}));S=await v.json()}async function Te(v){let U=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/events?${v}`);if(U.status===404)throw new Error(o("workflow.detail.unknownRun"));if(!U.ok)throw new Error(o("workflow.detail.eventsHttp",{status:U.status}));return await U.json()}function Le(v,U){let D=v.filter(R=>C.has(R.eventId)?!1:(C.add(R.eventId),!0));D.length!==0&&(y=U==="prepend"?[...D,...y]:[...y,...D],y.sort((R,oe)=>$e(R.eventId)-$e(oe.eventId)))}async function cn(){await ct();let v=await Te(new URLSearchParams({tail:"100"}));y=[],C=new Set,Le(v.events,"append"),u=v.oldestSeq,w=v.newestSeq,h=v.hasOlder,E=v.totalCount,Y()}async function Ee(){if(!(A||P||document.hidden)){P=!0;try{if(await ct(),w!==null){let v=await Te(new URLSearchParams({afterSeq:String(w),limit:"200"}));Le(v.events,"append"),v.newestSeq!==null&&(w=v.newestSeq),u===null&&v.oldestSeq!==null&&(u=v.oldestSeq),E=v.totalCount}else{let v=await Te(new URLSearchParams({tail:"1"}));Le(v.events,"append"),u=v.oldestSeq,w=v.newestSeq,h=v.hasOlder,E=v.totalCount}G(null),Y()}catch(v){G(v?.message??String(v))}finally{P=!1}}}async function un(){if(!(u===null||!h)){T.disabled=!0;try{let v=await Te(new URLSearchParams({beforeSeq:String(u),limit:"100"}));Le(v.events,"prepend"),v.oldestSeq!==null&&(u=v.oldestSeq),h=v.hasOlder,E=v.totalCount,G(null),Y()}catch(v){G(v?.message??String(v))}finally{T.disabled=!1}}}async function pn(){if(!S||ke.has(S.run.status)||O)return;if(!S.chatBinding?.larkAppId){G(o("workflow.detail.cancelUnavailable",{runId:t}));return}let v=ro(S),U=o("workflow.detail.cancelConfirm",{runId:t,...v});if(window.confirm(U)){O=!0,f.disabled=!0;try{let D=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/cancel`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"cancelled via dashboard"})});if(D.status===401)throw new Error(o("workflow.detail.writeAccessCancel"));let R=await D.json().catch(()=>({}));if(!D.ok||!R.ok)throw new Error(R.hint??R.error??o("workflow.detail.cancelHttp",{status:D.status}));dt(R.pending?o("workflow.detail.cancelPending"):null),G(null),await Ee()}catch(D){G(D?.message??String(D))}finally{O=!1,f.disabled=!1,Y()}}}async function fn(v,U){if(!te.has(v)){te.add(v),he.delete(v),Y();try{let D=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/attempts/${encodeURIComponent(U)}/${encodeURIComponent(v)}/resume`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});if(D.status===401)throw new Error(o("workflow.detail.writeAccessResume"));let R=await D.json().catch(()=>({}));if(!D.ok||!R.ok||!R.resumeId||!R.url)throw new Error(R.hint??R.message??R.error??o("workflow.detail.resumeStartFailed",{status:D.status}));ee.set(v,{resumeId:R.resumeId,url:R.url})}catch(D){let R=D?.message??String(D);he.set(v,R)}finally{te.delete(v),Y()}}}async function mn(v,U){if(!te.has(v)){te.add(v),he.delete(v),Y();try{let D=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/attempts/${encodeURIComponent(U)}/${encodeURIComponent(v)}/resume/end`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"ended_by_dashboard"})});if(D.status===401)throw new Error(o("workflow.detail.writeAccessResume"));let R=await D.json().catch(()=>({}));if(!D.ok||!R.ok)if(R.error==="resume_not_running")ee.delete(v);else throw new Error(R.hint??R.message??R.error??o("workflow.detail.resumeEndFailed",{status:D.status}));else ee.delete(v)}catch(D){let R=D?.message??String(D);he.set(v,R)}finally{te.delete(v),Y()}}}async function wn(v,U){if(!W.has(v)){W.add(v),F.delete(v),Y();try{let D=j.get(v)?.trim()||void 0,R=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/${U}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({comment:D})});if(R.status===401)throw new Error(o("workflow.detail.writeAccessApproval"));let oe=await R.json().catch(()=>({}));if(!R.ok||!oe.ok)throw new Error(oe.hint??oe.message??oe.error??o("workflow.detail.actionHttp",{action:U,status:R.status}));let _e=U==="approve"?o("workflow.detail.approved"):o("workflow.detail.rejected");F.set(v,{kind:"ok",text:oe.alreadyTerminal?o("workflow.detail.alreadyTerminal",{label:_e}):oe.pending?o("workflow.detail.workflowContinue",{label:_e}):o("workflow.detail.workflowRefreshing",{label:_e})}),G(null),await Ee()}catch(D){let R=D?.message??String(D);F.set(v,{kind:"error",text:R}),G(R)}finally{W.delete(v),Y()}}}function Y(){if(!S)return;it=I.scrollTop;let v=S.run;ke.has(v.status)&&dt(null),s.innerHTML=`${c(v.workflowId??"?")} \xB7 ${ne(v.status)} \xB7 lastSeq ${S.lastSeq}`,a.textContent=o("workflow.detail.refreshed",{time:new Date().toLocaleTimeString()}),f.hidden=ke.has(v.status),f.disabled=O||!S.chatBinding?.larkAppId,f.textContent=S.chatBinding?.larkAppId?o("workflow.detail.cancel"):o("workflow.detail.cliCancelOnly"),f.title=S.chatBinding?.larkAppId?o("workflow.detail.cancelTitle"):o("workflow.detail.cliCancelTitle",{runId:t}),ao(m,S),io(k,S),lo($,p,S,y),wo(g,S),go(l,S,H,q,{comments:j,statuses:F,resolving:W,onResolve:wn},{sessions:ee,pending:te,errors:he,onStart:fn,onEnd:mn},lt,dn)&&(lt=void 0),Fo(L,y),I.scrollTop=it,T.hidden=!h,b.textContent=o("workflow.detail.eventsLoaded",{loaded:y.length,total:E})}function Fe(){if(M!==null&&window.clearTimeout(M),S&&ke.has(S.run.status)){M=null;return}M=window.setTimeout(async()=>{await Ee(),A||Fe()},eo)}function ut(){document.hidden||Ee().then(()=>{!A&&M===null&&Fe()})}return T.addEventListener("click",()=>{un()}),f.addEventListener("click",()=>{pn()}),document.addEventListener("visibilitychange",ut),cn().then(()=>{G(null),A||Fe()}).catch(v=>{G(v?.message??String(v)),s.textContent=o("workflow.detail.loadFailed")}),()=>{A=!0,M!==null&&window.clearTimeout(M),document.removeEventListener("visibilitychange",ut)}}function ao(e,t){let n=t.run,s=[[o("workflow.summary.workflow"),c(n.workflowId??"?")],[o("workflow.summary.status"),ne(n.status)],[o("workflow.summary.lastSeq"),String(t.lastSeq)],[o("workflow.summary.updated"),c(new Date(t.updatedAt).toLocaleString())],[o("workflow.summary.revision"),c(Ne(n.revisionId))],[o("workflow.summary.initiator"),c(n.initiator??"-")]];n.failedNodeId&&s.push([o("workflow.summary.failedNode"),c(n.failedNodeId)]),n.cancelOriginEventId&&s.push([o("workflow.summary.cancelOrigin"),c(n.cancelOriginEventId)]),t.chatBinding&&(s.push([o("workflow.summary.chat"),`<code>${c(t.chatBinding.chatId)}</code>`]),s.push([o("workflow.summary.app"),`<code>${c(t.chatBinding.larkAppId)}</code>`])),e.innerHTML=s.map(([a,r])=>`<div class="wf-summary-item"><span>${a}</span><strong>${r}</strong></div>`).join("")}function so(e){if(!e.errorCode)return"";let t=e.errorMessage?` \u2014 ${Jo(e.errorMessage,96)}`:"";return`<div class="wf-run-error">
687
+ `;let s=e.querySelector("#wf-detail-subtitle"),a=e.querySelector("#wf-detail-refresh"),r=e.querySelector("#wf-detail-error"),i=e.querySelector("#wf-cancel-status"),m=e.querySelector("#wf-summary"),y=e.querySelector("#wf-dangling-panel"),k=e.querySelector("#wf-parallel-view"),h=e.querySelector("#wf-parallel-meta"),u=e.querySelector("#wf-node-tbody"),l=e.querySelector("#wf-io-list"),$=e.querySelector(".wf-timeline-scroll"),L=e.querySelector("#wf-event-tbody"),v=e.querySelector("#wf-event-meta"),f=e.querySelector("#wf-cancel-run"),I=e.querySelector("#wf-load-older"),T=null,S=[],M=new Set,p=null,w=null,g=!1,E=0,H=null,C=!1,j=!1,U=!1,R=new Set,ae=new Map,ie=new Map,W=new Map,ke=new Set,J=new Map,B=new Set,q=new Map,N=new Map,P=0,z=n.focusAttemptId;function F(b){if(!b){r.hidden=!0,r.textContent="";return}r.hidden=!1,r.textContent=b}function V(b){if(!b){i.hidden=!0,i.textContent="";return}i.hidden=!1,i.textContent=b}async function le(){let b=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/snapshot`);if(b.status===404)throw new Error(o("workflow.detail.unknownRun"));if(!b.ok)throw new Error(o("workflow.detail.snapshotHttp",{status:b.status}));T=await b.json()}async function He(b){let G=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/events?${b}`);if(G.status===404)throw new Error(o("workflow.detail.unknownRun"));if(!G.ok)throw new Error(o("workflow.detail.eventsHttp",{status:G.status}));return await G.json()}function Ce(b,G){let D=b.filter(A=>M.has(A.eventId)?!1:(M.add(A.eventId),!0));D.length!==0&&(S=G==="prepend"?[...D,...S]:[...S,...D],S.sort((A,de)=>Ee(A.eventId)-Ee(de.eventId)))}async function dn(){await le();let b=await He(new URLSearchParams({tail:"100"}));S=[],M=new Set,Ce(b.events,"append"),p=b.oldestSeq,w=b.newestSeq,g=b.hasOlder,E=b.totalCount,ee()}async function Ae(){if(!(C||j||document.hidden)){j=!0;try{if(await le(),w!==null){let b=await He(new URLSearchParams({afterSeq:String(w),limit:"200"}));Ce(b.events,"append"),b.newestSeq!==null&&(w=b.newestSeq),p===null&&b.oldestSeq!==null&&(p=b.oldestSeq),E=b.totalCount}else{let b=await He(new URLSearchParams({tail:"1"}));Ce(b.events,"append"),p=b.oldestSeq,w=b.newestSeq,g=b.hasOlder,E=b.totalCount}F(null),ee()}catch(b){F(b?.message??String(b))}finally{j=!1}}}async function cn(){if(!(p===null||!g)){I.disabled=!0;try{let b=await He(new URLSearchParams({beforeSeq:String(p),limit:"100"}));Ce(b.events,"prepend"),b.oldestSeq!==null&&(p=b.oldestSeq),g=b.hasOlder,E=b.totalCount,F(null),ee()}catch(b){F(b?.message??String(b))}finally{I.disabled=!1}}}async function un(){if(!T||Le.has(T.run.status)||U)return;if(!T.chatBinding?.larkAppId){F(o("workflow.detail.cancelUnavailable",{runId:t}));return}let b=ro(T),G=o("workflow.detail.cancelConfirm",{runId:t,...b});if(window.confirm(G)){U=!0,f.disabled=!0;try{let D=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/cancel`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"cancelled via dashboard"})});if(D.status===401)throw new Error(o("workflow.detail.writeAccessCancel"));let A=await D.json().catch(()=>({}));if(!D.ok||!A.ok)throw new Error(A.hint??A.error??o("workflow.detail.cancelHttp",{status:D.status}));V(A.pending?o("workflow.detail.cancelPending"):null),F(null),await Ae()}catch(D){F(D?.message??String(D))}finally{U=!1,f.disabled=!1,ee()}}}async function pn(b,G){if(!B.has(b)){B.add(b),q.delete(b),ee();try{let D=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/attempts/${encodeURIComponent(G)}/${encodeURIComponent(b)}/resume`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});if(D.status===401)throw new Error(o("workflow.detail.writeAccessResume"));let A=await D.json().catch(()=>({}));if(!D.ok||!A.ok||!A.resumeId||!A.url)throw new Error(A.hint??A.message??A.error??o("workflow.detail.resumeStartFailed",{status:D.status}));J.set(b,{resumeId:A.resumeId,url:A.url})}catch(D){let A=D?.message??String(D);q.set(b,A)}finally{B.delete(b),ee()}}}async function fn(b,G){if(!B.has(b)){B.add(b),q.delete(b),ee();try{let D=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/attempts/${encodeURIComponent(G)}/${encodeURIComponent(b)}/resume/end`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"ended_by_dashboard"})});if(D.status===401)throw new Error(o("workflow.detail.writeAccessResume"));let A=await D.json().catch(()=>({}));if(!D.ok||!A.ok)if(A.error==="resume_not_running")J.delete(b);else throw new Error(A.hint??A.message??A.error??o("workflow.detail.resumeEndFailed",{status:D.status}));else J.delete(b)}catch(D){let A=D?.message??String(D);q.set(b,A)}finally{B.delete(b),ee()}}}async function mn(b,G){if(!ke.has(b)){ke.add(b),W.delete(b),ee();try{let D=ie.get(b)?.trim()||void 0,A=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/${G}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({comment:D})});if(A.status===401)throw new Error(o("workflow.detail.writeAccessApproval"));let de=await A.json().catch(()=>({}));if(!A.ok||!de.ok)throw new Error(de.hint??de.message??de.error??o("workflow.detail.actionHttp",{action:G,status:A.status}));let Ke=G==="approve"?o("workflow.detail.approved"):o("workflow.detail.rejected");W.set(b,{kind:"ok",text:de.alreadyTerminal?o("workflow.detail.alreadyTerminal",{label:Ke}):de.pending?o("workflow.detail.workflowContinue",{label:Ke}):o("workflow.detail.workflowRefreshing",{label:Ke})}),F(null),await Ae()}catch(D){let A=D?.message??String(D);W.set(b,{kind:"error",text:A}),F(A)}finally{ke.delete(b),ee()}}}function ee(){if(!T)return;P=$.scrollTop;let b=T.run;Le.has(b.status)&&V(null),s.innerHTML=`${c(b.workflowId??"?")} \xB7 ${re(b.status)} \xB7 lastSeq ${T.lastSeq}`,a.textContent=o("workflow.detail.refreshed",{time:new Date().toLocaleTimeString()}),f.hidden=Le.has(b.status),f.disabled=U||!T.chatBinding?.larkAppId,f.textContent=T.chatBinding?.larkAppId?o("workflow.detail.cancel"):o("workflow.detail.cliCancelOnly"),f.title=T.chatBinding?.larkAppId?o("workflow.detail.cancelTitle"):o("workflow.detail.cliCancelTitle",{runId:t}),ao(m,T),io(y,T),lo(k,h,T,S),wo(u,T),go(l,T,R,ae,{comments:ie,statuses:W,resolving:ke,onResolve:mn},{sessions:J,pending:B,errors:q,onStart:pn,onEnd:fn},z,N)&&(z=void 0),Fo(L,S),$.scrollTop=P,I.hidden=!g,v.textContent=o("workflow.detail.eventsLoaded",{loaded:S.length,total:E})}function Ge(){if(H!==null&&window.clearTimeout(H),T&&Le.has(T.run.status)){H=null;return}H=window.setTimeout(async()=>{await Ae(),C||Ge()},eo)}function pt(){document.hidden||Ae().then(()=>{!C&&H===null&&Ge()})}return I.addEventListener("click",()=>{cn()}),f.addEventListener("click",()=>{un()}),document.addEventListener("visibilitychange",pt),dn().then(()=>{F(null),C||Ge()}).catch(b=>{F(b?.message??String(b)),s.textContent=o("workflow.detail.loadFailed")}),()=>{C=!0,H!==null&&window.clearTimeout(H),document.removeEventListener("visibilitychange",pt)}}function ao(e,t){let n=t.run,s=[[o("workflow.summary.workflow"),c(n.workflowId??"?")],[o("workflow.summary.status"),re(n.status)],[o("workflow.summary.lastSeq"),String(t.lastSeq)],[o("workflow.summary.updated"),c(new Date(t.updatedAt).toLocaleString())],[o("workflow.summary.revision"),c(ze(n.revisionId))],[o("workflow.summary.initiator"),c(n.initiator??"-")]];n.failedNodeId&&s.push([o("workflow.summary.failedNode"),c(n.failedNodeId)]),n.cancelOriginEventId&&s.push([o("workflow.summary.cancelOrigin"),c(n.cancelOriginEventId)]),t.chatBinding&&(s.push([o("workflow.summary.chat"),`<code>${c(t.chatBinding.chatId)}</code>`]),s.push([o("workflow.summary.app"),`<code>${c(t.chatBinding.larkAppId)}</code>`])),e.innerHTML=s.map(([a,r])=>`<div class="wf-summary-item"><span>${a}</span><strong>${r}</strong></div>`).join("")}function so(e){if(!e.errorCode)return"";let t=e.errorMessage?` \u2014 ${Jo(e.errorMessage,96)}`:"";return`<div class="wf-run-error">
676
688
  <span class="muted error">${c(e.errorCode)}</span>${c(t)}
677
689
  </div>`}function ro(e){let t=e.dangling;return{total:new Set([...t.activities,...t.effectAttempted,...t.waits,...t.cancels]).size,effects:t.effectAttempted.length,activities:t.activities.length,waits:t.waits.length,cancels:t.cancels.length}}function io(e,t){let n=t.dangling,s=[[o("workflow.dangling.activities"),n.activities],[o("workflow.dangling.effects"),n.effectAttempted],[o("workflow.dangling.waits"),n.waits],[o("workflow.dangling.cancels"),n.cancels]],a=new Set(s.flatMap(([,r])=>r)).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>${c(o("workflow.detail.dangling"))}</h3></div><div class="muted">${c(o("workflow.detail.noDangling"))}</div>`;return}e.innerHTML=`<div class="wf-panel-title"><h3>${c(o("workflow.detail.dangling"))}</h3><span class="wf-dangling has">${a}</span></div>
678
690
  <div class="wf-dangling-grid">
679
691
  ${s.map(([r,i])=>`<div><strong>${r}</strong>${i.length===0?`<div class="muted">${c(o("workflow.detail.none"))}</div>`:`<ul>${i.map(m=>`<li><code>${c(m)}</code></li>`).join("")}</ul>`}</div>`).join("")}
680
- </div>`}function lo(e,t,n,s){let a=co(s,n);if(a.length===0){t.textContent="",e.innerHTML=`<div class="empty">${c(o("workflow.detail.noParallelData"))}</div>`;return}let r=Date.now(),i=Math.min(...a.map(l=>l.startedAt)),m=Math.max(...a.map(l=>l.endedAt??r),i+1e3),k=Math.max(1,m-i),$=po(a,r),p=a.filter(l=>!l.endedAt&&(l.status==="running"||l.status==="effectAttempting")).length;t.textContent=o("workflow.detail.parallelMeta",{count:a.length,max:$,running:p});let g=a.sort((l,I)=>l.startedAt-I.startedAt||l.activityId.localeCompare(I.activityId)).map(l=>uo(l,i,k,r)).join("");e.innerHTML=`<div class="wf-parallel-axis">
681
- <span title="${c(new Date(i).toISOString())}">${c(Pe(i))}</span>
682
- <span title="${c(new Date(m).toISOString())}">${c(Pe(m))}</span>
692
+ </div>`}function lo(e,t,n,s){let a=co(s,n);if(a.length===0){t.textContent="",e.innerHTML=`<div class="empty">${c(o("workflow.detail.noParallelData"))}</div>`;return}let r=Date.now(),i=Math.min(...a.map(l=>l.startedAt)),m=Math.max(...a.map(l=>l.endedAt??r),i+1e3),y=Math.max(1,m-i),k=po(a,r),h=a.filter(l=>!l.endedAt&&(l.status==="running"||l.status==="effectAttempting")).length;t.textContent=o("workflow.detail.parallelMeta",{count:a.length,max:k,running:h});let u=a.sort((l,$)=>l.startedAt-$.startedAt||l.activityId.localeCompare($.activityId)).map(l=>uo(l,i,y,r)).join("");e.innerHTML=`<div class="wf-parallel-axis">
693
+ <span title="${c(new Date(i).toISOString())}">${c(_e(i))}</span>
694
+ <span title="${c(new Date(m).toISOString())}">${c(_e(m))}</span>
683
695
  </div>
684
- <div class="wf-parallel-list">${g}</div>`}function co(e,t){let n=new Map,s=new Map(t.activities.map(a=>[a.activityId,a.ownerNodeId]));for(let a of[...e].sort((r,i)=>$e(r.eventId)-$e(i.eventId))){let r=Wo(a);if(!r)continue;let i=typeof r.activityId=="string"?r.activityId:void 0,m=typeof r.attemptId=="string"?r.attemptId:void 0;if(!i||!m)continue;let k=n.get(m);if(a.type==="attemptCreated"){let $=typeof r.attemptNumber=="number"?r.attemptNumber:void 0;k={nodeId:typeof r.nodeId=="string"?r.nodeId:s.get(i),activityId:i,attemptId:m,attemptNumber:$,status:"pending",startedAt:a.timestamp},n.set(m,k);continue}k||(k={nodeId:s.get(i),activityId:i,attemptId:m,status:"pending",startedAt:a.timestamp},n.set(m,k)),a.type==="activityRunning"?(k.status="running",k.runningAt=a.timestamp):a.type==="effectAttempted"?k.status="effectAttempting":a.type==="activityWaiting"||a.type==="waitCreated"?k.status="waiting":fo(a.type)&&(k.status=mo(a.type),k.endedAt=a.timestamp,k.endType=a.type)}return[...n.values()]}function uo(e,t,n,s){let a=e.endedAt??s,r=zt((e.startedAt-t)/n*100,0,100),i=zt((Math.max(a,e.startedAt+1)-e.startedAt)/n*100,.7,100-r),m=e.nodeId??e.activityId,k=e.attemptNumber!==void 0?`#${e.attemptNumber}`:Ne(e.attemptId),$=[`${m} ${e.status}`,`${new Date(e.startedAt).toISOString()} \u2192 ${e.endedAt?new Date(e.endedAt).toISOString():o("workflow.detail.parallelNow")}`,e.endType?`end: ${e.endType}`:void 0].filter(Boolean).join(`
696
+ <div class="wf-parallel-list">${u}</div>`}function co(e,t){let n=new Map,s=new Map(t.activities.map(a=>[a.activityId,a.ownerNodeId]));for(let a of[...e].sort((r,i)=>Ee(r.eventId)-Ee(i.eventId))){let r=Wo(a);if(!r)continue;let i=typeof r.activityId=="string"?r.activityId:void 0,m=typeof r.attemptId=="string"?r.attemptId:void 0;if(!i||!m)continue;let y=n.get(m);if(a.type==="attemptCreated"){let k=typeof r.attemptNumber=="number"?r.attemptNumber:void 0;y={nodeId:typeof r.nodeId=="string"?r.nodeId:s.get(i),activityId:i,attemptId:m,attemptNumber:k,status:"pending",startedAt:a.timestamp},n.set(m,y);continue}y||(y={nodeId:s.get(i),activityId:i,attemptId:m,status:"pending",startedAt:a.timestamp},n.set(m,y)),a.type==="activityRunning"?(y.status="running",y.runningAt=a.timestamp):a.type==="effectAttempted"?y.status="effectAttempting":a.type==="activityWaiting"||a.type==="waitCreated"?y.status="waiting":fo(a.type)&&(y.status=mo(a.type),y.endedAt=a.timestamp,y.endType=a.type)}return[...n.values()]}function uo(e,t,n,s){let a=e.endedAt??s,r=zt((e.startedAt-t)/n*100,0,100),i=zt((Math.max(a,e.startedAt+1)-e.startedAt)/n*100,.7,100-r),m=e.nodeId??e.activityId,y=e.attemptNumber!==void 0?`#${e.attemptNumber}`:ze(e.attemptId),k=[`${m} ${e.status}`,`${new Date(e.startedAt).toISOString()} \u2192 ${e.endedAt?new Date(e.endedAt).toISOString():o("workflow.detail.parallelNow")}`,e.endType?`end: ${e.endType}`:void 0].filter(Boolean).join(`
685
697
  `);return`<div class="wf-parallel-row">
686
698
  <div class="wf-parallel-label">
687
699
  <code>${c(m)}</code>
688
- <span class="muted">${c(e.activityId)} \xB7 ${c(k)}</span>
700
+ <span class="muted">${c(e.activityId)} \xB7 ${c(y)}</span>
689
701
  </div>
690
702
  <div class="wf-parallel-track">
691
- <div class="wf-parallel-bar wf-parallel-${c(e.status)}" style="left:${r.toFixed(3)}%;width:${i.toFixed(3)}%;" title="${c($)}">
692
- <span>${c(le(e.status))}</span>
703
+ <div class="wf-parallel-bar wf-parallel-${c(e.status)}" style="left:${r.toFixed(3)}%;width:${i.toFixed(3)}%;" title="${c(k)}">
704
+ <span>${c(fe(e.status))}</span>
693
705
  </div>
694
706
  </div>
695
707
  </div>`}function po(e,t){let n=[];for(let r of e)n.push({time:r.startedAt,delta:1}),n.push({time:r.endedAt??t,delta:-1});n.sort((r,i)=>r.time-i.time||i.delta-r.delta);let s=0,a=0;for(let r of n)s+=r.delta,a=Math.max(a,s);return a}function fo(e){return e==="activitySucceeded"||e==="activityFailed"||e==="activityTimedOut"||e==="activityCanceled"}function mo(e){return e==="activitySucceeded"?"succeeded":e==="activityCanceled"?"cancelled":e==="activityTimedOut"?"timedOut":"failed"}function wo(e,t){let n=new Map(t.activities.map(r=>[r.activityId,r])),s=new Set,a=[];for(let r of t.nodes){let i=(r.activityId?n.get(r.activityId):void 0)??t.activities.find(m=>m.ownerNodeId===r.nodeId);i&&s.add(i.activityId),a.push(Ft(r,i))}for(let r of t.activities)s.has(r.activityId)||a.push(Ft(void 0,r));e.innerHTML=a.length>0?a.join(""):`<tr><td colspan="7" class="empty">${c(o("workflow.detail.noNodes"))}</td></tr>`}function Ft(e,t){let n=t?.attempts[t.attempts.length-1];return`<tr>
696
708
  <td>${e?`<code>${c(e.nodeId)}</code>`:'<span class="muted">-</span>'}</td>
697
- <td>${e?ne(e.status):'<span class="muted">-</span>'}</td>
709
+ <td>${e?re(e.status):'<span class="muted">-</span>'}</td>
698
710
  <td>${t?`<code>${c(t.activityId)}</code>`:'<span class="muted">-</span>'}</td>
699
- <td>${t?ne(t.status):'<span class="muted">-</span>'}</td>
711
+ <td>${t?re(t.status):'<span class="muted">-</span>'}</td>
700
712
  <td>${t?.attempts.length??0}</td>
701
713
  <td>${n?`<code>${c(n.attemptId)}</code>`:'<span class="muted">-</span>'}</td>
702
714
  <td>${n?Uo(n):`<span class="muted">${c(o("workflow.detail.idle"))}</span>`}</td>
703
- </tr>`}function go(e,t,n,s,a,r,i,m){Bo(e,n,s),Ho(e,a.comments);let k=!!(i&&t.attemptIO?.[i]?.terminal);k&&i&&n.add(at(i,o("workflow.detail.liveTerminal")));let $=ho(t),p=new Set;if(m){for(let l of $){p.add(l.key);let I=m.get(l.key);I||(I=bo(l.key),m.set(l.key,I),e.appendChild(I.article)),yo(I,l,n,a,r,i)}for(let[l,I]of Array.from(m))p.has(l)||(I.article.remove(),m.delete(l));if($.length===0){if(!e.querySelector(".wf-io-empty-placeholder")){let l=document.createElement("div");l.className="empty wf-io-empty-placeholder",l.textContent=o("workflow.detail.noNodeIO"),e.appendChild(l)}}else e.querySelector(".wf-io-empty-placeholder")?.remove()}else{let l=[];for(let I of $)l.push(Io(I,n,a,r,i));e.innerHTML=l.length>0?l.join(""):`<div class="empty">${c(o("workflow.detail.noNodeIO"))}</div>`}qo(e,s);let g=Do(e,i);return Oo(e,n),Po(e,s),Ro(e,a),en(e,r),g&&k}function ho(e){let t=new Map(e.activities.map(a=>[a.activityId,a])),n=new Set,s=[];for(let a of e.nodes){let r=(a.activityId?t.get(a.activityId):void 0)??e.activities.find(i=>i.ownerNodeId===a.nodeId);if(!r){s.push({key:`node:${a.nodeId}`,node:a});continue}n.add(r.activityId),s.push({key:`activity:${r.activityId}`,node:a,activity:r,io:e.attemptIO?.[qe(r)?.attemptId??""]})}for(let a of e.activities)n.has(a.activityId)||s.push({key:`activity:${a.activityId}`,activity:a,io:e.attemptIO?.[qe(a)?.attemptId??""]});return s}function bo(e){let t=document.createElement("article");t.className="wf-io-card",t.dataset.wfCardKey=e;let n=document.createElement("div");n.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",t.appendChild(n),t.appendChild(s),t.appendChild(a),{article:t,head:n,terminalSlot:s,grid:a,currentTerminalUrl:null}}function yo(e,t,n,s,a,r){let i=qe(t.activity),m=t.node?.nodeId??t.activity?.ownerNodeId??t.activity?.activityId??"unknown",k=!!(i&&i.attemptId===r);e.article.classList.toggle("is-focused",k),i?e.article.dataset.wfAttemptCard=i.attemptId:delete e.article.dataset.wfAttemptCard;let $=Zt(i,s);e.head.innerHTML=`
715
+ </tr>`}function go(e,t,n,s,a,r,i,m){Bo(e,n,s),Co(e,a.comments);let y=!!(i&&t.attemptIO?.[i]?.terminal);y&&i&&n.add(dt(i,o("workflow.detail.liveTerminal")));let k=ho(t),h=new Set;if(m){for(let l of k){h.add(l.key);let $=m.get(l.key);$||($=bo(l.key),m.set(l.key,$),e.appendChild($.article)),yo($,l,n,a,r,i)}for(let[l,$]of Array.from(m))h.has(l)||($.article.remove(),m.delete(l));if(k.length===0){if(!e.querySelector(".wf-io-empty-placeholder")){let l=document.createElement("div");l.className="empty wf-io-empty-placeholder",l.textContent=o("workflow.detail.noNodeIO"),e.appendChild(l)}}else e.querySelector(".wf-io-empty-placeholder")?.remove()}else{let l=[];for(let $ of k)l.push(To($,n,a,r,i));e.innerHTML=l.length>0?l.join(""):`<div class="empty">${c(o("workflow.detail.noNodeIO"))}</div>`}Oo(e,s);let u=Do(e,i);return qo(e,n),Po(e,s),Ro(e,a),en(e,r),u&&y}function ho(e){let t=new Map(e.activities.map(a=>[a.activityId,a])),n=new Set,s=[];for(let a of e.nodes){let r=(a.activityId?t.get(a.activityId):void 0)??e.activities.find(i=>i.ownerNodeId===a.nodeId);if(!r){s.push({key:`node:${a.nodeId}`,node:a});continue}n.add(r.activityId),s.push({key:`activity:${r.activityId}`,node:a,activity:r,io:e.attemptIO?.[Fe(r)?.attemptId??""]})}for(let a of e.activities)n.has(a.activityId)||s.push({key:`activity:${a.activityId}`,activity:a,io:e.attemptIO?.[Fe(a)?.attemptId??""]});return s}function bo(e){let t=document.createElement("article");t.className="wf-io-card",t.dataset.wfCardKey=e;let n=document.createElement("div");n.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",t.appendChild(n),t.appendChild(s),t.appendChild(a),{article:t,head:n,terminalSlot:s,grid:a,currentTerminalUrl:null}}function yo(e,t,n,s,a,r){let i=Fe(t.activity),m=t.node?.nodeId??t.activity?.ownerNodeId??t.activity?.activityId??"unknown",y=!!(i&&i.attemptId===r);e.article.classList.toggle("is-focused",y),i?e.article.dataset.wfAttemptCard=i.attemptId:delete e.article.dataset.wfAttemptCard;let k=Zt(i,s);e.head.innerHTML=`
704
716
  <header>
705
717
  <div>
706
718
  <strong><code>${c(m)}</code></strong>
707
719
  <span class="muted">${t.activity?c(t.activity.activityId):c(o("workflow.detail.notDispatched"))}</span>
708
720
  </div>
709
- <div>${t.node?ne(t.node.status):""} ${t.activity?ne(t.activity.status):""}</div>
721
+ <div>${t.node?re(t.node.status):""} ${t.activity?re(t.activity.status):""}</div>
710
722
  </header>
711
723
  <div class="wf-io-meta">
712
724
  ${i?`${c(o("workflow.detail.attempt"))} <code>${c(i.attemptId)}</code>`:c(o("workflow.detail.noAttempt"))}
713
725
  </div>
714
- ${$}
715
- `;let p=Jt(i,t.activity,t.io?.terminal,a),g=p?.url??null;if(g!==e.currentTerminalUrl)p===null?e.terminalSlot.innerHTML="":e.terminalSlot.innerHTML=Gt(t.key,i,t.activity,t.io?.terminal,p,n,a),e.currentTerminalUrl=g;else if(p!==null&&t.io?.terminal){let I=e.terminalSlot.querySelector("details.wf-terminal-block > summary");if(I){let L=Kt(p.kind);I.innerHTML=`${c(L)} ${Xt(i,t.io.terminal)}`}i&&Ao(e.terminalSlot,i,t.activity,t.io.terminal,p,a)}let l=i?.attemptId??t.activity?.activityId??t.node?.nodeId??"unknown";e.grid.innerHTML=`
716
- ${Z(l,o("workflow.detail.authoredInput"),t.io?.input,n)}
717
- ${Z(l,o("workflow.detail.resolvedInput"),t.io?.resolvedInput,n)}
718
- ${Z(l,o("workflow.detail.output"),t.io?.output,n)}
719
- ${Z(l,o("workflow.detail.executionLog"),t.io?.log,n)}
720
- ${t.io?.waitPrompt?Z(l,o("workflow.detail.waitPrompt"),t.io.waitPrompt,n):""}
721
- `}function Jt(e,t,n,s){if(!n||n.error)return null;if(To(e,n))return{kind:"live",url:Eo(n)};if(!e||!t||!Lo(e,n))return null;let a=xo();if(!a)return null;let r=s?.sessions.get(e.attemptId);return r?{kind:"resume",url:r.url,resumeId:r.resumeId,downloadUrl:_t(a,t.activityId,e.attemptId)}:{kind:"replay",url:Mo(a,t.activityId,e.attemptId,!!n.hasPtyLog),downloadUrl:_t(a,t.activityId,e.attemptId)}}function Gt(e,t,n,s,a,r,i){if(!s)return"";let m=Kt(a.kind),k=at(e,m),$=Xt(t,s),p=vo(a.kind),g=a.kind==="replay"||a.kind==="resume"?`<a class="btn-link" href="${c(a.downloadUrl)}" download>${c(o("workflow.detail.downloadFullLog"))}</a>`:"",l=t?Yt(t,n,s,a,i):"",I=t?Qt(t.attemptId,i):"";return`<details class="wf-io-block wf-terminal-block" data-io-key="${c(k)}"${r.has(k)?" open":""}>
722
- <summary>${c(m)} ${$}</summary>
726
+ ${k}
727
+ `;let h=Jt(i,t.activity,t.io?.terminal,a),u=h?.url??null;if(u!==e.currentTerminalUrl)h===null?e.terminalSlot.innerHTML="":e.terminalSlot.innerHTML=Gt(t.key,i,t.activity,t.io?.terminal,h,n,a),e.currentTerminalUrl=u;else if(h!==null&&t.io?.terminal){let $=e.terminalSlot.querySelector("details.wf-terminal-block > summary");if($){let L=Kt(h.kind);$.innerHTML=`${c(L)} ${Xt(i,t.io.terminal)}`}i&&Ao(e.terminalSlot,i,t.activity,t.io.terminal,h,a)}let l=i?.attemptId??t.activity?.activityId??t.node?.nodeId??"unknown";e.grid.innerHTML=`
728
+ ${oe(l,o("workflow.detail.authoredInput"),t.io?.input,n)}
729
+ ${oe(l,o("workflow.detail.resolvedInput"),t.io?.resolvedInput,n)}
730
+ ${oe(l,o("workflow.detail.output"),t.io?.output,n)}
731
+ ${oe(l,o("workflow.detail.executionLog"),t.io?.log,n)}
732
+ ${t.io?.waitPrompt?oe(l,o("workflow.detail.waitPrompt"),t.io.waitPrompt,n):""}
733
+ `}function Jt(e,t,n,s){if(!n||n.error)return null;if(Io(e,n))return{kind:"live",url:Eo(n)};if(!e||!t||!Lo(e,n))return null;let a=xo();if(!a)return null;let r=s?.sessions.get(e.attemptId);return r?{kind:"resume",url:r.url,resumeId:r.resumeId,downloadUrl:_t(a,t.activityId,e.attemptId)}:{kind:"replay",url:Mo(a,t.activityId,e.attemptId,!!n.hasPtyLog),downloadUrl:_t(a,t.activityId,e.attemptId)}}function Gt(e,t,n,s,a,r,i){if(!s)return"";let m=Kt(a.kind),y=dt(e,m),k=Xt(t,s),h=vo(a.kind),u=a.kind==="replay"||a.kind==="resume"?`<a class="btn-link" href="${c(a.downloadUrl)}" download>${c(o("workflow.detail.downloadFullLog"))}</a>`:"",l=t?Yt(t,n,s,a,i):"",$=t?Qt(t.attemptId,i):"";return`<details class="wf-io-block wf-terminal-block" data-io-key="${c(y)}"${r.has(y)?" open":""}>
734
+ <summary>${c(m)} ${k}</summary>
723
735
  <div class="wf-terminal-actions">
724
- <a class="btn-link" href="${c(a.url)}" target="_blank" rel="noreferrer">${c(p)}</a>
725
- ${g}
736
+ <a class="btn-link" href="${c(a.url)}" target="_blank" rel="noreferrer">${c(h)}</a>
737
+ ${u}
726
738
  ${l}
727
739
  </div>
728
- ${I}
740
+ ${$}
729
741
  <iframe class="wf-terminal-frame" src="${c(a.url)}" title="${c(m)}" loading="lazy"></iframe>
730
- </details>`}function Kt(e){return e==="live"?o("workflow.detail.liveTerminal"):e==="resume"?o("workflow.detail.terminalResume"):o("workflow.detail.terminalReplay")}function vo(e){return e==="live"?o("workflow.detail.openTerminalNewTab"):e==="resume"?o("workflow.detail.openResumeNewTab"):o("workflow.detail.openReplayNewTab")}var Vt=new Set(["antigravity","codex-app","cursor","mira"]),ko=new Set(["aiden","coco","claude-code","codex","mtr","hermes"]);function $o(e){return!!e&&(ko.has(e)||Vt.has(e))}function So(e){return!!e&&Vt.has(e)}function Yt(e,t,n,s,a){if(!a||s.kind==="live"||!t)return"";let r=s.kind==="resume",i=a.pending.has(e.attemptId),m=`data-wf-resume-attempt="${c(e.attemptId)}" data-wf-resume-activity="${c(t.activityId)}"`;return r?`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="end" ${m}${i?" disabled":""}>${c(i?o("workflow.detail.resumeEnding"):o("workflow.detail.endResumeSession"))}</button>`:$o(n.cliId)?So(n.cliId)&&!n.cliSessionId?`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${c(o("workflow.detail.resumeMissingCliSession"))}">${c(o("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="start" ${m}${i?" disabled":""}>${c(i?o("workflow.detail.resumeStarting"):o("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${c(o("workflow.detail.resumeUnsupportedCli",{cliId:n.cliId??"?"}))}">${c(o("workflow.detail.resumeSession"))}</button>`}function Qt(e,t){if(!t)return"";let n=t.errors.get(e);return n?`<div class="hint-warn wf-resume-status" data-wf-resume-status="${c(e)}">${c(n)}</div>`:""}function Io(e,t,n,s,a){let r=qe(e.activity),i=e.node?.nodeId??e.activity?.ownerNodeId??e.activity?.activityId??"unknown",m=r?.attemptId??e.activity?.activityId??e.node?.nodeId??"unknown",k=Zt(r,n),$=r?.attemptId===a?" is-focused":"",p=r?` data-wf-attempt-card="${c(r.attemptId)}"`:"",g=Jt(r,e.activity,e.io?.terminal,s),l=g?Gt(m,r,e.activity,e.io?.terminal,g,t,s):"";return`<article class="wf-io-card${$}" data-wf-card-key="${c(e.key)}"${p}>
742
+ </details>`}function Kt(e){return e==="live"?o("workflow.detail.liveTerminal"):e==="resume"?o("workflow.detail.terminalResume"):o("workflow.detail.terminalReplay")}function vo(e){return e==="live"?o("workflow.detail.openTerminalNewTab"):e==="resume"?o("workflow.detail.openResumeNewTab"):o("workflow.detail.openReplayNewTab")}var Vt=new Set(["antigravity","codex-app","cursor","mira"]),ko=new Set(["aiden","coco","claude-code","codex","mtr","hermes"]);function $o(e){return!!e&&(ko.has(e)||Vt.has(e))}function So(e){return!!e&&Vt.has(e)}function Yt(e,t,n,s,a){if(!a||s.kind==="live"||!t)return"";let r=s.kind==="resume",i=a.pending.has(e.attemptId),m=`data-wf-resume-attempt="${c(e.attemptId)}" data-wf-resume-activity="${c(t.activityId)}"`;return r?`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="end" ${m}${i?" disabled":""}>${c(i?o("workflow.detail.resumeEnding"):o("workflow.detail.endResumeSession"))}</button>`:$o(n.cliId)?So(n.cliId)&&!n.cliSessionId?`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${c(o("workflow.detail.resumeMissingCliSession"))}">${c(o("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="start" ${m}${i?" disabled":""}>${c(i?o("workflow.detail.resumeStarting"):o("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${c(o("workflow.detail.resumeUnsupportedCli",{cliId:n.cliId??"?"}))}">${c(o("workflow.detail.resumeSession"))}</button>`}function Qt(e,t){if(!t)return"";let n=t.errors.get(e);return n?`<div class="hint-warn wf-resume-status" data-wf-resume-status="${c(e)}">${c(n)}</div>`:""}function To(e,t,n,s,a){let r=Fe(e.activity),i=e.node?.nodeId??e.activity?.ownerNodeId??e.activity?.activityId??"unknown",m=r?.attemptId??e.activity?.activityId??e.node?.nodeId??"unknown",y=Zt(r,n),k=r?.attemptId===a?" is-focused":"",h=r?` data-wf-attempt-card="${c(r.attemptId)}"`:"",u=Jt(r,e.activity,e.io?.terminal,s),l=u?Gt(m,r,e.activity,e.io?.terminal,u,t,s):"";return`<article class="wf-io-card${k}" data-wf-card-key="${c(e.key)}"${h}>
731
743
  <div class="wf-io-card-head">
732
744
  <header>
733
745
  <div>
734
746
  <strong><code>${c(i)}</code></strong>
735
747
  <span class="muted">${e.activity?c(e.activity.activityId):c(o("workflow.detail.notDispatched"))}</span>
736
748
  </div>
737
- <div>${e.node?ne(e.node.status):""} ${e.activity?ne(e.activity.status):""}</div>
749
+ <div>${e.node?re(e.node.status):""} ${e.activity?re(e.activity.status):""}</div>
738
750
  </header>
739
751
  <div class="wf-io-meta">
740
752
  ${r?`${c(o("workflow.detail.attempt"))} <code>${c(r.attemptId)}</code>`:c(o("workflow.detail.noAttempt"))}
741
753
  </div>
742
- ${k}
754
+ ${y}
743
755
  </div>
744
756
  <div class="wf-io-terminal-slot">${l}</div>
745
757
  <div class="wf-io-grid">
746
- ${Z(m,o("workflow.detail.authoredInput"),e.io?.input,t)}
747
- ${Z(m,o("workflow.detail.resolvedInput"),e.io?.resolvedInput,t)}
748
- ${Z(m,o("workflow.detail.output"),e.io?.output,t)}
749
- ${Z(m,o("workflow.detail.executionLog"),e.io?.log,t)}
750
- ${e.io?.waitPrompt?Z(m,o("workflow.detail.waitPrompt"),e.io.waitPrompt,t):""}
758
+ ${oe(m,o("workflow.detail.authoredInput"),e.io?.input,t)}
759
+ ${oe(m,o("workflow.detail.resolvedInput"),e.io?.resolvedInput,t)}
760
+ ${oe(m,o("workflow.detail.output"),e.io?.output,t)}
761
+ ${oe(m,o("workflow.detail.executionLog"),e.io?.log,t)}
762
+ ${e.io?.waitPrompt?oe(m,o("workflow.detail.waitPrompt"),e.io.waitPrompt,t):""}
751
763
  </div>
752
- </article>`}function qe(e){return e?.attempts[e.attempts.length-1]}function Xt(e,t){let n=[];return t.error?n.push(o("workflow.detail.error")):n.push(t.status==="live"?o("workflow.detail.terminalLive"):o("workflow.detail.terminalClosedShort")),e?.status&&n.push(e.status),t.webPort>0&&n.push(`:${t.webPort}`),`<span class="muted">${c(n.join(" \xB7 "))}</span>`}function To(e,t){return t.status==="live"&&t.webPort>0&&(e?.status==="pending"||e?.status==="running"||e?.status==="effectAttempting")}function Lo(e,t){return e.status==="succeeded"||e.status==="failed"||e.status==="cancelled"||e.status==="timedOut"?!!(t.sessionId||t.startedAt):!1}function Eo(e){return`http://${window.location.hostname||"127.0.0.1"}:${e.webPort}`}function Mo(e,t,n,s){let a=new URLSearchParams({runId:e,activityId:t,attemptId:n});return s&&a.set("hasPtyLog","1"),`/assets/terminal-replay.html?${a.toString()}`}function _t(e,t,n){return`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(t)}/${encodeURIComponent(n)}/terminal-log/raw?download=1`}function xo(){let e=window.location.hash.match(/^#\/workflows\/([^/?#]+)/);if(!e)return null;try{return decodeURIComponent(e[1])}catch{return null}}function Zt(e,t){if(!Co(e))return"";let n=e.attemptId,s=t.comments.get(n)??"",a=t.resolving.has(n),r=t.statuses.get(n),i=r?.kind==="error"?"hint-warn":"hint-ok";return`<div class="wf-approval-box" data-wf-approval="${c(n)}">
764
+ </article>`}function Fe(e){return e?.attempts[e.attempts.length-1]}function Xt(e,t){let n=[];return t.error?n.push(o("workflow.detail.error")):n.push(t.status==="live"?o("workflow.detail.terminalLive"):o("workflow.detail.terminalClosedShort")),e?.status&&n.push(e.status),t.webPort>0&&n.push(`:${t.webPort}`),`<span class="muted">${c(n.join(" \xB7 "))}</span>`}function Io(e,t){return t.status==="live"&&t.webPort>0&&(e?.status==="pending"||e?.status==="running"||e?.status==="effectAttempting")}function Lo(e,t){return e.status==="succeeded"||e.status==="failed"||e.status==="cancelled"||e.status==="timedOut"?!!(t.sessionId||t.startedAt):!1}function Eo(e){return`http://${window.location.hostname||"127.0.0.1"}:${e.webPort}`}function Mo(e,t,n,s){let a=new URLSearchParams({runId:e,activityId:t,attemptId:n});return s&&a.set("hasPtyLog","1"),`/assets/terminal-replay.html?${a.toString()}`}function _t(e,t,n){return`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(t)}/${encodeURIComponent(n)}/terminal-log/raw?download=1`}function xo(){let e=window.location.hash.match(/^#\/workflows\/([^/?#]+)/);if(!e)return null;try{return decodeURIComponent(e[1])}catch{return null}}function Zt(e,t){if(!Ho(e))return"";let n=e.attemptId,s=t.comments.get(n)??"",a=t.resolving.has(n),r=t.statuses.get(n),i=r?.kind==="error"?"hint-warn":"hint-ok";return`<div class="wf-approval-box" data-wf-approval="${c(n)}">
753
765
  <label>
754
766
  <span>${c(o("workflow.detail.approvalComment"))}</span>
755
767
  <textarea class="wf-approval-comment" data-wf-approval-comment="${c(n)}" rows="2" placeholder="${c(o("workflow.detail.optionalComment"))}"${a?" disabled":""}>${c(s)}</textarea>
@@ -760,18 +772,18 @@ ${Bt("manage")}
760
772
  ${a?`<span class="muted">${c(o("workflow.detail.submitting"))}</span>`:""}
761
773
  </div>
762
774
  ${r?`<div class="${i} wf-approval-status">${c(r.text)}</div>`:""}
763
- </div>`}function Co(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function Ho(e,t){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(n=>{let s=n.dataset.wfApprovalComment;s&&t.set(s,n.value)})}function en(e,t){e.querySelectorAll("button[data-wf-resume-action][data-wf-resume-attempt][data-wf-resume-activity]").forEach(n=>{n.dataset.wfResumeBound!=="1"&&(n.dataset.wfResumeBound="1",n.addEventListener("click",()=>{let s=n.dataset.wfResumeAttempt,a=n.dataset.wfResumeActivity,r=n.dataset.wfResumeAction;!s||!a||(r==="start"?t.onStart(s,a):r==="end"&&t.onEnd(s,a))}))})}function Ao(e,t,n,s,a,r){let i=e.querySelector(".wf-terminal-actions");if(!i)return;let m=i.querySelector('button[data-wf-resume-button="1"]'),k=Yt(t,n,s,a,r);m?m.outerHTML=k:k&&i.insertAdjacentHTML("beforeend",k);let $=e.querySelector("details.wf-terminal-block");if($){let p=$.querySelector(".wf-resume-status"),g=Qt(t.attemptId,r);p?p.outerHTML=g:g&&i.insertAdjacentHTML("afterend",g)}en(e,r)}function Ro(e,t){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(n=>{let s=n.dataset.wfApprovalComment;s&&n.addEventListener("input",()=>{t.comments.set(s,n.value)})}),e.querySelectorAll("button[data-wf-approval-action][data-wf-attempt-id]").forEach(n=>{n.addEventListener("click",()=>{let s=n.dataset.wfAttemptId,a=n.dataset.wfApprovalAction;!s||a!=="approve"&&a!=="reject"||t.onResolve(s,a)})})}function Z(e,t,n,s){let a=at(e,t);return`<details class="wf-io-block" data-io-key="${c(a)}"${s.has(a)?" open":""}>
775
+ </div>`}function Ho(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function Co(e,t){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(n=>{let s=n.dataset.wfApprovalComment;s&&t.set(s,n.value)})}function en(e,t){e.querySelectorAll("button[data-wf-resume-action][data-wf-resume-attempt][data-wf-resume-activity]").forEach(n=>{n.dataset.wfResumeBound!=="1"&&(n.dataset.wfResumeBound="1",n.addEventListener("click",()=>{let s=n.dataset.wfResumeAttempt,a=n.dataset.wfResumeActivity,r=n.dataset.wfResumeAction;!s||!a||(r==="start"?t.onStart(s,a):r==="end"&&t.onEnd(s,a))}))})}function Ao(e,t,n,s,a,r){let i=e.querySelector(".wf-terminal-actions");if(!i)return;let m=i.querySelector('button[data-wf-resume-button="1"]'),y=Yt(t,n,s,a,r);m?m.outerHTML=y:y&&i.insertAdjacentHTML("beforeend",y);let k=e.querySelector("details.wf-terminal-block");if(k){let h=k.querySelector(".wf-resume-status"),u=Qt(t.attemptId,r);h?h.outerHTML=u:u&&i.insertAdjacentHTML("afterend",u)}en(e,r)}function Ro(e,t){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(n=>{let s=n.dataset.wfApprovalComment;s&&n.addEventListener("input",()=>{t.comments.set(s,n.value)})}),e.querySelectorAll("button[data-wf-approval-action][data-wf-attempt-id]").forEach(n=>{n.addEventListener("click",()=>{let s=n.dataset.wfAttemptId,a=n.dataset.wfApprovalAction;!s||a!=="approve"&&a!=="reject"||t.onResolve(s,a)})})}function oe(e,t,n,s){let a=dt(e,t);return`<details class="wf-io-block" data-io-key="${c(a)}"${s.has(a)?" open":""}>
764
776
  <summary>${c(t)} ${No(n)}</summary>
765
777
  ${jo(n)}
766
- </details>`}function at(e,t){return`${e}:${t}`}function Do(e,t){if(!t)return!1;for(let n of e.querySelectorAll("[data-wf-attempt-card]"))if(n.dataset.wfAttemptCard===t)return n.scrollIntoView({block:"center"}),!0;return!1}function Bo(e,t,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(s=>{let a=s.dataset.ioKey;if(!a)return;s.open?t.add(a):t.delete(a);let r=s.querySelector(".wf-io-pre");r&&n.set(a,r.scrollTop)})}function Oo(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(n=>{n.dataset.ioToggleBound!=="1"&&(n.dataset.ioToggleBound="1",n.addEventListener("toggle",()=>{let s=n.dataset.ioKey;s&&(n.open?t.add(s):t.delete(s))}))})}function qo(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(n=>{let s=n.dataset.ioKey;if(!s)return;let a=t.get(s);if(a===void 0)return;let r=n.querySelector(".wf-io-pre");r&&(r.scrollTop=a)})}function Po(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(n=>{let s=n.dataset.ioKey;if(!s)return;let a=n.querySelector(".wf-io-pre");a&&a.dataset.ioScrollBound!=="1"&&(a.dataset.ioScrollBound="1",a.addEventListener("scroll",()=>{t.set(s,a.scrollTop)}))})}function No(e){if(!e)return`<span class="muted">${c(o("workflow.detail.empty"))}</span>`;let t=[];return e.outputBytes!==void 0&&t.push(`${e.outputBytes}B`),e.truncated&&t.push(o("workflow.detail.truncated")),e.error&&t.push(o("workflow.detail.error")),e.outputHash&&t.push(Ne(e.outputHash)),t.length?`<span class="muted">${c(t.join(" \xB7 "))}</span>`:""}function jo(e){if(!e)return`<div class="muted wf-io-empty">${c(o("workflow.detail.noData"))}</div>`;let t=e.value!==void 0?JSON.stringify(e.value,null,2):e.text??"",n=e.error?`<div class="muted error">${c(e.error)}</div>`:"";return t?`${n}<pre class="wf-io-pre">${c(t)}</pre>`:`${n}<div class="muted wf-io-empty">${c(o("workflow.detail.noPreview"))}</div>`}function Uo(e){let t=[];if(e.effectAttempted&&t.push(`${c(o("workflow.detail.effect"))} ${c(e.effectAttempted.provider)}`),e.wait){let n=e.wait.resolution?`${e.wait.resolution.kind}${e.wait.resolution.resolution?":"+e.wait.resolution.resolution:""}`:o("workflow.detail.open");t.push(`${c(o("workflow.detail.wait"))} ${c(e.wait.waitKind)} ${c(n)}`),e.wait.deadlineAt!==void 0&&t.push(`${c(o("workflow.detail.deadline"))} ${c(Pe(e.wait.deadlineAt))}`)}if(e.error){let n=`${e.error.errorCode}${e.error.errorClass?` \xB7 ${e.error.errorClass}`:""}`;t.push(`<span class="muted error">${c(n)}</span>`),e.error.errorMessage&&t.push(`<span class="error wf-error-msg">${c(e.error.errorMessage)}</span>`)}return e.output&&t.push(`${c(o("workflow.detail.output"))} ${c(Ne(e.output.outputHash))}`),e.runningMs!==void 0&&t.push(`${e.runningMs}ms`),t.length>0?t.join("<br/>"):'<span class="muted">-</span>'}function Fo(e,t){e.innerHTML=t.length>0?t.map(_o).join(""):`<tr><td colspan="7" class="empty">${c(o("workflow.detail.noEvents"))}</td></tr>`}function _o(e){let t=zo(e.payload);return`<tr>
767
- <td>${$e(e.eventId)}</td>
778
+ </details>`}function dt(e,t){return`${e}:${t}`}function Do(e,t){if(!t)return!1;for(let n of e.querySelectorAll("[data-wf-attempt-card]"))if(n.dataset.wfAttemptCard===t)return n.scrollIntoView({block:"center"}),!0;return!1}function Bo(e,t,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(s=>{let a=s.dataset.ioKey;if(!a)return;s.open?t.add(a):t.delete(a);let r=s.querySelector(".wf-io-pre");r&&n.set(a,r.scrollTop)})}function qo(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(n=>{n.dataset.ioToggleBound!=="1"&&(n.dataset.ioToggleBound="1",n.addEventListener("toggle",()=>{let s=n.dataset.ioKey;s&&(n.open?t.add(s):t.delete(s))}))})}function Oo(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(n=>{let s=n.dataset.ioKey;if(!s)return;let a=t.get(s);if(a===void 0)return;let r=n.querySelector(".wf-io-pre");r&&(r.scrollTop=a)})}function Po(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(n=>{let s=n.dataset.ioKey;if(!s)return;let a=n.querySelector(".wf-io-pre");a&&a.dataset.ioScrollBound!=="1"&&(a.dataset.ioScrollBound="1",a.addEventListener("scroll",()=>{t.set(s,a.scrollTop)}))})}function No(e){if(!e)return`<span class="muted">${c(o("workflow.detail.empty"))}</span>`;let t=[];return e.outputBytes!==void 0&&t.push(`${e.outputBytes}B`),e.truncated&&t.push(o("workflow.detail.truncated")),e.error&&t.push(o("workflow.detail.error")),e.outputHash&&t.push(ze(e.outputHash)),t.length?`<span class="muted">${c(t.join(" \xB7 "))}</span>`:""}function jo(e){if(!e)return`<div class="muted wf-io-empty">${c(o("workflow.detail.noData"))}</div>`;let t=e.value!==void 0?JSON.stringify(e.value,null,2):e.text??"",n=e.error?`<div class="muted error">${c(e.error)}</div>`:"";return t?`${n}<pre class="wf-io-pre">${c(t)}</pre>`:`${n}<div class="muted wf-io-empty">${c(o("workflow.detail.noPreview"))}</div>`}function Uo(e){let t=[];if(e.effectAttempted&&t.push(`${c(o("workflow.detail.effect"))} ${c(e.effectAttempted.provider)}`),e.wait){let n=e.wait.resolution?`${e.wait.resolution.kind}${e.wait.resolution.resolution?":"+e.wait.resolution.resolution:""}`:o("workflow.detail.open");t.push(`${c(o("workflow.detail.wait"))} ${c(e.wait.waitKind)} ${c(n)}`),e.wait.deadlineAt!==void 0&&t.push(`${c(o("workflow.detail.deadline"))} ${c(_e(e.wait.deadlineAt))}`)}if(e.error){let n=`${e.error.errorCode}${e.error.errorClass?` \xB7 ${e.error.errorClass}`:""}`;t.push(`<span class="muted error">${c(n)}</span>`),e.error.errorMessage&&t.push(`<span class="error wf-error-msg">${c(e.error.errorMessage)}</span>`)}return e.output&&t.push(`${c(o("workflow.detail.output"))} ${c(ze(e.output.outputHash))}`),e.runningMs!==void 0&&t.push(`${e.runningMs}ms`),t.length>0?t.join("<br/>"):'<span class="muted">-</span>'}function Fo(e,t){e.innerHTML=t.length>0?t.map(_o).join(""):`<tr><td colspan="7" class="empty">${c(o("workflow.detail.noEvents"))}</td></tr>`}function _o(e){let t=zo(e.payload);return`<tr>
779
+ <td>${Ee(e.eventId)}</td>
768
780
  <td><code>${c(e.type)}</code></td>
769
781
  <td>${c(e.actor)}</td>
770
782
  <td>${t.nodeId?`<code>${c(t.nodeId)}</code>`:"-"}</td>
771
783
  <td>${t.activityId?`<code>${c(t.activityId)}</code>`:"-"}</td>
772
784
  <td>${t.errorCode?`<span class="muted error">${c(t.errorCode)}</span>`:"-"}</td>
773
- <td title="${c(new Date(e.timestamp).toISOString())}">${c(Pe(e.timestamp))}</td>
774
- </tr>`}function $e(e){let t=e.lastIndexOf("-");if(t<0)return 0;let n=Number(e.slice(t+1));return Number.isFinite(n)?n:0}function zo(e){if(!e||typeof e!="object"||"ref"in e)return{};let t=e,n={};typeof t.nodeId=="string"&&(n.nodeId=t.nodeId),typeof t.activityId=="string"&&(n.activityId=t.activityId),typeof t.failedNodeId=="string"&&(n.nodeId=t.failedNodeId);let s=t.error;return s&&typeof s=="object"&&"errorCode"in s&&(n.errorCode=String(s.errorCode)),n}function Wo(e){return!e.payload||typeof e.payload!="object"||"ref"in e.payload?null:e.payload}function zt(e,t,n){return Math.min(n,Math.max(t,e))}function Ne(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function Jo(e,t){return e.length>t?e.slice(0,t-1)+"\u2026":e}function Pe(e){return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}function x(e){return e.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}function tn(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function nn(e){let t=location.hash.match(/^#\/(?:workflows\/catalog|workflows-catalog)\/([^/?#]+)$/);return t?Ko(e,decodeURIComponent(t[1])):Go(e)}function Go(e){e.innerHTML=`
785
+ <td title="${c(new Date(e.timestamp).toISOString())}">${c(_e(e.timestamp))}</td>
786
+ </tr>`}function Ee(e){let t=e.lastIndexOf("-");if(t<0)return 0;let n=Number(e.slice(t+1));return Number.isFinite(n)?n:0}function zo(e){if(!e||typeof e!="object"||"ref"in e)return{};let t=e,n={};typeof t.nodeId=="string"&&(n.nodeId=t.nodeId),typeof t.activityId=="string"&&(n.activityId=t.activityId),typeof t.failedNodeId=="string"&&(n.nodeId=t.failedNodeId);let s=t.error;return s&&typeof s=="object"&&"errorCode"in s&&(n.errorCode=String(s.errorCode)),n}function Wo(e){return!e.payload||typeof e.payload!="object"||"ref"in e.payload?null:e.payload}function zt(e,t,n){return Math.min(n,Math.max(t,e))}function ze(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function Jo(e,t){return e.length>t?e.slice(0,t-1)+"\u2026":e}function _e(e){return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}function x(e){return e.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}function tn(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function nn(e){let t=location.hash.match(/^#\/(?:workflows\/catalog|workflows-catalog)\/([^/?#]+)$/);return t?Ko(e,decodeURIComponent(t[1])):Go(e)}function Go(e){e.innerHTML=`
775
787
  <nav class="wf-subnav">
776
788
  <a href="#/workflows" data-i18n="workflow.subnav.runs">${x(o("workflow.subnav.runs"))}</a>
777
789
  <a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${x(o("workflow.subnav.catalog"))}</a>
@@ -800,7 +812,7 @@ ${Bt("manage")}
800
812
  <tbody id="catalog-tbody"></tbody>
801
813
  </table>
802
814
  </div>
803
- `;let t=e.querySelector("#catalog-tbody"),n=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),a=e.querySelector("#catalog-refresh"),r=[],i=null,m=!1;function k(){let g=(new FormData(s).get("q")??"").trim().toLowerCase();return g?r.filter(l=>l.workflowId.toLowerCase().includes(g)||l.path.toLowerCase().includes(g)):r}function $(){i?(n.textContent=o("catalog.loadFailed",{error:i}),n.classList.add("error")):(n.textContent=`${r.length}`,n.classList.remove("error"));let g=k();if(g.length===0){t.innerHTML=`<tr><td colspan="6" class="empty">${r.length===0?x(o("catalog.noDefinitions")):x(o("catalog.noFilterMatch"))}</td></tr>`;return}t.innerHTML=g.map(l=>`
815
+ `;let t=e.querySelector("#catalog-tbody"),n=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),a=e.querySelector("#catalog-refresh"),r=[],i=null,m=!1;function y(){let u=(new FormData(s).get("q")??"").trim().toLowerCase();return u?r.filter(l=>l.workflowId.toLowerCase().includes(u)||l.path.toLowerCase().includes(u)):r}function k(){i?(n.textContent=o("catalog.loadFailed",{error:i}),n.classList.add("error")):(n.textContent=`${r.length}`,n.classList.remove("error"));let u=y();if(u.length===0){t.innerHTML=`<tr><td colspan="6" class="empty">${r.length===0?x(o("catalog.noDefinitions")):x(o("catalog.noFilterMatch"))}</td></tr>`;return}t.innerHTML=u.map(l=>`
804
816
  <tr>
805
817
  <td><a href="#/workflows/catalog/${encodeURIComponent(l.workflowId)}"><code>${x(l.workflowId)}</code></a></td>
806
818
  <td>${l.version}</td>
@@ -809,7 +821,7 @@ ${Bt("manage")}
809
821
  <td><code>${x(tn(l.revisionId))}</code></td>
810
822
  <td><code>${x(l.path)}</code></td>
811
823
  </tr>
812
- `).join("")}async function p(){a.disabled=!0,n.textContent=o("catalog.loading");try{let g=await fetch("/api/workflows/definitions");if(!g.ok)throw new Error(`HTTP ${g.status}`);r=(await g.json()).definitions??[],i=null}catch(g){i=g?.message??String(g),r=[]}finally{a.disabled=!1,m||$()}}return s.addEventListener("input",$),a.addEventListener("click",()=>{p()}),p(),()=>{m=!0}}function Ko(e,t){e.innerHTML=`
824
+ `).join("")}async function h(){a.disabled=!0,n.textContent=o("catalog.loading");try{let u=await fetch("/api/workflows/definitions");if(!u.ok)throw new Error(`HTTP ${u.status}`);r=(await u.json()).definitions??[],i=null}catch(u){i=u?.message??String(u),r=[]}finally{a.disabled=!1,m||k()}}return s.addEventListener("input",k),a.addEventListener("click",()=>{h()}),h(),()=>{m=!0}}function Ko(e,t){e.innerHTML=`
813
825
  <div class="catalog-detail-head">
814
826
  <a class="btn-link" href="#/workflows/catalog">${x(o("catalog.back"))}</a>
815
827
  <div>
@@ -820,7 +832,7 @@ ${Bt("manage")}
820
832
  <section id="catalog-error" class="hint-warn" hidden></section>
821
833
  <section id="catalog-run-status" class="hint-ok" hidden></section>
822
834
  <div id="catalog-detail-body"></div>
823
- `;let n=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),a=e.querySelector("#catalog-run-status"),r=e.querySelector("#catalog-detail-body"),i=null,m=!1,k=!1;function $(f){s.hidden=!f,s.textContent=f??""}function p(f){a.hidden=!f,a.textContent=f??""}function g(f){let T={};for(let[S,y]of Object.entries(f??{}))"default"in y&&(T[S]=y.default);return T}function l(){if(!i)return;let f=i.definition;n.textContent=`${o("catalog.revision")} ${tn(i.revisionId)} \xB7 ${i.path}`;let T=JSON.stringify(g(f.params),null,2);r.innerHTML=`
835
+ `;let n=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),a=e.querySelector("#catalog-run-status"),r=e.querySelector("#catalog-detail-body"),i=null,m=!1,y=!1;function k(f){s.hidden=!f,s.textContent=f??""}function h(f){a.hidden=!f,a.textContent=f??""}function u(f){let I={};for(let[T,S]of Object.entries(f??{}))"default"in S&&(I[T]=S.default);return I}function l(){if(!i)return;let f=i.definition;n.textContent=`${o("catalog.revision")} ${tn(i.revisionId)} \xB7 ${i.path}`;let I=JSON.stringify(u(f.params),null,2);r.innerHTML=`
824
836
  <section class="wf-panel">
825
837
  <div class="wf-panel-title"><h3>${x(o("catalog.summary"))}</h3></div>
826
838
  <div class="wf-summary-grid">
@@ -836,7 +848,7 @@ ${Bt("manage")}
836
848
  <form id="catalog-run-form" class="catalog-run-form">
837
849
  <label>
838
850
  <span>${x(o("catalog.paramsJson"))}</span>
839
- <textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${x(o("catalog.paramsPlaceholder"))}">${x(T)}</textarea>
851
+ <textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${x(o("catalog.paramsPlaceholder"))}">${x(I)}</textarea>
840
852
  </label>
841
853
  <div class="catalog-chat-grid">
842
854
  <label>
@@ -863,7 +875,7 @@ ${Bt("manage")}
863
875
  <div class="wf-panel-title"><h3>${x(o("catalog.definitionJson"))}</h3></div>
864
876
  <pre class="wf-io-pre">${x(JSON.stringify(f,null,2))}</pre>
865
877
  </section>
866
- `,L()}async function I(){if(!i||k)return;let f=r.querySelector("#catalog-params"),T=r.querySelector("#catalog-chat-id"),S=r.querySelector("#catalog-lark-app-id"),y=r.querySelector("#catalog-run-btn"),C=r.querySelector("#catalog-param-errors"),u;try{if(u=JSON.parse(f.value||"{}"),!u||typeof u!="object"||Array.isArray(u))throw new Error(o("catalog.badParamsJson"))}catch(w){C.hidden=!1,C.innerHTML=`<div class="muted error">${x(w?.message??String(w))}</div>`;return}k=!0,y.disabled=!0,y.textContent=o("catalog.running"),C.hidden=!0,$(null),p(null);try{let w=await fetch(`/api/workflows/definitions/${encodeURIComponent(i.definition.workflowId)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({params:u,chatBinding:{chatId:T.value.trim(),larkAppId:S.value.trim()}})});if(w.status===401)throw new Error(o("catalog.writeAccess"));let h=await w.json().catch(()=>({}));if(!w.ok||!h.ok)throw h.issues?.length&&(C.hidden=!1,C.innerHTML=`<strong>${x(o("catalog.invalidParams"))}</strong><ul>${h.issues.map(E=>`<li>${x(o("catalog.issue",{path:E.path.length?E.path.join("."):"(root)",message:E.message}))}</li>`).join("")}</ul>`),new Error(h.hint??h.message??h.error??o("catalog.runHttp",{status:w.status}));p(o("catalog.runStarted")),h.runId&&(location.hash=`#/workflows/${encodeURIComponent(h.runId)}`)}catch(w){$(w?.message??String(w))}finally{k=!1,y.disabled=!1,y.textContent=o("catalog.run")}}function L(){r.querySelector("#catalog-run-form")?.addEventListener("submit",T=>{T.preventDefault(),I()})}async function b(){try{let f=await fetch(`/api/workflows/definitions/${encodeURIComponent(t)}`);if(f.status===404)throw new Error("unknown_workflow");if(!f.ok)throw new Error(`HTTP ${f.status}`);i=await f.json(),$(null),l()}catch(f){$(o("catalog.definitionLoadFailed",{error:f?.message??String(f)})),n.textContent=o("workflow.detail.loadFailed")}}return b().then(()=>{}),()=>{m=!0}}function Vo(e){let t=Object.entries(e??{});return t.length===0?`<div class="muted">${x(o("catalog.noParams"))}</div>`:`<div class="catalog-param-list">${t.map(([n,s])=>`
878
+ `,L()}async function $(){if(!i||y)return;let f=r.querySelector("#catalog-params"),I=r.querySelector("#catalog-chat-id"),T=r.querySelector("#catalog-lark-app-id"),S=r.querySelector("#catalog-run-btn"),M=r.querySelector("#catalog-param-errors"),p;try{if(p=JSON.parse(f.value||"{}"),!p||typeof p!="object"||Array.isArray(p))throw new Error(o("catalog.badParamsJson"))}catch(w){M.hidden=!1,M.innerHTML=`<div class="muted error">${x(w?.message??String(w))}</div>`;return}y=!0,S.disabled=!0,S.textContent=o("catalog.running"),M.hidden=!0,k(null),h(null);try{let w=await fetch(`/api/workflows/definitions/${encodeURIComponent(i.definition.workflowId)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({params:p,chatBinding:{chatId:I.value.trim(),larkAppId:T.value.trim()}})});if(w.status===401)throw new Error(o("catalog.writeAccess"));let g=await w.json().catch(()=>({}));if(!w.ok||!g.ok)throw g.issues?.length&&(M.hidden=!1,M.innerHTML=`<strong>${x(o("catalog.invalidParams"))}</strong><ul>${g.issues.map(E=>`<li>${x(o("catalog.issue",{path:E.path.length?E.path.join("."):"(root)",message:E.message}))}</li>`).join("")}</ul>`),new Error(g.hint??g.message??g.error??o("catalog.runHttp",{status:w.status}));h(o("catalog.runStarted")),g.runId&&(location.hash=`#/workflows/${encodeURIComponent(g.runId)}`)}catch(w){k(w?.message??String(w))}finally{y=!1,S.disabled=!1,S.textContent=o("catalog.run")}}function L(){r.querySelector("#catalog-run-form")?.addEventListener("submit",I=>{I.preventDefault(),$()})}async function v(){try{let f=await fetch(`/api/workflows/definitions/${encodeURIComponent(t)}`);if(f.status===404)throw new Error("unknown_workflow");if(!f.ok)throw new Error(`HTTP ${f.status}`);i=await f.json(),k(null),l()}catch(f){k(o("catalog.definitionLoadFailed",{error:f?.message??String(f)})),n.textContent=o("workflow.detail.loadFailed")}}return v().then(()=>{}),()=>{m=!0}}function Vo(e){let t=Object.entries(e??{});return t.length===0?`<div class="muted">${x(o("catalog.noParams"))}</div>`:`<div class="catalog-param-list">${t.map(([n,s])=>`
867
879
  <article class="catalog-param">
868
880
  <header>
869
881
  <code>${x(n)}</code>
@@ -873,7 +885,7 @@ ${Bt("manage")}
873
885
  ${s.description?`<div class="muted">${x(o("catalog.description"))}: ${x(s.description)}</div>`:""}
874
886
  ${"default"in s?`<pre class="wf-io-pre">${x(`${o("catalog.default")}: ${JSON.stringify(s.default,null,2)}`)}</pre>`:""}
875
887
  </article>
876
- `).join("")}</div>`}var pe=null,je=null;function Ue(){je!==null&&(window.clearInterval(je),je=null)}function on(){return pe||(pe=document.createElement("dialog"),pe.className="onboarding-dialog",document.body.appendChild(pe),pe.addEventListener("close",Ue),pe)}function Yo(e){return e.status==="waiting_for_scan"?o("botOnboarding.waiting"):e.status==="verifying"?o("botOnboarding.verifying"):e.status==="completed"?o("botOnboarding.completed"):e.status==="failed"?`${o("botOnboarding.failed")}: ${e.message??e.error??"unknown"}`:o("botOnboarding.starting")}function Se(e){let t=on(),n=e.qrDataUrl?`<div class="qr-card">
888
+ `).join("")}</div>`}var he=null,We=null;function Je(){We!==null&&(window.clearInterval(We),We=null)}function on(){return he||(he=document.createElement("dialog"),he.className="onboarding-dialog",document.body.appendChild(he),he.addEventListener("close",Je),he)}function Yo(e){return e.status==="waiting_for_scan"?o("botOnboarding.waiting"):e.status==="verifying"?o("botOnboarding.verifying"):e.status==="completed"?o("botOnboarding.completed"):e.status==="failed"?`${o("botOnboarding.failed")}: ${e.message??e.error??"unknown"}`:o("botOnboarding.starting")}function Me(e){let t=on(),n=e.qrDataUrl?`<div class="qr-card">
877
889
  <img class="qr-image" src="${e.qrDataUrl}" alt="${o("botOnboarding.qrAlt")}">
878
890
  ${e.qrUrl?`<a class="onboarding-link" href="${e.qrUrl}" target="_blank" rel="noopener">${o("botOnboarding.openLink")}</a>`:""}
879
891
  </div>`:"",s=e.appId?`<p><b>App ID:</b> <code>${e.appId}</code></p>`:"",a=e.status==="completed"?`<p class="hint-ok">${o("botOnboarding.restartHint")}</p>`:"";t.innerHTML=`<article>
@@ -886,4 +898,4 @@ ${Bt("manage")}
886
898
  ${s}
887
899
  ${a}
888
900
  <form method="dialog"><button>${o("botOnboarding.close")}</button></form>
889
- </article>`}async function Qo(e){let t=await fetch(`/api/bot-onboarding/${encodeURIComponent(e)}`),n=await t.json();if(!t.ok||!n?.job)throw new Error(n?.error??`http_${t.status}`);Se(n.job),(n.job.status==="completed"||n.job.status==="failed")&&Ue()}async function Xo(){Ue(),Se({id:"",status:"starting"});let e=on();e.open||e.showModal();try{let t=await fetch("/api/bot-onboarding/start",{method:"POST"}),n=await t.json();if(!t.ok||!n?.job?.id)throw new Error(n?.error??`http_${t.status}`);Se(n.job),je=window.setInterval(()=>{Qo(n.job.id).catch(s=>{Ue(),Se({id:n.job.id,status:"failed",message:s instanceof Error?s.message:String(s)})})},1200)}catch(t){Se({id:"",status:"failed",message:t instanceof Error?t.message:String(t)})}}function an(){let e=document.getElementById("add-bot-btn");e&&(e.onclick=()=>{Xo()})}var V=document.getElementById("root"),sn=!1;function Zo(){if(sn)return;sn=!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(--card,#fff);color:var(--text,#1f2329);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">\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\u3002<br>\u6700\u597D\u5173\u95ED\u5F53\u524D\u9875\u3002</p><button onclick="window.close()" style="padding:8px 22px;background:var(--accent,#3370ff);color:#fff;border:none;border-radius:8px;cursor:pointer;font-size:14px">\u5173\u95ED\u6B64\u9875</button></div>',document.body.appendChild(e)}var ea=window.fetch.bind(window);window.fetch=async function(...t){let n=await ea(...t);return n.status===401&&Zo(),n};var Ie=null;function st(){Ie&&(Ie(),Ie=null);let e=location.hash||"#/";e.startsWith("#/workflows/catalog")||e.startsWith("#/workflows-catalog")?Ie=nn(V):e.startsWith("#/workflows")?Ie=Wt(V):e.startsWith("#/groups")?It(V):e.startsWith("#/bot-defaults")?Et(V):e.startsWith("#/connectors")?Ut(V):e.startsWith("#/team/manage")?Pt(V):e.startsWith("#/team")?qt(V):e.startsWith("#/roles")?Ht(V):e.startsWith("#/schedules")?$t(V):e.startsWith("#/sessions")?vt(V):bt(V);for(let t of document.querySelectorAll(".sidebar-nav a")){let n=t.getAttribute("href")??"#/";t.classList.toggle("active",n===(e||"#/"))}}var rt=document.getElementById("status");function ln(){rt&&(rt.textContent=N.online?o("status.live"):o("status.disconnected"),rt.className="connection-status "+(N.online?"online":"offline"))}N.on(ln);function rn(){document.querySelectorAll("[data-i18n]").forEach(e=>{e.textContent=o(e.dataset.i18n??"")}),document.querySelectorAll("[data-locale]").forEach(e=>{e.classList.toggle("active",e.dataset.locale===ae.locale)}),document.querySelectorAll("[data-theme-mode]").forEach(e=>{e.classList.toggle("active",e.dataset.themeMode===ae.themeMode)}),ln()}function ta(){document.querySelectorAll("[data-locale]").forEach(e=>{e.onclick=()=>ae.setLocale(e.dataset.locale)}),document.querySelectorAll("[data-theme-mode]").forEach(e=>{e.onclick=()=>ae.setThemeMode(e.dataset.themeMode)})}(async()=>{ae.init(),ta(),an(),ae.on(()=>{rn(),st()}),rn();try{await pt()}catch(e){console.error("botmux dashboard bootstrap failed",e),N.setOnline(!1)}window.addEventListener("hashchange",st),st()})();})();
901
+ </article>`}async function Qo(e){let t=await fetch(`/api/bot-onboarding/${encodeURIComponent(e)}`),n=await t.json();if(!t.ok||!n?.job)throw new Error(n?.error??`http_${t.status}`);Me(n.job),(n.job.status==="completed"||n.job.status==="failed")&&Je()}async function Xo(){Je(),Me({id:"",status:"starting"});let e=on();e.open||e.showModal();try{let t=await fetch("/api/bot-onboarding/start",{method:"POST"}),n=await t.json();if(!t.ok||!n?.job?.id)throw new Error(n?.error??`http_${t.status}`);Me(n.job),We=window.setInterval(()=>{Qo(n.job.id).catch(s=>{Je(),Me({id:n.job.id,status:"failed",message:s instanceof Error?s.message:String(s)})})},1200)}catch(t){Me({id:"",status:"failed",message:t instanceof Error?t.message:String(t)})}}function an(){let e=document.getElementById("add-bot-btn");e&&(e.onclick=()=>{Xo()})}var Z=document.getElementById("root"),sn=!1;function Zo(){if(sn)return;sn=!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(--card,#fff);color:var(--text,#1f2329);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">\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\u3002<br>\u6700\u597D\u5173\u95ED\u5F53\u524D\u9875\u3002</p><button onclick="window.close()" style="padding:8px 22px;background:var(--accent,#3370ff);color:#fff;border:none;border-radius:8px;cursor:pointer;font-size:14px">\u5173\u95ED\u6B64\u9875</button></div>',document.body.appendChild(e)}var ea=window.fetch.bind(window);window.fetch=async function(...t){let n=await ea(...t);return n.status===401&&Zo(),n};var xe=null;function ct(){xe&&(xe(),xe=null);let e=location.hash||"#/";e.startsWith("#/workflows/catalog")||e.startsWith("#/workflows-catalog")?xe=nn(Z):e.startsWith("#/workflows")?xe=Wt(Z):e.startsWith("#/groups")?It(Z):e.startsWith("#/bot-defaults")?Mt(Z):e.startsWith("#/connectors")?Ut(Z):e.startsWith("#/team/manage")?Pt(Z):e.startsWith("#/team")?Ot(Z):e.startsWith("#/roles")?At(Z):e.startsWith("#/schedules")?St(Z):e.startsWith("#/sessions")?kt(Z):yt(Z);for(let t of document.querySelectorAll(".sidebar-nav a")){let n=t.getAttribute("href")??"#/";t.classList.toggle("active",n===(e||"#/"))}}var ut=document.getElementById("status");function ln(){ut&&(ut.textContent=_.online?o("status.live"):o("status.disconnected"),ut.className="connection-status "+(_.online?"online":"offline"))}_.on(ln);function rn(){document.querySelectorAll("[data-i18n]").forEach(e=>{e.textContent=o(e.dataset.i18n??"")}),document.querySelectorAll("[data-locale]").forEach(e=>{e.classList.toggle("active",e.dataset.locale===ce.locale)}),document.querySelectorAll("[data-theme-mode]").forEach(e=>{e.classList.toggle("active",e.dataset.themeMode===ce.themeMode)}),ln()}function ta(){document.querySelectorAll("[data-locale]").forEach(e=>{e.onclick=()=>ce.setLocale(e.dataset.locale)}),document.querySelectorAll("[data-theme-mode]").forEach(e=>{e.onclick=()=>ce.setThemeMode(e.dataset.themeMode)})}(async()=>{ce.init(),ta(),an(),ce.on(()=>{rn(),ct()}),rn();try{await ft()}catch(e){console.error("botmux dashboard bootstrap failed",e),_.setOnline(!1)}window.addEventListener("hashchange",ct),ct()})();})();