botmux 2.63.1 → 2.64.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bot-registry.d.ts +1 -0
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +9 -5
- package/dist/core/session-manager.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +9 -0
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/public-redact.d.ts +2 -1
- package/dist/dashboard/public-redact.d.ts.map +1 -1
- package/dist/dashboard/public-redact.js +3 -1
- package/dist/dashboard/public-redact.js.map +1 -1
- package/dist/dashboard/registry.d.ts +2 -0
- package/dist/dashboard/registry.d.ts.map +1 -1
- package/dist/dashboard/registry.js.map +1 -1
- package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults.js +5 -4
- package/dist/dashboard/web/bot-defaults.js.map +1 -1
- package/dist/dashboard/web/groups.d.ts.map +1 -1
- package/dist/dashboard/web/groups.js +8 -3
- package/dist/dashboard/web/groups.js.map +1 -1
- package/dist/dashboard/web/overview.d.ts.map +1 -1
- package/dist/dashboard/web/overview.js +6 -4
- package/dist/dashboard/web/overview.js.map +1 -1
- package/dist/dashboard/web/roles.d.ts.map +1 -1
- package/dist/dashboard/web/roles.js +3 -2
- package/dist/dashboard/web/roles.js.map +1 -1
- package/dist/dashboard/web/sessions.js +2 -2
- package/dist/dashboard/web/sessions.js.map +1 -1
- package/dist/dashboard/web/ui.d.ts +33 -0
- package/dist/dashboard/web/ui.d.ts.map +1 -1
- package/dist/dashboard/web/ui.js +84 -0
- package/dist/dashboard/web/ui.js.map +1 -1
- package/dist/dashboard-web/app.js +199 -194
- package/dist/dashboard-web/style.css +25 -0
- package/dist/dashboard.js +1 -1
- package/dist/dashboard.js.map +1 -1
- package/dist/im/lark/client.d.ts +11 -0
- package/dist/im/lark/client.d.ts.map +1 -1
- package/dist/im/lark/client.js +31 -3
- package/dist/im/lark/client.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +4 -0
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/im/lark/forwarded-renderer.d.ts.map +1 -1
- package/dist/im/lark/forwarded-renderer.js +10 -3
- package/dist/im/lark/forwarded-renderer.js.map +1 -1
- package/dist/im/lark/merge-forward.d.ts.map +1 -1
- package/dist/im/lark/merge-forward.js +33 -8
- package/dist/im/lark/merge-forward.js.map +1 -1
- package/dist/services/groups-store.d.ts +2 -0
- package/dist/services/groups-store.d.ts.map +1 -1
- package/dist/services/groups-store.js +1 -0
- package/dist/services/groups-store.js.map +1 -1
- package/dist/services/observed-bots-store.d.ts.map +1 -1
- package/dist/services/observed-bots-store.js +5 -0
- package/dist/services/observed-bots-store.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
"use strict";(()=>{var kt=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()}},G=new kt;async function an(){let[e,t]=await Promise.all([fetch("/api/sessions").then(a=>a.json()),fetch("/api/schedules").then(a=>a.json())]);G.upsertSessions(e.sessions??[]),G.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,i=>{try{let l=JSON.parse(i.data);G.applySse(a,l.body??l)}catch{}});n.onerror=()=>G.setOnline(!1),n.onopen=()=>G.setOnline(!0)}var $t="botmux.dashboard.locale",Io={"app.name":"botmux","app.subtitle":"\u98DE\u4E66 AI CLI \u63A7\u5236\u53F0","time.secondsAgo":"{value} \u79D2\u524D","time.minutesAgo":"{value} \u5206\u949F\u524D","time.hoursAgo":"{value} \u5C0F\u65F6\u524D","nav.overview":"\u603B\u89C8","nav.sessions":"\u4F1A\u8BDD","nav.groups":"\u7FA4\u7EC4","nav.schedules":"\u5B9A\u65F6","nav.settings":"\u8BBE\u7F6E","nav.botDefaults":"Bot \u914D\u7F6E","status.live":"\u5B9E\u65F6\u8FDE\u63A5","status.disconnected":"\u8FDE\u63A5\u65AD\u5F00","status.system":"\u7CFB\u7EDF","status.light":"\u6D45\u8272","status.dark":"\u6697\u9ED1","status.language":"\u8BED\u8A00","status.theme":"\u4E3B\u9898","theme.base":"\u57FA\u7840","theme.skins":"\u4E3B\u9898\u76AE\u80A4","skin.cyber":"2077","skin.genshin":"\u539F\u795E","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"\u851A\u84DD\u6863\u6848","skin.zzz":"\u7EDD\u533A\u96F6","skin.dragonball":"\u4E03\u9F99\u73E0","skin.ikun":"ikun","botOnboarding.add":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.title":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.intro":"\u9009\u62E9 CLI \u4E0E\u5DE5\u4F5C\u76EE\u5F55\uFF0C\u626B\u7801\u521B\u5EFA PersonalAgent \u5E94\u7528\u540E\u5199\u5165\u672C\u673A bots.json\uFF0C\u5E76\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u3002","botOnboarding.cliLabel":"CLI \u9002\u914D\u5668","botOnboarding.dirLabel":"\u5DE5\u4F5C\u76EE\u5F55","botOnboarding.dirPlaceholder":"\u9ED8\u8BA4 ~\uFF08\u5BB6\u76EE\u5F55\uFF09\uFF0C\u9700\u4E3A daemon \u4E3B\u673A\u4E0A\u5DF2\u5B58\u5728\u7684\u76EE\u5F55","botOnboarding.modelLabel":"\u6A21\u578B\uFF08\u53EF\u9009\uFF09","botOnboarding.modelPlaceholder":"\u7559\u7A7A\u4F7F\u7528\u8BE5 CLI \u7684\u9ED8\u8BA4\u6A21\u578B","botOnboarding.startScan":"\u5F00\u59CB\u626B\u7801","botOnboarding.cancel":"\u53D6\u6D88","botOnboarding.starting":"\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...","botOnboarding.waiting":"\u8BF7\u7528\u98DE\u4E66 App \u626B\u7801\u786E\u8BA4\u521B\u5EFA\u5E94\u7528\u3002","botOnboarding.verifying":"\u626B\u7801\u6210\u529F\uFF0C\u6B63\u5728\u6821\u9A8C\u51ED\u8BC1...","botOnboarding.configuringPermissions":"\u6B63\u5728\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u2026","botOnboarding.platformScanHint":"\u8BF7\u7528\u98DE\u4E66 App \u518D\u626B\u4E00\u6B21\u7801\u767B\u5F55\u5F00\u653E\u5E73\u53F0\uFF08\u7528\u4E8E\u81EA\u52A8\u5BFC\u5165\u6743\u9650\u3001\u914D\u7F6E\u56DE\u8C03\u3001\u63D0\u4EA4\u7248\u672C\uFF09\u3002","botOnboarding.platformQrAlt":"\u5F00\u653E\u5E73\u53F0\u767B\u5F55\u4E8C\u7EF4\u7801","botOnboarding.completed":"\u673A\u5668\u4EBA\u5DF2\u6DFB\u52A0\u3002","botOnboarding.permissionOk":"\u5DF2\u81EA\u52A8\u5BFC\u5165 {count} \u9879\u6743\u9650\u3002","botOnboarding.permissionSkipped":"\uFF08\u8DF3\u8FC7 {count} \u9879\u5F53\u524D\u79DF\u6237\u76EE\u5F55\u4E2D\u6CA1\u6709\u7684\u6743\u9650\uFF09","botOnboarding.permissionVersion":"\u5DF2\u63D0\u4EA4\u53D1\u5E03\u7248\u672C {version}\u3002","botOnboarding.permissionManual":"\u6743\u9650\u672A\u80FD\u81EA\u52A8\u914D\u7F6E\uFF0C\u8BF7\u624B\u52A8\u5B8C\u6210\u4EE5\u4E0B\u6B65\u9AA4\uFF1A","botOnboarding.metaDir":"\u76EE\u5F55","botOnboarding.failed":"\u6DFB\u52A0\u5931\u8D25","botOnboarding.openLink":"\u6253\u4E0D\u5F00\u626B\u7801\uFF1F\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00","botOnboarding.close":"\u5173\u95ED","botOnboarding.restartHint":"\u5DF2\u5199\u5165 bots.json\u3002\u6267\u884C pnpm daemon:restart \u540E\u65B0\u673A\u5668\u4EBA\u751F\u6548\u3002","botOnboarding.qrAlt":"\u98DE\u4E66\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA\u4E8C\u7EF4\u7801","overview.title":"\u5DE5\u4F5C\u53F0","overview.subtitle":"\u6570\u5B57\u5458\u5DE5\u5B9E\u65F6\u72B6\u6001 \xB7 \u540C\u6B65\u98DE\u4E66\u8BDD\u9898","overview.team":"AI \u56E2\u961F","overview.teamHint":"\u6BCF\u4F4D\u6570\u5B57\u5458\u5DE5\u7684\u5B9E\u65F6\u72B6\u6001","overview.attention":"\u9700\u8981\u4F60\u5904\u7406","overview.attentionHint":"\u5361\u4F4F\u7684\u4EFB\u52A1\uFF0C\u56DE\u4E2A\u8BDD\u5C31\u80FD\u7EE7\u7EED\u8DD1","overview.activeSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.activeSessionsHint":"\u6B63\u5728\u8FD0\u8F6C\u7684\u4F1A\u8BDD","overview.today":"\u6B64\u523B\u6982\u89C8","overview.todayHint":"\u6D3B\u8DC3\u4F1A\u8BDD\u5206\u5E03","overview.viewAll":"\u67E5\u770B\u5168\u90E8 \u2192","overview.botIdle":"\u5F85\u547D\u4E2D\uFF0C\u968F\u65F6\u53EF\u63A5\u65B0\u4EFB\u52A1","overview.botOffline":"\u79BB\u7EBF \u2014 daemon \u672A\u4E0A\u7EBF","overview.botBusy":"\u6267\u884C\u4E2D \xB7 {count} \u4F1A\u8BDD","overview.botNeedsYou":"\u7B49\u4F60\u56DE\u590D","overview.botReady":"\u5C31\u7EEA","overview.botOff":"\u79BB\u7EBF","overview.sessionsCount":"{count} \u4F1A\u8BDD","overview.lastActive":"{time}\u524D\u6D3B\u8DC3","overview.noAttention":"\u6CA1\u6709\u7B49\u4F60\u5904\u7406\u7684\u4E8B\u9879","strip.pending":"{count} \u4EF6\u5F85\u5904\u7406","strip.longest":"\u6700\u4E45\u5DF2\u7B49 {time} \u2014 {bot} {reason}","strip.handle":"\u7ACB\u5373\u5904\u7406","overview.openSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.workingSessions":"\u5DE5\u4F5C\u4E2D","overview.onlineBots":"\u5728\u7EBF Bot","overview.schedules":"\u5B9A\u65F6\u4EFB\u52A1","overview.groups":"\u7FA4\u804A\u8986\u76D6","overview.enabledSchedules":"\u5DF2\u542F\u7528","overview.total":"\u603B\u8BA1","overview.active":"\u6D3B\u8DC3","overview.daemonRegistry":"daemon \u6CE8\u518C\u8868","overview.chatMatrix":"\u7FA4\u804A\u77E9\u9635","overview.recentSessions":"\u6700\u8FD1\u4F1A\u8BDD","overview.nextSchedules":"\u5373\u5C06\u6267\u884C","overview.noSessions":"\u6682\u65E0\u4F1A\u8BDD\u3002","overview.noSchedules":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","sessions.title":"\u4F1A\u8BDD\u63A7\u5236","sessions.subtitle":"\u5B9A\u4F4D\u98DE\u4E66\u8BDD\u9898\u3001\u6253\u5F00 Web Terminal\u3001\u5173\u95ED\u6216\u6062\u590D CLI \u4F1A\u8BDD\u3002","sessions.search":"\u641C\u7D22\u5DE5\u4F5C\u76EE\u5F55 / \u6807\u9898 / ID","sessions.anyStatus":"\u5168\u90E8\u72B6\u6001","sessions.adoptAny":"adopt: \u5168\u90E8","sessions.adoptYes":"adopt: \u662F","sessions.adoptNo":"adopt: \u5426","sessions.activeOnly":"\u4EC5\u6D3B\u8DC3","sessions.closeSelected":"\u5173\u95ED\u9009\u4E2D","sessions.clearSelection":"\u53D6\u6D88\u9009\u62E9","sessions.selectedCount":"\u5DF2\u9009 {count} \u4E2A\u4F1A\u8BDD","sessions.bot":"bot","sessions.cli":"CLI","sessions.chat":"\u7FA4\u804A","sessions.openChat":"\u6253\u5F00\u7FA4\u804A","sessions.status":"\u72B6\u6001","sessions.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","sessions.viewMode":"\u4F1A\u8BDD\u89C6\u56FE","sessions.viewBoard":"\u72B6\u6001\u677F","sessions.viewTable":"\u8868\u683C","sessions.selectSession":"\u9009\u62E9\u4F1A\u8BDD","sessions.board.needsYou":"\u9700\u8981\u4F60","sessions.board.needsYouHint":"\u7B49\u5F85\u4ED3\u5E93\u3001TUI \u9009\u62E9\u6216\u989D\u5EA6\u5904\u7406","sessions.board.starting":"\u542F\u52A8\u4E2D","sessions.board.startingHint":"CLI \u6B63\u5728\u521B\u5EFA\u6216\u6062\u590D","sessions.board.working":"\u5E72\u6D3B\u4E2D","sessions.board.workingHint":"\u6B63\u5728\u8F93\u51FA\u3001\u5206\u6790\u6216\u6267\u884C\u5DE5\u5177","sessions.board.idle":"\u7A7A\u95F2","sessions.board.idleHint":"\u53EF\u7EE7\u7EED\u5BF9\u8BDD\u6216\u63A5\u65B0\u4EFB\u52A1","sessions.board.emptyColumn":"\u6682\u65E0\u4F1A\u8BDD","sessions.board.signalRepo":"\u5F85\u9009\u4ED3\u5E93","sessions.board.signalPrompt":"\u7B49\u5F85 TUI \u9009\u62E9","sessions.board.signalLimited":"\u989D\u5EA6\u53D7\u9650","sessions.board.dragHint":"\u62D6\u52A8\u5217\u5934\u8C03\u6574\u5217\u987A\u5E8F","sessions.board.moveLeft":"\u5DE6\u79FB\u6B64\u5217","sessions.board.moveRight":"\u53F3\u79FB\u6B64\u5217","groups.title":"\u7FA4\u7EC4\u4E0E Bot","groups.subtitle":"\u67E5\u770B chat x bot \u8986\u76D6\u77E9\u9635\uFF0C\u7BA1\u7406\u62C9\u7FA4\u3001oncall\u3001\u9000\u7FA4\u548C\u89E3\u6563\u3002","groups.search":"\u641C\u7D22\u7FA4\u540D / ID / owner","groups.missingOnly":"\u4EC5\u7F3A bot","groups.refresh":"\u5237\u65B0","groups.create":"\u65B0\u5EFA\u7FA4","groups.chat":"\u7FA4\u804A","groups.actions":"\u64CD\u4F5C","groups.addBots":"\u6DFB\u52A0 bot","groups.manage":"\u7BA1\u7406","groups.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u7FA4\u804A\u3002","groups.createTitle":"\u65B0\u5EFA\u7FA4\u804A","groups.createHelp":"\u9009\u62E9\u8981\u9080\u8BF7\u7684 bot\u3002dashboard \u4F1A\u81EA\u52A8\u9009\u62E9\u5728\u7EBF daemon \u4F5C\u4E3A\u521B\u5EFA\u8005\u3002","groups.name":"\u7FA4\u540D","groups.namePlaceholder":"\u4F8B\u5982 AI ChangeLog","groups.bindDir":"\u7ED1\u5B9A\u76EE\u5F55","groups.bindDirHelp":"\u65B0\u8BDD\u9898\u76F4\u63A5\u7528\u8BE5\u76EE\u5F55\u542F\u52A8 CLI\uFF0C\u8DF3\u8FC7 repo \u9009\u62E9\u3002","groups.botPicker":"Bot","groups.createSubmit":"\u521B\u5EFA","groups.cancel":"\u53D6\u6D88","groups.successTitle":"\u7FA4\u521B\u5EFA\u6210\u529F","groups.openGroup":"\u6253\u5F00\u65B0\u7FA4","groups.manageTitle":"\u7BA1\u7406 {name}","groups.owner":"\u7FA4\u4E3B","groups.oncall":"Oncall \u6A21\u5F0F","groups.oncallHelp":"\u5F00\u542F\u540E\uFF0C\u7FA4\u5185\u6210\u5458\u53EF @ \u673A\u5668\u4EBA\uFF1B\u65B0\u8BDD\u9898\u76F4\u63A5\u4F7F\u7528\u7ED1\u5B9A\u76EE\u5F55\u3002","groups.leaveTitle":"\u9009\u62E9\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.leaveSelected":"\u9009\u4E2D\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.disband":"\u89E3\u6563\u7FA4\u804A","groups.dangerHint":"\u89E3\u6563\u4EC5\u5F53\u5728\u7FA4\u673A\u5668\u4EBA\u662F\u7FA4\u4E3B\u65F6\u624D\u4F1A\u6210\u529F\uFF0C\u5426\u5219\u5EFA\u8BAE\u4F7F\u7528\u9000\u51FA\u7FA4\u804A\u3002","groups.save":"\u4FDD\u5B58","groups.needWorkingDir":"\u8BF7\u586B\u5DE5\u4F5C\u76EE\u5F55","groups.noBotsOnline":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u8BF7\u5148\u91CD\u542F daemon\u3002","schedules.title":"\u5B9A\u65F6\u4EFB\u52A1","schedules.subtitle":"\u8DE8 daemon \u67E5\u770B\u3001\u6682\u505C\u3001\u6062\u590D\u548C\u7ACB\u5373\u89E6\u53D1\u5B9A\u65F6\u4EFB\u52A1\u3002","schedules.search":"\u641C\u7D22\u540D\u79F0 / prompt / \u5DE5\u4F5C\u76EE\u5F55","schedules.anyKind":"\u5168\u90E8\u7C7B\u578B","schedules.enabledOnly":"\u4EC5\u542F\u7528","schedules.name":"\u540D\u79F0","schedules.bot":"bot","schedules.schedule":"\u89C4\u5219","schedules.next":"\u4E0B\u6B21","schedules.last":"\u4E0A\u6B21","schedules.repeat":"\u91CD\u590D","schedules.enabled":"\u542F\u7528","schedules.actions":"\u64CD\u4F5C","schedules.runNow":"\u7ACB\u5373\u8FD0\u884C","schedules.pause":"\u6682\u505C","schedules.resume":"\u6062\u590D","schedules.empty":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","settings.title":"\u5168\u5C40\u8BBE\u7F6E","settings.subtitle":"\u7BA1\u7406\u672C\u673A botmux dashboard \u4E0E\u6240\u6709 bot \u5171\u4EAB\u7684\u5168\u5C40\u884C\u4E3A\u3002","settings.loading":"\u6B63\u5728\u52A0\u8F7D\u8BBE\u7F6E\u2026","settings.loadFailed":"\u8BBE\u7F6E\u52A0\u8F7D\u5931\u8D25","settings.readOnlyVisitor":"\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u4FEE\u6539\u8BBE\u7F6E\u9700\u8981\u6388\u6743\u94FE\u63A5\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09","settings.sectionAccess":"\u8BBF\u95EE\u6743\u9650","settings.publicReadOnly":"\u5141\u8BB8\u65E0 token \u53EA\u8BFB\u8BBF\u95EE dashboard","settings.publicReadOnlyHelp":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 token \u7684\u8BBF\u95EE\u8005\u53EF\u4EE5\u67E5\u770B dashboard\u3001\u4F1A\u8BDD\u3001\u5B9A\u65F6\u4EFB\u52A1\u548C SSE\uFF1B\u5173\u95ED\u3001\u6682\u505C\u3001\u5BA1\u6279\u7B49\u5199\u64CD\u4F5C\u4ECD\u5FC5\u987B\u901A\u8FC7 token \u9274\u6743\u3002\u654F\u611F\u7EC8\u7AEF\u539F\u59CB\u65E5\u5FD7\u59CB\u7EC8\u9700\u8981 token\u3002","settings.sectionCards":"\u98DE\u4E66\u5361\u7247","settings.openTerminalInFeishu":"\u6D41\u5F0F\u5361\u7247\u7EC8\u7AEF\u6309\u94AE\u5728\u98DE\u4E66\u4FA7\u680F\u6253\u5F00","settings.openTerminalInFeishuHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF1A\u7EC8\u7AEF\u6309\u94AE\u76F4\u63A5\u6253\u5F00 Web Terminal URL\u3002\u5F00\u542F\u540E\u4F7F\u7528\u98DE\u4E66 web_url/open \u5305\u88C5\uFF0C\u5728\u98DE\u4E66 PC \u4FA7\u680F\u91CC\u6253\u5F00\uFF1B\u5199\u6743\u9650\u4ECD\u7531\u7EC8\u7AEF token \u63A7\u5236\u3002","settings.saving":"\u4FDD\u5B58\u4E2D\u2026","settings.saved":"\u5DF2\u4FDD\u5B58","settings.saveFailed":"\u4FDD\u5B58\u5931\u8D25","botDefaults.title":"\u6570\u5B57\u5458\u5DE5\u6863\u6848","botDefaults.subtitle":"\u6BCF\u4F4D\u5458\u5DE5\u7684\u9ED8\u8BA4\u884C\u4E3A\uFF1Aoncall\u3001\u4E3B\u52A8\u5F00\u5DE5\u3001\u4EBA\u8BBE\u89D2\u8272\u3001\u5361\u7247\u4E0E\u6388\u6743\u3002","botDefaults.metaOnline":"\u5728\u7EBF \xB7 daemon \u6B63\u5E38","botDefaults.search":"\u641C\u7D22 bot \u540D / app id","botDefaults.refresh":"\u5237\u65B0","botDefaults.sectionOncall":"\u65B0\u7FA4 Oncall","botDefaults.sectionBrand":"\u5361\u7247\u7B7E\u540D","botDefaults.warning":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 oncall binding \u7684\u7FA4\u4F1A\u5728\u4E0B\u6B21\u5F00\u65B0\u8BDD\u9898\u65F6\u81EA\u52A8\u7ED1\u5B9A\u5230\u8BE5\u76EE\u5F55\uFF1B\u624B\u52A8\u7ED1\u5B9A\u6216\u624B\u52A8\u89E3\u7ED1\u8FC7\u7684\u7FA4\u4E0D\u4F1A\u88AB\u8986\u76D6\u3002","botDefaults.empty":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u5148 botmux restart \u8BA9 daemon \u4E0A\u7EBF\u3002","botDefaults.defaultOncall":"\u9ED8\u8BA4\u8FDB\u5165 oncall \u6A21\u5F0F","botDefaults.defaultOncallHelp":"\u6240\u6709\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8\u7ED1\u5B9A","botDefaults.workingDir":"\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55","botDefaults.lastEnabled":"\u4E0A\u6B21\u542F\u7528\u65F6\u95F4","botDefaults.autobound":"\u5DF2\u81EA\u52A8\u7ED1\u5B9A {count} \u4E2A\u7FA4","botDefaults.save":"\u4FDD\u5B58","botDefaults.required":"\u5F00\u542F\u65F6\u5FC5\u987B\u586B\u5DE5\u4F5C\u76EE\u5F55","botDefaults.brandLabel":"\u4E2A\u6027\u7B7E\u540D\uFF08\u5361\u7247\u9875\u811A\uFF09","botDefaults.brandLabelHelp":"\u8BE5 bot \u53D1\u51FA\u7684\u5361\u7247\u9875\u811A\u7B7E\u540D\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u4E0D\u663E\u793A\uFF1B\u586B\u5199\uFF1D\u81EA\u5B9A\u4E49\uFF08\u652F\u6301 markdown\uFF0C\u5982 [Acme](https://\u2026)\uFF09\uFF1B\u6062\u590D\u9ED8\u8BA4\uFF1D\u663E\u793A botmux\u3002","botDefaults.brandLabelPlaceholder":"\u9ED8\u8BA4\uFF1Abotmux\uFF08\u7559\u7A7A\u5219\u4E0D\u663E\u793A\uFF09","botDefaults.brandSave":"\u4FDD\u5B58\u7B7E\u540D","botDefaults.brandReset":"\u6062\u590D\u9ED8\u8BA4","botDefaults.brandStateDefault":"\u5F53\u524D\uFF1A\u9ED8\u8BA4 botmux","botDefaults.brandStateOff":"\u5F53\u524D\uFF1A\u5DF2\u5173\u95ED","botDefaults.brandStateCustom":"\u5F53\u524D\uFF1A\u81EA\u5B9A\u4E49","botDefaults.sectionCard":"\u5361\u7247\u884C\u4E3A","botDefaults.disableStreaming":"\u5173\u95ED\u98DE\u4E66\u6D41\u5F0F\u5361\u7247","botDefaults.disableStreamingHelp":"\u4E0D\u518D\u53D1\u5B9E\u65F6\u5237\u65B0\u7684\u4F1A\u8BDD\u72B6\u6001\u5361\uFF08\u542B\u300C\u6253\u5F00\u7EC8\u7AEF\u300D\u5165\u53E3\uFF09\uFF1B\u4EFB\u52A1\u6700\u7EC8\u7ED3\u679C\u4ECD\u901A\u8FC7\u6D88\u606F\u9001\u8FBE\u3002\u9002\u5408\u5ACC\u6D41\u5F0F\u5361\u7247\u70E6\u7684\u573A\u666F\u3002","botDefaults.writableLink":"\u5361\u7247\u4E0A\u76F4\u63A5\u7ED9\u53EF\u64CD\u4F5C\uFF08\u53EF\u5199\uFF09\u7EC8\u7AEF\u94FE\u63A5","botDefaults.writableLinkHelp":"\u26A0\uFE0F \u5728\u6D41\u5F0F\u5361\u7247\u6B63\u6587\u76F4\u63A5\u8D34\u51FA\u53EF\u5199\u7EC8\u7AEF\u94FE\u63A5\uFF0C\u7FA4\u5185\u4EFB\u4F55\u4EBA\u90FD\u80FD\u70B9\u5F00\u5E76\u64CD\u63A7\u7EC8\u7AEF\u3002\u4E0D\u52FE\uFF1D\u4FDD\u6301\u73B0\u72B6\uFF08\u8D70\u300C\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u300D\u6309\u94AE\u79C1\u804A\u53D1\u7ED9\u70B9\u51FB\u8005\uFF09\u3002","botDefaults.writableLinkMoot":"\u5DF2\u5173\u95ED\u6D41\u5F0F\u5361\u7247","botDefaults.privateCard":"/card \u53D1\u79C1\u5BC6\u5361\u7247\uFF08\u4EC5\u6388\u6743\u4EBA\u53EF\u89C1\uFF09","botDefaults.privateCardHelp":"\u5F00\u542F\u540E /card \u6539\u7528\u300C\u4EC5\u7279\u5B9A\u4EBA\u53EF\u89C1\u300D\u7684\u4E34\u65F6\u5361\u7247\uFF1A\u53EA\u53D1\u7ED9 owner\uFF08allowedUsers\uFF09\uFF0C/grant \u6388\u6743\u5BF9\u8BDD\u7684\u4EBA\u548C\u7FA4\u91CC\u5176\u4ED6\u4EBA\u90FD\u770B\u4E0D\u5230\u3002\u4EE3\u4EF7\uFF1A\u662F\u9759\u6001\u5FEB\u7167\u3001\u4E0D\u4F1A\u5B9E\u65F6\u5237\u65B0\uFF1B\u4E14\u4EC5\u666E\u901A\u7FA4\u53EF\u7528\uFF08\u8BDD\u9898\u7FA4 / \u5355\u804A\u4F1A\u5931\u8D25\uFF0C\u4E0D\u964D\u7EA7\uFF09\u3002\u53EA\u5F71\u54CD /card \u547D\u4EE4\uFF0C\u81EA\u52A8\u6D41\u5F0F\u5361\u4E0D\u53D8\u3002","botDefaults.cardPrefSaved":"\u5DF2\u4FDD\u5B58","botDefaults.sectionRole":"\u9ED8\u8BA4\u89D2\u8272","botDefaults.roleHelp":"\u8BE5 bot \u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF08\u8DE8\u7FA4\u751F\u6548\uFF09\uFF0C\u4F1A\u6CE8\u5165\u5230\u8BE5 bot \u5728\u5404\u7FA4\u7684\u4F1A\u8BDD\u91CC\uFF1B\u5355\u4E2A\u7FA4\u53EF\u5728\u300C\u89D2\u8272\u300D\u9875\u5355\u72EC\u8986\u76D6\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u5220\u9664\u3002","botDefaults.rolePlaceholder":"\u4F8B\u5982\uFF1A\u4F60\u662F\u540E\u7AEF\u6392\u969C\u52A9\u624B\uFF0C\u56DE\u7B54\u7B80\u6D01\u3001\u4F18\u5148\u7ED9\u53EF\u6267\u884C\u547D\u4EE4\u2026","botDefaults.roleSave":"\u4FDD\u5B58\u89D2\u8272","botDefaults.roleDelete":"\u5220\u9664","botDefaults.roleSaved":"\u5DF2\u4FDD\u5B58","botDefaults.roleDeleted":"\u5DF2\u5220\u9664","botDefaults.roleLoadErr":"\u89D2\u8272\u52A0\u8F7D\u5931\u8D25","botDefaults.sectionAutoStart":"\u4E3B\u52A8\u5F00\u5DE5","botDefaults.autoStartJoin":"\u88AB\u62C9\u8FDB\u65B0\u7FA4\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartJoinHelp":"\u5F00\u542F\u540E\uFF0C\u673A\u5668\u4EBA\u4E00\u88AB\u62C9\u8FDB\u65B0\u7FA4\uFF08\u7FA4\u91CC\u6709\u6388\u6743\u7528\u6237 allowedUsers \u65F6\uFF09\u5C31\u81EA\u52A8\u5F00\u4E00\u4E2A\u4F1A\u8BDD\u5F00\u59CB\u5DE5\u4F5C\uFF0C\u65E0\u9700 @\u3002\u5728\u673A\u5668\u4EBA\u7684\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55\u542F\u52A8\uFF1B\u672A\u914D\u7F6E\u9ED8\u8BA4\u76EE\u5F55\u65F6\u5148\u5F39\u4ED3\u5E93\u9009\u62E9\u5361\u8BA9\u4F60\u9009\u3002\u524D\u63D0\uFF1A\u9700\u5728\u98DE\u4E66\u5F00\u653E\u5E73\u53F0\u4E3A\u672C\u5E94\u7528\u8BA2\u9605\u300C\u673A\u5668\u4EBA\u8FDB\u7FA4\u300D\u4E8B\u4EF6 im.chat.member.bot.added_v1\uFF0C\u5E76\u5F00\u901A\u7FA4\u6210\u5458\u8BFB\u53D6\u6743\u9650\u3002","botDefaults.autoStartJoinPrompt":"\u5165\u7FA4\u9996\u8F6E prompt\uFF08\u53EF\u9009\uFF09","botDefaults.autoStartJoinPromptPlaceholder":"\u586B\u4E86\uFF1D\u4F5C\u4E3A\u5165\u7FA4\u540E\u7684\u7B2C\u4E00\u6761\u4EFB\u52A1\uFF1B\u7559\u7A7A\uFF1D\u673A\u5668\u4EBA\u81EA\u5DF1\u770B\u7FA4\u91CC\u4FE1\u606F\u51B3\u5B9A\u505A\u4EC0\u4E48","botDefaults.autoStartJoinPromptSave":"\u4FDD\u5B58 prompt","botDefaults.autoStartTopic":"\u8BDD\u9898\u7FA4\u65B0\u8BDD\u9898\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartTopicHelp":"\u5F00\u542F\u540E\uFF0C\u5728\u8BDD\u9898\u7FA4\u91CC\u6BCF\u5F53\u6709\u4EBA\u65B0\u5F00\u4E00\u4E2A\u8BDD\u9898\uFF0C\u673A\u5668\u4EBA\u5C31\u4F1A\u81EA\u52A8\u63A5\u5165\u8BE5\u8BDD\u9898\u3001\u628A\u9996\u6761\u6D88\u606F\u5F53\u4F5C\u4EFB\u52A1\u5F00\u59CB\u5904\u7406\uFF0C\u65E0\u9700 @\u3002\u4EC5\u5BF9\u8BDD\u9898\u7FA4\u751F\u6548\uFF0C\u666E\u901A\u7FA4\u4E0D\u53D7\u5F71\u54CD\u3002","botDefaults.sectionGrant":"\u6388\u6743\u4E0E\u989D\u5EA6","botDefaults.restrictGrant":"\u9650\u5236\u88AB\u6388\u6743\u4EBA\u53EA\u80FD\u7EAF\u5BF9\u8BDD","botDefaults.restrictGrantHelp":"\u5F00\u542F\u540E\uFF0C\u88AB /grant \u6388\u6743\u7684\u4EBA\uFF08owner \u81EA\u5DF1\u4E0D\u53D7\u9650\uFF09\u53EA\u80FD\u53D1\u666E\u901A\u5BF9\u8BDD\uFF0C\u6240\u6709 slash \u547D\u4EE4\u4E00\u5F8B\u62E6\u622A\uFF1Abotmux \u81EA\u5E26\u547D\u4EE4\u3001\u900F\u4F20\u547D\u4EE4\u3001/workflow\u3001/introduce\u3001/t \u4EE5\u53CA CLI \u539F\u751F\u547D\u4EE4\uFF08/help \u7B49\uFF09\u3002\u5F62\u5982 /path/to/file \u7684\u5185\u5BB9\u4E0D\u4F1A\u88AB\u8BEF\u5224\u3002","botDefaults.quotaDefault":"\u9ED8\u8BA4\u6D88\u606F\u989D\u5EA6","botDefaults.quotaPlaceholder":"\u7559\u7A7A\uFF1D\u4E0D\u914D\u7F6E\u9ED8\u8BA4\u989D\u5EA6","botDefaults.quotaHelp":"\u4E0D\u5E26\u6570\u5B57\u7684 /grant @x \u9ED8\u8BA4\u7ED9\u7684\u6D88\u606F\u6761\u6570\u3002\u7559\u7A7A\u6216\u70B9\u300C\u5173\u95ED\u300D\u53EA\u662F\u4E0D\u518D\u7ED9\u88F8 /grant \u5957\u9ED8\u8BA4\u989D\u5EA6\uFF0C\u4E0D\u4F1A\u6E05\u6389\u5DF2\u6709\u7684\u989D\u5EA6\u8BA1\u6570\uFF0C\u4E5F\u4E0D\u5F71\u54CD\u663E\u5F0F /grant @x N\u2014\u2014\u5B83\u4EEC\u7167\u5E38\u7EE7\u7EED enforce\u3002\u989D\u5EA6\u7528\u5C3D\u4F1A\u81EA\u52A8\u64A4\u9500\u8BE5\u4EBA\u6388\u6743\u3002","botDefaults.quotaSave":"\u4FDD\u5B58\u989D\u5EA6","botDefaults.quotaOff":"\u5173\u95ED","botDefaults.quotaInvalid":"\u989D\u5EA6\u5FC5\u987B\u662F\u6B63\u6574\u6570","botDefaults.quotaStateOff":"\u5F53\u524D\uFF1A\u672A\u914D\u7F6E\u9ED8\u8BA4\u989D\u5EA6","botDefaults.quotaStateOn":"\u5F53\u524D\uFF1A\u6BCF\u4EBA {count} \u6761","nav.roles":"\u89D2\u8272\u7BA1\u7406","roles.title":"\u89D2\u8272\u7BA1\u7406","roles.subtitle":"\u4E3A\u6BCF\u4E2A\u7FA4\u7EC4\u7684\u6BCF\u4E2A Bot \u5355\u72EC\u8BBE\u7F6E\u89D2\u8272\u63D0\u793A\u8BCD\uFF0CBot \u5728\u8BE5\u7FA4\u4E2D\u4F1A\u4EE5\u6B64\u89D2\u8272\u884C\u4E8B\u3002","roles.search":"\u641C\u7D22\u7FA4\u540D/Bot/ID","roles.refresh":"\u5237\u65B0","roles.selectHint":"\u2190 \u5C55\u5F00\u7FA4\u7EC4\uFF0C\u9009\u62E9\u4E00\u4E2A Bot \u6765\u7F16\u8F91\u89D2\u8272","roles.editorPlaceholder":`\u8F93\u5165\u89D2\u8272\u63CF\u8FF0\uFF0C\u4F8B\u5982\uFF1A
|
|
1
|
+
"use strict";(()=>{var It=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()}},G=new It;async function ln(){let[e,t]=await Promise.all([fetch("/api/sessions").then(a=>a.json()),fetch("/api/schedules").then(a=>a.json())]);G.upsertSessions(e.sessions??[]),G.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,i=>{try{let l=JSON.parse(i.data);G.applySse(a,l.body??l)}catch{}});n.onerror=()=>G.setOnline(!1),n.onopen=()=>G.setOnline(!0)}var Tt="botmux.dashboard.locale",Ao={"app.name":"botmux","app.subtitle":"\u98DE\u4E66 AI CLI \u63A7\u5236\u53F0","time.secondsAgo":"{value} \u79D2\u524D","time.minutesAgo":"{value} \u5206\u949F\u524D","time.hoursAgo":"{value} \u5C0F\u65F6\u524D","nav.overview":"\u603B\u89C8","nav.sessions":"\u4F1A\u8BDD","nav.groups":"\u7FA4\u7EC4","nav.schedules":"\u5B9A\u65F6","nav.settings":"\u8BBE\u7F6E","nav.botDefaults":"Bot \u914D\u7F6E","status.live":"\u5B9E\u65F6\u8FDE\u63A5","status.disconnected":"\u8FDE\u63A5\u65AD\u5F00","status.system":"\u7CFB\u7EDF","status.light":"\u6D45\u8272","status.dark":"\u6697\u9ED1","status.language":"\u8BED\u8A00","status.theme":"\u4E3B\u9898","theme.base":"\u57FA\u7840","theme.skins":"\u4E3B\u9898\u76AE\u80A4","skin.cyber":"2077","skin.genshin":"\u539F\u795E","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"\u851A\u84DD\u6863\u6848","skin.zzz":"\u7EDD\u533A\u96F6","skin.dragonball":"\u4E03\u9F99\u73E0","skin.ikun":"ikun","botOnboarding.add":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.title":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.intro":"\u9009\u62E9 CLI \u4E0E\u5DE5\u4F5C\u76EE\u5F55\uFF0C\u626B\u7801\u521B\u5EFA PersonalAgent \u5E94\u7528\u540E\u5199\u5165\u672C\u673A bots.json\uFF0C\u5E76\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u3002","botOnboarding.cliLabel":"CLI \u9002\u914D\u5668","botOnboarding.dirLabel":"\u5DE5\u4F5C\u76EE\u5F55","botOnboarding.dirPlaceholder":"\u9ED8\u8BA4 ~\uFF08\u5BB6\u76EE\u5F55\uFF09\uFF0C\u9700\u4E3A daemon \u4E3B\u673A\u4E0A\u5DF2\u5B58\u5728\u7684\u76EE\u5F55","botOnboarding.modelLabel":"\u6A21\u578B\uFF08\u53EF\u9009\uFF09","botOnboarding.modelPlaceholder":"\u7559\u7A7A\u4F7F\u7528\u8BE5 CLI \u7684\u9ED8\u8BA4\u6A21\u578B","botOnboarding.startScan":"\u5F00\u59CB\u626B\u7801","botOnboarding.cancel":"\u53D6\u6D88","botOnboarding.starting":"\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...","botOnboarding.waiting":"\u8BF7\u7528\u98DE\u4E66 App \u626B\u7801\u786E\u8BA4\u521B\u5EFA\u5E94\u7528\u3002","botOnboarding.verifying":"\u626B\u7801\u6210\u529F\uFF0C\u6B63\u5728\u6821\u9A8C\u51ED\u8BC1...","botOnboarding.configuringPermissions":"\u6B63\u5728\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u2026","botOnboarding.platformScanHint":"\u8BF7\u7528\u98DE\u4E66 App \u518D\u626B\u4E00\u6B21\u7801\u767B\u5F55\u5F00\u653E\u5E73\u53F0\uFF08\u7528\u4E8E\u81EA\u52A8\u5BFC\u5165\u6743\u9650\u3001\u914D\u7F6E\u56DE\u8C03\u3001\u63D0\u4EA4\u7248\u672C\uFF09\u3002","botOnboarding.platformQrAlt":"\u5F00\u653E\u5E73\u53F0\u767B\u5F55\u4E8C\u7EF4\u7801","botOnboarding.completed":"\u673A\u5668\u4EBA\u5DF2\u6DFB\u52A0\u3002","botOnboarding.permissionOk":"\u5DF2\u81EA\u52A8\u5BFC\u5165 {count} \u9879\u6743\u9650\u3002","botOnboarding.permissionSkipped":"\uFF08\u8DF3\u8FC7 {count} \u9879\u5F53\u524D\u79DF\u6237\u76EE\u5F55\u4E2D\u6CA1\u6709\u7684\u6743\u9650\uFF09","botOnboarding.permissionVersion":"\u5DF2\u63D0\u4EA4\u53D1\u5E03\u7248\u672C {version}\u3002","botOnboarding.permissionManual":"\u6743\u9650\u672A\u80FD\u81EA\u52A8\u914D\u7F6E\uFF0C\u8BF7\u624B\u52A8\u5B8C\u6210\u4EE5\u4E0B\u6B65\u9AA4\uFF1A","botOnboarding.metaDir":"\u76EE\u5F55","botOnboarding.failed":"\u6DFB\u52A0\u5931\u8D25","botOnboarding.openLink":"\u6253\u4E0D\u5F00\u626B\u7801\uFF1F\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00","botOnboarding.close":"\u5173\u95ED","botOnboarding.restartHint":"\u5DF2\u5199\u5165 bots.json\u3002\u6267\u884C pnpm daemon:restart \u540E\u65B0\u673A\u5668\u4EBA\u751F\u6548\u3002","botOnboarding.qrAlt":"\u98DE\u4E66\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA\u4E8C\u7EF4\u7801","overview.title":"\u5DE5\u4F5C\u53F0","overview.subtitle":"\u6570\u5B57\u5458\u5DE5\u5B9E\u65F6\u72B6\u6001 \xB7 \u540C\u6B65\u98DE\u4E66\u8BDD\u9898","overview.team":"AI \u56E2\u961F","overview.teamHint":"\u6BCF\u4F4D\u6570\u5B57\u5458\u5DE5\u7684\u5B9E\u65F6\u72B6\u6001","overview.attention":"\u9700\u8981\u4F60\u5904\u7406","overview.attentionHint":"\u5361\u4F4F\u7684\u4EFB\u52A1\uFF0C\u56DE\u4E2A\u8BDD\u5C31\u80FD\u7EE7\u7EED\u8DD1","overview.activeSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.activeSessionsHint":"\u6B63\u5728\u8FD0\u8F6C\u7684\u4F1A\u8BDD","overview.today":"\u6B64\u523B\u6982\u89C8","overview.todayHint":"\u6D3B\u8DC3\u4F1A\u8BDD\u5206\u5E03","overview.viewAll":"\u67E5\u770B\u5168\u90E8 \u2192","overview.botIdle":"\u5F85\u547D\u4E2D\uFF0C\u968F\u65F6\u53EF\u63A5\u65B0\u4EFB\u52A1","overview.botOffline":"\u79BB\u7EBF \u2014 daemon \u672A\u4E0A\u7EBF","overview.botBusy":"\u6267\u884C\u4E2D \xB7 {count} \u4F1A\u8BDD","overview.botNeedsYou":"\u7B49\u4F60\u56DE\u590D","overview.botReady":"\u5C31\u7EEA","overview.botOff":"\u79BB\u7EBF","overview.sessionsCount":"{count} \u4F1A\u8BDD","overview.lastActive":"{time}\u524D\u6D3B\u8DC3","overview.noAttention":"\u6CA1\u6709\u7B49\u4F60\u5904\u7406\u7684\u4E8B\u9879","strip.pending":"{count} \u4EF6\u5F85\u5904\u7406","strip.longest":"\u6700\u4E45\u5DF2\u7B49 {time} \u2014 {bot} {reason}","strip.handle":"\u7ACB\u5373\u5904\u7406","overview.openSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.workingSessions":"\u5DE5\u4F5C\u4E2D","overview.onlineBots":"\u5728\u7EBF Bot","overview.schedules":"\u5B9A\u65F6\u4EFB\u52A1","overview.groups":"\u7FA4\u804A\u8986\u76D6","overview.enabledSchedules":"\u5DF2\u542F\u7528","overview.total":"\u603B\u8BA1","overview.active":"\u6D3B\u8DC3","overview.daemonRegistry":"daemon \u6CE8\u518C\u8868","overview.chatMatrix":"\u7FA4\u804A\u77E9\u9635","overview.recentSessions":"\u6700\u8FD1\u4F1A\u8BDD","overview.nextSchedules":"\u5373\u5C06\u6267\u884C","overview.noSessions":"\u6682\u65E0\u4F1A\u8BDD\u3002","overview.noSchedules":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","sessions.title":"\u4F1A\u8BDD\u63A7\u5236","sessions.subtitle":"\u5B9A\u4F4D\u98DE\u4E66\u8BDD\u9898\u3001\u6253\u5F00 Web Terminal\u3001\u5173\u95ED\u6216\u6062\u590D CLI \u4F1A\u8BDD\u3002","sessions.search":"\u641C\u7D22\u5DE5\u4F5C\u76EE\u5F55 / \u6807\u9898 / ID","sessions.anyStatus":"\u5168\u90E8\u72B6\u6001","sessions.adoptAny":"adopt: \u5168\u90E8","sessions.adoptYes":"adopt: \u662F","sessions.adoptNo":"adopt: \u5426","sessions.activeOnly":"\u4EC5\u6D3B\u8DC3","sessions.closeSelected":"\u5173\u95ED\u9009\u4E2D","sessions.clearSelection":"\u53D6\u6D88\u9009\u62E9","sessions.selectedCount":"\u5DF2\u9009 {count} \u4E2A\u4F1A\u8BDD","sessions.bot":"bot","sessions.cli":"CLI","sessions.chat":"\u7FA4\u804A","sessions.openChat":"\u6253\u5F00\u7FA4\u804A","sessions.status":"\u72B6\u6001","sessions.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","sessions.viewMode":"\u4F1A\u8BDD\u89C6\u56FE","sessions.viewBoard":"\u72B6\u6001\u677F","sessions.viewTable":"\u8868\u683C","sessions.selectSession":"\u9009\u62E9\u4F1A\u8BDD","sessions.board.needsYou":"\u9700\u8981\u4F60","sessions.board.needsYouHint":"\u7B49\u5F85\u4ED3\u5E93\u3001TUI \u9009\u62E9\u6216\u989D\u5EA6\u5904\u7406","sessions.board.starting":"\u542F\u52A8\u4E2D","sessions.board.startingHint":"CLI \u6B63\u5728\u521B\u5EFA\u6216\u6062\u590D","sessions.board.working":"\u5E72\u6D3B\u4E2D","sessions.board.workingHint":"\u6B63\u5728\u8F93\u51FA\u3001\u5206\u6790\u6216\u6267\u884C\u5DE5\u5177","sessions.board.idle":"\u7A7A\u95F2","sessions.board.idleHint":"\u53EF\u7EE7\u7EED\u5BF9\u8BDD\u6216\u63A5\u65B0\u4EFB\u52A1","sessions.board.emptyColumn":"\u6682\u65E0\u4F1A\u8BDD","sessions.board.signalRepo":"\u5F85\u9009\u4ED3\u5E93","sessions.board.signalPrompt":"\u7B49\u5F85 TUI \u9009\u62E9","sessions.board.signalLimited":"\u989D\u5EA6\u53D7\u9650","sessions.board.dragHint":"\u62D6\u52A8\u5217\u5934\u8C03\u6574\u5217\u987A\u5E8F","sessions.board.moveLeft":"\u5DE6\u79FB\u6B64\u5217","sessions.board.moveRight":"\u53F3\u79FB\u6B64\u5217","groups.title":"\u7FA4\u7EC4\u4E0E Bot","groups.subtitle":"\u67E5\u770B chat x bot \u8986\u76D6\u77E9\u9635\uFF0C\u7BA1\u7406\u62C9\u7FA4\u3001oncall\u3001\u9000\u7FA4\u548C\u89E3\u6563\u3002","groups.search":"\u641C\u7D22\u7FA4\u540D / ID / owner","groups.missingOnly":"\u4EC5\u7F3A bot","groups.refresh":"\u5237\u65B0","groups.create":"\u65B0\u5EFA\u7FA4","groups.chat":"\u7FA4\u804A","groups.actions":"\u64CD\u4F5C","groups.addBots":"\u6DFB\u52A0 bot","groups.manage":"\u7BA1\u7406","groups.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u7FA4\u804A\u3002","groups.createTitle":"\u65B0\u5EFA\u7FA4\u804A","groups.createHelp":"\u9009\u62E9\u8981\u9080\u8BF7\u7684 bot\u3002dashboard \u4F1A\u81EA\u52A8\u9009\u62E9\u5728\u7EBF daemon \u4F5C\u4E3A\u521B\u5EFA\u8005\u3002","groups.name":"\u7FA4\u540D","groups.namePlaceholder":"\u4F8B\u5982 AI ChangeLog","groups.bindDir":"\u7ED1\u5B9A\u76EE\u5F55","groups.bindDirHelp":"\u65B0\u8BDD\u9898\u76F4\u63A5\u7528\u8BE5\u76EE\u5F55\u542F\u52A8 CLI\uFF0C\u8DF3\u8FC7 repo \u9009\u62E9\u3002","groups.botPicker":"Bot","groups.createSubmit":"\u521B\u5EFA","groups.cancel":"\u53D6\u6D88","groups.successTitle":"\u7FA4\u521B\u5EFA\u6210\u529F","groups.openGroup":"\u6253\u5F00\u65B0\u7FA4","groups.manageTitle":"\u7BA1\u7406 {name}","groups.owner":"\u7FA4\u4E3B","groups.oncall":"Oncall \u6A21\u5F0F","groups.oncallHelp":"\u5F00\u542F\u540E\uFF0C\u7FA4\u5185\u6210\u5458\u53EF @ \u673A\u5668\u4EBA\uFF1B\u65B0\u8BDD\u9898\u76F4\u63A5\u4F7F\u7528\u7ED1\u5B9A\u76EE\u5F55\u3002","groups.leaveTitle":"\u9009\u62E9\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.leaveSelected":"\u9009\u4E2D\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.disband":"\u89E3\u6563\u7FA4\u804A","groups.dangerHint":"\u89E3\u6563\u4EC5\u5F53\u5728\u7FA4\u673A\u5668\u4EBA\u662F\u7FA4\u4E3B\u65F6\u624D\u4F1A\u6210\u529F\uFF0C\u5426\u5219\u5EFA\u8BAE\u4F7F\u7528\u9000\u51FA\u7FA4\u804A\u3002","groups.save":"\u4FDD\u5B58","groups.needWorkingDir":"\u8BF7\u586B\u5DE5\u4F5C\u76EE\u5F55","groups.noBotsOnline":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u8BF7\u5148\u91CD\u542F daemon\u3002","schedules.title":"\u5B9A\u65F6\u4EFB\u52A1","schedules.subtitle":"\u8DE8 daemon \u67E5\u770B\u3001\u6682\u505C\u3001\u6062\u590D\u548C\u7ACB\u5373\u89E6\u53D1\u5B9A\u65F6\u4EFB\u52A1\u3002","schedules.search":"\u641C\u7D22\u540D\u79F0 / prompt / \u5DE5\u4F5C\u76EE\u5F55","schedules.anyKind":"\u5168\u90E8\u7C7B\u578B","schedules.enabledOnly":"\u4EC5\u542F\u7528","schedules.name":"\u540D\u79F0","schedules.bot":"bot","schedules.schedule":"\u89C4\u5219","schedules.next":"\u4E0B\u6B21","schedules.last":"\u4E0A\u6B21","schedules.repeat":"\u91CD\u590D","schedules.enabled":"\u542F\u7528","schedules.actions":"\u64CD\u4F5C","schedules.runNow":"\u7ACB\u5373\u8FD0\u884C","schedules.pause":"\u6682\u505C","schedules.resume":"\u6062\u590D","schedules.empty":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","settings.title":"\u5168\u5C40\u8BBE\u7F6E","settings.subtitle":"\u7BA1\u7406\u672C\u673A botmux dashboard \u4E0E\u6240\u6709 bot \u5171\u4EAB\u7684\u5168\u5C40\u884C\u4E3A\u3002","settings.loading":"\u6B63\u5728\u52A0\u8F7D\u8BBE\u7F6E\u2026","settings.loadFailed":"\u8BBE\u7F6E\u52A0\u8F7D\u5931\u8D25","settings.readOnlyVisitor":"\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u4FEE\u6539\u8BBE\u7F6E\u9700\u8981\u6388\u6743\u94FE\u63A5\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09","settings.sectionAccess":"\u8BBF\u95EE\u6743\u9650","settings.publicReadOnly":"\u5141\u8BB8\u65E0 token \u53EA\u8BFB\u8BBF\u95EE dashboard","settings.publicReadOnlyHelp":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 token \u7684\u8BBF\u95EE\u8005\u53EF\u4EE5\u67E5\u770B dashboard\u3001\u4F1A\u8BDD\u3001\u5B9A\u65F6\u4EFB\u52A1\u548C SSE\uFF1B\u5173\u95ED\u3001\u6682\u505C\u3001\u5BA1\u6279\u7B49\u5199\u64CD\u4F5C\u4ECD\u5FC5\u987B\u901A\u8FC7 token \u9274\u6743\u3002\u654F\u611F\u7EC8\u7AEF\u539F\u59CB\u65E5\u5FD7\u59CB\u7EC8\u9700\u8981 token\u3002","settings.sectionCards":"\u98DE\u4E66\u5361\u7247","settings.openTerminalInFeishu":"\u6D41\u5F0F\u5361\u7247\u7EC8\u7AEF\u6309\u94AE\u5728\u98DE\u4E66\u4FA7\u680F\u6253\u5F00","settings.openTerminalInFeishuHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF1A\u7EC8\u7AEF\u6309\u94AE\u76F4\u63A5\u6253\u5F00 Web Terminal URL\u3002\u5F00\u542F\u540E\u4F7F\u7528\u98DE\u4E66 web_url/open \u5305\u88C5\uFF0C\u5728\u98DE\u4E66 PC \u4FA7\u680F\u91CC\u6253\u5F00\uFF1B\u5199\u6743\u9650\u4ECD\u7531\u7EC8\u7AEF token \u63A7\u5236\u3002","settings.saving":"\u4FDD\u5B58\u4E2D\u2026","settings.saved":"\u5DF2\u4FDD\u5B58","settings.saveFailed":"\u4FDD\u5B58\u5931\u8D25","botDefaults.title":"\u6570\u5B57\u5458\u5DE5\u6863\u6848","botDefaults.subtitle":"\u6BCF\u4F4D\u5458\u5DE5\u7684\u9ED8\u8BA4\u884C\u4E3A\uFF1Aoncall\u3001\u4E3B\u52A8\u5F00\u5DE5\u3001\u4EBA\u8BBE\u89D2\u8272\u3001\u5361\u7247\u4E0E\u6388\u6743\u3002","botDefaults.metaOnline":"\u5728\u7EBF \xB7 daemon \u6B63\u5E38","botDefaults.search":"\u641C\u7D22 bot \u540D / app id","botDefaults.refresh":"\u5237\u65B0","botDefaults.sectionOncall":"\u65B0\u7FA4 Oncall","botDefaults.sectionBrand":"\u5361\u7247\u7B7E\u540D","botDefaults.warning":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 oncall binding \u7684\u7FA4\u4F1A\u5728\u4E0B\u6B21\u5F00\u65B0\u8BDD\u9898\u65F6\u81EA\u52A8\u7ED1\u5B9A\u5230\u8BE5\u76EE\u5F55\uFF1B\u624B\u52A8\u7ED1\u5B9A\u6216\u624B\u52A8\u89E3\u7ED1\u8FC7\u7684\u7FA4\u4E0D\u4F1A\u88AB\u8986\u76D6\u3002","botDefaults.empty":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u5148 botmux restart \u8BA9 daemon \u4E0A\u7EBF\u3002","botDefaults.defaultOncall":"\u9ED8\u8BA4\u8FDB\u5165 oncall \u6A21\u5F0F","botDefaults.defaultOncallHelp":"\u6240\u6709\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8\u7ED1\u5B9A","botDefaults.workingDir":"\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55","botDefaults.lastEnabled":"\u4E0A\u6B21\u542F\u7528\u65F6\u95F4","botDefaults.autobound":"\u5DF2\u81EA\u52A8\u7ED1\u5B9A {count} \u4E2A\u7FA4","botDefaults.save":"\u4FDD\u5B58","botDefaults.required":"\u5F00\u542F\u65F6\u5FC5\u987B\u586B\u5DE5\u4F5C\u76EE\u5F55","botDefaults.brandLabel":"\u4E2A\u6027\u7B7E\u540D\uFF08\u5361\u7247\u9875\u811A\uFF09","botDefaults.brandLabelHelp":"\u8BE5 bot \u53D1\u51FA\u7684\u5361\u7247\u9875\u811A\u7B7E\u540D\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u4E0D\u663E\u793A\uFF1B\u586B\u5199\uFF1D\u81EA\u5B9A\u4E49\uFF08\u652F\u6301 markdown\uFF0C\u5982 [Acme](https://\u2026)\uFF09\uFF1B\u6062\u590D\u9ED8\u8BA4\uFF1D\u663E\u793A botmux\u3002","botDefaults.brandLabelPlaceholder":"\u9ED8\u8BA4\uFF1Abotmux\uFF08\u7559\u7A7A\u5219\u4E0D\u663E\u793A\uFF09","botDefaults.brandSave":"\u4FDD\u5B58\u7B7E\u540D","botDefaults.brandReset":"\u6062\u590D\u9ED8\u8BA4","botDefaults.brandStateDefault":"\u5F53\u524D\uFF1A\u9ED8\u8BA4 botmux","botDefaults.brandStateOff":"\u5F53\u524D\uFF1A\u5DF2\u5173\u95ED","botDefaults.brandStateCustom":"\u5F53\u524D\uFF1A\u81EA\u5B9A\u4E49","botDefaults.sectionCard":"\u5361\u7247\u884C\u4E3A","botDefaults.disableStreaming":"\u5173\u95ED\u98DE\u4E66\u6D41\u5F0F\u5361\u7247","botDefaults.disableStreamingHelp":"\u4E0D\u518D\u53D1\u5B9E\u65F6\u5237\u65B0\u7684\u4F1A\u8BDD\u72B6\u6001\u5361\uFF08\u542B\u300C\u6253\u5F00\u7EC8\u7AEF\u300D\u5165\u53E3\uFF09\uFF1B\u4EFB\u52A1\u6700\u7EC8\u7ED3\u679C\u4ECD\u901A\u8FC7\u6D88\u606F\u9001\u8FBE\u3002\u9002\u5408\u5ACC\u6D41\u5F0F\u5361\u7247\u70E6\u7684\u573A\u666F\u3002","botDefaults.writableLink":"\u5361\u7247\u4E0A\u76F4\u63A5\u7ED9\u53EF\u64CD\u4F5C\uFF08\u53EF\u5199\uFF09\u7EC8\u7AEF\u94FE\u63A5","botDefaults.writableLinkHelp":"\u26A0\uFE0F \u5728\u6D41\u5F0F\u5361\u7247\u6B63\u6587\u76F4\u63A5\u8D34\u51FA\u53EF\u5199\u7EC8\u7AEF\u94FE\u63A5\uFF0C\u7FA4\u5185\u4EFB\u4F55\u4EBA\u90FD\u80FD\u70B9\u5F00\u5E76\u64CD\u63A7\u7EC8\u7AEF\u3002\u4E0D\u52FE\uFF1D\u4FDD\u6301\u73B0\u72B6\uFF08\u8D70\u300C\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u300D\u6309\u94AE\u79C1\u804A\u53D1\u7ED9\u70B9\u51FB\u8005\uFF09\u3002","botDefaults.writableLinkMoot":"\u5DF2\u5173\u95ED\u6D41\u5F0F\u5361\u7247","botDefaults.privateCard":"/card \u53D1\u79C1\u5BC6\u5361\u7247\uFF08\u4EC5\u6388\u6743\u4EBA\u53EF\u89C1\uFF09","botDefaults.privateCardHelp":"\u5F00\u542F\u540E /card \u6539\u7528\u300C\u4EC5\u7279\u5B9A\u4EBA\u53EF\u89C1\u300D\u7684\u4E34\u65F6\u5361\u7247\uFF1A\u53EA\u53D1\u7ED9 owner\uFF08allowedUsers\uFF09\uFF0C/grant \u6388\u6743\u5BF9\u8BDD\u7684\u4EBA\u548C\u7FA4\u91CC\u5176\u4ED6\u4EBA\u90FD\u770B\u4E0D\u5230\u3002\u4EE3\u4EF7\uFF1A\u662F\u9759\u6001\u5FEB\u7167\u3001\u4E0D\u4F1A\u5B9E\u65F6\u5237\u65B0\uFF1B\u4E14\u4EC5\u666E\u901A\u7FA4\u53EF\u7528\uFF08\u8BDD\u9898\u7FA4 / \u5355\u804A\u4F1A\u5931\u8D25\uFF0C\u4E0D\u964D\u7EA7\uFF09\u3002\u53EA\u5F71\u54CD /card \u547D\u4EE4\uFF0C\u81EA\u52A8\u6D41\u5F0F\u5361\u4E0D\u53D8\u3002","botDefaults.cardPrefSaved":"\u5DF2\u4FDD\u5B58","botDefaults.sectionRole":"\u9ED8\u8BA4\u89D2\u8272","botDefaults.roleHelp":"\u8BE5 bot \u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF08\u8DE8\u7FA4\u751F\u6548\uFF09\uFF0C\u4F1A\u6CE8\u5165\u5230\u8BE5 bot \u5728\u5404\u7FA4\u7684\u4F1A\u8BDD\u91CC\uFF1B\u5355\u4E2A\u7FA4\u53EF\u5728\u300C\u89D2\u8272\u300D\u9875\u5355\u72EC\u8986\u76D6\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u5220\u9664\u3002","botDefaults.rolePlaceholder":"\u4F8B\u5982\uFF1A\u4F60\u662F\u540E\u7AEF\u6392\u969C\u52A9\u624B\uFF0C\u56DE\u7B54\u7B80\u6D01\u3001\u4F18\u5148\u7ED9\u53EF\u6267\u884C\u547D\u4EE4\u2026","botDefaults.roleSave":"\u4FDD\u5B58\u89D2\u8272","botDefaults.roleDelete":"\u5220\u9664","botDefaults.roleSaved":"\u5DF2\u4FDD\u5B58","botDefaults.roleDeleted":"\u5DF2\u5220\u9664","botDefaults.roleLoadErr":"\u89D2\u8272\u52A0\u8F7D\u5931\u8D25","botDefaults.sectionAutoStart":"\u4E3B\u52A8\u5F00\u5DE5","botDefaults.autoStartJoin":"\u88AB\u62C9\u8FDB\u65B0\u7FA4\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartJoinHelp":"\u5F00\u542F\u540E\uFF0C\u673A\u5668\u4EBA\u4E00\u88AB\u62C9\u8FDB\u65B0\u7FA4\uFF08\u7FA4\u91CC\u6709\u6388\u6743\u7528\u6237 allowedUsers \u65F6\uFF09\u5C31\u81EA\u52A8\u5F00\u4E00\u4E2A\u4F1A\u8BDD\u5F00\u59CB\u5DE5\u4F5C\uFF0C\u65E0\u9700 @\u3002\u5728\u673A\u5668\u4EBA\u7684\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55\u542F\u52A8\uFF1B\u672A\u914D\u7F6E\u9ED8\u8BA4\u76EE\u5F55\u65F6\u5148\u5F39\u4ED3\u5E93\u9009\u62E9\u5361\u8BA9\u4F60\u9009\u3002\u524D\u63D0\uFF1A\u9700\u5728\u98DE\u4E66\u5F00\u653E\u5E73\u53F0\u4E3A\u672C\u5E94\u7528\u8BA2\u9605\u300C\u673A\u5668\u4EBA\u8FDB\u7FA4\u300D\u4E8B\u4EF6 im.chat.member.bot.added_v1\uFF0C\u5E76\u5F00\u901A\u7FA4\u6210\u5458\u8BFB\u53D6\u6743\u9650\u3002","botDefaults.autoStartJoinPrompt":"\u5165\u7FA4\u9996\u8F6E prompt\uFF08\u53EF\u9009\uFF09","botDefaults.autoStartJoinPromptPlaceholder":"\u586B\u4E86\uFF1D\u4F5C\u4E3A\u5165\u7FA4\u540E\u7684\u7B2C\u4E00\u6761\u4EFB\u52A1\uFF1B\u7559\u7A7A\uFF1D\u673A\u5668\u4EBA\u81EA\u5DF1\u770B\u7FA4\u91CC\u4FE1\u606F\u51B3\u5B9A\u505A\u4EC0\u4E48","botDefaults.autoStartJoinPromptSave":"\u4FDD\u5B58 prompt","botDefaults.autoStartTopic":"\u8BDD\u9898\u7FA4\u65B0\u8BDD\u9898\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartTopicHelp":"\u5F00\u542F\u540E\uFF0C\u5728\u8BDD\u9898\u7FA4\u91CC\u6BCF\u5F53\u6709\u4EBA\u65B0\u5F00\u4E00\u4E2A\u8BDD\u9898\uFF0C\u673A\u5668\u4EBA\u5C31\u4F1A\u81EA\u52A8\u63A5\u5165\u8BE5\u8BDD\u9898\u3001\u628A\u9996\u6761\u6D88\u606F\u5F53\u4F5C\u4EFB\u52A1\u5F00\u59CB\u5904\u7406\uFF0C\u65E0\u9700 @\u3002\u4EC5\u5BF9\u8BDD\u9898\u7FA4\u751F\u6548\uFF0C\u666E\u901A\u7FA4\u4E0D\u53D7\u5F71\u54CD\u3002","botDefaults.sectionGrant":"\u6388\u6743\u4E0E\u989D\u5EA6","botDefaults.restrictGrant":"\u9650\u5236\u88AB\u6388\u6743\u4EBA\u53EA\u80FD\u7EAF\u5BF9\u8BDD","botDefaults.restrictGrantHelp":"\u5F00\u542F\u540E\uFF0C\u88AB /grant \u6388\u6743\u7684\u4EBA\uFF08owner \u81EA\u5DF1\u4E0D\u53D7\u9650\uFF09\u53EA\u80FD\u53D1\u666E\u901A\u5BF9\u8BDD\uFF0C\u6240\u6709 slash \u547D\u4EE4\u4E00\u5F8B\u62E6\u622A\uFF1Abotmux \u81EA\u5E26\u547D\u4EE4\u3001\u900F\u4F20\u547D\u4EE4\u3001/workflow\u3001/introduce\u3001/t \u4EE5\u53CA CLI \u539F\u751F\u547D\u4EE4\uFF08/help \u7B49\uFF09\u3002\u5F62\u5982 /path/to/file \u7684\u5185\u5BB9\u4E0D\u4F1A\u88AB\u8BEF\u5224\u3002","botDefaults.quotaDefault":"\u9ED8\u8BA4\u6D88\u606F\u989D\u5EA6","botDefaults.quotaPlaceholder":"\u7559\u7A7A\uFF1D\u4E0D\u914D\u7F6E\u9ED8\u8BA4\u989D\u5EA6","botDefaults.quotaHelp":"\u4E0D\u5E26\u6570\u5B57\u7684 /grant @x \u9ED8\u8BA4\u7ED9\u7684\u6D88\u606F\u6761\u6570\u3002\u7559\u7A7A\u6216\u70B9\u300C\u5173\u95ED\u300D\u53EA\u662F\u4E0D\u518D\u7ED9\u88F8 /grant \u5957\u9ED8\u8BA4\u989D\u5EA6\uFF0C\u4E0D\u4F1A\u6E05\u6389\u5DF2\u6709\u7684\u989D\u5EA6\u8BA1\u6570\uFF0C\u4E5F\u4E0D\u5F71\u54CD\u663E\u5F0F /grant @x N\u2014\u2014\u5B83\u4EEC\u7167\u5E38\u7EE7\u7EED enforce\u3002\u989D\u5EA6\u7528\u5C3D\u4F1A\u81EA\u52A8\u64A4\u9500\u8BE5\u4EBA\u6388\u6743\u3002","botDefaults.quotaSave":"\u4FDD\u5B58\u989D\u5EA6","botDefaults.quotaOff":"\u5173\u95ED","botDefaults.quotaInvalid":"\u989D\u5EA6\u5FC5\u987B\u662F\u6B63\u6574\u6570","botDefaults.quotaStateOff":"\u5F53\u524D\uFF1A\u672A\u914D\u7F6E\u9ED8\u8BA4\u989D\u5EA6","botDefaults.quotaStateOn":"\u5F53\u524D\uFF1A\u6BCF\u4EBA {count} \u6761","nav.roles":"\u89D2\u8272\u7BA1\u7406","roles.title":"\u89D2\u8272\u7BA1\u7406","roles.subtitle":"\u4E3A\u6BCF\u4E2A\u7FA4\u7EC4\u7684\u6BCF\u4E2A Bot \u5355\u72EC\u8BBE\u7F6E\u89D2\u8272\u63D0\u793A\u8BCD\uFF0CBot \u5728\u8BE5\u7FA4\u4E2D\u4F1A\u4EE5\u6B64\u89D2\u8272\u884C\u4E8B\u3002","roles.search":"\u641C\u7D22\u7FA4\u540D/Bot/ID","roles.refresh":"\u5237\u65B0","roles.selectHint":"\u2190 \u5C55\u5F00\u7FA4\u7EC4\uFF0C\u9009\u62E9\u4E00\u4E2A Bot \u6765\u7F16\u8F91\u89D2\u8272","roles.editorPlaceholder":`\u8F93\u5165\u89D2\u8272\u63CF\u8FF0\uFF0C\u4F8B\u5982\uFF1A
|
|
2
2
|
\u4F60\u662F\u672C\u7FA4\u7684\u6280\u672F\u987E\u95EE\uFF0C\u8D1F\u8D23\u56DE\u7B54\u6240\u6709\u6280\u672F\u95EE\u9898...`,"roles.configured":"\u5DF2\u914D\u7F6E","roles.unconfigured":"\u672A\u914D\u7F6E","roles.noChats":"\u6682\u65E0\u7FA4\u7EC4","roles.preview":"\u9884\u89C8","roles.previewEmpty":"\uFF08\u7A7A\u5185\u5BB9\uFF09","roles.saved":"\u5DF2\u4FDD\u5B58","roles.delete":"\u5220\u9664","roles.save":"\u4FDD\u5B58","roles.confirmDelete":"\u786E\u8BA4\u5220\u9664\u8BE5 Bot \u5728\u6B64\u7FA4\u7684\u89D2\u8272\u914D\u7F6E\uFF1F","roles.botsWithRoles":"\u4E2A Bot \u5DF2\u914D\u7F6E\u89D2\u8272","roles.emptyError":"\u89D2\u8272\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u8BF7\u5148\u8F93\u5165\u5185\u5BB9","roles.saveFailed":"\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5","common.none":"\u65E0","common.unknown":"\u672A\u77E5","common.now":"\u521A\u521A","common.never":"\u4ECE\u672A","common.all":"\u5168\u90E8","nav.workflows":"\u5DE5\u4F5C\u6D41(beta)","nav.workflowCatalog":"\u76EE\u5F55","workflow.subnav.runs":"\u8FD0\u884C","workflow.subnav.catalog":"\u76EE\u5F55","workflow.searchPlaceholder":"\u641C\u7D22 runId / workflowId / chatId","workflow.filter.nonTerminal":"\u975E\u7EC8\u6001","workflow.filter.all":"\u5168\u90E8","workflow.status.pending":"\u5F85\u5F00\u59CB","workflow.status.running":"\u8FD0\u884C\u4E2D","workflow.status.waiting":"\u7B49\u5F85\u4E2D","workflow.status.effectAttempting":"\u526F\u4F5C\u7528\u4E2D","workflow.status.timedOut":"\u5DF2\u8D85\u65F6","workflow.status.succeeded":"\u6210\u529F","workflow.status.failed":"\u5931\u8D25","workflow.status.cancelled":"\u5DF2\u53D6\u6D88","workflow.table.run":"\u8FD0\u884C","workflow.table.workflow":"\u5DE5\u4F5C\u6D41","workflow.table.status":"\u72B6\u6001","workflow.table.lastSeq":"\u6700\u540E\u5E8F\u53F7","workflow.table.dangling":"\u60AC\u6302 dEf/dAct/dWait","workflow.table.updated":"\u66F4\u65B0\u65F6\u95F4","workflow.table.chatApp":"\u7FA4\u804A / \u5E94\u7528","workflow.list.failedLoad":"\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","workflow.list.noRuns":"\u6CA1\u6709\u5339\u914D\u7684\u8FD0\u884C\u3002","workflow.list.noFilterMatch":"\u6CA1\u6709\u7B26\u5408\u7B5B\u9009\u6761\u4EF6\u7684\u8FD0\u884C\u3002","workflow.list.loaded":"{count} \u4E2A\u8FD0\u884C \xB7 \u5237\u65B0\u4E8E {time}","workflow.list.error":"\u9519\u8BEF\uFF1A{error}","workflow.detail.back":"\u8FD4\u56DE","workflow.detail.loading":"\u52A0\u8F7D\u4E2D...","workflow.detail.loadFailed":"\u52A0\u8F7D\u5931\u8D25","workflow.detail.cancel":"\u53D6\u6D88","workflow.detail.cliCancelOnly":"\u4EC5 CLI \u53EF\u53D6\u6D88","workflow.detail.cancelTitle":"\u53D6\u6D88\u8FD9\u4E2A\u5DE5\u4F5C\u6D41\u8FD0\u884C","workflow.detail.cliCancelTitle":"\u65E0\u6CD5\u5728\u9875\u9762\u53D6\u6D88\uFF1A\u8BF7\u4F7F\u7528 botmux workflow cancel {runId}","workflow.detail.nodes":"\u8282\u70B9 / Activity","workflow.detail.parallel":"\u5E76\u53D1\u6267\u884C","workflow.detail.parallelMeta":"{count} \u6B21\u5C1D\u8BD5 \xB7 \u6700\u9AD8\u5E76\u53D1 {max} \xB7 \u8FD0\u884C\u4E2D {running}","workflow.detail.noParallelData":"\u8FD8\u6CA1\u6709 attempt \u65F6\u95F4\u6570\u636E\u3002","workflow.detail.parallelNow":"\u73B0\u5728","workflow.detail.node":"\u8282\u70B9","workflow.detail.nodeStatus":"\u8282\u70B9\u72B6\u6001","workflow.detail.activity":"Activity","workflow.detail.activityStatus":"Activity \u72B6\u6001","workflow.detail.attempts":"\u5C1D\u8BD5\u6B21\u6570","workflow.detail.current":"\u5F53\u524D\u5C1D\u8BD5","workflow.detail.detail":"\u8BE6\u60C5","workflow.detail.nodeIO":"\u8282\u70B9\u8F93\u5165\u8F93\u51FA","workflow.detail.timeline":"\u65F6\u95F4\u7EBF","workflow.detail.loadOlder":"\u52A0\u8F7D\u66F4\u65E9\u4E8B\u4EF6","workflow.detail.seq":"\u5E8F\u53F7","workflow.detail.actor":"\u6267\u884C\u8005","workflow.detail.error":"\u9519\u8BEF","workflow.detail.event":"\u4E8B\u4EF6","workflow.detail.time":"\u65F6\u95F4","workflow.detail.refreshed":"\u5237\u65B0\u4E8E {time}","workflow.detail.unknownRun":"\u672A\u77E5\u8FD0\u884C","workflow.detail.snapshotHttp":"snapshot HTTP {status}","workflow.detail.eventsHttp":"events HTTP {status}","workflow.detail.cancelUnavailable":"\u65E0\u6CD5\u53D6\u6D88\uFF1A\u8BF7\u4F7F\u7528 botmux workflow cancel {runId}","workflow.detail.cancelConfirm":`\u786E\u8BA4\u53D6\u6D88\u5DE5\u4F5C\u6D41\u8FD0\u884C {runId}\uFF1F
|
|
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"},Lo={"app.name":"botmux","app.subtitle":"Feishu AI CLI Control","time.secondsAgo":"{value}s ago","time.minutesAgo":"{value}m ago","time.hoursAgo":"{value}h ago","nav.overview":"Overview","nav.sessions":"Sessions","nav.groups":"Groups","nav.schedules":"Schedules","nav.settings":"Settings","nav.botDefaults":"Bot Defaults","status.live":"Live","status.disconnected":"Disconnected","status.system":"System","status.light":"Light","status.dark":"Dark","status.language":"Language","status.theme":"Theme","theme.base":"Basic","theme.skins":"Skins","skin.cyber":"2077","skin.genshin":"Genshin","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"Blue Archive","skin.zzz":"ZZZ","skin.dragonball":"Dragon Ball","skin.ikun":"ikun","botOnboarding.add":"Add Bot","botOnboarding.title":"Add Bot","botOnboarding.intro":"Pick a CLI and working directory, scan to create a PersonalAgent app \u2014 the dashboard writes it to local bots.json and auto-configures Open Platform permissions.","botOnboarding.cliLabel":"CLI adapter","botOnboarding.dirLabel":"Working directory","botOnboarding.dirPlaceholder":"Default ~ (home); must exist on the daemon host","botOnboarding.modelLabel":"Model (optional)","botOnboarding.modelPlaceholder":"Leave empty for the CLI default model","botOnboarding.startScan":"Start scan","botOnboarding.cancel":"Cancel","botOnboarding.starting":"Generating QR code...","botOnboarding.waiting":"Scan with the Feishu app to create the app.","botOnboarding.verifying":"Scan accepted. Verifying credentials...","botOnboarding.configuringPermissions":"Auto-configuring Open Platform permissions\u2026","botOnboarding.platformScanHint":"Scan once more with the Feishu app to sign in to the Open Platform (to auto-import permissions, set the callback, and submit a version).","botOnboarding.platformQrAlt":"Open Platform login QR code","botOnboarding.completed":"Bot added.","botOnboarding.permissionOk":"Auto-imported {count} permissions.","botOnboarding.permissionSkipped":"({count} skipped \u2014 not in the tenant catalog)","botOnboarding.permissionVersion":"Submitted version {version}.","botOnboarding.permissionManual":"Permissions could not be auto-configured. Complete these steps manually:","botOnboarding.metaDir":"Dir","botOnboarding.failed":"Add failed","botOnboarding.openLink":"Open scan link in browser","botOnboarding.close":"Close","botOnboarding.restartHint":"bots.json has been updated. Run pnpm daemon:restart for the new bot to take effect.","botOnboarding.qrAlt":"Feishu bot onboarding QR code","overview.title":"Workbench","overview.subtitle":"Live status of your AI teammates \xB7 synced with Feishu topics","overview.team":"AI Team","overview.teamHint":"Live status of every digital teammate","overview.attention":"Needs You","overview.attentionHint":"Blocked tasks \u2014 one reply gets them moving again","overview.activeSessions":"Active Sessions","overview.activeSessionsHint":"Sessions currently running","overview.today":"Right Now","overview.todayHint":"Active session distribution","overview.viewAll":"View all \u2192","overview.botIdle":"Standing by, ready for new tasks","overview.botOffline":"Offline \u2014 daemon not running","overview.botBusy":"Working \xB7 {count} sessions","overview.botNeedsYou":"Waiting on you","overview.botReady":"Ready","overview.botOff":"Offline","overview.sessionsCount":"{count} sessions","overview.lastActive":"active {time} ago","overview.noAttention":"Nothing waiting on you","strip.pending":"{count} pending","strip.longest":"waiting {time} \u2014 {bot} {reason}","strip.handle":"Handle now","overview.openSessions":"Active Sessions","overview.workingSessions":"Working","overview.onlineBots":"Online Bots","overview.schedules":"Schedules","overview.groups":"Groups Seen","overview.enabledSchedules":"Enabled","overview.total":"total","overview.active":"active","overview.daemonRegistry":"daemon registry","overview.chatMatrix":"chat matrix","overview.recentSessions":"Recent Sessions","overview.nextSchedules":"Next Runs","overview.noSessions":"No sessions yet.","overview.noSchedules":"No schedules yet.","sessions.title":"Session Control","sessions.subtitle":"Locate Feishu topics, open Web Terminal, close or resume CLI sessions.","sessions.search":"Search working dir / title / IDs","sessions.anyStatus":"Any status","sessions.adoptAny":"adopt: any","sessions.adoptYes":"adopt: yes","sessions.adoptNo":"adopt: no","sessions.activeOnly":"Active only","sessions.closeSelected":"Close selected","sessions.clearSelection":"Clear","sessions.selectedCount":"{count} sessions selected","sessions.bot":"Bot","sessions.cli":"CLI","sessions.chat":"Chat","sessions.openChat":"Open chat","sessions.status":"Status","sessions.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.","sessions.viewMode":"Session view","sessions.viewBoard":"Board","sessions.viewTable":"Table","sessions.selectSession":"Select session","sessions.board.needsYou":"Needs You","sessions.board.needsYouHint":"Repo, TUI, or usage limit waiting","sessions.board.starting":"Starting","sessions.board.startingHint":"CLI is spawning or resuming","sessions.board.working":"Working","sessions.board.workingHint":"Streaming, analyzing, or using tools","sessions.board.idle":"Idle","sessions.board.idleHint":"Ready for the next message","sessions.board.emptyColumn":"No sessions","sessions.board.signalRepo":"Repo needed","sessions.board.signalPrompt":"TUI choice needed","sessions.board.signalLimited":"Usage limited","sessions.board.dragHint":"Drag header to reorder columns","sessions.board.moveLeft":"Move column left","sessions.board.moveRight":"Move column right","groups.title":"Groups & Bots","groups.subtitle":"Inspect the chat x bot matrix and manage group creation, oncall, leave, and disband flows.","groups.search":"Search chat name / ID / owner","groups.missingOnly":"Missing bot only","groups.refresh":"Refresh","groups.create":"New Group","groups.chat":"Chat","groups.actions":"Actions","groups.addBots":"Add Bots","groups.manage":"Manage","groups.empty":"No chats match the filters.","groups.createTitle":"Create New Group","groups.createHelp":"Pick bots to invite. The dashboard chooses an online daemon as creator.","groups.name":"Group Name","groups.namePlaceholder":"e.g. AI ChangeLog","groups.bindDir":"Bind Directory","groups.bindDirHelp":"New topics start the CLI here and skip repo selection.","groups.botPicker":"Bots","groups.createSubmit":"Create","groups.cancel":"Cancel","groups.successTitle":"Group Created","groups.openGroup":"Open Group","groups.manageTitle":"Manage {name}","groups.owner":"Owner","groups.oncall":"Oncall Mode","groups.oncallHelp":"When enabled, group members can @ the bot; new topics use the bound directory.","groups.leaveTitle":"Select Bots to Leave","groups.leaveSelected":"Selected Bots Leave","groups.disband":"Disband Group","groups.dangerHint":"Disband only works when an in-chat bot is the owner. Otherwise prefer leaving the chat.","groups.save":"Save","groups.needWorkingDir":"Working directory is required","groups.noBotsOnline":"No bots online. Restart the daemon first.","schedules.title":"Schedules","schedules.subtitle":"View, pause, resume, and run scheduled tasks across daemons.","schedules.search":"Search name / prompt / working dir","schedules.anyKind":"Any kind","schedules.enabledOnly":"Enabled only","schedules.name":"Name","schedules.bot":"Bot","schedules.schedule":"Schedule","schedules.next":"Next","schedules.last":"Last","schedules.repeat":"Repeat","schedules.enabled":"Enabled","schedules.actions":"Actions","schedules.runNow":"Run Now","schedules.pause":"Pause","schedules.resume":"Resume","schedules.empty":"No schedules.","settings.title":"Global Settings","settings.subtitle":"Manage machine-wide botmux dashboard behavior shared by every bot.","settings.loading":"Loading settings\u2026","settings.loadFailed":"Failed to load settings","settings.readOnlyVisitor":"Read-only access \u2014 changing settings requires an authorized link (run botmux dashboard).","settings.sectionAccess":"Access","settings.publicReadOnly":"Allow tokenless read-only dashboard access","settings.publicReadOnlyHelp":"When enabled, visitors without a token can view the dashboard, sessions, schedules, and SSE. Writes such as close, pause, and approvals still require token auth. Sensitive raw terminal logs always require a token.","settings.sectionCards":"Feishu Cards","settings.openTerminalInFeishu":"Open streaming-card terminals in the Feishu sidebar","settings.openTerminalInFeishuHelp":"Off by default: terminal buttons open the Web Terminal URL directly. When enabled, botmux wraps the URL with Feishu web_url/open so Feishu PC opens it in a sidebar. Terminal write access is still controlled by its token.","settings.saving":"Saving\u2026","settings.saved":"Saved","settings.saveFailed":"Save failed","botDefaults.title":"Bot Profiles","botDefaults.subtitle":"Per-bot defaults: oncall, proactive start, persona role, cards and grants.","botDefaults.metaOnline":"Online \xB7 daemon healthy","botDefaults.search":"Search bot name / app id","botDefaults.refresh":"Refresh","botDefaults.sectionOncall":"New-chat Oncall","botDefaults.sectionBrand":"Card Signature","botDefaults.warning":"When enabled, chats without an oncall binding auto-bind to this directory on their next new topic. Manually bound or unbound chats are preserved.","botDefaults.empty":"No bots online. Run botmux restart first.","botDefaults.defaultOncall":"Default to oncall mode","botDefaults.defaultOncallHelp":"Unbound chats auto-bind on the next new topic","botDefaults.workingDir":"Default Working Directory","botDefaults.lastEnabled":"Last Enabled","botDefaults.autobound":"{count} chats auto-bound","botDefaults.save":"Save","botDefaults.required":"Working directory is required when enabled","botDefaults.brandLabel":"Signature (card footer)","botDefaults.brandLabelHelp":"Footer signature on cards this bot sends. Save empty = hide; fill in = custom (markdown ok, e.g. [Acme](https://\u2026)); Reset = show botmux.","botDefaults.brandLabelPlaceholder":"Default: botmux (empty = hidden)","botDefaults.brandSave":"Save Signature","botDefaults.brandReset":"Reset to default","botDefaults.brandStateDefault":"Current: default botmux","botDefaults.brandStateOff":"Current: off","botDefaults.brandStateCustom":"Current: custom","botDefaults.sectionCard":"Card Behavior","botDefaults.disableStreaming":"Disable streaming card","botDefaults.disableStreamingHelp":"Stop posting the live session status card (and its Open Terminal entry). The task's final result still arrives as a message. For those who find the live card noisy.","botDefaults.writableLink":"Put a writable terminal link on the card","botDefaults.writableLinkHelp":'\u26A0\uFE0F Embeds a writable terminal link in the streaming card body \u2014 anyone in the chat can open and drive the terminal. Off = current behavior (private DM via the "Get Write Link" button).',"botDefaults.writableLinkMoot":"Streaming card disabled \u2014 this has no effect","botDefaults.privateCard":"/card sends a private card (authorized users only)","botDefaults.privateCardHelp":'Makes /card send an ephemeral "visible-to-specific-people" card: delivered only to the owner (allowedUsers); /grant-authorized talk users and everyone else in the chat cannot see it. Trade-off: it is a static snapshot (no live updates) and only works in regular group chats (topic groups / DMs fail, with no fallback). Affects only the /card command; the auto streaming card is unchanged.',"botDefaults.cardPrefSaved":"Saved","botDefaults.sectionRole":"Default Role","botDefaults.roleHelp":"This bot's default persona (applies across all chats), injected into the bot's sessions in every chat; a single group can override it on the Roles page. Save empty = delete.","botDefaults.rolePlaceholder":"e.g. You are a backend triage assistant; answer concisely, prefer runnable commands\u2026","botDefaults.roleSave":"Save role","botDefaults.roleDelete":"Delete","botDefaults.roleSaved":"Saved","botDefaults.roleDeleted":"Deleted","botDefaults.roleLoadErr":"Failed to load role","botDefaults.sectionAutoStart":"Proactive Start","botDefaults.autoStartJoin":"Auto-start when added to a new chat","botDefaults.autoStartJoinHelp":'When enabled, the bot auto-starts a session and gets to work the moment it is added to a new chat (when an authorized user / allowedUsers is a member), no @ needed. It launches in the bot default working dir; if none is configured it shows a repo-select card first. Prerequisite: subscribe the "bot joined chat" event im.chat.member.bot.added_v1 for this app and grant the member-read scope in the Feishu console.',"botDefaults.autoStartJoinPrompt":"First-turn prompt on join (optional)","botDefaults.autoStartJoinPromptPlaceholder":"Filled = used as the first task after joining; blank = the bot reads the chat and decides what to do","botDefaults.autoStartJoinPromptSave":"Save prompt","botDefaults.autoStartTopic":"Auto-start on new topics in topic groups","botDefaults.autoStartTopicHelp":"When enabled, in a topic group the bot automatically joins each newly opened topic and starts working on its first message, no @ needed. Topic groups only \u2014 regular groups are unaffected.","botDefaults.sectionGrant":"Authorization & Quota","botDefaults.restrictGrant":"Restrict grantees to plain conversation","botDefaults.restrictGrantHelp":"When enabled, /grant-authorized users (the owner is exempt) can only send plain messages; every slash command is blocked: botmux built-in commands, passthrough commands, /workflow, /introduce, /t, and CLI-native commands (/help, etc.). Text like /path/to/file is not misclassified.","botDefaults.quotaDefault":"Default message quota","botDefaults.quotaPlaceholder":"Empty = no default quota","botDefaults.quotaHelp":'Message count a bare /grant @x (no number) hands out. Empty or "Turn off" merely stops applying a default to bare /grant \u2014 it does NOT clear existing quota counters, nor affect an explicit /grant @x N; those keep being enforced. Authorization is auto-revoked once a quota runs out.',"botDefaults.quotaSave":"Save quota","botDefaults.quotaOff":"Turn off","botDefaults.quotaInvalid":"Quota must be a positive integer","botDefaults.quotaStateOff":"Current: no default quota","botDefaults.quotaStateOn":"Current: {count} per grantee","nav.roles":"Roles","roles.title":"Role Management","roles.subtitle":"Set per-bot role prompts for each group. Each bot adopts its own persona in the selected group.","roles.search":"Search group / bot / ID","roles.refresh":"Refresh","roles.selectHint":"\u2190 Expand a group and select a bot to edit its role","roles.editorPlaceholder":`Enter role description, e.g.:
|
|
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"},Co={"app.name":"botmux","app.subtitle":"Feishu AI CLI Control","time.secondsAgo":"{value}s ago","time.minutesAgo":"{value}m ago","time.hoursAgo":"{value}h ago","nav.overview":"Overview","nav.sessions":"Sessions","nav.groups":"Groups","nav.schedules":"Schedules","nav.settings":"Settings","nav.botDefaults":"Bot Defaults","status.live":"Live","status.disconnected":"Disconnected","status.system":"System","status.light":"Light","status.dark":"Dark","status.language":"Language","status.theme":"Theme","theme.base":"Basic","theme.skins":"Skins","skin.cyber":"2077","skin.genshin":"Genshin","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"Blue Archive","skin.zzz":"ZZZ","skin.dragonball":"Dragon Ball","skin.ikun":"ikun","botOnboarding.add":"Add Bot","botOnboarding.title":"Add Bot","botOnboarding.intro":"Pick a CLI and working directory, scan to create a PersonalAgent app \u2014 the dashboard writes it to local bots.json and auto-configures Open Platform permissions.","botOnboarding.cliLabel":"CLI adapter","botOnboarding.dirLabel":"Working directory","botOnboarding.dirPlaceholder":"Default ~ (home); must exist on the daemon host","botOnboarding.modelLabel":"Model (optional)","botOnboarding.modelPlaceholder":"Leave empty for the CLI default model","botOnboarding.startScan":"Start scan","botOnboarding.cancel":"Cancel","botOnboarding.starting":"Generating QR code...","botOnboarding.waiting":"Scan with the Feishu app to create the app.","botOnboarding.verifying":"Scan accepted. Verifying credentials...","botOnboarding.configuringPermissions":"Auto-configuring Open Platform permissions\u2026","botOnboarding.platformScanHint":"Scan once more with the Feishu app to sign in to the Open Platform (to auto-import permissions, set the callback, and submit a version).","botOnboarding.platformQrAlt":"Open Platform login QR code","botOnboarding.completed":"Bot added.","botOnboarding.permissionOk":"Auto-imported {count} permissions.","botOnboarding.permissionSkipped":"({count} skipped \u2014 not in the tenant catalog)","botOnboarding.permissionVersion":"Submitted version {version}.","botOnboarding.permissionManual":"Permissions could not be auto-configured. Complete these steps manually:","botOnboarding.metaDir":"Dir","botOnboarding.failed":"Add failed","botOnboarding.openLink":"Open scan link in browser","botOnboarding.close":"Close","botOnboarding.restartHint":"bots.json has been updated. Run pnpm daemon:restart for the new bot to take effect.","botOnboarding.qrAlt":"Feishu bot onboarding QR code","overview.title":"Workbench","overview.subtitle":"Live status of your AI teammates \xB7 synced with Feishu topics","overview.team":"AI Team","overview.teamHint":"Live status of every digital teammate","overview.attention":"Needs You","overview.attentionHint":"Blocked tasks \u2014 one reply gets them moving again","overview.activeSessions":"Active Sessions","overview.activeSessionsHint":"Sessions currently running","overview.today":"Right Now","overview.todayHint":"Active session distribution","overview.viewAll":"View all \u2192","overview.botIdle":"Standing by, ready for new tasks","overview.botOffline":"Offline \u2014 daemon not running","overview.botBusy":"Working \xB7 {count} sessions","overview.botNeedsYou":"Waiting on you","overview.botReady":"Ready","overview.botOff":"Offline","overview.sessionsCount":"{count} sessions","overview.lastActive":"active {time} ago","overview.noAttention":"Nothing waiting on you","strip.pending":"{count} pending","strip.longest":"waiting {time} \u2014 {bot} {reason}","strip.handle":"Handle now","overview.openSessions":"Active Sessions","overview.workingSessions":"Working","overview.onlineBots":"Online Bots","overview.schedules":"Schedules","overview.groups":"Groups Seen","overview.enabledSchedules":"Enabled","overview.total":"total","overview.active":"active","overview.daemonRegistry":"daemon registry","overview.chatMatrix":"chat matrix","overview.recentSessions":"Recent Sessions","overview.nextSchedules":"Next Runs","overview.noSessions":"No sessions yet.","overview.noSchedules":"No schedules yet.","sessions.title":"Session Control","sessions.subtitle":"Locate Feishu topics, open Web Terminal, close or resume CLI sessions.","sessions.search":"Search working dir / title / IDs","sessions.anyStatus":"Any status","sessions.adoptAny":"adopt: any","sessions.adoptYes":"adopt: yes","sessions.adoptNo":"adopt: no","sessions.activeOnly":"Active only","sessions.closeSelected":"Close selected","sessions.clearSelection":"Clear","sessions.selectedCount":"{count} sessions selected","sessions.bot":"Bot","sessions.cli":"CLI","sessions.chat":"Chat","sessions.openChat":"Open chat","sessions.status":"Status","sessions.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.","sessions.viewMode":"Session view","sessions.viewBoard":"Board","sessions.viewTable":"Table","sessions.selectSession":"Select session","sessions.board.needsYou":"Needs You","sessions.board.needsYouHint":"Repo, TUI, or usage limit waiting","sessions.board.starting":"Starting","sessions.board.startingHint":"CLI is spawning or resuming","sessions.board.working":"Working","sessions.board.workingHint":"Streaming, analyzing, or using tools","sessions.board.idle":"Idle","sessions.board.idleHint":"Ready for the next message","sessions.board.emptyColumn":"No sessions","sessions.board.signalRepo":"Repo needed","sessions.board.signalPrompt":"TUI choice needed","sessions.board.signalLimited":"Usage limited","sessions.board.dragHint":"Drag header to reorder columns","sessions.board.moveLeft":"Move column left","sessions.board.moveRight":"Move column right","groups.title":"Groups & Bots","groups.subtitle":"Inspect the chat x bot matrix and manage group creation, oncall, leave, and disband flows.","groups.search":"Search chat name / ID / owner","groups.missingOnly":"Missing bot only","groups.refresh":"Refresh","groups.create":"New Group","groups.chat":"Chat","groups.actions":"Actions","groups.addBots":"Add Bots","groups.manage":"Manage","groups.empty":"No chats match the filters.","groups.createTitle":"Create New Group","groups.createHelp":"Pick bots to invite. The dashboard chooses an online daemon as creator.","groups.name":"Group Name","groups.namePlaceholder":"e.g. AI ChangeLog","groups.bindDir":"Bind Directory","groups.bindDirHelp":"New topics start the CLI here and skip repo selection.","groups.botPicker":"Bots","groups.createSubmit":"Create","groups.cancel":"Cancel","groups.successTitle":"Group Created","groups.openGroup":"Open Group","groups.manageTitle":"Manage {name}","groups.owner":"Owner","groups.oncall":"Oncall Mode","groups.oncallHelp":"When enabled, group members can @ the bot; new topics use the bound directory.","groups.leaveTitle":"Select Bots to Leave","groups.leaveSelected":"Selected Bots Leave","groups.disband":"Disband Group","groups.dangerHint":"Disband only works when an in-chat bot is the owner. Otherwise prefer leaving the chat.","groups.save":"Save","groups.needWorkingDir":"Working directory is required","groups.noBotsOnline":"No bots online. Restart the daemon first.","schedules.title":"Schedules","schedules.subtitle":"View, pause, resume, and run scheduled tasks across daemons.","schedules.search":"Search name / prompt / working dir","schedules.anyKind":"Any kind","schedules.enabledOnly":"Enabled only","schedules.name":"Name","schedules.bot":"Bot","schedules.schedule":"Schedule","schedules.next":"Next","schedules.last":"Last","schedules.repeat":"Repeat","schedules.enabled":"Enabled","schedules.actions":"Actions","schedules.runNow":"Run Now","schedules.pause":"Pause","schedules.resume":"Resume","schedules.empty":"No schedules.","settings.title":"Global Settings","settings.subtitle":"Manage machine-wide botmux dashboard behavior shared by every bot.","settings.loading":"Loading settings\u2026","settings.loadFailed":"Failed to load settings","settings.readOnlyVisitor":"Read-only access \u2014 changing settings requires an authorized link (run botmux dashboard).","settings.sectionAccess":"Access","settings.publicReadOnly":"Allow tokenless read-only dashboard access","settings.publicReadOnlyHelp":"When enabled, visitors without a token can view the dashboard, sessions, schedules, and SSE. Writes such as close, pause, and approvals still require token auth. Sensitive raw terminal logs always require a token.","settings.sectionCards":"Feishu Cards","settings.openTerminalInFeishu":"Open streaming-card terminals in the Feishu sidebar","settings.openTerminalInFeishuHelp":"Off by default: terminal buttons open the Web Terminal URL directly. When enabled, botmux wraps the URL with Feishu web_url/open so Feishu PC opens it in a sidebar. Terminal write access is still controlled by its token.","settings.saving":"Saving\u2026","settings.saved":"Saved","settings.saveFailed":"Save failed","botDefaults.title":"Bot Profiles","botDefaults.subtitle":"Per-bot defaults: oncall, proactive start, persona role, cards and grants.","botDefaults.metaOnline":"Online \xB7 daemon healthy","botDefaults.search":"Search bot name / app id","botDefaults.refresh":"Refresh","botDefaults.sectionOncall":"New-chat Oncall","botDefaults.sectionBrand":"Card Signature","botDefaults.warning":"When enabled, chats without an oncall binding auto-bind to this directory on their next new topic. Manually bound or unbound chats are preserved.","botDefaults.empty":"No bots online. Run botmux restart first.","botDefaults.defaultOncall":"Default to oncall mode","botDefaults.defaultOncallHelp":"Unbound chats auto-bind on the next new topic","botDefaults.workingDir":"Default Working Directory","botDefaults.lastEnabled":"Last Enabled","botDefaults.autobound":"{count} chats auto-bound","botDefaults.save":"Save","botDefaults.required":"Working directory is required when enabled","botDefaults.brandLabel":"Signature (card footer)","botDefaults.brandLabelHelp":"Footer signature on cards this bot sends. Save empty = hide; fill in = custom (markdown ok, e.g. [Acme](https://\u2026)); Reset = show botmux.","botDefaults.brandLabelPlaceholder":"Default: botmux (empty = hidden)","botDefaults.brandSave":"Save Signature","botDefaults.brandReset":"Reset to default","botDefaults.brandStateDefault":"Current: default botmux","botDefaults.brandStateOff":"Current: off","botDefaults.brandStateCustom":"Current: custom","botDefaults.sectionCard":"Card Behavior","botDefaults.disableStreaming":"Disable streaming card","botDefaults.disableStreamingHelp":"Stop posting the live session status card (and its Open Terminal entry). The task's final result still arrives as a message. For those who find the live card noisy.","botDefaults.writableLink":"Put a writable terminal link on the card","botDefaults.writableLinkHelp":'\u26A0\uFE0F Embeds a writable terminal link in the streaming card body \u2014 anyone in the chat can open and drive the terminal. Off = current behavior (private DM via the "Get Write Link" button).',"botDefaults.writableLinkMoot":"Streaming card disabled \u2014 this has no effect","botDefaults.privateCard":"/card sends a private card (authorized users only)","botDefaults.privateCardHelp":'Makes /card send an ephemeral "visible-to-specific-people" card: delivered only to the owner (allowedUsers); /grant-authorized talk users and everyone else in the chat cannot see it. Trade-off: it is a static snapshot (no live updates) and only works in regular group chats (topic groups / DMs fail, with no fallback). Affects only the /card command; the auto streaming card is unchanged.',"botDefaults.cardPrefSaved":"Saved","botDefaults.sectionRole":"Default Role","botDefaults.roleHelp":"This bot's default persona (applies across all chats), injected into the bot's sessions in every chat; a single group can override it on the Roles page. Save empty = delete.","botDefaults.rolePlaceholder":"e.g. You are a backend triage assistant; answer concisely, prefer runnable commands\u2026","botDefaults.roleSave":"Save role","botDefaults.roleDelete":"Delete","botDefaults.roleSaved":"Saved","botDefaults.roleDeleted":"Deleted","botDefaults.roleLoadErr":"Failed to load role","botDefaults.sectionAutoStart":"Proactive Start","botDefaults.autoStartJoin":"Auto-start when added to a new chat","botDefaults.autoStartJoinHelp":'When enabled, the bot auto-starts a session and gets to work the moment it is added to a new chat (when an authorized user / allowedUsers is a member), no @ needed. It launches in the bot default working dir; if none is configured it shows a repo-select card first. Prerequisite: subscribe the "bot joined chat" event im.chat.member.bot.added_v1 for this app and grant the member-read scope in the Feishu console.',"botDefaults.autoStartJoinPrompt":"First-turn prompt on join (optional)","botDefaults.autoStartJoinPromptPlaceholder":"Filled = used as the first task after joining; blank = the bot reads the chat and decides what to do","botDefaults.autoStartJoinPromptSave":"Save prompt","botDefaults.autoStartTopic":"Auto-start on new topics in topic groups","botDefaults.autoStartTopicHelp":"When enabled, in a topic group the bot automatically joins each newly opened topic and starts working on its first message, no @ needed. Topic groups only \u2014 regular groups are unaffected.","botDefaults.sectionGrant":"Authorization & Quota","botDefaults.restrictGrant":"Restrict grantees to plain conversation","botDefaults.restrictGrantHelp":"When enabled, /grant-authorized users (the owner is exempt) can only send plain messages; every slash command is blocked: botmux built-in commands, passthrough commands, /workflow, /introduce, /t, and CLI-native commands (/help, etc.). Text like /path/to/file is not misclassified.","botDefaults.quotaDefault":"Default message quota","botDefaults.quotaPlaceholder":"Empty = no default quota","botDefaults.quotaHelp":'Message count a bare /grant @x (no number) hands out. Empty or "Turn off" merely stops applying a default to bare /grant \u2014 it does NOT clear existing quota counters, nor affect an explicit /grant @x N; those keep being enforced. Authorization is auto-revoked once a quota runs out.',"botDefaults.quotaSave":"Save quota","botDefaults.quotaOff":"Turn off","botDefaults.quotaInvalid":"Quota must be a positive integer","botDefaults.quotaStateOff":"Current: no default quota","botDefaults.quotaStateOn":"Current: {count} per grantee","nav.roles":"Roles","roles.title":"Role Management","roles.subtitle":"Set per-bot role prompts for each group. Each bot adopts its own persona in the selected group.","roles.search":"Search group / bot / ID","roles.refresh":"Refresh","roles.selectHint":"\u2190 Expand a group and select a bot to edit its role","roles.editorPlaceholder":`Enter role description, e.g.:
|
|
8
8
|
You are a code reviewer for this group...`,"roles.configured":"Configured","roles.unconfigured":"None","roles.noChats":"No groups","roles.preview":"Preview","roles.previewEmpty":"(empty)","roles.saved":"Saved","roles.delete":"Delete","roles.save":"Save","roles.confirmDelete":"Delete this bot's role config for this group?","roles.botsWithRoles":"bots configured","roles.emptyError":"Role content cannot be empty","roles.saveFailed":"Save failed, please retry","common.none":"None","common.unknown":"Unknown","common.now":"now","common.never":"never","common.all":"All","nav.workflows":"Workflows (beta)","nav.workflowCatalog":"Catalog","workflow.subnav.runs":"Runs","workflow.subnav.catalog":"Catalog","workflow.searchPlaceholder":"search runId / workflowId / chatId","workflow.filter.nonTerminal":"non-terminal","workflow.filter.all":"all","workflow.status.pending":"pending","workflow.status.running":"running","workflow.status.waiting":"waiting","workflow.status.effectAttempting":"effect","workflow.status.timedOut":"timed out","workflow.status.succeeded":"succeeded","workflow.status.failed":"failed","workflow.status.cancelled":"cancelled","workflow.table.run":"run","workflow.table.workflow":"workflow","workflow.table.status":"status","workflow.table.lastSeq":"lastSeq","workflow.table.dangling":"dEf/dAct/dWait","workflow.table.updated":"updated","workflow.table.chatApp":"chat / app","workflow.list.failedLoad":"Failed to load: {error}","workflow.list.noRuns":"No runs match.","workflow.list.noFilterMatch":"No runs match this filter.","workflow.list.loaded":"{count} runs \xB7 refreshed {time}","workflow.list.error":"error: {error}","workflow.detail.back":"Back","workflow.detail.loading":"Loading...","workflow.detail.loadFailed":"Load failed","workflow.detail.cancel":"Cancel","workflow.detail.cliCancelOnly":"CLI cancel only","workflow.detail.cancelTitle":"Cancel this workflow run","workflow.detail.cliCancelTitle":"Cancel unavailable: use botmux workflow cancel {runId}","workflow.detail.nodes":"Nodes / Activities","workflow.detail.parallel":"Parallel execution","workflow.detail.parallelMeta":"{count} attempt(s) \xB7 max parallel {max} \xB7 running {running}","workflow.detail.noParallelData":"No attempt timing data yet.","workflow.detail.parallelNow":"now","workflow.detail.node":"node","workflow.detail.nodeStatus":"node status","workflow.detail.activity":"activity","workflow.detail.activityStatus":"activity status","workflow.detail.attempts":"attempts","workflow.detail.current":"current","workflow.detail.detail":"detail","workflow.detail.nodeIO":"Node I/O","workflow.detail.timeline":"Timeline","workflow.detail.loadOlder":"Load older","workflow.detail.seq":"seq","workflow.detail.actor":"actor","workflow.detail.error":"error","workflow.detail.event":"event","workflow.detail.time":"time","workflow.detail.refreshed":"refreshed {time}","workflow.detail.unknownRun":"unknown run","workflow.detail.snapshotHttp":"snapshot HTTP {status}","workflow.detail.eventsHttp":"events HTTP {status}","workflow.detail.cancelUnavailable":"cancel unavailable: use botmux workflow cancel {runId}","workflow.detail.cancelConfirm":`Cancel workflow run {runId}?
|
|
9
9
|
|
|
10
10
|
{total} dangling item(s) will be handled by cancel-driven recovery.
|
|
11
11
|
effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"workflow.detail.writeAccessCancel":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and click cancel again.","workflow.detail.cancelHttp":"cancel HTTP {status}","workflow.detail.cancelPending":"cancel pending; waiting for running activity to drain","workflow.detail.writeAccessApproval":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and approve/reject again.","workflow.detail.actionHttp":"{action} HTTP {status}","workflow.detail.approved":"approved","workflow.detail.rejected":"rejected","workflow.detail.alreadyTerminal":"Run already terminal; {label} was not applied.","workflow.detail.workflowContinue":"{label}; waiting for workflow to continue.","workflow.detail.workflowRefreshing":"{label}; refreshing workflow state.","workflow.detail.eventsLoaded":"{loaded}/{total} events loaded","workflow.detail.dangling":"Dangling","workflow.detail.noDangling":"No dangling work.","workflow.detail.none":"none","workflow.detail.noNodes":"No nodes yet.","workflow.detail.idle":"idle","workflow.detail.noNodeIO":"No node I/O yet.","workflow.detail.notDispatched":"not dispatched","workflow.detail.noAttempt":"No attempt yet","workflow.detail.attempt":"attempt","workflow.detail.authoredInput":"Authored input","workflow.detail.resolvedInput":"Resolved input","workflow.detail.output":"Output","workflow.detail.executionLog":"Execution log","workflow.detail.liveTerminal":"Live terminal","workflow.detail.terminalLive":"live","workflow.detail.terminalClosedShort":"closed","workflow.detail.terminalClosed":"Terminal is closed. Use the execution log below for the final transcript.","workflow.detail.openTerminalNewTab":"Open terminal in new tab","workflow.detail.terminalReplay":"Terminal replay","workflow.detail.openReplayNewTab":"Open replay in new tab","workflow.detail.downloadFullLog":"Download full log","workflow.detail.terminalResume":"Debug session","workflow.detail.openResumeNewTab":"Open debug session in new tab","workflow.detail.resumeSession":"Resume session","workflow.detail.resumeStarting":"Starting\u2026","workflow.detail.endResumeSession":"End debug session","workflow.detail.resumeEnding":"Ending\u2026","workflow.detail.resumeUnsupportedCli":'CLI "{cliId}" does not support resume',"workflow.detail.resumeMissingCliSession":"Missing cliSessionId \u2014 cannot resume","workflow.detail.resumeStartFailed":"Failed to start debug session (HTTP {status})","workflow.detail.resumeEndFailed":"Failed to end debug session (HTTP {status})","workflow.detail.writeAccessResume":"Resume requires dashboard write access.","workflow.detail.waitPrompt":"Wait prompt","workflow.detail.approvalComment":"Approval comment","workflow.detail.optionalComment":"Optional comment","workflow.detail.approve":"Approve","workflow.detail.reject":"Reject","workflow.detail.submitting":"Submitting...","workflow.detail.empty":"empty","workflow.detail.truncated":"truncated","workflow.detail.noData":"No data.","workflow.detail.noPreview":"No preview.","workflow.detail.open":"open","workflow.detail.deadline":"deadline","workflow.detail.effect":"effect","workflow.detail.wait":"wait","workflow.detail.noEvents":"No events.","workflow.summary.workflow":"workflow","workflow.summary.status":"status","workflow.summary.lastSeq":"lastSeq","workflow.summary.updated":"updated","workflow.summary.revision":"revision","workflow.summary.initiator":"initiator","workflow.summary.failedNode":"failedNode","workflow.summary.cancelOrigin":"cancelOrigin","workflow.summary.chat":"chat","workflow.summary.app":"app","workflow.dangling.activities":"activities","workflow.dangling.effects":"effects","workflow.dangling.waits":"waits","workflow.dangling.cancels":"cancels","catalog.title":"Workflow catalog","catalog.subtitle":"Create a workflow run from a saved workflow definition.","catalog.searchPlaceholder":"search workflowId / path","catalog.refresh":"Refresh","catalog.loading":"Loading catalog...","catalog.loadFailed":"Failed to load catalog: {error}","catalog.noDefinitions":"No workflow definitions found.","catalog.noFilterMatch":"No definitions match this filter.","catalog.table.workflow":"workflow","catalog.table.version":"version","catalog.table.params":"params","catalog.table.nodes":"nodes","catalog.table.revision":"revision","catalog.table.path":"path","catalog.paramSummary":"{required}/{total} required","catalog.back":"Back to catalog","catalog.detailTitle":"Workflow definition","catalog.definitionLoadFailed":"Failed to load definition: {error}","catalog.summary":"Summary","catalog.paramsSchema":"Params schema","catalog.definitionJson":"Definition JSON","catalog.runPanel":"Run workflow","catalog.paramsJson":"Params JSON","catalog.paramsPlaceholder":`{
|
|
12
12
|
"city": "\u5317\u4EAC"
|
|
13
|
-
}`,"catalog.chatId":"Chat ID","catalog.larkAppId":"Lark app ID","catalog.chatBindingHint":"Required so humanGate cards and cancel routing know which Lark chat owns the run.","catalog.run":"Run","catalog.running":"Starting...","catalog.badParamsJson":"Params must be a JSON object.","catalog.writeAccess":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and run again.","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"Run started; opening detail page...","catalog.invalidParams":"Invalid params","catalog.issue":"{path}: {message}","catalog.noParams":"No params declared.","catalog.required":"required","catalog.optional":"optional","catalog.default":"default","catalog.description":"description","catalog.path":"path","catalog.revision":"revision","catalog.nodeCount":"nodes"},sn={zh:Io,en:Lo};function rn(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 Eo(e=[]){for(let t of e){let n=rn(t);if(n)return n}return"zh"}function nt(e){return(t,n)=>{let s=sn[e][t]??sn.zh[t]??t;return n?s.replace(/\{(\w+)\}/g,(a,i)=>{let l=n[i];return l==null?`{${i}}`:String(l)}):s}}function ln(e,t){return(e?rn(e.getItem($t)):null)??Eo(t)}var St="botmux.dashboard.theme",dn="botmux.dashboard.sessions.view";function xo(e){return e==="system"||e==="light"||e==="dark"?e:null}function Mo(e){return e==="board"||e==="table"?e:null}function cn(e,t){return e==="system"?t?"dark":"light":e}function un(e){return xo(e?.getItem(St))??"dark"}function pn(e){return Mo(e?.getItem(dn))??"board"}var mn="botmux.dashboard.sessions.boardOrder",Fe=["needs-you","starting","working","idle"];function Ho(e){if(!Array.isArray(e)||e.length!==Fe.length)return null;let t=new Set(e);if(t.size!==e.length)return null;for(let n of Fe)if(!t.has(n))return null;return e.slice()}function fn(e){try{let t=e?.getItem(mn);return t?Ho(JSON.parse(t))??[...Fe]:[...Fe]}catch{return[...Fe]}}function Tt(e,t){try{e?.setItem(mn,JSON.stringify(t))}catch{}}function gn(e,t){try{e?.setItem(dn,t)}catch{}}var Co=["default","cyber","genshin","fallout","prts","bluearchive","zzz","dragonball","ikun"],It="botmux.dashboard.skin";function Ao(e){return typeof e=="string"&&Co.includes(e)?e:null}function bn(e){return Ao(e?.getItem(It))??"default"}var Do="\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF830123456789\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E$#%&@*+=<>/\\",hn=["186 100% 60%","56 97% 60%","330 100% 64%","150 80% 58%"],Et=[{key:"shake",dur:280},{key:"rgb",dur:340},{key:"tear",dur:400},{key:"invert",dur:220},{key:"slice",dur:320},{key:"blackout",dur:260}],wn=["ESTABLISHING NETLINK","BYPASSING ICE","DECRYPTING DATAFLOW","SYNCING BOTMUX TELEMETRY","ACCESS GRANTED"],yn="0123456789ABCDEF#<>*/=+\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C",Ro=3200,We=[],Be=0,ot=0;function Ht(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function xt(e,t){let n="";for(let s=0;s<e;s++)n+=t[Math.floor(Math.random()*t.length)];return n}function Oo(e){let t=document.createElement("div");t.className="cyber-rain";let n=Math.max(10,Math.min(26,Math.round(window.innerWidth/70)));for(let s=0;s<n;s++){let a=document.createElement("span");a.className="cyber-rain-col",a.textContent=xt(28+Math.floor(Math.random()*22),Do);let i=hn[Math.floor(Math.random()*hn.length)];a.style.cssText=`left:${(s+.5)/n*100}%;--rc:${i};--sz:${10+Math.floor(Math.random()*9)}px;--op:${(.25+Math.random()*.45).toFixed(2)};--dur:${(6+Math.random()*9).toFixed(1)}s;--delay:${(-Math.random()*12).toFixed(1)}s;`,t.appendChild(a)}e.appendChild(t)}function qo(){if(Ht())return;let e=document.body,t=()=>{let n=Et[Math.floor(Math.random()*Et.length)],s=`cp-fx-${n.key}`;e.classList.add(s),We.push(window.setTimeout(()=>e.classList.remove(s),n.dur)),We.push(window.setTimeout(t,2400+Math.random()*4200))};We.push(window.setTimeout(t,1800+Math.random()*2600))}function Bo(){We.forEach(e=>window.clearTimeout(e)),We=[];for(let e of Et)document.body.classList.remove(`cp-fx-${e.key}`)}function Po(){if(Ht()||document.getElementById("cyber-boot"))return;let e=document.createElement("div");e.id="cyber-boot",e.className="cyber-boot",e.setAttribute("aria-hidden","true"),e.innerHTML='<div class="cyber-boot-grid"></div><div class="cyber-loader"><div class="cyber-loader-frame"><div class="cyber-loader-head"><span>KIROSHI NETLINK</span><span class="cyber-loader-jp">\u4FB5\u5165\u4E2D</span></div><div class="cyber-loader-line"><span class="cyber-loader-prompt">></span><span class="cyber-loader-text"></span><span class="cyber-loader-cursor">_</span></div><div class="cyber-loader-stream"></div></div></div>',document.body.appendChild(e);let t=e.querySelector(".cyber-loader-text"),n=e.querySelector(".cyber-loader-stream"),s=0,a=0,i=0;Be=window.setInterval(()=>{let l=wn[s];t&&(a<l.length?(a+=1,t.textContent=l.slice(0,a)+xt(l.length-a,yn),t.classList.remove("done")):i<16?(i+=1,t.textContent=l,t.classList.add("done")):(s=(s+1)%wn.length,a=0,i=0)),n&&(n.textContent=xt(26,yn))},50),ot=window.setTimeout(()=>{window.clearInterval(Be),Be=0,e.remove()},Ro)}function No(){Be&&(window.clearInterval(Be),Be=0),ot&&(window.clearTimeout(ot),ot=0),document.getElementById("cyber-boot")?.remove()}var Uo=320,vn=16,Ge=!0,qe=0,Lt=0,at=!1,st=[],Mt=[];function jo(){if(at)return;at=!0,Ge=!1,qe=0;let e=Ht(),t="";for(let s=0;s<vn;s++){let a=s%3===0?"186 100% 52%":s%3===1?"330 100% 58%":"56 97% 52%",i=(s%2===0?1:-1)*(8+s%5*7);t+=`<span class="cyber-breach-shard" style="top:${s/vn*100}%;height:${2+s%4*3}%;--shift:${i}px;--delay:${s%8*.09}s;--dur:${(.36+s%5*.12).toFixed(2)}s;--hue:${a}"></span>`}let n=document.createElement("div");n.id="cyber-breach",n.className="cyber-breach",n.setAttribute("aria-hidden","true"),n.innerHTML=`<span class="cyber-breach-flash"></span><span class="cyber-breach-grid"></span><div class="cyber-breach-shards">${t}</div><div class="cyber-breach-banner"><span class="cyber-breach-tag">// BREACH PROTOCOL \u2014 SYSTEM OVERRIDE</span><span class="cyber-breach-caption" data-text="SYSTEM BREACH">SYSTEM BREACH</span><span class="cyber-breach-sub" data-text="NETWATCH OVERRIDE ENGAGED">NETWATCH OVERRIDE ENGAGED</span></div>`,document.body.appendChild(n),e||document.body.classList.add("cyber-breach-quake"),st.push(window.setTimeout(()=>document.body.classList.remove("cyber-breach-quake"),760)),st.push(window.setTimeout(()=>{n.remove(),at=!1},e?2600:4200))}function zo(){Ge=!0,qe=0;let e=document.documentElement,t=()=>e.scrollHeight-(window.innerHeight+window.scrollY)<=4,n=v=>{v<=0||!t()||(qe+=v,qe>Uo&&Ge&&jo())},s=v=>n(v.deltaY),a=v=>{Lt=v.touches[0]?.clientY??0},i=v=>{let y=v.touches[0]?.clientY??0,h=Lt-y;Lt=y,n(h)},l=()=>{t()||(qe=0,Ge=!0)},p=(v,y)=>{window.addEventListener(v,y,{passive:!0}),Mt.push([v,y])};p("wheel",s),p("touchstart",a),p("touchmove",i),p("scroll",l)}function _o(){for(let[e,t]of Mt)window.removeEventListener(e,t);Mt=[],st.forEach(e=>window.clearTimeout(e)),st=[],document.body.classList.remove("cyber-breach-quake"),document.getElementById("cyber-breach")?.remove(),at=!1,Ge=!0,qe=0}function kn(e,t=!1){if(!(typeof document>"u")){if(!e){document.getElementById("cyber-fx")?.remove(),document.getElementById("cyber-hud")?.remove(),document.getElementById("cyber-glitch")?.remove(),Bo(),No(),_o();return}if(!document.getElementById("cyber-fx")){let n=document.createElement("div");n.id="cyber-fx",n.className="cyber-fx",n.setAttribute("aria-hidden","true"),n.innerHTML='<div class="cyber-fx-grid"></div><div class="cyber-fx-scan"></div><span class="cyber-flicker"></span><span class="cyber-rollline"></span>',Oo(n),document.body.appendChild(n);let s=document.createElement("div");s.id="cyber-hud",s.className="cyber-hud",s.setAttribute("aria-hidden","true"),s.innerHTML='<span class="cyber-hud-corner tl"></span><span class="cyber-hud-corner tr"></span><span class="cyber-hud-corner bl"></span><span class="cyber-hud-corner br"></span><span class="cyber-hud-tag">NIGHT CITY // NETWATCH</span>',document.body.appendChild(s);let a=document.createElement("div");a.id="cyber-glitch",a.className="cyber-glitch",a.setAttribute("aria-hidden","true"),document.body.appendChild(a),qo(),zo()}t&&Po()}}var Fo={genshin:2e3,zzz:1900,dragonball:1900,ikun:1900},Wo='<span class="si-bball" aria-hidden="true"><span class="si-bball-seams"><svg viewBox="0 0 100 100"><g fill="none" stroke="#3a1d08" stroke-width="3.4" stroke-linecap="round"><path d="M50 4V96"/><path d="M4 50H96"/><path d="M50 4 Q14 50 50 96"/><path d="M50 4 Q86 50 50 96"/></g></svg></span></span>';function Go(e){switch(e){case"genshin":return'<span class="si-gi-shine" aria-hidden="true"></span><span class="si-gi-text">\u539F\u795E\uFF0C\u542F\u52A8</span>';case"zzz":return'<span class="si-static" aria-hidden="true"></span><span class="si-roll" aria-hidden="true"></span><span class="si-now">NOW LOADING</span>';case"dragonball":return'<span class="si-speed" aria-hidden="true"></span><img class="si-cloud" src="/assets/skins/dragonball-wukong.webp" alt="">';case"ikun":return Wo;default:return""}}function Jo(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function $n(e){if(typeof document>"u"||Jo())return;let t=Fo[e];if(!t)return;document.getElementById("skin-intro")?.remove();let n=document.createElement("div");n.id="skin-intro",n.className=`skin-intro si-${e}`,n.setAttribute("aria-hidden","true"),n.style.setProperty("--si-dur",`${t}ms`),n.innerHTML=Go(e),document.body.appendChild(n),window.setTimeout(()=>n.remove(),t+80)}var At=class{locale="zh";themeMode="system";resolvedTheme="light";skin="default";listeners=new Set;translate=nt(this.locale);mediaQuery=null;init(){let t=typeof window<"u"?window:void 0;this.locale=ln(t?.localStorage,Vo()),this.translate=nt(this.locale),this.themeMode=un(t?.localStorage),this.skin=bn(t?.localStorage),this.mediaQuery=t?.matchMedia?.("(prefers-color-scheme: dark)")??null,this.mediaQuery?.addEventListener("change",()=>{this.applyTheme(),this.emit()}),this.applyTheme(),this.applySkin(),this.applyLocale()}t(t,n){return this.translate(t,n)}setLocale(t){this.locale!==t&&(this.locale=t,this.translate=nt(t),window.localStorage.setItem($t,t),this.applyLocale(),this.emit())}get theme(){return this.skin==="default"?this.themeMode:this.skin}setTheme(t){let n=t==="system"||t==="light"||t==="dark",s=n?"default":t,a=s!==this.skin;n&&this.themeMode!==t&&(this.themeMode=t,window.localStorage.setItem(St,this.themeMode)),a&&(this.skin=s,window.localStorage.setItem(It,this.skin)),this.applyTheme(),this.applySkin(a),this.emit()}on(t){return this.listeners.add(t),()=>this.listeners.delete(t)}emit(){for(let t of this.listeners)t()}applyTheme(){this.resolvedTheme=cn(this.themeMode,!!this.mediaQuery?.matches);let t=this.skin==="default"?this.resolvedTheme:Ko[this.skin];document.documentElement.dataset.theme=t,document.documentElement.dataset.themeMode=this.themeMode}applySkin(t=!1){document.documentElement.dataset.skin=this.skin,kn(this.skin==="cyber",t),t&&this.skin!=="cyber"&&this.skin!=="default"&&$n(this.skin)}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}},Ko={default:"light",cyber:"dark",genshin:"light",fallout:"dark",prts:"dark",bluearchive:"dark",zzz:"dark",dragonball:"light",ikun:"dark"};function Vo(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var me=new At;function o(e,t){return me.t(e,t)}function r(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function ue(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 Sn=[{c1:"#5be3ff",c2:"#4f8bff"},{c1:"#b89bff",c2:"#6b4df0"},{c1:"#7ce0c3",c2:"#2e9e8f"},{c1:"#8fb4ff",c2:"#3b62d8"},{c1:"#ffd28f",c2:"#d8783b"},{c1:"#7df0a8",c2:"#1f9e63"},{c1:"#9fd0ff",c2:"#4878c8"},{c1:"#ff9fb8",c2:"#d84a78"}];function de(e){let t=0,n=String(e??"");for(let i=0;i<n.length;i++)t=t*31+n.charCodeAt(i)>>>0;let{c1:s,c2:a}=Sn[t%Sn.length];return`--c1:${s};--c2:${a}`}var Tn=new Map,In=new Map,Ct=null;function Pe(){return Ct??=(async()=>{try{let e=await fetch("/api/groups");if(!e.ok)throw new Error(`HTTP ${e.status}`);let t=await e.json();for(let n of t.bots??[])n.larkAppId&&n.botName&&n.botName!==n.larkAppId&&Tn.set(n.larkAppId,String(n.botName));for(let n of t.chats??[])n.chatId&&n.name&&In.set(n.chatId,String(n.name))}catch{Ct=null}})(),Ct}function fe(e){let t=e.larkAppId?Tn.get(e.larkAppId):void 0;return t||(e.botName&&e.botName!==e.larkAppId?String(e.botName):String(e.botName??e.larkAppId??"-"))}function Ne(e){return e.chatId&&In.get(e.chatId)||null}function $e(e){let t=String(e??"");return t.replace(/^(?:@\S+\s*)+/,"").trim()||t}function Te(e){return e.status==="closed"?null:e.pendingRepo?o("sessions.board.signalRepo"):e.tuiPromptActive?o("sessions.board.signalPrompt"):e.status==="limited"?o("sessions.board.signalLimited"):null}var Ln={chats:[],bots:[]};async function Yo(){try{let e=await fetch("/api/groups");if(!e.ok)return;Ln=await e.json()}catch{}}var Dt=new Set(["working","analyzing","active","starting"]);function Qo(e){let t=new Map,n=a=>{let i=t.get(a);return i||(i={botName:a,larkAppId:a,cliId:"unknown",online:!1,sessions:[],active:[],busy:[],attention:[],lastActiveAt:0},t.set(a,i)),i};for(let a of Ln.bots??[]){let i=n(a.larkAppId??a.botName??"-");i.online=!0,a.botName&&(i.botName=a.botName)}let s=[...e].sort((a,i)=>+(a.status==="closed")-+(i.status==="closed"));for(let a of s){let i=a.larkAppId??a.botName??"-";if(a.status==="closed"&&!t.has(i))continue;let l=n(i);a.botName&&(l.botName===l.larkAppId||!l.botName)&&(l.botName=a.botName),l.sessions.push(a),a.cliId&&l.cliId==="unknown"&&(l.cliId=a.cliId),l.lastActiveAt=Math.max(l.lastActiveAt,Number(a.lastMessageAt??0)),a.status!=="closed"&&(l.active.push(a),Dt.has(a.status)&&l.busy.push(a),Te(a)&&l.attention.push(a))}return[...t.values()].sort((a,i)=>{let l=p=>p.attention.length?0:p.busy.length?1:p.online||p.active.length?2:3;return l(a)!==l(i)?l(a)-l(i):i.lastActiveAt-a.lastActiveAt})}function Xo(e){let t=!e.online&&e.active.length===0,n=e.attention.length>0,s=e.busy.length>0,a=n?"warn":s?"busy":t?"off":"ok",i;if(n){let p=e.attention[0];i=`<b>${r(($e(p.title)||p.sessionId).slice(0,60))}</b> \xB7 ${r(Te(p)??"")}`}else if(s){let p=[...e.busy].sort((v,y)=>Number(y.lastMessageAt??0)-Number(v.lastMessageAt??0))[0];i=`<b>${r(($e(p.title)||p.sessionId).slice(0,60))}</b>`}else t?i=r(o("overview.botOffline")):i=r(o("overview.botIdle"));let l=n?`<span class="tag tag-warn">${r(o("overview.botNeedsYou"))}</span>`:s?`<span class="tag tag-run">${r(o("overview.botBusy",{count:e.busy.length}))}</span>`:t?`<span class="tag tag-off">${r(o("overview.botOff"))}</span>`:`<span class="tag tag-ok">${r(o("overview.botReady"))}</span>`;return`<article class="mate${n?" mate-attn":""}${t?" mate-off":""}">
|
|
13
|
+
}`,"catalog.chatId":"Chat ID","catalog.larkAppId":"Lark app ID","catalog.chatBindingHint":"Required so humanGate cards and cancel routing know which Lark chat owns the run.","catalog.run":"Run","catalog.running":"Starting...","catalog.badParamsJson":"Params must be a JSON object.","catalog.writeAccess":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and run again.","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"Run started; opening detail page...","catalog.invalidParams":"Invalid params","catalog.issue":"{path}: {message}","catalog.noParams":"No params declared.","catalog.required":"required","catalog.optional":"optional","catalog.default":"default","catalog.description":"description","catalog.path":"path","catalog.revision":"revision","catalog.nodeCount":"nodes"},dn={zh:Ao,en:Co};function cn(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 Do(e=[]){for(let t of e){let n=cn(t);if(n)return n}return"zh"}function nt(e){return(t,n)=>{let s=dn[e][t]??dn.zh[t]??t;return n?s.replace(/\{(\w+)\}/g,(a,i)=>{let l=n[i];return l==null?`{${i}}`:String(l)}):s}}function un(e,t){return(e?cn(e.getItem(Tt)):null)??Do(t)}var Lt="botmux.dashboard.theme",pn="botmux.dashboard.sessions.view";function Ro(e){return e==="system"||e==="light"||e==="dark"?e:null}function Oo(e){return e==="board"||e==="table"?e:null}function mn(e,t){return e==="system"?t?"dark":"light":e}function fn(e){return Ro(e?.getItem(Lt))??"dark"}function gn(e){return Oo(e?.getItem(pn))??"board"}var bn="botmux.dashboard.sessions.boardOrder",Fe=["needs-you","starting","working","idle"];function Bo(e){if(!Array.isArray(e)||e.length!==Fe.length)return null;let t=new Set(e);if(t.size!==e.length)return null;for(let n of Fe)if(!t.has(n))return null;return e.slice()}function hn(e){try{let t=e?.getItem(bn);return t?Bo(JSON.parse(t))??[...Fe]:[...Fe]}catch{return[...Fe]}}function Et(e,t){try{e?.setItem(bn,JSON.stringify(t))}catch{}}function wn(e,t){try{e?.setItem(pn,t)}catch{}}var qo=["default","cyber","genshin","fallout","prts","bluearchive","zzz","dragonball","ikun"],xt="botmux.dashboard.skin";function Po(e){return typeof e=="string"&&qo.includes(e)?e:null}function yn(e){return Po(e?.getItem(xt))??"default"}var No="\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF830123456789\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E$#%&@*+=<>/\\",vn=["186 100% 60%","56 97% 60%","330 100% 64%","150 80% 58%"],Ht=[{key:"shake",dur:280},{key:"rgb",dur:340},{key:"tear",dur:400},{key:"invert",dur:220},{key:"slice",dur:320},{key:"blackout",dur:260}],kn=["ESTABLISHING NETLINK","BYPASSING ICE","DECRYPTING DATAFLOW","SYNCING BOTMUX TELEMETRY","ACCESS GRANTED"],$n="0123456789ABCDEF#<>*/=+\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C",Uo=3200,We=[],Pe=0,ot=0;function Dt(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function At(e,t){let n="";for(let s=0;s<e;s++)n+=t[Math.floor(Math.random()*t.length)];return n}function jo(e){let t=document.createElement("div");t.className="cyber-rain";let n=Math.max(10,Math.min(26,Math.round(window.innerWidth/70)));for(let s=0;s<n;s++){let a=document.createElement("span");a.className="cyber-rain-col",a.textContent=At(28+Math.floor(Math.random()*22),No);let i=vn[Math.floor(Math.random()*vn.length)];a.style.cssText=`left:${(s+.5)/n*100}%;--rc:${i};--sz:${10+Math.floor(Math.random()*9)}px;--op:${(.25+Math.random()*.45).toFixed(2)};--dur:${(6+Math.random()*9).toFixed(1)}s;--delay:${(-Math.random()*12).toFixed(1)}s;`,t.appendChild(a)}e.appendChild(t)}function zo(){if(Dt())return;let e=document.body,t=()=>{let n=Ht[Math.floor(Math.random()*Ht.length)],s=`cp-fx-${n.key}`;e.classList.add(s),We.push(window.setTimeout(()=>e.classList.remove(s),n.dur)),We.push(window.setTimeout(t,2400+Math.random()*4200))};We.push(window.setTimeout(t,1800+Math.random()*2600))}function _o(){We.forEach(e=>window.clearTimeout(e)),We=[];for(let e of Ht)document.body.classList.remove(`cp-fx-${e.key}`)}function Fo(){if(Dt()||document.getElementById("cyber-boot"))return;let e=document.createElement("div");e.id="cyber-boot",e.className="cyber-boot",e.setAttribute("aria-hidden","true"),e.innerHTML='<div class="cyber-boot-grid"></div><div class="cyber-loader"><div class="cyber-loader-frame"><div class="cyber-loader-head"><span>KIROSHI NETLINK</span><span class="cyber-loader-jp">\u4FB5\u5165\u4E2D</span></div><div class="cyber-loader-line"><span class="cyber-loader-prompt">></span><span class="cyber-loader-text"></span><span class="cyber-loader-cursor">_</span></div><div class="cyber-loader-stream"></div></div></div>',document.body.appendChild(e);let t=e.querySelector(".cyber-loader-text"),n=e.querySelector(".cyber-loader-stream"),s=0,a=0,i=0;Pe=window.setInterval(()=>{let l=kn[s];t&&(a<l.length?(a+=1,t.textContent=l.slice(0,a)+At(l.length-a,$n),t.classList.remove("done")):i<16?(i+=1,t.textContent=l,t.classList.add("done")):(s=(s+1)%kn.length,a=0,i=0)),n&&(n.textContent=At(26,$n))},50),ot=window.setTimeout(()=>{window.clearInterval(Pe),Pe=0,e.remove()},Uo)}function Wo(){Pe&&(window.clearInterval(Pe),Pe=0),ot&&(window.clearTimeout(ot),ot=0),document.getElementById("cyber-boot")?.remove()}var Go=320,Sn=16,Ge=!0,qe=0,Mt=0,at=!1,st=[],Ct=[];function Jo(){if(at)return;at=!0,Ge=!1,qe=0;let e=Dt(),t="";for(let s=0;s<Sn;s++){let a=s%3===0?"186 100% 52%":s%3===1?"330 100% 58%":"56 97% 52%",i=(s%2===0?1:-1)*(8+s%5*7);t+=`<span class="cyber-breach-shard" style="top:${s/Sn*100}%;height:${2+s%4*3}%;--shift:${i}px;--delay:${s%8*.09}s;--dur:${(.36+s%5*.12).toFixed(2)}s;--hue:${a}"></span>`}let n=document.createElement("div");n.id="cyber-breach",n.className="cyber-breach",n.setAttribute("aria-hidden","true"),n.innerHTML=`<span class="cyber-breach-flash"></span><span class="cyber-breach-grid"></span><div class="cyber-breach-shards">${t}</div><div class="cyber-breach-banner"><span class="cyber-breach-tag">// BREACH PROTOCOL \u2014 SYSTEM OVERRIDE</span><span class="cyber-breach-caption" data-text="SYSTEM BREACH">SYSTEM BREACH</span><span class="cyber-breach-sub" data-text="NETWATCH OVERRIDE ENGAGED">NETWATCH OVERRIDE ENGAGED</span></div>`,document.body.appendChild(n),e||document.body.classList.add("cyber-breach-quake"),st.push(window.setTimeout(()=>document.body.classList.remove("cyber-breach-quake"),760)),st.push(window.setTimeout(()=>{n.remove(),at=!1},e?2600:4200))}function Ko(){Ge=!0,qe=0;let e=document.documentElement,t=()=>e.scrollHeight-(window.innerHeight+window.scrollY)<=4,n=v=>{v<=0||!t()||(qe+=v,qe>Go&&Ge&&Jo())},s=v=>n(v.deltaY),a=v=>{Mt=v.touches[0]?.clientY??0},i=v=>{let y=v.touches[0]?.clientY??0,h=Mt-y;Mt=y,n(h)},l=()=>{t()||(qe=0,Ge=!0)},p=(v,y)=>{window.addEventListener(v,y,{passive:!0}),Ct.push([v,y])};p("wheel",s),p("touchstart",a),p("touchmove",i),p("scroll",l)}function Vo(){for(let[e,t]of Ct)window.removeEventListener(e,t);Ct=[],st.forEach(e=>window.clearTimeout(e)),st=[],document.body.classList.remove("cyber-breach-quake"),document.getElementById("cyber-breach")?.remove(),at=!1,Ge=!0,qe=0}function In(e,t=!1){if(!(typeof document>"u")){if(!e){document.getElementById("cyber-fx")?.remove(),document.getElementById("cyber-hud")?.remove(),document.getElementById("cyber-glitch")?.remove(),_o(),Wo(),Vo();return}if(!document.getElementById("cyber-fx")){let n=document.createElement("div");n.id="cyber-fx",n.className="cyber-fx",n.setAttribute("aria-hidden","true"),n.innerHTML='<div class="cyber-fx-grid"></div><div class="cyber-fx-scan"></div><span class="cyber-flicker"></span><span class="cyber-rollline"></span>',jo(n),document.body.appendChild(n);let s=document.createElement("div");s.id="cyber-hud",s.className="cyber-hud",s.setAttribute("aria-hidden","true"),s.innerHTML='<span class="cyber-hud-corner tl"></span><span class="cyber-hud-corner tr"></span><span class="cyber-hud-corner bl"></span><span class="cyber-hud-corner br"></span><span class="cyber-hud-tag">NIGHT CITY // NETWATCH</span>',document.body.appendChild(s);let a=document.createElement("div");a.id="cyber-glitch",a.className="cyber-glitch",a.setAttribute("aria-hidden","true"),document.body.appendChild(a),zo(),Ko()}t&&Fo()}}var Yo={genshin:2e3,zzz:1900,dragonball:1900,ikun:1900},Qo='<span class="si-bball" aria-hidden="true"><span class="si-bball-seams"><svg viewBox="0 0 100 100"><g fill="none" stroke="#3a1d08" stroke-width="3.4" stroke-linecap="round"><path d="M50 4V96"/><path d="M4 50H96"/><path d="M50 4 Q14 50 50 96"/><path d="M50 4 Q86 50 50 96"/></g></svg></span></span>';function Xo(e){switch(e){case"genshin":return'<span class="si-gi-shine" aria-hidden="true"></span><span class="si-gi-text">\u539F\u795E\uFF0C\u542F\u52A8</span>';case"zzz":return'<span class="si-static" aria-hidden="true"></span><span class="si-roll" aria-hidden="true"></span><span class="si-now">NOW LOADING</span>';case"dragonball":return'<span class="si-speed" aria-hidden="true"></span><img class="si-cloud" src="/assets/skins/dragonball-wukong.webp" alt="">';case"ikun":return Qo;default:return""}}function Zo(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Tn(e){if(typeof document>"u"||Zo())return;let t=Yo[e];if(!t)return;document.getElementById("skin-intro")?.remove();let n=document.createElement("div");n.id="skin-intro",n.className=`skin-intro si-${e}`,n.setAttribute("aria-hidden","true"),n.style.setProperty("--si-dur",`${t}ms`),n.innerHTML=Xo(e),document.body.appendChild(n),window.setTimeout(()=>n.remove(),t+80)}var Ot=class{locale="zh";themeMode="system";resolvedTheme="light";skin="default";listeners=new Set;translate=nt(this.locale);mediaQuery=null;init(){let t=typeof window<"u"?window:void 0;this.locale=un(t?.localStorage,ta()),this.translate=nt(this.locale),this.themeMode=fn(t?.localStorage),this.skin=yn(t?.localStorage),this.mediaQuery=t?.matchMedia?.("(prefers-color-scheme: dark)")??null,this.mediaQuery?.addEventListener("change",()=>{this.applyTheme(),this.emit()}),this.applyTheme(),this.applySkin(),this.applyLocale()}t(t,n){return this.translate(t,n)}setLocale(t){this.locale!==t&&(this.locale=t,this.translate=nt(t),window.localStorage.setItem(Tt,t),this.applyLocale(),this.emit())}get theme(){return this.skin==="default"?this.themeMode:this.skin}setTheme(t){let n=t==="system"||t==="light"||t==="dark",s=n?"default":t,a=s!==this.skin;n&&this.themeMode!==t&&(this.themeMode=t,window.localStorage.setItem(Lt,this.themeMode)),a&&(this.skin=s,window.localStorage.setItem(xt,this.skin)),this.applyTheme(),this.applySkin(a),this.emit()}on(t){return this.listeners.add(t),()=>this.listeners.delete(t)}emit(){for(let t of this.listeners)t()}applyTheme(){this.resolvedTheme=mn(this.themeMode,!!this.mediaQuery?.matches);let t=this.skin==="default"?this.resolvedTheme:ea[this.skin];document.documentElement.dataset.theme=t,document.documentElement.dataset.themeMode=this.themeMode}applySkin(t=!1){document.documentElement.dataset.skin=this.skin,In(this.skin==="cyber",t),t&&this.skin!=="cyber"&&this.skin!=="default"&&Tn(this.skin)}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}},ea={default:"light",cyber:"dark",genshin:"light",fallout:"dark",prts:"dark",bluearchive:"dark",zzz:"dark",dragonball:"light",ikun:"dark"};function ta(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var me=new Ot;function o(e,t){return me.t(e,t)}function r(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function ue(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 Ln=[{c1:"#5be3ff",c2:"#4f8bff"},{c1:"#b89bff",c2:"#6b4df0"},{c1:"#7ce0c3",c2:"#2e9e8f"},{c1:"#8fb4ff",c2:"#3b62d8"},{c1:"#ffd28f",c2:"#d8783b"},{c1:"#7df0a8",c2:"#1f9e63"},{c1:"#9fd0ff",c2:"#4878c8"},{c1:"#ff9fb8",c2:"#d84a78"}];function En(e){let t=0,n=String(e??"");for(let i=0;i<n.length;i++)t=t*31+n.charCodeAt(i)>>>0;let{c1:s,c2:a}=Ln[t%Ln.length];return`--c1:${s};--c2:${a}`}var it=new Map,rt=new Map;function na(e,t){return t?it.get(t):e?rt.get(String(e)):void 0}function de(e){let t=e.name??"",n=e.avatarUrl??na(e.name,e.larkAppId),s=e.size==="sm"?" orb-avatar-sm":"",a=n?" orb-has-img":"",i=e.dot?`<i class="orb-dot orb-dot-${e.dot}"></i>`:"",l=n?`<img class="orb-img" src="${r(n)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar${s}${a}" style="${En(t)}" aria-hidden="true">${l}${i}</span>`}function oa(e){return e?lt.get(e):void 0}function xn(e){let t=e.name??e.chatId??"",n=e.avatarUrl??oa(e.chatId),s=e.size==="sm"?" orb-avatar-sm":"",a=n?" orb-has-img":"",i=n?`<img class="orb-img" src="${r(n)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar orb-square${s}${a}" style="${En(t)}" aria-hidden="true">${i}</span>`}var Mn=new Map,Hn=new Map,lt=new Map,Rt=null,An="botmux.avatarCache.v1";function aa(){try{let e=typeof window<"u"?window.localStorage.getItem(An):null;if(!e)return;let t=JSON.parse(e);for(let[n,s]of Object.entries(t.botByAppId??{}))it.set(n,s);for(let[n,s]of Object.entries(t.botByName??{}))rt.set(n,s);for(let[n,s]of Object.entries(t.chatById??{}))lt.set(n,s)}catch{}}function sa(){try{if(typeof window>"u")return;window.localStorage.setItem(An,JSON.stringify({botByAppId:Object.fromEntries(it),botByName:Object.fromEntries(rt),chatById:Object.fromEntries(lt)}))}catch{}}aa();function fe(){return Rt??=(async()=>{try{let e=await fetch("/api/groups");if(!e.ok)throw new Error(`HTTP ${e.status}`);let t=await e.json();for(let n of t.bots??[])n.larkAppId&&n.botName&&n.botName!==n.larkAppId&&Mn.set(n.larkAppId,String(n.botName)),n.botAvatarUrl&&(n.larkAppId&&it.set(n.larkAppId,String(n.botAvatarUrl)),n.botName&&rt.set(String(n.botName),String(n.botAvatarUrl)));for(let n of t.chats??[])n.chatId&&n.name&&Hn.set(n.chatId,String(n.name)),n.chatId&&n.avatar&<.set(n.chatId,String(n.avatar));sa()}catch{Rt=null}})(),Rt}function ge(e){let t=e.larkAppId?Mn.get(e.larkAppId):void 0;return t||(e.botName&&e.botName!==e.larkAppId?String(e.botName):String(e.botName??e.larkAppId??"-"))}function Ne(e){return e.chatId&&Hn.get(e.chatId)||null}function Se(e){let t=String(e??"");return t.replace(/^(?:@\S+\s*)+/,"").trim()||t}function Te(e){return e.status==="closed"?null:e.pendingRepo?o("sessions.board.signalRepo"):e.tuiPromptActive?o("sessions.board.signalPrompt"):e.status==="limited"?o("sessions.board.signalLimited"):null}var Cn={chats:[],bots:[]};async function ia(){try{let e=await fetch("/api/groups");if(!e.ok)return;Cn=await e.json()}catch{}}var Bt=new Set(["working","analyzing","active","starting"]);function ra(e){let t=new Map,n=a=>{let i=t.get(a);return i||(i={botName:a,larkAppId:a,cliId:"unknown",online:!1,sessions:[],active:[],busy:[],attention:[],lastActiveAt:0},t.set(a,i)),i};for(let a of Cn.bots??[]){let i=n(a.larkAppId??a.botName??"-");i.online=!0,a.botName&&(i.botName=a.botName),a.botAvatarUrl&&(i.botAvatarUrl=a.botAvatarUrl)}let s=[...e].sort((a,i)=>+(a.status==="closed")-+(i.status==="closed"));for(let a of s){let i=a.larkAppId??a.botName??"-";if(a.status==="closed"&&!t.has(i))continue;let l=n(i);a.botName&&(l.botName===l.larkAppId||!l.botName)&&(l.botName=a.botName),l.sessions.push(a),a.cliId&&l.cliId==="unknown"&&(l.cliId=a.cliId),l.lastActiveAt=Math.max(l.lastActiveAt,Number(a.lastMessageAt??0)),a.status!=="closed"&&(l.active.push(a),Bt.has(a.status)&&l.busy.push(a),Te(a)&&l.attention.push(a))}return[...t.values()].sort((a,i)=>{let l=p=>p.attention.length?0:p.busy.length?1:p.online||p.active.length?2:3;return l(a)!==l(i)?l(a)-l(i):i.lastActiveAt-a.lastActiveAt})}function la(e){let t=!e.online&&e.active.length===0,n=e.attention.length>0,s=e.busy.length>0,a=n?"warn":s?"busy":t?"off":"ok",i;if(n){let p=e.attention[0];i=`<b>${r((Se(p.title)||p.sessionId).slice(0,60))}</b> \xB7 ${r(Te(p)??"")}`}else if(s){let p=[...e.busy].sort((v,y)=>Number(y.lastMessageAt??0)-Number(v.lastMessageAt??0))[0];i=`<b>${r((Se(p.title)||p.sessionId).slice(0,60))}</b>`}else t?i=r(o("overview.botOffline")):i=r(o("overview.botIdle"));let l=n?`<span class="tag tag-warn">${r(o("overview.botNeedsYou"))}</span>`:s?`<span class="tag tag-run">${r(o("overview.botBusy",{count:e.busy.length}))}</span>`:t?`<span class="tag tag-off">${r(o("overview.botOff"))}</span>`:`<span class="tag tag-ok">${r(o("overview.botReady"))}</span>`;return`<article class="mate${n?" mate-attn":""}${t?" mate-off":""}">
|
|
14
14
|
<div class="mate-top">
|
|
15
|
-
|
|
15
|
+
${de({name:e.botName,larkAppId:e.larkAppId,avatarUrl:e.botAvatarUrl,dot:a})}
|
|
16
16
|
<div class="mate-id">
|
|
17
17
|
<b>${r(e.botName)}</b>
|
|
18
18
|
<span class="mate-role">${r(e.cliId)}</span>
|
|
@@ -23,31 +23,31 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
23
23
|
${l}
|
|
24
24
|
<span>${e.lastActiveAt?r(o("overview.lastActive",{time:ue(e.lastActiveAt)})):r(o("common.never"))}</span>
|
|
25
25
|
</div>
|
|
26
|
-
</article>`}function
|
|
27
|
-
|
|
26
|
+
</article>`}function da(e){let t=ge(e);return`<article class="qcard" data-id="${r(e.sessionId)}">
|
|
27
|
+
${de({name:t,larkAppId:e.larkAppId,size:"sm"})}
|
|
28
28
|
<div class="qcard-tx">
|
|
29
|
-
<b>${r(t)} \xB7 ${r((
|
|
29
|
+
<b>${r(t)} \xB7 ${r((Se(e.title)||e.sessionId).slice(0,56))}</b>
|
|
30
30
|
<span>${r(Te(e)??"")} \xB7 ${ue(e.lastMessageAt)}</span>
|
|
31
31
|
</div>
|
|
32
32
|
<a class="qcard-go" href="#/sessions">${r(o("strip.handle"))}</a>
|
|
33
|
-
</article>`}function
|
|
34
|
-
|
|
33
|
+
</article>`}function ca(e){let t=ge(e);return`<li class="sess-row">
|
|
34
|
+
${de({name:t,larkAppId:e.larkAppId,size:"sm"})}
|
|
35
35
|
<div class="sess-tx">
|
|
36
|
-
<b>${r((
|
|
36
|
+
<b>${r((Se(e.title)||e.sessionId).slice(0,64))}</b>
|
|
37
37
|
<span>${r(t)} \xB7 ${r(Ne(e)??e.cliId??"unknown")} \xB7 ${ue(e.lastMessageAt)}</span>
|
|
38
38
|
</div>
|
|
39
39
|
<span class="status status-${r(e.status??"unknown")}">${r(e.status??"unknown")}</span>
|
|
40
|
-
</li>`}function
|
|
40
|
+
</li>`}function ua(e){let t=e.nextRunAt?new Date(e.nextRunAt).toLocaleString():"-";return`<li class="overview-list-row">
|
|
41
41
|
<div>
|
|
42
42
|
<strong>${r(e.name??e.id)}</strong>
|
|
43
|
-
<span>${r(
|
|
43
|
+
<span>${r(ge(e))} \xB7 ${r(e.parsed?.display??"")}</span>
|
|
44
44
|
</div>
|
|
45
45
|
<span>${r(t)}</span>
|
|
46
|
-
</li>`}function
|
|
46
|
+
</li>`}function pa(e,t,n){let s=e+t+n;if(s===0)return`<div class="donut-wrap"><div class="donut" style="background:conic-gradient(var(--border) 0 360deg)"></div>
|
|
47
47
|
<div class="donut-center"><b>0</b><span>${r(o("overview.openSessions"))}</span></div></div>`;let a=e/s*360,i=a+t/s*360;return`<div class="donut-wrap">
|
|
48
48
|
<div class="donut" style="background:conic-gradient(var(--accent) 0 ${a}deg, var(--warning) ${a}deg ${i}deg, var(--success) ${i}deg 360deg)"></div>
|
|
49
49
|
<div class="donut-center"><b>${s}</b><span>${r(o("overview.openSessions"))}</span></div>
|
|
50
|
-
</div>`}async function
|
|
50
|
+
</div>`}async function Dn(e){e.innerHTML=`<section class="page hero-page">
|
|
51
51
|
<div class="page-heading">
|
|
52
52
|
<div>
|
|
53
53
|
<p class="eyebrow">${o("app.subtitle")}</p>
|
|
@@ -101,25 +101,25 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
101
101
|
</section>
|
|
102
102
|
</div>
|
|
103
103
|
</div>
|
|
104
|
-
</section>`;let t=e.querySelector("#overview-pills"),n=e.querySelector("#team-grid"),s=e.querySelector("#attention-list"),a=e.querySelector("#recent-sessions"),i=e.querySelector("#today-donut"),l=e.querySelector("#next-schedules");function p(){let v=[...G.sessions.values()],y=v.filter(f=>f.status!=="closed"),h=y.filter(f=>Te(f)).sort((f,w)=>Number(f.lastMessageAt??0)-Number(w.lastMessageAt??0)),k=y.filter(f=>
|
|
104
|
+
</section>`;let t=e.querySelector("#overview-pills"),n=e.querySelector("#team-grid"),s=e.querySelector("#attention-list"),a=e.querySelector("#recent-sessions"),i=e.querySelector("#today-donut"),l=e.querySelector("#next-schedules");function p(){let v=[...G.sessions.values()],y=v.filter(f=>f.status!=="closed"),h=y.filter(f=>Te(f)).sort((f,w)=>Number(f.lastMessageAt??0)-Number(w.lastMessageAt??0)),k=y.filter(f=>Bt.has(f.status)&&!Te(f)),u=y.length-h.length-k.length,E=ra(v),q=E.filter(f=>f.online||f.active.length>0).length;t.innerHTML=`
|
|
105
105
|
<span class="pill">${r(o("overview.workingSessions"))} <b>${k.length}</b></span>
|
|
106
106
|
<span class="pill${h.length?" pill-hot":""}">${r(o("overview.attention"))} <b>${h.length}</b></span>
|
|
107
|
-
<span class="pill">${r(o("overview.onlineBots"))} <b>${
|
|
107
|
+
<span class="pill">${r(o("overview.onlineBots"))} <b>${q}</b></span>`,n.innerHTML=E.length?E.map(la).join(""):`<div class="empty">${o("overview.noSessions")}</div>`,s.innerHTML=h.length?h.map(da).join(""):`<div class="qcard qcard-empty">${o("overview.noAttention")}</div>`;let $=y.filter(f=>Bt.has(f.status)||f.status==="idle").sort((f,w)=>Number(w.lastMessageAt??0)-Number(f.lastMessageAt??0)).slice(0,7);a.innerHTML=$.length?$.map(ca).join(""):`<li class="empty">${o("overview.noSessions")}</li>`,i.innerHTML=`${pa(k.length,h.length,Math.max(0,u))}
|
|
108
108
|
<div class="donut-legend">
|
|
109
109
|
<span><i style="background:var(--accent)"></i>${r(o("overview.workingSessions"))} ${k.length}</span>
|
|
110
110
|
<span><i style="background:var(--warning)"></i>${r(o("overview.attention"))} ${h.length}</span>
|
|
111
111
|
<span><i style="background:var(--success)"></i>${r(o("sessions.board.idle"))} ${Math.max(0,u)}</span>
|
|
112
|
-
</div>`;let d=[...G.schedules.values()].filter(f=>f.nextRunAt).sort((f,w)=>Date.parse(f.nextRunAt)-Date.parse(w.nextRunAt)).slice(0,5);l.innerHTML=d.length?d.map(
|
|
112
|
+
</div>`;let d=[...G.schedules.values()].filter(f=>f.nextRunAt).sort((f,w)=>Date.parse(f.nextRunAt)-Date.parse(w.nextRunAt)).slice(0,5);l.innerHTML=d.length?d.map(ua).join(""):`<li class="empty">${o("overview.noSchedules")}</li>`}G.on(p),p(),ia().then(p),fe().then(p)}function Le(e,t){return`<th data-sort="${e}" data-label="${r(t)}">${r(t)}</th>`}var Bn=["claude-code","seed","codex","codex-app","cursor","gemini","opencode","mtr","hermes","mira","pi","copilot","aiden","coco","unknown"],Rn=[{id:"needs-you",labelKey:"sessions.board.needsYou",hintKey:"sessions.board.needsYouHint"},{id:"starting",labelKey:"sessions.board.starting",hintKey:"sessions.board.startingHint"},{id:"working",labelKey:"sessions.board.working",hintKey:"sessions.board.workingHint"},{id:"idle",labelKey:"sessions.board.idle",hintKey:"sessions.board.idleHint"}];function ma(e){return String(e??"unknown").toLowerCase().replace(/[^a-z0-9_-]/g,"-")}function fa(e){let t=String(e??"").trim();return t?t.replace(/\\/g,"/").split("/").filter(Boolean).at(-1)??t:"-"}function On(e){if(!e.webPort)return null;let t=e.proxyPort??e.webPort,n=e.proxyPort?`/s/${encodeURIComponent(e.sessionId)}`:"";return`http://${location.hostname}:${t}${n}`}function ga(e){return e.status==="closed"?null:e.pendingRepo||e.tuiPromptActive||e.status==="limited"?"needs-you":e.status==="starting"?"starting":e.status==="working"||e.status==="analyzing"||e.status==="active"?"working":"idle"}function ba(){return`<details class="filter-cli">
|
|
113
113
|
<summary>${o("sessions.cli")} \xB7 <b id="cli-filter-count">${o("common.all")}</b></summary>
|
|
114
114
|
<div class="filter-cli-pop" role="group" aria-label="${o("sessions.cli")}">
|
|
115
|
-
${
|
|
115
|
+
${Bn.map(e=>`
|
|
116
116
|
<label class="filter-check">
|
|
117
117
|
<input type="checkbox" name="cli" value="${r(e)}" checked>
|
|
118
118
|
<span>${r(e)}</span>
|
|
119
119
|
</label>
|
|
120
120
|
`).join("")}
|
|
121
121
|
</div>
|
|
122
|
-
</details>`}function
|
|
122
|
+
</details>`}function ha(){return`<section class="page">
|
|
123
123
|
<div class="page-heading">
|
|
124
124
|
<div>
|
|
125
125
|
<p class="eyebrow">${o("nav.sessions")}</p>
|
|
@@ -143,7 +143,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
143
143
|
<option value="yes">${o("sessions.adoptYes")}</option>
|
|
144
144
|
<option value="no">${o("sessions.adoptNo")}</option>
|
|
145
145
|
</select>
|
|
146
|
-
${
|
|
146
|
+
${ba()}
|
|
147
147
|
<label class="filter-toggle"><input type="checkbox" name="active" checked> <span>${o("sessions.activeOnly")}</span></label>
|
|
148
148
|
</form>
|
|
149
149
|
<div id="bulk-bar" class="bulk-bar" hidden>
|
|
@@ -154,47 +154,47 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
154
154
|
<table id="sessions-table">
|
|
155
155
|
<thead><tr>
|
|
156
156
|
<th><input type="checkbox" id="select-all" title="${o("sessions.activeOnly")}"></th>
|
|
157
|
-
${
|
|
158
|
-
${
|
|
159
|
-
${
|
|
160
|
-
${
|
|
161
|
-
${
|
|
162
|
-
${
|
|
163
|
-
${
|
|
164
|
-
${
|
|
157
|
+
${Le("botName",o("sessions.bot"))}
|
|
158
|
+
${Le("cliId",o("sessions.cli"))}
|
|
159
|
+
${Le("status",o("sessions.status"))}
|
|
160
|
+
${Le("title",o("sessions.titleCol"))}
|
|
161
|
+
${Le("workingDir",o("sessions.workingDir"))}
|
|
162
|
+
${Le("spawnedAt",o("sessions.created"))}
|
|
163
|
+
${Le("lastMessageAt",o("sessions.last"))}
|
|
164
|
+
${Le("adopt",o("sessions.adopt"))}
|
|
165
165
|
<th>${o("sessions.actions")}</th>
|
|
166
166
|
</tr></thead>
|
|
167
167
|
<tbody></tbody>
|
|
168
168
|
</table>
|
|
169
169
|
<div id="sessions-board" class="sessions-board" hidden></div>
|
|
170
170
|
<dialog id="drawer"></dialog>
|
|
171
|
-
</section>`}function
|
|
171
|
+
</section>`}function qn(e){e.innerHTML=ha();let t=e.querySelector("#sessions-table tbody"),n=e.querySelector("#filters"),s=e.querySelector("#drawer"),a=e.querySelector("#select-all"),i=e.querySelector("#bulk-bar"),l=e.querySelector("#bulk-count"),p=e.querySelector("#bulk-close"),v=e.querySelector("#bulk-clear"),y=e.querySelector("#sessions-table"),h=e.querySelector("#sessions-board"),k=e.querySelectorAll("[data-view]"),u=new Set,E="lastMessageAt",q="desc",$=gn(window.localStorage),d=hn(window.localStorage),f=null,w="",I="",x=!1;function M(){return d.map(c=>Rn.find(g=>g.id===c)).filter(c=>!!c)}function H(c,g){let S=d.indexOf(c),L=S+g;if(S<0||L<0||L>=d.length)return;let T=[...d];T.splice(S,1),T.splice(L,0,c),d=T,Et(window.localStorage,d),Q()}function O(c,g){if(c===g)return;let S=d.indexOf(c),L=d.indexOf(g);if(S<0||L<0)return;let T=[...d];T.splice(S,1),T.splice(L,0,c),d=T,Et(window.localStorage,d),Q()}function z(c){let g=c.status==="closed",S=u.has(c.sessionId)?"checked":"";return`<tr data-id="${r(c.sessionId)}">
|
|
172
172
|
<td><input type="checkbox" class="row-select" ${S} ${g?"disabled":""}></td>
|
|
173
|
-
<td>${r(
|
|
174
|
-
<td><span class="badge cli-${
|
|
173
|
+
<td>${r(ge(c))}</td>
|
|
174
|
+
<td><span class="badge cli-${ma(c.cliId)}">${r(c.cliId??"unknown")}</span></td>
|
|
175
175
|
<td><span class="status status-${r(c.status??"unknown")}">${r(c.status??"unknown")}</span></td>
|
|
176
|
-
<td title="${r(String(c.title??""))}">${r(
|
|
176
|
+
<td title="${r(String(c.title??""))}">${r(Se(c.title??"").slice(0,48))}</td>
|
|
177
177
|
<td title="${r(c.workingDir??"")}">${r((c.workingDir??"").slice(-34))}</td>
|
|
178
178
|
<td>${ue(c.spawnedAt)}</td>
|
|
179
179
|
<td>${ue(c.lastMessageAt)}</td>
|
|
180
180
|
<td>${c.adopt?'<span class="badge">adopt</span>':""}</td>
|
|
181
181
|
<td><button class="open" type="button">${o("sessions.details")}</button></td>
|
|
182
|
-
</tr>`}function j(c){return c.scope!=="chat"||!c.feishuChatLink?null:`<a class="btn-link" href="${r(c.feishuChatLink)}" target="_blank" rel="noopener">${o("sessions.openChat")}</a>`}function ee(c){return c.pendingRepo?o("sessions.board.signalRepo"):c.tuiPromptActive?o("sessions.board.signalPrompt"):c.status==="limited"?o("sessions.board.signalLimited"):""}function ae(c){let g=u.has(c.sessionId),S
|
|
182
|
+
</tr>`}function j(c){return c.scope!=="chat"||!c.feishuChatLink?null:`<a class="btn-link" href="${r(c.feishuChatLink)}" target="_blank" rel="noopener">${o("sessions.openChat")}</a>`}function ee(c){return c.pendingRepo?o("sessions.board.signalRepo"):c.tuiPromptActive?o("sessions.board.signalPrompt"):c.status==="limited"?o("sessions.board.signalLimited"):""}function ae(c){let g=u.has(c.sessionId),S=Se(c.title)||c.sessionId,L=ge(c),T=Ne(c),P=On(c),B=ee(c);return`<article class="session-card${g?" selected":""}" data-id="${r(c.sessionId)}" aria-pressed="${g}">
|
|
183
183
|
<div class="session-card-top">
|
|
184
|
-
|
|
184
|
+
${de({name:L,larkAppId:c.larkAppId,size:"sm"})}
|
|
185
185
|
<div class="session-card-title">
|
|
186
186
|
<strong title="${r(String(c.title??S))}">${r(String(S).slice(0,72))}</strong>
|
|
187
|
-
<span>${r(L)} \xB7 ${r(
|
|
187
|
+
<span>${r(L)} \xB7 ${r(T??c.cliId??"unknown")}</span>
|
|
188
188
|
</div>
|
|
189
189
|
<span class="status status-${r(c.status??"unknown")}">${r(c.status??"unknown")}</span>
|
|
190
190
|
</div>
|
|
191
191
|
<div class="session-card-meta">
|
|
192
|
-
<span title="${r(c.workingDir??"")}">${r(
|
|
192
|
+
<span title="${r(c.workingDir??"")}">${r(fa(c.workingDir))}</span>
|
|
193
193
|
${c.adopt?'<span class="badge">adopt</span>':""}
|
|
194
194
|
</div>
|
|
195
195
|
<div class="session-card-time">
|
|
196
196
|
<span>${r(o("sessions.last"))}: ${ue(c.lastMessageAt)}</span>
|
|
197
|
-
${
|
|
197
|
+
${B?`<span class="session-signal">${r(B)} \xB7 ${ue(c.lastMessageAt)}</span>`:""}
|
|
198
198
|
</div>
|
|
199
199
|
<div class="session-card-actions">
|
|
200
200
|
${j(c)??`<button type="button" data-action="locate">${o("sessions.locate")}</button>`}
|
|
@@ -202,32 +202,32 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
202
202
|
${P?`<a class="btn-link primary" href="${r(P)}" target="_blank" rel="noopener">${o("sessions.openTerminal")}</a>`:""}
|
|
203
203
|
<button type="button" class="contrast" data-action="close">${o("sessions.close")}</button>
|
|
204
204
|
</div>
|
|
205
|
-
</article>`}function Z(c,g,S){let L=Number(c.lastMessageAt??0),
|
|
205
|
+
</article>`}function Z(c,g,S){let L=Number(c.lastMessageAt??0),T=Number(g.lastMessageAt??0);return L!==T?S==="needs-you"?L-T:T-L:String(c.title??c.sessionId).localeCompare(String(g.title??g.sessionId))}function J(c){let g=new Map(Rn.map(T=>[T.id,[]]));for(let T of c){let P=ga(T);P&&g.get(P).push(T)}let S=M(),L=S.map((T,P)=>{let B=(g.get(T.id)??[]).sort((X,Y)=>Z(X,Y,T.id));return`<section class="session-board-column session-board-${T.id}" data-col="${T.id}">
|
|
206
206
|
<header draggable="true" title="${r(o("sessions.board.dragHint"))}">
|
|
207
207
|
<div>
|
|
208
|
-
<h2>${r(o(
|
|
209
|
-
<p>${r(o(
|
|
208
|
+
<h2>${r(o(T.labelKey))}</h2>
|
|
209
|
+
<p>${r(o(T.hintKey))}</p>
|
|
210
210
|
</div>
|
|
211
211
|
<span class="session-board-head-right">
|
|
212
212
|
<span class="session-board-move">
|
|
213
|
-
<button type="button" data-move-col="${
|
|
213
|
+
<button type="button" data-move-col="${T.id}" data-dir="-1"
|
|
214
214
|
aria-label="${r(o("sessions.board.moveLeft"))}" ${P===0?"disabled":""}>\u2039</button>
|
|
215
|
-
<button type="button" data-move-col="${
|
|
215
|
+
<button type="button" data-move-col="${T.id}" data-dir="1"
|
|
216
216
|
aria-label="${r(o("sessions.board.moveRight"))}" ${P===S.length-1?"disabled":""}>\u203A</button>
|
|
217
217
|
</span>
|
|
218
|
-
<span class="session-board-count">${
|
|
218
|
+
<span class="session-board-count">${B.length}</span>
|
|
219
219
|
</span>
|
|
220
220
|
</header>
|
|
221
221
|
<div class="session-board-list">
|
|
222
|
-
${
|
|
222
|
+
${B.length?B.map(ae).join(""):`<div class="session-board-empty">${o("sessions.board.emptyColumn")}</div>`}
|
|
223
223
|
</div>
|
|
224
|
-
</section>`}).join("");L!==w&&(w=L,h.innerHTML=L,h.classList.toggle("board-enter",!x),x=!0)}function se(){let c=new FormData(n),g=(c.get("q")??"").toLowerCase(),S=c.getAll("cli"),L=S.length>0&&S.length<
|
|
224
|
+
</section>`}).join("");L!==w&&(w=L,h.innerHTML=L,h.classList.toggle("board-enter",!x),x=!0)}function se(){let c=new FormData(n),g=(c.get("q")??"").toLowerCase(),S=c.getAll("cli"),L=S.length>0&&S.length<Bn.length,T=c.get("status"),P=c.get("adopt"),B=!!c.get("active"),X=[...G.sessions.values()].filter(Y=>!L||S.includes(Y.cliId??"unknown")).filter(Y=>!T||Y.status===T).filter(Y=>!P||P==="yes"==!!Y.adopt).filter(Y=>!B||Y.status!=="closed").filter(Y=>!g||JSON.stringify(Y).toLowerCase().includes(g));return X.sort(ve),X}function He(c,g){return g==="spawnedAt"||g==="lastMessageAt"?Number(c[g]??0):g==="adopt"?!!c.adopt:String(c[g]??"").toLowerCase()}function ve(c,g){let S=He(c,E),L=He(g,E),T=0;return typeof S=="number"&&typeof L=="number"?T=S-L:typeof S=="boolean"&&typeof L=="boolean"?T=Number(S)-Number(L):T=String(S).localeCompare(String(L)),T===0&&(T=Number(c.lastMessageAt??0)-Number(g.lastMessageAt??0)),q==="asc"?T:-T}function ie(){y.querySelectorAll("th[data-sort]").forEach(c=>{let g=c.dataset.sort===E;c.classList.toggle("sorted",g),c.setAttribute("aria-sort",g?q==="asc"?"ascending":"descending":"none");let S=c.dataset.label??c.textContent?.trim()??"";c.textContent=g?`${S} ${q==="asc"?"\u25B2":"\u25BC"}`:S})}function re(c){i.hidden=u.size===0,l.textContent=o("sessions.selectedCount",{count:u.size});let g=c.filter(L=>L.status!=="closed");if(g.length===0){a.checked=!1,a.indeterminate=!1,a.disabled=!0;return}a.disabled=!1;let S=g.filter(L=>u.has(L.sessionId)).length;a.checked=S===g.length,a.indeterminate=S>0&&S<g.length}function te(){k.forEach(c=>{let g=c.dataset.view===$;c.classList.toggle("active",g),c.setAttribute("aria-pressed",String(g))})}function pe(){let c=n.querySelector("#cli-filter-count");if(!c)return;let g=[...n.querySelectorAll('input[name="cli"]')],S=g.filter(L=>L.checked).length;c.textContent=S===g.length?o("common.all"):`${S}/${g.length}`,c.classList.toggle("cli-filter-active",S!==g.length)}function Q(){let c=se();for(let L of[...u]){let T=G.sessions.get(L);(!T||T.status==="closed")&&u.delete(L)}let g=c.filter(L=>L.status!=="closed"),S=$==="board"?g:c;if(y.hidden=$!=="table",h.hidden=$!=="board",$==="table"){let L=c.length?c.map(z).join(""):`<tr><td colspan="10" class="empty">${o("sessions.empty")}</td></tr>`;L!==I&&(I=L,t.innerHTML=L)}else J(g);te(),ie(),pe(),re(S)}async function ke(c,g){g&&(g.disabled=!0,g.textContent=o("sessions.locating"));try{let S=await fetch(`/api/sessions/${encodeURIComponent(c.sessionId)}/locate`,{method:"POST"}),L=await S.json();if(L.ok){if(!g)return;let T=30;g.textContent=o("sessions.cooldown",{seconds:T});let P=setInterval(()=>{T-=1,T<=0?(clearInterval(P),g.disabled=!1,g.textContent=o("sessions.locate")):g.textContent=o("sessions.cooldown",{seconds:T})},1e3)}else alert(`Locate failed: ${L.error??S.status}`),g&&(g.disabled=!1,g.textContent=o("sessions.locate"))}catch(S){alert(`Locate error: ${S}`),g&&(g.disabled=!1,g.textContent=o("sessions.locate"))}}async function $e(c,g){if(!confirm(o("sessions.closeConfirm")))return!1;g&&(g.disabled=!0);try{let S=await fetch(`/api/sessions/${encodeURIComponent(c.sessionId)}/close`,{method:"POST"}),L=await S.json().catch(()=>({}));return!S.ok||L?.ok===!1?(S.status!==401&&alert(`Close failed: ${L?.error??S.status}`),!1):!0}catch(S){return alert(`Close error: ${S}`),!1}finally{g&&(g.disabled=!1)}}function V(c){let g=c.status==="closed",S=On(c);s.innerHTML=`<article>
|
|
225
225
|
<header>
|
|
226
|
-
<h3>${r(
|
|
226
|
+
<h3>${r(Se(c.title)||c.sessionId)}</h3>
|
|
227
227
|
<span class="status status-${r(c.status??"unknown")}">${r(c.status??"unknown")}</span>
|
|
228
228
|
<p><code>${r(c.sessionId)}</code> <button data-copy="${r(c.sessionId)}">${o("sessions.copy")}</button></p>
|
|
229
229
|
</header>
|
|
230
|
-
<p><b>${o("sessions.bot")}:</b> ${r(
|
|
230
|
+
<p><b>${o("sessions.bot")}:</b> ${r(ge(c))} \xB7 <b>${o("sessions.cli")}:</b> ${r(c.cliId??"?")}</p>
|
|
231
231
|
${Ne(c)?`<p><b>${o("sessions.chat")}:</b> ${r(Ne(c))}</p>`:""}
|
|
232
232
|
<p><b>chatId:</b> <code>${r(c.chatId??"")}</code> <button data-copy="${r(c.chatId??"")}">${o("sessions.copy")}</button></p>
|
|
233
233
|
<p><b>rootMessageId:</b> <code>${r(c.rootMessageId??"")}</code> <button data-copy="${r(c.rootMessageId??"")}">${o("sessions.copy")}</button></p>
|
|
@@ -240,7 +240,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
240
240
|
${g?"":`<button id="close-btn" type="button" class="contrast">${o("sessions.close")}</button>`}
|
|
241
241
|
</div>
|
|
242
242
|
<form method="dialog"><button>${o("sessions.dismiss")}</button></form>
|
|
243
|
-
</article>`,s.querySelectorAll("[data-copy]").forEach(
|
|
243
|
+
</article>`,s.querySelectorAll("[data-copy]").forEach(B=>{B.onclick=()=>{navigator.clipboard.writeText(B.dataset.copy??""),B.textContent=o("sessions.copied"),setTimeout(()=>{B.textContent=o("sessions.copy")},800)}});let L=s.querySelector("#locate-btn");L&&(L.onclick=()=>{ke(c,L)});let T=s.querySelector("#resume-btn");T&&(T.onclick=async()=>{T.disabled=!0;try{let B=await fetch(`/api/sessions/${encodeURIComponent(c.sessionId)}/resume`,{method:"POST"}),X=await B.json().catch(()=>({}));if(!B.ok||X.ok===!1){alert(`${o("sessions.resumeFailed")}: ${X?.error??B.status}`),T.disabled=!1;return}s.close()}catch(B){alert(`${o("sessions.resumeFailed")}: ${B}`),T.disabled=!1}});let P=s.querySelector("#close-btn");P&&(P.onclick=async()=>{await $e(c,P)&&s.close()}),s.showModal()}t.addEventListener("click",c=>{let g=c.target;if(g.classList.contains("row-select")){let P=g.closest("tr[data-id]");if(!P)return;g.checked?u.add(P.dataset.id):u.delete(P.dataset.id),re(se());return}let S=g.closest("td");if(S&&S.querySelector(".row-select"))return;let L=g.closest("tr[data-id]");if(!L)return;let T=G.sessions.get(L.dataset.id);T&&V(T)}),h.addEventListener("click",c=>{let g=c.target,S=g.closest("button[data-move-col]");if(S){H(S.dataset.moveCol,Number(S.dataset.dir));return}let L=g.closest(".session-card[data-id]");if(!L)return;let T=G.sessions.get(L.dataset.id);if(!T)return;let P=g.closest("button[data-action]");if(P){let B=P.dataset.action;B==="details"?V(T):B==="locate"?ke(T,P):B==="close"&&$e(T,P).then(X=>{X&&(u.delete(T.sessionId),Q())});return}g.closest("a, button, input, label")||(u.has(T.sessionId)?u.delete(T.sessionId):u.add(T.sessionId),L.classList.toggle("selected",u.has(T.sessionId)),L.setAttribute("aria-pressed",String(u.has(T.sessionId))),re(se().filter(B=>B.status!=="closed")))}),h.addEventListener("dragstart",c=>{let S=c.target.closest(".session-board-column > header[draggable]")?.closest(".session-board-column");S?.dataset.col&&(f=S.dataset.col,S.classList.add("dragging"),c.dataTransfer&&(c.dataTransfer.effectAllowed="move",c.dataTransfer.setData("text/plain",f)))}),h.addEventListener("dragover",c=>{if(!f)return;c.preventDefault(),c.dataTransfer&&(c.dataTransfer.dropEffect="move");let g=c.target.closest(".session-board-column");h.querySelectorAll(".drag-over").forEach(S=>S.classList.remove("drag-over")),g&&g.dataset.col!==f&&g.classList.add("drag-over")}),h.addEventListener("drop",c=>{if(!f)return;c.preventDefault();let g=c.target.closest(".session-board-column"),S=f;f=null,g?.dataset.col&&O(S,g.dataset.col)}),h.addEventListener("dragend",()=>{f=null,h.querySelectorAll(".drag-over, .dragging").forEach(c=>c.classList.remove("drag-over","dragging"))}),k.forEach(c=>{c.addEventListener("click",()=>{let g=c.dataset.view==="table"?"table":"board";g!==$&&($=g,wn(window.localStorage,$),Q())})}),a.addEventListener("change",()=>{let c=se().filter(g=>g.status!=="closed");for(let g of c)a.checked?u.add(g.sessionId):u.delete(g.sessionId);Q()}),v.addEventListener("click",()=>{u.clear(),Q()}),p.addEventListener("click",async()=>{let c=[...u];if(c.length===0||!confirm(o("sessions.closeBulkConfirm",{count:c.length})))return;p.disabled=!0,v.disabled=!0;let g=p.textContent,S=0,L=0,T=[...c];p.textContent=`0/${c.length}`;async function P(){for(;T.length;){let B=T.shift();try{let X=await fetch(`/api/sessions/${encodeURIComponent(B)}/close`,{method:"POST"}),Y=await X.json().catch(()=>({}));(!X.ok||Y?.ok===!1)&&(L+=1)}catch{L+=1}finally{S+=1,p.textContent=`${S}/${c.length}`}}}await Promise.all(Array.from({length:Math.min(6,c.length)},()=>P())),p.textContent=g,p.disabled=!1,v.disabled=!1,u.clear(),Q(),L>0&&alert(`Failed: ${L}/${c.length}`)}),y.querySelectorAll("th[data-sort]").forEach(c=>{c.addEventListener("click",()=>{let g=c.dataset.sort;E===g?q=q==="asc"?"desc":"asc":(E=g,q=g==="spawnedAt"||g==="lastMessageAt"?"desc":"asc"),Q()})}),n.addEventListener("input",Q),G.on(Q),Q(),fe().then(Q)}function wa(){return`<section class="page">
|
|
244
244
|
<div class="page-heading">
|
|
245
245
|
<div>
|
|
246
246
|
<p class="eyebrow">${o("nav.schedules")}</p>
|
|
@@ -265,19 +265,19 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
265
265
|
</tr></thead>
|
|
266
266
|
<tbody id="schedules-tbody"></tbody>
|
|
267
267
|
</table>
|
|
268
|
-
</section>`}function
|
|
268
|
+
</section>`}function Pn(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function Nn(e){e.innerHTML=wa();let t=e.querySelector("#schedules-tbody"),n=e.querySelector("#sched-filters");function s(){let i=new FormData(n),l=(i.get("q")??"").toLowerCase(),p=i.get("kind"),v=!!i.get("enabled");return[...G.schedules.values()].filter(y=>!p||y.parsed?.kind===p).filter(y=>!v||y.enabled).filter(y=>!l||JSON.stringify(y).toLowerCase().includes(l)).sort((y,h)=>{if(y.enabled!==h.enabled)return y.enabled?-1:1;let k=y.nextRunAt?Date.parse(y.nextRunAt):1/0,u=h.nextRunAt?Date.parse(h.nextRunAt):1/0;return k-u})}function a(){t.innerHTML=s().map(i=>`<tr data-id="${r(i.id)}">
|
|
269
269
|
<td>${r(i.name??i.id)}</td>
|
|
270
270
|
<td>${r(i.botName??i.larkAppId??"-")}</td>
|
|
271
271
|
<td><code>${r(i.parsed?.display??"?")}</code></td>
|
|
272
|
-
<td>${
|
|
273
|
-
<td>${
|
|
272
|
+
<td>${Pn(i.nextRunAt)}</td>
|
|
273
|
+
<td>${Pn(i.lastRunAt)} ${i.lastStatus==="error"?"\u26A0\uFE0F":""}</td>
|
|
274
274
|
<td>${i.repeat?`${i.repeat.completed}/${i.repeat.times??"\u221E"}`:"\u2014"}</td>
|
|
275
275
|
<td>${i.enabled?"\u2713":"\u2717"}</td>
|
|
276
276
|
<td class="actions-cell">
|
|
277
277
|
<button data-op="run" type="button">${o("schedules.runNow")}</button>
|
|
278
278
|
${i.enabled?`<button data-op="pause" type="button">${o("schedules.pause")}</button>`:`<button data-op="resume" type="button">${o("schedules.resume")}</button>`}
|
|
279
279
|
</td>
|
|
280
|
-
</tr>`).join("")||`<tr><td colspan="8" class="empty">${o("schedules.empty")}</td></tr>`}t.addEventListener("click",async i=>{let l=i.target.closest("button[data-op]");if(!l)return;let p=l.closest("tr[data-id]");if(!p)return;let v=p.dataset.id,y=l.dataset.op;l.disabled=!0;let h=l.textContent;l.textContent="...";try{let k=await fetch(`/api/schedules/${encodeURIComponent(v)}/${y}`,{method:"POST"}),u=await k.json().catch(()=>({}));(!k.ok||u.ok===!1)&&alert(`Failed: ${k.status} ${u?.error??""}`.trim())}catch(k){alert("Network error: "+k)}finally{l.disabled=!1,l.textContent=h}}),n.addEventListener("input",a),G.on(a),a()}var oe={chats:[],bots:[]};function
|
|
280
|
+
</tr>`).join("")||`<tr><td colspan="8" class="empty">${o("schedules.empty")}</td></tr>`}t.addEventListener("click",async i=>{let l=i.target.closest("button[data-op]");if(!l)return;let p=l.closest("tr[data-id]");if(!p)return;let v=p.dataset.id,y=l.dataset.op;l.disabled=!0;let h=l.textContent;l.textContent="...";try{let k=await fetch(`/api/schedules/${encodeURIComponent(v)}/${y}`,{method:"POST"}),u=await k.json().catch(()=>({}));(!k.ok||u.ok===!1)&&alert(`Failed: ${k.status} ${u?.error??""}`.trim())}catch(k){alert("Network error: "+k)}finally{l.disabled=!1,l.textContent=h}}),n.addEventListener("input",a),G.on(a),a()}var oe={chats:[],bots:[]};function ya(){return`<section class="page">
|
|
281
281
|
<div class="page-heading">
|
|
282
282
|
<div>
|
|
283
283
|
<p class="eyebrow">${o("nav.groups")}</p>
|
|
@@ -296,12 +296,12 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
296
296
|
<tbody id="g-body"></tbody>
|
|
297
297
|
</table>
|
|
298
298
|
<dialog id="g-drawer"></dialog>
|
|
299
|
-
</section>`}async function Ue(){oe=await(await fetch("/api/groups")).json()}async function
|
|
299
|
+
</section>`}async function Ue(){oe=await(await fetch("/api/groups")).json()}async function va(){return(await fetch("/api/groups")).json()}function ka(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 Un(e,t){return e.filter(n=>!t||!t.has(n.larkAppId)).map(n=>`
|
|
300
300
|
<label class="checkbox-row">
|
|
301
301
|
<input type="checkbox" name="bot" value="${r(n.larkAppId)}">
|
|
302
302
|
${r(n.botName??n.larkAppId)} <small>(${r(n.larkAppId)})</small>
|
|
303
303
|
</label>
|
|
304
|
-
`).join("")}async function
|
|
304
|
+
`).join("")}async function jn(e){e.innerHTML=ya();let t=e.querySelector("#g-head"),n=e.querySelector("#g-body"),s=e.querySelector("#g-filters"),a=e.querySelector("#g-refresh"),i=e.querySelector("#g-drawer");a.onclick=async()=>{a.disabled=!0;try{await Ue(),h()}finally{a.disabled=!1}};let l=e.querySelector("#g-create");l.onclick=()=>p(),await Ue();function p(){let u=oe.bots;if(u.length===0){alert(o("groups.noBotsOnline"));return}i.innerHTML=`
|
|
305
305
|
<article>
|
|
306
306
|
<header><h3>${o("groups.createTitle")}</h3></header>
|
|
307
307
|
<p>${o("groups.createHelp")}</p>
|
|
@@ -317,14 +317,14 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
317
317
|
</label>
|
|
318
318
|
<fieldset>
|
|
319
319
|
<legend>${o("groups.botPicker")}</legend>
|
|
320
|
-
${
|
|
320
|
+
${Un(u)}
|
|
321
321
|
</fieldset>
|
|
322
322
|
<div class="actions">
|
|
323
323
|
<button type="submit" class="primary">${o("groups.createSubmit")}</button>
|
|
324
324
|
<button type="button" id="g-create-cancel">${o("groups.cancel")}</button>
|
|
325
325
|
</div>
|
|
326
326
|
</form>
|
|
327
|
-
</article>`,i.showModal(),i.querySelector("#g-create-cancel").onclick=()=>i.close(),i.querySelector("#g-createform").onsubmit=async $=>{$.preventDefault();let d=new FormData($.target),f=(d.get("name")??"").trim(),w=(d.get("bindWorkingDir")??"").trim(),
|
|
327
|
+
</article>`,i.showModal(),i.querySelector("#g-create-cancel").onclick=()=>i.close(),i.querySelector("#g-createform").onsubmit=async $=>{$.preventDefault();let d=new FormData($.target),f=(d.get("name")??"").trim(),w=(d.get("bindWorkingDir")??"").trim(),I=d.getAll("bot");if(I.length===0){alert("Pick at least one bot.");return}let x=$.target.querySelector("button[type=submit]");x&&(x.disabled=!0,x.textContent="Creating...");try{let M=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:f||void 0,larkAppIds:I,bindWorkingDir:w||void 0})}),H=await M.json();if(H.ok&&H.chatId){v(H);let O=Array.isArray(H.invalidBotIds)?H.invalidBotIds:[],z=I.filter(ee=>!O.includes(ee)),j=new Set(z);typeof H.creator=="string"&&H.creator&&j.add(H.creator),E(H.chatId,f||H.chatId,z,H.creator),h(),q(H.chatId,j).catch(()=>{})}else alert(`Failed: ${H.error??M.status}`),i.close()}catch(M){alert("Network error: "+M),i.close()}};function E($,d,f,w){let I=new Set(f);w&&I.add(w);let x=oe.bots.map(H=>({larkAppId:H.larkAppId,botName:H.botName,inChat:I.has(H.larkAppId),oncallChat:null})),M={chatId:$,name:d,ownerId:w??null,memberBots:x};oe.chats=[M,...oe.chats.filter(H=>H.chatId!==$)]}async function q($,d){let f=[600,1200,1200,1200,1200,1200];for(let w of f){await new Promise(M=>setTimeout(M,w));let I;try{I=await va()}catch{continue}let x=(I.chats??[]).find(M=>M.chatId===$);if(x&&ka(x,d)){oe=I,h();return}}}}function v(u){let E=String(u.chatId),q=typeof u.shareLink=="string"&&u.shareLink?u.shareLink:`https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(E)}`,$=u.invalidBotIds??[],d=u.invalidUserIds??[],f=u.autoInvitedOpenId,w=!!u.autoInviteRejected,I=u.ownerTransferredTo,x=u.transferError,M=u.notifyMessageId,H=u.notifyError,O=Array.isArray(u.oncallBindings)?u.oncallBindings:[],z=O.filter(J=>J?.ok).length,j=O.filter(J=>!J?.ok),ee=O.length>0?j.length===0?`<p class="hint-ok">\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1A<code>${r(u.bindResolvedPath??"")}</code>\uFF08${z}/${O.length} bots\uFF09</p>`:`<p class="hint-warn">\u76EE\u5F55\u7ED1\u5B9A\u90E8\u5206\u5931\u8D25\uFF1A\u6210\u529F ${z}/${O.length}\u3002${j.map(J=>`<br><code>${r(J.larkAppId??"?")}</code>: ${r(J.error??"unknown")}`).join("")}</p>`:"",ae;if(f){let J=I?"<br><small>\u7FA4\u4E3B\u5DF2\u4ECE\u673A\u5668\u4EBA\u8F6C\u8BA9\u7ED9\u4F60\u3002</small>":x?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08${r(x)}\uFF09\uFF0C\u4F60\u73B0\u5728\u662F\u6210\u5458\u4F46\u7FA4\u4E3B\u4ECD\u662F\u673A\u5668\u4EBA\u3002</small>`:"",se=M?`<br><small>\u673A\u5668\u4EBA\u5DF2\u5728\u7FA4\u91CC @ \u4E86\u4F60\uFF08\u6D88\u606F id <code>${r(M)}</code>\uFF09\uFF0C\u770B\u98DE\u4E66\u901A\u77E5\u5C31\u80FD\u8FDB\u7FA4\u3002</small>`:H?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8 @ \u901A\u77E5\u5931\u8D25\uFF08${r(H)}\uFF09\uFF0C\u65B0\u7FA4\u53EF\u80FD\u4E0D\u4F1A\u4E3B\u52A8\u51FA\u73B0\u5728\u4F60\u4FA7\u8FB9\u680F\uFF0C\u5EFA\u8BAE\u4ECE\u4E0B\u9762\u6309\u94AE\u8DF3\u8FDB\u53BB\u3002</small>`:"";ae=`<p class="hint-ok">\u5DF2\u81EA\u52A8\u9080\u8BF7\u4F60\uFF08<code>${r(f)}</code>\uFF09\u4F5C\u4E3A\u6210\u5458\u3002${J}${se}</p>`}else w?ae='<p class="hint-warn">\u98DE\u4E66\u62D2\u7EDD\u4E86\u81EA\u52A8\u9080\u8BF7\uFF08\u4F60\u7684 open_id \u5728\u521B\u5EFA\u8005 bot \u7684 scope \u4E0B\u4E0D\u53EF\u7528\uFF09\u3002<strong>\u4F60\u76EE\u524D\u4E0D\u662F\u65B0\u7FA4\u6210\u5458</strong>\uFF0C\u9700\u8981\u8BA9\u7FA4\u91CC\u7684\u67D0\u4E2A\u673A\u5668\u4EBA\u624B\u52A8\u628A\u4F60\u52A0\u8FDB\u6765\u3002</p>':ae='<p class="hint-warn">\u6CA1\u5728 dashboard \u7F13\u5B58\u91CC\u627E\u5230 ownerOpenId\uFF0C<strong>\u6CA1\u6709\u81EA\u52A8\u9080\u8BF7\u4F60</strong>\u3002\u70B9\u5F00\u4E0B\u9762\u94FE\u63A5\u524D\uFF0C\u5148\u8BA9\u7FA4\u91CC\u4EFB\u4E00\u673A\u5668\u4EBA\u624B\u52A8\u628A\u4F60\u52A0\u8FDB\u53BB\u3002</p>';let Z=[$.length?`<li>\u65E0\u6548 bot id: <code>${$.map(r).join(", ")}</code></li>`:"",d.length?`<li>\u65E0\u6548\u7528\u6237 open_id: <code>${d.map(r).join(", ")}</code></li>`:""].filter(Boolean).join("");i.innerHTML=`
|
|
328
328
|
<article>
|
|
329
329
|
<header><h3>${o("groups.successTitle")}</h3></header>
|
|
330
330
|
<p><b>chatId:</b> <code>${r(E)}</code> <button type="button" data-copy="${r(E)}">${o("sessions.copy")}</button></p>
|
|
@@ -333,36 +333,41 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
333
333
|
${ee}
|
|
334
334
|
${Z?`<ul>${Z}</ul>`:""}
|
|
335
335
|
<div class="actions">
|
|
336
|
-
<a class="btn-link primary" href="${
|
|
336
|
+
<a class="btn-link primary" href="${q}" target="_blank" rel="noopener">${o("groups.openGroup")}</a>
|
|
337
337
|
<button type="button" id="g-create-close">${o("sessions.dismiss")}</button>
|
|
338
338
|
</div>
|
|
339
339
|
</article>`,i.querySelectorAll("[data-copy]").forEach(J=>{J.onclick=()=>{navigator.clipboard.writeText(J.dataset.copy??""),J.textContent=o("sessions.copied"),setTimeout(()=>{J.textContent=o("sessions.copy")},800)}}),i.querySelector("#g-create-close").onclick=()=>i.close()}function y(){t.innerHTML=`<tr>
|
|
340
340
|
<th>${o("groups.chat")}</th>
|
|
341
341
|
${oe.bots.map(u=>`<th>${r(u.botName??u.larkAppId)}</th>`).join("")}
|
|
342
342
|
<th>${o("groups.actions")}</th>
|
|
343
|
-
</tr>`}function h(){y();let u=new FormData(s),E=(u.get("q")??"").toLowerCase(),
|
|
343
|
+
</tr>`}function h(){y();let u=new FormData(s),E=(u.get("q")??"").toLowerCase(),q=!!u.get("missing"),$=oe.chats.filter(d=>!E||(d.name??"").toLowerCase().includes(E)||d.chatId.toLowerCase().includes(E)||(d.ownerId??"").toLowerCase().includes(E)).filter(d=>!q||d.memberBots.some(f=>!f.inChat));if($.length===0){n.innerHTML=`<tr><td colspan="${oe.bots.length+2}" class="empty">${o("groups.empty")}</td></tr>`;return}n.innerHTML=$.map(d=>`<tr data-chat="${r(d.chatId)}">
|
|
344
344
|
<td>
|
|
345
|
-
<
|
|
346
|
-
|
|
345
|
+
<div class="g-chat-cell">
|
|
346
|
+
${xn({chatId:d.chatId,name:d.name,avatarUrl:d.avatar,size:"sm"})}
|
|
347
|
+
<div class="g-chat-meta">
|
|
348
|
+
<strong>${r(d.name??d.chatId)}</strong><br>
|
|
349
|
+
<small><code>${r(d.chatId)}</code></small>
|
|
350
|
+
</div>
|
|
351
|
+
</div>
|
|
347
352
|
</td>
|
|
348
|
-
${oe.bots.map(f=>{let w=d.memberBots.find(M=>M.larkAppId===f.larkAppId),
|
|
353
|
+
${oe.bots.map(f=>{let w=d.memberBots.find(M=>M.larkAppId===f.larkAppId),I=w?w.error?"!":w.inChat?"\u2713":"\u2717":"?";return`<td class="${w?w.error?"cell-error":w.inChat?"cell-in":"cell-out":"cell-unknown"}" title="${r(w?.error??"")}">${I}</td>`}).join("")}
|
|
349
354
|
<td>
|
|
350
355
|
<button class="add-bots" type="button">${o("groups.addBots")}</button>
|
|
351
356
|
<button class="manage-chat" type="button">${o("groups.manage")}</button>
|
|
352
357
|
</td>
|
|
353
|
-
</tr>`).join("")}h(),n.addEventListener("click",async u=>{let E=u.target.closest("button.add-bots");if(!E)return;let $=E.closest("tr[data-chat]").dataset.chat,d=oe.chats.find(
|
|
358
|
+
</tr>`).join("")}h(),n.addEventListener("click",async u=>{let E=u.target.closest("button.add-bots");if(!E)return;let $=E.closest("tr[data-chat]").dataset.chat,d=oe.chats.find(I=>I.chatId===$);if(!d)return;let f=new Set(d.memberBots.filter(I=>I.inChat).map(I=>I.larkAppId));if(!oe.bots.filter(I=>!f.has(I.larkAppId)).length){alert("All configured bots are already in this chat.");return}i.innerHTML=`
|
|
354
359
|
<article>
|
|
355
360
|
<header><h3>${o("groups.addBots")} \xB7 ${r(d.name??d.chatId)}</h3></header>
|
|
356
361
|
<p>${o("groups.createHelp")}</p>
|
|
357
362
|
<form id="g-addform">
|
|
358
|
-
${
|
|
363
|
+
${Un(oe.bots,f)}
|
|
359
364
|
<div class="actions">
|
|
360
365
|
<button type="submit" class="primary">${o("groups.addBots")}</button>
|
|
361
366
|
<button type="button" id="g-cancel">${o("groups.cancel")}</button>
|
|
362
367
|
</div>
|
|
363
368
|
</form>
|
|
364
|
-
</article>`,i.showModal(),i.querySelector("#g-cancel").onclick=()=>i.close(),i.querySelector("#g-addform").onsubmit=async
|
|
365
|
-
`);alert(z),await Ue(),h()}else alert(`Unexpected response: ${JSON.stringify(O)}`)}catch(H){alert("Network error: "+H)}finally{i.close()}}}),n.addEventListener("click",async u=>{let E=u.target.closest("button.manage-chat");if(!E)return;let $=E.closest("tr[data-chat]").dataset.chat,d=oe.chats.find(f=>f.chatId===$);d&&k(d)});function k(u){let E=u.memberBots.filter($=>$.inChat),
|
|
369
|
+
</article>`,i.showModal(),i.querySelector("#g-cancel").onclick=()=>i.close(),i.querySelector("#g-addform").onsubmit=async I=>{I.preventDefault();let M=new FormData(I.target).getAll("bot");if(M.length===0){alert("Pick at least one bot.");return}try{let O=await(await fetch(`/api/groups/${encodeURIComponent($)}/add-bots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:M})})).json();if(O.error==="no_proxy_bot")alert("No bot is currently in this chat \u2014 add one manually in Feishu first, then retry.");else if(O.result){let z=O.result.map(j=>`${j.id}: ${j.ok?"OK":`failed (${j.error??"unknown"})`}`).join(`
|
|
370
|
+
`);alert(z),await Ue(),h()}else alert(`Unexpected response: ${JSON.stringify(O)}`)}catch(H){alert("Network error: "+H)}finally{i.close()}}}),n.addEventListener("click",async u=>{let E=u.target.closest("button.manage-chat");if(!E)return;let $=E.closest("tr[data-chat]").dataset.chat,d=oe.chats.find(f=>f.chatId===$);d&&k(d)});function k(u){let E=u.memberBots.filter($=>$.inChat),q=typeof u.ownerId=="string"?u.ownerId:"";i.innerHTML=`
|
|
366
371
|
<article>
|
|
367
372
|
<header><h3>${o("groups.manageTitle",{name:u.name??u.chatId})}</h3></header>
|
|
368
373
|
<p><b>chatId:</b> <code>${r(u.chatId)}</code></p>
|
|
@@ -394,7 +399,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
394
399
|
<label class="checkbox-row">
|
|
395
400
|
<input type="checkbox" name="leave-bot" value="${r($.larkAppId)}">
|
|
396
401
|
${r($.botName??$.larkAppId)}
|
|
397
|
-
<small>${$.larkAppId===
|
|
402
|
+
<small>${$.larkAppId===q?"\xB7 \u7FA4\u4E3B":""}</small>
|
|
398
403
|
</label>
|
|
399
404
|
`).join("")}
|
|
400
405
|
</fieldset>
|
|
@@ -405,14 +410,14 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
405
410
|
</div>
|
|
406
411
|
<p class="hint-warn"><small>${o("groups.dangerHint")}</small></p>
|
|
407
412
|
<form method="dialog"><button>${o("sessions.dismiss")}</button></form>
|
|
408
|
-
</article>`,i.showModal(),i.querySelectorAll(".oncall-row").forEach($=>{let d=$.dataset.bot,f=$.querySelector("input[data-action=toggle]"),w=$.querySelector("input[data-input=workingDir]"),
|
|
409
|
-
`);alert(w||`Unexpected: ${JSON.stringify(f)}`),await Ue(),h()}catch(d){alert("Network error: "+d)}finally{i.close()}},i.querySelector("#g-disband-btn").onclick=async()=>{if(E.length===0||!confirm(`\u786E\u5B9A\u89E3\u6563\u7FA4\u804A\u300C${u.name??u.chatId}\u300D\uFF1F\u6B64\u64CD\u4F5C\u4E0D\u53EF\u6062\u590D\uFF0C\u672C\u7FA4\u6240\u6709\u673A\u5668\u4EBA\u4F1A\u8BDD\u4E5F\u4F1A\u4E00\u5E76\u5173\u95ED\u3002`))return;let $=[...E].sort((f,w)=>(w.larkAppId===
|
|
413
|
+
</article>`,i.showModal(),i.querySelectorAll(".oncall-row").forEach($=>{let d=$.dataset.bot,f=$.querySelector("input[data-action=toggle]"),w=$.querySelector("input[data-input=workingDir]"),I=$.querySelector("button[data-action=save]"),x=$.querySelector("[data-status]");f.addEventListener("change",()=>{w.disabled=!f.checked,f.checked&&w.focus()}),I.addEventListener("click",async()=>{x.textContent="",x.className="oncall-status";let M=f.checked,H=w.value.trim();if(M&&!H){x.textContent=o("groups.needWorkingDir"),x.classList.add("hint-warn-inline");return}I.disabled=!0;try{let O=`/api/groups/${encodeURIComponent(u.chatId)}/oncall/${encodeURIComponent(d)}`,z=M?await fetch(O,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({workingDir:H})}):await fetch(O,{method:"DELETE"}),j=await z.json().catch(()=>({}));if(z.ok&&j.ok){x.textContent=M?`\u2713 \u5DF2\u7ED1\u5B9A \u2192 ${j.resolvedPath??H}`:"\u2713 \u5DF2\u89E3\u7ED1",x.classList.add("hint-ok");try{await Ue(),h()}catch{}}else x.textContent=`\u2717 ${j.error??z.status}`,x.classList.add("hint-warn-inline")}catch(O){x.textContent=`\u2717 ${O?.message??O}`,x.classList.add("hint-warn-inline")}finally{I.disabled=!1}})}),i.querySelector("#g-leave-btn").onclick=async()=>{let $=[...i.querySelectorAll("input[name=leave-bot]:checked")].map(d=>d.value);if($.length===0){alert("\u81F3\u5C11\u9009\u4E00\u4E2A\u673A\u5668\u4EBA");return}if(confirm(`\u786E\u5B9A\u8BA9 ${$.length} \u4E2A\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A\uFF1F\u8BE5 bot \u5728\u6B64\u7FA4\u7684\u4F1A\u8BDD\u4F1A\u4E00\u5E76\u5173\u95ED\u3002`))try{let f=await(await fetch(`/api/groups/${encodeURIComponent(u.chatId)}/leave`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:$})})).json(),w=(f.result??[]).map(I=>{if(!I.ok)return`${I.larkAppId}: \u5931\u8D25 (${I.error??"unknown"})`;let x=I.closedSessions??[],M=x.filter(z=>!z.ok).length,H=x.length-M,O=x.length===0?"":M===0?`\uFF08\u5173\u95ED ${H} \u4E2A\u4F1A\u8BDD\uFF09`:`\uFF08\u5173\u95ED ${H} \u4E2A\uFF0C${M} \u4E2A\u5931\u8D25\uFF09`;return`${I.larkAppId}: OK${O}`}).join(`
|
|
414
|
+
`);alert(w||`Unexpected: ${JSON.stringify(f)}`),await Ue(),h()}catch(d){alert("Network error: "+d)}finally{i.close()}},i.querySelector("#g-disband-btn").onclick=async()=>{if(E.length===0||!confirm(`\u786E\u5B9A\u89E3\u6563\u7FA4\u804A\u300C${u.name??u.chatId}\u300D\uFF1F\u6B64\u64CD\u4F5C\u4E0D\u53EF\u6062\u590D\uFF0C\u672C\u7FA4\u6240\u6709\u673A\u5668\u4EBA\u4F1A\u8BDD\u4E5F\u4F1A\u4E00\u5E76\u5173\u95ED\u3002`))return;let $=[...E].sort((f,w)=>(w.larkAppId===q?1:0)-(f.larkAppId===q?1:0)),d=[];for(let f of $)try{let w=await fetch(`/api/groups/${encodeURIComponent(u.chatId)}/disband`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppId:f.larkAppId})}),I=await w.json();if(I.ok){let x=I.closedSessions??[],M=x.filter(z=>!z.ok).length,H=x.length-M,O=x.length===0?"":M===0?`
|
|
410
415
|
\u5173\u95ED\u4E86 ${H} \u4E2A\u4F1A\u8BDD\u3002`:`
|
|
411
|
-
\u5173\u95ED\u4E86 ${H} \u4E2A\u4F1A\u8BDD\uFF0C${M} \u4E2A\u4F1A\u8BDD\u5173\u95ED\u5931\u8D25\u3002`;alert(`\u5DF2\u89E3\u6563\uFF08\u7531 ${f.botName??f.larkAppId} \u6267\u884C\uFF09${O}`),await Ue(),h(),i.close();return}d.push(`${f.botName??f.larkAppId}: ${
|
|
416
|
+
\u5173\u95ED\u4E86 ${H} \u4E2A\u4F1A\u8BDD\uFF0C${M} \u4E2A\u4F1A\u8BDD\u5173\u95ED\u5931\u8D25\u3002`;alert(`\u5DF2\u89E3\u6563\uFF08\u7531 ${f.botName??f.larkAppId} \u6267\u884C\uFF09${O}`),await Ue(),h(),i.close();return}d.push(`${f.botName??f.larkAppId}: ${I.error??w.status}`)}catch(w){d.push(`${f.botName??f.larkAppId}: ${w}`)}alert(`\u6240\u6709\u5728\u7FA4\u673A\u5668\u4EBA\u5747\u65E0\u6CD5\u89E3\u6563\uFF1A
|
|
412
417
|
${d.join(`
|
|
413
418
|
`)}
|
|
414
419
|
|
|
415
|
-
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",h)}var
|
|
420
|
+
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",h)}var be={bots:[]},ze=null,je=null;function zn(e){let t=null;for(let n of G.sessions.values())n.larkAppId!==e||!n.cliId||(!t||Number(n.lastMessageAt??0)>Number(t.lastMessageAt??0))&&(t=n);return t?.cliId??""}function $a(){return`<section class="page">
|
|
416
421
|
<div class="page-heading">
|
|
417
422
|
<div>
|
|
418
423
|
<p class="eyebrow">${o("nav.botDefaults")}</p>
|
|
@@ -428,31 +433,31 @@ ${d.join(`
|
|
|
428
433
|
<aside id="bd-roster" class="bd-roster"></aside>
|
|
429
434
|
<div id="bd-list" class="bd-detail"></div>
|
|
430
435
|
</div>
|
|
431
|
-
</section>`}async function
|
|
432
|
-
|
|
436
|
+
</section>`}async function _n(){try{let e=await fetch("/api/bots"),t=await e.json().catch(()=>({}));if(!e.ok){ze=t?.error?`HTTP ${e.status}: ${t.error}${t.path?` (${t.path})`:""}`:`HTTP ${e.status}`,be={bots:[]};return}if(!t||!Array.isArray(t.bots)){ze="unexpected response shape (no `bots` array)",be={bots:[]};return}ze=null,be=t}catch(e){ze=e?.message??String(e),be={bots:[]}}}function Fn(e){if(!e)return"\u2014";let t=new Date(e);return Number.isNaN(t.getTime())?"\u2014":t.toLocaleString()}async function Wn(e){e.innerHTML=$a();let t=e.querySelector("#bd-list"),n=e.querySelector("#bd-roster"),s=e.querySelector("#bd-filters"),a=e.querySelector("#bd-refresh");a.onclick=async()=>{a.disabled=!0;try{await _n(),i()}finally{a.disabled=!1}},t.addEventListener("click",d=>{let f=d.target.closest(".toggle-tx small, small.bd-help");f&&(d.preventDefault(),f.classList.toggle("open"))}),await _n();function i(){let f=(new FormData(s).get("q")??"").toLowerCase(),w=be.bots.filter(x=>!f||(x.botName??"").toLowerCase().includes(f)||(x.larkAppId??"").toLowerCase().includes(f));if(ze){n.innerHTML="",t.innerHTML=`<p class="hint-warn">\u65E0\u6CD5\u52A0\u8F7D bot \u5217\u8868\uFF1A${r(ze)}<br>\u5E38\u89C1\u539F\u56E0\uFF1Adashboard / daemon \u8FDB\u7A0B\u8FD8\u5728\u8DD1\u65E7\u4EE3\u7801\uFF0C\u6267\u884C <code>botmux restart</code> \u540E\u5237\u65B0\u3002</p>`;return}if(w.length===0){n.innerHTML="",t.innerHTML=`<p class="empty">${o("botDefaults.empty")}</p>`;return}(!je||!w.some(x=>x.larkAppId===je))&&(je=w[0].larkAppId),n.innerHTML=w.map(l).join(""),n.querySelectorAll(".bd-roster-item").forEach(x=>{x.onclick=()=>{je=x.dataset.appid,i()}});let I=w.find(x=>x.larkAppId===je);t.innerHTML=p(I),$()}function l(d){let f=d.botName??d.larkAppId,w=zn(d.larkAppId),I=d.defaultOncall?.enabled?'<span class="bd-roster-flag">oncall</span>':"";return`<div class="bd-roster-item${d.larkAppId===je?" on":""}" data-appid="${r(d.larkAppId)}" role="button" tabindex="0">
|
|
437
|
+
${de({name:f,larkAppId:d.larkAppId,size:"sm"})}
|
|
433
438
|
<div class="bd-roster-tx">
|
|
434
439
|
<b>${r(f)}</b>
|
|
435
440
|
<span>${r(w||d.larkAppId.slice(0,14))}</span>
|
|
436
441
|
</div>
|
|
437
|
-
${
|
|
442
|
+
${I}
|
|
438
443
|
</div>`}function p(d){if(d.error)return`<article class="bd-card bd-profile" data-appid="${r(d.larkAppId)}">
|
|
439
444
|
<header class="bd-profile-head">
|
|
440
|
-
|
|
445
|
+
${de({name:d.botName??d.larkAppId,larkAppId:d.larkAppId})}
|
|
441
446
|
<div class="bd-profile-id"><strong>${r(d.botName??d.larkAppId)}</strong>
|
|
442
447
|
<code>${r(d.larkAppId)}</code></div>
|
|
443
448
|
</header>
|
|
444
449
|
<p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${r(d.error)}</p>
|
|
445
|
-
</article>`;let f=d.defaultOncall??{enabled:!1,workingDir:"",since:0},w=!!f.enabled,
|
|
450
|
+
</article>`;let f=d.defaultOncall??{enabled:!1,workingDir:"",since:0},w=!!f.enabled,I=d.botName??d.larkAppId,x=zn(d.larkAppId);return`<article class="bd-card bd-profile" data-appid="${r(d.larkAppId)}">
|
|
446
451
|
<header class="bd-profile-head">
|
|
447
|
-
|
|
452
|
+
${de({name:I,larkAppId:d.larkAppId,dot:"ok"})}
|
|
448
453
|
<div class="bd-profile-id">
|
|
449
|
-
<strong>${r(
|
|
454
|
+
<strong>${r(I)}</strong>
|
|
450
455
|
${x?`<span class="mate-role">${r(x)}</span>`:""}
|
|
451
456
|
<code>${r(d.larkAppId)}</code>
|
|
452
457
|
</div>
|
|
453
458
|
<div class="bd-profile-meta bd-meta">
|
|
454
459
|
<small class="bd-meta-ok">\u25CF ${o("botDefaults.metaOnline")}</small>
|
|
455
|
-
<small data-oncall-since>${o("botDefaults.lastEnabled")}: ${r(
|
|
460
|
+
<small data-oncall-since>${o("botDefaults.lastEnabled")}: ${r(Fn(f.since??0))}</small>
|
|
456
461
|
<small>${o("botDefaults.autobound",{count:d.autoboundChatCount??0})}</small>
|
|
457
462
|
</div>
|
|
458
463
|
</header>
|
|
@@ -477,7 +482,7 @@ ${d.join(`
|
|
|
477
482
|
<button type="button" class="primary" data-action="save">${o("botDefaults.save")}</button>
|
|
478
483
|
<span class="oncall-status" data-status></span>
|
|
479
484
|
</div>
|
|
480
|
-
${
|
|
485
|
+
${q(d)}
|
|
481
486
|
</section>
|
|
482
487
|
</section>
|
|
483
488
|
<section class="bd-tile">${v(d)}</section>
|
|
@@ -512,7 +517,7 @@ ${d.join(`
|
|
|
512
517
|
<span class="oncall-status" data-brand-status></span>
|
|
513
518
|
</div>
|
|
514
519
|
</div>
|
|
515
|
-
</section>`}function k(d){let f=d.disableStreamingCard===!0,w=d.writableTerminalLinkInCard===!0,
|
|
520
|
+
</section>`}function k(d){let f=d.disableStreamingCard===!0,w=d.writableTerminalLinkInCard===!0,I=d.privateCard===!0;return`<section class="bd-section">
|
|
516
521
|
<h3 class="bd-section-title">${o("botDefaults.sectionCard")}</h3>
|
|
517
522
|
<label class="toggle-row">
|
|
518
523
|
<input type="checkbox" data-action="toggle-disable-streaming" ${f?"checked":""}>
|
|
@@ -527,7 +532,7 @@ ${d.join(`
|
|
|
527
532
|
<small>${o("botDefaults.writableLinkHelp")}</small></span>
|
|
528
533
|
</label>
|
|
529
534
|
<label class="toggle-row">
|
|
530
|
-
<input type="checkbox" data-action="toggle-private-card" ${
|
|
535
|
+
<input type="checkbox" data-action="toggle-private-card" ${I?"checked":""}>
|
|
531
536
|
<span class="switch" aria-hidden="true"></span>
|
|
532
537
|
<span class="toggle-tx"><strong>${o("botDefaults.privateCard")}</strong>
|
|
533
538
|
<small>${o("botDefaults.privateCardHelp")}</small></span>
|
|
@@ -559,7 +564,7 @@ ${d.join(`
|
|
|
559
564
|
<span class="oncall-status" data-grant-status></span>
|
|
560
565
|
</div>
|
|
561
566
|
</div>
|
|
562
|
-
</section>`}function
|
|
567
|
+
</section>`}function q(d){let f=d.autoStartOnGroupJoin===!0,w=d.autoStartOnNewTopic===!0,I=typeof d.autoStartOnGroupJoinPrompt=="string"?d.autoStartOnGroupJoinPrompt:"";return`<div class="bd-subsection">
|
|
563
568
|
<h4 class="bd-subsection-title">${o("botDefaults.sectionAutoStart")}</h4>
|
|
564
569
|
<label class="toggle-row">
|
|
565
570
|
<input type="checkbox" data-action="toggle-auto-join" ${f?"checked":""}>
|
|
@@ -571,7 +576,7 @@ ${d.join(`
|
|
|
571
576
|
<label>
|
|
572
577
|
<span>${o("botDefaults.autoStartJoinPrompt")}</span>
|
|
573
578
|
<textarea data-input="autoJoinPrompt" rows="3"
|
|
574
|
-
placeholder="${r(o("botDefaults.autoStartJoinPromptPlaceholder"))}">${r(
|
|
579
|
+
placeholder="${r(o("botDefaults.autoStartJoinPromptPlaceholder"))}">${r(I)}</textarea>
|
|
575
580
|
</label>
|
|
576
581
|
<div class="actions">
|
|
577
582
|
<button type="button" class="primary" data-action="save-auto-join-prompt">${o("botDefaults.autoStartJoinPromptSave")}</button>
|
|
@@ -586,7 +591,7 @@ ${d.join(`
|
|
|
586
591
|
<div class="actions">
|
|
587
592
|
<span class="oncall-status" data-auto-start-status></span>
|
|
588
593
|
</div>
|
|
589
|
-
</div>`}function $(){t.querySelectorAll(".bd-card").forEach(d=>{let f=d.dataset.appid,w=d.querySelector("input[data-action=toggle]"),
|
|
594
|
+
</div>`}function $(){t.querySelectorAll(".bd-card").forEach(d=>{let f=d.dataset.appid,w=d.querySelector("input[data-action=toggle]"),I=d.querySelector("input[data-input=workingDir]"),x=d.querySelector("button[data-action=save]"),M=d.querySelector("[data-status]");if(!w||!I||!x||!M)return;w.addEventListener("change",()=>{I.disabled=!w.checked,w.checked&&I.focus()}),x.addEventListener("click",async()=>{M.textContent="",M.className="oncall-status";let K=w.checked,U=I.value.trim();if(K&&!U){M.textContent=o("botDefaults.required"),M.classList.add("hint-warn-inline");return}x.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(f)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:K,workingDir:U})}),_=await N.json().catch(()=>({}));if(N.ok&&_.ok){let b=_.resolvedPath?` \u2192 ${_.resolvedPath}`:"";M.textContent=K?`\u2713 \u5DF2\u5F00\u542F${b}\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",M.classList.add("hint-ok");let R=be.bots.find(C=>C.larkAppId===f);R&&_.defaultOncall&&(R.defaultOncall=_.defaultOncall);let D=d.querySelector("[data-oncall-since]");D&&_.defaultOncall?.since!=null&&(D.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${Fn(_.defaultOncall.since)}`)}else M.textContent=`\u2717 ${_.error??N.status}`,M.classList.add("hint-warn-inline")}catch(N){M.textContent=`\u2717 ${N?.message??N}`,M.classList.add("hint-warn-inline")}finally{x.disabled=!1}});let H=d.querySelector("input[data-input=brandLabel]"),O=d.querySelector("button[data-action=save-brand]"),z=d.querySelector("button[data-action=reset-brand]"),j=d.querySelector("[data-brand-status]"),ee=d.querySelector("[data-brand-state]");async function ae(K,U){if(j){j.textContent="",j.className="oncall-status",U.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(f)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:K})}),_=await N.json().catch(()=>({}));if(N.ok&&_.ok){let b=_.brandLabel??null;j.textContent="\u2713",j.classList.add("hint-ok"),H&&(H.value=b??""),ee&&(ee.textContent=y(b));let R=be.bots.find(D=>D.larkAppId===f);R&&(R.brandLabel=b)}else j.textContent=`\u2717 ${_.error??N.status}`,j.classList.add("hint-warn-inline")}catch(N){j.textContent=`\u2717 ${N?.message??N}`,j.classList.add("hint-warn-inline")}finally{U.disabled=!1}}}H&&O&&O.addEventListener("click",()=>ae(H.value,O)),z&&z.addEventListener("click",()=>ae(null,z));let Z=d.querySelector("input[data-action=toggle-disable-streaming]"),J=d.querySelector("input[data-action=toggle-writable-link]"),se=d.querySelector("input[data-action=toggle-private-card]"),He=d.querySelector("[data-card-pref-status]"),ve=d.querySelector("[data-card-pref-moot]");async function ie(K,U,N=He){if(N){N.textContent="",N.className="oncall-status",U.disabled=!0;try{let _=await fetch(`/api/bots/${encodeURIComponent(f)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(K)}),b=await _.json().catch(()=>({}));if(_.ok&&b.ok){N.textContent=`\u2713 ${o("botDefaults.cardPrefSaved")}`,N.classList.add("hint-ok");let R=be.bots.find(D=>D.larkAppId===f);R&&(R.disableStreamingCard=b.disableStreamingCard,R.writableTerminalLinkInCard=b.writableTerminalLinkInCard,R.privateCard=b.privateCard,R.autoStartOnGroupJoin=b.autoStartOnGroupJoin,R.autoStartOnGroupJoinPrompt=b.autoStartOnGroupJoinPrompt,R.autoStartOnNewTopic=b.autoStartOnNewTopic)}else N.textContent=`\u2717 ${b.error??_.status}`,N.classList.add("hint-warn-inline")}catch(_){N.textContent=`\u2717 ${_?.message??_}`,N.classList.add("hint-warn-inline")}finally{U===J?U.disabled=!!Z?.checked:U.disabled=!1}}}Z&&Z.addEventListener("change",()=>{let K=Z.checked;J&&(J.disabled=K),ve&&(ve.hidden=!K),ie({disableStreamingCard:K},Z)}),J&&J.addEventListener("change",()=>{ie({writableTerminalLinkInCard:J.checked},J)}),se&&se.addEventListener("change",()=>{ie({privateCard:se.checked},se)});let re=d.querySelector("input[data-action=toggle-auto-join]"),te=d.querySelector("input[data-action=toggle-auto-topic]"),pe=d.querySelector("textarea[data-input=autoJoinPrompt]"),Q=d.querySelector("button[data-action=save-auto-join-prompt]"),ke=d.querySelector("[data-auto-start-status]");re&&re.addEventListener("change",()=>{ie({autoStartOnGroupJoin:re.checked},re,ke)}),te&&te.addEventListener("change",()=>{ie({autoStartOnNewTopic:te.checked},te,ke)}),pe&&Q&&Q.addEventListener("click",()=>{ie({autoStartOnGroupJoinPrompt:pe.value},Q,ke)});let $e=d.querySelector("textarea[data-input=teamRole]"),V=d.querySelector("button[data-action=save-role]"),c=d.querySelector("button[data-action=delete-role]"),g=d.querySelector("[data-role-status]");if($e&&V&&c&&g){let N=function(b){let R=t.querySelector(`.bd-card[data-appid="${CSS.escape(f)}"]`);if(!R)return;let D=R.querySelector("textarea[data-input=teamRole]"),C=R.querySelector("button[data-action=save-role]"),ne=R.querySelector("button[data-action=delete-role]");D&&(D.value=b,D.disabled=!1),C&&(C.disabled=!1),ne&&(ne.disabled=!1)};var rn=N;let K=`/api/team/local-bots/${encodeURIComponent(f)}/role`,U=be.bots.find(b=>b.larkAppId===f);U&&typeof U.teamRole!="string"&&!U.teamRoleLoading&&(U.teamRoleLoading=!0,(async()=>{try{let b=await fetch(K),R=await b.json().catch(()=>({}));b.ok&&R.ok?(U.teamRole=R.role??"",N(U.teamRole)):(g.textContent=`\u2717 ${o("botDefaults.roleLoadErr")}: ${R.error??b.status}`,g.classList.add("hint-warn-inline"))}catch(b){g.textContent=`\u2717 ${o("botDefaults.roleLoadErr")}: ${b?.message??b}`,g.classList.add("hint-warn-inline")}finally{U.teamRoleLoading=!1}})());async function _(b,R,D){if(g&&!(!U||typeof U.teamRole!="string")){g.textContent="",g.className="oncall-status",V.disabled=!0,c.disabled=!0;try{let C=await fetch(K,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({role:b})}),ne=await C.json().catch(()=>({}));C.ok&&ne.ok?(U&&(U.teamRole=b.trim()),g.textContent=`\u2713 ${D?o("botDefaults.roleDeleted"):o("botDefaults.roleSaved")}`,g.classList.add("hint-ok")):(g.textContent=`\u2717 ${ne.error??C.status}`,g.classList.add("hint-warn-inline"))}catch(C){g.textContent=`\u2717 ${C?.message??C}`,g.classList.add("hint-warn-inline")}finally{V.disabled=!1,c.disabled=!1}}}V.addEventListener("click",()=>_($e.value,V,!1)),c.addEventListener("click",()=>{$e.value="",_("",c,!0)})}let S=d.querySelector("input[data-action=toggle-restrict-grant]"),L=d.querySelector("input[data-input=quotaLimit]"),T=d.querySelector("button[data-action=save-quota]"),P=d.querySelector("button[data-action=off-quota]"),B=d.querySelector("[data-grant-status]"),X=d.querySelector("[data-quota-state]");async function Y(K,U){if(B){B.textContent="",B.className="oncall-status",U.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(f)}/grant-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(K)}),_=await N.json().catch(()=>({}));if(N.ok&&_.ok){B.textContent=`\u2713 ${o("botDefaults.cardPrefSaved")}`,B.classList.add("hint-ok");let b=typeof _.messageQuotaDefaultLimit=="number"?_.messageQuotaDefaultLimit:null,R=be.bots.find(D=>D.larkAppId===f);R&&(R.restrictGrantCommands=_.restrictGrantCommands===!0,R.messageQuotaDefaultLimit=b),X&&(X.textContent=u(b)),L&&"messageQuotaDefaultLimit"in K&&(L.value=b==null?"":String(b))}else B.textContent=`\u2717 ${_.error??N.status}`,B.classList.add("hint-warn-inline")}catch(N){B.textContent=`\u2717 ${N?.message??N}`,B.classList.add("hint-warn-inline")}finally{U.disabled=!1}}}S&&S.addEventListener("change",()=>{Y({restrictGrantCommands:S.checked},S)}),L&&T&&T.addEventListener("click",()=>{let K=L.value.trim();if(K===""){Y({messageQuotaDefaultLimit:null},T);return}if(!/^[1-9]\d*$/.test(K)){B&&(B.textContent=`\u2717 ${o("botDefaults.quotaInvalid")}`,B.className="oncall-status hint-warn-inline");return}Y({messageQuotaDefaultLimit:Number(K)},T)}),L&&P&&P.addEventListener("click",()=>{L.value="",Y({messageQuotaDefaultLimit:null},P)})})}i(),fe().then(i),s.addEventListener("input",i)}var qt=4096,ct=[],he=null,we=null,ce="",_e=new Set;function Sa(){return`<section class="page roles-page">
|
|
590
595
|
<div class="page-heading">
|
|
591
596
|
<div>
|
|
592
597
|
<p class="eyebrow">${o("nav.roles")}</p>
|
|
@@ -625,12 +630,12 @@ ${d.join(`
|
|
|
625
630
|
</div>
|
|
626
631
|
</div>
|
|
627
632
|
</div>
|
|
628
|
-
</section>`}async function
|
|
629
|
-
<div class="roles-bot-row ${
|
|
633
|
+
</section>`}async function dt(){ct=((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 Jn(e,t){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)).json()}async function Ia(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 Ta(e,t){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{method:"DELETE"})).ok}function Kn(e){return e.memberBots.filter(t=>t.inChat&&t.hasRole).length}function La(e){return e.memberBots.filter(t=>t.inChat).length}function Ae(e=""){let t=document.getElementById("roles-tree");if(!t)return;let n=e.toLowerCase(),s=ct.filter(a=>{if(!n)return!0;let i=a.chatId.toLowerCase().includes(n)||(a.name??"").toLowerCase().includes(n),l=a.memberBots.some(p=>p.larkAppId.toLowerCase().includes(n)||(p.botName??"").toLowerCase().includes(n));return i||l});if(s.length===0){t.innerHTML=`<div class="roles-empty">${o("roles.noChats")}</div>`;return}t.innerHTML=s.map(a=>{let i=_e.has(a.chatId),l=a.memberBots.filter(k=>k.inChat),p=i?"\u25BE":"\u25B8",v=Kn(a),y=La(a),h=i?l.map(k=>`
|
|
634
|
+
<div class="roles-bot-row ${he===a.chatId&&we===k.larkAppId?"selected":""}"
|
|
630
635
|
data-group-id="${r(a.chatId)}"
|
|
631
636
|
data-bot-id="${r(k.larkAppId)}">
|
|
632
637
|
<span class="roles-bot-indent"></span>
|
|
633
|
-
|
|
638
|
+
${de({name:k.botName,larkAppId:k.larkAppId,size:"sm"})}
|
|
634
639
|
<div class="roles-bot-info">
|
|
635
640
|
<div class="roles-bot-name">${r(k.botName)}</div>
|
|
636
641
|
<div class="roles-bot-id">${r(k.larkAppId)}</div>
|
|
@@ -640,7 +645,7 @@ ${d.join(`
|
|
|
640
645
|
</span>
|
|
641
646
|
</div>`).join(""):"";return`
|
|
642
647
|
<div class="roles-group-section">
|
|
643
|
-
<div class="roles-group-row ${i?"expanded":""} ${
|
|
648
|
+
<div class="roles-group-row ${i?"expanded":""} ${he===a.chatId&&!we?"selected":""}"
|
|
644
649
|
data-group-id="${r(a.chatId)}">
|
|
645
650
|
<span class="roles-group-arrow">${p}</span>
|
|
646
651
|
<span class="roles-group-icon" aria-hidden="true"><svg viewBox="0 0 16 16"><circle cx="5.6" cy="5.8" r="2.4"/><path d="M1.8 13.2c.5-2.4 2-3.6 3.8-3.6s3.3 1.2 3.8 3.6"/><circle cx="11" cy="6.8" r="1.9"/><path d="M9.8 12.6c.4-1.7 1.5-2.6 2.8-2.6 1 0 1.9.5 2.4 1.6"/></svg></span>
|
|
@@ -653,12 +658,12 @@ ${d.join(`
|
|
|
653
658
|
<span class="roles-group-chevron"></span>
|
|
654
659
|
</div>
|
|
655
660
|
<div class="roles-bot-list">${h}</div>
|
|
656
|
-
</div>`}).join(""),t.querySelectorAll(".roles-group-row").forEach(a=>{a.addEventListener("click",()=>{let i=a.dataset.groupId;i&&(_e.has(i)?_e.delete(i):_e.add(i),
|
|
661
|
+
</div>`}).join(""),t.querySelectorAll(".roles-group-row").forEach(a=>{a.addEventListener("click",()=>{let i=a.dataset.groupId;i&&(_e.has(i)?_e.delete(i):_e.add(i),Ae(document.getElementById("roles-search")?.value??""))})}),t.querySelectorAll(".roles-bot-row").forEach(a=>{a.addEventListener("click",i=>{i.stopPropagation();let l=a.dataset.groupId,p=a.dataset.botId;l&&p&&Ea(l,p)})})}async function Ea(e,t){he=e,we=t;let n=await Jn(t,e),s=document.getElementById("roles-editor-empty"),a=document.getElementById("roles-editor-form"),i=document.getElementById("roles-editor-textarea"),l=document.getElementById("roles-editor-group-name"),p=document.getElementById("roles-editor-bot-name"),v=document.getElementById("roles-editor-chat-id");s&&(s.style.display="none"),a&&(a.style.display="");let y=ct.find(u=>u.chatId===e),h=y?.memberBots.find(u=>u.larkAppId===t);l&&(l.textContent=y?.name??e),p&&(p.textContent=h?.botName??t),v&&(v.textContent=`${e} \xB7 ${t}`),ce=n.content??"",i&&(i.value=ce,i.focus()),Pt(),Nt(),Ae(document.getElementById("roles-search")?.value??"");let k=document.getElementById("roles-delete");k&&(k.style.display=n.hasRole?"":"none")}function Pt(){let e=document.getElementById("roles-editor-bytecount");if(!e)return;let t=new TextEncoder().encode(ce).length;e.textContent=`${t} / ${qt} bytes`,e.className=`roles-bytecount ${t>3800?"warn":""} ${t>qt?"over":""}`,xa(t)}function xa(e){let t=document.getElementById("roles-save");if(!t)return;let n=e??new TextEncoder().encode(ce).length;t.disabled=n>qt||ce.trim().length===0}function Nt(){let e=document.getElementById("roles-preview");e&&(ce.trim()?e.innerHTML=`<strong>${o("roles.preview")}</strong><pre>${r(ce)}</pre>`:e.innerHTML=`<small>${o("roles.previewEmpty")}</small>`)}function Gn(){he=null,we=null,ce="";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 Vn(e){e.innerHTML=Sa(),_e.clear(),Gn(),await dt(),await fe();for(let t of ct)Kn(t)>0&&_e.add(t.chatId);Ae(),document.getElementById("roles-search")?.addEventListener("input",t=>{Ae(t.target.value)}),document.getElementById("roles-refresh")?.addEventListener("click",async()=>{if(await dt(),Ae(document.getElementById("roles-search")?.value??""),he&&we){let t=await Jn(we,he),n=document.getElementById("roles-editor-textarea");n&&(n.value=t.content??""),ce=t.content??"",Pt(),Nt();let s=document.getElementById("roles-delete");s&&(s.style.display=t.hasRole?"":"none")}}),document.getElementById("roles-save")?.addEventListener("click",async function(){if(!(!he||!we)){this.disabled=!0,this.textContent="...";try{if(await Ia(we,he,ce)){await dt(),Ae(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=ce.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(!(!he||!we)&&confirm(o("roles.confirmDelete"))){this.disabled=!0,this.textContent="...";try{await Ta(we,he)&&(await dt(),Gn(),Ae(document.getElementById("roles-search")?.value??""))}finally{this.disabled=!1,this.textContent=o("roles.delete")}}}),document.getElementById("roles-editor-textarea")?.addEventListener("input",t=>{ce=t.target.value,Pt(),Nt()})}async function mt(e){let t=await fetch(e);return{status:t.status,body:await t.json().catch(()=>({}))}}async function ft(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 De=(e,t)=>ft("POST",e,t),Ma=(e,t)=>ft("PUT",e,t),Ut=[],Yn=[],Qn="",ut="",jt=new Map,pt=new Map,Je=new Set,Ke=new Set;function F(e){return document.getElementById(e)}function gt(){return[...Ut,...Yn]}function Ce(e){let t=jt.get(e);return t||(t=new Set,jt.set(e,t)),t}function Ha(e){return gt().find(t=>t.key===e)}function Xn(e){let t=(n,s,a)=>`<a href="${n}" style="padding:6px 14px;border-radius:8px;text-decoration:none;font-size:14px;font-weight:600;${a?"background:var(--accent);color:var(--on-accent)":"color:var(--muted);background:var(--surface-muted)"}">${s}</a>`;return`<div style="display:flex;gap:8px;margin-bottom:14px">${t("#/team","\u6211\u7684\u56E2\u961F",e==="home")}${t("#/team/manage","\u56E2\u961F\u7BA1\u7406",e==="manage")}</div>`}function Aa(){return`<section class="page">
|
|
657
662
|
<div class="page-heading"><div>
|
|
658
663
|
<p class="eyebrow">\u56E2\u961F</p><h1>\u56E2\u961F\u534F\u4F5C\uFF08\u8DE8\u90E8\u7F72\uFF09</h1>
|
|
659
664
|
<p class="tf-lede">\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>
|
|
660
665
|
</div></div>
|
|
661
|
-
${
|
|
666
|
+
${Xn("home")}
|
|
662
667
|
<div class="card" style="margin-bottom:16px">
|
|
663
668
|
<h2 style="margin-top:0">\u672C\u90E8\u7F72</h2>
|
|
664
669
|
<p>\u6211\u7684\u98DE\u4E66\u8EAB\u4EFD\uFF1A<b id="tf-owner">\u672A\u7ED1\u5B9A</b>
|
|
@@ -687,12 +692,12 @@ ${Gn("home")}
|
|
|
687
692
|
</div>
|
|
688
693
|
</div>
|
|
689
694
|
</div>
|
|
690
|
-
</section>`}function $a(e){let t=(F("tf-search").value||"").trim().toLowerCase();if(t&&!((e.name||"")+" "+(e.cliId||"")+" "+(e.capability||"")).toLowerCase().includes(t))return!1;let n=F("tf-cli").value;return!(n&&e.cliId!==n||F("tf-fcap").checked&&!e.capability||F("tf-frole").checked&&!e.hasTeamRole)}function Sa(e,t){let n=[...e.deployments].sort((a,i)=>a.local===i.local?0:a.local?-1:1),s="";for(let a of n){let i=t.filter(u=>u.deployment.id===a.id);if(!i.length)continue;let l=a.id===Wn,p=l?"\u672C\u90E8\u7F72":a.stale?"\u8FDC\u7AEF\xB7\u79BB\u7EBF\uFF1F":"\u8FDC\u7AEF",v=e.kind==="local"&&!l?` <button class="tf-rmmember ghost" data-team="${r(e.teamId)}" data-dep="${r(a.id)}" data-name="${r(a.name)}" style="font-size:12px">\u79FB\u9664</button>`:"",y=`${e.key}::${a.id}`,h=Ke.has(y),k=i.filter(u=>Ce(e.key).has(u.larkAppId)).length;if(s+=`<div class="tf-dep-h" data-dk="${r(y)}" style="cursor:pointer;margin:10px 0 2px"><b>${h?"\u25BE":"\u25B8"} ${r(a.name)}</b> <span class="muted" style="font-size:12px">\uFF08${p}\uFF09\xB7 ${i.length} \u4E2A${k?`\uFF0C\u5DF2\u9009 ${k}`:""}</span>${v}</div>`,!!h){s+='<table style="width:100%;border-collapse:collapse;font-size:14px"><tbody>';for(let u of i){let E=r(u.larkAppId),B=Ce(e.key).has(u.larkAppId)?" checked":"",$=u.deployment.stale?"opacity:.55":"",d=l?`<input class="tf-cap" data-app="${E}" value="${r(u.capability||"")}" placeholder="\u80FD\u529B\u6807\u7B7E\u2026" style="width:92%;padding:3px 6px">`:u.capability?r(u.capability):'<span class="muted">\u2014</span>',f=u.hasTeamRole?l?`<button class="tf-role" data-app="${E}" data-name="${r(u.name)}">\u67E5\u770B</button>`:"\u6709\u89D2\u8272":'<span class="muted">\u2014</span>';s+=`<tr style="${$}"><td style="padding:4px 8px"><input type="checkbox" class="tf-pick" data-tk="${r(e.key)}" data-app="${E}"${B}></td><td style="padding:4px 8px">${r(u.name)}</td><td style="padding:4px 8px" class="muted">${r(u.cliId)}</td><td style="padding:4px 8px">${d}</td><td style="padding:4px 8px">${f}</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="${r(e.key)}" value="${r(dt.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="${r(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="${r(e.key)}" style="font-size:13px;display:block;flex-basis:100%"></span></div>`,s}function Le(){let e=F("tf-teams"),t=pt();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>',F("tf-count").textContent="";return}let n="",s=new Set,a=new Set;for(let l of t){let p=l.bots.filter($a);p.forEach(k=>s.add(k.larkAppId)),l.bots.forEach(k=>a.add(k.larkAppId));let v=new Set(p.map(k=>k.larkAppId));[...Ce(l.key)].forEach(k=>{v.has(k)||Ce(l.key).delete(k)});let y=!Je.has(l.key),h=l.kind==="remote"?l.ok?' <span class="ok" style="font-size:12px">\u5DF2\u8FDE\u63A5</span>':` <span class="err" style="font-size:12px">\u8FDE\u63A5\u5931\u8D25\uFF1A${r(l.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="${r(l.key)}" style="cursor:pointer;display:flex;align-items:center;gap:8px;flex-wrap:wrap"><b style="font-size:15px">${y?"\u25B8":"\u25BE"} ${r(l.label)}</b>`+(l.sub?` <span class="muted" style="font-size:12px">${r(l.sub)}</span>`:"")+h+` <span class="muted" style="font-size:12px">\xB7 ${l.deployments.length} \u4E2A\u90E8\u7F72 \xB7 ${l.bots.length} \u4E2A\u673A\u5668\u4EBA</span></div>`,y||(n+=l.kind==="remote"&&!l.ok?'<p class="muted" style="margin:8px 0 0">\u65E0\u6CD5\u83B7\u53D6\u8BE5\u56E2\u961F\u82B1\u540D\u518C\u3002</p>':Sa(l,p)),n+="</div>"}e.innerHTML=n;let i=t.length>1?`\uFF08\u8DE8 ${t.length} \u4E2A\u56E2\u961F\uFF0C\u53BB\u91CD\uFF09`:"";F("tf-count").textContent=`\xB7 ${s.size===a.size?`${a.size}`:`${s.size} / ${a.size}`} \u4E2A\u673A\u5668\u4EBA${i}`,Ta()}function Ta(){let e=F("tf-teams");e.querySelectorAll(".tf-team-h").forEach(t=>{t.onclick=()=>{let n=t.dataset.tk;Je.has(n)?Je.delete(n):Je.add(n),Le()}}),e.querySelectorAll(".tf-dep-h").forEach(t=>{t.onclick=()=>{let n=t.dataset.dk;Ke.has(n)?Ke.delete(n):Ke.add(n),Le()}}),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=()=>{dt.set(t.dataset.tk,t.value)}}),e.querySelectorAll(".tf-cap").forEach(t=>{t.onchange=async()=>{let n=t.dataset.app,s=t.value;await ya("/api/team/local-bots/"+encodeURIComponent(n)+"/capability",{capability:s}),pt().forEach(a=>{let i=a.bots.find(l=>l.larkAppId===n);i&&(i.capability=s.trim()||null)})}}),e.querySelectorAll(".tf-role").forEach(t=>{t.onclick=()=>La(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 ut("DELETE",`/api/team/hosted/${encodeURIComponent(t.dataset.team)}/members/${encodeURIComponent(t.dataset.dep)}`),Ve())}}),e.querySelectorAll(".tf-grp").forEach(t=>{t.onclick=async()=>{let n=t.dataset.tk,s=va(n);if(!s)return;let a=[...Ce(n)],i=e.querySelector(`.tf-gout[data-tk="${CSS.escape(n)}"]`);if(!a.length){i.innerHTML='<span class="err">\u8BF7\u5148\u52FE\u9009\u81F3\u5C11\u4E00\u4E2A\u673A\u5668\u4EBA</span>';return}let l=(e.querySelector(`.tf-gname[data-tk="${CSS.escape(n)}"]`)?.value||"").trim()||"\u534F\u4F5C\u7FA4";i.innerHTML='<span class="muted">\u5EFA\u7FA4\u4E2D\u2026</span>';let p=s.kind==="local"?await Ae("/api/team/federated-group",{name:l,larkAppIds:a,teamId:s.teamId}):await Ae("/api/team/remote-group",{hubUrl:s.hubUrl,teamId:s.teamId,name:l,larkAppIds:a});if(Ia(i,p.body,p.status),p.body?.ok){Ce(n).clear(),dt.delete(n);let v=i.innerHTML,y=()=>{let h=e.querySelector(`.tf-gout[data-tk="${CSS.escape(n)}"]`);h&&(h.innerHTML=v)};s.kind==="local"?Ve().then(y):(Le(),y())}}})}function Ia(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${r((t.invalidBotIds||[]).join(", "))}</span>`:"",i=(t.invalidOwnerUnionIds||[]).length?`<span class="err"> \xB7 ${(t.invalidOwnerUnionIds||[]).length} \u4E2A owner \u672A\u80FD\u62C9\u8FDB</span>`:"",l=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>':"",p=(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>`:"",v=t.delegatedTo?`\uFF08\u7531\u300C${r(t.delegatedTo)}\u300D\u5EFA\u7FA4\uFF09`:"";e.innerHTML=`<span class="ok">\u7FA4\u5DF2\u521B\u5EFA</span>${v} \xB7 <a href="${r(s)}" target="_blank">\u5728\u98DE\u4E66\u6253\u5F00</a>${a}${i}${l}${p}`}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">${r(String(a))}</span>`}}async function La(e,t){let n=await ct("/api/team/local-bots/"+encodeURIComponent(e)+"/role");F("tf-modal-title").textContent="\u9ED8\u8BA4\u89D2\u8272 \xB7 "+t,F("tf-modal-text").value=n.body?.role||"",F("tf-modal").dataset.app=e,F("tf-modal").style.display="flex"}function Jn(){let e=Array.from(new Set(pt().flatMap(s=>s.bots.map(a=>a.cliId)).filter(Boolean))).sort(),t=F("tf-cli"),n=t.value;t.innerHTML='<option value="">\u5168\u90E8 CLI</option>'+e.map(s=>`<option value="${r(s)}">${r(s)}</option>`).join(""),t.value=n}async function Ve(){let t=(await ct("/api/team/hosted")).body;if(!t?.ok){Bt=[],Le();return}Wn=t.deployment.deploymentId,lt=t.suggestedHubUrl||"",F("tf-owner").textContent=t.deployment.ownerName||(t.deployment.ownerUnionId?"\u5DF2\u7ED1\u5B9A":"\u672A\u7ED1\u5B9A"),Bt=(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||[]})),Jn(),Le()}async function Ea(){Fn=((await ct("/api/team/remote-roster")).body?.memberships||[]).map(n=>{let s=n.roster?.deployments||[],a=s.find(l=>l.local),i=a?.name?`${a.name} \u7684\u56E2\u961F`:n.teamName||n.teamId;return{kind:"remote",key:`${n.hubUrl}::${n.teamId}`,teamId:n.teamId,label:i,sub:n.hubUrl,ok:!!n.ok,error:n.error,hubUrl:n.hubUrl,deployments:s,bots:n.roster?.bots||[]}}),Jn(),Le()}function Kn(e){e.innerHTML=ka(),Pt.clear(),dt.clear(),Je.clear(),Ke.clear(),["tf-search","tf-cli","tf-fcap","tf-frole"].forEach(t=>{let n=F(t);n.oninput=Le,n.onchange=Le}),F("tf-modal-cancel").onclick=()=>{F("tf-modal").style.display="none"},Ma(),Ve(),Ea()}function xa(){return`<section class="page">
|
|
695
|
+
</section>`}function Ca(e){let t=(F("tf-search").value||"").trim().toLowerCase();if(t&&!((e.name||"")+" "+(e.cliId||"")+" "+(e.capability||"")).toLowerCase().includes(t))return!1;let n=F("tf-cli").value;return!(n&&e.cliId!==n||F("tf-fcap").checked&&!e.capability||F("tf-frole").checked&&!e.hasTeamRole)}function Da(e,t){let n=[...e.deployments].sort((a,i)=>a.local===i.local?0:a.local?-1:1),s="";for(let a of n){let i=t.filter(u=>u.deployment.id===a.id);if(!i.length)continue;let l=a.id===Qn,p=l?"\u672C\u90E8\u7F72":a.stale?"\u8FDC\u7AEF\xB7\u79BB\u7EBF\uFF1F":"\u8FDC\u7AEF",v=e.kind==="local"&&!l?` <button class="tf-rmmember ghost" data-team="${r(e.teamId)}" data-dep="${r(a.id)}" data-name="${r(a.name)}" style="font-size:12px">\u79FB\u9664</button>`:"",y=`${e.key}::${a.id}`,h=Ke.has(y),k=i.filter(u=>Ce(e.key).has(u.larkAppId)).length;if(s+=`<div class="tf-dep-h" data-dk="${r(y)}" style="cursor:pointer;margin:10px 0 2px"><b>${h?"\u25BE":"\u25B8"} ${r(a.name)}</b> <span class="muted" style="font-size:12px">\uFF08${p}\uFF09\xB7 ${i.length} \u4E2A${k?`\uFF0C\u5DF2\u9009 ${k}`:""}</span>${v}</div>`,!!h){s+='<table style="width:100%;border-collapse:collapse;font-size:14px"><tbody>';for(let u of i){let E=r(u.larkAppId),q=Ce(e.key).has(u.larkAppId)?" checked":"",$=u.deployment.stale?"opacity:.55":"",d=l?`<input class="tf-cap" data-app="${E}" value="${r(u.capability||"")}" placeholder="\u80FD\u529B\u6807\u7B7E\u2026" style="width:92%;padding:3px 6px">`:u.capability?r(u.capability):'<span class="muted">\u2014</span>',f=u.hasTeamRole?l?`<button class="tf-role" data-app="${E}" data-name="${r(u.name)}">\u67E5\u770B</button>`:"\u6709\u89D2\u8272":'<span class="muted">\u2014</span>';s+=`<tr style="${$}"><td style="padding:4px 8px"><input type="checkbox" class="tf-pick" data-tk="${r(e.key)}" data-app="${E}"${q}></td><td style="padding:4px 8px">${r(u.name)}</td><td style="padding:4px 8px" class="muted">${r(u.cliId)}</td><td style="padding:4px 8px">${d}</td><td style="padding:4px 8px">${f}</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="${r(e.key)}" value="${r(pt.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="${r(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="${r(e.key)}" style="font-size:13px;display:block;flex-basis:100%"></span></div>`,s}function Ee(){let e=F("tf-teams"),t=gt();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>',F("tf-count").textContent="";return}let n="",s=new Set,a=new Set;for(let l of t){let p=l.bots.filter(Ca);p.forEach(k=>s.add(k.larkAppId)),l.bots.forEach(k=>a.add(k.larkAppId));let v=new Set(p.map(k=>k.larkAppId));[...Ce(l.key)].forEach(k=>{v.has(k)||Ce(l.key).delete(k)});let y=!Je.has(l.key),h=l.kind==="remote"?l.ok?' <span class="ok" style="font-size:12px">\u5DF2\u8FDE\u63A5</span>':` <span class="err" style="font-size:12px">\u8FDE\u63A5\u5931\u8D25\uFF1A${r(l.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="${r(l.key)}" style="cursor:pointer;display:flex;align-items:center;gap:8px;flex-wrap:wrap"><b style="font-size:15px">${y?"\u25B8":"\u25BE"} ${r(l.label)}</b>`+(l.sub?` <span class="muted" style="font-size:12px">${r(l.sub)}</span>`:"")+h+` <span class="muted" style="font-size:12px">\xB7 ${l.deployments.length} \u4E2A\u90E8\u7F72 \xB7 ${l.bots.length} \u4E2A\u673A\u5668\u4EBA</span></div>`,y||(n+=l.kind==="remote"&&!l.ok?'<p class="muted" style="margin:8px 0 0">\u65E0\u6CD5\u83B7\u53D6\u8BE5\u56E2\u961F\u82B1\u540D\u518C\u3002</p>':Da(l,p)),n+="</div>"}e.innerHTML=n;let i=t.length>1?`\uFF08\u8DE8 ${t.length} \u4E2A\u56E2\u961F\uFF0C\u53BB\u91CD\uFF09`:"";F("tf-count").textContent=`\xB7 ${s.size===a.size?`${a.size}`:`${s.size} / ${a.size}`} \u4E2A\u673A\u5668\u4EBA${i}`,Ra()}function Ra(){let e=F("tf-teams");e.querySelectorAll(".tf-team-h").forEach(t=>{t.onclick=()=>{let n=t.dataset.tk;Je.has(n)?Je.delete(n):Je.add(n),Ee()}}),e.querySelectorAll(".tf-dep-h").forEach(t=>{t.onclick=()=>{let n=t.dataset.dk;Ke.has(n)?Ke.delete(n):Ke.add(n),Ee()}}),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=()=>{pt.set(t.dataset.tk,t.value)}}),e.querySelectorAll(".tf-cap").forEach(t=>{t.onchange=async()=>{let n=t.dataset.app,s=t.value;await Ma("/api/team/local-bots/"+encodeURIComponent(n)+"/capability",{capability:s}),gt().forEach(a=>{let i=a.bots.find(l=>l.larkAppId===n);i&&(i.capability=s.trim()||null)})}}),e.querySelectorAll(".tf-role").forEach(t=>{t.onclick=()=>Ba(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 ft("DELETE",`/api/team/hosted/${encodeURIComponent(t.dataset.team)}/members/${encodeURIComponent(t.dataset.dep)}`),Ve())}}),e.querySelectorAll(".tf-grp").forEach(t=>{t.onclick=async()=>{let n=t.dataset.tk,s=Ha(n);if(!s)return;let a=[...Ce(n)],i=e.querySelector(`.tf-gout[data-tk="${CSS.escape(n)}"]`);if(!a.length){i.innerHTML='<span class="err">\u8BF7\u5148\u52FE\u9009\u81F3\u5C11\u4E00\u4E2A\u673A\u5668\u4EBA</span>';return}let l=(e.querySelector(`.tf-gname[data-tk="${CSS.escape(n)}"]`)?.value||"").trim()||"\u534F\u4F5C\u7FA4";i.innerHTML='<span class="muted">\u5EFA\u7FA4\u4E2D\u2026</span>';let p=s.kind==="local"?await De("/api/team/federated-group",{name:l,larkAppIds:a,teamId:s.teamId}):await De("/api/team/remote-group",{hubUrl:s.hubUrl,teamId:s.teamId,name:l,larkAppIds:a});if(Oa(i,p.body,p.status),p.body?.ok){Ce(n).clear(),pt.delete(n);let v=i.innerHTML,y=()=>{let h=e.querySelector(`.tf-gout[data-tk="${CSS.escape(n)}"]`);h&&(h.innerHTML=v)};s.kind==="local"?Ve().then(y):(Ee(),y())}}})}function Oa(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${r((t.invalidBotIds||[]).join(", "))}</span>`:"",i=(t.invalidOwnerUnionIds||[]).length?`<span class="err"> \xB7 ${(t.invalidOwnerUnionIds||[]).length} \u4E2A owner \u672A\u80FD\u62C9\u8FDB</span>`:"",l=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>':"",p=(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>`:"",v=t.delegatedTo?`\uFF08\u7531\u300C${r(t.delegatedTo)}\u300D\u5EFA\u7FA4\uFF09`:"";e.innerHTML=`<span class="ok">\u7FA4\u5DF2\u521B\u5EFA</span>${v} \xB7 <a href="${r(s)}" target="_blank">\u5728\u98DE\u4E66\u6253\u5F00</a>${a}${i}${l}${p}`}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">${r(String(a))}</span>`}}async function Ba(e,t){let n=await mt("/api/team/local-bots/"+encodeURIComponent(e)+"/role");F("tf-modal-title").textContent="\u9ED8\u8BA4\u89D2\u8272 \xB7 "+t,F("tf-modal-text").value=n.body?.role||"",F("tf-modal").dataset.app=e,F("tf-modal").style.display="flex"}function Zn(){let e=Array.from(new Set(gt().flatMap(s=>s.bots.map(a=>a.cliId)).filter(Boolean))).sort(),t=F("tf-cli"),n=t.value;t.innerHTML='<option value="">\u5168\u90E8 CLI</option>'+e.map(s=>`<option value="${r(s)}">${r(s)}</option>`).join(""),t.value=n}async function Ve(){let t=(await mt("/api/team/hosted")).body;if(!t?.ok){Ut=[],Ee();return}Qn=t.deployment.deploymentId,ut=t.suggestedHubUrl||"",F("tf-owner").textContent=t.deployment.ownerName||(t.deployment.ownerUnionId?"\u5DF2\u7ED1\u5B9A":"\u672A\u7ED1\u5B9A"),Ut=(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||[]})),Zn(),Ee()}async function qa(){Yn=((await mt("/api/team/remote-roster")).body?.memberships||[]).map(n=>{let s=n.roster?.deployments||[],a=s.find(l=>l.local),i=a?.name?`${a.name} \u7684\u56E2\u961F`:n.teamName||n.teamId;return{kind:"remote",key:`${n.hubUrl}::${n.teamId}`,teamId:n.teamId,label:i,sub:n.hubUrl,ok:!!n.ok,error:n.error,hubUrl:n.hubUrl,deployments:s,bots:n.roster?.bots||[]}}),Zn(),Ee()}function eo(e){e.innerHTML=Aa(),jt.clear(),pt.clear(),Je.clear(),Ke.clear(),["tf-search","tf-cli","tf-fcap","tf-frole"].forEach(t=>{let n=F(t);n.oninput=Ee,n.onchange=Ee}),F("tf-modal-cancel").onclick=()=>{F("tf-modal").style.display="none"},Na(),Ve(),qa()}function Pa(){return`<section class="page">
|
|
691
696
|
<div class="page-heading"><div>
|
|
692
697
|
<p class="eyebrow">\u56E2\u961F</p><h1>\u56E2\u961F\u7BA1\u7406</h1>
|
|
693
698
|
<p class="tf-lede">\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>
|
|
694
699
|
</div></div>
|
|
695
|
-
${
|
|
700
|
+
${Xn("manage")}
|
|
696
701
|
<div class="card" style="margin-bottom:16px">
|
|
697
702
|
<h2 style="margin-top:0">\u6211\u6258\u7BA1\u7684\u56E2\u961F</h2>
|
|
698
703
|
<p style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:6px">
|
|
@@ -711,7 +716,7 @@ ${Gn("manage")}
|
|
|
711
716
|
</p>
|
|
712
717
|
<div id="tm-join-out" style="display:none;margin-top:6px"></div>
|
|
713
718
|
</div>
|
|
714
|
-
</section>`}async function
|
|
719
|
+
</section>`}async function zt(){let t=(await mt("/api/team/hosted")).body,n=F("tm-list");ut=t?.suggestedHubUrl||ut;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 i=(a.deployments||[]).filter(l=>!l.local).length;return`<div class="card" style="margin:0 0 8px;padding:10px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
715
720
|
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
716
721
|
<b>${r(a.name)}</b>${a.isDefault?' <span class="muted" style="font-size:12px">\u9ED8\u8BA4</span>':""}
|
|
717
722
|
<span class="muted" style="font-size:12px">\xB7 ${(a.deployments||[]).length} \u4E2A\u90E8\u7F72${i?`\uFF08\u542B ${i} \u8FDC\u7AEF\uFF09`:""} \xB7 ${(a.bots||[]).length} \u4E2A\u673A\u5668\u4EBA</span>
|
|
@@ -720,7 +725,7 @@ ${Gn("manage")}
|
|
|
720
725
|
${a.isDefault?"":`<button class="tm-del ghost" data-team="${r(a.teamId)}" data-name="${r(a.name)}" style="font-size:12px">\u5220\u9664</button>`}
|
|
721
726
|
</span>
|
|
722
727
|
</div>
|
|
723
|
-
<div class="tm-inv-out" data-team="${r(a.teamId)}" style="display:none;margin-top:6px;font-size:13px"></div></div>`}).join(""),n.querySelectorAll(".tm-invite").forEach(a=>{a.onclick=async()=>{let i=a.dataset.team,l=n.querySelector(`.tm-inv-out[data-team="${CSS.escape(i)}"]`);l.style.display="",l.innerHTML='<span class="muted">\u751F\u6210\u4E2D\u2026</span>';let p=await
|
|
728
|
+
<div class="tm-inv-out" data-team="${r(a.teamId)}" style="display:none;margin-top:6px;font-size:13px"></div></div>`}).join(""),n.querySelectorAll(".tm-invite").forEach(a=>{a.onclick=async()=>{let i=a.dataset.team,l=n.querySelector(`.tm-inv-out[data-team="${CSS.escape(i)}"]`);l.style.display="",l.innerHTML='<span class="muted">\u751F\u6210\u4E2D\u2026</span>';let p=await De("/api/team/local-invite",{teamId:i});p.body?.code?l.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>${r(ut)}</code><br>\u9080\u8BF7\u7801\uFF1A<code style="font-size:15px">${r(p.body.code)}</code>`:l.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 ft("DELETE","/api/team/hosted/"+encodeURIComponent(a.dataset.team)),zt())}})}function to(e){e.innerHTML=Pa(),F("tm-create").onclick=async()=>{let t=F("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 De("/api/team/hosted",{name:t});s.body?.ok?(n.innerHTML='<span class="ok">\u5DF2\u521B\u5EFA</span>',F("tm-newname").value="",zt()):n.innerHTML=`<span class="err">\u521B\u5EFA\u5931\u8D25\uFF1A${r(String(s.body?.error||s.status))}</span>`},F("tm-join").onclick=async()=>{let t=F("tm-hub").value.trim(),n=F("tm-code").value.trim(),s=F("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 De("/api/team/join-remote",{hubUrl:t,inviteCode:n});if(a.body?.ok)s.innerHTML=`<span class="ok">\u5DF2\u52A0\u5165\u300C${r(a.body.teamName||"")}\u300D\uFF0C\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u67E5\u770B\u3002</span>`,F("tm-code").value="";else{let i=a.body?.error||a.status,l=i==="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":i==="deployment_already_joined"?"\u4F60\u7684\u90E8\u7F72\u5DF2\u7ECF\u52A0\u5165\u8FC7\u8FD9\u4E2A\u56E2\u961F\u4E86":i==="hub_unreachable"?"\u8FDE\u4E0D\u4E0A\u5BF9\u65B9 Hub\uFF08\u68C0\u67E5\u5730\u5740/\u7F51\u7EDC\uFF09":i==="hub_timeout"?"\u5BF9\u65B9 Hub \u54CD\u5E94\u8D85\u65F6":`\u52A0\u5165\u5931\u8D25\uFF1A${i}`;s.innerHTML=`<span class="err">${r(String(l))}</span>`}},zt()}function Na(){F("tf-autobind").onclick=async()=>{let e=F("tf-bind-out");e.style.display="",e.innerHTML='<span class="muted">\u8BC6\u522B\u4E2D\u2026</span>';let n=(await De("/api/team/identity/auto-bind")).body;if(n?.ok&&n.owner){e.innerHTML=`<span class="ok">\u5DF2\u7ED1\u5B9A\uFF1A${r(n.owner.name||n.owner.unionId)}</span>`,Ve();return}if(n?.ok&&n.needChoice&&Array.isArray(n.candidates)){let s=n.candidates.map(a=>`<button class="tf-pickowner ghost" data-union="${r(a.unionId)}" style="margin:2px">${r(a.name||a.unionId)}</button>`).join(" ");e.innerHTML=`\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 l=(await De("/api/team/identity/auto-bind",{unionId:a.dataset.union})).body;l?.ok&&l.owner?(e.innerHTML=`<span class="ok">\u5DF2\u7ED1\u5B9A\uFF1A${r(l.owner.name||l.owner.unionId)}</span>`,Ve()):e.innerHTML=`<span class="err">\u7ED1\u5B9A\u5931\u8D25\uFF1A${r(String(l?.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${r(String(n?.error||"unknown"))}</span>`}}async function _t(e){let t=await fetch(e);return{status:t.status,body:await t.json().catch(()=>({}))}}async function Wt(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 W(e){return document.getElementById(e)}function Re(e){return(W(e).value||"").trim()}var Gt=[],Kt=[];function Ua(){return`<section class="page">
|
|
724
729
|
<div class="page-heading">
|
|
725
730
|
<div>
|
|
726
731
|
<p class="eyebrow">\u63A5\u5165\u70B9 \xB7 beta</p>
|
|
@@ -782,11 +787,11 @@ ${Gn("manage")}
|
|
|
782
787
|
<h2 style="margin-top:0">\u5DF2\u6709\u63A5\u5165\u70B9 <span class="muted" id="cn-count" style="font-size:13px"></span></h2>
|
|
783
788
|
<div id="cn-list">\u52A0\u8F7D\u4E2D\u2026</div>
|
|
784
789
|
</div>
|
|
785
|
-
</section>`}function
|
|
790
|
+
</section>`}function Ft(){let e=W("cn-kind").value,t=W("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-dyn").forEach(n=>{n.style.display=t==="dynamic"?"":"none"}),document.querySelectorAll(".cn-life").forEach(n=>{n.style.display=t==="new-group"?"":"none"})}function no(e){return`${location.origin}/webhook/${encodeURIComponent(e)}`}function ja(e){return e==="fixed"?"\u56FA\u5B9A\u7FA4":e==="new-group"?"\u6BCF\u6B21\u65B0\u5EFA\u7FA4":"\u8BF7\u6C42\u6307\u5B9A\u7FA4"}function za(e){return e==="workflow"?"\u5DE5\u4F5C\u6D41":"\u5355\u8F6E"}function Jt(e){return Kt.find(n=>n.chatId===e)?.name||e}function _a(e){return Kt.filter(t=>t.bots.includes(e))}function oo(){let e=W("cn-bot").value,t=_a(e),n=p=>`<option value="${r(p.chatId)}">${r(p.name||p.chatId)}</option>`,s=W("cn-chat-sel"),a=s.value;s.innerHTML=t.length?t.map(n).join(""):'<option value="">\uFF08\u8BE5\u673A\u5668\u4EBA\u6682\u65E0\u53EF\u89C1\u7FA4\uFF0C\u70B9\u53F3\u4FA7\u624B\u52A8\u586B ID\uFF09</option>',a&&t.some(p=>p.chatId===a)&&(s.value=a);let i=W("cn-allow-sel"),l=new Set(Array.from(i.selectedOptions).map(p=>p.value));i.innerHTML=t.map(n).join(""),Array.from(i.options).forEach(p=>{l.has(p.value)&&(p.selected=!0)})}function Fa(e){let t=W("cn-list");if(W("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=Gt.find(v=>v.larkAppId===n.target.botId),a=no(n.id),i=(n.verify?.type??"token")==="token",l=i?"\u4EE4\u724C":"\u7B7E\u540D",p=n.target.mode==="fixed"&&n.target.chatId?` \xB7 \u6295\u9012\u300C${r(Jt(n.target.chatId))}\u300D`:"";return`<div class="card" style="margin:0 0 10px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
786
791
|
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
787
792
|
<b style="font-size:15px">${r(n.name)}</b>
|
|
788
793
|
<span class="${n.enabled?"ok":"muted"}" style="font-size:12px">${n.enabled?"\u5DF2\u542F\u7528":"\u5DF2\u505C\u7528"}</span>
|
|
789
|
-
<span class="muted" style="font-size:12px">\xB7 ${r(s?.botName||n.target.botId)} \xB7 ${
|
|
794
|
+
<span class="muted" style="font-size:12px">\xB7 ${r(s?.botName||n.target.botId)} \xB7 ${za(n.target.kind)} \xB7 ${ja(n.target.mode)}${p} \xB7 ${l}</span>
|
|
790
795
|
<span style="margin-left:auto;display:flex;gap:6px">
|
|
791
796
|
<button class="cn-toggle ghost" data-id="${r(n.id)}" data-on="${n.enabled}" style="font-size:12px">${n.enabled?"\u505C\u7528":"\u542F\u7528"}</button>
|
|
792
797
|
<button class="cn-del ghost" data-id="${r(n.id)}" style="font-size:12px">\u5220\u9664</button>
|
|
@@ -795,15 +800,15 @@ ${Gn("manage")}
|
|
|
795
800
|
<div style="margin-top:6px;font-size:13px;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
796
801
|
<span class="muted">Webhook URL\uFF1A</span><code style="font-size:12px;word-break:break-all">${r(a)}${i?"/<\u4EE4\u724C>":""}</code>
|
|
797
802
|
<button class="cn-copy ghost" data-url="${r(a)}" style="font-size:12px">\u590D\u5236</button>
|
|
798
|
-
</div>${i?'<div class="muted" style="font-size:12px;margin-top:4px">\u4EE4\u724C\u6A21\u5F0F\uFF1A\u8C03\u7528\u65F6\u5728 URL \u672B\u5C3E\u8FFD\u52A0 <code>/<\u4EE4\u724C></code>\uFF08\u4EE4\u724C\u4EC5\u521B\u5EFA/\u8F6E\u6362\u65F6\u663E\u793A\u4E00\u6B21\uFF09\u3002</div>':""}${n.target.mode==="dynamic"?'<div class="muted" style="font-size:12px;margin-top:4px">\u52A8\u6001\u6A21\u5F0F\uFF1A\u8BF7\u6C42\u9700\u5E26\u76EE\u6807\u7FA4 \u2014\u2014 <code>?chatId=<\u7FA4ID></code> \u6216\u5934 <code>x-botmux-chat-id</code> \u6216 body <code>{"chatId":"\u2026"}</code>\u3002</div>':""}${n.promptEnvelope?.instruction?`<div class="muted" style="font-size:12px;margin-top:4px">\u5904\u7406\u6307\u4EE4\uFF1A${r(n.promptEnvelope.instruction)}</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
|
|
803
|
+
</div>${i?'<div class="muted" style="font-size:12px;margin-top:4px">\u4EE4\u724C\u6A21\u5F0F\uFF1A\u8C03\u7528\u65F6\u5728 URL \u672B\u5C3E\u8FFD\u52A0 <code>/<\u4EE4\u724C></code>\uFF08\u4EE4\u724C\u4EC5\u521B\u5EFA/\u8F6E\u6362\u65F6\u663E\u793A\u4E00\u6B21\uFF09\u3002</div>':""}${n.target.mode==="dynamic"?'<div class="muted" style="font-size:12px;margin-top:4px">\u52A8\u6001\u6A21\u5F0F\uFF1A\u8BF7\u6C42\u9700\u5E26\u76EE\u6807\u7FA4 \u2014\u2014 <code>?chatId=<\u7FA4ID></code> \u6216\u5934 <code>x-botmux-chat-id</code> \u6216 body <code>{"chatId":"\u2026"}</code>\u3002</div>':""}${n.promptEnvelope?.instruction?`<div class="muted" style="font-size:12px;margin-top:4px">\u5904\u7406\u6307\u4EE4\uFF1A${r(n.promptEnvelope.instruction)}</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 Wt("PATCH","/api/connectors/"+encodeURIComponent(n.dataset.id),{enabled:n.dataset.on!=="true"}),bt()}}),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 Wt("DELETE","/api/connectors/"+encodeURIComponent(n.dataset.id)),bt())}})}async function bt(){let[e,t,n]=await Promise.all([_t("/api/bots"),_t("/api/connectors"),_t("/api/groups")]);Gt=(e.body?.bots||[]).map(i=>({larkAppId:i.larkAppId,botName:i.botName||i.larkAppId})),Kt=(n.body?.chats||[]).map(i=>({chatId:i.chatId,name:i.name||"",bots:(i.memberBots||[]).filter(l=>l.inChat).map(l=>l.larkAppId)}));let s=W("cn-bot"),a=s.value;s.innerHTML=Gt.map(i=>`<option value="${r(i.larkAppId)}">${r(i.botName)}</option>`).join("")||'<option value="">\uFF08\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF09</option>',a&&(s.value=a),oo(),Fa(t.body?.connectors||[])}function ao(e){e.innerHTML=Ua(),W("cn-kind").onchange=Ft,W("cn-mode").onchange=Ft,W("cn-bot").onchange=oo,W("cn-chat-manual").onclick=t=>{t.preventDefault();let n=W("cn-chat"),s=W("cn-chat-sel"),a=n.style.display==="none";n.style.display=a?"":"none",s.style.display=a?"none":"",W("cn-chat-manual").textContent=a?"\u4ECE\u7FA4\u5217\u8868\u9009\u62E9 \u2190":"\u627E\u4E0D\u5230\u7FA4\uFF1F\u624B\u52A8\u586B ID \u2192"},Ft(),W("cn-create").onclick=async()=>{let t=W("cn-create-out"),n=Re("cn-name"),s=W("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=W("cn-kind").value,i=W("cn-mode").value,l={name:n,enabled:!0,target:{kind:a,mode:i,botId:s},promptEnvelope:{sourceName:n}},p=Re("cn-instruction");if(p&&(l.promptEnvelope.instruction=p),a==="workflow"){if(!Re("cn-wf")){t.innerHTML='<span class="err">\u8BF7\u586B\u5DE5\u4F5C\u6D41 ID</span>';return}l.target.workflowId=Re("cn-wf")}if(i==="fixed"){let k=W("cn-chat").style.display!=="none"?Re("cn-chat"):W("cn-chat-sel").value;if(!k){t.innerHTML='<span class="err">\u8BF7\u9009\u62E9\uFF08\u6216\u624B\u52A8\u586B\uFF09\u6295\u9012\u7684\u7FA4</span>';return}l.target.chatId=k}else{let h=Array.from(W("cn-allow-sel").selectedOptions).map(k=>k.value).filter(Boolean);h.length&&(l.target.allowChats=h)}if(i==="new-group"){let h=Re("cn-dedup");l.lifecycleExtractors=h?{dedupKey:h}:null}l.verify={type:W("cn-verify").value};let v=Re("cn-secret");v&&(l.secret=v),t.innerHTML='<span class="muted">\u521B\u5EFA\u4E2D\u2026</span>';let y=await Wt("POST","/api/connectors",l);if(y.status===201&&y.body?.ok){t.innerHTML="";let h=W("cn-created");h.style.display="";let k=y.body.webhookUrl||no(y.body.connector.id),u=y.body.secret,E=(y.body.connector?.verify?.type??"token")==="token",q=i==="dynamic",$=q?l.target.allowChats?.[0]||"<\u7FA4ID>":"",d=q?`${r(k)}?chatId=${r($)}`:r(k),f;E&&q?f=`<p class="muted" style="font-size:12px;margin:6px 0 0">\u52A8\u6001\u6A21\u5F0F\uFF1AURL \u5DF2\u542B\u4EE4\u724C\uFF0C\u8C03\u7528\u65F6\u518D\u5E26\u4E0A\u76EE\u6807\u7FA4 ID${$!=="<\u7FA4ID>"?`\uFF08${r(Jt(l.target.allowChats[0]))}\uFF09`:""}\uFF1A</p>
|
|
799
804
|
<pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${d}' -H 'content-type: application/json' -d '{}'</code></pre>
|
|
800
805
|
<p class="muted" style="font-size:12px;margin:6px 0 0">\u7FA4\u4E5F\u53EF\u653E\u8BF7\u6C42\u5934 <code>x-botmux-chat-id</code> \u6216 body <code>{"chatId":"\u2026"}</code>\u3002\u26A0\uFE0F URL \u5373\u51ED\u8BC1\uFF0C\u52FF\u6CC4\u6F0F\u3002</p>`:E?f=`<p class="muted" style="font-size:12px;margin:6px 0 0">\u6B64 URL \u5DF2\u542B\u4EE4\u724C\u3001\u4E14\u56FA\u5B9A\u6295\u9012\u5230\u6240\u9009\u7FA4\uFF0C\u76F4\u63A5 POST \u5373\u53EF\u89E6\u53D1\uFF1A</p>
|
|
801
806
|
<pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${d}' -H 'content-type: application/json' -d '{}'</code></pre>
|
|
802
|
-
<p class="muted" style="font-size:12px;margin:6px 0 0">\u26A0\uFE0F URL \u5373\u51ED\u8BC1\uFF0C\u8BF7\u52FF\u516C\u5F00\u6CC4\u6F0F\uFF1B\u53EF\u5728\u4E0B\u65B9\u5217\u8868\u5220\u9664\u6216\u8F6E\u6362\u3002</p>`:f=`<p class="muted" style="font-size:12px;margin:6px 0 0">\u5916\u90E8\u7CFB\u7EDF\u9700\u5BF9 <code>timestamp.body</code> \u505A HMAC-SHA256 \u7B7E\u540D\uFF0C\u5E76\u5E26\u4E0A <code>x-botmux-timestamp</code> / <code>x-botmux-nonce</code> / <code>x-botmux-signature</code> \u5934\u8C03\u7528${
|
|
803
|
-
<p class="ok" style="margin:0 0 6px">\u5DF2\u521B\u5EFA\u300C${r(n)}\u300D${i==="fixed"&&l.target.chatId?`<span class="muted" style="font-weight:400;font-size:13px"> \xB7 \u6295\u9012\u5230\u300C${r(
|
|
807
|
+
<p class="muted" style="font-size:12px;margin:6px 0 0">\u26A0\uFE0F URL \u5373\u51ED\u8BC1\uFF0C\u8BF7\u52FF\u516C\u5F00\u6CC4\u6F0F\uFF1B\u53EF\u5728\u4E0B\u65B9\u5217\u8868\u5220\u9664\u6216\u8F6E\u6362\u3002</p>`:f=`<p class="muted" style="font-size:12px;margin:6px 0 0">\u5916\u90E8\u7CFB\u7EDF\u9700\u5BF9 <code>timestamp.body</code> \u505A HMAC-SHA256 \u7B7E\u540D\uFF0C\u5E76\u5E26\u4E0A <code>x-botmux-timestamp</code> / <code>x-botmux-nonce</code> / <code>x-botmux-signature</code> \u5934\u8C03\u7528${q?"\uFF0C\u540C\u65F6\u6309\u4E0A\u9762\u65B9\u5F0F\u5E26\u76EE\u6807\u7FA4 ID":""}\u3002</p>`,h.innerHTML=`<div class="card" style="padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
808
|
+
<p class="ok" style="margin:0 0 6px">\u5DF2\u521B\u5EFA\u300C${r(n)}\u300D${i==="fixed"&&l.target.chatId?`<span class="muted" style="font-weight:400;font-size:13px"> \xB7 \u6295\u9012\u5230\u300C${r(Jt(l.target.chatId))}\u300D</span>`:""}</p>
|
|
804
809
|
<p style="margin:4px 0;font-size:13px"><span class="muted">Webhook URL\uFF1A</span><code style="word-break:break-all">${r(k)}</code></p>
|
|
805
810
|
${u?`<p style="margin:4px 0;font-size:13px"><span class="muted">${E?"\u8BBF\u95EE\u4EE4\u724C":"\u7B7E\u540D\u5BC6\u94A5"}\uFF08\u53EA\u663E\u793A\u8FD9\u4E00\u6B21\uFF0C\u8BF7\u4FDD\u5B58\uFF09\uFF1A</span><code>${r(u)}</code></p>`:""}
|
|
806
|
-
${f}</div>`,["cn-name","cn-wf","cn-chat","cn-dedup","cn-secret","cn-instruction"].forEach(w=>{W(w).value=""}),W("cn-allow-sel").selectedIndex=-1,
|
|
811
|
+
${f}</div>`,["cn-name","cn-wf","cn-chat","cn-dedup","cn-secret","cn-instruction"].forEach(w=>{W(w).value=""}),W("cn-allow-sel").selectedIndex=-1,bt()}else{let h=y.body?.error||y.status;t.innerHTML=`<span class="err">\u521B\u5EFA\u5931\u8D25\uFF1A${r(String(h))}</span>`}},bt()}var xe=null,Ye=null,Vt=!0;function Wa(){return`<section class="page">
|
|
807
812
|
<div class="page-heading">
|
|
808
813
|
<div>
|
|
809
814
|
<p class="eyebrow">${o("nav.settings")}</p>
|
|
@@ -812,13 +817,13 @@ ${Gn("manage")}
|
|
|
812
817
|
</div>
|
|
813
818
|
</div>
|
|
814
819
|
<div id="settings-body"></div>
|
|
815
|
-
</section>`}function
|
|
820
|
+
</section>`}function Ga(){if(Ye)return`<p class="hint-warn">${o("settings.loadFailed")}: ${r(Ye)}</p>`;if(!xe)return`<p class="empty">${o("settings.loading")}</p>`;let e=Vt?"":"disabled";return`<div class="settings-grid">
|
|
816
821
|
<article class="bd-card settings-card">
|
|
817
|
-
${
|
|
822
|
+
${Vt?"":`<p class="hint-warn">${o("settings.readOnlyVisitor")}</p>`}
|
|
818
823
|
<section class="bd-section">
|
|
819
824
|
<h3 class="bd-section-title">${o("settings.sectionAccess")}</h3>
|
|
820
825
|
<label class="toggle-row">
|
|
821
|
-
<input type="checkbox" data-setting="publicReadOnly" ${
|
|
826
|
+
<input type="checkbox" data-setting="publicReadOnly" ${xe.publicReadOnly?"checked":""} ${e}>
|
|
822
827
|
<span class="switch" aria-hidden="true"></span>
|
|
823
828
|
<span class="toggle-tx"><strong>${o("settings.publicReadOnly")}</strong>
|
|
824
829
|
<small>${o("settings.publicReadOnlyHelp")}</small></span>
|
|
@@ -827,7 +832,7 @@ ${Gn("manage")}
|
|
|
827
832
|
<section class="bd-section">
|
|
828
833
|
<h3 class="bd-section-title">${o("settings.sectionCards")}</h3>
|
|
829
834
|
<label class="toggle-row">
|
|
830
|
-
<input type="checkbox" data-setting="openTerminalInFeishu" ${
|
|
835
|
+
<input type="checkbox" data-setting="openTerminalInFeishu" ${xe.openTerminalInFeishu?"checked":""} ${e}>
|
|
831
836
|
<span class="switch" aria-hidden="true"></span>
|
|
832
837
|
<span class="toggle-tx"><strong>${o("settings.openTerminalInFeishu")}</strong>
|
|
833
838
|
<small>${o("settings.openTerminalInFeishuHelp")}</small></span>
|
|
@@ -837,7 +842,7 @@ ${Gn("manage")}
|
|
|
837
842
|
<span class="oncall-status" data-settings-status></span>
|
|
838
843
|
</div>
|
|
839
844
|
</article>
|
|
840
|
-
</div>`}async function
|
|
845
|
+
</div>`}async function Ja(){try{let e=await fetch("/api/settings"),t=await e.json().catch(()=>({}));if(!e.ok){xe=null,Ye=t?.error??`HTTP ${e.status}`;return}xe={publicReadOnly:t.settings?.publicReadOnly===!0,openTerminalInFeishu:t.settings?.openTerminalInFeishu===!0},Vt=t.authed===!0,Ye=null}catch(e){xe=null,Ye=e?.message??String(e)}}async function so(e){e.innerHTML=Wa();let t=e.querySelector("#settings-body");function n(){t.innerHTML=Ga(),i()}function s(){return t.querySelector("[data-settings-status]")}async function a(l,p){if(!xe)return;let v=!p.checked;p.disabled=!0;let y=s();y&&(y.textContent=o("settings.saving"),y.className="oncall-status");try{let h=await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(l)}),k=await h.json().catch(()=>({}));if(!h.ok||k.ok===!1)throw new Error(k?.error??`HTTP ${h.status}`);xe={publicReadOnly:k.settings?.publicReadOnly===!0,openTerminalInFeishu:k.settings?.openTerminalInFeishu===!0},y&&(y.textContent=o("settings.saved"),y.classList.add("hint-ok"))}catch(h){p.checked=v,y&&(y.textContent=`${o("settings.saveFailed")}: ${h?.message??h}`,y.classList.add("hint-warn-inline"))}finally{p.disabled=!1}}function i(){t.querySelectorAll("input[data-setting]").forEach(l=>{l.addEventListener("change",()=>{let p=l.dataset.setting;a({[p]:l.checked},l)})})}n(),await Ja(),n()}function Ka(){let e=[["",o("workflow.filter.nonTerminal")],["all",o("workflow.filter.all")],["pending",Me("pending")],["running",Me("running")],["waiting",Me("waiting")],["succeeded",Me("succeeded")],["failed",Me("failed")],["cancelled",Me("cancelled")]];return`
|
|
841
846
|
<nav class="wf-subnav">
|
|
842
847
|
<a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${m(o("workflow.subnav.runs"))}</a>
|
|
843
848
|
<a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${m(o("workflow.subnav.catalog"))}</a>
|
|
@@ -857,15 +862,15 @@ ${Gn("manage")}
|
|
|
857
862
|
</tr></thead>
|
|
858
863
|
<tbody id="wf-tbody"></tbody>
|
|
859
864
|
</table>
|
|
860
|
-
`}var
|
|
865
|
+
`}var Va=5e3,Ya=2e3,Qe=new Set(["succeeded","failed","cancelled"]);function m(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function Qa(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 Ie(e){return`<span class="${Qe.has(e)?"wf-status terminal":"wf-status live"} wf-status-${m(e)}">${m(Me(e))}</span>`}function Me(e){let t=`workflow.status.${e}`,n=o(t);return n===t?e:n}function co(e){let t=location.hash.match(/^#\/workflows\/([^?#]+)(?:\?([^#]*))?$/);if(t){let n=new URLSearchParams(t[2]??"");return Za(e,decodeURIComponent(t[1]),{focusAttemptId:n.get("attempt")??void 0})}return Xa(e)}function Xa(e){e.innerHTML=Ka();let t=e.querySelector("#wf-tbody"),n=e.querySelector("#wf-filters"),s=e.querySelector("#wf-last-load"),a=[],i=null,l=!1,p=null,v=!1;function y($){let f=(new FormData(n).get("q")??"").trim().toLowerCase();return f?$.filter(w=>w.runId.toLowerCase().includes(f)||w.workflowId.toLowerCase().includes(f)||(w.chatId??"").toLowerCase().includes(f)):$}function h(){let $=y(a);if($.length===0){t.innerHTML=`<tr><td colspan="7" class="empty">${p?m(o("workflow.list.failedLoad",{error:p})):a.length===0?m(o("workflow.list.noRuns")):m(o("workflow.list.noFilterMatch"))}</td></tr>`;return}t.innerHTML=$.map(d=>{let f=`${d.dEf}/${d.dAct}/${d.dWait}`,w=d.dEf+d.dAct+d.dWait>0?"wf-dangling has":"wf-dangling none",I=[];d.chatId&&I.push(m(d.chatId)),d.larkAppId&&I.push(`<span class="muted">${m(d.larkAppId)}</span>`);let x=I.length>0?I.join("<br/>"):"\u2014",M=ts(d);return`<tr data-runid="${m(d.runId)}">
|
|
861
866
|
<td><a href="#/workflows/${encodeURIComponent(d.runId)}"><code>${m(d.runId)}</code></a></td>
|
|
862
867
|
<td>${m(d.workflowId)}</td>
|
|
863
|
-
<td>${
|
|
868
|
+
<td>${Ie(d.status)}${d.failedNodeId?` <span class="muted">(${m(d.failedNodeId)})</span>`:""}${M}</td>
|
|
864
869
|
<td>${d.lastSeq}</td>
|
|
865
870
|
<td class="${w}">${f}</td>
|
|
866
|
-
<td title="${m(new Date(d.updatedAt).toISOString())}">${
|
|
871
|
+
<td title="${m(new Date(d.updatedAt).toISOString())}">${Qa(d.updatedAt)}</td>
|
|
867
872
|
<td>${x}</td>
|
|
868
|
-
</tr>`}).join("")}function k(){p?(s.textContent=o("workflow.list.error",{error:p}),s.classList.add("error")):(s.textContent=o("workflow.list.loaded",{count:a.length,time:new Date().toLocaleTimeString()}),s.classList.remove("error"))}async function u(){if(!(v||l)&&!document.hidden){l=!0;try{let $=n.elements.namedItem("status")?.value??"",d=new URLSearchParams;$==="all"?d.set("all","1"):$&&d.set("status",$);let f="/api/workflows/runs"+(d.toString()?`?${d}`:""),w=await fetch(f);w.ok?(a=(await w.json()).runs??[],p=null):(p=`HTTP ${w.status}`,a=[])}catch($){p=$?.message??String($),a=[]}finally{l=!1,v||(h(),k())}}}function E(){i!==null&&window.clearTimeout(i),i=window.setTimeout(async()=>{await u(),v||E()},
|
|
873
|
+
</tr>`}).join("")}function k(){p?(s.textContent=o("workflow.list.error",{error:p}),s.classList.add("error")):(s.textContent=o("workflow.list.loaded",{count:a.length,time:new Date().toLocaleTimeString()}),s.classList.remove("error"))}async function u(){if(!(v||l)&&!document.hidden){l=!0;try{let $=n.elements.namedItem("status")?.value??"",d=new URLSearchParams;$==="all"?d.set("all","1"):$&&d.set("status",$);let f="/api/workflows/runs"+(d.toString()?`?${d}`:""),w=await fetch(f);w.ok?(a=(await w.json()).runs??[],p=null):(p=`HTTP ${w.status}`,a=[])}catch($){p=$?.message??String($),a=[]}finally{l=!1,v||(h(),k())}}}function E(){i!==null&&window.clearTimeout(i),i=window.setTimeout(async()=>{await u(),v||E()},Va)}function q(){document.hidden||u()}return n.addEventListener("input",()=>{h()}),n.addEventListener("change",$=>{$.target.getAttribute("name")==="status"&&u()}),document.addEventListener("visibilitychange",q),u().then(()=>{v||E()}),()=>{v=!0,i!==null&&window.clearTimeout(i),document.removeEventListener("visibilitychange",q)}}function Za(e,t,n={}){e.innerHTML=`
|
|
869
874
|
<div class="wf-detail-head">
|
|
870
875
|
<a class="btn-link" href="#/workflows">${m(o("workflow.detail.back"))}</a>
|
|
871
876
|
<div>
|
|
@@ -921,16 +926,16 @@ ${Gn("manage")}
|
|
|
921
926
|
</div>
|
|
922
927
|
<div id="wf-event-meta" class="muted"></div>
|
|
923
928
|
</section>
|
|
924
|
-
`;let s=e.querySelector("#wf-detail-subtitle"),a=e.querySelector("#wf-detail-refresh"),i=e.querySelector("#wf-detail-error"),l=e.querySelector("#wf-cancel-status"),p=e.querySelector("#wf-summary"),v=e.querySelector("#wf-dangling-panel"),y=e.querySelector("#wf-parallel-view"),h=e.querySelector("#wf-parallel-meta"),k=e.querySelector("#wf-node-tbody"),u=e.querySelector("#wf-io-list"),E=e.querySelector(".wf-timeline-scroll"),
|
|
929
|
+
`;let s=e.querySelector("#wf-detail-subtitle"),a=e.querySelector("#wf-detail-refresh"),i=e.querySelector("#wf-detail-error"),l=e.querySelector("#wf-cancel-status"),p=e.querySelector("#wf-summary"),v=e.querySelector("#wf-dangling-panel"),y=e.querySelector("#wf-parallel-view"),h=e.querySelector("#wf-parallel-meta"),k=e.querySelector("#wf-node-tbody"),u=e.querySelector("#wf-io-list"),E=e.querySelector(".wf-timeline-scroll"),q=e.querySelector("#wf-event-tbody"),$=e.querySelector("#wf-event-meta"),d=e.querySelector("#wf-cancel-run"),f=e.querySelector("#wf-load-older"),w=null,I=[],x=new Set,M=null,H=null,O=!1,z=0,j=null,ee=!1,ae=!1,Z=!1,J=new Set,se=new Map,He=new Map,ve=new Map,ie=new Set,re=new Map,te=new Set,pe=new Map,Q=new Map,ke=0,$e=n.focusAttemptId;function V(b){if(!b){i.hidden=!0,i.textContent="";return}i.hidden=!1,i.textContent=b}function c(b){if(!b){l.hidden=!0,l.textContent="";return}l.hidden=!1,l.textContent=b}async function g(){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}));w=await b.json()}async function S(b){let R=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/events?${b}`);if(R.status===404)throw new Error(o("workflow.detail.unknownRun"));if(!R.ok)throw new Error(o("workflow.detail.eventsHttp",{status:R.status}));return await R.json()}function L(b,R){let D=b.filter(C=>x.has(C.eventId)?!1:(x.add(C.eventId),!0));D.length!==0&&(I=R==="prepend"?[...D,...I]:[...I,...D],I.sort((C,ne)=>Xe(C.eventId)-Xe(ne.eventId)))}async function T(){await g();let b=await S(new URLSearchParams({tail:"100"}));I=[],x=new Set,L(b.events,"append"),M=b.oldestSeq,H=b.newestSeq,O=b.hasOlder,z=b.totalCount,U()}async function P(){if(!(ee||ae||document.hidden)){ae=!0;try{if(await g(),H!==null){let b=await S(new URLSearchParams({afterSeq:String(H),limit:"200"}));L(b.events,"append"),b.newestSeq!==null&&(H=b.newestSeq),M===null&&b.oldestSeq!==null&&(M=b.oldestSeq),z=b.totalCount}else{let b=await S(new URLSearchParams({tail:"1"}));L(b.events,"append"),M=b.oldestSeq,H=b.newestSeq,O=b.hasOlder,z=b.totalCount}V(null),U()}catch(b){V(b?.message??String(b))}finally{ae=!1}}}async function B(){if(!(M===null||!O)){f.disabled=!0;try{let b=await S(new URLSearchParams({beforeSeq:String(M),limit:"100"}));L(b.events,"prepend"),b.oldestSeq!==null&&(M=b.oldestSeq),O=b.hasOlder,z=b.totalCount,V(null),U()}catch(b){V(b?.message??String(b))}finally{f.disabled=!1}}}async function X(){if(!w||Qe.has(w.run.status)||Z)return;if(!w.chatBinding?.larkAppId){V(o("workflow.detail.cancelUnavailable",{runId:t}));return}let b=ns(w),R=o("workflow.detail.cancelConfirm",{runId:t,...b});if(window.confirm(R)){Z=!0,d.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 C=await D.json().catch(()=>({}));if(!D.ok||!C.ok)throw new Error(C.hint??C.error??o("workflow.detail.cancelHttp",{status:D.status}));c(C.pending?o("workflow.detail.cancelPending"):null),V(null),await P()}catch(D){V(D?.message??String(D))}finally{Z=!1,d.disabled=!1,U()}}}async function Y(b,R){if(!te.has(b)){te.add(b),pe.delete(b),U();try{let D=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/attempts/${encodeURIComponent(R)}/${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 C=await D.json().catch(()=>({}));if(!D.ok||!C.ok||!C.resumeId||!C.url)throw new Error(C.hint??C.message??C.error??o("workflow.detail.resumeStartFailed",{status:D.status}));re.set(b,{resumeId:C.resumeId,url:C.url})}catch(D){let C=D?.message??String(D);pe.set(b,C)}finally{te.delete(b),U()}}}async function rn(b,R){if(!te.has(b)){te.add(b),pe.delete(b),U();try{let D=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/attempts/${encodeURIComponent(R)}/${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 C=await D.json().catch(()=>({}));if(!D.ok||!C.ok)if(C.error==="resume_not_running")re.delete(b);else throw new Error(C.hint??C.message??C.error??o("workflow.detail.resumeEndFailed",{status:D.status}));else re.delete(b)}catch(D){let C=D?.message??String(D);pe.set(b,C)}finally{te.delete(b),U()}}}async function K(b,R){if(!ie.has(b)){ie.add(b),ve.delete(b),U();try{let D=He.get(b)?.trim()||void 0,C=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/${R}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({comment:D})});if(C.status===401)throw new Error(o("workflow.detail.writeAccessApproval"));let ne=await C.json().catch(()=>({}));if(!C.ok||!ne.ok)throw new Error(ne.hint??ne.message??ne.error??o("workflow.detail.actionHttp",{action:R,status:C.status}));let St=R==="approve"?o("workflow.detail.approved"):o("workflow.detail.rejected");ve.set(b,{kind:"ok",text:ne.alreadyTerminal?o("workflow.detail.alreadyTerminal",{label:St}):ne.pending?o("workflow.detail.workflowContinue",{label:St}):o("workflow.detail.workflowRefreshing",{label:St})}),V(null),await P()}catch(D){let C=D?.message??String(D);ve.set(b,{kind:"error",text:C}),V(C)}finally{ie.delete(b),U()}}}function U(){if(!w)return;ke=E.scrollTop;let b=w.run;Qe.has(b.status)&&c(null),s.innerHTML=`${m(b.workflowId??"?")} \xB7 ${Ie(b.status)} \xB7 lastSeq ${w.lastSeq}`,a.textContent=o("workflow.detail.refreshed",{time:new Date().toLocaleTimeString()}),d.hidden=Qe.has(b.status),d.disabled=Z||!w.chatBinding?.larkAppId,d.textContent=w.chatBinding?.larkAppId?o("workflow.detail.cancel"):o("workflow.detail.cliCancelOnly"),d.title=w.chatBinding?.larkAppId?o("workflow.detail.cancelTitle"):o("workflow.detail.cliCancelTitle",{runId:t}),es(p,w),os(v,w),as(y,h,w,I),cs(k,w),us(u,w,J,se,{comments:He,statuses:ve,resolving:ie,onResolve:K},{sessions:re,pending:te,errors:pe,onStart:Y,onEnd:rn},$e,Q)&&($e=void 0),qs(q,I),E.scrollTop=ke,f.hidden=!O,$.textContent=o("workflow.detail.eventsLoaded",{loaded:I.length,total:z})}function N(){if(j!==null&&window.clearTimeout(j),w&&Qe.has(w.run.status)){j=null;return}j=window.setTimeout(async()=>{await P(),ee||N()},Ya)}function _(){document.hidden||P().then(()=>{!ee&&j===null&&N()})}return f.addEventListener("click",()=>{B()}),d.addEventListener("click",()=>{X()}),document.addEventListener("visibilitychange",_),T().then(()=>{V(null),ee||N()}).catch(b=>{V(b?.message??String(b)),s.textContent=o("workflow.detail.loadFailed")}),()=>{ee=!0,j!==null&&window.clearTimeout(j),document.removeEventListener("visibilitychange",_)}}function es(e,t){let n=t.run,s=[[o("workflow.summary.workflow"),m(n.workflowId??"?")],[o("workflow.summary.status"),Ie(n.status)],[o("workflow.summary.lastSeq"),String(t.lastSeq)],[o("workflow.summary.updated"),m(new Date(t.updatedAt).toLocaleString())],[o("workflow.summary.revision"),m(yt(n.revisionId))],[o("workflow.summary.initiator"),m(n.initiator??"-")]];n.failedNodeId&&s.push([o("workflow.summary.failedNode"),m(n.failedNodeId)]),n.cancelOriginEventId&&s.push([o("workflow.summary.cancelOrigin"),m(n.cancelOriginEventId)]),t.chatBinding&&(s.push([o("workflow.summary.chat"),`<code>${m(t.chatBinding.chatId)}</code>`]),s.push([o("workflow.summary.app"),`<code>${m(t.chatBinding.larkAppId)}</code>`])),e.innerHTML=s.map(([a,i])=>`<div class="wf-summary-item"><span>${a}</span><strong>${i}</strong></div>`).join("")}function ts(e){if(!e.errorCode)return"";let t=e.errorMessage?` \u2014 ${js(e.errorMessage,96)}`:"";return`<div class="wf-run-error">
|
|
925
930
|
<span class="muted error">${m(e.errorCode)}</span>${m(t)}
|
|
926
|
-
</div>`}function
|
|
931
|
+
</div>`}function ns(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 os(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(([,i])=>i)).size;if(e.className=a>0?"wf-panel wf-dangling-panel has":"wf-panel wf-dangling-panel",a===0){e.innerHTML=`<div class="wf-panel-title"><h3>${m(o("workflow.detail.dangling"))}</h3></div><div class="muted">${m(o("workflow.detail.noDangling"))}</div>`;return}e.innerHTML=`<div class="wf-panel-title"><h3>${m(o("workflow.detail.dangling"))}</h3><span class="wf-dangling has">${a}</span></div>
|
|
927
932
|
<div class="wf-dangling-grid">
|
|
928
933
|
${s.map(([i,l])=>`<div><strong>${i}</strong>${l.length===0?`<div class="muted">${m(o("workflow.detail.none"))}</div>`:`<ul>${l.map(p=>`<li><code>${m(p)}</code></li>`).join("")}</ul>`}</div>`).join("")}
|
|
929
|
-
</div>`}function
|
|
930
|
-
<span title="${m(new Date(l).toISOString())}">${m(
|
|
931
|
-
<span title="${m(new Date(p).toISOString())}">${m(
|
|
934
|
+
</div>`}function as(e,t,n,s){let a=ss(s,n);if(a.length===0){t.textContent="",e.innerHTML=`<div class="empty">${m(o("workflow.detail.noParallelData"))}</div>`;return}let i=Date.now(),l=Math.min(...a.map(u=>u.startedAt)),p=Math.max(...a.map(u=>u.endedAt??i),l+1e3),v=Math.max(1,p-l),y=rs(a,i),h=a.filter(u=>!u.endedAt&&(u.status==="running"||u.status==="effectAttempting")).length;t.textContent=o("workflow.detail.parallelMeta",{count:a.length,max:y,running:h});let k=a.sort((u,E)=>u.startedAt-E.startedAt||u.activityId.localeCompare(E.activityId)).map(u=>is(u,l,v,i)).join("");e.innerHTML=`<div class="wf-parallel-axis">
|
|
935
|
+
<span title="${m(new Date(l).toISOString())}">${m(wt(l))}</span>
|
|
936
|
+
<span title="${m(new Date(p).toISOString())}">${m(wt(p))}</span>
|
|
932
937
|
</div>
|
|
933
|
-
<div class="wf-parallel-list">${k}</div>`}function
|
|
938
|
+
<div class="wf-parallel-list">${k}</div>`}function ss(e,t){let n=new Map,s=new Map(t.activities.map(a=>[a.activityId,a.ownerNodeId]));for(let a of[...e].sort((i,l)=>Xe(i.eventId)-Xe(l.eventId))){let i=Us(a);if(!i)continue;let l=typeof i.activityId=="string"?i.activityId:void 0,p=typeof i.attemptId=="string"?i.attemptId:void 0;if(!l||!p)continue;let v=n.get(p);if(a.type==="attemptCreated"){let y=typeof i.attemptNumber=="number"?i.attemptNumber:void 0;v={nodeId:typeof i.nodeId=="string"?i.nodeId:s.get(l),activityId:l,attemptId:p,attemptNumber:y,status:"pending",startedAt:a.timestamp},n.set(p,v);continue}v||(v={nodeId:s.get(l),activityId:l,attemptId:p,status:"pending",startedAt:a.timestamp},n.set(p,v)),a.type==="activityRunning"?(v.status="running",v.runningAt=a.timestamp):a.type==="effectAttempted"?v.status="effectAttempting":a.type==="activityWaiting"||a.type==="waitCreated"?v.status="waiting":ls(a.type)&&(v.status=ds(a.type),v.endedAt=a.timestamp,v.endType=a.type)}return[...n.values()]}function is(e,t,n,s){let a=e.endedAt??s,i=lo((e.startedAt-t)/n*100,0,100),l=lo((Math.max(a,e.startedAt+1)-e.startedAt)/n*100,.7,100-i),p=e.nodeId??e.activityId,v=e.attemptNumber!==void 0?`#${e.attemptNumber}`:yt(e.attemptId),y=[`${p} ${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(`
|
|
934
939
|
`);return`<div class="wf-parallel-row">
|
|
935
940
|
<div class="wf-parallel-label">
|
|
936
941
|
<code>${m(p)}</code>
|
|
@@ -938,36 +943,36 @@ ${Gn("manage")}
|
|
|
938
943
|
</div>
|
|
939
944
|
<div class="wf-parallel-track">
|
|
940
945
|
<div class="wf-parallel-bar wf-parallel-${m(e.status)}" style="left:${i.toFixed(3)}%;width:${l.toFixed(3)}%;" title="${m(y)}">
|
|
941
|
-
<span>${m(
|
|
946
|
+
<span>${m(Me(e.status))}</span>
|
|
942
947
|
</div>
|
|
943
948
|
</div>
|
|
944
|
-
</div>`}function
|
|
949
|
+
</div>`}function rs(e,t){let n=[];for(let i of e)n.push({time:i.startedAt,delta:1}),n.push({time:i.endedAt??t,delta:-1});n.sort((i,l)=>i.time-l.time||l.delta-i.delta);let s=0,a=0;for(let i of n)s+=i.delta,a=Math.max(a,s);return a}function ls(e){return e==="activitySucceeded"||e==="activityFailed"||e==="activityTimedOut"||e==="activityCanceled"}function ds(e){return e==="activitySucceeded"?"succeeded":e==="activityCanceled"?"cancelled":e==="activityTimedOut"?"timedOut":"failed"}function cs(e,t){let n=new Map(t.activities.map(i=>[i.activityId,i])),s=new Set,a=[];for(let i of t.nodes){let l=(i.activityId?n.get(i.activityId):void 0)??t.activities.find(p=>p.ownerNodeId===i.nodeId);l&&s.add(l.activityId),a.push(io(i,l))}for(let i of t.activities)s.has(i.activityId)||a.push(io(void 0,i));e.innerHTML=a.length>0?a.join(""):`<tr><td colspan="7" class="empty">${m(o("workflow.detail.noNodes"))}</td></tr>`}function io(e,t){let n=t?.attempts[t.attempts.length-1];return`<tr>
|
|
945
950
|
<td>${e?`<code>${m(e.nodeId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
946
|
-
<td>${e?
|
|
951
|
+
<td>${e?Ie(e.status):'<span class="muted">-</span>'}</td>
|
|
947
952
|
<td>${t?`<code>${m(t.activityId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
948
|
-
<td>${t?
|
|
953
|
+
<td>${t?Ie(t.status):'<span class="muted">-</span>'}</td>
|
|
949
954
|
<td>${t?.attempts.length??0}</td>
|
|
950
955
|
<td>${n?`<code>${m(n.attemptId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
951
|
-
<td>${n?
|
|
952
|
-
</tr>`}function
|
|
956
|
+
<td>${n?Bs(n):`<span class="muted">${m(o("workflow.detail.idle"))}</span>`}</td>
|
|
957
|
+
</tr>`}function us(e,t,n,s,a,i,l,p){Hs(e,n,s),Ls(e,a.comments);let v=!!(l&&t.attemptIO?.[l]?.terminal);v&&l&&n.add(Yt(l,o("workflow.detail.liveTerminal")));let y=ps(t),h=new Set;if(p){for(let u of y){h.add(u.key);let E=p.get(u.key);E||(E=ms(u.key),p.set(u.key,E),e.appendChild(E.article)),fs(E,u,n,a,i,l)}for(let[u,E]of Array.from(p))h.has(u)||(E.article.remove(),p.delete(u));if(y.length===0){if(!e.querySelector(".wf-io-empty-placeholder")){let u=document.createElement("div");u.className="empty wf-io-empty-placeholder",u.textContent=o("workflow.detail.noNodeIO"),e.appendChild(u)}}else e.querySelector(".wf-io-empty-placeholder")?.remove()}else{let u=[];for(let E of y)u.push(ys(E,n,a,i,l));e.innerHTML=u.length>0?u.join(""):`<div class="empty">${m(o("workflow.detail.noNodeIO"))}</div>`}Cs(e,s);let k=Ms(e,l);return As(e,n),Ds(e,s),xs(e,a),yo(e,i),k&&v}function ps(e){let t=new Map(e.activities.map(a=>[a.activityId,a])),n=new Set,s=[];for(let a of e.nodes){let i=(a.activityId?t.get(a.activityId):void 0)??e.activities.find(l=>l.ownerNodeId===a.nodeId);if(!i){s.push({key:`node:${a.nodeId}`,node:a});continue}n.add(i.activityId),s.push({key:`activity:${i.activityId}`,node:a,activity:i,io:e.attemptIO?.[ht(i)?.attemptId??""]})}for(let a of e.activities)n.has(a.activityId)||s.push({key:`activity:${a.activityId}`,activity:a,io:e.attemptIO?.[ht(a)?.attemptId??""]});return s}function ms(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 fs(e,t,n,s,a,i){let l=ht(t.activity),p=t.node?.nodeId??t.activity?.ownerNodeId??t.activity?.activityId??"unknown",v=!!(l&&l.attemptId===i);e.article.classList.toggle("is-focused",v),l?e.article.dataset.wfAttemptCard=l.attemptId:delete e.article.dataset.wfAttemptCard;let y=wo(l,s);e.head.innerHTML=`
|
|
953
958
|
<header>
|
|
954
959
|
<div>
|
|
955
960
|
<strong><code>${m(p)}</code></strong>
|
|
956
961
|
<span class="muted">${t.activity?m(t.activity.activityId):m(o("workflow.detail.notDispatched"))}</span>
|
|
957
962
|
</div>
|
|
958
|
-
<div>${t.node?
|
|
963
|
+
<div>${t.node?Ie(t.node.status):""} ${t.activity?Ie(t.activity.status):""}</div>
|
|
959
964
|
</header>
|
|
960
965
|
<div class="wf-io-meta">
|
|
961
966
|
${l?`${m(o("workflow.detail.attempt"))} <code>${m(l.attemptId)}</code>`:m(o("workflow.detail.noAttempt"))}
|
|
962
967
|
</div>
|
|
963
968
|
${y}
|
|
964
|
-
`;let h=
|
|
965
|
-
${
|
|
966
|
-
${
|
|
967
|
-
${
|
|
968
|
-
${
|
|
969
|
-
${t.io?.waitPrompt?
|
|
970
|
-
`}function
|
|
969
|
+
`;let h=uo(l,t.activity,t.io?.terminal,a),k=h?.url??null;if(k!==e.currentTerminalUrl)h===null?e.terminalSlot.innerHTML="":e.terminalSlot.innerHTML=po(t.key,l,t.activity,t.io?.terminal,h,n,a),e.currentTerminalUrl=k;else if(h!==null&&t.io?.terminal){let E=e.terminalSlot.querySelector("details.wf-terminal-block > summary");if(E){let q=mo(h.kind);E.innerHTML=`${m(q)} ${ho(l,t.io.terminal)}`}l&&Es(e.terminalSlot,l,t.activity,t.io.terminal,h,a)}let u=l?.attemptId??t.activity?.activityId??t.node?.nodeId??"unknown";e.grid.innerHTML=`
|
|
970
|
+
${ye(u,o("workflow.detail.authoredInput"),t.io?.input,n)}
|
|
971
|
+
${ye(u,o("workflow.detail.resolvedInput"),t.io?.resolvedInput,n)}
|
|
972
|
+
${ye(u,o("workflow.detail.output"),t.io?.output,n)}
|
|
973
|
+
${ye(u,o("workflow.detail.executionLog"),t.io?.log,n)}
|
|
974
|
+
${t.io?.waitPrompt?ye(u,o("workflow.detail.waitPrompt"),t.io.waitPrompt,n):""}
|
|
975
|
+
`}function uo(e,t,n,s){if(!n||n.error)return null;if(vs(e,n))return{kind:"live",url:$s(n)};if(!e||!t||!ks(e,n))return null;let a=Is();if(!a)return null;let i=s?.sessions.get(e.attemptId);return i?{kind:"resume",url:i.url,resumeId:i.resumeId,downloadUrl:ro(a,t.activityId,e.attemptId)}:{kind:"replay",url:Ss(a,t.activityId,e.attemptId,!!n.hasPtyLog),downloadUrl:ro(a,t.activityId,e.attemptId)}}function po(e,t,n,s,a,i,l){if(!s)return"";let p=mo(a.kind),v=Yt(e,p),y=ho(t,s),h=gs(a.kind),k=a.kind==="replay"||a.kind==="resume"?`<a class="btn-link" href="${m(a.downloadUrl)}" download>${m(o("workflow.detail.downloadFullLog"))}</a>`:"",u=t?go(t,n,s,a,l):"",E=t?bo(t.attemptId,l):"";return`<details class="wf-io-block wf-terminal-block" data-io-key="${m(v)}"${i.has(v)?" open":""}>
|
|
971
976
|
<summary>${m(p)} ${y}</summary>
|
|
972
977
|
<div class="wf-terminal-actions">
|
|
973
978
|
<a class="btn-link" href="${m(a.url)}" target="_blank" rel="noreferrer">${m(h)}</a>
|
|
@@ -976,14 +981,14 @@ ${Gn("manage")}
|
|
|
976
981
|
</div>
|
|
977
982
|
${E}
|
|
978
983
|
<iframe class="wf-terminal-frame" src="${m(a.url)}" title="${m(p)}" loading="lazy"></iframe>
|
|
979
|
-
</details>`}function
|
|
984
|
+
</details>`}function mo(e){return e==="live"?o("workflow.detail.liveTerminal"):e==="resume"?o("workflow.detail.terminalResume"):o("workflow.detail.terminalReplay")}function gs(e){return e==="live"?o("workflow.detail.openTerminalNewTab"):e==="resume"?o("workflow.detail.openResumeNewTab"):o("workflow.detail.openReplayNewTab")}var fo=new Set(["antigravity","codex-app","cursor","mira"]),bs=new Set(["aiden","coco","claude-code","seed","codex","mtr","hermes","pi"]);function hs(e){return!!e&&(bs.has(e)||fo.has(e))}function ws(e){return!!e&&fo.has(e)}function go(e,t,n,s,a){if(!a||s.kind==="live"||!t)return"";let i=s.kind==="resume",l=a.pending.has(e.attemptId),p=`data-wf-resume-attempt="${m(e.attemptId)}" data-wf-resume-activity="${m(t.activityId)}"`;return i?`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="end" ${p}${l?" disabled":""}>${m(l?o("workflow.detail.resumeEnding"):o("workflow.detail.endResumeSession"))}</button>`:hs(n.cliId)?ws(n.cliId)&&!n.cliSessionId?`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${m(o("workflow.detail.resumeMissingCliSession"))}">${m(o("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="start" ${p}${l?" disabled":""}>${m(l?o("workflow.detail.resumeStarting"):o("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${m(o("workflow.detail.resumeUnsupportedCli",{cliId:n.cliId??"?"}))}">${m(o("workflow.detail.resumeSession"))}</button>`}function bo(e,t){if(!t)return"";let n=t.errors.get(e);return n?`<div class="hint-warn wf-resume-status" data-wf-resume-status="${m(e)}">${m(n)}</div>`:""}function ys(e,t,n,s,a){let i=ht(e.activity),l=e.node?.nodeId??e.activity?.ownerNodeId??e.activity?.activityId??"unknown",p=i?.attemptId??e.activity?.activityId??e.node?.nodeId??"unknown",v=wo(i,n),y=i?.attemptId===a?" is-focused":"",h=i?` data-wf-attempt-card="${m(i.attemptId)}"`:"",k=uo(i,e.activity,e.io?.terminal,s),u=k?po(p,i,e.activity,e.io?.terminal,k,t,s):"";return`<article class="wf-io-card${y}" data-wf-card-key="${m(e.key)}"${h}>
|
|
980
985
|
<div class="wf-io-card-head">
|
|
981
986
|
<header>
|
|
982
987
|
<div>
|
|
983
988
|
<strong><code>${m(l)}</code></strong>
|
|
984
989
|
<span class="muted">${e.activity?m(e.activity.activityId):m(o("workflow.detail.notDispatched"))}</span>
|
|
985
990
|
</div>
|
|
986
|
-
<div>${e.node?
|
|
991
|
+
<div>${e.node?Ie(e.node.status):""} ${e.activity?Ie(e.activity.status):""}</div>
|
|
987
992
|
</header>
|
|
988
993
|
<div class="wf-io-meta">
|
|
989
994
|
${i?`${m(o("workflow.detail.attempt"))} <code>${m(i.attemptId)}</code>`:m(o("workflow.detail.noAttempt"))}
|
|
@@ -992,13 +997,13 @@ ${Gn("manage")}
|
|
|
992
997
|
</div>
|
|
993
998
|
<div class="wf-io-terminal-slot">${u}</div>
|
|
994
999
|
<div class="wf-io-grid">
|
|
995
|
-
${
|
|
996
|
-
${
|
|
997
|
-
${
|
|
998
|
-
${
|
|
999
|
-
${e.io?.waitPrompt?
|
|
1000
|
+
${ye(p,o("workflow.detail.authoredInput"),e.io?.input,t)}
|
|
1001
|
+
${ye(p,o("workflow.detail.resolvedInput"),e.io?.resolvedInput,t)}
|
|
1002
|
+
${ye(p,o("workflow.detail.output"),e.io?.output,t)}
|
|
1003
|
+
${ye(p,o("workflow.detail.executionLog"),e.io?.log,t)}
|
|
1004
|
+
${e.io?.waitPrompt?ye(p,o("workflow.detail.waitPrompt"),e.io.waitPrompt,t):""}
|
|
1000
1005
|
</div>
|
|
1001
|
-
</article>`}function
|
|
1006
|
+
</article>`}function ht(e){return e?.attempts[e.attempts.length-1]}function ho(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">${m(n.join(" \xB7 "))}</span>`}function vs(e,t){return t.status==="live"&&t.webPort>0&&(e?.status==="pending"||e?.status==="running"||e?.status==="effectAttempting")}function ks(e,t){return e.status==="succeeded"||e.status==="failed"||e.status==="cancelled"||e.status==="timedOut"?!!(t.sessionId||t.startedAt):!1}function $s(e){return`http://${window.location.hostname||"127.0.0.1"}:${e.webPort}`}function Ss(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 ro(e,t,n){return`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(t)}/${encodeURIComponent(n)}/terminal-log/raw?download=1`}function Is(){let e=window.location.hash.match(/^#\/workflows\/([^/?#]+)/);if(!e)return null;try{return decodeURIComponent(e[1])}catch{return null}}function wo(e,t){if(!Ts(e))return"";let n=e.attemptId,s=t.comments.get(n)??"",a=t.resolving.has(n),i=t.statuses.get(n),l=i?.kind==="error"?"hint-warn":"hint-ok";return`<div class="wf-approval-box" data-wf-approval="${m(n)}">
|
|
1002
1007
|
<label>
|
|
1003
1008
|
<span>${m(o("workflow.detail.approvalComment"))}</span>
|
|
1004
1009
|
<textarea class="wf-approval-comment" data-wf-approval-comment="${m(n)}" rows="2" placeholder="${m(o("workflow.detail.optionalComment"))}"${a?" disabled":""}>${m(s)}</textarea>
|
|
@@ -1009,120 +1014,120 @@ ${Gn("manage")}
|
|
|
1009
1014
|
${a?`<span class="muted">${m(o("workflow.detail.submitting"))}</span>`:""}
|
|
1010
1015
|
</div>
|
|
1011
1016
|
${i?`<div class="${l} wf-approval-status">${m(i.text)}</div>`:""}
|
|
1012
|
-
</div>`}function
|
|
1013
|
-
<summary>${m(t)} ${
|
|
1014
|
-
${
|
|
1015
|
-
</details>`}function
|
|
1017
|
+
</div>`}function Ts(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function Ls(e,t){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(n=>{let s=n.dataset.wfApprovalComment;s&&t.set(s,n.value)})}function yo(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,i=n.dataset.wfResumeAction;!s||!a||(i==="start"?t.onStart(s,a):i==="end"&&t.onEnd(s,a))}))})}function Es(e,t,n,s,a,i){let l=e.querySelector(".wf-terminal-actions");if(!l)return;let p=l.querySelector('button[data-wf-resume-button="1"]'),v=go(t,n,s,a,i);p?p.outerHTML=v:v&&l.insertAdjacentHTML("beforeend",v);let y=e.querySelector("details.wf-terminal-block");if(y){let h=y.querySelector(".wf-resume-status"),k=bo(t.attemptId,i);h?h.outerHTML=k:k&&l.insertAdjacentHTML("afterend",k)}yo(e,i)}function xs(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 ye(e,t,n,s){let a=Yt(e,t);return`<details class="wf-io-block" data-io-key="${m(a)}"${s.has(a)?" open":""}>
|
|
1018
|
+
<summary>${m(t)} ${Rs(n)}</summary>
|
|
1019
|
+
${Os(n)}
|
|
1020
|
+
</details>`}function Yt(e,t){return`${e}:${t}`}function Ms(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 Hs(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 i=s.querySelector(".wf-io-pre");i&&n.set(a,i.scrollTop)})}function As(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 Cs(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 i=n.querySelector(".wf-io-pre");i&&(i.scrollTop=a)})}function Ds(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 Rs(e){if(!e)return`<span class="muted">${m(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(yt(e.outputHash)),t.length?`<span class="muted">${m(t.join(" \xB7 "))}</span>`:""}function Os(e){if(!e)return`<div class="muted wf-io-empty">${m(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">${m(e.error)}</div>`:"";return t?`${n}<pre class="wf-io-pre">${m(t)}</pre>`:`${n}<div class="muted wf-io-empty">${m(o("workflow.detail.noPreview"))}</div>`}function Bs(e){let t=[];if(e.effectAttempted&&t.push(`${m(o("workflow.detail.effect"))} ${m(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(`${m(o("workflow.detail.wait"))} ${m(e.wait.waitKind)} ${m(n)}`),e.wait.deadlineAt!==void 0&&t.push(`${m(o("workflow.detail.deadline"))} ${m(wt(e.wait.deadlineAt))}`)}if(e.error){let n=`${e.error.errorCode}${e.error.errorClass?` \xB7 ${e.error.errorClass}`:""}`;t.push(`<span class="muted error">${m(n)}</span>`),e.error.errorMessage&&t.push(`<span class="error wf-error-msg">${m(e.error.errorMessage)}</span>`)}return e.output&&t.push(`${m(o("workflow.detail.output"))} ${m(yt(e.output.outputHash))}`),e.runningMs!==void 0&&t.push(`${e.runningMs}ms`),t.length>0?t.join("<br/>"):'<span class="muted">-</span>'}function qs(e,t){e.innerHTML=t.length>0?t.map(Ps).join(""):`<tr><td colspan="7" class="empty">${m(o("workflow.detail.noEvents"))}</td></tr>`}function Ps(e){let t=Ns(e.payload);return`<tr>
|
|
1016
1021
|
<td>${Xe(e.eventId)}</td>
|
|
1017
1022
|
<td><code>${m(e.type)}</code></td>
|
|
1018
1023
|
<td>${m(e.actor)}</td>
|
|
1019
1024
|
<td>${t.nodeId?`<code>${m(t.nodeId)}</code>`:"-"}</td>
|
|
1020
1025
|
<td>${t.activityId?`<code>${m(t.activityId)}</code>`:"-"}</td>
|
|
1021
1026
|
<td>${t.errorCode?`<span class="muted error">${m(t.errorCode)}</span>`:"-"}</td>
|
|
1022
|
-
<td title="${m(new Date(e.timestamp).toISOString())}">${m(
|
|
1023
|
-
</tr>`}function Xe(e){let t=e.lastIndexOf("-");if(t<0)return 0;let n=Number(e.slice(t+1));return Number.isFinite(n)?n:0}function
|
|
1027
|
+
<td title="${m(new Date(e.timestamp).toISOString())}">${m(wt(e.timestamp))}</td>
|
|
1028
|
+
</tr>`}function Xe(e){let t=e.lastIndexOf("-");if(t<0)return 0;let n=Number(e.slice(t+1));return Number.isFinite(n)?n:0}function Ns(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 Us(e){return!e.payload||typeof e.payload!="object"||"ref"in e.payload?null:e.payload}function lo(e,t,n){return Math.min(n,Math.max(t,e))}function yt(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function js(e,t){return e.length>t?e.slice(0,t-1)+"\u2026":e}function wt(e){return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}function A(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function vo(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function ko(e){let t=location.hash.match(/^#\/(?:workflows\/catalog|workflows-catalog)\/([^/?#]+)$/);return t?_s(e,decodeURIComponent(t[1])):zs(e)}function zs(e){e.innerHTML=`
|
|
1024
1029
|
<nav class="wf-subnav">
|
|
1025
|
-
<a href="#/workflows" data-i18n="workflow.subnav.runs">${
|
|
1026
|
-
<a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${
|
|
1030
|
+
<a href="#/workflows" data-i18n="workflow.subnav.runs">${A(o("workflow.subnav.runs"))}</a>
|
|
1031
|
+
<a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${A(o("workflow.subnav.catalog"))}</a>
|
|
1027
1032
|
</nav>
|
|
1028
1033
|
<section class="catalog-head">
|
|
1029
1034
|
<div>
|
|
1030
|
-
<h2>${
|
|
1031
|
-
<p class="muted">${
|
|
1035
|
+
<h2>${A(o("catalog.title"))}</h2>
|
|
1036
|
+
<p class="muted">${A(o("catalog.subtitle"))}</p>
|
|
1032
1037
|
</div>
|
|
1033
|
-
<button id="catalog-refresh" type="button">${
|
|
1038
|
+
<button id="catalog-refresh" type="button">${A(o("catalog.refresh"))}</button>
|
|
1034
1039
|
</section>
|
|
1035
1040
|
<form id="catalog-filters" class="filters">
|
|
1036
|
-
<input type="search" name="q" placeholder="${
|
|
1041
|
+
<input type="search" name="q" placeholder="${A(o("catalog.searchPlaceholder"))}" />
|
|
1037
1042
|
<span id="catalog-status" class="muted"></span>
|
|
1038
1043
|
</form>
|
|
1039
1044
|
<div class="wf-table-scroll">
|
|
1040
1045
|
<table>
|
|
1041
1046
|
<thead><tr>
|
|
1042
|
-
<th>${
|
|
1043
|
-
<th>${
|
|
1044
|
-
<th>${
|
|
1045
|
-
<th>${
|
|
1046
|
-
<th>${
|
|
1047
|
-
<th>${
|
|
1047
|
+
<th>${A(o("catalog.table.workflow"))}</th>
|
|
1048
|
+
<th>${A(o("catalog.table.version"))}</th>
|
|
1049
|
+
<th>${A(o("catalog.table.params"))}</th>
|
|
1050
|
+
<th>${A(o("catalog.table.nodes"))}</th>
|
|
1051
|
+
<th>${A(o("catalog.table.revision"))}</th>
|
|
1052
|
+
<th>${A(o("catalog.table.path"))}</th>
|
|
1048
1053
|
</tr></thead>
|
|
1049
1054
|
<tbody id="catalog-tbody"></tbody>
|
|
1050
1055
|
</table>
|
|
1051
1056
|
</div>
|
|
1052
|
-
`;let t=e.querySelector("#catalog-tbody"),n=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),a=e.querySelector("#catalog-refresh"),i=[],l=null,p=!1;function v(){let k=(new FormData(s).get("q")??"").trim().toLowerCase();return k?i.filter(u=>u.workflowId.toLowerCase().includes(k)||u.path.toLowerCase().includes(k)):i}function y(){l?(n.textContent=o("catalog.loadFailed",{error:l}),n.classList.add("error")):(n.textContent=`${i.length}`,n.classList.remove("error"));let k=v();if(k.length===0){t.innerHTML=`<tr><td colspan="6" class="empty">${i.length===0?
|
|
1057
|
+
`;let t=e.querySelector("#catalog-tbody"),n=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),a=e.querySelector("#catalog-refresh"),i=[],l=null,p=!1;function v(){let k=(new FormData(s).get("q")??"").trim().toLowerCase();return k?i.filter(u=>u.workflowId.toLowerCase().includes(k)||u.path.toLowerCase().includes(k)):i}function y(){l?(n.textContent=o("catalog.loadFailed",{error:l}),n.classList.add("error")):(n.textContent=`${i.length}`,n.classList.remove("error"));let k=v();if(k.length===0){t.innerHTML=`<tr><td colspan="6" class="empty">${i.length===0?A(o("catalog.noDefinitions")):A(o("catalog.noFilterMatch"))}</td></tr>`;return}t.innerHTML=k.map(u=>`
|
|
1053
1058
|
<tr>
|
|
1054
|
-
<td><a href="#/workflows/catalog/${encodeURIComponent(u.workflowId)}"><code>${
|
|
1059
|
+
<td><a href="#/workflows/catalog/${encodeURIComponent(u.workflowId)}"><code>${A(u.workflowId)}</code></a></td>
|
|
1055
1060
|
<td>${u.version}</td>
|
|
1056
|
-
<td>${
|
|
1061
|
+
<td>${A(o("catalog.paramSummary",{required:u.requiredParamCount,total:u.paramCount}))}</td>
|
|
1057
1062
|
<td>${u.nodeCount}</td>
|
|
1058
|
-
<td><code>${
|
|
1059
|
-
<td><code>${
|
|
1063
|
+
<td><code>${A(vo(u.revisionId))}</code></td>
|
|
1064
|
+
<td><code>${A(u.path)}</code></td>
|
|
1060
1065
|
</tr>
|
|
1061
|
-
`).join("")}async function h(){a.disabled=!0,n.textContent=o("catalog.loading");try{let k=await fetch("/api/workflows/definitions");if(!k.ok)throw new Error(`HTTP ${k.status}`);i=(await k.json()).definitions??[],l=null}catch(k){l=k?.message??String(k),i=[]}finally{a.disabled=!1,p||y()}}return s.addEventListener("input",y),a.addEventListener("click",()=>{h()}),h(),()=>{p=!0}}function
|
|
1066
|
+
`).join("")}async function h(){a.disabled=!0,n.textContent=o("catalog.loading");try{let k=await fetch("/api/workflows/definitions");if(!k.ok)throw new Error(`HTTP ${k.status}`);i=(await k.json()).definitions??[],l=null}catch(k){l=k?.message??String(k),i=[]}finally{a.disabled=!1,p||y()}}return s.addEventListener("input",y),a.addEventListener("click",()=>{h()}),h(),()=>{p=!0}}function _s(e,t){e.innerHTML=`
|
|
1062
1067
|
<div class="catalog-detail-head">
|
|
1063
|
-
<a class="btn-link" href="#/workflows/catalog">${
|
|
1068
|
+
<a class="btn-link" href="#/workflows/catalog">${A(o("catalog.back"))}</a>
|
|
1064
1069
|
<div>
|
|
1065
|
-
<h2><code>${
|
|
1066
|
-
<div id="catalog-detail-subtitle" class="muted">${
|
|
1070
|
+
<h2><code>${A(t)}</code></h2>
|
|
1071
|
+
<div id="catalog-detail-subtitle" class="muted">${A(o("workflow.detail.loading"))}</div>
|
|
1067
1072
|
</div>
|
|
1068
1073
|
</div>
|
|
1069
1074
|
<section id="catalog-error" class="hint-warn" hidden></section>
|
|
1070
1075
|
<section id="catalog-run-status" class="hint-ok" hidden></section>
|
|
1071
1076
|
<div id="catalog-detail-body"></div>
|
|
1072
|
-
`;let n=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),a=e.querySelector("#catalog-run-status"),i=e.querySelector("#catalog-detail-body"),l=null,p=!1,v=!1;function y(d){s.hidden=!d,s.textContent=d??""}function h(d){a.hidden=!d,a.textContent=d??""}function k(d){let f={};for(let[w,
|
|
1077
|
+
`;let n=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),a=e.querySelector("#catalog-run-status"),i=e.querySelector("#catalog-detail-body"),l=null,p=!1,v=!1;function y(d){s.hidden=!d,s.textContent=d??""}function h(d){a.hidden=!d,a.textContent=d??""}function k(d){let f={};for(let[w,I]of Object.entries(d??{}))"default"in I&&(f[w]=I.default);return f}function u(){if(!l)return;let d=l.definition;n.textContent=`${o("catalog.revision")} ${vo(l.revisionId)} \xB7 ${l.path}`;let f=JSON.stringify(k(d.params),null,2);i.innerHTML=`
|
|
1073
1078
|
<section class="wf-panel">
|
|
1074
|
-
<div class="wf-panel-title"><h3>${
|
|
1079
|
+
<div class="wf-panel-title"><h3>${A(o("catalog.summary"))}</h3></div>
|
|
1075
1080
|
<div class="wf-summary-grid">
|
|
1076
|
-
<div class="wf-summary-item"><span>${
|
|
1077
|
-
<div class="wf-summary-item"><span>${
|
|
1078
|
-
<div class="wf-summary-item"><span>${
|
|
1079
|
-
<div class="wf-summary-item"><span>${
|
|
1081
|
+
<div class="wf-summary-item"><span>${A(o("catalog.table.workflow"))}</span><strong><code>${A(d.workflowId)}</code></strong></div>
|
|
1082
|
+
<div class="wf-summary-item"><span>${A(o("catalog.table.version"))}</span><strong>${d.version}</strong></div>
|
|
1083
|
+
<div class="wf-summary-item"><span>${A(o("catalog.nodeCount"))}</span><strong>${Object.keys(d.nodes).length}</strong></div>
|
|
1084
|
+
<div class="wf-summary-item"><span>${A(o("catalog.path"))}</span><strong><code>${A(l.path)}</code></strong></div>
|
|
1080
1085
|
</div>
|
|
1081
1086
|
</section>
|
|
1082
1087
|
|
|
1083
1088
|
<section class="wf-panel">
|
|
1084
|
-
<div class="wf-panel-title"><h3>${
|
|
1089
|
+
<div class="wf-panel-title"><h3>${A(o("catalog.runPanel"))}</h3></div>
|
|
1085
1090
|
<form id="catalog-run-form" class="catalog-run-form">
|
|
1086
1091
|
<label>
|
|
1087
|
-
<span>${
|
|
1088
|
-
<textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${
|
|
1092
|
+
<span>${A(o("catalog.paramsJson"))}</span>
|
|
1093
|
+
<textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${A(o("catalog.paramsPlaceholder"))}">${A(f)}</textarea>
|
|
1089
1094
|
</label>
|
|
1090
1095
|
<div class="catalog-chat-grid">
|
|
1091
1096
|
<label>
|
|
1092
|
-
<span>${
|
|
1097
|
+
<span>${A(o("catalog.chatId"))}</span>
|
|
1093
1098
|
<input id="catalog-chat-id" type="text" autocomplete="off" />
|
|
1094
1099
|
</label>
|
|
1095
1100
|
<label>
|
|
1096
|
-
<span>${
|
|
1101
|
+
<span>${A(o("catalog.larkAppId"))}</span>
|
|
1097
1102
|
<input id="catalog-lark-app-id" type="text" autocomplete="off" />
|
|
1098
1103
|
</label>
|
|
1099
1104
|
</div>
|
|
1100
|
-
<div class="muted">${
|
|
1105
|
+
<div class="muted">${A(o("catalog.chatBindingHint"))}</div>
|
|
1101
1106
|
<div id="catalog-param-errors" class="catalog-param-errors" hidden></div>
|
|
1102
|
-
<button id="catalog-run-btn" type="submit" class="primary">${
|
|
1107
|
+
<button id="catalog-run-btn" type="submit" class="primary">${A(o("catalog.run"))}</button>
|
|
1103
1108
|
</form>
|
|
1104
1109
|
</section>
|
|
1105
1110
|
|
|
1106
1111
|
<section class="wf-panel">
|
|
1107
|
-
<div class="wf-panel-title"><h3>${
|
|
1108
|
-
${
|
|
1112
|
+
<div class="wf-panel-title"><h3>${A(o("catalog.paramsSchema"))}</h3></div>
|
|
1113
|
+
${Fs(d.params)}
|
|
1109
1114
|
</section>
|
|
1110
1115
|
|
|
1111
1116
|
<section class="wf-panel">
|
|
1112
|
-
<div class="wf-panel-title"><h3>${
|
|
1113
|
-
<pre class="wf-io-pre">${
|
|
1117
|
+
<div class="wf-panel-title"><h3>${A(o("catalog.definitionJson"))}</h3></div>
|
|
1118
|
+
<pre class="wf-io-pre">${A(JSON.stringify(d,null,2))}</pre>
|
|
1114
1119
|
</section>
|
|
1115
|
-
`,
|
|
1120
|
+
`,q()}async function E(){if(!l||v)return;let d=i.querySelector("#catalog-params"),f=i.querySelector("#catalog-chat-id"),w=i.querySelector("#catalog-lark-app-id"),I=i.querySelector("#catalog-run-btn"),x=i.querySelector("#catalog-param-errors"),M;try{if(M=JSON.parse(d.value||"{}"),!M||typeof M!="object"||Array.isArray(M))throw new Error(o("catalog.badParamsJson"))}catch(H){x.hidden=!1,x.innerHTML=`<div class="muted error">${A(H?.message??String(H))}</div>`;return}v=!0,I.disabled=!0,I.textContent=o("catalog.running"),x.hidden=!0,y(null),h(null);try{let H=await fetch(`/api/workflows/definitions/${encodeURIComponent(l.definition.workflowId)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({params:M,chatBinding:{chatId:f.value.trim(),larkAppId:w.value.trim()}})});if(H.status===401)throw new Error(o("catalog.writeAccess"));let O=await H.json().catch(()=>({}));if(!H.ok||!O.ok)throw O.issues?.length&&(x.hidden=!1,x.innerHTML=`<strong>${A(o("catalog.invalidParams"))}</strong><ul>${O.issues.map(z=>`<li>${A(o("catalog.issue",{path:z.path.length?z.path.join("."):"(root)",message:z.message}))}</li>`).join("")}</ul>`),new Error(O.hint??O.message??O.error??o("catalog.runHttp",{status:H.status}));h(o("catalog.runStarted")),O.runId&&(location.hash=`#/workflows/${encodeURIComponent(O.runId)}`)}catch(H){y(H?.message??String(H))}finally{v=!1,I.disabled=!1,I.textContent=o("catalog.run")}}function q(){i.querySelector("#catalog-run-form")?.addEventListener("submit",f=>{f.preventDefault(),E()})}async function $(){try{let d=await fetch(`/api/workflows/definitions/${encodeURIComponent(t)}`);if(d.status===404)throw new Error("unknown_workflow");if(!d.ok)throw new Error(`HTTP ${d.status}`);l=await d.json(),y(null),u()}catch(d){y(o("catalog.definitionLoadFailed",{error:d?.message??String(d)})),n.textContent=o("workflow.detail.loadFailed")}}return $().then(()=>{}),()=>{p=!0}}function Fs(e){let t=Object.entries(e??{});return t.length===0?`<div class="muted">${A(o("catalog.noParams"))}</div>`:`<div class="catalog-param-list">${t.map(([n,s])=>`
|
|
1116
1121
|
<article class="catalog-param">
|
|
1117
1122
|
<header>
|
|
1118
|
-
<code>${
|
|
1119
|
-
<span class="wf-status">${
|
|
1120
|
-
<span class="muted">${
|
|
1123
|
+
<code>${A(n)}</code>
|
|
1124
|
+
<span class="wf-status">${A(s.required?o("catalog.required"):o("catalog.optional"))}</span>
|
|
1125
|
+
<span class="muted">${A(s.type)}${s.format?` \xB7 ${A(s.format)}`:""}</span>
|
|
1121
1126
|
</header>
|
|
1122
|
-
${s.description?`<div class="muted">${
|
|
1123
|
-
${"default"in s?`<pre class="wf-io-pre">${
|
|
1127
|
+
${s.description?`<div class="muted">${A(o("catalog.description"))}: ${A(s.description)}</div>`:""}
|
|
1128
|
+
${"default"in s?`<pre class="wf-io-pre">${A(`${o("catalog.default")}: ${JSON.stringify(s.default,null,2)}`)}</pre>`:""}
|
|
1124
1129
|
</article>
|
|
1125
|
-
`).join("")}</div>`}var
|
|
1130
|
+
`).join("")}</div>`}var Oe=null,vt=null;function et(){vt!==null&&(window.clearInterval(vt),vt=null)}function Xt(){return Oe||(Oe=document.createElement("dialog"),Oe.className="onboarding-dialog",document.body.appendChild(Oe),Oe.addEventListener("close",et),Oe)}function Ws(e){return e.status==="waiting_for_scan"?o("botOnboarding.waiting"):e.status==="verifying"?o("botOnboarding.verifying"):e.status==="configuring_permissions"?e.permissionStatusMsg?`${o("botOnboarding.configuringPermissions")} ${e.permissionStatusMsg}`:o("botOnboarding.configuringPermissions"):e.status==="waiting_for_platform_scan"?o("botOnboarding.platformScanHint"):e.status==="completed"?o("botOnboarding.completed"):e.status==="failed"?`${o("botOnboarding.failed")}: ${r(e.message??e.error??"unknown")}`:o("botOnboarding.starting")}function Gs(e){if(e.status!=="completed"||!e.permission)return"";let t=e.permission;if(t.ok){let s=[o("botOnboarding.permissionOk",{count:t.scopeCount??0})];t.skippedScopeCount&&t.skippedScopeCount>0&&s.push(o("botOnboarding.permissionSkipped",{count:t.skippedScopeCount})),t.versionId&&s.push(o("botOnboarding.permissionVersion",{version:r(t.versionId)}));let a=`<p class="hint-ok">\u2705 ${s.join(" ")}</p>`;return t.scopeWarning&&(a+=`<p class="hint-warn">\u26A0\uFE0F ${r(t.scopeWarning)}</p>`),a}let n=(e.remainingSteps??[]).map(s=>`<li><a href="${r(s.url)}" target="_blank" rel="noopener">${r(s.title)}</a></li>`).join("");return`<p class="hint-warn">\u26A0\uFE0F ${o("botOnboarding.permissionManual")}${t.message?`\uFF08${r(t.message)}\uFF09`:""}</p>`+(n?`<ol class="onboarding-steps">${n}</ol>`:"")}function Ze(e){let t=Xt(),n=e.status==="waiting_for_scan"&&e.qrDataUrl?`<div class="qr-card">
|
|
1126
1131
|
<img class="qr-image" src="${e.qrDataUrl}" alt="${o("botOnboarding.qrAlt")}">
|
|
1127
1132
|
${e.qrUrl?`<a class="onboarding-link" href="${r(e.qrUrl)}" target="_blank" rel="noopener">${o("botOnboarding.openLink")}</a>`:""}
|
|
1128
1133
|
</div>`:"",s=e.status==="waiting_for_platform_scan"&&e.platformQrDataUrl?`<div class="qr-card">
|
|
@@ -1132,14 +1137,14 @@ ${Gn("manage")}
|
|
|
1132
1137
|
<h3>${o("botOnboarding.title")}</h3>
|
|
1133
1138
|
<p>${o("botOnboarding.intro")}</p>
|
|
1134
1139
|
</header>
|
|
1135
|
-
<p class="onboarding-status status-${e.status}">${
|
|
1140
|
+
<p class="onboarding-status status-${e.status}">${Ws(e)}</p>
|
|
1136
1141
|
${n}
|
|
1137
1142
|
${s}
|
|
1138
1143
|
${a}
|
|
1139
|
-
${
|
|
1144
|
+
${Gs(e)}
|
|
1140
1145
|
${i}
|
|
1141
1146
|
<form method="dialog"><button>${o("botOnboarding.close")}</button></form>
|
|
1142
|
-
</article>`}async function
|
|
1147
|
+
</article>`}async function Js(){try{let e=await fetch("/api/cli-options"),t=await e.json();if(e.ok&&Array.isArray(t?.options))return t.options}catch{}return[{id:"claude-code",label:"Claude"}]}function Qt(e,t){let n=Xt(),s=e.map(p=>`<option value="${r(p.id)}">${r(p.label)}\uFF08${r(p.id)}\uFF09</option>`).join(""),a=t?`<p class="form-error">${r(t)}</p>`:"";n.innerHTML=`<article>
|
|
1143
1148
|
<header>
|
|
1144
1149
|
<h3>${o("botOnboarding.title")}</h3>
|
|
1145
1150
|
<p>${o("botOnboarding.intro")}</p>
|
|
@@ -1163,8 +1168,8 @@ ${Gn("manage")}
|
|
|
1163
1168
|
<button type="submit" class="primary">${o("botOnboarding.startScan")}</button>
|
|
1164
1169
|
</menu>
|
|
1165
1170
|
</form>
|
|
1166
|
-
</article>`;let i=n.querySelector("#onboarding-form");n.querySelector("#ob-cancel")?.addEventListener("click",()=>n.close()),i?.addEventListener("submit",p=>{p.preventDefault();let v=n.querySelector("#ob-cli")?.value??"",y=n.querySelector("#ob-dir")?.value??"",h=n.querySelector("#ob-model")?.value??"";
|
|
1171
|
+
</article>`;let i=n.querySelector("#onboarding-form");n.querySelector("#ob-cancel")?.addEventListener("click",()=>n.close()),i?.addEventListener("submit",p=>{p.preventDefault();let v=n.querySelector("#ob-cli")?.value??"",y=n.querySelector("#ob-dir")?.value??"",h=n.querySelector("#ob-model")?.value??"";Ks({cliId:v,workingDir:y,model:h},e)})}async function Ks(e,t){et(),Ze({id:"",status:"starting"});try{let n=await fetch("/api/bot-onboarding/start",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({cliId:e.cliId,workingDir:e.workingDir.trim(),model:e.model.trim()||void 0})}),s=await n.json();if(n.status===400){Qt(t,s?.message??s?.error??"invalid_input");return}if(!n.ok||!s?.job?.id)throw new Error(s?.error??`http_${n.status}`);Ze(s.job),vt=window.setInterval(()=>{Vs(s.job.id).catch(a=>{et(),Ze({id:s.job.id,status:"failed",message:a instanceof Error?a.message:String(a)})})},1200)}catch(n){Ze({id:"",status:"failed",message:n instanceof Error?n.message:String(n)})}}async function Vs(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}`);Ze(n.job),(n.job.status==="completed"||n.job.status==="failed")&&et()}async function Ys(){et();let e=Xt();Qt([{id:"claude-code",label:"Claude"}]),e.open||e.showModal();let t=await Js();e.open&&e.querySelector("#onboarding-form")&&Qt(t)}function $o(){let e=document.getElementById("add-bot-btn");e&&(e.onclick=()=>{Ys()})}var Qs={monitor:'<rect width="20" height="14" x="2" y="3" rx="2"/><line x1="8" x2="16" y1="21" y2="21"/><line x1="12" x2="12" y1="17" y2="21"/>',sun:'<circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/>',moon:'<path d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"/>',cpu:'<path d="M12 20v2"/><path d="M12 2v2"/><path d="M17 20v2"/><path d="M17 2v2"/><path d="M2 12h2"/><path d="M2 17h2"/><path d="M2 7h2"/><path d="M20 12h2"/><path d="M20 17h2"/><path d="M20 7h2"/><path d="M7 20v2"/><path d="M7 2v2"/><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="8" y="8" width="8" height="8" rx="1"/>',sparkles:'<path d="M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z"/><path d="M20 2v4"/><path d="M22 4h-4"/><circle cx="4" cy="20" r="2"/>',zap:'<path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z"/>',terminal:'<path d="M12 19h8"/><path d="m4 17 6-6-6-6"/>',keyRound:'<path d="M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z"/><circle cx="16.5" cy="7.5" r=".5" fill="currentColor"/>',network:'<rect x="16" y="16" width="6" height="6" rx="1"/><rect x="2" y="16" width="6" height="6" rx="1"/><rect x="9" y="2" width="6" height="6" rx="1"/><path d="M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3"/><path d="M12 12V8"/>',swords:'<polyline points="14.5 17.5 3 6 3 3 6 3 17.5 14.5"/><line x1="13" x2="19" y1="19" y2="13"/><line x1="16" x2="20" y1="16" y2="20"/><line x1="19" x2="21" y1="21" y2="19"/><polyline points="14.5 6.5 18 3 21 3 21 6 17.5 9.5"/><line x1="5" x2="9" y1="14" y2="18"/><line x1="7" x2="4" y1="17" y2="20"/><line x1="3" x2="5" y1="19" y2="21"/>',flame:'<path d="M12 3q1 4 4 6.5t3 5.5a1 1 0 0 1-14 0 5 5 0 0 1 1-3 1 1 0 0 0 5 0c0-2-1.5-3-1.5-5q0-2 2.5-4"/>',ball:'<path d="M11 7a16 16 20 0 1 10.98 4.362"/><path d="M12 12a13 13 0 0 1-8.66 5"/><path d="M16.83 13.634a16 16 0 0 1-9.267 7.328"/><path d="M20.66 17A13 13 0 0 0 12 12a13 13 0 0 1 0-10"/><path d="M8.17 15.366a16 16 0 0 1-1.713-11.69"/><circle cx="12" cy="12" r="10"/>',chevron:'<path d="m6 9 6 6 6-6"/>'},Io=[{labelKey:"theme.base",options:[{value:"system",labelKey:"status.system",icon:"monitor"},{value:"light",labelKey:"status.light",icon:"sun"},{value:"dark",labelKey:"status.dark",icon:"moon"}]},{labelKey:"theme.skins",options:[{value:"cyber",labelKey:"skin.cyber",icon:"cpu"},{value:"genshin",labelKey:"skin.genshin",icon:"sparkles"},{value:"fallout",labelKey:"skin.fallout",icon:"zap"},{value:"prts",labelKey:"skin.prts",icon:"terminal"},{value:"bluearchive",labelKey:"skin.bluearchive",icon:"keyRound"},{value:"zzz",labelKey:"skin.zzz",icon:"network"},{value:"dragonball",labelKey:"skin.dragonball",icon:"flame"},{value:"ikun",labelKey:"skin.ikun",icon:"ball"}]}],So=Io.flatMap(e=>e.options),Be=!1;function Zt(e){return`<svg class="tm-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${Qs[e]??""}</svg>`}function Xs(e){return e.replace(/[&<>"]/g,t=>({"&":"&","<":"<",">":">",'"':"""})[t])}function To(){let e=document.getElementById("theme-menu"),t=document.getElementById("theme-menu-btn"),n=document.getElementById("theme-menu-pop");if(!e||!t||!n)return;n.innerHTML=Io.map(a=>`<div class="tm-group" data-label-key="${a.labelKey}"></div>`+a.options.map(i=>`<button type="button" class="tm-item" role="option" data-value="${i.value}"><span class="tm-ic">${Zt(i.icon)}</span><span class="tm-label" data-label-key="${i.labelKey}"></span></button>`).join("")).join("");let s=a=>{Be=a,n.hidden=!Be,t.setAttribute("aria-expanded",String(Be)),e.classList.toggle("open",Be)};t.addEventListener("click",a=>{a.stopPropagation(),s(!Be)}),n.addEventListener("click",a=>{let i=a.target.closest(".tm-item");i&&(me.setTheme(i.dataset.value??"system"),s(!1))}),document.addEventListener("click",a=>{Be&&!e.contains(a.target)&&s(!1)}),document.addEventListener("keydown",a=>{a.key==="Escape"&&Be&&s(!1)}),en()}function en(){let e=document.getElementById("theme-menu-btn");if(!e)return;let t=So.find(n=>n.value===me.theme)??So[0];e.innerHTML=`<span class="tm-ic">${Zt(t.icon)}</span><span class="tm-current">${Xs(o(t.labelKey))}</span><span class="tm-chev">${Zt("chevron")}</span>`,document.querySelectorAll("#theme-menu-pop [data-label-key]").forEach(n=>{n.textContent=o(n.dataset.labelKey??"")}),document.querySelectorAll("#theme-menu-pop .tm-item").forEach(n=>{n.classList.toggle("active",n.dataset.value===me.theme)})}var le=document.getElementById("root"),kt=!0,xo=!1,Mo=["roles","bot-defaults","team","connectors"],tn=!1;function Zs(){if(tn)return;tn=!0;let e=document.createElement("div");e.id="auth-expired-overlay",e.style.cssText="position:fixed;inset:0;background:rgba(0,0,0,.65);display:flex;align-items:center;justify-content:center;z-index:9999",e.innerHTML='<div style="background:var(--surface);color:var(--fg);border:1px solid var(--border);border-radius:12px;padding:36px 40px;max-width:460px;width:90vw;text-align:center;box-shadow:0 12px 40px rgba(0,0,0,.35)"><h2 style="margin:0 0 14px;font-size:19px;color:var(--fg)">\u8BBF\u95EE\u94FE\u63A5\u5DF2\u5931\u6548</h2><p style="margin:0 0 24px;line-height:1.7;color:var(--muted,#8f959e);font-size:14px">\u5F53\u524D\u94FE\u63A5/\u8BBF\u95EE\u5DF2\u5931\u6548\uFF0C\u8BF7\u4F7F\u7528\u6700\u65B0\u6388\u6743\u94FE\u63A5\u91CD\u65B0\u8FDB\u5165\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09\u3002</p><button id="auth-expired-dismiss" type="button" style="padding:8px 22px;background:var(--accent);color:var(--on-accent);border:none;border-radius:8px;cursor:pointer;font-size:14px">\u77E5\u9053\u4E86</button></div>',document.body.appendChild(e);let t=()=>{e.remove(),tn=!1};e.querySelector("#auth-expired-dismiss")?.addEventListener("click",t),e.addEventListener("click",n=>{n.target===e&&t()})}var nn;function ei(){let e=document.getElementById("readonly-toast");e||(e=document.createElement("div"),e.id="readonly-toast",e.style.cssText="position:fixed;left:50%;bottom:28px;transform:translateX(-50%);z-index:9999;background:var(--fg,#1f2329);color:var(--bg,#fff);padding:10px 18px;border-radius:8px;font-size:13px;box-shadow:0 8px 24px rgba(0,0,0,.25)",document.body.appendChild(e)),e.textContent="\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u6B64\u64CD\u4F5C\u9700\u8981\u6388\u6743\u94FE\u63A5\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09",e.style.display="block",nn&&window.clearTimeout(nn),nn=window.setTimeout(()=>{e.style.display="none"},4e3)}var ti=window.fetch.bind(window);window.fetch=async function(...t){let n=await ti(...t);if(n.status===401){let s=(t[1]?.method??"GET").toUpperCase();(s==="GET"||s==="HEAD")&&!xo?Zs():ei()}return n};var on="";function $t(){let e=document.getElementById("attention-strip");if(!e)return;let t=[...G.sessions.values()].map(a=>({s:a,reason:Te(a)})).filter(a=>!!a.reason).sort((a,i)=>Number(a.s.lastMessageAt??0)-Number(i.s.lastMessageAt??0));if(t.length===0){e.hidden=!0,e.innerHTML="",on="";return}let n=t[0],s=`
|
|
1167
1172
|
<span class="attention-strip-ic" aria-hidden="true">!</span>
|
|
1168
1173
|
<b>${r(o("strip.pending",{count:t.length}))}</b>
|
|
1169
|
-
<span class="attention-strip-longest">${r(o("strip.longest",{time:ue(n.s.lastMessageAt),bot:
|
|
1170
|
-
<a class="attention-strip-go" href="#/sessions">${r(o("strip.handle"))}</a>`;e.hidden=!1,s!==
|
|
1174
|
+
<span class="attention-strip-longest">${r(o("strip.longest",{time:ue(n.s.lastMessageAt),bot:ge(n.s),reason:n.reason}))}</span>
|
|
1175
|
+
<a class="attention-strip-go" href="#/sessions">${r(o("strip.handle"))}</a>`;e.hidden=!1,s!==on&&(on=s,e.innerHTML=s)}G.on($t);fe().then($t);async function ni(){try{let e=await fetch("/api/settings");if(e.ok){let t=await e.json();kt=!!t.authed,xo=!!(t.settings&&t.settings.publicReadOnly)}}catch{}}function oi(){for(let t of Mo){let n=document.querySelector(`.sidebar-nav a[data-route="${t}"]`);n&&(n.style.display=kt?"":"none")}let e=document.getElementById("add-bot-btn");e&&(e.style.display=kt?"":"none")}function ai(e){e.innerHTML='<section class="auth-required" style="max-width:520px;margin:64px auto;text-align:center;background:var(--surface);color:var(--fg);border:1px solid var(--border);border-radius:14px;padding:40px 36px;box-shadow:0 8px 28px rgba(0,0,0,.12)"><h2 style="margin:0 0 12px;font-size:20px;color:var(--fg)">\u6B64\u9875\u9700\u8981\u6388\u6743\u94FE\u63A5</h2><p style="margin:0 0 24px;line-height:1.7;color:var(--muted);font-size:14px">\u4F60\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u7BA1\u7406\u9875\uFF08\u89D2\u8272 / Bot \u914D\u7F6E / \u56E2\u961F / \u63A5\u5165\u70B9\uFF09\u9700\u8981\u6388\u6743\u94FE\u63A5\u3002\u8FD0\u884C <code>botmux dashboard</code> \u83B7\u53D6\u6700\u65B0\u94FE\u63A5\u540E\u5373\u53EF\u7BA1\u7406\u3002</p><a href="#/" style="display:inline-block;padding:8px 22px;background:var(--accent);color:var(--on-accent);border-radius:8px;text-decoration:none;font-size:14px">\u8FD4\u56DE\u603B\u89C8</a></section>'}var tt=null;function Lo(e){for(let t of document.querySelectorAll(".sidebar-nav a")){let n=t.getAttribute("href")??"#/";t.classList.toggle("active",n===(e||"#/"))}}function an(){tt&&(tt(),tt=null);let e=location.hash||"#/";if(!kt&&Mo.some(t=>e.startsWith("#/"+t))){ai(le),Lo(e);return}e.startsWith("#/workflows/catalog")||e.startsWith("#/workflows-catalog")?tt=ko(le):e.startsWith("#/workflows")?tt=co(le):e.startsWith("#/groups")?jn(le):e.startsWith("#/settings")?so(le):e.startsWith("#/bot-defaults")?Wn(le):e.startsWith("#/connectors")?ao(le):e.startsWith("#/team/manage")?to(le):e.startsWith("#/team")?eo(le):e.startsWith("#/roles")?Vn(le):e.startsWith("#/schedules")?Nn(le):e.startsWith("#/sessions")?qn(le):Dn(le),Lo(e)}var sn=document.getElementById("status");function Ho(){sn&&(sn.textContent=G.online?o("status.live"):o("status.disconnected"),sn.className="connection-status "+(G.online?"online":"offline"))}G.on(Ho);function Eo(){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===me.locale)}),en(),Ho()}function si(){document.querySelectorAll("[data-locale]").forEach(e=>{e.onclick=()=>me.setLocale(e.dataset.locale)}),To()}(async()=>{me.init(),si(),$o(),me.on(()=>{Eo(),$t(),an()}),Eo(),$t(),await ni(),oi();try{await ln()}catch(e){console.error("botmux dashboard bootstrap failed",e),G.setOnline(!1)}window.addEventListener("hashchange",an),an()})();})();
|