botmux 2.66.1 → 2.66.2
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/adapters/cli/traex.js +3 -3
- package/dist/adapters/cli/traex.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +121 -0
- package/dist/cli.js.map +1 -1
- package/dist/core/command-handler.d.ts +10 -0
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +50 -2
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts +2 -0
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +91 -1
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/idle-worker-sweeper.d.ts.map +1 -1
- package/dist/core/idle-worker-sweeper.js +2 -1
- package/dist/core/idle-worker-sweeper.js.map +1 -1
- package/dist/core/inherit-peer.d.ts.map +1 -1
- package/dist/core/inherit-peer.js +23 -3
- package/dist/core/inherit-peer.js.map +1 -1
- package/dist/core/persistent-backend.d.ts +18 -0
- package/dist/core/persistent-backend.d.ts.map +1 -0
- package/dist/core/persistent-backend.js +64 -0
- package/dist/core/persistent-backend.js.map +1 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +1 -33
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/worker-pool.d.ts +27 -2
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +97 -3
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts +24 -0
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +28 -26
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/web/app.js +3 -0
- package/dist/dashboard/web/app.js.map +1 -1
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +6 -0
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/sessions.d.ts.map +1 -1
- package/dist/dashboard/web/sessions.js +80 -7
- package/dist/dashboard/web/sessions.js.map +1 -1
- package/dist/dashboard/web/ui.d.ts +1 -0
- package/dist/dashboard/web/ui.d.ts.map +1 -1
- package/dist/dashboard/web/ui.js +6 -0
- package/dist/dashboard/web/ui.js.map +1 -1
- package/dist/dashboard-web/app.js +299 -299
- package/dist/dashboard-web/style.css +82 -0
- package/dist/dashboard.js +25 -1
- package/dist/dashboard.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +6 -0
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +6 -0
- package/dist/i18n/zh.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,53 +1,53 @@
|
|
|
1
|
-
"use strict";(()=>{var Nt=class{sessions=new Map;schedules=new Map;online=!0;listeners=new Set;upsertSessions(n){for(let o of n)this.sessions.set(o.sessionId,o);this.emit()}upsertSchedules(n){for(let o of n)this.schedules.set(o.id,o);this.emit()}applySse(n,o){if(n==="session.spawned")this.sessions.set(o.session.sessionId,o.session);else if(n==="session.update"){let s=this.sessions.get(o.sessionId);s&&this.sessions.set(o.sessionId,{...s,...o.patch})}else if(n==="session.exited"){let s=this.sessions.get(o.sessionId);s&&this.sessions.set(o.sessionId,{...s,status:"closed"})}else if(n==="schedule.created")this.schedules.set(o.schedule.id,o.schedule);else if(n==="schedule.updated"){let s=this.schedules.get(o.id);s&&this.schedules.set(o.id,{...s,...o.patch})}else if(n==="schedule.deleted")this.schedules.delete(o.id);else return;this.emit()}setOnline(n){this.online!==n&&(this.online=n,this.emit())}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}},Z=new Nt;async function yn(){let[e,n]=await Promise.all([fetch("/api/sessions").then(a=>a.json()),fetch("/api/schedules").then(a=>a.json())]);Z.upsertSessions(e.sessions??[]),Z.upsertSchedules(n.schedules??[]);let o=new EventSource("/events"),s=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let a of s)o.addEventListener(a,r=>{try{let l=JSON.parse(r.data);Z.applySse(a,l.body??l)}catch{}});o.onerror=()=>Z.setOnline(!1),o.onopen=()=>Z.setOnline(!0)}var Pt="botmux.dashboard.locale",Fo={"app.name":"botmux","app.subtitle":"\u98DE\u4E66 AI CLI \u63A7\u5236\u53F0","time.secondsAgo":"{value} \u79D2\u524D","time.minutesAgo":"{value} \u5206\u949F\u524D","time.hoursAgo":"{value} \u5C0F\u65F6\u524D","nav.overview":"\u603B\u89C8","nav.sessions":"\u4F1A\u8BDD","nav.groups":"\u7FA4\u7EC4","nav.schedules":"\u5B9A\u65F6","nav.settings":"\u8BBE\u7F6E","nav.botDefaults":"Bot \u914D\u7F6E","status.live":"\u5B9E\u65F6\u8FDE\u63A5","status.disconnected":"\u8FDE\u63A5\u65AD\u5F00","status.system":"\u7CFB\u7EDF","status.light":"\u6D45\u8272","status.dark":"\u6697\u9ED1","status.language":"\u8BED\u8A00","status.theme":"\u4E3B\u9898","theme.base":"\u57FA\u7840","theme.skins":"\u4E3B\u9898\u76AE\u80A4","skin.cyber":"2077","skin.genshin":"\u539F\u795E","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"\u851A\u84DD\u6863\u6848","skin.zzz":"\u7EDD\u533A\u96F6","skin.dragonball":"\u4E03\u9F99\u73E0","skin.ikun":"ikun","botOnboarding.add":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.title":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.intro":"\u9009\u62E9 CLI \u4E0E\u5DE5\u4F5C\u76EE\u5F55\uFF0C\u626B\u7801\u521B\u5EFA PersonalAgent \u5E94\u7528\u540E\u5199\u5165\u672C\u673A bots.json\uFF0C\u5E76\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u3002","botOnboarding.cliLabel":"CLI \u9002\u914D\u5668","botOnboarding.dirLabel":"\u5DE5\u4F5C\u76EE\u5F55","botOnboarding.dirPlaceholder":"\u9ED8\u8BA4 ~\uFF08\u5BB6\u76EE\u5F55\uFF09\uFF0C\u9700\u4E3A daemon \u4E3B\u673A\u4E0A\u5DF2\u5B58\u5728\u7684\u76EE\u5F55","botOnboarding.modelLabel":"\u6A21\u578B\uFF08\u53EF\u9009\uFF09","botOnboarding.modelPlaceholder":"\u7559\u7A7A\u4F7F\u7528\u8BE5 CLI \u7684\u9ED8\u8BA4\u6A21\u578B","botOnboarding.startScan":"\u5F00\u59CB\u626B\u7801","botOnboarding.cancel":"\u53D6\u6D88","botOnboarding.starting":"\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...","botOnboarding.waiting":"\u8BF7\u7528\u98DE\u4E66 App \u626B\u7801\u786E\u8BA4\u521B\u5EFA\u5E94\u7528\u3002","botOnboarding.verifying":"\u626B\u7801\u6210\u529F\uFF0C\u6B63\u5728\u6821\u9A8C\u51ED\u8BC1...","botOnboarding.configuringPermissions":"\u6B63\u5728\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u2026","botOnboarding.platformScanHint":"\u8BF7\u7528\u98DE\u4E66 App \u518D\u626B\u4E00\u6B21\u7801\u767B\u5F55\u5F00\u653E\u5E73\u53F0\uFF08\u7528\u4E8E\u81EA\u52A8\u5BFC\u5165\u6743\u9650\u3001\u914D\u7F6E\u56DE\u8C03\u3001\u63D0\u4EA4\u7248\u672C\uFF09\u3002","botOnboarding.platformQrAlt":"\u5F00\u653E\u5E73\u53F0\u767B\u5F55\u4E8C\u7EF4\u7801","botOnboarding.completed":"\u673A\u5668\u4EBA\u5DF2\u6DFB\u52A0\u3002","botOnboarding.permissionOk":"\u5DF2\u81EA\u52A8\u5BFC\u5165 {count} \u9879\u6743\u9650\u3002","botOnboarding.permissionSkipped":"\uFF08\u8DF3\u8FC7 {count} \u9879\u5F53\u524D\u79DF\u6237\u76EE\u5F55\u4E2D\u6CA1\u6709\u7684\u6743\u9650\uFF09","botOnboarding.permissionVersion":"\u5DF2\u63D0\u4EA4\u53D1\u5E03\u7248\u672C {version}\u3002","botOnboarding.permissionManual":"\u6743\u9650\u672A\u80FD\u81EA\u52A8\u914D\u7F6E\uFF0C\u8BF7\u624B\u52A8\u5B8C\u6210\u4EE5\u4E0B\u6B65\u9AA4\uFF1A","botOnboarding.metaDir":"\u76EE\u5F55","botOnboarding.failed":"\u6DFB\u52A0\u5931\u8D25","botOnboarding.openLink":"\u6253\u4E0D\u5F00\u626B\u7801\uFF1F\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00","botOnboarding.close":"\u5173\u95ED","botOnboarding.restartHint":"\u5DF2\u5199\u5165 bots.json\u3002\u6267\u884C pnpm daemon:restart \u540E\u65B0\u673A\u5668\u4EBA\u751F\u6548\u3002","botOnboarding.qrAlt":"\u98DE\u4E66\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA\u4E8C\u7EF4\u7801","overview.title":"\u5DE5\u4F5C\u53F0","overview.subtitle":"\u6570\u5B57\u5458\u5DE5\u5B9E\u65F6\u72B6\u6001 \xB7 \u540C\u6B65\u98DE\u4E66\u8BDD\u9898","overview.team":"AI \u56E2\u961F","overview.teamHint":"\u6BCF\u4F4D\u6570\u5B57\u5458\u5DE5\u7684\u5B9E\u65F6\u72B6\u6001","overview.attention":"\u9700\u8981\u4F60\u5904\u7406","overview.attentionHint":"\u5361\u4F4F\u7684\u4EFB\u52A1\uFF0C\u56DE\u4E2A\u8BDD\u5C31\u80FD\u7EE7\u7EED\u8DD1","overview.activeSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.activeSessionsHint":"\u6B63\u5728\u8FD0\u8F6C\u7684\u4F1A\u8BDD","overview.today":"\u6B64\u523B\u6982\u89C8","overview.todayHint":"\u6D3B\u8DC3\u4F1A\u8BDD\u5206\u5E03","overview.viewAll":"\u67E5\u770B\u5168\u90E8 \u2192","overview.botIdle":"\u5F85\u547D\u4E2D\uFF0C\u968F\u65F6\u53EF\u63A5\u65B0\u4EFB\u52A1","overview.botOffline":"\u79BB\u7EBF \u2014 daemon \u672A\u4E0A\u7EBF","overview.botBusy":"\u6267\u884C\u4E2D \xB7 {count} \u4F1A\u8BDD","overview.botNeedsYou":"\u7B49\u4F60\u56DE\u590D","overview.botReady":"\u5C31\u7EEA","overview.botOff":"\u79BB\u7EBF","overview.sessionsCount":"{count} \u4F1A\u8BDD","overview.lastActive":"{time}\u524D\u6D3B\u8DC3","overview.noAttention":"\u6CA1\u6709\u7B49\u4F60\u5904\u7406\u7684\u4E8B\u9879","strip.pending":"{count} \u4EF6\u5F85\u5904\u7406","strip.longest":"\u6700\u4E45\u5DF2\u7B49 {time} \u2014 {bot} {reason}","strip.handle":"\u7ACB\u5373\u5904\u7406","overview.openSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.workingSessions":"\u5DE5\u4F5C\u4E2D","overview.onlineBots":"\u5728\u7EBF Bot","overview.schedules":"\u5B9A\u65F6\u4EFB\u52A1","overview.groups":"\u7FA4\u804A\u8986\u76D6","overview.enabledSchedules":"\u5DF2\u542F\u7528","overview.total":"\u603B\u8BA1","overview.active":"\u6D3B\u8DC3","overview.daemonRegistry":"daemon \u6CE8\u518C\u8868","overview.chatMatrix":"\u7FA4\u804A\u77E9\u9635","overview.recentSessions":"\u6700\u8FD1\u4F1A\u8BDD","overview.nextSchedules":"\u5373\u5C06\u6267\u884C","overview.noSessions":"\u6682\u65E0\u4F1A\u8BDD\u3002","overview.noSchedules":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","sessions.title":"\u4F1A\u8BDD\u63A7\u5236","sessions.subtitle":"\u5B9A\u4F4D\u98DE\u4E66\u8BDD\u9898\u3001\u6253\u5F00 Web Terminal\u3001\u5173\u95ED\u6216\u6062\u590D CLI \u4F1A\u8BDD\u3002","sessions.search":"\u641C\u7D22\u5DE5\u4F5C\u76EE\u5F55 / \u6807\u9898 / ID","sessions.anyStatus":"\u5168\u90E8\u72B6\u6001","sessions.adoptAny":"adopt: \u5168\u90E8","sessions.adoptYes":"adopt: \u662F","sessions.adoptNo":"adopt: \u5426","sessions.activeOnly":"\u4EC5\u6D3B\u8DC3","sessions.closeSelected":"\u5173\u95ED\u9009\u4E2D","sessions.clearSelection":"\u53D6\u6D88\u9009\u62E9","sessions.selectedCount":"\u5DF2\u9009 {count} \u4E2A\u4F1A\u8BDD","sessions.bot":"bot","sessions.cli":"CLI","sessions.chat":"\u7FA4\u804A","sessions.openChat":"\u6253\u5F00\u7FA4\u804A","sessions.status":"\u72B6\u6001","sessions.titleCol":"\u6807\u9898","sessions.workingDir":"\u5DE5\u4F5C\u76EE\u5F55","sessions.created":"\u521B\u5EFA","sessions.last":"\u6700\u8FD1","sessions.adopt":"\u63A5\u5165","sessions.actions":"\u64CD\u4F5C","sessions.details":"\u8BE6\u60C5","sessions.copy":"\u590D\u5236","sessions.copied":"\u5DF2\u590D\u5236","sessions.locate":"\u5B9A\u4F4D\u8BDD\u9898","sessions.locating":"\u53D1\u9001\u4E2D...","sessions.cooldown":"\u51B7\u5374 {seconds}s","sessions.openTerminal":"\u7EC8\u7AEF","sessions.close":"\u5173\u95ED\u4F1A\u8BDD","sessions.resume":"\u6062\u590D\u4F1A\u8BDD","sessions.dismiss":"\u5173\u95ED","sessions.closeConfirm":"\u5173\u95ED\u8FD9\u4E2A\u4F1A\u8BDD\uFF1F","sessions.resumeFailed":"\u6062\u590D\u5931\u8D25","sessions.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.viewBoard":"\u72B6\u6001\u677F","sessions.viewTable":"\u8868\u683C","sessions.selectSession":"\u9009\u62E9\u4F1A\u8BDD","sessions.board.needsYou":"\u9700\u8981\u4F60","sessions.board.needsYouHint":"\u7B49\u5F85\u4ED3\u5E93\u3001TUI \u9009\u62E9\u6216\u989D\u5EA6\u5904\u7406","sessions.board.starting":"\u542F\u52A8\u4E2D","sessions.board.startingHint":"CLI \u6B63\u5728\u521B\u5EFA\u6216\u6062\u590D","sessions.board.working":"\u5E72\u6D3B\u4E2D","sessions.board.workingHint":"\u6B63\u5728\u8F93\u51FA\u3001\u5206\u6790\u6216\u6267\u884C\u5DE5\u5177","sessions.board.idle":"\u7A7A\u95F2","sessions.board.idleHint":"\u53EF\u7EE7\u7EED\u5BF9\u8BDD\u6216\u63A5\u65B0\u4EFB\u52A1","sessions.board.emptyColumn":"\u6682\u65E0\u4F1A\u8BDD","sessions.board.signalRepo":"\u5F85\u9009\u4ED3\u5E93","sessions.board.signalPrompt":"\u7B49\u5F85 TUI \u9009\u62E9","sessions.board.signalLimited":"\u989D\u5EA6\u53D7\u9650","sessions.board.signalAgent":"\u9700\u8981\u4EBA\u5DE5\u4ECB\u5165","sessions.board.waiting":"\u7B49\u5F85","sessions.board.dragHint":"\u62D6\u52A8\u5217\u5934\u8C03\u6574\u5217\u987A\u5E8F","sessions.board.moveLeft":"\u5DE6\u79FB\u6B64\u5217","sessions.board.moveRight":"\u53F3\u79FB\u6B64\u5217","groups.title":"\u7FA4\u7EC4\u4E0E Bot","groups.subtitle":"\u67E5\u770B chat x bot \u8986\u76D6\u77E9\u9635\uFF0C\u7BA1\u7406\u62C9\u7FA4\u3001oncall\u3001\u9000\u7FA4\u548C\u89E3\u6563\u3002","groups.search":"\u641C\u7D22\u7FA4\u540D / ID / owner","groups.missingOnly":"\u4EC5\u7F3A bot","groups.refresh":"\u5237\u65B0","groups.create":"\u65B0\u5EFA\u7FA4","groups.chat":"\u7FA4\u804A","groups.actions":"\u64CD\u4F5C","groups.addBots":"\u6DFB\u52A0 bot","groups.manage":"\u7BA1\u7406","groups.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u7FA4\u804A\u3002","groups.createTitle":"\u65B0\u5EFA\u7FA4\u804A","groups.createHelp":"\u9009\u62E9\u8981\u9080\u8BF7\u7684 bot\u3002dashboard \u4F1A\u81EA\u52A8\u9009\u62E9\u5728\u7EBF daemon \u4F5C\u4E3A\u521B\u5EFA\u8005\u3002","groups.name":"\u7FA4\u540D","groups.namePlaceholder":"\u4F8B\u5982 AI ChangeLog","groups.bindDir":"\u7ED1\u5B9A\u76EE\u5F55","groups.bindDirHelp":"\u65B0\u8BDD\u9898\u76F4\u63A5\u7528\u8BE5\u76EE\u5F55\u542F\u52A8 CLI\uFF0C\u8DF3\u8FC7 repo \u9009\u62E9\u3002","groups.botPicker":"Bot","groups.createSubmit":"\u521B\u5EFA","groups.cancel":"\u53D6\u6D88","groups.successTitle":"\u7FA4\u521B\u5EFA\u6210\u529F","groups.openGroup":"\u6253\u5F00\u65B0\u7FA4","groups.manageTitle":"\u7BA1\u7406 {name}","groups.owner":"\u7FA4\u4E3B","groups.oncall":"Oncall \u6A21\u5F0F","groups.oncallHelp":"\u5F00\u542F\u540E\uFF0C\u7FA4\u5185\u6210\u5458\u53EF @ \u673A\u5668\u4EBA\uFF1B\u65B0\u8BDD\u9898\u76F4\u63A5\u4F7F\u7528\u7ED1\u5B9A\u76EE\u5F55\u3002","groups.leaveTitle":"\u9009\u62E9\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.leaveSelected":"\u9009\u4E2D\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.disband":"\u89E3\u6563\u7FA4\u804A","groups.dangerHint":"\u89E3\u6563\u4EC5\u5F53\u5728\u7FA4\u673A\u5668\u4EBA\u662F\u7FA4\u4E3B\u65F6\u624D\u4F1A\u6210\u529F\uFF0C\u5426\u5219\u5EFA\u8BAE\u4F7F\u7528\u9000\u51FA\u7FA4\u804A\u3002","groups.save":"\u4FDD\u5B58","groups.needWorkingDir":"\u8BF7\u586B\u5DE5\u4F5C\u76EE\u5F55","groups.noBotsOnline":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u8BF7\u5148\u91CD\u542F daemon\u3002","schedules.title":"\u5B9A\u65F6\u4EFB\u52A1","schedules.subtitle":"\u8DE8 daemon \u67E5\u770B\u3001\u6682\u505C\u3001\u6062\u590D\u548C\u7ACB\u5373\u89E6\u53D1\u5B9A\u65F6\u4EFB\u52A1\u3002","schedules.search":"\u641C\u7D22\u540D\u79F0 / prompt / \u5DE5\u4F5C\u76EE\u5F55","schedules.anyKind":"\u5168\u90E8\u7C7B\u578B","schedules.enabledOnly":"\u4EC5\u542F\u7528","schedules.name":"\u540D\u79F0","schedules.bot":"bot","schedules.schedule":"\u89C4\u5219","schedules.next":"\u4E0B\u6B21","schedules.last":"\u4E0A\u6B21","schedules.repeat":"\u91CD\u590D","schedules.enabled":"\u542F\u7528","schedules.actions":"\u64CD\u4F5C","schedules.runNow":"\u7ACB\u5373\u8FD0\u884C","schedules.pause":"\u6682\u505C","schedules.resume":"\u6062\u590D","schedules.empty":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","settings.title":"\u5168\u5C40\u8BBE\u7F6E","settings.subtitle":"\u7BA1\u7406\u672C\u673A botmux dashboard \u4E0E\u6240\u6709 bot \u5171\u4EAB\u7684\u5168\u5C40\u884C\u4E3A\u3002","settings.loading":"\u6B63\u5728\u52A0\u8F7D\u8BBE\u7F6E\u2026","settings.loadFailed":"\u8BBE\u7F6E\u52A0\u8F7D\u5931\u8D25","settings.readOnlyVisitor":"\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u4FEE\u6539\u8BBE\u7F6E\u9700\u8981\u6388\u6743\u94FE\u63A5\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09","settings.sectionAccess":"\u8BBF\u95EE\u6743\u9650","settings.publicReadOnly":"\u5141\u8BB8\u65E0 token \u53EA\u8BFB\u8BBF\u95EE dashboard","settings.publicReadOnlyHelp":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 token \u7684\u8BBF\u95EE\u8005\u53EF\u4EE5\u67E5\u770B dashboard\u3001\u4F1A\u8BDD\u3001\u5B9A\u65F6\u4EFB\u52A1\u548C SSE\uFF1B\u5173\u95ED\u3001\u6682\u505C\u3001\u5BA1\u6279\u7B49\u5199\u64CD\u4F5C\u4ECD\u5FC5\u987B\u901A\u8FC7 token \u9274\u6743\u3002\u654F\u611F\u7EC8\u7AEF\u539F\u59CB\u65E5\u5FD7\u59CB\u7EC8\u9700\u8981 token\u3002","settings.sectionCards":"\u98DE\u4E66\u5361\u7247","settings.openTerminalInFeishu":"\u6D41\u5F0F\u5361\u7247\u7EC8\u7AEF\u6309\u94AE\u5728\u98DE\u4E66\u4FA7\u680F\u6253\u5F00","settings.openTerminalInFeishuHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF1A\u7EC8\u7AEF\u6309\u94AE\u76F4\u63A5\u6253\u5F00 Web Terminal URL\u3002\u5F00\u542F\u540E\u4F7F\u7528\u98DE\u4E66 web_url/open \u5305\u88C5\uFF0C\u5728\u98DE\u4E66 PC \u4FA7\u680F\u91CC\u6253\u5F00\uFF1B\u5199\u6743\u9650\u4ECD\u7531\u7EC8\u7AEF token \u63A7\u5236\u3002","settings.saving":"\u4FDD\u5B58\u4E2D\u2026","settings.saved":"\u5DF2\u4FDD\u5B58","settings.saveFailed":"\u4FDD\u5B58\u5931\u8D25","settings.sectionMaintenance":"\u81EA\u52A8\u7EF4\u62A4","settings.autoUpdate":"\u81EA\u52A8\u66F4\u65B0","settings.autoUpdateHelp":"\u9ED8\u8BA4\u5173\u95ED\u3002\u5230\u70B9\u6267\u884C npm install -g botmux@latest \u5B89\u88C5\u6700\u65B0\u7248\u672C\uFF08\u53EA\u4E0B\u8F7D\u5B89\u88C5\u3001\u672C\u8EAB\u4E0D\u91CD\u542F\uFF09\u3002\u4EC5 npm \u5168\u5C40\u5B89\u88C5\u53EF\u7528\u3002","settings.autoRestart":"\u81EA\u52A8\u91CD\u542F","settings.autoRestartHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF0C\u9700\u5148\u5F00\u542F\u81EA\u52A8\u66F4\u65B0\u3002\u81EA\u52A8\u66F4\u65B0\u88C5\u5230\u65B0\u7248\u672C\u540E\uFF0C\u82E5\u6CA1\u6709\u8FDB\u884C\u4E2D\u7684\u4F1A\u8BDD\u5219\u81EA\u52A8\u91CD\u542F\u4EE5\u751F\u6548\uFF08\u649E\u4E0A\u5FD9\u788C\u4F1A\u8BDD\u5219\u8DF3\u5230\u6B21\u65E5\uFF09\u3002","settings.autoUpdateLocalDev":"\u5F53\u524D\u4E3A\u672C\u5730\u5F00\u53D1\u5B89\u88C5\uFF08\u4ECE\u6E90\u7801\u8FD0\u884C\uFF09\uFF0C\u81EA\u52A8\u66F4\u65B0\u4E0D\u53EF\u7528\u3002","settings.maintenanceTime":"\u65F6\u95F4","botDefaults.title":"\u6570\u5B57\u5458\u5DE5\u6863\u6848","botDefaults.subtitle":"\u6BCF\u4F4D\u5458\u5DE5\u7684\u9ED8\u8BA4\u884C\u4E3A\uFF1Aoncall\u3001\u4E3B\u52A8\u5F00\u5DE5\u3001\u4EBA\u8BBE\u89D2\u8272\u3001\u5361\u7247\u4E0E\u6388\u6743\u3002","botDefaults.metaOnline":"\u5728\u7EBF \xB7 daemon \u6B63\u5E38","botDefaults.search":"\u641C\u7D22 bot \u540D / app id","botDefaults.refresh":"\u5237\u65B0","botDefaults.sectionOncall":"\u65B0\u7FA4 Oncall","botDefaults.sectionBrand":"\u5361\u7247\u7B7E\u540D","botDefaults.warning":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 oncall binding \u7684\u7FA4\u4F1A\u5728\u4E0B\u6B21\u5F00\u65B0\u8BDD\u9898\u65F6\u81EA\u52A8\u7ED1\u5B9A\u5230\u8BE5\u76EE\u5F55\uFF1B\u624B\u52A8\u7ED1\u5B9A\u6216\u624B\u52A8\u89E3\u7ED1\u8FC7\u7684\u7FA4\u4E0D\u4F1A\u88AB\u8986\u76D6\u3002","botDefaults.empty":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u5148 botmux restart \u8BA9 daemon \u4E0A\u7EBF\u3002","botDefaults.defaultOncall":"\u9ED8\u8BA4\u8FDB\u5165 oncall \u6A21\u5F0F","botDefaults.defaultOncallHelp":"\u6240\u6709\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8\u7ED1\u5B9A","botDefaults.workingDir":"\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55","botDefaults.lastEnabled":"\u4E0A\u6B21\u542F\u7528\u65F6\u95F4","botDefaults.autobound":"\u5DF2\u81EA\u52A8\u7ED1\u5B9A {count} \u4E2A\u7FA4","botDefaults.save":"\u4FDD\u5B58","botDefaults.required":"\u5F00\u542F\u65F6\u5FC5\u987B\u586B\u5DE5\u4F5C\u76EE\u5F55","botDefaults.brandLabel":"\u4E2A\u6027\u7B7E\u540D\uFF08\u5361\u7247\u9875\u811A\uFF09","botDefaults.brandLabelHelp":"\u8BE5 bot \u53D1\u51FA\u7684\u5361\u7247\u9875\u811A\u7B7E\u540D\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u4E0D\u663E\u793A\uFF1B\u586B\u5199\uFF1D\u81EA\u5B9A\u4E49\uFF08\u652F\u6301 markdown\uFF0C\u5982 [Acme](https://\u2026)\uFF09\uFF1B\u6062\u590D\u9ED8\u8BA4\uFF1D\u663E\u793A botmux\u3002","botDefaults.brandLabelPlaceholder":"\u9ED8\u8BA4\uFF1Abotmux\uFF08\u7559\u7A7A\u5219\u4E0D\u663E\u793A\uFF09","botDefaults.sectionSandbox":"\u6587\u4EF6\u6C99\u76D2\uFF08oncall\uFF09","botDefaults.sandboxToggle":"\u5F00\u542F\u6587\u4EF6\u6C99\u76D2","botDefaults.sandboxHelp":"\u5F00\u542F\u540E\uFF0C\u8BE5 bot \u7684\u6BCF\u4E2A\u4F1A\u8BDD\u90FD\u8DD1\u5728\u6309\u4F1A\u8BDD\u9694\u79BB\u7684\u6C99\u76D2\u91CC\uFF1A\u53EA\u770B\u5F97\u5230\u4E00\u4EFD\u9879\u76EE\u526F\u672C\uFF0C\u78B0\u4E0D\u5230\u4F60\u78C1\u76D8\u4E0A\u7684\u771F\u5B9E\u6587\u4EF6\u3001\u5BC6\u94A5\u3001\u522B\u7684\u4F1A\u8BDD\u6570\u636E\u3002\u9002\u5408\u628A\u673A\u5668\u4EBA\u5206\u4EAB\u7ED9\u534A\u53D7\u4FE1\u4EFB\u7684\u4EBA\uFF08oncall\uFF09\u3002\u4EC5 Linux \u751F\u6548\uFF0C\u4E0B\u4E2A\u65B0\u4F1A\u8BDD\u8D77\u6548\u3002","botDefaults.sandboxSaved":"\u5DF2\u4FDD\u5B58\uFF08\u4E0B\u4E2A\u65B0\u4F1A\u8BDD\u751F\u6548\uFF09","botDefaults.brandSave":"\u4FDD\u5B58\u7B7E\u540D","botDefaults.brandReset":"\u6062\u590D\u9ED8\u8BA4","botDefaults.brandStateDefault":"\u5F53\u524D\uFF1A\u9ED8\u8BA4 botmux","botDefaults.brandStateOff":"\u5F53\u524D\uFF1A\u5DF2\u5173\u95ED","botDefaults.brandStateCustom":"\u5F53\u524D\uFF1A\u81EA\u5B9A\u4E49","botDefaults.sectionCard":"\u5361\u7247\u884C\u4E3A","botDefaults.disableStreaming":"\u5173\u95ED\u98DE\u4E66\u6D41\u5F0F\u5361\u7247","botDefaults.disableStreamingHelp":"\u4E0D\u518D\u53D1\u5B9E\u65F6\u5237\u65B0\u7684\u4F1A\u8BDD\u72B6\u6001\u5361\uFF08\u542B\u300C\u6253\u5F00\u7EC8\u7AEF\u300D\u5165\u53E3\uFF09\uFF1B\u4EFB\u52A1\u6700\u7EC8\u7ED3\u679C\u4ECD\u901A\u8FC7\u6D88\u606F\u9001\u8FBE\u3002\u9002\u5408\u5ACC\u6D41\u5F0F\u5361\u7247\u70E6\u7684\u573A\u666F\u3002","botDefaults.writableLink":"\u5361\u7247\u4E0A\u76F4\u63A5\u7ED9\u53EF\u64CD\u4F5C\uFF08\u53EF\u5199\uFF09\u7EC8\u7AEF\u94FE\u63A5","botDefaults.writableLinkHelp":"\u26A0\uFE0F \u5728\u6D41\u5F0F\u5361\u7247\u6B63\u6587\u76F4\u63A5\u8D34\u51FA\u53EF\u5199\u7EC8\u7AEF\u94FE\u63A5\uFF0C\u7FA4\u5185\u4EFB\u4F55\u4EBA\u90FD\u80FD\u70B9\u5F00\u5E76\u64CD\u63A7\u7EC8\u7AEF\u3002\u4E0D\u52FE\uFF1D\u4FDD\u6301\u73B0\u72B6\uFF08\u8D70\u300C\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u300D\u6309\u94AE\u79C1\u804A\u53D1\u7ED9\u70B9\u51FB\u8005\uFF09\u3002","botDefaults.writableLinkMoot":"\u5DF2\u5173\u95ED\u6D41\u5F0F\u5361\u7247","botDefaults.privateCard":"/card \u53D1\u79C1\u5BC6\u5361\u7247\uFF08\u4EC5\u6388\u6743\u4EBA\u53EF\u89C1\uFF09","botDefaults.privateCardHelp":"\u5F00\u542F\u540E /card \u6539\u7528\u300C\u4EC5\u7279\u5B9A\u4EBA\u53EF\u89C1\u300D\u7684\u4E34\u65F6\u5361\u7247\uFF1A\u53EA\u53D1\u7ED9 owner\uFF08allowedUsers\uFF09\uFF0C/grant \u6388\u6743\u5BF9\u8BDD\u7684\u4EBA\u548C\u7FA4\u91CC\u5176\u4ED6\u4EBA\u90FD\u770B\u4E0D\u5230\u3002\u4EE3\u4EF7\uFF1A\u662F\u9759\u6001\u5FEB\u7167\u3001\u4E0D\u4F1A\u5B9E\u65F6\u5237\u65B0\uFF1B\u4E14\u4EC5\u666E\u901A\u7FA4\u53EF\u7528\uFF08\u8BDD\u9898\u7FA4 / \u5355\u804A\u4F1A\u5931\u8D25\uFF0C\u4E0D\u964D\u7EA7\uFF09\u3002\u53EA\u5F71\u54CD /card \u547D\u4EE4\uFF0C\u81EA\u52A8\u6D41\u5F0F\u5361\u4E0D\u53D8\u3002","botDefaults.cardPrefSaved":"\u5DF2\u4FDD\u5B58","botDefaults.sectionRole":"\u9ED8\u8BA4\u89D2\u8272","botDefaults.roleHelp":"\u8BE5 bot \u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF08\u8DE8\u7FA4\u751F\u6548\uFF09\uFF0C\u4F1A\u6CE8\u5165\u5230\u8BE5 bot \u5728\u5404\u7FA4\u7684\u4F1A\u8BDD\u91CC\uFF1B\u5355\u4E2A\u7FA4\u53EF\u5728\u300C\u89D2\u8272\u300D\u9875\u5355\u72EC\u8986\u76D6\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u5220\u9664\u3002","botDefaults.rolePlaceholder":"\u4F8B\u5982\uFF1A\u4F60\u662F\u540E\u7AEF\u6392\u969C\u52A9\u624B\uFF0C\u56DE\u7B54\u7B80\u6D01\u3001\u4F18\u5148\u7ED9\u53EF\u6267\u884C\u547D\u4EE4\u2026","botDefaults.roleSave":"\u4FDD\u5B58\u89D2\u8272","botDefaults.roleDelete":"\u5220\u9664","botDefaults.roleSaved":"\u5DF2\u4FDD\u5B58","botDefaults.roleDeleted":"\u5DF2\u5220\u9664","botDefaults.roleLoadErr":"\u89D2\u8272\u52A0\u8F7D\u5931\u8D25","botDefaults.sectionAutoStart":"\u4E3B\u52A8\u5F00\u5DE5","botDefaults.autoStartJoin":"\u88AB\u62C9\u8FDB\u65B0\u7FA4\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartJoinHelp":"\u5F00\u542F\u540E\uFF0C\u673A\u5668\u4EBA\u4E00\u88AB\u62C9\u8FDB\u65B0\u7FA4\uFF08\u7FA4\u91CC\u6709\u6388\u6743\u7528\u6237 allowedUsers \u65F6\uFF09\u5C31\u81EA\u52A8\u5F00\u4E00\u4E2A\u4F1A\u8BDD\u5F00\u59CB\u5DE5\u4F5C\uFF0C\u65E0\u9700 @\u3002\u5728\u673A\u5668\u4EBA\u7684\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55\u542F\u52A8\uFF1B\u672A\u914D\u7F6E\u9ED8\u8BA4\u76EE\u5F55\u65F6\u5148\u5F39\u4ED3\u5E93\u9009\u62E9\u5361\u8BA9\u4F60\u9009\u3002\u524D\u63D0\uFF1A\u9700\u5728\u98DE\u4E66\u5F00\u653E\u5E73\u53F0\u4E3A\u672C\u5E94\u7528\u8BA2\u9605\u300C\u673A\u5668\u4EBA\u8FDB\u7FA4\u300D\u4E8B\u4EF6 im.chat.member.bot.added_v1\uFF0C\u5E76\u5F00\u901A\u7FA4\u6210\u5458\u8BFB\u53D6\u6743\u9650\u3002","botDefaults.autoStartJoinPrompt":"\u5165\u7FA4\u9996\u8F6E prompt\uFF08\u53EF\u9009\uFF09","botDefaults.autoStartJoinPromptPlaceholder":"\u586B\u4E86\uFF1D\u4F5C\u4E3A\u5165\u7FA4\u540E\u7684\u7B2C\u4E00\u6761\u4EFB\u52A1\uFF1B\u7559\u7A7A\uFF1D\u673A\u5668\u4EBA\u81EA\u5DF1\u770B\u7FA4\u91CC\u4FE1\u606F\u51B3\u5B9A\u505A\u4EC0\u4E48","botDefaults.autoStartJoinPromptSave":"\u4FDD\u5B58 prompt","botDefaults.autoStartTopic":"\u8BDD\u9898\u7FA4\u65B0\u8BDD\u9898\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartTopicHelp":"\u5F00\u542F\u540E\uFF0C\u5728\u8BDD\u9898\u7FA4\u91CC\u6BCF\u5F53\u6709\u4EBA\u65B0\u5F00\u4E00\u4E2A\u8BDD\u9898\uFF0C\u673A\u5668\u4EBA\u5C31\u4F1A\u81EA\u52A8\u63A5\u5165\u8BE5\u8BDD\u9898\u3001\u628A\u9996\u6761\u6D88\u606F\u5F53\u4F5C\u4EFB\u52A1\u5F00\u59CB\u5904\u7406\uFF0C\u65E0\u9700 @\u3002\u4EC5\u5BF9\u8BDD\u9898\u7FA4\u751F\u6548\uFF0C\u666E\u901A\u7FA4\u4E0D\u53D7\u5F71\u54CD\u3002","botDefaults.sectionSessionMode":"\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.p2pMode":"\u79C1\u804A\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.p2pThread":"thread\uFF08\u6BCF\u6761 DM \u72EC\u7ACB\u4F1A\u8BDD\uFF09","botDefaults.p2pChat":"chat\uFF08\u6241\u5E73\u8FDE\u7EED\u5355\u804A\u4F1A\u8BDD\uFF09","botDefaults.p2pHelp":"\u79C1\u804A\uFF081:1 DM\uFF09\u7684\u4F1A\u8BDD\u65B9\u5F0F\uFF1Athread = \u6BCF\u6761\u9876\u5C42\u6D88\u606F\u5404\u81EA\u8D77\u72EC\u7ACB\u4F1A\u8BDD\uFF08\u907F\u514D\u628A\u5BF9\u8BDD\u5806\u8FDB\u540C\u4E00\u4E2A CLI \u8FDB\u7A0B\uFF09\uFF1Bchat = \u6574\u6BB5 DM \u5171\u7528\u4E00\u4E2A\u8FDE\u7EED\u4F1A\u8BDD\u3001\u5171\u4EAB\u4E0A\u4E0B\u6587\uFF08\u7C7B Hermes\uFF09\u3002\u6539\u540E\u7ACB\u5373\u751F\u6548\u3002","botDefaults.regularGroupMode":"\u666E\u901A\u7FA4\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.regularGroupModeChat":"chat\uFF08\u6241\u5E73\u8FDE\u7EED\u5355\u804A\u4F1A\u8BDD\uFF0C\u9ED8\u8BA4\uFF09","botDefaults.regularGroupModeNewTopic":"new-topic\uFF08\u6BCF\u6761\u9876\u5C42 @ \u5404\u5F00\u72EC\u7ACB\u8BDD\u9898\u4E0E\u4F1A\u8BDD\uFF09","botDefaults.regularGroupModeShared":"shared\uFF08\u8BDD\u9898\u6A21\u5F0F\u4F46\u590D\u7528\u540C\u4E00\u4E2A session\uFF09","botDefaults.regularGroupModeHelp":"\u666E\u901A\u7FA4\uFF08\u975E\u8BDD\u9898\u7FA4\uFF09\u91CC @ \u8BE5 bot \u7684\u65B0\u9876\u5C42\u6D88\u606F\u600E\u4E48\u5F00\u4F1A\u8BDD\uFF1Achat = \u6574\u7FA4\u5171\u7528\u4E00\u4E2A\u8FDE\u7EED\u4F1A\u8BDD\uFF08\u9ED8\u8BA4\uFF09\uFF1Bnew-topic = \u6BCF\u6761\u9876\u5C42 @ \u5728\u539F\u6D88\u606F\u4E0B\u5F00\u72EC\u7ACB\u8BDD\u9898\u3001\u5404\u81EA\u72EC\u7ACB\u4F1A\u8BDD\uFF1Bshared = \u8BDD\u9898\u6A21\u5F0F\u4F46\u590D\u7528\u540C\u4E00\u4E2A session\uFF08\u56DE\u590D\u843D\u5728\u8BDD\u9898\u91CC\u3001\u4F46\u5171\u7528\u672C\u7FA4\u4F1A\u8BDD\u4E0E\u4E0A\u4E0B\u6587\uFF09\u3002\u8FD9\u662F per-bot \u9ED8\u8BA4\uFF0C\u5177\u4F53\u67D0\u4E2A\u7FA4\u53EF\u7528 /reply-mode \u5355\u72EC\u8986\u76D6\u3002\u6539\u540E\u7ACB\u5373\u751F\u6548\u3002","botDefaults.mentionMode":"\u7FA4\u804A @ \u7B56\u7565","botDefaults.mentionModeAlways":"\u90FD\u9700\u8981 @\uFF08\u9ED8\u8BA4\uFF09","botDefaults.mentionModeTopic":"\u4EC5\u8BDD\u9898\u5185\u4E0D\u9700\u8981 @","botDefaults.mentionModeNever":"\u6240\u6709\u6D88\u606F\u90FD\u4E0D\u9700\u8981 @","botDefaults.mentionModeHelp":"\u8BE5 bot \u5168\u5C40\u751F\u6548\uFF0C\u51B3\u5B9A\u7FA4\u91CC\u8981\u4E0D\u8981 @ \u624D\u56DE\uFF1A\u300C\u90FD\u9700\u8981 @\u300D= \u4EFB\u4F55\u6D88\u606F\u90FD\u5F97 @\uFF08\u9ED8\u8BA4\uFF0C\u6700\u5B89\u5168\uFF1B\u591A\u4EBA\u7FA4\u91CC\u8BDD\u9898\u5185\u4E5F\u8981 @\uFF09\uFF1B\u300C\u4EC5\u8BDD\u9898\u5185\u4E0D\u9700\u8981 @\u300D= \u8D77\u65B0\u5BF9\u8BDD / \u9876\u5C42\u4ECD\u8981 @\uFF0C\u4F46\u5728\u8BE5 bot \u5DF2\u5F00\u7684\u4EFB\u4F55\u8BDD\u9898\u91CC\uFF08new-topic / shared / \u8BDD\u9898\u7FA4\uFF09\u540E\u7EED\u6D88\u606F\u514D @ \u7EED\u804A\uFF1B\u300C\u6240\u6709\u6D88\u606F\u90FD\u4E0D\u9700\u8981 @\u300D= \u8BE5 bot \u6709\u5BF9\u8BDD\u6743\u9650\u7684\u7FA4\u91CC\u975E @ \u6D88\u606F\u4E5F\u56DE\uFF08\u542B\u5168\u65B0\u6D88\u606F\u51B7\u542F\u52A8\uFF0C\u4EC5\u9002\u5408\u4E13\u7528 / \u503C\u73ED\u5C0F\u7FA4\uFF0C\u591A\u4EBA\u7FA4\u91CC\u4F1A\u89C1\u6D88\u606F\u5C31\u56DE\uFF09\u3002\u6CE8\uFF1A\u7FA4\u91CC\u53EA\u6709\u4F60\u548C\u8BE5 bot\uFF081 \u5BF9 1\uFF09\u65F6\u4E00\u76F4\u514D @\uFF0C\u4E0E\u672C\u8BBE\u7F6E\u65E0\u5173\u3002","botDefaults.sectionGrant":"\u6388\u6743\u4E0E\u989D\u5EA6","botDefaults.restrictGrant":"\u9650\u5236\u88AB\u6388\u6743\u4EBA\u53EA\u80FD\u7EAF\u5BF9\u8BDD","botDefaults.restrictGrantHelp":"\u5F00\u542F\u540E\uFF0C\u88AB /grant \u6388\u6743\u7684\u4EBA\uFF08owner \u81EA\u5DF1\u4E0D\u53D7\u9650\uFF09\u53EA\u80FD\u53D1\u666E\u901A\u5BF9\u8BDD\uFF0C\u6240\u6709 slash \u547D\u4EE4\u4E00\u5F8B\u62E6\u622A\uFF1Abotmux \u81EA\u5E26\u547D\u4EE4\u3001\u900F\u4F20\u547D\u4EE4\u3001/workflow\u3001/introduce\u3001/t \u4EE5\u53CA CLI \u539F\u751F\u547D\u4EE4\uFF08/help \u7B49\uFF09\u3002\u5F62\u5982 /path/to/file \u7684\u5185\u5BB9\u4E0D\u4F1A\u88AB\u8BEF\u5224\u3002","botDefaults.quotaDefault":"\u9ED8\u8BA4\u6D88\u606F\u989D\u5EA6","botDefaults.quotaPlaceholder":"\u7559\u7A7A\uFF1D\u4E0D\u914D\u7F6E\u9ED8\u8BA4\u989D\u5EA6","botDefaults.quotaHelp":"\u4E0D\u5E26\u6570\u5B57\u7684 /grant @x \u9ED8\u8BA4\u7ED9\u7684\u6D88\u606F\u6761\u6570\u3002\u7559\u7A7A\u6216\u70B9\u300C\u5173\u95ED\u300D\u53EA\u662F\u4E0D\u518D\u7ED9\u88F8 /grant \u5957\u9ED8\u8BA4\u989D\u5EA6\uFF0C\u4E0D\u4F1A\u6E05\u6389\u5DF2\u6709\u7684\u989D\u5EA6\u8BA1\u6570\uFF0C\u4E5F\u4E0D\u5F71\u54CD\u663E\u5F0F /grant @x N\u2014\u2014\u5B83\u4EEC\u7167\u5E38\u7EE7\u7EED enforce\u3002\u989D\u5EA6\u7528\u5C3D\u4F1A\u81EA\u52A8\u64A4\u9500\u8BE5\u4EBA\u6388\u6743\u3002","botDefaults.quotaSave":"\u4FDD\u5B58\u989D\u5EA6","botDefaults.quotaOff":"\u5173\u95ED","botDefaults.quotaInvalid":"\u989D\u5EA6\u5FC5\u987B\u662F\u6B63\u6574\u6570","botDefaults.quotaStateOff":"\u5F53\u524D\uFF1A\u672A\u914D\u7F6E\u9ED8\u8BA4\u989D\u5EA6","botDefaults.quotaStateOn":"\u5F53\u524D\uFF1A\u6BCF\u4EBA {count} \u6761","nav.roles":"\u89D2\u8272\u7BA1\u7406","roles.title":"\u89D2\u8272\u7BA1\u7406","roles.subtitle":"\u4E3A\u6BCF\u4E2A\u7FA4\u7EC4\u7684\u6BCF\u4E2A Bot \u5355\u72EC\u8BBE\u7F6E\u89D2\u8272\u63D0\u793A\u8BCD\uFF0CBot \u5728\u8BE5\u7FA4\u4E2D\u4F1A\u4EE5\u6B64\u89D2\u8272\u884C\u4E8B\u3002","roles.search":"\u641C\u7D22\u7FA4\u540D/Bot/ID","roles.refresh":"\u5237\u65B0","roles.selectHint":"\u2190 \u5C55\u5F00\u7FA4\u7EC4\uFF0C\u9009\u62E9\u4E00\u4E2A Bot \u6765\u7F16\u8F91\u89D2\u8272","roles.editorPlaceholder":`\u8F93\u5165\u89D2\u8272\u63CF\u8FF0\uFF0C\u4F8B\u5982\uFF1A
|
|
1
|
+
"use strict";(()=>{var Pt=class{sessions=new Map;schedules=new Map;online=!0;listeners=new Set;upsertSessions(n){for(let o of n)this.sessions.set(o.sessionId,o);this.emit()}upsertSchedules(n){for(let o of n)this.schedules.set(o.id,o);this.emit()}applySse(n,o){if(n==="session.spawned")this.sessions.set(o.session.sessionId,o.session);else if(n==="session.update"){let s=this.sessions.get(o.sessionId);s&&this.sessions.set(o.sessionId,{...s,...o.patch})}else if(n==="session.exited"){let s=this.sessions.get(o.sessionId);s&&this.sessions.set(o.sessionId,{...s,status:"closed"})}else if(n==="schedule.created")this.schedules.set(o.schedule.id,o.schedule);else if(n==="schedule.updated"){let s=this.schedules.get(o.id);s&&this.schedules.set(o.id,{...s,...o.patch})}else if(n==="schedule.deleted")this.schedules.delete(o.id);else return;this.emit()}setOnline(n){this.online!==n&&(this.online=n,this.emit())}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}},Q=new Pt;async function kn(){let[e,n]=await Promise.all([fetch("/api/sessions").then(a=>a.json()),fetch("/api/schedules").then(a=>a.json())]);Q.upsertSessions(e.sessions??[]),Q.upsertSchedules(n.schedules??[]);let o=new EventSource("/events"),s=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let a of s)o.addEventListener(a,i=>{try{let l=JSON.parse(i.data);Q.applySse(a,l.body??l)}catch{}});o.onerror=()=>Q.setOnline(!1),o.onopen=()=>Q.setOnline(!0)}var qt="botmux.dashboard.locale",Wo={"app.name":"botmux","app.subtitle":"\u98DE\u4E66 AI CLI \u63A7\u5236\u53F0","time.secondsAgo":"{value} \u79D2\u524D","time.minutesAgo":"{value} \u5206\u949F\u524D","time.hoursAgo":"{value} \u5C0F\u65F6\u524D","nav.overview":"\u603B\u89C8","nav.sessions":"\u4F1A\u8BDD","nav.groups":"\u7FA4\u7EC4","nav.schedules":"\u5B9A\u65F6","nav.settings":"\u8BBE\u7F6E","nav.botDefaults":"Bot \u914D\u7F6E","status.live":"\u5B9E\u65F6\u8FDE\u63A5","status.disconnected":"\u8FDE\u63A5\u65AD\u5F00","status.system":"\u7CFB\u7EDF","status.light":"\u6D45\u8272","status.dark":"\u6697\u9ED1","status.language":"\u8BED\u8A00","status.theme":"\u4E3B\u9898","theme.base":"\u57FA\u7840","theme.skins":"\u4E3B\u9898\u76AE\u80A4","skin.cyber":"2077","skin.genshin":"\u539F\u795E","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"\u851A\u84DD\u6863\u6848","skin.zzz":"\u7EDD\u533A\u96F6","skin.dragonball":"\u4E03\u9F99\u73E0","skin.ikun":"ikun","botOnboarding.add":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.title":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.intro":"\u9009\u62E9 CLI \u4E0E\u5DE5\u4F5C\u76EE\u5F55\uFF0C\u626B\u7801\u521B\u5EFA PersonalAgent \u5E94\u7528\u540E\u5199\u5165\u672C\u673A bots.json\uFF0C\u5E76\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u3002","botOnboarding.cliLabel":"CLI \u9002\u914D\u5668","botOnboarding.dirLabel":"\u5DE5\u4F5C\u76EE\u5F55","botOnboarding.dirPlaceholder":"\u9ED8\u8BA4 ~\uFF08\u5BB6\u76EE\u5F55\uFF09\uFF0C\u9700\u4E3A daemon \u4E3B\u673A\u4E0A\u5DF2\u5B58\u5728\u7684\u76EE\u5F55","botOnboarding.modelLabel":"\u6A21\u578B\uFF08\u53EF\u9009\uFF09","botOnboarding.modelPlaceholder":"\u7559\u7A7A\u4F7F\u7528\u8BE5 CLI \u7684\u9ED8\u8BA4\u6A21\u578B","botOnboarding.startScan":"\u5F00\u59CB\u626B\u7801","botOnboarding.cancel":"\u53D6\u6D88","botOnboarding.starting":"\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...","botOnboarding.waiting":"\u8BF7\u7528\u98DE\u4E66 App \u626B\u7801\u786E\u8BA4\u521B\u5EFA\u5E94\u7528\u3002","botOnboarding.verifying":"\u626B\u7801\u6210\u529F\uFF0C\u6B63\u5728\u6821\u9A8C\u51ED\u8BC1...","botOnboarding.configuringPermissions":"\u6B63\u5728\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u2026","botOnboarding.platformScanHint":"\u8BF7\u7528\u98DE\u4E66 App \u518D\u626B\u4E00\u6B21\u7801\u767B\u5F55\u5F00\u653E\u5E73\u53F0\uFF08\u7528\u4E8E\u81EA\u52A8\u5BFC\u5165\u6743\u9650\u3001\u914D\u7F6E\u56DE\u8C03\u3001\u63D0\u4EA4\u7248\u672C\uFF09\u3002","botOnboarding.platformQrAlt":"\u5F00\u653E\u5E73\u53F0\u767B\u5F55\u4E8C\u7EF4\u7801","botOnboarding.completed":"\u673A\u5668\u4EBA\u5DF2\u6DFB\u52A0\u3002","botOnboarding.permissionOk":"\u5DF2\u81EA\u52A8\u5BFC\u5165 {count} \u9879\u6743\u9650\u3002","botOnboarding.permissionSkipped":"\uFF08\u8DF3\u8FC7 {count} \u9879\u5F53\u524D\u79DF\u6237\u76EE\u5F55\u4E2D\u6CA1\u6709\u7684\u6743\u9650\uFF09","botOnboarding.permissionVersion":"\u5DF2\u63D0\u4EA4\u53D1\u5E03\u7248\u672C {version}\u3002","botOnboarding.permissionManual":"\u6743\u9650\u672A\u80FD\u81EA\u52A8\u914D\u7F6E\uFF0C\u8BF7\u624B\u52A8\u5B8C\u6210\u4EE5\u4E0B\u6B65\u9AA4\uFF1A","botOnboarding.metaDir":"\u76EE\u5F55","botOnboarding.failed":"\u6DFB\u52A0\u5931\u8D25","botOnboarding.openLink":"\u6253\u4E0D\u5F00\u626B\u7801\uFF1F\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00","botOnboarding.close":"\u5173\u95ED","botOnboarding.restartHint":"\u5DF2\u5199\u5165 bots.json\u3002\u6267\u884C pnpm daemon:restart \u540E\u65B0\u673A\u5668\u4EBA\u751F\u6548\u3002","botOnboarding.qrAlt":"\u98DE\u4E66\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA\u4E8C\u7EF4\u7801","overview.title":"\u5DE5\u4F5C\u53F0","overview.subtitle":"\u6570\u5B57\u5458\u5DE5\u5B9E\u65F6\u72B6\u6001 \xB7 \u540C\u6B65\u98DE\u4E66\u8BDD\u9898","overview.team":"AI \u56E2\u961F","overview.teamHint":"\u6BCF\u4F4D\u6570\u5B57\u5458\u5DE5\u7684\u5B9E\u65F6\u72B6\u6001","overview.attention":"\u9700\u8981\u4F60\u5904\u7406","overview.attentionHint":"\u5361\u4F4F\u7684\u4EFB\u52A1\uFF0C\u56DE\u4E2A\u8BDD\u5C31\u80FD\u7EE7\u7EED\u8DD1","overview.activeSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.activeSessionsHint":"\u6B63\u5728\u8FD0\u8F6C\u7684\u4F1A\u8BDD","overview.today":"\u6B64\u523B\u6982\u89C8","overview.todayHint":"\u6D3B\u8DC3\u4F1A\u8BDD\u5206\u5E03","overview.viewAll":"\u67E5\u770B\u5168\u90E8 \u2192","overview.botIdle":"\u5F85\u547D\u4E2D\uFF0C\u968F\u65F6\u53EF\u63A5\u65B0\u4EFB\u52A1","overview.botOffline":"\u79BB\u7EBF \u2014 daemon \u672A\u4E0A\u7EBF","overview.botBusy":"\u6267\u884C\u4E2D \xB7 {count} \u4F1A\u8BDD","overview.botNeedsYou":"\u7B49\u4F60\u56DE\u590D","overview.botReady":"\u5C31\u7EEA","overview.botOff":"\u79BB\u7EBF","overview.sessionsCount":"{count} \u4F1A\u8BDD","overview.lastActive":"{time}\u524D\u6D3B\u8DC3","overview.noAttention":"\u6CA1\u6709\u7B49\u4F60\u5904\u7406\u7684\u4E8B\u9879","strip.pending":"{count} \u4EF6\u5F85\u5904\u7406","strip.longest":"\u6700\u4E45\u5DF2\u7B49 {time} \u2014 {bot} {reason}","strip.handle":"\u7ACB\u5373\u5904\u7406","overview.openSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.workingSessions":"\u5DE5\u4F5C\u4E2D","overview.onlineBots":"\u5728\u7EBF Bot","overview.schedules":"\u5B9A\u65F6\u4EFB\u52A1","overview.groups":"\u7FA4\u804A\u8986\u76D6","overview.enabledSchedules":"\u5DF2\u542F\u7528","overview.total":"\u603B\u8BA1","overview.active":"\u6D3B\u8DC3","overview.daemonRegistry":"daemon \u6CE8\u518C\u8868","overview.chatMatrix":"\u7FA4\u804A\u77E9\u9635","overview.recentSessions":"\u6700\u8FD1\u4F1A\u8BDD","overview.nextSchedules":"\u5373\u5C06\u6267\u884C","overview.noSessions":"\u6682\u65E0\u4F1A\u8BDD\u3002","overview.noSchedules":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","sessions.title":"\u4F1A\u8BDD\u63A7\u5236","sessions.subtitle":"\u5B9A\u4F4D\u98DE\u4E66\u8BDD\u9898\u3001\u6253\u5F00 Web Terminal\u3001\u5173\u95ED\u6216\u6062\u590D CLI \u4F1A\u8BDD\u3002","sessions.search":"\u641C\u7D22\u5DE5\u4F5C\u76EE\u5F55 / \u6807\u9898 / ID","sessions.anyStatus":"\u5168\u90E8\u72B6\u6001","sessions.adoptAny":"adopt: \u5168\u90E8","sessions.adoptYes":"adopt: \u662F","sessions.adoptNo":"adopt: \u5426","sessions.activeOnly":"\u4EC5\u6D3B\u8DC3","sessions.closeSelected":"\u5173\u95ED\u9009\u4E2D","sessions.clearSelection":"\u53D6\u6D88\u9009\u62E9","sessions.selectedCount":"\u5DF2\u9009 {count} \u4E2A\u4F1A\u8BDD","sessions.bot":"bot","sessions.cli":"CLI","sessions.chat":"\u7FA4\u804A","sessions.openChat":"\u6253\u5F00\u7FA4\u804A","sessions.status":"\u72B6\u6001","sessions.titleCol":"\u6807\u9898","sessions.workingDir":"\u5DE5\u4F5C\u76EE\u5F55","sessions.created":"\u521B\u5EFA","sessions.last":"\u6700\u8FD1","sessions.adopt":"\u63A5\u5165","sessions.actions":"\u64CD\u4F5C","sessions.details":"\u8BE6\u60C5","sessions.copy":"\u590D\u5236","sessions.copied":"\u5DF2\u590D\u5236","sessions.locate":"\u5B9A\u4F4D\u8BDD\u9898","sessions.locating":"\u53D1\u9001\u4E2D...","sessions.cooldown":"\u51B7\u5374 {seconds}s","sessions.openTerminal":"\u7EC8\u7AEF","sessions.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.viewBoard":"\u72B6\u6001\u677F","sessions.viewTable":"\u8868\u683C","sessions.selectSession":"\u9009\u62E9\u4F1A\u8BDD","sessions.board.needsYou":"\u9700\u8981\u4F60","sessions.board.needsYouHint":"\u7B49\u5F85\u4ED3\u5E93\u3001TUI \u9009\u62E9\u6216\u989D\u5EA6\u5904\u7406","sessions.board.starting":"\u542F\u52A8\u4E2D","sessions.board.startingHint":"CLI \u6B63\u5728\u521B\u5EFA\u6216\u6062\u590D","sessions.board.working":"\u5E72\u6D3B\u4E2D","sessions.board.workingHint":"\u6B63\u5728\u8F93\u51FA\u3001\u5206\u6790\u6216\u6267\u884C\u5DE5\u5177","sessions.board.idle":"\u7A7A\u95F2","sessions.board.idleHint":"\u53EF\u7EE7\u7EED\u5BF9\u8BDD\u6216\u63A5\u65B0\u4EFB\u52A1","sessions.board.emptyColumn":"\u6682\u65E0\u4F1A\u8BDD","sessions.board.signalRepo":"\u5F85\u9009\u4ED3\u5E93","sessions.board.signalPrompt":"\u7B49\u5F85 TUI \u9009\u62E9","sessions.board.signalLimited":"\u989D\u5EA6\u53D7\u9650","sessions.board.signalAgent":"\u9700\u8981\u4EBA\u5DE5\u4ECB\u5165","sessions.board.waiting":"\u7B49\u5F85","sessions.board.dragHint":"\u62D6\u52A8\u5217\u5934\u8C03\u6574\u5217\u987A\u5E8F","sessions.board.moveLeft":"\u5DE6\u79FB\u6B64\u5217","sessions.board.moveRight":"\u53F3\u79FB\u6B64\u5217","groups.title":"\u7FA4\u7EC4\u4E0E Bot","groups.subtitle":"\u67E5\u770B chat x bot \u8986\u76D6\u77E9\u9635\uFF0C\u7BA1\u7406\u62C9\u7FA4\u3001oncall\u3001\u9000\u7FA4\u548C\u89E3\u6563\u3002","groups.search":"\u641C\u7D22\u7FA4\u540D / ID / owner","groups.missingOnly":"\u4EC5\u7F3A bot","groups.refresh":"\u5237\u65B0","groups.create":"\u65B0\u5EFA\u7FA4","groups.chat":"\u7FA4\u804A","groups.actions":"\u64CD\u4F5C","groups.addBots":"\u6DFB\u52A0 bot","groups.manage":"\u7BA1\u7406","groups.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u7FA4\u804A\u3002","groups.createTitle":"\u65B0\u5EFA\u7FA4\u804A","groups.createHelp":"\u9009\u62E9\u8981\u9080\u8BF7\u7684 bot\u3002dashboard \u4F1A\u81EA\u52A8\u9009\u62E9\u5728\u7EBF daemon \u4F5C\u4E3A\u521B\u5EFA\u8005\u3002","groups.name":"\u7FA4\u540D","groups.namePlaceholder":"\u4F8B\u5982 AI ChangeLog","groups.bindDir":"\u7ED1\u5B9A\u76EE\u5F55","groups.bindDirHelp":"\u65B0\u8BDD\u9898\u76F4\u63A5\u7528\u8BE5\u76EE\u5F55\u542F\u52A8 CLI\uFF0C\u8DF3\u8FC7 repo \u9009\u62E9\u3002","groups.botPicker":"Bot","groups.createSubmit":"\u521B\u5EFA","groups.cancel":"\u53D6\u6D88","groups.successTitle":"\u7FA4\u521B\u5EFA\u6210\u529F","groups.openGroup":"\u6253\u5F00\u65B0\u7FA4","groups.manageTitle":"\u7BA1\u7406 {name}","groups.owner":"\u7FA4\u4E3B","groups.oncall":"Oncall \u6A21\u5F0F","groups.oncallHelp":"\u5F00\u542F\u540E\uFF0C\u7FA4\u5185\u6210\u5458\u53EF @ \u673A\u5668\u4EBA\uFF1B\u65B0\u8BDD\u9898\u76F4\u63A5\u4F7F\u7528\u7ED1\u5B9A\u76EE\u5F55\u3002","groups.leaveTitle":"\u9009\u62E9\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.leaveSelected":"\u9009\u4E2D\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.disband":"\u89E3\u6563\u7FA4\u804A","groups.dangerHint":"\u89E3\u6563\u4EC5\u5F53\u5728\u7FA4\u673A\u5668\u4EBA\u662F\u7FA4\u4E3B\u65F6\u624D\u4F1A\u6210\u529F\uFF0C\u5426\u5219\u5EFA\u8BAE\u4F7F\u7528\u9000\u51FA\u7FA4\u804A\u3002","groups.save":"\u4FDD\u5B58","groups.needWorkingDir":"\u8BF7\u586B\u5DE5\u4F5C\u76EE\u5F55","groups.noBotsOnline":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u8BF7\u5148\u91CD\u542F daemon\u3002","schedules.title":"\u5B9A\u65F6\u4EFB\u52A1","schedules.subtitle":"\u8DE8 daemon \u67E5\u770B\u3001\u6682\u505C\u3001\u6062\u590D\u548C\u7ACB\u5373\u89E6\u53D1\u5B9A\u65F6\u4EFB\u52A1\u3002","schedules.search":"\u641C\u7D22\u540D\u79F0 / prompt / \u5DE5\u4F5C\u76EE\u5F55","schedules.anyKind":"\u5168\u90E8\u7C7B\u578B","schedules.enabledOnly":"\u4EC5\u542F\u7528","schedules.name":"\u540D\u79F0","schedules.bot":"bot","schedules.schedule":"\u89C4\u5219","schedules.next":"\u4E0B\u6B21","schedules.last":"\u4E0A\u6B21","schedules.repeat":"\u91CD\u590D","schedules.enabled":"\u542F\u7528","schedules.actions":"\u64CD\u4F5C","schedules.runNow":"\u7ACB\u5373\u8FD0\u884C","schedules.pause":"\u6682\u505C","schedules.resume":"\u6062\u590D","schedules.empty":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","settings.title":"\u5168\u5C40\u8BBE\u7F6E","settings.subtitle":"\u7BA1\u7406\u672C\u673A botmux dashboard \u4E0E\u6240\u6709 bot \u5171\u4EAB\u7684\u5168\u5C40\u884C\u4E3A\u3002","settings.loading":"\u6B63\u5728\u52A0\u8F7D\u8BBE\u7F6E\u2026","settings.loadFailed":"\u8BBE\u7F6E\u52A0\u8F7D\u5931\u8D25","settings.readOnlyVisitor":"\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u4FEE\u6539\u8BBE\u7F6E\u9700\u8981\u6388\u6743\u94FE\u63A5\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09","settings.sectionAccess":"\u8BBF\u95EE\u6743\u9650","settings.publicReadOnly":"\u5141\u8BB8\u65E0 token \u53EA\u8BFB\u8BBF\u95EE dashboard","settings.publicReadOnlyHelp":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 token \u7684\u8BBF\u95EE\u8005\u53EF\u4EE5\u67E5\u770B dashboard\u3001\u4F1A\u8BDD\u3001\u5B9A\u65F6\u4EFB\u52A1\u548C SSE\uFF1B\u5173\u95ED\u3001\u6682\u505C\u3001\u5BA1\u6279\u7B49\u5199\u64CD\u4F5C\u4ECD\u5FC5\u987B\u901A\u8FC7 token \u9274\u6743\u3002\u654F\u611F\u7EC8\u7AEF\u539F\u59CB\u65E5\u5FD7\u59CB\u7EC8\u9700\u8981 token\u3002","settings.sectionCards":"\u98DE\u4E66\u5361\u7247","settings.openTerminalInFeishu":"\u6D41\u5F0F\u5361\u7247\u7EC8\u7AEF\u6309\u94AE\u5728\u98DE\u4E66\u4FA7\u680F\u6253\u5F00","settings.openTerminalInFeishuHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF1A\u7EC8\u7AEF\u6309\u94AE\u76F4\u63A5\u6253\u5F00 Web Terminal URL\u3002\u5F00\u542F\u540E\u4F7F\u7528\u98DE\u4E66 web_url/open \u5305\u88C5\uFF0C\u5728\u98DE\u4E66 PC \u4FA7\u680F\u91CC\u6253\u5F00\uFF1B\u5199\u6743\u9650\u4ECD\u7531\u7EC8\u7AEF token \u63A7\u5236\u3002","settings.saving":"\u4FDD\u5B58\u4E2D\u2026","settings.saved":"\u5DF2\u4FDD\u5B58","settings.saveFailed":"\u4FDD\u5B58\u5931\u8D25","settings.sectionMaintenance":"\u81EA\u52A8\u7EF4\u62A4","settings.autoUpdate":"\u81EA\u52A8\u66F4\u65B0","settings.autoUpdateHelp":"\u9ED8\u8BA4\u5173\u95ED\u3002\u5230\u70B9\u6267\u884C npm install -g botmux@latest \u5B89\u88C5\u6700\u65B0\u7248\u672C\uFF08\u53EA\u4E0B\u8F7D\u5B89\u88C5\u3001\u672C\u8EAB\u4E0D\u91CD\u542F\uFF09\u3002\u4EC5 npm \u5168\u5C40\u5B89\u88C5\u53EF\u7528\u3002","settings.autoRestart":"\u81EA\u52A8\u91CD\u542F","settings.autoRestartHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF0C\u9700\u5148\u5F00\u542F\u81EA\u52A8\u66F4\u65B0\u3002\u81EA\u52A8\u66F4\u65B0\u88C5\u5230\u65B0\u7248\u672C\u540E\uFF0C\u82E5\u6CA1\u6709\u8FDB\u884C\u4E2D\u7684\u4F1A\u8BDD\u5219\u81EA\u52A8\u91CD\u542F\u4EE5\u751F\u6548\uFF08\u649E\u4E0A\u5FD9\u788C\u4F1A\u8BDD\u5219\u8DF3\u5230\u6B21\u65E5\uFF09\u3002","settings.autoUpdateLocalDev":"\u5F53\u524D\u4E3A\u672C\u5730\u5F00\u53D1\u5B89\u88C5\uFF08\u4ECE\u6E90\u7801\u8FD0\u884C\uFF09\uFF0C\u81EA\u52A8\u66F4\u65B0\u4E0D\u53EF\u7528\u3002","settings.maintenanceTime":"\u65F6\u95F4","botDefaults.title":"\u6570\u5B57\u5458\u5DE5\u6863\u6848","botDefaults.subtitle":"\u6BCF\u4F4D\u5458\u5DE5\u7684\u9ED8\u8BA4\u884C\u4E3A\uFF1Aoncall\u3001\u4E3B\u52A8\u5F00\u5DE5\u3001\u4EBA\u8BBE\u89D2\u8272\u3001\u5361\u7247\u4E0E\u6388\u6743\u3002","botDefaults.metaOnline":"\u5728\u7EBF \xB7 daemon \u6B63\u5E38","botDefaults.search":"\u641C\u7D22 bot \u540D / app id","botDefaults.refresh":"\u5237\u65B0","botDefaults.sectionOncall":"\u65B0\u7FA4 Oncall","botDefaults.sectionBrand":"\u5361\u7247\u7B7E\u540D","botDefaults.warning":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 oncall binding \u7684\u7FA4\u4F1A\u5728\u4E0B\u6B21\u5F00\u65B0\u8BDD\u9898\u65F6\u81EA\u52A8\u7ED1\u5B9A\u5230\u8BE5\u76EE\u5F55\uFF1B\u624B\u52A8\u7ED1\u5B9A\u6216\u624B\u52A8\u89E3\u7ED1\u8FC7\u7684\u7FA4\u4E0D\u4F1A\u88AB\u8986\u76D6\u3002","botDefaults.empty":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u5148 botmux restart \u8BA9 daemon \u4E0A\u7EBF\u3002","botDefaults.defaultOncall":"\u9ED8\u8BA4\u8FDB\u5165 oncall \u6A21\u5F0F","botDefaults.defaultOncallHelp":"\u6240\u6709\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8\u7ED1\u5B9A","botDefaults.workingDir":"\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55","botDefaults.lastEnabled":"\u4E0A\u6B21\u542F\u7528\u65F6\u95F4","botDefaults.autobound":"\u5DF2\u81EA\u52A8\u7ED1\u5B9A {count} \u4E2A\u7FA4","botDefaults.save":"\u4FDD\u5B58","botDefaults.required":"\u5F00\u542F\u65F6\u5FC5\u987B\u586B\u5DE5\u4F5C\u76EE\u5F55","botDefaults.brandLabel":"\u4E2A\u6027\u7B7E\u540D\uFF08\u5361\u7247\u9875\u811A\uFF09","botDefaults.brandLabelHelp":"\u8BE5 bot \u53D1\u51FA\u7684\u5361\u7247\u9875\u811A\u7B7E\u540D\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u4E0D\u663E\u793A\uFF1B\u586B\u5199\uFF1D\u81EA\u5B9A\u4E49\uFF08\u652F\u6301 markdown\uFF0C\u5982 [Acme](https://\u2026)\uFF09\uFF1B\u6062\u590D\u9ED8\u8BA4\uFF1D\u663E\u793A botmux\u3002","botDefaults.brandLabelPlaceholder":"\u9ED8\u8BA4\uFF1Abotmux\uFF08\u7559\u7A7A\u5219\u4E0D\u663E\u793A\uFF09","botDefaults.sectionSandbox":"\u6587\u4EF6\u6C99\u76D2\uFF08oncall\uFF09","botDefaults.sandboxToggle":"\u5F00\u542F\u6587\u4EF6\u6C99\u76D2","botDefaults.sandboxHelp":"\u5F00\u542F\u540E\uFF0C\u8BE5 bot \u7684\u6BCF\u4E2A\u4F1A\u8BDD\u90FD\u8DD1\u5728\u6309\u4F1A\u8BDD\u9694\u79BB\u7684\u6C99\u76D2\u91CC\uFF1A\u53EA\u770B\u5F97\u5230\u4E00\u4EFD\u9879\u76EE\u526F\u672C\uFF0C\u78B0\u4E0D\u5230\u4F60\u78C1\u76D8\u4E0A\u7684\u771F\u5B9E\u6587\u4EF6\u3001\u5BC6\u94A5\u3001\u522B\u7684\u4F1A\u8BDD\u6570\u636E\u3002\u9002\u5408\u628A\u673A\u5668\u4EBA\u5206\u4EAB\u7ED9\u534A\u53D7\u4FE1\u4EFB\u7684\u4EBA\uFF08oncall\uFF09\u3002\u4EC5 Linux \u751F\u6548\uFF0C\u4E0B\u4E2A\u65B0\u4F1A\u8BDD\u8D77\u6548\u3002","botDefaults.sandboxSaved":"\u5DF2\u4FDD\u5B58\uFF08\u4E0B\u4E2A\u65B0\u4F1A\u8BDD\u751F\u6548\uFF09","botDefaults.brandSave":"\u4FDD\u5B58\u7B7E\u540D","botDefaults.brandReset":"\u6062\u590D\u9ED8\u8BA4","botDefaults.brandStateDefault":"\u5F53\u524D\uFF1A\u9ED8\u8BA4 botmux","botDefaults.brandStateOff":"\u5F53\u524D\uFF1A\u5DF2\u5173\u95ED","botDefaults.brandStateCustom":"\u5F53\u524D\uFF1A\u81EA\u5B9A\u4E49","botDefaults.sectionCard":"\u5361\u7247\u884C\u4E3A","botDefaults.disableStreaming":"\u5173\u95ED\u98DE\u4E66\u6D41\u5F0F\u5361\u7247","botDefaults.disableStreamingHelp":"\u4E0D\u518D\u53D1\u5B9E\u65F6\u5237\u65B0\u7684\u4F1A\u8BDD\u72B6\u6001\u5361\uFF08\u542B\u300C\u6253\u5F00\u7EC8\u7AEF\u300D\u5165\u53E3\uFF09\uFF1B\u4EFB\u52A1\u6700\u7EC8\u7ED3\u679C\u4ECD\u901A\u8FC7\u6D88\u606F\u9001\u8FBE\u3002\u9002\u5408\u5ACC\u6D41\u5F0F\u5361\u7247\u70E6\u7684\u573A\u666F\u3002","botDefaults.writableLink":"\u5361\u7247\u4E0A\u76F4\u63A5\u7ED9\u53EF\u64CD\u4F5C\uFF08\u53EF\u5199\uFF09\u7EC8\u7AEF\u94FE\u63A5","botDefaults.writableLinkHelp":"\u26A0\uFE0F \u5728\u6D41\u5F0F\u5361\u7247\u6B63\u6587\u76F4\u63A5\u8D34\u51FA\u53EF\u5199\u7EC8\u7AEF\u94FE\u63A5\uFF0C\u7FA4\u5185\u4EFB\u4F55\u4EBA\u90FD\u80FD\u70B9\u5F00\u5E76\u64CD\u63A7\u7EC8\u7AEF\u3002\u4E0D\u52FE\uFF1D\u4FDD\u6301\u73B0\u72B6\uFF08\u8D70\u300C\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u300D\u6309\u94AE\u79C1\u804A\u53D1\u7ED9\u70B9\u51FB\u8005\uFF09\u3002","botDefaults.writableLinkMoot":"\u5DF2\u5173\u95ED\u6D41\u5F0F\u5361\u7247","botDefaults.privateCard":"/card \u53D1\u79C1\u5BC6\u5361\u7247\uFF08\u4EC5\u6388\u6743\u4EBA\u53EF\u89C1\uFF09","botDefaults.privateCardHelp":"\u5F00\u542F\u540E /card \u6539\u7528\u300C\u4EC5\u7279\u5B9A\u4EBA\u53EF\u89C1\u300D\u7684\u4E34\u65F6\u5361\u7247\uFF1A\u53EA\u53D1\u7ED9 owner\uFF08allowedUsers\uFF09\uFF0C/grant \u6388\u6743\u5BF9\u8BDD\u7684\u4EBA\u548C\u7FA4\u91CC\u5176\u4ED6\u4EBA\u90FD\u770B\u4E0D\u5230\u3002\u4EE3\u4EF7\uFF1A\u662F\u9759\u6001\u5FEB\u7167\u3001\u4E0D\u4F1A\u5B9E\u65F6\u5237\u65B0\uFF1B\u4E14\u4EC5\u666E\u901A\u7FA4\u53EF\u7528\uFF08\u8BDD\u9898\u7FA4 / \u5355\u804A\u4F1A\u5931\u8D25\uFF0C\u4E0D\u964D\u7EA7\uFF09\u3002\u53EA\u5F71\u54CD /card \u547D\u4EE4\uFF0C\u81EA\u52A8\u6D41\u5F0F\u5361\u4E0D\u53D8\u3002","botDefaults.cardPrefSaved":"\u5DF2\u4FDD\u5B58","botDefaults.sectionRole":"\u9ED8\u8BA4\u89D2\u8272","botDefaults.roleHelp":"\u8BE5 bot \u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF08\u8DE8\u7FA4\u751F\u6548\uFF09\uFF0C\u4F1A\u6CE8\u5165\u5230\u8BE5 bot \u5728\u5404\u7FA4\u7684\u4F1A\u8BDD\u91CC\uFF1B\u5355\u4E2A\u7FA4\u53EF\u5728\u300C\u89D2\u8272\u300D\u9875\u5355\u72EC\u8986\u76D6\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u5220\u9664\u3002","botDefaults.rolePlaceholder":"\u4F8B\u5982\uFF1A\u4F60\u662F\u540E\u7AEF\u6392\u969C\u52A9\u624B\uFF0C\u56DE\u7B54\u7B80\u6D01\u3001\u4F18\u5148\u7ED9\u53EF\u6267\u884C\u547D\u4EE4\u2026","botDefaults.roleSave":"\u4FDD\u5B58\u89D2\u8272","botDefaults.roleDelete":"\u5220\u9664","botDefaults.roleSaved":"\u5DF2\u4FDD\u5B58","botDefaults.roleDeleted":"\u5DF2\u5220\u9664","botDefaults.roleLoadErr":"\u89D2\u8272\u52A0\u8F7D\u5931\u8D25","botDefaults.sectionAutoStart":"\u4E3B\u52A8\u5F00\u5DE5","botDefaults.autoStartJoin":"\u88AB\u62C9\u8FDB\u65B0\u7FA4\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartJoinHelp":"\u5F00\u542F\u540E\uFF0C\u673A\u5668\u4EBA\u4E00\u88AB\u62C9\u8FDB\u65B0\u7FA4\uFF08\u7FA4\u91CC\u6709\u6388\u6743\u7528\u6237 allowedUsers \u65F6\uFF09\u5C31\u81EA\u52A8\u5F00\u4E00\u4E2A\u4F1A\u8BDD\u5F00\u59CB\u5DE5\u4F5C\uFF0C\u65E0\u9700 @\u3002\u5728\u673A\u5668\u4EBA\u7684\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55\u542F\u52A8\uFF1B\u672A\u914D\u7F6E\u9ED8\u8BA4\u76EE\u5F55\u65F6\u5148\u5F39\u4ED3\u5E93\u9009\u62E9\u5361\u8BA9\u4F60\u9009\u3002\u524D\u63D0\uFF1A\u9700\u5728\u98DE\u4E66\u5F00\u653E\u5E73\u53F0\u4E3A\u672C\u5E94\u7528\u8BA2\u9605\u300C\u673A\u5668\u4EBA\u8FDB\u7FA4\u300D\u4E8B\u4EF6 im.chat.member.bot.added_v1\uFF0C\u5E76\u5F00\u901A\u7FA4\u6210\u5458\u8BFB\u53D6\u6743\u9650\u3002","botDefaults.autoStartJoinPrompt":"\u5165\u7FA4\u9996\u8F6E prompt\uFF08\u53EF\u9009\uFF09","botDefaults.autoStartJoinPromptPlaceholder":"\u586B\u4E86\uFF1D\u4F5C\u4E3A\u5165\u7FA4\u540E\u7684\u7B2C\u4E00\u6761\u4EFB\u52A1\uFF1B\u7559\u7A7A\uFF1D\u673A\u5668\u4EBA\u81EA\u5DF1\u770B\u7FA4\u91CC\u4FE1\u606F\u51B3\u5B9A\u505A\u4EC0\u4E48","botDefaults.autoStartJoinPromptSave":"\u4FDD\u5B58 prompt","botDefaults.autoStartTopic":"\u8BDD\u9898\u7FA4\u65B0\u8BDD\u9898\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartTopicHelp":"\u5F00\u542F\u540E\uFF0C\u5728\u8BDD\u9898\u7FA4\u91CC\u6BCF\u5F53\u6709\u4EBA\u65B0\u5F00\u4E00\u4E2A\u8BDD\u9898\uFF0C\u673A\u5668\u4EBA\u5C31\u4F1A\u81EA\u52A8\u63A5\u5165\u8BE5\u8BDD\u9898\u3001\u628A\u9996\u6761\u6D88\u606F\u5F53\u4F5C\u4EFB\u52A1\u5F00\u59CB\u5904\u7406\uFF0C\u65E0\u9700 @\u3002\u4EC5\u5BF9\u8BDD\u9898\u7FA4\u751F\u6548\uFF0C\u666E\u901A\u7FA4\u4E0D\u53D7\u5F71\u54CD\u3002","botDefaults.sectionSessionMode":"\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.p2pMode":"\u79C1\u804A\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.p2pThread":"thread\uFF08\u6BCF\u6761 DM \u72EC\u7ACB\u4F1A\u8BDD\uFF09","botDefaults.p2pChat":"chat\uFF08\u6241\u5E73\u8FDE\u7EED\u5355\u804A\u4F1A\u8BDD\uFF09","botDefaults.p2pHelp":"\u79C1\u804A\uFF081:1 DM\uFF09\u7684\u4F1A\u8BDD\u65B9\u5F0F\uFF1Athread = \u6BCF\u6761\u9876\u5C42\u6D88\u606F\u5404\u81EA\u8D77\u72EC\u7ACB\u4F1A\u8BDD\uFF08\u907F\u514D\u628A\u5BF9\u8BDD\u5806\u8FDB\u540C\u4E00\u4E2A CLI \u8FDB\u7A0B\uFF09\uFF1Bchat = \u6574\u6BB5 DM \u5171\u7528\u4E00\u4E2A\u8FDE\u7EED\u4F1A\u8BDD\u3001\u5171\u4EAB\u4E0A\u4E0B\u6587\uFF08\u7C7B Hermes\uFF09\u3002\u6539\u540E\u7ACB\u5373\u751F\u6548\u3002","botDefaults.regularGroupMode":"\u666E\u901A\u7FA4\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.regularGroupModeChat":"chat\uFF08\u6241\u5E73\u8FDE\u7EED\u5355\u804A\u4F1A\u8BDD\uFF0C\u9ED8\u8BA4\uFF09","botDefaults.regularGroupModeNewTopic":"new-topic\uFF08\u6BCF\u6761\u9876\u5C42 @ \u5404\u5F00\u72EC\u7ACB\u8BDD\u9898\u4E0E\u4F1A\u8BDD\uFF09","botDefaults.regularGroupModeShared":"shared\uFF08\u8BDD\u9898\u6A21\u5F0F\u4F46\u590D\u7528\u540C\u4E00\u4E2A session\uFF09","botDefaults.regularGroupModeHelp":"\u666E\u901A\u7FA4\uFF08\u975E\u8BDD\u9898\u7FA4\uFF09\u91CC @ \u8BE5 bot \u7684\u65B0\u9876\u5C42\u6D88\u606F\u600E\u4E48\u5F00\u4F1A\u8BDD\uFF1Achat = \u6574\u7FA4\u5171\u7528\u4E00\u4E2A\u8FDE\u7EED\u4F1A\u8BDD\uFF08\u9ED8\u8BA4\uFF09\uFF1Bnew-topic = \u6BCF\u6761\u9876\u5C42 @ \u5728\u539F\u6D88\u606F\u4E0B\u5F00\u72EC\u7ACB\u8BDD\u9898\u3001\u5404\u81EA\u72EC\u7ACB\u4F1A\u8BDD\uFF1Bshared = \u8BDD\u9898\u6A21\u5F0F\u4F46\u590D\u7528\u540C\u4E00\u4E2A session\uFF08\u56DE\u590D\u843D\u5728\u8BDD\u9898\u91CC\u3001\u4F46\u5171\u7528\u672C\u7FA4\u4F1A\u8BDD\u4E0E\u4E0A\u4E0B\u6587\uFF09\u3002\u8FD9\u662F per-bot \u9ED8\u8BA4\uFF0C\u5177\u4F53\u67D0\u4E2A\u7FA4\u53EF\u7528 /reply-mode \u5355\u72EC\u8986\u76D6\u3002\u6539\u540E\u7ACB\u5373\u751F\u6548\u3002","botDefaults.mentionMode":"\u7FA4\u804A @ \u7B56\u7565","botDefaults.mentionModeAlways":"\u90FD\u9700\u8981 @\uFF08\u9ED8\u8BA4\uFF09","botDefaults.mentionModeTopic":"\u4EC5\u8BDD\u9898\u5185\u4E0D\u9700\u8981 @","botDefaults.mentionModeNever":"\u6240\u6709\u6D88\u606F\u90FD\u4E0D\u9700\u8981 @","botDefaults.mentionModeHelp":"\u8BE5 bot \u5168\u5C40\u751F\u6548\uFF0C\u51B3\u5B9A\u7FA4\u91CC\u8981\u4E0D\u8981 @ \u624D\u56DE\uFF1A\u300C\u90FD\u9700\u8981 @\u300D= \u4EFB\u4F55\u6D88\u606F\u90FD\u5F97 @\uFF08\u9ED8\u8BA4\uFF0C\u6700\u5B89\u5168\uFF1B\u591A\u4EBA\u7FA4\u91CC\u8BDD\u9898\u5185\u4E5F\u8981 @\uFF09\uFF1B\u300C\u4EC5\u8BDD\u9898\u5185\u4E0D\u9700\u8981 @\u300D= \u8D77\u65B0\u5BF9\u8BDD / \u9876\u5C42\u4ECD\u8981 @\uFF0C\u4F46\u5728\u8BE5 bot \u5DF2\u5F00\u7684\u4EFB\u4F55\u8BDD\u9898\u91CC\uFF08new-topic / shared / \u8BDD\u9898\u7FA4\uFF09\u540E\u7EED\u6D88\u606F\u514D @ \u7EED\u804A\uFF1B\u300C\u6240\u6709\u6D88\u606F\u90FD\u4E0D\u9700\u8981 @\u300D= \u8BE5 bot \u6709\u5BF9\u8BDD\u6743\u9650\u7684\u7FA4\u91CC\u975E @ \u6D88\u606F\u4E5F\u56DE\uFF08\u542B\u5168\u65B0\u6D88\u606F\u51B7\u542F\u52A8\uFF0C\u4EC5\u9002\u5408\u4E13\u7528 / \u503C\u73ED\u5C0F\u7FA4\uFF0C\u591A\u4EBA\u7FA4\u91CC\u4F1A\u89C1\u6D88\u606F\u5C31\u56DE\uFF09\u3002\u6CE8\uFF1A\u7FA4\u91CC\u53EA\u6709\u4F60\u548C\u8BE5 bot\uFF081 \u5BF9 1\uFF09\u65F6\u4E00\u76F4\u514D @\uFF0C\u4E0E\u672C\u8BBE\u7F6E\u65E0\u5173\u3002","botDefaults.sectionGrant":"\u6388\u6743\u4E0E\u989D\u5EA6","botDefaults.restrictGrant":"\u9650\u5236\u88AB\u6388\u6743\u4EBA\u53EA\u80FD\u7EAF\u5BF9\u8BDD","botDefaults.restrictGrantHelp":"\u5F00\u542F\u540E\uFF0C\u88AB /grant \u6388\u6743\u7684\u4EBA\uFF08owner \u81EA\u5DF1\u4E0D\u53D7\u9650\uFF09\u53EA\u80FD\u53D1\u666E\u901A\u5BF9\u8BDD\uFF0C\u6240\u6709 slash \u547D\u4EE4\u4E00\u5F8B\u62E6\u622A\uFF1Abotmux \u81EA\u5E26\u547D\u4EE4\u3001\u900F\u4F20\u547D\u4EE4\u3001/workflow\u3001/introduce\u3001/t \u4EE5\u53CA CLI \u539F\u751F\u547D\u4EE4\uFF08/help \u7B49\uFF09\u3002\u5F62\u5982 /path/to/file \u7684\u5185\u5BB9\u4E0D\u4F1A\u88AB\u8BEF\u5224\u3002","botDefaults.quotaDefault":"\u9ED8\u8BA4\u6D88\u606F\u989D\u5EA6","botDefaults.quotaPlaceholder":"\u7559\u7A7A\uFF1D\u4E0D\u914D\u7F6E\u9ED8\u8BA4\u989D\u5EA6","botDefaults.quotaHelp":"\u4E0D\u5E26\u6570\u5B57\u7684 /grant @x \u9ED8\u8BA4\u7ED9\u7684\u6D88\u606F\u6761\u6570\u3002\u7559\u7A7A\u6216\u70B9\u300C\u5173\u95ED\u300D\u53EA\u662F\u4E0D\u518D\u7ED9\u88F8 /grant \u5957\u9ED8\u8BA4\u989D\u5EA6\uFF0C\u4E0D\u4F1A\u6E05\u6389\u5DF2\u6709\u7684\u989D\u5EA6\u8BA1\u6570\uFF0C\u4E5F\u4E0D\u5F71\u54CD\u663E\u5F0F /grant @x N\u2014\u2014\u5B83\u4EEC\u7167\u5E38\u7EE7\u7EED enforce\u3002\u989D\u5EA6\u7528\u5C3D\u4F1A\u81EA\u52A8\u64A4\u9500\u8BE5\u4EBA\u6388\u6743\u3002","botDefaults.quotaSave":"\u4FDD\u5B58\u989D\u5EA6","botDefaults.quotaOff":"\u5173\u95ED","botDefaults.quotaInvalid":"\u989D\u5EA6\u5FC5\u987B\u662F\u6B63\u6574\u6570","botDefaults.quotaStateOff":"\u5F53\u524D\uFF1A\u672A\u914D\u7F6E\u9ED8\u8BA4\u989D\u5EA6","botDefaults.quotaStateOn":"\u5F53\u524D\uFF1A\u6BCF\u4EBA {count} \u6761","nav.roles":"\u89D2\u8272\u7BA1\u7406","roles.title":"\u89D2\u8272\u7BA1\u7406","roles.subtitle":"\u4E3A\u6BCF\u4E2A\u7FA4\u7EC4\u7684\u6BCF\u4E2A Bot \u5355\u72EC\u8BBE\u7F6E\u89D2\u8272\u63D0\u793A\u8BCD\uFF0CBot \u5728\u8BE5\u7FA4\u4E2D\u4F1A\u4EE5\u6B64\u89D2\u8272\u884C\u4E8B\u3002","roles.search":"\u641C\u7D22\u7FA4\u540D/Bot/ID","roles.refresh":"\u5237\u65B0","roles.selectHint":"\u2190 \u5C55\u5F00\u7FA4\u7EC4\uFF0C\u9009\u62E9\u4E00\u4E2A Bot \u6765\u7F16\u8F91\u89D2\u8272","roles.editorPlaceholder":`\u8F93\u5165\u89D2\u8272\u63CF\u8FF0\uFF0C\u4F8B\u5982\uFF1A
|
|
2
2
|
\u4F60\u662F\u672C\u7FA4\u7684\u6280\u672F\u987E\u95EE\uFF0C\u8D1F\u8D23\u56DE\u7B54\u6240\u6709\u6280\u672F\u95EE\u9898...`,"roles.configured":"\u5DF2\u914D\u7F6E","roles.unconfigured":"\u672A\u914D\u7F6E","roles.noChats":"\u6682\u65E0\u7FA4\u7EC4","roles.preview":"\u9884\u89C8","roles.previewEmpty":"\uFF08\u7A7A\u5185\u5BB9\uFF09","roles.saved":"\u5DF2\u4FDD\u5B58","roles.delete":"\u5220\u9664","roles.save":"\u4FDD\u5B58","roles.confirmDelete":"\u786E\u8BA4\u5220\u9664\u8BE5 Bot \u5728\u6B64\u7FA4\u7684\u89D2\u8272\u914D\u7F6E\uFF1F","roles.botsWithRoles":"\u4E2A Bot \u5DF2\u914D\u7F6E\u89D2\u8272","roles.emptyError":"\u89D2\u8272\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u8BF7\u5148\u8F93\u5165\u5185\u5BB9","roles.saveFailed":"\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5","common.none":"\u65E0","common.unknown":"\u672A\u77E5","common.now":"\u521A\u521A","common.never":"\u4ECE\u672A","common.all":"\u5168\u90E8","nav.workflows":"\u5DE5\u4F5C\u6D41(beta)","nav.workflowCatalog":"\u76EE\u5F55","workflow.subnav.runs":"\u8FD0\u884C","workflow.subnav.catalog":"\u76EE\u5F55","workflow.searchPlaceholder":"\u641C\u7D22 runId / workflowId / chatId","workflow.filter.nonTerminal":"\u975E\u7EC8\u6001","workflow.filter.all":"\u5168\u90E8","workflow.status.pending":"\u5F85\u5F00\u59CB","workflow.status.running":"\u8FD0\u884C\u4E2D","workflow.status.waiting":"\u7B49\u5F85\u4E2D","workflow.status.effectAttempting":"\u526F\u4F5C\u7528\u4E2D","workflow.status.timedOut":"\u5DF2\u8D85\u65F6","workflow.status.succeeded":"\u6210\u529F","workflow.status.failed":"\u5931\u8D25","workflow.status.cancelled":"\u5DF2\u53D6\u6D88","workflow.table.run":"\u8FD0\u884C","workflow.table.workflow":"\u5DE5\u4F5C\u6D41","workflow.table.status":"\u72B6\u6001","workflow.table.lastSeq":"\u6700\u540E\u5E8F\u53F7","workflow.table.dangling":"\u60AC\u6302 dEf/dAct/dWait","workflow.table.updated":"\u66F4\u65B0\u65F6\u95F4","workflow.table.chatApp":"\u7FA4\u804A / \u5E94\u7528","workflow.list.failedLoad":"\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","workflow.list.noRuns":"\u6CA1\u6709\u5339\u914D\u7684\u8FD0\u884C\u3002","workflow.list.noFilterMatch":"\u6CA1\u6709\u7B26\u5408\u7B5B\u9009\u6761\u4EF6\u7684\u8FD0\u884C\u3002","workflow.list.loaded":"{count} \u4E2A\u8FD0\u884C \xB7 \u5237\u65B0\u4E8E {time}","workflow.list.error":"\u9519\u8BEF\uFF1A{error}","workflow.detail.back":"\u8FD4\u56DE","workflow.detail.loading":"\u52A0\u8F7D\u4E2D...","workflow.detail.loadFailed":"\u52A0\u8F7D\u5931\u8D25","workflow.detail.cancel":"\u53D6\u6D88","workflow.detail.cliCancelOnly":"\u4EC5 CLI \u53EF\u53D6\u6D88","workflow.detail.cancelTitle":"\u53D6\u6D88\u8FD9\u4E2A\u5DE5\u4F5C\u6D41\u8FD0\u884C","workflow.detail.cliCancelTitle":"\u65E0\u6CD5\u5728\u9875\u9762\u53D6\u6D88\uFF1A\u8BF7\u4F7F\u7528 botmux workflow cancel {runId}","workflow.detail.nodes":"\u8282\u70B9 / Activity","workflow.detail.parallel":"\u5E76\u53D1\u6267\u884C","workflow.detail.parallelMeta":"{count} \u6B21\u5C1D\u8BD5 \xB7 \u6700\u9AD8\u5E76\u53D1 {max} \xB7 \u8FD0\u884C\u4E2D {running}","workflow.detail.noParallelData":"\u8FD8\u6CA1\u6709 attempt \u65F6\u95F4\u6570\u636E\u3002","workflow.detail.parallelNow":"\u73B0\u5728","workflow.detail.node":"\u8282\u70B9","workflow.detail.nodeStatus":"\u8282\u70B9\u72B6\u6001","workflow.detail.activity":"Activity","workflow.detail.activityStatus":"Activity \u72B6\u6001","workflow.detail.attempts":"\u5C1D\u8BD5\u6B21\u6570","workflow.detail.current":"\u5F53\u524D\u5C1D\u8BD5","workflow.detail.detail":"\u8BE6\u60C5","workflow.detail.nodeIO":"\u8282\u70B9\u8F93\u5165\u8F93\u51FA","workflow.detail.timeline":"\u65F6\u95F4\u7EBF","workflow.detail.loadOlder":"\u52A0\u8F7D\u66F4\u65E9\u4E8B\u4EF6","workflow.detail.seq":"\u5E8F\u53F7","workflow.detail.actor":"\u6267\u884C\u8005","workflow.detail.error":"\u9519\u8BEF","workflow.detail.event":"\u4E8B\u4EF6","workflow.detail.time":"\u65F6\u95F4","workflow.detail.refreshed":"\u5237\u65B0\u4E8E {time}","workflow.detail.unknownRun":"\u672A\u77E5\u8FD0\u884C","workflow.detail.snapshotHttp":"snapshot HTTP {status}","workflow.detail.eventsHttp":"events HTTP {status}","workflow.detail.cancelUnavailable":"\u65E0\u6CD5\u53D6\u6D88\uFF1A\u8BF7\u4F7F\u7528 botmux workflow cancel {runId}","workflow.detail.cancelConfirm":`\u786E\u8BA4\u53D6\u6D88\u5DE5\u4F5C\u6D41\u8FD0\u884C {runId}\uFF1F
|
|
3
3
|
|
|
4
4
|
{total} \u4E2A\u60AC\u6302\u9879\u4F1A\u7531 cancel recovery \u5904\u7406\u3002
|
|
5
5
|
effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"workflow.detail.writeAccessCancel":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u70B9\u51FB\u53D6\u6D88\u3002","workflow.detail.cancelHttp":"cancel HTTP {status}","workflow.detail.cancelPending":"\u53D6\u6D88\u5DF2\u63D0\u4EA4\uFF1B\u7B49\u5F85\u8FD0\u884C\u4E2D\u7684 activity \u6536\u655B","workflow.detail.writeAccessApproval":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u5BA1\u6279\u3002","workflow.detail.actionHttp":"{action} HTTP {status}","workflow.detail.approved":"\u5DF2\u901A\u8FC7","workflow.detail.rejected":"\u5DF2\u62D2\u7EDD","workflow.detail.alreadyTerminal":"\u8FD0\u884C\u5DF2\u7EC8\u6001\uFF1B\u672A\u5E94\u7528\u201C{label}\u201D\u3002","workflow.detail.workflowContinue":"{label}\uFF1B\u7B49\u5F85\u5DE5\u4F5C\u6D41\u7EE7\u7EED\u6267\u884C\u3002","workflow.detail.workflowRefreshing":"{label}\uFF1B\u6B63\u5728\u5237\u65B0\u5DE5\u4F5C\u6D41\u72B6\u6001\u3002","workflow.detail.eventsLoaded":"\u5DF2\u52A0\u8F7D {loaded}/{total} \u4E2A\u4E8B\u4EF6","workflow.detail.dangling":"\u60AC\u6302\u9879","workflow.detail.noDangling":"\u6CA1\u6709\u60AC\u6302\u5DE5\u4F5C\u3002","workflow.detail.none":"\u65E0","workflow.detail.noNodes":"\u8FD8\u6CA1\u6709\u8282\u70B9\u3002","workflow.detail.idle":"\u7A7A\u95F2","workflow.detail.noNodeIO":"\u8FD8\u6CA1\u6709\u8282\u70B9\u8F93\u5165\u8F93\u51FA\u3002","workflow.detail.notDispatched":"\u5C1A\u672A\u6D3E\u53D1","workflow.detail.noAttempt":"\u8FD8\u6CA1\u6709\u5C1D\u8BD5","workflow.detail.attempt":"\u5C1D\u8BD5","workflow.detail.authoredInput":"\u539F\u59CB\u8F93\u5165","workflow.detail.resolvedInput":"\u89E3\u6790\u540E\u8F93\u5165","workflow.detail.output":"\u8F93\u51FA","workflow.detail.executionLog":"\u6267\u884C\u65E5\u5FD7","workflow.detail.liveTerminal":"\u5B9E\u65F6\u7EC8\u7AEF","workflow.detail.terminalLive":"\u5728\u7EBF","workflow.detail.terminalClosedShort":"\u5DF2\u5173\u95ED","workflow.detail.terminalClosed":"\u7EC8\u7AEF\u5DF2\u5173\u95ED\u3002\u8BF7\u67E5\u770B\u4E0B\u65B9\u6267\u884C\u65E5\u5FD7\u83B7\u53D6\u6700\u7EC8\u8BB0\u5F55\u3002","workflow.detail.openTerminalNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u7EC8\u7AEF","workflow.detail.terminalReplay":"\u7EC8\u7AEF\u56DE\u653E","workflow.detail.openReplayNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u56DE\u653E","workflow.detail.downloadFullLog":"\u4E0B\u8F7D\u5B8C\u6574\u65E5\u5FD7","workflow.detail.terminalResume":"\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.openResumeNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.resumeSession":"\u7EE7\u7EED\u4F1A\u8BDD","workflow.detail.resumeStarting":"\u6B63\u5728\u542F\u52A8\u2026","workflow.detail.endResumeSession":"\u7ED3\u675F\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.resumeEnding":"\u7ED3\u675F\u4E2D\u2026","workflow.detail.resumeUnsupportedCli":"{cliId} CLI \u4E0D\u652F\u6301 resume","workflow.detail.resumeMissingCliSession":"\u7F3A\u5C11 cliSessionId\uFF0C\u65E0\u6CD5 resume","workflow.detail.resumeStartFailed":"\u542F\u52A8\u8C03\u8BD5\u4F1A\u8BDD\u5931\u8D25 (HTTP {status})","workflow.detail.resumeEndFailed":"\u7ED3\u675F\u8C03\u8BD5\u4F1A\u8BDD\u5931\u8D25 (HTTP {status})","workflow.detail.writeAccessResume":"\u9700\u8981\u5199\u5165\u6743\u9650\u624D\u80FD resume \u4F1A\u8BDD\u3002","workflow.detail.waitPrompt":"\u7B49\u5F85\u63D0\u793A","workflow.detail.approvalComment":"\u5BA1\u6279\u5907\u6CE8","workflow.detail.optionalComment":"\u53EF\u9009\u5907\u6CE8","workflow.detail.approve":"\u901A\u8FC7","workflow.detail.reject":"\u62D2\u7EDD","workflow.detail.submitting":"\u63D0\u4EA4\u4E2D...","workflow.detail.empty":"\u7A7A","workflow.detail.truncated":"\u5DF2\u622A\u65AD","workflow.detail.noData":"\u6CA1\u6709\u6570\u636E\u3002","workflow.detail.noPreview":"\u6CA1\u6709\u9884\u89C8\u3002","workflow.detail.open":"\u6253\u5F00","workflow.detail.deadline":"\u622A\u6B62","workflow.detail.effect":"\u526F\u4F5C\u7528","workflow.detail.wait":"\u7B49\u5F85","workflow.detail.noEvents":"\u8FD8\u6CA1\u6709\u4E8B\u4EF6\u3002","workflow.summary.workflow":"\u5DE5\u4F5C\u6D41","workflow.summary.status":"\u72B6\u6001","workflow.summary.lastSeq":"\u6700\u540E\u5E8F\u53F7","workflow.summary.updated":"\u66F4\u65B0\u65F6\u95F4","workflow.summary.revision":"\u4FEE\u8BA2","workflow.summary.initiator":"\u53D1\u8D77\u4EBA","workflow.summary.failedNode":"\u5931\u8D25\u8282\u70B9","workflow.summary.cancelOrigin":"\u53D6\u6D88\u6765\u6E90","workflow.summary.chat":"\u7FA4\u804A","workflow.summary.app":"\u5E94\u7528","workflow.dangling.activities":"Activities","workflow.dangling.effects":"Effects","workflow.dangling.waits":"Waits","workflow.dangling.cancels":"Cancels","catalog.title":"\u5DE5\u4F5C\u6D41\u76EE\u5F55","catalog.subtitle":"\u4ECE\u5DF2\u4FDD\u5B58\u7684 workflow \u5B9A\u4E49\u521B\u5EFA\u4E00\u6B21\u8FD0\u884C\u3002","catalog.searchPlaceholder":"\u641C\u7D22 workflowId / \u8DEF\u5F84","catalog.refresh":"\u5237\u65B0","catalog.loading":"\u6B63\u5728\u52A0\u8F7D\u76EE\u5F55...","catalog.loadFailed":"\u76EE\u5F55\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","catalog.noDefinitions":"\u6CA1\u6709\u627E\u5230 workflow \u5B9A\u4E49\u3002","catalog.noFilterMatch":"\u6CA1\u6709\u7B26\u5408\u7B5B\u9009\u6761\u4EF6\u7684\u5B9A\u4E49\u3002","catalog.table.workflow":"\u5DE5\u4F5C\u6D41","catalog.table.version":"\u7248\u672C","catalog.table.params":"\u53C2\u6570","catalog.table.nodes":"\u8282\u70B9","catalog.table.revision":"\u4FEE\u8BA2","catalog.table.path":"\u8DEF\u5F84","catalog.paramSummary":"{required}/{total} \u5FC5\u586B","catalog.back":"\u8FD4\u56DE\u76EE\u5F55","catalog.detailTitle":"\u5DE5\u4F5C\u6D41\u5B9A\u4E49","catalog.definitionLoadFailed":"\u5B9A\u4E49\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","catalog.summary":"\u6458\u8981","catalog.paramsSchema":"\u53C2\u6570 Schema","catalog.definitionJson":"\u5B9A\u4E49 JSON","catalog.runPanel":"\u8FD0\u884C\u5DE5\u4F5C\u6D41","catalog.paramsJson":"\u53C2\u6570 JSON","catalog.paramsPlaceholder":`{
|
|
6
6
|
"city": "\u5317\u4EAC"
|
|
7
|
-
}`,"catalog.chatId":"\u7FA4\u804A ID","catalog.larkAppId":"\u98DE\u4E66\u5E94\u7528 ID","catalog.chatBindingHint":"\u5FC5\u586B\uFF0C\u7528\u4E8E\u786E\u5B9A humanGate \u5361\u7247\u53D1\u9001\u5230\u54EA\u4E2A\u98DE\u4E66\u7FA4\uFF0C\u4EE5\u53CA\u53D6\u6D88\u8DEF\u7531\u5F52\u5C5E\u3002","catalog.run":"\u8FD0\u884C","catalog.running":"\u542F\u52A8\u4E2D...","catalog.badParamsJson":"\u53C2\u6570\u5FC5\u987B\u662F JSON object\u3002","catalog.writeAccess":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u8FD0\u884C\u3002","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"\u8FD0\u884C\u5DF2\u542F\u52A8\uFF1B\u6B63\u5728\u6253\u5F00\u8BE6\u60C5\u9875...","catalog.invalidParams":"\u53C2\u6570\u65E0\u6548","catalog.issue":"{path}: {message}","catalog.noParams":"\u6CA1\u6709\u58F0\u660E\u53C2\u6570\u3002","catalog.required":"\u5FC5\u586B","catalog.optional":"\u53EF\u9009","catalog.default":"\u9ED8\u8BA4\u503C","catalog.description":"\u8BF4\u660E","catalog.path":"\u8DEF\u5F84","catalog.revision":"\u4FEE\u8BA2","catalog.nodeCount":"\u8282\u70B9\u6570"},Go={"app.name":"botmux","app.subtitle":"Feishu AI CLI Control","time.secondsAgo":"{value}s ago","time.minutesAgo":"{value}m ago","time.hoursAgo":"{value}h ago","nav.overview":"Overview","nav.sessions":"Sessions","nav.groups":"Groups","nav.schedules":"Schedules","nav.settings":"Settings","nav.botDefaults":"Bot Defaults","status.live":"Live","status.disconnected":"Disconnected","status.system":"System","status.light":"Light","status.dark":"Dark","status.language":"Language","status.theme":"Theme","theme.base":"Basic","theme.skins":"Skins","skin.cyber":"2077","skin.genshin":"Genshin","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"Blue Archive","skin.zzz":"ZZZ","skin.dragonball":"Dragon Ball","skin.ikun":"ikun","botOnboarding.add":"Add Bot","botOnboarding.title":"Add Bot","botOnboarding.intro":"Pick a CLI and working directory, scan to create a PersonalAgent app \u2014 the dashboard writes it to local bots.json and auto-configures Open Platform permissions.","botOnboarding.cliLabel":"CLI adapter","botOnboarding.dirLabel":"Working directory","botOnboarding.dirPlaceholder":"Default ~ (home); must exist on the daemon host","botOnboarding.modelLabel":"Model (optional)","botOnboarding.modelPlaceholder":"Leave empty for the CLI default model","botOnboarding.startScan":"Start scan","botOnboarding.cancel":"Cancel","botOnboarding.starting":"Generating QR code...","botOnboarding.waiting":"Scan with the Feishu app to create the app.","botOnboarding.verifying":"Scan accepted. Verifying credentials...","botOnboarding.configuringPermissions":"Auto-configuring Open Platform permissions\u2026","botOnboarding.platformScanHint":"Scan once more with the Feishu app to sign in to the Open Platform (to auto-import permissions, set the callback, and submit a version).","botOnboarding.platformQrAlt":"Open Platform login QR code","botOnboarding.completed":"Bot added.","botOnboarding.permissionOk":"Auto-imported {count} permissions.","botOnboarding.permissionSkipped":"({count} skipped \u2014 not in the tenant catalog)","botOnboarding.permissionVersion":"Submitted version {version}.","botOnboarding.permissionManual":"Permissions could not be auto-configured. Complete these steps manually:","botOnboarding.metaDir":"Dir","botOnboarding.failed":"Add failed","botOnboarding.openLink":"Open scan link in browser","botOnboarding.close":"Close","botOnboarding.restartHint":"bots.json has been updated. Run pnpm daemon:restart for the new bot to take effect.","botOnboarding.qrAlt":"Feishu bot onboarding QR code","overview.title":"Workbench","overview.subtitle":"Live status of your AI teammates \xB7 synced with Feishu topics","overview.team":"AI Team","overview.teamHint":"Live status of every digital teammate","overview.attention":"Needs You","overview.attentionHint":"Blocked tasks \u2014 one reply gets them moving again","overview.activeSessions":"Active Sessions","overview.activeSessionsHint":"Sessions currently running","overview.today":"Right Now","overview.todayHint":"Active session distribution","overview.viewAll":"View all \u2192","overview.botIdle":"Standing by, ready for new tasks","overview.botOffline":"Offline \u2014 daemon not running","overview.botBusy":"Working \xB7 {count} sessions","overview.botNeedsYou":"Waiting on you","overview.botReady":"Ready","overview.botOff":"Offline","overview.sessionsCount":"{count} sessions","overview.lastActive":"active {time} ago","overview.noAttention":"Nothing waiting on you","strip.pending":"{count} pending","strip.longest":"waiting {time} \u2014 {bot} {reason}","strip.handle":"Handle now","overview.openSessions":"Active Sessions","overview.workingSessions":"Working","overview.onlineBots":"Online Bots","overview.schedules":"Schedules","overview.groups":"Groups Seen","overview.enabledSchedules":"Enabled","overview.total":"total","overview.active":"active","overview.daemonRegistry":"daemon registry","overview.chatMatrix":"chat matrix","overview.recentSessions":"Recent Sessions","overview.nextSchedules":"Next Runs","overview.noSessions":"No sessions yet.","overview.noSchedules":"No schedules yet.","sessions.title":"Session Control","sessions.subtitle":"Locate Feishu topics, open Web Terminal, close or resume CLI sessions.","sessions.search":"Search working dir / title / IDs","sessions.anyStatus":"Any status","sessions.adoptAny":"adopt: any","sessions.adoptYes":"adopt: yes","sessions.adoptNo":"adopt: no","sessions.activeOnly":"Active only","sessions.closeSelected":"Close selected","sessions.clearSelection":"Clear","sessions.selectedCount":"{count} sessions selected","sessions.bot":"Bot","sessions.cli":"CLI","sessions.chat":"Chat","sessions.openChat":"Open chat","sessions.status":"Status","sessions.titleCol":"Title","sessions.workingDir":"Working Dir","sessions.created":"Created","sessions.last":"Last","sessions.adopt":"Adopt","sessions.actions":"Actions","sessions.details":"Details","sessions.copy":"Copy","sessions.copied":"Copied","sessions.locate":"Locate Topic","sessions.locating":"Sending...","sessions.cooldown":"Cooldown {seconds}s","sessions.openTerminal":"Terminal","sessions.close":"Close Session","sessions.resume":"Resume Session","sessions.dismiss":"Close","sessions.closeConfirm":"Close this session?","sessions.resumeFailed":"Resume failed","sessions.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.viewBoard":"Board","sessions.viewTable":"Table","sessions.selectSession":"Select session","sessions.board.needsYou":"Needs You","sessions.board.needsYouHint":"Repo, TUI, or usage limit waiting","sessions.board.starting":"Starting","sessions.board.startingHint":"CLI is spawning or resuming","sessions.board.working":"Working","sessions.board.workingHint":"Streaming, analyzing, or using tools","sessions.board.idle":"Idle","sessions.board.idleHint":"Ready for the next message","sessions.board.emptyColumn":"No sessions","sessions.board.signalRepo":"Repo needed","sessions.board.signalPrompt":"TUI choice needed","sessions.board.signalLimited":"Usage limited","sessions.board.signalAgent":"Needs human input","sessions.board.waiting":"Waiting","sessions.board.dragHint":"Drag header to reorder columns","sessions.board.moveLeft":"Move column left","sessions.board.moveRight":"Move column right","groups.title":"Groups & Bots","groups.subtitle":"Inspect the chat x bot matrix and manage group creation, oncall, leave, and disband flows.","groups.search":"Search chat name / ID / owner","groups.missingOnly":"Missing bot only","groups.refresh":"Refresh","groups.create":"New Group","groups.chat":"Chat","groups.actions":"Actions","groups.addBots":"Add Bots","groups.manage":"Manage","groups.empty":"No chats match the filters.","groups.createTitle":"Create New Group","groups.createHelp":"Pick bots to invite. The dashboard chooses an online daemon as creator.","groups.name":"Group Name","groups.namePlaceholder":"e.g. AI ChangeLog","groups.bindDir":"Bind Directory","groups.bindDirHelp":"New topics start the CLI here and skip repo selection.","groups.botPicker":"Bots","groups.createSubmit":"Create","groups.cancel":"Cancel","groups.successTitle":"Group Created","groups.openGroup":"Open Group","groups.manageTitle":"Manage {name}","groups.owner":"Owner","groups.oncall":"Oncall Mode","groups.oncallHelp":"When enabled, group members can @ the bot; new topics use the bound directory.","groups.leaveTitle":"Select Bots to Leave","groups.leaveSelected":"Selected Bots Leave","groups.disband":"Disband Group","groups.dangerHint":"Disband only works when an in-chat bot is the owner. Otherwise prefer leaving the chat.","groups.save":"Save","groups.needWorkingDir":"Working directory is required","groups.noBotsOnline":"No bots online. Restart the daemon first.","schedules.title":"Schedules","schedules.subtitle":"View, pause, resume, and run scheduled tasks across daemons.","schedules.search":"Search name / prompt / working dir","schedules.anyKind":"Any kind","schedules.enabledOnly":"Enabled only","schedules.name":"Name","schedules.bot":"Bot","schedules.schedule":"Schedule","schedules.next":"Next","schedules.last":"Last","schedules.repeat":"Repeat","schedules.enabled":"Enabled","schedules.actions":"Actions","schedules.runNow":"Run Now","schedules.pause":"Pause","schedules.resume":"Resume","schedules.empty":"No schedules.","settings.title":"Global Settings","settings.subtitle":"Manage machine-wide botmux dashboard behavior shared by every bot.","settings.loading":"Loading settings\u2026","settings.loadFailed":"Failed to load settings","settings.readOnlyVisitor":"Read-only access \u2014 changing settings requires an authorized link (run botmux dashboard).","settings.sectionAccess":"Access","settings.publicReadOnly":"Allow tokenless read-only dashboard access","settings.publicReadOnlyHelp":"When enabled, visitors without a token can view the dashboard, sessions, schedules, and SSE. Writes such as close, pause, and approvals still require token auth. Sensitive raw terminal logs always require a token.","settings.sectionCards":"Feishu Cards","settings.openTerminalInFeishu":"Open streaming-card terminals in the Feishu sidebar","settings.openTerminalInFeishuHelp":"Off by default: terminal buttons open the Web Terminal URL directly. When enabled, botmux wraps the URL with Feishu web_url/open so Feishu PC opens it in a sidebar. Terminal write access is still controlled by its token.","settings.saving":"Saving\u2026","settings.saved":"Saved","settings.saveFailed":"Save failed","settings.sectionMaintenance":"Auto Maintenance","settings.autoUpdate":"Auto update","settings.autoUpdateHelp":"Off by default. At the set time, runs npm install -g botmux@latest to install the latest version (download/install only \u2014 no restart). npm-global installs only.","settings.autoRestart":"Auto restart","settings.autoRestartHelp":"Off by default; requires auto-update. After auto-update installs a newer version, restart to apply it if no session is in progress (busy \u21D2 slips to the next day).","settings.autoUpdateLocalDev":"This is a local-dev install (running from source); auto-update is unavailable.","settings.maintenanceTime":"Time","botDefaults.title":"Bot Profiles","botDefaults.subtitle":"Per-bot defaults: oncall, proactive start, persona role, cards and grants.","botDefaults.metaOnline":"Online \xB7 daemon healthy","botDefaults.search":"Search bot name / app id","botDefaults.refresh":"Refresh","botDefaults.sectionOncall":"New-chat Oncall","botDefaults.sectionBrand":"Card Signature","botDefaults.warning":"When enabled, chats without an oncall binding auto-bind to this directory on their next new topic. Manually bound or unbound chats are preserved.","botDefaults.empty":"No bots online. Run botmux restart first.","botDefaults.defaultOncall":"Default to oncall mode","botDefaults.defaultOncallHelp":"Unbound chats auto-bind on the next new topic","botDefaults.workingDir":"Default Working Directory","botDefaults.lastEnabled":"Last Enabled","botDefaults.autobound":"{count} chats auto-bound","botDefaults.save":"Save","botDefaults.required":"Working directory is required when enabled","botDefaults.brandLabel":"Signature (card footer)","botDefaults.brandLabelHelp":"Footer signature on cards this bot sends. Save empty = hide; fill in = custom (markdown ok, e.g. [Acme](https://\u2026)); Reset = show botmux.","botDefaults.brandLabelPlaceholder":"Default: botmux (empty = hidden)","botDefaults.sectionSandbox":"File sandbox (oncall)","botDefaults.sandboxToggle":"Enable file sandbox","botDefaults.sandboxHelp":"When on, every session of this bot runs in a per-session sandbox: only a project copy is visible \u2014 your real files, secrets, and other sessions are not. For sharing the bot with semi-trusted users (oncall). Linux only; applies to the next new session.","botDefaults.sandboxSaved":"Saved (applies to the next new session)","botDefaults.brandSave":"Save Signature","botDefaults.brandReset":"Reset to default","botDefaults.brandStateDefault":"Current: default botmux","botDefaults.brandStateOff":"Current: off","botDefaults.brandStateCustom":"Current: custom","botDefaults.sectionCard":"Card Behavior","botDefaults.disableStreaming":"Disable streaming card","botDefaults.disableStreamingHelp":"Stop posting the live session status card (and its Open Terminal entry). The task's final result still arrives as a message. For those who find the live card noisy.","botDefaults.writableLink":"Put a writable terminal link on the card","botDefaults.writableLinkHelp":'\u26A0\uFE0F Embeds a writable terminal link in the streaming card body \u2014 anyone in the chat can open and drive the terminal. Off = current behavior (private DM via the "Get Write Link" button).',"botDefaults.writableLinkMoot":"Streaming card disabled \u2014 this has no effect","botDefaults.privateCard":"/card sends a private card (authorized users only)","botDefaults.privateCardHelp":'Makes /card send an ephemeral "visible-to-specific-people" card: delivered only to the owner (allowedUsers); /grant-authorized talk users and everyone else in the chat cannot see it. Trade-off: it is a static snapshot (no live updates) and only works in regular group chats (topic groups / DMs fail, with no fallback). Affects only the /card command; the auto streaming card is unchanged.',"botDefaults.cardPrefSaved":"Saved","botDefaults.sectionRole":"Default Role","botDefaults.roleHelp":"This bot's default persona (applies across all chats), injected into the bot's sessions in every chat; a single group can override it on the Roles page. Save empty = delete.","botDefaults.rolePlaceholder":"e.g. You are a backend triage assistant; answer concisely, prefer runnable commands\u2026","botDefaults.roleSave":"Save role","botDefaults.roleDelete":"Delete","botDefaults.roleSaved":"Saved","botDefaults.roleDeleted":"Deleted","botDefaults.roleLoadErr":"Failed to load role","botDefaults.sectionAutoStart":"Proactive Start","botDefaults.autoStartJoin":"Auto-start when added to a new chat","botDefaults.autoStartJoinHelp":'When enabled, the bot auto-starts a session and gets to work the moment it is added to a new chat (when an authorized user / allowedUsers is a member), no @ needed. It launches in the bot default working dir; if none is configured it shows a repo-select card first. Prerequisite: subscribe the "bot joined chat" event im.chat.member.bot.added_v1 for this app and grant the member-read scope in the Feishu console.',"botDefaults.autoStartJoinPrompt":"First-turn prompt on join (optional)","botDefaults.autoStartJoinPromptPlaceholder":"Filled = used as the first task after joining; blank = the bot reads the chat and decides what to do","botDefaults.autoStartJoinPromptSave":"Save prompt","botDefaults.autoStartTopic":"Auto-start on new topics in topic groups","botDefaults.autoStartTopicHelp":"When enabled, in a topic group the bot automatically joins each newly opened topic and starts working on its first message, no @ needed. Topic groups only \u2014 regular groups are unaffected.","botDefaults.sectionSessionMode":"Session mode","botDefaults.p2pMode":"Private chat session mode","botDefaults.p2pThread":"thread (separate session per DM)","botDefaults.p2pChat":"chat (flat continuous session)","botDefaults.p2pHelp":"How 1:1 DMs are sessioned: thread = each top-level message starts its own session (keeps chatter out of one CLI process); chat = the whole DM shares one continuous session and context (Hermes-like). Takes effect immediately.","botDefaults.regularGroupMode":"Regular group session mode","botDefaults.regularGroupModeChat":"chat (flat continuous session, default)","botDefaults.regularGroupModeNewTopic":"new-topic (each top-level @ opens its own topic & session)","botDefaults.regularGroupModeShared":"shared (topic display, reusing one session)","botDefaults.regularGroupModeHelp":"How new top-level @mentions in regular (non-topic) groups are sessioned: chat = the whole group shares one continuous session (default); new-topic = each top-level @ opens its own topic with a separate session; shared = topic display but reuse the same session (replies fold into a topic yet share the group session & context). This is the per-bot default; a specific group can override it via /reply-mode. Takes effect immediately.","botDefaults.mentionMode":"Group @ policy","botDefaults.mentionModeAlways":"Always require @ (default)","botDefaults.mentionModeTopic":"No @ needed inside topics","botDefaults.mentionModeNever":"Never require @","botDefaults.mentionModeHelp":'Bot-global: controls when an @ is required to get a reply in groups. "Always require @" = every message needs an @ (default, safest; inside topics too, in multi-person groups); "No @ needed inside topics" = starting a new conversation / top-level still needs @, but follow-ups inside ANY topic this bot already drives (new-topic / shared / topic-group) continue without @; "Never require @" = non-@ messages are answered too wherever the bot has talk access (including cold-starting on a brand-new message \u2014 only suitable for dedicated / on-call small groups; in busy multi-person groups it replies to everything). Note: when you are alone with this bot (1:1) replies never need an @, independent of this setting.',"botDefaults.sectionGrant":"Authorization & Quota","botDefaults.restrictGrant":"Restrict grantees to plain conversation","botDefaults.restrictGrantHelp":"When enabled, /grant-authorized users (the owner is exempt) can only send plain messages; every slash command is blocked: botmux built-in commands, passthrough commands, /workflow, /introduce, /t, and CLI-native commands (/help, etc.). Text like /path/to/file is not misclassified.","botDefaults.quotaDefault":"Default message quota","botDefaults.quotaPlaceholder":"Empty = no default quota","botDefaults.quotaHelp":'Message count a bare /grant @x (no number) hands out. Empty or "Turn off" merely stops applying a default to bare /grant \u2014 it does NOT clear existing quota counters, nor affect an explicit /grant @x N; those keep being enforced. Authorization is auto-revoked once a quota runs out.',"botDefaults.quotaSave":"Save quota","botDefaults.quotaOff":"Turn off","botDefaults.quotaInvalid":"Quota must be a positive integer","botDefaults.quotaStateOff":"Current: no default quota","botDefaults.quotaStateOn":"Current: {count} per grantee","nav.roles":"Roles","roles.title":"Role Management","roles.subtitle":"Set per-bot role prompts for each group. Each bot adopts its own persona in the selected group.","roles.search":"Search group / bot / ID","roles.refresh":"Refresh","roles.selectHint":"\u2190 Expand a group and select a bot to edit its role","roles.editorPlaceholder":`Enter role description, e.g.:
|
|
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"},Jo={"app.name":"botmux","app.subtitle":"Feishu AI CLI Control","time.secondsAgo":"{value}s ago","time.minutesAgo":"{value}m ago","time.hoursAgo":"{value}h ago","nav.overview":"Overview","nav.sessions":"Sessions","nav.groups":"Groups","nav.schedules":"Schedules","nav.settings":"Settings","nav.botDefaults":"Bot Defaults","status.live":"Live","status.disconnected":"Disconnected","status.system":"System","status.light":"Light","status.dark":"Dark","status.language":"Language","status.theme":"Theme","theme.base":"Basic","theme.skins":"Skins","skin.cyber":"2077","skin.genshin":"Genshin","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"Blue Archive","skin.zzz":"ZZZ","skin.dragonball":"Dragon Ball","skin.ikun":"ikun","botOnboarding.add":"Add Bot","botOnboarding.title":"Add Bot","botOnboarding.intro":"Pick a CLI and working directory, scan to create a PersonalAgent app \u2014 the dashboard writes it to local bots.json and auto-configures Open Platform permissions.","botOnboarding.cliLabel":"CLI adapter","botOnboarding.dirLabel":"Working directory","botOnboarding.dirPlaceholder":"Default ~ (home); must exist on the daemon host","botOnboarding.modelLabel":"Model (optional)","botOnboarding.modelPlaceholder":"Leave empty for the CLI default model","botOnboarding.startScan":"Start scan","botOnboarding.cancel":"Cancel","botOnboarding.starting":"Generating QR code...","botOnboarding.waiting":"Scan with the Feishu app to create the app.","botOnboarding.verifying":"Scan accepted. Verifying credentials...","botOnboarding.configuringPermissions":"Auto-configuring Open Platform permissions\u2026","botOnboarding.platformScanHint":"Scan once more with the Feishu app to sign in to the Open Platform (to auto-import permissions, set the callback, and submit a version).","botOnboarding.platformQrAlt":"Open Platform login QR code","botOnboarding.completed":"Bot added.","botOnboarding.permissionOk":"Auto-imported {count} permissions.","botOnboarding.permissionSkipped":"({count} skipped \u2014 not in the tenant catalog)","botOnboarding.permissionVersion":"Submitted version {version}.","botOnboarding.permissionManual":"Permissions could not be auto-configured. Complete these steps manually:","botOnboarding.metaDir":"Dir","botOnboarding.failed":"Add failed","botOnboarding.openLink":"Open scan link in browser","botOnboarding.close":"Close","botOnboarding.restartHint":"bots.json has been updated. Run pnpm daemon:restart for the new bot to take effect.","botOnboarding.qrAlt":"Feishu bot onboarding QR code","overview.title":"Workbench","overview.subtitle":"Live status of your AI teammates \xB7 synced with Feishu topics","overview.team":"AI Team","overview.teamHint":"Live status of every digital teammate","overview.attention":"Needs You","overview.attentionHint":"Blocked tasks \u2014 one reply gets them moving again","overview.activeSessions":"Active Sessions","overview.activeSessionsHint":"Sessions currently running","overview.today":"Right Now","overview.todayHint":"Active session distribution","overview.viewAll":"View all \u2192","overview.botIdle":"Standing by, ready for new tasks","overview.botOffline":"Offline \u2014 daemon not running","overview.botBusy":"Working \xB7 {count} sessions","overview.botNeedsYou":"Waiting on you","overview.botReady":"Ready","overview.botOff":"Offline","overview.sessionsCount":"{count} sessions","overview.lastActive":"active {time} ago","overview.noAttention":"Nothing waiting on you","strip.pending":"{count} pending","strip.longest":"waiting {time} \u2014 {bot} {reason}","strip.handle":"Handle now","overview.openSessions":"Active Sessions","overview.workingSessions":"Working","overview.onlineBots":"Online Bots","overview.schedules":"Schedules","overview.groups":"Groups Seen","overview.enabledSchedules":"Enabled","overview.total":"total","overview.active":"active","overview.daemonRegistry":"daemon registry","overview.chatMatrix":"chat matrix","overview.recentSessions":"Recent Sessions","overview.nextSchedules":"Next Runs","overview.noSessions":"No sessions yet.","overview.noSchedules":"No schedules yet.","sessions.title":"Session Control","sessions.subtitle":"Locate Feishu topics, open Web Terminal, close or resume CLI sessions.","sessions.search":"Search working dir / title / IDs","sessions.anyStatus":"Any status","sessions.adoptAny":"adopt: any","sessions.adoptYes":"adopt: yes","sessions.adoptNo":"adopt: no","sessions.activeOnly":"Active only","sessions.closeSelected":"Close selected","sessions.clearSelection":"Clear","sessions.selectedCount":"{count} sessions selected","sessions.bot":"Bot","sessions.cli":"CLI","sessions.chat":"Chat","sessions.openChat":"Open chat","sessions.status":"Status","sessions.titleCol":"Title","sessions.workingDir":"Working Dir","sessions.created":"Created","sessions.last":"Last","sessions.adopt":"Adopt","sessions.actions":"Actions","sessions.details":"Details","sessions.copy":"Copy","sessions.copied":"Copied","sessions.locate":"Locate Topic","sessions.locating":"Sending...","sessions.cooldown":"Cooldown {seconds}s","sessions.openTerminal":"Terminal","sessions.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.viewBoard":"Board","sessions.viewTable":"Table","sessions.selectSession":"Select session","sessions.board.needsYou":"Needs You","sessions.board.needsYouHint":"Repo, TUI, or usage limit waiting","sessions.board.starting":"Starting","sessions.board.startingHint":"CLI is spawning or resuming","sessions.board.working":"Working","sessions.board.workingHint":"Streaming, analyzing, or using tools","sessions.board.idle":"Idle","sessions.board.idleHint":"Ready for the next message","sessions.board.emptyColumn":"No sessions","sessions.board.signalRepo":"Repo needed","sessions.board.signalPrompt":"TUI choice needed","sessions.board.signalLimited":"Usage limited","sessions.board.signalAgent":"Needs human input","sessions.board.waiting":"Waiting","sessions.board.dragHint":"Drag header to reorder columns","sessions.board.moveLeft":"Move column left","sessions.board.moveRight":"Move column right","groups.title":"Groups & Bots","groups.subtitle":"Inspect the chat x bot matrix and manage group creation, oncall, leave, and disband flows.","groups.search":"Search chat name / ID / owner","groups.missingOnly":"Missing bot only","groups.refresh":"Refresh","groups.create":"New Group","groups.chat":"Chat","groups.actions":"Actions","groups.addBots":"Add Bots","groups.manage":"Manage","groups.empty":"No chats match the filters.","groups.createTitle":"Create New Group","groups.createHelp":"Pick bots to invite. The dashboard chooses an online daemon as creator.","groups.name":"Group Name","groups.namePlaceholder":"e.g. AI ChangeLog","groups.bindDir":"Bind Directory","groups.bindDirHelp":"New topics start the CLI here and skip repo selection.","groups.botPicker":"Bots","groups.createSubmit":"Create","groups.cancel":"Cancel","groups.successTitle":"Group Created","groups.openGroup":"Open Group","groups.manageTitle":"Manage {name}","groups.owner":"Owner","groups.oncall":"Oncall Mode","groups.oncallHelp":"When enabled, group members can @ the bot; new topics use the bound directory.","groups.leaveTitle":"Select Bots to Leave","groups.leaveSelected":"Selected Bots Leave","groups.disband":"Disband Group","groups.dangerHint":"Disband only works when an in-chat bot is the owner. Otherwise prefer leaving the chat.","groups.save":"Save","groups.needWorkingDir":"Working directory is required","groups.noBotsOnline":"No bots online. Restart the daemon first.","schedules.title":"Schedules","schedules.subtitle":"View, pause, resume, and run scheduled tasks across daemons.","schedules.search":"Search name / prompt / working dir","schedules.anyKind":"Any kind","schedules.enabledOnly":"Enabled only","schedules.name":"Name","schedules.bot":"Bot","schedules.schedule":"Schedule","schedules.next":"Next","schedules.last":"Last","schedules.repeat":"Repeat","schedules.enabled":"Enabled","schedules.actions":"Actions","schedules.runNow":"Run Now","schedules.pause":"Pause","schedules.resume":"Resume","schedules.empty":"No schedules.","settings.title":"Global Settings","settings.subtitle":"Manage machine-wide botmux dashboard behavior shared by every bot.","settings.loading":"Loading settings\u2026","settings.loadFailed":"Failed to load settings","settings.readOnlyVisitor":"Read-only access \u2014 changing settings requires an authorized link (run botmux dashboard).","settings.sectionAccess":"Access","settings.publicReadOnly":"Allow tokenless read-only dashboard access","settings.publicReadOnlyHelp":"When enabled, visitors without a token can view the dashboard, sessions, schedules, and SSE. Writes such as close, pause, and approvals still require token auth. Sensitive raw terminal logs always require a token.","settings.sectionCards":"Feishu Cards","settings.openTerminalInFeishu":"Open streaming-card terminals in the Feishu sidebar","settings.openTerminalInFeishuHelp":"Off by default: terminal buttons open the Web Terminal URL directly. When enabled, botmux wraps the URL with Feishu web_url/open so Feishu PC opens it in a sidebar. Terminal write access is still controlled by its token.","settings.saving":"Saving\u2026","settings.saved":"Saved","settings.saveFailed":"Save failed","settings.sectionMaintenance":"Auto Maintenance","settings.autoUpdate":"Auto update","settings.autoUpdateHelp":"Off by default. At the set time, runs npm install -g botmux@latest to install the latest version (download/install only \u2014 no restart). npm-global installs only.","settings.autoRestart":"Auto restart","settings.autoRestartHelp":"Off by default; requires auto-update. After auto-update installs a newer version, restart to apply it if no session is in progress (busy \u21D2 slips to the next day).","settings.autoUpdateLocalDev":"This is a local-dev install (running from source); auto-update is unavailable.","settings.maintenanceTime":"Time","botDefaults.title":"Bot Profiles","botDefaults.subtitle":"Per-bot defaults: oncall, proactive start, persona role, cards and grants.","botDefaults.metaOnline":"Online \xB7 daemon healthy","botDefaults.search":"Search bot name / app id","botDefaults.refresh":"Refresh","botDefaults.sectionOncall":"New-chat Oncall","botDefaults.sectionBrand":"Card Signature","botDefaults.warning":"When enabled, chats without an oncall binding auto-bind to this directory on their next new topic. Manually bound or unbound chats are preserved.","botDefaults.empty":"No bots online. Run botmux restart first.","botDefaults.defaultOncall":"Default to oncall mode","botDefaults.defaultOncallHelp":"Unbound chats auto-bind on the next new topic","botDefaults.workingDir":"Default Working Directory","botDefaults.lastEnabled":"Last Enabled","botDefaults.autobound":"{count} chats auto-bound","botDefaults.save":"Save","botDefaults.required":"Working directory is required when enabled","botDefaults.brandLabel":"Signature (card footer)","botDefaults.brandLabelHelp":"Footer signature on cards this bot sends. Save empty = hide; fill in = custom (markdown ok, e.g. [Acme](https://\u2026)); Reset = show botmux.","botDefaults.brandLabelPlaceholder":"Default: botmux (empty = hidden)","botDefaults.sectionSandbox":"File sandbox (oncall)","botDefaults.sandboxToggle":"Enable file sandbox","botDefaults.sandboxHelp":"When on, every session of this bot runs in a per-session sandbox: only a project copy is visible \u2014 your real files, secrets, and other sessions are not. For sharing the bot with semi-trusted users (oncall). Linux only; applies to the next new session.","botDefaults.sandboxSaved":"Saved (applies to the next new session)","botDefaults.brandSave":"Save Signature","botDefaults.brandReset":"Reset to default","botDefaults.brandStateDefault":"Current: default botmux","botDefaults.brandStateOff":"Current: off","botDefaults.brandStateCustom":"Current: custom","botDefaults.sectionCard":"Card Behavior","botDefaults.disableStreaming":"Disable streaming card","botDefaults.disableStreamingHelp":"Stop posting the live session status card (and its Open Terminal entry). The task's final result still arrives as a message. For those who find the live card noisy.","botDefaults.writableLink":"Put a writable terminal link on the card","botDefaults.writableLinkHelp":'\u26A0\uFE0F Embeds a writable terminal link in the streaming card body \u2014 anyone in the chat can open and drive the terminal. Off = current behavior (private DM via the "Get Write Link" button).',"botDefaults.writableLinkMoot":"Streaming card disabled \u2014 this has no effect","botDefaults.privateCard":"/card sends a private card (authorized users only)","botDefaults.privateCardHelp":'Makes /card send an ephemeral "visible-to-specific-people" card: delivered only to the owner (allowedUsers); /grant-authorized talk users and everyone else in the chat cannot see it. Trade-off: it is a static snapshot (no live updates) and only works in regular group chats (topic groups / DMs fail, with no fallback). Affects only the /card command; the auto streaming card is unchanged.',"botDefaults.cardPrefSaved":"Saved","botDefaults.sectionRole":"Default Role","botDefaults.roleHelp":"This bot's default persona (applies across all chats), injected into the bot's sessions in every chat; a single group can override it on the Roles page. Save empty = delete.","botDefaults.rolePlaceholder":"e.g. You are a backend triage assistant; answer concisely, prefer runnable commands\u2026","botDefaults.roleSave":"Save role","botDefaults.roleDelete":"Delete","botDefaults.roleSaved":"Saved","botDefaults.roleDeleted":"Deleted","botDefaults.roleLoadErr":"Failed to load role","botDefaults.sectionAutoStart":"Proactive Start","botDefaults.autoStartJoin":"Auto-start when added to a new chat","botDefaults.autoStartJoinHelp":'When enabled, the bot auto-starts a session and gets to work the moment it is added to a new chat (when an authorized user / allowedUsers is a member), no @ needed. It launches in the bot default working dir; if none is configured it shows a repo-select card first. Prerequisite: subscribe the "bot joined chat" event im.chat.member.bot.added_v1 for this app and grant the member-read scope in the Feishu console.',"botDefaults.autoStartJoinPrompt":"First-turn prompt on join (optional)","botDefaults.autoStartJoinPromptPlaceholder":"Filled = used as the first task after joining; blank = the bot reads the chat and decides what to do","botDefaults.autoStartJoinPromptSave":"Save prompt","botDefaults.autoStartTopic":"Auto-start on new topics in topic groups","botDefaults.autoStartTopicHelp":"When enabled, in a topic group the bot automatically joins each newly opened topic and starts working on its first message, no @ needed. Topic groups only \u2014 regular groups are unaffected.","botDefaults.sectionSessionMode":"Session mode","botDefaults.p2pMode":"Private chat session mode","botDefaults.p2pThread":"thread (separate session per DM)","botDefaults.p2pChat":"chat (flat continuous session)","botDefaults.p2pHelp":"How 1:1 DMs are sessioned: thread = each top-level message starts its own session (keeps chatter out of one CLI process); chat = the whole DM shares one continuous session and context (Hermes-like). Takes effect immediately.","botDefaults.regularGroupMode":"Regular group session mode","botDefaults.regularGroupModeChat":"chat (flat continuous session, default)","botDefaults.regularGroupModeNewTopic":"new-topic (each top-level @ opens its own topic & session)","botDefaults.regularGroupModeShared":"shared (topic display, reusing one session)","botDefaults.regularGroupModeHelp":"How new top-level @mentions in regular (non-topic) groups are sessioned: chat = the whole group shares one continuous session (default); new-topic = each top-level @ opens its own topic with a separate session; shared = topic display but reuse the same session (replies fold into a topic yet share the group session & context). This is the per-bot default; a specific group can override it via /reply-mode. Takes effect immediately.","botDefaults.mentionMode":"Group @ policy","botDefaults.mentionModeAlways":"Always require @ (default)","botDefaults.mentionModeTopic":"No @ needed inside topics","botDefaults.mentionModeNever":"Never require @","botDefaults.mentionModeHelp":'Bot-global: controls when an @ is required to get a reply in groups. "Always require @" = every message needs an @ (default, safest; inside topics too, in multi-person groups); "No @ needed inside topics" = starting a new conversation / top-level still needs @, but follow-ups inside ANY topic this bot already drives (new-topic / shared / topic-group) continue without @; "Never require @" = non-@ messages are answered too wherever the bot has talk access (including cold-starting on a brand-new message \u2014 only suitable for dedicated / on-call small groups; in busy multi-person groups it replies to everything). Note: when you are alone with this bot (1:1) replies never need an @, independent of this setting.',"botDefaults.sectionGrant":"Authorization & Quota","botDefaults.restrictGrant":"Restrict grantees to plain conversation","botDefaults.restrictGrantHelp":"When enabled, /grant-authorized users (the owner is exempt) can only send plain messages; every slash command is blocked: botmux built-in commands, passthrough commands, /workflow, /introduce, /t, and CLI-native commands (/help, etc.). Text like /path/to/file is not misclassified.","botDefaults.quotaDefault":"Default message quota","botDefaults.quotaPlaceholder":"Empty = no default quota","botDefaults.quotaHelp":'Message count a bare /grant @x (no number) hands out. Empty or "Turn off" merely stops applying a default to bare /grant \u2014 it does NOT clear existing quota counters, nor affect an explicit /grant @x N; those keep being enforced. Authorization is auto-revoked once a quota runs out.',"botDefaults.quotaSave":"Save quota","botDefaults.quotaOff":"Turn off","botDefaults.quotaInvalid":"Quota must be a positive integer","botDefaults.quotaStateOff":"Current: no default quota","botDefaults.quotaStateOn":"Current: {count} per grantee","nav.roles":"Roles","roles.title":"Role Management","roles.subtitle":"Set per-bot role prompts for each group. Each bot adopts its own persona in the selected group.","roles.search":"Search group / bot / ID","roles.refresh":"Refresh","roles.selectHint":"\u2190 Expand a group and select a bot to edit its role","roles.editorPlaceholder":`Enter role description, e.g.:
|
|
8
8
|
You are a code reviewer for this group...`,"roles.configured":"Configured","roles.unconfigured":"None","roles.noChats":"No groups","roles.preview":"Preview","roles.previewEmpty":"(empty)","roles.saved":"Saved","roles.delete":"Delete","roles.save":"Save","roles.confirmDelete":"Delete this bot's role config for this group?","roles.botsWithRoles":"bots configured","roles.emptyError":"Role content cannot be empty","roles.saveFailed":"Save failed, please retry","common.none":"None","common.unknown":"Unknown","common.now":"now","common.never":"never","common.all":"All","nav.workflows":"Workflows (beta)","nav.workflowCatalog":"Catalog","workflow.subnav.runs":"Runs","workflow.subnav.catalog":"Catalog","workflow.searchPlaceholder":"search runId / workflowId / chatId","workflow.filter.nonTerminal":"non-terminal","workflow.filter.all":"all","workflow.status.pending":"pending","workflow.status.running":"running","workflow.status.waiting":"waiting","workflow.status.effectAttempting":"effect","workflow.status.timedOut":"timed out","workflow.status.succeeded":"succeeded","workflow.status.failed":"failed","workflow.status.cancelled":"cancelled","workflow.table.run":"run","workflow.table.workflow":"workflow","workflow.table.status":"status","workflow.table.lastSeq":"lastSeq","workflow.table.dangling":"dEf/dAct/dWait","workflow.table.updated":"updated","workflow.table.chatApp":"chat / app","workflow.list.failedLoad":"Failed to load: {error}","workflow.list.noRuns":"No runs match.","workflow.list.noFilterMatch":"No runs match this filter.","workflow.list.loaded":"{count} runs \xB7 refreshed {time}","workflow.list.error":"error: {error}","workflow.detail.back":"Back","workflow.detail.loading":"Loading...","workflow.detail.loadFailed":"Load failed","workflow.detail.cancel":"Cancel","workflow.detail.cliCancelOnly":"CLI cancel only","workflow.detail.cancelTitle":"Cancel this workflow run","workflow.detail.cliCancelTitle":"Cancel unavailable: use botmux workflow cancel {runId}","workflow.detail.nodes":"Nodes / Activities","workflow.detail.parallel":"Parallel execution","workflow.detail.parallelMeta":"{count} attempt(s) \xB7 max parallel {max} \xB7 running {running}","workflow.detail.noParallelData":"No attempt timing data yet.","workflow.detail.parallelNow":"now","workflow.detail.node":"node","workflow.detail.nodeStatus":"node status","workflow.detail.activity":"activity","workflow.detail.activityStatus":"activity status","workflow.detail.attempts":"attempts","workflow.detail.current":"current","workflow.detail.detail":"detail","workflow.detail.nodeIO":"Node I/O","workflow.detail.timeline":"Timeline","workflow.detail.loadOlder":"Load older","workflow.detail.seq":"seq","workflow.detail.actor":"actor","workflow.detail.error":"error","workflow.detail.event":"event","workflow.detail.time":"time","workflow.detail.refreshed":"refreshed {time}","workflow.detail.unknownRun":"unknown run","workflow.detail.snapshotHttp":"snapshot HTTP {status}","workflow.detail.eventsHttp":"events HTTP {status}","workflow.detail.cancelUnavailable":"cancel unavailable: use botmux workflow cancel {runId}","workflow.detail.cancelConfirm":`Cancel workflow run {runId}?
|
|
9
9
|
|
|
10
10
|
{total} dangling item(s) will be handled by cancel-driven recovery.
|
|
11
11
|
effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"workflow.detail.writeAccessCancel":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and click cancel again.","workflow.detail.cancelHttp":"cancel HTTP {status}","workflow.detail.cancelPending":"cancel pending; waiting for running activity to drain","workflow.detail.writeAccessApproval":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and approve/reject again.","workflow.detail.actionHttp":"{action} HTTP {status}","workflow.detail.approved":"approved","workflow.detail.rejected":"rejected","workflow.detail.alreadyTerminal":"Run already terminal; {label} was not applied.","workflow.detail.workflowContinue":"{label}; waiting for workflow to continue.","workflow.detail.workflowRefreshing":"{label}; refreshing workflow state.","workflow.detail.eventsLoaded":"{loaded}/{total} events loaded","workflow.detail.dangling":"Dangling","workflow.detail.noDangling":"No dangling work.","workflow.detail.none":"none","workflow.detail.noNodes":"No nodes yet.","workflow.detail.idle":"idle","workflow.detail.noNodeIO":"No node I/O yet.","workflow.detail.notDispatched":"not dispatched","workflow.detail.noAttempt":"No attempt yet","workflow.detail.attempt":"attempt","workflow.detail.authoredInput":"Authored input","workflow.detail.resolvedInput":"Resolved input","workflow.detail.output":"Output","workflow.detail.executionLog":"Execution log","workflow.detail.liveTerminal":"Live terminal","workflow.detail.terminalLive":"live","workflow.detail.terminalClosedShort":"closed","workflow.detail.terminalClosed":"Terminal is closed. Use the execution log below for the final transcript.","workflow.detail.openTerminalNewTab":"Open terminal in new tab","workflow.detail.terminalReplay":"Terminal replay","workflow.detail.openReplayNewTab":"Open replay in new tab","workflow.detail.downloadFullLog":"Download full log","workflow.detail.terminalResume":"Debug session","workflow.detail.openResumeNewTab":"Open debug session in new tab","workflow.detail.resumeSession":"Resume session","workflow.detail.resumeStarting":"Starting\u2026","workflow.detail.endResumeSession":"End debug session","workflow.detail.resumeEnding":"Ending\u2026","workflow.detail.resumeUnsupportedCli":'CLI "{cliId}" does not support resume',"workflow.detail.resumeMissingCliSession":"Missing cliSessionId \u2014 cannot resume","workflow.detail.resumeStartFailed":"Failed to start debug session (HTTP {status})","workflow.detail.resumeEndFailed":"Failed to end debug session (HTTP {status})","workflow.detail.writeAccessResume":"Resume requires dashboard write access.","workflow.detail.waitPrompt":"Wait prompt","workflow.detail.approvalComment":"Approval comment","workflow.detail.optionalComment":"Optional comment","workflow.detail.approve":"Approve","workflow.detail.reject":"Reject","workflow.detail.submitting":"Submitting...","workflow.detail.empty":"empty","workflow.detail.truncated":"truncated","workflow.detail.noData":"No data.","workflow.detail.noPreview":"No preview.","workflow.detail.open":"open","workflow.detail.deadline":"deadline","workflow.detail.effect":"effect","workflow.detail.wait":"wait","workflow.detail.noEvents":"No events.","workflow.summary.workflow":"workflow","workflow.summary.status":"status","workflow.summary.lastSeq":"lastSeq","workflow.summary.updated":"updated","workflow.summary.revision":"revision","workflow.summary.initiator":"initiator","workflow.summary.failedNode":"failedNode","workflow.summary.cancelOrigin":"cancelOrigin","workflow.summary.chat":"chat","workflow.summary.app":"app","workflow.dangling.activities":"activities","workflow.dangling.effects":"effects","workflow.dangling.waits":"waits","workflow.dangling.cancels":"cancels","catalog.title":"Workflow catalog","catalog.subtitle":"Create a workflow run from a saved workflow definition.","catalog.searchPlaceholder":"search workflowId / path","catalog.refresh":"Refresh","catalog.loading":"Loading catalog...","catalog.loadFailed":"Failed to load catalog: {error}","catalog.noDefinitions":"No workflow definitions found.","catalog.noFilterMatch":"No definitions match this filter.","catalog.table.workflow":"workflow","catalog.table.version":"version","catalog.table.params":"params","catalog.table.nodes":"nodes","catalog.table.revision":"revision","catalog.table.path":"path","catalog.paramSummary":"{required}/{total} required","catalog.back":"Back to catalog","catalog.detailTitle":"Workflow definition","catalog.definitionLoadFailed":"Failed to load definition: {error}","catalog.summary":"Summary","catalog.paramsSchema":"Params schema","catalog.definitionJson":"Definition JSON","catalog.runPanel":"Run workflow","catalog.paramsJson":"Params JSON","catalog.paramsPlaceholder":`{
|
|
12
12
|
"city": "\u5317\u4EAC"
|
|
13
|
-
}`,"catalog.chatId":"Chat ID","catalog.larkAppId":"Lark app ID","catalog.chatBindingHint":"Required so humanGate cards and cancel routing know which Lark chat owns the run.","catalog.run":"Run","catalog.running":"Starting...","catalog.badParamsJson":"Params must be a JSON object.","catalog.writeAccess":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and run again.","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"Run started; opening detail page...","catalog.invalidParams":"Invalid params","catalog.issue":"{path}: {message}","catalog.noParams":"No params declared.","catalog.required":"required","catalog.optional":"optional","catalog.default":"default","catalog.description":"description","catalog.path":"path","catalog.revision":"revision","catalog.nodeCount":"nodes"},vn={zh:Fo,en:Go};function bt(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 zo(e=[]){for(let n of e){let o=bt(n);if(o)return o}return"zh"}function ht(e){return(n,o)=>{let s=vn[e][n]??vn.zh[n]??n;return o?s.replace(/\{(\w+)\}/g,(a,r)=>{let l=o[r];return l==null?`{${r}}`:String(l)}):s}}function kn(e,n){return(e?bt(e.getItem(Pt)):null)??zo(n)}var qt="botmux.dashboard.theme",$n="botmux.dashboard.sessions.view";function _o(e){return e==="system"||e==="light"||e==="dark"?e:null}function Wo(e){return e==="board"||e==="table"?e:null}function Sn(e,n){return e==="system"?n?"dark":"light":e}function Tn(e){return _o(e?.getItem(qt))??"dark"}function Ln(e){return Wo(e?.getItem($n))??"board"}var In="botmux.dashboard.sessions.boardOrder",tt=["needs-you","starting","working","idle"];function Jo(e){if(!Array.isArray(e)||e.length!==tt.length)return null;let n=new Set(e);if(n.size!==e.length)return null;for(let o of tt)if(!n.has(o))return null;return e.slice()}function Mn(e){try{let n=e?.getItem(In);return n?Jo(JSON.parse(n))??[...tt]:[...tt]}catch{return[...tt]}}function Ut(e,n){try{e?.setItem(In,JSON.stringify(n))}catch{}}function xn(e,n){try{e?.setItem($n,n)}catch{}}var Ko=["default","cyber","genshin","fallout","prts","bluearchive","zzz","dragonball","ikun"],jt="botmux.dashboard.skin";function Vo(e){return typeof e=="string"&&Ko.includes(e)?e:null}function En(e){return Vo(e?.getItem(jt))??"default"}var Yo="\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF830123456789\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E$#%&@*+=<>/\\",Hn=["186 100% 60%","56 97% 60%","330 100% 64%","150 80% 58%"],Gt=[{key:"shake",dur:280},{key:"rgb",dur:340},{key:"tear",dur:400},{key:"invert",dur:220},{key:"slice",dur:320},{key:"blackout",dur:260}],Cn=["ESTABLISHING NETLINK","BYPASSING ICE","DECRYPTING DATAFLOW","SYNCING BOTMUX TELEMETRY","ACCESS GRANTED"],An="0123456789ABCDEF#<>*/=+\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C",Qo=3200,nt=[],Ke=0,wt=0;function Wt(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function zt(e,n){let o="";for(let s=0;s<e;s++)o+=n[Math.floor(Math.random()*n.length)];return o}function Xo(e){let n=document.createElement("div");n.className="cyber-rain";let o=Math.max(10,Math.min(26,Math.round(window.innerWidth/70)));for(let s=0;s<o;s++){let a=document.createElement("span");a.className="cyber-rain-col",a.textContent=zt(28+Math.floor(Math.random()*22),Yo);let r=Hn[Math.floor(Math.random()*Hn.length)];a.style.cssText=`left:${(s+.5)/o*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(a)}e.appendChild(n)}function Zo(){if(Wt())return;let e=document.body,n=()=>{let o=Gt[Math.floor(Math.random()*Gt.length)],s=`cp-fx-${o.key}`;e.classList.add(s),nt.push(window.setTimeout(()=>e.classList.remove(s),o.dur)),nt.push(window.setTimeout(n,2400+Math.random()*4200))};nt.push(window.setTimeout(n,1800+Math.random()*2600))}function ea(){nt.forEach(e=>window.clearTimeout(e)),nt=[];for(let e of Gt)document.body.classList.remove(`cp-fx-${e.key}`)}function ta(){if(Wt()||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"),o=e.querySelector(".cyber-loader-stream"),s=0,a=0,r=0;Ke=window.setInterval(()=>{let l=Cn[s];n&&(a<l.length?(a+=1,n.textContent=l.slice(0,a)+zt(l.length-a,An),n.classList.remove("done")):r<16?(r+=1,n.textContent=l,n.classList.add("done")):(s=(s+1)%Cn.length,a=0,r=0)),o&&(o.textContent=zt(26,An))},50),wt=window.setTimeout(()=>{window.clearInterval(Ke),Ke=0,e.remove()},Qo)}function na(){Ke&&(window.clearInterval(Ke),Ke=0),wt&&(window.clearTimeout(wt),wt=0),document.getElementById("cyber-boot")?.remove()}var oa=320,Dn=16,ot=!0,Je=0,Ft=0,yt=!1,vt=[],_t=[];function aa(){if(yt)return;yt=!0,ot=!1,Je=0;let e=Wt(),n="";for(let s=0;s<Dn;s++){let a=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/Dn*100}%;height:${2+s%4*3}%;--shift:${r}px;--delay:${s%8*.09}s;--dur:${(.36+s%5*.12).toFixed(2)}s;--hue:${a}"></span>`}let o=document.createElement("div");o.id="cyber-breach",o.className="cyber-breach",o.setAttribute("aria-hidden","true"),o.innerHTML=`<span class="cyber-breach-flash"></span><span class="cyber-breach-grid"></span><div class="cyber-breach-shards">${n}</div><div class="cyber-breach-banner"><span class="cyber-breach-tag">// BREACH PROTOCOL \u2014 SYSTEM OVERRIDE</span><span class="cyber-breach-caption" data-text="SYSTEM BREACH">SYSTEM BREACH</span><span class="cyber-breach-sub" data-text="NETWATCH OVERRIDE ENGAGED">NETWATCH OVERRIDE ENGAGED</span></div>`,document.body.appendChild(o),e||document.body.classList.add("cyber-breach-quake"),vt.push(window.setTimeout(()=>document.body.classList.remove("cyber-breach-quake"),760)),vt.push(window.setTimeout(()=>{o.remove(),yt=!1},e?2600:4200))}function sa(){ot=!0,Je=0;let e=document.documentElement,n=()=>e.scrollHeight-(window.innerHeight+window.scrollY)<=4,o=w=>{w<=0||!n()||(Je+=w,Je>oa&&ot&&aa())},s=w=>o(w.deltaY),a=w=>{Ft=w.touches[0]?.clientY??0},r=w=>{let h=w.touches[0]?.clientY??0,y=Ft-h;Ft=h,o(y)},l=()=>{n()||(Je=0,ot=!0)},c=(w,h)=>{window.addEventListener(w,h,{passive:!0}),_t.push([w,h])};c("wheel",s),c("touchstart",a),c("touchmove",r),c("scroll",l)}function ra(){for(let[e,n]of _t)window.removeEventListener(e,n);_t=[],vt.forEach(e=>window.clearTimeout(e)),vt=[],document.body.classList.remove("cyber-breach-quake"),document.getElementById("cyber-breach")?.remove(),yt=!1,ot=!0,Je=0}function Rn(e,n=!1){if(!(typeof document>"u")){if(!e){document.getElementById("cyber-fx")?.remove(),document.getElementById("cyber-hud")?.remove(),document.getElementById("cyber-glitch")?.remove(),ea(),na(),ra();return}if(!document.getElementById("cyber-fx")){let o=document.createElement("div");o.id="cyber-fx",o.className="cyber-fx",o.setAttribute("aria-hidden","true"),o.innerHTML='<div class="cyber-fx-grid"></div><div class="cyber-fx-scan"></div><span class="cyber-flicker"></span><span class="cyber-rollline"></span>',Xo(o),document.body.appendChild(o);let s=document.createElement("div");s.id="cyber-hud",s.className="cyber-hud",s.setAttribute("aria-hidden","true"),s.innerHTML='<span class="cyber-hud-corner tl"></span><span class="cyber-hud-corner tr"></span><span class="cyber-hud-corner bl"></span><span class="cyber-hud-corner br"></span><span class="cyber-hud-tag">NIGHT CITY // NETWATCH</span>',document.body.appendChild(s);let a=document.createElement("div");a.id="cyber-glitch",a.className="cyber-glitch",a.setAttribute("aria-hidden","true"),document.body.appendChild(a),Zo(),sa()}n&&ta()}}var ia={genshin:2e3,zzz:1900,dragonball:1900,ikun:1900},la='<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 da(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 la;default:return""}}function ca(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function On(e){if(typeof document>"u"||ca())return;let n=ia[e];if(!n)return;document.getElementById("skin-intro")?.remove();let o=document.createElement("div");o.id="skin-intro",o.className=`skin-intro si-${e}`,o.setAttribute("aria-hidden","true"),o.style.setProperty("--si-dur",`${n}ms`),o.innerHTML=da(e),document.body.appendChild(o),window.setTimeout(()=>o.remove(),n+80)}var Kt=class{locale="zh";themeMode="system";resolvedTheme="light";skin="default";listeners=new Set;translate=ht(this.locale);mediaQuery=null;init(){let n=typeof window<"u"?window:void 0;this.locale=kn(n?.localStorage,pa()),this.translate=ht(this.locale),this.themeMode=Tn(n?.localStorage),this.skin=En(n?.localStorage),this.mediaQuery=n?.matchMedia?.("(prefers-color-scheme: dark)")??null,this.mediaQuery?.addEventListener("change",()=>{this.applyTheme(),this.emit()}),this.applyTheme(),this.applySkin(),this.applyLocale()}t(n,o){return this.translate(n,o)}setLocale(n){this.locale!==n&&(this.locale=n,this.translate=ht(n),window.localStorage.setItem(Pt,n),this.applyLocale(),this.emit())}get theme(){return this.skin==="default"?this.themeMode:this.skin}setTheme(n){let o=n==="system"||n==="light"||n==="dark",s=o?"default":n,a=s!==this.skin;o&&this.themeMode!==n&&(this.themeMode=n,window.localStorage.setItem(qt,this.themeMode)),a&&(this.skin=s,window.localStorage.setItem(jt,this.skin)),this.applyTheme(),this.applySkin(a),this.emit()}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}applyTheme(){this.resolvedTheme=Sn(this.themeMode,!!this.mediaQuery?.matches);let n=this.skin==="default"?this.resolvedTheme:ua[this.skin];document.documentElement.dataset.theme=n,document.documentElement.dataset.themeMode=this.themeMode}applySkin(n=!1){document.documentElement.dataset.skin=this.skin,Rn(this.skin==="cyber",n),n&&this.skin!=="cyber"&&this.skin!=="default"&&On(this.skin)}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}},ua={default:"light",cyber:"dark",genshin:"light",fallout:"dark",prts:"dark",bluearchive:"dark",zzz:"dark",dragonball:"light",ikun:"dark"};function pa(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var Te=new Kt;function t(e,n){return Te.t(e,n)}function i(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function Le(e){if(!e)return"-";let n=Date.now()-e;return n<6e4?t("common.now"):n<36e5?Math.floor(n/6e4)+"m":n<864e5?Math.floor(n/36e5)+"h":Math.floor(n/864e5)+"d"}var Bn=[{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 Nn(e){let n=0,o=String(e??"");for(let r=0;r<o.length;r++)n=n*31+o.charCodeAt(r)>>>0;let{c1:s,c2:a}=Bn[n%Bn.length];return`--c1:${s};--c2:${a}`}var kt=new Map,$t=new Map;function ma(e,n){return n?kt.get(n):e?$t.get(String(e)):void 0}function he(e){let n=e.name??"",o=e.avatarUrl??ma(e.name,e.larkAppId),s=e.size==="sm"?" orb-avatar-sm":"",a=o?" orb-has-img":"",r=e.dot?`<i class="orb-dot orb-dot-${e.dot}"></i>`:"",l=o?`<img class="orb-img" src="${i(o)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar${s}${a}" style="${Nn(n)}" aria-hidden="true">${l}${r}</span>`}function fa(e){return e?St.get(e):void 0}function Pn(e){let n=e.name??e.chatId??"",o=e.avatarUrl??fa(e.chatId),s=e.size==="sm"?" orb-avatar-sm":"",a=o?" orb-has-img":"",r=o?`<img class="orb-img" src="${i(o)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar orb-square${s}${a}" style="${Nn(n)}" aria-hidden="true">${r}</span>`}var qn=new Map,Un=new Map,St=new Map,Jt=null,jn="botmux.avatarCache.v1";function ga(){try{let e=typeof window<"u"?window.localStorage.getItem(jn):null;if(!e)return;let n=JSON.parse(e);for(let[o,s]of Object.entries(n.botByAppId??{}))kt.set(o,s);for(let[o,s]of Object.entries(n.botByName??{}))$t.set(o,s);for(let[o,s]of Object.entries(n.chatById??{}))St.set(o,s)}catch{}}function ba(){try{if(typeof window>"u")return;window.localStorage.setItem(jn,JSON.stringify({botByAppId:Object.fromEntries(kt),botByName:Object.fromEntries($t),chatById:Object.fromEntries(St)}))}catch{}}ga();function Ee(){return Jt??=(async()=>{try{let e=await fetch("/api/groups");if(!e.ok)throw new Error(`HTTP ${e.status}`);let n=await e.json();for(let o of n.bots??[])o.larkAppId&&o.botName&&o.botName!==o.larkAppId&&qn.set(o.larkAppId,String(o.botName)),o.botAvatarUrl&&(o.larkAppId&&kt.set(o.larkAppId,String(o.botAvatarUrl)),o.botName&&$t.set(String(o.botName),String(o.botAvatarUrl)));for(let o of n.chats??[])o.chatId&&o.name&&Un.set(o.chatId,String(o.name)),o.chatId&&o.avatar&&St.set(o.chatId,String(o.avatar));ba()}catch{Jt=null}})(),Jt}function He(e){let n=e.larkAppId?qn.get(e.larkAppId):void 0;return n||(e.botName&&e.botName!==e.larkAppId?String(e.botName):String(e.botName??e.larkAppId??"-"))}function Ve(e){return e.chatId&&Un.get(e.chatId)||null}function Re(e){let n=String(e??"");return n.replace(/^(?:@\S+\s*)+/,"").trim()||n}function Ne(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 de(e){let n=Number(e.agentAttention?.at??e.lastMessageAt??0);if(Number.isFinite(n))return n;let o=Number(e.lastMessageAt??0);return Number.isFinite(o)?o:0}var Fn={chats:[],bots:[]};async function ha(){try{let e=await fetch("/api/groups");if(!e.ok)return;Fn=await e.json()}catch{}}var Vt=new Set(["working","analyzing","active","starting"]);function wa(e){let n=new Map,o=a=>{let r=n.get(a);return r||(r={botName:a,larkAppId:a,cliId:"unknown",online:!1,sessions:[],active:[],busy:[],attention:[],lastActiveAt:0},n.set(a,r)),r};for(let a of Fn.bots??[]){let r=o(a.larkAppId??a.botName??"-");r.online=!0,a.botName&&(r.botName=a.botName),a.botAvatarUrl&&(r.botAvatarUrl=a.botAvatarUrl)}let s=[...e].sort((a,r)=>+(a.status==="closed")-+(r.status==="closed"));for(let a of s){let r=a.larkAppId??a.botName??"-";if(a.status==="closed"&&!n.has(r))continue;let l=o(r);a.botName&&(l.botName===l.larkAppId||!l.botName)&&(l.botName=a.botName),l.sessions.push(a),a.cliId&&l.cliId==="unknown"&&(l.cliId=a.cliId),l.lastActiveAt=Math.max(l.lastActiveAt,Number(a.lastMessageAt??0)),a.status!=="closed"&&(l.active.push(a),Vt.has(a.status)&&l.busy.push(a),Ne(a)&&l.attention.push(a))}return[...n.values()].sort((a,r)=>{let l=c=>c.attention.length?0:c.busy.length?1:c.online||c.active.length?2:3;return l(a)!==l(r)?l(a)-l(r):r.lastActiveAt-a.lastActiveAt})}function ya(e){let n=!e.online&&e.active.length===0,o=e.attention.length>0,s=e.busy.length>0,a=o?"warn":s?"busy":n?"off":"ok",r;if(o){let c=[...e.attention].sort((w,h)=>de(w)-de(h))[0];r=`<b>${i((Re(c.title)||c.sessionId).slice(0,60))}</b> \xB7 ${i(Ne(c)??"")}`}else if(s){let c=[...e.busy].sort((w,h)=>Number(h.lastMessageAt??0)-Number(w.lastMessageAt??0))[0];r=`<b>${i((Re(c.title)||c.sessionId).slice(0,60))}</b>`}else n?r=i(t("overview.botOffline")):r=i(t("overview.botIdle"));let l=o?`<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${o?" mate-attn":""}${n?" mate-off":""}">
|
|
13
|
+
}`,"catalog.chatId":"Chat ID","catalog.larkAppId":"Lark app ID","catalog.chatBindingHint":"Required so humanGate cards and cancel routing know which Lark chat owns the run.","catalog.run":"Run","catalog.running":"Starting...","catalog.badParamsJson":"Params must be a JSON object.","catalog.writeAccess":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and run again.","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"Run started; opening detail page...","catalog.invalidParams":"Invalid params","catalog.issue":"{path}: {message}","catalog.noParams":"No params declared.","catalog.required":"required","catalog.optional":"optional","catalog.default":"default","catalog.description":"description","catalog.path":"path","catalog.revision":"revision","catalog.nodeCount":"nodes"},$n={zh:Wo,en:Jo};function ht(e){if(typeof e!="string")return null;let n=e.trim().toLowerCase();return n==="zh"||n.startsWith("zh-")?"zh":n==="en"||n.startsWith("en-")?"en":null}function Ko(e=[]){for(let n of e){let o=ht(n);if(o)return o}return"zh"}function wt(e){return(n,o)=>{let s=$n[e][n]??$n.zh[n]??n;return o?s.replace(/\{(\w+)\}/g,(a,i)=>{let l=o[i];return l==null?`{${i}}`:String(l)}):s}}function Sn(e,n){return(e?ht(e.getItem(qt)):null)??Ko(n)}var Ut="botmux.dashboard.theme",Tn="botmux.dashboard.sessions.view";function Vo(e){return e==="system"||e==="light"||e==="dark"?e:null}function Yo(e){return e==="board"||e==="table"?e:null}function Ln(e,n){return e==="system"?n?"dark":"light":e}function In(e){return Vo(e?.getItem(Ut))??"dark"}function Mn(e){return Yo(e?.getItem(Tn))??"board"}var xn="botmux.dashboard.sessions.boardOrder",ot=["needs-you","starting","working","idle"];function Qo(e){if(!Array.isArray(e)||e.length!==ot.length)return null;let n=new Set(e);if(n.size!==e.length)return null;for(let o of ot)if(!n.has(o))return null;return e.slice()}function En(e){try{let n=e?.getItem(xn);return n?Qo(JSON.parse(n))??[...ot]:[...ot]}catch{return[...ot]}}function jt(e,n){try{e?.setItem(xn,JSON.stringify(n))}catch{}}function Hn(e,n){try{e?.setItem(Tn,n)}catch{}}var Xo=["default","cyber","genshin","fallout","prts","bluearchive","zzz","dragonball","ikun"],Ft="botmux.dashboard.skin";function Zo(e){return typeof e=="string"&&Xo.includes(e)?e:null}function Cn(e){return Zo(e?.getItem(Ft))??"default"}var ea="\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF830123456789\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E$#%&@*+=<>/\\",An=["186 100% 60%","56 97% 60%","330 100% 64%","150 80% 58%"],zt=[{key:"shake",dur:280},{key:"rgb",dur:340},{key:"tear",dur:400},{key:"invert",dur:220},{key:"slice",dur:320},{key:"blackout",dur:260}],Dn=["ESTABLISHING NETLINK","BYPASSING ICE","DECRYPTING DATAFLOW","SYNCING BOTMUX TELEMETRY","ACCESS GRANTED"],Rn="0123456789ABCDEF#<>*/=+\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C",ta=3200,at=[],Ke=0,yt=0;function Jt(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function _t(e,n){let o="";for(let s=0;s<e;s++)o+=n[Math.floor(Math.random()*n.length)];return o}function na(e){let n=document.createElement("div");n.className="cyber-rain";let o=Math.max(10,Math.min(26,Math.round(window.innerWidth/70)));for(let s=0;s<o;s++){let a=document.createElement("span");a.className="cyber-rain-col",a.textContent=_t(28+Math.floor(Math.random()*22),ea);let i=An[Math.floor(Math.random()*An.length)];a.style.cssText=`left:${(s+.5)/o*100}%;--rc:${i};--sz:${10+Math.floor(Math.random()*9)}px;--op:${(.25+Math.random()*.45).toFixed(2)};--dur:${(6+Math.random()*9).toFixed(1)}s;--delay:${(-Math.random()*12).toFixed(1)}s;`,n.appendChild(a)}e.appendChild(n)}function oa(){if(Jt())return;let e=document.body,n=()=>{let o=zt[Math.floor(Math.random()*zt.length)],s=`cp-fx-${o.key}`;e.classList.add(s),at.push(window.setTimeout(()=>e.classList.remove(s),o.dur)),at.push(window.setTimeout(n,2400+Math.random()*4200))};at.push(window.setTimeout(n,1800+Math.random()*2600))}function aa(){at.forEach(e=>window.clearTimeout(e)),at=[];for(let e of zt)document.body.classList.remove(`cp-fx-${e.key}`)}function sa(){if(Jt()||document.getElementById("cyber-boot"))return;let e=document.createElement("div");e.id="cyber-boot",e.className="cyber-boot",e.setAttribute("aria-hidden","true"),e.innerHTML='<div class="cyber-boot-grid"></div><div class="cyber-loader"><div class="cyber-loader-frame"><div class="cyber-loader-head"><span>KIROSHI NETLINK</span><span class="cyber-loader-jp">\u4FB5\u5165\u4E2D</span></div><div class="cyber-loader-line"><span class="cyber-loader-prompt">></span><span class="cyber-loader-text"></span><span class="cyber-loader-cursor">_</span></div><div class="cyber-loader-stream"></div></div></div>',document.body.appendChild(e);let n=e.querySelector(".cyber-loader-text"),o=e.querySelector(".cyber-loader-stream"),s=0,a=0,i=0;Ke=window.setInterval(()=>{let l=Dn[s];n&&(a<l.length?(a+=1,n.textContent=l.slice(0,a)+_t(l.length-a,Rn),n.classList.remove("done")):i<16?(i+=1,n.textContent=l,n.classList.add("done")):(s=(s+1)%Dn.length,a=0,i=0)),o&&(o.textContent=_t(26,Rn))},50),yt=window.setTimeout(()=>{window.clearInterval(Ke),Ke=0,e.remove()},ta)}function ia(){Ke&&(window.clearInterval(Ke),Ke=0),yt&&(window.clearTimeout(yt),yt=0),document.getElementById("cyber-boot")?.remove()}var ra=320,On=16,st=!0,Je=0,Gt=0,vt=!1,kt=[],Wt=[];function la(){if(vt)return;vt=!0,st=!1,Je=0;let e=Jt(),n="";for(let s=0;s<On;s++){let a=s%3===0?"186 100% 52%":s%3===1?"330 100% 58%":"56 97% 52%",i=(s%2===0?1:-1)*(8+s%5*7);n+=`<span class="cyber-breach-shard" style="top:${s/On*100}%;height:${2+s%4*3}%;--shift:${i}px;--delay:${s%8*.09}s;--dur:${(.36+s%5*.12).toFixed(2)}s;--hue:${a}"></span>`}let o=document.createElement("div");o.id="cyber-breach",o.className="cyber-breach",o.setAttribute("aria-hidden","true"),o.innerHTML=`<span class="cyber-breach-flash"></span><span class="cyber-breach-grid"></span><div class="cyber-breach-shards">${n}</div><div class="cyber-breach-banner"><span class="cyber-breach-tag">// BREACH PROTOCOL \u2014 SYSTEM OVERRIDE</span><span class="cyber-breach-caption" data-text="SYSTEM BREACH">SYSTEM BREACH</span><span class="cyber-breach-sub" data-text="NETWATCH OVERRIDE ENGAGED">NETWATCH OVERRIDE ENGAGED</span></div>`,document.body.appendChild(o),e||document.body.classList.add("cyber-breach-quake"),kt.push(window.setTimeout(()=>document.body.classList.remove("cyber-breach-quake"),760)),kt.push(window.setTimeout(()=>{o.remove(),vt=!1},e?2600:4200))}function da(){st=!0,Je=0;let e=document.documentElement,n=()=>e.scrollHeight-(window.innerHeight+window.scrollY)<=4,o=w=>{w<=0||!n()||(Je+=w,Je>ra&&st&&la())},s=w=>o(w.deltaY),a=w=>{Gt=w.touches[0]?.clientY??0},i=w=>{let h=w.touches[0]?.clientY??0,y=Gt-h;Gt=h,o(y)},l=()=>{n()||(Je=0,st=!0)},c=(w,h)=>{window.addEventListener(w,h,{passive:!0}),Wt.push([w,h])};c("wheel",s),c("touchstart",a),c("touchmove",i),c("scroll",l)}function ca(){for(let[e,n]of Wt)window.removeEventListener(e,n);Wt=[],kt.forEach(e=>window.clearTimeout(e)),kt=[],document.body.classList.remove("cyber-breach-quake"),document.getElementById("cyber-breach")?.remove(),vt=!1,st=!0,Je=0}function Bn(e,n=!1){if(!(typeof document>"u")){if(!e){document.getElementById("cyber-fx")?.remove(),document.getElementById("cyber-hud")?.remove(),document.getElementById("cyber-glitch")?.remove(),aa(),ia(),ca();return}if(!document.getElementById("cyber-fx")){let o=document.createElement("div");o.id="cyber-fx",o.className="cyber-fx",o.setAttribute("aria-hidden","true"),o.innerHTML='<div class="cyber-fx-grid"></div><div class="cyber-fx-scan"></div><span class="cyber-flicker"></span><span class="cyber-rollline"></span>',na(o),document.body.appendChild(o);let s=document.createElement("div");s.id="cyber-hud",s.className="cyber-hud",s.setAttribute("aria-hidden","true"),s.innerHTML='<span class="cyber-hud-corner tl"></span><span class="cyber-hud-corner tr"></span><span class="cyber-hud-corner bl"></span><span class="cyber-hud-corner br"></span><span class="cyber-hud-tag">NIGHT CITY // NETWATCH</span>',document.body.appendChild(s);let a=document.createElement("div");a.id="cyber-glitch",a.className="cyber-glitch",a.setAttribute("aria-hidden","true"),document.body.appendChild(a),oa(),da()}n&&sa()}}var ua={genshin:2e3,zzz:1900,dragonball:1900,ikun:1900},pa='<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 ma(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 pa;default:return""}}function fa(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Nn(e){if(typeof document>"u"||fa())return;let n=ua[e];if(!n)return;document.getElementById("skin-intro")?.remove();let o=document.createElement("div");o.id="skin-intro",o.className=`skin-intro si-${e}`,o.setAttribute("aria-hidden","true"),o.style.setProperty("--si-dur",`${n}ms`),o.innerHTML=ma(e),document.body.appendChild(o),window.setTimeout(()=>o.remove(),n+80)}var Vt=class{locale="zh";themeMode="system";resolvedTheme="light";skin="default";authed=!0;listeners=new Set;translate=wt(this.locale);mediaQuery=null;init(){let n=typeof window<"u"?window:void 0;this.locale=Sn(n?.localStorage,ba()),this.translate=wt(this.locale),this.themeMode=In(n?.localStorage),this.skin=Cn(n?.localStorage),this.mediaQuery=n?.matchMedia?.("(prefers-color-scheme: dark)")??null,this.mediaQuery?.addEventListener("change",()=>{this.applyTheme(),this.emit()}),this.applyTheme(),this.applySkin(),this.applyLocale()}t(n,o){return this.translate(n,o)}setLocale(n){this.locale!==n&&(this.locale=n,this.translate=wt(n),window.localStorage.setItem(qt,n),this.applyLocale(),this.emit())}get theme(){return this.skin==="default"?this.themeMode:this.skin}setTheme(n){let o=n==="system"||n==="light"||n==="dark",s=o?"default":n,a=s!==this.skin;o&&this.themeMode!==n&&(this.themeMode=n,window.localStorage.setItem(Ut,this.themeMode)),a&&(this.skin=s,window.localStorage.setItem(Ft,this.skin)),this.applyTheme(),this.applySkin(a),this.emit()}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}applyTheme(){this.resolvedTheme=Ln(this.themeMode,!!this.mediaQuery?.matches);let n=this.skin==="default"?this.resolvedTheme:ga[this.skin];document.documentElement.dataset.theme=n,document.documentElement.dataset.themeMode=this.themeMode}applySkin(n=!1){document.documentElement.dataset.skin=this.skin,Bn(this.skin==="cyber",n),n&&this.skin!=="cyber"&&this.skin!=="default"&&Nn(this.skin)}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}},ga={default:"light",cyber:"dark",genshin:"light",fallout:"dark",prts:"dark",bluearchive:"dark",zzz:"dark",dragonball:"light",ikun:"dark"};function ba(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var ce=new Vt;function t(e,n){return ce.t(e,n)}function r(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function Le(e){if(!e)return"-";let n=Date.now()-e;return n<6e4?t("common.now"):n<36e5?Math.floor(n/6e4)+"m":n<864e5?Math.floor(n/36e5)+"h":Math.floor(n/864e5)+"d"}var Pn=[{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 qn(e){let n=0,o=String(e??"");for(let i=0;i<o.length;i++)n=n*31+o.charCodeAt(i)>>>0;let{c1:s,c2:a}=Pn[n%Pn.length];return`--c1:${s};--c2:${a}`}var $t=new Map,St=new Map;function ha(e,n){return n?$t.get(n):e?St.get(String(e)):void 0}function ye(e){let n=e.name??"",o=e.avatarUrl??ha(e.name,e.larkAppId),s=e.size==="sm"?" orb-avatar-sm":"",a=o?" orb-has-img":"",i=e.dot?`<i class="orb-dot orb-dot-${e.dot}"></i>`:"",l=o?`<img class="orb-img" src="${r(o)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar${s}${a}" style="${qn(n)}" aria-hidden="true">${l}${i}</span>`}function wa(e){return e?Tt.get(e):void 0}function Un(e){let n=e.name??e.chatId??"",o=e.avatarUrl??wa(e.chatId),s=e.size==="sm"?" orb-avatar-sm":"",a=o?" orb-has-img":"",i=o?`<img class="orb-img" src="${r(o)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar orb-square${s}${a}" style="${qn(n)}" aria-hidden="true">${i}</span>`}var jn=new Map,Fn=new Map,Tt=new Map,Kt=null,Gn="botmux.avatarCache.v1";function ya(){try{let e=typeof window<"u"?window.localStorage.getItem(Gn):null;if(!e)return;let n=JSON.parse(e);for(let[o,s]of Object.entries(n.botByAppId??{}))$t.set(o,s);for(let[o,s]of Object.entries(n.botByName??{}))St.set(o,s);for(let[o,s]of Object.entries(n.chatById??{}))Tt.set(o,s)}catch{}}function va(){try{if(typeof window>"u")return;window.localStorage.setItem(Gn,JSON.stringify({botByAppId:Object.fromEntries($t),botByName:Object.fromEntries(St),chatById:Object.fromEntries(Tt)}))}catch{}}ya();function Ee(){return Kt??=(async()=>{try{let e=await fetch("/api/groups");if(!e.ok)throw new Error(`HTTP ${e.status}`);let n=await e.json();for(let o of n.bots??[])o.larkAppId&&o.botName&&o.botName!==o.larkAppId&&jn.set(o.larkAppId,String(o.botName)),o.botAvatarUrl&&(o.larkAppId&&$t.set(o.larkAppId,String(o.botAvatarUrl)),o.botName&&St.set(String(o.botName),String(o.botAvatarUrl)));for(let o of n.chats??[])o.chatId&&o.name&&Fn.set(o.chatId,String(o.name)),o.chatId&&o.avatar&&Tt.set(o.chatId,String(o.avatar));va()}catch{Kt=null}})(),Kt}function He(e){let n=e.larkAppId?jn.get(e.larkAppId):void 0;return n||(e.botName&&e.botName!==e.larkAppId?String(e.botName):String(e.botName??e.larkAppId??"-"))}function Ve(e){return e.chatId&&Fn.get(e.chatId)||null}function Re(e){let n=String(e??"");return n.replace(/^(?:@\S+\s*)+/,"").trim()||n}function Ne(e){return e.status==="closed"?null:e.agentAttention?.reason?e.agentAttention.reason:e.agentAttention?t("sessions.board.signalAgent"):e.pendingRepo?t("sessions.board.signalRepo"):e.tuiPromptActive?t("sessions.board.signalPrompt"):e.status==="limited"?t("sessions.board.signalLimited"):null}function ue(e){let n=Number(e.agentAttention?.at??e.lastMessageAt??0);if(Number.isFinite(n))return n;let o=Number(e.lastMessageAt??0);return Number.isFinite(o)?o:0}var zn={chats:[],bots:[]};async function ka(){try{let e=await fetch("/api/groups");if(!e.ok)return;zn=await e.json()}catch{}}var Yt=new Set(["working","analyzing","active","starting"]);function $a(e){let n=new Map,o=a=>{let i=n.get(a);return i||(i={botName:a,larkAppId:a,cliId:"unknown",online:!1,sessions:[],active:[],busy:[],attention:[],lastActiveAt:0},n.set(a,i)),i};for(let a of zn.bots??[]){let i=o(a.larkAppId??a.botName??"-");i.online=!0,a.botName&&(i.botName=a.botName),a.botAvatarUrl&&(i.botAvatarUrl=a.botAvatarUrl)}let s=[...e].sort((a,i)=>+(a.status==="closed")-+(i.status==="closed"));for(let a of s){let i=a.larkAppId??a.botName??"-";if(a.status==="closed"&&!n.has(i))continue;let l=o(i);a.botName&&(l.botName===l.larkAppId||!l.botName)&&(l.botName=a.botName),l.sessions.push(a),a.cliId&&l.cliId==="unknown"&&(l.cliId=a.cliId),l.lastActiveAt=Math.max(l.lastActiveAt,Number(a.lastMessageAt??0)),a.status!=="closed"&&(l.active.push(a),Yt.has(a.status)&&l.busy.push(a),Ne(a)&&l.attention.push(a))}return[...n.values()].sort((a,i)=>{let l=c=>c.attention.length?0:c.busy.length?1:c.online||c.active.length?2:3;return l(a)!==l(i)?l(a)-l(i):i.lastActiveAt-a.lastActiveAt})}function Sa(e){let n=!e.online&&e.active.length===0,o=e.attention.length>0,s=e.busy.length>0,a=o?"warn":s?"busy":n?"off":"ok",i;if(o){let c=[...e.attention].sort((w,h)=>ue(w)-ue(h))[0];i=`<b>${r((Re(c.title)||c.sessionId).slice(0,60))}</b> \xB7 ${r(Ne(c)??"")}`}else if(s){let c=[...e.busy].sort((w,h)=>Number(h.lastMessageAt??0)-Number(w.lastMessageAt??0))[0];i=`<b>${r((Re(c.title)||c.sessionId).slice(0,60))}</b>`}else n?i=r(t("overview.botOffline")):i=r(t("overview.botIdle"));let l=o?`<span class="tag tag-warn">${r(t("overview.botNeedsYou"))}</span>`:s?`<span class="tag tag-run">${r(t("overview.botBusy",{count:e.busy.length}))}</span>`:n?`<span class="tag tag-off">${r(t("overview.botOff"))}</span>`:`<span class="tag tag-ok">${r(t("overview.botReady"))}</span>`;return`<article class="mate${o?" mate-attn":""}${n?" mate-off":""}">
|
|
14
14
|
<div class="mate-top">
|
|
15
|
-
${
|
|
15
|
+
${ye({name:e.botName,larkAppId:e.larkAppId,avatarUrl:e.botAvatarUrl,dot:a})}
|
|
16
16
|
<div class="mate-id">
|
|
17
|
-
<b>${
|
|
18
|
-
<span class="mate-role">${
|
|
17
|
+
<b>${r(e.botName)}</b>
|
|
18
|
+
<span class="mate-role">${r(e.cliId)}</span>
|
|
19
19
|
</div>
|
|
20
20
|
</div>
|
|
21
|
-
<div class="mate-task">${
|
|
21
|
+
<div class="mate-task">${i}</div>
|
|
22
22
|
<div class="mate-foot">
|
|
23
23
|
${l}
|
|
24
|
-
<span>${e.lastActiveAt?
|
|
24
|
+
<span>${e.lastActiveAt?r(t("overview.lastActive",{time:Le(e.lastActiveAt)})):r(t("common.never"))}</span>
|
|
25
25
|
</div>
|
|
26
|
-
</article>`}function
|
|
27
|
-
${
|
|
26
|
+
</article>`}function Ta(e){let n=He(e);return`<article class="qcard" data-id="${r(e.sessionId)}">
|
|
27
|
+
${ye({name:n,larkAppId:e.larkAppId,size:"sm"})}
|
|
28
28
|
<div class="qcard-tx">
|
|
29
|
-
<b>${
|
|
30
|
-
<span>${
|
|
29
|
+
<b>${r(n)} \xB7 ${r((Re(e.title)||e.sessionId).slice(0,56))}</b>
|
|
30
|
+
<span>${r(Ne(e)??"")} \xB7 ${Le(ue(e))}</span>
|
|
31
31
|
</div>
|
|
32
|
-
<a class="qcard-go" href="#/sessions">${
|
|
33
|
-
</article>`}function
|
|
34
|
-
${
|
|
32
|
+
<a class="qcard-go" href="#/sessions">${r(t("strip.handle"))}</a>
|
|
33
|
+
</article>`}function La(e){let n=He(e);return`<li class="sess-row">
|
|
34
|
+
${ye({name:n,larkAppId:e.larkAppId,size:"sm"})}
|
|
35
35
|
<div class="sess-tx">
|
|
36
|
-
<b>${
|
|
37
|
-
<span>${
|
|
36
|
+
<b>${r((Re(e.title)||e.sessionId).slice(0,64))}</b>
|
|
37
|
+
<span>${r(n)} \xB7 ${r(Ve(e)??e.cliId??"unknown")} \xB7 ${Le(e.lastMessageAt)}</span>
|
|
38
38
|
</div>
|
|
39
|
-
<span class="status status-${
|
|
40
|
-
</li>`}function
|
|
39
|
+
<span class="status status-${r(e.status??"unknown")}">${r(e.status??"unknown")}</span>
|
|
40
|
+
</li>`}function Ia(e){let n=e.nextRunAt?new Date(e.nextRunAt).toLocaleString():"-";return`<li class="overview-list-row">
|
|
41
41
|
<div>
|
|
42
|
-
<strong>${
|
|
43
|
-
<span>${
|
|
42
|
+
<strong>${r(e.name??e.id)}</strong>
|
|
43
|
+
<span>${r(He(e))} \xB7 ${r(e.parsed?.display??"")}</span>
|
|
44
44
|
</div>
|
|
45
|
-
<span>${
|
|
46
|
-
</li>`}function
|
|
47
|
-
<div class="donut-center"><b>0</b><span>${
|
|
48
|
-
<div class="donut" style="background:conic-gradient(var(--accent) 0 ${a}deg, var(--warning) ${a}deg ${
|
|
49
|
-
<div class="donut-center"><b>${s}</b><span>${
|
|
50
|
-
</div>`}async function
|
|
45
|
+
<span>${r(n)}</span>
|
|
46
|
+
</li>`}function Ma(e,n,o){let s=e+n+o;if(s===0)return`<div class="donut-wrap"><div class="donut" style="background:conic-gradient(var(--border) 0 360deg)"></div>
|
|
47
|
+
<div class="donut-center"><b>0</b><span>${r(t("overview.openSessions"))}</span></div></div>`;let a=e/s*360,i=a+n/s*360;return`<div class="donut-wrap">
|
|
48
|
+
<div class="donut" style="background:conic-gradient(var(--accent) 0 ${a}deg, var(--warning) ${a}deg ${i}deg, var(--success) ${i}deg 360deg)"></div>
|
|
49
|
+
<div class="donut-center"><b>${s}</b><span>${r(t("overview.openSessions"))}</span></div>
|
|
50
|
+
</div>`}async function _n(e){e.innerHTML=`<section class="page hero-page">
|
|
51
51
|
<div class="page-heading">
|
|
52
52
|
<div>
|
|
53
53
|
<p class="eyebrow">${t("app.subtitle")}</p>
|
|
@@ -101,25 +101,25 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
101
101
|
</section>
|
|
102
102
|
</div>
|
|
103
103
|
</div>
|
|
104
|
-
</section>`;let n=e.querySelector("#overview-pills"),o=e.querySelector("#team-grid"),s=e.querySelector("#attention-list"),a=e.querySelector("#recent-sessions"),
|
|
105
|
-
<span class="pill">${
|
|
106
|
-
<span class="pill${y.length?" pill-hot":""}">${
|
|
107
|
-
<span class="pill">${
|
|
104
|
+
</section>`;let n=e.querySelector("#overview-pills"),o=e.querySelector("#team-grid"),s=e.querySelector("#attention-list"),a=e.querySelector("#recent-sessions"),i=e.querySelector("#today-donut"),l=e.querySelector("#next-schedules");function c(){let w=[...Q.sessions.values()],h=w.filter(v=>v.status!=="closed"),y=h.filter(v=>Ne(v)).sort((v,d)=>ue(v)-ue(d)),k=h.filter(v=>Yt.has(v.status)&&!Ne(v)),p=h.length-y.length-k.length,E=$a(w),O=E.filter(v=>v.online||v.active.length>0).length;n.innerHTML=`
|
|
105
|
+
<span class="pill">${r(t("overview.workingSessions"))} <b>${k.length}</b></span>
|
|
106
|
+
<span class="pill${y.length?" pill-hot":""}">${r(t("overview.attention"))} <b>${y.length}</b></span>
|
|
107
|
+
<span class="pill">${r(t("overview.onlineBots"))} <b>${O}</b></span>`,o.innerHTML=E.length?E.map(Sa).join(""):`<div class="empty">${t("overview.noSessions")}</div>`,s.innerHTML=y.length?y.map(Ta).join(""):`<div class="qcard qcard-empty">${t("overview.noAttention")}</div>`;let T=h.filter(v=>Yt.has(v.status)||v.status==="idle").sort((v,d)=>Number(d.lastMessageAt??0)-Number(v.lastMessageAt??0)).slice(0,7);a.innerHTML=T.length?T.map(La).join(""):`<li class="empty">${t("overview.noSessions")}</li>`,i.innerHTML=`${Ma(k.length,y.length,Math.max(0,p))}
|
|
108
108
|
<div class="donut-legend">
|
|
109
|
-
<span><i style="background:var(--accent)"></i>${
|
|
110
|
-
<span><i style="background:var(--warning)"></i>${
|
|
111
|
-
<span><i style="background:var(--success)"></i>${
|
|
112
|
-
</div>`;let f=[...
|
|
109
|
+
<span><i style="background:var(--accent)"></i>${r(t("overview.workingSessions"))} ${k.length}</span>
|
|
110
|
+
<span><i style="background:var(--warning)"></i>${r(t("overview.attention"))} ${y.length}</span>
|
|
111
|
+
<span><i style="background:var(--success)"></i>${r(t("sessions.board.idle"))} ${Math.max(0,p)}</span>
|
|
112
|
+
</div>`;let f=[...Q.schedules.values()].filter(v=>v.nextRunAt).sort((v,d)=>Date.parse(v.nextRunAt)-Date.parse(d.nextRunAt)).slice(0,5);l.innerHTML=f.length?f.map(Ia).join(""):`<li class="empty">${t("overview.noSchedules")}</li>`}Q.on(c),c(),ka().then(c),Ee().then(c)}function Pe(e,n){return`<th data-sort="${e}" data-label="${r(n)}">${r(n)}</th>`}var Yn=["claude-code","seed","codex","codex-app","cursor","gemini","opencode","mtr","hermes","mira","pi","copilot","aiden","coco","oh-my-pi","unknown"],Wn=[{id:"needs-you",labelKey:"sessions.board.needsYou",hintKey:"sessions.board.needsYouHint"},{id:"starting",labelKey:"sessions.board.starting",hintKey:"sessions.board.startingHint"},{id:"working",labelKey:"sessions.board.working",hintKey:"sessions.board.workingHint"},{id:"idle",labelKey:"sessions.board.idle",hintKey:"sessions.board.idleHint"}];function xa(e){return String(e??"unknown").toLowerCase().replace(/[^a-z0-9_-]/g,"-")}function Ea(e){let n=String(e??"").trim();return n?n.replace(/\\/g,"/").split("/").filter(Boolean).at(-1)??n:"-"}function Jn(e){if(!e.webPort)return null;let n=e.proxyPort??e.webPort,o=e.proxyPort?`/s/${encodeURIComponent(e.sessionId)}`:"";return`http://${location.hostname}:${n}${o}`}var Ye={pin:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M8 14.3s4.2-3.9 4.2-7.3A4.2 4.2 0 0 0 8 2.9a4.2 4.2 0 0 0-4.2 4.1C3.8 10.4 8 14.3 8 14.3z"/><circle cx="8" cy="6.9" r="1.5"/></svg>',openChat:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M9.4 2.8h3.8v3.8"/><path d="M13.2 2.8 7.3 8.7"/><path d="M11.5 9.3v2.9a1.2 1.2 0 0 1-1.2 1.2H3.8a1.2 1.2 0 0 1-1.2-1.2V5.7a1.2 1.2 0 0 1 1.2-1.2h2.9"/></svg>',details:'<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="2.2" y="2.9" width="11.6" height="10.2" rx="1.8"/><path d="M9.9 2.9v10.2"/></svg>',terminal:'<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="1.7" y="2.7" width="12.6" height="10.6" rx="2"/><path d="M4.4 6.3 6.4 8.1 4.4 9.9"/><path d="M8.2 10.2h3.4"/></svg>',key:'<svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="6" cy="6.1" r="3"/><path d="M8.1 8.2 13 13.1"/><path d="M11.3 11.4 12.6 10.1"/><path d="M12.7 12.8 13.7 11.8"/></svg>',close:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M4.2 4.2 11.8 11.8"/><path d="M11.8 4.2 4.2 11.8"/></svg>'};function Qt(e,n,o,s=""){return`<button type="button" class="card-act${s?" "+s:""}" data-action="${e}" title="${r(o)}" aria-label="${r(o)}">${n}</button>`}function Kn(e){if(!e)return"";let n=`<a class="term-btn term-open" href="${r(e)}" target="_blank" rel="noopener" title="${r(t("sessions.openTerminal"))}" aria-label="${r(t("sessions.openTerminal"))}">${Ye.terminal}</a>`;if(!ce.authed)return`<span class="term-pill solo">${n}</span>`;let o=`<button type="button" class="term-btn term-write" data-action="write-link" title="${r(t("sessions.writeLinkHint"))}" aria-label="${r(t("sessions.writeLink"))}">${Ye.key}</button>`;return`<span class="term-pill">${n}${o}</span>`}async function Vn(e,n){let o=window.open("about:blank","_blank");o&&(o.opener=null),n&&(n.disabled=!0);try{let s=await fetch(`/api/sessions/${encodeURIComponent(e.sessionId)}/write-link`),a=await s.json().catch(()=>({}));if(!s.ok||a?.ok===!1||!a?.url){o?.close(),s.status!==401&&alert(`${t("sessions.writeLinkFail")}: ${a?.error??s.status}`);return}o?o.location.href=a.url:window.open(a.url,"_blank","noopener")}catch(s){o?.close(),alert(`${t("sessions.writeLinkFail")}: ${s}`)}finally{n&&(n.disabled=!1)}}function Ha(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 Ca(){return`<details class="filter-cli">
|
|
113
113
|
<summary>${t("sessions.cli")} \xB7 <b id="cli-filter-count">${t("common.all")}</b></summary>
|
|
114
114
|
<div class="filter-cli-pop" role="group" aria-label="${t("sessions.cli")}">
|
|
115
|
-
${
|
|
115
|
+
${Yn.map(e=>`
|
|
116
116
|
<label class="filter-check">
|
|
117
|
-
<input type="checkbox" name="cli" value="${
|
|
118
|
-
<span>${
|
|
117
|
+
<input type="checkbox" name="cli" value="${r(e)}" checked>
|
|
118
|
+
<span>${r(e)}</span>
|
|
119
119
|
</label>
|
|
120
120
|
`).join("")}
|
|
121
121
|
</div>
|
|
122
|
-
</details>`}function
|
|
122
|
+
</details>`}function Aa(){return`<section class="page">
|
|
123
123
|
<div class="page-heading">
|
|
124
124
|
<div>
|
|
125
125
|
<p class="eyebrow">${t("nav.sessions")}</p>
|
|
@@ -143,7 +143,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
143
143
|
<option value="yes">${t("sessions.adoptYes")}</option>
|
|
144
144
|
<option value="no">${t("sessions.adoptNo")}</option>
|
|
145
145
|
</select>
|
|
146
|
-
${
|
|
146
|
+
${Ca()}
|
|
147
147
|
<label class="filter-toggle"><input type="checkbox" name="active" checked> <span>${t("sessions.activeOnly")}</span></label>
|
|
148
148
|
</form>
|
|
149
149
|
<div id="bulk-bar" class="bulk-bar" hidden>
|
|
@@ -168,88 +168,88 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
168
168
|
</table>
|
|
169
169
|
<div id="sessions-board" class="sessions-board" hidden></div>
|
|
170
170
|
<dialog id="drawer"></dialog>
|
|
171
|
-
</section>`}function
|
|
172
|
-
<td><input type="checkbox" class="row-select" ${S} ${
|
|
173
|
-
<td>${
|
|
174
|
-
<td><span class="badge cli-${
|
|
175
|
-
<td><span class="status status-${
|
|
176
|
-
<td title="${
|
|
177
|
-
<td title="${
|
|
171
|
+
</section>`}function Qn(e){e.innerHTML=Aa();let n=e.querySelector("#sessions-table tbody"),o=e.querySelector("#filters"),s=e.querySelector("#drawer"),a=e.querySelector("#select-all"),i=e.querySelector("#bulk-bar"),l=e.querySelector("#bulk-count"),c=e.querySelector("#bulk-close"),w=e.querySelector("#bulk-clear"),h=e.querySelector("#sessions-table"),y=e.querySelector("#sessions-board"),k=e.querySelectorAll("[data-view]"),p=new Set,E="lastMessageAt",O="desc",T=Mn(window.localStorage),f=En(window.localStorage),v=null,d="",b="",x=!1;function H(){return f.map(u=>Wn.find(g=>g.id===u)).filter(u=>!!u)}function I(u,g){let S=f.indexOf(u),L=S+g;if(S<0||L<0||L>=f.length)return;let M=[...f];M.splice(S,1),M.splice(L,0,u),f=M,jt(window.localStorage,f),V()}function C(u,g){if(u===g)return;let S=f.indexOf(u),L=f.indexOf(g);if(S<0||L<0)return;let M=[...f];M.splice(S,1),M.splice(L,0,u),f=M,jt(window.localStorage,f),V()}function q(u){let g=u.status==="closed",S=p.has(u.sessionId)?"checked":"";return`<tr data-id="${r(u.sessionId)}">
|
|
172
|
+
<td><input type="checkbox" class="row-select" ${S} ${g?"disabled":""}></td>
|
|
173
|
+
<td>${r(He(u))}</td>
|
|
174
|
+
<td><span class="badge cli-${xa(u.cliId)}">${r(u.cliId??"unknown")}</span></td>
|
|
175
|
+
<td><span class="status status-${r(u.status??"unknown")}">${r(u.status??"unknown")}</span></td>
|
|
176
|
+
<td title="${r(String(u.title??""))}">${r(Re(u.title??"").slice(0,48))}</td>
|
|
177
|
+
<td title="${r(u.workingDir??"")}">${r((u.workingDir??"").slice(-34))}</td>
|
|
178
178
|
<td>${Le(u.spawnedAt)}</td>
|
|
179
179
|
<td>${Le(u.lastMessageAt)}</td>
|
|
180
180
|
<td>${u.adopt?'<span class="badge">adopt</span>':""}</td>
|
|
181
181
|
<td><button class="open" type="button">${t("sessions.details")}</button></td>
|
|
182
|
-
</tr>`}function
|
|
182
|
+
</tr>`}function F(u){if(u.scope!=="chat"||!u.feishuChatLink)return null;let g=t("sessions.openChat");return`<a class="card-act" href="${r(u.feishuChatLink)}" target="_blank" rel="noopener" title="${r(g)}" aria-label="${r(g)}">${Ye.openChat}</a>`}function ie(u){return u.agentAttention?.reason?u.agentAttention.reason:u.agentAttention?t("sessions.board.signalAgent"):u.pendingRepo?t("sessions.board.signalRepo"):u.tuiPromptActive?t("sessions.board.signalPrompt"):u.status==="limited"?t("sessions.board.signalLimited"):""}function te(u){let g=p.has(u.sessionId),S=Re(u.title)||u.sessionId,L=He(u),M=Ve(u),U=Jn(u),G=ie(u),X=Ea(u.workingDir);return`<article class="session-card${g?" selected":""}" data-id="${r(u.sessionId)}" aria-pressed="${g}">
|
|
183
183
|
<div class="session-card-top">
|
|
184
|
-
${
|
|
184
|
+
${ye({name:L,larkAppId:u.larkAppId,size:"sm"})}
|
|
185
185
|
<div class="session-card-title">
|
|
186
|
-
<strong title="${
|
|
187
|
-
<span>${
|
|
186
|
+
<strong title="${r(String(u.title??S))}">${r(String(S).slice(0,72))}</strong>
|
|
187
|
+
<span>${r(L)} \xB7 ${r(M??u.cliId??"unknown")}</span>
|
|
188
188
|
</div>
|
|
189
|
-
<span class="status status-${
|
|
189
|
+
<span class="status status-${r(u.status??"unknown")}">${r(u.status??"unknown")}</span>
|
|
190
190
|
</div>
|
|
191
|
-
${
|
|
192
|
-
${
|
|
191
|
+
${X!=="-"||u.adopt?`<div class="session-card-meta">
|
|
192
|
+
${X!=="-"?`<span title="${r(u.workingDir??"")}">${r(X)}</span>`:""}
|
|
193
193
|
${u.adopt?'<span class="badge">adopt</span>':""}
|
|
194
194
|
</div>`:""}
|
|
195
195
|
<div class="session-card-time">
|
|
196
|
-
<span>${u.agentAttention?.at?`${
|
|
196
|
+
<span>${u.agentAttention?.at?`${r(t("sessions.board.waiting"))} ${Le(ue(u))}`:`${r(t("sessions.last"))}: ${Le(u.lastMessageAt)}`}</span>
|
|
197
197
|
</div>
|
|
198
|
-
${
|
|
198
|
+
${G?`<div class="session-signal" title="${r(G)}">${r(G)}</div>`:""}
|
|
199
199
|
<div class="session-card-actions">
|
|
200
|
-
${
|
|
201
|
-
|
|
202
|
-
${
|
|
203
|
-
|
|
200
|
+
${F(u)??Qt("locate",Ye.pin,t("sessions.locate"))}
|
|
201
|
+
${Qt("details",Ye.details,t("sessions.details"))}
|
|
202
|
+
${Kn(U)}
|
|
203
|
+
${Qt("close",Ye.close,t("sessions.close"),"danger")}
|
|
204
204
|
</div>
|
|
205
|
-
</article>`}function
|
|
206
|
-
<header draggable="true" title="${
|
|
205
|
+
</article>`}function he(u,g,S){let L=S==="needs-you"?ue(u):Number(u.lastMessageAt??0),M=S==="needs-you"?ue(g):Number(g.lastMessageAt??0);return L!==M?S==="needs-you"?L-M:M-L:String(u.title??u.sessionId).localeCompare(String(g.title??g.sessionId))}function ne(u){let g=new Map(Wn.map(M=>[M.id,[]]));for(let M of u){let U=Ha(M);U&&g.get(U).push(M)}let S=H(),L=S.map((M,U)=>{let G=(g.get(M.id)??[]).sort((X,z)=>he(X,z,M.id));return`<section class="session-board-column session-board-${M.id}" data-col="${M.id}">
|
|
206
|
+
<header draggable="true" title="${r(t("sessions.board.dragHint"))}">
|
|
207
207
|
<div>
|
|
208
|
-
<h2>${
|
|
209
|
-
<p>${
|
|
208
|
+
<h2>${r(t(M.labelKey))}</h2>
|
|
209
|
+
<p>${r(t(M.hintKey))}</p>
|
|
210
210
|
</div>
|
|
211
211
|
<span class="session-board-head-right">
|
|
212
212
|
<span class="session-board-move">
|
|
213
213
|
<button type="button" data-move-col="${M.id}" data-dir="-1"
|
|
214
|
-
aria-label="${
|
|
214
|
+
aria-label="${r(t("sessions.board.moveLeft"))}" ${U===0?"disabled":""}>\u2039</button>
|
|
215
215
|
<button type="button" data-move-col="${M.id}" data-dir="1"
|
|
216
|
-
aria-label="${
|
|
216
|
+
aria-label="${r(t("sessions.board.moveRight"))}" ${U===S.length-1?"disabled":""}>\u203A</button>
|
|
217
217
|
</span>
|
|
218
|
-
<span class="session-board-count">${
|
|
218
|
+
<span class="session-board-count">${G.length}</span>
|
|
219
219
|
</span>
|
|
220
220
|
</header>
|
|
221
221
|
<div class="session-board-list">
|
|
222
|
-
${
|
|
222
|
+
${G.length?G.map(te).join(""):`<div class="session-board-empty">${t("sessions.board.emptyColumn")}</div>`}
|
|
223
223
|
</div>
|
|
224
|
-
</section>`}).join("");L!==d&&(d=L,y.innerHTML=L,y.classList.toggle("board-enter",!x),x=!0)}function
|
|
224
|
+
</section>`}).join("");L!==d&&(d=L,y.innerHTML=L,y.classList.toggle("board-enter",!x),x=!0)}function le(){let u=new FormData(o),g=(u.get("q")??"").toLowerCase(),S=u.getAll("cli"),L=S.length>0&&S.length<Yn.length,M=u.get("status"),U=u.get("adopt"),G=!!u.get("active"),X=[...Q.sessions.values()].filter(z=>!L||S.includes(z.cliId??"unknown")).filter(z=>!M||z.status===M).filter(z=>!U||U==="yes"==!!z.adopt).filter(z=>!G||z.status!=="closed").filter(z=>!g||JSON.stringify(z).toLowerCase().includes(g));return X.sort($e),X}function me(u,g){return g==="spawnedAt"||g==="lastMessageAt"?Number(u[g]??0):g==="adopt"?!!u.adopt:String(u[g]??"").toLowerCase()}function $e(u,g){let S=me(u,E),L=me(g,E),M=0;return typeof S=="number"&&typeof L=="number"?M=S-L:typeof S=="boolean"&&typeof L=="boolean"?M=Number(S)-Number(L):M=String(S).localeCompare(String(L)),M===0&&(M=Number(u.lastMessageAt??0)-Number(g.lastMessageAt??0)),O==="asc"?M:-M}function Be(){h.querySelectorAll("th[data-sort]").forEach(u=>{let g=u.dataset.sort===E;u.classList.toggle("sorted",g),u.setAttribute("aria-sort",g?O==="asc"?"ascending":"descending":"none");let S=u.dataset.label??u.textContent?.trim()??"";u.textContent=g?`${S} ${O==="asc"?"\u25B2":"\u25BC"}`:S})}function Se(u){i.hidden=p.size===0,l.textContent=t("sessions.selectedCount",{count:p.size});let g=u.filter(L=>L.status!=="closed");if(g.length===0){a.checked=!1,a.indeterminate=!1,a.disabled=!0;return}a.disabled=!1;let S=g.filter(L=>p.has(L.sessionId)).length;a.checked=S===g.length,a.indeterminate=S>0&&S<g.length}function ae(){k.forEach(u=>{let g=u.dataset.view===T;u.classList.toggle("active",g),u.setAttribute("aria-pressed",String(g))})}function re(){let u=o.querySelector("#cli-filter-count");if(!u)return;let g=[...o.querySelectorAll('input[name="cli"]')],S=g.filter(L=>L.checked).length;u.textContent=S===g.length?t("common.all"):`${S}/${g.length}`,u.classList.toggle("cli-filter-active",S!==g.length)}function V(){let u=le();for(let L of[...p]){let M=Q.sessions.get(L);(!M||M.status==="closed")&&p.delete(L)}let g=u.filter(L=>L.status!=="closed"),S=T==="board"?g:u;if(h.hidden=T!=="table",y.hidden=T!=="board",T==="table"){let L=u.length?u.map(q).join(""):`<tr><td colspan="10" class="empty">${t("sessions.empty")}</td></tr>`;L!==b&&(b=L,n.innerHTML=L)}else ne(g);ae(),Be(),re(),Se(S)}async function Ie(u,g){g&&(g.disabled=!0,g.textContent=t("sessions.locating"));try{let S=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/locate`,{method:"POST"}),L=await S.json();if(L.ok){if(!g)return;let M=30;g.textContent=t("sessions.cooldown",{seconds:M});let U=setInterval(()=>{M-=1,M<=0?(clearInterval(U),g.disabled=!1,g.textContent=t("sessions.locate")):g.textContent=t("sessions.cooldown",{seconds:M})},1e3)}else alert(`Locate failed: ${L.error??S.status}`),g&&(g.disabled=!1,g.textContent=t("sessions.locate"))}catch(S){alert(`Locate error: ${S}`),g&&(g.disabled=!1,g.textContent=t("sessions.locate"))}}async function Me(u,g){if(!confirm(t("sessions.closeConfirm")))return!1;g&&(g.disabled=!0);try{let S=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/close`,{method:"POST"}),L=await S.json().catch(()=>({}));return!S.ok||L?.ok===!1?(S.status!==401&&alert(`Close failed: ${L?.error??S.status}`),!1):!0}catch(S){return alert(`Close error: ${S}`),!1}finally{g&&(g.disabled=!1)}}function se(u){let g=u.status==="closed",S=Jn(u);s.innerHTML=`<article>
|
|
225
225
|
<header>
|
|
226
|
-
<h3>${
|
|
227
|
-
<span class="status status-${
|
|
228
|
-
<p><code>${
|
|
226
|
+
<h3>${r(Re(u.title)||u.sessionId)}</h3>
|
|
227
|
+
<span class="status status-${r(u.status??"unknown")}">${r(u.status??"unknown")}</span>
|
|
228
|
+
<p><code>${r(u.sessionId)}</code> <button data-copy="${r(u.sessionId)}">${t("sessions.copy")}</button></p>
|
|
229
229
|
</header>
|
|
230
|
-
<p><b>${t("sessions.bot")}:</b> ${
|
|
231
|
-
${Ve(u)?`<p><b>${t("sessions.chat")}:</b> ${
|
|
232
|
-
<p><b>chatId:</b> <code>${
|
|
233
|
-
<p><b>rootMessageId:</b> <code>${
|
|
234
|
-
${u.threadId?`<p><b>threadId:</b> <code>${
|
|
235
|
-
<p><b>${t("sessions.workingDir")}:</b> ${
|
|
230
|
+
<p><b>${t("sessions.bot")}:</b> ${r(He(u))} \xB7 <b>${t("sessions.cli")}:</b> ${r(u.cliId??"?")}</p>
|
|
231
|
+
${Ve(u)?`<p><b>${t("sessions.chat")}:</b> ${r(Ve(u))}</p>`:""}
|
|
232
|
+
<p><b>chatId:</b> <code>${r(u.chatId??"")}</code> <button data-copy="${r(u.chatId??"")}">${t("sessions.copy")}</button></p>
|
|
233
|
+
<p><b>rootMessageId:</b> <code>${r(u.rootMessageId??"")}</code> <button data-copy="${r(u.rootMessageId??"")}">${t("sessions.copy")}</button></p>
|
|
234
|
+
${u.threadId?`<p><b>threadId:</b> <code>${r(u.threadId)}</code></p>`:""}
|
|
235
|
+
<p><b>${t("sessions.workingDir")}:</b> ${r(u.workingDir??"-")}</p>
|
|
236
236
|
<div class="actions">
|
|
237
|
-
${
|
|
238
|
-
${
|
|
239
|
-
${
|
|
240
|
-
${
|
|
237
|
+
${F(u)??`<button id="locate-btn" type="button">${t("sessions.locate")}</button>`}
|
|
238
|
+
${Kn(S)}
|
|
239
|
+
${g?`<button id="resume-btn" type="button" class="primary">${t("sessions.resume")}</button>`:""}
|
|
240
|
+
${g?"":`<button id="close-btn" type="button" class="contrast">${t("sessions.close")}</button>`}
|
|
241
241
|
<button id="land-btn" type="button">${t("sessions.land")}</button>
|
|
242
242
|
</div>
|
|
243
243
|
<div id="land-area"></div>
|
|
244
244
|
<form method="dialog"><button>${t("sessions.dismiss")}</button></form>
|
|
245
|
-
</article>`,s.querySelectorAll("[data-copy]").forEach(
|
|
246
|
-
\u2026(truncated)`:"");
|
|
247
|
-
<p><b>${
|
|
248
|
-
<pre style="max-height:320px;overflow:auto;white-space:pre-wrap">${
|
|
245
|
+
</article>`,s.querySelectorAll("[data-copy]").forEach(ee=>{ee.onclick=()=>{navigator.clipboard.writeText(ee.dataset.copy??""),ee.textContent=t("sessions.copied"),setTimeout(()=>{ee.textContent=t("sessions.copy")},800)}});let L=s.querySelector("#locate-btn");L&&(L.onclick=()=>{Ie(u,L)});let M=s.querySelector(".term-write");M&&(M.onclick=()=>{Vn(u,M)});let U=s.querySelector("#resume-btn");U&&(U.onclick=async()=>{U.disabled=!0;try{let ee=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/resume`,{method:"POST"}),oe=await ee.json().catch(()=>({}));if(!ee.ok||oe.ok===!1){alert(`${t("sessions.resumeFailed")}: ${oe?.error??ee.status}`),U.disabled=!1;return}s.close()}catch(ee){alert(`${t("sessions.resumeFailed")}: ${ee}`),U.disabled=!1}});let G=s.querySelector("#close-btn");G&&(G.onclick=async()=>{await Me(u,G)&&s.close()});let X=s.querySelector("#land-btn"),z=s.querySelector("#land-area");X&&z&&(X.onclick=async()=>{X.disabled=!0,z.innerHTML=`<p>${t("sessions.landLoading")}</p>`;try{let ee=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/sandbox-diff`),oe=await ee.json().catch(()=>({}));if(!oe.ok){z.innerHTML=`<p>${t("sessions.landUnavailable")}: ${r(oe.error??String(ee.status))}</p>`,X.disabled=!1;return}if(oe.empty){z.innerHTML=`<p>${t("sessions.landEmpty")}</p>`,X.disabled=!1;return}let W=String(oe.patch??""),xe=W.slice(0,2e4)+(W.length>2e4?`
|
|
246
|
+
\u2026(truncated)`:"");z.innerHTML=`
|
|
247
|
+
<p><b>${oe.files}</b> files (+${oe.insertions}/-${oe.deletions}) \u2192 <code>${r(String(oe.workingDir??""))}</code></p>
|
|
248
|
+
<pre style="max-height:320px;overflow:auto;white-space:pre-wrap">${r(xe)}</pre>
|
|
249
249
|
<div class="actions">
|
|
250
250
|
<button id="land-apply" type="button" class="primary">${t("sessions.landApply")}</button>
|
|
251
251
|
<button id="land-discard" type="button" class="contrast">${t("sessions.landDiscard")}</button>
|
|
252
|
-
</div>`;let
|
|
252
|
+
</div>`;let we=z.querySelector("#land-apply"),$=z.querySelector("#land-discard");we.onclick=async()=>{we.disabled=!0,$.disabled=!0;let Z=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/sandbox-land/apply`,{method:"POST"}),A=await Z.json().catch(()=>({}));z.innerHTML=A.ok?`<p>\u2705 ${t("sessions.landApplied")}: ${A.files} files (+${A.insertions}/-${A.deletions}) \u2192 <code>${r(String(A.workingDir??""))}</code></p>`:`<p>\u274C ${t("sessions.landFailed")}: ${r(A.error??String(Z.status))}</p>`},$.onclick=async()=>{await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/sandbox-land/discard`,{method:"POST"}),z.innerHTML=`<p>\u{1F5D1} ${t("sessions.landDiscarded")}</p>`}}catch(ee){z.innerHTML=`<p>${t("sessions.landUnavailable")}: ${r(String(ee))}</p>`,X.disabled=!1}}),s.showModal()}n.addEventListener("click",u=>{let g=u.target;if(g.classList.contains("row-select")){let U=g.closest("tr[data-id]");if(!U)return;g.checked?p.add(U.dataset.id):p.delete(U.dataset.id),Se(le());return}let S=g.closest("td");if(S&&S.querySelector(".row-select"))return;let L=g.closest("tr[data-id]");if(!L)return;let M=Q.sessions.get(L.dataset.id);M&&se(M)}),y.addEventListener("click",u=>{let g=u.target,S=g.closest("button[data-move-col]");if(S){I(S.dataset.moveCol,Number(S.dataset.dir));return}let L=g.closest(".session-card[data-id]");if(!L)return;let M=Q.sessions.get(L.dataset.id);if(!M)return;let U=g.closest("button[data-action]");if(U){let G=U.dataset.action;G==="details"?se(M):G==="write-link"?Vn(M,U):G==="locate"?Ie(M,U):G==="close"&&Me(M,U).then(X=>{X&&(p.delete(M.sessionId),V())});return}g.closest("a, button, input, label")||(p.has(M.sessionId)?p.delete(M.sessionId):p.add(M.sessionId),L.classList.toggle("selected",p.has(M.sessionId)),L.setAttribute("aria-pressed",String(p.has(M.sessionId))),Se(le().filter(G=>G.status!=="closed")))}),y.addEventListener("dragstart",u=>{let S=u.target.closest(".session-board-column > header[draggable]")?.closest(".session-board-column");S?.dataset.col&&(v=S.dataset.col,S.classList.add("dragging"),u.dataTransfer&&(u.dataTransfer.effectAllowed="move",u.dataTransfer.setData("text/plain",v)))}),y.addEventListener("dragover",u=>{if(!v)return;u.preventDefault(),u.dataTransfer&&(u.dataTransfer.dropEffect="move");let g=u.target.closest(".session-board-column");y.querySelectorAll(".drag-over").forEach(S=>S.classList.remove("drag-over")),g&&g.dataset.col!==v&&g.classList.add("drag-over")}),y.addEventListener("drop",u=>{if(!v)return;u.preventDefault();let g=u.target.closest(".session-board-column"),S=v;v=null,g?.dataset.col&&C(S,g.dataset.col)}),y.addEventListener("dragend",()=>{v=null,y.querySelectorAll(".drag-over, .dragging").forEach(u=>u.classList.remove("drag-over","dragging"))}),k.forEach(u=>{u.addEventListener("click",()=>{let g=u.dataset.view==="table"?"table":"board";g!==T&&(T=g,Hn(window.localStorage,T),V())})}),a.addEventListener("change",()=>{let u=le().filter(g=>g.status!=="closed");for(let g of u)a.checked?p.add(g.sessionId):p.delete(g.sessionId);V()}),w.addEventListener("click",()=>{p.clear(),V()}),c.addEventListener("click",async()=>{let u=[...p];if(u.length===0||!confirm(t("sessions.closeBulkConfirm",{count:u.length})))return;c.disabled=!0,w.disabled=!0;let g=c.textContent,S=0,L=0,M=[...u];c.textContent=`0/${u.length}`;async function U(){for(;M.length;){let G=M.shift();try{let X=await fetch(`/api/sessions/${encodeURIComponent(G)}/close`,{method:"POST"}),z=await X.json().catch(()=>({}));(!X.ok||z?.ok===!1)&&(L+=1)}catch{L+=1}finally{S+=1,c.textContent=`${S}/${u.length}`}}}await Promise.all(Array.from({length:Math.min(6,u.length)},()=>U())),c.textContent=g,c.disabled=!1,w.disabled=!1,p.clear(),V(),L>0&&alert(`Failed: ${L}/${u.length}`)}),h.querySelectorAll("th[data-sort]").forEach(u=>{u.addEventListener("click",()=>{let g=u.dataset.sort;E===g?O=O==="asc"?"desc":"asc":(E=g,O=g==="spawnedAt"||g==="lastMessageAt"?"desc":"asc"),V()})}),o.addEventListener("input",V),Q.on(V),V(),Ee().then(V)}function Da(){return`<section class="page">
|
|
253
253
|
<div class="page-heading">
|
|
254
254
|
<div>
|
|
255
255
|
<p class="eyebrow">${t("nav.schedules")}</p>
|
|
@@ -274,19 +274,19 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
274
274
|
</tr></thead>
|
|
275
275
|
<tbody id="schedules-tbody"></tbody>
|
|
276
276
|
</table>
|
|
277
|
-
</section>`}function
|
|
278
|
-
<td>${i
|
|
279
|
-
<td>${i
|
|
280
|
-
<td><code>${i
|
|
281
|
-
<td>${
|
|
282
|
-
<td>${
|
|
283
|
-
<td>${
|
|
284
|
-
<td>${
|
|
277
|
+
</section>`}function Xn(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function Zn(e){e.innerHTML=Da();let n=e.querySelector("#schedules-tbody"),o=e.querySelector("#sched-filters");function s(){let i=new FormData(o),l=(i.get("q")??"").toLowerCase(),c=i.get("kind"),w=!!i.get("enabled");return[...Q.schedules.values()].filter(h=>!c||h.parsed?.kind===c).filter(h=>!w||h.enabled).filter(h=>!l||JSON.stringify(h).toLowerCase().includes(l)).sort((h,y)=>{if(h.enabled!==y.enabled)return h.enabled?-1:1;let k=h.nextRunAt?Date.parse(h.nextRunAt):1/0,p=y.nextRunAt?Date.parse(y.nextRunAt):1/0;return k-p})}function a(){n.innerHTML=s().map(i=>`<tr data-id="${r(i.id)}">
|
|
278
|
+
<td>${r(i.name??i.id)}</td>
|
|
279
|
+
<td>${r(i.botName??i.larkAppId??"-")}</td>
|
|
280
|
+
<td><code>${r(i.parsed?.display??"?")}</code></td>
|
|
281
|
+
<td>${Xn(i.nextRunAt)}</td>
|
|
282
|
+
<td>${Xn(i.lastRunAt)} ${i.lastStatus==="error"?"\u26A0\uFE0F":""}</td>
|
|
283
|
+
<td>${i.repeat?`${i.repeat.completed}/${i.repeat.times??"\u221E"}`:"\u2014"}</td>
|
|
284
|
+
<td>${i.enabled?"\u2713":"\u2717"}</td>
|
|
285
285
|
<td class="actions-cell">
|
|
286
286
|
<button data-op="run" type="button">${t("schedules.runNow")}</button>
|
|
287
|
-
${
|
|
287
|
+
${i.enabled?`<button data-op="pause" type="button">${t("schedules.pause")}</button>`:`<button data-op="resume" type="button">${t("schedules.resume")}</button>`}
|
|
288
288
|
</td>
|
|
289
|
-
</tr>`).join("")||`<tr><td colspan="8" class="empty">${t("schedules.empty")}</td></tr>`}n.addEventListener("click",async
|
|
289
|
+
</tr>`).join("")||`<tr><td colspan="8" class="empty">${t("schedules.empty")}</td></tr>`}n.addEventListener("click",async i=>{let l=i.target.closest("button[data-op]");if(!l)return;let c=l.closest("tr[data-id]");if(!c)return;let w=c.dataset.id,h=l.dataset.op;l.disabled=!0;let y=l.textContent;l.textContent="...";try{let k=await fetch(`/api/schedules/${encodeURIComponent(w)}/${h}`,{method:"POST"}),p=await k.json().catch(()=>({}));(!k.ok||p.ok===!1)&&alert(`Failed: ${k.status} ${p?.error??""}`.trim())}catch(k){alert("Network error: "+k)}finally{l.disabled=!1,l.textContent=y}}),o.addEventListener("input",a),Q.on(a),a()}var pe={chats:[],bots:[]};function Ra(){return`<section class="page">
|
|
290
290
|
<div class="page-heading">
|
|
291
291
|
<div>
|
|
292
292
|
<p class="eyebrow">${t("nav.groups")}</p>
|
|
@@ -305,12 +305,12 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
305
305
|
<tbody id="g-body"></tbody>
|
|
306
306
|
</table>
|
|
307
307
|
<dialog id="g-drawer"></dialog>
|
|
308
|
-
</section>`}async function
|
|
308
|
+
</section>`}async function Qe(){pe=await(await fetch("/api/groups")).json()}async function Oa(){return(await fetch("/api/groups")).json()}function Ba(e,n){if(n.size===0)return!0;let o=e?.memberBots??[];for(let s of n)if(!o.some(a=>a.larkAppId===s&&a.inChat))return!1;return!0}function eo(e,n){return e.filter(o=>!n||!n.has(o.larkAppId)).map(o=>`
|
|
309
309
|
<label class="checkbox-row">
|
|
310
|
-
<input type="checkbox" name="bot" value="${
|
|
311
|
-
${
|
|
310
|
+
<input type="checkbox" name="bot" value="${r(o.larkAppId)}">
|
|
311
|
+
${r(o.botName??o.larkAppId)} <small>(${r(o.larkAppId)})</small>
|
|
312
312
|
</label>
|
|
313
|
-
`).join("")}async function
|
|
313
|
+
`).join("")}async function to(e){e.innerHTML=Ra();let n=e.querySelector("#g-head"),o=e.querySelector("#g-body"),s=e.querySelector("#g-filters"),a=e.querySelector("#g-refresh"),i=e.querySelector("#g-drawer");a.onclick=async()=>{a.disabled=!0;try{await Qe(),y()}finally{a.disabled=!1}};let l=e.querySelector("#g-create");l.onclick=()=>c(),await Qe();function c(){let p=pe.bots;if(p.length===0){alert(t("groups.noBotsOnline"));return}i.innerHTML=`
|
|
314
314
|
<article>
|
|
315
315
|
<header><h3>${t("groups.createTitle")}</h3></header>
|
|
316
316
|
<p>${t("groups.createHelp")}</p>
|
|
@@ -326,75 +326,75 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
326
326
|
</label>
|
|
327
327
|
<fieldset>
|
|
328
328
|
<legend>${t("groups.botPicker")}</legend>
|
|
329
|
-
${
|
|
329
|
+
${eo(p)}
|
|
330
330
|
</fieldset>
|
|
331
331
|
<div class="actions">
|
|
332
332
|
<button type="submit" class="primary">${t("groups.createSubmit")}</button>
|
|
333
333
|
<button type="button" id="g-create-cancel">${t("groups.cancel")}</button>
|
|
334
334
|
</div>
|
|
335
335
|
</form>
|
|
336
|
-
</article>`,
|
|
336
|
+
</article>`,i.showModal(),i.querySelector("#g-create-cancel").onclick=()=>i.close(),i.querySelector("#g-createform").onsubmit=async T=>{T.preventDefault();let f=new FormData(T.target),v=(f.get("name")??"").trim(),d=(f.get("bindWorkingDir")??"").trim(),b=f.getAll("bot");if(b.length===0){alert("Pick at least one bot.");return}let x=T.target.querySelector("button[type=submit]");x&&(x.disabled=!0,x.textContent="Creating...");try{let H=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:v||void 0,larkAppIds:b,bindWorkingDir:d||void 0})}),I=await H.json();if(I.ok&&I.chatId){w(I);let C=Array.isArray(I.invalidBotIds)?I.invalidBotIds:[],q=b.filter(ie=>!C.includes(ie)),F=new Set(q);typeof I.creator=="string"&&I.creator&&F.add(I.creator),E(I.chatId,v||I.chatId,q,I.creator),y(),O(I.chatId,F).catch(()=>{})}else alert(`Failed: ${I.error??H.status}`),i.close()}catch(H){alert("Network error: "+H),i.close()}};function E(T,f,v,d){let b=new Set(v);d&&b.add(d);let x=pe.bots.map(I=>({larkAppId:I.larkAppId,botName:I.botName,inChat:b.has(I.larkAppId),oncallChat:null})),H={chatId:T,name:f,ownerId:d??null,memberBots:x};pe.chats=[H,...pe.chats.filter(I=>I.chatId!==T)]}async function O(T,f){let v=[600,1200,1200,1200,1200,1200];for(let d of v){await new Promise(H=>setTimeout(H,d));let b;try{b=await Oa()}catch{continue}let x=(b.chats??[]).find(H=>H.chatId===T);if(x&&Ba(x,f)){pe=b,y();return}}}}function w(p){let E=String(p.chatId),O=typeof p.shareLink=="string"&&p.shareLink?p.shareLink:`https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(E)}`,T=p.invalidBotIds??[],f=p.invalidUserIds??[],v=p.autoInvitedOpenId,d=!!p.autoInviteRejected,b=p.ownerTransferredTo,x=p.transferError,H=p.notifyMessageId,I=p.notifyError,C=Array.isArray(p.oncallBindings)?p.oncallBindings:[],q=C.filter(ne=>ne?.ok).length,F=C.filter(ne=>!ne?.ok),ie=C.length>0?F.length===0?`<p class="hint-ok">\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1A<code>${r(p.bindResolvedPath??"")}</code>\uFF08${q}/${C.length} bots\uFF09</p>`:`<p class="hint-warn">\u76EE\u5F55\u7ED1\u5B9A\u90E8\u5206\u5931\u8D25\uFF1A\u6210\u529F ${q}/${C.length}\u3002${F.map(ne=>`<br><code>${r(ne.larkAppId??"?")}</code>: ${r(ne.error??"unknown")}`).join("")}</p>`:"",te;if(v){let ne=b?"<br><small>\u7FA4\u4E3B\u5DF2\u4ECE\u673A\u5668\u4EBA\u8F6C\u8BA9\u7ED9\u4F60\u3002</small>":x?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08${r(x)}\uFF09\uFF0C\u4F60\u73B0\u5728\u662F\u6210\u5458\u4F46\u7FA4\u4E3B\u4ECD\u662F\u673A\u5668\u4EBA\u3002</small>`:"",le=H?`<br><small>\u673A\u5668\u4EBA\u5DF2\u5728\u7FA4\u91CC @ \u4E86\u4F60\uFF08\u6D88\u606F id <code>${r(H)}</code>\uFF09\uFF0C\u770B\u98DE\u4E66\u901A\u77E5\u5C31\u80FD\u8FDB\u7FA4\u3002</small>`:I?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8 @ \u901A\u77E5\u5931\u8D25\uFF08${r(I)}\uFF09\uFF0C\u65B0\u7FA4\u53EF\u80FD\u4E0D\u4F1A\u4E3B\u52A8\u51FA\u73B0\u5728\u4F60\u4FA7\u8FB9\u680F\uFF0C\u5EFA\u8BAE\u4ECE\u4E0B\u9762\u6309\u94AE\u8DF3\u8FDB\u53BB\u3002</small>`:"";te=`<p class="hint-ok">\u5DF2\u81EA\u52A8\u9080\u8BF7\u4F60\uFF08<code>${r(v)}</code>\uFF09\u4F5C\u4E3A\u6210\u5458\u3002${ne}${le}</p>`}else d?te='<p class="hint-warn">\u98DE\u4E66\u62D2\u7EDD\u4E86\u81EA\u52A8\u9080\u8BF7\uFF08\u4F60\u7684 open_id \u5728\u521B\u5EFA\u8005 bot \u7684 scope \u4E0B\u4E0D\u53EF\u7528\uFF09\u3002<strong>\u4F60\u76EE\u524D\u4E0D\u662F\u65B0\u7FA4\u6210\u5458</strong>\uFF0C\u9700\u8981\u8BA9\u7FA4\u91CC\u7684\u67D0\u4E2A\u673A\u5668\u4EBA\u624B\u52A8\u628A\u4F60\u52A0\u8FDB\u6765\u3002</p>':te='<p class="hint-warn">\u6CA1\u5728 dashboard \u7F13\u5B58\u91CC\u627E\u5230 ownerOpenId\uFF0C<strong>\u6CA1\u6709\u81EA\u52A8\u9080\u8BF7\u4F60</strong>\u3002\u70B9\u5F00\u4E0B\u9762\u94FE\u63A5\u524D\uFF0C\u5148\u8BA9\u7FA4\u91CC\u4EFB\u4E00\u673A\u5668\u4EBA\u624B\u52A8\u628A\u4F60\u52A0\u8FDB\u53BB\u3002</p>';let he=[T.length?`<li>\u65E0\u6548 bot id: <code>${T.map(r).join(", ")}</code></li>`:"",f.length?`<li>\u65E0\u6548\u7528\u6237 open_id: <code>${f.map(r).join(", ")}</code></li>`:""].filter(Boolean).join("");i.innerHTML=`
|
|
337
337
|
<article>
|
|
338
338
|
<header><h3>${t("groups.successTitle")}</h3></header>
|
|
339
|
-
<p><b>chatId:</b> <code>${
|
|
340
|
-
<p><b>\u521B\u5EFA\u8005:</b> <code>${
|
|
341
|
-
${
|
|
342
|
-
${
|
|
343
|
-
${
|
|
339
|
+
<p><b>chatId:</b> <code>${r(E)}</code> <button type="button" data-copy="${r(E)}">${t("sessions.copy")}</button></p>
|
|
340
|
+
<p><b>\u521B\u5EFA\u8005:</b> <code>${r(p.creator??"?")}</code></p>
|
|
341
|
+
${te}
|
|
342
|
+
${ie}
|
|
343
|
+
${he?`<ul>${he}</ul>`:""}
|
|
344
344
|
<div class="actions">
|
|
345
345
|
<a class="btn-link primary" href="${O}" target="_blank" rel="noopener">${t("groups.openGroup")}</a>
|
|
346
346
|
<button type="button" id="g-create-close">${t("sessions.dismiss")}</button>
|
|
347
347
|
</div>
|
|
348
|
-
</article>`,
|
|
348
|
+
</article>`,i.querySelectorAll("[data-copy]").forEach(ne=>{ne.onclick=()=>{navigator.clipboard.writeText(ne.dataset.copy??""),ne.textContent=t("sessions.copied"),setTimeout(()=>{ne.textContent=t("sessions.copy")},800)}}),i.querySelector("#g-create-close").onclick=()=>i.close()}function h(){n.innerHTML=`<tr>
|
|
349
349
|
<th>${t("groups.chat")}</th>
|
|
350
|
-
${
|
|
350
|
+
${pe.bots.map(p=>`<th>${r(p.botName??p.larkAppId)}</th>`).join("")}
|
|
351
351
|
<th>${t("groups.actions")}</th>
|
|
352
|
-
</tr>`}function y(){h();let p=new FormData(s),E=(p.get("q")??"").toLowerCase(),O=!!p.get("missing"),T=
|
|
352
|
+
</tr>`}function y(){h();let p=new FormData(s),E=(p.get("q")??"").toLowerCase(),O=!!p.get("missing"),T=pe.chats.filter(f=>!E||(f.name??"").toLowerCase().includes(E)||f.chatId.toLowerCase().includes(E)||(f.ownerId??"").toLowerCase().includes(E)).filter(f=>!O||f.memberBots.some(v=>!v.inChat));if(T.length===0){o.innerHTML=`<tr><td colspan="${pe.bots.length+2}" class="empty">${t("groups.empty")}</td></tr>`;return}o.innerHTML=T.map(f=>`<tr data-chat="${r(f.chatId)}">
|
|
353
353
|
<td>
|
|
354
354
|
<div class="g-chat-cell">
|
|
355
|
-
${
|
|
355
|
+
${Un({chatId:f.chatId,name:f.name,avatarUrl:f.avatar,size:"sm"})}
|
|
356
356
|
<div class="g-chat-meta">
|
|
357
|
-
<strong>${
|
|
358
|
-
<small><code>${
|
|
357
|
+
<strong>${r(f.name??f.chatId)}</strong><br>
|
|
358
|
+
<small><code>${r(f.chatId)}</code></small>
|
|
359
359
|
</div>
|
|
360
360
|
</div>
|
|
361
361
|
</td>
|
|
362
|
-
${
|
|
362
|
+
${pe.bots.map(v=>{let d=f.memberBots.find(H=>H.larkAppId===v.larkAppId),b=d?d.error?"!":d.inChat?"\u2713":"\u2717":"?";return`<td class="${d?d.error?"cell-error":d.inChat?"cell-in":"cell-out":"cell-unknown"}" title="${r(d?.error??"")}">${b}</td>`}).join("")}
|
|
363
363
|
<td>
|
|
364
364
|
<button class="add-bots" type="button">${t("groups.addBots")}</button>
|
|
365
365
|
<button class="manage-chat" type="button">${t("groups.manage")}</button>
|
|
366
366
|
</td>
|
|
367
|
-
</tr>`).join("")}y(),o.addEventListener("click",async p=>{let E=p.target.closest("button.add-bots");if(!E)return;let T=E.closest("tr[data-chat]").dataset.chat,f=
|
|
367
|
+
</tr>`).join("")}y(),o.addEventListener("click",async p=>{let E=p.target.closest("button.add-bots");if(!E)return;let T=E.closest("tr[data-chat]").dataset.chat,f=pe.chats.find(b=>b.chatId===T);if(!f)return;let v=new Set(f.memberBots.filter(b=>b.inChat).map(b=>b.larkAppId));if(!pe.bots.filter(b=>!v.has(b.larkAppId)).length){alert("All configured bots are already in this chat.");return}i.innerHTML=`
|
|
368
368
|
<article>
|
|
369
|
-
<header><h3>${t("groups.addBots")} \xB7 ${
|
|
369
|
+
<header><h3>${t("groups.addBots")} \xB7 ${r(f.name??f.chatId)}</h3></header>
|
|
370
370
|
<p>${t("groups.createHelp")}</p>
|
|
371
371
|
<form id="g-addform">
|
|
372
|
-
${
|
|
372
|
+
${eo(pe.bots,v)}
|
|
373
373
|
<div class="actions">
|
|
374
374
|
<button type="submit" class="primary">${t("groups.addBots")}</button>
|
|
375
375
|
<button type="button" id="g-cancel">${t("groups.cancel")}</button>
|
|
376
376
|
</div>
|
|
377
377
|
</form>
|
|
378
|
-
</article>`,
|
|
379
|
-
`);alert(q),await
|
|
378
|
+
</article>`,i.showModal(),i.querySelector("#g-cancel").onclick=()=>i.close(),i.querySelector("#g-addform").onsubmit=async b=>{b.preventDefault();let H=new FormData(b.target).getAll("bot");if(H.length===0){alert("Pick at least one bot.");return}try{let C=await(await fetch(`/api/groups/${encodeURIComponent(T)}/add-bots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:H})})).json();if(C.error==="no_proxy_bot")alert("No bot is currently in this chat \u2014 add one manually in Feishu first, then retry.");else if(C.result){let q=C.result.map(F=>`${F.id}: ${F.ok?"OK":`failed (${F.error??"unknown"})`}`).join(`
|
|
379
|
+
`);alert(q),await Qe(),y()}else alert(`Unexpected response: ${JSON.stringify(C)}`)}catch(I){alert("Network error: "+I)}finally{i.close()}}}),o.addEventListener("click",async p=>{let E=p.target.closest("button.manage-chat");if(!E)return;let T=E.closest("tr[data-chat]").dataset.chat,f=pe.chats.find(v=>v.chatId===T);f&&k(f)});function k(p){let E=p.memberBots.filter(T=>T.inChat),O=typeof p.ownerId=="string"?p.ownerId:"";i.innerHTML=`
|
|
380
380
|
<article>
|
|
381
381
|
<header><h3>${t("groups.manageTitle",{name:p.name??p.chatId})}</h3></header>
|
|
382
|
-
<p><b>chatId:</b> <code>${
|
|
383
|
-
<p><b>${t("groups.owner")}:</b> <code>${
|
|
382
|
+
<p><b>chatId:</b> <code>${r(p.chatId)}</code></p>
|
|
383
|
+
<p><b>${t("groups.owner")}:</b> <code>${r(p.ownerId??t("common.unknown"))}</code></p>
|
|
384
384
|
|
|
385
385
|
<fieldset>
|
|
386
386
|
<legend>${t("groups.oncall")}</legend>
|
|
387
387
|
<p><small>${t("groups.oncallHelp")}</small></p>
|
|
388
388
|
${E.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':E.map(T=>{let f=!!T.oncallChat,v=T.oncallChat?.workingDir??"";return`
|
|
389
|
-
<div class="oncall-row" data-bot="${
|
|
389
|
+
<div class="oncall-row" data-bot="${r(T.larkAppId)}">
|
|
390
390
|
<label class="checkbox-row">
|
|
391
391
|
<input type="checkbox" data-action="toggle" ${f?"checked":""}>
|
|
392
|
-
<strong>${
|
|
393
|
-
<small>(${
|
|
392
|
+
<strong>${r(T.botName??T.larkAppId)}</strong>
|
|
393
|
+
<small>(${r(T.larkAppId)})</small>
|
|
394
394
|
</label>
|
|
395
395
|
<div class="oncall-row-body">
|
|
396
396
|
<input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
|
|
397
|
-
value="${
|
|
397
|
+
value="${r(v)}" ${f?"":"disabled"}>
|
|
398
398
|
<button type="button" data-action="save">${t("groups.save")}</button>
|
|
399
399
|
<span class="oncall-status" data-status></span>
|
|
400
400
|
</div>
|
|
@@ -406,8 +406,8 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
406
406
|
<legend>${t("groups.leaveTitle")}</legend>
|
|
407
407
|
${E.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':E.map(T=>`
|
|
408
408
|
<label class="checkbox-row">
|
|
409
|
-
<input type="checkbox" name="leave-bot" value="${
|
|
410
|
-
${
|
|
409
|
+
<input type="checkbox" name="leave-bot" value="${r(T.larkAppId)}">
|
|
410
|
+
${r(T.botName??T.larkAppId)}
|
|
411
411
|
<small>${T.larkAppId===O?"\xB7 \u7FA4\u4E3B":""}</small>
|
|
412
412
|
</label>
|
|
413
413
|
`).join("")}
|
|
@@ -419,14 +419,14 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
419
419
|
</div>
|
|
420
420
|
<p class="hint-warn"><small>${t("groups.dangerHint")}</small></p>
|
|
421
421
|
<form method="dialog"><button>${t("sessions.dismiss")}</button></form>
|
|
422
|
-
</article>`,
|
|
423
|
-
`);alert(d||`Unexpected: ${JSON.stringify(v)}`),await
|
|
422
|
+
</article>`,i.showModal(),i.querySelectorAll(".oncall-row").forEach(T=>{let f=T.dataset.bot,v=T.querySelector("input[data-action=toggle]"),d=T.querySelector("input[data-input=workingDir]"),b=T.querySelector("button[data-action=save]"),x=T.querySelector("[data-status]");v.addEventListener("change",()=>{d.disabled=!v.checked,v.checked&&d.focus()}),b.addEventListener("click",async()=>{x.textContent="",x.className="oncall-status";let H=v.checked,I=d.value.trim();if(H&&!I){x.textContent=t("groups.needWorkingDir"),x.classList.add("hint-warn-inline");return}b.disabled=!0;try{let C=`/api/groups/${encodeURIComponent(p.chatId)}/oncall/${encodeURIComponent(f)}`,q=H?await fetch(C,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({workingDir:I})}):await fetch(C,{method:"DELETE"}),F=await q.json().catch(()=>({}));if(q.ok&&F.ok){x.textContent=H?`\u2713 \u5DF2\u7ED1\u5B9A \u2192 ${F.resolvedPath??I}`:"\u2713 \u5DF2\u89E3\u7ED1",x.classList.add("hint-ok");try{await Qe(),y()}catch{}}else x.textContent=`\u2717 ${F.error??q.status}`,x.classList.add("hint-warn-inline")}catch(C){x.textContent=`\u2717 ${C?.message??C}`,x.classList.add("hint-warn-inline")}finally{b.disabled=!1}})}),i.querySelector("#g-leave-btn").onclick=async()=>{let T=[...i.querySelectorAll("input[name=leave-bot]:checked")].map(f=>f.value);if(T.length===0){alert("\u81F3\u5C11\u9009\u4E00\u4E2A\u673A\u5668\u4EBA");return}if(confirm(`\u786E\u5B9A\u8BA9 ${T.length} \u4E2A\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A\uFF1F\u8BE5 bot \u5728\u6B64\u7FA4\u7684\u4F1A\u8BDD\u4F1A\u4E00\u5E76\u5173\u95ED\u3002`))try{let v=await(await fetch(`/api/groups/${encodeURIComponent(p.chatId)}/leave`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:T})})).json(),d=(v.result??[]).map(b=>{if(!b.ok)return`${b.larkAppId}: \u5931\u8D25 (${b.error??"unknown"})`;let x=b.closedSessions??[],H=x.filter(q=>!q.ok).length,I=x.length-H,C=x.length===0?"":H===0?`\uFF08\u5173\u95ED ${I} \u4E2A\u4F1A\u8BDD\uFF09`:`\uFF08\u5173\u95ED ${I} \u4E2A\uFF0C${H} \u4E2A\u5931\u8D25\uFF09`;return`${b.larkAppId}: OK${C}`}).join(`
|
|
423
|
+
`);alert(d||`Unexpected: ${JSON.stringify(v)}`),await Qe(),y()}catch(f){alert("Network error: "+f)}finally{i.close()}},i.querySelector("#g-disband-btn").onclick=async()=>{if(E.length===0||!confirm(`\u786E\u5B9A\u89E3\u6563\u7FA4\u804A\u300C${p.name??p.chatId}\u300D\uFF1F\u6B64\u64CD\u4F5C\u4E0D\u53EF\u6062\u590D\uFF0C\u672C\u7FA4\u6240\u6709\u673A\u5668\u4EBA\u4F1A\u8BDD\u4E5F\u4F1A\u4E00\u5E76\u5173\u95ED\u3002`))return;let T=[...E].sort((v,d)=>(d.larkAppId===O?1:0)-(v.larkAppId===O?1:0)),f=[];for(let v of T)try{let d=await fetch(`/api/groups/${encodeURIComponent(p.chatId)}/disband`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppId:v.larkAppId})}),b=await d.json();if(b.ok){let x=b.closedSessions??[],H=x.filter(q=>!q.ok).length,I=x.length-H,C=x.length===0?"":H===0?`
|
|
424
424
|
\u5173\u95ED\u4E86 ${I} \u4E2A\u4F1A\u8BDD\u3002`:`
|
|
425
|
-
\u5173\u95ED\u4E86 ${I} \u4E2A\u4F1A\u8BDD\uFF0C${H} \u4E2A\u4F1A\u8BDD\u5173\u95ED\u5931\u8D25\u3002`;alert(`\u5DF2\u89E3\u6563\uFF08\u7531 ${v.botName??v.larkAppId} \u6267\u884C\uFF09${C}`),await
|
|
425
|
+
\u5173\u95ED\u4E86 ${I} \u4E2A\u4F1A\u8BDD\uFF0C${H} \u4E2A\u4F1A\u8BDD\u5173\u95ED\u5931\u8D25\u3002`;alert(`\u5DF2\u89E3\u6563\uFF08\u7531 ${v.botName??v.larkAppId} \u6267\u884C\uFF09${C}`),await Qe(),y(),i.close();return}f.push(`${v.botName??v.larkAppId}: ${b.error??d.status}`)}catch(d){f.push(`${v.botName??v.larkAppId}: ${d}`)}alert(`\u6240\u6709\u5728\u7FA4\u673A\u5668\u4EBA\u5747\u65E0\u6CD5\u89E3\u6563\uFF1A
|
|
426
426
|
${f.join(`
|
|
427
427
|
`)}
|
|
428
428
|
|
|
429
|
-
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",y)}var
|
|
429
|
+
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",y)}var ve={bots:[]},Ze=null,Xe=null;function no(e){let n=null;for(let o of Q.sessions.values())o.larkAppId!==e||!o.cliId||(!n||Number(o.lastMessageAt??0)>Number(n.lastMessageAt??0))&&(n=o);return n?.cliId??""}function Na(){return`<section class="page">
|
|
430
430
|
<div class="page-heading">
|
|
431
431
|
<div>
|
|
432
432
|
<p class="eyebrow">${t("nav.botDefaults")}</p>
|
|
@@ -442,31 +442,31 @@ ${f.join(`
|
|
|
442
442
|
<aside id="bd-roster" class="bd-roster"></aside>
|
|
443
443
|
<div id="bd-list" class="bd-detail"></div>
|
|
444
444
|
</div>
|
|
445
|
-
</section>`}async function
|
|
446
|
-
${
|
|
445
|
+
</section>`}async function oo(){try{let e=await fetch("/api/bots"),n=await e.json().catch(()=>({}));if(!e.ok){Ze=n?.error?`HTTP ${e.status}: ${n.error}${n.path?` (${n.path})`:""}`:`HTTP ${e.status}`,ve={bots:[]};return}if(!n||!Array.isArray(n.bots)){Ze="unexpected response shape (no `bots` array)",ve={bots:[]};return}Ze=null,ve=n}catch(e){Ze=e?.message??String(e),ve={bots:[]}}}function ao(e){if(!e)return"\u2014";let n=new Date(e);return Number.isNaN(n.getTime())?"\u2014":n.toLocaleString()}async function so(e){e.innerHTML=Na();let n=e.querySelector("#bd-list"),o=e.querySelector("#bd-roster"),s=e.querySelector("#bd-filters"),a=e.querySelector("#bd-refresh");a.onclick=async()=>{a.disabled=!0;try{await oo(),i()}finally{a.disabled=!1}},n.addEventListener("click",d=>{let b=d.target.closest(".toggle-tx small, small.bd-help");b&&(d.preventDefault(),b.classList.toggle("open"))}),await oo();function i(){let b=(new FormData(s).get("q")??"").toLowerCase(),x=ve.bots.filter(I=>!b||(I.botName??"").toLowerCase().includes(b)||(I.larkAppId??"").toLowerCase().includes(b));if(Ze){o.innerHTML="",n.innerHTML=`<p class="hint-warn">\u65E0\u6CD5\u52A0\u8F7D bot \u5217\u8868\uFF1A${r(Ze)}<br>\u5E38\u89C1\u539F\u56E0\uFF1Adashboard / daemon \u8FDB\u7A0B\u8FD8\u5728\u8DD1\u65E7\u4EE3\u7801\uFF0C\u6267\u884C <code>botmux restart</code> \u540E\u5237\u65B0\u3002</p>`;return}if(x.length===0){o.innerHTML="",n.innerHTML=`<p class="empty">${t("botDefaults.empty")}</p>`;return}(!Xe||!x.some(I=>I.larkAppId===Xe))&&(Xe=x[0].larkAppId),o.innerHTML=x.map(l).join(""),o.querySelectorAll(".bd-roster-item").forEach(I=>{I.onclick=()=>{Xe=I.dataset.appid,i()}});let H=x.find(I=>I.larkAppId===Xe);n.innerHTML=c(H),v()}function l(d){let b=d.botName??d.larkAppId,x=no(d.larkAppId),H=d.defaultOncall?.enabled?'<span class="bd-roster-flag">oncall</span>':"";return`<div class="bd-roster-item${d.larkAppId===Xe?" on":""}" data-appid="${r(d.larkAppId)}" role="button" tabindex="0">
|
|
446
|
+
${ye({name:b,larkAppId:d.larkAppId,size:"sm"})}
|
|
447
447
|
<div class="bd-roster-tx">
|
|
448
|
-
<b>${
|
|
449
|
-
<span>${
|
|
448
|
+
<b>${r(b)}</b>
|
|
449
|
+
<span>${r(x||d.larkAppId.slice(0,14))}</span>
|
|
450
450
|
</div>
|
|
451
451
|
${H}
|
|
452
|
-
</div>`}function c(d){if(d.error)return`<article class="bd-card bd-profile" data-appid="${
|
|
452
|
+
</div>`}function c(d){if(d.error)return`<article class="bd-card bd-profile" data-appid="${r(d.larkAppId)}">
|
|
453
453
|
<header class="bd-profile-head">
|
|
454
|
-
${
|
|
455
|
-
<div class="bd-profile-id"><strong>${
|
|
456
|
-
<code>${
|
|
454
|
+
${ye({name:d.botName??d.larkAppId,larkAppId:d.larkAppId})}
|
|
455
|
+
<div class="bd-profile-id"><strong>${r(d.botName??d.larkAppId)}</strong>
|
|
456
|
+
<code>${r(d.larkAppId)}</code></div>
|
|
457
457
|
</header>
|
|
458
|
-
<p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${
|
|
459
|
-
</article>`;let
|
|
458
|
+
<p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${r(d.error)}</p>
|
|
459
|
+
</article>`;let b=d.defaultOncall??{enabled:!1,workingDir:"",since:0},x=!!b.enabled,H=d.botName??d.larkAppId,I=no(d.larkAppId);return`<article class="bd-card bd-profile" data-appid="${r(d.larkAppId)}">
|
|
460
460
|
<header class="bd-profile-head">
|
|
461
|
-
${
|
|
461
|
+
${ye({name:H,larkAppId:d.larkAppId,dot:"ok"})}
|
|
462
462
|
<div class="bd-profile-id">
|
|
463
|
-
<strong>${
|
|
464
|
-
${I?`<span class="mate-role">${
|
|
465
|
-
<code>${
|
|
463
|
+
<strong>${r(H)}</strong>
|
|
464
|
+
${I?`<span class="mate-role">${r(I)}</span>`:""}
|
|
465
|
+
<code>${r(d.larkAppId)}</code>
|
|
466
466
|
</div>
|
|
467
467
|
<div class="bd-profile-meta bd-meta">
|
|
468
468
|
<small class="bd-meta-ok">\u25CF ${t("botDefaults.metaOnline")}</small>
|
|
469
|
-
<small data-oncall-since>${t("botDefaults.lastEnabled")}: ${
|
|
469
|
+
<small data-oncall-since>${t("botDefaults.lastEnabled")}: ${r(ao(b.since??0))}</small>
|
|
470
470
|
<small>${t("botDefaults.autobound",{count:d.autoboundChatCount??0})}</small>
|
|
471
471
|
</div>
|
|
472
472
|
</header>
|
|
@@ -484,7 +484,7 @@ ${f.join(`
|
|
|
484
484
|
<label>
|
|
485
485
|
<span>${t("botDefaults.workingDir")}</span>
|
|
486
486
|
<input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
|
|
487
|
-
value="${
|
|
487
|
+
value="${r(b.workingDir??"")}" ${x?"":"disabled"}>
|
|
488
488
|
</label>
|
|
489
489
|
</div>
|
|
490
490
|
<div class="actions">
|
|
@@ -500,27 +500,27 @@ ${f.join(`
|
|
|
500
500
|
<section class="bd-tile">${k(d)}${y(d)}</section>
|
|
501
501
|
<section class="bd-tile">${T(d)}</section>
|
|
502
502
|
</div>
|
|
503
|
-
</article>`}function w(d){let
|
|
503
|
+
</article>`}function w(d){let b=typeof d.teamRole=="string";return`<section class="bd-section">
|
|
504
504
|
<h3 class="bd-section-title">${t("botDefaults.sectionRole")}</h3>
|
|
505
505
|
<p class="bd-section-note">${t("botDefaults.roleHelp")}</p>
|
|
506
506
|
<textarea data-input="teamRole" rows="6"
|
|
507
|
-
placeholder="${
|
|
508
|
-
style="width:100%;box-sizing:border-box;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px"${
|
|
507
|
+
placeholder="${r(t("botDefaults.rolePlaceholder"))}"
|
|
508
|
+
style="width:100%;box-sizing:border-box;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px"${b?"":" disabled"}>${b?r(d.teamRole):""}</textarea>
|
|
509
509
|
<div class="actions">
|
|
510
|
-
<button type="button" class="primary" data-action="save-role"${
|
|
511
|
-
<button type="button" data-action="delete-role"${
|
|
510
|
+
<button type="button" class="primary" data-action="save-role"${b?"":" disabled"}>${t("botDefaults.roleSave")}</button>
|
|
511
|
+
<button type="button" data-action="delete-role"${b?"":" disabled"}>${t("botDefaults.roleDelete")}</button>
|
|
512
512
|
<span class="oncall-status" data-role-status></span>
|
|
513
513
|
</div>
|
|
514
|
-
</section>`}function h(d){return d==null?t("botDefaults.brandStateDefault"):d.trim()===""?t("botDefaults.brandStateOff"):t("botDefaults.brandStateCustom")}function y(d){let
|
|
514
|
+
</section>`}function h(d){return d==null?t("botDefaults.brandStateDefault"):d.trim()===""?t("botDefaults.brandStateOff"):t("botDefaults.brandStateCustom")}function y(d){let b=d.brandLabel??null;return`<section class="bd-section">
|
|
515
515
|
<h3 class="bd-section-title">${t("botDefaults.sectionBrand")}</h3>
|
|
516
516
|
<div class="bd-row bd-brand">
|
|
517
517
|
<label>
|
|
518
518
|
<span>${t("botDefaults.brandLabel")}</span>
|
|
519
519
|
<input type="text" data-input="brandLabel"
|
|
520
|
-
placeholder="${
|
|
521
|
-
value="${
|
|
520
|
+
placeholder="${r(t("botDefaults.brandLabelPlaceholder"))}"
|
|
521
|
+
value="${r(b??"")}">
|
|
522
522
|
</label>
|
|
523
|
-
<small data-brand-state>${
|
|
523
|
+
<small data-brand-state>${r(h(b))}</small>
|
|
524
524
|
<small class="bd-help">${t("botDefaults.brandLabelHelp")}</small>
|
|
525
525
|
<div class="actions">
|
|
526
526
|
<button type="button" class="primary" data-action="save-brand">${t("botDefaults.brandSave")}</button>
|
|
@@ -528,16 +528,16 @@ ${f.join(`
|
|
|
528
528
|
<span class="oncall-status" data-brand-status></span>
|
|
529
529
|
</div>
|
|
530
530
|
</div>
|
|
531
|
-
</section>`}function k(d){let
|
|
531
|
+
</section>`}function k(d){let b=d.disableStreamingCard===!0,x=d.writableTerminalLinkInCard===!0,H=d.privateCard===!0;return`<section class="bd-section">
|
|
532
532
|
<h3 class="bd-section-title">${t("botDefaults.sectionCard")}</h3>
|
|
533
533
|
<label class="toggle-row">
|
|
534
|
-
<input type="checkbox" data-action="toggle-disable-streaming" ${
|
|
534
|
+
<input type="checkbox" data-action="toggle-disable-streaming" ${b?"checked":""}>
|
|
535
535
|
<span class="switch" aria-hidden="true"></span>
|
|
536
536
|
<span class="toggle-tx"><strong>${t("botDefaults.disableStreaming")}</strong>
|
|
537
537
|
<small>${t("botDefaults.disableStreamingHelp")}</small></span>
|
|
538
538
|
</label>
|
|
539
539
|
<label class="toggle-row">
|
|
540
|
-
<input type="checkbox" data-action="toggle-writable-link" ${x?"checked":""} ${
|
|
540
|
+
<input type="checkbox" data-action="toggle-writable-link" ${x?"checked":""} ${b?"disabled":""}>
|
|
541
541
|
<span class="switch" aria-hidden="true"></span>
|
|
542
542
|
<span class="toggle-tx"><strong>${t("botDefaults.writableLink")}</strong>
|
|
543
543
|
<small>${t("botDefaults.writableLinkHelp")}</small></span>
|
|
@@ -549,17 +549,17 @@ ${f.join(`
|
|
|
549
549
|
<small>${t("botDefaults.privateCardHelp")}</small></span>
|
|
550
550
|
</label>
|
|
551
551
|
<div class="actions">
|
|
552
|
-
<small data-card-pref-moot class="hint-warn-inline" ${
|
|
552
|
+
<small data-card-pref-moot class="hint-warn-inline" ${b?"":"hidden"}>${t("botDefaults.writableLinkMoot")}</small>
|
|
553
553
|
<span class="oncall-status" data-card-pref-status></span>
|
|
554
554
|
</div>
|
|
555
|
-
</section>`}function p(d){let
|
|
555
|
+
</section>`}function p(d){let b=d.p2pMode==="chat"?"chat":"thread",x=d.regularGroupReplyMode==="new-topic"||d.regularGroupReplyMode==="shared"?d.regularGroupReplyMode:"chat",H=d.regularGroupMentionMode==="topic"||d.regularGroupMentionMode==="never"?d.regularGroupMentionMode:"always",I=(q,F)=>`<option value="${q}" ${x===q?"selected":""}>${r(F)}</option>`,C=(q,F)=>`<option value="${q}" ${H===q?"selected":""}>${r(F)}</option>`;return`<section class="bd-section">
|
|
556
556
|
<h3 class="bd-section-title">${t("botDefaults.sectionSessionMode")}</h3>
|
|
557
557
|
<div class="bd-row">
|
|
558
558
|
<label>
|
|
559
559
|
<span>${t("botDefaults.p2pMode")}</span>
|
|
560
560
|
<select data-input="p2pMode">
|
|
561
|
-
<option value="thread" ${
|
|
562
|
-
<option value="chat" ${
|
|
561
|
+
<option value="thread" ${b==="chat"?"":"selected"}>${r(t("botDefaults.p2pThread"))}</option>
|
|
562
|
+
<option value="chat" ${b==="chat"?"selected":""}>${r(t("botDefaults.p2pChat"))}</option>
|
|
563
563
|
</select>
|
|
564
564
|
</label>
|
|
565
565
|
<small class="bd-help">${t("botDefaults.p2pHelp")}</small>
|
|
@@ -595,10 +595,10 @@ ${f.join(`
|
|
|
595
595
|
<span class="oncall-status" data-mention-mode-status></span>
|
|
596
596
|
</div>
|
|
597
597
|
</div>
|
|
598
|
-
</section>`}function E(d){let
|
|
598
|
+
</section>`}function E(d){let b=d.sandbox===!0;return`<section class="bd-section">
|
|
599
599
|
<h3 class="bd-section-title">${t("botDefaults.sectionSandbox")}</h3>
|
|
600
600
|
<label class="toggle-row">
|
|
601
|
-
<input type="checkbox" data-action="toggle-sandbox" ${
|
|
601
|
+
<input type="checkbox" data-action="toggle-sandbox" ${b?"checked":""}>
|
|
602
602
|
<span class="switch" aria-hidden="true"></span>
|
|
603
603
|
<span class="toggle-tx"><strong>${t("botDefaults.sandboxToggle")}</strong>
|
|
604
604
|
<small>${t("botDefaults.sandboxHelp")}</small></span>
|
|
@@ -606,10 +606,10 @@ ${f.join(`
|
|
|
606
606
|
<div class="actions">
|
|
607
607
|
<span class="oncall-status" data-sandbox-status></span>
|
|
608
608
|
</div>
|
|
609
|
-
</section>`}function O(d){return d==null?t("botDefaults.quotaStateOff"):t("botDefaults.quotaStateOn",{count:d})}function T(d){let
|
|
609
|
+
</section>`}function O(d){return d==null?t("botDefaults.quotaStateOff"):t("botDefaults.quotaStateOn",{count:d})}function T(d){let b=d.restrictGrantCommands===!0,x=typeof d.messageQuotaDefaultLimit=="number"?d.messageQuotaDefaultLimit:null;return`<section class="bd-section">
|
|
610
610
|
<h3 class="bd-section-title">${t("botDefaults.sectionGrant")}</h3>
|
|
611
611
|
<label class="toggle-row">
|
|
612
|
-
<input type="checkbox" data-action="toggle-restrict-grant" ${
|
|
612
|
+
<input type="checkbox" data-action="toggle-restrict-grant" ${b?"checked":""}>
|
|
613
613
|
<span class="switch" aria-hidden="true"></span>
|
|
614
614
|
<span class="toggle-tx"><strong>${t("botDefaults.restrictGrant")}</strong>
|
|
615
615
|
<small>${t("botDefaults.restrictGrantHelp")}</small></span>
|
|
@@ -618,10 +618,10 @@ ${f.join(`
|
|
|
618
618
|
<label>
|
|
619
619
|
<span>${t("botDefaults.quotaDefault")}</span>
|
|
620
620
|
<input type="number" min="1" step="1" data-input="quotaLimit"
|
|
621
|
-
placeholder="${
|
|
621
|
+
placeholder="${r(t("botDefaults.quotaPlaceholder"))}"
|
|
622
622
|
value="${x??""}">
|
|
623
623
|
</label>
|
|
624
|
-
<small data-quota-state>${
|
|
624
|
+
<small data-quota-state>${r(O(x))}</small>
|
|
625
625
|
<small class="bd-help">${t("botDefaults.quotaHelp")}</small>
|
|
626
626
|
<div class="actions">
|
|
627
627
|
<button type="button" class="primary" data-action="save-quota">${t("botDefaults.quotaSave")}</button>
|
|
@@ -629,10 +629,10 @@ ${f.join(`
|
|
|
629
629
|
<span class="oncall-status" data-grant-status></span>
|
|
630
630
|
</div>
|
|
631
631
|
</div>
|
|
632
|
-
</section>`}function f(d){let
|
|
632
|
+
</section>`}function f(d){let b=d.autoStartOnGroupJoin===!0,x=d.autoStartOnNewTopic===!0,H=typeof d.autoStartOnGroupJoinPrompt=="string"?d.autoStartOnGroupJoinPrompt:"";return`<div class="bd-subsection">
|
|
633
633
|
<h4 class="bd-subsection-title">${t("botDefaults.sectionAutoStart")}</h4>
|
|
634
634
|
<label class="toggle-row">
|
|
635
|
-
<input type="checkbox" data-action="toggle-auto-join" ${
|
|
635
|
+
<input type="checkbox" data-action="toggle-auto-join" ${b?"checked":""}>
|
|
636
636
|
<span class="switch" aria-hidden="true"></span>
|
|
637
637
|
<span class="toggle-tx"><strong>${t("botDefaults.autoStartJoin")}</strong>
|
|
638
638
|
<small>${t("botDefaults.autoStartJoinHelp")}</small></span>
|
|
@@ -641,7 +641,7 @@ ${f.join(`
|
|
|
641
641
|
<label>
|
|
642
642
|
<span>${t("botDefaults.autoStartJoinPrompt")}</span>
|
|
643
643
|
<textarea data-input="autoJoinPrompt" rows="3"
|
|
644
|
-
placeholder="${
|
|
644
|
+
placeholder="${r(t("botDefaults.autoStartJoinPromptPlaceholder"))}">${r(H)}</textarea>
|
|
645
645
|
</label>
|
|
646
646
|
<div class="actions">
|
|
647
647
|
<button type="button" class="primary" data-action="save-auto-join-prompt">${t("botDefaults.autoStartJoinPromptSave")}</button>
|
|
@@ -656,7 +656,7 @@ ${f.join(`
|
|
|
656
656
|
<div class="actions">
|
|
657
657
|
<span class="oncall-status" data-auto-start-status></span>
|
|
658
658
|
</div>
|
|
659
|
-
</div>`}function v(){n.querySelectorAll(".bd-card").forEach(d=>{let g=d.dataset.appid,x=d.querySelector("input[data-action=toggle]"),H=d.querySelector("input[data-input=workingDir]"),I=d.querySelector("button[data-action=save]"),C=d.querySelector("[data-status]");if(!x||!H||!I||!C)return;x.addEventListener("change",()=>{H.disabled=!x.checked,x.checked&&H.focus()}),I.addEventListener("click",async()=>{C.textContent="",C.className="oncall-status";let X=x.checked,N=H.value.trim();if(X&&!N){C.textContent=t("botDefaults.required"),C.classList.add("hint-warn-inline");return}I.disabled=!0;try{let R=await fetch(`/api/bots/${encodeURIComponent(g)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:X,workingDir:N})}),F=await R.json().catch(()=>({}));if(R.ok&&F.ok){let P=F.resolvedPath?` \u2192 ${F.resolvedPath}`:"";C.textContent=X?`\u2713 \u5DF2\u5F00\u542F${P}\uFF08\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8 oncall\uFF09`:"\u2713 \u5DF2\u5173\u95ED\uFF08\u5DF2\u7ED1\u5B9A\u7684\u7FA4\u4E0D\u52A8\uFF09",C.classList.add("hint-ok");let _=we.bots.find(Se=>Se.larkAppId===g);_&&F.defaultOncall&&(_.defaultOncall=F.defaultOncall);let le=d.querySelector("[data-oncall-since]");le&&F.defaultOncall?.since!=null&&(le.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${eo(F.defaultOncall.since)}`)}else C.textContent=`\u2717 ${F.error??R.status}`,C.classList.add("hint-warn-inline")}catch(R){C.textContent=`\u2717 ${R?.message??R}`,C.classList.add("hint-warn-inline")}finally{I.disabled=!1}});let q=d.querySelector("input[data-input=brandLabel]"),G=d.querySelector("button[data-action=save-brand]"),se=d.querySelector("button[data-action=reset-brand]"),ee=d.querySelector("[data-brand-status]"),ge=d.querySelector("[data-brand-state]");async function te(X,N){if(ee){ee.textContent="",ee.className="oncall-status",N.disabled=!0;try{let R=await fetch(`/api/bots/${encodeURIComponent(g)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:X})}),F=await R.json().catch(()=>({}));if(R.ok&&F.ok){let P=F.brandLabel??null;ee.textContent="\u2713",ee.classList.add("hint-ok"),q&&(q.value=P??""),ge&&(ge.textContent=h(P));let _=we.bots.find(le=>le.larkAppId===g);_&&(_.brandLabel=P)}else ee.textContent=`\u2717 ${F.error??R.status}`,ee.classList.add("hint-warn-inline")}catch(R){ee.textContent=`\u2717 ${R?.message??R}`,ee.classList.add("hint-warn-inline")}finally{N.disabled=!1}}}q&&G&&G.addEventListener("click",()=>te(q.value,G)),se&&se.addEventListener("click",()=>te(null,se));let ie=d.querySelector("input[data-action=toggle-disable-streaming]"),ue=d.querySelector("input[data-action=toggle-writable-link]"),ve=d.querySelector("input[data-action=toggle-private-card]"),Be=d.querySelector("[data-card-pref-status]"),ke=d.querySelector("[data-card-pref-moot]");async function oe(X,N,R=Be){if(R){R.textContent="",R.className="oncall-status",N.disabled=!0;try{let F=await fetch(`/api/bots/${encodeURIComponent(g)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(X)}),P=await F.json().catch(()=>({}));if(F.ok&&P.ok){R.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,R.classList.add("hint-ok");let _=we.bots.find(le=>le.larkAppId===g);_&&(_.disableStreamingCard=P.disableStreamingCard,_.writableTerminalLinkInCard=P.writableTerminalLinkInCard,_.privateCard=P.privateCard,_.autoStartOnGroupJoin=P.autoStartOnGroupJoin,_.autoStartOnGroupJoinPrompt=P.autoStartOnGroupJoinPrompt,_.autoStartOnNewTopic=P.autoStartOnNewTopic,_.regularGroupReplyMode=P.regularGroupReplyMode,_.regularGroupMentionMode=P.regularGroupMentionMode)}else R.textContent=`\u2717 ${P.error??F.status}`,R.classList.add("hint-warn-inline")}catch(F){R.textContent=`\u2717 ${F?.message??F}`,R.classList.add("hint-warn-inline")}finally{N===ue?N.disabled=!!ie?.checked:N.disabled=!1}}}ie&&ie.addEventListener("change",()=>{let X=ie.checked;ue&&(ue.disabled=X),ke&&(ke.hidden=!X),oe({disableStreamingCard:X},ie)}),ue&&ue.addEventListener("change",()=>{oe({writableTerminalLinkInCard:ue.checked},ue)}),ve&&ve.addEventListener("change",()=>{oe({privateCard:ve.checked},ve)});let re=d.querySelector("input[data-action=toggle-sandbox]"),Y=d.querySelector("[data-sandbox-status]");re&&re.addEventListener("change",async()=>{let X=re.checked;Y&&(Y.textContent="",Y.className="oncall-status"),re.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(g)}/sandbox`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:X})}),R=await N.json().catch(()=>({}));if(N.ok&&R.ok){Y&&(Y.textContent=`\u2713 ${t("botDefaults.sandboxSaved")}`,Y.classList.add("hint-ok"));let F=we.bots.find(P=>P.larkAppId===g);F&&(F.sandbox=R.sandbox===!0)}else Y&&(Y.textContent=`\u2717 ${R.error??N.status}`,Y.classList.add("hint-warn-inline")),re.checked=!X}catch(N){Y&&(Y.textContent=`\u2717 ${N?.message??N}`,Y.classList.add("hint-warn-inline")),re.checked=!X}finally{re.disabled=!1}});let Ie=d.querySelector("input[data-action=toggle-auto-join]"),Me=d.querySelector("input[data-action=toggle-auto-topic]"),ae=d.querySelector("textarea[data-input=autoJoinPrompt]"),u=d.querySelector("button[data-action=save-auto-join-prompt]"),b=d.querySelector("[data-auto-start-status]");Ie&&Ie.addEventListener("change",()=>{oe({autoStartOnGroupJoin:Ie.checked},Ie,b)}),Me&&Me.addEventListener("change",()=>{oe({autoStartOnNewTopic:Me.checked},Me,b)}),ae&&u&&u.addEventListener("click",()=>{oe({autoStartOnGroupJoinPrompt:ae.value},u,b)});let S=d.querySelector("select[data-input=p2pMode]"),L=d.querySelector("[data-p2p-status]");S&&L&&S.addEventListener("change",async()=>{let X=S.value==="chat"?"chat":"thread";L.textContent="",L.className="oncall-status",S.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(g)}/p2p-mode`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({p2pMode:X})}),R=await N.json().catch(()=>({}));if(N.ok&&R.ok){L.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,L.classList.add("hint-ok");let F=we.bots.find(P=>P.larkAppId===g);F&&(F.p2pMode=R.p2pMode==="chat"?"chat":"thread")}else L.textContent=`\u2717 ${R.error??N.status}`,L.classList.add("hint-warn-inline")}catch(N){L.textContent=`\u2717 ${N?.message??N}`,L.classList.add("hint-warn-inline")}finally{S.disabled=!1}});let M=d.querySelector("select[data-input=regularGroupMode]"),U=d.querySelector("[data-regular-group-status]");M&&M.addEventListener("change",()=>{oe({regularGroupReplyMode:M.value},M,U)});let z=d.querySelector("select[data-input=regularGroupMentionMode]"),W=d.querySelector("[data-mention-mode-status]");z&&z.addEventListener("change",()=>{oe({regularGroupMentionMode:z.value},z,W)});let j=d.querySelector("textarea[data-input=teamRole]"),ne=d.querySelector("button[data-action=save-role]"),xe=d.querySelector("button[data-action=delete-role]"),Q=d.querySelector("[data-role-status]");if(j&&ne&&xe&&Q){let R=function(P){let _=n.querySelector(`.bd-card[data-appid="${CSS.escape(g)}"]`);if(!_)return;let le=_.querySelector("textarea[data-input=teamRole]"),Se=_.querySelector("button[data-action=save-role]"),et=_.querySelector("button[data-action=delete-role]");le&&(le.value=P,le.disabled=!1),Se&&(Se.disabled=!1),et&&(et.disabled=!1)};var gt=R;let X=`/api/team/local-bots/${encodeURIComponent(g)}/role`,N=we.bots.find(P=>P.larkAppId===g);N&&typeof N.teamRole!="string"&&!N.teamRoleLoading&&(N.teamRoleLoading=!0,(async()=>{try{let P=await fetch(X),_=await P.json().catch(()=>({}));P.ok&&_.ok?(N.teamRole=_.role??"",R(N.teamRole)):(Q.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${_.error??P.status}`,Q.classList.add("hint-warn-inline"))}catch(P){Q.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${P?.message??P}`,Q.classList.add("hint-warn-inline")}finally{N.teamRoleLoading=!1}})());async function F(P,_,le){if(Q&&!(!N||typeof N.teamRole!="string")){Q.textContent="",Q.className="oncall-status",ne.disabled=!0,xe.disabled=!0;try{let Se=await fetch(X,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({role:P})}),et=await Se.json().catch(()=>({}));Se.ok&&et.ok?(N&&(N.teamRole=P.trim()),Q.textContent=`\u2713 ${le?t("botDefaults.roleDeleted"):t("botDefaults.roleSaved")}`,Q.classList.add("hint-ok")):(Q.textContent=`\u2717 ${et.error??Se.status}`,Q.classList.add("hint-warn-inline"))}catch(Se){Q.textContent=`\u2717 ${Se?.message??Se}`,Q.classList.add("hint-warn-inline")}finally{ne.disabled=!1,xe.disabled=!1}}}ne.addEventListener("click",()=>F(j.value,ne,!1)),xe.addEventListener("click",()=>{j.value="",F("",xe,!0)})}let $e=d.querySelector("input[data-action=toggle-restrict-grant]"),be=d.querySelector("input[data-input=quotaLimit]"),$=d.querySelector("button[data-action=save-quota]"),J=d.querySelector("button[data-action=off-quota]"),D=d.querySelector("[data-grant-status]"),B=d.querySelector("[data-quota-state]");async function pe(X,N){if(D){D.textContent="",D.className="oncall-status",N.disabled=!0;try{let R=await fetch(`/api/bots/${encodeURIComponent(g)}/grant-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(X)}),F=await R.json().catch(()=>({}));if(R.ok&&F.ok){D.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,D.classList.add("hint-ok");let P=typeof F.messageQuotaDefaultLimit=="number"?F.messageQuotaDefaultLimit:null,_=we.bots.find(le=>le.larkAppId===g);_&&(_.restrictGrantCommands=F.restrictGrantCommands===!0,_.messageQuotaDefaultLimit=P),B&&(B.textContent=O(P)),be&&"messageQuotaDefaultLimit"in X&&(be.value=P==null?"":String(P))}else D.textContent=`\u2717 ${F.error??R.status}`,D.classList.add("hint-warn-inline")}catch(R){D.textContent=`\u2717 ${R?.message??R}`,D.classList.add("hint-warn-inline")}finally{N.disabled=!1}}}$e&&$e.addEventListener("change",()=>{pe({restrictGrantCommands:$e.checked},$e)}),be&&$&&$.addEventListener("click",()=>{let X=be.value.trim();if(X===""){pe({messageQuotaDefaultLimit:null},$);return}if(!/^[1-9]\d*$/.test(X)){D&&(D.textContent=`\u2717 ${t("botDefaults.quotaInvalid")}`,D.className="oncall-status hint-warn-inline");return}pe({messageQuotaDefaultLimit:Number(X)},$)}),be&&J&&J.addEventListener("click",()=>{be.value="",pe({messageQuotaDefaultLimit:null},J)})})}r(),Ee().then(r),s.addEventListener("input",r)}var Yt=4096,Lt=[],Ce=null,Ae=null,ye="",Ze=new Set;function Ra(){return`<section class="page roles-page">
|
|
659
|
+
</div>`}function v(){n.querySelectorAll(".bd-card").forEach(d=>{let b=d.dataset.appid,x=d.querySelector("input[data-action=toggle]"),H=d.querySelector("input[data-input=workingDir]"),I=d.querySelector("button[data-action=save]"),C=d.querySelector("[data-status]");if(!x||!H||!I||!C)return;x.addEventListener("change",()=>{H.disabled=!x.checked,x.checked&&H.focus()}),I.addEventListener("click",async()=>{C.textContent="",C.className="oncall-status";let Y=x.checked,N=H.value.trim();if(Y&&!N){C.textContent=t("botDefaults.required"),C.classList.add("hint-warn-inline");return}I.disabled=!0;try{let R=await fetch(`/api/bots/${encodeURIComponent(b)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:Y,workingDir:N})}),j=await R.json().catch(()=>({}));if(R.ok&&j.ok){let P=j.resolvedPath?` \u2192 ${j.resolvedPath}`:"";C.textContent=Y?`\u2713 \u5DF2\u5F00\u542F${P}\uFF08\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8 oncall\uFF09`:"\u2713 \u5DF2\u5173\u95ED\uFF08\u5DF2\u7ED1\u5B9A\u7684\u7FA4\u4E0D\u52A8\uFF09",C.classList.add("hint-ok");let _=ve.bots.find(Te=>Te.larkAppId===b);_&&j.defaultOncall&&(_.defaultOncall=j.defaultOncall);let de=d.querySelector("[data-oncall-since]");de&&j.defaultOncall?.since!=null&&(de.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${ao(j.defaultOncall.since)}`)}else C.textContent=`\u2717 ${j.error??R.status}`,C.classList.add("hint-warn-inline")}catch(R){C.textContent=`\u2717 ${R?.message??R}`,C.classList.add("hint-warn-inline")}finally{I.disabled=!1}});let q=d.querySelector("input[data-input=brandLabel]"),F=d.querySelector("button[data-action=save-brand]"),ie=d.querySelector("button[data-action=reset-brand]"),te=d.querySelector("[data-brand-status]"),he=d.querySelector("[data-brand-state]");async function ne(Y,N){if(te){te.textContent="",te.className="oncall-status",N.disabled=!0;try{let R=await fetch(`/api/bots/${encodeURIComponent(b)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:Y})}),j=await R.json().catch(()=>({}));if(R.ok&&j.ok){let P=j.brandLabel??null;te.textContent="\u2713",te.classList.add("hint-ok"),q&&(q.value=P??""),he&&(he.textContent=h(P));let _=ve.bots.find(de=>de.larkAppId===b);_&&(_.brandLabel=P)}else te.textContent=`\u2717 ${j.error??R.status}`,te.classList.add("hint-warn-inline")}catch(R){te.textContent=`\u2717 ${R?.message??R}`,te.classList.add("hint-warn-inline")}finally{N.disabled=!1}}}q&&F&&F.addEventListener("click",()=>ne(q.value,F)),ie&&ie.addEventListener("click",()=>ne(null,ie));let le=d.querySelector("input[data-action=toggle-disable-streaming]"),me=d.querySelector("input[data-action=toggle-writable-link]"),$e=d.querySelector("input[data-action=toggle-private-card]"),Be=d.querySelector("[data-card-pref-status]"),Se=d.querySelector("[data-card-pref-moot]");async function ae(Y,N,R=Be){if(R){R.textContent="",R.className="oncall-status",N.disabled=!0;try{let j=await fetch(`/api/bots/${encodeURIComponent(b)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(Y)}),P=await j.json().catch(()=>({}));if(j.ok&&P.ok){R.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,R.classList.add("hint-ok");let _=ve.bots.find(de=>de.larkAppId===b);_&&(_.disableStreamingCard=P.disableStreamingCard,_.writableTerminalLinkInCard=P.writableTerminalLinkInCard,_.privateCard=P.privateCard,_.autoStartOnGroupJoin=P.autoStartOnGroupJoin,_.autoStartOnGroupJoinPrompt=P.autoStartOnGroupJoinPrompt,_.autoStartOnNewTopic=P.autoStartOnNewTopic,_.regularGroupReplyMode=P.regularGroupReplyMode,_.regularGroupMentionMode=P.regularGroupMentionMode)}else R.textContent=`\u2717 ${P.error??j.status}`,R.classList.add("hint-warn-inline")}catch(j){R.textContent=`\u2717 ${j?.message??j}`,R.classList.add("hint-warn-inline")}finally{N===me?N.disabled=!!le?.checked:N.disabled=!1}}}le&&le.addEventListener("change",()=>{let Y=le.checked;me&&(me.disabled=Y),Se&&(Se.hidden=!Y),ae({disableStreamingCard:Y},le)}),me&&me.addEventListener("change",()=>{ae({writableTerminalLinkInCard:me.checked},me)}),$e&&$e.addEventListener("change",()=>{ae({privateCard:$e.checked},$e)});let re=d.querySelector("input[data-action=toggle-sandbox]"),V=d.querySelector("[data-sandbox-status]");re&&re.addEventListener("change",async()=>{let Y=re.checked;V&&(V.textContent="",V.className="oncall-status"),re.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(b)}/sandbox`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:Y})}),R=await N.json().catch(()=>({}));if(N.ok&&R.ok){V&&(V.textContent=`\u2713 ${t("botDefaults.sandboxSaved")}`,V.classList.add("hint-ok"));let j=ve.bots.find(P=>P.larkAppId===b);j&&(j.sandbox=R.sandbox===!0)}else V&&(V.textContent=`\u2717 ${R.error??N.status}`,V.classList.add("hint-warn-inline")),re.checked=!Y}catch(N){V&&(V.textContent=`\u2717 ${N?.message??N}`,V.classList.add("hint-warn-inline")),re.checked=!Y}finally{re.disabled=!1}});let Ie=d.querySelector("input[data-action=toggle-auto-join]"),Me=d.querySelector("input[data-action=toggle-auto-topic]"),se=d.querySelector("textarea[data-input=autoJoinPrompt]"),u=d.querySelector("button[data-action=save-auto-join-prompt]"),g=d.querySelector("[data-auto-start-status]");Ie&&Ie.addEventListener("change",()=>{ae({autoStartOnGroupJoin:Ie.checked},Ie,g)}),Me&&Me.addEventListener("change",()=>{ae({autoStartOnNewTopic:Me.checked},Me,g)}),se&&u&&u.addEventListener("click",()=>{ae({autoStartOnGroupJoinPrompt:se.value},u,g)});let S=d.querySelector("select[data-input=p2pMode]"),L=d.querySelector("[data-p2p-status]");S&&L&&S.addEventListener("change",async()=>{let Y=S.value==="chat"?"chat":"thread";L.textContent="",L.className="oncall-status",S.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(b)}/p2p-mode`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({p2pMode:Y})}),R=await N.json().catch(()=>({}));if(N.ok&&R.ok){L.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,L.classList.add("hint-ok");let j=ve.bots.find(P=>P.larkAppId===b);j&&(j.p2pMode=R.p2pMode==="chat"?"chat":"thread")}else L.textContent=`\u2717 ${R.error??N.status}`,L.classList.add("hint-warn-inline")}catch(N){L.textContent=`\u2717 ${N?.message??N}`,L.classList.add("hint-warn-inline")}finally{S.disabled=!1}});let M=d.querySelector("select[data-input=regularGroupMode]"),U=d.querySelector("[data-regular-group-status]");M&&M.addEventListener("change",()=>{ae({regularGroupReplyMode:M.value},M,U)});let G=d.querySelector("select[data-input=regularGroupMentionMode]"),X=d.querySelector("[data-mention-mode-status]");G&&G.addEventListener("change",()=>{ae({regularGroupMentionMode:G.value},G,X)});let z=d.querySelector("textarea[data-input=teamRole]"),ee=d.querySelector("button[data-action=save-role]"),oe=d.querySelector("button[data-action=delete-role]"),W=d.querySelector("[data-role-status]");if(z&&ee&&oe&&W){let R=function(P){let _=n.querySelector(`.bd-card[data-appid="${CSS.escape(b)}"]`);if(!_)return;let de=_.querySelector("textarea[data-input=teamRole]"),Te=_.querySelector("button[data-action=save-role]"),nt=_.querySelector("button[data-action=delete-role]");de&&(de.value=P,de.disabled=!1),Te&&(Te.disabled=!1),nt&&(nt.disabled=!1)};var bt=R;let Y=`/api/team/local-bots/${encodeURIComponent(b)}/role`,N=ve.bots.find(P=>P.larkAppId===b);N&&typeof N.teamRole!="string"&&!N.teamRoleLoading&&(N.teamRoleLoading=!0,(async()=>{try{let P=await fetch(Y),_=await P.json().catch(()=>({}));P.ok&&_.ok?(N.teamRole=_.role??"",R(N.teamRole)):(W.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${_.error??P.status}`,W.classList.add("hint-warn-inline"))}catch(P){W.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${P?.message??P}`,W.classList.add("hint-warn-inline")}finally{N.teamRoleLoading=!1}})());async function j(P,_,de){if(W&&!(!N||typeof N.teamRole!="string")){W.textContent="",W.className="oncall-status",ee.disabled=!0,oe.disabled=!0;try{let Te=await fetch(Y,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({role:P})}),nt=await Te.json().catch(()=>({}));Te.ok&&nt.ok?(N&&(N.teamRole=P.trim()),W.textContent=`\u2713 ${de?t("botDefaults.roleDeleted"):t("botDefaults.roleSaved")}`,W.classList.add("hint-ok")):(W.textContent=`\u2717 ${nt.error??Te.status}`,W.classList.add("hint-warn-inline"))}catch(Te){W.textContent=`\u2717 ${Te?.message??Te}`,W.classList.add("hint-warn-inline")}finally{ee.disabled=!1,oe.disabled=!1}}}ee.addEventListener("click",()=>j(z.value,ee,!1)),oe.addEventListener("click",()=>{z.value="",j("",oe,!0)})}let xe=d.querySelector("input[data-action=toggle-restrict-grant]"),we=d.querySelector("input[data-input=quotaLimit]"),$=d.querySelector("button[data-action=save-quota]"),Z=d.querySelector("button[data-action=off-quota]"),A=d.querySelector("[data-grant-status]"),B=d.querySelector("[data-quota-state]");async function fe(Y,N){if(A){A.textContent="",A.className="oncall-status",N.disabled=!0;try{let R=await fetch(`/api/bots/${encodeURIComponent(b)}/grant-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(Y)}),j=await R.json().catch(()=>({}));if(R.ok&&j.ok){A.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,A.classList.add("hint-ok");let P=typeof j.messageQuotaDefaultLimit=="number"?j.messageQuotaDefaultLimit:null,_=ve.bots.find(de=>de.larkAppId===b);_&&(_.restrictGrantCommands=j.restrictGrantCommands===!0,_.messageQuotaDefaultLimit=P),B&&(B.textContent=O(P)),we&&"messageQuotaDefaultLimit"in Y&&(we.value=P==null?"":String(P))}else A.textContent=`\u2717 ${j.error??R.status}`,A.classList.add("hint-warn-inline")}catch(R){A.textContent=`\u2717 ${R?.message??R}`,A.classList.add("hint-warn-inline")}finally{N.disabled=!1}}}xe&&xe.addEventListener("change",()=>{fe({restrictGrantCommands:xe.checked},xe)}),we&&$&&$.addEventListener("click",()=>{let Y=we.value.trim();if(Y===""){fe({messageQuotaDefaultLimit:null},$);return}if(!/^[1-9]\d*$/.test(Y)){A&&(A.textContent=`\u2717 ${t("botDefaults.quotaInvalid")}`,A.className="oncall-status hint-warn-inline");return}fe({messageQuotaDefaultLimit:Number(Y)},$)}),we&&Z&&Z.addEventListener("click",()=>{we.value="",fe({messageQuotaDefaultLimit:null},Z)})})}i(),Ee().then(i),s.addEventListener("input",i)}var Xt=4096,It=[],Ce=null,Ae=null,ke="",et=new Set;function Pa(){return`<section class="page roles-page">
|
|
660
660
|
<div class="page-heading">
|
|
661
661
|
<div>
|
|
662
662
|
<p class="eyebrow">${t("nav.roles")}</p>
|
|
@@ -695,27 +695,27 @@ ${f.join(`
|
|
|
695
695
|
</div>
|
|
696
696
|
</div>
|
|
697
697
|
</div>
|
|
698
|
-
</section>`}async function
|
|
698
|
+
</section>`}async function Lt(){It=((await(await fetch("/api/groups")).json()).chats??[]).map(o=>({chatId:o.chatId,name:o.name??o.chatId,memberBots:(o.memberBots??[]).map(s=>({larkAppId:s.larkAppId,botName:s.botName??s.larkAppId,inChat:s.inChat??!1,hasRole:s.hasRole??!1,oncallChat:s.oncallChat??null}))}))}async function ro(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`)).json()}async function qa(e,n,o){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({content:o})})).ok}async function Ua(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`,{method:"DELETE"})).ok}function lo(e){return e.memberBots.filter(n=>n.inChat&&n.hasRole).length}function ja(e){return e.memberBots.filter(n=>n.inChat).length}function je(e=""){let n=document.getElementById("roles-tree");if(!n)return;let o=e.toLowerCase(),s=It.filter(a=>{if(!o)return!0;let i=a.chatId.toLowerCase().includes(o)||(a.name??"").toLowerCase().includes(o),l=a.memberBots.some(c=>c.larkAppId.toLowerCase().includes(o)||(c.botName??"").toLowerCase().includes(o));return i||l});if(s.length===0){n.innerHTML=`<div class="roles-empty">${t("roles.noChats")}</div>`;return}n.innerHTML=s.map(a=>{let i=et.has(a.chatId),l=a.memberBots.filter(k=>k.inChat),c=i?"\u25BE":"\u25B8",w=lo(a),h=ja(a),y=i?l.map(k=>`
|
|
699
699
|
<div class="roles-bot-row ${Ce===a.chatId&&Ae===k.larkAppId?"selected":""}"
|
|
700
|
-
data-group-id="${
|
|
701
|
-
data-bot-id="${
|
|
700
|
+
data-group-id="${r(a.chatId)}"
|
|
701
|
+
data-bot-id="${r(k.larkAppId)}">
|
|
702
702
|
<span class="roles-bot-indent"></span>
|
|
703
|
-
${
|
|
703
|
+
${ye({name:k.botName,larkAppId:k.larkAppId,size:"sm"})}
|
|
704
704
|
<div class="roles-bot-info">
|
|
705
|
-
<div class="roles-bot-name">${
|
|
706
|
-
<div class="roles-bot-id">${
|
|
705
|
+
<div class="roles-bot-name">${r(k.botName)}</div>
|
|
706
|
+
<div class="roles-bot-id">${r(k.larkAppId)}</div>
|
|
707
707
|
</div>
|
|
708
708
|
<span class="roles-badge ${k.hasRole?"has-role":"no-role"}">
|
|
709
709
|
${k.hasRole?t("roles.configured"):t("roles.unconfigured")}
|
|
710
710
|
</span>
|
|
711
711
|
</div>`).join(""):"";return`
|
|
712
712
|
<div class="roles-group-section">
|
|
713
|
-
<div class="roles-group-row ${
|
|
714
|
-
data-group-id="${
|
|
713
|
+
<div class="roles-group-row ${i?"expanded":""} ${Ce===a.chatId&&!Ae?"selected":""}"
|
|
714
|
+
data-group-id="${r(a.chatId)}">
|
|
715
715
|
<span class="roles-group-arrow">${c}</span>
|
|
716
716
|
<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>
|
|
717
717
|
<div class="roles-group-info">
|
|
718
|
-
<div class="roles-group-name">${
|
|
718
|
+
<div class="roles-group-name">${r(a.name??a.chatId)}</div>
|
|
719
719
|
<div class="roles-group-meta">
|
|
720
720
|
${w}/${h} ${t("roles.botsWithRoles")}
|
|
721
721
|
</div>
|
|
@@ -723,12 +723,12 @@ ${f.join(`
|
|
|
723
723
|
<span class="roles-group-chevron"></span>
|
|
724
724
|
</div>
|
|
725
725
|
<div class="roles-bot-list">${y}</div>
|
|
726
|
-
</div>`}).join(""),n.querySelectorAll(".roles-group-row").forEach(a=>{a.addEventListener("click",()=>{let
|
|
726
|
+
</div>`}).join(""),n.querySelectorAll(".roles-group-row").forEach(a=>{a.addEventListener("click",()=>{let i=a.dataset.groupId;i&&(et.has(i)?et.delete(i):et.add(i),je(document.getElementById("roles-search")?.value??""))})}),n.querySelectorAll(".roles-bot-row").forEach(a=>{a.addEventListener("click",i=>{i.stopPropagation();let l=a.dataset.groupId,c=a.dataset.botId;l&&c&&Fa(l,c)})})}async function Fa(e,n){Ce=e,Ae=n;let o=await ro(n,e),s=document.getElementById("roles-editor-empty"),a=document.getElementById("roles-editor-form"),i=document.getElementById("roles-editor-textarea"),l=document.getElementById("roles-editor-group-name"),c=document.getElementById("roles-editor-bot-name"),w=document.getElementById("roles-editor-chat-id");s&&(s.style.display="none"),a&&(a.style.display="");let h=It.find(p=>p.chatId===e),y=h?.memberBots.find(p=>p.larkAppId===n);l&&(l.textContent=h?.name??e),c&&(c.textContent=y?.botName??n),w&&(w.textContent=`${e} \xB7 ${n}`),ke=o.content??"",i&&(i.value=ke,i.focus()),Zt(),en(),je(document.getElementById("roles-search")?.value??"");let k=document.getElementById("roles-delete");k&&(k.style.display=o.hasRole?"":"none")}function Zt(){let e=document.getElementById("roles-editor-bytecount");if(!e)return;let n=new TextEncoder().encode(ke).length;e.textContent=`${n} / ${Xt} bytes`,e.className=`roles-bytecount ${n>3800?"warn":""} ${n>Xt?"over":""}`,Ga(n)}function Ga(e){let n=document.getElementById("roles-save");if(!n)return;let o=e??new TextEncoder().encode(ke).length;n.disabled=o>Xt||ke.trim().length===0}function en(){let e=document.getElementById("roles-preview");e&&(ke.trim()?e.innerHTML=`<strong>${t("roles.preview")}</strong><pre>${r(ke)}</pre>`:e.innerHTML=`<small>${t("roles.previewEmpty")}</small>`)}function io(){Ce=null,Ae=null,ke="";let e=document.getElementById("roles-editor-empty"),n=document.getElementById("roles-editor-form"),o=document.getElementById("roles-editor-textarea"),s=document.getElementById("roles-delete");e&&(e.style.display=""),n&&(n.style.display="none"),o&&(o.value=""),s&&(s.style.display="none")}async function co(e){e.innerHTML=Pa(),et.clear(),io(),await Lt(),await Ee();for(let n of It)lo(n)>0&&et.add(n.chatId);je(),document.getElementById("roles-search")?.addEventListener("input",n=>{je(n.target.value)}),document.getElementById("roles-refresh")?.addEventListener("click",async()=>{if(await Lt(),je(document.getElementById("roles-search")?.value??""),Ce&&Ae){let n=await ro(Ae,Ce),o=document.getElementById("roles-editor-textarea");o&&(o.value=n.content??""),ke=n.content??"",Zt(),en();let s=document.getElementById("roles-delete");s&&(s.style.display=n.hasRole?"":"none")}}),document.getElementById("roles-save")?.addEventListener("click",async function(){if(!(!Ce||!Ae)){this.disabled=!0,this.textContent="...";try{if(await qa(Ae,Ce,ke)){await Lt(),je(document.getElementById("roles-search")?.value??"");let o=document.getElementById("roles-delete");o&&(o.style.display="");let s=document.createElement("span");s.className="roles-saved-flash",s.textContent=` ${t("roles.saved")}`,document.querySelector(".roles-editor-footer")?.appendChild(s),setTimeout(()=>s.remove(),2e3)}else{let o=document.createElement("span");o.className="roles-saved-flash roles-save-error",o.textContent=ke.trim().length===0?` ${t("roles.emptyError")}`:` ${t("roles.saveFailed")}`,document.querySelector(".roles-editor-footer")?.appendChild(o),setTimeout(()=>o.remove(),3e3)}}finally{this.disabled=!1,this.textContent=t("roles.save")}}}),document.getElementById("roles-delete")?.addEventListener("click",async function(){if(!(!Ce||!Ae)&&confirm(t("roles.confirmDelete"))){this.disabled=!0,this.textContent="...";try{await Ua(Ae,Ce)&&(await Lt(),io(),je(document.getElementById("roles-search")?.value??""))}finally{this.disabled=!1,this.textContent=t("roles.delete")}}}),document.getElementById("roles-editor-textarea")?.addEventListener("input",n=>{ke=n.target.value,Zt(),en()})}async function Et(e){let n=await fetch(e);return{status:n.status,body:await n.json().catch(()=>({}))}}async function Ht(e,n,o){let s=await fetch(n,{method:e,headers:{"content-type":"application/json"},body:o?JSON.stringify(o):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}var Ge=(e,n)=>Ht("POST",e,n),za=(e,n)=>Ht("PUT",e,n),tn=[],uo=[],po="",Mt="",nn=new Map,xt=new Map,it=new Set,rt=new Set;function J(e){return document.getElementById(e)}function Ct(){return[...tn,...uo]}function Fe(e){let n=nn.get(e);return n||(n=new Set,nn.set(e,n)),n}function _a(e){return Ct().find(n=>n.key===e)}function mo(e){let n=(o,s,a)=>`<a href="${o}" style="padding:6px 14px;border-radius:8px;text-decoration:none;font-size:14px;font-weight:600;${a?"background:var(--accent);color:var(--on-accent)":"color:var(--muted);background:var(--surface-muted)"}">${s}</a>`;return`<div style="display:flex;gap:8px;margin-bottom:14px">${n("#/team",t("team.navHome"),e==="home")}${n("#/team/manage",t("team.navManage"),e==="manage")}</div>`}function Wa(){return`<section class="page">
|
|
727
727
|
<div class="page-heading"><div>
|
|
728
728
|
<p class="eyebrow">${t("team.eyebrow")}</p><h1>${t("team.homeTitle")}</h1>
|
|
729
729
|
<p class="tf-lede">${t("team.homeLede")}</p>
|
|
730
730
|
</div></div>
|
|
731
|
-
${
|
|
731
|
+
${mo("home")}
|
|
732
732
|
<div class="card" style="margin-bottom:16px">
|
|
733
733
|
<h2 style="margin-top:0">${t("team.localDeployTitle")}</h2>
|
|
734
734
|
<p>${t("team.myIdentity")}<b id="tf-owner">${t("team.unbound")}</b>
|
|
@@ -757,12 +757,12 @@ ${lo("home")}
|
|
|
757
757
|
</div>
|
|
758
758
|
</div>
|
|
759
759
|
</div>
|
|
760
|
-
</section>`}function
|
|
760
|
+
</section>`}function Ja(e){let n=(J("tf-search").value||"").trim().toLowerCase();if(n&&!((e.name||"")+" "+(e.cliId||"")+" "+(e.capability||"")).toLowerCase().includes(n))return!1;let o=J("tf-cli").value;return!(o&&e.cliId!==o||J("tf-fcap").checked&&!e.capability||J("tf-frole").checked&&!e.hasTeamRole)}function Ka(e,n){let o=[...e.deployments].sort((a,i)=>a.local===i.local?0:a.local?-1:1),s="";for(let a of o){let i=n.filter(p=>p.deployment.id===a.id);if(!i.length)continue;let l=a.id===po,c=l?t("team.tagLocal"):a.stale?t("team.tagRemoteStale"):t("team.tagRemote"),w=e.kind==="local"&&!l?` <button class="tf-rmmember ghost" data-team="${r(e.teamId)}" data-dep="${r(a.id)}" data-name="${r(a.name)}" style="font-size:12px">${t("team.removeMember")}</button>`:"",h=`${e.key}::${a.id}`,y=rt.has(h),k=i.filter(p=>Fe(e.key).has(p.larkAppId)).length;if(s+=`<div class="tf-dep-h" data-dk="${r(h)}" style="cursor:pointer;margin:10px 0 2px"><b>${y?"\u25BE":"\u25B8"} ${r(a.name)}</b> <span class="muted" style="font-size:12px">${t("team.depTag",{tag:c})} \xB7 ${t("team.depCount",{count:i.length})}${k?t("team.depSelected",{n:k}):""}</span>${w}</div>`,!!y){s+='<table style="width:100%;border-collapse:collapse;font-size:14px"><tbody>';for(let p of i){let E=r(p.larkAppId),O=Fe(e.key).has(p.larkAppId)?" checked":"",T=p.deployment.stale?"opacity:.55":"",f=l?`<input class="tf-cap" data-app="${E}" value="${r(p.capability||"")}" placeholder="${t("team.capPh")}" style="width:92%;padding:3px 6px">`:p.capability?r(p.capability):'<span class="muted">\u2014</span>',v=p.hasTeamRole?l?`<button class="tf-role" data-app="${E}" data-name="${r(p.name)}">${t("team.viewRole")}</button>`:t("team.hasRoleShort"):'<span class="muted">\u2014</span>';s+=`<tr style="${T}"><td style="padding:4px 8px"><input type="checkbox" class="tf-pick" data-tk="${r(e.key)}" data-app="${E}"${O}></td><td style="padding:4px 8px">${r(p.name)}</td><td style="padding:4px 8px" class="muted">${r(p.cliId)}</td><td style="padding:4px 8px">${f}</td><td style="padding:4px 8px">${v}</td></tr>`}s+="</tbody></table>"}}return s||(s=`<p class="muted" style="margin:8px 0 0">${t("team.noMatch")}</p>`),s+=`<div style="margin-top:12px;display:flex;gap:8px;flex-wrap:wrap;align-items:center"><input class="tf-gname" data-tk="${r(e.key)}" value="${r(xt.get(e.key)||"")}" placeholder="${t("team.gnamePh")}" style="min-width:200px"><button class="tf-grp primary" data-tk="${r(e.key)}">${t("team.pullGroupBtn")}</button><span class="muted" style="font-size:13px">${t("team.pullGroupHint")}</span><span class="tf-gout" data-tk="${r(e.key)}" style="font-size:13px;display:block;flex-basis:100%"></span></div>`,s}function qe(){let e=J("tf-teams"),n=Ct();if(!n.length){e.innerHTML=`<p class="muted">${t("team.noTeams")}</p>`,J("tf-count").textContent="";return}let o="",s=new Set,a=new Set;for(let c of n){let w=c.bots.filter(Ja);w.forEach(p=>s.add(p.larkAppId)),c.bots.forEach(p=>a.add(p.larkAppId));let h=new Set(w.map(p=>p.larkAppId));[...Fe(c.key)].forEach(p=>{h.has(p)||Fe(c.key).delete(p)});let y=!it.has(c.key),k=c.kind==="remote"?c.ok?` <span class="ok" style="font-size:12px">${t("team.connected")}</span>`:` <span class="err" style="font-size:12px">${t("team.connectFail",{error:r(c.error||"")})}</span>`:` <span class="muted" style="font-size:12px">${t("team.iHost")}</span>`;o+=`<div class="card" style="margin:0 0 12px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)"><div class="tf-team-h" data-tk="${r(c.key)}" style="cursor:pointer;display:flex;align-items:center;gap:8px;flex-wrap:wrap"><b style="font-size:15px">${y?"\u25B8":"\u25BE"} ${r(c.label)}</b>`+(c.sub?` <span class="muted" style="font-size:12px">${r(c.sub)}</span>`:"")+k+` <span class="muted" style="font-size:12px">\xB7 ${t("team.teamMeta",{deps:c.deployments.length,bots:c.bots.length})}</span></div>`,y||(o+=c.kind==="remote"&&!c.ok?`<p class="muted" style="margin:8px 0 0">${t("team.rosterFail")}</p>`:Ka(c,w)),o+="</div>"}e.innerHTML=o;let i=n.length>1?t("team.acrossTeams",{n:n.length}):"",l=s.size===a.size?`${a.size}`:`${s.size} / ${a.size}`;J("tf-count").textContent=`\xB7 ${l} ${t("team.botsWord")}${i}`,Va()}function Va(){let e=J("tf-teams");e.querySelectorAll(".tf-team-h").forEach(n=>{n.onclick=()=>{let o=n.dataset.tk;it.has(o)?it.delete(o):it.add(o),qe()}}),e.querySelectorAll(".tf-dep-h").forEach(n=>{n.onclick=()=>{let o=n.dataset.dk;rt.has(o)?rt.delete(o):rt.add(o),qe()}}),e.querySelectorAll(".tf-pick").forEach(n=>{n.onchange=()=>{let o=Fe(n.dataset.tk);n.checked?o.add(n.dataset.app):o.delete(n.dataset.app)}}),e.querySelectorAll(".tf-gname").forEach(n=>{n.oninput=()=>{xt.set(n.dataset.tk,n.value)}}),e.querySelectorAll(".tf-cap").forEach(n=>{n.onchange=async()=>{let o=n.dataset.app,s=n.value;await za("/api/team/local-bots/"+encodeURIComponent(o)+"/capability",{capability:s}),Ct().forEach(a=>{let i=a.bots.find(l=>l.larkAppId===o);i&&(i.capability=s.trim()||null)})}}),e.querySelectorAll(".tf-role").forEach(n=>{n.onclick=()=>Qa(n.dataset.app,n.dataset.name||"")}),e.querySelectorAll(".tf-rmmember").forEach(n=>{n.onclick=async o=>{o.stopPropagation(),confirm(t("team.removeMemberConfirm",{name:n.dataset.name||""}))&&(await Ht("DELETE",`/api/team/hosted/${encodeURIComponent(n.dataset.team)}/members/${encodeURIComponent(n.dataset.dep)}`),lt())}}),e.querySelectorAll(".tf-grp").forEach(n=>{n.onclick=async()=>{let o=n.dataset.tk,s=_a(o);if(!s)return;let a=[...Fe(o)],i=e.querySelector(`.tf-gout[data-tk="${CSS.escape(o)}"]`);if(!a.length){i.innerHTML=`<span class="err">${t("team.errPickBot")}</span>`;return}let l=(e.querySelector(`.tf-gname[data-tk="${CSS.escape(o)}"]`)?.value||"").trim()||t("team.defaultGroupName");i.innerHTML=`<span class="muted">${t("team.creatingGroup")}</span>`;let c=s.kind==="local"?await Ge("/api/team/federated-group",{name:l,larkAppIds:a,teamId:s.teamId}):await Ge("/api/team/remote-group",{hubUrl:s.hubUrl,teamId:s.teamId,name:l,larkAppIds:a});if(Ya(i,c.body,c.status),c.body?.ok){Fe(o).clear(),xt.delete(o);let w=i.innerHTML,h=()=>{let y=e.querySelector(`.tf-gout[data-tk="${CSS.escape(o)}"]`);y&&(y.innerHTML=w)};s.kind==="local"?lt().then(h):(qe(),h())}}})}function Ya(e,n,o){if(n?.ok&&n.chatId){let s=n.shareLink||"https://applink.feishu.cn/client/chat/open?openChatId="+encodeURIComponent(n.chatId),a=(n.invalidBotIds||[]).length?` <span class="err"> \xB7 ${t("team.invalidBots",{ids:r((n.invalidBotIds||[]).join(", "))})}</span>`:"",i=(n.invalidOwnerUnionIds||[]).length?`<span class="err"> \xB7 ${t("team.invalidOwners",{n:(n.invalidOwnerUnionIds||[]).length})}</span>`:"",l=n.missingOperatorIdentity?`<span class="err"> \xB7 ${t("team.missingIdentity")}</span>`:"",c=(n.skippedNoOwner||[]).length?`<span class="err"> \xB7 ${t("team.skippedNoOwner",{n:(n.skippedNoOwner||[]).length})}</span>`:"",w=n.delegatedTo?t("team.delegatedBy",{name:r(n.delegatedTo)}):"";e.innerHTML=`<span class="ok">${t("team.groupCreated")}</span>${w} \xB7 <a href="${r(s)}" target="_blank">${t("team.openInLark")}</a>${a}${i}${l}${c}`}else{let s=n?.error||o,a=s==="no_local_online_bot"?t("team.errNoLocalBot"):s==="all_bots_skipped_no_owner"?t("team.errAllSkipped"):s==="no_creator_available"?t("team.errNoCreator"):s==="delegation_timeout"?t("team.errDelegationTimeout"):t("team.errGroupCreate",{error:String(s)});e.innerHTML=`<span class="err">${r(String(a))}</span>`}}async function Qa(e,n){let o=await Et("/api/team/local-bots/"+encodeURIComponent(e)+"/role");J("tf-modal-title").textContent=t("team.roleModalTitleName",{name:n}),J("tf-modal-text").value=o.body?.role||"",J("tf-modal").dataset.app=e,J("tf-modal").style.display="flex"}function fo(){let e=Array.from(new Set(Ct().flatMap(s=>s.bots.map(a=>a.cliId)).filter(Boolean))).sort(),n=J("tf-cli"),o=n.value;n.innerHTML=`<option value="">${t("team.allCli")}</option>`+e.map(s=>`<option value="${r(s)}">${r(s)}</option>`).join(""),n.value=o}async function lt(){let n=(await Et("/api/team/hosted")).body;if(!n?.ok){tn=[],qe();return}po=n.deployment.deploymentId,Mt=n.suggestedHubUrl||"",J("tf-owner").textContent=n.deployment.ownerName||(n.deployment.ownerUnionId?t("team.bound"):t("team.unbound")),tn=(n.teams||[]).map(o=>({kind:"local",key:`local:${o.teamId}`,teamId:o.teamId,label:o.isDefault?t("team.myHostedTeam"):o.name,sub:"",ok:!0,deployments:o.deployments||[],bots:o.bots||[]})),fo(),qe()}async function Xa(){uo=((await Et("/api/team/remote-roster")).body?.memberships||[]).map(o=>{let s=o.roster?.deployments||[],a=s.find(l=>l.local),i=a?.name?t("team.remoteTeamLabel",{name:a.name}):o.teamName||o.teamId;return{kind:"remote",key:`${o.hubUrl}::${o.teamId}`,teamId:o.teamId,label:i,sub:o.hubUrl,ok:!!o.ok,error:o.error,hubUrl:o.hubUrl,deployments:s,bots:o.roster?.bots||[]}}),fo(),qe()}function go(e){e.innerHTML=Wa(),nn.clear(),xt.clear(),it.clear(),rt.clear(),["tf-search","tf-cli","tf-fcap","tf-frole"].forEach(n=>{let o=J(n);o.oninput=qe,o.onchange=qe}),J("tf-modal-cancel").onclick=()=>{J("tf-modal").style.display="none"},es(),lt(),Xa()}function Za(){return`<section class="page">
|
|
761
761
|
<div class="page-heading"><div>
|
|
762
762
|
<p class="eyebrow">${t("team.eyebrow")}</p><h1>${t("team.manageTitle")}</h1>
|
|
763
763
|
<p class="tf-lede">${t("team.manageLede")}</p>
|
|
764
764
|
</div></div>
|
|
765
|
-
${
|
|
765
|
+
${mo("manage")}
|
|
766
766
|
<div class="card" style="margin-bottom:16px">
|
|
767
767
|
<h2 style="margin-top:0">${t("team.hostedTitle")}</h2>
|
|
768
768
|
<p style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:6px">
|
|
@@ -781,16 +781,16 @@ ${lo("manage")}
|
|
|
781
781
|
</p>
|
|
782
782
|
<div id="tm-join-out" style="display:none;margin-top:6px"></div>
|
|
783
783
|
</div>
|
|
784
|
-
</section>`}async function
|
|
784
|
+
</section>`}async function on(){let n=(await Et("/api/team/hosted")).body,o=J("tm-list");Mt=n?.suggestedHubUrl||Mt;let s=n?.teams||[];if(!s.length){o.innerHTML=`<p class="muted">${t("team.noTeamsShort")}</p>`;return}o.innerHTML=s.map(a=>{let i=(a.deployments||[]).filter(l=>!l.local).length;return`<div class="card" style="margin:0 0 8px;padding:10px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
785
785
|
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
786
|
-
<b>${
|
|
787
|
-
<span class="muted" style="font-size:12px">\xB7 ${t("team.manageMetaDeps",{count:(a.deployments||[]).length})}${
|
|
786
|
+
<b>${r(a.name)}</b>${a.isDefault?` <span class="muted" style="font-size:12px">${t("team.default")}</span>`:""}
|
|
787
|
+
<span class="muted" style="font-size:12px">\xB7 ${t("team.manageMetaDeps",{count:(a.deployments||[]).length})}${i?t("team.manageMetaRemote",{r:i}):""} \xB7 ${t("team.manageMetaBots",{count:(a.bots||[]).length})}</span>
|
|
788
788
|
<span style="margin-left:auto;display:flex;gap:6px">
|
|
789
|
-
<button class="tm-invite ghost" data-team="${
|
|
790
|
-
${a.isDefault?"":`<button class="tm-del ghost" data-team="${
|
|
789
|
+
<button class="tm-invite ghost" data-team="${r(a.teamId)}" style="font-size:12px">${t("team.genInvite")}</button>
|
|
790
|
+
${a.isDefault?"":`<button class="tm-del ghost" data-team="${r(a.teamId)}" data-name="${r(a.name)}" style="font-size:12px">${t("team.delBtn")}</button>`}
|
|
791
791
|
</span>
|
|
792
792
|
</div>
|
|
793
|
-
<div class="tm-inv-out" data-team="${
|
|
793
|
+
<div class="tm-inv-out" data-team="${r(a.teamId)}" style="display:none;margin-top:6px;font-size:13px"></div></div>`}).join(""),o.querySelectorAll(".tm-invite").forEach(a=>{a.onclick=async()=>{let i=a.dataset.team,l=o.querySelector(`.tm-inv-out[data-team="${CSS.escape(i)}"]`);l.style.display="",l.innerHTML=`<span class="muted">${t("team.generating")}</span>`;let c=await Ge("/api/team/local-invite",{teamId:i});c.body?.code?l.innerHTML=`${t("team.inviteResultLede")}<br>${t("team.inviteHub")}<code>${r(Mt)}</code><br>${t("team.inviteCode")}<code style="font-size:15px">${r(c.body.code)}</code>`:l.innerHTML=`<span class="err">${t("team.genFail")}</span>`}}),o.querySelectorAll(".tm-del").forEach(a=>{a.onclick=async()=>{confirm(t("team.delConfirm",{name:a.dataset.name||""}))&&(await Ht("DELETE","/api/team/hosted/"+encodeURIComponent(a.dataset.team)),on())}})}function bo(e){e.innerHTML=Za(),J("tm-create").onclick=async()=>{let n=J("tm-newname").value.trim(),o=e.querySelector(".tm-cout");if(!n){o.innerHTML=`<span class="err">${t("team.errName")}</span>`;return}o.innerHTML=`<span class="muted">${t("team.creating")}</span>`;let s=await Ge("/api/team/hosted",{name:n});s.body?.ok?(o.innerHTML=`<span class="ok">${t("team.created")}</span>`,J("tm-newname").value="",on()):o.innerHTML=`<span class="err">${t("team.createFail",{error:r(String(s.body?.error||s.status))})}</span>`},J("tm-join").onclick=async()=>{let n=J("tm-hub").value.trim(),o=J("tm-code").value.trim(),s=J("tm-join-out");if(s.style.display="",!n||!o){s.innerHTML=`<span class="err">${t("team.errHubCode")}</span>`;return}s.innerHTML=`<span class="muted">${t("team.joining")}</span>`;let a=await Ge("/api/team/join-remote",{hubUrl:n,inviteCode:o});if(a.body?.ok)s.innerHTML=`<span class="ok">${t("team.joined",{name:r(a.body.teamName||"")})}</span>`,J("tm-code").value="";else{let i=a.body?.error||a.status,l=i==="cannot_join_self"?t("team.joinErrSelf"):i==="deployment_already_joined"?t("team.joinErrAlready"):i==="hub_unreachable"?t("team.joinErrUnreachable"):i==="hub_timeout"?t("team.joinErrTimeout"):t("team.joinErrGeneric",{error:String(i)});s.innerHTML=`<span class="err">${r(String(l))}</span>`}},on()}function es(){J("tf-autobind").onclick=async()=>{let e=J("tf-bind-out");e.style.display="",e.innerHTML=`<span class="muted">${t("team.identifying")}</span>`;let o=(await Ge("/api/team/identity/auto-bind")).body;if(o?.ok&&o.owner){e.innerHTML=`<span class="ok">${t("team.bound2",{name:r(o.owner.name||o.owner.unionId)})}</span>`,lt();return}if(o?.ok&&o.needChoice&&Array.isArray(o.candidates)){let s=o.candidates.map(a=>`<button class="tf-pickowner ghost" data-union="${r(a.unionId)}" style="margin:2px">${r(a.name||a.unionId)}</button>`).join(" ");e.innerHTML=`${t("team.multiCandidate")}<br>${s}`,e.querySelectorAll(".tf-pickowner").forEach(a=>{a.onclick=async()=>{e.innerHTML=`<span class="muted">${t("team.binding")}</span>`;let l=(await Ge("/api/team/identity/auto-bind",{unionId:a.dataset.union})).body;l?.ok&&l.owner?(e.innerHTML=`<span class="ok">${t("team.bound2",{name:r(l.owner.name||l.owner.unionId)})}</span>`,lt()):e.innerHTML=`<span class="err">${t("team.bindFail",{error:r(String(l?.error||"unknown"))})}</span>`}});return}if(o?.error==="no_candidates"){e.innerHTML=`<span class="err">${t("team.noCandidates")}</span>`;return}e.innerHTML=`<span class="err">${t("team.bindFail",{error:r(String(o?.error||"unknown"))})}</span>`}}async function an(e){let n=await fetch(e);return{status:n.status,body:await n.json().catch(()=>({}))}}async function rn(e,n,o){let s=await fetch(n,{method:e,headers:{"content-type":"application/json"},body:o?JSON.stringify(o):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}function K(e){return document.getElementById(e)}function ze(e){return(K(e).value||"").trim()}var ln=[],cn=[];function ts(){return`<section class="page">
|
|
794
794
|
<div class="page-heading">
|
|
795
795
|
<div>
|
|
796
796
|
<p class="eyebrow">Webhook</p>
|
|
@@ -852,28 +852,28 @@ ${lo("manage")}
|
|
|
852
852
|
<h2 style="margin-top:0">${t("connectors.listTitle")} <span class="muted" id="cn-count" style="font-size:13px"></span></h2>
|
|
853
853
|
<div id="cn-list">${t("connectors.loading")}</div>
|
|
854
854
|
</div>
|
|
855
|
-
</section>`}function
|
|
855
|
+
</section>`}function sn(){let e=K("cn-kind").value,n=K("cn-mode").value;document.querySelectorAll(".cn-wf").forEach(o=>{o.style.display=e==="workflow"?"":"none"}),document.querySelectorAll(".cn-fixed").forEach(o=>{o.style.display=n==="fixed"?"":"none"}),document.querySelectorAll(".cn-allow").forEach(o=>{o.style.display=n==="fixed"?"none":""}),document.querySelectorAll(".cn-dyn").forEach(o=>{o.style.display=n==="dynamic"?"":"none"}),document.querySelectorAll(".cn-life").forEach(o=>{o.style.display=n==="new-group"?"":"none"})}function ho(e){return`${location.origin}/webhook/${encodeURIComponent(e)}`}function ns(e){return e==="fixed"?t("connectors.modeLabelFixed"):e==="new-group"?t("connectors.modeLabelNewGroup"):t("connectors.modeLabelDynamic")}function os(e){return e==="workflow"?t("connectors.kindLabelWorkflow"):t("connectors.kindLabelTurn")}function dn(e){return cn.find(o=>o.chatId===e)?.name||e}function as(e){return cn.filter(n=>n.bots.includes(e))}function wo(){let e=K("cn-bot").value,n=as(e),o=c=>`<option value="${r(c.chatId)}">${r(c.name||c.chatId)}</option>`,s=K("cn-chat-sel"),a=s.value;s.innerHTML=n.length?n.map(o).join(""):`<option value="">${t("connectors.noBotGroups")}</option>`,a&&n.some(c=>c.chatId===a)&&(s.value=a);let i=K("cn-allow-sel"),l=new Set(Array.from(i.selectedOptions).map(c=>c.value));i.innerHTML=n.map(o).join(""),Array.from(i.options).forEach(c=>{l.has(c.value)&&(c.selected=!0)})}function ss(e){let n=K("cn-list");if(K("cn-count").textContent=e.length?t("connectors.count",{count:e.length}):"",!e.length){n.innerHTML=`<p class="muted">${t("connectors.empty")}</p>`;return}n.innerHTML=e.map(o=>{let s=ln.find(w=>w.larkAppId===o.target.botId),a=ho(o.id),i=(o.verify?.type??"token")==="token",l=i?t("connectors.badgeToken"):t("connectors.badgeSign"),c=o.target.mode==="fixed"&&o.target.chatId?` \xB7 ${t("connectors.dest",{name:r(dn(o.target.chatId))})}`:"";return`<div class="card" style="margin:0 0 10px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
856
856
|
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
857
|
-
<b style="font-size:15px">${
|
|
857
|
+
<b style="font-size:15px">${r(o.name)}</b>
|
|
858
858
|
<span class="${o.enabled?"ok":"muted"}" style="font-size:12px">${o.enabled?t("connectors.enabled"):t("connectors.disabled")}</span>
|
|
859
|
-
<span class="muted" style="font-size:12px">\xB7 ${
|
|
859
|
+
<span class="muted" style="font-size:12px">\xB7 ${r(s?.botName||o.target.botId)} \xB7 ${os(o.target.kind)} \xB7 ${ns(o.target.mode)}${c} \xB7 ${l}</span>
|
|
860
860
|
<span style="margin-left:auto;display:flex;gap:6px">
|
|
861
|
-
<button class="cn-toggle ghost" data-id="${
|
|
862
|
-
<button class="cn-del ghost" data-id="${
|
|
861
|
+
<button class="cn-toggle ghost" data-id="${r(o.id)}" data-on="${o.enabled}" style="font-size:12px">${o.enabled?t("connectors.btnDisable"):t("connectors.btnEnable")}</button>
|
|
862
|
+
<button class="cn-del ghost" data-id="${r(o.id)}" style="font-size:12px">${t("connectors.btnDel")}</button>
|
|
863
863
|
</span>
|
|
864
864
|
</div>
|
|
865
865
|
<div style="margin-top:6px;font-size:13px;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
866
|
-
<span class="muted">${t("connectors.webhookUrl")}</span><code style="font-size:12px;word-break:break-all">${
|
|
867
|
-
<button class="cn-copy ghost" data-url="${
|
|
868
|
-
</div>${
|
|
866
|
+
<span class="muted">${t("connectors.webhookUrl")}</span><code style="font-size:12px;word-break:break-all">${r(a)}${i?"/<token>":""}</code>
|
|
867
|
+
<button class="cn-copy ghost" data-url="${r(a)}" style="font-size:12px">${t("connectors.copy")}</button>
|
|
868
|
+
</div>${i?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.tokenHint")}</div>`:""}${o.target.mode==="dynamic"?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.dynamicReqHint")}</div>`:""}${o.promptEnvelope?.instruction?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.instructionPrefix")}${r(o.promptEnvelope.instruction)}</div>`:""}</div>`}).join(""),n.querySelectorAll(".cn-copy").forEach(o=>{o.onclick=()=>{navigator.clipboard?.writeText(o.dataset.url),o.textContent=t("connectors.copied"),setTimeout(()=>o.textContent=t("connectors.copy"),1200)}}),n.querySelectorAll(".cn-toggle").forEach(o=>{o.onclick=async()=>{await rn("PATCH","/api/connectors/"+encodeURIComponent(o.dataset.id),{enabled:o.dataset.on!=="true"}),At()}}),n.querySelectorAll(".cn-del").forEach(o=>{o.onclick=async()=>{confirm(t("connectors.delConfirm"))&&(await rn("DELETE","/api/connectors/"+encodeURIComponent(o.dataset.id)),At())}})}async function At(){let[e,n,o]=await Promise.all([an("/api/bots"),an("/api/connectors"),an("/api/groups")]);ln=(e.body?.bots||[]).map(i=>({larkAppId:i.larkAppId,botName:i.botName||i.larkAppId})),cn=(o.body?.chats||[]).map(i=>({chatId:i.chatId,name:i.name||"",bots:(i.memberBots||[]).filter(l=>l.inChat).map(l=>l.larkAppId)}));let s=K("cn-bot"),a=s.value;s.innerHTML=ln.map(i=>`<option value="${r(i.larkAppId)}">${r(i.botName)}</option>`).join("")||`<option value="">${t("connectors.noOnlineBots")}</option>`,a&&(s.value=a),wo(),ss(n.body?.connectors||[])}function yo(e){e.innerHTML=ts(),K("cn-kind").onchange=sn,K("cn-mode").onchange=sn,K("cn-bot").onchange=wo,K("cn-chat-manual").onclick=n=>{n.preventDefault();let o=K("cn-chat"),s=K("cn-chat-sel"),a=o.style.display==="none";o.style.display=a?"":"none",s.style.display=a?"none":"",K("cn-chat-manual").textContent=a?t("connectors.chatListLink"):t("connectors.chatManualLink")},sn(),K("cn-create").onclick=async()=>{let n=K("cn-create-out"),o=ze("cn-name"),s=K("cn-bot").value;if(!o){n.innerHTML=`<span class="err">${t("connectors.errName")}</span>`;return}if(!s){n.innerHTML=`<span class="err">${t("connectors.errBot")}</span>`;return}let a=K("cn-kind").value,i=K("cn-mode").value,l={name:o,enabled:!0,target:{kind:a,mode:i,botId:s},promptEnvelope:{sourceName:o}},c=ze("cn-instruction");if(c&&(l.promptEnvelope.instruction=c),a==="workflow"){if(!ze("cn-wf")){n.innerHTML=`<span class="err">${t("connectors.errWf")}</span>`;return}l.target.workflowId=ze("cn-wf")}if(i==="fixed"){let k=K("cn-chat").style.display!=="none"?ze("cn-chat"):K("cn-chat-sel").value;if(!k){n.innerHTML=`<span class="err">${t("connectors.errChat")}</span>`;return}l.target.chatId=k}else{let y=Array.from(K("cn-allow-sel").selectedOptions).map(k=>k.value).filter(Boolean);y.length&&(l.target.allowChats=y)}if(i==="new-group"){let y=ze("cn-dedup");l.lifecycleExtractors=y?{dedupKey:y}:null}l.verify={type:K("cn-verify").value};let w=ze("cn-secret");w&&(l.secret=w),n.innerHTML=`<span class="muted">${t("connectors.creating")}</span>`;let h=await rn("POST","/api/connectors",l);if(h.status===201&&h.body?.ok){n.innerHTML="";let y=K("cn-created");y.style.display="";let k=h.body.webhookUrl||ho(h.body.connector.id),p=h.body.secret,E=(h.body.connector?.verify?.type??"token")==="token",O=i==="dynamic",T=O?l.target.allowChats?.[0]||"<chatId>":"",f=O?`${r(k)}?chatId=${r(T)}`:r(k),v;if(E&&O){let d=T!=="<chatId>"?`\uFF08${r(dn(l.target.allowChats[0]))}\uFF09`:"";v=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicLede",{gn:d})}</p>
|
|
869
869
|
<pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${f}' -H 'content-type: application/json' -d '{}'</code></pre>
|
|
870
870
|
<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicNote")}</p>`}else E?v=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageTokenLede")}</p>
|
|
871
871
|
<pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${f}' -H 'content-type: application/json' -d '{}'</code></pre>
|
|
872
872
|
<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageTokenNote")}</p>`:v=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageHmac")}${O?t("connectors.usageHmacDynamic"):""}</p>`;y.innerHTML=`<div class="card" style="padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
873
|
-
<p class="ok" style="margin:0 0 6px">${t("connectors.createdPrefix",{name:
|
|
874
|
-
<p style="margin:4px 0;font-size:13px"><span class="muted">${t("connectors.webhookUrl")}</span><code style="word-break:break-all">${
|
|
875
|
-
${p?`<p style="margin:4px 0;font-size:13px"><span class="muted">${E?t("connectors.tokenLabel"):t("connectors.signLabel")}${t("connectors.secretOnce")}</span><code>${
|
|
876
|
-
${v}</div>`,["cn-name","cn-wf","cn-chat","cn-dedup","cn-secret","cn-instruction"].forEach(d=>{
|
|
873
|
+
<p class="ok" style="margin:0 0 6px">${t("connectors.createdPrefix",{name:r(o)})}${i==="fixed"&&l.target.chatId?`<span class="muted" style="font-weight:400;font-size:13px"> \xB7 ${t("connectors.createdDest",{name:r(dn(l.target.chatId))})}</span>`:""}</p>
|
|
874
|
+
<p style="margin:4px 0;font-size:13px"><span class="muted">${t("connectors.webhookUrl")}</span><code style="word-break:break-all">${r(k)}</code></p>
|
|
875
|
+
${p?`<p style="margin:4px 0;font-size:13px"><span class="muted">${E?t("connectors.tokenLabel"):t("connectors.signLabel")}${t("connectors.secretOnce")}</span><code>${r(p)}</code></p>`:""}
|
|
876
|
+
${v}</div>`,["cn-name","cn-wf","cn-chat","cn-dedup","cn-secret","cn-instruction"].forEach(d=>{K(d).value=""}),K("cn-allow-sel").selectedIndex=-1,At()}else{let y=h.body?.error||h.status;n.innerHTML=`<span class="err">${t("connectors.createFailed",{error:r(String(y))})}</span>`}},At()}var ge=null,ct=null,dt=!0;function vo(e){return{publicReadOnly:e?.publicReadOnly===!0,openTerminalInFeishu:e?.openTerminalInFeishu===!0,maintenance:e?.maintenance&&typeof e.maintenance=="object"?e.maintenance:{},localDevInstall:e?.localDevInstall===!0}}function is(e,n){let o=e?.[n]??{};return{enabled:o.enabled===!0,time:typeof o.time=="string"?o.time:"04:00"}}function rs(){return`<section class="page">
|
|
877
877
|
<div class="page-heading">
|
|
878
878
|
<div>
|
|
879
879
|
<p class="eyebrow">${t("nav.settings")}</p>
|
|
@@ -882,7 +882,7 @@ ${lo("manage")}
|
|
|
882
882
|
</div>
|
|
883
883
|
</div>
|
|
884
884
|
<div id="settings-body"></div>
|
|
885
|
-
</section>`}function
|
|
885
|
+
</section>`}function ls(e){let{enabled:n,time:o}=is(ge.maintenance,"autoUpdate"),s=e?"disabled":"";return`<label class="toggle-row">
|
|
886
886
|
<input type="checkbox" data-maint="autoUpdate" ${n?"checked":""} ${s}>
|
|
887
887
|
<span class="switch" aria-hidden="true"></span>
|
|
888
888
|
<span class="toggle-tx"><strong>${t("settings.autoUpdate")}</strong>
|
|
@@ -890,20 +890,20 @@ ${lo("manage")}
|
|
|
890
890
|
</label>
|
|
891
891
|
<div class="maint-time">
|
|
892
892
|
<label>${t("settings.maintenanceTime")}
|
|
893
|
-
<input type="time" data-maint-time="autoUpdate" value="${
|
|
893
|
+
<input type="time" data-maint-time="autoUpdate" value="${r(o)}" ${s}>
|
|
894
894
|
</label>
|
|
895
|
-
</div>`}function
|
|
896
|
-
<input type="checkbox" data-maint="autoRestart" ${
|
|
895
|
+
</div>`}function ds(e){return`<label class="toggle-row">
|
|
896
|
+
<input type="checkbox" data-maint="autoRestart" ${ge.maintenance.autoRestart?.enabled===!0?"checked":""} ${e?"disabled":""}>
|
|
897
897
|
<span class="switch" aria-hidden="true"></span>
|
|
898
898
|
<span class="toggle-tx"><strong>${t("settings.autoRestart")}</strong>
|
|
899
899
|
<small>${t("settings.autoRestartHelp")}</small></span>
|
|
900
|
-
</label>`}function
|
|
900
|
+
</label>`}function cs(){if(ct)return`<p class="hint-warn">${t("settings.loadFailed")}: ${r(ct)}</p>`;if(!ge)return`<p class="empty">${t("settings.loading")}</p>`;let e=dt?"":"disabled",n=!dt||ge.localDevInstall;return`<div class="settings-grid">
|
|
901
901
|
<article class="bd-card settings-card">
|
|
902
|
-
${
|
|
902
|
+
${dt?"":`<p class="hint-warn">${t("settings.readOnlyVisitor")}</p>`}
|
|
903
903
|
<section class="bd-section">
|
|
904
904
|
<h3 class="bd-section-title">${t("settings.sectionAccess")}</h3>
|
|
905
905
|
<label class="toggle-row">
|
|
906
|
-
<input type="checkbox" data-setting="publicReadOnly" ${
|
|
906
|
+
<input type="checkbox" data-setting="publicReadOnly" ${ge.publicReadOnly?"checked":""} ${e}>
|
|
907
907
|
<span class="switch" aria-hidden="true"></span>
|
|
908
908
|
<span class="toggle-tx"><strong>${t("settings.publicReadOnly")}</strong>
|
|
909
909
|
<small>${t("settings.publicReadOnlyHelp")}</small></span>
|
|
@@ -912,7 +912,7 @@ ${lo("manage")}
|
|
|
912
912
|
<section class="bd-section">
|
|
913
913
|
<h3 class="bd-section-title">${t("settings.sectionCards")}</h3>
|
|
914
914
|
<label class="toggle-row">
|
|
915
|
-
<input type="checkbox" data-setting="openTerminalInFeishu" ${
|
|
915
|
+
<input type="checkbox" data-setting="openTerminalInFeishu" ${ge.openTerminalInFeishu?"checked":""} ${e}>
|
|
916
916
|
<span class="switch" aria-hidden="true"></span>
|
|
917
917
|
<span class="toggle-tx"><strong>${t("settings.openTerminalInFeishu")}</strong>
|
|
918
918
|
<small>${t("settings.openTerminalInFeishuHelp")}</small></span>
|
|
@@ -920,15 +920,15 @@ ${lo("manage")}
|
|
|
920
920
|
</section>
|
|
921
921
|
<section class="bd-section">
|
|
922
922
|
<h3 class="bd-section-title">${t("settings.sectionMaintenance")}</h3>
|
|
923
|
-
${
|
|
924
|
-
${
|
|
925
|
-
${
|
|
923
|
+
${ls(n)}
|
|
924
|
+
${ge.localDevInstall?`<p class="hint-warn">${t("settings.autoUpdateLocalDev")}</p>`:""}
|
|
925
|
+
${ds(!dt||ge.maintenance.autoUpdate?.enabled!==!0)}
|
|
926
926
|
</section>
|
|
927
927
|
<div class="actions settings-actions">
|
|
928
928
|
<span class="oncall-status" data-settings-status></span>
|
|
929
929
|
</div>
|
|
930
930
|
</article>
|
|
931
|
-
</div>`}async function
|
|
931
|
+
</div>`}async function us(){try{let e=await fetch("/api/settings"),n=await e.json().catch(()=>({}));if(!e.ok){ge=null,ct=n?.error??`HTTP ${e.status}`;return}ge=vo(n.settings),dt=n.authed===!0,ct=null}catch(e){ge=null,ct=e?.message??String(e)}}async function ko(e){e.innerHTML=rs();let n=e.querySelector("#settings-body");function o(){n.innerHTML=cs(),i()}function s(){return n.querySelector("[data-settings-status]")}async function a(l,c,w){if(!ge)return;w.disabled=!0;let h=s();h&&(h.textContent=t("settings.saving"),h.className="oncall-status");try{let y=await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(l)}),k=await y.json().catch(()=>({}));if(!y.ok||k.ok===!1)throw new Error(k?.error??`HTTP ${y.status}`);ge=vo(k.settings),h&&(h.textContent=t("settings.saved"),h.classList.add("hint-ok"))}catch(y){c(),h&&(h.textContent=`${t("settings.saveFailed")}: ${y?.message??y}`,h.classList.add("hint-warn-inline"))}finally{w.disabled=!1}}function i(){n.querySelectorAll("input[data-setting]").forEach(c=>{c.addEventListener("change",()=>{let w=c.dataset.setting,h=!c.checked;a({[w]:c.checked},()=>{c.checked=h},c)})});let l=(c,w,h)=>{let k=n.querySelector(`input[data-maint="${c}"]`)?.checked??!1,p;if(c==="autoUpdate"){let E=n.querySelector('input[data-maint-time="autoUpdate"]');p={enabled:k,time:E?.value||"04:00"}}else p={enabled:k};a({maintenance:{[c]:p}},h,w).then(()=>o())};n.querySelectorAll("input[data-maint]").forEach(c=>{c.addEventListener("change",()=>{let w=c.dataset.maint,h=!c.checked;l(w,c,()=>{c.checked=h})})}),n.querySelectorAll("input[data-maint-time]").forEach(c=>{c.addEventListener("change",()=>{let w=c.dataset.maintTime,h=c.defaultValue;l(w,c,()=>{c.value=h})})})}o(),await us(),o()}function ps(){let e=[["",t("workflow.filter.nonTerminal")],["all",t("workflow.filter.all")],["pending",Ue("pending")],["running",Ue("running")],["waiting",Ue("waiting")],["succeeded",Ue("succeeded")],["failed",Ue("failed")],["cancelled",Ue("cancelled")]];return`
|
|
932
932
|
<nav class="wf-subnav">
|
|
933
933
|
<a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${m(t("workflow.subnav.runs"))}</a>
|
|
934
934
|
<a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${m(t("workflow.subnav.catalog"))}</a>
|
|
@@ -948,15 +948,15 @@ ${lo("manage")}
|
|
|
948
948
|
</tr></thead>
|
|
949
949
|
<tbody id="wf-tbody"></tbody>
|
|
950
950
|
</table>
|
|
951
|
-
`}var
|
|
951
|
+
`}var ms=5e3,fs=2e3,ut=new Set(["succeeded","failed","cancelled"]);function m(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function gs(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 Oe(e){return`<span class="${ut.has(e)?"wf-status terminal":"wf-status live"} wf-status-${m(e)}">${m(Ue(e))}</span>`}function Ue(e){let n=`workflow.status.${e}`,o=t(n);return o===n?e:o}function Lo(e){let n=location.hash.match(/^#\/workflows\/([^?#]+)(?:\?([^#]*))?$/);if(n){let o=new URLSearchParams(n[2]??"");return hs(e,decodeURIComponent(n[1]),{focusAttemptId:o.get("attempt")??void 0})}return bs(e)}function bs(e){e.innerHTML=ps();let n=e.querySelector("#wf-tbody"),o=e.querySelector("#wf-filters"),s=e.querySelector("#wf-last-load"),a=[],i=null,l=!1,c=null,w=!1;function h(T){let v=(new FormData(o).get("q")??"").trim().toLowerCase();return v?T.filter(d=>d.runId.toLowerCase().includes(v)||d.workflowId.toLowerCase().includes(v)||(d.chatId??"").toLowerCase().includes(v)):T}function y(){let T=h(a);if(T.length===0){n.innerHTML=`<tr><td colspan="7" class="empty">${c?m(t("workflow.list.failedLoad",{error:c})):a.length===0?m(t("workflow.list.noRuns")):m(t("workflow.list.noFilterMatch"))}</td></tr>`;return}n.innerHTML=T.map(f=>{let v=`${f.dEf}/${f.dAct}/${f.dWait}`,d=f.dEf+f.dAct+f.dWait>0?"wf-dangling has":"wf-dangling none",b=[];f.chatId&&b.push(m(f.chatId)),f.larkAppId&&b.push(`<span class="muted">${m(f.larkAppId)}</span>`);let x=b.length>0?b.join("<br/>"):"\u2014",H=ys(f);return`<tr data-runid="${m(f.runId)}">
|
|
952
952
|
<td><a href="#/workflows/${encodeURIComponent(f.runId)}"><code>${m(f.runId)}</code></a></td>
|
|
953
953
|
<td>${m(f.workflowId)}</td>
|
|
954
954
|
<td>${Oe(f.status)}${f.failedNodeId?` <span class="muted">(${m(f.failedNodeId)})</span>`:""}${H}</td>
|
|
955
955
|
<td>${f.lastSeq}</td>
|
|
956
956
|
<td class="${d}">${v}</td>
|
|
957
|
-
<td title="${m(new Date(f.updatedAt).toISOString())}">${
|
|
957
|
+
<td title="${m(new Date(f.updatedAt).toISOString())}">${gs(f.updatedAt)}</td>
|
|
958
958
|
<td>${x}</td>
|
|
959
|
-
</tr>`}).join("")}function k(){c?(s.textContent=t("workflow.list.error",{error:c}),s.classList.add("error")):(s.textContent=t("workflow.list.loaded",{count:a.length,time:new Date().toLocaleTimeString()}),s.classList.remove("error"))}async function p(){if(!(w||l)&&!document.hidden){l=!0;try{let T=o.elements.namedItem("status")?.value??"",f=new URLSearchParams;T==="all"?f.set("all","1"):T&&f.set("status",T);let v="/api/workflows/runs"+(f.toString()?`?${f}`:""),d=await fetch(v);d.ok?(a=(await d.json()).runs??[],c=null):(c=`HTTP ${d.status}`,a=[])}catch(T){c=T?.message??String(T),a=[]}finally{l=!1,w||(y(),k())}}}function E(){
|
|
959
|
+
</tr>`}).join("")}function k(){c?(s.textContent=t("workflow.list.error",{error:c}),s.classList.add("error")):(s.textContent=t("workflow.list.loaded",{count:a.length,time:new Date().toLocaleTimeString()}),s.classList.remove("error"))}async function p(){if(!(w||l)&&!document.hidden){l=!0;try{let T=o.elements.namedItem("status")?.value??"",f=new URLSearchParams;T==="all"?f.set("all","1"):T&&f.set("status",T);let v="/api/workflows/runs"+(f.toString()?`?${f}`:""),d=await fetch(v);d.ok?(a=(await d.json()).runs??[],c=null):(c=`HTTP ${d.status}`,a=[])}catch(T){c=T?.message??String(T),a=[]}finally{l=!1,w||(y(),k())}}}function E(){i!==null&&window.clearTimeout(i),i=window.setTimeout(async()=>{await p(),w||E()},ms)}function O(){document.hidden||p()}return o.addEventListener("input",()=>{y()}),o.addEventListener("change",T=>{T.target.getAttribute("name")==="status"&&p()}),document.addEventListener("visibilitychange",O),p().then(()=>{w||E()}),()=>{w=!0,i!==null&&window.clearTimeout(i),document.removeEventListener("visibilitychange",O)}}function hs(e,n,o={}){e.innerHTML=`
|
|
960
960
|
<div class="wf-detail-head">
|
|
961
961
|
<a class="btn-link" href="#/workflows">${m(t("workflow.detail.back"))}</a>
|
|
962
962
|
<div>
|
|
@@ -1012,35 +1012,35 @@ ${lo("manage")}
|
|
|
1012
1012
|
</div>
|
|
1013
1013
|
<div id="wf-event-meta" class="muted"></div>
|
|
1014
1014
|
</section>
|
|
1015
|
-
`;let s=e.querySelector("#wf-detail-subtitle"),a=e.querySelector("#wf-detail-refresh"),
|
|
1015
|
+
`;let s=e.querySelector("#wf-detail-subtitle"),a=e.querySelector("#wf-detail-refresh"),i=e.querySelector("#wf-detail-error"),l=e.querySelector("#wf-cancel-status"),c=e.querySelector("#wf-summary"),w=e.querySelector("#wf-dangling-panel"),h=e.querySelector("#wf-parallel-view"),y=e.querySelector("#wf-parallel-meta"),k=e.querySelector("#wf-node-tbody"),p=e.querySelector("#wf-io-list"),E=e.querySelector(".wf-timeline-scroll"),O=e.querySelector("#wf-event-tbody"),T=e.querySelector("#wf-event-meta"),f=e.querySelector("#wf-cancel-run"),v=e.querySelector("#wf-load-older"),d=null,b=[],x=new Set,H=null,I=null,C=!1,q=0,F=null,ie=!1,te=!1,he=!1,ne=new Set,le=new Map,me=new Map,$e=new Map,Be=new Set,Se=new Map,ae=new Set,re=new Map,V=new Map,Ie=0,Me=o.focusAttemptId;function se($){if(!$){i.hidden=!0,i.textContent="";return}i.hidden=!1,i.textContent=$}function u($){if(!$){l.hidden=!0,l.textContent="";return}l.hidden=!1,l.textContent=$}async function g(){let $=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/snapshot`);if($.status===404)throw new Error(t("workflow.detail.unknownRun"));if(!$.ok)throw new Error(t("workflow.detail.snapshotHttp",{status:$.status}));d=await $.json()}async function S($){let Z=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/events?${$}`);if(Z.status===404)throw new Error(t("workflow.detail.unknownRun"));if(!Z.ok)throw new Error(t("workflow.detail.eventsHttp",{status:Z.status}));return await Z.json()}function L($,Z){let A=$.filter(B=>x.has(B.eventId)?!1:(x.add(B.eventId),!0));A.length!==0&&(b=Z==="prepend"?[...A,...b]:[...b,...A],b.sort((B,fe)=>pt(B.eventId)-pt(fe.eventId)))}async function M(){await g();let $=await S(new URLSearchParams({tail:"100"}));b=[],x=new Set,L($.events,"append"),H=$.oldestSeq,I=$.newestSeq,C=$.hasOlder,q=$.totalCount,W()}async function U(){if(!(ie||te||document.hidden)){te=!0;try{if(await g(),I!==null){let $=await S(new URLSearchParams({afterSeq:String(I),limit:"200"}));L($.events,"append"),$.newestSeq!==null&&(I=$.newestSeq),H===null&&$.oldestSeq!==null&&(H=$.oldestSeq),q=$.totalCount}else{let $=await S(new URLSearchParams({tail:"1"}));L($.events,"append"),H=$.oldestSeq,I=$.newestSeq,C=$.hasOlder,q=$.totalCount}se(null),W()}catch($){se($?.message??String($))}finally{te=!1}}}async function G(){if(!(H===null||!C)){v.disabled=!0;try{let $=await S(new URLSearchParams({beforeSeq:String(H),limit:"100"}));L($.events,"prepend"),$.oldestSeq!==null&&(H=$.oldestSeq),C=$.hasOlder,q=$.totalCount,se(null),W()}catch($){se($?.message??String($))}finally{v.disabled=!1}}}async function X(){if(!d||ut.has(d.run.status)||he)return;if(!d.chatBinding?.larkAppId){se(t("workflow.detail.cancelUnavailable",{runId:n}));return}let $=vs(d),Z=t("workflow.detail.cancelConfirm",{runId:n,...$});if(window.confirm(Z)){he=!0,f.disabled=!0;try{let A=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/cancel`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"cancelled via dashboard"})});if(A.status===401)throw new Error(t("workflow.detail.writeAccessCancel"));let B=await A.json().catch(()=>({}));if(!A.ok||!B.ok)throw new Error(B.hint??B.error??t("workflow.detail.cancelHttp",{status:A.status}));u(B.pending?t("workflow.detail.cancelPending"):null),se(null),await U()}catch(A){se(A?.message??String(A))}finally{he=!1,f.disabled=!1,W()}}}async function z($,Z){if(!ae.has($)){ae.add($),re.delete($),W();try{let A=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/attempts/${encodeURIComponent(Z)}/${encodeURIComponent($)}/resume`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});if(A.status===401)throw new Error(t("workflow.detail.writeAccessResume"));let B=await A.json().catch(()=>({}));if(!A.ok||!B.ok||!B.resumeId||!B.url)throw new Error(B.hint??B.message??B.error??t("workflow.detail.resumeStartFailed",{status:A.status}));Se.set($,{resumeId:B.resumeId,url:B.url})}catch(A){let B=A?.message??String(A);re.set($,B)}finally{ae.delete($),W()}}}async function ee($,Z){if(!ae.has($)){ae.add($),re.delete($),W();try{let A=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/attempts/${encodeURIComponent(Z)}/${encodeURIComponent($)}/resume/end`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"ended_by_dashboard"})});if(A.status===401)throw new Error(t("workflow.detail.writeAccessResume"));let B=await A.json().catch(()=>({}));if(!A.ok||!B.ok)if(B.error==="resume_not_running")Se.delete($);else throw new Error(B.hint??B.message??B.error??t("workflow.detail.resumeEndFailed",{status:A.status}));else Se.delete($)}catch(A){let B=A?.message??String(A);re.set($,B)}finally{ae.delete($),W()}}}async function oe($,Z){if(!Be.has($)){Be.add($),$e.delete($),W();try{let A=me.get($)?.trim()||void 0,B=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/${Z}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({comment:A})});if(B.status===401)throw new Error(t("workflow.detail.writeAccessApproval"));let fe=await B.json().catch(()=>({}));if(!B.ok||!fe.ok)throw new Error(fe.hint??fe.message??fe.error??t("workflow.detail.actionHttp",{action:Z,status:B.status}));let bt=Z==="approve"?t("workflow.detail.approved"):t("workflow.detail.rejected");$e.set($,{kind:"ok",text:fe.alreadyTerminal?t("workflow.detail.alreadyTerminal",{label:bt}):fe.pending?t("workflow.detail.workflowContinue",{label:bt}):t("workflow.detail.workflowRefreshing",{label:bt})}),se(null),await U()}catch(A){let B=A?.message??String(A);$e.set($,{kind:"error",text:B}),se(B)}finally{Be.delete($),W()}}}function W(){if(!d)return;Ie=E.scrollTop;let $=d.run;ut.has($.status)&&u(null),s.innerHTML=`${m($.workflowId??"?")} \xB7 ${Oe($.status)} \xB7 lastSeq ${d.lastSeq}`,a.textContent=t("workflow.detail.refreshed",{time:new Date().toLocaleTimeString()}),f.hidden=ut.has($.status),f.disabled=he||!d.chatBinding?.larkAppId,f.textContent=d.chatBinding?.larkAppId?t("workflow.detail.cancel"):t("workflow.detail.cliCancelOnly"),f.title=d.chatBinding?.larkAppId?t("workflow.detail.cancelTitle"):t("workflow.detail.cliCancelTitle",{runId:n}),ws(c,d),ks(w,d),$s(h,y,d,b),xs(k,d),Es(p,d,ne,le,{comments:me,statuses:$e,resolving:Be,onResolve:oe},{sessions:Se,pending:ae,errors:re,onStart:z,onEnd:ee},Me,V)&&(Me=void 0),ti(O,b),E.scrollTop=Ie,v.hidden=!C,T.textContent=t("workflow.detail.eventsLoaded",{loaded:b.length,total:q})}function xe(){if(F!==null&&window.clearTimeout(F),d&&ut.has(d.run.status)){F=null;return}F=window.setTimeout(async()=>{await U(),ie||xe()},fs)}function we(){document.hidden||U().then(()=>{!ie&&F===null&&xe()})}return v.addEventListener("click",()=>{G()}),f.addEventListener("click",()=>{X()}),document.addEventListener("visibilitychange",we),M().then(()=>{se(null),ie||xe()}).catch($=>{se($?.message??String($)),s.textContent=t("workflow.detail.loadFailed")}),()=>{ie=!0,F!==null&&window.clearTimeout(F),document.removeEventListener("visibilitychange",we)}}function ws(e,n){let o=n.run,s=[[t("workflow.summary.workflow"),m(o.workflowId??"?")],[t("workflow.summary.status"),Oe(o.status)],[t("workflow.summary.lastSeq"),String(n.lastSeq)],[t("workflow.summary.updated"),m(new Date(n.updatedAt).toLocaleString())],[t("workflow.summary.revision"),m(Ot(o.revisionId))],[t("workflow.summary.initiator"),m(o.initiator??"-")]];o.failedNodeId&&s.push([t("workflow.summary.failedNode"),m(o.failedNodeId)]),o.cancelOriginEventId&&s.push([t("workflow.summary.cancelOrigin"),m(o.cancelOriginEventId)]),n.chatBinding&&(s.push([t("workflow.summary.chat"),`<code>${m(n.chatBinding.chatId)}</code>`]),s.push([t("workflow.summary.app"),`<code>${m(n.chatBinding.larkAppId)}</code>`])),e.innerHTML=s.map(([a,i])=>`<div class="wf-summary-item"><span>${a}</span><strong>${i}</strong></div>`).join("")}function ys(e){if(!e.errorCode)return"";let n=e.errorMessage?` \u2014 ${si(e.errorMessage,96)}`:"";return`<div class="wf-run-error">
|
|
1016
1016
|
<span class="muted error">${m(e.errorCode)}</span>${m(n)}
|
|
1017
|
-
</div>`}function
|
|
1017
|
+
</div>`}function vs(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 ks(e,n){let o=n.dangling,s=[[t("workflow.dangling.activities"),o.activities],[t("workflow.dangling.effects"),o.effectAttempted],[t("workflow.dangling.waits"),o.waits],[t("workflow.dangling.cancels"),o.cancels]],a=new Set(s.flatMap(([,i])=>i)).size;if(e.className=a>0?"wf-panel wf-dangling-panel has":"wf-panel wf-dangling-panel",a===0){e.innerHTML=`<div class="wf-panel-title"><h3>${m(t("workflow.detail.dangling"))}</h3></div><div class="muted">${m(t("workflow.detail.noDangling"))}</div>`;return}e.innerHTML=`<div class="wf-panel-title"><h3>${m(t("workflow.detail.dangling"))}</h3><span class="wf-dangling has">${a}</span></div>
|
|
1018
1018
|
<div class="wf-dangling-grid">
|
|
1019
|
-
${s.map(([
|
|
1020
|
-
</div>`}function
|
|
1021
|
-
<span title="${m(new Date(l).toISOString())}">${m(
|
|
1022
|
-
<span title="${m(new Date(c).toISOString())}">${m(
|
|
1019
|
+
${s.map(([i,l])=>`<div><strong>${i}</strong>${l.length===0?`<div class="muted">${m(t("workflow.detail.none"))}</div>`:`<ul>${l.map(c=>`<li><code>${m(c)}</code></li>`).join("")}</ul>`}</div>`).join("")}
|
|
1020
|
+
</div>`}function $s(e,n,o,s){let a=Ss(s,o);if(a.length===0){n.textContent="",e.innerHTML=`<div class="empty">${m(t("workflow.detail.noParallelData"))}</div>`;return}let i=Date.now(),l=Math.min(...a.map(p=>p.startedAt)),c=Math.max(...a.map(p=>p.endedAt??i),l+1e3),w=Math.max(1,c-l),h=Ls(a,i),y=a.filter(p=>!p.endedAt&&(p.status==="running"||p.status==="effectAttempting")).length;n.textContent=t("workflow.detail.parallelMeta",{count:a.length,max:h,running:y});let k=a.sort((p,E)=>p.startedAt-E.startedAt||p.activityId.localeCompare(E.activityId)).map(p=>Ts(p,l,w,i)).join("");e.innerHTML=`<div class="wf-parallel-axis">
|
|
1021
|
+
<span title="${m(new Date(l).toISOString())}">${m(Rt(l))}</span>
|
|
1022
|
+
<span title="${m(new Date(c).toISOString())}">${m(Rt(c))}</span>
|
|
1023
1023
|
</div>
|
|
1024
|
-
<div class="wf-parallel-list">${k}</div>`}function
|
|
1024
|
+
<div class="wf-parallel-list">${k}</div>`}function Ss(e,n){let o=new Map,s=new Map(n.activities.map(a=>[a.activityId,a.ownerNodeId]));for(let a of[...e].sort((i,l)=>pt(i.eventId)-pt(l.eventId))){let i=ai(a);if(!i)continue;let l=typeof i.activityId=="string"?i.activityId:void 0,c=typeof i.attemptId=="string"?i.attemptId:void 0;if(!l||!c)continue;let w=o.get(c);if(a.type==="attemptCreated"){let h=typeof i.attemptNumber=="number"?i.attemptNumber:void 0;w={nodeId:typeof i.nodeId=="string"?i.nodeId:s.get(l),activityId:l,attemptId:c,attemptNumber:h,status:"pending",startedAt:a.timestamp},o.set(c,w);continue}w||(w={nodeId:s.get(l),activityId:l,attemptId:c,status:"pending",startedAt:a.timestamp},o.set(c,w)),a.type==="activityRunning"?(w.status="running",w.runningAt=a.timestamp):a.type==="effectAttempted"?w.status="effectAttempting":a.type==="activityWaiting"||a.type==="waitCreated"?w.status="waiting":Is(a.type)&&(w.status=Ms(a.type),w.endedAt=a.timestamp,w.endType=a.type)}return[...o.values()]}function Ts(e,n,o,s){let a=e.endedAt??s,i=To((e.startedAt-n)/o*100,0,100),l=To((Math.max(a,e.startedAt+1)-e.startedAt)/o*100,.7,100-i),c=e.nodeId??e.activityId,w=e.attemptNumber!==void 0?`#${e.attemptNumber}`:Ot(e.attemptId),h=[`${c} ${e.status}`,`${new Date(e.startedAt).toISOString()} \u2192 ${e.endedAt?new Date(e.endedAt).toISOString():t("workflow.detail.parallelNow")}`,e.endType?`end: ${e.endType}`:void 0].filter(Boolean).join(`
|
|
1025
1025
|
`);return`<div class="wf-parallel-row">
|
|
1026
1026
|
<div class="wf-parallel-label">
|
|
1027
1027
|
<code>${m(c)}</code>
|
|
1028
1028
|
<span class="muted">${m(e.activityId)} \xB7 ${m(w)}</span>
|
|
1029
1029
|
</div>
|
|
1030
1030
|
<div class="wf-parallel-track">
|
|
1031
|
-
<div class="wf-parallel-bar wf-parallel-${m(e.status)}" style="left:${
|
|
1031
|
+
<div class="wf-parallel-bar wf-parallel-${m(e.status)}" style="left:${i.toFixed(3)}%;width:${l.toFixed(3)}%;" title="${m(h)}">
|
|
1032
1032
|
<span>${m(Ue(e.status))}</span>
|
|
1033
1033
|
</div>
|
|
1034
1034
|
</div>
|
|
1035
|
-
</div>`}function
|
|
1035
|
+
</div>`}function Ls(e,n){let o=[];for(let i of e)o.push({time:i.startedAt,delta:1}),o.push({time:i.endedAt??n,delta:-1});o.sort((i,l)=>i.time-l.time||l.delta-i.delta);let s=0,a=0;for(let i of o)s+=i.delta,a=Math.max(a,s);return a}function Is(e){return e==="activitySucceeded"||e==="activityFailed"||e==="activityTimedOut"||e==="activityCanceled"}function Ms(e){return e==="activitySucceeded"?"succeeded":e==="activityCanceled"?"cancelled":e==="activityTimedOut"?"timedOut":"failed"}function xs(e,n){let o=new Map(n.activities.map(i=>[i.activityId,i])),s=new Set,a=[];for(let i of n.nodes){let l=(i.activityId?o.get(i.activityId):void 0)??n.activities.find(c=>c.ownerNodeId===i.nodeId);l&&s.add(l.activityId),a.push($o(i,l))}for(let i of n.activities)s.has(i.activityId)||a.push($o(void 0,i));e.innerHTML=a.length>0?a.join(""):`<tr><td colspan="7" class="empty">${m(t("workflow.detail.noNodes"))}</td></tr>`}function $o(e,n){let o=n?.attempts[n.attempts.length-1];return`<tr>
|
|
1036
1036
|
<td>${e?`<code>${m(e.nodeId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
1037
1037
|
<td>${e?Oe(e.status):'<span class="muted">-</span>'}</td>
|
|
1038
1038
|
<td>${n?`<code>${m(n.activityId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
1039
1039
|
<td>${n?Oe(n.status):'<span class="muted">-</span>'}</td>
|
|
1040
1040
|
<td>${n?.attempts.length??0}</td>
|
|
1041
1041
|
<td>${o?`<code>${m(o.attemptId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
1042
|
-
<td>${o?
|
|
1043
|
-
</tr>`}function
|
|
1042
|
+
<td>${o?ei(o):`<span class="muted">${m(t("workflow.detail.idle"))}</span>`}</td>
|
|
1043
|
+
</tr>`}function Es(e,n,o,s,a,i,l,c){Ks(e,o,s),zs(e,a.comments);let w=!!(l&&n.attemptIO?.[l]?.terminal);w&&l&&o.add(un(l,t("workflow.detail.liveTerminal")));let h=Hs(n),y=new Set;if(c){for(let p of h){y.add(p.key);let E=c.get(p.key);E||(E=Cs(p.key),c.set(p.key,E),e.appendChild(E.article)),As(E,p,o,a,i,l)}for(let[p,E]of Array.from(c))y.has(p)||(E.article.remove(),c.delete(p));if(h.length===0){if(!e.querySelector(".wf-io-empty-placeholder")){let p=document.createElement("div");p.className="empty wf-io-empty-placeholder",p.textContent=t("workflow.detail.noNodeIO"),e.appendChild(p)}}else e.querySelector(".wf-io-empty-placeholder")?.remove()}else{let p=[];for(let E of h)p.push(Ns(E,o,a,i,l));e.innerHTML=p.length>0?p.join(""):`<div class="empty">${m(t("workflow.detail.noNodeIO"))}</div>`}Ys(e,s);let k=Js(e,l);return Vs(e,o),Qs(e,s),Ws(e,a),Ro(e,i),k&&w}function Hs(e){let n=new Map(e.activities.map(a=>[a.activityId,a])),o=new Set,s=[];for(let a of e.nodes){let i=(a.activityId?n.get(a.activityId):void 0)??e.activities.find(l=>l.ownerNodeId===a.nodeId);if(!i){s.push({key:`node:${a.nodeId}`,node:a});continue}o.add(i.activityId),s.push({key:`activity:${i.activityId}`,node:a,activity:i,io:e.attemptIO?.[Dt(i)?.attemptId??""]})}for(let a of e.activities)o.has(a.activityId)||s.push({key:`activity:${a.activityId}`,activity:a,io:e.attemptIO?.[Dt(a)?.attemptId??""]});return s}function Cs(e){let n=document.createElement("article");n.className="wf-io-card",n.dataset.wfCardKey=e;let o=document.createElement("div");o.className="wf-io-card-head";let s=document.createElement("div");s.className="wf-io-terminal-slot";let a=document.createElement("div");return a.className="wf-io-grid",n.appendChild(o),n.appendChild(s),n.appendChild(a),{article:n,head:o,terminalSlot:s,grid:a,currentTerminalUrl:null}}function As(e,n,o,s,a,i){let l=Dt(n.activity),c=n.node?.nodeId??n.activity?.ownerNodeId??n.activity?.activityId??"unknown",w=!!(l&&l.attemptId===i);e.article.classList.toggle("is-focused",w),l?e.article.dataset.wfAttemptCard=l.attemptId:delete e.article.dataset.wfAttemptCard;let h=Do(l,s);e.head.innerHTML=`
|
|
1044
1044
|
<header>
|
|
1045
1045
|
<div>
|
|
1046
1046
|
<strong><code>${m(c)}</code></strong>
|
|
@@ -1052,13 +1052,13 @@ ${lo("manage")}
|
|
|
1052
1052
|
${l?`${m(t("workflow.detail.attempt"))} <code>${m(l.attemptId)}</code>`:m(t("workflow.detail.noAttempt"))}
|
|
1053
1053
|
</div>
|
|
1054
1054
|
${h}
|
|
1055
|
-
`;let y
|
|
1055
|
+
`;let y=Io(l,n.activity,n.io?.terminal,a),k=y?.url??null;if(k!==e.currentTerminalUrl)y===null?e.terminalSlot.innerHTML="":e.terminalSlot.innerHTML=Mo(n.key,l,n.activity,n.io?.terminal,y,o,a),e.currentTerminalUrl=k;else if(y!==null&&n.io?.terminal){let E=e.terminalSlot.querySelector("details.wf-terminal-block > summary");if(E){let O=xo(y.kind);E.innerHTML=`${m(O)} ${Ao(l,n.io.terminal)}`}l&&_s(e.terminalSlot,l,n.activity,n.io.terminal,y,a)}let p=l?.attemptId??n.activity?.activityId??n.node?.nodeId??"unknown";e.grid.innerHTML=`
|
|
1056
1056
|
${De(p,t("workflow.detail.authoredInput"),n.io?.input,o)}
|
|
1057
1057
|
${De(p,t("workflow.detail.resolvedInput"),n.io?.resolvedInput,o)}
|
|
1058
1058
|
${De(p,t("workflow.detail.output"),n.io?.output,o)}
|
|
1059
1059
|
${De(p,t("workflow.detail.executionLog"),n.io?.log,o)}
|
|
1060
1060
|
${n.io?.waitPrompt?De(p,t("workflow.detail.waitPrompt"),n.io.waitPrompt,o):""}
|
|
1061
|
-
`}function
|
|
1061
|
+
`}function Io(e,n,o,s){if(!o||o.error)return null;if(Ps(e,o))return{kind:"live",url:Us(o)};if(!e||!n||!qs(e,o))return null;let a=Fs();if(!a)return null;let i=s?.sessions.get(e.attemptId);return i?{kind:"resume",url:i.url,resumeId:i.resumeId,downloadUrl:So(a,n.activityId,e.attemptId)}:{kind:"replay",url:js(a,n.activityId,e.attemptId,!!o.hasPtyLog),downloadUrl:So(a,n.activityId,e.attemptId)}}function Mo(e,n,o,s,a,i,l){if(!s)return"";let c=xo(a.kind),w=un(e,c),h=Ao(n,s),y=Ds(a.kind),k=a.kind==="replay"||a.kind==="resume"?`<a class="btn-link" href="${m(a.downloadUrl)}" download>${m(t("workflow.detail.downloadFullLog"))}</a>`:"",p=n?Ho(n,o,s,a,l):"",E=n?Co(n.attemptId,l):"";return`<details class="wf-io-block wf-terminal-block" data-io-key="${m(w)}"${i.has(w)?" open":""}>
|
|
1062
1062
|
<summary>${m(c)} ${h}</summary>
|
|
1063
1063
|
<div class="wf-terminal-actions">
|
|
1064
1064
|
<a class="btn-link" href="${m(a.url)}" target="_blank" rel="noreferrer">${m(y)}</a>
|
|
@@ -1067,7 +1067,7 @@ ${lo("manage")}
|
|
|
1067
1067
|
</div>
|
|
1068
1068
|
${E}
|
|
1069
1069
|
<iframe class="wf-terminal-frame" src="${m(a.url)}" title="${m(c)}" loading="lazy"></iframe>
|
|
1070
|
-
</details>`}function
|
|
1070
|
+
</details>`}function xo(e){return e==="live"?t("workflow.detail.liveTerminal"):e==="resume"?t("workflow.detail.terminalResume"):t("workflow.detail.terminalReplay")}function Ds(e){return e==="live"?t("workflow.detail.openTerminalNewTab"):e==="resume"?t("workflow.detail.openResumeNewTab"):t("workflow.detail.openReplayNewTab")}var Eo=new Set(["antigravity","codex-app","cursor","mira"]),Rs=new Set(["aiden","coco","claude-code","seed","codex","mtr","hermes","pi"]);function Os(e){return!!e&&(Rs.has(e)||Eo.has(e))}function Bs(e){return!!e&&Eo.has(e)}function Ho(e,n,o,s,a){if(!a||s.kind==="live"||!n)return"";let i=s.kind==="resume",l=a.pending.has(e.attemptId),c=`data-wf-resume-attempt="${m(e.attemptId)}" data-wf-resume-activity="${m(n.activityId)}"`;return i?`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="end" ${c}${l?" disabled":""}>${m(l?t("workflow.detail.resumeEnding"):t("workflow.detail.endResumeSession"))}</button>`:Os(o.cliId)?Bs(o.cliId)&&!o.cliSessionId?`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${m(t("workflow.detail.resumeMissingCliSession"))}">${m(t("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="start" ${c}${l?" disabled":""}>${m(l?t("workflow.detail.resumeStarting"):t("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${m(t("workflow.detail.resumeUnsupportedCli",{cliId:o.cliId??"?"}))}">${m(t("workflow.detail.resumeSession"))}</button>`}function Co(e,n){if(!n)return"";let o=n.errors.get(e);return o?`<div class="hint-warn wf-resume-status" data-wf-resume-status="${m(e)}">${m(o)}</div>`:""}function Ns(e,n,o,s,a){let i=Dt(e.activity),l=e.node?.nodeId??e.activity?.ownerNodeId??e.activity?.activityId??"unknown",c=i?.attemptId??e.activity?.activityId??e.node?.nodeId??"unknown",w=Do(i,o),h=i?.attemptId===a?" is-focused":"",y=i?` data-wf-attempt-card="${m(i.attemptId)}"`:"",k=Io(i,e.activity,e.io?.terminal,s),p=k?Mo(c,i,e.activity,e.io?.terminal,k,n,s):"";return`<article class="wf-io-card${h}" data-wf-card-key="${m(e.key)}"${y}>
|
|
1071
1071
|
<div class="wf-io-card-head">
|
|
1072
1072
|
<header>
|
|
1073
1073
|
<div>
|
|
@@ -1077,7 +1077,7 @@ ${lo("manage")}
|
|
|
1077
1077
|
<div>${e.node?Oe(e.node.status):""} ${e.activity?Oe(e.activity.status):""}</div>
|
|
1078
1078
|
</header>
|
|
1079
1079
|
<div class="wf-io-meta">
|
|
1080
|
-
${
|
|
1080
|
+
${i?`${m(t("workflow.detail.attempt"))} <code>${m(i.attemptId)}</code>`:m(t("workflow.detail.noAttempt"))}
|
|
1081
1081
|
</div>
|
|
1082
1082
|
${w}
|
|
1083
1083
|
</div>
|
|
@@ -1089,7 +1089,7 @@ ${lo("manage")}
|
|
|
1089
1089
|
${De(c,t("workflow.detail.executionLog"),e.io?.log,n)}
|
|
1090
1090
|
${e.io?.waitPrompt?De(c,t("workflow.detail.waitPrompt"),e.io.waitPrompt,n):""}
|
|
1091
1091
|
</div>
|
|
1092
|
-
</article>`}function
|
|
1092
|
+
</article>`}function Dt(e){return e?.attempts[e.attempts.length-1]}function Ao(e,n){let o=[];return n.error?o.push(t("workflow.detail.error")):o.push(n.status==="live"?t("workflow.detail.terminalLive"):t("workflow.detail.terminalClosedShort")),e?.status&&o.push(e.status),n.webPort>0&&o.push(`:${n.webPort}`),`<span class="muted">${m(o.join(" \xB7 "))}</span>`}function Ps(e,n){return n.status==="live"&&n.webPort>0&&(e?.status==="pending"||e?.status==="running"||e?.status==="effectAttempting")}function qs(e,n){return e.status==="succeeded"||e.status==="failed"||e.status==="cancelled"||e.status==="timedOut"?!!(n.sessionId||n.startedAt):!1}function Us(e){return`http://${window.location.hostname||"127.0.0.1"}:${e.webPort}`}function js(e,n,o,s){let a=new URLSearchParams({runId:e,activityId:n,attemptId:o});return s&&a.set("hasPtyLog","1"),`/assets/terminal-replay.html?${a.toString()}`}function So(e,n,o){return`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(n)}/${encodeURIComponent(o)}/terminal-log/raw?download=1`}function Fs(){let e=window.location.hash.match(/^#\/workflows\/([^/?#]+)/);if(!e)return null;try{return decodeURIComponent(e[1])}catch{return null}}function Do(e,n){if(!Gs(e))return"";let o=e.attemptId,s=n.comments.get(o)??"",a=n.resolving.has(o),i=n.statuses.get(o),l=i?.kind==="error"?"hint-warn":"hint-ok";return`<div class="wf-approval-box" data-wf-approval="${m(o)}">
|
|
1093
1093
|
<label>
|
|
1094
1094
|
<span>${m(t("workflow.detail.approvalComment"))}</span>
|
|
1095
1095
|
<textarea class="wf-approval-comment" data-wf-approval-comment="${m(o)}" rows="2" placeholder="${m(t("workflow.detail.optionalComment"))}"${a?" disabled":""}>${m(s)}</textarea>
|
|
@@ -1099,138 +1099,138 @@ ${lo("manage")}
|
|
|
1099
1099
|
<button type="button" data-wf-approval-action="reject" data-wf-attempt-id="${m(o)}"${a?" disabled":""}>${m(t("workflow.detail.reject"))}</button>
|
|
1100
1100
|
${a?`<span class="muted">${m(t("workflow.detail.submitting"))}</span>`:""}
|
|
1101
1101
|
</div>
|
|
1102
|
-
${
|
|
1103
|
-
</div>`}function
|
|
1104
|
-
<summary>${m(n)} ${
|
|
1105
|
-
${
|
|
1106
|
-
</details>`}function
|
|
1107
|
-
<td>${
|
|
1102
|
+
${i?`<div class="${l} wf-approval-status">${m(i.text)}</div>`:""}
|
|
1103
|
+
</div>`}function Gs(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function zs(e,n){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(o=>{let s=o.dataset.wfApprovalComment;s&&n.set(s,o.value)})}function Ro(e,n){e.querySelectorAll("button[data-wf-resume-action][data-wf-resume-attempt][data-wf-resume-activity]").forEach(o=>{o.dataset.wfResumeBound!=="1"&&(o.dataset.wfResumeBound="1",o.addEventListener("click",()=>{let s=o.dataset.wfResumeAttempt,a=o.dataset.wfResumeActivity,i=o.dataset.wfResumeAction;!s||!a||(i==="start"?n.onStart(s,a):i==="end"&&n.onEnd(s,a))}))})}function _s(e,n,o,s,a,i){let l=e.querySelector(".wf-terminal-actions");if(!l)return;let c=l.querySelector('button[data-wf-resume-button="1"]'),w=Ho(n,o,s,a,i);c?c.outerHTML=w:w&&l.insertAdjacentHTML("beforeend",w);let h=e.querySelector("details.wf-terminal-block");if(h){let y=h.querySelector(".wf-resume-status"),k=Co(n.attemptId,i);y?y.outerHTML=k:k&&l.insertAdjacentHTML("afterend",k)}Ro(e,i)}function Ws(e,n){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(o=>{let s=o.dataset.wfApprovalComment;s&&o.addEventListener("input",()=>{n.comments.set(s,o.value)})}),e.querySelectorAll("button[data-wf-approval-action][data-wf-attempt-id]").forEach(o=>{o.addEventListener("click",()=>{let s=o.dataset.wfAttemptId,a=o.dataset.wfApprovalAction;!s||a!=="approve"&&a!=="reject"||n.onResolve(s,a)})})}function De(e,n,o,s){let a=un(e,n);return`<details class="wf-io-block" data-io-key="${m(a)}"${s.has(a)?" open":""}>
|
|
1104
|
+
<summary>${m(n)} ${Xs(o)}</summary>
|
|
1105
|
+
${Zs(o)}
|
|
1106
|
+
</details>`}function un(e,n){return`${e}:${n}`}function Js(e,n){if(!n)return!1;for(let o of e.querySelectorAll("[data-wf-attempt-card]"))if(o.dataset.wfAttemptCard===n)return o.scrollIntoView({block:"center"}),!0;return!1}function Ks(e,n,o){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(s=>{let a=s.dataset.ioKey;if(!a)return;s.open?n.add(a):n.delete(a);let i=s.querySelector(".wf-io-pre");i&&o.set(a,i.scrollTop)})}function Vs(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(o=>{o.dataset.ioToggleBound!=="1"&&(o.dataset.ioToggleBound="1",o.addEventListener("toggle",()=>{let s=o.dataset.ioKey;s&&(o.open?n.add(s):n.delete(s))}))})}function Ys(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(o=>{let s=o.dataset.ioKey;if(!s)return;let a=n.get(s);if(a===void 0)return;let i=o.querySelector(".wf-io-pre");i&&(i.scrollTop=a)})}function Qs(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(o=>{let s=o.dataset.ioKey;if(!s)return;let a=o.querySelector(".wf-io-pre");a&&a.dataset.ioScrollBound!=="1"&&(a.dataset.ioScrollBound="1",a.addEventListener("scroll",()=>{n.set(s,a.scrollTop)}))})}function Xs(e){if(!e)return`<span class="muted">${m(t("workflow.detail.empty"))}</span>`;let n=[];return e.outputBytes!==void 0&&n.push(`${e.outputBytes}B`),e.truncated&&n.push(t("workflow.detail.truncated")),e.error&&n.push(t("workflow.detail.error")),e.outputHash&&n.push(Ot(e.outputHash)),n.length?`<span class="muted">${m(n.join(" \xB7 "))}</span>`:""}function Zs(e){if(!e)return`<div class="muted wf-io-empty">${m(t("workflow.detail.noData"))}</div>`;let n=e.value!==void 0?JSON.stringify(e.value,null,2):e.text??"",o=e.error?`<div class="muted error">${m(e.error)}</div>`:"";return n?`${o}<pre class="wf-io-pre">${m(n)}</pre>`:`${o}<div class="muted wf-io-empty">${m(t("workflow.detail.noPreview"))}</div>`}function ei(e){let n=[];if(e.effectAttempted&&n.push(`${m(t("workflow.detail.effect"))} ${m(e.effectAttempted.provider)}`),e.wait){let o=e.wait.resolution?`${e.wait.resolution.kind}${e.wait.resolution.resolution?":"+e.wait.resolution.resolution:""}`:t("workflow.detail.open");n.push(`${m(t("workflow.detail.wait"))} ${m(e.wait.waitKind)} ${m(o)}`),e.wait.deadlineAt!==void 0&&n.push(`${m(t("workflow.detail.deadline"))} ${m(Rt(e.wait.deadlineAt))}`)}if(e.error){let o=`${e.error.errorCode}${e.error.errorClass?` \xB7 ${e.error.errorClass}`:""}`;n.push(`<span class="muted error">${m(o)}</span>`),e.error.errorMessage&&n.push(`<span class="error wf-error-msg">${m(e.error.errorMessage)}</span>`)}return e.output&&n.push(`${m(t("workflow.detail.output"))} ${m(Ot(e.output.outputHash))}`),e.runningMs!==void 0&&n.push(`${e.runningMs}ms`),n.length>0?n.join("<br/>"):'<span class="muted">-</span>'}function ti(e,n){e.innerHTML=n.length>0?n.map(ni).join(""):`<tr><td colspan="7" class="empty">${m(t("workflow.detail.noEvents"))}</td></tr>`}function ni(e){let n=oi(e.payload);return`<tr>
|
|
1107
|
+
<td>${pt(e.eventId)}</td>
|
|
1108
1108
|
<td><code>${m(e.type)}</code></td>
|
|
1109
1109
|
<td>${m(e.actor)}</td>
|
|
1110
1110
|
<td>${n.nodeId?`<code>${m(n.nodeId)}</code>`:"-"}</td>
|
|
1111
1111
|
<td>${n.activityId?`<code>${m(n.activityId)}</code>`:"-"}</td>
|
|
1112
1112
|
<td>${n.errorCode?`<span class="muted error">${m(n.errorCode)}</span>`:"-"}</td>
|
|
1113
|
-
<td title="${m(new Date(e.timestamp).toISOString())}">${m(
|
|
1114
|
-
</tr>`}function
|
|
1113
|
+
<td title="${m(new Date(e.timestamp).toISOString())}">${m(Rt(e.timestamp))}</td>
|
|
1114
|
+
</tr>`}function pt(e){let n=e.lastIndexOf("-");if(n<0)return 0;let o=Number(e.slice(n+1));return Number.isFinite(o)?o:0}function oi(e){if(!e||typeof e!="object"||"ref"in e)return{};let n=e,o={};typeof n.nodeId=="string"&&(o.nodeId=n.nodeId),typeof n.activityId=="string"&&(o.activityId=n.activityId),typeof n.failedNodeId=="string"&&(o.nodeId=n.failedNodeId);let s=n.error;return s&&typeof s=="object"&&"errorCode"in s&&(o.errorCode=String(s.errorCode)),o}function ai(e){return!e.payload||typeof e.payload!="object"||"ref"in e.payload?null:e.payload}function To(e,n,o){return Math.min(o,Math.max(n,e))}function Ot(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function si(e,n){return e.length>n?e.slice(0,n-1)+"\u2026":e}function Rt(e){return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}function D(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function Oo(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function Bo(e){let n=location.hash.match(/^#\/(?:workflows\/catalog|workflows-catalog)\/([^/?#]+)$/);return n?ri(e,decodeURIComponent(n[1])):ii(e)}function ii(e){e.innerHTML=`
|
|
1115
1115
|
<nav class="wf-subnav">
|
|
1116
|
-
<a href="#/workflows" data-i18n="workflow.subnav.runs">${
|
|
1117
|
-
<a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${
|
|
1116
|
+
<a href="#/workflows" data-i18n="workflow.subnav.runs">${D(t("workflow.subnav.runs"))}</a>
|
|
1117
|
+
<a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${D(t("workflow.subnav.catalog"))}</a>
|
|
1118
1118
|
</nav>
|
|
1119
1119
|
<section class="catalog-head">
|
|
1120
1120
|
<div>
|
|
1121
|
-
<h2>${
|
|
1122
|
-
<p class="muted">${
|
|
1121
|
+
<h2>${D(t("catalog.title"))}</h2>
|
|
1122
|
+
<p class="muted">${D(t("catalog.subtitle"))}</p>
|
|
1123
1123
|
</div>
|
|
1124
|
-
<button id="catalog-refresh" type="button">${
|
|
1124
|
+
<button id="catalog-refresh" type="button">${D(t("catalog.refresh"))}</button>
|
|
1125
1125
|
</section>
|
|
1126
1126
|
<form id="catalog-filters" class="filters">
|
|
1127
|
-
<input type="search" name="q" placeholder="${
|
|
1127
|
+
<input type="search" name="q" placeholder="${D(t("catalog.searchPlaceholder"))}" />
|
|
1128
1128
|
<span id="catalog-status" class="muted"></span>
|
|
1129
1129
|
</form>
|
|
1130
1130
|
<div class="wf-table-scroll">
|
|
1131
1131
|
<table>
|
|
1132
1132
|
<thead><tr>
|
|
1133
|
-
<th>${
|
|
1134
|
-
<th>${
|
|
1135
|
-
<th>${
|
|
1136
|
-
<th>${
|
|
1137
|
-
<th>${
|
|
1138
|
-
<th>${
|
|
1133
|
+
<th>${D(t("catalog.table.workflow"))}</th>
|
|
1134
|
+
<th>${D(t("catalog.table.version"))}</th>
|
|
1135
|
+
<th>${D(t("catalog.table.params"))}</th>
|
|
1136
|
+
<th>${D(t("catalog.table.nodes"))}</th>
|
|
1137
|
+
<th>${D(t("catalog.table.revision"))}</th>
|
|
1138
|
+
<th>${D(t("catalog.table.path"))}</th>
|
|
1139
1139
|
</tr></thead>
|
|
1140
1140
|
<tbody id="catalog-tbody"></tbody>
|
|
1141
1141
|
</table>
|
|
1142
1142
|
</div>
|
|
1143
|
-
`;let n=e.querySelector("#catalog-tbody"),o=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),a=e.querySelector("#catalog-refresh"),
|
|
1143
|
+
`;let n=e.querySelector("#catalog-tbody"),o=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),a=e.querySelector("#catalog-refresh"),i=[],l=null,c=!1;function w(){let k=(new FormData(s).get("q")??"").trim().toLowerCase();return k?i.filter(p=>p.workflowId.toLowerCase().includes(k)||p.path.toLowerCase().includes(k)):i}function h(){l?(o.textContent=t("catalog.loadFailed",{error:l}),o.classList.add("error")):(o.textContent=`${i.length}`,o.classList.remove("error"));let k=w();if(k.length===0){n.innerHTML=`<tr><td colspan="6" class="empty">${i.length===0?D(t("catalog.noDefinitions")):D(t("catalog.noFilterMatch"))}</td></tr>`;return}n.innerHTML=k.map(p=>`
|
|
1144
1144
|
<tr>
|
|
1145
|
-
<td><a href="#/workflows/catalog/${encodeURIComponent(p.workflowId)}"><code>${
|
|
1145
|
+
<td><a href="#/workflows/catalog/${encodeURIComponent(p.workflowId)}"><code>${D(p.workflowId)}</code></a></td>
|
|
1146
1146
|
<td>${p.version}</td>
|
|
1147
|
-
<td>${
|
|
1147
|
+
<td>${D(t("catalog.paramSummary",{required:p.requiredParamCount,total:p.paramCount}))}</td>
|
|
1148
1148
|
<td>${p.nodeCount}</td>
|
|
1149
|
-
<td><code>${
|
|
1150
|
-
<td><code>${
|
|
1149
|
+
<td><code>${D(Oo(p.revisionId))}</code></td>
|
|
1150
|
+
<td><code>${D(p.path)}</code></td>
|
|
1151
1151
|
</tr>
|
|
1152
|
-
`).join("")}async function y(){a.disabled=!0,o.textContent=t("catalog.loading");try{let k=await fetch("/api/workflows/definitions");if(!k.ok)throw new Error(`HTTP ${k.status}`);
|
|
1152
|
+
`).join("")}async function y(){a.disabled=!0,o.textContent=t("catalog.loading");try{let k=await fetch("/api/workflows/definitions");if(!k.ok)throw new Error(`HTTP ${k.status}`);i=(await k.json()).definitions??[],l=null}catch(k){l=k?.message??String(k),i=[]}finally{a.disabled=!1,c||h()}}return s.addEventListener("input",h),a.addEventListener("click",()=>{y()}),y(),()=>{c=!0}}function ri(e,n){e.innerHTML=`
|
|
1153
1153
|
<div class="catalog-detail-head">
|
|
1154
|
-
<a class="btn-link" href="#/workflows/catalog">${
|
|
1154
|
+
<a class="btn-link" href="#/workflows/catalog">${D(t("catalog.back"))}</a>
|
|
1155
1155
|
<div>
|
|
1156
|
-
<h2><code>${
|
|
1157
|
-
<div id="catalog-detail-subtitle" class="muted">${
|
|
1156
|
+
<h2><code>${D(n)}</code></h2>
|
|
1157
|
+
<div id="catalog-detail-subtitle" class="muted">${D(t("workflow.detail.loading"))}</div>
|
|
1158
1158
|
</div>
|
|
1159
1159
|
</div>
|
|
1160
1160
|
<section id="catalog-error" class="hint-warn" hidden></section>
|
|
1161
1161
|
<section id="catalog-run-status" class="hint-ok" hidden></section>
|
|
1162
1162
|
<div id="catalog-detail-body"></div>
|
|
1163
|
-
`;let o=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),a=e.querySelector("#catalog-run-status"),
|
|
1163
|
+
`;let o=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),a=e.querySelector("#catalog-run-status"),i=e.querySelector("#catalog-detail-body"),l=null,c=!1,w=!1;function h(f){s.hidden=!f,s.textContent=f??""}function y(f){a.hidden=!f,a.textContent=f??""}function k(f){let v={};for(let[d,b]of Object.entries(f??{}))"default"in b&&(v[d]=b.default);return v}function p(){if(!l)return;let f=l.definition;o.textContent=`${t("catalog.revision")} ${Oo(l.revisionId)} \xB7 ${l.path}`;let v=JSON.stringify(k(f.params),null,2);i.innerHTML=`
|
|
1164
1164
|
<section class="wf-panel">
|
|
1165
|
-
<div class="wf-panel-title"><h3>${
|
|
1165
|
+
<div class="wf-panel-title"><h3>${D(t("catalog.summary"))}</h3></div>
|
|
1166
1166
|
<div class="wf-summary-grid">
|
|
1167
|
-
<div class="wf-summary-item"><span>${
|
|
1168
|
-
<div class="wf-summary-item"><span>${
|
|
1169
|
-
<div class="wf-summary-item"><span>${
|
|
1170
|
-
<div class="wf-summary-item"><span>${
|
|
1167
|
+
<div class="wf-summary-item"><span>${D(t("catalog.table.workflow"))}</span><strong><code>${D(f.workflowId)}</code></strong></div>
|
|
1168
|
+
<div class="wf-summary-item"><span>${D(t("catalog.table.version"))}</span><strong>${f.version}</strong></div>
|
|
1169
|
+
<div class="wf-summary-item"><span>${D(t("catalog.nodeCount"))}</span><strong>${Object.keys(f.nodes).length}</strong></div>
|
|
1170
|
+
<div class="wf-summary-item"><span>${D(t("catalog.path"))}</span><strong><code>${D(l.path)}</code></strong></div>
|
|
1171
1171
|
</div>
|
|
1172
1172
|
</section>
|
|
1173
1173
|
|
|
1174
1174
|
<section class="wf-panel">
|
|
1175
|
-
<div class="wf-panel-title"><h3>${
|
|
1175
|
+
<div class="wf-panel-title"><h3>${D(t("catalog.runPanel"))}</h3></div>
|
|
1176
1176
|
<form id="catalog-run-form" class="catalog-run-form">
|
|
1177
1177
|
<label>
|
|
1178
|
-
<span>${
|
|
1179
|
-
<textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${
|
|
1178
|
+
<span>${D(t("catalog.paramsJson"))}</span>
|
|
1179
|
+
<textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${D(t("catalog.paramsPlaceholder"))}">${D(v)}</textarea>
|
|
1180
1180
|
</label>
|
|
1181
1181
|
<div class="catalog-chat-grid">
|
|
1182
1182
|
<label>
|
|
1183
|
-
<span>${
|
|
1183
|
+
<span>${D(t("catalog.chatId"))}</span>
|
|
1184
1184
|
<input id="catalog-chat-id" type="text" autocomplete="off" />
|
|
1185
1185
|
</label>
|
|
1186
1186
|
<label>
|
|
1187
|
-
<span>${
|
|
1187
|
+
<span>${D(t("catalog.larkAppId"))}</span>
|
|
1188
1188
|
<input id="catalog-lark-app-id" type="text" autocomplete="off" />
|
|
1189
1189
|
</label>
|
|
1190
1190
|
</div>
|
|
1191
|
-
<div class="muted">${
|
|
1191
|
+
<div class="muted">${D(t("catalog.chatBindingHint"))}</div>
|
|
1192
1192
|
<div id="catalog-param-errors" class="catalog-param-errors" hidden></div>
|
|
1193
|
-
<button id="catalog-run-btn" type="submit" class="primary">${
|
|
1193
|
+
<button id="catalog-run-btn" type="submit" class="primary">${D(t("catalog.run"))}</button>
|
|
1194
1194
|
</form>
|
|
1195
1195
|
</section>
|
|
1196
1196
|
|
|
1197
1197
|
<section class="wf-panel">
|
|
1198
|
-
<div class="wf-panel-title"><h3>${
|
|
1199
|
-
${
|
|
1198
|
+
<div class="wf-panel-title"><h3>${D(t("catalog.paramsSchema"))}</h3></div>
|
|
1199
|
+
${li(f.params)}
|
|
1200
1200
|
</section>
|
|
1201
1201
|
|
|
1202
1202
|
<section class="wf-panel">
|
|
1203
|
-
<div class="wf-panel-title"><h3>${
|
|
1204
|
-
<pre class="wf-io-pre">${
|
|
1203
|
+
<div class="wf-panel-title"><h3>${D(t("catalog.definitionJson"))}</h3></div>
|
|
1204
|
+
<pre class="wf-io-pre">${D(JSON.stringify(f,null,2))}</pre>
|
|
1205
1205
|
</section>
|
|
1206
|
-
`,O()}async function E(){if(!l||w)return;let f=
|
|
1206
|
+
`,O()}async function E(){if(!l||w)return;let f=i.querySelector("#catalog-params"),v=i.querySelector("#catalog-chat-id"),d=i.querySelector("#catalog-lark-app-id"),b=i.querySelector("#catalog-run-btn"),x=i.querySelector("#catalog-param-errors"),H;try{if(H=JSON.parse(f.value||"{}"),!H||typeof H!="object"||Array.isArray(H))throw new Error(t("catalog.badParamsJson"))}catch(I){x.hidden=!1,x.innerHTML=`<div class="muted error">${D(I?.message??String(I))}</div>`;return}w=!0,b.disabled=!0,b.textContent=t("catalog.running"),x.hidden=!0,h(null),y(null);try{let I=await fetch(`/api/workflows/definitions/${encodeURIComponent(l.definition.workflowId)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({params:H,chatBinding:{chatId:v.value.trim(),larkAppId:d.value.trim()}})});if(I.status===401)throw new Error(t("catalog.writeAccess"));let C=await I.json().catch(()=>({}));if(!I.ok||!C.ok)throw C.issues?.length&&(x.hidden=!1,x.innerHTML=`<strong>${D(t("catalog.invalidParams"))}</strong><ul>${C.issues.map(q=>`<li>${D(t("catalog.issue",{path:q.path.length?q.path.join("."):"(root)",message:q.message}))}</li>`).join("")}</ul>`),new Error(C.hint??C.message??C.error??t("catalog.runHttp",{status:I.status}));y(t("catalog.runStarted")),C.runId&&(location.hash=`#/workflows/${encodeURIComponent(C.runId)}`)}catch(I){h(I?.message??String(I))}finally{w=!1,b.disabled=!1,b.textContent=t("catalog.run")}}function O(){i.querySelector("#catalog-run-form")?.addEventListener("submit",v=>{v.preventDefault(),E()})}async function T(){try{let f=await fetch(`/api/workflows/definitions/${encodeURIComponent(n)}`);if(f.status===404)throw new Error("unknown_workflow");if(!f.ok)throw new Error(`HTTP ${f.status}`);l=await f.json(),h(null),p()}catch(f){h(t("catalog.definitionLoadFailed",{error:f?.message??String(f)})),o.textContent=t("workflow.detail.loadFailed")}}return T().then(()=>{}),()=>{c=!0}}function li(e){let n=Object.entries(e??{});return n.length===0?`<div class="muted">${D(t("catalog.noParams"))}</div>`:`<div class="catalog-param-list">${n.map(([o,s])=>`
|
|
1207
1207
|
<article class="catalog-param">
|
|
1208
1208
|
<header>
|
|
1209
|
-
<code>${
|
|
1210
|
-
<span class="wf-status">${
|
|
1211
|
-
<span class="muted">${
|
|
1209
|
+
<code>${D(o)}</code>
|
|
1210
|
+
<span class="wf-status">${D(s.required?t("catalog.required"):t("catalog.optional"))}</span>
|
|
1211
|
+
<span class="muted">${D(s.type)}${s.format?` \xB7 ${D(s.format)}`:""}</span>
|
|
1212
1212
|
</header>
|
|
1213
|
-
${s.description?`<div class="muted">${
|
|
1214
|
-
${"default"in s?`<pre class="wf-io-pre">${
|
|
1213
|
+
${s.description?`<div class="muted">${D(t("catalog.description"))}: ${D(s.description)}</div>`:""}
|
|
1214
|
+
${"default"in s?`<pre class="wf-io-pre">${D(`${t("catalog.default")}: ${JSON.stringify(s.default,null,2)}`)}</pre>`:""}
|
|
1215
1215
|
</article>
|
|
1216
|
-
`).join("")}</div>`}var _e=null,
|
|
1216
|
+
`).join("")}</div>`}var _e=null,Bt=null;function ft(){Bt!==null&&(window.clearInterval(Bt),Bt=null)}function mn(){return _e||(_e=document.createElement("dialog"),_e.className="onboarding-dialog",document.body.appendChild(_e),_e.addEventListener("close",ft),_e)}function di(e){return e.status==="waiting_for_scan"?t("botOnboarding.waiting"):e.status==="verifying"?t("botOnboarding.verifying"):e.status==="configuring_permissions"?e.permissionStatusMsg?`${t("botOnboarding.configuringPermissions")} ${e.permissionStatusMsg}`:t("botOnboarding.configuringPermissions"):e.status==="waiting_for_platform_scan"?t("botOnboarding.platformScanHint"):e.status==="completed"?t("botOnboarding.completed"):e.status==="failed"?`${t("botOnboarding.failed")}: ${r(e.message??e.error??"unknown")}`:t("botOnboarding.starting")}function ci(e){if(e.status!=="completed"||!e.permission)return"";let n=e.permission;if(n.ok){let s=[t("botOnboarding.permissionOk",{count:n.scopeCount??0})];n.skippedScopeCount&&n.skippedScopeCount>0&&s.push(t("botOnboarding.permissionSkipped",{count:n.skippedScopeCount})),n.versionId&&s.push(t("botOnboarding.permissionVersion",{version:r(n.versionId)}));let a=`<p class="hint-ok">\u2705 ${s.join(" ")}</p>`;return n.scopeWarning&&(a+=`<p class="hint-warn">\u26A0\uFE0F ${r(n.scopeWarning)}</p>`),a}let o=(e.remainingSteps??[]).map(s=>`<li><a href="${r(s.url)}" target="_blank" rel="noopener">${r(s.title)}</a></li>`).join("");return`<p class="hint-warn">\u26A0\uFE0F ${t("botOnboarding.permissionManual")}${n.message?`\uFF08${r(n.message)}\uFF09`:""}</p>`+(o?`<ol class="onboarding-steps">${o}</ol>`:"")}function mt(e){let n=mn(),o=e.status==="waiting_for_scan"&&e.qrDataUrl?`<div class="qr-card">
|
|
1217
1217
|
<img class="qr-image" src="${e.qrDataUrl}" alt="${t("botOnboarding.qrAlt")}">
|
|
1218
|
-
${e.qrUrl?`<a class="onboarding-link" href="${
|
|
1218
|
+
${e.qrUrl?`<a class="onboarding-link" href="${r(e.qrUrl)}" target="_blank" rel="noopener">${t("botOnboarding.openLink")}</a>`:""}
|
|
1219
1219
|
</div>`:"",s=e.status==="waiting_for_platform_scan"&&e.platformQrDataUrl?`<div class="qr-card">
|
|
1220
1220
|
<img class="qr-image" src="${e.platformQrDataUrl}" alt="${t("botOnboarding.platformQrAlt")}">
|
|
1221
|
-
</div>`:"",a=e.appId?`<p><b>App ID:</b> <code>${
|
|
1221
|
+
</div>`:"",a=e.appId?`<p><b>App ID:</b> <code>${r(e.appId)}</code>`+(e.cliId?` \uFF5C <b>CLI:</b> <code>${r(e.cliId)}</code>`:"")+(e.workingDir?` \uFF5C <b>${t("botOnboarding.metaDir")}:</b> <code>${r(e.workingDir)}</code>`:"")+"</p>":"",i=e.status==="completed"?`<p class="hint-ok">${t("botOnboarding.restartHint")}</p>`:"";n.innerHTML=`<article>
|
|
1222
1222
|
<header>
|
|
1223
1223
|
<h3>${t("botOnboarding.title")}</h3>
|
|
1224
1224
|
<p>${t("botOnboarding.intro")}</p>
|
|
1225
1225
|
</header>
|
|
1226
|
-
<p class="onboarding-status status-${e.status}">${
|
|
1226
|
+
<p class="onboarding-status status-${e.status}">${di(e)}</p>
|
|
1227
1227
|
${o}
|
|
1228
1228
|
${s}
|
|
1229
1229
|
${a}
|
|
1230
|
-
${
|
|
1231
|
-
${
|
|
1230
|
+
${ci(e)}
|
|
1231
|
+
${i}
|
|
1232
1232
|
<form method="dialog"><button>${t("botOnboarding.close")}</button></form>
|
|
1233
|
-
</article>`}async function
|
|
1233
|
+
</article>`}async function ui(){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 pn(e,n){let o=mn(),s=e.map(c=>`<option value="${r(c.id)}">${r(c.label)}\uFF08${r(c.id)}\uFF09</option>`).join(""),a=n?`<p class="form-error">${r(n)}</p>`:"";o.innerHTML=`<article>
|
|
1234
1234
|
<header>
|
|
1235
1235
|
<h3>${t("botOnboarding.title")}</h3>
|
|
1236
1236
|
<p>${t("botOnboarding.intro")}</p>
|
|
@@ -1254,8 +1254,8 @@ ${lo("manage")}
|
|
|
1254
1254
|
<button type="submit" class="primary">${t("botOnboarding.startScan")}</button>
|
|
1255
1255
|
</menu>
|
|
1256
1256
|
</form>
|
|
1257
|
-
</article>`;let
|
|
1257
|
+
</article>`;let i=o.querySelector("#onboarding-form");o.querySelector("#ob-cancel")?.addEventListener("click",()=>o.close()),i?.addEventListener("submit",c=>{c.preventDefault();let w=o.querySelector("#ob-cli")?.value??"",h=o.querySelector("#ob-dir")?.value??"",y=o.querySelector("#ob-model")?.value??"";pi({cliId:w,workingDir:h,model:y},e)})}async function pi(e,n){ft(),mt({id:"",status:"starting"});try{let o=await fetch("/api/bot-onboarding/start",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({cliId:e.cliId,workingDir:e.workingDir.trim(),model:e.model.trim()||void 0})}),s=await o.json();if(o.status===400){pn(n,s?.message??s?.error??"invalid_input");return}if(!o.ok||!s?.job?.id)throw new Error(s?.error??`http_${o.status}`);mt(s.job),Bt=window.setInterval(()=>{mi(s.job.id).catch(a=>{ft(),mt({id:s.job.id,status:"failed",message:a instanceof Error?a.message:String(a)})})},1200)}catch(o){mt({id:"",status:"failed",message:o instanceof Error?o.message:String(o)})}}async function mi(e){let n=await fetch(`/api/bot-onboarding/${encodeURIComponent(e)}`),o=await n.json();if(!n.ok||!o?.job)throw new Error(o?.error??`http_${n.status}`);mt(o.job),(o.job.status==="completed"||o.job.status==="failed")&&ft()}async function fi(){ft();let e=mn();pn([{id:"claude-code",label:"Claude"}]),e.open||e.showModal();let n=await ui();e.open&&e.querySelector("#onboarding-form")&&pn(n)}function No(){let e=document.getElementById("add-bot-btn");e&&(e.onclick=()=>{fi()})}var gi={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"/>'},qo=[{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"}]}],Po=qo.flatMap(e=>e.options),We=!1;function fn(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">${gi[e]??""}</svg>`}function bi(e){return e.replace(/[&<>"]/g,n=>({"&":"&","<":"<",">":">",'"':"""})[n])}function Uo(){let e=document.getElementById("theme-menu"),n=document.getElementById("theme-menu-btn"),o=document.getElementById("theme-menu-pop");if(!e||!n||!o)return;o.innerHTML=qo.map(a=>`<div class="tm-group" data-label-key="${a.labelKey}"></div>`+a.options.map(i=>`<button type="button" class="tm-item" role="option" data-value="${i.value}"><span class="tm-ic">${fn(i.icon)}</span><span class="tm-label" data-label-key="${i.labelKey}"></span></button>`).join("")).join("");let s=a=>{We=a,o.hidden=!We,n.setAttribute("aria-expanded",String(We)),e.classList.toggle("open",We)};n.addEventListener("click",a=>{a.stopPropagation(),s(!We)}),o.addEventListener("click",a=>{let i=a.target.closest(".tm-item");i&&(ce.setTheme(i.dataset.value??"system"),s(!1))}),document.addEventListener("click",a=>{We&&!e.contains(a.target)&&s(!1)}),document.addEventListener("keydown",a=>{a.key==="Escape"&&We&&s(!1)}),gn()}function gn(){let e=document.getElementById("theme-menu-btn");if(!e)return;let n=Po.find(o=>o.value===ce.theme)??Po[0];e.innerHTML=`<span class="tm-ic">${fn(n.icon)}</span><span class="tm-current">${bi(t(n.labelKey))}</span><span class="tm-chev">${fn("chevron")}</span>`,document.querySelectorAll("#theme-menu-pop [data-label-key]").forEach(o=>{o.textContent=t(o.dataset.labelKey??"")}),document.querySelectorAll("#theme-menu-pop .tm-item").forEach(o=>{o.classList.toggle("active",o.dataset.value===ce.theme)})}var be=document.getElementById("root"),tt=!0,Go=!1,zo=["roles","bot-defaults","team","connectors"],bn=!1;function hi(){if(bn)return;bn=!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(),bn=!1};e.querySelector("#auth-expired-dismiss")?.addEventListener("click",n),e.addEventListener("click",o=>{o.target===e&&n()})}var hn;function wi(){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",hn&&window.clearTimeout(hn),hn=window.setTimeout(()=>{e.style.display="none"},4e3)}var yi=window.fetch.bind(window);window.fetch=async function(...n){let o=await yi(...n);if(o.status===401){let s=(n[1]?.method??"GET").toUpperCase();(s==="GET"||s==="HEAD")&&!Go?hi():wi()}return o};var wn="";function Nt(){let e=document.getElementById("attention-strip");if(!e)return;let n=[...Q.sessions.values()].map(a=>({s:a,reason:Ne(a)})).filter(a=>!!a.reason).sort((a,i)=>ue(a.s)-ue(i.s));if(n.length===0){e.hidden=!0,e.innerHTML="",wn="";return}let o=n[0],s=`
|
|
1258
1258
|
<span class="attention-strip-ic" aria-hidden="true">!</span>
|
|
1259
|
-
<b>${
|
|
1260
|
-
<span class="attention-strip-longest">${
|
|
1261
|
-
<a class="attention-strip-go" href="#/sessions">${
|
|
1259
|
+
<b>${r(t("strip.pending",{count:n.length}))}</b>
|
|
1260
|
+
<span class="attention-strip-longest">${r(t("strip.longest",{time:Le(ue(o.s)),bot:He(o.s),reason:o.reason}))}</span>
|
|
1261
|
+
<a class="attention-strip-go" href="#/sessions">${r(t("strip.handle"))}</a>`;e.hidden=!1,s!==wn&&(wn=s,e.innerHTML=s)}Q.on(Nt);Ee().then(Nt);async function vi(){try{let e=await fetch("/api/settings");if(e.ok){let n=await e.json();tt=!!n.authed,ce.authed=tt,Go=!!(n.settings&&n.settings.publicReadOnly);let o=ht(n.lang);o&&ce.setLocale(o)}}catch{}}async function ki(e){if(tt)try{await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({lang:e})})}catch{}}function $i(){for(let n of zo){let o=document.querySelector(`.sidebar-nav a[data-route="${n}"]`);o&&(o.style.display=tt?"":"none")}let e=document.getElementById("add-bot-btn");e&&(e.style.display=tt?"":"none")}function Si(e){e.innerHTML='<section class="auth-required" style="max-width:520px;margin:64px auto;text-align:center;background:var(--surface);color:var(--fg);border:1px solid var(--border);border-radius:14px;padding:40px 36px;box-shadow:0 8px 28px rgba(0,0,0,.12)"><h2 style="margin:0 0 12px;font-size:20px;color:var(--fg)">\u6B64\u9875\u9700\u8981\u6388\u6743\u94FE\u63A5</h2><p style="margin:0 0 24px;line-height:1.7;color:var(--muted);font-size:14px">\u4F60\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u7BA1\u7406\u9875\uFF08\u89D2\u8272 / Bot \u914D\u7F6E / \u56E2\u961F / Webhook\uFF09\u9700\u8981\u6388\u6743\u94FE\u63A5\u3002\u8FD0\u884C <code>botmux dashboard</code> \u83B7\u53D6\u6700\u65B0\u94FE\u63A5\u540E\u5373\u53EF\u7BA1\u7406\u3002</p><a href="#/" style="display:inline-block;padding:8px 22px;background:var(--accent);color:var(--on-accent);border-radius:8px;text-decoration:none;font-size:14px">\u8FD4\u56DE\u603B\u89C8</a></section>'}var gt=null;function jo(e){for(let n of document.querySelectorAll(".sidebar-nav a")){let o=n.getAttribute("href")??"#/";n.classList.toggle("active",o===(e||"#/"))}}function yn(){gt&&(gt(),gt=null);let e=location.hash||"#/";if(!tt&&zo.some(n=>e.startsWith("#/"+n))){Si(be),jo(e);return}e.startsWith("#/workflows/catalog")||e.startsWith("#/workflows-catalog")?gt=Bo(be):e.startsWith("#/workflows")?gt=Lo(be):e.startsWith("#/groups")?to(be):e.startsWith("#/settings")?ko(be):e.startsWith("#/bot-defaults")?so(be):e.startsWith("#/connectors")?yo(be):e.startsWith("#/team/manage")?bo(be):e.startsWith("#/team")?go(be):e.startsWith("#/roles")?co(be):e.startsWith("#/schedules")?Zn(be):e.startsWith("#/sessions")?Qn(be):_n(be),jo(e)}var vn=document.getElementById("status");function _o(){vn&&(vn.textContent=Q.online?t("status.live"):t("status.disconnected"),vn.className="connection-status "+(Q.online?"online":"offline"))}Q.on(_o);function Fo(){document.querySelectorAll("[data-i18n]").forEach(e=>{e.textContent=t(e.dataset.i18n??"")}),document.querySelectorAll("[data-locale]").forEach(e=>{e.classList.toggle("active",e.dataset.locale===ce.locale)}),gn(),_o()}function Ti(){document.querySelectorAll("[data-locale]").forEach(e=>{e.onclick=()=>{let n=e.dataset.locale;ce.setLocale(n),ki(n)}}),Uo()}(async()=>{ce.init(),Ti(),No(),ce.on(()=>{Fo(),Nt(),yn()}),Fo(),Nt(),await vi(),$i();try{await kn()}catch(e){console.error("botmux dashboard bootstrap failed",e),Q.setOnline(!1)}window.addEventListener("hashchange",yn),yn()})();})();
|