botmux 2.76.1 → 2.77.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/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +2 -1
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +40 -38
- package/dist/core/session-manager.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +5 -4
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +10 -0
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/settings.d.ts.map +1 -1
- package/dist/dashboard/web/settings.js +19 -0
- package/dist/dashboard/web/settings.js.map +1 -1
- package/dist/dashboard-web/app.js +111 -100
- package/dist/dashboard.js +11 -2
- package/dist/dashboard.js.map +1 -1
- package/dist/global-config.d.ts +11 -0
- package/dist/global-config.d.ts.map +1 -1
- package/dist/global-config.js +13 -0
- package/dist/global-config.js.map +1 -1
- package/dist/services/project-scanner.d.ts +5 -2
- package/dist/services/project-scanner.d.ts.map +1 -1
- package/dist/services/project-scanner.js +9 -6
- package/dist/services/project-scanner.js.map +1 -1
- package/dist/services/resumable-session-discovery.d.ts.map +1 -1
- package/dist/services/resumable-session-discovery.js +8 -4
- package/dist/services/resumable-session-discovery.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
"use strict";(()=>{var bn=class{sessions=new Map;schedules=new Map;online=!0;listeners=new Set;upsertSessions(n){for(let a of n)this.sessions.set(a.sessionId,a);this.emit()}upsertSchedules(n){for(let a of n)this.schedules.set(a.id,a);this.emit()}applySse(n,a){if(n==="session.spawned")this.sessions.set(a.session.sessionId,a.session);else if(n==="session.update"){let s=this.sessions.get(a.sessionId);s&&this.sessions.set(a.sessionId,{...s,...a.patch})}else if(n==="session.exited"){let s=this.sessions.get(a.sessionId);s&&this.sessions.set(a.sessionId,{...s,status:"closed"})}else if(n==="schedule.created")this.schedules.set(a.schedule.id,a.schedule);else if(n==="schedule.updated"){let s=this.schedules.get(a.id);s&&this.schedules.set(a.id,{...s,...a.patch})}else if(n==="schedule.deleted")this.schedules.delete(a.id);else return;this.emit()}setOnline(n){this.online!==n&&(this.online=n,this.emit())}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}},V=new bn;async function ua(){let[e,n]=await Promise.all([fetch("/api/sessions").then(o=>o.json()),fetch("/api/schedules").then(o=>o.json())]);V.upsertSessions(e.sessions??[]),V.upsertSchedules(n.schedules??[]);let a=new EventSource("/events"),s=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let o of s)a.addEventListener(o,r=>{try{let c=JSON.parse(r.data);V.applySse(o,c.body??c)}catch{}});a.onerror=()=>V.setOnline(!1),a.onopen=()=>V.setOnline(!0)}var hn="botmux.dashboard.locale",rs={"app.name":"botmux","app.subtitle":"\u98DE\u4E66 AI CLI \u63A7\u5236\u53F0","time.secondsAgo":"{value} \u79D2\u524D","time.minutesAgo":"{value} \u5206\u949F\u524D","time.hoursAgo":"{value} \u5C0F\u65F6\u524D","nav.overview":"\u603B\u89C8","nav.sessions":"\u4F1A\u8BDD","nav.sidebarCollapse":"\u6536\u8D77\u83DC\u5355\u680F","nav.sidebarExpand":"\u5C55\u5F00\u83DC\u5355\u680F","nav.groups":"\u7FA4\u7EC4","nav.schedules":"\u5B9A\u65F6","nav.settings":"\u8BBE\u7F6E","nav.botDefaults":"Bot \u914D\u7F6E","status.live":"\u5B9E\u65F6\u8FDE\u63A5","status.disconnected":"\u8FDE\u63A5\u65AD\u5F00","status.system":"\u7CFB\u7EDF","status.light":"\u6D45\u8272","status.dark":"\u6697\u9ED1","status.language":"\u8BED\u8A00","status.theme":"\u4E3B\u9898","theme.base":"\u57FA\u7840","theme.skins":"\u4E3B\u9898\u76AE\u80A4","skin.cyber":"2077","skin.genshin":"\u539F\u795E","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"\u851A\u84DD\u6863\u6848","skin.zzz":"\u7EDD\u533A\u96F6","skin.dragonball":"\u4E03\u9F99\u73E0","skin.ikun":"ikun","botOnboarding.add":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.title":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.intro":"\u9009\u62E9 CLI \u4E0E\u5DE5\u4F5C\u76EE\u5F55\uFF0C\u626B\u7801\u521B\u5EFA PersonalAgent \u5E94\u7528\u540E\u5199\u5165\u672C\u673A bots.json\uFF0C\u5E76\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u3002","botOnboarding.cliLabel":"CLI \u9002\u914D\u5668","botOnboarding.dirLabel":"\u5DE5\u4F5C\u76EE\u5F55","botOnboarding.dirPlaceholder":"\u9ED8\u8BA4 ~\uFF08\u5BB6\u76EE\u5F55\uFF09\uFF0C\u9700\u4E3A daemon \u4E3B\u673A\u4E0A\u5DF2\u5B58\u5728\u7684\u76EE\u5F55","botOnboarding.modelLabel":"\u6A21\u578B\uFF08\u53EF\u9009\uFF09","botOnboarding.modelPlaceholder":"\u7559\u7A7A\u4F7F\u7528\u8BE5 CLI \u7684\u9ED8\u8BA4\u6A21\u578B","botOnboarding.startScan":"\u5F00\u59CB\u626B\u7801","botOnboarding.cancel":"\u53D6\u6D88","botOnboarding.starting":"\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...","botOnboarding.waiting":"\u8BF7\u7528\u98DE\u4E66 App \u626B\u7801\u786E\u8BA4\u521B\u5EFA\u5E94\u7528\u3002","botOnboarding.verifying":"\u626B\u7801\u6210\u529F\uFF0C\u6B63\u5728\u6821\u9A8C\u51ED\u8BC1...","botOnboarding.configuringPermissions":"\u6B63\u5728\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u2026","botOnboarding.platformScanHint":"\u8BF7\u7528\u98DE\u4E66 App \u518D\u626B\u4E00\u6B21\u7801\u767B\u5F55\u5F00\u653E\u5E73\u53F0\uFF08\u7528\u4E8E\u81EA\u52A8\u5BFC\u5165\u6743\u9650\u3001\u914D\u7F6E\u56DE\u8C03\u3001\u63D0\u4EA4\u7248\u672C\uFF09\u3002","botOnboarding.platformQrAlt":"\u5F00\u653E\u5E73\u53F0\u767B\u5F55\u4E8C\u7EF4\u7801","botOnboarding.completed":"\u673A\u5668\u4EBA\u5DF2\u6DFB\u52A0\u3002","botOnboarding.permissionOk":"\u5DF2\u81EA\u52A8\u5BFC\u5165 {count} \u9879\u6743\u9650\u3002","botOnboarding.permissionSkipped":"\uFF08\u8DF3\u8FC7 {count} \u9879\u5F53\u524D\u79DF\u6237\u76EE\u5F55\u4E2D\u6CA1\u6709\u7684\u6743\u9650\uFF09","botOnboarding.permissionVersion":"\u5DF2\u63D0\u4EA4\u53D1\u5E03\u7248\u672C {version}\u3002","botOnboarding.permissionManual":"\u6743\u9650\u672A\u80FD\u81EA\u52A8\u914D\u7F6E\uFF0C\u8BF7\u624B\u52A8\u5B8C\u6210\u4EE5\u4E0B\u6B65\u9AA4\uFF1A","botOnboarding.metaDir":"\u76EE\u5F55","botOnboarding.failed":"\u6DFB\u52A0\u5931\u8D25","botOnboarding.openLink":"\u6253\u4E0D\u5F00\u626B\u7801\uFF1F\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00","botOnboarding.close":"\u5173\u95ED","botOnboarding.restartHint":"\u5DF2\u5199\u5165 bots.json\u3002\u6267\u884C pnpm daemon:restart \u540E\u65B0\u673A\u5668\u4EBA\u751F\u6548\u3002","botOnboarding.qrAlt":"\u98DE\u4E66\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA\u4E8C\u7EF4\u7801","overview.title":"\u5DE5\u4F5C\u53F0","overview.subtitle":"\u6570\u5B57\u5458\u5DE5\u5B9E\u65F6\u72B6\u6001 \xB7 \u540C\u6B65\u98DE\u4E66\u8BDD\u9898","overview.team":"AI \u56E2\u961F","overview.teamHint":"\u6BCF\u4F4D\u6570\u5B57\u5458\u5DE5\u7684\u5B9E\u65F6\u72B6\u6001","overview.attention":"\u9700\u8981\u4F60\u5904\u7406","overview.attentionHint":"\u5361\u4F4F\u7684\u4EFB\u52A1\uFF0C\u56DE\u4E2A\u8BDD\u5C31\u80FD\u7EE7\u7EED\u8DD1","overview.activeSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.activeSessionsHint":"\u6B63\u5728\u8FD0\u8F6C\u7684\u4F1A\u8BDD","overview.today":"\u6B64\u523B\u6982\u89C8","overview.todayHint":"\u6D3B\u8DC3\u4F1A\u8BDD\u5206\u5E03","overview.viewAll":"\u67E5\u770B\u5168\u90E8 \u2192","overview.botIdle":"\u5F85\u547D\u4E2D\uFF0C\u968F\u65F6\u53EF\u63A5\u65B0\u4EFB\u52A1","overview.botOffline":"\u79BB\u7EBF \u2014 daemon \u672A\u4E0A\u7EBF","overview.botBusy":"\u6267\u884C\u4E2D \xB7 {count} \u4F1A\u8BDD","overview.botNeedsYou":"\u7B49\u4F60\u56DE\u590D","overview.botReady":"\u5C31\u7EEA","overview.botOff":"\u79BB\u7EBF","overview.sessionsCount":"{count} \u4F1A\u8BDD","overview.lastActive":"{time}\u524D\u6D3B\u8DC3","overview.noAttention":"\u6CA1\u6709\u7B49\u4F60\u5904\u7406\u7684\u4E8B\u9879","overview.teamExpand":"\u5C55\u5F00\u5168\u90E8 {count} \u4F4D \u25BE","overview.teamCollapse":"\u6536\u8D77 \u25B4","strip.pending":"{count} \u4EF6\u5F85\u5904\u7406","strip.longest":"\u6700\u4E45\u5DF2\u7B49 {time} \u2014 {bot} {reason}","strip.handle":"\u7ACB\u5373\u5904\u7406","overview.openSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.workingSessions":"\u5DE5\u4F5C\u4E2D","overview.onlineBots":"\u5728\u7EBF Bot","overview.schedules":"\u5B9A\u65F6\u4EFB\u52A1","overview.groups":"\u7FA4\u804A\u8986\u76D6","overview.enabledSchedules":"\u5DF2\u542F\u7528","overview.total":"\u603B\u8BA1","overview.active":"\u6D3B\u8DC3","overview.daemonRegistry":"daemon \u6CE8\u518C\u8868","overview.chatMatrix":"\u7FA4\u804A\u77E9\u9635","overview.recentSessions":"\u6700\u8FD1\u4F1A\u8BDD","overview.nextSchedules":"\u5373\u5C06\u6267\u884C","overview.noSessions":"\u6682\u65E0\u4F1A\u8BDD\u3002","overview.noSchedules":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","sessions.title":"\u4F1A\u8BDD\u63A7\u5236","sessions.subtitle":"\u5B9A\u4F4D\u98DE\u4E66\u8BDD\u9898\u3001\u6253\u5F00 Web Terminal\u3001\u5173\u95ED\u6216\u6062\u590D CLI \u4F1A\u8BDD\u3002","sessions.search":"\u641C\u7D22\u5DE5\u4F5C\u76EE\u5F55 / \u6807\u9898 / ID","sessions.anyStatus":"\u5168\u90E8\u72B6\u6001","sessions.adoptAny":"adopt: \u5168\u90E8","sessions.adoptYes":"adopt: \u662F","sessions.adoptNo":"adopt: \u5426","sessions.activeOnly":"\u4EC5\u6D3B\u8DC3","sessions.closeSelected":"\u5173\u95ED\u9009\u4E2D","sessions.clearSelection":"\u53D6\u6D88\u9009\u62E9","sessions.selectedCount":"\u5DF2\u9009 {count} \u4E2A\u4F1A\u8BDD","sessions.bot":"bot","sessions.cli":"CLI","sessions.chat":"\u7FA4\u804A","sessions.openChat":"\u6253\u5F00\u7FA4\u804A","sessions.status":"\u72B6\u6001","sessions.tokenIn":"Token In","sessions.tokenOut":"Token Out","sessions.titleCol":"\u6807\u9898","sessions.workingDir":"\u5DE5\u4F5C\u76EE\u5F55","sessions.created":"\u521B\u5EFA","sessions.last":"\u6700\u8FD1","sessions.adopt":"\u63A5\u5165","sessions.actions":"\u64CD\u4F5C","sessions.details":"\u8BE6\u60C5","sessions.copy":"\u590D\u5236","sessions.copied":"\u5DF2\u590D\u5236","sessions.locate":"\u5B9A\u4F4D\u8BDD\u9898","sessions.locating":"\u53D1\u9001\u4E2D...","sessions.cooldown":"\u51B7\u5374 {seconds}s","sessions.openTerminal":"\u7EC8\u7AEF","sessions.writeLink":"\u64CD\u4F5C\u94FE\u63A5","sessions.writeLinkHint":"\u83B7\u53D6\u53EF\u64CD\u4F5C\u7EC8\u7AEF\u94FE\u63A5\uFF08\u5E26\u5199\u6743\u9650 token\uFF0C\u65B0\u6807\u7B7E\u6253\u5F00\uFF09","sessions.writeLinkFail":"\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u5931\u8D25","sessions.close":"\u5173\u95ED\u4F1A\u8BDD","sessions.resume":"\u6062\u590D\u4F1A\u8BDD","sessions.dismiss":"\u5173\u95ED","sessions.closeConfirm":"\u5173\u95ED\u8FD9\u4E2A\u4F1A\u8BDD\uFF1F","sessions.resumeFailed":"\u6062\u590D\u5931\u8D25","sessions.land":"\u843D\u76D8","sessions.landLoading":"\u52A0\u8F7D\u6C99\u76D2 diff\u2026","sessions.landUnavailable":"\u65E0\u6CD5\u843D\u76D8","sessions.landEmpty":"\u6C99\u76D2\u526F\u672C\u6CA1\u6709\u6539\u52A8\u3002","sessions.landApply":"\u5E94\u7528\u5230\u78C1\u76D8","sessions.landDiscard":"\u4E22\u5F03","sessions.landApplied":"\u5DF2\u843D\u76D8","sessions.landFailed":"\u843D\u76D8\u5931\u8D25","sessions.landDiscarded":"\u5DF2\u4E22\u5F03\uFF08\u6C99\u76D2\u526F\u672C\u672A\u5E94\u7528\uFF09\u3002","connectors.lede":"\u8BA9\u5916\u90E8\u7CFB\u7EDF\uFF08\u76D1\u63A7\u544A\u8B66\u3001CI\u3001\u5DE5\u5355\u2026\uFF09\u901A\u8FC7\u4E00\u4E2A webhook \u89E6\u53D1\u673A\u5668\u4EBA\u5728\u7FA4\u91CC\u8BF4\u8BDD\u6216\u8DD1\u5DE5\u4F5C\u6D41\u3002","connectors.createTitle":"\u65B0\u5EFA Webhook","connectors.fName":"\u540D\u79F0","connectors.fNamePh":"\u5982\uFF1A\u7EBF\u4E0A\u544A\u8B66","connectors.fBot":"\u89E6\u53D1\u7684\u673A\u5668\u4EBA","connectors.fKind":"\u89E6\u53D1\u65B9\u5F0F","connectors.kindTurn":"\u5355\u8F6E\u5BF9\u8BDD\uFF08\u8BA9\u673A\u5668\u4EBA\u56DE\u5E94\u4E00\u6B21\uFF09","connectors.kindWorkflow":"\u5DE5\u4F5C\u6D41","connectors.fWf":"\u5DE5\u4F5C\u6D41 ID","connectors.fMode":"\u6295\u9012\u5230\u54EA\u4E2A\u7FA4","connectors.modeDynamic":"\u7531\u8BF7\u6C42\u6307\u5B9A\uFF08\u7FA4\u968F\u8BF7\u6C42\u4F20\u5165\uFF09","connectors.modeFixed":"\u56FA\u5B9A\u7FA4","connectors.modeNewGroup":"\u6BCF\u6B21\u65B0\u5EFA\u7FA4","connectors.fFixedChat":"\u6295\u9012\u5230\u7684\u7FA4","connectors.fChatManualPh":"\u624B\u52A8\u586B\u7FA4 ID\uFF1Aoc_\u2026","connectors.chatManualLink":"\u627E\u4E0D\u5230\u7FA4\uFF1F\u624B\u52A8\u586B ID \u2192","connectors.chatListLink":"\u4ECE\u7FA4\u5217\u8868\u9009\u62E9 \u2190","connectors.fAllow":"\u5141\u8BB8\u7684\u7FA4","connectors.optional":"\uFF08\u53EF\u9009\uFF09","connectors.allowHint":"\u6309\u4F4F Ctrl/\u2318 \u591A\u9009\uFF1B\u7559\u7A7A = \u4E0D\u9650\u3002\u53EA\u7528\u4E8E\u6821\u9A8C\u8BF7\u6C42\u4F20\u5165\u7684\u7FA4\u662F\u5426\u88AB\u5141\u8BB8\u3002","connectors.dynamicHint":'<b>\u52A8\u6001\u6A21\u5F0F</b>\uFF1A\u7FA4 ID \u968F\u6BCF\u6B21\u8BF7\u6C42\u4F20\u5165\uFF0C\u4E09\u9009\u4E00 \u2014\u2014 \u67E5\u8BE2\u53C2\u6570 <code>?chatId=<\u7FA4ID></code> \xB7 \u8BF7\u6C42\u5934 <code>x-botmux-chat-id: <\u7FA4ID></code> \xB7 \u8BF7\u6C42\u4F53 <code>{"chatId":"<\u7FA4ID>"}</code>\u3002<br>\u60F3"\u4E00\u4E2A URL \u76F4\u63A5\u89E6\u53D1\u3001\u4E0D\u5E26\u53C2\u6570"\uFF0C\u8BF7\u6539\u9009\u300C\u56FA\u5B9A\u7FA4\u300D\u3002',"connectors.fDedup":"\u53BB\u91CD\u5B57\u6BB5","connectors.fDedupPh":"\u5982 alert.id\uFF08\u4ECE\u4E8B\u4EF6 body \u53D6\u503C\uFF09","connectors.dedupHint":"\u586B\u4E86\uFF1A\u547D\u4E2D\u76F8\u540C\u503C\u7684\u4E8B\u4EF6\u90FD\u6295\u5230<b>\u540C\u4E00\u4E2A\u7FA4</b>\u3002\u7559\u7A7A\uFF1A\u6BCF\u4E2A\u4E8B\u4EF6<b>\u65B0\u5EFA\u4E00\u4E2A\u7FA4</b>\u3002","connectors.fInstruction":"\u5904\u7406\u6307\u4EE4","connectors.fInstructionPh":"\u4E8B\u4EF6\u89E6\u53D1\u65F6\u8BA9\u673A\u5668\u4EBA\u505A\u4EC0\u4E48\u3002\u5982\uFF1A\u603B\u7ED3\u8FD9\u6761\u544A\u8B66\u7684\u4E25\u91CD\u7A0B\u5EA6\uFF0C@\u76F8\u5173 oncall\uFF0C\u7ED9\u51FA\u6392\u67E5\u5EFA\u8BAE\u3002\u7559\u7A7A = \u53EA\u628A\u4E8B\u4EF6\u539F\u6837\u4EA4\u7ED9\u6A21\u578B\u81EA\u7531\u53D1\u6325\u3002","connectors.fVerify":"\u6821\u9A8C\u65B9\u5F0F","connectors.verifyToken":"\u4EE4\u724C\uFF08\u7B80\u5355\uFF1A\u5BC6\u94A5\u653E\u8FDB URL\uFF0C\u4E00\u6761 curl \u5C31\u80FD\u89E6\u53D1\uFF09","connectors.verifyHmac":"HMAC \u7B7E\u540D\uFF08\u9AD8\u7EA7\uFF1A\u66F4\u5B89\u5168\uFF0C\u9700\u81EA\u884C\u5BF9\u8BF7\u6C42\u7B7E\u540D\uFF09","connectors.fSecret":"\u5BC6\u94A5 / \u4EE4\u724C","connectors.fSecretPh":"\u7559\u7A7A\u81EA\u52A8\u751F\u6210\uFF08\u53EA\u663E\u793A\u4E00\u6B21\uFF09","connectors.btnCreate":"\u521B\u5EFA","connectors.listTitle":"\u5DF2\u6709 Webhook","connectors.loading":"\u52A0\u8F7D\u4E2D\u2026","connectors.noBotGroups":"\uFF08\u8BE5\u673A\u5668\u4EBA\u6682\u65E0\u53EF\u89C1\u7FA4\uFF0C\u70B9\u53F3\u4FA7\u624B\u52A8\u586B ID\uFF09","connectors.modeLabelFixed":"\u56FA\u5B9A\u7FA4","connectors.modeLabelNewGroup":"\u6BCF\u6B21\u65B0\u5EFA\u7FA4","connectors.modeLabelDynamic":"\u8BF7\u6C42\u6307\u5B9A\u7FA4","connectors.kindLabelWorkflow":"\u5DE5\u4F5C\u6D41","connectors.kindLabelTurn":"\u5355\u8F6E","connectors.count":"\xB7 {count} \u4E2A","connectors.empty":"\u8FD8\u6CA1\u6709 Webhook\u3002\u7528\u4E0A\u9762\u7684\u8868\u5355\u521B\u5EFA\u4E00\u4E2A\u3002","connectors.enabled":"\u5DF2\u542F\u7528","connectors.disabled":"\u5DF2\u505C\u7528","connectors.badgeToken":"\u4EE4\u724C","connectors.badgeSign":"\u7B7E\u540D","connectors.dest":"\u6295\u9012\u300C{name}\u300D","connectors.btnDisable":"\u505C\u7528","connectors.btnEnable":"\u542F\u7528","connectors.btnDel":"\u5220\u9664","connectors.webhookUrl":"Webhook URL\uFF1A","connectors.copy":"\u590D\u5236","connectors.copied":"\u5DF2\u590D\u5236","connectors.tokenHint":"\u4EE4\u724C\u6A21\u5F0F\uFF1A\u8C03\u7528\u65F6\u5728 URL \u672B\u5C3E\u8FFD\u52A0 <code>/<\u4EE4\u724C></code>\uFF08\u4EE4\u724C\u4EC5\u521B\u5EFA/\u8F6E\u6362\u65F6\u663E\u793A\u4E00\u6B21\uFF09\u3002","connectors.dynamicReqHint":'\u52A8\u6001\u6A21\u5F0F\uFF1A\u8BF7\u6C42\u9700\u5E26\u76EE\u6807\u7FA4 \u2014\u2014 <code>?chatId=<\u7FA4ID></code> \u6216\u5934 <code>x-botmux-chat-id</code> \u6216 body <code>{"chatId":"\u2026"}</code>\u3002',"connectors.instructionPrefix":"\u5904\u7406\u6307\u4EE4\uFF1A","connectors.delConfirm":"\u5220\u9664\u8FD9\u4E2A Webhook\uFF1F\u5B83\u7684 URL \u4F1A\u7ACB\u5373\u5931\u6548\u3002","connectors.errName":"\u8BF7\u586B\u540D\u79F0","connectors.errBot":"\u8BF7\u9009\u673A\u5668\u4EBA","connectors.errWf":"\u8BF7\u586B\u5DE5\u4F5C\u6D41 ID","connectors.errChat":"\u8BF7\u9009\u62E9\uFF08\u6216\u624B\u52A8\u586B\uFF09\u6295\u9012\u7684\u7FA4","connectors.creating":"\u521B\u5EFA\u4E2D\u2026","connectors.usageDynamicLede":"\u52A8\u6001\u6A21\u5F0F\uFF1AURL \u5DF2\u542B\u4EE4\u724C\uFF0C\u8C03\u7528\u65F6\u518D\u5E26\u4E0A\u76EE\u6807\u7FA4 ID{gn}\uFF1A","connectors.usageDynamicNote":'\u7FA4\u4E5F\u53EF\u653E\u8BF7\u6C42\u5934 <code>x-botmux-chat-id</code> \u6216 body <code>{"chatId":"\u2026"}</code>\u3002\u26A0\uFE0F URL \u5373\u51ED\u8BC1\uFF0C\u52FF\u6CC4\u6F0F\u3002',"connectors.usageTokenLede":"\u6B64 URL \u5DF2\u542B\u4EE4\u724C\u3001\u4E14\u56FA\u5B9A\u6295\u9012\u5230\u6240\u9009\u7FA4\uFF0C\u76F4\u63A5 POST \u5373\u53EF\u89E6\u53D1\uFF1A","connectors.usageTokenNote":"\u26A0\uFE0F URL \u5373\u51ED\u8BC1\uFF0C\u8BF7\u52FF\u516C\u5F00\u6CC4\u6F0F\uFF1B\u53EF\u5728\u4E0B\u65B9\u5217\u8868\u5220\u9664\u6216\u8F6E\u6362\u3002","connectors.usageHmac":"\u5916\u90E8\u7CFB\u7EDF\u9700\u5BF9 <code>timestamp.body</code> \u505A HMAC-SHA256 \u7B7E\u540D\uFF0C\u5E76\u5E26\u4E0A <code>x-botmux-timestamp</code> / <code>x-botmux-nonce</code> / <code>x-botmux-signature</code> \u5934\u8C03\u7528","connectors.usageHmacDynamic":"\uFF0C\u540C\u65F6\u6309\u4E0A\u9762\u65B9\u5F0F\u5E26\u76EE\u6807\u7FA4 ID","connectors.createdPrefix":"\u5DF2\u521B\u5EFA\u300C{name}\u300D","connectors.createdDest":"\u6295\u9012\u5230\u300C{name}\u300D","connectors.tokenLabel":"\u8BBF\u95EE\u4EE4\u724C","connectors.signLabel":"\u7B7E\u540D\u5BC6\u94A5","connectors.secretOnce":"\uFF08\u53EA\u663E\u793A\u8FD9\u4E00\u6B21\uFF0C\u8BF7\u4FDD\u5B58\uFF09\uFF1A","connectors.createFailed":"\u521B\u5EFA\u5931\u8D25\uFF1A{error}","connectors.noOnlineBots":"\uFF08\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF09","team.navHome":"\u6211\u7684\u56E2\u961F","team.navManage":"\u56E2\u961F\u7BA1\u7406","team.eyebrow":"\u56E2\u961F","team.homeTitle":"\u56E2\u961F\u534F\u4F5C\uFF08\u8DE8\u90E8\u7F72\uFF09","team.homeLede":"\u628A\u522B\u7684\u90E8\u7F72\uFF08\u540C\u4E8B\u81EA\u5DF1\u8DD1\u7684 botmux\uFF09\u9080\u8BF7\u8FDB\u540C\u4E00\u4E2A\u56E2\u961F\uFF0C\u4E92\u76F8\u53D1\u73B0\u673A\u5668\u4EBA\u3001\u534F\u4F5C\u62C9\u7FA4\u3002","team.localDeployTitle":"\u672C\u90E8\u7F72","team.myIdentity":"\u6211\u7684\u98DE\u4E66\u8EAB\u4EFD\uFF1A","team.unbound":"\u672A\u7ED1\u5B9A","team.bindBtn":"\u7ED1\u5B9A","team.bindHint":"\uFF08\u7528\u673A\u5668\u4EBA\u51ED\u8BC1\u81EA\u52A8\u8BC6\u522B\u4F60\uFF1B\u7ED1\u5B9A\u540E\u62C9\u7FA4\u4F1A\u628A\u4F60\u62C9\u8FDB\u7FA4\u3001\u673A\u5668\u4EBA\u4E5F\u5F52\u5230\u4F60\u540D\u4E0B\uFF09","team.myTeams":"\u6211\u7684\u56E2\u961F","team.searchPh":"\u641C\u7D22 \u540D\u79F0/\u80FD\u529B/CLI\u2026","team.allCli":"\u5168\u90E8 CLI","team.hasCap":"\u6709\u80FD\u529B\u6807\u7B7E","team.hasRole":"\u6709\u9ED8\u8BA4\u89D2\u8272","team.teamsHint":"\u6BCF\u4E2A\u56E2\u961F\u91CC\u52FE\u9009\u673A\u5668\u4EBA\u5373\u53EF\u5355\u72EC\u62C9\u7FA4\uFF08\u81EA\u52A8\u5E26\u4E0A\u5404\u81EA\u8D1F\u8D23\u4EBA\uFF09\u3002\u8981\u65B0\u5EFA\u56E2\u961F / \u751F\u6210\u9080\u8BF7\u7801 / \u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\uFF0C\u53BB\u300C\u56E2\u961F\u7BA1\u7406\u300D\u3002","team.loading":"\u52A0\u8F7D\u4E2D\u2026","team.roleModalTitle":"\u9ED8\u8BA4\u89D2\u8272","team.roleModalHint":"\u8BE5\u673A\u5668\u4EBA\u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF08\u8DE8\u7FA4\u751F\u6548\uFF09\uFF0C\u6B64\u5904\u53EA\u8BFB\u3002\u5982\u9700\u4FEE\u6539\uFF0C\u8BF7\u5230\u300CBot \u914D\u7F6E\u300D\u9875\u3002","team.close":"\u5173\u95ED","team.tagLocal":"\u672C\u90E8\u7F72","team.tagRemoteStale":"\u8FDC\u7AEF\xB7\u79BB\u7EBF\uFF1F","team.tagRemote":"\u8FDC\u7AEF","team.removeMember":"\u79FB\u9664","team.depTag":"\uFF08{tag}\uFF09","team.depCount":"{count} \u4E2A","team.depSelected":"\uFF0C\u5DF2\u9009 {n}","team.capPh":"\u80FD\u529B\u6807\u7B7E\u2026","team.viewRole":"\u67E5\u770B","team.hasRoleShort":"\u6709\u89D2\u8272","team.noMatch":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u673A\u5668\u4EBA\u3002","team.gnamePh":"\u7FA4\u540D\uFF08\u5982\uFF1A\u8DE8\u56E2\u961F\u6392\u969C\uFF09","team.pullGroupBtn":"\u628A\u52FE\u9009\u7684\u673A\u5668\u4EBA\u62C9\u4E00\u4E2A\u7FA4","team.pullGroupHint":"\u52FE\u9009\u673A\u5668\u4EBA \u2192 \u62C9\u5230\u4E00\u4E2A\u98DE\u4E66\u7FA4\uFF08\u81EA\u52A8\u542B owner\uFF09","team.noTeams":"\u8FD8\u6CA1\u6709\u56E2\u961F\u3002\u53BB\u300C\u56E2\u961F\u7BA1\u7406\u300D\u751F\u6210\u9080\u8BF7\u7801\u8BA9\u522B\u4EBA\u52A0\u5165\u4F60\uFF0C\u6216\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\u3002","team.connected":"\u5DF2\u8FDE\u63A5","team.connectFail":"\u8FDE\u63A5\u5931\u8D25\uFF1A{error}","team.iHost":"\u6211\u6258\u7BA1","team.teamMeta":"{deps} \u4E2A\u90E8\u7F72 \xB7 {bots} \u4E2A\u673A\u5668\u4EBA","team.rosterFail":"\u65E0\u6CD5\u83B7\u53D6\u8BE5\u56E2\u961F\u82B1\u540D\u518C\u3002","team.acrossTeams":"\uFF08\u8DE8 {n} \u4E2A\u56E2\u961F\uFF0C\u53BB\u91CD\uFF09","team.botsWord":"\u4E2A\u673A\u5668\u4EBA","team.groupCreated":"\u7FA4\u5DF2\u521B\u5EFA","team.delegatedBy":"\uFF08\u7531\u300C{name}\u300D\u5EFA\u7FA4\uFF09","team.openInLark":"\u5728\u98DE\u4E66\u6253\u5F00","team.invalidBots":"\u672A\u52A0\u5165\u7684\u673A\u5668\u4EBA\uFF1A{ids}","team.invalidOwners":"{n} \u4E2A owner \u672A\u80FD\u62C9\u8FDB","team.missingIdentity":"\u4F60\u672A\u7ED1\u5B9A\u98DE\u4E66\u8EAB\u4EFD\uFF0C\u6CA1\u628A\u4F60\u81EA\u5DF1\u62C9\u8FDB\u7FA4\uFF08\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u7ED1\u5B9A\uFF09","team.skippedNoOwner":"{n} \u4E2A\u673A\u5668\u4EBA\u56E0\u8D1F\u8D23\u4EBA\u672A\u7ED1\u5B9A\u8EAB\u4EFD\u88AB\u8DF3\u8FC7\uFF08\u672A\u52A0\u5165\u7FA4\uFF09","team.errNoLocalBot":"\u8BF7\u81F3\u5C11\u52FE\u9009\u4E00\u4E2A\u4F60\u81EA\u5DF1\uFF08\u672C\u90E8\u7F72\uFF09\u7684\u5728\u7EBF\u673A\u5668\u4EBA\u2014\u2014\u7FA4\u8981\u7531\u5B83\u521B\u5EFA\u5E76\u628A\u4F60\uFF08\u53D1\u8D77\u4EBA\uFF09\u62C9\u8FDB\u7FA4\u3002","team.errAllSkipped":"\u6240\u9009\u673A\u5668\u4EBA\u7684\u8D1F\u8D23\u4EBA\u90FD\u6CA1\u7ED1\u5B9A\u8EAB\u4EFD\uFF0C\u65E0\u6CD5\u62C9\u7FA4\uFF08\u673A\u5668\u4EBA\u4E0D\u80FD\u8FDB\u4E00\u4E2A owner \u4E0D\u5728\u7684\u7FA4\uFF09\u3002\u8BF7\u8BA9\u5BF9\u5E94\u90E8\u7F72\u5148\u7ED1\u5B9A\u8EAB\u4EFD\u3002","team.errNoCreator":"\u6CA1\u6709\u53EF\u7528\u7684\u5EFA\u7FA4\u53D1\u8D77\u65B9\uFF08\u76F8\u5173\u90E8\u7F72\u90FD\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF0C\u6216\u4E0D\u53EF\u8FBE\uFF09","team.errDelegationTimeout":"\u59D4\u6258\u5BF9\u65B9\u90E8\u7F72\u5EFA\u7FA4\u8D85\u65F6\uFF08\u53EF\u80FD\u5DF2\u5EFA\uFF0C\u53BB\u98DE\u4E66\u786E\u8BA4\uFF0C\u52FF\u91CD\u590D\u70B9\uFF09","team.errGroupCreate":"\u5EFA\u7FA4\u5931\u8D25\uFF1A{error}","team.roleModalTitleName":"\u9ED8\u8BA4\u89D2\u8272 \xB7 {name}","team.bound":"\u5DF2\u7ED1\u5B9A","team.myHostedTeam":"\u6211\u6258\u7BA1\u7684\u56E2\u961F","team.remoteTeamLabel":"{name} \u7684\u56E2\u961F","team.manageTitle":"\u56E2\u961F\u7BA1\u7406","team.manageLede":"\u521B\u5EFA\u591A\u4E2A\u56E2\u961F\u3001\u7ED9\u6BCF\u4E2A\u56E2\u961F\u751F\u6210\u9080\u8BF7\u7801\u3001\u6216\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\u3002\u4E00\u4E2A\u56E2\u961F = \u4F60\u672C\u90E8\u7F72\u7684\u673A\u5668\u4EBA + \u52A0\u5165\u8BE5\u56E2\u961F\u7684\u5176\u5B83\u90E8\u7F72\u3002","team.hostedTitle":"\u6211\u6258\u7BA1\u7684\u56E2\u961F","team.newTeamPh":"\u65B0\u56E2\u961F\u540D\u79F0","team.createTeamBtn":"\u521B\u5EFA\u56E2\u961F","team.joinTitle":"\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F","team.hubPh":"Hub \u5730\u5740\uFF0C\u5982 http://10.0.0.5:7891","team.codePh":"\u9080\u8BF7\u7801","team.joinBtn":"\u52A0\u5165","team.noTeamsShort":"\u8FD8\u6CA1\u6709\u56E2\u961F\u3002","team.default":"\u9ED8\u8BA4","team.manageMetaDeps":"{count} \u4E2A\u90E8\u7F72","team.manageMetaRemote":"\uFF08\u542B {r} \u8FDC\u7AEF\uFF09","team.manageMetaBots":"{count} \u4E2A\u673A\u5668\u4EBA","team.genInvite":"\u751F\u6210\u9080\u8BF7\u7801","team.delBtn":"\u5220\u9664","team.generating":"\u751F\u6210\u4E2D\u2026","team.inviteResultLede":"\u628A\u4E0B\u9762\u4E24\u9879\u53D1\u7ED9\u522B\u7684\u90E8\u7F72\u7684\u4EBA\uFF0824 \u5C0F\u65F6\u5185\u3001\u5355\u6B21\u6709\u6548\uFF09\uFF1A","team.inviteHub":"Hub \u5730\u5740\uFF1A","team.inviteCode":"\u9080\u8BF7\u7801\uFF1A","team.genFail":"\u751F\u6210\u5931\u8D25\u3002","team.delConfirm":"\u5220\u9664\u56E2\u961F\u300C{name}\u300D\uFF1F\u5DF2\u52A0\u5165\u5B83\u7684\u90E8\u7F72\u4F1A\u88AB\u79FB\u9664\uFF08\u4E0D\u5F71\u54CD\u4ED6\u4EEC\u81EA\u5DF1\u7684\u90E8\u7F72\uFF09\u3002","team.errName":"\u8BF7\u586B\u56E2\u961F\u540D\u79F0","team.creating":"\u521B\u5EFA\u4E2D\u2026","team.created":"\u5DF2\u521B\u5EFA","team.createFail":"\u521B\u5EFA\u5931\u8D25\uFF1A{error}","team.errHubCode":"\u8BF7\u586B Hub \u5730\u5740\u548C\u9080\u8BF7\u7801\u3002","team.joining":"\u52A0\u5165\u4E2D\u2026","team.joined":"\u5DF2\u52A0\u5165\u300C{name}\u300D\uFF0C\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u67E5\u770B\u3002","team.joinErrSelf":"\u8FD9\u662F\u4F60\u81EA\u5DF1\u7684\u90E8\u7F72\uFF0C\u4E0D\u80FD\u52A0\u5165\u81EA\u5DF1\uFF08\u9080\u8BF7\u7801\u8981\u53D1\u7ED9\u522B\u7684\u90E8\u7F72\u7684\u4EBA\u7528\uFF09","team.joinErrAlready":"\u4F60\u7684\u90E8\u7F72\u5DF2\u7ECF\u52A0\u5165\u8FC7\u8FD9\u4E2A\u56E2\u961F\u4E86","team.joinErrUnreachable":"\u8FDE\u4E0D\u4E0A\u5BF9\u65B9 Hub\uFF08\u68C0\u67E5\u5730\u5740/\u7F51\u7EDC\uFF09","team.joinErrTimeout":"\u5BF9\u65B9 Hub \u54CD\u5E94\u8D85\u65F6","team.joinErrGeneric":"\u52A0\u5165\u5931\u8D25\uFF1A{error}","team.identifying":"\u8BC6\u522B\u4E2D\u2026","team.bound2":"\u5DF2\u7ED1\u5B9A\uFF1A{name}","team.multiCandidate":"\u8BC6\u522B\u5230\u591A\u4E2A\u5019\u9009\uFF0C\u70B9\u4F60\u81EA\u5DF1\uFF1A","team.binding":"\u7ED1\u5B9A\u4E2D\u2026","team.bindFail":"\u7ED1\u5B9A\u5931\u8D25\uFF1A{error}","team.noCandidates":"\u6CA1\u8BC6\u522B\u5230\u8EAB\u4EFD\uFF1A\u8BF7\u786E\u8BA4\u673A\u5668\u4EBA\u914D\u7F6E\u4E86 allowedUsers\uFF08\u5141\u8BB8\u4F7F\u7528\u8005\uFF09\uFF0C\u4E14\u673A\u5668\u4EBA\u6709\u901A\u8BAF\u5F55\u6743\u9650\u3002","team.removeMemberConfirm":"\u628A\u300C{name}\u300D\u79FB\u51FA\u8FD9\u4E2A\u56E2\u961F\uFF1F\u5B83\u7684\u673A\u5668\u4EBA\u5C06\u4ECE\u672C\u56E2\u961F\u82B1\u540D\u518C\u6D88\u5931\uFF08\u4E0D\u5F71\u54CD\u5BF9\u65B9\u81EA\u5DF1\u7684\u90E8\u7F72\uFF09\u3002","team.creatingGroup":"\u5EFA\u7FA4\u4E2D\u2026","team.defaultGroupName":"\u534F\u4F5C\u7FA4","team.errPickBot":"\u8BF7\u5148\u52FE\u9009\u81F3\u5C11\u4E00\u4E2A\u673A\u5668\u4EBA","sessions.closeBulkConfirm":"\u5173\u95ED\u9009\u4E2D\u7684 {count} \u4E2A\u4F1A\u8BDD\uFF1F","sessions.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u4F1A\u8BDD\u3002","sessions.viewMode":"\u4F1A\u8BDD\u89C6\u56FE","sessions.viewKanban":"\u770B\u677F","sessions.viewBoard":"\u72B6\u6001\u677F","sessions.viewTable":"\u8868\u683C","sessions.selectSession":"\u9009\u62E9\u4F1A\u8BDD","sessions.board.needsYou":"\u9700\u8981\u4F60","sessions.board.needsYouHint":"\u7B49\u5F85\u4ED3\u5E93\u3001TUI \u9009\u62E9\u6216\u989D\u5EA6\u5904\u7406","sessions.board.starting":"\u542F\u52A8\u4E2D","sessions.board.startingHint":"CLI \u6B63\u5728\u521B\u5EFA\u6216\u6062\u590D","sessions.board.working":"\u5E72\u6D3B\u4E2D","sessions.board.workingHint":"\u6B63\u5728\u8F93\u51FA\u3001\u5206\u6790\u6216\u6267\u884C\u5DE5\u5177","sessions.board.idle":"\u7A7A\u95F2","sessions.board.idleHint":"\u53EF\u7EE7\u7EED\u5BF9\u8BDD\u6216\u63A5\u65B0\u4EFB\u52A1","sessions.board.emptyColumn":"\u6682\u65E0\u4F1A\u8BDD","sessions.board.signalRepo":"\u5F85\u9009\u4ED3\u5E93","sessions.board.signalPrompt":"\u7B49\u5F85 TUI \u9009\u62E9","sessions.board.signalLimited":"\u989D\u5EA6\u53D7\u9650","sessions.board.signalAgent":"\u9700\u8981\u4EBA\u5DE5\u4ECB\u5165","sessions.board.waiting":"\u7B49\u5F85","sessions.board.dragHint":"\u62D6\u52A8\u5217\u5934\u8C03\u6574\u5217\u987A\u5E8F","sessions.board.moveLeft":"\u5DE6\u79FB\u6B64\u5217","sessions.board.moveRight":"\u53F3\u79FB\u6B64\u5217","sessions.kanban.backlog":"\u5F85\u529E\u6C60","sessions.kanban.todo":"\u5F85\u529E","sessions.kanban.inProgress":"\u8FDB\u884C\u4E2D","sessions.kanban.inReview":"\u5F85\u786E\u8BA4","sessions.kanban.done":"\u5DF2\u5B8C\u6210","sessions.kanban.updated":"\u66F4\u65B0\u4E8E {time}","sessions.kanban.moreHidden":"\u8FD8\u6709 {count} \u4E2A\u672A\u663E\u793A","sessions.kanban.openTab":"\u65B0\u6807\u7B7E\u9875\u6253\u5F00","sessions.kanban.openFeishu":"\u6253\u5F00\u98DE\u4E66","sessions.kanban.terminalLoading":"\u6B63\u5728\u6253\u5F00\u7EC8\u7AEF\u2026","sessions.kanban.rename":"\u91CD\u547D\u540D\uFF08\u53CC\u51FB\u6807\u9898\u4E5F\u53EF\uFF09","sessions.kanban.renameFail":"\u91CD\u547D\u540D\u5931\u8D25","sessions.kanban.moveFail":"\u79FB\u52A8\u5931\u8D25","sessions.kanban.groupBy":"\u5206\u7EC4\u7EF4\u5EA6","sessions.kanban.groupFlow":"\u5DE5\u4F5C\u6D41","sessions.kanban.groupTeam":"\u56E2\u961F","sessions.kanban.groupBot":"\u673A\u5668\u4EBA","sessions.kanban.teamLoading":"\u6B63\u5728\u52A0\u8F7D\u56E2\u961F\u2026","sessions.kanban.noTeam":"\u6682\u65E0\u56E2\u961F","sessions.kanban.teamScope":"{chats} \u4E2A\u534F\u4F5C\u7FA4 \xB7 {sessions} \u4E2A\u4F1A\u8BDD","sessions.kanban.remoteHint":"\u6765\u81EA {name} \u90E8\u7F72\u7684\u4F1A\u8BDD\uFF08\u5FEB\u7167\uFF0C\u7EC8\u7AEF/\u5386\u53F2\u5728\u5BF9\u65B9\u673A\u5668\u4E0A\uFF09","sessions.kanban.clusterDragHint":"\u62D6\u52A8\u6807\u9898\u6574\u7EC4\u79FB\u52A8","sessions.history.title":"\u4F1A\u8BDD\u5386\u53F2","sessions.history.loading":"\u6B63\u5728\u62C9\u53D6\u98DE\u4E66\u6D88\u606F\u2026","sessions.history.fail":"\u5386\u53F2\u62C9\u53D6\u5931\u8D25","sessions.history.empty":"\u6CA1\u6709\u6D88\u606F","sessions.history.user":"\u7528\u6237","sessions.history.owner":"\u521B\u5EFA\u8005","sessions.history.staleHint":"dashboard \u6216 daemon \u8FDB\u7A0B\u53EF\u80FD\u8FD8\u5728\u8DD1\u65E7\u7248\u672C\uFF0Cbotmux restart \u540E\u91CD\u8BD5","groups.title":"\u7FA4\u7EC4\u4E0E Bot","groups.subtitle":"\u67E5\u770B chat x bot \u8986\u76D6\u77E9\u9635\uFF0C\u7BA1\u7406\u62C9\u7FA4\u3001oncall\u3001\u9000\u7FA4\u548C\u89E3\u6563\u3002","groups.search":"\u641C\u7D22\u7FA4\u540D / ID / owner","groups.missingOnly":"\u4EC5\u7F3A bot","groups.refresh":"\u5237\u65B0","groups.create":"\u65B0\u5EFA\u7FA4","groups.chat":"\u7FA4\u804A","groups.actions":"\u64CD\u4F5C","groups.addBots":"\u6DFB\u52A0 bot","groups.manage":"\u7BA1\u7406","groups.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u7FA4\u804A\u3002","groups.createTitle":"\u65B0\u5EFA\u7FA4\u804A","groups.createHelp":"\u9009\u62E9\u8981\u9080\u8BF7\u7684 bot\u3002dashboard \u4F1A\u81EA\u52A8\u9009\u62E9\u5728\u7EBF daemon \u4F5C\u4E3A\u521B\u5EFA\u8005\u3002","groups.name":"\u7FA4\u540D","groups.namePlaceholder":"\u4F8B\u5982 AI ChangeLog","groups.bindDir":"\u7ED1\u5B9A\u76EE\u5F55","groups.bindDirHelp":"\u65B0\u8BDD\u9898\u76F4\u63A5\u7528\u8BE5\u76EE\u5F55\u542F\u52A8 CLI\uFF0C\u8DF3\u8FC7 repo \u9009\u62E9\u3002","groups.botPicker":"Bot","groups.createSubmit":"\u521B\u5EFA","groups.cancel":"\u53D6\u6D88","groups.successTitle":"\u7FA4\u521B\u5EFA\u6210\u529F","groups.openGroup":"\u6253\u5F00\u65B0\u7FA4","groups.manageTitle":"\u7BA1\u7406 {name}","groups.owner":"\u7FA4\u4E3B","groups.oncall":"Oncall \u6A21\u5F0F","groups.oncallHelp":"\u5F00\u542F\u540E\uFF0C\u7FA4\u5185\u6210\u5458\u53EF @ \u673A\u5668\u4EBA\uFF1B\u65B0\u8BDD\u9898\u76F4\u63A5\u4F7F\u7528\u7ED1\u5B9A\u76EE\u5F55\u3002","groups.leaveTitle":"\u9009\u62E9\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.leaveSelected":"\u9009\u4E2D\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.disband":"\u89E3\u6563\u7FA4\u804A","groups.dangerHint":"\u89E3\u6563\u4EC5\u5F53\u5728\u7FA4\u673A\u5668\u4EBA\u662F\u7FA4\u4E3B\u65F6\u624D\u4F1A\u6210\u529F\uFF0C\u5426\u5219\u5EFA\u8BAE\u4F7F\u7528\u9000\u51FA\u7FA4\u804A\u3002","groups.save":"\u4FDD\u5B58","groups.needWorkingDir":"\u8BF7\u586B\u5DE5\u4F5C\u76EE\u5F55","groups.noBotsOnline":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u8BF7\u5148\u91CD\u542F daemon\u3002","schedules.title":"\u5B9A\u65F6\u4EFB\u52A1","schedules.subtitle":"\u8DE8 daemon \u67E5\u770B\u3001\u6682\u505C\u3001\u6062\u590D\u548C\u7ACB\u5373\u89E6\u53D1\u5B9A\u65F6\u4EFB\u52A1\u3002","schedules.search":"\u641C\u7D22\u540D\u79F0 / prompt / \u5DE5\u4F5C\u76EE\u5F55","schedules.anyKind":"\u5168\u90E8\u7C7B\u578B","schedules.enabledOnly":"\u4EC5\u542F\u7528","schedules.name":"\u540D\u79F0","schedules.bot":"bot","schedules.schedule":"\u89C4\u5219","schedules.next":"\u4E0B\u6B21","schedules.last":"\u4E0A\u6B21","schedules.repeat":"\u91CD\u590D","schedules.enabled":"\u542F\u7528","schedules.actions":"\u64CD\u4F5C","schedules.runNow":"\u7ACB\u5373\u8FD0\u884C","schedules.pause":"\u6682\u505C","schedules.resume":"\u6062\u590D","schedules.empty":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","settings.title":"\u5168\u5C40\u8BBE\u7F6E","settings.subtitle":"\u7BA1\u7406\u672C\u673A botmux dashboard \u4E0E\u6240\u6709 bot \u5171\u4EAB\u7684\u5168\u5C40\u884C\u4E3A\u3002","settings.loading":"\u6B63\u5728\u52A0\u8F7D\u8BBE\u7F6E\u2026","settings.loadFailed":"\u8BBE\u7F6E\u52A0\u8F7D\u5931\u8D25","settings.readOnlyVisitor":"\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u4FEE\u6539\u8BBE\u7F6E\u9700\u8981\u6388\u6743\u94FE\u63A5\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09","settings.sectionAccess":"\u8BBF\u95EE\u6743\u9650","settings.publicReadOnly":"\u5141\u8BB8\u65E0 token \u53EA\u8BFB\u8BBF\u95EE dashboard","settings.publicReadOnlyHelp":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 token \u7684\u8BBF\u95EE\u8005\u53EF\u4EE5\u67E5\u770B dashboard\u3001\u4F1A\u8BDD\u3001\u5B9A\u65F6\u4EFB\u52A1\u548C SSE\uFF1B\u5173\u95ED\u3001\u6682\u505C\u3001\u5BA1\u6279\u7B49\u5199\u64CD\u4F5C\u4ECD\u5FC5\u987B\u901A\u8FC7 token \u9274\u6743\u3002\u654F\u611F\u7EC8\u7AEF\u539F\u59CB\u65E5\u5FD7\u59CB\u7EC8\u9700\u8981 token\u3002","settings.sectionCards":"\u98DE\u4E66\u5361\u7247","settings.openTerminalInFeishu":"\u6D41\u5F0F\u5361\u7247\u7EC8\u7AEF\u6309\u94AE\u5728\u98DE\u4E66\u4FA7\u680F\u6253\u5F00","settings.openTerminalInFeishuHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF1A\u7EC8\u7AEF\u6309\u94AE\u76F4\u63A5\u6253\u5F00 Web Terminal URL\u3002\u5F00\u542F\u540E\u4F7F\u7528\u98DE\u4E66 web_url/open \u5305\u88C5\uFF0C\u5728\u98DE\u4E66 PC \u4FA7\u680F\u91CC\u6253\u5F00\uFF1B\u5199\u6743\u9650\u4ECD\u7531\u7EC8\u7AEF token \u63A7\u5236\u3002","settings.saving":"\u4FDD\u5B58\u4E2D\u2026","settings.saved":"\u5DF2\u4FDD\u5B58","settings.saveFailed":"\u4FDD\u5B58\u5931\u8D25","settings.sectionMaintenance":"\u81EA\u52A8\u7EF4\u62A4","settings.autoUpdate":"\u81EA\u52A8\u66F4\u65B0","settings.autoUpdateHelp":"\u9ED8\u8BA4\u5173\u95ED\u3002\u5230\u70B9\u6267\u884C npm install -g botmux@latest \u5B89\u88C5\u6700\u65B0\u7248\u672C\uFF08\u53EA\u4E0B\u8F7D\u5B89\u88C5\u3001\u672C\u8EAB\u4E0D\u91CD\u542F\uFF09\u3002\u4EC5 npm \u5168\u5C40\u5B89\u88C5\u53EF\u7528\u3002","settings.autoRestart":"\u81EA\u52A8\u91CD\u542F","settings.autoRestartHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF0C\u9700\u5148\u5F00\u542F\u81EA\u52A8\u66F4\u65B0\u3002\u81EA\u52A8\u66F4\u65B0\u88C5\u5230\u65B0\u7248\u672C\u540E\uFF0C\u82E5\u6CA1\u6709\u8FDB\u884C\u4E2D\u7684\u4F1A\u8BDD\u5219\u81EA\u52A8\u91CD\u542F\u4EE5\u751F\u6548\uFF08\u649E\u4E0A\u5FD9\u788C\u4F1A\u8BDD\u5219\u8DF3\u5230\u6B21\u65E5\uFF09\u3002","settings.autoUpdateLocalDev":"\u5F53\u524D\u4E3A\u672C\u5730\u5F00\u53D1\u5B89\u88C5\uFF08\u4ECE\u6E90\u7801\u8FD0\u884C\uFF09\uFF0C\u81EA\u52A8\u66F4\u65B0\u4E0D\u53EF\u7528\u3002","settings.maintenanceTime":"\u65F6\u95F4","botDefaults.title":"\u6570\u5B57\u5458\u5DE5\u6863\u6848","botDefaults.subtitle":"\u6BCF\u4F4D\u5458\u5DE5\u7684\u9ED8\u8BA4\u884C\u4E3A\uFF1Aoncall\u3001\u4E3B\u52A8\u5F00\u5DE5\u3001\u4EBA\u8BBE\u89D2\u8272\u3001\u5361\u7247\u4E0E\u6388\u6743\u3002","botDefaults.metaOnline":"\u5728\u7EBF \xB7 daemon \u6B63\u5E38","botDefaults.search":"\u641C\u7D22 bot \u540D / app id","botDefaults.refresh":"\u5237\u65B0","botDefaults.sectionOncall":"\u65B0\u7FA4 Oncall","botDefaults.sectionBrand":"\u5361\u7247\u7B7E\u540D","botDefaults.warning":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 oncall binding \u7684\u7FA4\u4F1A\u5728\u4E0B\u6B21\u5F00\u65B0\u8BDD\u9898\u65F6\u81EA\u52A8\u7ED1\u5B9A\u5230\u8BE5\u76EE\u5F55\uFF1B\u624B\u52A8\u7ED1\u5B9A\u6216\u624B\u52A8\u89E3\u7ED1\u8FC7\u7684\u7FA4\u4E0D\u4F1A\u88AB\u8986\u76D6\u3002","botDefaults.empty":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u5148 botmux restart \u8BA9 daemon \u4E0A\u7EBF\u3002","botDefaults.defaultOncall":"\u9ED8\u8BA4\u8FDB\u5165 oncall \u6A21\u5F0F","botDefaults.defaultOncallHelp":"\u6240\u6709\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8\u7ED1\u5B9A","botDefaults.workingDir":"\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55","botDefaults.lastEnabled":"\u4E0A\u6B21\u542F\u7528\u65F6\u95F4","botDefaults.autobound":"\u5DF2\u81EA\u52A8\u7ED1\u5B9A {count} \u4E2A\u7FA4","botDefaults.save":"\u4FDD\u5B58","botDefaults.required":"\u5F00\u542F\u65F6\u5FC5\u987B\u586B\u5DE5\u4F5C\u76EE\u5F55","botDefaults.brandLabel":"\u4E2A\u6027\u7B7E\u540D\uFF08\u5361\u7247\u9875\u811A\uFF09","botDefaults.brandLabelHelp":"\u8BE5 bot \u53D1\u51FA\u7684\u5361\u7247\u9875\u811A\u7B7E\u540D\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u4E0D\u663E\u793A\uFF1B\u586B\u5199\uFF1D\u81EA\u5B9A\u4E49\uFF08\u652F\u6301 markdown\uFF0C\u5982 [Acme](https://\u2026)\uFF09\uFF1B\u6062\u590D\u9ED8\u8BA4\uFF1D\u663E\u793A botmux\u3002","botDefaults.brandLabelPlaceholder":"\u9ED8\u8BA4\uFF1Abotmux\uFF08\u7559\u7A7A\u5219\u4E0D\u663E\u793A\uFF09","botDefaults.sectionSandbox":"\u6587\u4EF6\u6C99\u76D2\uFF08oncall\uFF09","botDefaults.sandboxToggle":"\u5F00\u542F\u6587\u4EF6\u6C99\u76D2","botDefaults.sandboxHelp":"\u5F00\u542F\u540E\uFF0C\u8BE5 bot \u7684\u6BCF\u4E2A\u4F1A\u8BDD\u90FD\u8DD1\u5728\u6309\u4F1A\u8BDD\u9694\u79BB\u7684\u6C99\u76D2\u91CC\uFF1A\u53EA\u770B\u5F97\u5230\u4E00\u4EFD\u9879\u76EE\u526F\u672C\uFF0C\u78B0\u4E0D\u5230\u4F60\u78C1\u76D8\u4E0A\u7684\u771F\u5B9E\u6587\u4EF6\u3001\u5BC6\u94A5\u3001\u522B\u7684\u4F1A\u8BDD\u6570\u636E\u3002\u9002\u5408\u628A\u673A\u5668\u4EBA\u5206\u4EAB\u7ED9\u534A\u53D7\u4FE1\u4EFB\u7684\u4EBA\uFF08oncall\uFF09\u3002\u4EC5 Linux \u751F\u6548\uFF0C\u4E0B\u4E2A\u65B0\u4F1A\u8BDD\u8D77\u6548\u3002","botDefaults.sandboxSaved":"\u5DF2\u4FDD\u5B58\uFF08\u4E0B\u4E2A\u65B0\u4F1A\u8BDD\u751F\u6548\uFF09","botDefaults.brandSave":"\u4FDD\u5B58\u7B7E\u540D","botDefaults.brandReset":"\u6062\u590D\u9ED8\u8BA4","botDefaults.brandStateDefault":"\u5F53\u524D\uFF1A\u9ED8\u8BA4 botmux","botDefaults.brandStateOff":"\u5F53\u524D\uFF1A\u5DF2\u5173\u95ED","botDefaults.brandStateCustom":"\u5F53\u524D\uFF1A\u81EA\u5B9A\u4E49","botDefaults.sectionCard":"\u5361\u7247\u884C\u4E3A","botDefaults.disableStreaming":"\u5173\u95ED\u98DE\u4E66\u6D41\u5F0F\u5361\u7247","botDefaults.disableStreamingHelp":"\u4E0D\u518D\u53D1\u5B9E\u65F6\u5237\u65B0\u7684\u4F1A\u8BDD\u72B6\u6001\u5361\uFF08\u542B\u300C\u6253\u5F00\u7EC8\u7AEF\u300D\u5165\u53E3\uFF09\uFF1B\u4EFB\u52A1\u6700\u7EC8\u7ED3\u679C\u4ECD\u901A\u8FC7\u6D88\u606F\u9001\u8FBE\u3002\u9002\u5408\u5ACC\u6D41\u5F0F\u5361\u7247\u70E6\u7684\u573A\u666F\u3002","botDefaults.writableLink":"\u5361\u7247\u4E0A\u76F4\u63A5\u7ED9\u53EF\u64CD\u4F5C\uFF08\u53EF\u5199\uFF09\u7EC8\u7AEF\u94FE\u63A5","botDefaults.writableLinkHelp":"\u26A0\uFE0F \u5728\u6D41\u5F0F\u5361\u7247\u6B63\u6587\u76F4\u63A5\u8D34\u51FA\u53EF\u5199\u7EC8\u7AEF\u94FE\u63A5\uFF0C\u7FA4\u5185\u4EFB\u4F55\u4EBA\u90FD\u80FD\u70B9\u5F00\u5E76\u64CD\u63A7\u7EC8\u7AEF\u3002\u4E0D\u52FE\uFF1D\u4FDD\u6301\u73B0\u72B6\uFF08\u8D70\u300C\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u300D\u6309\u94AE\u79C1\u804A\u53D1\u7ED9\u70B9\u51FB\u8005\uFF09\u3002","botDefaults.writableLinkMoot":"\u5DF2\u5173\u95ED\u6D41\u5F0F\u5361\u7247","botDefaults.privateCard":"/card \u53D1\u79C1\u5BC6\u5361\u7247\uFF08\u4EC5\u6388\u6743\u4EBA\u53EF\u89C1\uFF09","botDefaults.privateCardHelp":"\u5F00\u542F\u540E /card \u6539\u7528\u300C\u4EC5\u7279\u5B9A\u4EBA\u53EF\u89C1\u300D\u7684\u4E34\u65F6\u5361\u7247\uFF1A\u53EA\u53D1\u7ED9 owner\uFF08allowedUsers\uFF09\uFF0C/grant \u6388\u6743\u5BF9\u8BDD\u7684\u4EBA\u548C\u7FA4\u91CC\u5176\u4ED6\u4EBA\u90FD\u770B\u4E0D\u5230\u3002\u4EE3\u4EF7\uFF1A\u662F\u9759\u6001\u5FEB\u7167\u3001\u4E0D\u4F1A\u5B9E\u65F6\u5237\u65B0\uFF1B\u4E14\u4EC5\u666E\u901A\u7FA4\u53EF\u7528\uFF08\u8BDD\u9898\u7FA4 / \u5355\u804A\u4F1A\u5931\u8D25\uFF0C\u4E0D\u964D\u7EA7\uFF09\u3002\u53EA\u5F71\u54CD /card \u547D\u4EE4\uFF0C\u81EA\u52A8\u6D41\u5F0F\u5361\u4E0D\u53D8\u3002","botDefaults.cardPrefSaved":"\u5DF2\u4FDD\u5B58","botDefaults.sectionRole":"\u9ED8\u8BA4\u89D2\u8272","botDefaults.roleHelp":"\u8BE5 bot \u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF08\u8DE8\u7FA4\u751F\u6548\uFF09\uFF0C\u4F1A\u6CE8\u5165\u5230\u8BE5 bot \u5728\u5404\u7FA4\u7684\u4F1A\u8BDD\u91CC\uFF1B\u5355\u4E2A\u7FA4\u53EF\u5728\u300C\u89D2\u8272\u300D\u9875\u5355\u72EC\u8986\u76D6\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u5220\u9664\u3002","botDefaults.rolePlaceholder":"\u4F8B\u5982\uFF1A\u4F60\u662F\u540E\u7AEF\u6392\u969C\u52A9\u624B\uFF0C\u56DE\u7B54\u7B80\u6D01\u3001\u4F18\u5148\u7ED9\u53EF\u6267\u884C\u547D\u4EE4\u2026","botDefaults.roleSave":"\u4FDD\u5B58\u89D2\u8272","botDefaults.roleDelete":"\u5220\u9664","botDefaults.roleSaved":"\u5DF2\u4FDD\u5B58","botDefaults.roleDeleted":"\u5DF2\u5220\u9664","botDefaults.roleLoadErr":"\u89D2\u8272\u52A0\u8F7D\u5931\u8D25","botDefaults.sectionAutoStart":"\u4E3B\u52A8\u5F00\u5DE5","botDefaults.autoStartJoin":"\u88AB\u62C9\u8FDB\u65B0\u7FA4\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartJoinHelp":"\u5F00\u542F\u540E\uFF0C\u673A\u5668\u4EBA\u4E00\u88AB\u62C9\u8FDB\u65B0\u7FA4\uFF08\u7FA4\u91CC\u6709\u6388\u6743\u7528\u6237 allowedUsers \u65F6\uFF09\u5C31\u81EA\u52A8\u5F00\u4E00\u4E2A\u4F1A\u8BDD\u5F00\u59CB\u5DE5\u4F5C\uFF0C\u65E0\u9700 @\u3002\u5728\u673A\u5668\u4EBA\u7684\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55\u542F\u52A8\uFF1B\u672A\u914D\u7F6E\u9ED8\u8BA4\u76EE\u5F55\u65F6\u5148\u5F39\u4ED3\u5E93\u9009\u62E9\u5361\u8BA9\u4F60\u9009\u3002\u524D\u63D0\uFF1A\u9700\u5728\u98DE\u4E66\u5F00\u653E\u5E73\u53F0\u4E3A\u672C\u5E94\u7528\u8BA2\u9605\u300C\u673A\u5668\u4EBA\u8FDB\u7FA4\u300D\u4E8B\u4EF6 im.chat.member.bot.added_v1\uFF0C\u5E76\u5F00\u901A\u7FA4\u6210\u5458\u8BFB\u53D6\u6743\u9650\u3002","botDefaults.autoStartJoinPrompt":"\u5165\u7FA4\u9996\u8F6E prompt\uFF08\u53EF\u9009\uFF09","botDefaults.autoStartJoinPromptPlaceholder":"\u586B\u4E86\uFF1D\u4F5C\u4E3A\u5165\u7FA4\u540E\u7684\u7B2C\u4E00\u6761\u4EFB\u52A1\uFF1B\u7559\u7A7A\uFF1D\u673A\u5668\u4EBA\u81EA\u5DF1\u770B\u7FA4\u91CC\u4FE1\u606F\u51B3\u5B9A\u505A\u4EC0\u4E48","botDefaults.autoStartJoinPromptSave":"\u4FDD\u5B58 prompt","botDefaults.autoStartTopic":"\u8BDD\u9898\u7FA4\u65B0\u8BDD\u9898\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartTopicHelp":"\u5F00\u542F\u540E\uFF0C\u5728\u8BDD\u9898\u7FA4\u91CC\u6BCF\u5F53\u6709\u4EBA\u65B0\u5F00\u4E00\u4E2A\u8BDD\u9898\uFF0C\u673A\u5668\u4EBA\u5C31\u4F1A\u81EA\u52A8\u63A5\u5165\u8BE5\u8BDD\u9898\u3001\u628A\u9996\u6761\u6D88\u606F\u5F53\u4F5C\u4EFB\u52A1\u5F00\u59CB\u5904\u7406\uFF0C\u65E0\u9700 @\u3002\u4EC5\u5BF9\u8BDD\u9898\u7FA4\u751F\u6548\uFF0C\u666E\u901A\u7FA4\u4E0D\u53D7\u5F71\u54CD\u3002","botDefaults.sectionSessionMode":"\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.p2pMode":"\u79C1\u804A\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.p2pThread":"thread\uFF08\u6BCF\u6761 DM \u72EC\u7ACB\u4F1A\u8BDD\uFF09","botDefaults.p2pChat":"chat\uFF08\u6241\u5E73\u8FDE\u7EED\u5355\u804A\u4F1A\u8BDD\uFF09","botDefaults.p2pHelp":"\u79C1\u804A\uFF081:1 DM\uFF09\u7684\u4F1A\u8BDD\u65B9\u5F0F\uFF1Athread = \u6BCF\u6761\u9876\u5C42\u6D88\u606F\u5404\u81EA\u8D77\u72EC\u7ACB\u4F1A\u8BDD\uFF08\u907F\u514D\u628A\u5BF9\u8BDD\u5806\u8FDB\u540C\u4E00\u4E2A CLI \u8FDB\u7A0B\uFF09\uFF1Bchat = \u6574\u6BB5 DM \u5171\u7528\u4E00\u4E2A\u8FDE\u7EED\u4F1A\u8BDD\u3001\u5171\u4EAB\u4E0A\u4E0B\u6587\uFF08\u7C7B Hermes\uFF09\u3002\u6539\u540E\u7ACB\u5373\u751F\u6548\u3002","botDefaults.regularGroupMode":"\u666E\u901A\u7FA4\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.regularGroupModeChat":"chat\uFF08\u6241\u5E73\u8FDE\u7EED\u5355\u804A\u4F1A\u8BDD\uFF0C\u9ED8\u8BA4\uFF09","botDefaults.regularGroupModeNewTopic":"new-topic\uFF08\u6BCF\u6761\u9876\u5C42 @ \u5404\u5F00\u72EC\u7ACB\u8BDD\u9898\u4E0E\u4F1A\u8BDD\uFF09","botDefaults.regularGroupModeShared":"shared\uFF08\u8BDD\u9898\u6A21\u5F0F\u4F46\u590D\u7528\u540C\u4E00\u4E2A session\uFF09","botDefaults.regularGroupModeHelp":"\u666E\u901A\u7FA4\uFF08\u975E\u8BDD\u9898\u7FA4\uFF09\u91CC @ \u8BE5 bot \u7684\u65B0\u9876\u5C42\u6D88\u606F\u600E\u4E48\u5F00\u4F1A\u8BDD\uFF1Achat = \u6574\u7FA4\u5171\u7528\u4E00\u4E2A\u8FDE\u7EED\u4F1A\u8BDD\uFF08\u9ED8\u8BA4\uFF09\uFF1Bnew-topic = \u6BCF\u6761\u9876\u5C42 @ \u5728\u539F\u6D88\u606F\u4E0B\u5F00\u72EC\u7ACB\u8BDD\u9898\u3001\u5404\u81EA\u72EC\u7ACB\u4F1A\u8BDD\uFF1Bshared = \u8BDD\u9898\u6A21\u5F0F\u4F46\u590D\u7528\u540C\u4E00\u4E2A session\uFF08\u56DE\u590D\u843D\u5728\u8BDD\u9898\u91CC\u3001\u4F46\u5171\u7528\u672C\u7FA4\u4F1A\u8BDD\u4E0E\u4E0A\u4E0B\u6587\uFF09\u3002\u8FD9\u662F per-bot \u9ED8\u8BA4\uFF0C\u5177\u4F53\u67D0\u4E2A\u7FA4\u53EF\u7528 /reply-mode \u5355\u72EC\u8986\u76D6\u3002\u6539\u540E\u7ACB\u5373\u751F\u6548\u3002","botDefaults.mentionMode":"\u7FA4\u804A @ \u7B56\u7565","botDefaults.mentionModeAlways":"\u90FD\u9700\u8981 @\uFF08\u9ED8\u8BA4\uFF09","botDefaults.mentionModeTopic":"\u4EC5\u8BDD\u9898\u5185\u4E0D\u9700\u8981 @","botDefaults.mentionModeNever":"\u6240\u6709\u6D88\u606F\u90FD\u4E0D\u9700\u8981 @","botDefaults.mentionModeHelp":"\u8BE5 bot \u5168\u5C40\u751F\u6548\uFF0C\u51B3\u5B9A\u7FA4\u91CC\u8981\u4E0D\u8981 @ \u624D\u56DE\uFF1A\u300C\u90FD\u9700\u8981 @\u300D= \u4EFB\u4F55\u6D88\u606F\u90FD\u5F97 @\uFF08\u9ED8\u8BA4\uFF0C\u6700\u5B89\u5168\uFF1B\u591A\u4EBA\u7FA4\u91CC\u8BDD\u9898\u5185\u4E5F\u8981 @\uFF09\uFF1B\u300C\u4EC5\u8BDD\u9898\u5185\u4E0D\u9700\u8981 @\u300D= \u8D77\u65B0\u5BF9\u8BDD / \u9876\u5C42\u4ECD\u8981 @\uFF0C\u4F46\u5728\u8BE5 bot \u5DF2\u5F00\u7684\u4EFB\u4F55\u8BDD\u9898\u91CC\uFF08new-topic / shared / \u8BDD\u9898\u7FA4\uFF09\u540E\u7EED\u6D88\u606F\u514D @ \u7EED\u804A\uFF1B\u300C\u6240\u6709\u6D88\u606F\u90FD\u4E0D\u9700\u8981 @\u300D= \u8BE5 bot \u6709\u5BF9\u8BDD\u6743\u9650\u7684\u7FA4\u91CC\u975E @ \u6D88\u606F\u4E5F\u56DE\uFF08\u542B\u5168\u65B0\u6D88\u606F\u51B7\u542F\u52A8\uFF0C\u4EC5\u9002\u5408\u4E13\u7528 / \u503C\u73ED\u5C0F\u7FA4\uFF0C\u591A\u4EBA\u7FA4\u91CC\u4F1A\u89C1\u6D88\u606F\u5C31\u56DE\uFF09\u3002\u6CE8\uFF1A\u7FA4\u91CC\u53EA\u6709\u4F60\u548C\u8BE5 bot\uFF081 \u5BF9 1\uFF09\u65F6\u4E00\u76F4\u514D @\uFF0C\u4E0E\u672C\u8BBE\u7F6E\u65E0\u5173\u3002","botDefaults.sectionGrant":"\u6388\u6743\u4E0E\u989D\u5EA6","botDefaults.restrictGrant":"\u9650\u5236\u88AB\u6388\u6743\u4EBA\u53EA\u80FD\u7EAF\u5BF9\u8BDD","botDefaults.restrictGrantHelp":"\u5F00\u542F\u540E\uFF0C\u88AB /grant \u6388\u6743\u7684\u4EBA\uFF08owner \u81EA\u5DF1\u4E0D\u53D7\u9650\uFF09\u53EA\u80FD\u53D1\u666E\u901A\u5BF9\u8BDD\uFF0C\u6240\u6709 slash \u547D\u4EE4\u4E00\u5F8B\u62E6\u622A\uFF1Abotmux \u81EA\u5E26\u547D\u4EE4\u3001\u900F\u4F20\u547D\u4EE4\u3001/workflow\u3001/introduce\u3001/t \u4EE5\u53CA CLI \u539F\u751F\u547D\u4EE4\uFF08/help \u7B49\uFF09\u3002\u5F62\u5982 /path/to/file \u7684\u5185\u5BB9\u4E0D\u4F1A\u88AB\u8BEF\u5224\u3002","botDefaults.quotaDefault":"\u9ED8\u8BA4\u6D88\u606F\u989D\u5EA6","botDefaults.quotaPlaceholder":"\u7559\u7A7A\uFF1D\u4E0D\u914D\u7F6E\u9ED8\u8BA4\u989D\u5EA6","botDefaults.quotaHelp":"\u4E0D\u5E26\u6570\u5B57\u7684 /grant @x \u9ED8\u8BA4\u7ED9\u7684\u6D88\u606F\u6761\u6570\u3002\u7559\u7A7A\u6216\u70B9\u300C\u5173\u95ED\u300D\u53EA\u662F\u4E0D\u518D\u7ED9\u88F8 /grant \u5957\u9ED8\u8BA4\u989D\u5EA6\uFF0C\u4E0D\u4F1A\u6E05\u6389\u5DF2\u6709\u7684\u989D\u5EA6\u8BA1\u6570\uFF0C\u4E5F\u4E0D\u5F71\u54CD\u663E\u5F0F /grant @x N\u2014\u2014\u5B83\u4EEC\u7167\u5E38\u7EE7\u7EED enforce\u3002\u989D\u5EA6\u7528\u5C3D\u4F1A\u81EA\u52A8\u64A4\u9500\u8BE5\u4EBA\u6388\u6743\u3002","botDefaults.quotaSave":"\u4FDD\u5B58\u989D\u5EA6","botDefaults.quotaOff":"\u5173\u95ED","botDefaults.quotaInvalid":"\u989D\u5EA6\u5FC5\u987B\u662F\u6B63\u6574\u6570","botDefaults.quotaStateOff":"\u5F53\u524D\uFF1A\u672A\u914D\u7F6E\u9ED8\u8BA4\u989D\u5EA6","botDefaults.quotaStateOn":"\u5F53\u524D\uFF1A\u6BCF\u4EBA {count} \u6761","nav.roles":"\u89D2\u8272\u7BA1\u7406","roles.title":"\u89D2\u8272\u7BA1\u7406","roles.subtitle":"\u4E3A\u6BCF\u4E2A\u7FA4\u7EC4\u7684\u6BCF\u4E2A Bot \u5355\u72EC\u8BBE\u7F6E\u89D2\u8272\u63D0\u793A\u8BCD\uFF0CBot \u5728\u8BE5\u7FA4\u4E2D\u4F1A\u4EE5\u6B64\u89D2\u8272\u884C\u4E8B\u3002","roles.search":"\u641C\u7D22\u7FA4\u540D/Bot/ID","roles.refresh":"\u5237\u65B0","roles.selectHint":"\u2190 \u5C55\u5F00\u7FA4\u7EC4\uFF0C\u9009\u62E9\u4E00\u4E2A Bot \u6765\u7F16\u8F91\u89D2\u8272","roles.editorPlaceholder":`\u8F93\u5165\u89D2\u8272\u63CF\u8FF0\uFF0C\u4F8B\u5982\uFF1A
|
|
1
|
+
"use strict";(()=>{var bn=class{sessions=new Map;schedules=new Map;online=!0;listeners=new Set;upsertSessions(n){for(let a of n)this.sessions.set(a.sessionId,a);this.emit()}upsertSchedules(n){for(let a of n)this.schedules.set(a.id,a);this.emit()}applySse(n,a){if(n==="session.spawned")this.sessions.set(a.session.sessionId,a.session);else if(n==="session.update"){let s=this.sessions.get(a.sessionId);s&&this.sessions.set(a.sessionId,{...s,...a.patch})}else if(n==="session.exited"){let s=this.sessions.get(a.sessionId);s&&this.sessions.set(a.sessionId,{...s,status:"closed"})}else if(n==="schedule.created")this.schedules.set(a.schedule.id,a.schedule);else if(n==="schedule.updated"){let s=this.schedules.get(a.id);s&&this.schedules.set(a.id,{...s,...a.patch})}else if(n==="schedule.deleted")this.schedules.delete(a.id);else return;this.emit()}setOnline(n){this.online!==n&&(this.online=n,this.emit())}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}},V=new bn;async function ua(){let[e,n]=await Promise.all([fetch("/api/sessions").then(o=>o.json()),fetch("/api/schedules").then(o=>o.json())]);V.upsertSessions(e.sessions??[]),V.upsertSchedules(n.schedules??[]);let a=new EventSource("/events"),s=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let o of s)a.addEventListener(o,r=>{try{let c=JSON.parse(r.data);V.applySse(o,c.body??c)}catch{}});a.onerror=()=>V.setOnline(!1),a.onopen=()=>V.setOnline(!0)}var hn="botmux.dashboard.locale",rs={"app.name":"botmux","app.subtitle":"\u98DE\u4E66 AI CLI \u63A7\u5236\u53F0","time.secondsAgo":"{value} \u79D2\u524D","time.minutesAgo":"{value} \u5206\u949F\u524D","time.hoursAgo":"{value} \u5C0F\u65F6\u524D","nav.overview":"\u603B\u89C8","nav.sessions":"\u4F1A\u8BDD","nav.sidebarCollapse":"\u6536\u8D77\u83DC\u5355\u680F","nav.sidebarExpand":"\u5C55\u5F00\u83DC\u5355\u680F","nav.groups":"\u7FA4\u7EC4","nav.schedules":"\u5B9A\u65F6","nav.settings":"\u8BBE\u7F6E","nav.botDefaults":"Bot \u914D\u7F6E","status.live":"\u5B9E\u65F6\u8FDE\u63A5","status.disconnected":"\u8FDE\u63A5\u65AD\u5F00","status.system":"\u7CFB\u7EDF","status.light":"\u6D45\u8272","status.dark":"\u6697\u9ED1","status.language":"\u8BED\u8A00","status.theme":"\u4E3B\u9898","theme.base":"\u57FA\u7840","theme.skins":"\u4E3B\u9898\u76AE\u80A4","skin.cyber":"2077","skin.genshin":"\u539F\u795E","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"\u851A\u84DD\u6863\u6848","skin.zzz":"\u7EDD\u533A\u96F6","skin.dragonball":"\u4E03\u9F99\u73E0","skin.ikun":"ikun","botOnboarding.add":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.title":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.intro":"\u9009\u62E9 CLI \u4E0E\u5DE5\u4F5C\u76EE\u5F55\uFF0C\u626B\u7801\u521B\u5EFA PersonalAgent \u5E94\u7528\u540E\u5199\u5165\u672C\u673A bots.json\uFF0C\u5E76\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u3002","botOnboarding.cliLabel":"CLI \u9002\u914D\u5668","botOnboarding.dirLabel":"\u5DE5\u4F5C\u76EE\u5F55","botOnboarding.dirPlaceholder":"\u9ED8\u8BA4 ~\uFF08\u5BB6\u76EE\u5F55\uFF09\uFF0C\u9700\u4E3A daemon \u4E3B\u673A\u4E0A\u5DF2\u5B58\u5728\u7684\u76EE\u5F55","botOnboarding.modelLabel":"\u6A21\u578B\uFF08\u53EF\u9009\uFF09","botOnboarding.modelPlaceholder":"\u7559\u7A7A\u4F7F\u7528\u8BE5 CLI \u7684\u9ED8\u8BA4\u6A21\u578B","botOnboarding.startScan":"\u5F00\u59CB\u626B\u7801","botOnboarding.cancel":"\u53D6\u6D88","botOnboarding.starting":"\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...","botOnboarding.waiting":"\u8BF7\u7528\u98DE\u4E66 App \u626B\u7801\u786E\u8BA4\u521B\u5EFA\u5E94\u7528\u3002","botOnboarding.verifying":"\u626B\u7801\u6210\u529F\uFF0C\u6B63\u5728\u6821\u9A8C\u51ED\u8BC1...","botOnboarding.configuringPermissions":"\u6B63\u5728\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u2026","botOnboarding.platformScanHint":"\u8BF7\u7528\u98DE\u4E66 App \u518D\u626B\u4E00\u6B21\u7801\u767B\u5F55\u5F00\u653E\u5E73\u53F0\uFF08\u7528\u4E8E\u81EA\u52A8\u5BFC\u5165\u6743\u9650\u3001\u914D\u7F6E\u56DE\u8C03\u3001\u63D0\u4EA4\u7248\u672C\uFF09\u3002","botOnboarding.platformQrAlt":"\u5F00\u653E\u5E73\u53F0\u767B\u5F55\u4E8C\u7EF4\u7801","botOnboarding.completed":"\u673A\u5668\u4EBA\u5DF2\u6DFB\u52A0\u3002","botOnboarding.permissionOk":"\u5DF2\u81EA\u52A8\u5BFC\u5165 {count} \u9879\u6743\u9650\u3002","botOnboarding.permissionSkipped":"\uFF08\u8DF3\u8FC7 {count} \u9879\u5F53\u524D\u79DF\u6237\u76EE\u5F55\u4E2D\u6CA1\u6709\u7684\u6743\u9650\uFF09","botOnboarding.permissionVersion":"\u5DF2\u63D0\u4EA4\u53D1\u5E03\u7248\u672C {version}\u3002","botOnboarding.permissionManual":"\u6743\u9650\u672A\u80FD\u81EA\u52A8\u914D\u7F6E\uFF0C\u8BF7\u624B\u52A8\u5B8C\u6210\u4EE5\u4E0B\u6B65\u9AA4\uFF1A","botOnboarding.metaDir":"\u76EE\u5F55","botOnboarding.failed":"\u6DFB\u52A0\u5931\u8D25","botOnboarding.openLink":"\u6253\u4E0D\u5F00\u626B\u7801\uFF1F\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00","botOnboarding.close":"\u5173\u95ED","botOnboarding.restartHint":"\u5DF2\u5199\u5165 bots.json\u3002\u6267\u884C pnpm daemon:restart \u540E\u65B0\u673A\u5668\u4EBA\u751F\u6548\u3002","botOnboarding.qrAlt":"\u98DE\u4E66\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA\u4E8C\u7EF4\u7801","overview.title":"\u5DE5\u4F5C\u53F0","overview.subtitle":"\u6570\u5B57\u5458\u5DE5\u5B9E\u65F6\u72B6\u6001 \xB7 \u540C\u6B65\u98DE\u4E66\u8BDD\u9898","overview.team":"AI \u56E2\u961F","overview.teamHint":"\u6BCF\u4F4D\u6570\u5B57\u5458\u5DE5\u7684\u5B9E\u65F6\u72B6\u6001","overview.attention":"\u9700\u8981\u4F60\u5904\u7406","overview.attentionHint":"\u5361\u4F4F\u7684\u4EFB\u52A1\uFF0C\u56DE\u4E2A\u8BDD\u5C31\u80FD\u7EE7\u7EED\u8DD1","overview.activeSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.activeSessionsHint":"\u6B63\u5728\u8FD0\u8F6C\u7684\u4F1A\u8BDD","overview.today":"\u6B64\u523B\u6982\u89C8","overview.todayHint":"\u6D3B\u8DC3\u4F1A\u8BDD\u5206\u5E03","overview.viewAll":"\u67E5\u770B\u5168\u90E8 \u2192","overview.botIdle":"\u5F85\u547D\u4E2D\uFF0C\u968F\u65F6\u53EF\u63A5\u65B0\u4EFB\u52A1","overview.botOffline":"\u79BB\u7EBF \u2014 daemon \u672A\u4E0A\u7EBF","overview.botBusy":"\u6267\u884C\u4E2D \xB7 {count} \u4F1A\u8BDD","overview.botNeedsYou":"\u7B49\u4F60\u56DE\u590D","overview.botReady":"\u5C31\u7EEA","overview.botOff":"\u79BB\u7EBF","overview.sessionsCount":"{count} \u4F1A\u8BDD","overview.lastActive":"{time}\u524D\u6D3B\u8DC3","overview.noAttention":"\u6CA1\u6709\u7B49\u4F60\u5904\u7406\u7684\u4E8B\u9879","overview.teamExpand":"\u5C55\u5F00\u5168\u90E8 {count} \u4F4D \u25BE","overview.teamCollapse":"\u6536\u8D77 \u25B4","strip.pending":"{count} \u4EF6\u5F85\u5904\u7406","strip.longest":"\u6700\u4E45\u5DF2\u7B49 {time} \u2014 {bot} {reason}","strip.handle":"\u7ACB\u5373\u5904\u7406","overview.openSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.workingSessions":"\u5DE5\u4F5C\u4E2D","overview.onlineBots":"\u5728\u7EBF Bot","overview.schedules":"\u5B9A\u65F6\u4EFB\u52A1","overview.groups":"\u7FA4\u804A\u8986\u76D6","overview.enabledSchedules":"\u5DF2\u542F\u7528","overview.total":"\u603B\u8BA1","overview.active":"\u6D3B\u8DC3","overview.daemonRegistry":"daemon \u6CE8\u518C\u8868","overview.chatMatrix":"\u7FA4\u804A\u77E9\u9635","overview.recentSessions":"\u6700\u8FD1\u4F1A\u8BDD","overview.nextSchedules":"\u5373\u5C06\u6267\u884C","overview.noSessions":"\u6682\u65E0\u4F1A\u8BDD\u3002","overview.noSchedules":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","sessions.title":"\u4F1A\u8BDD\u63A7\u5236","sessions.subtitle":"\u5B9A\u4F4D\u98DE\u4E66\u8BDD\u9898\u3001\u6253\u5F00 Web Terminal\u3001\u5173\u95ED\u6216\u6062\u590D CLI \u4F1A\u8BDD\u3002","sessions.search":"\u641C\u7D22\u5DE5\u4F5C\u76EE\u5F55 / \u6807\u9898 / ID","sessions.anyStatus":"\u5168\u90E8\u72B6\u6001","sessions.adoptAny":"adopt: \u5168\u90E8","sessions.adoptYes":"adopt: \u662F","sessions.adoptNo":"adopt: \u5426","sessions.activeOnly":"\u4EC5\u6D3B\u8DC3","sessions.closeSelected":"\u5173\u95ED\u9009\u4E2D","sessions.clearSelection":"\u53D6\u6D88\u9009\u62E9","sessions.selectedCount":"\u5DF2\u9009 {count} \u4E2A\u4F1A\u8BDD","sessions.bot":"bot","sessions.cli":"CLI","sessions.chat":"\u7FA4\u804A","sessions.openChat":"\u6253\u5F00\u7FA4\u804A","sessions.status":"\u72B6\u6001","sessions.tokenIn":"Token In","sessions.tokenOut":"Token Out","sessions.titleCol":"\u6807\u9898","sessions.workingDir":"\u5DE5\u4F5C\u76EE\u5F55","sessions.created":"\u521B\u5EFA","sessions.last":"\u6700\u8FD1","sessions.adopt":"\u63A5\u5165","sessions.actions":"\u64CD\u4F5C","sessions.details":"\u8BE6\u60C5","sessions.copy":"\u590D\u5236","sessions.copied":"\u5DF2\u590D\u5236","sessions.locate":"\u5B9A\u4F4D\u8BDD\u9898","sessions.locating":"\u53D1\u9001\u4E2D...","sessions.cooldown":"\u51B7\u5374 {seconds}s","sessions.openTerminal":"\u7EC8\u7AEF","sessions.writeLink":"\u64CD\u4F5C\u94FE\u63A5","sessions.writeLinkHint":"\u83B7\u53D6\u53EF\u64CD\u4F5C\u7EC8\u7AEF\u94FE\u63A5\uFF08\u5E26\u5199\u6743\u9650 token\uFF0C\u65B0\u6807\u7B7E\u6253\u5F00\uFF09","sessions.writeLinkFail":"\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u5931\u8D25","sessions.close":"\u5173\u95ED\u4F1A\u8BDD","sessions.resume":"\u6062\u590D\u4F1A\u8BDD","sessions.dismiss":"\u5173\u95ED","sessions.closeConfirm":"\u5173\u95ED\u8FD9\u4E2A\u4F1A\u8BDD\uFF1F","sessions.resumeFailed":"\u6062\u590D\u5931\u8D25","sessions.land":"\u843D\u76D8","sessions.landLoading":"\u52A0\u8F7D\u6C99\u76D2 diff\u2026","sessions.landUnavailable":"\u65E0\u6CD5\u843D\u76D8","sessions.landEmpty":"\u6C99\u76D2\u526F\u672C\u6CA1\u6709\u6539\u52A8\u3002","sessions.landApply":"\u5E94\u7528\u5230\u78C1\u76D8","sessions.landDiscard":"\u4E22\u5F03","sessions.landApplied":"\u5DF2\u843D\u76D8","sessions.landFailed":"\u843D\u76D8\u5931\u8D25","sessions.landDiscarded":"\u5DF2\u4E22\u5F03\uFF08\u6C99\u76D2\u526F\u672C\u672A\u5E94\u7528\uFF09\u3002","connectors.lede":"\u8BA9\u5916\u90E8\u7CFB\u7EDF\uFF08\u76D1\u63A7\u544A\u8B66\u3001CI\u3001\u5DE5\u5355\u2026\uFF09\u901A\u8FC7\u4E00\u4E2A webhook \u89E6\u53D1\u673A\u5668\u4EBA\u5728\u7FA4\u91CC\u8BF4\u8BDD\u6216\u8DD1\u5DE5\u4F5C\u6D41\u3002","connectors.createTitle":"\u65B0\u5EFA Webhook","connectors.fName":"\u540D\u79F0","connectors.fNamePh":"\u5982\uFF1A\u7EBF\u4E0A\u544A\u8B66","connectors.fBot":"\u89E6\u53D1\u7684\u673A\u5668\u4EBA","connectors.fKind":"\u89E6\u53D1\u65B9\u5F0F","connectors.kindTurn":"\u5355\u8F6E\u5BF9\u8BDD\uFF08\u8BA9\u673A\u5668\u4EBA\u56DE\u5E94\u4E00\u6B21\uFF09","connectors.kindWorkflow":"\u5DE5\u4F5C\u6D41","connectors.fWf":"\u5DE5\u4F5C\u6D41 ID","connectors.fMode":"\u6295\u9012\u5230\u54EA\u4E2A\u7FA4","connectors.modeDynamic":"\u7531\u8BF7\u6C42\u6307\u5B9A\uFF08\u7FA4\u968F\u8BF7\u6C42\u4F20\u5165\uFF09","connectors.modeFixed":"\u56FA\u5B9A\u7FA4","connectors.modeNewGroup":"\u6BCF\u6B21\u65B0\u5EFA\u7FA4","connectors.fFixedChat":"\u6295\u9012\u5230\u7684\u7FA4","connectors.fChatManualPh":"\u624B\u52A8\u586B\u7FA4 ID\uFF1Aoc_\u2026","connectors.chatManualLink":"\u627E\u4E0D\u5230\u7FA4\uFF1F\u624B\u52A8\u586B ID \u2192","connectors.chatListLink":"\u4ECE\u7FA4\u5217\u8868\u9009\u62E9 \u2190","connectors.fAllow":"\u5141\u8BB8\u7684\u7FA4","connectors.optional":"\uFF08\u53EF\u9009\uFF09","connectors.allowHint":"\u6309\u4F4F Ctrl/\u2318 \u591A\u9009\uFF1B\u7559\u7A7A = \u4E0D\u9650\u3002\u53EA\u7528\u4E8E\u6821\u9A8C\u8BF7\u6C42\u4F20\u5165\u7684\u7FA4\u662F\u5426\u88AB\u5141\u8BB8\u3002","connectors.dynamicHint":'<b>\u52A8\u6001\u6A21\u5F0F</b>\uFF1A\u7FA4 ID \u968F\u6BCF\u6B21\u8BF7\u6C42\u4F20\u5165\uFF0C\u4E09\u9009\u4E00 \u2014\u2014 \u67E5\u8BE2\u53C2\u6570 <code>?chatId=<\u7FA4ID></code> \xB7 \u8BF7\u6C42\u5934 <code>x-botmux-chat-id: <\u7FA4ID></code> \xB7 \u8BF7\u6C42\u4F53 <code>{"chatId":"<\u7FA4ID>"}</code>\u3002<br>\u60F3"\u4E00\u4E2A URL \u76F4\u63A5\u89E6\u53D1\u3001\u4E0D\u5E26\u53C2\u6570"\uFF0C\u8BF7\u6539\u9009\u300C\u56FA\u5B9A\u7FA4\u300D\u3002',"connectors.fDedup":"\u53BB\u91CD\u5B57\u6BB5","connectors.fDedupPh":"\u5982 alert.id\uFF08\u4ECE\u4E8B\u4EF6 body \u53D6\u503C\uFF09","connectors.dedupHint":"\u586B\u4E86\uFF1A\u547D\u4E2D\u76F8\u540C\u503C\u7684\u4E8B\u4EF6\u90FD\u6295\u5230<b>\u540C\u4E00\u4E2A\u7FA4</b>\u3002\u7559\u7A7A\uFF1A\u6BCF\u4E2A\u4E8B\u4EF6<b>\u65B0\u5EFA\u4E00\u4E2A\u7FA4</b>\u3002","connectors.fInstruction":"\u5904\u7406\u6307\u4EE4","connectors.fInstructionPh":"\u4E8B\u4EF6\u89E6\u53D1\u65F6\u8BA9\u673A\u5668\u4EBA\u505A\u4EC0\u4E48\u3002\u5982\uFF1A\u603B\u7ED3\u8FD9\u6761\u544A\u8B66\u7684\u4E25\u91CD\u7A0B\u5EA6\uFF0C@\u76F8\u5173 oncall\uFF0C\u7ED9\u51FA\u6392\u67E5\u5EFA\u8BAE\u3002\u7559\u7A7A = \u53EA\u628A\u4E8B\u4EF6\u539F\u6837\u4EA4\u7ED9\u6A21\u578B\u81EA\u7531\u53D1\u6325\u3002","connectors.fVerify":"\u6821\u9A8C\u65B9\u5F0F","connectors.verifyToken":"\u4EE4\u724C\uFF08\u7B80\u5355\uFF1A\u5BC6\u94A5\u653E\u8FDB URL\uFF0C\u4E00\u6761 curl \u5C31\u80FD\u89E6\u53D1\uFF09","connectors.verifyHmac":"HMAC \u7B7E\u540D\uFF08\u9AD8\u7EA7\uFF1A\u66F4\u5B89\u5168\uFF0C\u9700\u81EA\u884C\u5BF9\u8BF7\u6C42\u7B7E\u540D\uFF09","connectors.fSecret":"\u5BC6\u94A5 / \u4EE4\u724C","connectors.fSecretPh":"\u7559\u7A7A\u81EA\u52A8\u751F\u6210\uFF08\u53EA\u663E\u793A\u4E00\u6B21\uFF09","connectors.btnCreate":"\u521B\u5EFA","connectors.listTitle":"\u5DF2\u6709 Webhook","connectors.loading":"\u52A0\u8F7D\u4E2D\u2026","connectors.noBotGroups":"\uFF08\u8BE5\u673A\u5668\u4EBA\u6682\u65E0\u53EF\u89C1\u7FA4\uFF0C\u70B9\u53F3\u4FA7\u624B\u52A8\u586B ID\uFF09","connectors.modeLabelFixed":"\u56FA\u5B9A\u7FA4","connectors.modeLabelNewGroup":"\u6BCF\u6B21\u65B0\u5EFA\u7FA4","connectors.modeLabelDynamic":"\u8BF7\u6C42\u6307\u5B9A\u7FA4","connectors.kindLabelWorkflow":"\u5DE5\u4F5C\u6D41","connectors.kindLabelTurn":"\u5355\u8F6E","connectors.count":"\xB7 {count} \u4E2A","connectors.empty":"\u8FD8\u6CA1\u6709 Webhook\u3002\u7528\u4E0A\u9762\u7684\u8868\u5355\u521B\u5EFA\u4E00\u4E2A\u3002","connectors.enabled":"\u5DF2\u542F\u7528","connectors.disabled":"\u5DF2\u505C\u7528","connectors.badgeToken":"\u4EE4\u724C","connectors.badgeSign":"\u7B7E\u540D","connectors.dest":"\u6295\u9012\u300C{name}\u300D","connectors.btnDisable":"\u505C\u7528","connectors.btnEnable":"\u542F\u7528","connectors.btnDel":"\u5220\u9664","connectors.webhookUrl":"Webhook URL\uFF1A","connectors.copy":"\u590D\u5236","connectors.copied":"\u5DF2\u590D\u5236","connectors.tokenHint":"\u4EE4\u724C\u6A21\u5F0F\uFF1A\u8C03\u7528\u65F6\u5728 URL \u672B\u5C3E\u8FFD\u52A0 <code>/<\u4EE4\u724C></code>\uFF08\u4EE4\u724C\u4EC5\u521B\u5EFA/\u8F6E\u6362\u65F6\u663E\u793A\u4E00\u6B21\uFF09\u3002","connectors.dynamicReqHint":'\u52A8\u6001\u6A21\u5F0F\uFF1A\u8BF7\u6C42\u9700\u5E26\u76EE\u6807\u7FA4 \u2014\u2014 <code>?chatId=<\u7FA4ID></code> \u6216\u5934 <code>x-botmux-chat-id</code> \u6216 body <code>{"chatId":"\u2026"}</code>\u3002',"connectors.instructionPrefix":"\u5904\u7406\u6307\u4EE4\uFF1A","connectors.delConfirm":"\u5220\u9664\u8FD9\u4E2A Webhook\uFF1F\u5B83\u7684 URL \u4F1A\u7ACB\u5373\u5931\u6548\u3002","connectors.errName":"\u8BF7\u586B\u540D\u79F0","connectors.errBot":"\u8BF7\u9009\u673A\u5668\u4EBA","connectors.errWf":"\u8BF7\u586B\u5DE5\u4F5C\u6D41 ID","connectors.errChat":"\u8BF7\u9009\u62E9\uFF08\u6216\u624B\u52A8\u586B\uFF09\u6295\u9012\u7684\u7FA4","connectors.creating":"\u521B\u5EFA\u4E2D\u2026","connectors.usageDynamicLede":"\u52A8\u6001\u6A21\u5F0F\uFF1AURL \u5DF2\u542B\u4EE4\u724C\uFF0C\u8C03\u7528\u65F6\u518D\u5E26\u4E0A\u76EE\u6807\u7FA4 ID{gn}\uFF1A","connectors.usageDynamicNote":'\u7FA4\u4E5F\u53EF\u653E\u8BF7\u6C42\u5934 <code>x-botmux-chat-id</code> \u6216 body <code>{"chatId":"\u2026"}</code>\u3002\u26A0\uFE0F URL \u5373\u51ED\u8BC1\uFF0C\u52FF\u6CC4\u6F0F\u3002',"connectors.usageTokenLede":"\u6B64 URL \u5DF2\u542B\u4EE4\u724C\u3001\u4E14\u56FA\u5B9A\u6295\u9012\u5230\u6240\u9009\u7FA4\uFF0C\u76F4\u63A5 POST \u5373\u53EF\u89E6\u53D1\uFF1A","connectors.usageTokenNote":"\u26A0\uFE0F URL \u5373\u51ED\u8BC1\uFF0C\u8BF7\u52FF\u516C\u5F00\u6CC4\u6F0F\uFF1B\u53EF\u5728\u4E0B\u65B9\u5217\u8868\u5220\u9664\u6216\u8F6E\u6362\u3002","connectors.usageHmac":"\u5916\u90E8\u7CFB\u7EDF\u9700\u5BF9 <code>timestamp.body</code> \u505A HMAC-SHA256 \u7B7E\u540D\uFF0C\u5E76\u5E26\u4E0A <code>x-botmux-timestamp</code> / <code>x-botmux-nonce</code> / <code>x-botmux-signature</code> \u5934\u8C03\u7528","connectors.usageHmacDynamic":"\uFF0C\u540C\u65F6\u6309\u4E0A\u9762\u65B9\u5F0F\u5E26\u76EE\u6807\u7FA4 ID","connectors.createdPrefix":"\u5DF2\u521B\u5EFA\u300C{name}\u300D","connectors.createdDest":"\u6295\u9012\u5230\u300C{name}\u300D","connectors.tokenLabel":"\u8BBF\u95EE\u4EE4\u724C","connectors.signLabel":"\u7B7E\u540D\u5BC6\u94A5","connectors.secretOnce":"\uFF08\u53EA\u663E\u793A\u8FD9\u4E00\u6B21\uFF0C\u8BF7\u4FDD\u5B58\uFF09\uFF1A","connectors.createFailed":"\u521B\u5EFA\u5931\u8D25\uFF1A{error}","connectors.noOnlineBots":"\uFF08\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF09","team.navHome":"\u6211\u7684\u56E2\u961F","team.navManage":"\u56E2\u961F\u7BA1\u7406","team.eyebrow":"\u56E2\u961F","team.homeTitle":"\u56E2\u961F\u534F\u4F5C\uFF08\u8DE8\u90E8\u7F72\uFF09","team.homeLede":"\u628A\u522B\u7684\u90E8\u7F72\uFF08\u540C\u4E8B\u81EA\u5DF1\u8DD1\u7684 botmux\uFF09\u9080\u8BF7\u8FDB\u540C\u4E00\u4E2A\u56E2\u961F\uFF0C\u4E92\u76F8\u53D1\u73B0\u673A\u5668\u4EBA\u3001\u534F\u4F5C\u62C9\u7FA4\u3002","team.localDeployTitle":"\u672C\u90E8\u7F72","team.myIdentity":"\u6211\u7684\u98DE\u4E66\u8EAB\u4EFD\uFF1A","team.unbound":"\u672A\u7ED1\u5B9A","team.bindBtn":"\u7ED1\u5B9A","team.bindHint":"\uFF08\u7528\u673A\u5668\u4EBA\u51ED\u8BC1\u81EA\u52A8\u8BC6\u522B\u4F60\uFF1B\u7ED1\u5B9A\u540E\u62C9\u7FA4\u4F1A\u628A\u4F60\u62C9\u8FDB\u7FA4\u3001\u673A\u5668\u4EBA\u4E5F\u5F52\u5230\u4F60\u540D\u4E0B\uFF09","team.myTeams":"\u6211\u7684\u56E2\u961F","team.searchPh":"\u641C\u7D22 \u540D\u79F0/\u80FD\u529B/CLI\u2026","team.allCli":"\u5168\u90E8 CLI","team.hasCap":"\u6709\u80FD\u529B\u6807\u7B7E","team.hasRole":"\u6709\u9ED8\u8BA4\u89D2\u8272","team.teamsHint":"\u6BCF\u4E2A\u56E2\u961F\u91CC\u52FE\u9009\u673A\u5668\u4EBA\u5373\u53EF\u5355\u72EC\u62C9\u7FA4\uFF08\u81EA\u52A8\u5E26\u4E0A\u5404\u81EA\u8D1F\u8D23\u4EBA\uFF09\u3002\u8981\u65B0\u5EFA\u56E2\u961F / \u751F\u6210\u9080\u8BF7\u7801 / \u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\uFF0C\u53BB\u300C\u56E2\u961F\u7BA1\u7406\u300D\u3002","team.loading":"\u52A0\u8F7D\u4E2D\u2026","team.roleModalTitle":"\u9ED8\u8BA4\u89D2\u8272","team.roleModalHint":"\u8BE5\u673A\u5668\u4EBA\u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF08\u8DE8\u7FA4\u751F\u6548\uFF09\uFF0C\u6B64\u5904\u53EA\u8BFB\u3002\u5982\u9700\u4FEE\u6539\uFF0C\u8BF7\u5230\u300CBot \u914D\u7F6E\u300D\u9875\u3002","team.close":"\u5173\u95ED","team.tagLocal":"\u672C\u90E8\u7F72","team.tagRemoteStale":"\u8FDC\u7AEF\xB7\u79BB\u7EBF\uFF1F","team.tagRemote":"\u8FDC\u7AEF","team.removeMember":"\u79FB\u9664","team.depTag":"\uFF08{tag}\uFF09","team.depCount":"{count} \u4E2A","team.depSelected":"\uFF0C\u5DF2\u9009 {n}","team.capPh":"\u80FD\u529B\u6807\u7B7E\u2026","team.viewRole":"\u67E5\u770B","team.hasRoleShort":"\u6709\u89D2\u8272","team.noMatch":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u673A\u5668\u4EBA\u3002","team.gnamePh":"\u7FA4\u540D\uFF08\u5982\uFF1A\u8DE8\u56E2\u961F\u6392\u969C\uFF09","team.pullGroupBtn":"\u628A\u52FE\u9009\u7684\u673A\u5668\u4EBA\u62C9\u4E00\u4E2A\u7FA4","team.pullGroupHint":"\u52FE\u9009\u673A\u5668\u4EBA \u2192 \u62C9\u5230\u4E00\u4E2A\u98DE\u4E66\u7FA4\uFF08\u81EA\u52A8\u542B owner\uFF09","team.noTeams":"\u8FD8\u6CA1\u6709\u56E2\u961F\u3002\u53BB\u300C\u56E2\u961F\u7BA1\u7406\u300D\u751F\u6210\u9080\u8BF7\u7801\u8BA9\u522B\u4EBA\u52A0\u5165\u4F60\uFF0C\u6216\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\u3002","team.connected":"\u5DF2\u8FDE\u63A5","team.connectFail":"\u8FDE\u63A5\u5931\u8D25\uFF1A{error}","team.iHost":"\u6211\u6258\u7BA1","team.teamMeta":"{deps} \u4E2A\u90E8\u7F72 \xB7 {bots} \u4E2A\u673A\u5668\u4EBA","team.rosterFail":"\u65E0\u6CD5\u83B7\u53D6\u8BE5\u56E2\u961F\u82B1\u540D\u518C\u3002","team.acrossTeams":"\uFF08\u8DE8 {n} \u4E2A\u56E2\u961F\uFF0C\u53BB\u91CD\uFF09","team.botsWord":"\u4E2A\u673A\u5668\u4EBA","team.groupCreated":"\u7FA4\u5DF2\u521B\u5EFA","team.delegatedBy":"\uFF08\u7531\u300C{name}\u300D\u5EFA\u7FA4\uFF09","team.openInLark":"\u5728\u98DE\u4E66\u6253\u5F00","team.invalidBots":"\u672A\u52A0\u5165\u7684\u673A\u5668\u4EBA\uFF1A{ids}","team.invalidOwners":"{n} \u4E2A owner \u672A\u80FD\u62C9\u8FDB","team.missingIdentity":"\u4F60\u672A\u7ED1\u5B9A\u98DE\u4E66\u8EAB\u4EFD\uFF0C\u6CA1\u628A\u4F60\u81EA\u5DF1\u62C9\u8FDB\u7FA4\uFF08\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u7ED1\u5B9A\uFF09","team.skippedNoOwner":"{n} \u4E2A\u673A\u5668\u4EBA\u56E0\u8D1F\u8D23\u4EBA\u672A\u7ED1\u5B9A\u8EAB\u4EFD\u88AB\u8DF3\u8FC7\uFF08\u672A\u52A0\u5165\u7FA4\uFF09","team.errNoLocalBot":"\u8BF7\u81F3\u5C11\u52FE\u9009\u4E00\u4E2A\u4F60\u81EA\u5DF1\uFF08\u672C\u90E8\u7F72\uFF09\u7684\u5728\u7EBF\u673A\u5668\u4EBA\u2014\u2014\u7FA4\u8981\u7531\u5B83\u521B\u5EFA\u5E76\u628A\u4F60\uFF08\u53D1\u8D77\u4EBA\uFF09\u62C9\u8FDB\u7FA4\u3002","team.errAllSkipped":"\u6240\u9009\u673A\u5668\u4EBA\u7684\u8D1F\u8D23\u4EBA\u90FD\u6CA1\u7ED1\u5B9A\u8EAB\u4EFD\uFF0C\u65E0\u6CD5\u62C9\u7FA4\uFF08\u673A\u5668\u4EBA\u4E0D\u80FD\u8FDB\u4E00\u4E2A owner \u4E0D\u5728\u7684\u7FA4\uFF09\u3002\u8BF7\u8BA9\u5BF9\u5E94\u90E8\u7F72\u5148\u7ED1\u5B9A\u8EAB\u4EFD\u3002","team.errNoCreator":"\u6CA1\u6709\u53EF\u7528\u7684\u5EFA\u7FA4\u53D1\u8D77\u65B9\uFF08\u76F8\u5173\u90E8\u7F72\u90FD\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF0C\u6216\u4E0D\u53EF\u8FBE\uFF09","team.errDelegationTimeout":"\u59D4\u6258\u5BF9\u65B9\u90E8\u7F72\u5EFA\u7FA4\u8D85\u65F6\uFF08\u53EF\u80FD\u5DF2\u5EFA\uFF0C\u53BB\u98DE\u4E66\u786E\u8BA4\uFF0C\u52FF\u91CD\u590D\u70B9\uFF09","team.errGroupCreate":"\u5EFA\u7FA4\u5931\u8D25\uFF1A{error}","team.roleModalTitleName":"\u9ED8\u8BA4\u89D2\u8272 \xB7 {name}","team.bound":"\u5DF2\u7ED1\u5B9A","team.myHostedTeam":"\u6211\u6258\u7BA1\u7684\u56E2\u961F","team.remoteTeamLabel":"{name} \u7684\u56E2\u961F","team.manageTitle":"\u56E2\u961F\u7BA1\u7406","team.manageLede":"\u521B\u5EFA\u591A\u4E2A\u56E2\u961F\u3001\u7ED9\u6BCF\u4E2A\u56E2\u961F\u751F\u6210\u9080\u8BF7\u7801\u3001\u6216\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\u3002\u4E00\u4E2A\u56E2\u961F = \u4F60\u672C\u90E8\u7F72\u7684\u673A\u5668\u4EBA + \u52A0\u5165\u8BE5\u56E2\u961F\u7684\u5176\u5B83\u90E8\u7F72\u3002","team.hostedTitle":"\u6211\u6258\u7BA1\u7684\u56E2\u961F","team.newTeamPh":"\u65B0\u56E2\u961F\u540D\u79F0","team.createTeamBtn":"\u521B\u5EFA\u56E2\u961F","team.joinTitle":"\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F","team.hubPh":"Hub \u5730\u5740\uFF0C\u5982 http://10.0.0.5:7891","team.codePh":"\u9080\u8BF7\u7801","team.joinBtn":"\u52A0\u5165","team.noTeamsShort":"\u8FD8\u6CA1\u6709\u56E2\u961F\u3002","team.default":"\u9ED8\u8BA4","team.manageMetaDeps":"{count} \u4E2A\u90E8\u7F72","team.manageMetaRemote":"\uFF08\u542B {r} \u8FDC\u7AEF\uFF09","team.manageMetaBots":"{count} \u4E2A\u673A\u5668\u4EBA","team.genInvite":"\u751F\u6210\u9080\u8BF7\u7801","team.delBtn":"\u5220\u9664","team.generating":"\u751F\u6210\u4E2D\u2026","team.inviteResultLede":"\u628A\u4E0B\u9762\u4E24\u9879\u53D1\u7ED9\u522B\u7684\u90E8\u7F72\u7684\u4EBA\uFF0824 \u5C0F\u65F6\u5185\u3001\u5355\u6B21\u6709\u6548\uFF09\uFF1A","team.inviteHub":"Hub \u5730\u5740\uFF1A","team.inviteCode":"\u9080\u8BF7\u7801\uFF1A","team.genFail":"\u751F\u6210\u5931\u8D25\u3002","team.delConfirm":"\u5220\u9664\u56E2\u961F\u300C{name}\u300D\uFF1F\u5DF2\u52A0\u5165\u5B83\u7684\u90E8\u7F72\u4F1A\u88AB\u79FB\u9664\uFF08\u4E0D\u5F71\u54CD\u4ED6\u4EEC\u81EA\u5DF1\u7684\u90E8\u7F72\uFF09\u3002","team.errName":"\u8BF7\u586B\u56E2\u961F\u540D\u79F0","team.creating":"\u521B\u5EFA\u4E2D\u2026","team.created":"\u5DF2\u521B\u5EFA","team.createFail":"\u521B\u5EFA\u5931\u8D25\uFF1A{error}","team.errHubCode":"\u8BF7\u586B Hub \u5730\u5740\u548C\u9080\u8BF7\u7801\u3002","team.joining":"\u52A0\u5165\u4E2D\u2026","team.joined":"\u5DF2\u52A0\u5165\u300C{name}\u300D\uFF0C\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u67E5\u770B\u3002","team.joinErrSelf":"\u8FD9\u662F\u4F60\u81EA\u5DF1\u7684\u90E8\u7F72\uFF0C\u4E0D\u80FD\u52A0\u5165\u81EA\u5DF1\uFF08\u9080\u8BF7\u7801\u8981\u53D1\u7ED9\u522B\u7684\u90E8\u7F72\u7684\u4EBA\u7528\uFF09","team.joinErrAlready":"\u4F60\u7684\u90E8\u7F72\u5DF2\u7ECF\u52A0\u5165\u8FC7\u8FD9\u4E2A\u56E2\u961F\u4E86","team.joinErrUnreachable":"\u8FDE\u4E0D\u4E0A\u5BF9\u65B9 Hub\uFF08\u68C0\u67E5\u5730\u5740/\u7F51\u7EDC\uFF09","team.joinErrTimeout":"\u5BF9\u65B9 Hub \u54CD\u5E94\u8D85\u65F6","team.joinErrGeneric":"\u52A0\u5165\u5931\u8D25\uFF1A{error}","team.identifying":"\u8BC6\u522B\u4E2D\u2026","team.bound2":"\u5DF2\u7ED1\u5B9A\uFF1A{name}","team.multiCandidate":"\u8BC6\u522B\u5230\u591A\u4E2A\u5019\u9009\uFF0C\u70B9\u4F60\u81EA\u5DF1\uFF1A","team.binding":"\u7ED1\u5B9A\u4E2D\u2026","team.bindFail":"\u7ED1\u5B9A\u5931\u8D25\uFF1A{error}","team.noCandidates":"\u6CA1\u8BC6\u522B\u5230\u8EAB\u4EFD\uFF1A\u8BF7\u786E\u8BA4\u673A\u5668\u4EBA\u914D\u7F6E\u4E86 allowedUsers\uFF08\u5141\u8BB8\u4F7F\u7528\u8005\uFF09\uFF0C\u4E14\u673A\u5668\u4EBA\u6709\u901A\u8BAF\u5F55\u6743\u9650\u3002","team.removeMemberConfirm":"\u628A\u300C{name}\u300D\u79FB\u51FA\u8FD9\u4E2A\u56E2\u961F\uFF1F\u5B83\u7684\u673A\u5668\u4EBA\u5C06\u4ECE\u672C\u56E2\u961F\u82B1\u540D\u518C\u6D88\u5931\uFF08\u4E0D\u5F71\u54CD\u5BF9\u65B9\u81EA\u5DF1\u7684\u90E8\u7F72\uFF09\u3002","team.creatingGroup":"\u5EFA\u7FA4\u4E2D\u2026","team.defaultGroupName":"\u534F\u4F5C\u7FA4","team.errPickBot":"\u8BF7\u5148\u52FE\u9009\u81F3\u5C11\u4E00\u4E2A\u673A\u5668\u4EBA","sessions.closeBulkConfirm":"\u5173\u95ED\u9009\u4E2D\u7684 {count} \u4E2A\u4F1A\u8BDD\uFF1F","sessions.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u4F1A\u8BDD\u3002","sessions.viewMode":"\u4F1A\u8BDD\u89C6\u56FE","sessions.viewKanban":"\u770B\u677F","sessions.viewBoard":"\u72B6\u6001\u677F","sessions.viewTable":"\u8868\u683C","sessions.selectSession":"\u9009\u62E9\u4F1A\u8BDD","sessions.board.needsYou":"\u9700\u8981\u4F60","sessions.board.needsYouHint":"\u7B49\u5F85\u4ED3\u5E93\u3001TUI \u9009\u62E9\u6216\u989D\u5EA6\u5904\u7406","sessions.board.starting":"\u542F\u52A8\u4E2D","sessions.board.startingHint":"CLI \u6B63\u5728\u521B\u5EFA\u6216\u6062\u590D","sessions.board.working":"\u5E72\u6D3B\u4E2D","sessions.board.workingHint":"\u6B63\u5728\u8F93\u51FA\u3001\u5206\u6790\u6216\u6267\u884C\u5DE5\u5177","sessions.board.idle":"\u7A7A\u95F2","sessions.board.idleHint":"\u53EF\u7EE7\u7EED\u5BF9\u8BDD\u6216\u63A5\u65B0\u4EFB\u52A1","sessions.board.emptyColumn":"\u6682\u65E0\u4F1A\u8BDD","sessions.board.signalRepo":"\u5F85\u9009\u4ED3\u5E93","sessions.board.signalPrompt":"\u7B49\u5F85 TUI \u9009\u62E9","sessions.board.signalLimited":"\u989D\u5EA6\u53D7\u9650","sessions.board.signalAgent":"\u9700\u8981\u4EBA\u5DE5\u4ECB\u5165","sessions.board.waiting":"\u7B49\u5F85","sessions.board.dragHint":"\u62D6\u52A8\u5217\u5934\u8C03\u6574\u5217\u987A\u5E8F","sessions.board.moveLeft":"\u5DE6\u79FB\u6B64\u5217","sessions.board.moveRight":"\u53F3\u79FB\u6B64\u5217","sessions.kanban.backlog":"\u5F85\u529E\u6C60","sessions.kanban.todo":"\u5F85\u529E","sessions.kanban.inProgress":"\u8FDB\u884C\u4E2D","sessions.kanban.inReview":"\u5F85\u786E\u8BA4","sessions.kanban.done":"\u5DF2\u5B8C\u6210","sessions.kanban.updated":"\u66F4\u65B0\u4E8E {time}","sessions.kanban.moreHidden":"\u8FD8\u6709 {count} \u4E2A\u672A\u663E\u793A","sessions.kanban.openTab":"\u65B0\u6807\u7B7E\u9875\u6253\u5F00","sessions.kanban.openFeishu":"\u6253\u5F00\u98DE\u4E66","sessions.kanban.terminalLoading":"\u6B63\u5728\u6253\u5F00\u7EC8\u7AEF\u2026","sessions.kanban.rename":"\u91CD\u547D\u540D\uFF08\u53CC\u51FB\u6807\u9898\u4E5F\u53EF\uFF09","sessions.kanban.renameFail":"\u91CD\u547D\u540D\u5931\u8D25","sessions.kanban.moveFail":"\u79FB\u52A8\u5931\u8D25","sessions.kanban.groupBy":"\u5206\u7EC4\u7EF4\u5EA6","sessions.kanban.groupFlow":"\u5DE5\u4F5C\u6D41","sessions.kanban.groupTeam":"\u56E2\u961F","sessions.kanban.groupBot":"\u673A\u5668\u4EBA","sessions.kanban.teamLoading":"\u6B63\u5728\u52A0\u8F7D\u56E2\u961F\u2026","sessions.kanban.noTeam":"\u6682\u65E0\u56E2\u961F","sessions.kanban.teamScope":"{chats} \u4E2A\u534F\u4F5C\u7FA4 \xB7 {sessions} \u4E2A\u4F1A\u8BDD","sessions.kanban.remoteHint":"\u6765\u81EA {name} \u90E8\u7F72\u7684\u4F1A\u8BDD\uFF08\u5FEB\u7167\uFF0C\u7EC8\u7AEF/\u5386\u53F2\u5728\u5BF9\u65B9\u673A\u5668\u4E0A\uFF09","sessions.kanban.clusterDragHint":"\u62D6\u52A8\u6807\u9898\u6574\u7EC4\u79FB\u52A8","sessions.history.title":"\u4F1A\u8BDD\u5386\u53F2","sessions.history.loading":"\u6B63\u5728\u62C9\u53D6\u98DE\u4E66\u6D88\u606F\u2026","sessions.history.fail":"\u5386\u53F2\u62C9\u53D6\u5931\u8D25","sessions.history.empty":"\u6CA1\u6709\u6D88\u606F","sessions.history.user":"\u7528\u6237","sessions.history.owner":"\u521B\u5EFA\u8005","sessions.history.staleHint":"dashboard \u6216 daemon \u8FDB\u7A0B\u53EF\u80FD\u8FD8\u5728\u8DD1\u65E7\u7248\u672C\uFF0Cbotmux restart \u540E\u91CD\u8BD5","groups.title":"\u7FA4\u7EC4\u4E0E Bot","groups.subtitle":"\u67E5\u770B chat x bot \u8986\u76D6\u77E9\u9635\uFF0C\u7BA1\u7406\u62C9\u7FA4\u3001oncall\u3001\u9000\u7FA4\u548C\u89E3\u6563\u3002","groups.search":"\u641C\u7D22\u7FA4\u540D / ID / owner","groups.missingOnly":"\u4EC5\u7F3A bot","groups.refresh":"\u5237\u65B0","groups.create":"\u65B0\u5EFA\u7FA4","groups.chat":"\u7FA4\u804A","groups.actions":"\u64CD\u4F5C","groups.addBots":"\u6DFB\u52A0 bot","groups.manage":"\u7BA1\u7406","groups.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u7FA4\u804A\u3002","groups.createTitle":"\u65B0\u5EFA\u7FA4\u804A","groups.createHelp":"\u9009\u62E9\u8981\u9080\u8BF7\u7684 bot\u3002dashboard \u4F1A\u81EA\u52A8\u9009\u62E9\u5728\u7EBF daemon \u4F5C\u4E3A\u521B\u5EFA\u8005\u3002","groups.name":"\u7FA4\u540D","groups.namePlaceholder":"\u4F8B\u5982 AI ChangeLog","groups.bindDir":"\u7ED1\u5B9A\u76EE\u5F55","groups.bindDirHelp":"\u65B0\u8BDD\u9898\u76F4\u63A5\u7528\u8BE5\u76EE\u5F55\u542F\u52A8 CLI\uFF0C\u8DF3\u8FC7 repo \u9009\u62E9\u3002","groups.botPicker":"Bot","groups.createSubmit":"\u521B\u5EFA","groups.cancel":"\u53D6\u6D88","groups.successTitle":"\u7FA4\u521B\u5EFA\u6210\u529F","groups.openGroup":"\u6253\u5F00\u65B0\u7FA4","groups.manageTitle":"\u7BA1\u7406 {name}","groups.owner":"\u7FA4\u4E3B","groups.oncall":"Oncall \u6A21\u5F0F","groups.oncallHelp":"\u5F00\u542F\u540E\uFF0C\u7FA4\u5185\u6210\u5458\u53EF @ \u673A\u5668\u4EBA\uFF1B\u65B0\u8BDD\u9898\u76F4\u63A5\u4F7F\u7528\u7ED1\u5B9A\u76EE\u5F55\u3002","groups.leaveTitle":"\u9009\u62E9\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.leaveSelected":"\u9009\u4E2D\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.disband":"\u89E3\u6563\u7FA4\u804A","groups.dangerHint":"\u89E3\u6563\u4EC5\u5F53\u5728\u7FA4\u673A\u5668\u4EBA\u662F\u7FA4\u4E3B\u65F6\u624D\u4F1A\u6210\u529F\uFF0C\u5426\u5219\u5EFA\u8BAE\u4F7F\u7528\u9000\u51FA\u7FA4\u804A\u3002","groups.save":"\u4FDD\u5B58","groups.needWorkingDir":"\u8BF7\u586B\u5DE5\u4F5C\u76EE\u5F55","groups.noBotsOnline":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u8BF7\u5148\u91CD\u542F daemon\u3002","schedules.title":"\u5B9A\u65F6\u4EFB\u52A1","schedules.subtitle":"\u8DE8 daemon \u67E5\u770B\u3001\u6682\u505C\u3001\u6062\u590D\u548C\u7ACB\u5373\u89E6\u53D1\u5B9A\u65F6\u4EFB\u52A1\u3002","schedules.search":"\u641C\u7D22\u540D\u79F0 / prompt / \u5DE5\u4F5C\u76EE\u5F55","schedules.anyKind":"\u5168\u90E8\u7C7B\u578B","schedules.enabledOnly":"\u4EC5\u542F\u7528","schedules.name":"\u540D\u79F0","schedules.bot":"bot","schedules.schedule":"\u89C4\u5219","schedules.next":"\u4E0B\u6B21","schedules.last":"\u4E0A\u6B21","schedules.repeat":"\u91CD\u590D","schedules.enabled":"\u542F\u7528","schedules.actions":"\u64CD\u4F5C","schedules.runNow":"\u7ACB\u5373\u8FD0\u884C","schedules.pause":"\u6682\u505C","schedules.resume":"\u6062\u590D","schedules.empty":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","settings.title":"\u5168\u5C40\u8BBE\u7F6E","settings.subtitle":"\u7BA1\u7406\u672C\u673A botmux dashboard \u4E0E\u6240\u6709 bot \u5171\u4EAB\u7684\u5168\u5C40\u884C\u4E3A\u3002","settings.loading":"\u6B63\u5728\u52A0\u8F7D\u8BBE\u7F6E\u2026","settings.loadFailed":"\u8BBE\u7F6E\u52A0\u8F7D\u5931\u8D25","settings.readOnlyVisitor":"\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u4FEE\u6539\u8BBE\u7F6E\u9700\u8981\u6388\u6743\u94FE\u63A5\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09","settings.sectionAccess":"\u8BBF\u95EE\u6743\u9650","settings.publicReadOnly":"\u5141\u8BB8\u65E0 token \u53EA\u8BFB\u8BBF\u95EE dashboard","settings.publicReadOnlyHelp":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 token \u7684\u8BBF\u95EE\u8005\u53EF\u4EE5\u67E5\u770B dashboard\u3001\u4F1A\u8BDD\u3001\u5B9A\u65F6\u4EFB\u52A1\u548C SSE\uFF1B\u5173\u95ED\u3001\u6682\u505C\u3001\u5BA1\u6279\u7B49\u5199\u64CD\u4F5C\u4ECD\u5FC5\u987B\u901A\u8FC7 token \u9274\u6743\u3002\u654F\u611F\u7EC8\u7AEF\u539F\u59CB\u65E5\u5FD7\u59CB\u7EC8\u9700\u8981 token\u3002","settings.sectionCards":"\u98DE\u4E66\u5361\u7247","settings.openTerminalInFeishu":"\u6D41\u5F0F\u5361\u7247\u7EC8\u7AEF\u6309\u94AE\u5728\u98DE\u4E66\u4FA7\u680F\u6253\u5F00","settings.openTerminalInFeishuHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF1A\u7EC8\u7AEF\u6309\u94AE\u76F4\u63A5\u6253\u5F00 Web Terminal URL\u3002\u5F00\u542F\u540E\u4F7F\u7528\u98DE\u4E66 web_url/open \u5305\u88C5\uFF0C\u5728\u98DE\u4E66 PC \u4FA7\u680F\u91CC\u6253\u5F00\uFF1B\u5199\u6743\u9650\u4ECD\u7531\u7EC8\u7AEF token \u63A7\u5236\u3002","settings.sectionRepoPicker":"\u4ED3\u5E93\u9009\u62E9","settings.repoPickerMode":"\u4ED3\u5E93\u9009\u62E9\u5361\u6A21\u5F0F","settings.repoPickerModeAll":"\u4ED3\u5E93 + worktree","settings.repoPickerModeRepos":"\u4EC5\u4E3B\u4ED3\u5E93","settings.repoPickerModeHelp":"\u9ED8\u8BA4\u663E\u793A\u4ED3\u5E93\u548C linked worktree\u3002\u9009\u62E9\u300C\u4EC5\u4E3B\u4ED3\u5E93\u300D\u540E\uFF0C\u521D\u59CB\u5316\u548C\u88F8 /repo \u7684\u9009\u62E9\u5361\u53EA\u5217\u4E3B\u4ED3\u5E93\uFF1B\u663E\u5F0F /repo /abs/path/to/worktree \u4ECD\u53EF\u76F4\u8FBE worktree\u3002","settings.saving":"\u4FDD\u5B58\u4E2D\u2026","settings.saved":"\u5DF2\u4FDD\u5B58","settings.saveFailed":"\u4FDD\u5B58\u5931\u8D25","settings.sectionMaintenance":"\u81EA\u52A8\u7EF4\u62A4","settings.autoUpdate":"\u81EA\u52A8\u66F4\u65B0","settings.autoUpdateHelp":"\u9ED8\u8BA4\u5173\u95ED\u3002\u5230\u70B9\u6267\u884C npm install -g botmux@latest \u5B89\u88C5\u6700\u65B0\u7248\u672C\uFF08\u53EA\u4E0B\u8F7D\u5B89\u88C5\u3001\u672C\u8EAB\u4E0D\u91CD\u542F\uFF09\u3002\u4EC5 npm \u5168\u5C40\u5B89\u88C5\u53EF\u7528\u3002","settings.autoRestart":"\u81EA\u52A8\u91CD\u542F","settings.autoRestartHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF0C\u9700\u5148\u5F00\u542F\u81EA\u52A8\u66F4\u65B0\u3002\u81EA\u52A8\u66F4\u65B0\u88C5\u5230\u65B0\u7248\u672C\u540E\uFF0C\u82E5\u6CA1\u6709\u8FDB\u884C\u4E2D\u7684\u4F1A\u8BDD\u5219\u81EA\u52A8\u91CD\u542F\u4EE5\u751F\u6548\uFF08\u649E\u4E0A\u5FD9\u788C\u4F1A\u8BDD\u5219\u8DF3\u5230\u6B21\u65E5\uFF09\u3002","settings.autoUpdateLocalDev":"\u5F53\u524D\u4E3A\u672C\u5730\u5F00\u53D1\u5B89\u88C5\uFF08\u4ECE\u6E90\u7801\u8FD0\u884C\uFF09\uFF0C\u81EA\u52A8\u66F4\u65B0\u4E0D\u53EF\u7528\u3002","settings.maintenanceTime":"\u65F6\u95F4","botDefaults.title":"\u6570\u5B57\u5458\u5DE5\u6863\u6848","botDefaults.subtitle":"\u6BCF\u4F4D\u5458\u5DE5\u7684\u9ED8\u8BA4\u884C\u4E3A\uFF1Aoncall\u3001\u4E3B\u52A8\u5F00\u5DE5\u3001\u4EBA\u8BBE\u89D2\u8272\u3001\u5361\u7247\u4E0E\u6388\u6743\u3002","botDefaults.metaOnline":"\u5728\u7EBF \xB7 daemon \u6B63\u5E38","botDefaults.search":"\u641C\u7D22 bot \u540D / app id","botDefaults.refresh":"\u5237\u65B0","botDefaults.sectionOncall":"\u65B0\u7FA4 Oncall","botDefaults.sectionBrand":"\u5361\u7247\u7B7E\u540D","botDefaults.warning":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 oncall binding \u7684\u7FA4\u4F1A\u5728\u4E0B\u6B21\u5F00\u65B0\u8BDD\u9898\u65F6\u81EA\u52A8\u7ED1\u5B9A\u5230\u8BE5\u76EE\u5F55\uFF1B\u624B\u52A8\u7ED1\u5B9A\u6216\u624B\u52A8\u89E3\u7ED1\u8FC7\u7684\u7FA4\u4E0D\u4F1A\u88AB\u8986\u76D6\u3002","botDefaults.empty":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u5148 botmux restart \u8BA9 daemon \u4E0A\u7EBF\u3002","botDefaults.defaultOncall":"\u9ED8\u8BA4\u8FDB\u5165 oncall \u6A21\u5F0F","botDefaults.defaultOncallHelp":"\u6240\u6709\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8\u7ED1\u5B9A","botDefaults.workingDir":"\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55","botDefaults.lastEnabled":"\u4E0A\u6B21\u542F\u7528\u65F6\u95F4","botDefaults.autobound":"\u5DF2\u81EA\u52A8\u7ED1\u5B9A {count} \u4E2A\u7FA4","botDefaults.save":"\u4FDD\u5B58","botDefaults.required":"\u5F00\u542F\u65F6\u5FC5\u987B\u586B\u5DE5\u4F5C\u76EE\u5F55","botDefaults.brandLabel":"\u4E2A\u6027\u7B7E\u540D\uFF08\u5361\u7247\u9875\u811A\uFF09","botDefaults.brandLabelHelp":"\u8BE5 bot \u53D1\u51FA\u7684\u5361\u7247\u9875\u811A\u7B7E\u540D\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u4E0D\u663E\u793A\uFF1B\u586B\u5199\uFF1D\u81EA\u5B9A\u4E49\uFF08\u652F\u6301 markdown\uFF0C\u5982 [Acme](https://\u2026)\uFF09\uFF1B\u6062\u590D\u9ED8\u8BA4\uFF1D\u663E\u793A botmux\u3002","botDefaults.brandLabelPlaceholder":"\u9ED8\u8BA4\uFF1Abotmux\uFF08\u7559\u7A7A\u5219\u4E0D\u663E\u793A\uFF09","botDefaults.sectionSandbox":"\u6587\u4EF6\u6C99\u76D2\uFF08oncall\uFF09","botDefaults.sandboxToggle":"\u5F00\u542F\u6587\u4EF6\u6C99\u76D2","botDefaults.sandboxHelp":"\u5F00\u542F\u540E\uFF0C\u8BE5 bot \u7684\u6BCF\u4E2A\u4F1A\u8BDD\u90FD\u8DD1\u5728\u6309\u4F1A\u8BDD\u9694\u79BB\u7684\u6C99\u76D2\u91CC\uFF1A\u53EA\u770B\u5F97\u5230\u4E00\u4EFD\u9879\u76EE\u526F\u672C\uFF0C\u78B0\u4E0D\u5230\u4F60\u78C1\u76D8\u4E0A\u7684\u771F\u5B9E\u6587\u4EF6\u3001\u5BC6\u94A5\u3001\u522B\u7684\u4F1A\u8BDD\u6570\u636E\u3002\u9002\u5408\u628A\u673A\u5668\u4EBA\u5206\u4EAB\u7ED9\u534A\u53D7\u4FE1\u4EFB\u7684\u4EBA\uFF08oncall\uFF09\u3002\u4EC5 Linux \u751F\u6548\uFF0C\u4E0B\u4E2A\u65B0\u4F1A\u8BDD\u8D77\u6548\u3002","botDefaults.sandboxSaved":"\u5DF2\u4FDD\u5B58\uFF08\u4E0B\u4E2A\u65B0\u4F1A\u8BDD\u751F\u6548\uFF09","botDefaults.brandSave":"\u4FDD\u5B58\u7B7E\u540D","botDefaults.brandReset":"\u6062\u590D\u9ED8\u8BA4","botDefaults.brandStateDefault":"\u5F53\u524D\uFF1A\u9ED8\u8BA4 botmux","botDefaults.brandStateOff":"\u5F53\u524D\uFF1A\u5DF2\u5173\u95ED","botDefaults.brandStateCustom":"\u5F53\u524D\uFF1A\u81EA\u5B9A\u4E49","botDefaults.sectionCard":"\u5361\u7247\u884C\u4E3A","botDefaults.disableStreaming":"\u5173\u95ED\u98DE\u4E66\u6D41\u5F0F\u5361\u7247","botDefaults.disableStreamingHelp":"\u4E0D\u518D\u53D1\u5B9E\u65F6\u5237\u65B0\u7684\u4F1A\u8BDD\u72B6\u6001\u5361\uFF08\u542B\u300C\u6253\u5F00\u7EC8\u7AEF\u300D\u5165\u53E3\uFF09\uFF1B\u4EFB\u52A1\u6700\u7EC8\u7ED3\u679C\u4ECD\u901A\u8FC7\u6D88\u606F\u9001\u8FBE\u3002\u9002\u5408\u5ACC\u6D41\u5F0F\u5361\u7247\u70E6\u7684\u573A\u666F\u3002","botDefaults.writableLink":"\u5361\u7247\u4E0A\u76F4\u63A5\u7ED9\u53EF\u64CD\u4F5C\uFF08\u53EF\u5199\uFF09\u7EC8\u7AEF\u94FE\u63A5","botDefaults.writableLinkHelp":"\u26A0\uFE0F \u5728\u6D41\u5F0F\u5361\u7247\u6B63\u6587\u76F4\u63A5\u8D34\u51FA\u53EF\u5199\u7EC8\u7AEF\u94FE\u63A5\uFF0C\u7FA4\u5185\u4EFB\u4F55\u4EBA\u90FD\u80FD\u70B9\u5F00\u5E76\u64CD\u63A7\u7EC8\u7AEF\u3002\u4E0D\u52FE\uFF1D\u4FDD\u6301\u73B0\u72B6\uFF08\u8D70\u300C\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u300D\u6309\u94AE\u79C1\u804A\u53D1\u7ED9\u70B9\u51FB\u8005\uFF09\u3002","botDefaults.writableLinkMoot":"\u5DF2\u5173\u95ED\u6D41\u5F0F\u5361\u7247","botDefaults.privateCard":"/card \u53D1\u79C1\u5BC6\u5361\u7247\uFF08\u4EC5\u6388\u6743\u4EBA\u53EF\u89C1\uFF09","botDefaults.privateCardHelp":"\u5F00\u542F\u540E /card \u6539\u7528\u300C\u4EC5\u7279\u5B9A\u4EBA\u53EF\u89C1\u300D\u7684\u4E34\u65F6\u5361\u7247\uFF1A\u53EA\u53D1\u7ED9 owner\uFF08allowedUsers\uFF09\uFF0C/grant \u6388\u6743\u5BF9\u8BDD\u7684\u4EBA\u548C\u7FA4\u91CC\u5176\u4ED6\u4EBA\u90FD\u770B\u4E0D\u5230\u3002\u4EE3\u4EF7\uFF1A\u662F\u9759\u6001\u5FEB\u7167\u3001\u4E0D\u4F1A\u5B9E\u65F6\u5237\u65B0\uFF1B\u4E14\u4EC5\u666E\u901A\u7FA4\u53EF\u7528\uFF08\u8BDD\u9898\u7FA4 / \u5355\u804A\u4F1A\u5931\u8D25\uFF0C\u4E0D\u964D\u7EA7\uFF09\u3002\u53EA\u5F71\u54CD /card \u547D\u4EE4\uFF0C\u81EA\u52A8\u6D41\u5F0F\u5361\u4E0D\u53D8\u3002","botDefaults.cardPrefSaved":"\u5DF2\u4FDD\u5B58","botDefaults.sectionRole":"\u9ED8\u8BA4\u89D2\u8272","botDefaults.roleHelp":"\u8BE5 bot \u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF08\u8DE8\u7FA4\u751F\u6548\uFF09\uFF0C\u4F1A\u6CE8\u5165\u5230\u8BE5 bot \u5728\u5404\u7FA4\u7684\u4F1A\u8BDD\u91CC\uFF1B\u5355\u4E2A\u7FA4\u53EF\u5728\u300C\u89D2\u8272\u300D\u9875\u5355\u72EC\u8986\u76D6\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u5220\u9664\u3002","botDefaults.rolePlaceholder":"\u4F8B\u5982\uFF1A\u4F60\u662F\u540E\u7AEF\u6392\u969C\u52A9\u624B\uFF0C\u56DE\u7B54\u7B80\u6D01\u3001\u4F18\u5148\u7ED9\u53EF\u6267\u884C\u547D\u4EE4\u2026","botDefaults.roleSave":"\u4FDD\u5B58\u89D2\u8272","botDefaults.roleDelete":"\u5220\u9664","botDefaults.roleSaved":"\u5DF2\u4FDD\u5B58","botDefaults.roleDeleted":"\u5DF2\u5220\u9664","botDefaults.roleLoadErr":"\u89D2\u8272\u52A0\u8F7D\u5931\u8D25","botDefaults.sectionAutoStart":"\u4E3B\u52A8\u5F00\u5DE5","botDefaults.autoStartJoin":"\u88AB\u62C9\u8FDB\u65B0\u7FA4\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartJoinHelp":"\u5F00\u542F\u540E\uFF0C\u673A\u5668\u4EBA\u4E00\u88AB\u62C9\u8FDB\u65B0\u7FA4\uFF08\u7FA4\u91CC\u6709\u6388\u6743\u7528\u6237 allowedUsers \u65F6\uFF09\u5C31\u81EA\u52A8\u5F00\u4E00\u4E2A\u4F1A\u8BDD\u5F00\u59CB\u5DE5\u4F5C\uFF0C\u65E0\u9700 @\u3002\u5728\u673A\u5668\u4EBA\u7684\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55\u542F\u52A8\uFF1B\u672A\u914D\u7F6E\u9ED8\u8BA4\u76EE\u5F55\u65F6\u5148\u5F39\u4ED3\u5E93\u9009\u62E9\u5361\u8BA9\u4F60\u9009\u3002\u524D\u63D0\uFF1A\u9700\u5728\u98DE\u4E66\u5F00\u653E\u5E73\u53F0\u4E3A\u672C\u5E94\u7528\u8BA2\u9605\u300C\u673A\u5668\u4EBA\u8FDB\u7FA4\u300D\u4E8B\u4EF6 im.chat.member.bot.added_v1\uFF0C\u5E76\u5F00\u901A\u7FA4\u6210\u5458\u8BFB\u53D6\u6743\u9650\u3002","botDefaults.autoStartJoinPrompt":"\u5165\u7FA4\u9996\u8F6E prompt\uFF08\u53EF\u9009\uFF09","botDefaults.autoStartJoinPromptPlaceholder":"\u586B\u4E86\uFF1D\u4F5C\u4E3A\u5165\u7FA4\u540E\u7684\u7B2C\u4E00\u6761\u4EFB\u52A1\uFF1B\u7559\u7A7A\uFF1D\u673A\u5668\u4EBA\u81EA\u5DF1\u770B\u7FA4\u91CC\u4FE1\u606F\u51B3\u5B9A\u505A\u4EC0\u4E48","botDefaults.autoStartJoinPromptSave":"\u4FDD\u5B58 prompt","botDefaults.autoStartTopic":"\u8BDD\u9898\u7FA4\u65B0\u8BDD\u9898\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartTopicHelp":"\u5F00\u542F\u540E\uFF0C\u5728\u8BDD\u9898\u7FA4\u91CC\u6BCF\u5F53\u6709\u4EBA\u65B0\u5F00\u4E00\u4E2A\u8BDD\u9898\uFF0C\u673A\u5668\u4EBA\u5C31\u4F1A\u81EA\u52A8\u63A5\u5165\u8BE5\u8BDD\u9898\u3001\u628A\u9996\u6761\u6D88\u606F\u5F53\u4F5C\u4EFB\u52A1\u5F00\u59CB\u5904\u7406\uFF0C\u65E0\u9700 @\u3002\u4EC5\u5BF9\u8BDD\u9898\u7FA4\u751F\u6548\uFF0C\u666E\u901A\u7FA4\u4E0D\u53D7\u5F71\u54CD\u3002","botDefaults.sectionSessionMode":"\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.p2pMode":"\u79C1\u804A\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.p2pThread":"thread\uFF08\u6BCF\u6761 DM \u72EC\u7ACB\u4F1A\u8BDD\uFF09","botDefaults.p2pChat":"chat\uFF08\u6241\u5E73\u8FDE\u7EED\u5355\u804A\u4F1A\u8BDD\uFF09","botDefaults.p2pHelp":"\u79C1\u804A\uFF081:1 DM\uFF09\u7684\u4F1A\u8BDD\u65B9\u5F0F\uFF1Athread = \u6BCF\u6761\u9876\u5C42\u6D88\u606F\u5404\u81EA\u8D77\u72EC\u7ACB\u4F1A\u8BDD\uFF08\u907F\u514D\u628A\u5BF9\u8BDD\u5806\u8FDB\u540C\u4E00\u4E2A CLI \u8FDB\u7A0B\uFF09\uFF1Bchat = \u6574\u6BB5 DM \u5171\u7528\u4E00\u4E2A\u8FDE\u7EED\u4F1A\u8BDD\u3001\u5171\u4EAB\u4E0A\u4E0B\u6587\uFF08\u7C7B Hermes\uFF09\u3002\u6539\u540E\u7ACB\u5373\u751F\u6548\u3002","botDefaults.regularGroupMode":"\u666E\u901A\u7FA4\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.regularGroupModeChat":"chat\uFF08\u6241\u5E73\u8FDE\u7EED\u5355\u804A\u4F1A\u8BDD\uFF0C\u9ED8\u8BA4\uFF09","botDefaults.regularGroupModeNewTopic":"new-topic\uFF08\u6BCF\u6761\u9876\u5C42 @ \u5404\u5F00\u72EC\u7ACB\u8BDD\u9898\u4E0E\u4F1A\u8BDD\uFF09","botDefaults.regularGroupModeShared":"shared\uFF08\u8BDD\u9898\u6A21\u5F0F\u4F46\u590D\u7528\u540C\u4E00\u4E2A session\uFF09","botDefaults.regularGroupModeHelp":"\u666E\u901A\u7FA4\uFF08\u975E\u8BDD\u9898\u7FA4\uFF09\u91CC @ \u8BE5 bot \u7684\u65B0\u9876\u5C42\u6D88\u606F\u600E\u4E48\u5F00\u4F1A\u8BDD\uFF1Achat = \u6574\u7FA4\u5171\u7528\u4E00\u4E2A\u8FDE\u7EED\u4F1A\u8BDD\uFF08\u9ED8\u8BA4\uFF09\uFF1Bnew-topic = \u6BCF\u6761\u9876\u5C42 @ \u5728\u539F\u6D88\u606F\u4E0B\u5F00\u72EC\u7ACB\u8BDD\u9898\u3001\u5404\u81EA\u72EC\u7ACB\u4F1A\u8BDD\uFF1Bshared = \u8BDD\u9898\u6A21\u5F0F\u4F46\u590D\u7528\u540C\u4E00\u4E2A session\uFF08\u56DE\u590D\u843D\u5728\u8BDD\u9898\u91CC\u3001\u4F46\u5171\u7528\u672C\u7FA4\u4F1A\u8BDD\u4E0E\u4E0A\u4E0B\u6587\uFF09\u3002\u8FD9\u662F per-bot \u9ED8\u8BA4\uFF0C\u5177\u4F53\u67D0\u4E2A\u7FA4\u53EF\u7528 /reply-mode \u5355\u72EC\u8986\u76D6\u3002\u6539\u540E\u7ACB\u5373\u751F\u6548\u3002","botDefaults.mentionMode":"\u7FA4\u804A @ \u7B56\u7565","botDefaults.mentionModeAlways":"\u90FD\u9700\u8981 @\uFF08\u9ED8\u8BA4\uFF09","botDefaults.mentionModeTopic":"\u4EC5\u8BDD\u9898\u5185\u4E0D\u9700\u8981 @","botDefaults.mentionModeNever":"\u6240\u6709\u6D88\u606F\u90FD\u4E0D\u9700\u8981 @","botDefaults.mentionModeHelp":"\u8BE5 bot \u5168\u5C40\u751F\u6548\uFF0C\u51B3\u5B9A\u7FA4\u91CC\u8981\u4E0D\u8981 @ \u624D\u56DE\uFF1A\u300C\u90FD\u9700\u8981 @\u300D= \u4EFB\u4F55\u6D88\u606F\u90FD\u5F97 @\uFF08\u9ED8\u8BA4\uFF0C\u6700\u5B89\u5168\uFF1B\u591A\u4EBA\u7FA4\u91CC\u8BDD\u9898\u5185\u4E5F\u8981 @\uFF09\uFF1B\u300C\u4EC5\u8BDD\u9898\u5185\u4E0D\u9700\u8981 @\u300D= \u8D77\u65B0\u5BF9\u8BDD / \u9876\u5C42\u4ECD\u8981 @\uFF0C\u4F46\u5728\u8BE5 bot \u5DF2\u5F00\u7684\u4EFB\u4F55\u8BDD\u9898\u91CC\uFF08new-topic / shared / \u8BDD\u9898\u7FA4\uFF09\u540E\u7EED\u6D88\u606F\u514D @ \u7EED\u804A\uFF1B\u300C\u6240\u6709\u6D88\u606F\u90FD\u4E0D\u9700\u8981 @\u300D= \u8BE5 bot \u6709\u5BF9\u8BDD\u6743\u9650\u7684\u7FA4\u91CC\u975E @ \u6D88\u606F\u4E5F\u56DE\uFF08\u542B\u5168\u65B0\u6D88\u606F\u51B7\u542F\u52A8\uFF0C\u4EC5\u9002\u5408\u4E13\u7528 / \u503C\u73ED\u5C0F\u7FA4\uFF0C\u591A\u4EBA\u7FA4\u91CC\u4F1A\u89C1\u6D88\u606F\u5C31\u56DE\uFF09\u3002\u6CE8\uFF1A\u7FA4\u91CC\u53EA\u6709\u4F60\u548C\u8BE5 bot\uFF081 \u5BF9 1\uFF09\u65F6\u4E00\u76F4\u514D @\uFF0C\u4E0E\u672C\u8BBE\u7F6E\u65E0\u5173\u3002","botDefaults.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.loading":"\u52A0\u8F7D\u4E2D\u2026","common.unknown":"\u672A\u77E5","common.now":"\u521A\u521A","common.never":"\u4ECE\u672A","common.all":"\u5168\u90E8","nav.workflows":"\u5DE5\u4F5C\u6D41(beta)","nav.workflowCatalog":"\u76EE\u5F55","workflow.subnav.runs":"\u8FD0\u884C","workflow.subnav.catalog":"\u76EE\u5F55","workflow.searchPlaceholder":"\u641C\u7D22 runId / workflowId / chatId","workflow.filter.nonTerminal":"\u975E\u7EC8\u6001","workflow.filter.all":"\u5168\u90E8","workflow.status.pending":"\u5F85\u5F00\u59CB","workflow.status.running":"\u8FD0\u884C\u4E2D","workflow.status.waiting":"\u7B49\u5F85\u4E2D","workflow.status.effectAttempting":"\u526F\u4F5C\u7528\u4E2D","workflow.status.timedOut":"\u5DF2\u8D85\u65F6","workflow.status.succeeded":"\u6210\u529F","workflow.status.failed":"\u5931\u8D25","workflow.status.cancelled":"\u5DF2\u53D6\u6D88","workflow.table.run":"\u8FD0\u884C","workflow.table.workflow":"\u5DE5\u4F5C\u6D41","workflow.table.status":"\u72B6\u6001","workflow.table.lastSeq":"\u6700\u540E\u5E8F\u53F7","workflow.table.dangling":"\u60AC\u6302 dEf/dAct/dWait","workflow.table.updated":"\u66F4\u65B0\u65F6\u95F4","workflow.table.chatApp":"\u7FA4\u804A / \u5E94\u7528","workflow.list.failedLoad":"\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","workflow.list.noRuns":"\u6CA1\u6709\u5339\u914D\u7684\u8FD0\u884C\u3002","workflow.list.noFilterMatch":"\u6CA1\u6709\u7B26\u5408\u7B5B\u9009\u6761\u4EF6\u7684\u8FD0\u884C\u3002","workflow.list.loaded":"{count} \u4E2A\u8FD0\u884C \xB7 \u5237\u65B0\u4E8E {time}","workflow.list.error":"\u9519\u8BEF\uFF1A{error}","workflow.detail.back":"\u8FD4\u56DE","workflow.detail.loading":"\u52A0\u8F7D\u4E2D...","workflow.detail.loadFailed":"\u52A0\u8F7D\u5931\u8D25","workflow.detail.cancel":"\u53D6\u6D88","workflow.detail.cliCancelOnly":"\u4EC5 CLI \u53EF\u53D6\u6D88","workflow.detail.cancelTitle":"\u53D6\u6D88\u8FD9\u4E2A\u5DE5\u4F5C\u6D41\u8FD0\u884C","workflow.detail.cliCancelTitle":"\u65E0\u6CD5\u5728\u9875\u9762\u53D6\u6D88\uFF1A\u8BF7\u4F7F\u7528 botmux workflow cancel {runId}","workflow.detail.nodes":"\u8282\u70B9 / Activity","workflow.detail.parallel":"\u5E76\u53D1\u6267\u884C","workflow.detail.parallelMeta":"{count} \u6B21\u5C1D\u8BD5 \xB7 \u6700\u9AD8\u5E76\u53D1 {max} \xB7 \u8FD0\u884C\u4E2D {running}","workflow.detail.noParallelData":"\u8FD8\u6CA1\u6709 attempt \u65F6\u95F4\u6570\u636E\u3002","workflow.detail.parallelNow":"\u73B0\u5728","workflow.detail.node":"\u8282\u70B9","workflow.detail.nodeStatus":"\u8282\u70B9\u72B6\u6001","workflow.detail.activity":"Activity","workflow.detail.activityStatus":"Activity \u72B6\u6001","workflow.detail.attempts":"\u5C1D\u8BD5\u6B21\u6570","workflow.detail.current":"\u5F53\u524D\u5C1D\u8BD5","workflow.detail.detail":"\u8BE6\u60C5","workflow.detail.nodeIO":"\u8282\u70B9\u8F93\u5165\u8F93\u51FA","workflow.detail.timeline":"\u65F6\u95F4\u7EBF","workflow.detail.loadOlder":"\u52A0\u8F7D\u66F4\u65E9\u4E8B\u4EF6","workflow.detail.seq":"\u5E8F\u53F7","workflow.detail.actor":"\u6267\u884C\u8005","workflow.detail.error":"\u9519\u8BEF","workflow.detail.event":"\u4E8B\u4EF6","workflow.detail.time":"\u65F6\u95F4","workflow.detail.refreshed":"\u5237\u65B0\u4E8E {time}","workflow.detail.unknownRun":"\u672A\u77E5\u8FD0\u884C","workflow.detail.snapshotHttp":"snapshot HTTP {status}","workflow.detail.eventsHttp":"events HTTP {status}","workflow.detail.cancelUnavailable":"\u65E0\u6CD5\u53D6\u6D88\uFF1A\u8BF7\u4F7F\u7528 botmux workflow cancel {runId}","workflow.detail.cancelConfirm":`\u786E\u8BA4\u53D6\u6D88\u5DE5\u4F5C\u6D41\u8FD0\u884C {runId}\uFF1F
|
|
3
3
|
|
|
4
4
|
{total} \u4E2A\u60AC\u6302\u9879\u4F1A\u7531 cancel recovery \u5904\u7406\u3002
|
|
5
5
|
effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"workflow.detail.writeAccessCancel":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u70B9\u51FB\u53D6\u6D88\u3002","workflow.detail.cancelHttp":"cancel HTTP {status}","workflow.detail.cancelPending":"\u53D6\u6D88\u5DF2\u63D0\u4EA4\uFF1B\u7B49\u5F85\u8FD0\u884C\u4E2D\u7684 activity \u6536\u655B","workflow.detail.writeAccessApproval":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u5BA1\u6279\u3002","workflow.detail.actionHttp":"{action} HTTP {status}","workflow.detail.approved":"\u5DF2\u901A\u8FC7","workflow.detail.rejected":"\u5DF2\u62D2\u7EDD","workflow.detail.alreadyTerminal":"\u8FD0\u884C\u5DF2\u7EC8\u6001\uFF1B\u672A\u5E94\u7528\u201C{label}\u201D\u3002","workflow.detail.workflowContinue":"{label}\uFF1B\u7B49\u5F85\u5DE5\u4F5C\u6D41\u7EE7\u7EED\u6267\u884C\u3002","workflow.detail.workflowRefreshing":"{label}\uFF1B\u6B63\u5728\u5237\u65B0\u5DE5\u4F5C\u6D41\u72B6\u6001\u3002","workflow.detail.eventsLoaded":"\u5DF2\u52A0\u8F7D {loaded}/{total} \u4E2A\u4E8B\u4EF6","workflow.detail.dangling":"\u60AC\u6302\u9879","workflow.detail.noDangling":"\u6CA1\u6709\u60AC\u6302\u5DE5\u4F5C\u3002","workflow.detail.none":"\u65E0","workflow.detail.noNodes":"\u8FD8\u6CA1\u6709\u8282\u70B9\u3002","workflow.detail.idle":"\u7A7A\u95F2","workflow.detail.noNodeIO":"\u8FD8\u6CA1\u6709\u8282\u70B9\u8F93\u5165\u8F93\u51FA\u3002","workflow.detail.notDispatched":"\u5C1A\u672A\u6D3E\u53D1","workflow.detail.noAttempt":"\u8FD8\u6CA1\u6709\u5C1D\u8BD5","workflow.detail.attempt":"\u5C1D\u8BD5","workflow.detail.authoredInput":"\u539F\u59CB\u8F93\u5165","workflow.detail.resolvedInput":"\u89E3\u6790\u540E\u8F93\u5165","workflow.detail.output":"\u8F93\u51FA","workflow.detail.executionLog":"\u6267\u884C\u65E5\u5FD7","workflow.detail.liveTerminal":"\u5B9E\u65F6\u7EC8\u7AEF","workflow.detail.terminalLive":"\u5728\u7EBF","workflow.detail.terminalClosedShort":"\u5DF2\u5173\u95ED","workflow.detail.terminalClosed":"\u7EC8\u7AEF\u5DF2\u5173\u95ED\u3002\u8BF7\u67E5\u770B\u4E0B\u65B9\u6267\u884C\u65E5\u5FD7\u83B7\u53D6\u6700\u7EC8\u8BB0\u5F55\u3002","workflow.detail.openTerminalNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u7EC8\u7AEF","workflow.detail.terminalReplay":"\u7EC8\u7AEF\u56DE\u653E","workflow.detail.openReplayNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u56DE\u653E","workflow.detail.downloadFullLog":"\u4E0B\u8F7D\u5B8C\u6574\u65E5\u5FD7","workflow.detail.terminalResume":"\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.openResumeNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.resumeSession":"\u7EE7\u7EED\u4F1A\u8BDD","workflow.detail.resumeStarting":"\u6B63\u5728\u542F\u52A8\u2026","workflow.detail.endResumeSession":"\u7ED3\u675F\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.resumeEnding":"\u7ED3\u675F\u4E2D\u2026","workflow.detail.resumeUnsupportedCli":"{cliId} CLI \u4E0D\u652F\u6301 resume","workflow.detail.resumeMissingCliSession":"\u7F3A\u5C11 cliSessionId\uFF0C\u65E0\u6CD5 resume","workflow.detail.resumeStartFailed":"\u542F\u52A8\u8C03\u8BD5\u4F1A\u8BDD\u5931\u8D25 (HTTP {status})","workflow.detail.resumeEndFailed":"\u7ED3\u675F\u8C03\u8BD5\u4F1A\u8BDD\u5931\u8D25 (HTTP {status})","workflow.detail.writeAccessResume":"\u9700\u8981\u5199\u5165\u6743\u9650\u624D\u80FD resume \u4F1A\u8BDD\u3002","workflow.detail.waitPrompt":"\u7B49\u5F85\u63D0\u793A","workflow.detail.approvalComment":"\u5BA1\u6279\u5907\u6CE8","workflow.detail.optionalComment":"\u53EF\u9009\u5907\u6CE8","workflow.detail.approve":"\u901A\u8FC7","workflow.detail.reject":"\u62D2\u7EDD","workflow.detail.submitting":"\u63D0\u4EA4\u4E2D...","workflow.detail.empty":"\u7A7A","workflow.detail.truncated":"\u5DF2\u622A\u65AD","workflow.detail.noData":"\u6CA1\u6709\u6570\u636E\u3002","workflow.detail.noPreview":"\u6CA1\u6709\u9884\u89C8\u3002","workflow.detail.open":"\u6253\u5F00","workflow.detail.deadline":"\u622A\u6B62","workflow.detail.effect":"\u526F\u4F5C\u7528","workflow.detail.wait":"\u7B49\u5F85","workflow.detail.noEvents":"\u8FD8\u6CA1\u6709\u4E8B\u4EF6\u3002","workflow.summary.workflow":"\u5DE5\u4F5C\u6D41","workflow.summary.status":"\u72B6\u6001","workflow.summary.lastSeq":"\u6700\u540E\u5E8F\u53F7","workflow.summary.updated":"\u66F4\u65B0\u65F6\u95F4","workflow.summary.revision":"\u4FEE\u8BA2","workflow.summary.initiator":"\u53D1\u8D77\u4EBA","workflow.summary.failedNode":"\u5931\u8D25\u8282\u70B9","workflow.summary.cancelOrigin":"\u53D6\u6D88\u6765\u6E90","workflow.summary.chat":"\u7FA4\u804A","workflow.summary.app":"\u5E94\u7528","workflow.dangling.activities":"Activities","workflow.dangling.effects":"Effects","workflow.dangling.waits":"Waits","workflow.dangling.cancels":"Cancels","catalog.title":"\u5DE5\u4F5C\u6D41\u76EE\u5F55","catalog.subtitle":"\u4ECE\u5DF2\u4FDD\u5B58\u7684 workflow \u5B9A\u4E49\u521B\u5EFA\u4E00\u6B21\u8FD0\u884C\u3002","catalog.searchPlaceholder":"\u641C\u7D22 workflowId / \u8DEF\u5F84","catalog.refresh":"\u5237\u65B0","catalog.loading":"\u6B63\u5728\u52A0\u8F7D\u76EE\u5F55...","catalog.loadFailed":"\u76EE\u5F55\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","catalog.noDefinitions":"\u6CA1\u6709\u627E\u5230 workflow \u5B9A\u4E49\u3002","catalog.noFilterMatch":"\u6CA1\u6709\u7B26\u5408\u7B5B\u9009\u6761\u4EF6\u7684\u5B9A\u4E49\u3002","catalog.table.workflow":"\u5DE5\u4F5C\u6D41","catalog.table.version":"\u7248\u672C","catalog.table.params":"\u53C2\u6570","catalog.table.nodes":"\u8282\u70B9","catalog.table.revision":"\u4FEE\u8BA2","catalog.table.path":"\u8DEF\u5F84","catalog.paramSummary":"{required}/{total} \u5FC5\u586B","catalog.back":"\u8FD4\u56DE\u76EE\u5F55","catalog.detailTitle":"\u5DE5\u4F5C\u6D41\u5B9A\u4E49","catalog.definitionLoadFailed":"\u5B9A\u4E49\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","catalog.summary":"\u6458\u8981","catalog.paramsSchema":"\u53C2\u6570 Schema","catalog.definitionJson":"\u5B9A\u4E49 JSON","catalog.runPanel":"\u8FD0\u884C\u5DE5\u4F5C\u6D41","catalog.paramsJson":"\u53C2\u6570 JSON","catalog.paramsPlaceholder":`{
|
|
6
6
|
"city": "\u5317\u4EAC"
|
|
7
|
-
}`,"catalog.chatId":"\u7FA4\u804A ID","catalog.larkAppId":"\u98DE\u4E66\u5E94\u7528 ID","catalog.chatBindingHint":"\u5FC5\u586B\uFF0C\u7528\u4E8E\u786E\u5B9A humanGate \u5361\u7247\u53D1\u9001\u5230\u54EA\u4E2A\u98DE\u4E66\u7FA4\uFF0C\u4EE5\u53CA\u53D6\u6D88\u8DEF\u7531\u5F52\u5C5E\u3002","catalog.run":"\u8FD0\u884C","catalog.running":"\u542F\u52A8\u4E2D...","catalog.badParamsJson":"\u53C2\u6570\u5FC5\u987B\u662F JSON object\u3002","catalog.writeAccess":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u8FD0\u884C\u3002","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"\u8FD0\u884C\u5DF2\u542F\u52A8\uFF1B\u6B63\u5728\u6253\u5F00\u8BE6\u60C5\u9875...","catalog.invalidParams":"\u53C2\u6570\u65E0\u6548","catalog.issue":"{path}: {message}","catalog.noParams":"\u6CA1\u6709\u58F0\u660E\u53C2\u6570\u3002","catalog.required":"\u5FC5\u586B","catalog.optional":"\u53EF\u9009","catalog.default":"\u9ED8\u8BA4\u503C","catalog.description":"\u8BF4\u660E","catalog.path":"\u8DEF\u5F84","catalog.revision":"\u4FEE\u8BA2","catalog.nodeCount":"\u8282\u70B9\u6570"},ls={"app.name":"botmux","app.subtitle":"Feishu AI CLI Control","time.secondsAgo":"{value}s ago","time.minutesAgo":"{value}m ago","time.hoursAgo":"{value}h ago","nav.overview":"Overview","nav.sessions":"Sessions","nav.sidebarCollapse":"Collapse sidebar","nav.sidebarExpand":"Expand sidebar","nav.groups":"Groups","nav.schedules":"Schedules","nav.settings":"Settings","nav.botDefaults":"Bot Defaults","status.live":"Live","status.disconnected":"Disconnected","status.system":"System","status.light":"Light","status.dark":"Dark","status.language":"Language","status.theme":"Theme","theme.base":"Basic","theme.skins":"Skins","skin.cyber":"2077","skin.genshin":"Genshin","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"Blue Archive","skin.zzz":"ZZZ","skin.dragonball":"Dragon Ball","skin.ikun":"ikun","botOnboarding.add":"Add Bot","botOnboarding.title":"Add Bot","botOnboarding.intro":"Pick a CLI and working directory, scan to create a PersonalAgent app \u2014 the dashboard writes it to local bots.json and auto-configures Open Platform permissions.","botOnboarding.cliLabel":"CLI adapter","botOnboarding.dirLabel":"Working directory","botOnboarding.dirPlaceholder":"Default ~ (home); must exist on the daemon host","botOnboarding.modelLabel":"Model (optional)","botOnboarding.modelPlaceholder":"Leave empty for the CLI default model","botOnboarding.startScan":"Start scan","botOnboarding.cancel":"Cancel","botOnboarding.starting":"Generating QR code...","botOnboarding.waiting":"Scan with the Feishu app to create the app.","botOnboarding.verifying":"Scan accepted. Verifying credentials...","botOnboarding.configuringPermissions":"Auto-configuring Open Platform permissions\u2026","botOnboarding.platformScanHint":"Scan once more with the Feishu app to sign in to the Open Platform (to auto-import permissions, set the callback, and submit a version).","botOnboarding.platformQrAlt":"Open Platform login QR code","botOnboarding.completed":"Bot added.","botOnboarding.permissionOk":"Auto-imported {count} permissions.","botOnboarding.permissionSkipped":"({count} skipped \u2014 not in the tenant catalog)","botOnboarding.permissionVersion":"Submitted version {version}.","botOnboarding.permissionManual":"Permissions could not be auto-configured. Complete these steps manually:","botOnboarding.metaDir":"Dir","botOnboarding.failed":"Add failed","botOnboarding.openLink":"Open scan link in browser","botOnboarding.close":"Close","botOnboarding.restartHint":"bots.json has been updated. Run pnpm daemon:restart for the new bot to take effect.","botOnboarding.qrAlt":"Feishu bot onboarding QR code","overview.title":"Workbench","overview.subtitle":"Live status of your AI teammates \xB7 synced with Feishu topics","overview.team":"AI Team","overview.teamHint":"Live status of every digital teammate","overview.attention":"Needs You","overview.attentionHint":"Blocked tasks \u2014 one reply gets them moving again","overview.activeSessions":"Active Sessions","overview.activeSessionsHint":"Sessions currently running","overview.today":"Right Now","overview.todayHint":"Active session distribution","overview.viewAll":"View all \u2192","overview.botIdle":"Standing by, ready for new tasks","overview.botOffline":"Offline \u2014 daemon not running","overview.botBusy":"Working \xB7 {count} sessions","overview.botNeedsYou":"Waiting on you","overview.botReady":"Ready","overview.botOff":"Offline","overview.sessionsCount":"{count} sessions","overview.lastActive":"active {time} ago","overview.noAttention":"Nothing waiting on you","overview.teamExpand":"Show all {count} \u25BE","overview.teamCollapse":"Collapse \u25B4","strip.pending":"{count} pending","strip.longest":"waiting {time} \u2014 {bot} {reason}","strip.handle":"Handle now","overview.openSessions":"Active Sessions","overview.workingSessions":"Working","overview.onlineBots":"Online Bots","overview.schedules":"Schedules","overview.groups":"Groups Seen","overview.enabledSchedules":"Enabled","overview.total":"total","overview.active":"active","overview.daemonRegistry":"daemon registry","overview.chatMatrix":"chat matrix","overview.recentSessions":"Recent Sessions","overview.nextSchedules":"Next Runs","overview.noSessions":"No sessions yet.","overview.noSchedules":"No schedules yet.","sessions.title":"Session Control","sessions.subtitle":"Locate Feishu topics, open Web Terminal, close or resume CLI sessions.","sessions.search":"Search working dir / title / IDs","sessions.anyStatus":"Any status","sessions.adoptAny":"adopt: any","sessions.adoptYes":"adopt: yes","sessions.adoptNo":"adopt: no","sessions.activeOnly":"Active only","sessions.closeSelected":"Close selected","sessions.clearSelection":"Clear","sessions.selectedCount":"{count} sessions selected","sessions.bot":"Bot","sessions.cli":"CLI","sessions.chat":"Chat","sessions.openChat":"Open chat","sessions.status":"Status","sessions.tokenIn":"Token In","sessions.tokenOut":"Token Out","sessions.titleCol":"Title","sessions.workingDir":"Working Dir","sessions.created":"Created","sessions.last":"Last","sessions.adopt":"Adopt","sessions.actions":"Actions","sessions.details":"Details","sessions.copy":"Copy","sessions.copied":"Copied","sessions.locate":"Locate Topic","sessions.locating":"Sending...","sessions.cooldown":"Cooldown {seconds}s","sessions.openTerminal":"Terminal","sessions.writeLink":"Write Link","sessions.writeLinkHint":"Get a writable terminal link (carries a write-access token; opens in a new tab)","sessions.writeLinkFail":"Failed to get write link","sessions.close":"Close Session","sessions.resume":"Resume Session","sessions.dismiss":"Close","sessions.closeConfirm":"Close this session?","sessions.resumeFailed":"Resume failed","sessions.land":"Land","sessions.landLoading":"Loading sandbox diff\u2026","sessions.landUnavailable":"Cannot land","sessions.landEmpty":"No changes in the sandbox clone.","sessions.landApply":"Apply to disk","sessions.landDiscard":"Discard","sessions.landApplied":"Landed","sessions.landFailed":"Land failed","sessions.landDiscarded":"Discarded (sandbox clone not applied).","connectors.lede":"Let external systems (alerts, CI, tickets\u2026) trigger a bot to speak in a group or run a workflow via one webhook.","connectors.createTitle":"New Webhook","connectors.fName":"Name","connectors.fNamePh":"e.g. Prod alerts","connectors.fBot":"Trigger bot","connectors.fKind":"Trigger type","connectors.kindTurn":"Single turn (bot responds once)","connectors.kindWorkflow":"Workflow","connectors.fWf":"Workflow ID","connectors.fMode":"Deliver to which group","connectors.modeDynamic":"Specified per request (chat passed in)","connectors.modeFixed":"Fixed group","connectors.modeNewGroup":"New group each time","connectors.fFixedChat":"Target group","connectors.fChatManualPh":"Enter chat ID manually: oc_\u2026","connectors.chatManualLink":"Group not listed? Enter ID manually \u2192","connectors.chatListLink":"\u2190 Pick from group list","connectors.fAllow":"Allowed groups","connectors.optional":" (optional)","connectors.allowHint":"Hold Ctrl/\u2318 to multi-select; empty = unrestricted. Only validates the chat passed in the request.","connectors.dynamicHint":'<b>Dynamic mode</b>: the chat ID is passed per request, one of three ways \u2014 query <code>?chatId=<chatId></code> \xB7 header <code>x-botmux-chat-id: <chatId></code> \xB7 body <code>{"chatId":"<chatId>"}</code>.<br>For "one URL triggers directly, no params", choose Fixed group instead.',"connectors.fDedup":"Dedup field","connectors.fDedupPh":"e.g. alert.id (read from event body)","connectors.dedupHint":"Set: events with the same value go to the <b>same group</b>. Empty: each event <b>creates a new group</b>.","connectors.fInstruction":"Instruction","connectors.fInstructionPh":"What the bot should do on the event. e.g. Summarize the severity, @ the oncall, suggest next steps. Empty = hand the raw event to the model.","connectors.fVerify":"Verification","connectors.verifyToken":"Token (simple: secret in the URL, one curl triggers it)","connectors.verifyHmac":"HMAC signature (advanced: more secure, sign the request yourself)","connectors.fSecret":"Secret / token","connectors.fSecretPh":"Leave empty to auto-generate (shown once)","connectors.btnCreate":"Create","connectors.listTitle":"Existing Webhooks","connectors.loading":"Loading\u2026","connectors.noBotGroups":"(This bot has no visible groups; enter an ID manually on the right)","connectors.modeLabelFixed":"Fixed group","connectors.modeLabelNewGroup":"New group each time","connectors.modeLabelDynamic":"Per-request group","connectors.kindLabelWorkflow":"Workflow","connectors.kindLabelTurn":"Single turn","connectors.count":"\xB7 {count}","connectors.empty":"No webhooks yet. Create one with the form above.","connectors.enabled":"Enabled","connectors.disabled":"Disabled","connectors.badgeToken":"Token","connectors.badgeSign":"Signed","connectors.dest":'to "{name}"',"connectors.btnDisable":"Disable","connectors.btnEnable":"Enable","connectors.btnDel":"Delete","connectors.webhookUrl":"Webhook URL: ","connectors.copy":"Copy","connectors.copied":"Copied","connectors.tokenHint":"Token mode: append <code>/<token></code> to the URL when calling (the token is shown only on create/rotate).","connectors.dynamicReqHint":'Dynamic mode: the request must carry the target chat \u2014 <code>?chatId=<chatId></code> or header <code>x-botmux-chat-id</code> or body <code>{"chatId":"\u2026"}</code>.',"connectors.instructionPrefix":"Instruction: ","connectors.delConfirm":"Delete this webhook? Its URL stops working immediately.","connectors.errName":"Enter a name","connectors.errBot":"Pick a bot","connectors.errWf":"Enter a workflow ID","connectors.errChat":"Pick (or enter) a target group","connectors.creating":"Creating\u2026","connectors.usageDynamicLede":"Dynamic mode: the URL already has the token; pass the target chat ID when calling{gn}:","connectors.usageDynamicNote":'The chat can also go in header <code>x-botmux-chat-id</code> or body <code>{"chatId":"\u2026"}</code>. \u26A0\uFE0F The URL is the credential \u2014 keep it secret.',"connectors.usageTokenLede":"This URL already has the token and a fixed target group; just POST to trigger:","connectors.usageTokenNote":"\u26A0\uFE0F The URL is the credential \u2014 keep it private; delete or rotate it in the list below.","connectors.usageHmac":"The external system must HMAC-SHA256-sign <code>timestamp.body</code> and call with <code>x-botmux-timestamp</code> / <code>x-botmux-nonce</code> / <code>x-botmux-signature</code> headers","connectors.usageHmacDynamic":", and also pass the target chat ID as above","connectors.createdPrefix":'Created "{name}"',"connectors.createdDest":'to "{name}"',"connectors.tokenLabel":"Access token","connectors.signLabel":"Signing secret","connectors.secretOnce":" (shown once \u2014 save it): ","connectors.createFailed":"Create failed: {error}","connectors.noOnlineBots":"(No online bots)","team.navHome":"My team","team.navManage":"Team management","team.eyebrow":"Team","team.homeTitle":"Team collaboration (cross-deployment)","team.homeLede":"Invite other deployments (botmux instances teammates run) into one team to discover bots across deployments and pull collaborative groups.","team.localDeployTitle":"This deployment","team.myIdentity":"My Lark identity: ","team.unbound":"Not bound","team.bindBtn":"Bind","team.bindHint":" (auto-identifies you via the bot credentials; once bound, pulling a group adds you and attributes the bots to you)","team.myTeams":"My teams","team.searchPh":"Search name / capability / CLI\u2026","team.allCli":"All CLIs","team.hasCap":"Has capability tag","team.hasRole":"Has default role","team.teamsHint":"Tick bots in any team to pull them into a group (each with its owner). To create a team / generate an invite code / join another team, go to Team management.","team.loading":"Loading\u2026","team.roleModalTitle":"Default role","team.roleModalHint":"The bot default persona (applies across groups), read-only here. To edit, go to the Bot Defaults page.","team.close":"Close","team.tagLocal":"This deployment","team.tagRemoteStale":"Remote \xB7 offline?","team.tagRemote":"Remote","team.removeMember":"Remove","team.depTag":"({tag})","team.depCount":"{count}","team.depSelected":", {n} selected","team.capPh":"Capability tag\u2026","team.viewRole":"View","team.hasRoleShort":"Has role","team.noMatch":"No bots match the filters.","team.gnamePh":"Group name (e.g. cross-team triage)","team.pullGroupBtn":"Pull ticked bots into a group","team.pullGroupHint":"Tick bots \u2192 pull into a Lark group (owner included automatically)","team.noTeams":"No teams yet. Go to Team management to generate an invite code for others to join you, or join another team.","team.connected":"Connected","team.connectFail":"Connection failed: {error}","team.iHost":"I host","team.teamMeta":"{deps} deployments \xB7 {bots} bots","team.rosterFail":"Could not fetch this team roster.","team.acrossTeams":" (across {n} teams, deduped)","team.botsWord":"bots","team.groupCreated":"Group created","team.delegatedBy":' (created by "{name}")',"team.openInLark":"Open in Lark","team.invalidBots":"Bots not added: {ids}","team.invalidOwners":"{n} owner(s) could not be added","team.missingIdentity":"You have not bound a Lark identity, so you were not added to the group (bind it in My team)","team.skippedNoOwner":"{n} bot(s) skipped because their owner has no bound identity (not added)","team.errNoLocalBot":"Tick at least one of your own (this deployment) online bots \u2014 the group is created by it and adds you (the initiator).","team.errAllSkipped":"None of the selected bot owners have a bound identity, so the group cannot be pulled (a bot cannot join a group without its owner). Have those deployments bind an identity first.","team.errNoCreator":"No available group creator (the relevant deployments have no online bot, or are unreachable)","team.errDelegationTimeout":"Timed out delegating group creation to the other deployment (it may have succeeded \u2014 check Lark, do not retry)","team.errGroupCreate":"Group creation failed: {error}","team.roleModalTitleName":"Default role \xB7 {name}","team.bound":"Bound","team.myHostedTeam":"My hosted team","team.remoteTeamLabel":"{name} team","team.manageTitle":"Team management","team.manageLede":"Create multiple teams, generate an invite code per team, or join another team. A team = this deployment bots + the other deployments that joined it.","team.hostedTitle":"Teams I host","team.newTeamPh":"New team name","team.createTeamBtn":"Create team","team.joinTitle":"Join another team","team.hubPh":"Hub address, e.g. http://10.0.0.5:7891","team.codePh":"Invite code","team.joinBtn":"Join","team.noTeamsShort":"No teams yet.","team.default":"Default","team.manageMetaDeps":"{count} deployments","team.manageMetaRemote":" (incl. {r} remote)","team.manageMetaBots":"{count} bots","team.genInvite":"Generate invite code","team.delBtn":"Delete","team.generating":"Generating\u2026","team.inviteResultLede":"Send the two items below to someone on another deployment (valid once, within 24h):","team.inviteHub":"Hub address: ","team.inviteCode":"Invite code: ","team.genFail":"Generation failed.","team.delConfirm":'Delete team "{name}"? Deployments that joined it will be removed (their own deployments are unaffected).',"team.errName":"Enter a team name","team.creating":"Creating\u2026","team.created":"Created","team.createFail":"Create failed: {error}","team.errHubCode":"Enter the hub address and invite code.","team.joining":"Joining\u2026","team.joined":'Joined "{name}" \u2014 see it in My team.',"team.joinErrSelf":"This is your own deployment; you cannot join yourself (the invite code is for someone on another deployment).","team.joinErrAlready":"Your deployment already joined this team.","team.joinErrUnreachable":"Cannot reach the hub (check the address/network).","team.joinErrTimeout":"The hub timed out.","team.joinErrGeneric":"Join failed: {error}","team.identifying":"Identifying\u2026","team.bound2":"Bound: {name}","team.multiCandidate":"Multiple candidates found \u2014 click yourself:","team.binding":"Binding\u2026","team.bindFail":"Bind failed: {error}","team.noCandidates":"No identity found: make sure the bot has allowedUsers configured and contacts permission.","team.removeMemberConfirm":'Remove "{name}" from this team? Its bots disappear from this team roster (their own deployment is unaffected).',"team.creatingGroup":"Creating group\u2026","team.defaultGroupName":"Collaboration group","team.errPickBot":"Tick at least one bot first","sessions.closeBulkConfirm":"Close {count} selected sessions?","sessions.empty":"No sessions match the filters.","sessions.viewMode":"Session view","sessions.viewKanban":"Kanban","sessions.viewBoard":"Board","sessions.viewTable":"Table","sessions.selectSession":"Select session","sessions.board.needsYou":"Needs You","sessions.board.needsYouHint":"Repo, TUI, or usage limit waiting","sessions.board.starting":"Starting","sessions.board.startingHint":"CLI is spawning or resuming","sessions.board.working":"Working","sessions.board.workingHint":"Streaming, analyzing, or using tools","sessions.board.idle":"Idle","sessions.board.idleHint":"Ready for the next message","sessions.board.emptyColumn":"No sessions","sessions.board.signalRepo":"Repo needed","sessions.board.signalPrompt":"TUI choice needed","sessions.board.signalLimited":"Usage limited","sessions.board.signalAgent":"Needs human input","sessions.board.waiting":"Waiting","sessions.board.dragHint":"Drag header to reorder columns","sessions.board.moveLeft":"Move column left","sessions.board.moveRight":"Move column right","sessions.kanban.backlog":"Backlog","sessions.kanban.todo":"Todo","sessions.kanban.inProgress":"In Progress","sessions.kanban.inReview":"In Review","sessions.kanban.done":"Done","sessions.kanban.updated":"Updated {time}","sessions.kanban.moreHidden":"{count} more hidden","sessions.kanban.openTab":"Open in new tab","sessions.kanban.openFeishu":"Open in Feishu","sessions.kanban.terminalLoading":"Opening terminal\u2026","sessions.kanban.rename":"Rename (double-click title works too)","sessions.kanban.renameFail":"Rename failed","sessions.kanban.moveFail":"Move failed","sessions.kanban.groupBy":"Group by","sessions.kanban.groupFlow":"Workflow","sessions.kanban.groupTeam":"Team","sessions.kanban.groupBot":"Bots","sessions.kanban.teamLoading":"Loading teams\u2026","sessions.kanban.noTeam":"No teams","sessions.kanban.teamScope":"{chats} collab chats \xB7 {sessions} sessions","sessions.kanban.remoteHint":"Session from the {name} deployment (snapshot; terminal/history live on their machine)","sessions.kanban.clusterDragHint":"Drag header to move the whole group","sessions.history.title":"History","sessions.history.loading":"Fetching Feishu messages\u2026","sessions.history.fail":"Failed to load history","sessions.history.empty":"No messages","sessions.history.user":"User","sessions.history.owner":"Owner","sessions.history.staleHint":"The dashboard or daemon process may still run an old build \u2014 botmux restart and retry","groups.title":"Groups & Bots","groups.subtitle":"Inspect the chat x bot matrix and manage group creation, oncall, leave, and disband flows.","groups.search":"Search chat name / ID / owner","groups.missingOnly":"Missing bot only","groups.refresh":"Refresh","groups.create":"New Group","groups.chat":"Chat","groups.actions":"Actions","groups.addBots":"Add Bots","groups.manage":"Manage","groups.empty":"No chats match the filters.","groups.createTitle":"Create New Group","groups.createHelp":"Pick bots to invite. The dashboard chooses an online daemon as creator.","groups.name":"Group Name","groups.namePlaceholder":"e.g. AI ChangeLog","groups.bindDir":"Bind Directory","groups.bindDirHelp":"New topics start the CLI here and skip repo selection.","groups.botPicker":"Bots","groups.createSubmit":"Create","groups.cancel":"Cancel","groups.successTitle":"Group Created","groups.openGroup":"Open Group","groups.manageTitle":"Manage {name}","groups.owner":"Owner","groups.oncall":"Oncall Mode","groups.oncallHelp":"When enabled, group members can @ the bot; new topics use the bound directory.","groups.leaveTitle":"Select Bots to Leave","groups.leaveSelected":"Selected Bots Leave","groups.disband":"Disband Group","groups.dangerHint":"Disband only works when an in-chat bot is the owner. Otherwise prefer leaving the chat.","groups.save":"Save","groups.needWorkingDir":"Working directory is required","groups.noBotsOnline":"No bots online. Restart the daemon first.","schedules.title":"Schedules","schedules.subtitle":"View, pause, resume, and run scheduled tasks across daemons.","schedules.search":"Search name / prompt / working dir","schedules.anyKind":"Any kind","schedules.enabledOnly":"Enabled only","schedules.name":"Name","schedules.bot":"Bot","schedules.schedule":"Schedule","schedules.next":"Next","schedules.last":"Last","schedules.repeat":"Repeat","schedules.enabled":"Enabled","schedules.actions":"Actions","schedules.runNow":"Run Now","schedules.pause":"Pause","schedules.resume":"Resume","schedules.empty":"No schedules.","settings.title":"Global Settings","settings.subtitle":"Manage machine-wide botmux dashboard behavior shared by every bot.","settings.loading":"Loading settings\u2026","settings.loadFailed":"Failed to load settings","settings.readOnlyVisitor":"Read-only access \u2014 changing settings requires an authorized link (run botmux dashboard).","settings.sectionAccess":"Access","settings.publicReadOnly":"Allow tokenless read-only dashboard access","settings.publicReadOnlyHelp":"When enabled, visitors without a token can view the dashboard, sessions, schedules, and SSE. Writes such as close, pause, and approvals still require token auth. Sensitive raw terminal logs always require a token.","settings.sectionCards":"Feishu Cards","settings.openTerminalInFeishu":"Open streaming-card terminals in the Feishu sidebar","settings.openTerminalInFeishuHelp":"Off by default: terminal buttons open the Web Terminal URL directly. When enabled, botmux wraps the URL with Feishu web_url/open so Feishu PC opens it in a sidebar. Terminal write access is still controlled by its token.","settings.saving":"Saving\u2026","settings.saved":"Saved","settings.saveFailed":"Save failed","settings.sectionMaintenance":"Auto Maintenance","settings.autoUpdate":"Auto update","settings.autoUpdateHelp":"Off by default. At the set time, runs npm install -g botmux@latest to install the latest version (download/install only \u2014 no restart). npm-global installs only.","settings.autoRestart":"Auto restart","settings.autoRestartHelp":"Off by default; requires auto-update. After auto-update installs a newer version, restart to apply it if no session is in progress (busy \u21D2 slips to the next day).","settings.autoUpdateLocalDev":"This is a local-dev install (running from source); auto-update is unavailable.","settings.maintenanceTime":"Time","botDefaults.title":"Bot Profiles","botDefaults.subtitle":"Per-bot defaults: oncall, proactive start, persona role, cards and grants.","botDefaults.metaOnline":"Online \xB7 daemon healthy","botDefaults.search":"Search bot name / app id","botDefaults.refresh":"Refresh","botDefaults.sectionOncall":"New-chat Oncall","botDefaults.sectionBrand":"Card Signature","botDefaults.warning":"When enabled, chats without an oncall binding auto-bind to this directory on their next new topic. Manually bound or unbound chats are preserved.","botDefaults.empty":"No bots online. Run botmux restart first.","botDefaults.defaultOncall":"Default to oncall mode","botDefaults.defaultOncallHelp":"Unbound chats auto-bind on the next new topic","botDefaults.workingDir":"Default Working Directory","botDefaults.lastEnabled":"Last Enabled","botDefaults.autobound":"{count} chats auto-bound","botDefaults.save":"Save","botDefaults.required":"Working directory is required when enabled","botDefaults.brandLabel":"Signature (card footer)","botDefaults.brandLabelHelp":"Footer signature on cards this bot sends. Save empty = hide; fill in = custom (markdown ok, e.g. [Acme](https://\u2026)); Reset = show botmux.","botDefaults.brandLabelPlaceholder":"Default: botmux (empty = hidden)","botDefaults.sectionSandbox":"File sandbox (oncall)","botDefaults.sandboxToggle":"Enable file sandbox","botDefaults.sandboxHelp":"When on, every session of this bot runs in a per-session sandbox: only a project copy is visible \u2014 your real files, secrets, and other sessions are not. For sharing the bot with semi-trusted users (oncall). Linux only; applies to the next new session.","botDefaults.sandboxSaved":"Saved (applies to the next new session)","botDefaults.brandSave":"Save Signature","botDefaults.brandReset":"Reset to default","botDefaults.brandStateDefault":"Current: default botmux","botDefaults.brandStateOff":"Current: off","botDefaults.brandStateCustom":"Current: custom","botDefaults.sectionCard":"Card Behavior","botDefaults.disableStreaming":"Disable streaming card","botDefaults.disableStreamingHelp":"Stop posting the live session status card (and its Open Terminal entry). The task's final result still arrives as a message. For those who find the live card noisy.","botDefaults.writableLink":"Put a writable terminal link on the card","botDefaults.writableLinkHelp":'\u26A0\uFE0F Embeds a writable terminal link in the streaming card body \u2014 anyone in the chat can open and drive the terminal. Off = current behavior (private DM via the "Get Write Link" button).',"botDefaults.writableLinkMoot":"Streaming card disabled \u2014 this has no effect","botDefaults.privateCard":"/card sends a private card (authorized users only)","botDefaults.privateCardHelp":'Makes /card send an ephemeral "visible-to-specific-people" card: delivered only to the owner (allowedUsers); /grant-authorized talk users and everyone else in the chat cannot see it. Trade-off: it is a static snapshot (no live updates) and only works in regular group chats (topic groups / DMs fail, with no fallback). Affects only the /card command; the auto streaming card is unchanged.',"botDefaults.cardPrefSaved":"Saved","botDefaults.sectionRole":"Default Role","botDefaults.roleHelp":"This bot's default persona (applies across all chats), injected into the bot's sessions in every chat; a single group can override it on the Roles page. Save empty = delete.","botDefaults.rolePlaceholder":"e.g. You are a backend triage assistant; answer concisely, prefer runnable commands\u2026","botDefaults.roleSave":"Save role","botDefaults.roleDelete":"Delete","botDefaults.roleSaved":"Saved","botDefaults.roleDeleted":"Deleted","botDefaults.roleLoadErr":"Failed to load role","botDefaults.sectionAutoStart":"Proactive Start","botDefaults.autoStartJoin":"Auto-start when added to a new chat","botDefaults.autoStartJoinHelp":'When enabled, the bot auto-starts a session and gets to work the moment it is added to a new chat (when an authorized user / allowedUsers is a member), no @ needed. It launches in the bot default working dir; if none is configured it shows a repo-select card first. Prerequisite: subscribe the "bot joined chat" event im.chat.member.bot.added_v1 for this app and grant the member-read scope in the Feishu console.',"botDefaults.autoStartJoinPrompt":"First-turn prompt on join (optional)","botDefaults.autoStartJoinPromptPlaceholder":"Filled = used as the first task after joining; blank = the bot reads the chat and decides what to do","botDefaults.autoStartJoinPromptSave":"Save prompt","botDefaults.autoStartTopic":"Auto-start on new topics in topic groups","botDefaults.autoStartTopicHelp":"When enabled, in a topic group the bot automatically joins each newly opened topic and starts working on its first message, no @ needed. Topic groups only \u2014 regular groups are unaffected.","botDefaults.sectionSessionMode":"Session mode","botDefaults.p2pMode":"Private chat session mode","botDefaults.p2pThread":"thread (separate session per DM)","botDefaults.p2pChat":"chat (flat continuous session)","botDefaults.p2pHelp":"How 1:1 DMs are sessioned: thread = each top-level message starts its own session (keeps chatter out of one CLI process); chat = the whole DM shares one continuous session and context (Hermes-like). Takes effect immediately.","botDefaults.regularGroupMode":"Regular group session mode","botDefaults.regularGroupModeChat":"chat (flat continuous session, default)","botDefaults.regularGroupModeNewTopic":"new-topic (each top-level @ opens its own topic & session)","botDefaults.regularGroupModeShared":"shared (topic display, reusing one session)","botDefaults.regularGroupModeHelp":"How new top-level @mentions in regular (non-topic) groups are sessioned: chat = the whole group shares one continuous session (default); new-topic = each top-level @ opens its own topic with a separate session; shared = topic display but reuse the same session (replies fold into a topic yet share the group session & context). This is the per-bot default; a specific group can override it via /reply-mode. Takes effect immediately.","botDefaults.mentionMode":"Group @ policy","botDefaults.mentionModeAlways":"Always require @ (default)","botDefaults.mentionModeTopic":"No @ needed inside topics","botDefaults.mentionModeNever":"Never require @","botDefaults.mentionModeHelp":'Bot-global: controls when an @ is required to get a reply in groups. "Always require @" = every message needs an @ (default, safest; inside topics too, in multi-person groups); "No @ needed inside topics" = starting a new conversation / top-level still needs @, but follow-ups inside ANY topic this bot already drives (new-topic / shared / topic-group) continue without @; "Never require @" = non-@ messages are answered too wherever the bot has talk access (including cold-starting on a brand-new message \u2014 only suitable for dedicated / on-call small groups; in busy multi-person groups it replies to everything). Note: when you are alone with this bot (1:1) replies never need an @, independent of this setting.',"botDefaults.sectionGrant":"Authorization & Quota","botDefaults.restrictGrant":"Restrict grantees to plain conversation","botDefaults.restrictGrantHelp":"When enabled, /grant-authorized users (the owner is exempt) can only send plain messages; every slash command is blocked: botmux built-in commands, passthrough commands, /workflow, /introduce, /t, and CLI-native commands (/help, etc.). Text like /path/to/file is not misclassified.","botDefaults.quotaDefault":"Default message quota","botDefaults.quotaPlaceholder":"Empty = no default quota","botDefaults.quotaHelp":'Message count a bare /grant @x (no number) hands out. Empty or "Turn off" merely stops applying a default to bare /grant \u2014 it does NOT clear existing quota counters, nor affect an explicit /grant @x N; those keep being enforced. Authorization is auto-revoked once a quota runs out.',"botDefaults.quotaSave":"Save quota","botDefaults.quotaOff":"Turn off","botDefaults.quotaInvalid":"Quota must be a positive integer","botDefaults.quotaStateOff":"Current: no default quota","botDefaults.quotaStateOn":"Current: {count} per grantee","nav.roles":"Roles","roles.title":"Role Management","roles.subtitle":"Set per-bot role prompts for each group. Each bot adopts its own persona in the selected group.","roles.search":"Search group / bot / ID","roles.refresh":"Refresh","roles.selectHint":"\u2190 Expand a group and select a bot to edit its role","roles.editorPlaceholder":`Enter role description, e.g.:
|
|
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"},ls={"app.name":"botmux","app.subtitle":"Feishu AI CLI Control","time.secondsAgo":"{value}s ago","time.minutesAgo":"{value}m ago","time.hoursAgo":"{value}h ago","nav.overview":"Overview","nav.sessions":"Sessions","nav.sidebarCollapse":"Collapse sidebar","nav.sidebarExpand":"Expand sidebar","nav.groups":"Groups","nav.schedules":"Schedules","nav.settings":"Settings","nav.botDefaults":"Bot Defaults","status.live":"Live","status.disconnected":"Disconnected","status.system":"System","status.light":"Light","status.dark":"Dark","status.language":"Language","status.theme":"Theme","theme.base":"Basic","theme.skins":"Skins","skin.cyber":"2077","skin.genshin":"Genshin","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"Blue Archive","skin.zzz":"ZZZ","skin.dragonball":"Dragon Ball","skin.ikun":"ikun","botOnboarding.add":"Add Bot","botOnboarding.title":"Add Bot","botOnboarding.intro":"Pick a CLI and working directory, scan to create a PersonalAgent app \u2014 the dashboard writes it to local bots.json and auto-configures Open Platform permissions.","botOnboarding.cliLabel":"CLI adapter","botOnboarding.dirLabel":"Working directory","botOnboarding.dirPlaceholder":"Default ~ (home); must exist on the daemon host","botOnboarding.modelLabel":"Model (optional)","botOnboarding.modelPlaceholder":"Leave empty for the CLI default model","botOnboarding.startScan":"Start scan","botOnboarding.cancel":"Cancel","botOnboarding.starting":"Generating QR code...","botOnboarding.waiting":"Scan with the Feishu app to create the app.","botOnboarding.verifying":"Scan accepted. Verifying credentials...","botOnboarding.configuringPermissions":"Auto-configuring Open Platform permissions\u2026","botOnboarding.platformScanHint":"Scan once more with the Feishu app to sign in to the Open Platform (to auto-import permissions, set the callback, and submit a version).","botOnboarding.platformQrAlt":"Open Platform login QR code","botOnboarding.completed":"Bot added.","botOnboarding.permissionOk":"Auto-imported {count} permissions.","botOnboarding.permissionSkipped":"({count} skipped \u2014 not in the tenant catalog)","botOnboarding.permissionVersion":"Submitted version {version}.","botOnboarding.permissionManual":"Permissions could not be auto-configured. Complete these steps manually:","botOnboarding.metaDir":"Dir","botOnboarding.failed":"Add failed","botOnboarding.openLink":"Open scan link in browser","botOnboarding.close":"Close","botOnboarding.restartHint":"bots.json has been updated. Run pnpm daemon:restart for the new bot to take effect.","botOnboarding.qrAlt":"Feishu bot onboarding QR code","overview.title":"Workbench","overview.subtitle":"Live status of your AI teammates \xB7 synced with Feishu topics","overview.team":"AI Team","overview.teamHint":"Live status of every digital teammate","overview.attention":"Needs You","overview.attentionHint":"Blocked tasks \u2014 one reply gets them moving again","overview.activeSessions":"Active Sessions","overview.activeSessionsHint":"Sessions currently running","overview.today":"Right Now","overview.todayHint":"Active session distribution","overview.viewAll":"View all \u2192","overview.botIdle":"Standing by, ready for new tasks","overview.botOffline":"Offline \u2014 daemon not running","overview.botBusy":"Working \xB7 {count} sessions","overview.botNeedsYou":"Waiting on you","overview.botReady":"Ready","overview.botOff":"Offline","overview.sessionsCount":"{count} sessions","overview.lastActive":"active {time} ago","overview.noAttention":"Nothing waiting on you","overview.teamExpand":"Show all {count} \u25BE","overview.teamCollapse":"Collapse \u25B4","strip.pending":"{count} pending","strip.longest":"waiting {time} \u2014 {bot} {reason}","strip.handle":"Handle now","overview.openSessions":"Active Sessions","overview.workingSessions":"Working","overview.onlineBots":"Online Bots","overview.schedules":"Schedules","overview.groups":"Groups Seen","overview.enabledSchedules":"Enabled","overview.total":"total","overview.active":"active","overview.daemonRegistry":"daemon registry","overview.chatMatrix":"chat matrix","overview.recentSessions":"Recent Sessions","overview.nextSchedules":"Next Runs","overview.noSessions":"No sessions yet.","overview.noSchedules":"No schedules yet.","sessions.title":"Session Control","sessions.subtitle":"Locate Feishu topics, open Web Terminal, close or resume CLI sessions.","sessions.search":"Search working dir / title / IDs","sessions.anyStatus":"Any status","sessions.adoptAny":"adopt: any","sessions.adoptYes":"adopt: yes","sessions.adoptNo":"adopt: no","sessions.activeOnly":"Active only","sessions.closeSelected":"Close selected","sessions.clearSelection":"Clear","sessions.selectedCount":"{count} sessions selected","sessions.bot":"Bot","sessions.cli":"CLI","sessions.chat":"Chat","sessions.openChat":"Open chat","sessions.status":"Status","sessions.tokenIn":"Token In","sessions.tokenOut":"Token Out","sessions.titleCol":"Title","sessions.workingDir":"Working Dir","sessions.created":"Created","sessions.last":"Last","sessions.adopt":"Adopt","sessions.actions":"Actions","sessions.details":"Details","sessions.copy":"Copy","sessions.copied":"Copied","sessions.locate":"Locate Topic","sessions.locating":"Sending...","sessions.cooldown":"Cooldown {seconds}s","sessions.openTerminal":"Terminal","sessions.writeLink":"Write Link","sessions.writeLinkHint":"Get a writable terminal link (carries a write-access token; opens in a new tab)","sessions.writeLinkFail":"Failed to get write link","sessions.close":"Close Session","sessions.resume":"Resume Session","sessions.dismiss":"Close","sessions.closeConfirm":"Close this session?","sessions.resumeFailed":"Resume failed","sessions.land":"Land","sessions.landLoading":"Loading sandbox diff\u2026","sessions.landUnavailable":"Cannot land","sessions.landEmpty":"No changes in the sandbox clone.","sessions.landApply":"Apply to disk","sessions.landDiscard":"Discard","sessions.landApplied":"Landed","sessions.landFailed":"Land failed","sessions.landDiscarded":"Discarded (sandbox clone not applied).","connectors.lede":"Let external systems (alerts, CI, tickets\u2026) trigger a bot to speak in a group or run a workflow via one webhook.","connectors.createTitle":"New Webhook","connectors.fName":"Name","connectors.fNamePh":"e.g. Prod alerts","connectors.fBot":"Trigger bot","connectors.fKind":"Trigger type","connectors.kindTurn":"Single turn (bot responds once)","connectors.kindWorkflow":"Workflow","connectors.fWf":"Workflow ID","connectors.fMode":"Deliver to which group","connectors.modeDynamic":"Specified per request (chat passed in)","connectors.modeFixed":"Fixed group","connectors.modeNewGroup":"New group each time","connectors.fFixedChat":"Target group","connectors.fChatManualPh":"Enter chat ID manually: oc_\u2026","connectors.chatManualLink":"Group not listed? Enter ID manually \u2192","connectors.chatListLink":"\u2190 Pick from group list","connectors.fAllow":"Allowed groups","connectors.optional":" (optional)","connectors.allowHint":"Hold Ctrl/\u2318 to multi-select; empty = unrestricted. Only validates the chat passed in the request.","connectors.dynamicHint":'<b>Dynamic mode</b>: the chat ID is passed per request, one of three ways \u2014 query <code>?chatId=<chatId></code> \xB7 header <code>x-botmux-chat-id: <chatId></code> \xB7 body <code>{"chatId":"<chatId>"}</code>.<br>For "one URL triggers directly, no params", choose Fixed group instead.',"connectors.fDedup":"Dedup field","connectors.fDedupPh":"e.g. alert.id (read from event body)","connectors.dedupHint":"Set: events with the same value go to the <b>same group</b>. Empty: each event <b>creates a new group</b>.","connectors.fInstruction":"Instruction","connectors.fInstructionPh":"What the bot should do on the event. e.g. Summarize the severity, @ the oncall, suggest next steps. Empty = hand the raw event to the model.","connectors.fVerify":"Verification","connectors.verifyToken":"Token (simple: secret in the URL, one curl triggers it)","connectors.verifyHmac":"HMAC signature (advanced: more secure, sign the request yourself)","connectors.fSecret":"Secret / token","connectors.fSecretPh":"Leave empty to auto-generate (shown once)","connectors.btnCreate":"Create","connectors.listTitle":"Existing Webhooks","connectors.loading":"Loading\u2026","connectors.noBotGroups":"(This bot has no visible groups; enter an ID manually on the right)","connectors.modeLabelFixed":"Fixed group","connectors.modeLabelNewGroup":"New group each time","connectors.modeLabelDynamic":"Per-request group","connectors.kindLabelWorkflow":"Workflow","connectors.kindLabelTurn":"Single turn","connectors.count":"\xB7 {count}","connectors.empty":"No webhooks yet. Create one with the form above.","connectors.enabled":"Enabled","connectors.disabled":"Disabled","connectors.badgeToken":"Token","connectors.badgeSign":"Signed","connectors.dest":'to "{name}"',"connectors.btnDisable":"Disable","connectors.btnEnable":"Enable","connectors.btnDel":"Delete","connectors.webhookUrl":"Webhook URL: ","connectors.copy":"Copy","connectors.copied":"Copied","connectors.tokenHint":"Token mode: append <code>/<token></code> to the URL when calling (the token is shown only on create/rotate).","connectors.dynamicReqHint":'Dynamic mode: the request must carry the target chat \u2014 <code>?chatId=<chatId></code> or header <code>x-botmux-chat-id</code> or body <code>{"chatId":"\u2026"}</code>.',"connectors.instructionPrefix":"Instruction: ","connectors.delConfirm":"Delete this webhook? Its URL stops working immediately.","connectors.errName":"Enter a name","connectors.errBot":"Pick a bot","connectors.errWf":"Enter a workflow ID","connectors.errChat":"Pick (or enter) a target group","connectors.creating":"Creating\u2026","connectors.usageDynamicLede":"Dynamic mode: the URL already has the token; pass the target chat ID when calling{gn}:","connectors.usageDynamicNote":'The chat can also go in header <code>x-botmux-chat-id</code> or body <code>{"chatId":"\u2026"}</code>. \u26A0\uFE0F The URL is the credential \u2014 keep it secret.',"connectors.usageTokenLede":"This URL already has the token and a fixed target group; just POST to trigger:","connectors.usageTokenNote":"\u26A0\uFE0F The URL is the credential \u2014 keep it private; delete or rotate it in the list below.","connectors.usageHmac":"The external system must HMAC-SHA256-sign <code>timestamp.body</code> and call with <code>x-botmux-timestamp</code> / <code>x-botmux-nonce</code> / <code>x-botmux-signature</code> headers","connectors.usageHmacDynamic":", and also pass the target chat ID as above","connectors.createdPrefix":'Created "{name}"',"connectors.createdDest":'to "{name}"',"connectors.tokenLabel":"Access token","connectors.signLabel":"Signing secret","connectors.secretOnce":" (shown once \u2014 save it): ","connectors.createFailed":"Create failed: {error}","connectors.noOnlineBots":"(No online bots)","team.navHome":"My team","team.navManage":"Team management","team.eyebrow":"Team","team.homeTitle":"Team collaboration (cross-deployment)","team.homeLede":"Invite other deployments (botmux instances teammates run) into one team to discover bots across deployments and pull collaborative groups.","team.localDeployTitle":"This deployment","team.myIdentity":"My Lark identity: ","team.unbound":"Not bound","team.bindBtn":"Bind","team.bindHint":" (auto-identifies you via the bot credentials; once bound, pulling a group adds you and attributes the bots to you)","team.myTeams":"My teams","team.searchPh":"Search name / capability / CLI\u2026","team.allCli":"All CLIs","team.hasCap":"Has capability tag","team.hasRole":"Has default role","team.teamsHint":"Tick bots in any team to pull them into a group (each with its owner). To create a team / generate an invite code / join another team, go to Team management.","team.loading":"Loading\u2026","team.roleModalTitle":"Default role","team.roleModalHint":"The bot default persona (applies across groups), read-only here. To edit, go to the Bot Defaults page.","team.close":"Close","team.tagLocal":"This deployment","team.tagRemoteStale":"Remote \xB7 offline?","team.tagRemote":"Remote","team.removeMember":"Remove","team.depTag":"({tag})","team.depCount":"{count}","team.depSelected":", {n} selected","team.capPh":"Capability tag\u2026","team.viewRole":"View","team.hasRoleShort":"Has role","team.noMatch":"No bots match the filters.","team.gnamePh":"Group name (e.g. cross-team triage)","team.pullGroupBtn":"Pull ticked bots into a group","team.pullGroupHint":"Tick bots \u2192 pull into a Lark group (owner included automatically)","team.noTeams":"No teams yet. Go to Team management to generate an invite code for others to join you, or join another team.","team.connected":"Connected","team.connectFail":"Connection failed: {error}","team.iHost":"I host","team.teamMeta":"{deps} deployments \xB7 {bots} bots","team.rosterFail":"Could not fetch this team roster.","team.acrossTeams":" (across {n} teams, deduped)","team.botsWord":"bots","team.groupCreated":"Group created","team.delegatedBy":' (created by "{name}")',"team.openInLark":"Open in Lark","team.invalidBots":"Bots not added: {ids}","team.invalidOwners":"{n} owner(s) could not be added","team.missingIdentity":"You have not bound a Lark identity, so you were not added to the group (bind it in My team)","team.skippedNoOwner":"{n} bot(s) skipped because their owner has no bound identity (not added)","team.errNoLocalBot":"Tick at least one of your own (this deployment) online bots \u2014 the group is created by it and adds you (the initiator).","team.errAllSkipped":"None of the selected bot owners have a bound identity, so the group cannot be pulled (a bot cannot join a group without its owner). Have those deployments bind an identity first.","team.errNoCreator":"No available group creator (the relevant deployments have no online bot, or are unreachable)","team.errDelegationTimeout":"Timed out delegating group creation to the other deployment (it may have succeeded \u2014 check Lark, do not retry)","team.errGroupCreate":"Group creation failed: {error}","team.roleModalTitleName":"Default role \xB7 {name}","team.bound":"Bound","team.myHostedTeam":"My hosted team","team.remoteTeamLabel":"{name} team","team.manageTitle":"Team management","team.manageLede":"Create multiple teams, generate an invite code per team, or join another team. A team = this deployment bots + the other deployments that joined it.","team.hostedTitle":"Teams I host","team.newTeamPh":"New team name","team.createTeamBtn":"Create team","team.joinTitle":"Join another team","team.hubPh":"Hub address, e.g. http://10.0.0.5:7891","team.codePh":"Invite code","team.joinBtn":"Join","team.noTeamsShort":"No teams yet.","team.default":"Default","team.manageMetaDeps":"{count} deployments","team.manageMetaRemote":" (incl. {r} remote)","team.manageMetaBots":"{count} bots","team.genInvite":"Generate invite code","team.delBtn":"Delete","team.generating":"Generating\u2026","team.inviteResultLede":"Send the two items below to someone on another deployment (valid once, within 24h):","team.inviteHub":"Hub address: ","team.inviteCode":"Invite code: ","team.genFail":"Generation failed.","team.delConfirm":'Delete team "{name}"? Deployments that joined it will be removed (their own deployments are unaffected).',"team.errName":"Enter a team name","team.creating":"Creating\u2026","team.created":"Created","team.createFail":"Create failed: {error}","team.errHubCode":"Enter the hub address and invite code.","team.joining":"Joining\u2026","team.joined":'Joined "{name}" \u2014 see it in My team.',"team.joinErrSelf":"This is your own deployment; you cannot join yourself (the invite code is for someone on another deployment).","team.joinErrAlready":"Your deployment already joined this team.","team.joinErrUnreachable":"Cannot reach the hub (check the address/network).","team.joinErrTimeout":"The hub timed out.","team.joinErrGeneric":"Join failed: {error}","team.identifying":"Identifying\u2026","team.bound2":"Bound: {name}","team.multiCandidate":"Multiple candidates found \u2014 click yourself:","team.binding":"Binding\u2026","team.bindFail":"Bind failed: {error}","team.noCandidates":"No identity found: make sure the bot has allowedUsers configured and contacts permission.","team.removeMemberConfirm":'Remove "{name}" from this team? Its bots disappear from this team roster (their own deployment is unaffected).',"team.creatingGroup":"Creating group\u2026","team.defaultGroupName":"Collaboration group","team.errPickBot":"Tick at least one bot first","sessions.closeBulkConfirm":"Close {count} selected sessions?","sessions.empty":"No sessions match the filters.","sessions.viewMode":"Session view","sessions.viewKanban":"Kanban","sessions.viewBoard":"Board","sessions.viewTable":"Table","sessions.selectSession":"Select session","sessions.board.needsYou":"Needs You","sessions.board.needsYouHint":"Repo, TUI, or usage limit waiting","sessions.board.starting":"Starting","sessions.board.startingHint":"CLI is spawning or resuming","sessions.board.working":"Working","sessions.board.workingHint":"Streaming, analyzing, or using tools","sessions.board.idle":"Idle","sessions.board.idleHint":"Ready for the next message","sessions.board.emptyColumn":"No sessions","sessions.board.signalRepo":"Repo needed","sessions.board.signalPrompt":"TUI choice needed","sessions.board.signalLimited":"Usage limited","sessions.board.signalAgent":"Needs human input","sessions.board.waiting":"Waiting","sessions.board.dragHint":"Drag header to reorder columns","sessions.board.moveLeft":"Move column left","sessions.board.moveRight":"Move column right","sessions.kanban.backlog":"Backlog","sessions.kanban.todo":"Todo","sessions.kanban.inProgress":"In Progress","sessions.kanban.inReview":"In Review","sessions.kanban.done":"Done","sessions.kanban.updated":"Updated {time}","sessions.kanban.moreHidden":"{count} more hidden","sessions.kanban.openTab":"Open in new tab","sessions.kanban.openFeishu":"Open in Feishu","sessions.kanban.terminalLoading":"Opening terminal\u2026","sessions.kanban.rename":"Rename (double-click title works too)","sessions.kanban.renameFail":"Rename failed","sessions.kanban.moveFail":"Move failed","sessions.kanban.groupBy":"Group by","sessions.kanban.groupFlow":"Workflow","sessions.kanban.groupTeam":"Team","sessions.kanban.groupBot":"Bots","sessions.kanban.teamLoading":"Loading teams\u2026","sessions.kanban.noTeam":"No teams","sessions.kanban.teamScope":"{chats} collab chats \xB7 {sessions} sessions","sessions.kanban.remoteHint":"Session from the {name} deployment (snapshot; terminal/history live on their machine)","sessions.kanban.clusterDragHint":"Drag header to move the whole group","sessions.history.title":"History","sessions.history.loading":"Fetching Feishu messages\u2026","sessions.history.fail":"Failed to load history","sessions.history.empty":"No messages","sessions.history.user":"User","sessions.history.owner":"Owner","sessions.history.staleHint":"The dashboard or daemon process may still run an old build \u2014 botmux restart and retry","groups.title":"Groups & Bots","groups.subtitle":"Inspect the chat x bot matrix and manage group creation, oncall, leave, and disband flows.","groups.search":"Search chat name / ID / owner","groups.missingOnly":"Missing bot only","groups.refresh":"Refresh","groups.create":"New Group","groups.chat":"Chat","groups.actions":"Actions","groups.addBots":"Add Bots","groups.manage":"Manage","groups.empty":"No chats match the filters.","groups.createTitle":"Create New Group","groups.createHelp":"Pick bots to invite. The dashboard chooses an online daemon as creator.","groups.name":"Group Name","groups.namePlaceholder":"e.g. AI ChangeLog","groups.bindDir":"Bind Directory","groups.bindDirHelp":"New topics start the CLI here and skip repo selection.","groups.botPicker":"Bots","groups.createSubmit":"Create","groups.cancel":"Cancel","groups.successTitle":"Group Created","groups.openGroup":"Open Group","groups.manageTitle":"Manage {name}","groups.owner":"Owner","groups.oncall":"Oncall Mode","groups.oncallHelp":"When enabled, group members can @ the bot; new topics use the bound directory.","groups.leaveTitle":"Select Bots to Leave","groups.leaveSelected":"Selected Bots Leave","groups.disband":"Disband Group","groups.dangerHint":"Disband only works when an in-chat bot is the owner. Otherwise prefer leaving the chat.","groups.save":"Save","groups.needWorkingDir":"Working directory is required","groups.noBotsOnline":"No bots online. Restart the daemon first.","schedules.title":"Schedules","schedules.subtitle":"View, pause, resume, and run scheduled tasks across daemons.","schedules.search":"Search name / prompt / working dir","schedules.anyKind":"Any kind","schedules.enabledOnly":"Enabled only","schedules.name":"Name","schedules.bot":"Bot","schedules.schedule":"Schedule","schedules.next":"Next","schedules.last":"Last","schedules.repeat":"Repeat","schedules.enabled":"Enabled","schedules.actions":"Actions","schedules.runNow":"Run Now","schedules.pause":"Pause","schedules.resume":"Resume","schedules.empty":"No schedules.","settings.title":"Global Settings","settings.subtitle":"Manage machine-wide botmux dashboard behavior shared by every bot.","settings.loading":"Loading settings\u2026","settings.loadFailed":"Failed to load settings","settings.readOnlyVisitor":"Read-only access \u2014 changing settings requires an authorized link (run botmux dashboard).","settings.sectionAccess":"Access","settings.publicReadOnly":"Allow tokenless read-only dashboard access","settings.publicReadOnlyHelp":"When enabled, visitors without a token can view the dashboard, sessions, schedules, and SSE. Writes such as close, pause, and approvals still require token auth. Sensitive raw terminal logs always require a token.","settings.sectionCards":"Feishu Cards","settings.openTerminalInFeishu":"Open streaming-card terminals in the Feishu sidebar","settings.openTerminalInFeishuHelp":"Off by default: terminal buttons open the Web Terminal URL directly. When enabled, botmux wraps the URL with Feishu web_url/open so Feishu PC opens it in a sidebar. Terminal write access is still controlled by its token.","settings.sectionRepoPicker":"Repo Picker","settings.repoPickerMode":"Repo picker card mode","settings.repoPickerModeAll":"Repos + worktrees","settings.repoPickerModeRepos":"Main repos only","settings.repoPickerModeHelp":"Default shows repositories and linked worktrees. Main repos only hides linked worktrees from initialization and bare /repo cards; explicit /repo /abs/path/to/worktree still works.","settings.saving":"Saving\u2026","settings.saved":"Saved","settings.saveFailed":"Save failed","settings.sectionMaintenance":"Auto Maintenance","settings.autoUpdate":"Auto update","settings.autoUpdateHelp":"Off by default. At the set time, runs npm install -g botmux@latest to install the latest version (download/install only \u2014 no restart). npm-global installs only.","settings.autoRestart":"Auto restart","settings.autoRestartHelp":"Off by default; requires auto-update. After auto-update installs a newer version, restart to apply it if no session is in progress (busy \u21D2 slips to the next day).","settings.autoUpdateLocalDev":"This is a local-dev install (running from source); auto-update is unavailable.","settings.maintenanceTime":"Time","botDefaults.title":"Bot Profiles","botDefaults.subtitle":"Per-bot defaults: oncall, proactive start, persona role, cards and grants.","botDefaults.metaOnline":"Online \xB7 daemon healthy","botDefaults.search":"Search bot name / app id","botDefaults.refresh":"Refresh","botDefaults.sectionOncall":"New-chat Oncall","botDefaults.sectionBrand":"Card Signature","botDefaults.warning":"When enabled, chats without an oncall binding auto-bind to this directory on their next new topic. Manually bound or unbound chats are preserved.","botDefaults.empty":"No bots online. Run botmux restart first.","botDefaults.defaultOncall":"Default to oncall mode","botDefaults.defaultOncallHelp":"Unbound chats auto-bind on the next new topic","botDefaults.workingDir":"Default Working Directory","botDefaults.lastEnabled":"Last Enabled","botDefaults.autobound":"{count} chats auto-bound","botDefaults.save":"Save","botDefaults.required":"Working directory is required when enabled","botDefaults.brandLabel":"Signature (card footer)","botDefaults.brandLabelHelp":"Footer signature on cards this bot sends. Save empty = hide; fill in = custom (markdown ok, e.g. [Acme](https://\u2026)); Reset = show botmux.","botDefaults.brandLabelPlaceholder":"Default: botmux (empty = hidden)","botDefaults.sectionSandbox":"File sandbox (oncall)","botDefaults.sandboxToggle":"Enable file sandbox","botDefaults.sandboxHelp":"When on, every session of this bot runs in a per-session sandbox: only a project copy is visible \u2014 your real files, secrets, and other sessions are not. For sharing the bot with semi-trusted users (oncall). Linux only; applies to the next new session.","botDefaults.sandboxSaved":"Saved (applies to the next new session)","botDefaults.brandSave":"Save Signature","botDefaults.brandReset":"Reset to default","botDefaults.brandStateDefault":"Current: default botmux","botDefaults.brandStateOff":"Current: off","botDefaults.brandStateCustom":"Current: custom","botDefaults.sectionCard":"Card Behavior","botDefaults.disableStreaming":"Disable streaming card","botDefaults.disableStreamingHelp":"Stop posting the live session status card (and its Open Terminal entry). The task's final result still arrives as a message. For those who find the live card noisy.","botDefaults.writableLink":"Put a writable terminal link on the card","botDefaults.writableLinkHelp":'\u26A0\uFE0F Embeds a writable terminal link in the streaming card body \u2014 anyone in the chat can open and drive the terminal. Off = current behavior (private DM via the "Get Write Link" button).',"botDefaults.writableLinkMoot":"Streaming card disabled \u2014 this has no effect","botDefaults.privateCard":"/card sends a private card (authorized users only)","botDefaults.privateCardHelp":'Makes /card send an ephemeral "visible-to-specific-people" card: delivered only to the owner (allowedUsers); /grant-authorized talk users and everyone else in the chat cannot see it. Trade-off: it is a static snapshot (no live updates) and only works in regular group chats (topic groups / DMs fail, with no fallback). Affects only the /card command; the auto streaming card is unchanged.',"botDefaults.cardPrefSaved":"Saved","botDefaults.sectionRole":"Default Role","botDefaults.roleHelp":"This bot's default persona (applies across all chats), injected into the bot's sessions in every chat; a single group can override it on the Roles page. Save empty = delete.","botDefaults.rolePlaceholder":"e.g. You are a backend triage assistant; answer concisely, prefer runnable commands\u2026","botDefaults.roleSave":"Save role","botDefaults.roleDelete":"Delete","botDefaults.roleSaved":"Saved","botDefaults.roleDeleted":"Deleted","botDefaults.roleLoadErr":"Failed to load role","botDefaults.sectionAutoStart":"Proactive Start","botDefaults.autoStartJoin":"Auto-start when added to a new chat","botDefaults.autoStartJoinHelp":'When enabled, the bot auto-starts a session and gets to work the moment it is added to a new chat (when an authorized user / allowedUsers is a member), no @ needed. It launches in the bot default working dir; if none is configured it shows a repo-select card first. Prerequisite: subscribe the "bot joined chat" event im.chat.member.bot.added_v1 for this app and grant the member-read scope in the Feishu console.',"botDefaults.autoStartJoinPrompt":"First-turn prompt on join (optional)","botDefaults.autoStartJoinPromptPlaceholder":"Filled = used as the first task after joining; blank = the bot reads the chat and decides what to do","botDefaults.autoStartJoinPromptSave":"Save prompt","botDefaults.autoStartTopic":"Auto-start on new topics in topic groups","botDefaults.autoStartTopicHelp":"When enabled, in a topic group the bot automatically joins each newly opened topic and starts working on its first message, no @ needed. Topic groups only \u2014 regular groups are unaffected.","botDefaults.sectionSessionMode":"Session mode","botDefaults.p2pMode":"Private chat session mode","botDefaults.p2pThread":"thread (separate session per DM)","botDefaults.p2pChat":"chat (flat continuous session)","botDefaults.p2pHelp":"How 1:1 DMs are sessioned: thread = each top-level message starts its own session (keeps chatter out of one CLI process); chat = the whole DM shares one continuous session and context (Hermes-like). Takes effect immediately.","botDefaults.regularGroupMode":"Regular group session mode","botDefaults.regularGroupModeChat":"chat (flat continuous session, default)","botDefaults.regularGroupModeNewTopic":"new-topic (each top-level @ opens its own topic & session)","botDefaults.regularGroupModeShared":"shared (topic display, reusing one session)","botDefaults.regularGroupModeHelp":"How new top-level @mentions in regular (non-topic) groups are sessioned: chat = the whole group shares one continuous session (default); new-topic = each top-level @ opens its own topic with a separate session; shared = topic display but reuse the same session (replies fold into a topic yet share the group session & context). This is the per-bot default; a specific group can override it via /reply-mode. Takes effect immediately.","botDefaults.mentionMode":"Group @ policy","botDefaults.mentionModeAlways":"Always require @ (default)","botDefaults.mentionModeTopic":"No @ needed inside topics","botDefaults.mentionModeNever":"Never require @","botDefaults.mentionModeHelp":'Bot-global: controls when an @ is required to get a reply in groups. "Always require @" = every message needs an @ (default, safest; inside topics too, in multi-person groups); "No @ needed inside topics" = starting a new conversation / top-level still needs @, but follow-ups inside ANY topic this bot already drives (new-topic / shared / topic-group) continue without @; "Never require @" = non-@ messages are answered too wherever the bot has talk access (including cold-starting on a brand-new message \u2014 only suitable for dedicated / on-call small groups; in busy multi-person groups it replies to everything). Note: when you are alone with this bot (1:1) replies never need an @, independent of this setting.',"botDefaults.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.loading":"Loading\u2026","common.unknown":"Unknown","common.now":"now","common.never":"never","common.all":"All","nav.workflows":"Workflows (beta)","nav.workflowCatalog":"Catalog","workflow.subnav.runs":"Runs","workflow.subnav.catalog":"Catalog","workflow.searchPlaceholder":"search runId / workflowId / chatId","workflow.filter.nonTerminal":"non-terminal","workflow.filter.all":"all","workflow.status.pending":"pending","workflow.status.running":"running","workflow.status.waiting":"waiting","workflow.status.effectAttempting":"effect","workflow.status.timedOut":"timed out","workflow.status.succeeded":"succeeded","workflow.status.failed":"failed","workflow.status.cancelled":"cancelled","workflow.table.run":"run","workflow.table.workflow":"workflow","workflow.table.status":"status","workflow.table.lastSeq":"lastSeq","workflow.table.dangling":"dEf/dAct/dWait","workflow.table.updated":"updated","workflow.table.chatApp":"chat / app","workflow.list.failedLoad":"Failed to load: {error}","workflow.list.noRuns":"No runs match.","workflow.list.noFilterMatch":"No runs match this filter.","workflow.list.loaded":"{count} runs \xB7 refreshed {time}","workflow.list.error":"error: {error}","workflow.detail.back":"Back","workflow.detail.loading":"Loading...","workflow.detail.loadFailed":"Load failed","workflow.detail.cancel":"Cancel","workflow.detail.cliCancelOnly":"CLI cancel only","workflow.detail.cancelTitle":"Cancel this workflow run","workflow.detail.cliCancelTitle":"Cancel unavailable: use botmux workflow cancel {runId}","workflow.detail.nodes":"Nodes / Activities","workflow.detail.parallel":"Parallel execution","workflow.detail.parallelMeta":"{count} attempt(s) \xB7 max parallel {max} \xB7 running {running}","workflow.detail.noParallelData":"No attempt timing data yet.","workflow.detail.parallelNow":"now","workflow.detail.node":"node","workflow.detail.nodeStatus":"node status","workflow.detail.activity":"activity","workflow.detail.activityStatus":"activity status","workflow.detail.attempts":"attempts","workflow.detail.current":"current","workflow.detail.detail":"detail","workflow.detail.nodeIO":"Node I/O","workflow.detail.timeline":"Timeline","workflow.detail.loadOlder":"Load older","workflow.detail.seq":"seq","workflow.detail.actor":"actor","workflow.detail.error":"error","workflow.detail.event":"event","workflow.detail.time":"time","workflow.detail.refreshed":"refreshed {time}","workflow.detail.unknownRun":"unknown run","workflow.detail.snapshotHttp":"snapshot HTTP {status}","workflow.detail.eventsHttp":"events HTTP {status}","workflow.detail.cancelUnavailable":"cancel unavailable: use botmux workflow cancel {runId}","workflow.detail.cancelConfirm":`Cancel workflow run {runId}?
|
|
9
9
|
|
|
10
10
|
{total} dangling item(s) will be handled by cancel-driven recovery.
|
|
11
11
|
effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"workflow.detail.writeAccessCancel":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and click cancel again.","workflow.detail.cancelHttp":"cancel HTTP {status}","workflow.detail.cancelPending":"cancel pending; waiting for running activity to drain","workflow.detail.writeAccessApproval":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and approve/reject again.","workflow.detail.actionHttp":"{action} HTTP {status}","workflow.detail.approved":"approved","workflow.detail.rejected":"rejected","workflow.detail.alreadyTerminal":"Run already terminal; {label} was not applied.","workflow.detail.workflowContinue":"{label}; waiting for workflow to continue.","workflow.detail.workflowRefreshing":"{label}; refreshing workflow state.","workflow.detail.eventsLoaded":"{loaded}/{total} events loaded","workflow.detail.dangling":"Dangling","workflow.detail.noDangling":"No dangling work.","workflow.detail.none":"none","workflow.detail.noNodes":"No nodes yet.","workflow.detail.idle":"idle","workflow.detail.noNodeIO":"No node I/O yet.","workflow.detail.notDispatched":"not dispatched","workflow.detail.noAttempt":"No attempt yet","workflow.detail.attempt":"attempt","workflow.detail.authoredInput":"Authored input","workflow.detail.resolvedInput":"Resolved input","workflow.detail.output":"Output","workflow.detail.executionLog":"Execution log","workflow.detail.liveTerminal":"Live terminal","workflow.detail.terminalLive":"live","workflow.detail.terminalClosedShort":"closed","workflow.detail.terminalClosed":"Terminal is closed. Use the execution log below for the final transcript.","workflow.detail.openTerminalNewTab":"Open terminal in new tab","workflow.detail.terminalReplay":"Terminal replay","workflow.detail.openReplayNewTab":"Open replay in new tab","workflow.detail.downloadFullLog":"Download full log","workflow.detail.terminalResume":"Debug session","workflow.detail.openResumeNewTab":"Open debug session in new tab","workflow.detail.resumeSession":"Resume session","workflow.detail.resumeStarting":"Starting\u2026","workflow.detail.endResumeSession":"End debug session","workflow.detail.resumeEnding":"Ending\u2026","workflow.detail.resumeUnsupportedCli":'CLI "{cliId}" does not support resume',"workflow.detail.resumeMissingCliSession":"Missing cliSessionId \u2014 cannot resume","workflow.detail.resumeStartFailed":"Failed to start debug session (HTTP {status})","workflow.detail.resumeEndFailed":"Failed to end debug session (HTTP {status})","workflow.detail.writeAccessResume":"Resume requires dashboard write access.","workflow.detail.waitPrompt":"Wait prompt","workflow.detail.approvalComment":"Approval comment","workflow.detail.optionalComment":"Optional comment","workflow.detail.approve":"Approve","workflow.detail.reject":"Reject","workflow.detail.submitting":"Submitting...","workflow.detail.empty":"empty","workflow.detail.truncated":"truncated","workflow.detail.noData":"No data.","workflow.detail.noPreview":"No preview.","workflow.detail.open":"open","workflow.detail.deadline":"deadline","workflow.detail.effect":"effect","workflow.detail.wait":"wait","workflow.detail.noEvents":"No events.","workflow.summary.workflow":"workflow","workflow.summary.status":"status","workflow.summary.lastSeq":"lastSeq","workflow.summary.updated":"updated","workflow.summary.revision":"revision","workflow.summary.initiator":"initiator","workflow.summary.failedNode":"failedNode","workflow.summary.cancelOrigin":"cancelOrigin","workflow.summary.chat":"chat","workflow.summary.app":"app","workflow.dangling.activities":"activities","workflow.dangling.effects":"effects","workflow.dangling.waits":"waits","workflow.dangling.cancels":"cancels","catalog.title":"Workflow catalog","catalog.subtitle":"Create a workflow run from a saved workflow definition.","catalog.searchPlaceholder":"search workflowId / path","catalog.refresh":"Refresh","catalog.loading":"Loading catalog...","catalog.loadFailed":"Failed to load catalog: {error}","catalog.noDefinitions":"No workflow definitions found.","catalog.noFilterMatch":"No definitions match this filter.","catalog.table.workflow":"workflow","catalog.table.version":"version","catalog.table.params":"params","catalog.table.nodes":"nodes","catalog.table.revision":"revision","catalog.table.path":"path","catalog.paramSummary":"{required}/{total} required","catalog.back":"Back to catalog","catalog.detailTitle":"Workflow definition","catalog.definitionLoadFailed":"Failed to load definition: {error}","catalog.summary":"Summary","catalog.paramsSchema":"Params schema","catalog.definitionJson":"Definition JSON","catalog.runPanel":"Run workflow","catalog.paramsJson":"Params JSON","catalog.paramsPlaceholder":`{
|
|
12
12
|
"city": "\u5317\u4EAC"
|
|
13
|
-
}`,"catalog.chatId":"Chat ID","catalog.larkAppId":"Lark app ID","catalog.chatBindingHint":"Required so humanGate cards and cancel routing know which Lark chat owns the run.","catalog.run":"Run","catalog.running":"Starting...","catalog.badParamsJson":"Params must be a JSON object.","catalog.writeAccess":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and run again.","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"Run started; opening detail page...","catalog.invalidParams":"Invalid params","catalog.issue":"{path}: {message}","catalog.noParams":"No params declared.","catalog.required":"required","catalog.optional":"optional","catalog.default":"default","catalog.description":"description","catalog.path":"path","catalog.revision":"revision","catalog.nodeCount":"nodes"},pa={zh:rs,en:ls};function Ft(e){if(typeof e!="string")return null;let n=e.trim().toLowerCase();return n==="zh"||n.startsWith("zh-")?"zh":n==="en"||n.startsWith("en-")?"en":null}function ds(e=[]){for(let n of e){let a=Ft(n);if(a)return a}return"zh"}function Gt(e){return(n,a)=>{let s=pa[e][n]??pa.zh[n]??n;return a?s.replace(/\{(\w+)\}/g,(o,r)=>{let c=a[r];return c==null?`{${r}}`:String(c)}):s}}function ma(e,n){return(e?Ft(e.getItem(hn)):null)??ds(n)}var wn="botmux.dashboard.theme",fa="botmux.dashboard.sessions.view";function cs(e){return e==="system"||e==="light"||e==="dark"?e:null}function yn(e){return e==="kanban"||e==="board"||e==="table"?e:null}function ga(e,n){return e==="system"?n?"dark":"light":e}function ba(e){return cs(e?.getItem(wn))??"dark"}function ha(e){return yn(e?.getItem(fa))??"board"}var wa="botmux.dashboard.sessions.boardOrder",Lt=["needs-you","starting","working","idle"];function us(e){if(!Array.isArray(e)||e.length!==Lt.length)return null;let n=new Set(e);if(n.size!==e.length)return null;for(let a of Lt)if(!n.has(a))return null;return e.slice()}function ya(e){try{let n=e?.getItem(wa);return n?us(JSON.parse(n))??[...Lt]:[...Lt]}catch{return[...Lt]}}function vn(e,n){try{e?.setItem(wa,JSON.stringify(n))}catch{}}function va(e,n){try{e?.setItem(fa,n)}catch{}}var ka="botmux.dashboard.sessions.kanbanGroupBy",kn="botmux.dashboard.sessions.kanbanTeam";function ps(e){return e==="flow"||e==="team"||e==="bot"?e:null}function $a(e){return ps(e?.getItem(ka))??"flow"}function Sa(e,n){try{e?.setItem(ka,n)}catch{}}var Ta="botmux.dashboard.sidebar";function ms(e){return e==="expanded"||e==="collapsed"?e:null}function La(e){return ms(e?.getItem(Ta))??"expanded"}function Ia(e,n){try{e?.setItem(Ta,n)}catch{}}var fs=["default","cyber","genshin","fallout","prts","bluearchive","zzz","dragonball","ikun"],$n="botmux.dashboard.skin";function gs(e){return typeof e=="string"&&fs.includes(e)?e:null}function Ma(e){return gs(e?.getItem($n))??"default"}var bs="\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF830123456789\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E$#%&@*+=<>/\\",xa=["186 100% 60%","56 97% 60%","330 100% 64%","150 80% 58%"],Tn=[{key:"shake",dur:280},{key:"rgb",dur:340},{key:"tear",dur:400},{key:"invert",dur:220},{key:"slice",dur:320},{key:"blackout",dur:260}],Ea=["ESTABLISHING NETLINK","BYPASSING ICE","DECRYPTING DATAFLOW","SYNCING BOTMUX TELEMETRY","ACCESS GRANTED"],Ha="0123456789ABCDEF#<>*/=+\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C",hs=3200,It=[],ht=0,_t=0;function Mn(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Ln(e,n){let a="";for(let s=0;s<e;s++)a+=n[Math.floor(Math.random()*n.length)];return a}function ws(e){let n=document.createElement("div");n.className="cyber-rain";let a=Math.max(10,Math.min(26,Math.round(window.innerWidth/70)));for(let s=0;s<a;s++){let o=document.createElement("span");o.className="cyber-rain-col",o.textContent=Ln(28+Math.floor(Math.random()*22),bs);let r=xa[Math.floor(Math.random()*xa.length)];o.style.cssText=`left:${(s+.5)/a*100}%;--rc:${r};--sz:${10+Math.floor(Math.random()*9)}px;--op:${(.25+Math.random()*.45).toFixed(2)};--dur:${(6+Math.random()*9).toFixed(1)}s;--delay:${(-Math.random()*12).toFixed(1)}s;`,n.appendChild(o)}e.appendChild(n)}function ys(){if(Mn())return;let e=document.body,n=()=>{let a=Tn[Math.floor(Math.random()*Tn.length)],s=`cp-fx-${a.key}`;e.classList.add(s),It.push(window.setTimeout(()=>e.classList.remove(s),a.dur)),It.push(window.setTimeout(n,2400+Math.random()*4200))};It.push(window.setTimeout(n,1800+Math.random()*2600))}function vs(){It.forEach(e=>window.clearTimeout(e)),It=[];for(let e of Tn)document.body.classList.remove(`cp-fx-${e.key}`)}function ks(){if(Mn()||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 n=e.querySelector(".cyber-loader-text"),a=e.querySelector(".cyber-loader-stream"),s=0,o=0,r=0;ht=window.setInterval(()=>{let c=Ea[s];n&&(o<c.length?(o+=1,n.textContent=c.slice(0,o)+Ln(c.length-o,Ha),n.classList.remove("done")):r<16?(r+=1,n.textContent=c,n.classList.add("done")):(s=(s+1)%Ea.length,o=0,r=0)),a&&(a.textContent=Ln(26,Ha))},50),_t=window.setTimeout(()=>{window.clearInterval(ht),ht=0,e.remove()},hs)}function $s(){ht&&(window.clearInterval(ht),ht=0),_t&&(window.clearTimeout(_t),_t=0),document.getElementById("cyber-boot")?.remove()}var Ss=320,Ca=16,Mt=!0,bt=0,Sn=0,zt=!1,Wt=[],In=[];function Ts(){if(zt)return;zt=!0,Mt=!1,bt=0;let e=Mn(),n="";for(let s=0;s<Ca;s++){let o=s%3===0?"186 100% 52%":s%3===1?"330 100% 58%":"56 97% 52%",r=(s%2===0?1:-1)*(8+s%5*7);n+=`<span class="cyber-breach-shard" style="top:${s/Ca*100}%;height:${2+s%4*3}%;--shift:${r}px;--delay:${s%8*.09}s;--dur:${(.36+s%5*.12).toFixed(2)}s;--hue:${o}"></span>`}let a=document.createElement("div");a.id="cyber-breach",a.className="cyber-breach",a.setAttribute("aria-hidden","true"),a.innerHTML=`<span class="cyber-breach-flash"></span><span class="cyber-breach-grid"></span><div class="cyber-breach-shards">${n}</div><div class="cyber-breach-banner"><span class="cyber-breach-tag">// BREACH PROTOCOL \u2014 SYSTEM OVERRIDE</span><span class="cyber-breach-caption" data-text="SYSTEM BREACH">SYSTEM BREACH</span><span class="cyber-breach-sub" data-text="NETWATCH OVERRIDE ENGAGED">NETWATCH OVERRIDE ENGAGED</span></div>`,document.body.appendChild(a),e||document.body.classList.add("cyber-breach-quake"),Wt.push(window.setTimeout(()=>document.body.classList.remove("cyber-breach-quake"),760)),Wt.push(window.setTimeout(()=>{a.remove(),zt=!1},e?2600:4200))}function Ls(){Mt=!0,bt=0;let e=document.documentElement,n=()=>e.scrollHeight-(window.innerHeight+window.scrollY)<=4,a=k=>{k<=0||!n()||(bt+=k,bt>Ss&&Mt&&Ts())},s=k=>a(k.deltaY),o=k=>{Sn=k.touches[0]?.clientY??0},r=k=>{let v=k.touches[0]?.clientY??0,L=Sn-v;Sn=v,a(L)},c=()=>{n()||(bt=0,Mt=!0)},m=(k,v)=>{window.addEventListener(k,v,{passive:!0}),In.push([k,v])};m("wheel",s),m("touchstart",o),m("touchmove",r),m("scroll",c)}function Is(){for(let[e,n]of In)window.removeEventListener(e,n);In=[],Wt.forEach(e=>window.clearTimeout(e)),Wt=[],document.body.classList.remove("cyber-breach-quake"),document.getElementById("cyber-breach")?.remove(),zt=!1,Mt=!0,bt=0}function Aa(e,n=!1){if(!(typeof document>"u")){if(!e){document.getElementById("cyber-fx")?.remove(),document.getElementById("cyber-hud")?.remove(),document.getElementById("cyber-glitch")?.remove(),vs(),$s(),Is();return}if(!document.getElementById("cyber-fx")){let a=document.createElement("div");a.id="cyber-fx",a.className="cyber-fx",a.setAttribute("aria-hidden","true"),a.innerHTML='<div class="cyber-fx-grid"></div><div class="cyber-fx-scan"></div><span class="cyber-flicker"></span><span class="cyber-rollline"></span>',ws(a),document.body.appendChild(a);let s=document.createElement("div");s.id="cyber-hud",s.className="cyber-hud",s.setAttribute("aria-hidden","true"),s.innerHTML='<span class="cyber-hud-corner tl"></span><span class="cyber-hud-corner tr"></span><span class="cyber-hud-corner bl"></span><span class="cyber-hud-corner br"></span><span class="cyber-hud-tag">NIGHT CITY // NETWATCH</span>',document.body.appendChild(s);let o=document.createElement("div");o.id="cyber-glitch",o.className="cyber-glitch",o.setAttribute("aria-hidden","true"),document.body.appendChild(o),ys(),Ls()}n&&ks()}}var Ms={genshin:2e3,zzz:1900,dragonball:1900,ikun:1900},xs='<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 Es(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 xs;default:return""}}function Hs(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Da(e){if(typeof document>"u"||Hs())return;let n=Ms[e];if(!n)return;document.getElementById("skin-intro")?.remove();let a=document.createElement("div");a.id="skin-intro",a.className=`skin-intro si-${e}`,a.setAttribute("aria-hidden","true"),a.style.setProperty("--si-dur",`${n}ms`),a.innerHTML=Es(e),document.body.appendChild(a),window.setTimeout(()=>a.remove(),n+80)}var En=class{locale="zh";themeMode="system";resolvedTheme="light";skin="default";authed=!0;listeners=new Set;translate=Gt(this.locale);mediaQuery=null;init(){let n=typeof window<"u"?window:void 0;this.locale=ma(n?.localStorage,As()),this.translate=Gt(this.locale),this.themeMode=ba(n?.localStorage),this.skin=Ma(n?.localStorage),this.mediaQuery=n?.matchMedia?.("(prefers-color-scheme: dark)")??null,this.mediaQuery?.addEventListener("change",()=>{this.applyTheme(),this.emit()}),this.applyTheme(),this.applySkin(),this.applyLocale()}t(n,a){return this.translate(n,a)}setLocale(n){this.locale!==n&&(this.locale=n,this.translate=Gt(n),window.localStorage.setItem(hn,n),this.applyLocale(),this.emit())}get theme(){return this.skin==="default"?this.themeMode:this.skin}setTheme(n){let a=n==="system"||n==="light"||n==="dark",s=a?"default":n,o=s!==this.skin;a&&this.themeMode!==n&&(this.themeMode=n,window.localStorage.setItem(wn,this.themeMode)),o&&(this.skin=s,window.localStorage.setItem($n,this.skin)),this.applyTheme(),this.applySkin(o),this.emit()}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}applyTheme(){this.resolvedTheme=ga(this.themeMode,!!this.mediaQuery?.matches);let n=this.skin==="default"?this.resolvedTheme:Cs[this.skin];document.documentElement.dataset.theme=n,document.documentElement.dataset.themeMode=this.themeMode}applySkin(n=!1){document.documentElement.dataset.skin=this.skin,Aa(this.skin==="cyber",n),n&&this.skin!=="cyber"&&this.skin!=="default"&&Da(this.skin)}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}},Cs={default:"light",cyber:"dark",genshin:"light",fallout:"dark",prts:"dark",bluearchive:"dark",zzz:"dark",dragonball:"light",ikun:"dark"};function As(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var $e=new En;function t(e,n){return $e.t(e,n)}function i(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function Be(e){if(!e)return"-";let n=Date.now()-e;return n<6e4?t("common.now"):n<36e5?Math.floor(n/6e4)+"m":n<864e5?Math.floor(n/36e5)+"h":Math.floor(n/864e5)+"d"}var Ra=[{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 Oa(e){let n=0,a=String(e??"");for(let r=0;r<a.length;r++)n=n*31+a.charCodeAt(r)>>>0;let{c1:s,c2:o}=Ra[n%Ra.length];return`--c1:${s};--c2:${o}`}var Kt=new Map,Jt=new Map;function Ds(e,n){return n?Kt.get(n):e?Jt.get(String(e)):void 0}function fe(e){let n=e.name??"",a=e.avatarUrl??Ds(e.name,e.larkAppId),s=e.size==="sm"?" orb-avatar-sm":"",o=a?" orb-has-img":"",r=e.dot?`<i class="orb-dot orb-dot-${e.dot}"></i>`:"",c=a?`<img class="orb-img" src="${i(a)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar${s}${o}" style="${Oa(n)}" aria-hidden="true">${c}${r}</span>`}function Rs(e){return e?Qt.get(e):void 0}function Yt(e){let n=e.name??e.chatId??"",a=e.avatarUrl??Rs(e.chatId),s=e.size==="sm"?" orb-avatar-sm":"",o=a?" orb-has-img":"",r=a?`<img class="orb-img" src="${i(a)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar orb-square${s}${o}" style="${Oa(n)}" aria-hidden="true">${r}</span>`}var xt=new Map,Vt=new Map,Qt=new Map,xn=null,Ba="botmux.avatarCache.v1";function Os(){try{let e=typeof window<"u"?window.localStorage.getItem(Ba):null;if(!e)return;let n=JSON.parse(e);for(let[a,s]of Object.entries(n.botByAppId??{}))Kt.set(a,s);for(let[a,s]of Object.entries(n.botByName??{}))Jt.set(a,s);for(let[a,s]of Object.entries(n.chatById??{}))Qt.set(a,s);for(let[a,s]of Object.entries(n.nameByAppId??{}))xt.set(a,s);for(let[a,s]of Object.entries(n.chatNameById??{}))Vt.set(a,s)}catch{}}function Bs(){try{if(typeof window>"u")return;window.localStorage.setItem(Ba,JSON.stringify({botByAppId:Object.fromEntries(Kt),botByName:Object.fromEntries(Jt),chatById:Object.fromEntries(Qt),nameByAppId:Object.fromEntries(xt),chatNameById:Object.fromEntries(Vt)}))}catch{}}Os();function _e(){return xn??=(async()=>{try{let e=await fetch("/api/groups");if(!e.ok)throw new Error(`HTTP ${e.status}`);let n=await e.json();for(let a of n.bots??[])a.larkAppId&&a.botName&&a.botName!==a.larkAppId&&xt.set(a.larkAppId,String(a.botName)),a.botAvatarUrl&&(a.larkAppId&&Kt.set(a.larkAppId,String(a.botAvatarUrl)),a.botName&&Jt.set(String(a.botName),String(a.botAvatarUrl)));for(let a of n.chats??[])a.chatId&&a.name&&Vt.set(a.chatId,String(a.name)),a.chatId&&a.avatar&&Qt.set(a.chatId,String(a.avatar));Bs()}catch{xn=null}})(),xn}function Na(e){return e?xt.get(e):void 0}function ye(e){let n=e.larkAppId?xt.get(e.larkAppId):void 0;return n||(e.botName&&e.botName!==e.larkAppId?String(e.botName):String(e.botName??e.larkAppId??"-"))}function nt(e){return e.chatId&&Vt.get(e.chatId)||null}function ve(e){let n=String(e??"");return n.replace(/^(?:@\S+\s*)+/,"").trim()||n}function wt(e){return`<div class="page-loading" role="status"><i class="page-loading-spin" aria-hidden="true"></i>${i(e??t("common.loading"))}</div>`}function at(e){return e.status==="closed"?null:e.agentAttention?.reason?e.agentAttention.reason:e.agentAttention?t("sessions.board.signalAgent"):e.pendingRepo?t("sessions.board.signalRepo"):e.tuiPromptActive?t("sessions.board.signalPrompt"):e.status==="limited"?t("sessions.board.signalLimited"):null}function Le(e){let n=Number(e.agentAttention?.at??e.lastMessageAt??0);if(Number.isFinite(n))return n;let a=Number(e.lastMessageAt??0);return Number.isFinite(a)?a:0}var Ua={chats:[],bots:[]};async function Ns(){try{let e=await fetch("/api/groups");if(!e.ok)return;Ua=await e.json()}catch{}}var Hn=new Set(["working","analyzing","active","starting"]);function Ps(e){let n=new Map,a=o=>{let r=n.get(o);return r||(r={botName:o,larkAppId:o,cliId:"unknown",online:!1,sessions:[],active:[],busy:[],attention:[],lastActiveAt:0},n.set(o,r)),r};for(let o of Ua.bots??[]){let r=a(o.larkAppId??o.botName??"-");r.online=!0,o.botName&&(r.botName=o.botName),o.botAvatarUrl&&(r.botAvatarUrl=o.botAvatarUrl)}let s=[...e].sort((o,r)=>+(o.status==="closed")-+(r.status==="closed"));for(let o of s){let r=o.larkAppId??o.botName??"-";if(o.status==="closed"&&!n.has(r))continue;let c=a(r);o.botName&&(c.botName===c.larkAppId||!c.botName)&&(c.botName=o.botName),c.sessions.push(o),o.cliId&&c.cliId==="unknown"&&(c.cliId=o.cliId),c.lastActiveAt=Math.max(c.lastActiveAt,Number(o.lastMessageAt??0)),o.status!=="closed"&&(c.active.push(o),Hn.has(o.status)&&c.busy.push(o),at(o)&&c.attention.push(o))}for(let o of n.values())if(o.botName===o.larkAppId){let r=Na(o.larkAppId);r&&(o.botName=r)}return[...n.values()].sort((o,r)=>{let c=m=>m.attention.length?0:m.busy.length?1:m.online||m.active.length?2:3;return c(o)!==c(r)?c(o)-c(r):r.lastActiveAt-o.lastActiveAt})}var ja="botmux.overview.teamExpanded",qs=230,Pa=13,qa=2;function Us(e){let n=e.clientWidth;return n?Math.max(1,Math.floor((n+Pa)/(qs+Pa)))*qa:qa*3}function js(){try{return window.localStorage.getItem(ja)==="1"}catch{return!1}}function Fs(e){try{window.localStorage.setItem(ja,e?"1":"0")}catch{}}function Gs(e){let n=!e.online&&e.active.length===0,a=e.attention.length>0,s=e.busy.length>0,o=a?"warn":s?"busy":n?"off":"ok",r;if(a){let m=[...e.attention].sort((k,v)=>Le(k)-Le(v))[0];r=`<b>${i((ve(m.title)||m.sessionId).slice(0,60))}</b> \xB7 ${i(at(m)??"")}`}else if(s){let m=[...e.busy].sort((k,v)=>Number(v.lastMessageAt??0)-Number(k.lastMessageAt??0))[0];r=`<b>${i((ve(m.title)||m.sessionId).slice(0,60))}</b>`}else n?r=i(t("overview.botOffline")):r=i(t("overview.botIdle"));let c=a?`<span class="tag tag-warn">${i(t("overview.botNeedsYou"))}</span>`:s?`<span class="tag tag-run">${i(t("overview.botBusy",{count:e.busy.length}))}</span>`:n?`<span class="tag tag-off">${i(t("overview.botOff"))}</span>`:`<span class="tag tag-ok">${i(t("overview.botReady"))}</span>`;return`<article class="mate${a?" mate-attn":""}${n?" mate-off":""}">
|
|
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"},pa={zh:rs,en:ls};function Ft(e){if(typeof e!="string")return null;let n=e.trim().toLowerCase();return n==="zh"||n.startsWith("zh-")?"zh":n==="en"||n.startsWith("en-")?"en":null}function ds(e=[]){for(let n of e){let a=Ft(n);if(a)return a}return"zh"}function Gt(e){return(n,a)=>{let s=pa[e][n]??pa.zh[n]??n;return a?s.replace(/\{(\w+)\}/g,(o,r)=>{let c=a[r];return c==null?`{${r}}`:String(c)}):s}}function ma(e,n){return(e?Ft(e.getItem(hn)):null)??ds(n)}var wn="botmux.dashboard.theme",fa="botmux.dashboard.sessions.view";function cs(e){return e==="system"||e==="light"||e==="dark"?e:null}function yn(e){return e==="kanban"||e==="board"||e==="table"?e:null}function ga(e,n){return e==="system"?n?"dark":"light":e}function ba(e){return cs(e?.getItem(wn))??"dark"}function ha(e){return yn(e?.getItem(fa))??"board"}var wa="botmux.dashboard.sessions.boardOrder",Lt=["needs-you","starting","working","idle"];function us(e){if(!Array.isArray(e)||e.length!==Lt.length)return null;let n=new Set(e);if(n.size!==e.length)return null;for(let a of Lt)if(!n.has(a))return null;return e.slice()}function ya(e){try{let n=e?.getItem(wa);return n?us(JSON.parse(n))??[...Lt]:[...Lt]}catch{return[...Lt]}}function vn(e,n){try{e?.setItem(wa,JSON.stringify(n))}catch{}}function va(e,n){try{e?.setItem(fa,n)}catch{}}var ka="botmux.dashboard.sessions.kanbanGroupBy",kn="botmux.dashboard.sessions.kanbanTeam";function ps(e){return e==="flow"||e==="team"||e==="bot"?e:null}function $a(e){return ps(e?.getItem(ka))??"flow"}function Sa(e,n){try{e?.setItem(ka,n)}catch{}}var Ta="botmux.dashboard.sidebar";function ms(e){return e==="expanded"||e==="collapsed"?e:null}function La(e){return ms(e?.getItem(Ta))??"expanded"}function Ia(e,n){try{e?.setItem(Ta,n)}catch{}}var fs=["default","cyber","genshin","fallout","prts","bluearchive","zzz","dragonball","ikun"],$n="botmux.dashboard.skin";function gs(e){return typeof e=="string"&&fs.includes(e)?e:null}function Ma(e){return gs(e?.getItem($n))??"default"}var bs="\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF830123456789\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E$#%&@*+=<>/\\",xa=["186 100% 60%","56 97% 60%","330 100% 64%","150 80% 58%"],Tn=[{key:"shake",dur:280},{key:"rgb",dur:340},{key:"tear",dur:400},{key:"invert",dur:220},{key:"slice",dur:320},{key:"blackout",dur:260}],Ea=["ESTABLISHING NETLINK","BYPASSING ICE","DECRYPTING DATAFLOW","SYNCING BOTMUX TELEMETRY","ACCESS GRANTED"],Ha="0123456789ABCDEF#<>*/=+\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C",hs=3200,It=[],ht=0,_t=0;function Mn(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Ln(e,n){let a="";for(let s=0;s<e;s++)a+=n[Math.floor(Math.random()*n.length)];return a}function ws(e){let n=document.createElement("div");n.className="cyber-rain";let a=Math.max(10,Math.min(26,Math.round(window.innerWidth/70)));for(let s=0;s<a;s++){let o=document.createElement("span");o.className="cyber-rain-col",o.textContent=Ln(28+Math.floor(Math.random()*22),bs);let r=xa[Math.floor(Math.random()*xa.length)];o.style.cssText=`left:${(s+.5)/a*100}%;--rc:${r};--sz:${10+Math.floor(Math.random()*9)}px;--op:${(.25+Math.random()*.45).toFixed(2)};--dur:${(6+Math.random()*9).toFixed(1)}s;--delay:${(-Math.random()*12).toFixed(1)}s;`,n.appendChild(o)}e.appendChild(n)}function ys(){if(Mn())return;let e=document.body,n=()=>{let a=Tn[Math.floor(Math.random()*Tn.length)],s=`cp-fx-${a.key}`;e.classList.add(s),It.push(window.setTimeout(()=>e.classList.remove(s),a.dur)),It.push(window.setTimeout(n,2400+Math.random()*4200))};It.push(window.setTimeout(n,1800+Math.random()*2600))}function vs(){It.forEach(e=>window.clearTimeout(e)),It=[];for(let e of Tn)document.body.classList.remove(`cp-fx-${e.key}`)}function ks(){if(Mn()||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 n=e.querySelector(".cyber-loader-text"),a=e.querySelector(".cyber-loader-stream"),s=0,o=0,r=0;ht=window.setInterval(()=>{let c=Ea[s];n&&(o<c.length?(o+=1,n.textContent=c.slice(0,o)+Ln(c.length-o,Ha),n.classList.remove("done")):r<16?(r+=1,n.textContent=c,n.classList.add("done")):(s=(s+1)%Ea.length,o=0,r=0)),a&&(a.textContent=Ln(26,Ha))},50),_t=window.setTimeout(()=>{window.clearInterval(ht),ht=0,e.remove()},hs)}function $s(){ht&&(window.clearInterval(ht),ht=0),_t&&(window.clearTimeout(_t),_t=0),document.getElementById("cyber-boot")?.remove()}var Ss=320,Ca=16,Mt=!0,bt=0,Sn=0,zt=!1,Wt=[],In=[];function Ts(){if(zt)return;zt=!0,Mt=!1,bt=0;let e=Mn(),n="";for(let s=0;s<Ca;s++){let o=s%3===0?"186 100% 52%":s%3===1?"330 100% 58%":"56 97% 52%",r=(s%2===0?1:-1)*(8+s%5*7);n+=`<span class="cyber-breach-shard" style="top:${s/Ca*100}%;height:${2+s%4*3}%;--shift:${r}px;--delay:${s%8*.09}s;--dur:${(.36+s%5*.12).toFixed(2)}s;--hue:${o}"></span>`}let a=document.createElement("div");a.id="cyber-breach",a.className="cyber-breach",a.setAttribute("aria-hidden","true"),a.innerHTML=`<span class="cyber-breach-flash"></span><span class="cyber-breach-grid"></span><div class="cyber-breach-shards">${n}</div><div class="cyber-breach-banner"><span class="cyber-breach-tag">// BREACH PROTOCOL \u2014 SYSTEM OVERRIDE</span><span class="cyber-breach-caption" data-text="SYSTEM BREACH">SYSTEM BREACH</span><span class="cyber-breach-sub" data-text="NETWATCH OVERRIDE ENGAGED">NETWATCH OVERRIDE ENGAGED</span></div>`,document.body.appendChild(a),e||document.body.classList.add("cyber-breach-quake"),Wt.push(window.setTimeout(()=>document.body.classList.remove("cyber-breach-quake"),760)),Wt.push(window.setTimeout(()=>{a.remove(),zt=!1},e?2600:4200))}function Ls(){Mt=!0,bt=0;let e=document.documentElement,n=()=>e.scrollHeight-(window.innerHeight+window.scrollY)<=4,a=k=>{k<=0||!n()||(bt+=k,bt>Ss&&Mt&&Ts())},s=k=>a(k.deltaY),o=k=>{Sn=k.touches[0]?.clientY??0},r=k=>{let v=k.touches[0]?.clientY??0,L=Sn-v;Sn=v,a(L)},c=()=>{n()||(bt=0,Mt=!0)},p=(k,v)=>{window.addEventListener(k,v,{passive:!0}),In.push([k,v])};p("wheel",s),p("touchstart",o),p("touchmove",r),p("scroll",c)}function Is(){for(let[e,n]of In)window.removeEventListener(e,n);In=[],Wt.forEach(e=>window.clearTimeout(e)),Wt=[],document.body.classList.remove("cyber-breach-quake"),document.getElementById("cyber-breach")?.remove(),zt=!1,Mt=!0,bt=0}function Aa(e,n=!1){if(!(typeof document>"u")){if(!e){document.getElementById("cyber-fx")?.remove(),document.getElementById("cyber-hud")?.remove(),document.getElementById("cyber-glitch")?.remove(),vs(),$s(),Is();return}if(!document.getElementById("cyber-fx")){let a=document.createElement("div");a.id="cyber-fx",a.className="cyber-fx",a.setAttribute("aria-hidden","true"),a.innerHTML='<div class="cyber-fx-grid"></div><div class="cyber-fx-scan"></div><span class="cyber-flicker"></span><span class="cyber-rollline"></span>',ws(a),document.body.appendChild(a);let s=document.createElement("div");s.id="cyber-hud",s.className="cyber-hud",s.setAttribute("aria-hidden","true"),s.innerHTML='<span class="cyber-hud-corner tl"></span><span class="cyber-hud-corner tr"></span><span class="cyber-hud-corner bl"></span><span class="cyber-hud-corner br"></span><span class="cyber-hud-tag">NIGHT CITY // NETWATCH</span>',document.body.appendChild(s);let o=document.createElement("div");o.id="cyber-glitch",o.className="cyber-glitch",o.setAttribute("aria-hidden","true"),document.body.appendChild(o),ys(),Ls()}n&&ks()}}var Ms={genshin:2e3,zzz:1900,dragonball:1900,ikun:1900},xs='<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 Es(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 xs;default:return""}}function Hs(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Da(e){if(typeof document>"u"||Hs())return;let n=Ms[e];if(!n)return;document.getElementById("skin-intro")?.remove();let a=document.createElement("div");a.id="skin-intro",a.className=`skin-intro si-${e}`,a.setAttribute("aria-hidden","true"),a.style.setProperty("--si-dur",`${n}ms`),a.innerHTML=Es(e),document.body.appendChild(a),window.setTimeout(()=>a.remove(),n+80)}var En=class{locale="zh";themeMode="system";resolvedTheme="light";skin="default";authed=!0;listeners=new Set;translate=Gt(this.locale);mediaQuery=null;init(){let n=typeof window<"u"?window:void 0;this.locale=ma(n?.localStorage,As()),this.translate=Gt(this.locale),this.themeMode=ba(n?.localStorage),this.skin=Ma(n?.localStorage),this.mediaQuery=n?.matchMedia?.("(prefers-color-scheme: dark)")??null,this.mediaQuery?.addEventListener("change",()=>{this.applyTheme(),this.emit()}),this.applyTheme(),this.applySkin(),this.applyLocale()}t(n,a){return this.translate(n,a)}setLocale(n){this.locale!==n&&(this.locale=n,this.translate=Gt(n),window.localStorage.setItem(hn,n),this.applyLocale(),this.emit())}get theme(){return this.skin==="default"?this.themeMode:this.skin}setTheme(n){let a=n==="system"||n==="light"||n==="dark",s=a?"default":n,o=s!==this.skin;a&&this.themeMode!==n&&(this.themeMode=n,window.localStorage.setItem(wn,this.themeMode)),o&&(this.skin=s,window.localStorage.setItem($n,this.skin)),this.applyTheme(),this.applySkin(o),this.emit()}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}applyTheme(){this.resolvedTheme=ga(this.themeMode,!!this.mediaQuery?.matches);let n=this.skin==="default"?this.resolvedTheme:Cs[this.skin];document.documentElement.dataset.theme=n,document.documentElement.dataset.themeMode=this.themeMode}applySkin(n=!1){document.documentElement.dataset.skin=this.skin,Aa(this.skin==="cyber",n),n&&this.skin!=="cyber"&&this.skin!=="default"&&Da(this.skin)}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}},Cs={default:"light",cyber:"dark",genshin:"light",fallout:"dark",prts:"dark",bluearchive:"dark",zzz:"dark",dragonball:"light",ikun:"dark"};function As(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var Se=new En;function t(e,n){return Se.t(e,n)}function i(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function Be(e){if(!e)return"-";let n=Date.now()-e;return n<6e4?t("common.now"):n<36e5?Math.floor(n/6e4)+"m":n<864e5?Math.floor(n/36e5)+"h":Math.floor(n/864e5)+"d"}var Ra=[{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 Oa(e){let n=0,a=String(e??"");for(let r=0;r<a.length;r++)n=n*31+a.charCodeAt(r)>>>0;let{c1:s,c2:o}=Ra[n%Ra.length];return`--c1:${s};--c2:${o}`}var Kt=new Map,Jt=new Map;function Ds(e,n){return n?Kt.get(n):e?Jt.get(String(e)):void 0}function fe(e){let n=e.name??"",a=e.avatarUrl??Ds(e.name,e.larkAppId),s=e.size==="sm"?" orb-avatar-sm":"",o=a?" orb-has-img":"",r=e.dot?`<i class="orb-dot orb-dot-${e.dot}"></i>`:"",c=a?`<img class="orb-img" src="${i(a)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar${s}${o}" style="${Oa(n)}" aria-hidden="true">${c}${r}</span>`}function Rs(e){return e?Qt.get(e):void 0}function Yt(e){let n=e.name??e.chatId??"",a=e.avatarUrl??Rs(e.chatId),s=e.size==="sm"?" orb-avatar-sm":"",o=a?" orb-has-img":"",r=a?`<img class="orb-img" src="${i(a)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar orb-square${s}${o}" style="${Oa(n)}" aria-hidden="true">${r}</span>`}var xt=new Map,Vt=new Map,Qt=new Map,xn=null,Ba="botmux.avatarCache.v1";function Os(){try{let e=typeof window<"u"?window.localStorage.getItem(Ba):null;if(!e)return;let n=JSON.parse(e);for(let[a,s]of Object.entries(n.botByAppId??{}))Kt.set(a,s);for(let[a,s]of Object.entries(n.botByName??{}))Jt.set(a,s);for(let[a,s]of Object.entries(n.chatById??{}))Qt.set(a,s);for(let[a,s]of Object.entries(n.nameByAppId??{}))xt.set(a,s);for(let[a,s]of Object.entries(n.chatNameById??{}))Vt.set(a,s)}catch{}}function Bs(){try{if(typeof window>"u")return;window.localStorage.setItem(Ba,JSON.stringify({botByAppId:Object.fromEntries(Kt),botByName:Object.fromEntries(Jt),chatById:Object.fromEntries(Qt),nameByAppId:Object.fromEntries(xt),chatNameById:Object.fromEntries(Vt)}))}catch{}}Os();function _e(){return xn??=(async()=>{try{let e=await fetch("/api/groups");if(!e.ok)throw new Error(`HTTP ${e.status}`);let n=await e.json();for(let a of n.bots??[])a.larkAppId&&a.botName&&a.botName!==a.larkAppId&&xt.set(a.larkAppId,String(a.botName)),a.botAvatarUrl&&(a.larkAppId&&Kt.set(a.larkAppId,String(a.botAvatarUrl)),a.botName&&Jt.set(String(a.botName),String(a.botAvatarUrl)));for(let a of n.chats??[])a.chatId&&a.name&&Vt.set(a.chatId,String(a.name)),a.chatId&&a.avatar&&Qt.set(a.chatId,String(a.avatar));Bs()}catch{xn=null}})(),xn}function Na(e){return e?xt.get(e):void 0}function ye(e){let n=e.larkAppId?xt.get(e.larkAppId):void 0;return n||(e.botName&&e.botName!==e.larkAppId?String(e.botName):String(e.botName??e.larkAppId??"-"))}function nt(e){return e.chatId&&Vt.get(e.chatId)||null}function ve(e){let n=String(e??"");return n.replace(/^(?:@\S+\s*)+/,"").trim()||n}function wt(e){return`<div class="page-loading" role="status"><i class="page-loading-spin" aria-hidden="true"></i>${i(e??t("common.loading"))}</div>`}function at(e){return e.status==="closed"?null:e.agentAttention?.reason?e.agentAttention.reason:e.agentAttention?t("sessions.board.signalAgent"):e.pendingRepo?t("sessions.board.signalRepo"):e.tuiPromptActive?t("sessions.board.signalPrompt"):e.status==="limited"?t("sessions.board.signalLimited"):null}function Ie(e){let n=Number(e.agentAttention?.at??e.lastMessageAt??0);if(Number.isFinite(n))return n;let a=Number(e.lastMessageAt??0);return Number.isFinite(a)?a:0}var Ua={chats:[],bots:[]};async function Ns(){try{let e=await fetch("/api/groups");if(!e.ok)return;Ua=await e.json()}catch{}}var Hn=new Set(["working","analyzing","active","starting"]);function Ps(e){let n=new Map,a=o=>{let r=n.get(o);return r||(r={botName:o,larkAppId:o,cliId:"unknown",online:!1,sessions:[],active:[],busy:[],attention:[],lastActiveAt:0},n.set(o,r)),r};for(let o of Ua.bots??[]){let r=a(o.larkAppId??o.botName??"-");r.online=!0,o.botName&&(r.botName=o.botName),o.botAvatarUrl&&(r.botAvatarUrl=o.botAvatarUrl)}let s=[...e].sort((o,r)=>+(o.status==="closed")-+(r.status==="closed"));for(let o of s){let r=o.larkAppId??o.botName??"-";if(o.status==="closed"&&!n.has(r))continue;let c=a(r);o.botName&&(c.botName===c.larkAppId||!c.botName)&&(c.botName=o.botName),c.sessions.push(o),o.cliId&&c.cliId==="unknown"&&(c.cliId=o.cliId),c.lastActiveAt=Math.max(c.lastActiveAt,Number(o.lastMessageAt??0)),o.status!=="closed"&&(c.active.push(o),Hn.has(o.status)&&c.busy.push(o),at(o)&&c.attention.push(o))}for(let o of n.values())if(o.botName===o.larkAppId){let r=Na(o.larkAppId);r&&(o.botName=r)}return[...n.values()].sort((o,r)=>{let c=p=>p.attention.length?0:p.busy.length?1:p.online||p.active.length?2:3;return c(o)!==c(r)?c(o)-c(r):r.lastActiveAt-o.lastActiveAt})}var ja="botmux.overview.teamExpanded",qs=230,Pa=13,qa=2;function Us(e){let n=e.clientWidth;return n?Math.max(1,Math.floor((n+Pa)/(qs+Pa)))*qa:qa*3}function js(){try{return window.localStorage.getItem(ja)==="1"}catch{return!1}}function Fs(e){try{window.localStorage.setItem(ja,e?"1":"0")}catch{}}function Gs(e){let n=!e.online&&e.active.length===0,a=e.attention.length>0,s=e.busy.length>0,o=a?"warn":s?"busy":n?"off":"ok",r;if(a){let p=[...e.attention].sort((k,v)=>Ie(k)-Ie(v))[0];r=`<b>${i((ve(p.title)||p.sessionId).slice(0,60))}</b> \xB7 ${i(at(p)??"")}`}else if(s){let p=[...e.busy].sort((k,v)=>Number(v.lastMessageAt??0)-Number(k.lastMessageAt??0))[0];r=`<b>${i((ve(p.title)||p.sessionId).slice(0,60))}</b>`}else n?r=i(t("overview.botOffline")):r=i(t("overview.botIdle"));let c=a?`<span class="tag tag-warn">${i(t("overview.botNeedsYou"))}</span>`:s?`<span class="tag tag-run">${i(t("overview.botBusy",{count:e.busy.length}))}</span>`:n?`<span class="tag tag-off">${i(t("overview.botOff"))}</span>`:`<span class="tag tag-ok">${i(t("overview.botReady"))}</span>`;return`<article class="mate${a?" mate-attn":""}${n?" mate-off":""}">
|
|
14
14
|
<div class="mate-top">
|
|
15
15
|
${fe({name:e.botName,larkAppId:e.larkAppId,avatarUrl:e.botAvatarUrl,dot:o})}
|
|
16
16
|
<div class="mate-id">
|
|
@@ -27,7 +27,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
27
27
|
${fe({name:n,larkAppId:e.larkAppId,size:"sm"})}
|
|
28
28
|
<div class="qcard-tx">
|
|
29
29
|
<b>${i(n)} \xB7 ${i((ve(e.title)||e.sessionId).slice(0,56))}</b>
|
|
30
|
-
<span>${i(at(e)??"")} \xB7 ${Be(
|
|
30
|
+
<span>${i(at(e)??"")} \xB7 ${Be(Ie(e))}</span>
|
|
31
31
|
</div>
|
|
32
32
|
<a class="qcard-go" href="#/sessions">${i(t("strip.handle"))}</a>
|
|
33
33
|
</article>`}function zs(e){let n=ye(e);return`<li class="sess-row">
|
|
@@ -102,15 +102,15 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
102
102
|
</section>
|
|
103
103
|
</div>
|
|
104
104
|
</div>
|
|
105
|
-
</section>`;let n=e.querySelector("#overview-pills"),a=e.querySelector("#team-grid"),s=e.querySelector("#team-toggle"),o=js();s.onclick=()=>{o=!o,Fs(o),v()};let r=e.querySelector("#attention-list"),c=e.querySelector("#recent-sessions"),
|
|
105
|
+
</section>`;let n=e.querySelector("#overview-pills"),a=e.querySelector("#team-grid"),s=e.querySelector("#team-toggle"),o=js();s.onclick=()=>{o=!o,Fs(o),v()};let r=e.querySelector("#attention-list"),c=e.querySelector("#recent-sessions"),p=e.querySelector("#today-donut"),k=e.querySelector("#next-schedules");function v(){let $=[...V.sessions.values()],g=$.filter(S=>S.status!=="closed"),O=g.filter(S=>at(S)).sort((S,A)=>Ie(S)-Ie(A)),D=g.filter(S=>Hn.has(S.status)&&!at(S)),R=g.length-O.length-D.length,I=Ps($),E=I.filter(S=>S.online||S.active.length>0).length;n.innerHTML=`
|
|
106
106
|
<span class="pill">${i(t("overview.workingSessions"))} <b>${D.length}</b></span>
|
|
107
107
|
<span class="pill${O.length?" pill-hot":""}">${i(t("overview.attention"))} <b>${O.length}</b></span>
|
|
108
|
-
<span class="pill">${i(t("overview.onlineBots"))} <b>${E}</b></span>`;let d=Us(a),y=o?I:I.slice(0,d);a.innerHTML=y.length?y.map(Gs).join(""):`<div class="empty">${t("overview.noSessions")}</div>`,I.length>d?(s.hidden=!1,s.textContent=o?t("overview.teamCollapse"):t("overview.teamExpand",{count:I.length})):s.hidden=!0,r.innerHTML=O.length?O.map(_s).join(""):`<div class="qcard qcard-empty">${t("overview.noAttention")}</div>`;let H=g.filter(S=>Hn.has(S.status)||S.status==="idle").sort((S,A)=>Number(A.lastMessageAt??0)-Number(S.lastMessageAt??0)).slice(0,7);c.innerHTML=H.length?H.map(zs).join(""):`<li class="empty">${t("overview.noSessions")}</li>`,
|
|
108
|
+
<span class="pill">${i(t("overview.onlineBots"))} <b>${E}</b></span>`;let d=Us(a),y=o?I:I.slice(0,d);a.innerHTML=y.length?y.map(Gs).join(""):`<div class="empty">${t("overview.noSessions")}</div>`,I.length>d?(s.hidden=!1,s.textContent=o?t("overview.teamCollapse"):t("overview.teamExpand",{count:I.length})):s.hidden=!0,r.innerHTML=O.length?O.map(_s).join(""):`<div class="qcard qcard-empty">${t("overview.noAttention")}</div>`;let H=g.filter(S=>Hn.has(S.status)||S.status==="idle").sort((S,A)=>Number(A.lastMessageAt??0)-Number(S.lastMessageAt??0)).slice(0,7);c.innerHTML=H.length?H.map(zs).join(""):`<li class="empty">${t("overview.noSessions")}</li>`,p.innerHTML=`${Ks(D.length,O.length,Math.max(0,R))}
|
|
109
109
|
<div class="donut-legend">
|
|
110
110
|
<span><i style="background:var(--accent)"></i>${i(t("overview.workingSessions"))} ${D.length}</span>
|
|
111
111
|
<span><i style="background:var(--warning)"></i>${i(t("overview.attention"))} ${O.length}</span>
|
|
112
112
|
<span><i style="background:var(--success)"></i>${i(t("sessions.board.idle"))} ${Math.max(0,R)}</span>
|
|
113
|
-
</div>`;let M=[...V.schedules.values()].filter(S=>S.nextRunAt).sort((S,A)=>Date.parse(S.nextRunAt)-Date.parse(A.nextRunAt)).slice(0,5);k.innerHTML=M.length?M.map(Ws).join(""):`<li class="empty">${t("overview.noSchedules")}</li>`}let L=()=>{if(!document.body.contains(a)){window.removeEventListener("resize",L);return}o||v()};window.addEventListener("resize",L),V.on(v),v(),Ns().then(v),_e().then(v)}var Ga=["backlog","todo","in_progress","in_review","done"];function _a(e){return typeof e=="string"&&Ga.includes(e)?e:null}function za(e){if(e.status==="closed")return"done";let n=_a(e.kanbanColumn);return n||(e.pendingRepo||e.tuiPromptActive||e.agentAttention||e.status==="limited"?"in_review":e.status==="starting"||e.status==="working"||e.status==="analyzing"||e.status==="active"?"in_progress":"todo")}var Js=1e15;function rt(e){if(typeof e.kanbanPosition=="number"&&Number.isFinite(e.kanbanPosition))return e.kanbanPosition;let n=typeof e.lastMessageAt=="number"&&Number.isFinite(e.lastMessageAt)?e.lastMessageAt:0;return Js-n}function Cn(e,n){return e!==null&&n!==null?(e+n)/2:e!==null?e+1024:n!==null?n-1024:1024}function ze(e,n){return`<th data-sort="${e}" data-label="${i(n)}">${i(n)}</th>`}function On(e){return typeof e=="number"&&Number.isFinite(e)?e:null}function Wa(e){let n=On(e);return n===null?"-":n.toLocaleString("en-US")}var Za=["claude-code","seed","codex","codex-app","cursor","gemini","opencode","mtr","hermes","mira","pi","copilot","aiden","coco","oh-my-pi","unknown"],Ka=[{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"}],Ja=[{id:"backlog",labelKey:"sessions.kanban.backlog"},{id:"todo",labelKey:"sessions.kanban.todo"},{id:"in_progress",labelKey:"sessions.kanban.inProgress"},{id:"in_review",labelKey:"sessions.kanban.inReview"},{id:"done",labelKey:"sessions.kanban.done"}],An=50;function Ys(e){let n=(a="")=>`<svg viewBox="0 0 14 14" aria-hidden="true"><circle cx="7" cy="7" r="5.4" fill="none" stroke="currentColor" stroke-width="1.6"${a}/>`;switch(e){case"backlog":return`${n(' stroke-dasharray="1.6 2.1"')}</svg>`;case"in_progress":return`${n()}<path d="M7,7 L7,3.6 A3.4,3.4 0 0 1 7,10.4 Z" fill="currentColor"/></svg>`;case"in_review":return`${n()}<path d="M7,7 L7,3.6 A3.4,3.4 0 1 1 3.6,7 Z" fill="currentColor"/></svg>`;case"done":return'<svg viewBox="0 0 14 14" aria-hidden="true"><circle cx="7" cy="7" r="6.2" fill="currentColor"/><path d="M4.4 7.2 6.2 9 9.7 5.4" fill="none" stroke="var(--surface)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>';default:return`${n()}</svg>`}}function Ya(e){return String(e??"unknown").toLowerCase().replace(/[^a-z0-9_-]/g,"-")}function Va(e){let n=String(e??"").trim();return n?n.replace(/\\/g,"/").split("/").filter(Boolean).at(-1)??n:"-"}function Dn(e){if(!e.webPort)return null;let n=e.proxyPort??e.webPort,a=e.proxyPort?`/s/${encodeURIComponent(e.sessionId)}`:"";return`http://${location.hostname}:${n}${a}`}var
|
|
113
|
+
</div>`;let M=[...V.schedules.values()].filter(S=>S.nextRunAt).sort((S,A)=>Date.parse(S.nextRunAt)-Date.parse(A.nextRunAt)).slice(0,5);k.innerHTML=M.length?M.map(Ws).join(""):`<li class="empty">${t("overview.noSchedules")}</li>`}let L=()=>{if(!document.body.contains(a)){window.removeEventListener("resize",L);return}o||v()};window.addEventListener("resize",L),V.on(v),v(),Ns().then(v),_e().then(v)}var Ga=["backlog","todo","in_progress","in_review","done"];function _a(e){return typeof e=="string"&&Ga.includes(e)?e:null}function za(e){if(e.status==="closed")return"done";let n=_a(e.kanbanColumn);return n||(e.pendingRepo||e.tuiPromptActive||e.agentAttention||e.status==="limited"?"in_review":e.status==="starting"||e.status==="working"||e.status==="analyzing"||e.status==="active"?"in_progress":"todo")}var Js=1e15;function rt(e){if(typeof e.kanbanPosition=="number"&&Number.isFinite(e.kanbanPosition))return e.kanbanPosition;let n=typeof e.lastMessageAt=="number"&&Number.isFinite(e.lastMessageAt)?e.lastMessageAt:0;return Js-n}function Cn(e,n){return e!==null&&n!==null?(e+n)/2:e!==null?e+1024:n!==null?n-1024:1024}function ze(e,n){return`<th data-sort="${e}" data-label="${i(n)}">${i(n)}</th>`}function On(e){return typeof e=="number"&&Number.isFinite(e)?e:null}function Wa(e){let n=On(e);return n===null?"-":n.toLocaleString("en-US")}var Za=["claude-code","seed","codex","codex-app","cursor","gemini","opencode","mtr","hermes","mira","pi","copilot","aiden","coco","oh-my-pi","unknown"],Ka=[{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"}],Ja=[{id:"backlog",labelKey:"sessions.kanban.backlog"},{id:"todo",labelKey:"sessions.kanban.todo"},{id:"in_progress",labelKey:"sessions.kanban.inProgress"},{id:"in_review",labelKey:"sessions.kanban.inReview"},{id:"done",labelKey:"sessions.kanban.done"}],An=50;function Ys(e){let n=(a="")=>`<svg viewBox="0 0 14 14" aria-hidden="true"><circle cx="7" cy="7" r="5.4" fill="none" stroke="currentColor" stroke-width="1.6"${a}/>`;switch(e){case"backlog":return`${n(' stroke-dasharray="1.6 2.1"')}</svg>`;case"in_progress":return`${n()}<path d="M7,7 L7,3.6 A3.4,3.4 0 0 1 7,10.4 Z" fill="currentColor"/></svg>`;case"in_review":return`${n()}<path d="M7,7 L7,3.6 A3.4,3.4 0 1 1 3.6,7 Z" fill="currentColor"/></svg>`;case"done":return'<svg viewBox="0 0 14 14" aria-hidden="true"><circle cx="7" cy="7" r="6.2" fill="currentColor"/><path d="M4.4 7.2 6.2 9 9.7 5.4" fill="none" stroke="var(--surface)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>';default:return`${n()}</svg>`}}function Ya(e){return String(e??"unknown").toLowerCase().replace(/[^a-z0-9_-]/g,"-")}function Va(e){let n=String(e??"").trim();return n?n.replace(/\\/g,"/").split("/").filter(Boolean).at(-1)??n:"-"}function Dn(e){if(!e.webPort)return null;let n=e.proxyPort??e.webPort,a=e.proxyPort?`/s/${encodeURIComponent(e.sessionId)}`:"";return`http://${location.hostname}:${n}${a}`}var Me={pin:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M8 14.3s4.2-3.9 4.2-7.3A4.2 4.2 0 0 0 8 2.9a4.2 4.2 0 0 0-4.2 4.1C3.8 10.4 8 14.3 8 14.3z"/><circle cx="8" cy="6.9" r="1.5"/></svg>',openChat:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M9.4 2.8h3.8v3.8"/><path d="M13.2 2.8 7.3 8.7"/><path d="M11.5 9.3v2.9a1.2 1.2 0 0 1-1.2 1.2H3.8a1.2 1.2 0 0 1-1.2-1.2V5.7a1.2 1.2 0 0 1 1.2-1.2h2.9"/></svg>',details:'<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="2.2" y="2.9" width="11.6" height="10.2" rx="1.8"/><path d="M9.9 2.9v10.2"/></svg>',terminal:'<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="1.7" y="2.7" width="12.6" height="10.6" rx="2"/><path d="M4.4 6.3 6.4 8.1 4.4 9.9"/><path d="M8.2 10.2h3.4"/></svg>',key:'<svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="6" cy="6.1" r="3"/><path d="M8.1 8.2 13 13.1"/><path d="M11.3 11.4 12.6 10.1"/><path d="M12.7 12.8 13.7 11.8"/></svg>',close:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M4.2 4.2 11.8 11.8"/><path d="M11.8 4.2 4.2 11.8"/></svg>',edit:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M10.7 3.3 12.7 5.3 6.3 11.7 3.7 12.3 4.3 9.7 10.7 3.3z"/></svg>',history:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M2.2 4.8a2 2 0 0 1 2-2h7.6a2 2 0 0 1 2 2v4.6a2 2 0 0 1-2 2H6.6l-2.9 2.4v-2.4h-.5a2 2 0 0 1-2-2z"/><path d="M5.2 6.2h5.6M5.2 8.4h3.6"/></svg>',feishu:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M2.6 4.4C6.4 4 10.4 5.4 13.4 8.2 9.8 7 6.4 6.6 3.4 7.4"/><path d="M13.4 8.2C9.6 8.7 6 10 2.9 12 5.6 9 8.8 7.6 13.4 8.2"/></svg>'};function Rn(e,n,a,s=""){return`<button type="button" class="card-act${s?" "+s:""}" data-action="${e}" title="${i(a)}" aria-label="${i(a)}">${n}</button>`}function Qa(e){if(!e)return"";let n=`<a class="term-btn term-open" href="${i(e)}" target="_blank" rel="noopener" title="${i(t("sessions.openTerminal"))}" aria-label="${i(t("sessions.openTerminal"))}">${Me.terminal}</a>`;if(!Se.authed)return`<span class="term-pill solo">${n}</span>`;let a=`<button type="button" class="term-btn term-write" data-action="write-link" title="${i(t("sessions.writeLinkHint"))}" aria-label="${i(t("sessions.writeLink"))}">${Me.key}</button>`;return`<span class="term-pill">${n}${a}</span>`}async function Xa(e,n){let a=window.open("about:blank","_blank");a&&(a.opener=null),n&&(n.disabled=!0);try{let s=await fetch(`/api/sessions/${encodeURIComponent(e.sessionId)}/write-link`),o=await s.json().catch(()=>({}));if(!s.ok||o?.ok===!1||!o?.url){a?.close(),s.status!==401&&alert(`${t("sessions.writeLinkFail")}: ${o?.error??s.status}`);return}a?a.location.href=o.url:window.open(o.url,"_blank","noopener")}catch(s){a?.close(),alert(`${t("sessions.writeLinkFail")}: ${s}`)}finally{n&&(n.disabled=!1)}}function Vs(e){return e.status==="closed"?null:e.pendingRepo||e.tuiPromptActive||e.agentAttention||e.status==="limited"?"needs-you":e.status==="starting"?"starting":e.status==="working"||e.status==="analyzing"||e.status==="active"?"working":"idle"}function Qs(){return`<details class="filter-cli">
|
|
114
114
|
<summary>${t("sessions.cli")} \xB7 <b id="cli-filter-count">${t("common.all")}</b></summary>
|
|
115
115
|
<div class="filter-cli-pop" role="group" aria-label="${t("sessions.cli")}">
|
|
116
116
|
${Za.map(e=>`
|
|
@@ -184,7 +184,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
184
184
|
<dialog id="drawer"></dialog>
|
|
185
185
|
<dialog id="term-modal" class="term-modal"></dialog>
|
|
186
186
|
<dialog id="history-modal" class="history-modal"></dialog>
|
|
187
|
-
</section>`}function eo(e){e.innerHTML=Xs();let n=e.querySelector("#sessions-table tbody"),a=e.querySelector("#filters"),s=e.querySelector("#drawer"),o=e.querySelector("#select-all"),r=e.querySelector("#bulk-bar"),c=e.querySelector("#bulk-count"),
|
|
187
|
+
</section>`}function eo(e){e.innerHTML=Xs();let n=e.querySelector("#sessions-table tbody"),a=e.querySelector("#filters"),s=e.querySelector("#drawer"),o=e.querySelector("#select-all"),r=e.querySelector("#bulk-bar"),c=e.querySelector("#bulk-count"),p=e.querySelector("#bulk-close"),k=e.querySelector("#bulk-clear"),v=e.querySelector("#sessions-table"),L=e.querySelector("#sessions-board"),$=e.querySelector("#sessions-kanban"),g=e.querySelector("#term-modal"),O=e.querySelector("#history-modal"),D=e.querySelector("#kanban-groupby"),R=e.querySelector("#kanban-team"),I=e.querySelector("#kanban-team-stats"),E=e.querySelectorAll(".sessions-view-toggle [data-view]"),d=new Set,y="lastMessageAt",H="desc",M=ha(window.localStorage),S=ya(window.localStorage),A=null,B="",_="",j="",Q=!1,le=null,He=!1,ge=null,J=new Map,se=$a(window.localStorage),Te=null,Re=null,ee=[],ue=null,de=!1,qe=!1,$e=(()=>{try{return window.localStorage.getItem(kn)??""}catch{return""}})();async function be(){if(!(qe||de)){qe=!0;try{let[l,u,f]=await Promise.all([fetch("/api/team/hosted").then(w=>w.json()).catch(()=>null),fetch("/api/team/remote-roster").then(w=>w.json()).catch(()=>null),fetch("/api/groups").then(w=>w.json()).catch(()=>null)]);Array.isArray(f?.chats)&&(ue=new Map(f.chats.map(w=>[String(w.chatId),{botIds:new Set((w.memberBots??[]).filter(T=>T.inChat).map(T=>String(T.larkAppId))),observedNames:new Set((w.observedBotNames??[]).map(T=>String(T)))}])));let m=w=>({ids:new Set(w.map(T=>String(T.larkAppId))),names:new Set(w.map(T=>String(T.name??"")).filter(Boolean))}),b=[];for(let w of l?.teams??[]){let{ids:T,names:C}=m(w.bots??[]);b.push({key:`local:${w.teamId}`,label:w.isDefault?t("team.myHostedTeam"):String(w.name??w.teamId),botIds:T,botNames:C,groupChats:new Set((w.groupChatIds??[]).map(q=>String(q)))})}for(let w of u?.memberships??[]){let{ids:T,names:C}=m(w.roster?.bots??[]);b.push({key:`${w.hubUrl}::${w.teamId}`,label:String(w.teamName??w.teamId??w.hubUrl),botIds:T,botNames:C,groupChats:new Set})}ee=b}finally{de=!0,qe=!1}ee.length&&!ee.some(l=>l.key===$e)&&($e=ee[0].key),delete R.dataset.loading,R.disabled=ee.length===0,R.innerHTML=ee.length?ee.map(l=>`<option value="${i(l.key)}"${l.key===$e?" selected":""}>${i(l.label)}</option>`).join(""):`<option value="">${i(t("sessions.kanban.noTeam"))}</option>`,j="",Z()}}let re=null,Ce="",Ae=0,ce=!1,je=new Map;async function Ze(l){let u=Ce===l.key&&Date.now()-Ae<3e4;if(!(ce||u)){ce=!0;try{let m=l.key.startsWith("local:")?`/api/team/board/local/${encodeURIComponent(l.key.slice(6))}`:`/api/team/remote-board?key=${encodeURIComponent(l.key)}`,b=await fetch(m),w=await b.json().catch(()=>({}));if(!b.ok||w?.ok===!1)return;let T=typeof w.deploymentId=="string"?w.deploymentId:null,C=[];je=new Map;for(let q of Array.isArray(w.reports)?w.reports:[])if(!(T&&q.deploymentId===T))for(let N of Array.isArray(q.sessions)?q.sessions:[]){let te={...N,remoteDeployment:q.deploymentName||q.deploymentId};C.push(te),je.set(String(N.sessionId),te)}re={board:w.board&&typeof w.board=="object"?w.board:{},remoteRows:C},Ce=l.key,Ae=Date.now(),j="",Z()}catch{}finally{ce=!1}}}async function et(l,u,f,m,b){try{let T=l.startsWith("local:")?await fetch(`/api/team/board/local/${encodeURIComponent(l.slice(6))}/move`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({sessionId:u,column:f,position:m})}):await fetch("/api/team/remote-board-move",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({key:l,sessionId:u,column:f,position:m})}),C=await T.json().catch(()=>({}));(!T.ok||C?.ok===!1)&&(re&&(b?re.board[u]=b:delete re.board[u]),j="",Z(),T.status!==401&&alert(`${t("sessions.kanban.moveFail")}: ${C?.error??T.status}`))}catch(w){re&&(b?re.board[u]=b:delete re.board[u]),j="",Z(),alert(`${t("sessions.kanban.moveFail")}: ${w}`)}}function ft(l,u,f){let m=ee.find(w=>w.key===$e)??ee[0];if(!m)return;(!re||Ce!==m.key)&&(re={board:{},remoteRows:re?.remoteRows??[]},Ce=m.key);let b=re.board[l];re.board[l]={column:u,position:f},et(m.key,l,u,f,b)}function it(){return S.map(l=>Ka.find(u=>u.id===l)).filter(l=>!!l)}function Ye(l,u){let f=S.indexOf(l),m=f+u;if(f<0||m<0||m>=S.length)return;let b=[...S];b.splice(f,1),b.splice(m,0,l),S=b,vn(window.localStorage,S),Z()}function Ve(l,u){if(l===u)return;let f=S.indexOf(l),m=S.indexOf(u);if(f<0||m<0)return;let b=[...S];b.splice(f,1),b.splice(m,0,l),S=b,vn(window.localStorage,S),Z()}function oe(l){let u=l.status==="closed",f=d.has(l.sessionId)?"checked":"";return`<tr data-id="${i(l.sessionId)}">
|
|
188
188
|
<td><input type="checkbox" class="row-select" ${f} ${u?"disabled":""}></td>
|
|
189
189
|
<td>${i(ye(l))}</td>
|
|
190
190
|
<td><span class="badge cli-${Ya(l.cliId)}">${i(l.cliId??"unknown")}</span></td>
|
|
@@ -197,12 +197,12 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
197
197
|
<td>${Be(l.lastMessageAt)}</td>
|
|
198
198
|
<td>${l.adopt?'<span class="badge">adopt</span>':""}</td>
|
|
199
199
|
<td><button class="open" type="button">${t("sessions.details")}</button></td>
|
|
200
|
-
</tr>`}function Ue(l){if(l.scope!=="chat"||!l.feishuChatLink)return null;let u=t("sessions.openChat");return`<a class="card-act" href="${i(l.feishuChatLink)}" target="_blank" rel="noopener" title="${i(u)}" aria-label="${i(u)}">${
|
|
200
|
+
</tr>`}function Ue(l){if(l.scope!=="chat"||!l.feishuChatLink)return null;let u=t("sessions.openChat");return`<a class="card-act" href="${i(l.feishuChatLink)}" target="_blank" rel="noopener" title="${i(u)}" aria-label="${i(u)}">${Me.feishu}</a>`}function Oe(l){return l.agentAttention?.reason?l.agentAttention.reason:l.agentAttention?t("sessions.board.signalAgent"):l.pendingRepo?t("sessions.board.signalRepo"):l.tuiPromptActive?t("sessions.board.signalPrompt"):l.status==="limited"?t("sessions.board.signalLimited"):""}function x(l){let u=d.has(l.sessionId),f=ve(l.title)||l.sessionId,m=ye(l),b=nt(l),w=Dn(l),T=Oe(l),C=Va(l.workingDir);return`<article class="session-card${u?" selected":""}" data-id="${i(l.sessionId)}" aria-pressed="${u}">
|
|
201
201
|
<div class="session-card-top">
|
|
202
|
-
${fe({name:
|
|
202
|
+
${fe({name:m,larkAppId:l.larkAppId,size:"sm"})}
|
|
203
203
|
<div class="session-card-title">
|
|
204
204
|
<strong title="${i(String(l.title??f))}">${i(String(f).slice(0,72))}</strong>
|
|
205
|
-
<span>${i(
|
|
205
|
+
<span>${i(m)} \xB7 ${i(b??l.cliId??"unknown")}</span>
|
|
206
206
|
</div>
|
|
207
207
|
<span class="status status-${i(l.status??"unknown")}">${i(l.status??"unknown")}</span>
|
|
208
208
|
</div>
|
|
@@ -211,16 +211,16 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
211
211
|
${l.adopt?'<span class="badge">adopt</span>':""}
|
|
212
212
|
</div>`:""}
|
|
213
213
|
<div class="session-card-time">
|
|
214
|
-
<span>${l.agentAttention?.at?`${i(t("sessions.board.waiting"))} ${Be(
|
|
214
|
+
<span>${l.agentAttention?.at?`${i(t("sessions.board.waiting"))} ${Be(Ie(l))}`:`${i(t("sessions.last"))}: ${Be(l.lastMessageAt)}`}</span>
|
|
215
215
|
</div>
|
|
216
216
|
${T?`<div class="session-signal" title="${i(T)}">${i(T)}</div>`:""}
|
|
217
217
|
<div class="session-card-actions">
|
|
218
|
-
${Ue(l)??Rn("locate",
|
|
219
|
-
${Rn("details",
|
|
218
|
+
${Ue(l)??Rn("locate",Me.pin,t("sessions.locate"))}
|
|
219
|
+
${Rn("details",Me.details,t("sessions.details"))}
|
|
220
220
|
${Qa(w)}
|
|
221
|
-
${Rn("close",
|
|
221
|
+
${Rn("close",Me.close,t("sessions.close"),"danger")}
|
|
222
222
|
</div>
|
|
223
|
-
</article>`}function ie(l,u,f){let
|
|
223
|
+
</article>`}function ie(l,u,f){let m=f==="needs-you"?Ie(l):Number(l.lastMessageAt??0),b=f==="needs-you"?Ie(u):Number(u.lastMessageAt??0);return m!==b?f==="needs-you"?m-b:b-m:String(l.title??l.sessionId).localeCompare(String(u.title??u.sessionId))}function U(l){let u=new Map(Ka.map(b=>[b.id,[]]));for(let b of l){let w=Vs(b);w&&u.get(w).push(b)}let f=it(),m=f.map((b,w)=>{let T=(u.get(b.id)??[]).sort((C,q)=>ie(C,q,b.id));return`<section class="session-board-column session-board-${b.id}" data-col="${b.id}">
|
|
224
224
|
<header draggable="true" title="${i(t("sessions.board.dragHint"))}">
|
|
225
225
|
<div>
|
|
226
226
|
<h2>${i(t(b.labelKey))}</h2>
|
|
@@ -239,16 +239,16 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
239
239
|
<div class="session-board-list">
|
|
240
240
|
${T.length?T.map(x).join(""):`<div class="session-board-empty">${t("sessions.board.emptyColumn")}</div>`}
|
|
241
241
|
</div>
|
|
242
|
-
</section>`}).join("");
|
|
242
|
+
</section>`}).join("");m!==B&&(B=m,L.innerHTML=m,L.classList.toggle("board-enter",!Q),Q=!0)}function G(l){let u=ve(l.title)||l.sessionId,f=ye(l),m=nt(l),b=Va(l.workingDir),w=Oe(l),T=[m,b!=="-"?b:null].filter(Boolean).join(" \xB7 "),C=String(l.status??"unknown"),q=typeof l.remoteDeployment=="string"?l.remoteDeployment:"";return`<article class="kanban-card${q?" kanban-card-remote":""}" data-id="${i(l.sessionId)}" tabindex="0" role="button" draggable="true">
|
|
243
243
|
<div class="kanban-card-top">
|
|
244
244
|
<span class="badge cli-${Ya(l.cliId)}">${i(l.cliId??"unknown")}</span>
|
|
245
245
|
${l.adopt?'<span class="badge">adopt</span>':""}
|
|
246
246
|
${q?`<span class="badge kanban-remote-badge" title="${i(t("sessions.kanban.remoteHint",{name:q}))}">${i(q)}</span>`:""}
|
|
247
247
|
<span class="kanban-card-top-right">
|
|
248
248
|
<span class="kanban-card-dot" data-status="${i(C)}" title="${i(C)}"></span>
|
|
249
|
-
${q?"":`<button type="button" class="card-act kanban-card-act" data-action="history" title="${i(t("sessions.history.title"))}" aria-label="${i(t("sessions.history.title"))}">${
|
|
250
|
-
${l.feishuChatLink?`<a class="card-act kanban-card-act" href="${i(l.feishuChatLink)}" target="_blank" rel="noopener" title="${i(t("sessions.kanban.openFeishu"))}" aria-label="${i(t("sessions.kanban.openFeishu"))}">${
|
|
251
|
-
<button type="button" class="card-act kanban-card-act" data-action="details" title="${i(t("sessions.details"))}" aria-label="${i(t("sessions.details"))}">${
|
|
249
|
+
${q?"":`<button type="button" class="card-act kanban-card-act" data-action="history" title="${i(t("sessions.history.title"))}" aria-label="${i(t("sessions.history.title"))}">${Me.history}</button>
|
|
250
|
+
${l.feishuChatLink?`<a class="card-act kanban-card-act" href="${i(l.feishuChatLink)}" target="_blank" rel="noopener" title="${i(t("sessions.kanban.openFeishu"))}" aria-label="${i(t("sessions.kanban.openFeishu"))}">${Me.feishu}</a>`:""}
|
|
251
|
+
<button type="button" class="card-act kanban-card-act" data-action="details" title="${i(t("sessions.details"))}" aria-label="${i(t("sessions.details"))}">${Me.details}</button>`}
|
|
252
252
|
</span>
|
|
253
253
|
</div>
|
|
254
254
|
<p class="kanban-card-title" title="${i(String(l.title??u))}">${i(String(u).slice(0,140))}</p>
|
|
@@ -258,31 +258,31 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
258
258
|
<span class="kanban-card-owner">${fe({name:f,larkAppId:l.larkAppId,size:"sm"})}<span>${i(f)}</span></span>
|
|
259
259
|
<span class="kanban-card-updated">${i(t("sessions.kanban.updated",{time:Be(l.lastMessageAt)}))}</span>
|
|
260
260
|
</div>
|
|
261
|
-
</article>`}function he(l){let u=[],f=new Map;for(let w of l){let T=String(w.chatId??w.sessionId),C=f.get(T);C||(C={chatId:T,rows:[]},f.set(T,C),u.push(C)),C.rows.push(w)}let
|
|
261
|
+
</article>`}function he(l){let u=[],f=new Map;for(let w of l){let T=String(w.chatId??w.sessionId),C=f.get(T);C||(C={chatId:T,rows:[]},f.set(T,C),u.push(C)),C.rows.push(w)}let m=[];return{html:u.map(w=>{if(m.push(...w.rows),w.rows.length<2)return G(w.rows[0]);let T=nt(w.rows[0])??w.chatId;return`<div class="kanban-cluster" data-chat="${i(w.chatId)}">
|
|
262
262
|
<header draggable="true" title="${i(T)} \xB7 ${i(t("sessions.kanban.clusterDragHint"))}">
|
|
263
263
|
${Yt({chatId:w.chatId,name:T,size:"sm"})}
|
|
264
264
|
<span class="kanban-cluster-name">${i(T)}</span>
|
|
265
265
|
<span class="kanban-cluster-count">${w.rows.length}</span>
|
|
266
266
|
</header>
|
|
267
267
|
${w.rows.map(G).join("")}
|
|
268
|
-
</div>`}).join(""),flat:
|
|
268
|
+
</div>`}).join(""),flat:m}}function gt(l){let u=new Map;for(let m of l){if(m.status==="closed")continue;let b=String(m.larkAppId||m.botName||"unknown"),w=u.get(b);w||(w={name:ye(m),larkAppId:m.larkAppId,rows:[]},u.set(b,w)),w.rows.push(m)}let f=[...u.values()].sort((m,b)=>m.name.localeCompare(b.name));return f.length?f.map(m=>{let b=m.rows.sort((T,C)=>Number(C.lastMessageAt??0)-Number(T.lastMessageAt??0)),{html:w}=he(b);return`<section class="kanban-column kanban-bot-col" data-bot="${i(m.larkAppId??m.name)}">
|
|
269
269
|
<header>
|
|
270
|
-
<span class="kanban-col-avatar">${fe({name:
|
|
271
|
-
<h2>${i(
|
|
270
|
+
<span class="kanban-col-avatar">${fe({name:m.name,larkAppId:m.larkAppId,size:"sm"})}</span>
|
|
271
|
+
<h2>${i(m.name)}</h2>
|
|
272
272
|
<span class="kanban-col-count">${b.length}</span>
|
|
273
273
|
</header>
|
|
274
274
|
<div class="kanban-col-list">${w}</div>
|
|
275
|
-
</section>`}).join(""):`<div class="kanban-col-empty">${t("sessions.board.emptyColumn")}</div>`}function X(l){let u=new Map(Ja.map(
|
|
275
|
+
</section>`}).join(""):`<div class="kanban-col-empty">${t("sessions.board.emptyColumn")}</div>`}function X(l){let u=new Map(Ja.map(m=>[m.id,[]]));for(let m of l)u.get(za(m)).push(m);let f=Ja.map(m=>{let b=(u.get(m.id)??[]).sort((q,N)=>rt(q)-rt(N)),w=0;m.id==="done"&&b.length>An&&(w=b.length-An,b=b.slice(0,An));let{html:T,flat:C}=he(b);return u.set(m.id,C),`<section class="kanban-column kanban-${m.id}" data-col="${m.id}">
|
|
276
276
|
<header>
|
|
277
|
-
<span class="kanban-col-icon">${Ys(
|
|
278
|
-
<h2>${i(t(
|
|
277
|
+
<span class="kanban-col-icon">${Ys(m.id)}</span>
|
|
278
|
+
<h2>${i(t(m.labelKey))}</h2>
|
|
279
279
|
<span class="kanban-col-count">${b.length+w}</span>
|
|
280
280
|
</header>
|
|
281
281
|
<div class="kanban-col-list">
|
|
282
282
|
${b.length?T:`<div class="kanban-col-empty">${t("sessions.board.emptyColumn")}</div>`}
|
|
283
283
|
${w?`<div class="kanban-col-more">${i(t("sessions.kanban.moreHidden",{count:w}))}</div>`:""}
|
|
284
284
|
</div>
|
|
285
|
-
</section>`}).join("");return J=u,f}function z(l){if(le||
|
|
285
|
+
</section>`}).join("");return J=u,f}function z(l){if(le||Te||He)return;$.classList.toggle("kanban-mode-bot",se==="bot");let u;if(se==="bot")u=gt(l),J=new Map;else if(se==="team")if(!de)u=`<div class="kanban-loading">${t("sessions.kanban.teamLoading")}</div>`,J=new Map,R.dataset.loading||(R.dataset.loading="1",R.disabled=!0,R.innerHTML=`<option>${i(t("sessions.kanban.teamLoading"))}</option>`),be();else{let m=ee.find(N=>N.key===$e)??ee[0],b=[],w=new Set;if(m){for(let N of m.groupChats)w.add(N);if(ue)for(let[N,te]of ue){if(w.has(N))continue;let me=!1;for(let Fe of m.botIds)if(te.botIds.has(Fe)){me=!0;break}if(me){for(let Fe of te.observedNames)if(m.botNames.has(Fe)){w.add(N);break}}}b=l.filter(N=>w.has(String(N.chatId)))}m&&Ze(m);let T=(Ce===m?.key?re?.board:null)??{},C=(Ce===m?.key?re?.remoteRows:null)??[],q=[...b,...C].map(N=>{let te=T[N.sessionId];return te?{...N,kanbanColumn:te.column,kanbanPosition:te.position}:N});I.textContent=t("sessions.kanban.teamScope",{chats:w.size,sessions:q.length}),u=X(q)}else u=X(l);if(u===j)return;j=u;let f=new Map;$.querySelectorAll(".kanban-col-list").forEach(m=>{let b=m.closest(".kanban-column")?.dataset.col;b&&m.scrollTop&&f.set(b,m.scrollTop)}),$.innerHTML=u,f.size&&$.querySelectorAll(".kanban-col-list").forEach(m=>{let b=m.closest(".kanban-column")?.dataset.col,w=b?f.get(b):void 0;w&&(m.scrollTop=w)})}async function F(l,u,f,m){try{let b=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/board`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({column:u,position:f})}),w=await b.json().catch(()=>({}));(!b.ok||w?.ok===!1)&&(l.kanbanColumn=m.column,l.kanbanPosition=m.position,j="",Z(),b.status!==401&&alert(`${t("sessions.kanban.moveFail")}: ${w?.error??b.status}`))}catch(b){l.kanbanColumn=m.column,l.kanbanPosition=m.position,j="",Z(),alert(`${t("sessions.kanban.moveFail")}: ${b}`)}}async function K(l,u){let f=l.title;l.title=u,j="",Z();try{let m=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/rename`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({title:u})}),b=await m.json().catch(()=>({}));(!m.ok||b?.ok===!1)&&(l.title=f,j="",Z(),m.status!==401&&alert(`${t("sessions.kanban.renameFail")}: ${b?.error??m.status}`))}catch(m){l.title=f,j="",Z(),alert(`${t("sessions.kanban.renameFail")}: ${m}`)}}function W(l){if(l==null||l==="")return"";let u=Number(l),f=Number.isFinite(u)&&u>0?new Date(u):new Date(String(l));return Number.isNaN(f.getTime())?"":f.toLocaleString()}function Y(l,u,f){let m=u.senderType==="user",b=m?u.senderName||(f&&u.senderId===f?t("sessions.history.owner"):t("sessions.history.user")):ye(l),w=W(u.createTime),T=String(u.content??"").trim()||`[${u.msgType??"message"}]`,C=m?u.senderAvatar?`<img class="history-avatar-img" src="${i(String(u.senderAvatar))}" alt="" decoding="async" referrerpolicy="no-referrer">`:`<span class="history-avatar-user" aria-hidden="true">${i(String(b).slice(0,1))}</span>`:fe({name:ye(l),larkAppId:l.larkAppId,size:"sm"});return`<div class="history-msg${m?" mine":""}">
|
|
286
286
|
${C}
|
|
287
287
|
<div class="history-msg-main">
|
|
288
288
|
<div class="history-msg-meta"><span>${i(b)}</span><time>${i(w)}</time></div>
|
|
@@ -295,23 +295,23 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
295
295
|
<span class="history-scope-tag">${i(t("sessions.history.title"))}</span>
|
|
296
296
|
</span>
|
|
297
297
|
<span class="term-modal-actions">
|
|
298
|
-
<button type="button" id="history-close" class="card-act" title="${i(t("sessions.dismiss"))}" aria-label="${i(t("sessions.dismiss"))}">${
|
|
298
|
+
<button type="button" id="history-close" class="card-act" title="${i(t("sessions.dismiss"))}" aria-label="${i(t("sessions.dismiss"))}">${Me.close}</button>
|
|
299
299
|
</span>
|
|
300
300
|
</div>
|
|
301
|
-
<div class="history-body"><div class="term-modal-loading">${t("sessions.history.loading")}</div></div>`,O.showModal(),O.querySelector("#history-close").onclick=()=>O.close();try{let f=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/history?limit=80`),
|
|
301
|
+
<div class="history-body"><div class="term-modal-loading">${t("sessions.history.loading")}</div></div>`,O.showModal(),O.querySelector("#history-close").onclick=()=>O.close();try{let f=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/history?limit=80`),m=await f.json().catch(()=>({}));if(!O.open)return;let b=O.querySelector(".history-body");if(!f.ok||m?.ok===!1){let T=String(m?.error??f.status),C=T==="not_found_yet"||T==="not_found";b.innerHTML=`<div class="history-error">${i(t("sessions.history.fail"))}: ${i(T)}${C?`<br><span>${i(t("sessions.history.staleHint"))}</span>`:""}</div>`;return}let w=Array.isArray(m.messages)?m.messages:[];if(!w.length){b.innerHTML=`<div class="history-error">${t("sessions.history.empty")}</div>`;return}b.innerHTML=`<div class="history-list">${w.map(T=>Y(l,T,m.ownerOpenId)).join("")}</div>`,b.scrollTop=b.scrollHeight}catch(f){if(!O.open)return;let m=O.querySelector(".history-body");m&&(m.innerHTML=`<div class="history-error">${i(t("sessions.history.fail"))}: ${i(String(f))}</div>`)}}function Le(l,u){let f=l.querySelector(".kanban-card-title");if(!f||l.querySelector(".kanban-rename-input"))return;He=!0;let m=document.createElement("input");m.type="text",m.className="kanban-rename-input",m.maxLength=200,m.value=ve(u.title)||"",f.replaceWith(m),m.focus(),m.select();let b=!1,w=T=>{if(b)return;b=!0,He=!1;let C=m.value.trim();T&&C&&C!==(ve(u.title)||"")?K(u,C):(j="",Z())};m.addEventListener("keydown",T=>{T.stopPropagation(),T.key==="Enter"?(T.preventDefault(),w(!0)):T.key==="Escape"&&(T.preventDefault(),w(!1))}),m.addEventListener("blur",()=>w(!0)),m.addEventListener("click",T=>T.stopPropagation())}function tt(l,u){for(let f of l.querySelectorAll(".kanban-card:not(.dragging)")){if(f.closest(".kanban-cluster.dragging"))continue;let m=f.getBoundingClientRect();if(u<m.top+m.height/2)return f}return null}function oa(){$.querySelectorAll(".drag-over, .dragging, .drop-before").forEach(l=>l.classList.remove("drag-over","dragging","drop-before"))}function Xo(l){let u=g.querySelector(".term-modal-name");if(!u||g.querySelector(".term-modal-name-input"))return;let f=document.createElement("input");f.type="text",f.className="term-modal-name-input",f.maxLength=200,f.value=ve(l.title)||"",u.replaceWith(f);let m=()=>{let T=getComputedStyle(f),C=document.createElement("span");C.style.cssText="position:absolute;visibility:hidden;white-space:pre",C.style.fontSize=T.fontSize,C.style.fontFamily=T.fontFamily,C.style.fontWeight=T.fontWeight,C.style.letterSpacing=T.letterSpacing,C.textContent=f.value||" ",document.body.appendChild(C);let q=C.offsetWidth;C.remove();let N=Math.round(window.innerWidth*.6);f.style.width=`${Math.min(Math.max(q+22,80),N)}px`};m(),f.addEventListener("input",m),f.focus(),f.select();let b=!1,w=T=>{if(b)return;b=!0;let C=f.value.trim(),q=ve(l.title)||"";if(T&&C&&C!==q){l.title=C;let N=document.createElement("strong");N.className="term-modal-name",N.title=C,N.textContent=C.slice(0,60),f.replaceWith(N),K(l,C)}else{let N=document.createElement("strong");N.className="term-modal-name",N.title=String(l.title??q),N.textContent=q.slice(0,60),f.replaceWith(N)}};f.addEventListener("keydown",T=>{T.stopPropagation(),T.key==="Enter"?(T.preventDefault(),w(!0)):T.key==="Escape"&&(T.preventDefault(),w(!1))}),f.addEventListener("blur",()=>w(!0))}async function sa(l){let u=Dn(l);if(!u){qt(l);return}let f=ve(l.title)||l.sessionId,m=l.feishuChatLink?`<a class="card-act" href="${i(l.feishuChatLink)}" target="_blank" rel="noopener" title="${i(t("sessions.kanban.openFeishu"))}" aria-label="${i(t("sessions.kanban.openFeishu"))}">${Me.feishu}</a>`:"";g.innerHTML=`<div class="term-modal-head">
|
|
302
302
|
<span class="term-modal-title">
|
|
303
303
|
${fe({name:ye(l),larkAppId:l.larkAppId,size:"sm"})}
|
|
304
304
|
<strong class="term-modal-name" title="${i(String(l.title??f))}">${i(String(f).slice(0,60))}</strong>
|
|
305
|
-
<button type="button" id="term-modal-edit" class="card-act" title="${i(t("sessions.kanban.rename"))}" aria-label="${i(t("sessions.kanban.rename"))}">${
|
|
305
|
+
<button type="button" id="term-modal-edit" class="card-act" title="${i(t("sessions.kanban.rename"))}" aria-label="${i(t("sessions.kanban.rename"))}">${Me.edit}</button>
|
|
306
306
|
<span class="status status-${i(l.status??"unknown")}">${i(l.status??"unknown")}</span>
|
|
307
307
|
</span>
|
|
308
308
|
<span class="term-modal-actions">
|
|
309
|
-
${
|
|
310
|
-
<a id="term-modal-tab" class="card-act" href="${i(u)}" target="_blank" rel="noopener" title="${i(t("sessions.kanban.openTab"))}" aria-label="${i(t("sessions.kanban.openTab"))}">${
|
|
311
|
-
<button type="button" id="term-modal-close" class="card-act" title="${i(t("sessions.dismiss"))}" aria-label="${i(t("sessions.dismiss"))}">${
|
|
309
|
+
${m}
|
|
310
|
+
<a id="term-modal-tab" class="card-act" href="${i(u)}" target="_blank" rel="noopener" title="${i(t("sessions.kanban.openTab"))}" aria-label="${i(t("sessions.kanban.openTab"))}">${Me.terminal}</a>
|
|
311
|
+
<button type="button" id="term-modal-close" class="card-act" title="${i(t("sessions.dismiss"))}" aria-label="${i(t("sessions.dismiss"))}">${Me.close}</button>
|
|
312
312
|
</span>
|
|
313
313
|
</div>
|
|
314
|
-
<div class="term-modal-body"><div class="term-modal-loading">${t("sessions.kanban.terminalLoading")}</div></div>`,g.showModal(),g.querySelector("#term-modal-close").onclick=()=>g.close(),g.querySelector("#term-modal-edit").onclick=()=>Xo(l);let b=u;if(
|
|
314
|
+
<div class="term-modal-body"><div class="term-modal-loading">${t("sessions.kanban.terminalLoading")}</div></div>`,g.showModal(),g.querySelector("#term-modal-close").onclick=()=>g.close(),g.querySelector("#term-modal-edit").onclick=()=>Xo(l);let b=u;if(Se.authed)try{let C=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/write-link`),q=await C.json().catch(()=>({}));C.ok&&q?.ok!==!1&&q?.url&&(b=q.url)}catch{}if(!g.open)return;let w=g.querySelector(".term-modal-body");w.innerHTML=`<iframe class="term-modal-frame" src="${i(b)}" allow="clipboard-read; clipboard-write"></iframe>`;let T=g.querySelector("#term-modal-tab");T&&(T.href=b)}function Pt(){let l=new FormData(a),u=(l.get("q")??"").toLowerCase(),f=l.getAll("cli"),m=f.length>0&&f.length<Za.length,b=l.get("status"),w=l.get("adopt"),T=!!l.get("active"),C=M==="kanban",q=[...V.sessions.values()].filter(N=>!m||f.includes(N.cliId??"unknown")).filter(N=>!b||N.status===b).filter(N=>!w||w==="yes"==!!N.adopt).filter(N=>!T||C||N.status!=="closed").filter(N=>!u||JSON.stringify(N).toLowerCase().includes(u));return q.sort(Zo),q}function ia(l,u){return u==="spawnedAt"||u==="lastMessageAt"?Number(l[u]??0):u==="tokenIn"?On(l.tokenUsage?.in)??-1:u==="tokenOut"?On(l.tokenUsage?.out)??-1:u==="adopt"?!!l.adopt:String(l[u]??"").toLowerCase()}function Zo(l,u){let f=ia(l,y),m=ia(u,y),b=0;return typeof f=="number"&&typeof m=="number"?b=f-m:typeof f=="boolean"&&typeof m=="boolean"?b=Number(f)-Number(m):b=String(f).localeCompare(String(m)),b===0&&(b=Number(l.lastMessageAt??0)-Number(u.lastMessageAt??0)),H==="asc"?b:-b}function es(){v.querySelectorAll("th[data-sort]").forEach(l=>{let u=l.dataset.sort===y;l.classList.toggle("sorted",u),l.setAttribute("aria-sort",u?H==="asc"?"ascending":"descending":"none");let f=l.dataset.label??l.textContent?.trim()??"";l.textContent=u?`${f} ${H==="asc"?"\u25B2":"\u25BC"}`:f})}function mn(l){r.hidden=d.size===0,c.textContent=t("sessions.selectedCount",{count:d.size});let u=l.filter(m=>m.status!=="closed");if(u.length===0){o.checked=!1,o.indeterminate=!1,o.disabled=!0;return}o.disabled=!1;let f=u.filter(m=>d.has(m.sessionId)).length;o.checked=f===u.length,o.indeterminate=f>0&&f<u.length}function ts(){E.forEach(l=>{let u=l.dataset.view===M;l.classList.toggle("active",u),l.setAttribute("aria-pressed",String(u))}),D.hidden=M!=="kanban",R.hidden=!(M==="kanban"&&se==="team"),I.hidden=R.hidden||!de,D.querySelectorAll("[data-groupby]").forEach(l=>{let u=l.dataset.groupby===se;l.classList.toggle("active",u),l.setAttribute("aria-pressed",String(u))})}function ns(){let l=a.querySelector("#cli-filter-count");if(!l)return;let u=[...a.querySelectorAll('input[name="cli"]')],f=u.filter(m=>m.checked).length;l.textContent=f===u.length?t("common.all"):`${f}/${u.length}`,l.classList.toggle("cli-filter-active",f!==u.length)}function Z(){let l=Pt();for(let m of[...d]){let b=V.sessions.get(m);(!b||b.status==="closed")&&d.delete(m)}let u=l.filter(m=>m.status!=="closed"),f=M==="table"?l:u;if(v.hidden=M!=="table",L.hidden=M!=="board",$.hidden=M!=="kanban",M==="table"){let m=l.length?l.map(oe).join(""):`<tr><td colspan="12" class="empty">${t("sessions.empty")}</td></tr>`;m!==_&&(_=m,n.innerHTML=m)}else M==="kanban"?z(l):U(u);ts(),es(),ns(),mn(f)}async function ra(l,u){u&&(u.disabled=!0,u.textContent=t("sessions.locating"));try{let f=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/locate`,{method:"POST"}),m=await f.json();if(m.ok){if(!u)return;let b=30;u.textContent=t("sessions.cooldown",{seconds:b});let w=setInterval(()=>{b-=1,b<=0?(clearInterval(w),u.disabled=!1,u.textContent=t("sessions.locate")):u.textContent=t("sessions.cooldown",{seconds:b})},1e3)}else alert(`Locate failed: ${m.error??f.status}`),u&&(u.disabled=!1,u.textContent=t("sessions.locate"))}catch(f){alert(`Locate error: ${f}`),u&&(u.disabled=!1,u.textContent=t("sessions.locate"))}}async function la(l,u){if(!confirm(t("sessions.closeConfirm")))return!1;u&&(u.disabled=!0);try{let f=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/close`,{method:"POST"}),m=await f.json().catch(()=>({}));return!f.ok||m?.ok===!1?(f.status!==401&&alert(`Close failed: ${m?.error??f.status}`),!1):!0}catch(f){return alert(`Close error: ${f}`),!1}finally{u&&(u.disabled=!1)}}function qt(l){let u=l.status==="closed",f=Dn(l);s.innerHTML=`<article>
|
|
315
315
|
<header>
|
|
316
316
|
<h3>${i(ve(l.title)||l.sessionId)}</h3>
|
|
317
317
|
<span class="status status-${i(l.status??"unknown")}">${i(l.status??"unknown")}</span>
|
|
@@ -333,14 +333,14 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
333
333
|
</div>
|
|
334
334
|
<div id="land-area"></div>
|
|
335
335
|
<form method="dialog"><button>${t("sessions.dismiss")}</button></form>
|
|
336
|
-
</article>`,s.querySelectorAll("[data-copy]").forEach(te=>{te.onclick=()=>{navigator.clipboard.writeText(te.dataset.copy??""),te.textContent=t("sessions.copied"),setTimeout(()=>{te.textContent=t("sessions.copy")},800)}});let
|
|
336
|
+
</article>`,s.querySelectorAll("[data-copy]").forEach(te=>{te.onclick=()=>{navigator.clipboard.writeText(te.dataset.copy??""),te.textContent=t("sessions.copied"),setTimeout(()=>{te.textContent=t("sessions.copy")},800)}});let m=s.querySelector("#locate-btn");m&&(m.onclick=()=>{ra(l,m)});let b=s.querySelector("#history-drawer-btn");b&&(b.onclick=()=>{pe(l)});let w=s.querySelector(".term-write");w&&(w.onclick=()=>{Xa(l,w)});let T=s.querySelector("#resume-btn");T&&(T.onclick=async()=>{T.disabled=!0;try{let te=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/resume`,{method:"POST"}),me=await te.json().catch(()=>({}));if(!te.ok||me.ok===!1){alert(`${t("sessions.resumeFailed")}: ${me?.error??te.status}`),T.disabled=!1;return}s.close()}catch(te){alert(`${t("sessions.resumeFailed")}: ${te}`),T.disabled=!1}});let C=s.querySelector("#close-btn");C&&(C.onclick=async()=>{await la(l,C)&&s.close()});let q=s.querySelector("#land-btn"),N=s.querySelector("#land-area");q&&N&&(q.onclick=async()=>{q.disabled=!0,N.innerHTML=`<p>${t("sessions.landLoading")}</p>`;try{let te=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/sandbox-diff`),me=await te.json().catch(()=>({}));if(!me.ok){N.innerHTML=`<p>${t("sessions.landUnavailable")}: ${i(me.error??String(te.status))}</p>`,q.disabled=!1;return}if(me.empty){N.innerHTML=`<p>${t("sessions.landEmpty")}</p>`,q.disabled=!1;return}let Fe=String(me.patch??""),fn=Fe.slice(0,2e4)+(Fe.length>2e4?`
|
|
337
337
|
\u2026(truncated)`:"");N.innerHTML=`
|
|
338
338
|
<p><b>${me.files}</b> files (+${me.insertions}/-${me.deletions}) \u2192 <code>${i(String(me.workingDir??""))}</code></p>
|
|
339
339
|
<pre style="max-height:320px;overflow:auto;white-space:pre-wrap">${i(fn)}</pre>
|
|
340
340
|
<div class="actions">
|
|
341
341
|
<button id="land-apply" type="button" class="primary">${t("sessions.landApply")}</button>
|
|
342
342
|
<button id="land-discard" type="button" class="contrast">${t("sessions.landDiscard")}</button>
|
|
343
|
-
</div>`;let Ge=N.querySelector("#land-apply"),jt=N.querySelector("#land-discard");Ge.onclick=async()=>{Ge.disabled=!0,jt.disabled=!0;let Qe=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/sandbox-land/apply`,{method:"POST"}),
|
|
343
|
+
</div>`;let Ge=N.querySelector("#land-apply"),jt=N.querySelector("#land-discard");Ge.onclick=async()=>{Ge.disabled=!0,jt.disabled=!0;let Qe=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/sandbox-land/apply`,{method:"POST"}),De=await Qe.json().catch(()=>({}));N.innerHTML=De.ok?`<p>\u2705 ${t("sessions.landApplied")}: ${De.files} files (+${De.insertions}/-${De.deletions}) \u2192 <code>${i(String(De.workingDir??""))}</code></p>`:`<p>\u274C ${t("sessions.landFailed")}: ${i(De.error??String(Qe.status))}</p>`},jt.onclick=async()=>{await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/sandbox-land/discard`,{method:"POST"}),N.innerHTML=`<p>\u{1F5D1} ${t("sessions.landDiscarded")}</p>`}}catch(te){N.innerHTML=`<p>${t("sessions.landUnavailable")}: ${i(String(te))}</p>`,q.disabled=!1}}),s.showModal()}n.addEventListener("click",l=>{let u=l.target;if(u.classList.contains("row-select")){let w=u.closest("tr[data-id]");if(!w)return;u.checked?d.add(w.dataset.id):d.delete(w.dataset.id),mn(Pt());return}let f=u.closest("td");if(f&&f.querySelector(".row-select"))return;let m=u.closest("tr[data-id]");if(!m)return;let b=V.sessions.get(m.dataset.id);b&&qt(b)}),L.addEventListener("click",l=>{let u=l.target,f=u.closest("button[data-move-col]");if(f){Ye(f.dataset.moveCol,Number(f.dataset.dir));return}let m=u.closest(".session-card[data-id]");if(!m)return;let b=V.sessions.get(m.dataset.id);if(!b)return;let w=u.closest("button[data-action]");if(w){let T=w.dataset.action;T==="details"?qt(b):T==="write-link"?Xa(b,w):T==="locate"?ra(b,w):T==="close"&&la(b,w).then(C=>{C&&(d.delete(b.sessionId),Z())});return}u.closest("a, button, input, label")||(d.has(b.sessionId)?d.delete(b.sessionId):d.add(b.sessionId),m.classList.toggle("selected",d.has(b.sessionId)),m.setAttribute("aria-pressed",String(d.has(b.sessionId))),mn(Pt().filter(T=>T.status!=="closed")))}),L.addEventListener("dragstart",l=>{let f=l.target.closest(".session-board-column > header[draggable]")?.closest(".session-board-column");f?.dataset.col&&(A=f.dataset.col,f.classList.add("dragging"),l.dataTransfer&&(l.dataTransfer.effectAllowed="move",l.dataTransfer.setData("text/plain",A)))}),L.addEventListener("dragover",l=>{if(!A)return;l.preventDefault(),l.dataTransfer&&(l.dataTransfer.dropEffect="move");let u=l.target.closest(".session-board-column");L.querySelectorAll(".drag-over").forEach(f=>f.classList.remove("drag-over")),u&&u.dataset.col!==A&&u.classList.add("drag-over")}),L.addEventListener("drop",l=>{if(!A)return;l.preventDefault();let u=l.target.closest(".session-board-column"),f=A;A=null,u?.dataset.col&&Ve(f,u.dataset.col)}),L.addEventListener("dragend",()=>{A=null,L.querySelectorAll(".drag-over, .dragging").forEach(l=>l.classList.remove("drag-over","dragging"))}),E.forEach(l=>{l.addEventListener("click",()=>{let u=yn(l.dataset.view)??"board";u!==M&&(M=u,va(window.localStorage,M),Z())})}),D.querySelectorAll("[data-groupby]").forEach(l=>{l.addEventListener("click",()=>{let u=l.dataset.groupby,f=u==="bot"?"bot":u==="team"?"team":"flow";f!==se&&(se=f,Sa(window.localStorage,f),j="",Z())})}),R.addEventListener("change",()=>{$e=R.value;try{window.localStorage.setItem(kn,$e)}catch{}j="",Z()});function Ut(){ge!==null&&(clearTimeout(ge),ge=null)}$.addEventListener("click",l=>{let u=l.target,f=u.closest(".kanban-card[data-id]");if(!f)return;let m=V.sessions.get(f.dataset.id);if(!m)return;let b=u.closest("button[data-action]");if(b){b.dataset.action==="details"?qt(m):b.dataset.action==="rename"?Le(f,m):b.dataset.action==="history"&&pe(m);return}u.closest("a, button, input, label")||(Ut(),ge=setTimeout(()=>{ge=null,sa(m)},220))}),$.addEventListener("dblclick",l=>{let u=l.target,f=u.closest(".kanban-card-title"),m=u.closest(".kanban-card[data-id]");if(!f||!m)return;Ut();let b=V.sessions.get(m.dataset.id);b&&Le(m,b)}),$.addEventListener("keydown",l=>{if(l.key!=="Enter"&&l.key!==" ")return;let u=l.target;if(!u.classList?.contains("kanban-card"))return;l.preventDefault();let f=V.sessions.get(u.dataset.id);f&&sa(f)}),$.addEventListener("dragstart",l=>{if(se==="bot")return;let u=l.target,f=u.closest(".kanban-cluster > header[draggable]");if(f){let b=f.closest(".kanban-cluster"),w=b.closest(".kanban-column")?.dataset.col;if(!b.dataset.chat||!w)return;Ut(),Te=b.dataset.chat,Re=w,b.classList.add("dragging"),l.dataTransfer&&(l.dataTransfer.effectAllowed="move",l.dataTransfer.setData("text/plain",`cluster:${Te}`));return}let m=u.closest(".kanban-card[data-id]");m&&(Ut(),le=m.dataset.id,m.classList.add("dragging"),l.dataTransfer&&(l.dataTransfer.effectAllowed="move",l.dataTransfer.setData("text/plain",le)))}),$.addEventListener("dragover",l=>{if(!le&&!Te)return;l.preventDefault(),l.dataTransfer&&(l.dataTransfer.dropEffect="move");let u=l.target.closest(".kanban-column");$.querySelectorAll(".drag-over").forEach(f=>f.classList.remove("drag-over")),$.querySelectorAll(".drop-before").forEach(f=>f.classList.remove("drop-before")),u&&(u.classList.add("drag-over"),tt(u,l.clientY)?.classList.add("drop-before"))}),$.addEventListener("drop",l=>{let u=Te,f=Re,m=le;if(!m&&!u)return;l.preventDefault(),le=null,Te=null,Re=null,oa();let b=l.target.closest(".kanban-column"),w=b?.dataset.col;if(!b||!w)return;let T=tt(b,l.clientY);if(u&&f){let Ge=(J.get(f)??[]).filter(we=>String(we.chatId)===u).filter(we=>!(we.status==="closed"&&w!=="done"));if(!Ge.length)return;let jt=new Set(Ge.map(we=>we.sessionId)),Qe=(J.get(w)??[]).filter(we=>!jt.has(we.sessionId)),De=T?Qe.findIndex(we=>we.sessionId===T.dataset.id):Qe.length;De<0&&(De=Qe.length);let da=De>0?Qe[De-1]:null,ca=De<Qe.length?Qe[De]:null,os=Cn(da?rt(da):null,ca?rt(ca):null);Ge.forEach((we,ss)=>{let gn=os+ss*.001;if(se==="team")ft(String(we.sessionId),w,gn);else{let is={column:we.kanbanColumn,position:we.kanbanPosition};we.kanbanColumn=w,we.kanbanPosition=gn,F(we,w,gn,is)}}),j="",Z();return}let C=V.sessions.get(m)??je.get(m);if(!C||C.status==="closed"&&w!=="done")return;let q=(J.get(w)??[]).filter(Ge=>Ge.sessionId!==m),N=T?q.findIndex(Ge=>Ge.sessionId===T.dataset.id):q.length;N<0&&(N=q.length);let te=N>0?q[N-1]:null,me=N<q.length?q[N]:null,Fe=Cn(te?rt(te):null,me?rt(me):null);if(se==="team"){ft(String(C.sessionId),w,Fe),j="",Z();return}let fn={column:C.kanbanColumn,position:C.kanbanPosition};C.kanbanColumn=w,C.kanbanPosition=Fe,j="",Z(),F(C,w,Fe,fn)}),$.addEventListener("dragend",()=>{le=null,Te=null,Re=null,oa(),j="",Z()}),g.addEventListener("click",l=>{l.target===g&&g.close()}),g.addEventListener("close",()=>{g.innerHTML=""}),O.addEventListener("click",l=>{l.target===O&&O.close()}),O.addEventListener("close",()=>{O.innerHTML=""}),o.addEventListener("change",()=>{let l=Pt().filter(u=>u.status!=="closed");for(let u of l)o.checked?d.add(u.sessionId):d.delete(u.sessionId);Z()}),k.addEventListener("click",()=>{d.clear(),Z()}),p.addEventListener("click",async()=>{let l=[...d];if(l.length===0||!confirm(t("sessions.closeBulkConfirm",{count:l.length})))return;p.disabled=!0,k.disabled=!0;let u=p.textContent,f=0,m=0,b=[...l];p.textContent=`0/${l.length}`;async function w(){for(;b.length;){let T=b.shift();try{let C=await fetch(`/api/sessions/${encodeURIComponent(T)}/close`,{method:"POST"}),q=await C.json().catch(()=>({}));(!C.ok||q?.ok===!1)&&(m+=1)}catch{m+=1}finally{f+=1,p.textContent=`${f}/${l.length}`}}}await Promise.all(Array.from({length:Math.min(6,l.length)},()=>w())),p.textContent=u,p.disabled=!1,k.disabled=!1,d.clear(),Z(),m>0&&alert(`Failed: ${m}/${l.length}`)}),v.querySelectorAll("th[data-sort]").forEach(l=>{l.addEventListener("click",()=>{let u=l.dataset.sort;y===u?H=H==="asc"?"desc":"asc":(y=u,H=u==="spawnedAt"||u==="lastMessageAt"?"desc":"asc"),Z()})}),a.addEventListener("input",Z),V.on(Z);let as=setInterval(()=>{if(!document.body.contains($)){clearInterval(as);return}M==="kanban"&&se==="team"&&(j="",Z())},3e4);Z(),_e().then(Z)}function Zs(){return`<section class="page">
|
|
344
344
|
<div class="page-heading">
|
|
345
345
|
<div>
|
|
346
346
|
<p class="eyebrow">${t("nav.schedules")}</p>
|
|
@@ -365,7 +365,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
365
365
|
</tr></thead>
|
|
366
366
|
<tbody id="schedules-tbody"></tbody>
|
|
367
367
|
</table>
|
|
368
|
-
</section>`}function to(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function no(e){e.innerHTML=Zs();let n=e.querySelector("#schedules-tbody"),a=e.querySelector("#sched-filters");function s(){let r=new FormData(a),c=(r.get("q")??"").toLowerCase(),
|
|
368
|
+
</section>`}function to(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function no(e){e.innerHTML=Zs();let n=e.querySelector("#schedules-tbody"),a=e.querySelector("#sched-filters");function s(){let r=new FormData(a),c=(r.get("q")??"").toLowerCase(),p=r.get("kind"),k=!!r.get("enabled");return[...V.schedules.values()].filter(v=>!p||v.parsed?.kind===p).filter(v=>!k||v.enabled).filter(v=>!c||JSON.stringify(v).toLowerCase().includes(c)).sort((v,L)=>{if(v.enabled!==L.enabled)return v.enabled?-1:1;let $=v.nextRunAt?Date.parse(v.nextRunAt):1/0,g=L.nextRunAt?Date.parse(L.nextRunAt):1/0;return $-g})}function o(){n.innerHTML=s().map(r=>`<tr data-id="${i(r.id)}">
|
|
369
369
|
<td>${i(r.name??r.id)}</td>
|
|
370
370
|
<td>${i(r.botName??r.larkAppId??"-")}</td>
|
|
371
371
|
<td><code>${i(r.parsed?.display??"?")}</code></td>
|
|
@@ -377,7 +377,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
377
377
|
<button data-op="run" type="button">${t("schedules.runNow")}</button>
|
|
378
378
|
${r.enabled?`<button data-op="pause" type="button">${t("schedules.pause")}</button>`:`<button data-op="resume" type="button">${t("schedules.resume")}</button>`}
|
|
379
379
|
</td>
|
|
380
|
-
</tr>`).join("")||`<tr><td colspan="8" class="empty">${t("schedules.empty")}</td></tr>`}n.addEventListener("click",async r=>{let c=r.target.closest("button[data-op]");if(!c)return;let
|
|
380
|
+
</tr>`).join("")||`<tr><td colspan="8" class="empty">${t("schedules.empty")}</td></tr>`}n.addEventListener("click",async r=>{let c=r.target.closest("button[data-op]");if(!c)return;let p=c.closest("tr[data-id]");if(!p)return;let k=p.dataset.id,v=c.dataset.op;c.disabled=!0;let L=c.textContent;c.textContent="...";try{let $=await fetch(`/api/schedules/${encodeURIComponent(k)}/${v}`,{method:"POST"}),g=await $.json().catch(()=>({}));(!$.ok||g.ok===!1)&&alert(`Failed: ${$.status} ${g?.error??""}`.trim())}catch($){alert("Network error: "+$)}finally{c.disabled=!1,c.textContent=L}}),a.addEventListener("input",o),V.on(o),o()}var xe={chats:[],bots:[]};function ei(){return`<section class="page">
|
|
381
381
|
<div class="page-heading">
|
|
382
382
|
<div>
|
|
383
383
|
<p class="eyebrow">${t("nav.groups")}</p>
|
|
@@ -399,12 +399,12 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
399
399
|
</table>
|
|
400
400
|
</div>
|
|
401
401
|
<dialog id="g-drawer"></dialog>
|
|
402
|
-
</section>`}async function yt(){
|
|
402
|
+
</section>`}async function yt(){xe=await(await fetch("/api/groups")).json()}async function ti(){return(await fetch("/api/groups")).json()}function ni(e,n){if(n.size===0)return!0;let a=e?.memberBots??[];for(let s of n)if(!a.some(o=>o.larkAppId===s&&o.inChat))return!1;return!0}function ao(e,n){return e.filter(a=>!n||!n.has(a.larkAppId)).map(a=>`
|
|
403
403
|
<label class="checkbox-row">
|
|
404
404
|
<input type="checkbox" name="bot" value="${i(a.larkAppId)}">
|
|
405
405
|
${i(a.botName??a.larkAppId)} <small>(${i(a.larkAppId)})</small>
|
|
406
406
|
</label>
|
|
407
|
-
`).join("")}async function oo(e){e.innerHTML=ei();let n=e.querySelector("#g-head"),a=e.querySelector("#g-body"),s=e.querySelector("#g-filters"),o=e.querySelector("#g-refresh"),r=e.querySelector("#g-drawer");o.onclick=async()=>{o.disabled=!0;try{await yt(),g()}finally{o.disabled=!1}};let c=e.querySelector("#g-create");c.onclick=()=>v();let
|
|
407
|
+
`).join("")}async function oo(e){e.innerHTML=ei();let n=e.querySelector("#g-head"),a=e.querySelector("#g-body"),s=e.querySelector("#g-filters"),o=e.querySelector("#g-refresh"),r=e.querySelector("#g-drawer");o.onclick=async()=>{o.disabled=!0;try{await yt(),g()}finally{o.disabled=!1}};let c=e.querySelector("#g-create");c.onclick=()=>v();let p=e.querySelector("#g-loading"),k=e.querySelector("#g-table-wrap");try{await yt()}finally{p.remove(),k.hidden=!1}function v(){let D=xe.bots;if(D.length===0){alert(t("groups.noBotsOnline"));return}r.innerHTML=`
|
|
408
408
|
<article>
|
|
409
409
|
<header><h3>${t("groups.createTitle")}</h3></header>
|
|
410
410
|
<p>${t("groups.createHelp")}</p>
|
|
@@ -427,12 +427,12 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
427
427
|
<button type="button" id="g-create-cancel">${t("groups.cancel")}</button>
|
|
428
428
|
</div>
|
|
429
429
|
</form>
|
|
430
|
-
</article>`,r.showModal(),r.querySelector("#g-create-cancel").onclick=()=>r.close(),r.querySelector("#g-createform").onsubmit=async E=>{E.preventDefault();let d=new FormData(E.target),y=(d.get("name")??"").trim(),H=(d.get("bindWorkingDir")??"").trim(),M=d.getAll("bot");if(M.length===0){alert("Pick at least one bot.");return}let S=E.target.querySelector("button[type=submit]");S&&(S.disabled=!0,S.textContent="Creating...");try{let A=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:y||void 0,larkAppIds:M,bindWorkingDir:H||void 0})}),B=await A.json();if(B.ok&&B.chatId){L(B);let _=Array.isArray(B.invalidBotIds)?B.invalidBotIds:[],j=M.filter(le=>!_.includes(le)),Q=new Set(j);typeof B.creator=="string"&&B.creator&&Q.add(B.creator),R(B.chatId,y||B.chatId,j,B.creator),g(),I(B.chatId,Q).catch(()=>{})}else alert(`Failed: ${B.error??A.status}`),r.close()}catch(A){alert("Network error: "+A),r.close()}};function R(E,d,y,H){let M=new Set(y);H&&M.add(H);let S=
|
|
430
|
+
</article>`,r.showModal(),r.querySelector("#g-create-cancel").onclick=()=>r.close(),r.querySelector("#g-createform").onsubmit=async E=>{E.preventDefault();let d=new FormData(E.target),y=(d.get("name")??"").trim(),H=(d.get("bindWorkingDir")??"").trim(),M=d.getAll("bot");if(M.length===0){alert("Pick at least one bot.");return}let S=E.target.querySelector("button[type=submit]");S&&(S.disabled=!0,S.textContent="Creating...");try{let A=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:y||void 0,larkAppIds:M,bindWorkingDir:H||void 0})}),B=await A.json();if(B.ok&&B.chatId){L(B);let _=Array.isArray(B.invalidBotIds)?B.invalidBotIds:[],j=M.filter(le=>!_.includes(le)),Q=new Set(j);typeof B.creator=="string"&&B.creator&&Q.add(B.creator),R(B.chatId,y||B.chatId,j,B.creator),g(),I(B.chatId,Q).catch(()=>{})}else alert(`Failed: ${B.error??A.status}`),r.close()}catch(A){alert("Network error: "+A),r.close()}};function R(E,d,y,H){let M=new Set(y);H&&M.add(H);let S=xe.bots.map(B=>({larkAppId:B.larkAppId,botName:B.botName,inChat:M.has(B.larkAppId),oncallChat:null})),A={chatId:E,name:d,ownerId:H??null,memberBots:S};xe.chats=[A,...xe.chats.filter(B=>B.chatId!==E)]}async function I(E,d){let y=[600,1200,1200,1200,1200,1200];for(let H of y){await new Promise(A=>setTimeout(A,H));let M;try{M=await ti()}catch{continue}let S=(M.chats??[]).find(A=>A.chatId===E);if(S&&ni(S,d)){xe=M,g();return}}}}function L(D){let R=String(D.chatId),I=typeof D.shareLink=="string"&&D.shareLink?D.shareLink:`https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(R)}`,E=D.invalidBotIds??[],d=D.invalidUserIds??[],y=D.autoInvitedOpenId,H=!!D.autoInviteRejected,M=D.ownerTransferredTo,S=D.transferError,A=D.notifyMessageId,B=D.notifyError,_=Array.isArray(D.oncallBindings)?D.oncallBindings:[],j=_.filter(J=>J?.ok).length,Q=_.filter(J=>!J?.ok),le=_.length>0?Q.length===0?`<p class="hint-ok">\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1A<code>${i(D.bindResolvedPath??"")}</code>\uFF08${j}/${_.length} bots\uFF09</p>`:`<p class="hint-warn">\u76EE\u5F55\u7ED1\u5B9A\u90E8\u5206\u5931\u8D25\uFF1A\u6210\u529F ${j}/${_.length}\u3002${Q.map(J=>`<br><code>${i(J.larkAppId??"?")}</code>: ${i(J.error??"unknown")}`).join("")}</p>`:"",He;if(y){let J=M?"<br><small>\u7FA4\u4E3B\u5DF2\u4ECE\u673A\u5668\u4EBA\u8F6C\u8BA9\u7ED9\u4F60\u3002</small>":S?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08${i(S)}\uFF09\uFF0C\u4F60\u73B0\u5728\u662F\u6210\u5458\u4F46\u7FA4\u4E3B\u4ECD\u662F\u673A\u5668\u4EBA\u3002</small>`:"",se=A?`<br><small>\u673A\u5668\u4EBA\u5DF2\u5728\u7FA4\u91CC @ \u4E86\u4F60\uFF08\u6D88\u606F id <code>${i(A)}</code>\uFF09\uFF0C\u770B\u98DE\u4E66\u901A\u77E5\u5C31\u80FD\u8FDB\u7FA4\u3002</small>`:B?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8 @ \u901A\u77E5\u5931\u8D25\uFF08${i(B)}\uFF09\uFF0C\u65B0\u7FA4\u53EF\u80FD\u4E0D\u4F1A\u4E3B\u52A8\u51FA\u73B0\u5728\u4F60\u4FA7\u8FB9\u680F\uFF0C\u5EFA\u8BAE\u4ECE\u4E0B\u9762\u6309\u94AE\u8DF3\u8FDB\u53BB\u3002</small>`:"";He=`<p class="hint-ok">\u5DF2\u81EA\u52A8\u9080\u8BF7\u4F60\uFF08<code>${i(y)}</code>\uFF09\u4F5C\u4E3A\u6210\u5458\u3002${J}${se}</p>`}else H?He='<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>':He='<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 ge=[E.length?`<li>\u65E0\u6548 bot id: <code>${E.map(i).join(", ")}</code></li>`:"",d.length?`<li>\u65E0\u6548\u7528\u6237 open_id: <code>${d.map(i).join(", ")}</code></li>`:""].filter(Boolean).join("");r.innerHTML=`
|
|
431
431
|
<article>
|
|
432
432
|
<header><h3>${t("groups.successTitle")}</h3></header>
|
|
433
433
|
<p><b>chatId:</b> <code>${i(R)}</code> <button type="button" data-copy="${i(R)}">${t("sessions.copy")}</button></p>
|
|
434
434
|
<p><b>\u521B\u5EFA\u8005:</b> <code>${i(D.creator??"?")}</code></p>
|
|
435
|
-
${
|
|
435
|
+
${He}
|
|
436
436
|
${le}
|
|
437
437
|
${ge?`<ul>${ge}</ul>`:""}
|
|
438
438
|
<div class="actions">
|
|
@@ -441,9 +441,9 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
441
441
|
</div>
|
|
442
442
|
</article>`,r.querySelectorAll("[data-copy]").forEach(J=>{J.onclick=()=>{navigator.clipboard.writeText(J.dataset.copy??""),J.textContent=t("sessions.copied"),setTimeout(()=>{J.textContent=t("sessions.copy")},800)}}),r.querySelector("#g-create-close").onclick=()=>r.close()}function $(){n.innerHTML=`<tr>
|
|
443
443
|
<th>${t("groups.chat")}</th>
|
|
444
|
-
${
|
|
444
|
+
${xe.bots.map(D=>`<th>${i(D.botName??D.larkAppId)}</th>`).join("")}
|
|
445
445
|
<th>${t("groups.actions")}</th>
|
|
446
|
-
</tr>`}function g(){$();let D=new FormData(s),R=(D.get("q")??"").toLowerCase(),I=!!D.get("missing"),E=
|
|
446
|
+
</tr>`}function g(){$();let D=new FormData(s),R=(D.get("q")??"").toLowerCase(),I=!!D.get("missing"),E=xe.chats.filter(d=>!R||(d.name??"").toLowerCase().includes(R)||d.chatId.toLowerCase().includes(R)||(d.ownerId??"").toLowerCase().includes(R)).filter(d=>!I||d.memberBots.some(y=>!y.inChat));if(E.length===0){a.innerHTML=`<tr><td colspan="${xe.bots.length+2}" class="empty">${t("groups.empty")}</td></tr>`;return}a.innerHTML=E.map(d=>`<tr data-chat="${i(d.chatId)}">
|
|
447
447
|
<td>
|
|
448
448
|
<div class="g-chat-cell">
|
|
449
449
|
${Yt({chatId:d.chatId,name:d.name,avatarUrl:d.avatar,size:"sm"})}
|
|
@@ -453,24 +453,24 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
453
453
|
</div>
|
|
454
454
|
</div>
|
|
455
455
|
</td>
|
|
456
|
-
${
|
|
456
|
+
${xe.bots.map(y=>{let H=d.memberBots.find(A=>A.larkAppId===y.larkAppId),M=H?H.error?"!":H.inChat?"\u2713":"\u2717":"?";return`<td class="${H?H.error?"cell-error":H.inChat?"cell-in":"cell-out":"cell-unknown"}" title="${i(H?.error??"")}">${M}</td>`}).join("")}
|
|
457
457
|
<td>
|
|
458
458
|
<button class="add-bots" type="button">${t("groups.addBots")}</button>
|
|
459
459
|
<button class="manage-chat" type="button">${t("groups.manage")}</button>
|
|
460
460
|
</td>
|
|
461
|
-
</tr>`).join("")}g(),a.addEventListener("click",async D=>{let R=D.target.closest("button.add-bots");if(!R)return;let E=R.closest("tr[data-chat]").dataset.chat,d=
|
|
461
|
+
</tr>`).join("")}g(),a.addEventListener("click",async D=>{let R=D.target.closest("button.add-bots");if(!R)return;let E=R.closest("tr[data-chat]").dataset.chat,d=xe.chats.find(M=>M.chatId===E);if(!d)return;let y=new Set(d.memberBots.filter(M=>M.inChat).map(M=>M.larkAppId));if(!xe.bots.filter(M=>!y.has(M.larkAppId)).length){alert("All configured bots are already in this chat.");return}r.innerHTML=`
|
|
462
462
|
<article>
|
|
463
463
|
<header><h3>${t("groups.addBots")} \xB7 ${i(d.name??d.chatId)}</h3></header>
|
|
464
464
|
<p>${t("groups.createHelp")}</p>
|
|
465
465
|
<form id="g-addform">
|
|
466
|
-
${ao(
|
|
466
|
+
${ao(xe.bots,y)}
|
|
467
467
|
<div class="actions">
|
|
468
468
|
<button type="submit" class="primary">${t("groups.addBots")}</button>
|
|
469
469
|
<button type="button" id="g-cancel">${t("groups.cancel")}</button>
|
|
470
470
|
</div>
|
|
471
471
|
</form>
|
|
472
472
|
</article>`,r.showModal(),r.querySelector("#g-cancel").onclick=()=>r.close(),r.querySelector("#g-addform").onsubmit=async M=>{M.preventDefault();let A=new FormData(M.target).getAll("bot");if(A.length===0){alert("Pick at least one bot.");return}try{let _=await(await fetch(`/api/groups/${encodeURIComponent(E)}/add-bots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:A})})).json();if(_.error==="no_proxy_bot")alert("No bot is currently in this chat \u2014 add one manually in Feishu first, then retry.");else if(_.result){let j=_.result.map(Q=>`${Q.id}: ${Q.ok?"OK":`failed (${Q.error??"unknown"})`}`).join(`
|
|
473
|
-
`);alert(j),await yt(),g()}else alert(`Unexpected response: ${JSON.stringify(_)}`)}catch(B){alert("Network error: "+B)}finally{r.close()}}}),a.addEventListener("click",async D=>{let R=D.target.closest("button.manage-chat");if(!R)return;let E=R.closest("tr[data-chat]").dataset.chat,d=
|
|
473
|
+
`);alert(j),await yt(),g()}else alert(`Unexpected response: ${JSON.stringify(_)}`)}catch(B){alert("Network error: "+B)}finally{r.close()}}}),a.addEventListener("click",async D=>{let R=D.target.closest("button.manage-chat");if(!R)return;let E=R.closest("tr[data-chat]").dataset.chat,d=xe.chats.find(y=>y.chatId===E);d&&O(d)});function O(D){let R=D.memberBots.filter(E=>E.inChat),I=typeof D.ownerId=="string"?D.ownerId:"";r.innerHTML=`
|
|
474
474
|
<article>
|
|
475
475
|
<header><h3>${t("groups.manageTitle",{name:D.name??D.chatId})}</h3></header>
|
|
476
476
|
<p><b>chatId:</b> <code>${i(D.chatId)}</code></p>
|
|
@@ -536,14 +536,14 @@ ${d.join(`
|
|
|
536
536
|
<aside id="bd-roster" class="bd-roster"></aside>
|
|
537
537
|
<div id="bd-list" class="bd-detail"></div>
|
|
538
538
|
</div>
|
|
539
|
-
</section>`}async function io(){try{let e=await fetch("/api/bots"),n=await e.json().catch(()=>({}));if(!e.ok){kt=n?.error?`HTTP ${e.status}: ${n.error}${n.path?` (${n.path})`:""}`:`HTTP ${e.status}`,Ne={bots:[]};return}if(!n||!Array.isArray(n.bots)){kt="unexpected response shape (no `bots` array)",Ne={bots:[]};return}kt=null,Ne=n}catch(e){kt=e?.message??String(e),Ne={bots:[]}}}function ro(e){if(!e)return"\u2014";let n=new Date(e);return Number.isNaN(n.getTime())?"\u2014":n.toLocaleString()}async function lo(e){e.innerHTML=ai();let n=e.querySelector("#bd-list"),a=e.querySelector("#bd-roster"),s=e.querySelector("#bd-filters"),o=e.querySelector("#bd-refresh");o.onclick=async()=>{o.disabled=!0;try{await io(),r()}finally{o.disabled=!1}},n.addEventListener("click",d=>{let y=d.target.closest(".toggle-tx small, small.bd-help");y&&(d.preventDefault(),y.classList.toggle("open"))}),n.innerHTML=wt(),await io();function r(){let y=(new FormData(s).get("q")??"").toLowerCase(),H=Ne.bots.filter(S=>!y||(S.botName??"").toLowerCase().includes(y)||(S.larkAppId??"").toLowerCase().includes(y));if(kt){a.innerHTML="",n.innerHTML=`<p class="hint-warn">\u65E0\u6CD5\u52A0\u8F7D bot \u5217\u8868\uFF1A${i(kt)}<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(H.length===0){a.innerHTML="",n.innerHTML=`<p class="empty">${t("botDefaults.empty")}</p>`;return}(!vt||!H.some(S=>S.larkAppId===vt))&&(vt=H[0].larkAppId),a.innerHTML=H.map(c).join(""),a.querySelectorAll(".bd-roster-item").forEach(S=>{S.onclick=()=>{vt=S.dataset.appid,r()}});let M=H.find(S=>S.larkAppId===vt);n.innerHTML=
|
|
539
|
+
</section>`}async function io(){try{let e=await fetch("/api/bots"),n=await e.json().catch(()=>({}));if(!e.ok){kt=n?.error?`HTTP ${e.status}: ${n.error}${n.path?` (${n.path})`:""}`:`HTTP ${e.status}`,Ne={bots:[]};return}if(!n||!Array.isArray(n.bots)){kt="unexpected response shape (no `bots` array)",Ne={bots:[]};return}kt=null,Ne=n}catch(e){kt=e?.message??String(e),Ne={bots:[]}}}function ro(e){if(!e)return"\u2014";let n=new Date(e);return Number.isNaN(n.getTime())?"\u2014":n.toLocaleString()}async function lo(e){e.innerHTML=ai();let n=e.querySelector("#bd-list"),a=e.querySelector("#bd-roster"),s=e.querySelector("#bd-filters"),o=e.querySelector("#bd-refresh");o.onclick=async()=>{o.disabled=!0;try{await io(),r()}finally{o.disabled=!1}},n.addEventListener("click",d=>{let y=d.target.closest(".toggle-tx small, small.bd-help");y&&(d.preventDefault(),y.classList.toggle("open"))}),n.innerHTML=wt(),await io();function r(){let y=(new FormData(s).get("q")??"").toLowerCase(),H=Ne.bots.filter(S=>!y||(S.botName??"").toLowerCase().includes(y)||(S.larkAppId??"").toLowerCase().includes(y));if(kt){a.innerHTML="",n.innerHTML=`<p class="hint-warn">\u65E0\u6CD5\u52A0\u8F7D bot \u5217\u8868\uFF1A${i(kt)}<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(H.length===0){a.innerHTML="",n.innerHTML=`<p class="empty">${t("botDefaults.empty")}</p>`;return}(!vt||!H.some(S=>S.larkAppId===vt))&&(vt=H[0].larkAppId),a.innerHTML=H.map(c).join(""),a.querySelectorAll(".bd-roster-item").forEach(S=>{S.onclick=()=>{vt=S.dataset.appid,r()}});let M=H.find(S=>S.larkAppId===vt);n.innerHTML=p(M),E()}function c(d){let y=d.botName??d.larkAppId,H=so(d.larkAppId),M=d.defaultOncall?.enabled?'<span class="bd-roster-flag">oncall</span>':"";return`<div class="bd-roster-item${d.larkAppId===vt?" on":""}" data-appid="${i(d.larkAppId)}" role="button" tabindex="0">
|
|
540
540
|
${fe({name:y,larkAppId:d.larkAppId,size:"sm"})}
|
|
541
541
|
<div class="bd-roster-tx">
|
|
542
542
|
<b>${i(y)}</b>
|
|
543
543
|
<span>${i(H||d.larkAppId.slice(0,14))}</span>
|
|
544
544
|
</div>
|
|
545
545
|
${M}
|
|
546
|
-
</div>`}function
|
|
546
|
+
</div>`}function p(d){if(d.error)return`<article class="bd-card bd-profile" data-appid="${i(d.larkAppId)}">
|
|
547
547
|
<header class="bd-profile-head">
|
|
548
548
|
${fe({name:d.botName??d.larkAppId,larkAppId:d.larkAppId})}
|
|
549
549
|
<div class="bd-profile-id"><strong>${i(d.botName??d.larkAppId)}</strong>
|
|
@@ -750,7 +750,7 @@ ${d.join(`
|
|
|
750
750
|
<div class="actions">
|
|
751
751
|
<span class="oncall-status" data-auto-start-status></span>
|
|
752
752
|
</div>
|
|
753
|
-
</div>`}function E(){n.querySelectorAll(".bd-card").forEach(d=>{let y=d.dataset.appid,H=d.querySelector("input[data-action=toggle]"),M=d.querySelector("input[data-input=workingDir]"),S=d.querySelector("button[data-action=save]"),A=d.querySelector("[data-status]");if(!H||!M||!S||!A)return;H.addEventListener("change",()=>{M.disabled=!H.checked,H.checked&&M.focus()}),S.addEventListener("click",async()=>{A.textContent="",A.className="oncall-status";let X=H.checked,z=M.value.trim();if(X&&!z){A.textContent=t("botDefaults.required"),A.classList.add("hint-warn-inline");return}S.disabled=!0;try{let F=await fetch(`/api/bots/${encodeURIComponent(y)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:X,workingDir:z})}),K=await F.json().catch(()=>({}));if(F.ok&&K.ok){let W=K.resolvedPath?` \u2192 ${K.resolvedPath}`:"";A.textContent=X?`\u2713 \u5DF2\u5F00\u542F${W}\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",A.classList.add("hint-ok");let Y=Ne.bots.find(Te=>Te.larkAppId===y);Y&&K.defaultOncall&&(Y.defaultOncall=K.defaultOncall);let pe=d.querySelector("[data-oncall-since]");pe&&K.defaultOncall?.since!=null&&(pe.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${ro(K.defaultOncall.since)}`)}else A.textContent=`\u2717 ${K.error??F.status}`,A.classList.add("hint-warn-inline")}catch(F){A.textContent=`\u2717 ${F?.message??F}`,A.classList.add("hint-warn-inline")}finally{S.disabled=!1}});let B=d.querySelector("input[data-input=brandLabel]"),_=d.querySelector("button[data-action=save-brand]"),j=d.querySelector("button[data-action=reset-brand]"),Q=d.querySelector("[data-brand-status]"),le=d.querySelector("[data-brand-state]");async function Ee(X,z){if(Q){Q.textContent="",Q.className="oncall-status",z.disabled=!0;try{let F=await fetch(`/api/bots/${encodeURIComponent(y)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:X})}),K=await F.json().catch(()=>({}));if(F.ok&&K.ok){let W=K.brandLabel??null;Q.textContent="\u2713",Q.classList.add("hint-ok"),B&&(B.value=W??""),le&&(le.textContent=v(W));let Y=Ne.bots.find(pe=>pe.larkAppId===y);Y&&(Y.brandLabel=W)}else Q.textContent=`\u2717 ${K.error??F.status}`,Q.classList.add("hint-warn-inline")}catch(F){Q.textContent=`\u2717 ${F?.message??F}`,Q.classList.add("hint-warn-inline")}finally{z.disabled=!1}}}B&&_&&_.addEventListener("click",()=>Ee(B.value,_)),j&&j.addEventListener("click",()=>Ee(null,j));let ge=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]"),Se=d.querySelector("[data-card-pref-status]"),Re=d.querySelector("[data-card-pref-moot]");async function ee(X,z,F=Se){if(F){F.textContent="",F.className="oncall-status",z.disabled=!0;try{let K=await fetch(`/api/bots/${encodeURIComponent(y)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(X)}),W=await K.json().catch(()=>({}));if(K.ok&&W.ok){F.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,F.classList.add("hint-ok");let Y=Ne.bots.find(pe=>pe.larkAppId===y);Y&&(Y.disableStreamingCard=W.disableStreamingCard,Y.writableTerminalLinkInCard=W.writableTerminalLinkInCard,Y.privateCard=W.privateCard,Y.autoStartOnGroupJoin=W.autoStartOnGroupJoin,Y.autoStartOnGroupJoinPrompt=W.autoStartOnGroupJoinPrompt,Y.autoStartOnNewTopic=W.autoStartOnNewTopic,Y.regularGroupReplyMode=W.regularGroupReplyMode,Y.regularGroupMentionMode=W.regularGroupMentionMode)}else F.textContent=`\u2717 ${W.error??K.status}`,F.classList.add("hint-warn-inline")}catch(K){F.textContent=`\u2717 ${K?.message??K}`,F.classList.add("hint-warn-inline")}finally{z===J?z.disabled=!!ge?.checked:z.disabled=!1}}}ge&&ge.addEventListener("change",()=>{let X=ge.checked;J&&(J.disabled=X),Re&&(Re.hidden=!X),ee({disableStreamingCard:X},ge)}),J&&J.addEventListener("change",()=>{ee({writableTerminalLinkInCard:J.checked},J)}),se&&se.addEventListener("change",()=>{ee({privateCard:se.checked},se)});let ue=d.querySelector("input[data-action=toggle-sandbox]"),de=d.querySelector("[data-sandbox-status]");ue&&ue.addEventListener("change",async()=>{let X=ue.checked;de&&(de.textContent="",de.className="oncall-status"),ue.disabled=!0;try{let z=await fetch(`/api/bots/${encodeURIComponent(y)}/sandbox`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:X})}),F=await z.json().catch(()=>({}));if(z.ok&&F.ok){de&&(de.textContent=`\u2713 ${t("botDefaults.sandboxSaved")}`,de.classList.add("hint-ok"));let K=Ne.bots.find(W=>W.larkAppId===y);K&&(K.sandbox=F.sandbox===!0)}else de&&(de.textContent=`\u2717 ${F.error??z.status}`,de.classList.add("hint-warn-inline")),ue.checked=!X}catch(z){de&&(de.textContent=`\u2717 ${z?.message??z}`,de.classList.add("hint-warn-inline")),ue.checked=!X}finally{ue.disabled=!1}});let qe=d.querySelector("input[data-action=toggle-auto-join]"),ke=d.querySelector("input[data-action=toggle-auto-topic]"),be=d.querySelector("textarea[data-input=autoJoinPrompt]"),re=d.querySelector("button[data-action=save-auto-join-prompt]"),He=d.querySelector("[data-auto-start-status]");qe&&qe.addEventListener("change",()=>{ee({autoStartOnGroupJoin:qe.checked},qe,He)}),ke&&ke.addEventListener("change",()=>{ee({autoStartOnNewTopic:ke.checked},ke,He)}),be&&re&&re.addEventListener("click",()=>{ee({autoStartOnGroupJoinPrompt:be.value},re,He)});let Ce=d.querySelector("select[data-input=p2pMode]"),ce=d.querySelector("[data-p2p-status]");Ce&&ce&&Ce.addEventListener("change",async()=>{let X=Ce.value==="chat"?"chat":"thread";ce.textContent="",ce.className="oncall-status",Ce.disabled=!0;try{let z=await fetch(`/api/bots/${encodeURIComponent(y)}/p2p-mode`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({p2pMode:X})}),F=await z.json().catch(()=>({}));if(z.ok&&F.ok){ce.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,ce.classList.add("hint-ok");let K=Ne.bots.find(W=>W.larkAppId===y);K&&(K.p2pMode=F.p2pMode==="chat"?"chat":"thread")}else ce.textContent=`\u2717 ${F.error??z.status}`,ce.classList.add("hint-warn-inline")}catch(z){ce.textContent=`\u2717 ${z?.message??z}`,ce.classList.add("hint-warn-inline")}finally{Ce.disabled=!1}});let je=d.querySelector("select[data-input=regularGroupMode]"),Ze=d.querySelector("[data-regular-group-status]");je&&je.addEventListener("change",()=>{ee({regularGroupReplyMode:je.value},je,Ze)});let et=d.querySelector("select[data-input=regularGroupMentionMode]"),ft=d.querySelector("[data-mention-mode-status]");et&&et.addEventListener("change",()=>{ee({regularGroupMentionMode:et.value},et,ft)});let it=d.querySelector("textarea[data-input=teamRole]"),Ye=d.querySelector("button[data-action=save-role]"),Ve=d.querySelector("button[data-action=delete-role]"),oe=d.querySelector("[data-role-status]");if(it&&Ye&&Ve&&oe){let F=function(W){let Y=n.querySelector(`.bd-card[data-appid="${CSS.escape(y)}"]`);if(!Y)return;let pe=Y.querySelector("textarea[data-input=teamRole]"),Te=Y.querySelector("button[data-action=save-role]"),tt=Y.querySelector("button[data-action=delete-role]");pe&&(pe.value=W,pe.disabled=!1),Te&&(Te.disabled=!1),tt&&(tt.disabled=!1)};var gt=F;let X=`/api/team/local-bots/${encodeURIComponent(y)}/role`,z=Ne.bots.find(W=>W.larkAppId===y);z&&typeof z.teamRole!="string"&&!z.teamRoleLoading&&(z.teamRoleLoading=!0,(async()=>{try{let W=await fetch(X),Y=await W.json().catch(()=>({}));W.ok&&Y.ok?(z.teamRole=Y.role??"",F(z.teamRole)):(oe.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${Y.error??W.status}`,oe.classList.add("hint-warn-inline"))}catch(W){oe.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${W?.message??W}`,oe.classList.add("hint-warn-inline")}finally{z.teamRoleLoading=!1}})());async function K(W,Y,pe){if(oe&&!(!z||typeof z.teamRole!="string")){oe.textContent="",oe.className="oncall-status",Ye.disabled=!0,Ve.disabled=!0;try{let Te=await fetch(X,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({role:W})}),tt=await Te.json().catch(()=>({}));Te.ok&&tt.ok?(z&&(z.teamRole=W.trim()),oe.textContent=`\u2713 ${pe?t("botDefaults.roleDeleted"):t("botDefaults.roleSaved")}`,oe.classList.add("hint-ok")):(oe.textContent=`\u2717 ${tt.error??Te.status}`,oe.classList.add("hint-warn-inline"))}catch(Te){oe.textContent=`\u2717 ${Te?.message??Te}`,oe.classList.add("hint-warn-inline")}finally{Ye.disabled=!1,Ve.disabled=!1}}}Ye.addEventListener("click",()=>K(it.value,Ye,!1)),Ve.addEventListener("click",()=>{it.value="",K("",Ve,!0)})}let Ue=d.querySelector("input[data-action=toggle-restrict-grant]"),Oe=d.querySelector("input[data-input=quotaLimit]"),x=d.querySelector("button[data-action=save-quota]"),ie=d.querySelector("button[data-action=off-quota]"),U=d.querySelector("[data-grant-status]"),G=d.querySelector("[data-quota-state]");async function he(X,z){if(U){U.textContent="",U.className="oncall-status",z.disabled=!0;try{let F=await fetch(`/api/bots/${encodeURIComponent(y)}/grant-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(X)}),K=await F.json().catch(()=>({}));if(F.ok&&K.ok){U.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,U.classList.add("hint-ok");let W=typeof K.messageQuotaDefaultLimit=="number"?K.messageQuotaDefaultLimit:null,Y=Ne.bots.find(pe=>pe.larkAppId===y);Y&&(Y.restrictGrantCommands=K.restrictGrantCommands===!0,Y.messageQuotaDefaultLimit=W),G&&(G.textContent=D(W)),Oe&&"messageQuotaDefaultLimit"in X&&(Oe.value=W==null?"":String(W))}else U.textContent=`\u2717 ${K.error??F.status}`,U.classList.add("hint-warn-inline")}catch(F){U.textContent=`\u2717 ${F?.message??F}`,U.classList.add("hint-warn-inline")}finally{z.disabled=!1}}}Ue&&Ue.addEventListener("change",()=>{he({restrictGrantCommands:Ue.checked},Ue)}),Oe&&x&&x.addEventListener("click",()=>{let X=Oe.value.trim();if(X===""){he({messageQuotaDefaultLimit:null},x);return}if(!/^[1-9]\d*$/.test(X)){U&&(U.textContent=`\u2717 ${t("botDefaults.quotaInvalid")}`,U.className="oncall-status hint-warn-inline");return}he({messageQuotaDefaultLimit:Number(X)},x)}),Oe&&ie&&ie.addEventListener("click",()=>{Oe.value="",he({messageQuotaDefaultLimit:null},ie)})})}r(),_e().then(r),s.addEventListener("input",r)}var Bn=4096,Zt=[],We=null,Ke=null,Pe="",$t=new Set;function oi(){return`<section class="page roles-page">
|
|
753
|
+
</div>`}function E(){n.querySelectorAll(".bd-card").forEach(d=>{let y=d.dataset.appid,H=d.querySelector("input[data-action=toggle]"),M=d.querySelector("input[data-input=workingDir]"),S=d.querySelector("button[data-action=save]"),A=d.querySelector("[data-status]");if(!H||!M||!S||!A)return;H.addEventListener("change",()=>{M.disabled=!H.checked,H.checked&&M.focus()}),S.addEventListener("click",async()=>{A.textContent="",A.className="oncall-status";let X=H.checked,z=M.value.trim();if(X&&!z){A.textContent=t("botDefaults.required"),A.classList.add("hint-warn-inline");return}S.disabled=!0;try{let F=await fetch(`/api/bots/${encodeURIComponent(y)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:X,workingDir:z})}),K=await F.json().catch(()=>({}));if(F.ok&&K.ok){let W=K.resolvedPath?` \u2192 ${K.resolvedPath}`:"";A.textContent=X?`\u2713 \u5DF2\u5F00\u542F${W}\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",A.classList.add("hint-ok");let Y=Ne.bots.find(Le=>Le.larkAppId===y);Y&&K.defaultOncall&&(Y.defaultOncall=K.defaultOncall);let pe=d.querySelector("[data-oncall-since]");pe&&K.defaultOncall?.since!=null&&(pe.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${ro(K.defaultOncall.since)}`)}else A.textContent=`\u2717 ${K.error??F.status}`,A.classList.add("hint-warn-inline")}catch(F){A.textContent=`\u2717 ${F?.message??F}`,A.classList.add("hint-warn-inline")}finally{S.disabled=!1}});let B=d.querySelector("input[data-input=brandLabel]"),_=d.querySelector("button[data-action=save-brand]"),j=d.querySelector("button[data-action=reset-brand]"),Q=d.querySelector("[data-brand-status]"),le=d.querySelector("[data-brand-state]");async function He(X,z){if(Q){Q.textContent="",Q.className="oncall-status",z.disabled=!0;try{let F=await fetch(`/api/bots/${encodeURIComponent(y)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:X})}),K=await F.json().catch(()=>({}));if(F.ok&&K.ok){let W=K.brandLabel??null;Q.textContent="\u2713",Q.classList.add("hint-ok"),B&&(B.value=W??""),le&&(le.textContent=v(W));let Y=Ne.bots.find(pe=>pe.larkAppId===y);Y&&(Y.brandLabel=W)}else Q.textContent=`\u2717 ${K.error??F.status}`,Q.classList.add("hint-warn-inline")}catch(F){Q.textContent=`\u2717 ${F?.message??F}`,Q.classList.add("hint-warn-inline")}finally{z.disabled=!1}}}B&&_&&_.addEventListener("click",()=>He(B.value,_)),j&&j.addEventListener("click",()=>He(null,j));let ge=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]"),Te=d.querySelector("[data-card-pref-status]"),Re=d.querySelector("[data-card-pref-moot]");async function ee(X,z,F=Te){if(F){F.textContent="",F.className="oncall-status",z.disabled=!0;try{let K=await fetch(`/api/bots/${encodeURIComponent(y)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(X)}),W=await K.json().catch(()=>({}));if(K.ok&&W.ok){F.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,F.classList.add("hint-ok");let Y=Ne.bots.find(pe=>pe.larkAppId===y);Y&&(Y.disableStreamingCard=W.disableStreamingCard,Y.writableTerminalLinkInCard=W.writableTerminalLinkInCard,Y.privateCard=W.privateCard,Y.autoStartOnGroupJoin=W.autoStartOnGroupJoin,Y.autoStartOnGroupJoinPrompt=W.autoStartOnGroupJoinPrompt,Y.autoStartOnNewTopic=W.autoStartOnNewTopic,Y.regularGroupReplyMode=W.regularGroupReplyMode,Y.regularGroupMentionMode=W.regularGroupMentionMode)}else F.textContent=`\u2717 ${W.error??K.status}`,F.classList.add("hint-warn-inline")}catch(K){F.textContent=`\u2717 ${K?.message??K}`,F.classList.add("hint-warn-inline")}finally{z===J?z.disabled=!!ge?.checked:z.disabled=!1}}}ge&&ge.addEventListener("change",()=>{let X=ge.checked;J&&(J.disabled=X),Re&&(Re.hidden=!X),ee({disableStreamingCard:X},ge)}),J&&J.addEventListener("change",()=>{ee({writableTerminalLinkInCard:J.checked},J)}),se&&se.addEventListener("change",()=>{ee({privateCard:se.checked},se)});let ue=d.querySelector("input[data-action=toggle-sandbox]"),de=d.querySelector("[data-sandbox-status]");ue&&ue.addEventListener("change",async()=>{let X=ue.checked;de&&(de.textContent="",de.className="oncall-status"),ue.disabled=!0;try{let z=await fetch(`/api/bots/${encodeURIComponent(y)}/sandbox`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:X})}),F=await z.json().catch(()=>({}));if(z.ok&&F.ok){de&&(de.textContent=`\u2713 ${t("botDefaults.sandboxSaved")}`,de.classList.add("hint-ok"));let K=Ne.bots.find(W=>W.larkAppId===y);K&&(K.sandbox=F.sandbox===!0)}else de&&(de.textContent=`\u2717 ${F.error??z.status}`,de.classList.add("hint-warn-inline")),ue.checked=!X}catch(z){de&&(de.textContent=`\u2717 ${z?.message??z}`,de.classList.add("hint-warn-inline")),ue.checked=!X}finally{ue.disabled=!1}});let qe=d.querySelector("input[data-action=toggle-auto-join]"),$e=d.querySelector("input[data-action=toggle-auto-topic]"),be=d.querySelector("textarea[data-input=autoJoinPrompt]"),re=d.querySelector("button[data-action=save-auto-join-prompt]"),Ce=d.querySelector("[data-auto-start-status]");qe&&qe.addEventListener("change",()=>{ee({autoStartOnGroupJoin:qe.checked},qe,Ce)}),$e&&$e.addEventListener("change",()=>{ee({autoStartOnNewTopic:$e.checked},$e,Ce)}),be&&re&&re.addEventListener("click",()=>{ee({autoStartOnGroupJoinPrompt:be.value},re,Ce)});let Ae=d.querySelector("select[data-input=p2pMode]"),ce=d.querySelector("[data-p2p-status]");Ae&&ce&&Ae.addEventListener("change",async()=>{let X=Ae.value==="chat"?"chat":"thread";ce.textContent="",ce.className="oncall-status",Ae.disabled=!0;try{let z=await fetch(`/api/bots/${encodeURIComponent(y)}/p2p-mode`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({p2pMode:X})}),F=await z.json().catch(()=>({}));if(z.ok&&F.ok){ce.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,ce.classList.add("hint-ok");let K=Ne.bots.find(W=>W.larkAppId===y);K&&(K.p2pMode=F.p2pMode==="chat"?"chat":"thread")}else ce.textContent=`\u2717 ${F.error??z.status}`,ce.classList.add("hint-warn-inline")}catch(z){ce.textContent=`\u2717 ${z?.message??z}`,ce.classList.add("hint-warn-inline")}finally{Ae.disabled=!1}});let je=d.querySelector("select[data-input=regularGroupMode]"),Ze=d.querySelector("[data-regular-group-status]");je&&je.addEventListener("change",()=>{ee({regularGroupReplyMode:je.value},je,Ze)});let et=d.querySelector("select[data-input=regularGroupMentionMode]"),ft=d.querySelector("[data-mention-mode-status]");et&&et.addEventListener("change",()=>{ee({regularGroupMentionMode:et.value},et,ft)});let it=d.querySelector("textarea[data-input=teamRole]"),Ye=d.querySelector("button[data-action=save-role]"),Ve=d.querySelector("button[data-action=delete-role]"),oe=d.querySelector("[data-role-status]");if(it&&Ye&&Ve&&oe){let F=function(W){let Y=n.querySelector(`.bd-card[data-appid="${CSS.escape(y)}"]`);if(!Y)return;let pe=Y.querySelector("textarea[data-input=teamRole]"),Le=Y.querySelector("button[data-action=save-role]"),tt=Y.querySelector("button[data-action=delete-role]");pe&&(pe.value=W,pe.disabled=!1),Le&&(Le.disabled=!1),tt&&(tt.disabled=!1)};var gt=F;let X=`/api/team/local-bots/${encodeURIComponent(y)}/role`,z=Ne.bots.find(W=>W.larkAppId===y);z&&typeof z.teamRole!="string"&&!z.teamRoleLoading&&(z.teamRoleLoading=!0,(async()=>{try{let W=await fetch(X),Y=await W.json().catch(()=>({}));W.ok&&Y.ok?(z.teamRole=Y.role??"",F(z.teamRole)):(oe.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${Y.error??W.status}`,oe.classList.add("hint-warn-inline"))}catch(W){oe.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${W?.message??W}`,oe.classList.add("hint-warn-inline")}finally{z.teamRoleLoading=!1}})());async function K(W,Y,pe){if(oe&&!(!z||typeof z.teamRole!="string")){oe.textContent="",oe.className="oncall-status",Ye.disabled=!0,Ve.disabled=!0;try{let Le=await fetch(X,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({role:W})}),tt=await Le.json().catch(()=>({}));Le.ok&&tt.ok?(z&&(z.teamRole=W.trim()),oe.textContent=`\u2713 ${pe?t("botDefaults.roleDeleted"):t("botDefaults.roleSaved")}`,oe.classList.add("hint-ok")):(oe.textContent=`\u2717 ${tt.error??Le.status}`,oe.classList.add("hint-warn-inline"))}catch(Le){oe.textContent=`\u2717 ${Le?.message??Le}`,oe.classList.add("hint-warn-inline")}finally{Ye.disabled=!1,Ve.disabled=!1}}}Ye.addEventListener("click",()=>K(it.value,Ye,!1)),Ve.addEventListener("click",()=>{it.value="",K("",Ve,!0)})}let Ue=d.querySelector("input[data-action=toggle-restrict-grant]"),Oe=d.querySelector("input[data-input=quotaLimit]"),x=d.querySelector("button[data-action=save-quota]"),ie=d.querySelector("button[data-action=off-quota]"),U=d.querySelector("[data-grant-status]"),G=d.querySelector("[data-quota-state]");async function he(X,z){if(U){U.textContent="",U.className="oncall-status",z.disabled=!0;try{let F=await fetch(`/api/bots/${encodeURIComponent(y)}/grant-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(X)}),K=await F.json().catch(()=>({}));if(F.ok&&K.ok){U.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,U.classList.add("hint-ok");let W=typeof K.messageQuotaDefaultLimit=="number"?K.messageQuotaDefaultLimit:null,Y=Ne.bots.find(pe=>pe.larkAppId===y);Y&&(Y.restrictGrantCommands=K.restrictGrantCommands===!0,Y.messageQuotaDefaultLimit=W),G&&(G.textContent=D(W)),Oe&&"messageQuotaDefaultLimit"in X&&(Oe.value=W==null?"":String(W))}else U.textContent=`\u2717 ${K.error??F.status}`,U.classList.add("hint-warn-inline")}catch(F){U.textContent=`\u2717 ${F?.message??F}`,U.classList.add("hint-warn-inline")}finally{z.disabled=!1}}}Ue&&Ue.addEventListener("change",()=>{he({restrictGrantCommands:Ue.checked},Ue)}),Oe&&x&&x.addEventListener("click",()=>{let X=Oe.value.trim();if(X===""){he({messageQuotaDefaultLimit:null},x);return}if(!/^[1-9]\d*$/.test(X)){U&&(U.textContent=`\u2717 ${t("botDefaults.quotaInvalid")}`,U.className="oncall-status hint-warn-inline");return}he({messageQuotaDefaultLimit:Number(X)},x)}),Oe&&ie&&ie.addEventListener("click",()=>{Oe.value="",he({messageQuotaDefaultLimit:null},ie)})})}r(),_e().then(r),s.addEventListener("input",r)}var Bn=4096,Zt=[],We=null,Ke=null,Pe="",$t=new Set;function oi(){return`<section class="page roles-page">
|
|
754
754
|
<div class="page-heading">
|
|
755
755
|
<div>
|
|
756
756
|
<p class="eyebrow">${t("nav.roles")}</p>
|
|
@@ -789,7 +789,7 @@ ${d.join(`
|
|
|
789
789
|
</div>
|
|
790
790
|
</div>
|
|
791
791
|
</div>
|
|
792
|
-
</section>`}async function Xt(){Zt=((await(await fetch("/api/groups")).json()).chats??[]).map(a=>({chatId:a.chatId,name:a.name??a.chatId,memberBots:(a.memberBots??[]).map(s=>({larkAppId:s.larkAppId,botName:s.botName??s.larkAppId,inChat:s.inChat??!1,hasRole:s.hasRole??!1,oncallChat:s.oncallChat??null}))}))}async function uo(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`)).json()}async function si(e,n,a){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({content:a})})).ok}async function ii(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`,{method:"DELETE"})).ok}function po(e){return e.memberBots.filter(n=>n.inChat&&n.hasRole).length}function ri(e){return e.memberBots.filter(n=>n.inChat).length}function lt(e=""){let n=document.getElementById("roles-tree");if(!n)return;let a=e.toLowerCase(),s=Zt.filter(o=>{if(!a)return!0;let r=o.chatId.toLowerCase().includes(a)||(o.name??"").toLowerCase().includes(a),c=o.memberBots.some(
|
|
792
|
+
</section>`}async function Xt(){Zt=((await(await fetch("/api/groups")).json()).chats??[]).map(a=>({chatId:a.chatId,name:a.name??a.chatId,memberBots:(a.memberBots??[]).map(s=>({larkAppId:s.larkAppId,botName:s.botName??s.larkAppId,inChat:s.inChat??!1,hasRole:s.hasRole??!1,oncallChat:s.oncallChat??null}))}))}async function uo(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`)).json()}async function si(e,n,a){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({content:a})})).ok}async function ii(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`,{method:"DELETE"})).ok}function po(e){return e.memberBots.filter(n=>n.inChat&&n.hasRole).length}function ri(e){return e.memberBots.filter(n=>n.inChat).length}function lt(e=""){let n=document.getElementById("roles-tree");if(!n)return;let a=e.toLowerCase(),s=Zt.filter(o=>{if(!a)return!0;let r=o.chatId.toLowerCase().includes(a)||(o.name??"").toLowerCase().includes(a),c=o.memberBots.some(p=>p.larkAppId.toLowerCase().includes(a)||(p.botName??"").toLowerCase().includes(a));return r||c});if(s.length===0){n.innerHTML=`<div class="roles-empty">${t("roles.noChats")}</div>`;return}n.innerHTML=s.map(o=>{let r=$t.has(o.chatId),c=o.memberBots.filter($=>$.inChat),p=r?"\u25BE":"\u25B8",k=po(o),v=ri(o),L=r?c.map($=>`
|
|
793
793
|
<div class="roles-bot-row ${We===o.chatId&&Ke===$.larkAppId?"selected":""}"
|
|
794
794
|
data-group-id="${i(o.chatId)}"
|
|
795
795
|
data-bot-id="${i($.larkAppId)}">
|
|
@@ -806,7 +806,7 @@ ${d.join(`
|
|
|
806
806
|
<div class="roles-group-section">
|
|
807
807
|
<div class="roles-group-row ${r?"expanded":""} ${We===o.chatId&&!Ke?"selected":""}"
|
|
808
808
|
data-group-id="${i(o.chatId)}">
|
|
809
|
-
<span class="roles-group-arrow">${
|
|
809
|
+
<span class="roles-group-arrow">${p}</span>
|
|
810
810
|
<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>
|
|
811
811
|
<div class="roles-group-info">
|
|
812
812
|
<div class="roles-group-name">${i(o.name??o.chatId)}</div>
|
|
@@ -817,7 +817,7 @@ ${d.join(`
|
|
|
817
817
|
<span class="roles-group-chevron"></span>
|
|
818
818
|
</div>
|
|
819
819
|
<div class="roles-bot-list">${L}</div>
|
|
820
|
-
</div>`}).join(""),n.querySelectorAll(".roles-group-row").forEach(o=>{o.addEventListener("click",()=>{let r=o.dataset.groupId;r&&($t.has(r)?$t.delete(r):$t.add(r),lt(document.getElementById("roles-search")?.value??""))})}),n.querySelectorAll(".roles-bot-row").forEach(o=>{o.addEventListener("click",r=>{r.stopPropagation();let c=o.dataset.groupId,
|
|
820
|
+
</div>`}).join(""),n.querySelectorAll(".roles-group-row").forEach(o=>{o.addEventListener("click",()=>{let r=o.dataset.groupId;r&&($t.has(r)?$t.delete(r):$t.add(r),lt(document.getElementById("roles-search")?.value??""))})}),n.querySelectorAll(".roles-bot-row").forEach(o=>{o.addEventListener("click",r=>{r.stopPropagation();let c=o.dataset.groupId,p=o.dataset.botId;c&&p&&li(c,p)})})}async function li(e,n){We=e,Ke=n;let a=await uo(n,e),s=document.getElementById("roles-editor-empty"),o=document.getElementById("roles-editor-form"),r=document.getElementById("roles-editor-textarea"),c=document.getElementById("roles-editor-group-name"),p=document.getElementById("roles-editor-bot-name"),k=document.getElementById("roles-editor-chat-id");s&&(s.style.display="none"),o&&(o.style.display="");let v=Zt.find(g=>g.chatId===e),L=v?.memberBots.find(g=>g.larkAppId===n);c&&(c.textContent=v?.name??e),p&&(p.textContent=L?.botName??n),k&&(k.textContent=`${e} \xB7 ${n}`),Pe=a.content??"",r&&(r.value=Pe,r.focus()),Nn(),Pn(),lt(document.getElementById("roles-search")?.value??"");let $=document.getElementById("roles-delete");$&&($.style.display=a.hasRole?"":"none")}function Nn(){let e=document.getElementById("roles-editor-bytecount");if(!e)return;let n=new TextEncoder().encode(Pe).length;e.textContent=`${n} / ${Bn} bytes`,e.className=`roles-bytecount ${n>3800?"warn":""} ${n>Bn?"over":""}`,di(n)}function di(e){let n=document.getElementById("roles-save");if(!n)return;let a=e??new TextEncoder().encode(Pe).length;n.disabled=a>Bn||Pe.trim().length===0}function Pn(){let e=document.getElementById("roles-preview");e&&(Pe.trim()?e.innerHTML=`<strong>${t("roles.preview")}</strong><pre>${i(Pe)}</pre>`:e.innerHTML=`<small>${t("roles.previewEmpty")}</small>`)}function co(){We=null,Ke=null,Pe="";let e=document.getElementById("roles-editor-empty"),n=document.getElementById("roles-editor-form"),a=document.getElementById("roles-editor-textarea"),s=document.getElementById("roles-delete");e&&(e.style.display=""),n&&(n.style.display="none"),a&&(a.value=""),s&&(s.style.display="none")}async function mo(e){e.innerHTML=oi(),$t.clear(),co();let n=document.getElementById("roles-tree");n&&(n.innerHTML=wt()),await Xt(),await _e();for(let a of Zt)po(a)>0&&$t.add(a.chatId);lt(),document.getElementById("roles-search")?.addEventListener("input",a=>{lt(a.target.value)}),document.getElementById("roles-refresh")?.addEventListener("click",async()=>{if(await Xt(),lt(document.getElementById("roles-search")?.value??""),We&&Ke){let a=await uo(Ke,We),s=document.getElementById("roles-editor-textarea");s&&(s.value=a.content??""),Pe=a.content??"",Nn(),Pn();let o=document.getElementById("roles-delete");o&&(o.style.display=a.hasRole?"":"none")}}),document.getElementById("roles-save")?.addEventListener("click",async function(){if(!(!We||!Ke)){this.disabled=!0,this.textContent="...";try{if(await si(Ke,We,Pe)){await Xt(),lt(document.getElementById("roles-search")?.value??"");let s=document.getElementById("roles-delete");s&&(s.style.display="");let o=document.createElement("span");o.className="roles-saved-flash",o.textContent=` ${t("roles.saved")}`,document.querySelector(".roles-editor-footer")?.appendChild(o),setTimeout(()=>o.remove(),2e3)}else{let s=document.createElement("span");s.className="roles-saved-flash roles-save-error",s.textContent=Pe.trim().length===0?` ${t("roles.emptyError")}`:` ${t("roles.saveFailed")}`,document.querySelector(".roles-editor-footer")?.appendChild(s),setTimeout(()=>s.remove(),3e3)}}finally{this.disabled=!1,this.textContent=t("roles.save")}}}),document.getElementById("roles-delete")?.addEventListener("click",async function(){if(!(!We||!Ke)&&confirm(t("roles.confirmDelete"))){this.disabled=!0,this.textContent="...";try{await ii(Ke,We)&&(await Xt(),co(),lt(document.getElementById("roles-search")?.value??""))}finally{this.disabled=!1,this.textContent=t("roles.delete")}}}),document.getElementById("roles-editor-textarea")?.addEventListener("input",a=>{Pe=a.target.value,Nn(),Pn()})}async function nn(e){let n=await fetch(e);return{status:n.status,body:await n.json().catch(()=>({}))}}async function an(e,n,a){let s=await fetch(n,{method:e,headers:{"content-type":"application/json"},body:a?JSON.stringify(a):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}var ct=(e,n)=>an("POST",e,n),ci=(e,n)=>an("PUT",e,n),qn=[],fo=[],go="",en="",Un=new Map,tn=new Map,Et=new Set,Ht=new Set;function ne(e){return document.getElementById(e)}function on(){return[...qn,...fo]}function dt(e){let n=Un.get(e);return n||(n=new Set,Un.set(e,n)),n}function ui(e){return on().find(n=>n.key===e)}function bo(e){let n=(a,s,o)=>`<a href="${a}" style="padding:6px 14px;border-radius:8px;text-decoration:none;font-size:14px;font-weight:600;${o?"background:var(--accent);color:var(--on-accent)":"color:var(--muted);background:var(--surface-muted)"}">${s}</a>`;return`<div style="display:flex;gap:8px;margin-bottom:14px">${n("#/team",t("team.navHome"),e==="home")}${n("#/team/manage",t("team.navManage"),e==="manage")}</div>`}function pi(){return`<section class="page">
|
|
821
821
|
<div class="page-heading"><div>
|
|
822
822
|
<p class="eyebrow">${t("team.eyebrow")}</p><h1>${t("team.homeTitle")}</h1>
|
|
823
823
|
<p class="tf-lede">${t("team.homeLede")}</p>
|
|
@@ -851,7 +851,7 @@ ${bo("home")}
|
|
|
851
851
|
</div>
|
|
852
852
|
</div>
|
|
853
853
|
</div>
|
|
854
|
-
</section>`}function mi(e){let n=(ne("tf-search").value||"").trim().toLowerCase();if(n&&!((e.name||"")+" "+(e.cliId||"")+" "+(e.capability||"")).toLowerCase().includes(n))return!1;let a=ne("tf-cli").value;return!(a&&e.cliId!==a||ne("tf-fcap").checked&&!e.capability||ne("tf-frole").checked&&!e.hasTeamRole)}function fi(e,n){let a=[...e.deployments].sort((o,r)=>o.local===r.local?0:o.local?-1:1),s="";for(let o of a){let r=n.filter(g=>g.deployment.id===o.id);if(!r.length)continue;let c=o.id===go,
|
|
854
|
+
</section>`}function mi(e){let n=(ne("tf-search").value||"").trim().toLowerCase();if(n&&!((e.name||"")+" "+(e.cliId||"")+" "+(e.capability||"")).toLowerCase().includes(n))return!1;let a=ne("tf-cli").value;return!(a&&e.cliId!==a||ne("tf-fcap").checked&&!e.capability||ne("tf-frole").checked&&!e.hasTeamRole)}function fi(e,n){let a=[...e.deployments].sort((o,r)=>o.local===r.local?0:o.local?-1:1),s="";for(let o of a){let r=n.filter(g=>g.deployment.id===o.id);if(!r.length)continue;let c=o.id===go,p=c?t("team.tagLocal"):o.stale?t("team.tagRemoteStale"):t("team.tagRemote"),k=e.kind==="local"&&!c?` <button class="tf-rmmember ghost" data-team="${i(e.teamId)}" data-dep="${i(o.id)}" data-name="${i(o.name)}" style="font-size:12px">${t("team.removeMember")}</button>`:"",v=`${e.key}::${o.id}`,L=Ht.has(v),$=r.filter(g=>dt(e.key).has(g.larkAppId)).length;if(s+=`<div class="tf-dep-h" data-dk="${i(v)}" style="cursor:pointer;margin:10px 0 2px"><b>${L?"\u25BE":"\u25B8"} ${i(o.name)}</b> <span class="muted" style="font-size:12px">${t("team.depTag",{tag:p})} \xB7 ${t("team.depCount",{count:r.length})}${$?t("team.depSelected",{n:$}):""}</span>${k}</div>`,!!L){s+='<table style="width:100%;border-collapse:collapse;font-size:14px"><tbody>';for(let g of r){let O=i(g.larkAppId),D=dt(e.key).has(g.larkAppId)?" checked":"",R=g.deployment.stale?"opacity:.55":"",I=c?`<input class="tf-cap" data-app="${O}" value="${i(g.capability||"")}" placeholder="${t("team.capPh")}" style="width:92%;padding:3px 6px">`:g.capability?i(g.capability):'<span class="muted">\u2014</span>',E=g.hasTeamRole?c?`<button class="tf-role" data-app="${O}" data-name="${i(g.name)}">${t("team.viewRole")}</button>`:t("team.hasRoleShort"):'<span class="muted">\u2014</span>';s+=`<tr style="${R}"><td style="padding:4px 8px"><input type="checkbox" class="tf-pick" data-tk="${i(e.key)}" data-app="${O}"${D}></td><td style="padding:4px 8px">${i(g.name)}</td><td style="padding:4px 8px" class="muted">${i(g.cliId)}</td><td style="padding:4px 8px">${I}</td><td style="padding:4px 8px">${E}</td></tr>`}s+="</tbody></table>"}}return s||(s=`<p class="muted" style="margin:8px 0 0">${t("team.noMatch")}</p>`),s+=`<div style="margin-top:12px;display:flex;gap:8px;flex-wrap:wrap;align-items:center"><input class="tf-gname" data-tk="${i(e.key)}" value="${i(tn.get(e.key)||"")}" placeholder="${t("team.gnamePh")}" style="min-width:200px"><button class="tf-grp primary" data-tk="${i(e.key)}">${t("team.pullGroupBtn")}</button><span class="muted" style="font-size:13px">${t("team.pullGroupHint")}</span><span class="tf-gout" data-tk="${i(e.key)}" style="font-size:13px;display:block;flex-basis:100%"></span></div>`,s}function ot(){let e=ne("tf-teams"),n=on();if(!n.length){e.innerHTML=`<p class="muted">${t("team.noTeams")}</p>`,ne("tf-count").textContent="";return}let a="",s=new Set,o=new Set;for(let p of n){let k=p.bots.filter(mi);k.forEach(g=>s.add(g.larkAppId)),p.bots.forEach(g=>o.add(g.larkAppId));let v=new Set(k.map(g=>g.larkAppId));[...dt(p.key)].forEach(g=>{v.has(g)||dt(p.key).delete(g)});let L=!Et.has(p.key),$=p.kind==="remote"?p.ok?` <span class="ok" style="font-size:12px">${t("team.connected")}</span>`:` <span class="err" style="font-size:12px">${t("team.connectFail",{error:i(p.error||"")})}</span>`:` <span class="muted" style="font-size:12px">${t("team.iHost")}</span>`;a+=`<div class="card" style="margin:0 0 12px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)"><div class="tf-team-h" data-tk="${i(p.key)}" style="cursor:pointer;display:flex;align-items:center;gap:8px;flex-wrap:wrap"><b style="font-size:15px">${L?"\u25B8":"\u25BE"} ${i(p.label)}</b>`+(p.sub?` <span class="muted" style="font-size:12px">${i(p.sub)}</span>`:"")+$+` <span class="muted" style="font-size:12px">\xB7 ${t("team.teamMeta",{deps:p.deployments.length,bots:p.bots.length})}</span></div>`,L||(a+=p.kind==="remote"&&!p.ok?`<p class="muted" style="margin:8px 0 0">${t("team.rosterFail")}</p>`:fi(p,k)),a+="</div>"}e.innerHTML=a;let r=n.length>1?t("team.acrossTeams",{n:n.length}):"",c=s.size===o.size?`${o.size}`:`${s.size} / ${o.size}`;ne("tf-count").textContent=`\xB7 ${c} ${t("team.botsWord")}${r}`,gi()}function gi(){let e=ne("tf-teams");e.querySelectorAll(".tf-team-h").forEach(n=>{n.onclick=()=>{let a=n.dataset.tk;Et.has(a)?Et.delete(a):Et.add(a),ot()}}),e.querySelectorAll(".tf-dep-h").forEach(n=>{n.onclick=()=>{let a=n.dataset.dk;Ht.has(a)?Ht.delete(a):Ht.add(a),ot()}}),e.querySelectorAll(".tf-pick").forEach(n=>{n.onchange=()=>{let a=dt(n.dataset.tk);n.checked?a.add(n.dataset.app):a.delete(n.dataset.app)}}),e.querySelectorAll(".tf-gname").forEach(n=>{n.oninput=()=>{tn.set(n.dataset.tk,n.value)}}),e.querySelectorAll(".tf-cap").forEach(n=>{n.onchange=async()=>{let a=n.dataset.app,s=n.value;await ci("/api/team/local-bots/"+encodeURIComponent(a)+"/capability",{capability:s}),on().forEach(o=>{let r=o.bots.find(c=>c.larkAppId===a);r&&(r.capability=s.trim()||null)})}}),e.querySelectorAll(".tf-role").forEach(n=>{n.onclick=()=>hi(n.dataset.app,n.dataset.name||"")}),e.querySelectorAll(".tf-rmmember").forEach(n=>{n.onclick=async a=>{a.stopPropagation(),confirm(t("team.removeMemberConfirm",{name:n.dataset.name||""}))&&(await an("DELETE",`/api/team/hosted/${encodeURIComponent(n.dataset.team)}/members/${encodeURIComponent(n.dataset.dep)}`),Ct())}}),e.querySelectorAll(".tf-grp").forEach(n=>{n.onclick=async()=>{let a=n.dataset.tk,s=ui(a);if(!s)return;let o=[...dt(a)],r=e.querySelector(`.tf-gout[data-tk="${CSS.escape(a)}"]`);if(!o.length){r.innerHTML=`<span class="err">${t("team.errPickBot")}</span>`;return}let c=(e.querySelector(`.tf-gname[data-tk="${CSS.escape(a)}"]`)?.value||"").trim()||t("team.defaultGroupName");r.innerHTML=`<span class="muted">${t("team.creatingGroup")}</span>`;let p=s.kind==="local"?await ct("/api/team/federated-group",{name:c,larkAppIds:o,teamId:s.teamId}):await ct("/api/team/remote-group",{hubUrl:s.hubUrl,teamId:s.teamId,name:c,larkAppIds:o});if(bi(r,p.body,p.status),p.body?.ok){dt(a).clear(),tn.delete(a);let k=r.innerHTML,v=()=>{let L=e.querySelector(`.tf-gout[data-tk="${CSS.escape(a)}"]`);L&&(L.innerHTML=k)};s.kind==="local"?Ct().then(v):(ot(),v())}}})}function bi(e,n,a){if(n?.ok&&n.chatId){let s=n.shareLink||"https://applink.feishu.cn/client/chat/open?openChatId="+encodeURIComponent(n.chatId),o=(n.invalidBotIds||[]).length?` <span class="err"> \xB7 ${t("team.invalidBots",{ids:i((n.invalidBotIds||[]).join(", "))})}</span>`:"",r=(n.invalidOwnerUnionIds||[]).length?`<span class="err"> \xB7 ${t("team.invalidOwners",{n:(n.invalidOwnerUnionIds||[]).length})}</span>`:"",c=n.missingOperatorIdentity?`<span class="err"> \xB7 ${t("team.missingIdentity")}</span>`:"",p=(n.skippedNoOwner||[]).length?`<span class="err"> \xB7 ${t("team.skippedNoOwner",{n:(n.skippedNoOwner||[]).length})}</span>`:"",k=n.delegatedTo?t("team.delegatedBy",{name:i(n.delegatedTo)}):"";e.innerHTML=`<span class="ok">${t("team.groupCreated")}</span>${k} \xB7 <a href="${i(s)}" target="_blank">${t("team.openInLark")}</a>${o}${r}${c}${p}`}else{let s=n?.error||a,o=s==="no_local_online_bot"?t("team.errNoLocalBot"):s==="all_bots_skipped_no_owner"?t("team.errAllSkipped"):s==="no_creator_available"?t("team.errNoCreator"):s==="delegation_timeout"?t("team.errDelegationTimeout"):t("team.errGroupCreate",{error:String(s)});e.innerHTML=`<span class="err">${i(String(o))}</span>`}}async function hi(e,n){let a=await nn("/api/team/local-bots/"+encodeURIComponent(e)+"/role");ne("tf-modal-title").textContent=t("team.roleModalTitleName",{name:n}),ne("tf-modal-text").value=a.body?.role||"",ne("tf-modal").dataset.app=e,ne("tf-modal").style.display="flex"}function ho(){let e=Array.from(new Set(on().flatMap(s=>s.bots.map(o=>o.cliId)).filter(Boolean))).sort(),n=ne("tf-cli"),a=n.value;n.innerHTML=`<option value="">${t("team.allCli")}</option>`+e.map(s=>`<option value="${i(s)}">${i(s)}</option>`).join(""),n.value=a}async function Ct(){let n=(await nn("/api/team/hosted")).body;if(!n?.ok){qn=[],ot();return}go=n.deployment.deploymentId,en=n.suggestedHubUrl||"",ne("tf-owner").textContent=n.deployment.ownerName||(n.deployment.ownerUnionId?t("team.bound"):t("team.unbound")),qn=(n.teams||[]).map(a=>({kind:"local",key:`local:${a.teamId}`,teamId:a.teamId,label:a.isDefault?t("team.myHostedTeam"):a.name,sub:"",ok:!0,deployments:a.deployments||[],bots:a.bots||[]})),ho(),ot()}async function wi(){fo=((await nn("/api/team/remote-roster")).body?.memberships||[]).map(a=>{let s=a.roster?.deployments||[],o=s.find(c=>c.local),r=o?.name?t("team.remoteTeamLabel",{name:o.name}):a.teamName||a.teamId;return{kind:"remote",key:`${a.hubUrl}::${a.teamId}`,teamId:a.teamId,label:r,sub:a.hubUrl,ok:!!a.ok,error:a.error,hubUrl:a.hubUrl,deployments:s,bots:a.roster?.bots||[]}}),ho(),ot()}function wo(e){e.innerHTML=pi(),Un.clear(),tn.clear(),Et.clear(),Ht.clear(),["tf-search","tf-cli","tf-fcap","tf-frole"].forEach(n=>{let a=ne(n);a.oninput=ot,a.onchange=ot}),ne("tf-modal-cancel").onclick=()=>{ne("tf-modal").style.display="none"},vi(),Ct(),wi()}function yi(){return`<section class="page">
|
|
855
855
|
<div class="page-heading"><div>
|
|
856
856
|
<p class="eyebrow">${t("team.eyebrow")}</p><h1>${t("team.manageTitle")}</h1>
|
|
857
857
|
<p class="tf-lede">${t("team.manageLede")}</p>
|
|
@@ -884,7 +884,7 @@ ${bo("manage")}
|
|
|
884
884
|
${o.isDefault?"":`<button class="tm-del ghost" data-team="${i(o.teamId)}" data-name="${i(o.name)}" style="font-size:12px">${t("team.delBtn")}</button>`}
|
|
885
885
|
</span>
|
|
886
886
|
</div>
|
|
887
|
-
<div class="tm-inv-out" data-team="${i(o.teamId)}" style="display:none;margin-top:6px;font-size:13px"></div></div>`}).join(""),a.querySelectorAll(".tm-invite").forEach(o=>{o.onclick=async()=>{let r=o.dataset.team,c=a.querySelector(`.tm-inv-out[data-team="${CSS.escape(r)}"]`);c.style.display="",c.innerHTML=`<span class="muted">${t("team.generating")}</span>`;let
|
|
887
|
+
<div class="tm-inv-out" data-team="${i(o.teamId)}" style="display:none;margin-top:6px;font-size:13px"></div></div>`}).join(""),a.querySelectorAll(".tm-invite").forEach(o=>{o.onclick=async()=>{let r=o.dataset.team,c=a.querySelector(`.tm-inv-out[data-team="${CSS.escape(r)}"]`);c.style.display="",c.innerHTML=`<span class="muted">${t("team.generating")}</span>`;let p=await ct("/api/team/local-invite",{teamId:r});p.body?.code?c.innerHTML=`${t("team.inviteResultLede")}<br>${t("team.inviteHub")}<code>${i(en)}</code><br>${t("team.inviteCode")}<code style="font-size:15px">${i(p.body.code)}</code>`:c.innerHTML=`<span class="err">${t("team.genFail")}</span>`}}),a.querySelectorAll(".tm-del").forEach(o=>{o.onclick=async()=>{confirm(t("team.delConfirm",{name:o.dataset.name||""}))&&(await an("DELETE","/api/team/hosted/"+encodeURIComponent(o.dataset.team)),jn())}})}function yo(e){e.innerHTML=yi(),ne("tm-create").onclick=async()=>{let n=ne("tm-newname").value.trim(),a=e.querySelector(".tm-cout");if(!n){a.innerHTML=`<span class="err">${t("team.errName")}</span>`;return}a.innerHTML=`<span class="muted">${t("team.creating")}</span>`;let s=await ct("/api/team/hosted",{name:n});s.body?.ok?(a.innerHTML=`<span class="ok">${t("team.created")}</span>`,ne("tm-newname").value="",jn()):a.innerHTML=`<span class="err">${t("team.createFail",{error:i(String(s.body?.error||s.status))})}</span>`},ne("tm-join").onclick=async()=>{let n=ne("tm-hub").value.trim(),a=ne("tm-code").value.trim(),s=ne("tm-join-out");if(s.style.display="",!n||!a){s.innerHTML=`<span class="err">${t("team.errHubCode")}</span>`;return}s.innerHTML=`<span class="muted">${t("team.joining")}</span>`;let o=await ct("/api/team/join-remote",{hubUrl:n,inviteCode:a});if(o.body?.ok)s.innerHTML=`<span class="ok">${t("team.joined",{name:i(o.body.teamName||"")})}</span>`,ne("tm-code").value="";else{let r=o.body?.error||o.status,c=r==="cannot_join_self"?t("team.joinErrSelf"):r==="deployment_already_joined"?t("team.joinErrAlready"):r==="hub_unreachable"?t("team.joinErrUnreachable"):r==="hub_timeout"?t("team.joinErrTimeout"):t("team.joinErrGeneric",{error:String(r)});s.innerHTML=`<span class="err">${i(String(c))}</span>`}},jn()}function vi(){ne("tf-autobind").onclick=async()=>{let e=ne("tf-bind-out");e.style.display="",e.innerHTML=`<span class="muted">${t("team.identifying")}</span>`;let a=(await ct("/api/team/identity/auto-bind")).body;if(a?.ok&&a.owner){e.innerHTML=`<span class="ok">${t("team.bound2",{name:i(a.owner.name||a.owner.unionId)})}</span>`,Ct();return}if(a?.ok&&a.needChoice&&Array.isArray(a.candidates)){let s=a.candidates.map(o=>`<button class="tf-pickowner ghost" data-union="${i(o.unionId)}" style="margin:2px">${i(o.name||o.unionId)}</button>`).join(" ");e.innerHTML=`${t("team.multiCandidate")}<br>${s}`,e.querySelectorAll(".tf-pickowner").forEach(o=>{o.onclick=async()=>{e.innerHTML=`<span class="muted">${t("team.binding")}</span>`;let c=(await ct("/api/team/identity/auto-bind",{unionId:o.dataset.union})).body;c?.ok&&c.owner?(e.innerHTML=`<span class="ok">${t("team.bound2",{name:i(c.owner.name||c.owner.unionId)})}</span>`,Ct()):e.innerHTML=`<span class="err">${t("team.bindFail",{error:i(String(c?.error||"unknown"))})}</span>`}});return}if(a?.error==="no_candidates"){e.innerHTML=`<span class="err">${t("team.noCandidates")}</span>`;return}e.innerHTML=`<span class="err">${t("team.bindFail",{error:i(String(a?.error||"unknown"))})}</span>`}}async function Fn(e){let n=await fetch(e);return{status:n.status,body:await n.json().catch(()=>({}))}}async function _n(e,n,a){let s=await fetch(n,{method:e,headers:{"content-type":"application/json"},body:a?JSON.stringify(a):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}function ae(e){return document.getElementById(e)}function ut(e){return(ae(e).value||"").trim()}var zn=[],Kn=[];function ki(){return`<section class="page">
|
|
888
888
|
<div class="page-heading">
|
|
889
889
|
<div>
|
|
890
890
|
<p class="eyebrow">Webhook</p>
|
|
@@ -946,11 +946,11 @@ ${bo("manage")}
|
|
|
946
946
|
<h2 style="margin-top:0">${t("connectors.listTitle")} <span class="muted" id="cn-count" style="font-size:13px"></span></h2>
|
|
947
947
|
<div id="cn-list">${t("connectors.loading")}</div>
|
|
948
948
|
</div>
|
|
949
|
-
</section>`}function Gn(){let e=ae("cn-kind").value,n=ae("cn-mode").value;document.querySelectorAll(".cn-wf").forEach(a=>{a.style.display=e==="workflow"?"":"none"}),document.querySelectorAll(".cn-fixed").forEach(a=>{a.style.display=n==="fixed"?"":"none"}),document.querySelectorAll(".cn-allow").forEach(a=>{a.style.display=n==="fixed"?"none":""}),document.querySelectorAll(".cn-dyn").forEach(a=>{a.style.display=n==="dynamic"?"":"none"}),document.querySelectorAll(".cn-life").forEach(a=>{a.style.display=n==="new-group"?"":"none"})}function vo(e){return`${location.origin}/webhook/${encodeURIComponent(e)}`}function $i(e){return e==="fixed"?t("connectors.modeLabelFixed"):e==="new-group"?t("connectors.modeLabelNewGroup"):t("connectors.modeLabelDynamic")}function Si(e){return e==="workflow"?t("connectors.kindLabelWorkflow"):t("connectors.kindLabelTurn")}function Wn(e){return Kn.find(a=>a.chatId===e)?.name||e}function Ti(e){return Kn.filter(n=>n.bots.includes(e))}function ko(){let e=ae("cn-bot").value,n=Ti(e),a=
|
|
949
|
+
</section>`}function Gn(){let e=ae("cn-kind").value,n=ae("cn-mode").value;document.querySelectorAll(".cn-wf").forEach(a=>{a.style.display=e==="workflow"?"":"none"}),document.querySelectorAll(".cn-fixed").forEach(a=>{a.style.display=n==="fixed"?"":"none"}),document.querySelectorAll(".cn-allow").forEach(a=>{a.style.display=n==="fixed"?"none":""}),document.querySelectorAll(".cn-dyn").forEach(a=>{a.style.display=n==="dynamic"?"":"none"}),document.querySelectorAll(".cn-life").forEach(a=>{a.style.display=n==="new-group"?"":"none"})}function vo(e){return`${location.origin}/webhook/${encodeURIComponent(e)}`}function $i(e){return e==="fixed"?t("connectors.modeLabelFixed"):e==="new-group"?t("connectors.modeLabelNewGroup"):t("connectors.modeLabelDynamic")}function Si(e){return e==="workflow"?t("connectors.kindLabelWorkflow"):t("connectors.kindLabelTurn")}function Wn(e){return Kn.find(a=>a.chatId===e)?.name||e}function Ti(e){return Kn.filter(n=>n.bots.includes(e))}function ko(){let e=ae("cn-bot").value,n=Ti(e),a=p=>`<option value="${i(p.chatId)}">${i(p.name||p.chatId)}</option>`,s=ae("cn-chat-sel"),o=s.value;s.innerHTML=n.length?n.map(a).join(""):`<option value="">${t("connectors.noBotGroups")}</option>`,o&&n.some(p=>p.chatId===o)&&(s.value=o);let r=ae("cn-allow-sel"),c=new Set(Array.from(r.selectedOptions).map(p=>p.value));r.innerHTML=n.map(a).join(""),Array.from(r.options).forEach(p=>{c.has(p.value)&&(p.selected=!0)})}function Li(e){let n=ae("cn-list");if(ae("cn-count").textContent=e.length?t("connectors.count",{count:e.length}):"",!e.length){n.innerHTML=`<p class="muted">${t("connectors.empty")}</p>`;return}n.innerHTML=e.map(a=>{let s=zn.find(k=>k.larkAppId===a.target.botId),o=vo(a.id),r=(a.verify?.type??"token")==="token",c=r?t("connectors.badgeToken"):t("connectors.badgeSign"),p=a.target.mode==="fixed"&&a.target.chatId?` \xB7 ${t("connectors.dest",{name:i(Wn(a.target.chatId))})}`:"";return`<div class="card" style="margin:0 0 10px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
950
950
|
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
951
951
|
<b style="font-size:15px">${i(a.name)}</b>
|
|
952
952
|
<span class="${a.enabled?"ok":"muted"}" style="font-size:12px">${a.enabled?t("connectors.enabled"):t("connectors.disabled")}</span>
|
|
953
|
-
<span class="muted" style="font-size:12px">\xB7 ${i(s?.botName||a.target.botId)} \xB7 ${Si(a.target.kind)} \xB7 ${$i(a.target.mode)}${
|
|
953
|
+
<span class="muted" style="font-size:12px">\xB7 ${i(s?.botName||a.target.botId)} \xB7 ${Si(a.target.kind)} \xB7 ${$i(a.target.mode)}${p} \xB7 ${c}</span>
|
|
954
954
|
<span style="margin-left:auto;display:flex;gap:6px">
|
|
955
955
|
<button class="cn-toggle ghost" data-id="${i(a.id)}" data-on="${a.enabled}" style="font-size:12px">${a.enabled?t("connectors.btnDisable"):t("connectors.btnEnable")}</button>
|
|
956
956
|
<button class="cn-del ghost" data-id="${i(a.id)}" style="font-size:12px">${t("connectors.btnDel")}</button>
|
|
@@ -959,7 +959,7 @@ ${bo("manage")}
|
|
|
959
959
|
<div style="margin-top:6px;font-size:13px;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
960
960
|
<span class="muted">${t("connectors.webhookUrl")}</span><code style="font-size:12px;word-break:break-all">${i(o)}${r?"/<token>":""}</code>
|
|
961
961
|
<button class="cn-copy ghost" data-url="${i(o)}" style="font-size:12px">${t("connectors.copy")}</button>
|
|
962
|
-
</div>${r?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.tokenHint")}</div>`:""}${a.target.mode==="dynamic"?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.dynamicReqHint")}</div>`:""}${a.promptEnvelope?.instruction?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.instructionPrefix")}${i(a.promptEnvelope.instruction)}</div>`:""}</div>`}).join(""),n.querySelectorAll(".cn-copy").forEach(a=>{a.onclick=()=>{navigator.clipboard?.writeText(a.dataset.url),a.textContent=t("connectors.copied"),setTimeout(()=>a.textContent=t("connectors.copy"),1200)}}),n.querySelectorAll(".cn-toggle").forEach(a=>{a.onclick=async()=>{await _n("PATCH","/api/connectors/"+encodeURIComponent(a.dataset.id),{enabled:a.dataset.on!=="true"}),sn()}}),n.querySelectorAll(".cn-del").forEach(a=>{a.onclick=async()=>{confirm(t("connectors.delConfirm"))&&(await _n("DELETE","/api/connectors/"+encodeURIComponent(a.dataset.id)),sn())}})}async function sn(){let[e,n,a]=await Promise.all([Fn("/api/bots"),Fn("/api/connectors"),Fn("/api/groups")]);zn=(e.body?.bots||[]).map(r=>({larkAppId:r.larkAppId,botName:r.botName||r.larkAppId})),Kn=(a.body?.chats||[]).map(r=>({chatId:r.chatId,name:r.name||"",bots:(r.memberBots||[]).filter(c=>c.inChat).map(c=>c.larkAppId)}));let s=ae("cn-bot"),o=s.value;s.innerHTML=zn.map(r=>`<option value="${i(r.larkAppId)}">${i(r.botName)}</option>`).join("")||`<option value="">${t("connectors.noOnlineBots")}</option>`,o&&(s.value=o),ko(),Li(n.body?.connectors||[])}function $o(e){e.innerHTML=ki(),ae("cn-kind").onchange=Gn,ae("cn-mode").onchange=Gn,ae("cn-bot").onchange=ko,ae("cn-chat-manual").onclick=n=>{n.preventDefault();let a=ae("cn-chat"),s=ae("cn-chat-sel"),o=a.style.display==="none";a.style.display=o?"":"none",s.style.display=o?"none":"",ae("cn-chat-manual").textContent=o?t("connectors.chatListLink"):t("connectors.chatManualLink")},Gn(),ae("cn-create").onclick=async()=>{let n=ae("cn-create-out"),a=ut("cn-name"),s=ae("cn-bot").value;if(!a){n.innerHTML=`<span class="err">${t("connectors.errName")}</span>`;return}if(!s){n.innerHTML=`<span class="err">${t("connectors.errBot")}</span>`;return}let o=ae("cn-kind").value,r=ae("cn-mode").value,c={name:a,enabled:!0,target:{kind:o,mode:r,botId:s},promptEnvelope:{sourceName:a}},
|
|
962
|
+
</div>${r?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.tokenHint")}</div>`:""}${a.target.mode==="dynamic"?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.dynamicReqHint")}</div>`:""}${a.promptEnvelope?.instruction?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.instructionPrefix")}${i(a.promptEnvelope.instruction)}</div>`:""}</div>`}).join(""),n.querySelectorAll(".cn-copy").forEach(a=>{a.onclick=()=>{navigator.clipboard?.writeText(a.dataset.url),a.textContent=t("connectors.copied"),setTimeout(()=>a.textContent=t("connectors.copy"),1200)}}),n.querySelectorAll(".cn-toggle").forEach(a=>{a.onclick=async()=>{await _n("PATCH","/api/connectors/"+encodeURIComponent(a.dataset.id),{enabled:a.dataset.on!=="true"}),sn()}}),n.querySelectorAll(".cn-del").forEach(a=>{a.onclick=async()=>{confirm(t("connectors.delConfirm"))&&(await _n("DELETE","/api/connectors/"+encodeURIComponent(a.dataset.id)),sn())}})}async function sn(){let[e,n,a]=await Promise.all([Fn("/api/bots"),Fn("/api/connectors"),Fn("/api/groups")]);zn=(e.body?.bots||[]).map(r=>({larkAppId:r.larkAppId,botName:r.botName||r.larkAppId})),Kn=(a.body?.chats||[]).map(r=>({chatId:r.chatId,name:r.name||"",bots:(r.memberBots||[]).filter(c=>c.inChat).map(c=>c.larkAppId)}));let s=ae("cn-bot"),o=s.value;s.innerHTML=zn.map(r=>`<option value="${i(r.larkAppId)}">${i(r.botName)}</option>`).join("")||`<option value="">${t("connectors.noOnlineBots")}</option>`,o&&(s.value=o),ko(),Li(n.body?.connectors||[])}function $o(e){e.innerHTML=ki(),ae("cn-kind").onchange=Gn,ae("cn-mode").onchange=Gn,ae("cn-bot").onchange=ko,ae("cn-chat-manual").onclick=n=>{n.preventDefault();let a=ae("cn-chat"),s=ae("cn-chat-sel"),o=a.style.display==="none";a.style.display=o?"":"none",s.style.display=o?"none":"",ae("cn-chat-manual").textContent=o?t("connectors.chatListLink"):t("connectors.chatManualLink")},Gn(),ae("cn-create").onclick=async()=>{let n=ae("cn-create-out"),a=ut("cn-name"),s=ae("cn-bot").value;if(!a){n.innerHTML=`<span class="err">${t("connectors.errName")}</span>`;return}if(!s){n.innerHTML=`<span class="err">${t("connectors.errBot")}</span>`;return}let o=ae("cn-kind").value,r=ae("cn-mode").value,c={name:a,enabled:!0,target:{kind:o,mode:r,botId:s},promptEnvelope:{sourceName:a}},p=ut("cn-instruction");if(p&&(c.promptEnvelope.instruction=p),o==="workflow"){if(!ut("cn-wf")){n.innerHTML=`<span class="err">${t("connectors.errWf")}</span>`;return}c.target.workflowId=ut("cn-wf")}if(r==="fixed"){let $=ae("cn-chat").style.display!=="none"?ut("cn-chat"):ae("cn-chat-sel").value;if(!$){n.innerHTML=`<span class="err">${t("connectors.errChat")}</span>`;return}c.target.chatId=$}else{let L=Array.from(ae("cn-allow-sel").selectedOptions).map($=>$.value).filter(Boolean);L.length&&(c.target.allowChats=L)}if(r==="new-group"){let L=ut("cn-dedup");c.lifecycleExtractors=L?{dedupKey:L}:null}c.verify={type:ae("cn-verify").value};let k=ut("cn-secret");k&&(c.secret=k),n.innerHTML=`<span class="muted">${t("connectors.creating")}</span>`;let v=await _n("POST","/api/connectors",c);if(v.status===201&&v.body?.ok){n.innerHTML="";let L=ae("cn-created");L.style.display="";let $=v.body.webhookUrl||vo(v.body.connector.id),g=v.body.secret,O=(v.body.connector?.verify?.type??"token")==="token",D=r==="dynamic",R=D?c.target.allowChats?.[0]||"<chatId>":"",I=D?`${i($)}?chatId=${i(R)}`:i($),E;if(O&&D){let d=R!=="<chatId>"?`\uFF08${i(Wn(c.target.allowChats[0]))}\uFF09`:"";E=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicLede",{gn:d})}</p>
|
|
963
963
|
<pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${I}' -H 'content-type: application/json' -d '{}'</code></pre>
|
|
964
964
|
<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicNote")}</p>`}else O?E=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageTokenLede")}</p>
|
|
965
965
|
<pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${I}' -H 'content-type: application/json' -d '{}'</code></pre>
|
|
@@ -967,7 +967,7 @@ ${bo("manage")}
|
|
|
967
967
|
<p class="ok" style="margin:0 0 6px">${t("connectors.createdPrefix",{name:i(a)})}${r==="fixed"&&c.target.chatId?`<span class="muted" style="font-weight:400;font-size:13px"> \xB7 ${t("connectors.createdDest",{name:i(Wn(c.target.chatId))})}</span>`:""}</p>
|
|
968
968
|
<p style="margin:4px 0;font-size:13px"><span class="muted">${t("connectors.webhookUrl")}</span><code style="word-break:break-all">${i($)}</code></p>
|
|
969
969
|
${g?`<p style="margin:4px 0;font-size:13px"><span class="muted">${O?t("connectors.tokenLabel"):t("connectors.signLabel")}${t("connectors.secretOnce")}</span><code>${i(g)}</code></p>`:""}
|
|
970
|
-
${E}</div>`,["cn-name","cn-wf","cn-chat","cn-dedup","cn-secret","cn-instruction"].forEach(d=>{ae(d).value=""}),ae("cn-allow-sel").selectedIndex=-1,sn()}else{let L=v.body?.error||v.status;n.innerHTML=`<span class="err">${t("connectors.createFailed",{error:i(String(L))})}</span>`}},sn()}var
|
|
970
|
+
${E}</div>`,["cn-name","cn-wf","cn-chat","cn-dedup","cn-secret","cn-instruction"].forEach(d=>{ae(d).value=""}),ae("cn-allow-sel").selectedIndex=-1,sn()}else{let L=v.body?.error||v.status;n.innerHTML=`<span class="err">${t("connectors.createFailed",{error:i(String(L))})}</span>`}},sn()}var ke=null,Dt=null,At=!0;function So(e){return{publicReadOnly:e?.publicReadOnly===!0,openTerminalInFeishu:e?.openTerminalInFeishu===!0,repoPickerMode:e?.repoPickerMode==="repos"?"repos":"all",maintenance:e?.maintenance&&typeof e.maintenance=="object"?e.maintenance:{},localDevInstall:e?.localDevInstall===!0}}function Ii(e,n){let a=e?.[n]??{};return{enabled:a.enabled===!0,time:typeof a.time=="string"?a.time:"04:00"}}function Mi(){return`<section class="page">
|
|
971
971
|
<div class="page-heading">
|
|
972
972
|
<div>
|
|
973
973
|
<p class="eyebrow">${t("nav.settings")}</p>
|
|
@@ -976,7 +976,7 @@ ${bo("manage")}
|
|
|
976
976
|
</div>
|
|
977
977
|
</div>
|
|
978
978
|
<div id="settings-body"></div>
|
|
979
|
-
</section>`}function xi(e){let{enabled:n,time:a}=Ii(
|
|
979
|
+
</section>`}function xi(e){let{enabled:n,time:a}=Ii(ke.maintenance,"autoUpdate"),s=e?"disabled":"";return`<label class="toggle-row">
|
|
980
980
|
<input type="checkbox" data-maint="autoUpdate" ${n?"checked":""} ${s}>
|
|
981
981
|
<span class="switch" aria-hidden="true"></span>
|
|
982
982
|
<span class="toggle-tx"><strong>${t("settings.autoUpdate")}</strong>
|
|
@@ -987,17 +987,17 @@ ${bo("manage")}
|
|
|
987
987
|
<input type="time" data-maint-time="autoUpdate" value="${i(a)}" ${s}>
|
|
988
988
|
</label>
|
|
989
989
|
</div>`}function Ei(e){return`<label class="toggle-row">
|
|
990
|
-
<input type="checkbox" data-maint="autoRestart" ${
|
|
990
|
+
<input type="checkbox" data-maint="autoRestart" ${ke.maintenance.autoRestart?.enabled===!0?"checked":""} ${e?"disabled":""}>
|
|
991
991
|
<span class="switch" aria-hidden="true"></span>
|
|
992
992
|
<span class="toggle-tx"><strong>${t("settings.autoRestart")}</strong>
|
|
993
993
|
<small>${t("settings.autoRestartHelp")}</small></span>
|
|
994
|
-
</label>`}function Hi(){if(Dt)return`<p class="hint-warn">${t("settings.loadFailed")}: ${i(Dt)}</p>`;if(!
|
|
994
|
+
</label>`}function Hi(){if(Dt)return`<p class="hint-warn">${t("settings.loadFailed")}: ${i(Dt)}</p>`;if(!ke)return`<p class="empty">${t("settings.loading")}</p>`;let e=At?"":"disabled",n=!At||ke.localDevInstall;return`<div class="settings-grid">
|
|
995
995
|
<article class="bd-card settings-card">
|
|
996
996
|
${At?"":`<p class="hint-warn">${t("settings.readOnlyVisitor")}</p>`}
|
|
997
997
|
<section class="bd-section">
|
|
998
998
|
<h3 class="bd-section-title">${t("settings.sectionAccess")}</h3>
|
|
999
999
|
<label class="toggle-row">
|
|
1000
|
-
<input type="checkbox" data-setting="publicReadOnly" ${
|
|
1000
|
+
<input type="checkbox" data-setting="publicReadOnly" ${ke.publicReadOnly?"checked":""} ${e}>
|
|
1001
1001
|
<span class="switch" aria-hidden="true"></span>
|
|
1002
1002
|
<span class="toggle-tx"><strong>${t("settings.publicReadOnly")}</strong>
|
|
1003
1003
|
<small>${t("settings.publicReadOnlyHelp")}</small></span>
|
|
@@ -1006,23 +1006,34 @@ ${bo("manage")}
|
|
|
1006
1006
|
<section class="bd-section">
|
|
1007
1007
|
<h3 class="bd-section-title">${t("settings.sectionCards")}</h3>
|
|
1008
1008
|
<label class="toggle-row">
|
|
1009
|
-
<input type="checkbox" data-setting="openTerminalInFeishu" ${
|
|
1009
|
+
<input type="checkbox" data-setting="openTerminalInFeishu" ${ke.openTerminalInFeishu?"checked":""} ${e}>
|
|
1010
1010
|
<span class="switch" aria-hidden="true"></span>
|
|
1011
1011
|
<span class="toggle-tx"><strong>${t("settings.openTerminalInFeishu")}</strong>
|
|
1012
1012
|
<small>${t("settings.openTerminalInFeishuHelp")}</small></span>
|
|
1013
1013
|
</label>
|
|
1014
1014
|
</section>
|
|
1015
|
+
<section class="bd-section">
|
|
1016
|
+
<h3 class="bd-section-title">${t("settings.sectionRepoPicker")}</h3>
|
|
1017
|
+
<label class="form-row">
|
|
1018
|
+
<span>${t("settings.repoPickerMode")}</span>
|
|
1019
|
+
<select data-select-setting="repoPickerMode" ${e}>
|
|
1020
|
+
<option value="all" ${ke.repoPickerMode==="all"?"selected":""}>${t("settings.repoPickerModeAll")}</option>
|
|
1021
|
+
<option value="repos" ${ke.repoPickerMode==="repos"?"selected":""}>${t("settings.repoPickerModeRepos")}</option>
|
|
1022
|
+
</select>
|
|
1023
|
+
<small>${t("settings.repoPickerModeHelp")}</small>
|
|
1024
|
+
</label>
|
|
1025
|
+
</section>
|
|
1015
1026
|
<section class="bd-section">
|
|
1016
1027
|
<h3 class="bd-section-title">${t("settings.sectionMaintenance")}</h3>
|
|
1017
1028
|
${xi(n)}
|
|
1018
|
-
${
|
|
1019
|
-
${Ei(!At||
|
|
1029
|
+
${ke.localDevInstall?`<p class="hint-warn">${t("settings.autoUpdateLocalDev")}</p>`:""}
|
|
1030
|
+
${Ei(!At||ke.maintenance.autoUpdate?.enabled!==!0)}
|
|
1020
1031
|
</section>
|
|
1021
1032
|
<div class="actions settings-actions">
|
|
1022
1033
|
<span class="oncall-status" data-settings-status></span>
|
|
1023
1034
|
</div>
|
|
1024
1035
|
</article>
|
|
1025
|
-
</div>`}async function Ci(){try{let e=await fetch("/api/settings"),n=await e.json().catch(()=>({}));if(!e.ok){
|
|
1036
|
+
</div>`}async function Ci(){try{let e=await fetch("/api/settings"),n=await e.json().catch(()=>({}));if(!e.ok){ke=null,Dt=n?.error??`HTTP ${e.status}`;return}ke=So(n.settings),At=n.authed===!0,Dt=null}catch(e){ke=null,Dt=e?.message??String(e)}}async function To(e){e.innerHTML=Mi();let n=e.querySelector("#settings-body");function a(){n.innerHTML=Hi(),r()}function s(){return n.querySelector("[data-settings-status]")}async function o(c,p,k){if(!ke)return;k.disabled=!0;let v=s();v&&(v.textContent=t("settings.saving"),v.className="oncall-status");try{let L=await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(c)}),$=await L.json().catch(()=>({}));if(!L.ok||$.ok===!1)throw new Error($?.error??`HTTP ${L.status}`);ke=So($.settings),v&&(v.textContent=t("settings.saved"),v.classList.add("hint-ok"))}catch(L){p(),v&&(v.textContent=`${t("settings.saveFailed")}: ${L?.message??L}`,v.classList.add("hint-warn-inline"))}finally{k.disabled=!1}}function r(){n.querySelectorAll("input[data-setting]").forEach(p=>{p.addEventListener("change",()=>{let k=p.dataset.setting,v=!p.checked;o({[k]:p.checked},()=>{p.checked=v},p)})}),n.querySelectorAll("select[data-select-setting]").forEach(p=>{p.addEventListener("change",()=>{let k=p.dataset.selectSetting,v=ke?.[k]??"all";o({[k]:p.value},()=>{p.value=v},p)})});let c=(p,k,v)=>{let $=n.querySelector(`input[data-maint="${p}"]`)?.checked??!1,g;if(p==="autoUpdate"){let O=n.querySelector('input[data-maint-time="autoUpdate"]');g={enabled:$,time:O?.value||"04:00"}}else g={enabled:$};o({maintenance:{[p]:g}},v,k).then(()=>a())};n.querySelectorAll("input[data-maint]").forEach(p=>{p.addEventListener("change",()=>{let k=p.dataset.maint,v=!p.checked;c(k,p,()=>{p.checked=v})})}),n.querySelectorAll("input[data-maint-time]").forEach(p=>{p.addEventListener("change",()=>{let k=p.dataset.maintTime,v=p.defaultValue;c(k,p,()=>{p.value=v})})})}a(),await Ci(),a()}function Ai(){let e=[["",t("workflow.filter.nonTerminal")],["all",t("workflow.filter.all")],["pending",st("pending")],["running",st("running")],["waiting",st("waiting")],["succeeded",st("succeeded")],["failed",st("failed")],["cancelled",st("cancelled")]];return`
|
|
1026
1037
|
<nav class="wf-subnav">
|
|
1027
1038
|
<a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${h(t("workflow.subnav.runs"))}</a>
|
|
1028
1039
|
<a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${h(t("workflow.subnav.catalog"))}</a>
|
|
@@ -1042,7 +1053,7 @@ ${bo("manage")}
|
|
|
1042
1053
|
</tr></thead>
|
|
1043
1054
|
<tbody id="wf-tbody"></tbody>
|
|
1044
1055
|
</table>
|
|
1045
|
-
`}var Di=5e3,Ri=2e3,Rt=new Set(["succeeded","failed","cancelled"]);function h(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function Oi(e){let n=new Date(e),s=Date.now()-e;return s<6e4?t("time.secondsAgo",{value:Math.max(1,Math.floor(s/1e3))}):s<36e5?t("time.minutesAgo",{value:Math.floor(s/6e4)}):s<864e5?t("time.hoursAgo",{value:Math.floor(s/36e5)}):n.toISOString().slice(0,19).replace("T"," ")}function Xe(e){return`<span class="${Rt.has(e)?"wf-status terminal":"wf-status live"} wf-status-${h(e)}">${h(st(e))}</span>`}function st(e){let n=`workflow.status.${e}`,a=t(n);return a===n?e:a}function xo(e){let n=location.hash.match(/^#\/workflows\/([^?#]+)(?:\?([^#]*))?$/);if(n){let a=new URLSearchParams(n[2]??"");return Ni(e,decodeURIComponent(n[1]),{focusAttemptId:a.get("attempt")??void 0})}return Bi(e)}function Bi(e){e.innerHTML=Ai();let n=e.querySelector("#wf-tbody"),a=e.querySelector("#wf-filters"),s=e.querySelector("#wf-last-load"),o=[],r=null,c=!1,
|
|
1056
|
+
`}var Di=5e3,Ri=2e3,Rt=new Set(["succeeded","failed","cancelled"]);function h(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function Oi(e){let n=new Date(e),s=Date.now()-e;return s<6e4?t("time.secondsAgo",{value:Math.max(1,Math.floor(s/1e3))}):s<36e5?t("time.minutesAgo",{value:Math.floor(s/6e4)}):s<864e5?t("time.hoursAgo",{value:Math.floor(s/36e5)}):n.toISOString().slice(0,19).replace("T"," ")}function Xe(e){return`<span class="${Rt.has(e)?"wf-status terminal":"wf-status live"} wf-status-${h(e)}">${h(st(e))}</span>`}function st(e){let n=`workflow.status.${e}`,a=t(n);return a===n?e:a}function xo(e){let n=location.hash.match(/^#\/workflows\/([^?#]+)(?:\?([^#]*))?$/);if(n){let a=new URLSearchParams(n[2]??"");return Ni(e,decodeURIComponent(n[1]),{focusAttemptId:a.get("attempt")??void 0})}return Bi(e)}function Bi(e){e.innerHTML=Ai();let n=e.querySelector("#wf-tbody"),a=e.querySelector("#wf-filters"),s=e.querySelector("#wf-last-load"),o=[],r=null,c=!1,p=null,k=!1;function v(R){let E=(new FormData(a).get("q")??"").trim().toLowerCase();return E?R.filter(d=>d.runId.toLowerCase().includes(E)||d.workflowId.toLowerCase().includes(E)||(d.chatId??"").toLowerCase().includes(E)):R}function L(){let R=v(o);if(R.length===0){n.innerHTML=`<tr><td colspan="7" class="empty">${p?h(t("workflow.list.failedLoad",{error:p})):o.length===0?h(t("workflow.list.noRuns")):h(t("workflow.list.noFilterMatch"))}</td></tr>`;return}n.innerHTML=R.map(I=>{let E=`${I.dEf}/${I.dAct}/${I.dWait}`,d=I.dEf+I.dAct+I.dWait>0?"wf-dangling has":"wf-dangling none",y=[];I.chatId&&y.push(h(I.chatId)),I.larkAppId&&y.push(`<span class="muted">${h(I.larkAppId)}</span>`);let H=y.length>0?y.join("<br/>"):"\u2014",M=qi(I);return`<tr data-runid="${h(I.runId)}">
|
|
1046
1057
|
<td><a href="#/workflows/${encodeURIComponent(I.runId)}"><code>${h(I.runId)}</code></a></td>
|
|
1047
1058
|
<td>${h(I.workflowId)}</td>
|
|
1048
1059
|
<td>${Xe(I.status)}${I.failedNodeId?` <span class="muted">(${h(I.failedNodeId)})</span>`:""}${M}</td>
|
|
@@ -1050,7 +1061,7 @@ ${bo("manage")}
|
|
|
1050
1061
|
<td class="${d}">${E}</td>
|
|
1051
1062
|
<td title="${h(new Date(I.updatedAt).toISOString())}">${Oi(I.updatedAt)}</td>
|
|
1052
1063
|
<td>${H}</td>
|
|
1053
|
-
</tr>`}).join("")}function $(){
|
|
1064
|
+
</tr>`}).join("")}function $(){p?(s.textContent=t("workflow.list.error",{error:p}),s.classList.add("error")):(s.textContent=t("workflow.list.loaded",{count:o.length,time:new Date().toLocaleTimeString()}),s.classList.remove("error"))}async function g(){if(!(k||c)&&!document.hidden){c=!0;try{let R=a.elements.namedItem("status")?.value??"",I=new URLSearchParams;R==="all"?I.set("all","1"):R&&I.set("status",R);let E="/api/workflows/runs"+(I.toString()?`?${I}`:""),d=await fetch(E);d.ok?(o=(await d.json()).runs??[],p=null):(p=`HTTP ${d.status}`,o=[])}catch(R){p=R?.message??String(R),o=[]}finally{c=!1,k||(L(),$())}}}function O(){r!==null&&window.clearTimeout(r),r=window.setTimeout(async()=>{await g(),k||O()},Di)}function D(){document.hidden||g()}return a.addEventListener("input",()=>{L()}),a.addEventListener("change",R=>{R.target.getAttribute("name")==="status"&&g()}),document.addEventListener("visibilitychange",D),g().then(()=>{k||O()}),()=>{k=!0,r!==null&&window.clearTimeout(r),document.removeEventListener("visibilitychange",D)}}function Ni(e,n,a={}){e.innerHTML=`
|
|
1054
1065
|
<div class="wf-detail-head">
|
|
1055
1066
|
<a class="btn-link" href="#/workflows">${h(t("workflow.detail.back"))}</a>
|
|
1056
1067
|
<div>
|
|
@@ -1106,19 +1117,19 @@ ${bo("manage")}
|
|
|
1106
1117
|
</div>
|
|
1107
1118
|
<div id="wf-event-meta" class="muted"></div>
|
|
1108
1119
|
</section>
|
|
1109
|
-
`;let s=e.querySelector("#wf-detail-subtitle"),o=e.querySelector("#wf-detail-refresh"),r=e.querySelector("#wf-detail-error"),c=e.querySelector("#wf-cancel-status"),
|
|
1120
|
+
`;let s=e.querySelector("#wf-detail-subtitle"),o=e.querySelector("#wf-detail-refresh"),r=e.querySelector("#wf-detail-error"),c=e.querySelector("#wf-cancel-status"),p=e.querySelector("#wf-summary"),k=e.querySelector("#wf-dangling-panel"),v=e.querySelector("#wf-parallel-view"),L=e.querySelector("#wf-parallel-meta"),$=e.querySelector("#wf-node-tbody"),g=e.querySelector("#wf-io-list"),O=e.querySelector(".wf-timeline-scroll"),D=e.querySelector("#wf-event-tbody"),R=e.querySelector("#wf-event-meta"),I=e.querySelector("#wf-cancel-run"),E=e.querySelector("#wf-load-older"),d=null,y=[],H=new Set,M=null,S=null,A=!1,B=0,_=null,j=!1,Q=!1,le=!1,He=new Set,ge=new Map,J=new Map,se=new Map,Te=new Set,Re=new Map,ee=new Set,ue=new Map,de=new Map,qe=0,$e=a.focusAttemptId;function be(x){if(!x){r.hidden=!0,r.textContent="";return}r.hidden=!1,r.textContent=x}function re(x){if(!x){c.hidden=!0,c.textContent="";return}c.hidden=!1,c.textContent=x}async function Ce(){let x=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/snapshot`);if(x.status===404)throw new Error(t("workflow.detail.unknownRun"));if(!x.ok)throw new Error(t("workflow.detail.snapshotHttp",{status:x.status}));d=await x.json()}async function Ae(x){let ie=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/events?${x}`);if(ie.status===404)throw new Error(t("workflow.detail.unknownRun"));if(!ie.ok)throw new Error(t("workflow.detail.eventsHttp",{status:ie.status}));return await ie.json()}function ce(x,ie){let U=x.filter(G=>H.has(G.eventId)?!1:(H.add(G.eventId),!0));U.length!==0&&(y=ie==="prepend"?[...U,...y]:[...y,...U],y.sort((G,he)=>Ot(G.eventId)-Ot(he.eventId)))}async function je(){await Ce();let x=await Ae(new URLSearchParams({tail:"100"}));y=[],H=new Set,ce(x.events,"append"),M=x.oldestSeq,S=x.newestSeq,A=x.hasOlder,B=x.totalCount,oe()}async function Ze(){if(!(j||Q||document.hidden)){Q=!0;try{if(await Ce(),S!==null){let x=await Ae(new URLSearchParams({afterSeq:String(S),limit:"200"}));ce(x.events,"append"),x.newestSeq!==null&&(S=x.newestSeq),M===null&&x.oldestSeq!==null&&(M=x.oldestSeq),B=x.totalCount}else{let x=await Ae(new URLSearchParams({tail:"1"}));ce(x.events,"append"),M=x.oldestSeq,S=x.newestSeq,A=x.hasOlder,B=x.totalCount}be(null),oe()}catch(x){be(x?.message??String(x))}finally{Q=!1}}}async function et(){if(!(M===null||!A)){E.disabled=!0;try{let x=await Ae(new URLSearchParams({beforeSeq:String(M),limit:"100"}));ce(x.events,"prepend"),x.oldestSeq!==null&&(M=x.oldestSeq),A=x.hasOlder,B=x.totalCount,be(null),oe()}catch(x){be(x?.message??String(x))}finally{E.disabled=!1}}}async function ft(){if(!d||Rt.has(d.run.status)||le)return;if(!d.chatBinding?.larkAppId){be(t("workflow.detail.cancelUnavailable",{runId:n}));return}let x=Ui(d),ie=t("workflow.detail.cancelConfirm",{runId:n,...x});if(window.confirm(ie)){le=!0,I.disabled=!0;try{let U=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/cancel`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"cancelled via dashboard"})});if(U.status===401)throw new Error(t("workflow.detail.writeAccessCancel"));let G=await U.json().catch(()=>({}));if(!U.ok||!G.ok)throw new Error(G.hint??G.error??t("workflow.detail.cancelHttp",{status:U.status}));re(G.pending?t("workflow.detail.cancelPending"):null),be(null),await Ze()}catch(U){be(U?.message??String(U))}finally{le=!1,I.disabled=!1,oe()}}}async function it(x,ie){if(!ee.has(x)){ee.add(x),ue.delete(x),oe();try{let U=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/attempts/${encodeURIComponent(ie)}/${encodeURIComponent(x)}/resume`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});if(U.status===401)throw new Error(t("workflow.detail.writeAccessResume"));let G=await U.json().catch(()=>({}));if(!U.ok||!G.ok||!G.resumeId||!G.url)throw new Error(G.hint??G.message??G.error??t("workflow.detail.resumeStartFailed",{status:U.status}));Re.set(x,{resumeId:G.resumeId,url:G.url})}catch(U){let G=U?.message??String(U);ue.set(x,G)}finally{ee.delete(x),oe()}}}async function Ye(x,ie){if(!ee.has(x)){ee.add(x),ue.delete(x),oe();try{let U=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/attempts/${encodeURIComponent(ie)}/${encodeURIComponent(x)}/resume/end`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"ended_by_dashboard"})});if(U.status===401)throw new Error(t("workflow.detail.writeAccessResume"));let G=await U.json().catch(()=>({}));if(!U.ok||!G.ok)if(G.error==="resume_not_running")Re.delete(x);else throw new Error(G.hint??G.message??G.error??t("workflow.detail.resumeEndFailed",{status:U.status}));else Re.delete(x)}catch(U){let G=U?.message??String(U);ue.set(x,G)}finally{ee.delete(x),oe()}}}async function Ve(x,ie){if(!Te.has(x)){Te.add(x),se.delete(x),oe();try{let U=J.get(x)?.trim()||void 0,G=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/${ie}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({comment:U})});if(G.status===401)throw new Error(t("workflow.detail.writeAccessApproval"));let he=await G.json().catch(()=>({}));if(!G.ok||!he.ok)throw new Error(he.hint??he.message??he.error??t("workflow.detail.actionHttp",{action:ie,status:G.status}));let gt=ie==="approve"?t("workflow.detail.approved"):t("workflow.detail.rejected");se.set(x,{kind:"ok",text:he.alreadyTerminal?t("workflow.detail.alreadyTerminal",{label:gt}):he.pending?t("workflow.detail.workflowContinue",{label:gt}):t("workflow.detail.workflowRefreshing",{label:gt})}),be(null),await Ze()}catch(U){let G=U?.message??String(U);se.set(x,{kind:"error",text:G}),be(G)}finally{Te.delete(x),oe()}}}function oe(){if(!d)return;qe=O.scrollTop;let x=d.run;Rt.has(x.status)&&re(null),s.innerHTML=`${h(x.workflowId??"?")} \xB7 ${Xe(x.status)} \xB7 lastSeq ${d.lastSeq}`,o.textContent=t("workflow.detail.refreshed",{time:new Date().toLocaleTimeString()}),I.hidden=Rt.has(x.status),I.disabled=le||!d.chatBinding?.larkAppId,I.textContent=d.chatBinding?.larkAppId?t("workflow.detail.cancel"):t("workflow.detail.cliCancelOnly"),I.title=d.chatBinding?.larkAppId?t("workflow.detail.cancelTitle"):t("workflow.detail.cliCancelTitle",{runId:n}),Pi(p,d),ji(k,d),Fi(v,L,d,y),Ji($,d),Yi(g,d,He,ge,{comments:J,statuses:se,resolving:Te,onResolve:Ve},{sessions:Re,pending:ee,errors:ue,onStart:it,onEnd:Ye},$e,de)&&($e=void 0),kr(D,y),O.scrollTop=qe,E.hidden=!A,R.textContent=t("workflow.detail.eventsLoaded",{loaded:y.length,total:B})}function Ue(){if(_!==null&&window.clearTimeout(_),d&&Rt.has(d.run.status)){_=null;return}_=window.setTimeout(async()=>{await Ze(),j||Ue()},Ri)}function Oe(){document.hidden||Ze().then(()=>{!j&&_===null&&Ue()})}return E.addEventListener("click",()=>{et()}),I.addEventListener("click",()=>{ft()}),document.addEventListener("visibilitychange",Oe),je().then(()=>{be(null),j||Ue()}).catch(x=>{be(x?.message??String(x)),s.textContent=t("workflow.detail.loadFailed")}),()=>{j=!0,_!==null&&window.clearTimeout(_),document.removeEventListener("visibilitychange",Oe)}}function Pi(e,n){let a=n.run,s=[[t("workflow.summary.workflow"),h(a.workflowId??"?")],[t("workflow.summary.status"),Xe(a.status)],[t("workflow.summary.lastSeq"),String(n.lastSeq)],[t("workflow.summary.updated"),h(new Date(n.updatedAt).toLocaleString())],[t("workflow.summary.revision"),h(dn(a.revisionId))],[t("workflow.summary.initiator"),h(a.initiator??"-")]];a.failedNodeId&&s.push([t("workflow.summary.failedNode"),h(a.failedNodeId)]),a.cancelOriginEventId&&s.push([t("workflow.summary.cancelOrigin"),h(a.cancelOriginEventId)]),n.chatBinding&&(s.push([t("workflow.summary.chat"),`<code>${h(n.chatBinding.chatId)}</code>`]),s.push([t("workflow.summary.app"),`<code>${h(n.chatBinding.larkAppId)}</code>`])),e.innerHTML=s.map(([o,r])=>`<div class="wf-summary-item"><span>${o}</span><strong>${r}</strong></div>`).join("")}function qi(e){if(!e.errorCode)return"";let n=e.errorMessage?` \u2014 ${Lr(e.errorMessage,96)}`:"";return`<div class="wf-run-error">
|
|
1110
1121
|
<span class="muted error">${h(e.errorCode)}</span>${h(n)}
|
|
1111
1122
|
</div>`}function Ui(e){let n=e.dangling;return{total:new Set([...n.activities,...n.effectAttempted,...n.waits,...n.cancels]).size,effects:n.effectAttempted.length,activities:n.activities.length,waits:n.waits.length,cancels:n.cancels.length}}function ji(e,n){let a=n.dangling,s=[[t("workflow.dangling.activities"),a.activities],[t("workflow.dangling.effects"),a.effectAttempted],[t("workflow.dangling.waits"),a.waits],[t("workflow.dangling.cancels"),a.cancels]],o=new Set(s.flatMap(([,r])=>r)).size;if(e.className=o>0?"wf-panel wf-dangling-panel has":"wf-panel wf-dangling-panel",o===0){e.innerHTML=`<div class="wf-panel-title"><h3>${h(t("workflow.detail.dangling"))}</h3></div><div class="muted">${h(t("workflow.detail.noDangling"))}</div>`;return}e.innerHTML=`<div class="wf-panel-title"><h3>${h(t("workflow.detail.dangling"))}</h3><span class="wf-dangling has">${o}</span></div>
|
|
1112
1123
|
<div class="wf-dangling-grid">
|
|
1113
|
-
${s.map(([r,c])=>`<div><strong>${r}</strong>${c.length===0?`<div class="muted">${h(t("workflow.detail.none"))}</div>`:`<ul>${c.map(
|
|
1114
|
-
</div>`}function Fi(e,n,a,s){let o=Gi(s,a);if(o.length===0){n.textContent="",e.innerHTML=`<div class="empty">${h(t("workflow.detail.noParallelData"))}</div>`;return}let r=Date.now(),c=Math.min(...o.map(g=>g.startedAt)),
|
|
1124
|
+
${s.map(([r,c])=>`<div><strong>${r}</strong>${c.length===0?`<div class="muted">${h(t("workflow.detail.none"))}</div>`:`<ul>${c.map(p=>`<li><code>${h(p)}</code></li>`).join("")}</ul>`}</div>`).join("")}
|
|
1125
|
+
</div>`}function Fi(e,n,a,s){let o=Gi(s,a);if(o.length===0){n.textContent="",e.innerHTML=`<div class="empty">${h(t("workflow.detail.noParallelData"))}</div>`;return}let r=Date.now(),c=Math.min(...o.map(g=>g.startedAt)),p=Math.max(...o.map(g=>g.endedAt??r),c+1e3),k=Math.max(1,p-c),v=zi(o,r),L=o.filter(g=>!g.endedAt&&(g.status==="running"||g.status==="effectAttempting")).length;n.textContent=t("workflow.detail.parallelMeta",{count:o.length,max:v,running:L});let $=o.sort((g,O)=>g.startedAt-O.startedAt||g.activityId.localeCompare(O.activityId)).map(g=>_i(g,c,k,r)).join("");e.innerHTML=`<div class="wf-parallel-axis">
|
|
1115
1126
|
<span title="${h(new Date(c).toISOString())}">${h(ln(c))}</span>
|
|
1116
|
-
<span title="${h(new Date(
|
|
1127
|
+
<span title="${h(new Date(p).toISOString())}">${h(ln(p))}</span>
|
|
1117
1128
|
</div>
|
|
1118
|
-
<div class="wf-parallel-list">${$}</div>`}function Gi(e,n){let a=new Map,s=new Map(n.activities.map(o=>[o.activityId,o.ownerNodeId]));for(let o of[...e].sort((r,c)=>Ot(r.eventId)-Ot(c.eventId))){let r=Tr(o);if(!r)continue;let c=typeof r.activityId=="string"?r.activityId:void 0,
|
|
1129
|
+
<div class="wf-parallel-list">${$}</div>`}function Gi(e,n){let a=new Map,s=new Map(n.activities.map(o=>[o.activityId,o.ownerNodeId]));for(let o of[...e].sort((r,c)=>Ot(r.eventId)-Ot(c.eventId))){let r=Tr(o);if(!r)continue;let c=typeof r.activityId=="string"?r.activityId:void 0,p=typeof r.attemptId=="string"?r.attemptId:void 0;if(!c||!p)continue;let k=a.get(p);if(o.type==="attemptCreated"){let v=typeof r.attemptNumber=="number"?r.attemptNumber:void 0;k={nodeId:typeof r.nodeId=="string"?r.nodeId:s.get(c),activityId:c,attemptId:p,attemptNumber:v,status:"pending",startedAt:o.timestamp},a.set(p,k);continue}k||(k={nodeId:s.get(c),activityId:c,attemptId:p,status:"pending",startedAt:o.timestamp},a.set(p,k)),o.type==="activityRunning"?(k.status="running",k.runningAt=o.timestamp):o.type==="effectAttempted"?k.status="effectAttempting":o.type==="activityWaiting"||o.type==="waitCreated"?k.status="waiting":Wi(o.type)&&(k.status=Ki(o.type),k.endedAt=o.timestamp,k.endType=o.type)}return[...a.values()]}function _i(e,n,a,s){let o=e.endedAt??s,r=Mo((e.startedAt-n)/a*100,0,100),c=Mo((Math.max(o,e.startedAt+1)-e.startedAt)/a*100,.7,100-r),p=e.nodeId??e.activityId,k=e.attemptNumber!==void 0?`#${e.attemptNumber}`:dn(e.attemptId),v=[`${p} ${e.status}`,`${new Date(e.startedAt).toISOString()} \u2192 ${e.endedAt?new Date(e.endedAt).toISOString():t("workflow.detail.parallelNow")}`,e.endType?`end: ${e.endType}`:void 0].filter(Boolean).join(`
|
|
1119
1130
|
`);return`<div class="wf-parallel-row">
|
|
1120
1131
|
<div class="wf-parallel-label">
|
|
1121
|
-
<code>${h(
|
|
1132
|
+
<code>${h(p)}</code>
|
|
1122
1133
|
<span class="muted">${h(e.activityId)} \xB7 ${h(k)}</span>
|
|
1123
1134
|
</div>
|
|
1124
1135
|
<div class="wf-parallel-track">
|
|
@@ -1126,7 +1137,7 @@ ${bo("manage")}
|
|
|
1126
1137
|
<span>${h(st(e.status))}</span>
|
|
1127
1138
|
</div>
|
|
1128
1139
|
</div>
|
|
1129
|
-
</div>`}function zi(e,n){let a=[];for(let r of e)a.push({time:r.startedAt,delta:1}),a.push({time:r.endedAt??n,delta:-1});a.sort((r,c)=>r.time-c.time||c.delta-r.delta);let s=0,o=0;for(let r of a)s+=r.delta,o=Math.max(o,s);return o}function Wi(e){return e==="activitySucceeded"||e==="activityFailed"||e==="activityTimedOut"||e==="activityCanceled"}function Ki(e){return e==="activitySucceeded"?"succeeded":e==="activityCanceled"?"cancelled":e==="activityTimedOut"?"timedOut":"failed"}function Ji(e,n){let a=new Map(n.activities.map(r=>[r.activityId,r])),s=new Set,o=[];for(let r of n.nodes){let c=(r.activityId?a.get(r.activityId):void 0)??n.activities.find(
|
|
1140
|
+
</div>`}function zi(e,n){let a=[];for(let r of e)a.push({time:r.startedAt,delta:1}),a.push({time:r.endedAt??n,delta:-1});a.sort((r,c)=>r.time-c.time||c.delta-r.delta);let s=0,o=0;for(let r of a)s+=r.delta,o=Math.max(o,s);return o}function Wi(e){return e==="activitySucceeded"||e==="activityFailed"||e==="activityTimedOut"||e==="activityCanceled"}function Ki(e){return e==="activitySucceeded"?"succeeded":e==="activityCanceled"?"cancelled":e==="activityTimedOut"?"timedOut":"failed"}function Ji(e,n){let a=new Map(n.activities.map(r=>[r.activityId,r])),s=new Set,o=[];for(let r of n.nodes){let c=(r.activityId?a.get(r.activityId):void 0)??n.activities.find(p=>p.ownerNodeId===r.nodeId);c&&s.add(c.activityId),o.push(Lo(r,c))}for(let r of n.activities)s.has(r.activityId)||o.push(Lo(void 0,r));e.innerHTML=o.length>0?o.join(""):`<tr><td colspan="7" class="empty">${h(t("workflow.detail.noNodes"))}</td></tr>`}function Lo(e,n){let a=n?.attempts[n.attempts.length-1];return`<tr>
|
|
1130
1141
|
<td>${e?`<code>${h(e.nodeId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
1131
1142
|
<td>${e?Xe(e.status):'<span class="muted">-</span>'}</td>
|
|
1132
1143
|
<td>${n?`<code>${h(n.activityId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
@@ -1134,10 +1145,10 @@ ${bo("manage")}
|
|
|
1134
1145
|
<td>${n?.attempts.length??0}</td>
|
|
1135
1146
|
<td>${a?`<code>${h(a.attemptId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
1136
1147
|
<td>${a?vr(a):`<span class="muted">${h(t("workflow.detail.idle"))}</span>`}</td>
|
|
1137
|
-
</tr>`}function Yi(e,n,a,s,o,r,c,
|
|
1148
|
+
</tr>`}function Yi(e,n,a,s,o,r,c,p){fr(e,a,s),cr(e,o.comments);let k=!!(c&&n.attemptIO?.[c]?.terminal);k&&c&&a.add(Jn(c,t("workflow.detail.liveTerminal")));let v=Vi(n),L=new Set;if(p){for(let g of v){L.add(g.key);let O=p.get(g.key);O||(O=Qi(g.key),p.set(g.key,O),e.appendChild(O.article)),Xi(O,g,a,o,r,c)}for(let[g,O]of Array.from(p))L.has(g)||(O.article.remove(),p.delete(g));if(v.length===0){if(!e.querySelector(".wf-io-empty-placeholder")){let g=document.createElement("div");g.className="empty wf-io-empty-placeholder",g.textContent=t("workflow.detail.noNodeIO"),e.appendChild(g)}}else e.querySelector(".wf-io-empty-placeholder")?.remove()}else{let g=[];for(let O of v)g.push(ar(O,a,o,r,c));e.innerHTML=g.length>0?g.join(""):`<div class="empty">${h(t("workflow.detail.noNodeIO"))}</div>`}br(e,s);let $=mr(e,c);return gr(e,a),hr(e,s),pr(e,o),No(e,r),$&&k}function Vi(e){let n=new Map(e.activities.map(o=>[o.activityId,o])),a=new Set,s=[];for(let o of e.nodes){let r=(o.activityId?n.get(o.activityId):void 0)??e.activities.find(c=>c.ownerNodeId===o.nodeId);if(!r){s.push({key:`node:${o.nodeId}`,node:o});continue}a.add(r.activityId),s.push({key:`activity:${r.activityId}`,node:o,activity:r,io:e.attemptIO?.[rn(r)?.attemptId??""]})}for(let o of e.activities)a.has(o.activityId)||s.push({key:`activity:${o.activityId}`,activity:o,io:e.attemptIO?.[rn(o)?.attemptId??""]});return s}function Qi(e){let n=document.createElement("article");n.className="wf-io-card",n.dataset.wfCardKey=e;let a=document.createElement("div");a.className="wf-io-card-head";let s=document.createElement("div");s.className="wf-io-terminal-slot";let o=document.createElement("div");return o.className="wf-io-grid",n.appendChild(a),n.appendChild(s),n.appendChild(o),{article:n,head:a,terminalSlot:s,grid:o,currentTerminalUrl:null}}function Xi(e,n,a,s,o,r){let c=rn(n.activity),p=n.node?.nodeId??n.activity?.ownerNodeId??n.activity?.activityId??"unknown",k=!!(c&&c.attemptId===r);e.article.classList.toggle("is-focused",k),c?e.article.dataset.wfAttemptCard=c.attemptId:delete e.article.dataset.wfAttemptCard;let v=Bo(c,s);e.head.innerHTML=`
|
|
1138
1149
|
<header>
|
|
1139
1150
|
<div>
|
|
1140
|
-
<strong><code>${h(
|
|
1151
|
+
<strong><code>${h(p)}</code></strong>
|
|
1141
1152
|
<span class="muted">${n.activity?h(n.activity.activityId):h(t("workflow.detail.notDispatched"))}</span>
|
|
1142
1153
|
</div>
|
|
1143
1154
|
<div>${n.node?Xe(n.node.status):""} ${n.activity?Xe(n.activity.status):""}</div>
|
|
@@ -1152,16 +1163,16 @@ ${bo("manage")}
|
|
|
1152
1163
|
${Je(g,t("workflow.detail.output"),n.io?.output,a)}
|
|
1153
1164
|
${Je(g,t("workflow.detail.executionLog"),n.io?.log,a)}
|
|
1154
1165
|
${n.io?.waitPrompt?Je(g,t("workflow.detail.waitPrompt"),n.io.waitPrompt,a):""}
|
|
1155
|
-
`}function Eo(e,n,a,s){if(!a||a.error)return null;if(or(e,a))return{kind:"live",url:ir(a)};if(!e||!n||!sr(e,a))return null;let o=lr();if(!o)return null;let r=s?.sessions.get(e.attemptId);return r?{kind:"resume",url:r.url,resumeId:r.resumeId,downloadUrl:Io(o,n.activityId,e.attemptId)}:{kind:"replay",url:rr(o,n.activityId,e.attemptId,!!a.hasPtyLog),downloadUrl:Io(o,n.activityId,e.attemptId)}}function Ho(e,n,a,s,o,r,c){if(!s)return"";let
|
|
1156
|
-
<summary>${h(
|
|
1166
|
+
`}function Eo(e,n,a,s){if(!a||a.error)return null;if(or(e,a))return{kind:"live",url:ir(a)};if(!e||!n||!sr(e,a))return null;let o=lr();if(!o)return null;let r=s?.sessions.get(e.attemptId);return r?{kind:"resume",url:r.url,resumeId:r.resumeId,downloadUrl:Io(o,n.activityId,e.attemptId)}:{kind:"replay",url:rr(o,n.activityId,e.attemptId,!!a.hasPtyLog),downloadUrl:Io(o,n.activityId,e.attemptId)}}function Ho(e,n,a,s,o,r,c){if(!s)return"";let p=Co(o.kind),k=Jn(e,p),v=Oo(n,s),L=Zi(o.kind),$=o.kind==="replay"||o.kind==="resume"?`<a class="btn-link" href="${h(o.downloadUrl)}" download>${h(t("workflow.detail.downloadFullLog"))}</a>`:"",g=n?Do(n,a,s,o,c):"",O=n?Ro(n.attemptId,c):"";return`<details class="wf-io-block wf-terminal-block" data-io-key="${h(k)}"${r.has(k)?" open":""}>
|
|
1167
|
+
<summary>${h(p)} ${v}</summary>
|
|
1157
1168
|
<div class="wf-terminal-actions">
|
|
1158
1169
|
<a class="btn-link" href="${h(o.url)}" target="_blank" rel="noreferrer">${h(L)}</a>
|
|
1159
1170
|
${$}
|
|
1160
1171
|
${g}
|
|
1161
1172
|
</div>
|
|
1162
1173
|
${O}
|
|
1163
|
-
<iframe class="wf-terminal-frame" src="${h(o.url)}" title="${h(
|
|
1164
|
-
</details>`}function Co(e){return e==="live"?t("workflow.detail.liveTerminal"):e==="resume"?t("workflow.detail.terminalResume"):t("workflow.detail.terminalReplay")}function Zi(e){return e==="live"?t("workflow.detail.openTerminalNewTab"):e==="resume"?t("workflow.detail.openResumeNewTab"):t("workflow.detail.openReplayNewTab")}var Ao=new Set(["antigravity","codex-app","cursor","mira"]),er=new Set(["aiden","coco","claude-code","seed","codex","mtr","hermes","pi"]);function tr(e){return!!e&&(er.has(e)||Ao.has(e))}function nr(e){return!!e&&Ao.has(e)}function Do(e,n,a,s,o){if(!o||s.kind==="live"||!n)return"";let r=s.kind==="resume",c=o.pending.has(e.attemptId),
|
|
1174
|
+
<iframe class="wf-terminal-frame" src="${h(o.url)}" title="${h(p)}" loading="lazy"></iframe>
|
|
1175
|
+
</details>`}function Co(e){return e==="live"?t("workflow.detail.liveTerminal"):e==="resume"?t("workflow.detail.terminalResume"):t("workflow.detail.terminalReplay")}function Zi(e){return e==="live"?t("workflow.detail.openTerminalNewTab"):e==="resume"?t("workflow.detail.openResumeNewTab"):t("workflow.detail.openReplayNewTab")}var Ao=new Set(["antigravity","codex-app","cursor","mira"]),er=new Set(["aiden","coco","claude-code","seed","codex","mtr","hermes","pi"]);function tr(e){return!!e&&(er.has(e)||Ao.has(e))}function nr(e){return!!e&&Ao.has(e)}function Do(e,n,a,s,o){if(!o||s.kind==="live"||!n)return"";let r=s.kind==="resume",c=o.pending.has(e.attemptId),p=`data-wf-resume-attempt="${h(e.attemptId)}" data-wf-resume-activity="${h(n.activityId)}"`;return r?`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="end" ${p}${c?" disabled":""}>${h(c?t("workflow.detail.resumeEnding"):t("workflow.detail.endResumeSession"))}</button>`:tr(a.cliId)?nr(a.cliId)&&!a.cliSessionId?`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${h(t("workflow.detail.resumeMissingCliSession"))}">${h(t("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="start" ${p}${c?" disabled":""}>${h(c?t("workflow.detail.resumeStarting"):t("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${h(t("workflow.detail.resumeUnsupportedCli",{cliId:a.cliId??"?"}))}">${h(t("workflow.detail.resumeSession"))}</button>`}function Ro(e,n){if(!n)return"";let a=n.errors.get(e);return a?`<div class="hint-warn wf-resume-status" data-wf-resume-status="${h(e)}">${h(a)}</div>`:""}function ar(e,n,a,s,o){let r=rn(e.activity),c=e.node?.nodeId??e.activity?.ownerNodeId??e.activity?.activityId??"unknown",p=r?.attemptId??e.activity?.activityId??e.node?.nodeId??"unknown",k=Bo(r,a),v=r?.attemptId===o?" is-focused":"",L=r?` data-wf-attempt-card="${h(r.attemptId)}"`:"",$=Eo(r,e.activity,e.io?.terminal,s),g=$?Ho(p,r,e.activity,e.io?.terminal,$,n,s):"";return`<article class="wf-io-card${v}" data-wf-card-key="${h(e.key)}"${L}>
|
|
1165
1176
|
<div class="wf-io-card-head">
|
|
1166
1177
|
<header>
|
|
1167
1178
|
<div>
|
|
@@ -1177,11 +1188,11 @@ ${bo("manage")}
|
|
|
1177
1188
|
</div>
|
|
1178
1189
|
<div class="wf-io-terminal-slot">${g}</div>
|
|
1179
1190
|
<div class="wf-io-grid">
|
|
1180
|
-
${Je(
|
|
1181
|
-
${Je(
|
|
1182
|
-
${Je(
|
|
1183
|
-
${Je(
|
|
1184
|
-
${e.io?.waitPrompt?Je(
|
|
1191
|
+
${Je(p,t("workflow.detail.authoredInput"),e.io?.input,n)}
|
|
1192
|
+
${Je(p,t("workflow.detail.resolvedInput"),e.io?.resolvedInput,n)}
|
|
1193
|
+
${Je(p,t("workflow.detail.output"),e.io?.output,n)}
|
|
1194
|
+
${Je(p,t("workflow.detail.executionLog"),e.io?.log,n)}
|
|
1195
|
+
${e.io?.waitPrompt?Je(p,t("workflow.detail.waitPrompt"),e.io.waitPrompt,n):""}
|
|
1185
1196
|
</div>
|
|
1186
1197
|
</article>`}function rn(e){return e?.attempts[e.attempts.length-1]}function Oo(e,n){let a=[];return n.error?a.push(t("workflow.detail.error")):a.push(n.status==="live"?t("workflow.detail.terminalLive"):t("workflow.detail.terminalClosedShort")),e?.status&&a.push(e.status),n.webPort>0&&a.push(`:${n.webPort}`),`<span class="muted">${h(a.join(" \xB7 "))}</span>`}function or(e,n){return n.status==="live"&&n.webPort>0&&(e?.status==="pending"||e?.status==="running"||e?.status==="effectAttempting")}function sr(e,n){return e.status==="succeeded"||e.status==="failed"||e.status==="cancelled"||e.status==="timedOut"?!!(n.sessionId||n.startedAt):!1}function ir(e){return`http://${window.location.hostname||"127.0.0.1"}:${e.webPort}`}function rr(e,n,a,s){let o=new URLSearchParams({runId:e,activityId:n,attemptId:a});return s&&o.set("hasPtyLog","1"),`/assets/terminal-replay.html?${o.toString()}`}function Io(e,n,a){return`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(n)}/${encodeURIComponent(a)}/terminal-log/raw?download=1`}function lr(){let e=window.location.hash.match(/^#\/workflows\/([^/?#]+)/);if(!e)return null;try{return decodeURIComponent(e[1])}catch{return null}}function Bo(e,n){if(!dr(e))return"";let a=e.attemptId,s=n.comments.get(a)??"",o=n.resolving.has(a),r=n.statuses.get(a),c=r?.kind==="error"?"hint-warn":"hint-ok";return`<div class="wf-approval-box" data-wf-approval="${h(a)}">
|
|
1187
1198
|
<label>
|
|
@@ -1194,7 +1205,7 @@ ${bo("manage")}
|
|
|
1194
1205
|
${o?`<span class="muted">${h(t("workflow.detail.submitting"))}</span>`:""}
|
|
1195
1206
|
</div>
|
|
1196
1207
|
${r?`<div class="${c} wf-approval-status">${h(r.text)}</div>`:""}
|
|
1197
|
-
</div>`}function dr(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function cr(e,n){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(a=>{let s=a.dataset.wfApprovalComment;s&&n.set(s,a.value)})}function No(e,n){e.querySelectorAll("button[data-wf-resume-action][data-wf-resume-attempt][data-wf-resume-activity]").forEach(a=>{a.dataset.wfResumeBound!=="1"&&(a.dataset.wfResumeBound="1",a.addEventListener("click",()=>{let s=a.dataset.wfResumeAttempt,o=a.dataset.wfResumeActivity,r=a.dataset.wfResumeAction;!s||!o||(r==="start"?n.onStart(s,o):r==="end"&&n.onEnd(s,o))}))})}function ur(e,n,a,s,o,r){let c=e.querySelector(".wf-terminal-actions");if(!c)return;let
|
|
1208
|
+
</div>`}function dr(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function cr(e,n){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(a=>{let s=a.dataset.wfApprovalComment;s&&n.set(s,a.value)})}function No(e,n){e.querySelectorAll("button[data-wf-resume-action][data-wf-resume-attempt][data-wf-resume-activity]").forEach(a=>{a.dataset.wfResumeBound!=="1"&&(a.dataset.wfResumeBound="1",a.addEventListener("click",()=>{let s=a.dataset.wfResumeAttempt,o=a.dataset.wfResumeActivity,r=a.dataset.wfResumeAction;!s||!o||(r==="start"?n.onStart(s,o):r==="end"&&n.onEnd(s,o))}))})}function ur(e,n,a,s,o,r){let c=e.querySelector(".wf-terminal-actions");if(!c)return;let p=c.querySelector('button[data-wf-resume-button="1"]'),k=Do(n,a,s,o,r);p?p.outerHTML=k:k&&c.insertAdjacentHTML("beforeend",k);let v=e.querySelector("details.wf-terminal-block");if(v){let L=v.querySelector(".wf-resume-status"),$=Ro(n.attemptId,r);L?L.outerHTML=$:$&&c.insertAdjacentHTML("afterend",$)}No(e,r)}function pr(e,n){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(a=>{let s=a.dataset.wfApprovalComment;s&&a.addEventListener("input",()=>{n.comments.set(s,a.value)})}),e.querySelectorAll("button[data-wf-approval-action][data-wf-attempt-id]").forEach(a=>{a.addEventListener("click",()=>{let s=a.dataset.wfAttemptId,o=a.dataset.wfApprovalAction;!s||o!=="approve"&&o!=="reject"||n.onResolve(s,o)})})}function Je(e,n,a,s){let o=Jn(e,n);return`<details class="wf-io-block" data-io-key="${h(o)}"${s.has(o)?" open":""}>
|
|
1198
1209
|
<summary>${h(n)} ${wr(a)}</summary>
|
|
1199
1210
|
${yr(a)}
|
|
1200
1211
|
</details>`}function Jn(e,n){return`${e}:${n}`}function mr(e,n){if(!n)return!1;for(let a of e.querySelectorAll("[data-wf-attempt-card]"))if(a.dataset.wfAttemptCard===n)return a.scrollIntoView({block:"center"}),!0;return!1}function fr(e,n,a){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(s=>{let o=s.dataset.ioKey;if(!o)return;s.open?n.add(o):n.delete(o);let r=s.querySelector(".wf-io-pre");r&&a.set(o,r.scrollTop)})}function gr(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(a=>{a.dataset.ioToggleBound!=="1"&&(a.dataset.ioToggleBound="1",a.addEventListener("toggle",()=>{let s=a.dataset.ioKey;s&&(a.open?n.add(s):n.delete(s))}))})}function br(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(a=>{let s=a.dataset.ioKey;if(!s)return;let o=n.get(s);if(o===void 0)return;let r=a.querySelector(".wf-io-pre");r&&(r.scrollTop=o)})}function hr(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(a=>{let s=a.dataset.ioKey;if(!s)return;let o=a.querySelector(".wf-io-pre");o&&o.dataset.ioScrollBound!=="1"&&(o.dataset.ioScrollBound="1",o.addEventListener("scroll",()=>{n.set(s,o.scrollTop)}))})}function wr(e){if(!e)return`<span class="muted">${h(t("workflow.detail.empty"))}</span>`;let n=[];return e.outputBytes!==void 0&&n.push(`${e.outputBytes}B`),e.truncated&&n.push(t("workflow.detail.truncated")),e.error&&n.push(t("workflow.detail.error")),e.outputHash&&n.push(dn(e.outputHash)),n.length?`<span class="muted">${h(n.join(" \xB7 "))}</span>`:""}function yr(e){if(!e)return`<div class="muted wf-io-empty">${h(t("workflow.detail.noData"))}</div>`;let n=e.value!==void 0?JSON.stringify(e.value,null,2):e.text??"",a=e.error?`<div class="muted error">${h(e.error)}</div>`:"";return n?`${a}<pre class="wf-io-pre">${h(n)}</pre>`:`${a}<div class="muted wf-io-empty">${h(t("workflow.detail.noPreview"))}</div>`}function vr(e){let n=[];if(e.effectAttempted&&n.push(`${h(t("workflow.detail.effect"))} ${h(e.effectAttempted.provider)}`),e.wait){let a=e.wait.resolution?`${e.wait.resolution.kind}${e.wait.resolution.resolution?":"+e.wait.resolution.resolution:""}`:t("workflow.detail.open");n.push(`${h(t("workflow.detail.wait"))} ${h(e.wait.waitKind)} ${h(a)}`),e.wait.deadlineAt!==void 0&&n.push(`${h(t("workflow.detail.deadline"))} ${h(ln(e.wait.deadlineAt))}`)}if(e.error){let a=`${e.error.errorCode}${e.error.errorClass?` \xB7 ${e.error.errorClass}`:""}`;n.push(`<span class="muted error">${h(a)}</span>`),e.error.errorMessage&&n.push(`<span class="error wf-error-msg">${h(e.error.errorMessage)}</span>`)}return e.output&&n.push(`${h(t("workflow.detail.output"))} ${h(dn(e.output.outputHash))}`),e.runningMs!==void 0&&n.push(`${e.runningMs}ms`),n.length>0?n.join("<br/>"):'<span class="muted">-</span>'}function kr(e,n){e.innerHTML=n.length>0?n.map($r).join(""):`<tr><td colspan="7" class="empty">${h(t("workflow.detail.noEvents"))}</td></tr>`}function $r(e){let n=Sr(e.payload);return`<tr>
|
|
@@ -1234,7 +1245,7 @@ ${bo("manage")}
|
|
|
1234
1245
|
<tbody id="catalog-tbody"></tbody>
|
|
1235
1246
|
</table>
|
|
1236
1247
|
</div>
|
|
1237
|
-
`;let n=e.querySelector("#catalog-tbody"),a=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),o=e.querySelector("#catalog-refresh"),r=[],c=null,
|
|
1248
|
+
`;let n=e.querySelector("#catalog-tbody"),a=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),o=e.querySelector("#catalog-refresh"),r=[],c=null,p=!1;function k(){let $=(new FormData(s).get("q")??"").trim().toLowerCase();return $?r.filter(g=>g.workflowId.toLowerCase().includes($)||g.path.toLowerCase().includes($)):r}function v(){c?(a.textContent=t("catalog.loadFailed",{error:c}),a.classList.add("error")):(a.textContent=`${r.length}`,a.classList.remove("error"));let $=k();if($.length===0){n.innerHTML=`<tr><td colspan="6" class="empty">${r.length===0?P(t("catalog.noDefinitions")):P(t("catalog.noFilterMatch"))}</td></tr>`;return}n.innerHTML=$.map(g=>`
|
|
1238
1249
|
<tr>
|
|
1239
1250
|
<td><a href="#/workflows/catalog/${encodeURIComponent(g.workflowId)}"><code>${P(g.workflowId)}</code></a></td>
|
|
1240
1251
|
<td>${g.version}</td>
|
|
@@ -1243,7 +1254,7 @@ ${bo("manage")}
|
|
|
1243
1254
|
<td><code>${P(Po(g.revisionId))}</code></td>
|
|
1244
1255
|
<td><code>${P(g.path)}</code></td>
|
|
1245
1256
|
</tr>
|
|
1246
|
-
`).join("")}async function L(){o.disabled=!0,a.textContent=t("catalog.loading");try{let $=await fetch("/api/workflows/definitions");if(!$.ok)throw new Error(`HTTP ${$.status}`);r=(await $.json()).definitions??[],c=null}catch($){c=$?.message??String($),r=[]}finally{o.disabled=!1,
|
|
1257
|
+
`).join("")}async function L(){o.disabled=!0,a.textContent=t("catalog.loading");try{let $=await fetch("/api/workflows/definitions");if(!$.ok)throw new Error(`HTTP ${$.status}`);r=(await $.json()).definitions??[],c=null}catch($){c=$?.message??String($),r=[]}finally{o.disabled=!1,p||v()}}return s.addEventListener("input",v),o.addEventListener("click",()=>{L()}),L(),()=>{p=!0}}function Mr(e,n){e.innerHTML=`
|
|
1247
1258
|
<div class="catalog-detail-head">
|
|
1248
1259
|
<a class="btn-link" href="#/workflows/catalog">${P(t("catalog.back"))}</a>
|
|
1249
1260
|
<div>
|
|
@@ -1254,7 +1265,7 @@ ${bo("manage")}
|
|
|
1254
1265
|
<section id="catalog-error" class="hint-warn" hidden></section>
|
|
1255
1266
|
<section id="catalog-run-status" class="hint-ok" hidden></section>
|
|
1256
1267
|
<div id="catalog-detail-body"></div>
|
|
1257
|
-
`;let a=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),o=e.querySelector("#catalog-run-status"),r=e.querySelector("#catalog-detail-body"),c=null,
|
|
1268
|
+
`;let a=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),o=e.querySelector("#catalog-run-status"),r=e.querySelector("#catalog-detail-body"),c=null,p=!1,k=!1;function v(I){s.hidden=!I,s.textContent=I??""}function L(I){o.hidden=!I,o.textContent=I??""}function $(I){let E={};for(let[d,y]of Object.entries(I??{}))"default"in y&&(E[d]=y.default);return E}function g(){if(!c)return;let I=c.definition;a.textContent=`${t("catalog.revision")} ${Po(c.revisionId)} \xB7 ${c.path}`;let E=JSON.stringify($(I.params),null,2);r.innerHTML=`
|
|
1258
1269
|
<section class="wf-panel">
|
|
1259
1270
|
<div class="wf-panel-title"><h3>${P(t("catalog.summary"))}</h3></div>
|
|
1260
1271
|
<div class="wf-summary-grid">
|
|
@@ -1297,7 +1308,7 @@ ${bo("manage")}
|
|
|
1297
1308
|
<div class="wf-panel-title"><h3>${P(t("catalog.definitionJson"))}</h3></div>
|
|
1298
1309
|
<pre class="wf-io-pre">${P(JSON.stringify(I,null,2))}</pre>
|
|
1299
1310
|
</section>
|
|
1300
|
-
`,D()}async function O(){if(!c||k)return;let I=r.querySelector("#catalog-params"),E=r.querySelector("#catalog-chat-id"),d=r.querySelector("#catalog-lark-app-id"),y=r.querySelector("#catalog-run-btn"),H=r.querySelector("#catalog-param-errors"),M;try{if(M=JSON.parse(I.value||"{}"),!M||typeof M!="object"||Array.isArray(M))throw new Error(t("catalog.badParamsJson"))}catch(S){H.hidden=!1,H.innerHTML=`<div class="muted error">${P(S?.message??String(S))}</div>`;return}k=!0,y.disabled=!0,y.textContent=t("catalog.running"),H.hidden=!0,v(null),L(null);try{let S=await fetch(`/api/workflows/definitions/${encodeURIComponent(c.definition.workflowId)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({params:M,chatBinding:{chatId:E.value.trim(),larkAppId:d.value.trim()}})});if(S.status===401)throw new Error(t("catalog.writeAccess"));let A=await S.json().catch(()=>({}));if(!S.ok||!A.ok)throw A.issues?.length&&(H.hidden=!1,H.innerHTML=`<strong>${P(t("catalog.invalidParams"))}</strong><ul>${A.issues.map(B=>`<li>${P(t("catalog.issue",{path:B.path.length?B.path.join("."):"(root)",message:B.message}))}</li>`).join("")}</ul>`),new Error(A.hint??A.message??A.error??t("catalog.runHttp",{status:S.status}));L(t("catalog.runStarted")),A.runId&&(location.hash=`#/workflows/${encodeURIComponent(A.runId)}`)}catch(S){v(S?.message??String(S))}finally{k=!1,y.disabled=!1,y.textContent=t("catalog.run")}}function D(){r.querySelector("#catalog-run-form")?.addEventListener("submit",E=>{E.preventDefault(),O()})}async function R(){try{let I=await fetch(`/api/workflows/definitions/${encodeURIComponent(n)}`);if(I.status===404)throw new Error("unknown_workflow");if(!I.ok)throw new Error(`HTTP ${I.status}`);c=await I.json(),v(null),g()}catch(I){v(t("catalog.definitionLoadFailed",{error:I?.message??String(I)})),a.textContent=t("workflow.detail.loadFailed")}}return R().then(()=>{}),()=>{
|
|
1311
|
+
`,D()}async function O(){if(!c||k)return;let I=r.querySelector("#catalog-params"),E=r.querySelector("#catalog-chat-id"),d=r.querySelector("#catalog-lark-app-id"),y=r.querySelector("#catalog-run-btn"),H=r.querySelector("#catalog-param-errors"),M;try{if(M=JSON.parse(I.value||"{}"),!M||typeof M!="object"||Array.isArray(M))throw new Error(t("catalog.badParamsJson"))}catch(S){H.hidden=!1,H.innerHTML=`<div class="muted error">${P(S?.message??String(S))}</div>`;return}k=!0,y.disabled=!0,y.textContent=t("catalog.running"),H.hidden=!0,v(null),L(null);try{let S=await fetch(`/api/workflows/definitions/${encodeURIComponent(c.definition.workflowId)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({params:M,chatBinding:{chatId:E.value.trim(),larkAppId:d.value.trim()}})});if(S.status===401)throw new Error(t("catalog.writeAccess"));let A=await S.json().catch(()=>({}));if(!S.ok||!A.ok)throw A.issues?.length&&(H.hidden=!1,H.innerHTML=`<strong>${P(t("catalog.invalidParams"))}</strong><ul>${A.issues.map(B=>`<li>${P(t("catalog.issue",{path:B.path.length?B.path.join("."):"(root)",message:B.message}))}</li>`).join("")}</ul>`),new Error(A.hint??A.message??A.error??t("catalog.runHttp",{status:S.status}));L(t("catalog.runStarted")),A.runId&&(location.hash=`#/workflows/${encodeURIComponent(A.runId)}`)}catch(S){v(S?.message??String(S))}finally{k=!1,y.disabled=!1,y.textContent=t("catalog.run")}}function D(){r.querySelector("#catalog-run-form")?.addEventListener("submit",E=>{E.preventDefault(),O()})}async function R(){try{let I=await fetch(`/api/workflows/definitions/${encodeURIComponent(n)}`);if(I.status===404)throw new Error("unknown_workflow");if(!I.ok)throw new Error(`HTTP ${I.status}`);c=await I.json(),v(null),g()}catch(I){v(t("catalog.definitionLoadFailed",{error:I?.message??String(I)})),a.textContent=t("workflow.detail.loadFailed")}}return R().then(()=>{}),()=>{p=!0}}function xr(e){let n=Object.entries(e??{});return n.length===0?`<div class="muted">${P(t("catalog.noParams"))}</div>`:`<div class="catalog-param-list">${n.map(([a,s])=>`
|
|
1301
1312
|
<article class="catalog-param">
|
|
1302
1313
|
<header>
|
|
1303
1314
|
<code>${P(a)}</code>
|
|
@@ -1307,7 +1318,7 @@ ${bo("manage")}
|
|
|
1307
1318
|
${s.description?`<div class="muted">${P(t("catalog.description"))}: ${P(s.description)}</div>`:""}
|
|
1308
1319
|
${"default"in s?`<pre class="wf-io-pre">${P(`${t("catalog.default")}: ${JSON.stringify(s.default,null,2)}`)}</pre>`:""}
|
|
1309
1320
|
</article>
|
|
1310
|
-
`).join("")}</div>`}var cn=78222186;function Uo(e){let n={maxWidth:e.style.maxWidth,padding:e.style.padding,flex:e.style.flex,minHeight:e.style.minHeight,display:e.style.display};e.style.maxWidth="none",e.style.padding="0",e.style.flex="1 1 auto",e.style.minHeight="0",e.style.display="flex";let a=!1,s,o="",r=g=>(g/1048576).toFixed(0);function c(){s&&(clearTimeout(s),s=void 0)}function
|
|
1321
|
+
`).join("")}</div>`}var cn=78222186;function Uo(e){let n={maxWidth:e.style.maxWidth,padding:e.style.padding,flex:e.style.flex,minHeight:e.style.minHeight,display:e.style.display};e.style.maxWidth="none",e.style.padding="0",e.style.flex="1 1 auto",e.style.minHeight="0",e.style.display="flex";let a=!1,s,o="",r=g=>(g/1048576).toFixed(0);function c(){s&&(clearTimeout(s),s=void 0)}function p(){c(),e.innerHTML=`
|
|
1311
1322
|
<iframe
|
|
1312
1323
|
src="/game/index.html"
|
|
1313
1324
|
title="HD2D Office"
|
|
@@ -1335,7 +1346,7 @@ ${bo("manage")}
|
|
|
1335
1346
|
${I?"\u91CD\u8BD5":"\u52A0\u8F7D\u529E\u516C\u5BA4"}\uFF08\u7EA6 ${r(O)} MB\uFF09
|
|
1336
1347
|
</button>
|
|
1337
1348
|
`}
|
|
1338
|
-
</div>`;let E=e.querySelector("#hd2d-load");E&&(E.onclick=()=>{o=e.querySelector("#hd2d-proxy")?.value.trim()??"",L()})}function v(g){if(!a){if(typeof g.proxy=="string"&&(o=g.proxy),g.state==="ready"){
|
|
1349
|
+
</div>`;let E=e.querySelector("#hd2d-load");E&&(E.onclick=()=>{o=e.querySelector("#hd2d-proxy")?.value.trim()??"",L()})}function v(g){if(!a){if(typeof g.proxy=="string"&&(o=g.proxy),g.state==="ready"){p();return}k(g),g.state==="downloading"&&(s=setTimeout(()=>{$()},700))}}async function L(){k({state:"downloading",received:0,total:cn});try{let g=await fetch("/api/game/download",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({proxy:o})});if(!g.ok)throw new Error(`HTTP ${g.status}`);v(await g.json())}catch(g){k({state:"error",received:0,total:cn,error:g instanceof Error?g.message:String(g)})}}async function $(){if(!a)try{let g=await fetch("/api/game/status");if(!g.ok){k({state:"absent",received:0,total:cn});return}v(await g.json())}catch{a||(s=setTimeout(()=>{$()},1500))}}return $(),()=>{a=!0,c(),e.innerHTML="",e.style.maxWidth=n.maxWidth,e.style.padding=n.padding,e.style.flex=n.flex,e.style.minHeight=n.minHeight,e.style.display=n.display}}var pt=null,un=null;function Nt(){un!==null&&(window.clearInterval(un),un=null)}function Vn(){return pt||(pt=document.createElement("dialog"),pt.className="onboarding-dialog",document.body.appendChild(pt),pt.addEventListener("close",Nt),pt)}function Er(e){return e.status==="waiting_for_scan"?t("botOnboarding.waiting"):e.status==="verifying"?t("botOnboarding.verifying"):e.status==="configuring_permissions"?e.permissionStatusMsg?`${t("botOnboarding.configuringPermissions")} ${e.permissionStatusMsg}`:t("botOnboarding.configuringPermissions"):e.status==="waiting_for_platform_scan"?t("botOnboarding.platformScanHint"):e.status==="completed"?t("botOnboarding.completed"):e.status==="failed"?`${t("botOnboarding.failed")}: ${i(e.message??e.error??"unknown")}`:t("botOnboarding.starting")}function Hr(e){if(e.status!=="completed"||!e.permission)return"";let n=e.permission;if(n.ok){let s=[t("botOnboarding.permissionOk",{count:n.scopeCount??0})];n.skippedScopeCount&&n.skippedScopeCount>0&&s.push(t("botOnboarding.permissionSkipped",{count:n.skippedScopeCount})),n.versionId&&s.push(t("botOnboarding.permissionVersion",{version:i(n.versionId)}));let o=`<p class="hint-ok">\u2705 ${s.join(" ")}</p>`;return n.scopeWarning&&(o+=`<p class="hint-warn">\u26A0\uFE0F ${i(n.scopeWarning)}</p>`),o}let a=(e.remainingSteps??[]).map(s=>`<li><a href="${i(s.url)}" target="_blank" rel="noopener">${i(s.title)}</a></li>`).join("");return`<p class="hint-warn">\u26A0\uFE0F ${t("botOnboarding.permissionManual")}${n.message?`\uFF08${i(n.message)}\uFF09`:""}</p>`+(a?`<ol class="onboarding-steps">${a}</ol>`:"")}function Bt(e){let n=Vn(),a=e.status==="waiting_for_scan"&&e.qrDataUrl?`<div class="qr-card">
|
|
1339
1350
|
<img class="qr-image" src="${e.qrDataUrl}" alt="${t("botOnboarding.qrAlt")}">
|
|
1340
1351
|
${e.qrUrl?`<a class="onboarding-link" href="${i(e.qrUrl)}" target="_blank" rel="noopener">${t("botOnboarding.openLink")}</a>`:""}
|
|
1341
1352
|
</div>`:"",s=e.status==="waiting_for_platform_scan"&&e.platformQrDataUrl?`<div class="qr-card">
|
|
@@ -1352,7 +1363,7 @@ ${bo("manage")}
|
|
|
1352
1363
|
${Hr(e)}
|
|
1353
1364
|
${r}
|
|
1354
1365
|
<form method="dialog"><button>${t("botOnboarding.close")}</button></form>
|
|
1355
|
-
</article>`}async function Cr(){try{let e=await fetch("/api/cli-options"),n=await e.json();if(e.ok&&Array.isArray(n?.options))return n.options}catch{}return[{id:"claude-code",label:"Claude"}]}function Yn(e,n){let a=Vn(),s=e.map(
|
|
1366
|
+
</article>`}async function Cr(){try{let e=await fetch("/api/cli-options"),n=await e.json();if(e.ok&&Array.isArray(n?.options))return n.options}catch{}return[{id:"claude-code",label:"Claude"}]}function Yn(e,n){let a=Vn(),s=e.map(p=>`<option value="${i(p.id)}">${i(p.label)}\uFF08${i(p.id)}\uFF09</option>`).join(""),o=n?`<p class="form-error">${i(n)}</p>`:"";a.innerHTML=`<article>
|
|
1356
1367
|
<header>
|
|
1357
1368
|
<h3>${t("botOnboarding.title")}</h3>
|
|
1358
1369
|
<p>${t("botOnboarding.intro")}</p>
|
|
@@ -1376,8 +1387,8 @@ ${bo("manage")}
|
|
|
1376
1387
|
<button type="submit" class="primary">${t("botOnboarding.startScan")}</button>
|
|
1377
1388
|
</menu>
|
|
1378
1389
|
</form>
|
|
1379
|
-
</article>`;let r=a.querySelector("#onboarding-form");a.querySelector("#ob-cancel")?.addEventListener("click",()=>a.close()),r?.addEventListener("submit",
|
|
1390
|
+
</article>`;let r=a.querySelector("#onboarding-form");a.querySelector("#ob-cancel")?.addEventListener("click",()=>a.close()),r?.addEventListener("submit",p=>{p.preventDefault();let k=a.querySelector("#ob-cli")?.value??"",v=a.querySelector("#ob-dir")?.value??"",L=a.querySelector("#ob-model")?.value??"";Ar({cliId:k,workingDir:v,model:L},e)})}async function Ar(e,n){Nt(),Bt({id:"",status:"starting"});try{let a=await fetch("/api/bot-onboarding/start",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({cliId:e.cliId,workingDir:e.workingDir.trim(),model:e.model.trim()||void 0})}),s=await a.json();if(a.status===400){Yn(n,s?.message??s?.error??"invalid_input");return}if(!a.ok||!s?.job?.id)throw new Error(s?.error??`http_${a.status}`);Bt(s.job),un=window.setInterval(()=>{Dr(s.job.id).catch(o=>{Nt(),Bt({id:s.job.id,status:"failed",message:o instanceof Error?o.message:String(o)})})},1200)}catch(a){Bt({id:"",status:"failed",message:a instanceof Error?a.message:String(a)})}}async function Dr(e){let n=await fetch(`/api/bot-onboarding/${encodeURIComponent(e)}`),a=await n.json();if(!n.ok||!a?.job)throw new Error(a?.error??`http_${n.status}`);Bt(a.job),(a.job.status==="completed"||a.job.status==="failed")&&Nt()}async function Rr(){Nt();let e=Vn();Yn([{id:"claude-code",label:"Claude"}]),e.open||e.showModal();let n=await Cr();e.open&&e.querySelector("#onboarding-form")&&Yn(n)}function jo(){let e=document.getElementById("add-bot-btn");e&&(e.onclick=()=>{Rr()})}var Or={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"/>'},Go=[{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"}]}],Fo=Go.flatMap(e=>e.options),mt=!1;function Qn(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">${Or[e]??""}</svg>`}function Br(e){return e.replace(/[&<>"]/g,n=>({"&":"&","<":"<",">":">",'"':"""})[n])}function _o(){let e=document.getElementById("theme-menu"),n=document.getElementById("theme-menu-btn"),a=document.getElementById("theme-menu-pop");if(!e||!n||!a)return;a.innerHTML=Go.map(o=>`<div class="tm-group" data-label-key="${o.labelKey}"></div>`+o.options.map(r=>`<button type="button" class="tm-item" role="option" data-value="${r.value}"><span class="tm-ic">${Qn(r.icon)}</span><span class="tm-label" data-label-key="${r.labelKey}"></span></button>`).join("")).join("");let s=o=>{mt=o,a.hidden=!mt,n.setAttribute("aria-expanded",String(mt)),e.classList.toggle("open",mt)};n.addEventListener("click",o=>{o.stopPropagation(),s(!mt)}),a.addEventListener("click",o=>{let r=o.target.closest(".tm-item");r&&(Se.setTheme(r.dataset.value??"system"),s(!1))}),document.addEventListener("click",o=>{mt&&!e.contains(o.target)&&s(!1)}),document.addEventListener("keydown",o=>{o.key==="Escape"&&mt&&s(!1)}),Xn()}function Xn(){let e=document.getElementById("theme-menu-btn");if(!e)return;let n=Fo.find(a=>a.value===Se.theme)??Fo[0];e.innerHTML=`<span class="tm-ic">${Qn(n.icon)}</span><span class="tm-current">${Br(t(n.labelKey))}</span><span class="tm-chev">${Qn("chevron")}</span>`,document.querySelectorAll("#theme-menu-pop [data-label-key]").forEach(a=>{a.textContent=t(a.dataset.labelKey??"")}),document.querySelectorAll("#theme-menu-pop .tm-item").forEach(a=>{a.classList.toggle("active",a.dataset.value===Se.theme)})}var Ee=document.getElementById("root"),Tt=!0,Yo=!1,Vo=["roles","bot-defaults","team","connectors"],Zn=!1;function Nr(){if(Zn)return;Zn=!0;let e=document.createElement("div");e.id="auth-expired-overlay",e.style.cssText="position:fixed;inset:0;background:rgba(0,0,0,.65);display:flex;align-items:center;justify-content:center;z-index:9999",e.innerHTML='<div style="background:var(--surface);color:var(--fg);border:1px solid var(--border);border-radius:12px;padding:36px 40px;max-width:460px;width:90vw;text-align:center;box-shadow:0 12px 40px rgba(0,0,0,.35)"><h2 style="margin:0 0 14px;font-size:19px;color:var(--fg)">\u8BBF\u95EE\u94FE\u63A5\u5DF2\u5931\u6548</h2><p style="margin:0 0 24px;line-height:1.7;color:var(--muted,#8f959e);font-size:14px">\u5F53\u524D\u94FE\u63A5/\u8BBF\u95EE\u5DF2\u5931\u6548\uFF0C\u8BF7\u4F7F\u7528\u6700\u65B0\u6388\u6743\u94FE\u63A5\u91CD\u65B0\u8FDB\u5165\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09\u3002</p><button id="auth-expired-dismiss" type="button" style="padding:8px 22px;background:var(--accent);color:var(--on-accent);border:none;border-radius:8px;cursor:pointer;font-size:14px">\u77E5\u9053\u4E86</button></div>',document.body.appendChild(e);let n=()=>{e.remove(),Zn=!1};e.querySelector("#auth-expired-dismiss")?.addEventListener("click",n),e.addEventListener("click",a=>{a.target===e&&n()})}var ea;function Pr(){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",ea&&window.clearTimeout(ea),ea=window.setTimeout(()=>{e.style.display="none"},4e3)}var qr=window.fetch.bind(window);window.fetch=async function(...n){let a=await qr(...n);if(a.status===401){let s=(n[1]?.method??"GET").toUpperCase();(s==="GET"||s==="HEAD")&&!Yo?Nr():Pr()}return a};var ta="";function pn(){let e=document.getElementById("attention-strip");if(!e)return;let n=[...V.sessions.values()].map(o=>({s:o,reason:at(o)})).filter(o=>!!o.reason).sort((o,r)=>Ie(o.s)-Ie(r.s));if(n.length===0){e.hidden=!0,e.innerHTML="",ta="";return}let a=n[0],s=`
|
|
1380
1391
|
<span class="attention-strip-ic" aria-hidden="true">!</span>
|
|
1381
1392
|
<b>${i(t("strip.pending",{count:n.length}))}</b>
|
|
1382
|
-
<span class="attention-strip-longest">${i(t("strip.longest",{time:Be(
|
|
1383
|
-
<a class="attention-strip-go" href="#/sessions">${i(t("strip.handle"))}</a>`;e.hidden=!1,s!==ta&&(ta=s,e.innerHTML=s)}V.on(pn);_e().then(pn);async function Ur(){try{let e=await fetch("/api/settings");if(e.ok){let n=await e.json();Tt=!!n.authed
|
|
1393
|
+
<span class="attention-strip-longest">${i(t("strip.longest",{time:Be(Ie(a.s)),bot:ye(a.s),reason:a.reason}))}</span>
|
|
1394
|
+
<a class="attention-strip-go" href="#/sessions">${i(t("strip.handle"))}</a>`;e.hidden=!1,s!==ta&&(ta=s,e.innerHTML=s)}V.on(pn);_e().then(pn);async function Ur(){try{let e=await fetch("/api/settings");if(e.ok){let n=await e.json();Tt=!!n.authed,Se.authed=Tt,Yo=!!(n.settings&&n.settings.publicReadOnly);let a=Ft(n.lang);a&&Se.setLocale(a)}}catch{}}async function jr(e){if(Tt)try{await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({lang:e})})}catch{}}function Fr(){for(let n of Vo){let a=document.querySelector(`.sidebar-nav a[data-route="${n}"]`);a&&(a.style.display=Tt?"":"none")}let e=document.getElementById("add-bot-btn");e&&(e.style.display=Tt?"":"none")}function Gr(e){e.innerHTML='<section class="auth-required" style="max-width:520px;margin:64px auto;text-align:center;background:var(--surface);color:var(--fg);border:1px solid var(--border);border-radius:14px;padding:40px 36px;box-shadow:0 8px 28px rgba(0,0,0,.12)"><h2 style="margin:0 0 12px;font-size:20px;color:var(--fg)">\u6B64\u9875\u9700\u8981\u6388\u6743\u94FE\u63A5</h2><p style="margin:0 0 24px;line-height:1.7;color:var(--muted);font-size:14px">\u4F60\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u7BA1\u7406\u9875\uFF08\u89D2\u8272 / Bot \u914D\u7F6E / \u56E2\u961F / Webhook\uFF09\u9700\u8981\u6388\u6743\u94FE\u63A5\u3002\u8FD0\u884C <code>botmux dashboard</code> \u83B7\u53D6\u6700\u65B0\u94FE\u63A5\u540E\u5373\u53EF\u7BA1\u7406\u3002</p><a href="#/" style="display:inline-block;padding:8px 22px;background:var(--accent);color:var(--on-accent);border-radius:8px;text-decoration:none;font-size:14px">\u8FD4\u56DE\u603B\u89C8</a></section>'}var St=null;function zo(e){for(let n of document.querySelectorAll(".sidebar-nav a")){let a=n.getAttribute("href")??"#/";n.classList.toggle("active",a===(e||"#/"))}}function na(){St&&(St(),St=null);let e=location.hash||"#/";if(!Tt&&Vo.some(n=>e.startsWith("#/"+n))){Gr(Ee),zo(e);return}e.startsWith("#/workflows/catalog")||e.startsWith("#/workflows-catalog")?St=qo(Ee):e.startsWith("#/workflows")?St=xo(Ee):e.startsWith("#/groups")?oo(Ee):e.startsWith("#/settings")?To(Ee):e.startsWith("#/bot-defaults")?lo(Ee):e.startsWith("#/connectors")?$o(Ee):e.startsWith("#/team/manage")?yo(Ee):e.startsWith("#/team")?wo(Ee):e.startsWith("#/roles")?mo(Ee):e.startsWith("#/schedules")?no(Ee):e.startsWith("#/sessions")?eo(Ee):e.startsWith("#/office")?St=Uo(Ee)??null:Fa(Ee),zo(e)}var aa=document.getElementById("status");function Qo(){aa&&(aa.textContent=V.online?t("status.live"):t("status.disconnected"),aa.className="connection-status "+(V.online?"online":"offline"))}V.on(Qo);function Wo(){document.querySelectorAll("[data-i18n]").forEach(e=>{e.textContent=t(e.dataset.i18n??"")}),document.querySelectorAll("[data-locale]").forEach(e=>{e.classList.toggle("active",e.dataset.locale===Se.locale)}),Xn(),Qo()}function _r(){document.querySelectorAll("[data-locale]").forEach(e=>{e.onclick=()=>{let n=e.dataset.locale;Se.setLocale(n),jr(n)}}),_o(),Wr()}var Ko="botmux.ownerAvatar.v1";function Jo(e,n){let a=document.querySelector(".brand-mark");!a||!e||(a.innerHTML=`<img class="brand-owner-img" src="${i(e)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.remove()">`,n&&(a.title=n))}function zr(){try{let e=JSON.parse(window.localStorage.getItem(Ko)??"null");e?.avatarUrl&&Jo(String(e.avatarUrl),e.name?String(e.name):void 0)}catch{}fetch("/api/owner-profile").then(e=>e.ok?e.json():null).then(e=>{if(!(!e?.ok||!e.avatarUrl)){Jo(String(e.avatarUrl),e.name?String(e.name):void 0);try{window.localStorage.setItem(Ko,JSON.stringify({avatarUrl:e.avatarUrl,name:e.name??""}))}catch{}}}).catch(()=>{})}function Wr(){let e=document.getElementById("sidebar-toggle");if(!e)return;let n=La(window.localStorage),a=()=>{document.documentElement.dataset.sidebar=n,e.title=t(n==="collapsed"?"nav.sidebarExpand":"nav.sidebarCollapse")};a(),e.addEventListener("click",()=>{n=n==="collapsed"?"expanded":"collapsed",Ia(window.localStorage,n),a()})}(async()=>{Se.init(),_r(),jo(),Se.on(()=>{Wo(),pn(),na()}),Wo(),pn(),await Ur(),Fr(),zr();try{await ua()}catch(e){console.error("botmux dashboard bootstrap failed",e),V.setOnline(!1)}window.addEventListener("hashchange",na),na()})();})();
|