botmux 2.71.5 → 2.73.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/backend/tmux-pipe-backend.d.ts +6 -0
- package/dist/adapters/backend/tmux-pipe-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.js +28 -0
- package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +175 -121
- package/dist/cli.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +134 -2
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/dashboard-rows.d.ts +4 -0
- package/dist/core/dashboard-rows.d.ts.map +1 -1
- package/dist/core/dashboard-rows.js +4 -0
- package/dist/core/dashboard-rows.js.map +1 -1
- package/dist/core/session-board.d.ts +9 -0
- package/dist/core/session-board.d.ts.map +1 -0
- package/dist/core/session-board.js +24 -0
- package/dist/core/session-board.js.map +1 -0
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +6 -4
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/federated-group-core.d.ts.map +1 -1
- package/dist/dashboard/federated-group-core.js +5 -0
- package/dist/dashboard/federated-group-core.js.map +1 -1
- package/dist/dashboard/federation-api.d.ts.map +1 -1
- package/dist/dashboard/federation-api.js +70 -1
- package/dist/dashboard/federation-api.js.map +1 -1
- package/dist/dashboard/federation-spoke-api.d.ts +16 -2
- package/dist/dashboard/federation-spoke-api.d.ts.map +1 -1
- package/dist/dashboard/federation-spoke-api.js +96 -3
- package/dist/dashboard/federation-spoke-api.js.map +1 -1
- package/dist/dashboard/registry.d.ts +6 -1
- package/dist/dashboard/registry.d.ts.map +1 -1
- package/dist/dashboard/registry.js +13 -1
- package/dist/dashboard/registry.js.map +1 -1
- package/dist/dashboard/web/app.d.ts.map +1 -1
- package/dist/dashboard/web/app.js +52 -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 +64 -0
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/kanban-model.d.ts +19 -0
- package/dist/dashboard/web/kanban-model.d.ts.map +1 -0
- package/dist/dashboard/web/kanban-model.js +40 -0
- package/dist/dashboard/web/kanban-model.js.map +1 -0
- package/dist/dashboard/web/preferences.d.ts +12 -1
- package/dist/dashboard/web/preferences.d.ts.map +1 -1
- package/dist/dashboard/web/preferences.js +32 -1
- package/dist/dashboard/web/preferences.js.map +1 -1
- package/dist/dashboard/web/sessions.d.ts.map +1 -1
- package/dist/dashboard/web/sessions.js +1059 -10
- package/dist/dashboard/web/sessions.js.map +1 -1
- package/dist/dashboard-web/app.js +519 -433
- package/dist/dashboard-web/index.html +3 -0
- package/dist/dashboard-web/style.css +692 -1
- package/dist/dashboard.js +72 -3
- package/dist/dashboard.js.map +1 -1
- package/dist/im/lark/client.d.ts +8 -0
- package/dist/im/lark/client.d.ts.map +1 -1
- package/dist/im/lark/client.js +32 -0
- package/dist/im/lark/client.js.map +1 -1
- package/dist/index-daemon.js +9 -0
- package/dist/index-daemon.js.map +1 -1
- package/dist/services/hook-runner.d.ts +10 -0
- package/dist/services/hook-runner.d.ts.map +1 -1
- package/dist/services/hook-runner.js +53 -19
- package/dist/services/hook-runner.js.map +1 -1
- package/dist/services/team-board-store.d.ts +33 -0
- package/dist/services/team-board-store.d.ts.map +1 -0
- package/dist/services/team-board-store.js +88 -0
- package/dist/services/team-board-store.js.map +1 -0
- package/dist/services/team-groups-store.d.ts +8 -0
- package/dist/services/team-groups-store.d.ts.map +1 -0
- package/dist/services/team-groups-store.js +31 -0
- package/dist/services/team-groups-store.js.map +1 -0
- package/dist/setup/bot-config-editor.d.ts +3 -2
- package/dist/setup/bot-config-editor.d.ts.map +1 -1
- package/dist/setup/bot-config-editor.js +1 -2
- package/dist/setup/bot-config-editor.js.map +1 -1
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/worker.js +1 -1
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,53 +1,53 @@
|
|
|
1
|
-
"use strict";(()=>{var jt=class{sessions=new Map;schedules=new Map;online=!0;listeners=new Set;upsertSessions(n){for(let o of n)this.sessions.set(o.sessionId,o);this.emit()}upsertSchedules(n){for(let o of n)this.schedules.set(o.id,o);this.emit()}applySse(n,o){if(n==="session.spawned")this.sessions.set(o.session.sessionId,o.session);else if(n==="session.update"){let s=this.sessions.get(o.sessionId);s&&this.sessions.set(o.sessionId,{...s,...o.patch})}else if(n==="session.exited"){let s=this.sessions.get(o.sessionId);s&&this.sessions.set(o.sessionId,{...s,status:"closed"})}else if(n==="schedule.created")this.schedules.set(o.schedule.id,o.schedule);else if(n==="schedule.updated"){let s=this.schedules.get(o.id);s&&this.schedules.set(o.id,{...s,...o.patch})}else if(n==="schedule.deleted")this.schedules.delete(o.id);else return;this.emit()}setOnline(n){this.online!==n&&(this.online=n,this.emit())}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}},ee=new jt;async function Ln(){let[e,n]=await Promise.all([fetch("/api/sessions").then(a=>a.json()),fetch("/api/schedules").then(a=>a.json())]);ee.upsertSessions(e.sessions??[]),ee.upsertSchedules(n.schedules??[]);let o=new EventSource("/events"),s=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let a of s)o.addEventListener(a,i=>{try{let l=JSON.parse(i.data);ee.applySse(a,l.body??l)}catch{}});o.onerror=()=>ee.setOnline(!1),o.onopen=()=>ee.setOnline(!0)}var Ft="botmux.dashboard.locale",Zo={"app.name":"botmux","app.subtitle":"\u98DE\u4E66 AI CLI \u63A7\u5236\u53F0","time.secondsAgo":"{value} \u79D2\u524D","time.minutesAgo":"{value} \u5206\u949F\u524D","time.hoursAgo":"{value} \u5C0F\u65F6\u524D","nav.overview":"\u603B\u89C8","nav.sessions":"\u4F1A\u8BDD","nav.groups":"\u7FA4\u7EC4","nav.schedules":"\u5B9A\u65F6","nav.settings":"\u8BBE\u7F6E","nav.botDefaults":"Bot \u914D\u7F6E","status.live":"\u5B9E\u65F6\u8FDE\u63A5","status.disconnected":"\u8FDE\u63A5\u65AD\u5F00","status.system":"\u7CFB\u7EDF","status.light":"\u6D45\u8272","status.dark":"\u6697\u9ED1","status.language":"\u8BED\u8A00","status.theme":"\u4E3B\u9898","theme.base":"\u57FA\u7840","theme.skins":"\u4E3B\u9898\u76AE\u80A4","skin.cyber":"2077","skin.genshin":"\u539F\u795E","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"\u851A\u84DD\u6863\u6848","skin.zzz":"\u7EDD\u533A\u96F6","skin.dragonball":"\u4E03\u9F99\u73E0","skin.ikun":"ikun","botOnboarding.add":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.title":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.intro":"\u9009\u62E9 CLI \u4E0E\u5DE5\u4F5C\u76EE\u5F55\uFF0C\u626B\u7801\u521B\u5EFA PersonalAgent \u5E94\u7528\u540E\u5199\u5165\u672C\u673A bots.json\uFF0C\u5E76\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u3002","botOnboarding.cliLabel":"CLI \u9002\u914D\u5668","botOnboarding.dirLabel":"\u5DE5\u4F5C\u76EE\u5F55","botOnboarding.dirPlaceholder":"\u9ED8\u8BA4 ~\uFF08\u5BB6\u76EE\u5F55\uFF09\uFF0C\u9700\u4E3A daemon \u4E3B\u673A\u4E0A\u5DF2\u5B58\u5728\u7684\u76EE\u5F55","botOnboarding.modelLabel":"\u6A21\u578B\uFF08\u53EF\u9009\uFF09","botOnboarding.modelPlaceholder":"\u7559\u7A7A\u4F7F\u7528\u8BE5 CLI \u7684\u9ED8\u8BA4\u6A21\u578B","botOnboarding.startScan":"\u5F00\u59CB\u626B\u7801","botOnboarding.cancel":"\u53D6\u6D88","botOnboarding.starting":"\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...","botOnboarding.waiting":"\u8BF7\u7528\u98DE\u4E66 App \u626B\u7801\u786E\u8BA4\u521B\u5EFA\u5E94\u7528\u3002","botOnboarding.verifying":"\u626B\u7801\u6210\u529F\uFF0C\u6B63\u5728\u6821\u9A8C\u51ED\u8BC1...","botOnboarding.configuringPermissions":"\u6B63\u5728\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u2026","botOnboarding.platformScanHint":"\u8BF7\u7528\u98DE\u4E66 App \u518D\u626B\u4E00\u6B21\u7801\u767B\u5F55\u5F00\u653E\u5E73\u53F0\uFF08\u7528\u4E8E\u81EA\u52A8\u5BFC\u5165\u6743\u9650\u3001\u914D\u7F6E\u56DE\u8C03\u3001\u63D0\u4EA4\u7248\u672C\uFF09\u3002","botOnboarding.platformQrAlt":"\u5F00\u653E\u5E73\u53F0\u767B\u5F55\u4E8C\u7EF4\u7801","botOnboarding.completed":"\u673A\u5668\u4EBA\u5DF2\u6DFB\u52A0\u3002","botOnboarding.permissionOk":"\u5DF2\u81EA\u52A8\u5BFC\u5165 {count} \u9879\u6743\u9650\u3002","botOnboarding.permissionSkipped":"\uFF08\u8DF3\u8FC7 {count} \u9879\u5F53\u524D\u79DF\u6237\u76EE\u5F55\u4E2D\u6CA1\u6709\u7684\u6743\u9650\uFF09","botOnboarding.permissionVersion":"\u5DF2\u63D0\u4EA4\u53D1\u5E03\u7248\u672C {version}\u3002","botOnboarding.permissionManual":"\u6743\u9650\u672A\u80FD\u81EA\u52A8\u914D\u7F6E\uFF0C\u8BF7\u624B\u52A8\u5B8C\u6210\u4EE5\u4E0B\u6B65\u9AA4\uFF1A","botOnboarding.metaDir":"\u76EE\u5F55","botOnboarding.failed":"\u6DFB\u52A0\u5931\u8D25","botOnboarding.openLink":"\u6253\u4E0D\u5F00\u626B\u7801\uFF1F\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00","botOnboarding.close":"\u5173\u95ED","botOnboarding.restartHint":"\u5DF2\u5199\u5165 bots.json\u3002\u6267\u884C pnpm daemon:restart \u540E\u65B0\u673A\u5668\u4EBA\u751F\u6548\u3002","botOnboarding.qrAlt":"\u98DE\u4E66\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA\u4E8C\u7EF4\u7801","overview.title":"\u5DE5\u4F5C\u53F0","overview.subtitle":"\u6570\u5B57\u5458\u5DE5\u5B9E\u65F6\u72B6\u6001 \xB7 \u540C\u6B65\u98DE\u4E66\u8BDD\u9898","overview.team":"AI \u56E2\u961F","overview.teamHint":"\u6BCF\u4F4D\u6570\u5B57\u5458\u5DE5\u7684\u5B9E\u65F6\u72B6\u6001","overview.attention":"\u9700\u8981\u4F60\u5904\u7406","overview.attentionHint":"\u5361\u4F4F\u7684\u4EFB\u52A1\uFF0C\u56DE\u4E2A\u8BDD\u5C31\u80FD\u7EE7\u7EED\u8DD1","overview.activeSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.activeSessionsHint":"\u6B63\u5728\u8FD0\u8F6C\u7684\u4F1A\u8BDD","overview.today":"\u6B64\u523B\u6982\u89C8","overview.todayHint":"\u6D3B\u8DC3\u4F1A\u8BDD\u5206\u5E03","overview.viewAll":"\u67E5\u770B\u5168\u90E8 \u2192","overview.botIdle":"\u5F85\u547D\u4E2D\uFF0C\u968F\u65F6\u53EF\u63A5\u65B0\u4EFB\u52A1","overview.botOffline":"\u79BB\u7EBF \u2014 daemon \u672A\u4E0A\u7EBF","overview.botBusy":"\u6267\u884C\u4E2D \xB7 {count} \u4F1A\u8BDD","overview.botNeedsYou":"\u7B49\u4F60\u56DE\u590D","overview.botReady":"\u5C31\u7EEA","overview.botOff":"\u79BB\u7EBF","overview.sessionsCount":"{count} \u4F1A\u8BDD","overview.lastActive":"{time}\u524D\u6D3B\u8DC3","overview.noAttention":"\u6CA1\u6709\u7B49\u4F60\u5904\u7406\u7684\u4E8B\u9879","overview.teamExpand":"\u5C55\u5F00\u5168\u90E8 {count} \u4F4D \u25BE","overview.teamCollapse":"\u6536\u8D77 \u25B4","strip.pending":"{count} \u4EF6\u5F85\u5904\u7406","strip.longest":"\u6700\u4E45\u5DF2\u7B49 {time} \u2014 {bot} {reason}","strip.handle":"\u7ACB\u5373\u5904\u7406","overview.openSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.workingSessions":"\u5DE5\u4F5C\u4E2D","overview.onlineBots":"\u5728\u7EBF Bot","overview.schedules":"\u5B9A\u65F6\u4EFB\u52A1","overview.groups":"\u7FA4\u804A\u8986\u76D6","overview.enabledSchedules":"\u5DF2\u542F\u7528","overview.total":"\u603B\u8BA1","overview.active":"\u6D3B\u8DC3","overview.daemonRegistry":"daemon \u6CE8\u518C\u8868","overview.chatMatrix":"\u7FA4\u804A\u77E9\u9635","overview.recentSessions":"\u6700\u8FD1\u4F1A\u8BDD","overview.nextSchedules":"\u5373\u5C06\u6267\u884C","overview.noSessions":"\u6682\u65E0\u4F1A\u8BDD\u3002","overview.noSchedules":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","sessions.title":"\u4F1A\u8BDD\u63A7\u5236","sessions.subtitle":"\u5B9A\u4F4D\u98DE\u4E66\u8BDD\u9898\u3001\u6253\u5F00 Web Terminal\u3001\u5173\u95ED\u6216\u6062\u590D CLI \u4F1A\u8BDD\u3002","sessions.search":"\u641C\u7D22\u5DE5\u4F5C\u76EE\u5F55 / \u6807\u9898 / ID","sessions.anyStatus":"\u5168\u90E8\u72B6\u6001","sessions.adoptAny":"adopt: \u5168\u90E8","sessions.adoptYes":"adopt: \u662F","sessions.adoptNo":"adopt: \u5426","sessions.activeOnly":"\u4EC5\u6D3B\u8DC3","sessions.closeSelected":"\u5173\u95ED\u9009\u4E2D","sessions.clearSelection":"\u53D6\u6D88\u9009\u62E9","sessions.selectedCount":"\u5DF2\u9009 {count} \u4E2A\u4F1A\u8BDD","sessions.bot":"bot","sessions.cli":"CLI","sessions.chat":"\u7FA4\u804A","sessions.openChat":"\u6253\u5F00\u7FA4\u804A","sessions.status":"\u72B6\u6001","sessions.tokenIn":"Token In","sessions.tokenOut":"Token Out","sessions.titleCol":"\u6807\u9898","sessions.workingDir":"\u5DE5\u4F5C\u76EE\u5F55","sessions.created":"\u521B\u5EFA","sessions.last":"\u6700\u8FD1","sessions.adopt":"\u63A5\u5165","sessions.actions":"\u64CD\u4F5C","sessions.details":"\u8BE6\u60C5","sessions.copy":"\u590D\u5236","sessions.copied":"\u5DF2\u590D\u5236","sessions.locate":"\u5B9A\u4F4D\u8BDD\u9898","sessions.locating":"\u53D1\u9001\u4E2D...","sessions.cooldown":"\u51B7\u5374 {seconds}s","sessions.openTerminal":"\u7EC8\u7AEF","sessions.writeLink":"\u64CD\u4F5C\u94FE\u63A5","sessions.writeLinkHint":"\u83B7\u53D6\u53EF\u64CD\u4F5C\u7EC8\u7AEF\u94FE\u63A5\uFF08\u5E26\u5199\u6743\u9650 token\uFF0C\u65B0\u6807\u7B7E\u6253\u5F00\uFF09","sessions.writeLinkFail":"\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u5931\u8D25","sessions.close":"\u5173\u95ED\u4F1A\u8BDD","sessions.resume":"\u6062\u590D\u4F1A\u8BDD","sessions.dismiss":"\u5173\u95ED","sessions.closeConfirm":"\u5173\u95ED\u8FD9\u4E2A\u4F1A\u8BDD\uFF1F","sessions.resumeFailed":"\u6062\u590D\u5931\u8D25","sessions.land":"\u843D\u76D8","sessions.landLoading":"\u52A0\u8F7D\u6C99\u76D2 diff\u2026","sessions.landUnavailable":"\u65E0\u6CD5\u843D\u76D8","sessions.landEmpty":"\u6C99\u76D2\u526F\u672C\u6CA1\u6709\u6539\u52A8\u3002","sessions.landApply":"\u5E94\u7528\u5230\u78C1\u76D8","sessions.landDiscard":"\u4E22\u5F03","sessions.landApplied":"\u5DF2\u843D\u76D8","sessions.landFailed":"\u843D\u76D8\u5931\u8D25","sessions.landDiscarded":"\u5DF2\u4E22\u5F03\uFF08\u6C99\u76D2\u526F\u672C\u672A\u5E94\u7528\uFF09\u3002","connectors.lede":"\u8BA9\u5916\u90E8\u7CFB\u7EDF\uFF08\u76D1\u63A7\u544A\u8B66\u3001CI\u3001\u5DE5\u5355\u2026\uFF09\u901A\u8FC7\u4E00\u4E2A webhook \u89E6\u53D1\u673A\u5668\u4EBA\u5728\u7FA4\u91CC\u8BF4\u8BDD\u6216\u8DD1\u5DE5\u4F5C\u6D41\u3002","connectors.createTitle":"\u65B0\u5EFA Webhook","connectors.fName":"\u540D\u79F0","connectors.fNamePh":"\u5982\uFF1A\u7EBF\u4E0A\u544A\u8B66","connectors.fBot":"\u89E6\u53D1\u7684\u673A\u5668\u4EBA","connectors.fKind":"\u89E6\u53D1\u65B9\u5F0F","connectors.kindTurn":"\u5355\u8F6E\u5BF9\u8BDD\uFF08\u8BA9\u673A\u5668\u4EBA\u56DE\u5E94\u4E00\u6B21\uFF09","connectors.kindWorkflow":"\u5DE5\u4F5C\u6D41","connectors.fWf":"\u5DE5\u4F5C\u6D41 ID","connectors.fMode":"\u6295\u9012\u5230\u54EA\u4E2A\u7FA4","connectors.modeDynamic":"\u7531\u8BF7\u6C42\u6307\u5B9A\uFF08\u7FA4\u968F\u8BF7\u6C42\u4F20\u5165\uFF09","connectors.modeFixed":"\u56FA\u5B9A\u7FA4","connectors.modeNewGroup":"\u6BCF\u6B21\u65B0\u5EFA\u7FA4","connectors.fFixedChat":"\u6295\u9012\u5230\u7684\u7FA4","connectors.fChatManualPh":"\u624B\u52A8\u586B\u7FA4 ID\uFF1Aoc_\u2026","connectors.chatManualLink":"\u627E\u4E0D\u5230\u7FA4\uFF1F\u624B\u52A8\u586B ID \u2192","connectors.chatListLink":"\u4ECE\u7FA4\u5217\u8868\u9009\u62E9 \u2190","connectors.fAllow":"\u5141\u8BB8\u7684\u7FA4","connectors.optional":"\uFF08\u53EF\u9009\uFF09","connectors.allowHint":"\u6309\u4F4F Ctrl/\u2318 \u591A\u9009\uFF1B\u7559\u7A7A = \u4E0D\u9650\u3002\u53EA\u7528\u4E8E\u6821\u9A8C\u8BF7\u6C42\u4F20\u5165\u7684\u7FA4\u662F\u5426\u88AB\u5141\u8BB8\u3002","connectors.dynamicHint":'<b>\u52A8\u6001\u6A21\u5F0F</b>\uFF1A\u7FA4 ID \u968F\u6BCF\u6B21\u8BF7\u6C42\u4F20\u5165\uFF0C\u4E09\u9009\u4E00 \u2014\u2014 \u67E5\u8BE2\u53C2\u6570 <code>?chatId=<\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 gn=class{sessions=new Map;schedules=new Map;online=!0;listeners=new Set;upsertSessions(n){for(let a of n)this.sessions.set(a.sessionId,a);this.emit()}upsertSchedules(n){for(let a of n)this.schedules.set(a.id,a);this.emit()}applySse(n,a){if(n==="session.spawned")this.sessions.set(a.session.sessionId,a.session);else if(n==="session.update"){let s=this.sessions.get(a.sessionId);s&&this.sessions.set(a.sessionId,{...s,...a.patch})}else if(n==="session.exited"){let s=this.sessions.get(a.sessionId);s&&this.sessions.set(a.sessionId,{...s,status:"closed"})}else if(n==="schedule.created")this.schedules.set(a.schedule.id,a.schedule);else if(n==="schedule.updated"){let s=this.schedules.get(a.id);s&&this.schedules.set(a.id,{...s,...a.patch})}else if(n==="schedule.deleted")this.schedules.delete(a.id);else return;this.emit()}setOnline(n){this.online!==n&&(this.online=n,this.emit())}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}},V=new gn;async function ca(){let[e,n]=await Promise.all([fetch("/api/sessions").then(o=>o.json()),fetch("/api/schedules").then(o=>o.json())]);V.upsertSessions(e.sessions??[]),V.upsertSchedules(n.schedules??[]);let a=new EventSource("/events"),s=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let o of s)a.addEventListener(o,l=>{try{let c=JSON.parse(l.data);V.applySse(o,c.body??c)}catch{}});a.onerror=()=>V.setOnline(!1),a.onopen=()=>V.setOnline(!0)}var bn="botmux.dashboard.locale",ss={"app.name":"botmux","app.subtitle":"\u98DE\u4E66 AI CLI \u63A7\u5236\u53F0","time.secondsAgo":"{value} \u79D2\u524D","time.minutesAgo":"{value} \u5206\u949F\u524D","time.hoursAgo":"{value} \u5C0F\u65F6\u524D","nav.overview":"\u603B\u89C8","nav.sessions":"\u4F1A\u8BDD","nav.sidebarCollapse":"\u6536\u8D77\u83DC\u5355\u680F","nav.sidebarExpand":"\u5C55\u5F00\u83DC\u5355\u680F","nav.groups":"\u7FA4\u7EC4","nav.schedules":"\u5B9A\u65F6","nav.settings":"\u8BBE\u7F6E","nav.botDefaults":"Bot \u914D\u7F6E","status.live":"\u5B9E\u65F6\u8FDE\u63A5","status.disconnected":"\u8FDE\u63A5\u65AD\u5F00","status.system":"\u7CFB\u7EDF","status.light":"\u6D45\u8272","status.dark":"\u6697\u9ED1","status.language":"\u8BED\u8A00","status.theme":"\u4E3B\u9898","theme.base":"\u57FA\u7840","theme.skins":"\u4E3B\u9898\u76AE\u80A4","skin.cyber":"2077","skin.genshin":"\u539F\u795E","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"\u851A\u84DD\u6863\u6848","skin.zzz":"\u7EDD\u533A\u96F6","skin.dragonball":"\u4E03\u9F99\u73E0","skin.ikun":"ikun","botOnboarding.add":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.title":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.intro":"\u9009\u62E9 CLI \u4E0E\u5DE5\u4F5C\u76EE\u5F55\uFF0C\u626B\u7801\u521B\u5EFA PersonalAgent \u5E94\u7528\u540E\u5199\u5165\u672C\u673A bots.json\uFF0C\u5E76\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u3002","botOnboarding.cliLabel":"CLI \u9002\u914D\u5668","botOnboarding.dirLabel":"\u5DE5\u4F5C\u76EE\u5F55","botOnboarding.dirPlaceholder":"\u9ED8\u8BA4 ~\uFF08\u5BB6\u76EE\u5F55\uFF09\uFF0C\u9700\u4E3A daemon \u4E3B\u673A\u4E0A\u5DF2\u5B58\u5728\u7684\u76EE\u5F55","botOnboarding.modelLabel":"\u6A21\u578B\uFF08\u53EF\u9009\uFF09","botOnboarding.modelPlaceholder":"\u7559\u7A7A\u4F7F\u7528\u8BE5 CLI \u7684\u9ED8\u8BA4\u6A21\u578B","botOnboarding.startScan":"\u5F00\u59CB\u626B\u7801","botOnboarding.cancel":"\u53D6\u6D88","botOnboarding.starting":"\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...","botOnboarding.waiting":"\u8BF7\u7528\u98DE\u4E66 App \u626B\u7801\u786E\u8BA4\u521B\u5EFA\u5E94\u7528\u3002","botOnboarding.verifying":"\u626B\u7801\u6210\u529F\uFF0C\u6B63\u5728\u6821\u9A8C\u51ED\u8BC1...","botOnboarding.configuringPermissions":"\u6B63\u5728\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u2026","botOnboarding.platformScanHint":"\u8BF7\u7528\u98DE\u4E66 App \u518D\u626B\u4E00\u6B21\u7801\u767B\u5F55\u5F00\u653E\u5E73\u53F0\uFF08\u7528\u4E8E\u81EA\u52A8\u5BFC\u5165\u6743\u9650\u3001\u914D\u7F6E\u56DE\u8C03\u3001\u63D0\u4EA4\u7248\u672C\uFF09\u3002","botOnboarding.platformQrAlt":"\u5F00\u653E\u5E73\u53F0\u767B\u5F55\u4E8C\u7EF4\u7801","botOnboarding.completed":"\u673A\u5668\u4EBA\u5DF2\u6DFB\u52A0\u3002","botOnboarding.permissionOk":"\u5DF2\u81EA\u52A8\u5BFC\u5165 {count} \u9879\u6743\u9650\u3002","botOnboarding.permissionSkipped":"\uFF08\u8DF3\u8FC7 {count} \u9879\u5F53\u524D\u79DF\u6237\u76EE\u5F55\u4E2D\u6CA1\u6709\u7684\u6743\u9650\uFF09","botOnboarding.permissionVersion":"\u5DF2\u63D0\u4EA4\u53D1\u5E03\u7248\u672C {version}\u3002","botOnboarding.permissionManual":"\u6743\u9650\u672A\u80FD\u81EA\u52A8\u914D\u7F6E\uFF0C\u8BF7\u624B\u52A8\u5B8C\u6210\u4EE5\u4E0B\u6B65\u9AA4\uFF1A","botOnboarding.metaDir":"\u76EE\u5F55","botOnboarding.failed":"\u6DFB\u52A0\u5931\u8D25","botOnboarding.openLink":"\u6253\u4E0D\u5F00\u626B\u7801\uFF1F\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00","botOnboarding.close":"\u5173\u95ED","botOnboarding.restartHint":"\u5DF2\u5199\u5165 bots.json\u3002\u6267\u884C pnpm daemon:restart \u540E\u65B0\u673A\u5668\u4EBA\u751F\u6548\u3002","botOnboarding.qrAlt":"\u98DE\u4E66\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA\u4E8C\u7EF4\u7801","overview.title":"\u5DE5\u4F5C\u53F0","overview.subtitle":"\u6570\u5B57\u5458\u5DE5\u5B9E\u65F6\u72B6\u6001 \xB7 \u540C\u6B65\u98DE\u4E66\u8BDD\u9898","overview.team":"AI \u56E2\u961F","overview.teamHint":"\u6BCF\u4F4D\u6570\u5B57\u5458\u5DE5\u7684\u5B9E\u65F6\u72B6\u6001","overview.attention":"\u9700\u8981\u4F60\u5904\u7406","overview.attentionHint":"\u5361\u4F4F\u7684\u4EFB\u52A1\uFF0C\u56DE\u4E2A\u8BDD\u5C31\u80FD\u7EE7\u7EED\u8DD1","overview.activeSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.activeSessionsHint":"\u6B63\u5728\u8FD0\u8F6C\u7684\u4F1A\u8BDD","overview.today":"\u6B64\u523B\u6982\u89C8","overview.todayHint":"\u6D3B\u8DC3\u4F1A\u8BDD\u5206\u5E03","overview.viewAll":"\u67E5\u770B\u5168\u90E8 \u2192","overview.botIdle":"\u5F85\u547D\u4E2D\uFF0C\u968F\u65F6\u53EF\u63A5\u65B0\u4EFB\u52A1","overview.botOffline":"\u79BB\u7EBF \u2014 daemon \u672A\u4E0A\u7EBF","overview.botBusy":"\u6267\u884C\u4E2D \xB7 {count} \u4F1A\u8BDD","overview.botNeedsYou":"\u7B49\u4F60\u56DE\u590D","overview.botReady":"\u5C31\u7EEA","overview.botOff":"\u79BB\u7EBF","overview.sessionsCount":"{count} \u4F1A\u8BDD","overview.lastActive":"{time}\u524D\u6D3B\u8DC3","overview.noAttention":"\u6CA1\u6709\u7B49\u4F60\u5904\u7406\u7684\u4E8B\u9879","overview.teamExpand":"\u5C55\u5F00\u5168\u90E8 {count} \u4F4D \u25BE","overview.teamCollapse":"\u6536\u8D77 \u25B4","strip.pending":"{count} \u4EF6\u5F85\u5904\u7406","strip.longest":"\u6700\u4E45\u5DF2\u7B49 {time} \u2014 {bot} {reason}","strip.handle":"\u7ACB\u5373\u5904\u7406","overview.openSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.workingSessions":"\u5DE5\u4F5C\u4E2D","overview.onlineBots":"\u5728\u7EBF Bot","overview.schedules":"\u5B9A\u65F6\u4EFB\u52A1","overview.groups":"\u7FA4\u804A\u8986\u76D6","overview.enabledSchedules":"\u5DF2\u542F\u7528","overview.total":"\u603B\u8BA1","overview.active":"\u6D3B\u8DC3","overview.daemonRegistry":"daemon \u6CE8\u518C\u8868","overview.chatMatrix":"\u7FA4\u804A\u77E9\u9635","overview.recentSessions":"\u6700\u8FD1\u4F1A\u8BDD","overview.nextSchedules":"\u5373\u5C06\u6267\u884C","overview.noSessions":"\u6682\u65E0\u4F1A\u8BDD\u3002","overview.noSchedules":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","sessions.title":"\u4F1A\u8BDD\u63A7\u5236","sessions.subtitle":"\u5B9A\u4F4D\u98DE\u4E66\u8BDD\u9898\u3001\u6253\u5F00 Web Terminal\u3001\u5173\u95ED\u6216\u6062\u590D CLI \u4F1A\u8BDD\u3002","sessions.search":"\u641C\u7D22\u5DE5\u4F5C\u76EE\u5F55 / \u6807\u9898 / ID","sessions.anyStatus":"\u5168\u90E8\u72B6\u6001","sessions.adoptAny":"adopt: \u5168\u90E8","sessions.adoptYes":"adopt: \u662F","sessions.adoptNo":"adopt: \u5426","sessions.activeOnly":"\u4EC5\u6D3B\u8DC3","sessions.closeSelected":"\u5173\u95ED\u9009\u4E2D","sessions.clearSelection":"\u53D6\u6D88\u9009\u62E9","sessions.selectedCount":"\u5DF2\u9009 {count} \u4E2A\u4F1A\u8BDD","sessions.bot":"bot","sessions.cli":"CLI","sessions.chat":"\u7FA4\u804A","sessions.openChat":"\u6253\u5F00\u7FA4\u804A","sessions.status":"\u72B6\u6001","sessions.tokenIn":"Token In","sessions.tokenOut":"Token Out","sessions.titleCol":"\u6807\u9898","sessions.workingDir":"\u5DE5\u4F5C\u76EE\u5F55","sessions.created":"\u521B\u5EFA","sessions.last":"\u6700\u8FD1","sessions.adopt":"\u63A5\u5165","sessions.actions":"\u64CD\u4F5C","sessions.details":"\u8BE6\u60C5","sessions.copy":"\u590D\u5236","sessions.copied":"\u5DF2\u590D\u5236","sessions.locate":"\u5B9A\u4F4D\u8BDD\u9898","sessions.locating":"\u53D1\u9001\u4E2D...","sessions.cooldown":"\u51B7\u5374 {seconds}s","sessions.openTerminal":"\u7EC8\u7AEF","sessions.writeLink":"\u64CD\u4F5C\u94FE\u63A5","sessions.writeLinkHint":"\u83B7\u53D6\u53EF\u64CD\u4F5C\u7EC8\u7AEF\u94FE\u63A5\uFF08\u5E26\u5199\u6743\u9650 token\uFF0C\u65B0\u6807\u7B7E\u6253\u5F00\uFF09","sessions.writeLinkFail":"\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u5931\u8D25","sessions.close":"\u5173\u95ED\u4F1A\u8BDD","sessions.resume":"\u6062\u590D\u4F1A\u8BDD","sessions.dismiss":"\u5173\u95ED","sessions.closeConfirm":"\u5173\u95ED\u8FD9\u4E2A\u4F1A\u8BDD\uFF1F","sessions.resumeFailed":"\u6062\u590D\u5931\u8D25","sessions.land":"\u843D\u76D8","sessions.landLoading":"\u52A0\u8F7D\u6C99\u76D2 diff\u2026","sessions.landUnavailable":"\u65E0\u6CD5\u843D\u76D8","sessions.landEmpty":"\u6C99\u76D2\u526F\u672C\u6CA1\u6709\u6539\u52A8\u3002","sessions.landApply":"\u5E94\u7528\u5230\u78C1\u76D8","sessions.landDiscard":"\u4E22\u5F03","sessions.landApplied":"\u5DF2\u843D\u76D8","sessions.landFailed":"\u843D\u76D8\u5931\u8D25","sessions.landDiscarded":"\u5DF2\u4E22\u5F03\uFF08\u6C99\u76D2\u526F\u672C\u672A\u5E94\u7528\uFF09\u3002","connectors.lede":"\u8BA9\u5916\u90E8\u7CFB\u7EDF\uFF08\u76D1\u63A7\u544A\u8B66\u3001CI\u3001\u5DE5\u5355\u2026\uFF09\u901A\u8FC7\u4E00\u4E2A webhook \u89E6\u53D1\u673A\u5668\u4EBA\u5728\u7FA4\u91CC\u8BF4\u8BDD\u6216\u8DD1\u5DE5\u4F5C\u6D41\u3002","connectors.createTitle":"\u65B0\u5EFA Webhook","connectors.fName":"\u540D\u79F0","connectors.fNamePh":"\u5982\uFF1A\u7EBF\u4E0A\u544A\u8B66","connectors.fBot":"\u89E6\u53D1\u7684\u673A\u5668\u4EBA","connectors.fKind":"\u89E6\u53D1\u65B9\u5F0F","connectors.kindTurn":"\u5355\u8F6E\u5BF9\u8BDD\uFF08\u8BA9\u673A\u5668\u4EBA\u56DE\u5E94\u4E00\u6B21\uFF09","connectors.kindWorkflow":"\u5DE5\u4F5C\u6D41","connectors.fWf":"\u5DE5\u4F5C\u6D41 ID","connectors.fMode":"\u6295\u9012\u5230\u54EA\u4E2A\u7FA4","connectors.modeDynamic":"\u7531\u8BF7\u6C42\u6307\u5B9A\uFF08\u7FA4\u968F\u8BF7\u6C42\u4F20\u5165\uFF09","connectors.modeFixed":"\u56FA\u5B9A\u7FA4","connectors.modeNewGroup":"\u6BCF\u6B21\u65B0\u5EFA\u7FA4","connectors.fFixedChat":"\u6295\u9012\u5230\u7684\u7FA4","connectors.fChatManualPh":"\u624B\u52A8\u586B\u7FA4 ID\uFF1Aoc_\u2026","connectors.chatManualLink":"\u627E\u4E0D\u5230\u7FA4\uFF1F\u624B\u52A8\u586B ID \u2192","connectors.chatListLink":"\u4ECE\u7FA4\u5217\u8868\u9009\u62E9 \u2190","connectors.fAllow":"\u5141\u8BB8\u7684\u7FA4","connectors.optional":"\uFF08\u53EF\u9009\uFF09","connectors.allowHint":"\u6309\u4F4F Ctrl/\u2318 \u591A\u9009\uFF1B\u7559\u7A7A = \u4E0D\u9650\u3002\u53EA\u7528\u4E8E\u6821\u9A8C\u8BF7\u6C42\u4F20\u5165\u7684\u7FA4\u662F\u5426\u88AB\u5141\u8BB8\u3002","connectors.dynamicHint":'<b>\u52A8\u6001\u6A21\u5F0F</b>\uFF1A\u7FA4 ID \u968F\u6BCF\u6B21\u8BF7\u6C42\u4F20\u5165\uFF0C\u4E09\u9009\u4E00 \u2014\u2014 \u67E5\u8BE2\u53C2\u6570 <code>?chatId=<\u7FA4ID></code> \xB7 \u8BF7\u6C42\u5934 <code>x-botmux-chat-id: <\u7FA4ID></code> \xB7 \u8BF7\u6C42\u4F53 <code>{"chatId":"<\u7FA4ID>"}</code>\u3002<br>\u60F3"\u4E00\u4E2A URL \u76F4\u63A5\u89E6\u53D1\u3001\u4E0D\u5E26\u53C2\u6570"\uFF0C\u8BF7\u6539\u9009\u300C\u56FA\u5B9A\u7FA4\u300D\u3002',"connectors.fDedup":"\u53BB\u91CD\u5B57\u6BB5","connectors.fDedupPh":"\u5982 alert.id\uFF08\u4ECE\u4E8B\u4EF6 body \u53D6\u503C\uFF09","connectors.dedupHint":"\u586B\u4E86\uFF1A\u547D\u4E2D\u76F8\u540C\u503C\u7684\u4E8B\u4EF6\u90FD\u6295\u5230<b>\u540C\u4E00\u4E2A\u7FA4</b>\u3002\u7559\u7A7A\uFF1A\u6BCF\u4E2A\u4E8B\u4EF6<b>\u65B0\u5EFA\u4E00\u4E2A\u7FA4</b>\u3002","connectors.fInstruction":"\u5904\u7406\u6307\u4EE4","connectors.fInstructionPh":"\u4E8B\u4EF6\u89E6\u53D1\u65F6\u8BA9\u673A\u5668\u4EBA\u505A\u4EC0\u4E48\u3002\u5982\uFF1A\u603B\u7ED3\u8FD9\u6761\u544A\u8B66\u7684\u4E25\u91CD\u7A0B\u5EA6\uFF0C@\u76F8\u5173 oncall\uFF0C\u7ED9\u51FA\u6392\u67E5\u5EFA\u8BAE\u3002\u7559\u7A7A = \u53EA\u628A\u4E8B\u4EF6\u539F\u6837\u4EA4\u7ED9\u6A21\u578B\u81EA\u7531\u53D1\u6325\u3002","connectors.fVerify":"\u6821\u9A8C\u65B9\u5F0F","connectors.verifyToken":"\u4EE4\u724C\uFF08\u7B80\u5355\uFF1A\u5BC6\u94A5\u653E\u8FDB URL\uFF0C\u4E00\u6761 curl \u5C31\u80FD\u89E6\u53D1\uFF09","connectors.verifyHmac":"HMAC \u7B7E\u540D\uFF08\u9AD8\u7EA7\uFF1A\u66F4\u5B89\u5168\uFF0C\u9700\u81EA\u884C\u5BF9\u8BF7\u6C42\u7B7E\u540D\uFF09","connectors.fSecret":"\u5BC6\u94A5 / \u4EE4\u724C","connectors.fSecretPh":"\u7559\u7A7A\u81EA\u52A8\u751F\u6210\uFF08\u53EA\u663E\u793A\u4E00\u6B21\uFF09","connectors.btnCreate":"\u521B\u5EFA","connectors.listTitle":"\u5DF2\u6709 Webhook","connectors.loading":"\u52A0\u8F7D\u4E2D\u2026","connectors.noBotGroups":"\uFF08\u8BE5\u673A\u5668\u4EBA\u6682\u65E0\u53EF\u89C1\u7FA4\uFF0C\u70B9\u53F3\u4FA7\u624B\u52A8\u586B ID\uFF09","connectors.modeLabelFixed":"\u56FA\u5B9A\u7FA4","connectors.modeLabelNewGroup":"\u6BCF\u6B21\u65B0\u5EFA\u7FA4","connectors.modeLabelDynamic":"\u8BF7\u6C42\u6307\u5B9A\u7FA4","connectors.kindLabelWorkflow":"\u5DE5\u4F5C\u6D41","connectors.kindLabelTurn":"\u5355\u8F6E","connectors.count":"\xB7 {count} \u4E2A","connectors.empty":"\u8FD8\u6CA1\u6709 Webhook\u3002\u7528\u4E0A\u9762\u7684\u8868\u5355\u521B\u5EFA\u4E00\u4E2A\u3002","connectors.enabled":"\u5DF2\u542F\u7528","connectors.disabled":"\u5DF2\u505C\u7528","connectors.badgeToken":"\u4EE4\u724C","connectors.badgeSign":"\u7B7E\u540D","connectors.dest":"\u6295\u9012\u300C{name}\u300D","connectors.btnDisable":"\u505C\u7528","connectors.btnEnable":"\u542F\u7528","connectors.btnDel":"\u5220\u9664","connectors.webhookUrl":"Webhook URL\uFF1A","connectors.copy":"\u590D\u5236","connectors.copied":"\u5DF2\u590D\u5236","connectors.tokenHint":"\u4EE4\u724C\u6A21\u5F0F\uFF1A\u8C03\u7528\u65F6\u5728 URL \u672B\u5C3E\u8FFD\u52A0 <code>/<\u4EE4\u724C></code>\uFF08\u4EE4\u724C\u4EC5\u521B\u5EFA/\u8F6E\u6362\u65F6\u663E\u793A\u4E00\u6B21\uFF09\u3002","connectors.dynamicReqHint":'\u52A8\u6001\u6A21\u5F0F\uFF1A\u8BF7\u6C42\u9700\u5E26\u76EE\u6807\u7FA4 \u2014\u2014 <code>?chatId=<\u7FA4ID></code> \u6216\u5934 <code>x-botmux-chat-id</code> \u6216 body <code>{"chatId":"\u2026"}</code>\u3002',"connectors.instructionPrefix":"\u5904\u7406\u6307\u4EE4\uFF1A","connectors.delConfirm":"\u5220\u9664\u8FD9\u4E2A Webhook\uFF1F\u5B83\u7684 URL \u4F1A\u7ACB\u5373\u5931\u6548\u3002","connectors.errName":"\u8BF7\u586B\u540D\u79F0","connectors.errBot":"\u8BF7\u9009\u673A\u5668\u4EBA","connectors.errWf":"\u8BF7\u586B\u5DE5\u4F5C\u6D41 ID","connectors.errChat":"\u8BF7\u9009\u62E9\uFF08\u6216\u624B\u52A8\u586B\uFF09\u6295\u9012\u7684\u7FA4","connectors.creating":"\u521B\u5EFA\u4E2D\u2026","connectors.usageDynamicLede":"\u52A8\u6001\u6A21\u5F0F\uFF1AURL \u5DF2\u542B\u4EE4\u724C\uFF0C\u8C03\u7528\u65F6\u518D\u5E26\u4E0A\u76EE\u6807\u7FA4 ID{gn}\uFF1A","connectors.usageDynamicNote":'\u7FA4\u4E5F\u53EF\u653E\u8BF7\u6C42\u5934 <code>x-botmux-chat-id</code> \u6216 body <code>{"chatId":"\u2026"}</code>\u3002\u26A0\uFE0F URL \u5373\u51ED\u8BC1\uFF0C\u52FF\u6CC4\u6F0F\u3002',"connectors.usageTokenLede":"\u6B64 URL \u5DF2\u542B\u4EE4\u724C\u3001\u4E14\u56FA\u5B9A\u6295\u9012\u5230\u6240\u9009\u7FA4\uFF0C\u76F4\u63A5 POST \u5373\u53EF\u89E6\u53D1\uFF1A","connectors.usageTokenNote":"\u26A0\uFE0F URL \u5373\u51ED\u8BC1\uFF0C\u8BF7\u52FF\u516C\u5F00\u6CC4\u6F0F\uFF1B\u53EF\u5728\u4E0B\u65B9\u5217\u8868\u5220\u9664\u6216\u8F6E\u6362\u3002","connectors.usageHmac":"\u5916\u90E8\u7CFB\u7EDF\u9700\u5BF9 <code>timestamp.body</code> \u505A HMAC-SHA256 \u7B7E\u540D\uFF0C\u5E76\u5E26\u4E0A <code>x-botmux-timestamp</code> / <code>x-botmux-nonce</code> / <code>x-botmux-signature</code> \u5934\u8C03\u7528","connectors.usageHmacDynamic":"\uFF0C\u540C\u65F6\u6309\u4E0A\u9762\u65B9\u5F0F\u5E26\u76EE\u6807\u7FA4 ID","connectors.createdPrefix":"\u5DF2\u521B\u5EFA\u300C{name}\u300D","connectors.createdDest":"\u6295\u9012\u5230\u300C{name}\u300D","connectors.tokenLabel":"\u8BBF\u95EE\u4EE4\u724C","connectors.signLabel":"\u7B7E\u540D\u5BC6\u94A5","connectors.secretOnce":"\uFF08\u53EA\u663E\u793A\u8FD9\u4E00\u6B21\uFF0C\u8BF7\u4FDD\u5B58\uFF09\uFF1A","connectors.createFailed":"\u521B\u5EFA\u5931\u8D25\uFF1A{error}","connectors.noOnlineBots":"\uFF08\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF09","team.navHome":"\u6211\u7684\u56E2\u961F","team.navManage":"\u56E2\u961F\u7BA1\u7406","team.eyebrow":"\u56E2\u961F","team.homeTitle":"\u56E2\u961F\u534F\u4F5C\uFF08\u8DE8\u90E8\u7F72\uFF09","team.homeLede":"\u628A\u522B\u7684\u90E8\u7F72\uFF08\u540C\u4E8B\u81EA\u5DF1\u8DD1\u7684 botmux\uFF09\u9080\u8BF7\u8FDB\u540C\u4E00\u4E2A\u56E2\u961F\uFF0C\u4E92\u76F8\u53D1\u73B0\u673A\u5668\u4EBA\u3001\u534F\u4F5C\u62C9\u7FA4\u3002","team.localDeployTitle":"\u672C\u90E8\u7F72","team.myIdentity":"\u6211\u7684\u98DE\u4E66\u8EAB\u4EFD\uFF1A","team.unbound":"\u672A\u7ED1\u5B9A","team.bindBtn":"\u7ED1\u5B9A","team.bindHint":"\uFF08\u7528\u673A\u5668\u4EBA\u51ED\u8BC1\u81EA\u52A8\u8BC6\u522B\u4F60\uFF1B\u7ED1\u5B9A\u540E\u62C9\u7FA4\u4F1A\u628A\u4F60\u62C9\u8FDB\u7FA4\u3001\u673A\u5668\u4EBA\u4E5F\u5F52\u5230\u4F60\u540D\u4E0B\uFF09","team.myTeams":"\u6211\u7684\u56E2\u961F","team.searchPh":"\u641C\u7D22 \u540D\u79F0/\u80FD\u529B/CLI\u2026","team.allCli":"\u5168\u90E8 CLI","team.hasCap":"\u6709\u80FD\u529B\u6807\u7B7E","team.hasRole":"\u6709\u9ED8\u8BA4\u89D2\u8272","team.teamsHint":"\u6BCF\u4E2A\u56E2\u961F\u91CC\u52FE\u9009\u673A\u5668\u4EBA\u5373\u53EF\u5355\u72EC\u62C9\u7FA4\uFF08\u81EA\u52A8\u5E26\u4E0A\u5404\u81EA\u8D1F\u8D23\u4EBA\uFF09\u3002\u8981\u65B0\u5EFA\u56E2\u961F / \u751F\u6210\u9080\u8BF7\u7801 / \u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\uFF0C\u53BB\u300C\u56E2\u961F\u7BA1\u7406\u300D\u3002","team.loading":"\u52A0\u8F7D\u4E2D\u2026","team.roleModalTitle":"\u9ED8\u8BA4\u89D2\u8272","team.roleModalHint":"\u8BE5\u673A\u5668\u4EBA\u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF08\u8DE8\u7FA4\u751F\u6548\uFF09\uFF0C\u6B64\u5904\u53EA\u8BFB\u3002\u5982\u9700\u4FEE\u6539\uFF0C\u8BF7\u5230\u300CBot \u914D\u7F6E\u300D\u9875\u3002","team.close":"\u5173\u95ED","team.tagLocal":"\u672C\u90E8\u7F72","team.tagRemoteStale":"\u8FDC\u7AEF\xB7\u79BB\u7EBF\uFF1F","team.tagRemote":"\u8FDC\u7AEF","team.removeMember":"\u79FB\u9664","team.depTag":"\uFF08{tag}\uFF09","team.depCount":"{count} \u4E2A","team.depSelected":"\uFF0C\u5DF2\u9009 {n}","team.capPh":"\u80FD\u529B\u6807\u7B7E\u2026","team.viewRole":"\u67E5\u770B","team.hasRoleShort":"\u6709\u89D2\u8272","team.noMatch":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u673A\u5668\u4EBA\u3002","team.gnamePh":"\u7FA4\u540D\uFF08\u5982\uFF1A\u8DE8\u56E2\u961F\u6392\u969C\uFF09","team.pullGroupBtn":"\u628A\u52FE\u9009\u7684\u673A\u5668\u4EBA\u62C9\u4E00\u4E2A\u7FA4","team.pullGroupHint":"\u52FE\u9009\u673A\u5668\u4EBA \u2192 \u62C9\u5230\u4E00\u4E2A\u98DE\u4E66\u7FA4\uFF08\u81EA\u52A8\u542B owner\uFF09","team.noTeams":"\u8FD8\u6CA1\u6709\u56E2\u961F\u3002\u53BB\u300C\u56E2\u961F\u7BA1\u7406\u300D\u751F\u6210\u9080\u8BF7\u7801\u8BA9\u522B\u4EBA\u52A0\u5165\u4F60\uFF0C\u6216\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\u3002","team.connected":"\u5DF2\u8FDE\u63A5","team.connectFail":"\u8FDE\u63A5\u5931\u8D25\uFF1A{error}","team.iHost":"\u6211\u6258\u7BA1","team.teamMeta":"{deps} \u4E2A\u90E8\u7F72 \xB7 {bots} \u4E2A\u673A\u5668\u4EBA","team.rosterFail":"\u65E0\u6CD5\u83B7\u53D6\u8BE5\u56E2\u961F\u82B1\u540D\u518C\u3002","team.acrossTeams":"\uFF08\u8DE8 {n} \u4E2A\u56E2\u961F\uFF0C\u53BB\u91CD\uFF09","team.botsWord":"\u4E2A\u673A\u5668\u4EBA","team.groupCreated":"\u7FA4\u5DF2\u521B\u5EFA","team.delegatedBy":"\uFF08\u7531\u300C{name}\u300D\u5EFA\u7FA4\uFF09","team.openInLark":"\u5728\u98DE\u4E66\u6253\u5F00","team.invalidBots":"\u672A\u52A0\u5165\u7684\u673A\u5668\u4EBA\uFF1A{ids}","team.invalidOwners":"{n} \u4E2A owner \u672A\u80FD\u62C9\u8FDB","team.missingIdentity":"\u4F60\u672A\u7ED1\u5B9A\u98DE\u4E66\u8EAB\u4EFD\uFF0C\u6CA1\u628A\u4F60\u81EA\u5DF1\u62C9\u8FDB\u7FA4\uFF08\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u7ED1\u5B9A\uFF09","team.skippedNoOwner":"{n} \u4E2A\u673A\u5668\u4EBA\u56E0\u8D1F\u8D23\u4EBA\u672A\u7ED1\u5B9A\u8EAB\u4EFD\u88AB\u8DF3\u8FC7\uFF08\u672A\u52A0\u5165\u7FA4\uFF09","team.errNoLocalBot":"\u8BF7\u81F3\u5C11\u52FE\u9009\u4E00\u4E2A\u4F60\u81EA\u5DF1\uFF08\u672C\u90E8\u7F72\uFF09\u7684\u5728\u7EBF\u673A\u5668\u4EBA\u2014\u2014\u7FA4\u8981\u7531\u5B83\u521B\u5EFA\u5E76\u628A\u4F60\uFF08\u53D1\u8D77\u4EBA\uFF09\u62C9\u8FDB\u7FA4\u3002","team.errAllSkipped":"\u6240\u9009\u673A\u5668\u4EBA\u7684\u8D1F\u8D23\u4EBA\u90FD\u6CA1\u7ED1\u5B9A\u8EAB\u4EFD\uFF0C\u65E0\u6CD5\u62C9\u7FA4\uFF08\u673A\u5668\u4EBA\u4E0D\u80FD\u8FDB\u4E00\u4E2A owner \u4E0D\u5728\u7684\u7FA4\uFF09\u3002\u8BF7\u8BA9\u5BF9\u5E94\u90E8\u7F72\u5148\u7ED1\u5B9A\u8EAB\u4EFD\u3002","team.errNoCreator":"\u6CA1\u6709\u53EF\u7528\u7684\u5EFA\u7FA4\u53D1\u8D77\u65B9\uFF08\u76F8\u5173\u90E8\u7F72\u90FD\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF0C\u6216\u4E0D\u53EF\u8FBE\uFF09","team.errDelegationTimeout":"\u59D4\u6258\u5BF9\u65B9\u90E8\u7F72\u5EFA\u7FA4\u8D85\u65F6\uFF08\u53EF\u80FD\u5DF2\u5EFA\uFF0C\u53BB\u98DE\u4E66\u786E\u8BA4\uFF0C\u52FF\u91CD\u590D\u70B9\uFF09","team.errGroupCreate":"\u5EFA\u7FA4\u5931\u8D25\uFF1A{error}","team.roleModalTitleName":"\u9ED8\u8BA4\u89D2\u8272 \xB7 {name}","team.bound":"\u5DF2\u7ED1\u5B9A","team.myHostedTeam":"\u6211\u6258\u7BA1\u7684\u56E2\u961F","team.remoteTeamLabel":"{name} \u7684\u56E2\u961F","team.manageTitle":"\u56E2\u961F\u7BA1\u7406","team.manageLede":"\u521B\u5EFA\u591A\u4E2A\u56E2\u961F\u3001\u7ED9\u6BCF\u4E2A\u56E2\u961F\u751F\u6210\u9080\u8BF7\u7801\u3001\u6216\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\u3002\u4E00\u4E2A\u56E2\u961F = \u4F60\u672C\u90E8\u7F72\u7684\u673A\u5668\u4EBA + \u52A0\u5165\u8BE5\u56E2\u961F\u7684\u5176\u5B83\u90E8\u7F72\u3002","team.hostedTitle":"\u6211\u6258\u7BA1\u7684\u56E2\u961F","team.newTeamPh":"\u65B0\u56E2\u961F\u540D\u79F0","team.createTeamBtn":"\u521B\u5EFA\u56E2\u961F","team.joinTitle":"\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F","team.hubPh":"Hub \u5730\u5740\uFF0C\u5982 http://10.0.0.5:7891","team.codePh":"\u9080\u8BF7\u7801","team.joinBtn":"\u52A0\u5165","team.noTeamsShort":"\u8FD8\u6CA1\u6709\u56E2\u961F\u3002","team.default":"\u9ED8\u8BA4","team.manageMetaDeps":"{count} \u4E2A\u90E8\u7F72","team.manageMetaRemote":"\uFF08\u542B {r} \u8FDC\u7AEF\uFF09","team.manageMetaBots":"{count} \u4E2A\u673A\u5668\u4EBA","team.genInvite":"\u751F\u6210\u9080\u8BF7\u7801","team.delBtn":"\u5220\u9664","team.generating":"\u751F\u6210\u4E2D\u2026","team.inviteResultLede":"\u628A\u4E0B\u9762\u4E24\u9879\u53D1\u7ED9\u522B\u7684\u90E8\u7F72\u7684\u4EBA\uFF0824 \u5C0F\u65F6\u5185\u3001\u5355\u6B21\u6709\u6548\uFF09\uFF1A","team.inviteHub":"Hub \u5730\u5740\uFF1A","team.inviteCode":"\u9080\u8BF7\u7801\uFF1A","team.genFail":"\u751F\u6210\u5931\u8D25\u3002","team.delConfirm":"\u5220\u9664\u56E2\u961F\u300C{name}\u300D\uFF1F\u5DF2\u52A0\u5165\u5B83\u7684\u90E8\u7F72\u4F1A\u88AB\u79FB\u9664\uFF08\u4E0D\u5F71\u54CD\u4ED6\u4EEC\u81EA\u5DF1\u7684\u90E8\u7F72\uFF09\u3002","team.errName":"\u8BF7\u586B\u56E2\u961F\u540D\u79F0","team.creating":"\u521B\u5EFA\u4E2D\u2026","team.created":"\u5DF2\u521B\u5EFA","team.createFail":"\u521B\u5EFA\u5931\u8D25\uFF1A{error}","team.errHubCode":"\u8BF7\u586B Hub \u5730\u5740\u548C\u9080\u8BF7\u7801\u3002","team.joining":"\u52A0\u5165\u4E2D\u2026","team.joined":"\u5DF2\u52A0\u5165\u300C{name}\u300D\uFF0C\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u67E5\u770B\u3002","team.joinErrSelf":"\u8FD9\u662F\u4F60\u81EA\u5DF1\u7684\u90E8\u7F72\uFF0C\u4E0D\u80FD\u52A0\u5165\u81EA\u5DF1\uFF08\u9080\u8BF7\u7801\u8981\u53D1\u7ED9\u522B\u7684\u90E8\u7F72\u7684\u4EBA\u7528\uFF09","team.joinErrAlready":"\u4F60\u7684\u90E8\u7F72\u5DF2\u7ECF\u52A0\u5165\u8FC7\u8FD9\u4E2A\u56E2\u961F\u4E86","team.joinErrUnreachable":"\u8FDE\u4E0D\u4E0A\u5BF9\u65B9 Hub\uFF08\u68C0\u67E5\u5730\u5740/\u7F51\u7EDC\uFF09","team.joinErrTimeout":"\u5BF9\u65B9 Hub \u54CD\u5E94\u8D85\u65F6","team.joinErrGeneric":"\u52A0\u5165\u5931\u8D25\uFF1A{error}","team.identifying":"\u8BC6\u522B\u4E2D\u2026","team.bound2":"\u5DF2\u7ED1\u5B9A\uFF1A{name}","team.multiCandidate":"\u8BC6\u522B\u5230\u591A\u4E2A\u5019\u9009\uFF0C\u70B9\u4F60\u81EA\u5DF1\uFF1A","team.binding":"\u7ED1\u5B9A\u4E2D\u2026","team.bindFail":"\u7ED1\u5B9A\u5931\u8D25\uFF1A{error}","team.noCandidates":"\u6CA1\u8BC6\u522B\u5230\u8EAB\u4EFD\uFF1A\u8BF7\u786E\u8BA4\u673A\u5668\u4EBA\u914D\u7F6E\u4E86 allowedUsers\uFF08\u5141\u8BB8\u4F7F\u7528\u8005\uFF09\uFF0C\u4E14\u673A\u5668\u4EBA\u6709\u901A\u8BAF\u5F55\u6743\u9650\u3002","team.removeMemberConfirm":"\u628A\u300C{name}\u300D\u79FB\u51FA\u8FD9\u4E2A\u56E2\u961F\uFF1F\u5B83\u7684\u673A\u5668\u4EBA\u5C06\u4ECE\u672C\u56E2\u961F\u82B1\u540D\u518C\u6D88\u5931\uFF08\u4E0D\u5F71\u54CD\u5BF9\u65B9\u81EA\u5DF1\u7684\u90E8\u7F72\uFF09\u3002","team.creatingGroup":"\u5EFA\u7FA4\u4E2D\u2026","team.defaultGroupName":"\u534F\u4F5C\u7FA4","team.errPickBot":"\u8BF7\u5148\u52FE\u9009\u81F3\u5C11\u4E00\u4E2A\u673A\u5668\u4EBA","sessions.closeBulkConfirm":"\u5173\u95ED\u9009\u4E2D\u7684 {count} \u4E2A\u4F1A\u8BDD\uFF1F","sessions.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u4F1A\u8BDD\u3002","sessions.viewMode":"\u4F1A\u8BDD\u89C6\u56FE","sessions.viewKanban":"\u770B\u677F","sessions.viewBoard":"\u72B6\u6001\u677F","sessions.viewTable":"\u8868\u683C","sessions.selectSession":"\u9009\u62E9\u4F1A\u8BDD","sessions.board.needsYou":"\u9700\u8981\u4F60","sessions.board.needsYouHint":"\u7B49\u5F85\u4ED3\u5E93\u3001TUI \u9009\u62E9\u6216\u989D\u5EA6\u5904\u7406","sessions.board.starting":"\u542F\u52A8\u4E2D","sessions.board.startingHint":"CLI \u6B63\u5728\u521B\u5EFA\u6216\u6062\u590D","sessions.board.working":"\u5E72\u6D3B\u4E2D","sessions.board.workingHint":"\u6B63\u5728\u8F93\u51FA\u3001\u5206\u6790\u6216\u6267\u884C\u5DE5\u5177","sessions.board.idle":"\u7A7A\u95F2","sessions.board.idleHint":"\u53EF\u7EE7\u7EED\u5BF9\u8BDD\u6216\u63A5\u65B0\u4EFB\u52A1","sessions.board.emptyColumn":"\u6682\u65E0\u4F1A\u8BDD","sessions.board.signalRepo":"\u5F85\u9009\u4ED3\u5E93","sessions.board.signalPrompt":"\u7B49\u5F85 TUI \u9009\u62E9","sessions.board.signalLimited":"\u989D\u5EA6\u53D7\u9650","sessions.board.signalAgent":"\u9700\u8981\u4EBA\u5DE5\u4ECB\u5165","sessions.board.waiting":"\u7B49\u5F85","sessions.board.dragHint":"\u62D6\u52A8\u5217\u5934\u8C03\u6574\u5217\u987A\u5E8F","sessions.board.moveLeft":"\u5DE6\u79FB\u6B64\u5217","sessions.board.moveRight":"\u53F3\u79FB\u6B64\u5217","sessions.kanban.backlog":"\u5F85\u529E\u6C60","sessions.kanban.todo":"\u5F85\u529E","sessions.kanban.inProgress":"\u8FDB\u884C\u4E2D","sessions.kanban.inReview":"\u5F85\u786E\u8BA4","sessions.kanban.done":"\u5DF2\u5B8C\u6210","sessions.kanban.updated":"\u66F4\u65B0\u4E8E {time}","sessions.kanban.moreHidden":"\u8FD8\u6709 {count} \u4E2A\u672A\u663E\u793A","sessions.kanban.openTab":"\u65B0\u6807\u7B7E\u9875\u6253\u5F00","sessions.kanban.openFeishu":"\u6253\u5F00\u98DE\u4E66","sessions.kanban.terminalLoading":"\u6B63\u5728\u6253\u5F00\u7EC8\u7AEF\u2026","sessions.kanban.rename":"\u91CD\u547D\u540D\uFF08\u53CC\u51FB\u6807\u9898\u4E5F\u53EF\uFF09","sessions.kanban.renameFail":"\u91CD\u547D\u540D\u5931\u8D25","sessions.kanban.moveFail":"\u79FB\u52A8\u5931\u8D25","sessions.kanban.groupBy":"\u5206\u7EC4\u7EF4\u5EA6","sessions.kanban.groupFlow":"\u5DE5\u4F5C\u6D41","sessions.kanban.groupTeam":"\u56E2\u961F","sessions.kanban.groupBot":"\u673A\u5668\u4EBA","sessions.kanban.teamLoading":"\u6B63\u5728\u52A0\u8F7D\u56E2\u961F\u2026","sessions.kanban.noTeam":"\u6682\u65E0\u56E2\u961F","sessions.kanban.teamScope":"{chats} \u4E2A\u534F\u4F5C\u7FA4 \xB7 {sessions} \u4E2A\u4F1A\u8BDD","sessions.kanban.remoteHint":"\u6765\u81EA {name} \u90E8\u7F72\u7684\u4F1A\u8BDD\uFF08\u5FEB\u7167\uFF0C\u7EC8\u7AEF/\u5386\u53F2\u5728\u5BF9\u65B9\u673A\u5668\u4E0A\uFF09","sessions.kanban.clusterDragHint":"\u62D6\u52A8\u6807\u9898\u6574\u7EC4\u79FB\u52A8","sessions.history.title":"\u4F1A\u8BDD\u5386\u53F2","sessions.history.loading":"\u6B63\u5728\u62C9\u53D6\u98DE\u4E66\u6D88\u606F\u2026","sessions.history.fail":"\u5386\u53F2\u62C9\u53D6\u5931\u8D25","sessions.history.empty":"\u6CA1\u6709\u6D88\u606F","sessions.history.user":"\u7528\u6237","sessions.history.owner":"\u521B\u5EFA\u8005","sessions.history.staleHint":"dashboard \u6216 daemon \u8FDB\u7A0B\u53EF\u80FD\u8FD8\u5728\u8DD1\u65E7\u7248\u672C\uFF0Cbotmux restart \u540E\u91CD\u8BD5","groups.title":"\u7FA4\u7EC4\u4E0E Bot","groups.subtitle":"\u67E5\u770B chat x bot \u8986\u76D6\u77E9\u9635\uFF0C\u7BA1\u7406\u62C9\u7FA4\u3001oncall\u3001\u9000\u7FA4\u548C\u89E3\u6563\u3002","groups.search":"\u641C\u7D22\u7FA4\u540D / ID / owner","groups.missingOnly":"\u4EC5\u7F3A bot","groups.refresh":"\u5237\u65B0","groups.create":"\u65B0\u5EFA\u7FA4","groups.chat":"\u7FA4\u804A","groups.actions":"\u64CD\u4F5C","groups.addBots":"\u6DFB\u52A0 bot","groups.manage":"\u7BA1\u7406","groups.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u7FA4\u804A\u3002","groups.createTitle":"\u65B0\u5EFA\u7FA4\u804A","groups.createHelp":"\u9009\u62E9\u8981\u9080\u8BF7\u7684 bot\u3002dashboard \u4F1A\u81EA\u52A8\u9009\u62E9\u5728\u7EBF daemon \u4F5C\u4E3A\u521B\u5EFA\u8005\u3002","groups.name":"\u7FA4\u540D","groups.namePlaceholder":"\u4F8B\u5982 AI ChangeLog","groups.bindDir":"\u7ED1\u5B9A\u76EE\u5F55","groups.bindDirHelp":"\u65B0\u8BDD\u9898\u76F4\u63A5\u7528\u8BE5\u76EE\u5F55\u542F\u52A8 CLI\uFF0C\u8DF3\u8FC7 repo \u9009\u62E9\u3002","groups.botPicker":"Bot","groups.createSubmit":"\u521B\u5EFA","groups.cancel":"\u53D6\u6D88","groups.successTitle":"\u7FA4\u521B\u5EFA\u6210\u529F","groups.openGroup":"\u6253\u5F00\u65B0\u7FA4","groups.manageTitle":"\u7BA1\u7406 {name}","groups.owner":"\u7FA4\u4E3B","groups.oncall":"Oncall \u6A21\u5F0F","groups.oncallHelp":"\u5F00\u542F\u540E\uFF0C\u7FA4\u5185\u6210\u5458\u53EF @ \u673A\u5668\u4EBA\uFF1B\u65B0\u8BDD\u9898\u76F4\u63A5\u4F7F\u7528\u7ED1\u5B9A\u76EE\u5F55\u3002","groups.leaveTitle":"\u9009\u62E9\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.leaveSelected":"\u9009\u4E2D\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.disband":"\u89E3\u6563\u7FA4\u804A","groups.dangerHint":"\u89E3\u6563\u4EC5\u5F53\u5728\u7FA4\u673A\u5668\u4EBA\u662F\u7FA4\u4E3B\u65F6\u624D\u4F1A\u6210\u529F\uFF0C\u5426\u5219\u5EFA\u8BAE\u4F7F\u7528\u9000\u51FA\u7FA4\u804A\u3002","groups.save":"\u4FDD\u5B58","groups.needWorkingDir":"\u8BF7\u586B\u5DE5\u4F5C\u76EE\u5F55","groups.noBotsOnline":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u8BF7\u5148\u91CD\u542F daemon\u3002","schedules.title":"\u5B9A\u65F6\u4EFB\u52A1","schedules.subtitle":"\u8DE8 daemon \u67E5\u770B\u3001\u6682\u505C\u3001\u6062\u590D\u548C\u7ACB\u5373\u89E6\u53D1\u5B9A\u65F6\u4EFB\u52A1\u3002","schedules.search":"\u641C\u7D22\u540D\u79F0 / prompt / \u5DE5\u4F5C\u76EE\u5F55","schedules.anyKind":"\u5168\u90E8\u7C7B\u578B","schedules.enabledOnly":"\u4EC5\u542F\u7528","schedules.name":"\u540D\u79F0","schedules.bot":"bot","schedules.schedule":"\u89C4\u5219","schedules.next":"\u4E0B\u6B21","schedules.last":"\u4E0A\u6B21","schedules.repeat":"\u91CD\u590D","schedules.enabled":"\u542F\u7528","schedules.actions":"\u64CD\u4F5C","schedules.runNow":"\u7ACB\u5373\u8FD0\u884C","schedules.pause":"\u6682\u505C","schedules.resume":"\u6062\u590D","schedules.empty":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","settings.title":"\u5168\u5C40\u8BBE\u7F6E","settings.subtitle":"\u7BA1\u7406\u672C\u673A botmux dashboard \u4E0E\u6240\u6709 bot \u5171\u4EAB\u7684\u5168\u5C40\u884C\u4E3A\u3002","settings.loading":"\u6B63\u5728\u52A0\u8F7D\u8BBE\u7F6E\u2026","settings.loadFailed":"\u8BBE\u7F6E\u52A0\u8F7D\u5931\u8D25","settings.readOnlyVisitor":"\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u4FEE\u6539\u8BBE\u7F6E\u9700\u8981\u6388\u6743\u94FE\u63A5\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09","settings.sectionAccess":"\u8BBF\u95EE\u6743\u9650","settings.publicReadOnly":"\u5141\u8BB8\u65E0 token \u53EA\u8BFB\u8BBF\u95EE dashboard","settings.publicReadOnlyHelp":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 token \u7684\u8BBF\u95EE\u8005\u53EF\u4EE5\u67E5\u770B dashboard\u3001\u4F1A\u8BDD\u3001\u5B9A\u65F6\u4EFB\u52A1\u548C SSE\uFF1B\u5173\u95ED\u3001\u6682\u505C\u3001\u5BA1\u6279\u7B49\u5199\u64CD\u4F5C\u4ECD\u5FC5\u987B\u901A\u8FC7 token \u9274\u6743\u3002\u654F\u611F\u7EC8\u7AEF\u539F\u59CB\u65E5\u5FD7\u59CB\u7EC8\u9700\u8981 token\u3002","settings.sectionCards":"\u98DE\u4E66\u5361\u7247","settings.openTerminalInFeishu":"\u6D41\u5F0F\u5361\u7247\u7EC8\u7AEF\u6309\u94AE\u5728\u98DE\u4E66\u4FA7\u680F\u6253\u5F00","settings.openTerminalInFeishuHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF1A\u7EC8\u7AEF\u6309\u94AE\u76F4\u63A5\u6253\u5F00 Web Terminal URL\u3002\u5F00\u542F\u540E\u4F7F\u7528\u98DE\u4E66 web_url/open \u5305\u88C5\uFF0C\u5728\u98DE\u4E66 PC \u4FA7\u680F\u91CC\u6253\u5F00\uFF1B\u5199\u6743\u9650\u4ECD\u7531\u7EC8\u7AEF token \u63A7\u5236\u3002","settings.saving":"\u4FDD\u5B58\u4E2D\u2026","settings.saved":"\u5DF2\u4FDD\u5B58","settings.saveFailed":"\u4FDD\u5B58\u5931\u8D25","settings.sectionMaintenance":"\u81EA\u52A8\u7EF4\u62A4","settings.autoUpdate":"\u81EA\u52A8\u66F4\u65B0","settings.autoUpdateHelp":"\u9ED8\u8BA4\u5173\u95ED\u3002\u5230\u70B9\u6267\u884C npm install -g botmux@latest \u5B89\u88C5\u6700\u65B0\u7248\u672C\uFF08\u53EA\u4E0B\u8F7D\u5B89\u88C5\u3001\u672C\u8EAB\u4E0D\u91CD\u542F\uFF09\u3002\u4EC5 npm \u5168\u5C40\u5B89\u88C5\u53EF\u7528\u3002","settings.autoRestart":"\u81EA\u52A8\u91CD\u542F","settings.autoRestartHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF0C\u9700\u5148\u5F00\u542F\u81EA\u52A8\u66F4\u65B0\u3002\u81EA\u52A8\u66F4\u65B0\u88C5\u5230\u65B0\u7248\u672C\u540E\uFF0C\u82E5\u6CA1\u6709\u8FDB\u884C\u4E2D\u7684\u4F1A\u8BDD\u5219\u81EA\u52A8\u91CD\u542F\u4EE5\u751F\u6548\uFF08\u649E\u4E0A\u5FD9\u788C\u4F1A\u8BDD\u5219\u8DF3\u5230\u6B21\u65E5\uFF09\u3002","settings.autoUpdateLocalDev":"\u5F53\u524D\u4E3A\u672C\u5730\u5F00\u53D1\u5B89\u88C5\uFF08\u4ECE\u6E90\u7801\u8FD0\u884C\uFF09\uFF0C\u81EA\u52A8\u66F4\u65B0\u4E0D\u53EF\u7528\u3002","settings.maintenanceTime":"\u65F6\u95F4","botDefaults.title":"\u6570\u5B57\u5458\u5DE5\u6863\u6848","botDefaults.subtitle":"\u6BCF\u4F4D\u5458\u5DE5\u7684\u9ED8\u8BA4\u884C\u4E3A\uFF1Aoncall\u3001\u4E3B\u52A8\u5F00\u5DE5\u3001\u4EBA\u8BBE\u89D2\u8272\u3001\u5361\u7247\u4E0E\u6388\u6743\u3002","botDefaults.metaOnline":"\u5728\u7EBF \xB7 daemon \u6B63\u5E38","botDefaults.search":"\u641C\u7D22 bot \u540D / app id","botDefaults.refresh":"\u5237\u65B0","botDefaults.sectionOncall":"\u65B0\u7FA4 Oncall","botDefaults.sectionBrand":"\u5361\u7247\u7B7E\u540D","botDefaults.warning":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 oncall binding \u7684\u7FA4\u4F1A\u5728\u4E0B\u6B21\u5F00\u65B0\u8BDD\u9898\u65F6\u81EA\u52A8\u7ED1\u5B9A\u5230\u8BE5\u76EE\u5F55\uFF1B\u624B\u52A8\u7ED1\u5B9A\u6216\u624B\u52A8\u89E3\u7ED1\u8FC7\u7684\u7FA4\u4E0D\u4F1A\u88AB\u8986\u76D6\u3002","botDefaults.empty":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u5148 botmux restart \u8BA9 daemon \u4E0A\u7EBF\u3002","botDefaults.defaultOncall":"\u9ED8\u8BA4\u8FDB\u5165 oncall \u6A21\u5F0F","botDefaults.defaultOncallHelp":"\u6240\u6709\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8\u7ED1\u5B9A","botDefaults.workingDir":"\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55","botDefaults.lastEnabled":"\u4E0A\u6B21\u542F\u7528\u65F6\u95F4","botDefaults.autobound":"\u5DF2\u81EA\u52A8\u7ED1\u5B9A {count} \u4E2A\u7FA4","botDefaults.save":"\u4FDD\u5B58","botDefaults.required":"\u5F00\u542F\u65F6\u5FC5\u987B\u586B\u5DE5\u4F5C\u76EE\u5F55","botDefaults.brandLabel":"\u4E2A\u6027\u7B7E\u540D\uFF08\u5361\u7247\u9875\u811A\uFF09","botDefaults.brandLabelHelp":"\u8BE5 bot \u53D1\u51FA\u7684\u5361\u7247\u9875\u811A\u7B7E\u540D\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u4E0D\u663E\u793A\uFF1B\u586B\u5199\uFF1D\u81EA\u5B9A\u4E49\uFF08\u652F\u6301 markdown\uFF0C\u5982 [Acme](https://\u2026)\uFF09\uFF1B\u6062\u590D\u9ED8\u8BA4\uFF1D\u663E\u793A botmux\u3002","botDefaults.brandLabelPlaceholder":"\u9ED8\u8BA4\uFF1Abotmux\uFF08\u7559\u7A7A\u5219\u4E0D\u663E\u793A\uFF09","botDefaults.sectionSandbox":"\u6587\u4EF6\u6C99\u76D2\uFF08oncall\uFF09","botDefaults.sandboxToggle":"\u5F00\u542F\u6587\u4EF6\u6C99\u76D2","botDefaults.sandboxHelp":"\u5F00\u542F\u540E\uFF0C\u8BE5 bot \u7684\u6BCF\u4E2A\u4F1A\u8BDD\u90FD\u8DD1\u5728\u6309\u4F1A\u8BDD\u9694\u79BB\u7684\u6C99\u76D2\u91CC\uFF1A\u53EA\u770B\u5F97\u5230\u4E00\u4EFD\u9879\u76EE\u526F\u672C\uFF0C\u78B0\u4E0D\u5230\u4F60\u78C1\u76D8\u4E0A\u7684\u771F\u5B9E\u6587\u4EF6\u3001\u5BC6\u94A5\u3001\u522B\u7684\u4F1A\u8BDD\u6570\u636E\u3002\u9002\u5408\u628A\u673A\u5668\u4EBA\u5206\u4EAB\u7ED9\u534A\u53D7\u4FE1\u4EFB\u7684\u4EBA\uFF08oncall\uFF09\u3002\u4EC5 Linux \u751F\u6548\uFF0C\u4E0B\u4E2A\u65B0\u4F1A\u8BDD\u8D77\u6548\u3002","botDefaults.sandboxSaved":"\u5DF2\u4FDD\u5B58\uFF08\u4E0B\u4E2A\u65B0\u4F1A\u8BDD\u751F\u6548\uFF09","botDefaults.brandSave":"\u4FDD\u5B58\u7B7E\u540D","botDefaults.brandReset":"\u6062\u590D\u9ED8\u8BA4","botDefaults.brandStateDefault":"\u5F53\u524D\uFF1A\u9ED8\u8BA4 botmux","botDefaults.brandStateOff":"\u5F53\u524D\uFF1A\u5DF2\u5173\u95ED","botDefaults.brandStateCustom":"\u5F53\u524D\uFF1A\u81EA\u5B9A\u4E49","botDefaults.sectionCard":"\u5361\u7247\u884C\u4E3A","botDefaults.disableStreaming":"\u5173\u95ED\u98DE\u4E66\u6D41\u5F0F\u5361\u7247","botDefaults.disableStreamingHelp":"\u4E0D\u518D\u53D1\u5B9E\u65F6\u5237\u65B0\u7684\u4F1A\u8BDD\u72B6\u6001\u5361\uFF08\u542B\u300C\u6253\u5F00\u7EC8\u7AEF\u300D\u5165\u53E3\uFF09\uFF1B\u4EFB\u52A1\u6700\u7EC8\u7ED3\u679C\u4ECD\u901A\u8FC7\u6D88\u606F\u9001\u8FBE\u3002\u9002\u5408\u5ACC\u6D41\u5F0F\u5361\u7247\u70E6\u7684\u573A\u666F\u3002","botDefaults.writableLink":"\u5361\u7247\u4E0A\u76F4\u63A5\u7ED9\u53EF\u64CD\u4F5C\uFF08\u53EF\u5199\uFF09\u7EC8\u7AEF\u94FE\u63A5","botDefaults.writableLinkHelp":"\u26A0\uFE0F \u5728\u6D41\u5F0F\u5361\u7247\u6B63\u6587\u76F4\u63A5\u8D34\u51FA\u53EF\u5199\u7EC8\u7AEF\u94FE\u63A5\uFF0C\u7FA4\u5185\u4EFB\u4F55\u4EBA\u90FD\u80FD\u70B9\u5F00\u5E76\u64CD\u63A7\u7EC8\u7AEF\u3002\u4E0D\u52FE\uFF1D\u4FDD\u6301\u73B0\u72B6\uFF08\u8D70\u300C\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u300D\u6309\u94AE\u79C1\u804A\u53D1\u7ED9\u70B9\u51FB\u8005\uFF09\u3002","botDefaults.writableLinkMoot":"\u5DF2\u5173\u95ED\u6D41\u5F0F\u5361\u7247","botDefaults.privateCard":"/card \u53D1\u79C1\u5BC6\u5361\u7247\uFF08\u4EC5\u6388\u6743\u4EBA\u53EF\u89C1\uFF09","botDefaults.privateCardHelp":"\u5F00\u542F\u540E /card \u6539\u7528\u300C\u4EC5\u7279\u5B9A\u4EBA\u53EF\u89C1\u300D\u7684\u4E34\u65F6\u5361\u7247\uFF1A\u53EA\u53D1\u7ED9 owner\uFF08allowedUsers\uFF09\uFF0C/grant \u6388\u6743\u5BF9\u8BDD\u7684\u4EBA\u548C\u7FA4\u91CC\u5176\u4ED6\u4EBA\u90FD\u770B\u4E0D\u5230\u3002\u4EE3\u4EF7\uFF1A\u662F\u9759\u6001\u5FEB\u7167\u3001\u4E0D\u4F1A\u5B9E\u65F6\u5237\u65B0\uFF1B\u4E14\u4EC5\u666E\u901A\u7FA4\u53EF\u7528\uFF08\u8BDD\u9898\u7FA4 / \u5355\u804A\u4F1A\u5931\u8D25\uFF0C\u4E0D\u964D\u7EA7\uFF09\u3002\u53EA\u5F71\u54CD /card \u547D\u4EE4\uFF0C\u81EA\u52A8\u6D41\u5F0F\u5361\u4E0D\u53D8\u3002","botDefaults.cardPrefSaved":"\u5DF2\u4FDD\u5B58","botDefaults.sectionRole":"\u9ED8\u8BA4\u89D2\u8272","botDefaults.roleHelp":"\u8BE5 bot \u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF08\u8DE8\u7FA4\u751F\u6548\uFF09\uFF0C\u4F1A\u6CE8\u5165\u5230\u8BE5 bot \u5728\u5404\u7FA4\u7684\u4F1A\u8BDD\u91CC\uFF1B\u5355\u4E2A\u7FA4\u53EF\u5728\u300C\u89D2\u8272\u300D\u9875\u5355\u72EC\u8986\u76D6\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u5220\u9664\u3002","botDefaults.rolePlaceholder":"\u4F8B\u5982\uFF1A\u4F60\u662F\u540E\u7AEF\u6392\u969C\u52A9\u624B\uFF0C\u56DE\u7B54\u7B80\u6D01\u3001\u4F18\u5148\u7ED9\u53EF\u6267\u884C\u547D\u4EE4\u2026","botDefaults.roleSave":"\u4FDD\u5B58\u89D2\u8272","botDefaults.roleDelete":"\u5220\u9664","botDefaults.roleSaved":"\u5DF2\u4FDD\u5B58","botDefaults.roleDeleted":"\u5DF2\u5220\u9664","botDefaults.roleLoadErr":"\u89D2\u8272\u52A0\u8F7D\u5931\u8D25","botDefaults.sectionAutoStart":"\u4E3B\u52A8\u5F00\u5DE5","botDefaults.autoStartJoin":"\u88AB\u62C9\u8FDB\u65B0\u7FA4\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartJoinHelp":"\u5F00\u542F\u540E\uFF0C\u673A\u5668\u4EBA\u4E00\u88AB\u62C9\u8FDB\u65B0\u7FA4\uFF08\u7FA4\u91CC\u6709\u6388\u6743\u7528\u6237 allowedUsers \u65F6\uFF09\u5C31\u81EA\u52A8\u5F00\u4E00\u4E2A\u4F1A\u8BDD\u5F00\u59CB\u5DE5\u4F5C\uFF0C\u65E0\u9700 @\u3002\u5728\u673A\u5668\u4EBA\u7684\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55\u542F\u52A8\uFF1B\u672A\u914D\u7F6E\u9ED8\u8BA4\u76EE\u5F55\u65F6\u5148\u5F39\u4ED3\u5E93\u9009\u62E9\u5361\u8BA9\u4F60\u9009\u3002\u524D\u63D0\uFF1A\u9700\u5728\u98DE\u4E66\u5F00\u653E\u5E73\u53F0\u4E3A\u672C\u5E94\u7528\u8BA2\u9605\u300C\u673A\u5668\u4EBA\u8FDB\u7FA4\u300D\u4E8B\u4EF6 im.chat.member.bot.added_v1\uFF0C\u5E76\u5F00\u901A\u7FA4\u6210\u5458\u8BFB\u53D6\u6743\u9650\u3002","botDefaults.autoStartJoinPrompt":"\u5165\u7FA4\u9996\u8F6E prompt\uFF08\u53EF\u9009\uFF09","botDefaults.autoStartJoinPromptPlaceholder":"\u586B\u4E86\uFF1D\u4F5C\u4E3A\u5165\u7FA4\u540E\u7684\u7B2C\u4E00\u6761\u4EFB\u52A1\uFF1B\u7559\u7A7A\uFF1D\u673A\u5668\u4EBA\u81EA\u5DF1\u770B\u7FA4\u91CC\u4FE1\u606F\u51B3\u5B9A\u505A\u4EC0\u4E48","botDefaults.autoStartJoinPromptSave":"\u4FDD\u5B58 prompt","botDefaults.autoStartTopic":"\u8BDD\u9898\u7FA4\u65B0\u8BDD\u9898\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartTopicHelp":"\u5F00\u542F\u540E\uFF0C\u5728\u8BDD\u9898\u7FA4\u91CC\u6BCF\u5F53\u6709\u4EBA\u65B0\u5F00\u4E00\u4E2A\u8BDD\u9898\uFF0C\u673A\u5668\u4EBA\u5C31\u4F1A\u81EA\u52A8\u63A5\u5165\u8BE5\u8BDD\u9898\u3001\u628A\u9996\u6761\u6D88\u606F\u5F53\u4F5C\u4EFB\u52A1\u5F00\u59CB\u5904\u7406\uFF0C\u65E0\u9700 @\u3002\u4EC5\u5BF9\u8BDD\u9898\u7FA4\u751F\u6548\uFF0C\u666E\u901A\u7FA4\u4E0D\u53D7\u5F71\u54CD\u3002","botDefaults.sectionSessionMode":"\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.p2pMode":"\u79C1\u804A\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.p2pThread":"thread\uFF08\u6BCF\u6761 DM \u72EC\u7ACB\u4F1A\u8BDD\uFF09","botDefaults.p2pChat":"chat\uFF08\u6241\u5E73\u8FDE\u7EED\u5355\u804A\u4F1A\u8BDD\uFF09","botDefaults.p2pHelp":"\u79C1\u804A\uFF081:1 DM\uFF09\u7684\u4F1A\u8BDD\u65B9\u5F0F\uFF1Athread = \u6BCF\u6761\u9876\u5C42\u6D88\u606F\u5404\u81EA\u8D77\u72EC\u7ACB\u4F1A\u8BDD\uFF08\u907F\u514D\u628A\u5BF9\u8BDD\u5806\u8FDB\u540C\u4E00\u4E2A CLI \u8FDB\u7A0B\uFF09\uFF1Bchat = \u6574\u6BB5 DM \u5171\u7528\u4E00\u4E2A\u8FDE\u7EED\u4F1A\u8BDD\u3001\u5171\u4EAB\u4E0A\u4E0B\u6587\uFF08\u7C7B Hermes\uFF09\u3002\u6539\u540E\u7ACB\u5373\u751F\u6548\u3002","botDefaults.regularGroupMode":"\u666E\u901A\u7FA4\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.regularGroupModeChat":"chat\uFF08\u6241\u5E73\u8FDE\u7EED\u5355\u804A\u4F1A\u8BDD\uFF0C\u9ED8\u8BA4\uFF09","botDefaults.regularGroupModeNewTopic":"new-topic\uFF08\u6BCF\u6761\u9876\u5C42 @ \u5404\u5F00\u72EC\u7ACB\u8BDD\u9898\u4E0E\u4F1A\u8BDD\uFF09","botDefaults.regularGroupModeShared":"shared\uFF08\u8BDD\u9898\u6A21\u5F0F\u4F46\u590D\u7528\u540C\u4E00\u4E2A session\uFF09","botDefaults.regularGroupModeHelp":"\u666E\u901A\u7FA4\uFF08\u975E\u8BDD\u9898\u7FA4\uFF09\u91CC @ \u8BE5 bot \u7684\u65B0\u9876\u5C42\u6D88\u606F\u600E\u4E48\u5F00\u4F1A\u8BDD\uFF1Achat = \u6574\u7FA4\u5171\u7528\u4E00\u4E2A\u8FDE\u7EED\u4F1A\u8BDD\uFF08\u9ED8\u8BA4\uFF09\uFF1Bnew-topic = \u6BCF\u6761\u9876\u5C42 @ \u5728\u539F\u6D88\u606F\u4E0B\u5F00\u72EC\u7ACB\u8BDD\u9898\u3001\u5404\u81EA\u72EC\u7ACB\u4F1A\u8BDD\uFF1Bshared = \u8BDD\u9898\u6A21\u5F0F\u4F46\u590D\u7528\u540C\u4E00\u4E2A session\uFF08\u56DE\u590D\u843D\u5728\u8BDD\u9898\u91CC\u3001\u4F46\u5171\u7528\u672C\u7FA4\u4F1A\u8BDD\u4E0E\u4E0A\u4E0B\u6587\uFF09\u3002\u8FD9\u662F per-bot \u9ED8\u8BA4\uFF0C\u5177\u4F53\u67D0\u4E2A\u7FA4\u53EF\u7528 /reply-mode \u5355\u72EC\u8986\u76D6\u3002\u6539\u540E\u7ACB\u5373\u751F\u6548\u3002","botDefaults.mentionMode":"\u7FA4\u804A @ \u7B56\u7565","botDefaults.mentionModeAlways":"\u90FD\u9700\u8981 @\uFF08\u9ED8\u8BA4\uFF09","botDefaults.mentionModeTopic":"\u4EC5\u8BDD\u9898\u5185\u4E0D\u9700\u8981 @","botDefaults.mentionModeNever":"\u6240\u6709\u6D88\u606F\u90FD\u4E0D\u9700\u8981 @","botDefaults.mentionModeHelp":"\u8BE5 bot \u5168\u5C40\u751F\u6548\uFF0C\u51B3\u5B9A\u7FA4\u91CC\u8981\u4E0D\u8981 @ \u624D\u56DE\uFF1A\u300C\u90FD\u9700\u8981 @\u300D= \u4EFB\u4F55\u6D88\u606F\u90FD\u5F97 @\uFF08\u9ED8\u8BA4\uFF0C\u6700\u5B89\u5168\uFF1B\u591A\u4EBA\u7FA4\u91CC\u8BDD\u9898\u5185\u4E5F\u8981 @\uFF09\uFF1B\u300C\u4EC5\u8BDD\u9898\u5185\u4E0D\u9700\u8981 @\u300D= \u8D77\u65B0\u5BF9\u8BDD / \u9876\u5C42\u4ECD\u8981 @\uFF0C\u4F46\u5728\u8BE5 bot \u5DF2\u5F00\u7684\u4EFB\u4F55\u8BDD\u9898\u91CC\uFF08new-topic / shared / \u8BDD\u9898\u7FA4\uFF09\u540E\u7EED\u6D88\u606F\u514D @ \u7EED\u804A\uFF1B\u300C\u6240\u6709\u6D88\u606F\u90FD\u4E0D\u9700\u8981 @\u300D= \u8BE5 bot \u6709\u5BF9\u8BDD\u6743\u9650\u7684\u7FA4\u91CC\u975E @ \u6D88\u606F\u4E5F\u56DE\uFF08\u542B\u5168\u65B0\u6D88\u606F\u51B7\u542F\u52A8\uFF0C\u4EC5\u9002\u5408\u4E13\u7528 / \u503C\u73ED\u5C0F\u7FA4\uFF0C\u591A\u4EBA\u7FA4\u91CC\u4F1A\u89C1\u6D88\u606F\u5C31\u56DE\uFF09\u3002\u6CE8\uFF1A\u7FA4\u91CC\u53EA\u6709\u4F60\u548C\u8BE5 bot\uFF081 \u5BF9 1\uFF09\u65F6\u4E00\u76F4\u514D @\uFF0C\u4E0E\u672C\u8BBE\u7F6E\u65E0\u5173\u3002","botDefaults.sectionGrant":"\u6388\u6743\u4E0E\u989D\u5EA6","botDefaults.restrictGrant":"\u9650\u5236\u88AB\u6388\u6743\u4EBA\u53EA\u80FD\u7EAF\u5BF9\u8BDD","botDefaults.restrictGrantHelp":"\u5F00\u542F\u540E\uFF0C\u88AB /grant \u6388\u6743\u7684\u4EBA\uFF08owner \u81EA\u5DF1\u4E0D\u53D7\u9650\uFF09\u53EA\u80FD\u53D1\u666E\u901A\u5BF9\u8BDD\uFF0C\u6240\u6709 slash \u547D\u4EE4\u4E00\u5F8B\u62E6\u622A\uFF1Abotmux \u81EA\u5E26\u547D\u4EE4\u3001\u900F\u4F20\u547D\u4EE4\u3001/workflow\u3001/introduce\u3001/t \u4EE5\u53CA CLI \u539F\u751F\u547D\u4EE4\uFF08/help \u7B49\uFF09\u3002\u5F62\u5982 /path/to/file \u7684\u5185\u5BB9\u4E0D\u4F1A\u88AB\u8BEF\u5224\u3002","botDefaults.quotaDefault":"\u9ED8\u8BA4\u6D88\u606F\u989D\u5EA6","botDefaults.quotaPlaceholder":"\u7559\u7A7A\uFF1D\u4E0D\u914D\u7F6E\u9ED8\u8BA4\u989D\u5EA6","botDefaults.quotaHelp":"\u4E0D\u5E26\u6570\u5B57\u7684 /grant @x \u9ED8\u8BA4\u7ED9\u7684\u6D88\u606F\u6761\u6570\u3002\u7559\u7A7A\u6216\u70B9\u300C\u5173\u95ED\u300D\u53EA\u662F\u4E0D\u518D\u7ED9\u88F8 /grant \u5957\u9ED8\u8BA4\u989D\u5EA6\uFF0C\u4E0D\u4F1A\u6E05\u6389\u5DF2\u6709\u7684\u989D\u5EA6\u8BA1\u6570\uFF0C\u4E5F\u4E0D\u5F71\u54CD\u663E\u5F0F /grant @x N\u2014\u2014\u5B83\u4EEC\u7167\u5E38\u7EE7\u7EED enforce\u3002\u989D\u5EA6\u7528\u5C3D\u4F1A\u81EA\u52A8\u64A4\u9500\u8BE5\u4EBA\u6388\u6743\u3002","botDefaults.quotaSave":"\u4FDD\u5B58\u989D\u5EA6","botDefaults.quotaOff":"\u5173\u95ED","botDefaults.quotaInvalid":"\u989D\u5EA6\u5FC5\u987B\u662F\u6B63\u6574\u6570","botDefaults.quotaStateOff":"\u5F53\u524D\uFF1A\u672A\u914D\u7F6E\u9ED8\u8BA4\u989D\u5EA6","botDefaults.quotaStateOn":"\u5F53\u524D\uFF1A\u6BCF\u4EBA {count} \u6761","nav.roles":"\u89D2\u8272\u7BA1\u7406","roles.title":"\u89D2\u8272\u7BA1\u7406","roles.subtitle":"\u4E3A\u6BCF\u4E2A\u7FA4\u7EC4\u7684\u6BCF\u4E2A Bot \u5355\u72EC\u8BBE\u7F6E\u89D2\u8272\u63D0\u793A\u8BCD\uFF0CBot \u5728\u8BE5\u7FA4\u4E2D\u4F1A\u4EE5\u6B64\u89D2\u8272\u884C\u4E8B\u3002","roles.search":"\u641C\u7D22\u7FA4\u540D/Bot/ID","roles.refresh":"\u5237\u65B0","roles.selectHint":"\u2190 \u5C55\u5F00\u7FA4\u7EC4\uFF0C\u9009\u62E9\u4E00\u4E2A Bot \u6765\u7F16\u8F91\u89D2\u8272","roles.editorPlaceholder":`\u8F93\u5165\u89D2\u8272\u63CF\u8FF0\uFF0C\u4F8B\u5982\uFF1A
|
|
2
2
|
\u4F60\u662F\u672C\u7FA4\u7684\u6280\u672F\u987E\u95EE\uFF0C\u8D1F\u8D23\u56DE\u7B54\u6240\u6709\u6280\u672F\u95EE\u9898...`,"roles.configured":"\u5DF2\u914D\u7F6E","roles.unconfigured":"\u672A\u914D\u7F6E","roles.noChats":"\u6682\u65E0\u7FA4\u7EC4","roles.preview":"\u9884\u89C8","roles.previewEmpty":"\uFF08\u7A7A\u5185\u5BB9\uFF09","roles.saved":"\u5DF2\u4FDD\u5B58","roles.delete":"\u5220\u9664","roles.save":"\u4FDD\u5B58","roles.confirmDelete":"\u786E\u8BA4\u5220\u9664\u8BE5 Bot \u5728\u6B64\u7FA4\u7684\u89D2\u8272\u914D\u7F6E\uFF1F","roles.botsWithRoles":"\u4E2A Bot \u5DF2\u914D\u7F6E\u89D2\u8272","roles.emptyError":"\u89D2\u8272\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u8BF7\u5148\u8F93\u5165\u5185\u5BB9","roles.saveFailed":"\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5","common.none":"\u65E0","common.loading":"\u52A0\u8F7D\u4E2D\u2026","common.unknown":"\u672A\u77E5","common.now":"\u521A\u521A","common.never":"\u4ECE\u672A","common.all":"\u5168\u90E8","nav.workflows":"\u5DE5\u4F5C\u6D41(beta)","nav.workflowCatalog":"\u76EE\u5F55","workflow.subnav.runs":"\u8FD0\u884C","workflow.subnav.catalog":"\u76EE\u5F55","workflow.searchPlaceholder":"\u641C\u7D22 runId / workflowId / chatId","workflow.filter.nonTerminal":"\u975E\u7EC8\u6001","workflow.filter.all":"\u5168\u90E8","workflow.status.pending":"\u5F85\u5F00\u59CB","workflow.status.running":"\u8FD0\u884C\u4E2D","workflow.status.waiting":"\u7B49\u5F85\u4E2D","workflow.status.effectAttempting":"\u526F\u4F5C\u7528\u4E2D","workflow.status.timedOut":"\u5DF2\u8D85\u65F6","workflow.status.succeeded":"\u6210\u529F","workflow.status.failed":"\u5931\u8D25","workflow.status.cancelled":"\u5DF2\u53D6\u6D88","workflow.table.run":"\u8FD0\u884C","workflow.table.workflow":"\u5DE5\u4F5C\u6D41","workflow.table.status":"\u72B6\u6001","workflow.table.lastSeq":"\u6700\u540E\u5E8F\u53F7","workflow.table.dangling":"\u60AC\u6302 dEf/dAct/dWait","workflow.table.updated":"\u66F4\u65B0\u65F6\u95F4","workflow.table.chatApp":"\u7FA4\u804A / \u5E94\u7528","workflow.list.failedLoad":"\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","workflow.list.noRuns":"\u6CA1\u6709\u5339\u914D\u7684\u8FD0\u884C\u3002","workflow.list.noFilterMatch":"\u6CA1\u6709\u7B26\u5408\u7B5B\u9009\u6761\u4EF6\u7684\u8FD0\u884C\u3002","workflow.list.loaded":"{count} \u4E2A\u8FD0\u884C \xB7 \u5237\u65B0\u4E8E {time}","workflow.list.error":"\u9519\u8BEF\uFF1A{error}","workflow.detail.back":"\u8FD4\u56DE","workflow.detail.loading":"\u52A0\u8F7D\u4E2D...","workflow.detail.loadFailed":"\u52A0\u8F7D\u5931\u8D25","workflow.detail.cancel":"\u53D6\u6D88","workflow.detail.cliCancelOnly":"\u4EC5 CLI \u53EF\u53D6\u6D88","workflow.detail.cancelTitle":"\u53D6\u6D88\u8FD9\u4E2A\u5DE5\u4F5C\u6D41\u8FD0\u884C","workflow.detail.cliCancelTitle":"\u65E0\u6CD5\u5728\u9875\u9762\u53D6\u6D88\uFF1A\u8BF7\u4F7F\u7528 botmux workflow cancel {runId}","workflow.detail.nodes":"\u8282\u70B9 / Activity","workflow.detail.parallel":"\u5E76\u53D1\u6267\u884C","workflow.detail.parallelMeta":"{count} \u6B21\u5C1D\u8BD5 \xB7 \u6700\u9AD8\u5E76\u53D1 {max} \xB7 \u8FD0\u884C\u4E2D {running}","workflow.detail.noParallelData":"\u8FD8\u6CA1\u6709 attempt \u65F6\u95F4\u6570\u636E\u3002","workflow.detail.parallelNow":"\u73B0\u5728","workflow.detail.node":"\u8282\u70B9","workflow.detail.nodeStatus":"\u8282\u70B9\u72B6\u6001","workflow.detail.activity":"Activity","workflow.detail.activityStatus":"Activity \u72B6\u6001","workflow.detail.attempts":"\u5C1D\u8BD5\u6B21\u6570","workflow.detail.current":"\u5F53\u524D\u5C1D\u8BD5","workflow.detail.detail":"\u8BE6\u60C5","workflow.detail.nodeIO":"\u8282\u70B9\u8F93\u5165\u8F93\u51FA","workflow.detail.timeline":"\u65F6\u95F4\u7EBF","workflow.detail.loadOlder":"\u52A0\u8F7D\u66F4\u65E9\u4E8B\u4EF6","workflow.detail.seq":"\u5E8F\u53F7","workflow.detail.actor":"\u6267\u884C\u8005","workflow.detail.error":"\u9519\u8BEF","workflow.detail.event":"\u4E8B\u4EF6","workflow.detail.time":"\u65F6\u95F4","workflow.detail.refreshed":"\u5237\u65B0\u4E8E {time}","workflow.detail.unknownRun":"\u672A\u77E5\u8FD0\u884C","workflow.detail.snapshotHttp":"snapshot HTTP {status}","workflow.detail.eventsHttp":"events HTTP {status}","workflow.detail.cancelUnavailable":"\u65E0\u6CD5\u53D6\u6D88\uFF1A\u8BF7\u4F7F\u7528 botmux workflow cancel {runId}","workflow.detail.cancelConfirm":`\u786E\u8BA4\u53D6\u6D88\u5DE5\u4F5C\u6D41\u8FD0\u884C {runId}\uFF1F
|
|
3
3
|
|
|
4
4
|
{total} \u4E2A\u60AC\u6302\u9879\u4F1A\u7531 cancel recovery \u5904\u7406\u3002
|
|
5
5
|
effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"workflow.detail.writeAccessCancel":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u70B9\u51FB\u53D6\u6D88\u3002","workflow.detail.cancelHttp":"cancel HTTP {status}","workflow.detail.cancelPending":"\u53D6\u6D88\u5DF2\u63D0\u4EA4\uFF1B\u7B49\u5F85\u8FD0\u884C\u4E2D\u7684 activity \u6536\u655B","workflow.detail.writeAccessApproval":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u5BA1\u6279\u3002","workflow.detail.actionHttp":"{action} HTTP {status}","workflow.detail.approved":"\u5DF2\u901A\u8FC7","workflow.detail.rejected":"\u5DF2\u62D2\u7EDD","workflow.detail.alreadyTerminal":"\u8FD0\u884C\u5DF2\u7EC8\u6001\uFF1B\u672A\u5E94\u7528\u201C{label}\u201D\u3002","workflow.detail.workflowContinue":"{label}\uFF1B\u7B49\u5F85\u5DE5\u4F5C\u6D41\u7EE7\u7EED\u6267\u884C\u3002","workflow.detail.workflowRefreshing":"{label}\uFF1B\u6B63\u5728\u5237\u65B0\u5DE5\u4F5C\u6D41\u72B6\u6001\u3002","workflow.detail.eventsLoaded":"\u5DF2\u52A0\u8F7D {loaded}/{total} \u4E2A\u4E8B\u4EF6","workflow.detail.dangling":"\u60AC\u6302\u9879","workflow.detail.noDangling":"\u6CA1\u6709\u60AC\u6302\u5DE5\u4F5C\u3002","workflow.detail.none":"\u65E0","workflow.detail.noNodes":"\u8FD8\u6CA1\u6709\u8282\u70B9\u3002","workflow.detail.idle":"\u7A7A\u95F2","workflow.detail.noNodeIO":"\u8FD8\u6CA1\u6709\u8282\u70B9\u8F93\u5165\u8F93\u51FA\u3002","workflow.detail.notDispatched":"\u5C1A\u672A\u6D3E\u53D1","workflow.detail.noAttempt":"\u8FD8\u6CA1\u6709\u5C1D\u8BD5","workflow.detail.attempt":"\u5C1D\u8BD5","workflow.detail.authoredInput":"\u539F\u59CB\u8F93\u5165","workflow.detail.resolvedInput":"\u89E3\u6790\u540E\u8F93\u5165","workflow.detail.output":"\u8F93\u51FA","workflow.detail.executionLog":"\u6267\u884C\u65E5\u5FD7","workflow.detail.liveTerminal":"\u5B9E\u65F6\u7EC8\u7AEF","workflow.detail.terminalLive":"\u5728\u7EBF","workflow.detail.terminalClosedShort":"\u5DF2\u5173\u95ED","workflow.detail.terminalClosed":"\u7EC8\u7AEF\u5DF2\u5173\u95ED\u3002\u8BF7\u67E5\u770B\u4E0B\u65B9\u6267\u884C\u65E5\u5FD7\u83B7\u53D6\u6700\u7EC8\u8BB0\u5F55\u3002","workflow.detail.openTerminalNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u7EC8\u7AEF","workflow.detail.terminalReplay":"\u7EC8\u7AEF\u56DE\u653E","workflow.detail.openReplayNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u56DE\u653E","workflow.detail.downloadFullLog":"\u4E0B\u8F7D\u5B8C\u6574\u65E5\u5FD7","workflow.detail.terminalResume":"\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.openResumeNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.resumeSession":"\u7EE7\u7EED\u4F1A\u8BDD","workflow.detail.resumeStarting":"\u6B63\u5728\u542F\u52A8\u2026","workflow.detail.endResumeSession":"\u7ED3\u675F\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.resumeEnding":"\u7ED3\u675F\u4E2D\u2026","workflow.detail.resumeUnsupportedCli":"{cliId} CLI \u4E0D\u652F\u6301 resume","workflow.detail.resumeMissingCliSession":"\u7F3A\u5C11 cliSessionId\uFF0C\u65E0\u6CD5 resume","workflow.detail.resumeStartFailed":"\u542F\u52A8\u8C03\u8BD5\u4F1A\u8BDD\u5931\u8D25 (HTTP {status})","workflow.detail.resumeEndFailed":"\u7ED3\u675F\u8C03\u8BD5\u4F1A\u8BDD\u5931\u8D25 (HTTP {status})","workflow.detail.writeAccessResume":"\u9700\u8981\u5199\u5165\u6743\u9650\u624D\u80FD resume \u4F1A\u8BDD\u3002","workflow.detail.waitPrompt":"\u7B49\u5F85\u63D0\u793A","workflow.detail.approvalComment":"\u5BA1\u6279\u5907\u6CE8","workflow.detail.optionalComment":"\u53EF\u9009\u5907\u6CE8","workflow.detail.approve":"\u901A\u8FC7","workflow.detail.reject":"\u62D2\u7EDD","workflow.detail.submitting":"\u63D0\u4EA4\u4E2D...","workflow.detail.empty":"\u7A7A","workflow.detail.truncated":"\u5DF2\u622A\u65AD","workflow.detail.noData":"\u6CA1\u6709\u6570\u636E\u3002","workflow.detail.noPreview":"\u6CA1\u6709\u9884\u89C8\u3002","workflow.detail.open":"\u6253\u5F00","workflow.detail.deadline":"\u622A\u6B62","workflow.detail.effect":"\u526F\u4F5C\u7528","workflow.detail.wait":"\u7B49\u5F85","workflow.detail.noEvents":"\u8FD8\u6CA1\u6709\u4E8B\u4EF6\u3002","workflow.summary.workflow":"\u5DE5\u4F5C\u6D41","workflow.summary.status":"\u72B6\u6001","workflow.summary.lastSeq":"\u6700\u540E\u5E8F\u53F7","workflow.summary.updated":"\u66F4\u65B0\u65F6\u95F4","workflow.summary.revision":"\u4FEE\u8BA2","workflow.summary.initiator":"\u53D1\u8D77\u4EBA","workflow.summary.failedNode":"\u5931\u8D25\u8282\u70B9","workflow.summary.cancelOrigin":"\u53D6\u6D88\u6765\u6E90","workflow.summary.chat":"\u7FA4\u804A","workflow.summary.app":"\u5E94\u7528","workflow.dangling.activities":"Activities","workflow.dangling.effects":"Effects","workflow.dangling.waits":"Waits","workflow.dangling.cancels":"Cancels","catalog.title":"\u5DE5\u4F5C\u6D41\u76EE\u5F55","catalog.subtitle":"\u4ECE\u5DF2\u4FDD\u5B58\u7684 workflow \u5B9A\u4E49\u521B\u5EFA\u4E00\u6B21\u8FD0\u884C\u3002","catalog.searchPlaceholder":"\u641C\u7D22 workflowId / \u8DEF\u5F84","catalog.refresh":"\u5237\u65B0","catalog.loading":"\u6B63\u5728\u52A0\u8F7D\u76EE\u5F55...","catalog.loadFailed":"\u76EE\u5F55\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","catalog.noDefinitions":"\u6CA1\u6709\u627E\u5230 workflow \u5B9A\u4E49\u3002","catalog.noFilterMatch":"\u6CA1\u6709\u7B26\u5408\u7B5B\u9009\u6761\u4EF6\u7684\u5B9A\u4E49\u3002","catalog.table.workflow":"\u5DE5\u4F5C\u6D41","catalog.table.version":"\u7248\u672C","catalog.table.params":"\u53C2\u6570","catalog.table.nodes":"\u8282\u70B9","catalog.table.revision":"\u4FEE\u8BA2","catalog.table.path":"\u8DEF\u5F84","catalog.paramSummary":"{required}/{total} \u5FC5\u586B","catalog.back":"\u8FD4\u56DE\u76EE\u5F55","catalog.detailTitle":"\u5DE5\u4F5C\u6D41\u5B9A\u4E49","catalog.definitionLoadFailed":"\u5B9A\u4E49\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","catalog.summary":"\u6458\u8981","catalog.paramsSchema":"\u53C2\u6570 Schema","catalog.definitionJson":"\u5B9A\u4E49 JSON","catalog.runPanel":"\u8FD0\u884C\u5DE5\u4F5C\u6D41","catalog.paramsJson":"\u53C2\u6570 JSON","catalog.paramsPlaceholder":`{
|
|
6
6
|
"city": "\u5317\u4EAC"
|
|
7
|
-
}`,"catalog.chatId":"\u7FA4\u804A ID","catalog.larkAppId":"\u98DE\u4E66\u5E94\u7528 ID","catalog.chatBindingHint":"\u5FC5\u586B\uFF0C\u7528\u4E8E\u786E\u5B9A humanGate \u5361\u7247\u53D1\u9001\u5230\u54EA\u4E2A\u98DE\u4E66\u7FA4\uFF0C\u4EE5\u53CA\u53D6\u6D88\u8DEF\u7531\u5F52\u5C5E\u3002","catalog.run":"\u8FD0\u884C","catalog.running":"\u542F\u52A8\u4E2D...","catalog.badParamsJson":"\u53C2\u6570\u5FC5\u987B\u662F JSON object\u3002","catalog.writeAccess":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u8FD0\u884C\u3002","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"\u8FD0\u884C\u5DF2\u542F\u52A8\uFF1B\u6B63\u5728\u6253\u5F00\u8BE6\u60C5\u9875...","catalog.invalidParams":"\u53C2\u6570\u65E0\u6548","catalog.issue":"{path}: {message}","catalog.noParams":"\u6CA1\u6709\u58F0\u660E\u53C2\u6570\u3002","catalog.required":"\u5FC5\u586B","catalog.optional":"\u53EF\u9009","catalog.default":"\u9ED8\u8BA4\u503C","catalog.description":"\u8BF4\u660E","catalog.path":"\u8DEF\u5F84","catalog.revision":"\u4FEE\u8BA2","catalog.nodeCount":"\u8282\u70B9\u6570"},ea={"app.name":"botmux","app.subtitle":"Feishu AI CLI Control","time.secondsAgo":"{value}s ago","time.minutesAgo":"{value}m ago","time.hoursAgo":"{value}h ago","nav.overview":"Overview","nav.sessions":"Sessions","nav.groups":"Groups","nav.schedules":"Schedules","nav.settings":"Settings","nav.botDefaults":"Bot Defaults","status.live":"Live","status.disconnected":"Disconnected","status.system":"System","status.light":"Light","status.dark":"Dark","status.language":"Language","status.theme":"Theme","theme.base":"Basic","theme.skins":"Skins","skin.cyber":"2077","skin.genshin":"Genshin","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"Blue Archive","skin.zzz":"ZZZ","skin.dragonball":"Dragon Ball","skin.ikun":"ikun","botOnboarding.add":"Add Bot","botOnboarding.title":"Add Bot","botOnboarding.intro":"Pick a CLI and working directory, scan to create a PersonalAgent app \u2014 the dashboard writes it to local bots.json and auto-configures Open Platform permissions.","botOnboarding.cliLabel":"CLI adapter","botOnboarding.dirLabel":"Working directory","botOnboarding.dirPlaceholder":"Default ~ (home); must exist on the daemon host","botOnboarding.modelLabel":"Model (optional)","botOnboarding.modelPlaceholder":"Leave empty for the CLI default model","botOnboarding.startScan":"Start scan","botOnboarding.cancel":"Cancel","botOnboarding.starting":"Generating QR code...","botOnboarding.waiting":"Scan with the Feishu app to create the app.","botOnboarding.verifying":"Scan accepted. Verifying credentials...","botOnboarding.configuringPermissions":"Auto-configuring Open Platform permissions\u2026","botOnboarding.platformScanHint":"Scan once more with the Feishu app to sign in to the Open Platform (to auto-import permissions, set the callback, and submit a version).","botOnboarding.platformQrAlt":"Open Platform login QR code","botOnboarding.completed":"Bot added.","botOnboarding.permissionOk":"Auto-imported {count} permissions.","botOnboarding.permissionSkipped":"({count} skipped \u2014 not in the tenant catalog)","botOnboarding.permissionVersion":"Submitted version {version}.","botOnboarding.permissionManual":"Permissions could not be auto-configured. Complete these steps manually:","botOnboarding.metaDir":"Dir","botOnboarding.failed":"Add failed","botOnboarding.openLink":"Open scan link in browser","botOnboarding.close":"Close","botOnboarding.restartHint":"bots.json has been updated. Run pnpm daemon:restart for the new bot to take effect.","botOnboarding.qrAlt":"Feishu bot onboarding QR code","overview.title":"Workbench","overview.subtitle":"Live status of your AI teammates \xB7 synced with Feishu topics","overview.team":"AI Team","overview.teamHint":"Live status of every digital teammate","overview.attention":"Needs You","overview.attentionHint":"Blocked tasks \u2014 one reply gets them moving again","overview.activeSessions":"Active Sessions","overview.activeSessionsHint":"Sessions currently running","overview.today":"Right Now","overview.todayHint":"Active session distribution","overview.viewAll":"View all \u2192","overview.botIdle":"Standing by, ready for new tasks","overview.botOffline":"Offline \u2014 daemon not running","overview.botBusy":"Working \xB7 {count} sessions","overview.botNeedsYou":"Waiting on you","overview.botReady":"Ready","overview.botOff":"Offline","overview.sessionsCount":"{count} sessions","overview.lastActive":"active {time} ago","overview.noAttention":"Nothing waiting on you","overview.teamExpand":"Show all {count} \u25BE","overview.teamCollapse":"Collapse \u25B4","strip.pending":"{count} pending","strip.longest":"waiting {time} \u2014 {bot} {reason}","strip.handle":"Handle now","overview.openSessions":"Active Sessions","overview.workingSessions":"Working","overview.onlineBots":"Online Bots","overview.schedules":"Schedules","overview.groups":"Groups Seen","overview.enabledSchedules":"Enabled","overview.total":"total","overview.active":"active","overview.daemonRegistry":"daemon registry","overview.chatMatrix":"chat matrix","overview.recentSessions":"Recent Sessions","overview.nextSchedules":"Next Runs","overview.noSessions":"No sessions yet.","overview.noSchedules":"No schedules yet.","sessions.title":"Session Control","sessions.subtitle":"Locate Feishu topics, open Web Terminal, close or resume CLI sessions.","sessions.search":"Search working dir / title / IDs","sessions.anyStatus":"Any status","sessions.adoptAny":"adopt: any","sessions.adoptYes":"adopt: yes","sessions.adoptNo":"adopt: no","sessions.activeOnly":"Active only","sessions.closeSelected":"Close selected","sessions.clearSelection":"Clear","sessions.selectedCount":"{count} sessions selected","sessions.bot":"Bot","sessions.cli":"CLI","sessions.chat":"Chat","sessions.openChat":"Open chat","sessions.status":"Status","sessions.tokenIn":"Token In","sessions.tokenOut":"Token Out","sessions.titleCol":"Title","sessions.workingDir":"Working Dir","sessions.created":"Created","sessions.last":"Last","sessions.adopt":"Adopt","sessions.actions":"Actions","sessions.details":"Details","sessions.copy":"Copy","sessions.copied":"Copied","sessions.locate":"Locate Topic","sessions.locating":"Sending...","sessions.cooldown":"Cooldown {seconds}s","sessions.openTerminal":"Terminal","sessions.writeLink":"Write Link","sessions.writeLinkHint":"Get a writable terminal link (carries a write-access token; opens in a new tab)","sessions.writeLinkFail":"Failed to get write link","sessions.close":"Close Session","sessions.resume":"Resume Session","sessions.dismiss":"Close","sessions.closeConfirm":"Close this session?","sessions.resumeFailed":"Resume failed","sessions.land":"Land","sessions.landLoading":"Loading sandbox diff\u2026","sessions.landUnavailable":"Cannot land","sessions.landEmpty":"No changes in the sandbox clone.","sessions.landApply":"Apply to disk","sessions.landDiscard":"Discard","sessions.landApplied":"Landed","sessions.landFailed":"Land failed","sessions.landDiscarded":"Discarded (sandbox clone not applied).","connectors.lede":"Let external systems (alerts, CI, tickets\u2026) trigger a bot to speak in a group or run a workflow via one webhook.","connectors.createTitle":"New Webhook","connectors.fName":"Name","connectors.fNamePh":"e.g. Prod alerts","connectors.fBot":"Trigger bot","connectors.fKind":"Trigger type","connectors.kindTurn":"Single turn (bot responds once)","connectors.kindWorkflow":"Workflow","connectors.fWf":"Workflow ID","connectors.fMode":"Deliver to which group","connectors.modeDynamic":"Specified per request (chat passed in)","connectors.modeFixed":"Fixed group","connectors.modeNewGroup":"New group each time","connectors.fFixedChat":"Target group","connectors.fChatManualPh":"Enter chat ID manually: oc_\u2026","connectors.chatManualLink":"Group not listed? Enter ID manually \u2192","connectors.chatListLink":"\u2190 Pick from group list","connectors.fAllow":"Allowed groups","connectors.optional":" (optional)","connectors.allowHint":"Hold Ctrl/\u2318 to multi-select; empty = unrestricted. Only validates the chat passed in the request.","connectors.dynamicHint":'<b>Dynamic mode</b>: the chat ID is passed per request, one of three ways \u2014 query <code>?chatId=<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"},is={"app.name":"botmux","app.subtitle":"Feishu AI CLI Control","time.secondsAgo":"{value}s ago","time.minutesAgo":"{value}m ago","time.hoursAgo":"{value}h ago","nav.overview":"Overview","nav.sessions":"Sessions","nav.sidebarCollapse":"Collapse sidebar","nav.sidebarExpand":"Expand sidebar","nav.groups":"Groups","nav.schedules":"Schedules","nav.settings":"Settings","nav.botDefaults":"Bot Defaults","status.live":"Live","status.disconnected":"Disconnected","status.system":"System","status.light":"Light","status.dark":"Dark","status.language":"Language","status.theme":"Theme","theme.base":"Basic","theme.skins":"Skins","skin.cyber":"2077","skin.genshin":"Genshin","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"Blue Archive","skin.zzz":"ZZZ","skin.dragonball":"Dragon Ball","skin.ikun":"ikun","botOnboarding.add":"Add Bot","botOnboarding.title":"Add Bot","botOnboarding.intro":"Pick a CLI and working directory, scan to create a PersonalAgent app \u2014 the dashboard writes it to local bots.json and auto-configures Open Platform permissions.","botOnboarding.cliLabel":"CLI adapter","botOnboarding.dirLabel":"Working directory","botOnboarding.dirPlaceholder":"Default ~ (home); must exist on the daemon host","botOnboarding.modelLabel":"Model (optional)","botOnboarding.modelPlaceholder":"Leave empty for the CLI default model","botOnboarding.startScan":"Start scan","botOnboarding.cancel":"Cancel","botOnboarding.starting":"Generating QR code...","botOnboarding.waiting":"Scan with the Feishu app to create the app.","botOnboarding.verifying":"Scan accepted. Verifying credentials...","botOnboarding.configuringPermissions":"Auto-configuring Open Platform permissions\u2026","botOnboarding.platformScanHint":"Scan once more with the Feishu app to sign in to the Open Platform (to auto-import permissions, set the callback, and submit a version).","botOnboarding.platformQrAlt":"Open Platform login QR code","botOnboarding.completed":"Bot added.","botOnboarding.permissionOk":"Auto-imported {count} permissions.","botOnboarding.permissionSkipped":"({count} skipped \u2014 not in the tenant catalog)","botOnboarding.permissionVersion":"Submitted version {version}.","botOnboarding.permissionManual":"Permissions could not be auto-configured. Complete these steps manually:","botOnboarding.metaDir":"Dir","botOnboarding.failed":"Add failed","botOnboarding.openLink":"Open scan link in browser","botOnboarding.close":"Close","botOnboarding.restartHint":"bots.json has been updated. Run pnpm daemon:restart for the new bot to take effect.","botOnboarding.qrAlt":"Feishu bot onboarding QR code","overview.title":"Workbench","overview.subtitle":"Live status of your AI teammates \xB7 synced with Feishu topics","overview.team":"AI Team","overview.teamHint":"Live status of every digital teammate","overview.attention":"Needs You","overview.attentionHint":"Blocked tasks \u2014 one reply gets them moving again","overview.activeSessions":"Active Sessions","overview.activeSessionsHint":"Sessions currently running","overview.today":"Right Now","overview.todayHint":"Active session distribution","overview.viewAll":"View all \u2192","overview.botIdle":"Standing by, ready for new tasks","overview.botOffline":"Offline \u2014 daemon not running","overview.botBusy":"Working \xB7 {count} sessions","overview.botNeedsYou":"Waiting on you","overview.botReady":"Ready","overview.botOff":"Offline","overview.sessionsCount":"{count} sessions","overview.lastActive":"active {time} ago","overview.noAttention":"Nothing waiting on you","overview.teamExpand":"Show all {count} \u25BE","overview.teamCollapse":"Collapse \u25B4","strip.pending":"{count} pending","strip.longest":"waiting {time} \u2014 {bot} {reason}","strip.handle":"Handle now","overview.openSessions":"Active Sessions","overview.workingSessions":"Working","overview.onlineBots":"Online Bots","overview.schedules":"Schedules","overview.groups":"Groups Seen","overview.enabledSchedules":"Enabled","overview.total":"total","overview.active":"active","overview.daemonRegistry":"daemon registry","overview.chatMatrix":"chat matrix","overview.recentSessions":"Recent Sessions","overview.nextSchedules":"Next Runs","overview.noSessions":"No sessions yet.","overview.noSchedules":"No schedules yet.","sessions.title":"Session Control","sessions.subtitle":"Locate Feishu topics, open Web Terminal, close or resume CLI sessions.","sessions.search":"Search working dir / title / IDs","sessions.anyStatus":"Any status","sessions.adoptAny":"adopt: any","sessions.adoptYes":"adopt: yes","sessions.adoptNo":"adopt: no","sessions.activeOnly":"Active only","sessions.closeSelected":"Close selected","sessions.clearSelection":"Clear","sessions.selectedCount":"{count} sessions selected","sessions.bot":"Bot","sessions.cli":"CLI","sessions.chat":"Chat","sessions.openChat":"Open chat","sessions.status":"Status","sessions.tokenIn":"Token In","sessions.tokenOut":"Token Out","sessions.titleCol":"Title","sessions.workingDir":"Working Dir","sessions.created":"Created","sessions.last":"Last","sessions.adopt":"Adopt","sessions.actions":"Actions","sessions.details":"Details","sessions.copy":"Copy","sessions.copied":"Copied","sessions.locate":"Locate Topic","sessions.locating":"Sending...","sessions.cooldown":"Cooldown {seconds}s","sessions.openTerminal":"Terminal","sessions.writeLink":"Write Link","sessions.writeLinkHint":"Get a writable terminal link (carries a write-access token; opens in a new tab)","sessions.writeLinkFail":"Failed to get write link","sessions.close":"Close Session","sessions.resume":"Resume Session","sessions.dismiss":"Close","sessions.closeConfirm":"Close this session?","sessions.resumeFailed":"Resume failed","sessions.land":"Land","sessions.landLoading":"Loading sandbox diff\u2026","sessions.landUnavailable":"Cannot land","sessions.landEmpty":"No changes in the sandbox clone.","sessions.landApply":"Apply to disk","sessions.landDiscard":"Discard","sessions.landApplied":"Landed","sessions.landFailed":"Land failed","sessions.landDiscarded":"Discarded (sandbox clone not applied).","connectors.lede":"Let external systems (alerts, CI, tickets\u2026) trigger a bot to speak in a group or run a workflow via one webhook.","connectors.createTitle":"New Webhook","connectors.fName":"Name","connectors.fNamePh":"e.g. Prod alerts","connectors.fBot":"Trigger bot","connectors.fKind":"Trigger type","connectors.kindTurn":"Single turn (bot responds once)","connectors.kindWorkflow":"Workflow","connectors.fWf":"Workflow ID","connectors.fMode":"Deliver to which group","connectors.modeDynamic":"Specified per request (chat passed in)","connectors.modeFixed":"Fixed group","connectors.modeNewGroup":"New group each time","connectors.fFixedChat":"Target group","connectors.fChatManualPh":"Enter chat ID manually: oc_\u2026","connectors.chatManualLink":"Group not listed? Enter ID manually \u2192","connectors.chatListLink":"\u2190 Pick from group list","connectors.fAllow":"Allowed groups","connectors.optional":" (optional)","connectors.allowHint":"Hold Ctrl/\u2318 to multi-select; empty = unrestricted. Only validates the chat passed in the request.","connectors.dynamicHint":'<b>Dynamic mode</b>: the chat ID is passed per request, one of three ways \u2014 query <code>?chatId=<chatId></code> \xB7 header <code>x-botmux-chat-id: <chatId></code> \xB7 body <code>{"chatId":"<chatId>"}</code>.<br>For "one URL triggers directly, no params", choose Fixed group instead.',"connectors.fDedup":"Dedup field","connectors.fDedupPh":"e.g. alert.id (read from event body)","connectors.dedupHint":"Set: events with the same value go to the <b>same group</b>. Empty: each event <b>creates a new group</b>.","connectors.fInstruction":"Instruction","connectors.fInstructionPh":"What the bot should do on the event. e.g. Summarize the severity, @ the oncall, suggest next steps. Empty = hand the raw event to the model.","connectors.fVerify":"Verification","connectors.verifyToken":"Token (simple: secret in the URL, one curl triggers it)","connectors.verifyHmac":"HMAC signature (advanced: more secure, sign the request yourself)","connectors.fSecret":"Secret / token","connectors.fSecretPh":"Leave empty to auto-generate (shown once)","connectors.btnCreate":"Create","connectors.listTitle":"Existing Webhooks","connectors.loading":"Loading\u2026","connectors.noBotGroups":"(This bot has no visible groups; enter an ID manually on the right)","connectors.modeLabelFixed":"Fixed group","connectors.modeLabelNewGroup":"New group each time","connectors.modeLabelDynamic":"Per-request group","connectors.kindLabelWorkflow":"Workflow","connectors.kindLabelTurn":"Single turn","connectors.count":"\xB7 {count}","connectors.empty":"No webhooks yet. Create one with the form above.","connectors.enabled":"Enabled","connectors.disabled":"Disabled","connectors.badgeToken":"Token","connectors.badgeSign":"Signed","connectors.dest":'to "{name}"',"connectors.btnDisable":"Disable","connectors.btnEnable":"Enable","connectors.btnDel":"Delete","connectors.webhookUrl":"Webhook URL: ","connectors.copy":"Copy","connectors.copied":"Copied","connectors.tokenHint":"Token mode: append <code>/<token></code> to the URL when calling (the token is shown only on create/rotate).","connectors.dynamicReqHint":'Dynamic mode: the request must carry the target chat \u2014 <code>?chatId=<chatId></code> or header <code>x-botmux-chat-id</code> or body <code>{"chatId":"\u2026"}</code>.',"connectors.instructionPrefix":"Instruction: ","connectors.delConfirm":"Delete this webhook? Its URL stops working immediately.","connectors.errName":"Enter a name","connectors.errBot":"Pick a bot","connectors.errWf":"Enter a workflow ID","connectors.errChat":"Pick (or enter) a target group","connectors.creating":"Creating\u2026","connectors.usageDynamicLede":"Dynamic mode: the URL already has the token; pass the target chat ID when calling{gn}:","connectors.usageDynamicNote":'The chat can also go in header <code>x-botmux-chat-id</code> or body <code>{"chatId":"\u2026"}</code>. \u26A0\uFE0F The URL is the credential \u2014 keep it secret.',"connectors.usageTokenLede":"This URL already has the token and a fixed target group; just POST to trigger:","connectors.usageTokenNote":"\u26A0\uFE0F The URL is the credential \u2014 keep it private; delete or rotate it in the list below.","connectors.usageHmac":"The external system must HMAC-SHA256-sign <code>timestamp.body</code> and call with <code>x-botmux-timestamp</code> / <code>x-botmux-nonce</code> / <code>x-botmux-signature</code> headers","connectors.usageHmacDynamic":", and also pass the target chat ID as above","connectors.createdPrefix":'Created "{name}"',"connectors.createdDest":'to "{name}"',"connectors.tokenLabel":"Access token","connectors.signLabel":"Signing secret","connectors.secretOnce":" (shown once \u2014 save it): ","connectors.createFailed":"Create failed: {error}","connectors.noOnlineBots":"(No online bots)","team.navHome":"My team","team.navManage":"Team management","team.eyebrow":"Team","team.homeTitle":"Team collaboration (cross-deployment)","team.homeLede":"Invite other deployments (botmux instances teammates run) into one team to discover bots across deployments and pull collaborative groups.","team.localDeployTitle":"This deployment","team.myIdentity":"My Lark identity: ","team.unbound":"Not bound","team.bindBtn":"Bind","team.bindHint":" (auto-identifies you via the bot credentials; once bound, pulling a group adds you and attributes the bots to you)","team.myTeams":"My teams","team.searchPh":"Search name / capability / CLI\u2026","team.allCli":"All CLIs","team.hasCap":"Has capability tag","team.hasRole":"Has default role","team.teamsHint":"Tick bots in any team to pull them into a group (each with its owner). To create a team / generate an invite code / join another team, go to Team management.","team.loading":"Loading\u2026","team.roleModalTitle":"Default role","team.roleModalHint":"The bot default persona (applies across groups), read-only here. To edit, go to the Bot Defaults page.","team.close":"Close","team.tagLocal":"This deployment","team.tagRemoteStale":"Remote \xB7 offline?","team.tagRemote":"Remote","team.removeMember":"Remove","team.depTag":"({tag})","team.depCount":"{count}","team.depSelected":", {n} selected","team.capPh":"Capability tag\u2026","team.viewRole":"View","team.hasRoleShort":"Has role","team.noMatch":"No bots match the filters.","team.gnamePh":"Group name (e.g. cross-team triage)","team.pullGroupBtn":"Pull ticked bots into a group","team.pullGroupHint":"Tick bots \u2192 pull into a Lark group (owner included automatically)","team.noTeams":"No teams yet. Go to Team management to generate an invite code for others to join you, or join another team.","team.connected":"Connected","team.connectFail":"Connection failed: {error}","team.iHost":"I host","team.teamMeta":"{deps} deployments \xB7 {bots} bots","team.rosterFail":"Could not fetch this team roster.","team.acrossTeams":" (across {n} teams, deduped)","team.botsWord":"bots","team.groupCreated":"Group created","team.delegatedBy":' (created by "{name}")',"team.openInLark":"Open in Lark","team.invalidBots":"Bots not added: {ids}","team.invalidOwners":"{n} owner(s) could not be added","team.missingIdentity":"You have not bound a Lark identity, so you were not added to the group (bind it in My team)","team.skippedNoOwner":"{n} bot(s) skipped because their owner has no bound identity (not added)","team.errNoLocalBot":"Tick at least one of your own (this deployment) online bots \u2014 the group is created by it and adds you (the initiator).","team.errAllSkipped":"None of the selected bot owners have a bound identity, so the group cannot be pulled (a bot cannot join a group without its owner). Have those deployments bind an identity first.","team.errNoCreator":"No available group creator (the relevant deployments have no online bot, or are unreachable)","team.errDelegationTimeout":"Timed out delegating group creation to the other deployment (it may have succeeded \u2014 check Lark, do not retry)","team.errGroupCreate":"Group creation failed: {error}","team.roleModalTitleName":"Default role \xB7 {name}","team.bound":"Bound","team.myHostedTeam":"My hosted team","team.remoteTeamLabel":"{name} team","team.manageTitle":"Team management","team.manageLede":"Create multiple teams, generate an invite code per team, or join another team. A team = this deployment bots + the other deployments that joined it.","team.hostedTitle":"Teams I host","team.newTeamPh":"New team name","team.createTeamBtn":"Create team","team.joinTitle":"Join another team","team.hubPh":"Hub address, e.g. http://10.0.0.5:7891","team.codePh":"Invite code","team.joinBtn":"Join","team.noTeamsShort":"No teams yet.","team.default":"Default","team.manageMetaDeps":"{count} deployments","team.manageMetaRemote":" (incl. {r} remote)","team.manageMetaBots":"{count} bots","team.genInvite":"Generate invite code","team.delBtn":"Delete","team.generating":"Generating\u2026","team.inviteResultLede":"Send the two items below to someone on another deployment (valid once, within 24h):","team.inviteHub":"Hub address: ","team.inviteCode":"Invite code: ","team.genFail":"Generation failed.","team.delConfirm":'Delete team "{name}"? Deployments that joined it will be removed (their own deployments are unaffected).',"team.errName":"Enter a team name","team.creating":"Creating\u2026","team.created":"Created","team.createFail":"Create failed: {error}","team.errHubCode":"Enter the hub address and invite code.","team.joining":"Joining\u2026","team.joined":'Joined "{name}" \u2014 see it in My team.',"team.joinErrSelf":"This is your own deployment; you cannot join yourself (the invite code is for someone on another deployment).","team.joinErrAlready":"Your deployment already joined this team.","team.joinErrUnreachable":"Cannot reach the hub (check the address/network).","team.joinErrTimeout":"The hub timed out.","team.joinErrGeneric":"Join failed: {error}","team.identifying":"Identifying\u2026","team.bound2":"Bound: {name}","team.multiCandidate":"Multiple candidates found \u2014 click yourself:","team.binding":"Binding\u2026","team.bindFail":"Bind failed: {error}","team.noCandidates":"No identity found: make sure the bot has allowedUsers configured and contacts permission.","team.removeMemberConfirm":'Remove "{name}" from this team? Its bots disappear from this team roster (their own deployment is unaffected).',"team.creatingGroup":"Creating group\u2026","team.defaultGroupName":"Collaboration group","team.errPickBot":"Tick at least one bot first","sessions.closeBulkConfirm":"Close {count} selected sessions?","sessions.empty":"No sessions match the filters.","sessions.viewMode":"Session view","sessions.viewKanban":"Kanban","sessions.viewBoard":"Board","sessions.viewTable":"Table","sessions.selectSession":"Select session","sessions.board.needsYou":"Needs You","sessions.board.needsYouHint":"Repo, TUI, or usage limit waiting","sessions.board.starting":"Starting","sessions.board.startingHint":"CLI is spawning or resuming","sessions.board.working":"Working","sessions.board.workingHint":"Streaming, analyzing, or using tools","sessions.board.idle":"Idle","sessions.board.idleHint":"Ready for the next message","sessions.board.emptyColumn":"No sessions","sessions.board.signalRepo":"Repo needed","sessions.board.signalPrompt":"TUI choice needed","sessions.board.signalLimited":"Usage limited","sessions.board.signalAgent":"Needs human input","sessions.board.waiting":"Waiting","sessions.board.dragHint":"Drag header to reorder columns","sessions.board.moveLeft":"Move column left","sessions.board.moveRight":"Move column right","sessions.kanban.backlog":"Backlog","sessions.kanban.todo":"Todo","sessions.kanban.inProgress":"In Progress","sessions.kanban.inReview":"In Review","sessions.kanban.done":"Done","sessions.kanban.updated":"Updated {time}","sessions.kanban.moreHidden":"{count} more hidden","sessions.kanban.openTab":"Open in new tab","sessions.kanban.openFeishu":"Open in Feishu","sessions.kanban.terminalLoading":"Opening terminal\u2026","sessions.kanban.rename":"Rename (double-click title works too)","sessions.kanban.renameFail":"Rename failed","sessions.kanban.moveFail":"Move failed","sessions.kanban.groupBy":"Group by","sessions.kanban.groupFlow":"Workflow","sessions.kanban.groupTeam":"Team","sessions.kanban.groupBot":"Bots","sessions.kanban.teamLoading":"Loading teams\u2026","sessions.kanban.noTeam":"No teams","sessions.kanban.teamScope":"{chats} collab chats \xB7 {sessions} sessions","sessions.kanban.remoteHint":"Session from the {name} deployment (snapshot; terminal/history live on their machine)","sessions.kanban.clusterDragHint":"Drag header to move the whole group","sessions.history.title":"History","sessions.history.loading":"Fetching Feishu messages\u2026","sessions.history.fail":"Failed to load history","sessions.history.empty":"No messages","sessions.history.user":"User","sessions.history.owner":"Owner","sessions.history.staleHint":"The dashboard or daemon process may still run an old build \u2014 botmux restart and retry","groups.title":"Groups & Bots","groups.subtitle":"Inspect the chat x bot matrix and manage group creation, oncall, leave, and disband flows.","groups.search":"Search chat name / ID / owner","groups.missingOnly":"Missing bot only","groups.refresh":"Refresh","groups.create":"New Group","groups.chat":"Chat","groups.actions":"Actions","groups.addBots":"Add Bots","groups.manage":"Manage","groups.empty":"No chats match the filters.","groups.createTitle":"Create New Group","groups.createHelp":"Pick bots to invite. The dashboard chooses an online daemon as creator.","groups.name":"Group Name","groups.namePlaceholder":"e.g. AI ChangeLog","groups.bindDir":"Bind Directory","groups.bindDirHelp":"New topics start the CLI here and skip repo selection.","groups.botPicker":"Bots","groups.createSubmit":"Create","groups.cancel":"Cancel","groups.successTitle":"Group Created","groups.openGroup":"Open Group","groups.manageTitle":"Manage {name}","groups.owner":"Owner","groups.oncall":"Oncall Mode","groups.oncallHelp":"When enabled, group members can @ the bot; new topics use the bound directory.","groups.leaveTitle":"Select Bots to Leave","groups.leaveSelected":"Selected Bots Leave","groups.disband":"Disband Group","groups.dangerHint":"Disband only works when an in-chat bot is the owner. Otherwise prefer leaving the chat.","groups.save":"Save","groups.needWorkingDir":"Working directory is required","groups.noBotsOnline":"No bots online. Restart the daemon first.","schedules.title":"Schedules","schedules.subtitle":"View, pause, resume, and run scheduled tasks across daemons.","schedules.search":"Search name / prompt / working dir","schedules.anyKind":"Any kind","schedules.enabledOnly":"Enabled only","schedules.name":"Name","schedules.bot":"Bot","schedules.schedule":"Schedule","schedules.next":"Next","schedules.last":"Last","schedules.repeat":"Repeat","schedules.enabled":"Enabled","schedules.actions":"Actions","schedules.runNow":"Run Now","schedules.pause":"Pause","schedules.resume":"Resume","schedules.empty":"No schedules.","settings.title":"Global Settings","settings.subtitle":"Manage machine-wide botmux dashboard behavior shared by every bot.","settings.loading":"Loading settings\u2026","settings.loadFailed":"Failed to load settings","settings.readOnlyVisitor":"Read-only access \u2014 changing settings requires an authorized link (run botmux dashboard).","settings.sectionAccess":"Access","settings.publicReadOnly":"Allow tokenless read-only dashboard access","settings.publicReadOnlyHelp":"When enabled, visitors without a token can view the dashboard, sessions, schedules, and SSE. Writes such as close, pause, and approvals still require token auth. Sensitive raw terminal logs always require a token.","settings.sectionCards":"Feishu Cards","settings.openTerminalInFeishu":"Open streaming-card terminals in the Feishu sidebar","settings.openTerminalInFeishuHelp":"Off by default: terminal buttons open the Web Terminal URL directly. When enabled, botmux wraps the URL with Feishu web_url/open so Feishu PC opens it in a sidebar. Terminal write access is still controlled by its token.","settings.saving":"Saving\u2026","settings.saved":"Saved","settings.saveFailed":"Save failed","settings.sectionMaintenance":"Auto Maintenance","settings.autoUpdate":"Auto update","settings.autoUpdateHelp":"Off by default. At the set time, runs npm install -g botmux@latest to install the latest version (download/install only \u2014 no restart). npm-global installs only.","settings.autoRestart":"Auto restart","settings.autoRestartHelp":"Off by default; requires auto-update. After auto-update installs a newer version, restart to apply it if no session is in progress (busy \u21D2 slips to the next day).","settings.autoUpdateLocalDev":"This is a local-dev install (running from source); auto-update is unavailable.","settings.maintenanceTime":"Time","botDefaults.title":"Bot Profiles","botDefaults.subtitle":"Per-bot defaults: oncall, proactive start, persona role, cards and grants.","botDefaults.metaOnline":"Online \xB7 daemon healthy","botDefaults.search":"Search bot name / app id","botDefaults.refresh":"Refresh","botDefaults.sectionOncall":"New-chat Oncall","botDefaults.sectionBrand":"Card Signature","botDefaults.warning":"When enabled, chats without an oncall binding auto-bind to this directory on their next new topic. Manually bound or unbound chats are preserved.","botDefaults.empty":"No bots online. Run botmux restart first.","botDefaults.defaultOncall":"Default to oncall mode","botDefaults.defaultOncallHelp":"Unbound chats auto-bind on the next new topic","botDefaults.workingDir":"Default Working Directory","botDefaults.lastEnabled":"Last Enabled","botDefaults.autobound":"{count} chats auto-bound","botDefaults.save":"Save","botDefaults.required":"Working directory is required when enabled","botDefaults.brandLabel":"Signature (card footer)","botDefaults.brandLabelHelp":"Footer signature on cards this bot sends. Save empty = hide; fill in = custom (markdown ok, e.g. [Acme](https://\u2026)); Reset = show botmux.","botDefaults.brandLabelPlaceholder":"Default: botmux (empty = hidden)","botDefaults.sectionSandbox":"File sandbox (oncall)","botDefaults.sandboxToggle":"Enable file sandbox","botDefaults.sandboxHelp":"When on, every session of this bot runs in a per-session sandbox: only a project copy is visible \u2014 your real files, secrets, and other sessions are not. For sharing the bot with semi-trusted users (oncall). Linux only; applies to the next new session.","botDefaults.sandboxSaved":"Saved (applies to the next new session)","botDefaults.brandSave":"Save Signature","botDefaults.brandReset":"Reset to default","botDefaults.brandStateDefault":"Current: default botmux","botDefaults.brandStateOff":"Current: off","botDefaults.brandStateCustom":"Current: custom","botDefaults.sectionCard":"Card Behavior","botDefaults.disableStreaming":"Disable streaming card","botDefaults.disableStreamingHelp":"Stop posting the live session status card (and its Open Terminal entry). The task's final result still arrives as a message. For those who find the live card noisy.","botDefaults.writableLink":"Put a writable terminal link on the card","botDefaults.writableLinkHelp":'\u26A0\uFE0F Embeds a writable terminal link in the streaming card body \u2014 anyone in the chat can open and drive the terminal. Off = current behavior (private DM via the "Get Write Link" button).',"botDefaults.writableLinkMoot":"Streaming card disabled \u2014 this has no effect","botDefaults.privateCard":"/card sends a private card (authorized users only)","botDefaults.privateCardHelp":'Makes /card send an ephemeral "visible-to-specific-people" card: delivered only to the owner (allowedUsers); /grant-authorized talk users and everyone else in the chat cannot see it. Trade-off: it is a static snapshot (no live updates) and only works in regular group chats (topic groups / DMs fail, with no fallback). Affects only the /card command; the auto streaming card is unchanged.',"botDefaults.cardPrefSaved":"Saved","botDefaults.sectionRole":"Default Role","botDefaults.roleHelp":"This bot's default persona (applies across all chats), injected into the bot's sessions in every chat; a single group can override it on the Roles page. Save empty = delete.","botDefaults.rolePlaceholder":"e.g. You are a backend triage assistant; answer concisely, prefer runnable commands\u2026","botDefaults.roleSave":"Save role","botDefaults.roleDelete":"Delete","botDefaults.roleSaved":"Saved","botDefaults.roleDeleted":"Deleted","botDefaults.roleLoadErr":"Failed to load role","botDefaults.sectionAutoStart":"Proactive Start","botDefaults.autoStartJoin":"Auto-start when added to a new chat","botDefaults.autoStartJoinHelp":'When enabled, the bot auto-starts a session and gets to work the moment it is added to a new chat (when an authorized user / allowedUsers is a member), no @ needed. It launches in the bot default working dir; if none is configured it shows a repo-select card first. Prerequisite: subscribe the "bot joined chat" event im.chat.member.bot.added_v1 for this app and grant the member-read scope in the Feishu console.',"botDefaults.autoStartJoinPrompt":"First-turn prompt on join (optional)","botDefaults.autoStartJoinPromptPlaceholder":"Filled = used as the first task after joining; blank = the bot reads the chat and decides what to do","botDefaults.autoStartJoinPromptSave":"Save prompt","botDefaults.autoStartTopic":"Auto-start on new topics in topic groups","botDefaults.autoStartTopicHelp":"When enabled, in a topic group the bot automatically joins each newly opened topic and starts working on its first message, no @ needed. Topic groups only \u2014 regular groups are unaffected.","botDefaults.sectionSessionMode":"Session mode","botDefaults.p2pMode":"Private chat session mode","botDefaults.p2pThread":"thread (separate session per DM)","botDefaults.p2pChat":"chat (flat continuous session)","botDefaults.p2pHelp":"How 1:1 DMs are sessioned: thread = each top-level message starts its own session (keeps chatter out of one CLI process); chat = the whole DM shares one continuous session and context (Hermes-like). Takes effect immediately.","botDefaults.regularGroupMode":"Regular group session mode","botDefaults.regularGroupModeChat":"chat (flat continuous session, default)","botDefaults.regularGroupModeNewTopic":"new-topic (each top-level @ opens its own topic & session)","botDefaults.regularGroupModeShared":"shared (topic display, reusing one session)","botDefaults.regularGroupModeHelp":"How new top-level @mentions in regular (non-topic) groups are sessioned: chat = the whole group shares one continuous session (default); new-topic = each top-level @ opens its own topic with a separate session; shared = topic display but reuse the same session (replies fold into a topic yet share the group session & context). This is the per-bot default; a specific group can override it via /reply-mode. Takes effect immediately.","botDefaults.mentionMode":"Group @ policy","botDefaults.mentionModeAlways":"Always require @ (default)","botDefaults.mentionModeTopic":"No @ needed inside topics","botDefaults.mentionModeNever":"Never require @","botDefaults.mentionModeHelp":'Bot-global: controls when an @ is required to get a reply in groups. "Always require @" = every message needs an @ (default, safest; inside topics too, in multi-person groups); "No @ needed inside topics" = starting a new conversation / top-level still needs @, but follow-ups inside ANY topic this bot already drives (new-topic / shared / topic-group) continue without @; "Never require @" = non-@ messages are answered too wherever the bot has talk access (including cold-starting on a brand-new message \u2014 only suitable for dedicated / on-call small groups; in busy multi-person groups it replies to everything). Note: when you are alone with this bot (1:1) replies never need an @, independent of this setting.',"botDefaults.sectionGrant":"Authorization & Quota","botDefaults.restrictGrant":"Restrict grantees to plain conversation","botDefaults.restrictGrantHelp":"When enabled, /grant-authorized users (the owner is exempt) can only send plain messages; every slash command is blocked: botmux built-in commands, passthrough commands, /workflow, /introduce, /t, and CLI-native commands (/help, etc.). Text like /path/to/file is not misclassified.","botDefaults.quotaDefault":"Default message quota","botDefaults.quotaPlaceholder":"Empty = no default quota","botDefaults.quotaHelp":'Message count a bare /grant @x (no number) hands out. Empty or "Turn off" merely stops applying a default to bare /grant \u2014 it does NOT clear existing quota counters, nor affect an explicit /grant @x N; those keep being enforced. Authorization is auto-revoked once a quota runs out.',"botDefaults.quotaSave":"Save quota","botDefaults.quotaOff":"Turn off","botDefaults.quotaInvalid":"Quota must be a positive integer","botDefaults.quotaStateOff":"Current: no default quota","botDefaults.quotaStateOn":"Current: {count} per grantee","nav.roles":"Roles","roles.title":"Role Management","roles.subtitle":"Set per-bot role prompts for each group. Each bot adopts its own persona in the selected group.","roles.search":"Search group / bot / ID","roles.refresh":"Refresh","roles.selectHint":"\u2190 Expand a group and select a bot to edit its role","roles.editorPlaceholder":`Enter role description, e.g.:
|
|
8
8
|
You are a code reviewer for this group...`,"roles.configured":"Configured","roles.unconfigured":"None","roles.noChats":"No groups","roles.preview":"Preview","roles.previewEmpty":"(empty)","roles.saved":"Saved","roles.delete":"Delete","roles.save":"Save","roles.confirmDelete":"Delete this bot's role config for this group?","roles.botsWithRoles":"bots configured","roles.emptyError":"Role content cannot be empty","roles.saveFailed":"Save failed, please retry","common.none":"None","common.loading":"Loading\u2026","common.unknown":"Unknown","common.now":"now","common.never":"never","common.all":"All","nav.workflows":"Workflows (beta)","nav.workflowCatalog":"Catalog","workflow.subnav.runs":"Runs","workflow.subnav.catalog":"Catalog","workflow.searchPlaceholder":"search runId / workflowId / chatId","workflow.filter.nonTerminal":"non-terminal","workflow.filter.all":"all","workflow.status.pending":"pending","workflow.status.running":"running","workflow.status.waiting":"waiting","workflow.status.effectAttempting":"effect","workflow.status.timedOut":"timed out","workflow.status.succeeded":"succeeded","workflow.status.failed":"failed","workflow.status.cancelled":"cancelled","workflow.table.run":"run","workflow.table.workflow":"workflow","workflow.table.status":"status","workflow.table.lastSeq":"lastSeq","workflow.table.dangling":"dEf/dAct/dWait","workflow.table.updated":"updated","workflow.table.chatApp":"chat / app","workflow.list.failedLoad":"Failed to load: {error}","workflow.list.noRuns":"No runs match.","workflow.list.noFilterMatch":"No runs match this filter.","workflow.list.loaded":"{count} runs \xB7 refreshed {time}","workflow.list.error":"error: {error}","workflow.detail.back":"Back","workflow.detail.loading":"Loading...","workflow.detail.loadFailed":"Load failed","workflow.detail.cancel":"Cancel","workflow.detail.cliCancelOnly":"CLI cancel only","workflow.detail.cancelTitle":"Cancel this workflow run","workflow.detail.cliCancelTitle":"Cancel unavailable: use botmux workflow cancel {runId}","workflow.detail.nodes":"Nodes / Activities","workflow.detail.parallel":"Parallel execution","workflow.detail.parallelMeta":"{count} attempt(s) \xB7 max parallel {max} \xB7 running {running}","workflow.detail.noParallelData":"No attempt timing data yet.","workflow.detail.parallelNow":"now","workflow.detail.node":"node","workflow.detail.nodeStatus":"node status","workflow.detail.activity":"activity","workflow.detail.activityStatus":"activity status","workflow.detail.attempts":"attempts","workflow.detail.current":"current","workflow.detail.detail":"detail","workflow.detail.nodeIO":"Node I/O","workflow.detail.timeline":"Timeline","workflow.detail.loadOlder":"Load older","workflow.detail.seq":"seq","workflow.detail.actor":"actor","workflow.detail.error":"error","workflow.detail.event":"event","workflow.detail.time":"time","workflow.detail.refreshed":"refreshed {time}","workflow.detail.unknownRun":"unknown run","workflow.detail.snapshotHttp":"snapshot HTTP {status}","workflow.detail.eventsHttp":"events HTTP {status}","workflow.detail.cancelUnavailable":"cancel unavailable: use botmux workflow cancel {runId}","workflow.detail.cancelConfirm":`Cancel workflow run {runId}?
|
|
9
9
|
|
|
10
10
|
{total} dangling item(s) will be handled by cancel-driven recovery.
|
|
11
11
|
effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"workflow.detail.writeAccessCancel":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and click cancel again.","workflow.detail.cancelHttp":"cancel HTTP {status}","workflow.detail.cancelPending":"cancel pending; waiting for running activity to drain","workflow.detail.writeAccessApproval":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and approve/reject again.","workflow.detail.actionHttp":"{action} HTTP {status}","workflow.detail.approved":"approved","workflow.detail.rejected":"rejected","workflow.detail.alreadyTerminal":"Run already terminal; {label} was not applied.","workflow.detail.workflowContinue":"{label}; waiting for workflow to continue.","workflow.detail.workflowRefreshing":"{label}; refreshing workflow state.","workflow.detail.eventsLoaded":"{loaded}/{total} events loaded","workflow.detail.dangling":"Dangling","workflow.detail.noDangling":"No dangling work.","workflow.detail.none":"none","workflow.detail.noNodes":"No nodes yet.","workflow.detail.idle":"idle","workflow.detail.noNodeIO":"No node I/O yet.","workflow.detail.notDispatched":"not dispatched","workflow.detail.noAttempt":"No attempt yet","workflow.detail.attempt":"attempt","workflow.detail.authoredInput":"Authored input","workflow.detail.resolvedInput":"Resolved input","workflow.detail.output":"Output","workflow.detail.executionLog":"Execution log","workflow.detail.liveTerminal":"Live terminal","workflow.detail.terminalLive":"live","workflow.detail.terminalClosedShort":"closed","workflow.detail.terminalClosed":"Terminal is closed. Use the execution log below for the final transcript.","workflow.detail.openTerminalNewTab":"Open terminal in new tab","workflow.detail.terminalReplay":"Terminal replay","workflow.detail.openReplayNewTab":"Open replay in new tab","workflow.detail.downloadFullLog":"Download full log","workflow.detail.terminalResume":"Debug session","workflow.detail.openResumeNewTab":"Open debug session in new tab","workflow.detail.resumeSession":"Resume session","workflow.detail.resumeStarting":"Starting\u2026","workflow.detail.endResumeSession":"End debug session","workflow.detail.resumeEnding":"Ending\u2026","workflow.detail.resumeUnsupportedCli":'CLI "{cliId}" does not support resume',"workflow.detail.resumeMissingCliSession":"Missing cliSessionId \u2014 cannot resume","workflow.detail.resumeStartFailed":"Failed to start debug session (HTTP {status})","workflow.detail.resumeEndFailed":"Failed to end debug session (HTTP {status})","workflow.detail.writeAccessResume":"Resume requires dashboard write access.","workflow.detail.waitPrompt":"Wait prompt","workflow.detail.approvalComment":"Approval comment","workflow.detail.optionalComment":"Optional comment","workflow.detail.approve":"Approve","workflow.detail.reject":"Reject","workflow.detail.submitting":"Submitting...","workflow.detail.empty":"empty","workflow.detail.truncated":"truncated","workflow.detail.noData":"No data.","workflow.detail.noPreview":"No preview.","workflow.detail.open":"open","workflow.detail.deadline":"deadline","workflow.detail.effect":"effect","workflow.detail.wait":"wait","workflow.detail.noEvents":"No events.","workflow.summary.workflow":"workflow","workflow.summary.status":"status","workflow.summary.lastSeq":"lastSeq","workflow.summary.updated":"updated","workflow.summary.revision":"revision","workflow.summary.initiator":"initiator","workflow.summary.failedNode":"failedNode","workflow.summary.cancelOrigin":"cancelOrigin","workflow.summary.chat":"chat","workflow.summary.app":"app","workflow.dangling.activities":"activities","workflow.dangling.effects":"effects","workflow.dangling.waits":"waits","workflow.dangling.cancels":"cancels","catalog.title":"Workflow catalog","catalog.subtitle":"Create a workflow run from a saved workflow definition.","catalog.searchPlaceholder":"search workflowId / path","catalog.refresh":"Refresh","catalog.loading":"Loading catalog...","catalog.loadFailed":"Failed to load catalog: {error}","catalog.noDefinitions":"No workflow definitions found.","catalog.noFilterMatch":"No definitions match this filter.","catalog.table.workflow":"workflow","catalog.table.version":"version","catalog.table.params":"params","catalog.table.nodes":"nodes","catalog.table.revision":"revision","catalog.table.path":"path","catalog.paramSummary":"{required}/{total} required","catalog.back":"Back to catalog","catalog.detailTitle":"Workflow definition","catalog.definitionLoadFailed":"Failed to load definition: {error}","catalog.summary":"Summary","catalog.paramsSchema":"Params schema","catalog.definitionJson":"Definition JSON","catalog.runPanel":"Run workflow","catalog.paramsJson":"Params JSON","catalog.paramsPlaceholder":`{
|
|
12
12
|
"city": "\u5317\u4EAC"
|
|
13
|
-
}`,"catalog.chatId":"Chat ID","catalog.larkAppId":"Lark app ID","catalog.chatBindingHint":"Required so humanGate cards and cancel routing know which Lark chat owns the run.","catalog.run":"Run","catalog.running":"Starting...","catalog.badParamsJson":"Params must be a JSON object.","catalog.writeAccess":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and run again.","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"Run started; opening detail page...","catalog.invalidParams":"Invalid params","catalog.issue":"{path}: {message}","catalog.noParams":"No params declared.","catalog.required":"required","catalog.optional":"optional","catalog.default":"default","catalog.description":"description","catalog.path":"path","catalog.revision":"revision","catalog.nodeCount":"nodes"},In={zh:Zo,en:ea};function yt(e){if(typeof e!="string")return null;let n=e.trim().toLowerCase();return n==="zh"||n.startsWith("zh-")?"zh":n==="en"||n.startsWith("en-")?"en":null}function ta(e=[]){for(let n of e){let o=yt(n);if(o)return o}return"zh"}function vt(e){return(n,o)=>{let s=In[e][n]??In.zh[n]??n;return o?s.replace(/\{(\w+)\}/g,(a,i)=>{let l=o[i];return l==null?`{${i}}`:String(l)}):s}}function Mn(e,n){return(e?yt(e.getItem(Ft)):null)??ta(n)}var Gt="botmux.dashboard.theme",xn="botmux.dashboard.sessions.view";function na(e){return e==="system"||e==="light"||e==="dark"?e:null}function oa(e){return e==="board"||e==="table"?e:null}function En(e,n){return e==="system"?n?"dark":"light":e}function Hn(e){return na(e?.getItem(Gt))??"dark"}function Cn(e){return oa(e?.getItem(xn))??"board"}var An="botmux.dashboard.sessions.boardOrder",at=["needs-you","starting","working","idle"];function aa(e){if(!Array.isArray(e)||e.length!==at.length)return null;let n=new Set(e);if(n.size!==e.length)return null;for(let o of at)if(!n.has(o))return null;return e.slice()}function Dn(e){try{let n=e?.getItem(An);return n?aa(JSON.parse(n))??[...at]:[...at]}catch{return[...at]}}function zt(e,n){try{e?.setItem(An,JSON.stringify(n))}catch{}}function Rn(e,n){try{e?.setItem(xn,n)}catch{}}var sa=["default","cyber","genshin","fallout","prts","bluearchive","zzz","dragonball","ikun"],_t="botmux.dashboard.skin";function ia(e){return typeof e=="string"&&sa.includes(e)?e:null}function On(e){return ia(e?.getItem(_t))??"default"}var ra="\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF830123456789\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E$#%&@*+=<>/\\",Bn=["186 100% 60%","56 97% 60%","330 100% 64%","150 80% 58%"],Jt=[{key:"shake",dur:280},{key:"rgb",dur:340},{key:"tear",dur:400},{key:"invert",dur:220},{key:"slice",dur:320},{key:"blackout",dur:260}],Nn=["ESTABLISHING NETLINK","BYPASSING ICE","DECRYPTING DATAFLOW","SYNCING BOTMUX TELEMETRY","ACCESS GRANTED"],Pn="0123456789ABCDEF#<>*/=+\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C",la=3200,st=[],Ke=0,kt=0;function Yt(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Kt(e,n){let o="";for(let s=0;s<e;s++)o+=n[Math.floor(Math.random()*n.length)];return o}function da(e){let n=document.createElement("div");n.className="cyber-rain";let o=Math.max(10,Math.min(26,Math.round(window.innerWidth/70)));for(let s=0;s<o;s++){let a=document.createElement("span");a.className="cyber-rain-col",a.textContent=Kt(28+Math.floor(Math.random()*22),ra);let i=Bn[Math.floor(Math.random()*Bn.length)];a.style.cssText=`left:${(s+.5)/o*100}%;--rc:${i};--sz:${10+Math.floor(Math.random()*9)}px;--op:${(.25+Math.random()*.45).toFixed(2)};--dur:${(6+Math.random()*9).toFixed(1)}s;--delay:${(-Math.random()*12).toFixed(1)}s;`,n.appendChild(a)}e.appendChild(n)}function ca(){if(Yt())return;let e=document.body,n=()=>{let o=Jt[Math.floor(Math.random()*Jt.length)],s=`cp-fx-${o.key}`;e.classList.add(s),st.push(window.setTimeout(()=>e.classList.remove(s),o.dur)),st.push(window.setTimeout(n,2400+Math.random()*4200))};st.push(window.setTimeout(n,1800+Math.random()*2600))}function ua(){st.forEach(e=>window.clearTimeout(e)),st=[];for(let e of Jt)document.body.classList.remove(`cp-fx-${e.key}`)}function pa(){if(Yt()||document.getElementById("cyber-boot"))return;let e=document.createElement("div");e.id="cyber-boot",e.className="cyber-boot",e.setAttribute("aria-hidden","true"),e.innerHTML='<div class="cyber-boot-grid"></div><div class="cyber-loader"><div class="cyber-loader-frame"><div class="cyber-loader-head"><span>KIROSHI NETLINK</span><span class="cyber-loader-jp">\u4FB5\u5165\u4E2D</span></div><div class="cyber-loader-line"><span class="cyber-loader-prompt">></span><span class="cyber-loader-text"></span><span class="cyber-loader-cursor">_</span></div><div class="cyber-loader-stream"></div></div></div>',document.body.appendChild(e);let n=e.querySelector(".cyber-loader-text"),o=e.querySelector(".cyber-loader-stream"),s=0,a=0,i=0;Ke=window.setInterval(()=>{let l=Nn[s];n&&(a<l.length?(a+=1,n.textContent=l.slice(0,a)+Kt(l.length-a,Pn),n.classList.remove("done")):i<16?(i+=1,n.textContent=l,n.classList.add("done")):(s=(s+1)%Nn.length,a=0,i=0)),o&&(o.textContent=Kt(26,Pn))},50),kt=window.setTimeout(()=>{window.clearInterval(Ke),Ke=0,e.remove()},la)}function ma(){Ke&&(window.clearInterval(Ke),Ke=0),kt&&(window.clearTimeout(kt),kt=0),document.getElementById("cyber-boot")?.remove()}var fa=320,qn=16,it=!0,Je=0,Wt=0,$t=!1,St=[],Vt=[];function ga(){if($t)return;$t=!0,it=!1,Je=0;let e=Yt(),n="";for(let s=0;s<qn;s++){let a=s%3===0?"186 100% 52%":s%3===1?"330 100% 58%":"56 97% 52%",i=(s%2===0?1:-1)*(8+s%5*7);n+=`<span class="cyber-breach-shard" style="top:${s/qn*100}%;height:${2+s%4*3}%;--shift:${i}px;--delay:${s%8*.09}s;--dur:${(.36+s%5*.12).toFixed(2)}s;--hue:${a}"></span>`}let o=document.createElement("div");o.id="cyber-breach",o.className="cyber-breach",o.setAttribute("aria-hidden","true"),o.innerHTML=`<span class="cyber-breach-flash"></span><span class="cyber-breach-grid"></span><div class="cyber-breach-shards">${n}</div><div class="cyber-breach-banner"><span class="cyber-breach-tag">// BREACH PROTOCOL \u2014 SYSTEM OVERRIDE</span><span class="cyber-breach-caption" data-text="SYSTEM BREACH">SYSTEM BREACH</span><span class="cyber-breach-sub" data-text="NETWATCH OVERRIDE ENGAGED">NETWATCH OVERRIDE ENGAGED</span></div>`,document.body.appendChild(o),e||document.body.classList.add("cyber-breach-quake"),St.push(window.setTimeout(()=>document.body.classList.remove("cyber-breach-quake"),760)),St.push(window.setTimeout(()=>{o.remove(),$t=!1},e?2600:4200))}function ba(){it=!0,Je=0;let e=document.documentElement,n=()=>e.scrollHeight-(window.innerHeight+window.scrollY)<=4,o=h=>{h<=0||!n()||(Je+=h,Je>fa&&it&&ga())},s=h=>o(h.deltaY),a=h=>{Wt=h.touches[0]?.clientY??0},i=h=>{let b=h.touches[0]?.clientY??0,v=Wt-b;Wt=b,o(v)},l=()=>{n()||(Je=0,it=!0)},c=(h,b)=>{window.addEventListener(h,b,{passive:!0}),Vt.push([h,b])};c("wheel",s),c("touchstart",a),c("touchmove",i),c("scroll",l)}function ha(){for(let[e,n]of Vt)window.removeEventListener(e,n);Vt=[],St.forEach(e=>window.clearTimeout(e)),St=[],document.body.classList.remove("cyber-breach-quake"),document.getElementById("cyber-breach")?.remove(),$t=!1,it=!0,Je=0}function Un(e,n=!1){if(!(typeof document>"u")){if(!e){document.getElementById("cyber-fx")?.remove(),document.getElementById("cyber-hud")?.remove(),document.getElementById("cyber-glitch")?.remove(),ua(),ma(),ha();return}if(!document.getElementById("cyber-fx")){let o=document.createElement("div");o.id="cyber-fx",o.className="cyber-fx",o.setAttribute("aria-hidden","true"),o.innerHTML='<div class="cyber-fx-grid"></div><div class="cyber-fx-scan"></div><span class="cyber-flicker"></span><span class="cyber-rollline"></span>',da(o),document.body.appendChild(o);let s=document.createElement("div");s.id="cyber-hud",s.className="cyber-hud",s.setAttribute("aria-hidden","true"),s.innerHTML='<span class="cyber-hud-corner tl"></span><span class="cyber-hud-corner tr"></span><span class="cyber-hud-corner bl"></span><span class="cyber-hud-corner br"></span><span class="cyber-hud-tag">NIGHT CITY // NETWATCH</span>',document.body.appendChild(s);let a=document.createElement("div");a.id="cyber-glitch",a.className="cyber-glitch",a.setAttribute("aria-hidden","true"),document.body.appendChild(a),ca(),ba()}n&&pa()}}var wa={genshin:2e3,zzz:1900,dragonball:1900,ikun:1900},ya='<span class="si-bball" aria-hidden="true"><span class="si-bball-seams"><svg viewBox="0 0 100 100"><g fill="none" stroke="#3a1d08" stroke-width="3.4" stroke-linecap="round"><path d="M50 4V96"/><path d="M4 50H96"/><path d="M50 4 Q14 50 50 96"/><path d="M50 4 Q86 50 50 96"/></g></svg></span></span>';function va(e){switch(e){case"genshin":return'<span class="si-gi-shine" aria-hidden="true"></span><span class="si-gi-text">\u539F\u795E\uFF0C\u542F\u52A8</span>';case"zzz":return'<span class="si-static" aria-hidden="true"></span><span class="si-roll" aria-hidden="true"></span><span class="si-now">NOW LOADING</span>';case"dragonball":return'<span class="si-speed" aria-hidden="true"></span><img class="si-cloud" src="/assets/skins/dragonball-wukong.webp" alt="">';case"ikun":return ya;default:return""}}function ka(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function jn(e){if(typeof document>"u"||ka())return;let n=wa[e];if(!n)return;document.getElementById("skin-intro")?.remove();let o=document.createElement("div");o.id="skin-intro",o.className=`skin-intro si-${e}`,o.setAttribute("aria-hidden","true"),o.style.setProperty("--si-dur",`${n}ms`),o.innerHTML=va(e),document.body.appendChild(o),window.setTimeout(()=>o.remove(),n+80)}var Xt=class{locale="zh";themeMode="system";resolvedTheme="light";skin="default";authed=!0;listeners=new Set;translate=vt(this.locale);mediaQuery=null;init(){let n=typeof window<"u"?window:void 0;this.locale=Mn(n?.localStorage,Sa()),this.translate=vt(this.locale),this.themeMode=Hn(n?.localStorage),this.skin=On(n?.localStorage),this.mediaQuery=n?.matchMedia?.("(prefers-color-scheme: dark)")??null,this.mediaQuery?.addEventListener("change",()=>{this.applyTheme(),this.emit()}),this.applyTheme(),this.applySkin(),this.applyLocale()}t(n,o){return this.translate(n,o)}setLocale(n){this.locale!==n&&(this.locale=n,this.translate=vt(n),window.localStorage.setItem(Ft,n),this.applyLocale(),this.emit())}get theme(){return this.skin==="default"?this.themeMode:this.skin}setTheme(n){let o=n==="system"||n==="light"||n==="dark",s=o?"default":n,a=s!==this.skin;o&&this.themeMode!==n&&(this.themeMode=n,window.localStorage.setItem(Gt,this.themeMode)),a&&(this.skin=s,window.localStorage.setItem(_t,this.skin)),this.applyTheme(),this.applySkin(a),this.emit()}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}applyTheme(){this.resolvedTheme=En(this.themeMode,!!this.mediaQuery?.matches);let n=this.skin==="default"?this.resolvedTheme:$a[this.skin];document.documentElement.dataset.theme=n,document.documentElement.dataset.themeMode=this.themeMode}applySkin(n=!1){document.documentElement.dataset.skin=this.skin,Un(this.skin==="cyber",n),n&&this.skin!=="cyber"&&this.skin!=="default"&&jn(this.skin)}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}},$a={default:"light",cyber:"dark",genshin:"light",fallout:"dark",prts:"dark",bluearchive:"dark",zzz:"dark",dragonball:"light",ikun:"dark"};function Sa(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var ce=new Xt;function t(e,n){return ce.t(e,n)}function r(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function Le(e){if(!e)return"-";let n=Date.now()-e;return n<6e4?t("common.now"):n<36e5?Math.floor(n/6e4)+"m":n<864e5?Math.floor(n/36e5)+"h":Math.floor(n/864e5)+"d"}var Fn=[{c1:"#5be3ff",c2:"#4f8bff"},{c1:"#b89bff",c2:"#6b4df0"},{c1:"#7ce0c3",c2:"#2e9e8f"},{c1:"#8fb4ff",c2:"#3b62d8"},{c1:"#ffd28f",c2:"#d8783b"},{c1:"#7df0a8",c2:"#1f9e63"},{c1:"#9fd0ff",c2:"#4878c8"},{c1:"#ff9fb8",c2:"#d84a78"}];function Gn(e){let n=0,o=String(e??"");for(let i=0;i<o.length;i++)n=n*31+o.charCodeAt(i)>>>0;let{c1:s,c2:a}=Fn[n%Fn.length];return`--c1:${s};--c2:${a}`}var Tt=new Map,Lt=new Map;function Ta(e,n){return n?Tt.get(n):e?Lt.get(String(e)):void 0}function ye(e){let n=e.name??"",o=e.avatarUrl??Ta(e.name,e.larkAppId),s=e.size==="sm"?" orb-avatar-sm":"",a=o?" orb-has-img":"",i=e.dot?`<i class="orb-dot orb-dot-${e.dot}"></i>`:"",l=o?`<img class="orb-img" src="${r(o)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar${s}${a}" style="${Gn(n)}" aria-hidden="true">${l}${i}</span>`}function La(e){return e?Mt.get(e):void 0}function zn(e){let n=e.name??e.chatId??"",o=e.avatarUrl??La(e.chatId),s=e.size==="sm"?" orb-avatar-sm":"",a=o?" orb-has-img":"",i=o?`<img class="orb-img" src="${r(o)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar orb-square${s}${a}" style="${Gn(n)}" aria-hidden="true">${i}</span>`}var rt=new Map,It=new Map,Mt=new Map,Qt=null,_n="botmux.avatarCache.v1";function Ia(){try{let e=typeof window<"u"?window.localStorage.getItem(_n):null;if(!e)return;let n=JSON.parse(e);for(let[o,s]of Object.entries(n.botByAppId??{}))Tt.set(o,s);for(let[o,s]of Object.entries(n.botByName??{}))Lt.set(o,s);for(let[o,s]of Object.entries(n.chatById??{}))Mt.set(o,s);for(let[o,s]of Object.entries(n.nameByAppId??{}))rt.set(o,s);for(let[o,s]of Object.entries(n.chatNameById??{}))It.set(o,s)}catch{}}function Ma(){try{if(typeof window>"u")return;window.localStorage.setItem(_n,JSON.stringify({botByAppId:Object.fromEntries(Tt),botByName:Object.fromEntries(Lt),chatById:Object.fromEntries(Mt),nameByAppId:Object.fromEntries(rt),chatNameById:Object.fromEntries(It)}))}catch{}}Ia();function Ee(){return Qt??=(async()=>{try{let e=await fetch("/api/groups");if(!e.ok)throw new Error(`HTTP ${e.status}`);let n=await e.json();for(let o of n.bots??[])o.larkAppId&&o.botName&&o.botName!==o.larkAppId&&rt.set(o.larkAppId,String(o.botName)),o.botAvatarUrl&&(o.larkAppId&&Tt.set(o.larkAppId,String(o.botAvatarUrl)),o.botName&&Lt.set(String(o.botName),String(o.botAvatarUrl)));for(let o of n.chats??[])o.chatId&&o.name&&It.set(o.chatId,String(o.name)),o.chatId&&o.avatar&&Mt.set(o.chatId,String(o.avatar));Ma()}catch{Qt=null}})(),Qt}function Wn(e){return e?rt.get(e):void 0}function He(e){let n=e.larkAppId?rt.get(e.larkAppId):void 0;return n||(e.botName&&e.botName!==e.larkAppId?String(e.botName):String(e.botName??e.larkAppId??"-"))}function Ve(e){return e.chatId&&It.get(e.chatId)||null}function Oe(e){let n=String(e??"");return n.replace(/^(?:@\S+\s*)+/,"").trim()||n}function Ye(e){return`<div class="page-loading" role="status"><i class="page-loading-spin" aria-hidden="true"></i>${r(e??t("common.loading"))}</div>`}function Pe(e){return e.status==="closed"?null:e.agentAttention?.reason?e.agentAttention.reason:e.agentAttention?t("sessions.board.signalAgent"):e.pendingRepo?t("sessions.board.signalRepo"):e.tuiPromptActive?t("sessions.board.signalPrompt"):e.status==="limited"?t("sessions.board.signalLimited"):null}function ue(e){let n=Number(e.agentAttention?.at??e.lastMessageAt??0);if(Number.isFinite(n))return n;let o=Number(e.lastMessageAt??0);return Number.isFinite(o)?o:0}var Vn={chats:[],bots:[]};async function xa(){try{let e=await fetch("/api/groups");if(!e.ok)return;Vn=await e.json()}catch{}}var Zt=new Set(["working","analyzing","active","starting"]);function Ea(e){let n=new Map,o=a=>{let i=n.get(a);return i||(i={botName:a,larkAppId:a,cliId:"unknown",online:!1,sessions:[],active:[],busy:[],attention:[],lastActiveAt:0},n.set(a,i)),i};for(let a of Vn.bots??[]){let i=o(a.larkAppId??a.botName??"-");i.online=!0,a.botName&&(i.botName=a.botName),a.botAvatarUrl&&(i.botAvatarUrl=a.botAvatarUrl)}let s=[...e].sort((a,i)=>+(a.status==="closed")-+(i.status==="closed"));for(let a of s){let i=a.larkAppId??a.botName??"-";if(a.status==="closed"&&!n.has(i))continue;let l=o(i);a.botName&&(l.botName===l.larkAppId||!l.botName)&&(l.botName=a.botName),l.sessions.push(a),a.cliId&&l.cliId==="unknown"&&(l.cliId=a.cliId),l.lastActiveAt=Math.max(l.lastActiveAt,Number(a.lastMessageAt??0)),a.status!=="closed"&&(l.active.push(a),Zt.has(a.status)&&l.busy.push(a),Pe(a)&&l.attention.push(a))}for(let a of n.values())if(a.botName===a.larkAppId){let i=Wn(a.larkAppId);i&&(a.botName=i)}return[...n.values()].sort((a,i)=>{let l=c=>c.attention.length?0:c.busy.length?1:c.online||c.active.length?2:3;return l(a)!==l(i)?l(a)-l(i):i.lastActiveAt-a.lastActiveAt})}var Yn="botmux.overview.teamExpanded",Ha=230,Jn=13,Kn=2;function Ca(e){let n=e.clientWidth;return n?Math.max(1,Math.floor((n+Jn)/(Ha+Jn)))*Kn:Kn*3}function Aa(){try{return window.localStorage.getItem(Yn)==="1"}catch{return!1}}function Da(e){try{window.localStorage.setItem(Yn,e?"1":"0")}catch{}}function Ra(e){let n=!e.online&&e.active.length===0,o=e.attention.length>0,s=e.busy.length>0,a=o?"warn":s?"busy":n?"off":"ok",i;if(o){let c=[...e.attention].sort((h,b)=>ue(h)-ue(b))[0];i=`<b>${r((Oe(c.title)||c.sessionId).slice(0,60))}</b> \xB7 ${r(Pe(c)??"")}`}else if(s){let c=[...e.busy].sort((h,b)=>Number(b.lastMessageAt??0)-Number(h.lastMessageAt??0))[0];i=`<b>${r((Oe(c.title)||c.sessionId).slice(0,60))}</b>`}else n?i=r(t("overview.botOffline")):i=r(t("overview.botIdle"));let l=o?`<span class="tag tag-warn">${r(t("overview.botNeedsYou"))}</span>`:s?`<span class="tag tag-run">${r(t("overview.botBusy",{count:e.busy.length}))}</span>`:n?`<span class="tag tag-off">${r(t("overview.botOff"))}</span>`:`<span class="tag tag-ok">${r(t("overview.botReady"))}</span>`;return`<article class="mate${o?" mate-attn":""}${n?" mate-off":""}">
|
|
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"},ua={zh:ss,en:is};function Ft(e){if(typeof e!="string")return null;let n=e.trim().toLowerCase();return n==="zh"||n.startsWith("zh-")?"zh":n==="en"||n.startsWith("en-")?"en":null}function rs(e=[]){for(let n of e){let a=Ft(n);if(a)return a}return"zh"}function _t(e){return(n,a)=>{let s=ua[e][n]??ua.zh[n]??n;return a?s.replace(/\{(\w+)\}/g,(o,l)=>{let c=a[l];return c==null?`{${l}}`:String(c)}):s}}function pa(e,n){return(e?Ft(e.getItem(bn)):null)??rs(n)}var hn="botmux.dashboard.theme",ma="botmux.dashboard.sessions.view";function ls(e){return e==="system"||e==="light"||e==="dark"?e:null}function wn(e){return e==="kanban"||e==="board"||e==="table"?e:null}function fa(e,n){return e==="system"?n?"dark":"light":e}function ga(e){return ls(e?.getItem(hn))??"dark"}function ba(e){return wn(e?.getItem(ma))??"board"}var ha="botmux.dashboard.sessions.boardOrder",Tt=["needs-you","starting","working","idle"];function ds(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 a of Tt)if(!n.has(a))return null;return e.slice()}function wa(e){try{let n=e?.getItem(ha);return n?ds(JSON.parse(n))??[...Tt]:[...Tt]}catch{return[...Tt]}}function yn(e,n){try{e?.setItem(ha,JSON.stringify(n))}catch{}}function ya(e,n){try{e?.setItem(ma,n)}catch{}}var va="botmux.dashboard.sessions.kanbanGroupBy",vn="botmux.dashboard.sessions.kanbanTeam";function cs(e){return e==="flow"||e==="team"||e==="bot"?e:null}function ka(e){return cs(e?.getItem(va))??"flow"}function $a(e,n){try{e?.setItem(va,n)}catch{}}var Sa="botmux.dashboard.sidebar";function us(e){return e==="expanded"||e==="collapsed"?e:null}function Ta(e){return us(e?.getItem(Sa))??"expanded"}function La(e,n){try{e?.setItem(Sa,n)}catch{}}var ps=["default","cyber","genshin","fallout","prts","bluearchive","zzz","dragonball","ikun"],kn="botmux.dashboard.skin";function ms(e){return typeof e=="string"&&ps.includes(e)?e:null}function Ia(e){return ms(e?.getItem(kn))??"default"}var fs="\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF830123456789\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E$#%&@*+=<>/\\",Ma=["186 100% 60%","56 97% 60%","330 100% 64%","150 80% 58%"],Sn=[{key:"shake",dur:280},{key:"rgb",dur:340},{key:"tear",dur:400},{key:"invert",dur:220},{key:"slice",dur:320},{key:"blackout",dur:260}],Ea=["ESTABLISHING NETLINK","BYPASSING ICE","DECRYPTING DATAFLOW","SYNCING BOTMUX TELEMETRY","ACCESS GRANTED"],xa="0123456789ABCDEF#<>*/=+\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C",gs=3200,Lt=[],ht=0,Gt=0;function In(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Tn(e,n){let a="";for(let s=0;s<e;s++)a+=n[Math.floor(Math.random()*n.length)];return a}function bs(e){let n=document.createElement("div");n.className="cyber-rain";let a=Math.max(10,Math.min(26,Math.round(window.innerWidth/70)));for(let s=0;s<a;s++){let o=document.createElement("span");o.className="cyber-rain-col",o.textContent=Tn(28+Math.floor(Math.random()*22),fs);let l=Ma[Math.floor(Math.random()*Ma.length)];o.style.cssText=`left:${(s+.5)/a*100}%;--rc:${l};--sz:${10+Math.floor(Math.random()*9)}px;--op:${(.25+Math.random()*.45).toFixed(2)};--dur:${(6+Math.random()*9).toFixed(1)}s;--delay:${(-Math.random()*12).toFixed(1)}s;`,n.appendChild(o)}e.appendChild(n)}function hs(){if(In())return;let e=document.body,n=()=>{let a=Sn[Math.floor(Math.random()*Sn.length)],s=`cp-fx-${a.key}`;e.classList.add(s),Lt.push(window.setTimeout(()=>e.classList.remove(s),a.dur)),Lt.push(window.setTimeout(n,2400+Math.random()*4200))};Lt.push(window.setTimeout(n,1800+Math.random()*2600))}function ws(){Lt.forEach(e=>window.clearTimeout(e)),Lt=[];for(let e of Sn)document.body.classList.remove(`cp-fx-${e.key}`)}function ys(){if(In()||document.getElementById("cyber-boot"))return;let e=document.createElement("div");e.id="cyber-boot",e.className="cyber-boot",e.setAttribute("aria-hidden","true"),e.innerHTML='<div class="cyber-boot-grid"></div><div class="cyber-loader"><div class="cyber-loader-frame"><div class="cyber-loader-head"><span>KIROSHI NETLINK</span><span class="cyber-loader-jp">\u4FB5\u5165\u4E2D</span></div><div class="cyber-loader-line"><span class="cyber-loader-prompt">></span><span class="cyber-loader-text"></span><span class="cyber-loader-cursor">_</span></div><div class="cyber-loader-stream"></div></div></div>',document.body.appendChild(e);let n=e.querySelector(".cyber-loader-text"),a=e.querySelector(".cyber-loader-stream"),s=0,o=0,l=0;ht=window.setInterval(()=>{let c=Ea[s];n&&(o<c.length?(o+=1,n.textContent=c.slice(0,o)+Tn(c.length-o,xa),n.classList.remove("done")):l<16?(l+=1,n.textContent=c,n.classList.add("done")):(s=(s+1)%Ea.length,o=0,l=0)),a&&(a.textContent=Tn(26,xa))},50),Gt=window.setTimeout(()=>{window.clearInterval(ht),ht=0,e.remove()},gs)}function vs(){ht&&(window.clearInterval(ht),ht=0),Gt&&(window.clearTimeout(Gt),Gt=0),document.getElementById("cyber-boot")?.remove()}var ks=320,Ha=16,It=!0,bt=0,$n=0,zt=!1,Wt=[],Ln=[];function $s(){if(zt)return;zt=!0,It=!1,bt=0;let e=In(),n="";for(let s=0;s<Ha;s++){let o=s%3===0?"186 100% 52%":s%3===1?"330 100% 58%":"56 97% 52%",l=(s%2===0?1:-1)*(8+s%5*7);n+=`<span class="cyber-breach-shard" style="top:${s/Ha*100}%;height:${2+s%4*3}%;--shift:${l}px;--delay:${s%8*.09}s;--dur:${(.36+s%5*.12).toFixed(2)}s;--hue:${o}"></span>`}let a=document.createElement("div");a.id="cyber-breach",a.className="cyber-breach",a.setAttribute("aria-hidden","true"),a.innerHTML=`<span class="cyber-breach-flash"></span><span class="cyber-breach-grid"></span><div class="cyber-breach-shards">${n}</div><div class="cyber-breach-banner"><span class="cyber-breach-tag">// BREACH PROTOCOL \u2014 SYSTEM OVERRIDE</span><span class="cyber-breach-caption" data-text="SYSTEM BREACH">SYSTEM BREACH</span><span class="cyber-breach-sub" data-text="NETWATCH OVERRIDE ENGAGED">NETWATCH OVERRIDE ENGAGED</span></div>`,document.body.appendChild(a),e||document.body.classList.add("cyber-breach-quake"),Wt.push(window.setTimeout(()=>document.body.classList.remove("cyber-breach-quake"),760)),Wt.push(window.setTimeout(()=>{a.remove(),zt=!1},e?2600:4200))}function Ss(){It=!0,bt=0;let e=document.documentElement,n=()=>e.scrollHeight-(window.innerHeight+window.scrollY)<=4,a=k=>{k<=0||!n()||(bt+=k,bt>ks&&It&&$s())},s=k=>a(k.deltaY),o=k=>{$n=k.touches[0]?.clientY??0},l=k=>{let v=k.touches[0]?.clientY??0,L=$n-v;$n=v,a(L)},c=()=>{n()||(bt=0,It=!0)},m=(k,v)=>{window.addEventListener(k,v,{passive:!0}),Ln.push([k,v])};m("wheel",s),m("touchstart",o),m("touchmove",l),m("scroll",c)}function Ts(){for(let[e,n]of Ln)window.removeEventListener(e,n);Ln=[],Wt.forEach(e=>window.clearTimeout(e)),Wt=[],document.body.classList.remove("cyber-breach-quake"),document.getElementById("cyber-breach")?.remove(),zt=!1,It=!0,bt=0}function Ca(e,n=!1){if(!(typeof document>"u")){if(!e){document.getElementById("cyber-fx")?.remove(),document.getElementById("cyber-hud")?.remove(),document.getElementById("cyber-glitch")?.remove(),ws(),vs(),Ts();return}if(!document.getElementById("cyber-fx")){let a=document.createElement("div");a.id="cyber-fx",a.className="cyber-fx",a.setAttribute("aria-hidden","true"),a.innerHTML='<div class="cyber-fx-grid"></div><div class="cyber-fx-scan"></div><span class="cyber-flicker"></span><span class="cyber-rollline"></span>',bs(a),document.body.appendChild(a);let s=document.createElement("div");s.id="cyber-hud",s.className="cyber-hud",s.setAttribute("aria-hidden","true"),s.innerHTML='<span class="cyber-hud-corner tl"></span><span class="cyber-hud-corner tr"></span><span class="cyber-hud-corner bl"></span><span class="cyber-hud-corner br"></span><span class="cyber-hud-tag">NIGHT CITY // NETWATCH</span>',document.body.appendChild(s);let o=document.createElement("div");o.id="cyber-glitch",o.className="cyber-glitch",o.setAttribute("aria-hidden","true"),document.body.appendChild(o),hs(),Ss()}n&&ys()}}var Ls={genshin:2e3,zzz:1900,dragonball:1900,ikun:1900},Is='<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 Ms(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 Is;default:return""}}function Es(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Aa(e){if(typeof document>"u"||Es())return;let n=Ls[e];if(!n)return;document.getElementById("skin-intro")?.remove();let a=document.createElement("div");a.id="skin-intro",a.className=`skin-intro si-${e}`,a.setAttribute("aria-hidden","true"),a.style.setProperty("--si-dur",`${n}ms`),a.innerHTML=Ms(e),document.body.appendChild(a),window.setTimeout(()=>a.remove(),n+80)}var En=class{locale="zh";themeMode="system";resolvedTheme="light";skin="default";authed=!0;listeners=new Set;translate=_t(this.locale);mediaQuery=null;init(){let n=typeof window<"u"?window:void 0;this.locale=pa(n?.localStorage,Hs()),this.translate=_t(this.locale),this.themeMode=ga(n?.localStorage),this.skin=Ia(n?.localStorage),this.mediaQuery=n?.matchMedia?.("(prefers-color-scheme: dark)")??null,this.mediaQuery?.addEventListener("change",()=>{this.applyTheme(),this.emit()}),this.applyTheme(),this.applySkin(),this.applyLocale()}t(n,a){return this.translate(n,a)}setLocale(n){this.locale!==n&&(this.locale=n,this.translate=_t(n),window.localStorage.setItem(bn,n),this.applyLocale(),this.emit())}get theme(){return this.skin==="default"?this.themeMode:this.skin}setTheme(n){let a=n==="system"||n==="light"||n==="dark",s=a?"default":n,o=s!==this.skin;a&&this.themeMode!==n&&(this.themeMode=n,window.localStorage.setItem(hn,this.themeMode)),o&&(this.skin=s,window.localStorage.setItem(kn,this.skin)),this.applyTheme(),this.applySkin(o),this.emit()}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}applyTheme(){this.resolvedTheme=fa(this.themeMode,!!this.mediaQuery?.matches);let n=this.skin==="default"?this.resolvedTheme:xs[this.skin];document.documentElement.dataset.theme=n,document.documentElement.dataset.themeMode=this.themeMode}applySkin(n=!1){document.documentElement.dataset.skin=this.skin,Ca(this.skin==="cyber",n),n&&this.skin!=="cyber"&&this.skin!=="default"&&Aa(this.skin)}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}},xs={default:"light",cyber:"dark",genshin:"light",fallout:"dark",prts:"dark",bluearchive:"dark",zzz:"dark",dragonball:"light",ikun:"dark"};function Hs(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var $e=new En;function t(e,n){return $e.t(e,n)}function i(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function Be(e){if(!e)return"-";let n=Date.now()-e;return n<6e4?t("common.now"):n<36e5?Math.floor(n/6e4)+"m":n<864e5?Math.floor(n/36e5)+"h":Math.floor(n/864e5)+"d"}var Da=[{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 Ra(e){let n=0,a=String(e??"");for(let l=0;l<a.length;l++)n=n*31+a.charCodeAt(l)>>>0;let{c1:s,c2:o}=Da[n%Da.length];return`--c1:${s};--c2:${o}`}var Kt=new Map,Jt=new Map;function Cs(e,n){return n?Kt.get(n):e?Jt.get(String(e)):void 0}function fe(e){let n=e.name??"",a=e.avatarUrl??Cs(e.name,e.larkAppId),s=e.size==="sm"?" orb-avatar-sm":"",o=a?" orb-has-img":"",l=e.dot?`<i class="orb-dot orb-dot-${e.dot}"></i>`:"",c=a?`<img class="orb-img" src="${i(a)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar${s}${o}" style="${Ra(n)}" aria-hidden="true">${c}${l}</span>`}function As(e){return e?Qt.get(e):void 0}function Yt(e){let n=e.name??e.chatId??"",a=e.avatarUrl??As(e.chatId),s=e.size==="sm"?" orb-avatar-sm":"",o=a?" orb-has-img":"",l=a?`<img class="orb-img" src="${i(a)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar orb-square${s}${o}" style="${Ra(n)}" aria-hidden="true">${l}</span>`}var Mt=new Map,Vt=new Map,Qt=new Map,Mn=null,Oa="botmux.avatarCache.v1";function Ds(){try{let e=typeof window<"u"?window.localStorage.getItem(Oa):null;if(!e)return;let n=JSON.parse(e);for(let[a,s]of Object.entries(n.botByAppId??{}))Kt.set(a,s);for(let[a,s]of Object.entries(n.botByName??{}))Jt.set(a,s);for(let[a,s]of Object.entries(n.chatById??{}))Qt.set(a,s);for(let[a,s]of Object.entries(n.nameByAppId??{}))Mt.set(a,s);for(let[a,s]of Object.entries(n.chatNameById??{}))Vt.set(a,s)}catch{}}function Rs(){try{if(typeof window>"u")return;window.localStorage.setItem(Oa,JSON.stringify({botByAppId:Object.fromEntries(Kt),botByName:Object.fromEntries(Jt),chatById:Object.fromEntries(Qt),nameByAppId:Object.fromEntries(Mt),chatNameById:Object.fromEntries(Vt)}))}catch{}}Ds();function Ge(){return Mn??=(async()=>{try{let e=await fetch("/api/groups");if(!e.ok)throw new Error(`HTTP ${e.status}`);let n=await e.json();for(let a of n.bots??[])a.larkAppId&&a.botName&&a.botName!==a.larkAppId&&Mt.set(a.larkAppId,String(a.botName)),a.botAvatarUrl&&(a.larkAppId&&Kt.set(a.larkAppId,String(a.botAvatarUrl)),a.botName&&Jt.set(String(a.botName),String(a.botAvatarUrl)));for(let a of n.chats??[])a.chatId&&a.name&&Vt.set(a.chatId,String(a.name)),a.chatId&&a.avatar&&Qt.set(a.chatId,String(a.avatar));Rs()}catch{Mn=null}})(),Mn}function Ba(e){return e?Mt.get(e):void 0}function ye(e){let n=e.larkAppId?Mt.get(e.larkAppId):void 0;return n||(e.botName&&e.botName!==e.larkAppId?String(e.botName):String(e.botName??e.larkAppId??"-"))}function nt(e){return e.chatId&&Vt.get(e.chatId)||null}function ve(e){let n=String(e??"");return n.replace(/^(?:@\S+\s*)+/,"").trim()||n}function wt(e){return`<div class="page-loading" role="status"><i class="page-loading-spin" aria-hidden="true"></i>${i(e??t("common.loading"))}</div>`}function at(e){return e.status==="closed"?null:e.agentAttention?.reason?e.agentAttention.reason:e.agentAttention?t("sessions.board.signalAgent"):e.pendingRepo?t("sessions.board.signalRepo"):e.tuiPromptActive?t("sessions.board.signalPrompt"):e.status==="limited"?t("sessions.board.signalLimited"):null}function Le(e){let n=Number(e.agentAttention?.at??e.lastMessageAt??0);if(Number.isFinite(n))return n;let a=Number(e.lastMessageAt??0);return Number.isFinite(a)?a:0}var qa={chats:[],bots:[]};async function Os(){try{let e=await fetch("/api/groups");if(!e.ok)return;qa=await e.json()}catch{}}var xn=new Set(["working","analyzing","active","starting"]);function Bs(e){let n=new Map,a=o=>{let l=n.get(o);return l||(l={botName:o,larkAppId:o,cliId:"unknown",online:!1,sessions:[],active:[],busy:[],attention:[],lastActiveAt:0},n.set(o,l)),l};for(let o of qa.bots??[]){let l=a(o.larkAppId??o.botName??"-");l.online=!0,o.botName&&(l.botName=o.botName),o.botAvatarUrl&&(l.botAvatarUrl=o.botAvatarUrl)}let s=[...e].sort((o,l)=>+(o.status==="closed")-+(l.status==="closed"));for(let o of s){let l=o.larkAppId??o.botName??"-";if(o.status==="closed"&&!n.has(l))continue;let c=a(l);o.botName&&(c.botName===c.larkAppId||!c.botName)&&(c.botName=o.botName),c.sessions.push(o),o.cliId&&c.cliId==="unknown"&&(c.cliId=o.cliId),c.lastActiveAt=Math.max(c.lastActiveAt,Number(o.lastMessageAt??0)),o.status!=="closed"&&(c.active.push(o),xn.has(o.status)&&c.busy.push(o),at(o)&&c.attention.push(o))}for(let o of n.values())if(o.botName===o.larkAppId){let l=Ba(o.larkAppId);l&&(o.botName=l)}return[...n.values()].sort((o,l)=>{let c=m=>m.attention.length?0:m.busy.length?1:m.online||m.active.length?2:3;return c(o)!==c(l)?c(o)-c(l):l.lastActiveAt-o.lastActiveAt})}var Ua="botmux.overview.teamExpanded",Ns=230,Na=13,Pa=2;function Ps(e){let n=e.clientWidth;return n?Math.max(1,Math.floor((n+Na)/(Ns+Na)))*Pa:Pa*3}function qs(){try{return window.localStorage.getItem(Ua)==="1"}catch{return!1}}function Us(e){try{window.localStorage.setItem(Ua,e?"1":"0")}catch{}}function js(e){let n=!e.online&&e.active.length===0,a=e.attention.length>0,s=e.busy.length>0,o=a?"warn":s?"busy":n?"off":"ok",l;if(a){let m=[...e.attention].sort((k,v)=>Le(k)-Le(v))[0];l=`<b>${i((ve(m.title)||m.sessionId).slice(0,60))}</b> \xB7 ${i(at(m)??"")}`}else if(s){let m=[...e.busy].sort((k,v)=>Number(v.lastMessageAt??0)-Number(k.lastMessageAt??0))[0];l=`<b>${i((ve(m.title)||m.sessionId).slice(0,60))}</b>`}else n?l=i(t("overview.botOffline")):l=i(t("overview.botIdle"));let c=a?`<span class="tag tag-warn">${i(t("overview.botNeedsYou"))}</span>`:s?`<span class="tag tag-run">${i(t("overview.botBusy",{count:e.busy.length}))}</span>`:n?`<span class="tag tag-off">${i(t("overview.botOff"))}</span>`:`<span class="tag tag-ok">${i(t("overview.botReady"))}</span>`;return`<article class="mate${a?" mate-attn":""}${n?" mate-off":""}">
|
|
14
14
|
<div class="mate-top">
|
|
15
|
-
${
|
|
15
|
+
${fe({name:e.botName,larkAppId:e.larkAppId,avatarUrl:e.botAvatarUrl,dot:o})}
|
|
16
16
|
<div class="mate-id">
|
|
17
|
-
<b>${
|
|
18
|
-
<span class="mate-role">${
|
|
17
|
+
<b>${i(e.botName)}</b>
|
|
18
|
+
<span class="mate-role">${i(e.cliId)}</span>
|
|
19
19
|
</div>
|
|
20
20
|
</div>
|
|
21
|
-
<div class="mate-task">${
|
|
21
|
+
<div class="mate-task">${l}</div>
|
|
22
22
|
<div class="mate-foot">
|
|
23
|
-
${
|
|
24
|
-
<span>${e.lastActiveAt?
|
|
23
|
+
${c}
|
|
24
|
+
<span>${e.lastActiveAt?i(t("overview.lastActive",{time:Be(e.lastActiveAt)})):i(t("common.never"))}</span>
|
|
25
25
|
</div>
|
|
26
|
-
</article>`}function
|
|
27
|
-
${
|
|
26
|
+
</article>`}function Fs(e){let n=ye(e);return`<article class="qcard" data-id="${i(e.sessionId)}">
|
|
27
|
+
${fe({name:n,larkAppId:e.larkAppId,size:"sm"})}
|
|
28
28
|
<div class="qcard-tx">
|
|
29
|
-
<b>${
|
|
30
|
-
<span>${
|
|
29
|
+
<b>${i(n)} \xB7 ${i((ve(e.title)||e.sessionId).slice(0,56))}</b>
|
|
30
|
+
<span>${i(at(e)??"")} \xB7 ${Be(Le(e))}</span>
|
|
31
31
|
</div>
|
|
32
|
-
<a class="qcard-go" href="#/sessions">${
|
|
33
|
-
</article>`}function
|
|
34
|
-
${
|
|
32
|
+
<a class="qcard-go" href="#/sessions">${i(t("strip.handle"))}</a>
|
|
33
|
+
</article>`}function _s(e){let n=ye(e);return`<li class="sess-row">
|
|
34
|
+
${fe({name:n,larkAppId:e.larkAppId,size:"sm"})}
|
|
35
35
|
<div class="sess-tx">
|
|
36
|
-
<b>${
|
|
37
|
-
<span>${
|
|
36
|
+
<b>${i((ve(e.title)||e.sessionId).slice(0,64))}</b>
|
|
37
|
+
<span>${i(n)} \xB7 ${i(nt(e)??e.cliId??"unknown")} \xB7 ${Be(e.lastMessageAt)}</span>
|
|
38
38
|
</div>
|
|
39
|
-
<span class="status status-${
|
|
40
|
-
</li>`}function
|
|
39
|
+
<span class="status status-${i(e.status??"unknown")}">${i(e.status??"unknown")}</span>
|
|
40
|
+
</li>`}function Gs(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>${i(e.name??e.id)}</strong>
|
|
43
|
+
<span>${i(ye(e))} \xB7 ${i(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 ${
|
|
49
|
-
<div class="donut-center"><b>${s}</b><span>${
|
|
50
|
-
</div>`}async function
|
|
45
|
+
<span>${i(n)}</span>
|
|
46
|
+
</li>`}function zs(e,n,a){let s=e+n+a;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>${i(t("overview.openSessions"))}</span></div></div>`;let o=e/s*360,l=o+n/s*360;return`<div class="donut-wrap">
|
|
48
|
+
<div class="donut" style="background:conic-gradient(var(--accent) 0 ${o}deg, var(--warning) ${o}deg ${l}deg, var(--success) ${l}deg 360deg)"></div>
|
|
49
|
+
<div class="donut-center"><b>${s}</b><span>${i(t("overview.openSessions"))}</span></div>
|
|
50
|
+
</div>`}async function ja(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>
|
|
@@ -102,34 +102,44 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
102
102
|
</section>
|
|
103
103
|
</div>
|
|
104
104
|
</div>
|
|
105
|
-
</section>`;let n=e.querySelector("#overview-pills"),
|
|
106
|
-
<span class="pill">${
|
|
107
|
-
<span class="pill${
|
|
108
|
-
<span class="pill">${
|
|
105
|
+
</section>`;let n=e.querySelector("#overview-pills"),a=e.querySelector("#team-grid"),s=e.querySelector("#team-toggle"),o=qs();s.onclick=()=>{o=!o,Us(o),v()};let l=e.querySelector("#attention-list"),c=e.querySelector("#recent-sessions"),m=e.querySelector("#today-donut"),k=e.querySelector("#next-schedules");function v(){let T=[...V.sessions.values()],w=T.filter($=>$.status!=="closed"),O=w.filter($=>at($)).sort(($,A)=>Le($)-Le(A)),D=w.filter($=>xn.has($.status)&&!at($)),R=w.length-O.length-D.length,M=Bs(T),x=M.filter($=>$.online||$.active.length>0).length;n.innerHTML=`
|
|
106
|
+
<span class="pill">${i(t("overview.workingSessions"))} <b>${D.length}</b></span>
|
|
107
|
+
<span class="pill${O.length?" pill-hot":""}">${i(t("overview.attention"))} <b>${O.length}</b></span>
|
|
108
|
+
<span class="pill">${i(t("overview.onlineBots"))} <b>${x}</b></span>`;let d=Ps(a),y=o?M:M.slice(0,d);a.innerHTML=y.length?y.map(js).join(""):`<div class="empty">${t("overview.noSessions")}</div>`,M.length>d?(s.hidden=!1,s.textContent=o?t("overview.teamCollapse"):t("overview.teamExpand",{count:M.length})):s.hidden=!0,l.innerHTML=O.length?O.map(Fs).join(""):`<div class="qcard qcard-empty">${t("overview.noAttention")}</div>`;let H=w.filter($=>xn.has($.status)||$.status==="idle").sort(($,A)=>Number(A.lastMessageAt??0)-Number($.lastMessageAt??0)).slice(0,7);c.innerHTML=H.length?H.map(_s).join(""):`<li class="empty">${t("overview.noSessions")}</li>`,m.innerHTML=`${zs(D.length,O.length,Math.max(0,R))}
|
|
109
109
|
<div class="donut-legend">
|
|
110
|
-
<span><i style="background:var(--accent)"></i>${
|
|
111
|
-
<span><i style="background:var(--warning)"></i>${
|
|
112
|
-
<span><i style="background:var(--success)"></i>${
|
|
113
|
-
</div>`;let
|
|
110
|
+
<span><i style="background:var(--accent)"></i>${i(t("overview.workingSessions"))} ${D.length}</span>
|
|
111
|
+
<span><i style="background:var(--warning)"></i>${i(t("overview.attention"))} ${O.length}</span>
|
|
112
|
+
<span><i style="background:var(--success)"></i>${i(t("sessions.board.idle"))} ${Math.max(0,R)}</span>
|
|
113
|
+
</div>`;let I=[...V.schedules.values()].filter($=>$.nextRunAt).sort(($,A)=>Date.parse($.nextRunAt)-Date.parse(A.nextRunAt)).slice(0,5);k.innerHTML=I.length?I.map(Gs).join(""):`<li class="empty">${t("overview.noSchedules")}</li>`}let L=()=>{if(!document.body.contains(a)){window.removeEventListener("resize",L);return}o||v()};window.addEventListener("resize",L),V.on(v),v(),Os().then(v),Ge().then(v)}var Fa=["backlog","todo","in_progress","in_review","done"];function _a(e){return typeof e=="string"&&Fa.includes(e)?e:null}function Ga(e){if(e.status==="closed")return"done";let n=_a(e.kanbanColumn);return n||(e.pendingRepo||e.tuiPromptActive||e.agentAttention||e.status==="limited"?"in_review":e.status==="starting"||e.status==="working"||e.status==="analyzing"||e.status==="active"?"in_progress":"todo")}var Ws=1e15;function rt(e){if(typeof e.kanbanPosition=="number"&&Number.isFinite(e.kanbanPosition))return e.kanbanPosition;let n=typeof e.lastMessageAt=="number"&&Number.isFinite(e.lastMessageAt)?e.lastMessageAt:0;return Ws-n}function Hn(e,n){return e!==null&&n!==null?(e+n)/2:e!==null?e+1024:n!==null?n-1024:1024}function ze(e,n){return`<th data-sort="${e}" data-label="${i(n)}">${i(n)}</th>`}function Rn(e){return typeof e=="number"&&Number.isFinite(e)?e:null}function za(e){let n=Rn(e);return n===null?"-":n.toLocaleString("en-US")}var Xa=["claude-code","seed","codex","codex-app","cursor","gemini","opencode","mtr","hermes","mira","pi","copilot","aiden","coco","oh-my-pi","unknown"],Wa=[{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"}],Ka=[{id:"backlog",labelKey:"sessions.kanban.backlog"},{id:"todo",labelKey:"sessions.kanban.todo"},{id:"in_progress",labelKey:"sessions.kanban.inProgress"},{id:"in_review",labelKey:"sessions.kanban.inReview"},{id:"done",labelKey:"sessions.kanban.done"}],Cn=50;function Ks(e){let n=(a="")=>`<svg viewBox="0 0 14 14" aria-hidden="true"><circle cx="7" cy="7" r="5.4" fill="none" stroke="currentColor" stroke-width="1.6"${a}/>`;switch(e){case"backlog":return`${n(' stroke-dasharray="1.6 2.1"')}</svg>`;case"in_progress":return`${n()}<path d="M7,7 L7,3.6 A3.4,3.4 0 0 1 7,10.4 Z" fill="currentColor"/></svg>`;case"in_review":return`${n()}<path d="M7,7 L7,3.6 A3.4,3.4 0 1 1 3.6,7 Z" fill="currentColor"/></svg>`;case"done":return'<svg viewBox="0 0 14 14" aria-hidden="true"><circle cx="7" cy="7" r="6.2" fill="currentColor"/><path d="M4.4 7.2 6.2 9 9.7 5.4" fill="none" stroke="var(--surface)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>';default:return`${n()}</svg>`}}function Ja(e){return String(e??"unknown").toLowerCase().replace(/[^a-z0-9_-]/g,"-")}function Ya(e){let n=String(e??"").trim();return n?n.replace(/\\/g,"/").split("/").filter(Boolean).at(-1)??n:"-"}function An(e){if(!e.webPort)return null;let n=e.proxyPort??e.webPort,a=e.proxyPort?`/s/${encodeURIComponent(e.sessionId)}`:"";return`http://${location.hostname}:${n}${a}`}var Ie={pin:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M8 14.3s4.2-3.9 4.2-7.3A4.2 4.2 0 0 0 8 2.9a4.2 4.2 0 0 0-4.2 4.1C3.8 10.4 8 14.3 8 14.3z"/><circle cx="8" cy="6.9" r="1.5"/></svg>',openChat:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M9.4 2.8h3.8v3.8"/><path d="M13.2 2.8 7.3 8.7"/><path d="M11.5 9.3v2.9a1.2 1.2 0 0 1-1.2 1.2H3.8a1.2 1.2 0 0 1-1.2-1.2V5.7a1.2 1.2 0 0 1 1.2-1.2h2.9"/></svg>',details:'<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="2.2" y="2.9" width="11.6" height="10.2" rx="1.8"/><path d="M9.9 2.9v10.2"/></svg>',terminal:'<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="1.7" y="2.7" width="12.6" height="10.6" rx="2"/><path d="M4.4 6.3 6.4 8.1 4.4 9.9"/><path d="M8.2 10.2h3.4"/></svg>',key:'<svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="6" cy="6.1" r="3"/><path d="M8.1 8.2 13 13.1"/><path d="M11.3 11.4 12.6 10.1"/><path d="M12.7 12.8 13.7 11.8"/></svg>',close:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M4.2 4.2 11.8 11.8"/><path d="M11.8 4.2 4.2 11.8"/></svg>',edit:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M10.7 3.3 12.7 5.3 6.3 11.7 3.7 12.3 4.3 9.7 10.7 3.3z"/></svg>',history:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M2.2 4.8a2 2 0 0 1 2-2h7.6a2 2 0 0 1 2 2v4.6a2 2 0 0 1-2 2H6.6l-2.9 2.4v-2.4h-.5a2 2 0 0 1-2-2z"/><path d="M5.2 6.2h5.6M5.2 8.4h3.6"/></svg>',feishu:'<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M2.6 4.4C6.4 4 10.4 5.4 13.4 8.2 9.8 7 6.4 6.6 3.4 7.4"/><path d="M13.4 8.2C9.6 8.7 6 10 2.9 12 5.6 9 8.8 7.6 13.4 8.2"/></svg>'};function Dn(e,n,a,s=""){return`<button type="button" class="card-act${s?" "+s:""}" data-action="${e}" title="${i(a)}" aria-label="${i(a)}">${n}</button>`}function Va(e){if(!e)return"";let n=`<a class="term-btn term-open" href="${i(e)}" target="_blank" rel="noopener" title="${i(t("sessions.openTerminal"))}" aria-label="${i(t("sessions.openTerminal"))}">${Ie.terminal}</a>`;if(!$e.authed)return`<span class="term-pill solo">${n}</span>`;let a=`<button type="button" class="term-btn term-write" data-action="write-link" title="${i(t("sessions.writeLinkHint"))}" aria-label="${i(t("sessions.writeLink"))}">${Ie.key}</button>`;return`<span class="term-pill">${n}${a}</span>`}async function Qa(e,n){let a=window.open("about:blank","_blank");a&&(a.opener=null),n&&(n.disabled=!0);try{let s=await fetch(`/api/sessions/${encodeURIComponent(e.sessionId)}/write-link`),o=await s.json().catch(()=>({}));if(!s.ok||o?.ok===!1||!o?.url){a?.close(),s.status!==401&&alert(`${t("sessions.writeLinkFail")}: ${o?.error??s.status}`);return}a?a.location.href=o.url:window.open(o.url,"_blank","noopener")}catch(s){a?.close(),alert(`${t("sessions.writeLinkFail")}: ${s}`)}finally{n&&(n.disabled=!1)}}function Js(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 Ys(){return`<details class="filter-cli">
|
|
114
114
|
<summary>${t("sessions.cli")} \xB7 <b id="cli-filter-count">${t("common.all")}</b></summary>
|
|
115
115
|
<div class="filter-cli-pop" role="group" aria-label="${t("sessions.cli")}">
|
|
116
|
-
${
|
|
116
|
+
${Xa.map(e=>`
|
|
117
117
|
<label class="filter-check">
|
|
118
|
-
<input type="checkbox" name="cli" value="${
|
|
119
|
-
<span>${
|
|
118
|
+
<input type="checkbox" name="cli" value="${i(e)}" checked>
|
|
119
|
+
<span>${i(e)}</span>
|
|
120
120
|
</label>
|
|
121
121
|
`).join("")}
|
|
122
122
|
</div>
|
|
123
|
-
</details>`}function
|
|
123
|
+
</details>`}function Vs(){return`<section class="page">
|
|
124
124
|
<div class="page-heading">
|
|
125
125
|
<div>
|
|
126
126
|
<p class="eyebrow">${t("nav.sessions")}</p>
|
|
127
127
|
<h1>${t("sessions.title")}</h1>
|
|
128
128
|
<p>${t("sessions.subtitle")}</p>
|
|
129
129
|
</div>
|
|
130
|
-
<div class="
|
|
131
|
-
<
|
|
132
|
-
<
|
|
130
|
+
<div class="sessions-view-controls">
|
|
131
|
+
<span id="kanban-team-stats" class="kanban-team-stats" hidden></span>
|
|
132
|
+
<select id="kanban-team" class="kanban-team-select" aria-label="${t("sessions.kanban.groupTeam")}" hidden></select>
|
|
133
|
+
<div class="segmented kanban-groupby" id="kanban-groupby" role="group" aria-label="${t("sessions.kanban.groupBy")}" hidden>
|
|
134
|
+
<button type="button" data-groupby="flow">${t("sessions.kanban.groupFlow")}</button>
|
|
135
|
+
<button type="button" data-groupby="team">${t("sessions.kanban.groupTeam")}</button>
|
|
136
|
+
<button type="button" data-groupby="bot">${t("sessions.kanban.groupBot")}</button>
|
|
137
|
+
</div>
|
|
138
|
+
<div class="segmented sessions-view-toggle" role="group" aria-label="${t("sessions.viewMode")}">
|
|
139
|
+
<button type="button" data-view="kanban">${t("sessions.viewKanban")}</button>
|
|
140
|
+
<button type="button" data-view="board">${t("sessions.viewBoard")}</button>
|
|
141
|
+
<button type="button" data-view="table">${t("sessions.viewTable")}</button>
|
|
142
|
+
</div>
|
|
133
143
|
</div>
|
|
134
144
|
</div>
|
|
135
145
|
<form id="filters" class="filters sessions-filters">
|
|
@@ -144,7 +154,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
144
154
|
<option value="yes">${t("sessions.adoptYes")}</option>
|
|
145
155
|
<option value="no">${t("sessions.adoptNo")}</option>
|
|
146
156
|
</select>
|
|
147
|
-
${
|
|
157
|
+
${Ys()}
|
|
148
158
|
<label class="filter-toggle"><input type="checkbox" name="active" checked> <span>${t("sessions.activeOnly")}</span></label>
|
|
149
159
|
</form>
|
|
150
160
|
<div id="bulk-bar" class="bulk-bar" hidden>
|
|
@@ -155,106 +165,182 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
155
165
|
<table id="sessions-table">
|
|
156
166
|
<thead><tr>
|
|
157
167
|
<th><input type="checkbox" id="select-all" title="${t("sessions.activeOnly")}"></th>
|
|
158
|
-
${
|
|
159
|
-
${
|
|
160
|
-
${
|
|
161
|
-
${
|
|
162
|
-
${
|
|
163
|
-
${
|
|
164
|
-
${
|
|
165
|
-
${
|
|
166
|
-
${
|
|
167
|
-
${
|
|
168
|
+
${ze("botName",t("sessions.bot"))}
|
|
169
|
+
${ze("cliId",t("sessions.cli"))}
|
|
170
|
+
${ze("status",t("sessions.status"))}
|
|
171
|
+
${ze("tokenIn",t("sessions.tokenIn"))}
|
|
172
|
+
${ze("tokenOut",t("sessions.tokenOut"))}
|
|
173
|
+
${ze("title",t("sessions.titleCol"))}
|
|
174
|
+
${ze("workingDir",t("sessions.workingDir"))}
|
|
175
|
+
${ze("spawnedAt",t("sessions.created"))}
|
|
176
|
+
${ze("lastMessageAt",t("sessions.last"))}
|
|
177
|
+
${ze("adopt",t("sessions.adopt"))}
|
|
168
178
|
<th>${t("sessions.actions")}</th>
|
|
169
179
|
</tr></thead>
|
|
170
180
|
<tbody></tbody>
|
|
171
181
|
</table>
|
|
172
182
|
<div id="sessions-board" class="sessions-board" hidden></div>
|
|
183
|
+
<div id="sessions-kanban" class="sessions-kanban" hidden></div>
|
|
173
184
|
<dialog id="drawer"></dialog>
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
<td><
|
|
178
|
-
<td
|
|
179
|
-
<td class="
|
|
180
|
-
<td class="
|
|
181
|
-
<td
|
|
182
|
-
<td
|
|
183
|
-
<td>${
|
|
184
|
-
<td>${
|
|
185
|
-
<td>${
|
|
185
|
+
<dialog id="term-modal" class="term-modal"></dialog>
|
|
186
|
+
<dialog id="history-modal" class="history-modal"></dialog>
|
|
187
|
+
</section>`}function Za(e){e.innerHTML=Vs();let n=e.querySelector("#sessions-table tbody"),a=e.querySelector("#filters"),s=e.querySelector("#drawer"),o=e.querySelector("#select-all"),l=e.querySelector("#bulk-bar"),c=e.querySelector("#bulk-count"),m=e.querySelector("#bulk-close"),k=e.querySelector("#bulk-clear"),v=e.querySelector("#sessions-table"),L=e.querySelector("#sessions-board"),T=e.querySelector("#sessions-kanban"),w=e.querySelector("#term-modal"),O=e.querySelector("#history-modal"),D=e.querySelector("#kanban-groupby"),R=e.querySelector("#kanban-team"),M=e.querySelector("#kanban-team-stats"),x=e.querySelectorAll(".sessions-view-toggle [data-view]"),d=new Set,y="lastMessageAt",H="desc",I=ba(window.localStorage),$=wa(window.localStorage),A=null,B="",G="",j="",Q=!1,le=null,Ee=!1,ge=null,J=new Map,se=ka(window.localStorage),Se=null,Re=null,ee=[],ue=null,de=!1,qe=!1,ke=(()=>{try{return window.localStorage.getItem(vn)??""}catch{return""}})();async function be(){if(!(qe||de)){qe=!0;try{let[r,u,f]=await Promise.all([fetch("/api/team/hosted").then(h=>h.json()).catch(()=>null),fetch("/api/team/remote-roster").then(h=>h.json()).catch(()=>null),fetch("/api/groups").then(h=>h.json()).catch(()=>null)]);Array.isArray(f?.chats)&&(ue=new Map(f.chats.map(h=>[String(h.chatId),{botIds:new Set((h.memberBots??[]).filter(S=>S.inChat).map(S=>String(S.larkAppId))),observedNames:new Set((h.observedBotNames??[]).map(S=>String(S)))}])));let p=h=>({ids:new Set(h.map(S=>String(S.larkAppId))),names:new Set(h.map(S=>String(S.name??"")).filter(Boolean))}),g=[];for(let h of r?.teams??[]){let{ids:S,names:C}=p(h.bots??[]);g.push({key:`local:${h.teamId}`,label:h.isDefault?t("team.myHostedTeam"):String(h.name??h.teamId),botIds:S,botNames:C,groupChats:new Set((h.groupChatIds??[]).map(q=>String(q)))})}for(let h of u?.memberships??[]){let{ids:S,names:C}=p(h.roster?.bots??[]);g.push({key:`${h.hubUrl}::${h.teamId}`,label:String(h.teamName??h.teamId??h.hubUrl),botIds:S,botNames:C,groupChats:new Set})}ee=g}finally{de=!0,qe=!1}ee.length&&!ee.some(r=>r.key===ke)&&(ke=ee[0].key),delete R.dataset.loading,R.disabled=ee.length===0,R.innerHTML=ee.length?ee.map(r=>`<option value="${i(r.key)}"${r.key===ke?" selected":""}>${i(r.label)}</option>`).join(""):`<option value="">${i(t("sessions.kanban.noTeam"))}</option>`,j="",Z()}}let re=null,xe="",He=0,ce=!1,je=new Map;async function Ze(r){let u=xe===r.key&&Date.now()-He<3e4;if(!(ce||u)){ce=!0;try{let p=r.key.startsWith("local:")?`/api/team/board/local/${encodeURIComponent(r.key.slice(6))}`:`/api/team/remote-board?key=${encodeURIComponent(r.key)}`,g=await fetch(p),h=await g.json().catch(()=>({}));if(!g.ok||h?.ok===!1)return;let S=typeof h.deploymentId=="string"?h.deploymentId:null,C=[];je=new Map;for(let q of Array.isArray(h.reports)?h.reports:[])if(!(S&&q.deploymentId===S))for(let N of Array.isArray(q.sessions)?q.sessions:[]){let te={...N,remoteDeployment:q.deploymentName||q.deploymentId};C.push(te),je.set(String(N.sessionId),te)}re={board:h.board&&typeof h.board=="object"?h.board:{},remoteRows:C},xe=r.key,He=Date.now(),j="",Z()}catch{}finally{ce=!1}}}async function et(r,u,f,p,g){try{let S=r.startsWith("local:")?await fetch(`/api/team/board/local/${encodeURIComponent(r.slice(6))}/move`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({sessionId:u,column:f,position:p})}):await fetch("/api/team/remote-board-move",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({key:r,sessionId:u,column:f,position:p})}),C=await S.json().catch(()=>({}));(!S.ok||C?.ok===!1)&&(re&&(g?re.board[u]=g:delete re.board[u]),j="",Z(),S.status!==401&&alert(`${t("sessions.kanban.moveFail")}: ${C?.error??S.status}`))}catch(h){re&&(g?re.board[u]=g:delete re.board[u]),j="",Z(),alert(`${t("sessions.kanban.moveFail")}: ${h}`)}}function ft(r,u,f){let p=ee.find(h=>h.key===ke)??ee[0];if(!p)return;(!re||xe!==p.key)&&(re={board:{},remoteRows:re?.remoteRows??[]},xe=p.key);let g=re.board[r];re.board[r]={column:u,position:f},et(p.key,r,u,f,g)}function it(){return $.map(r=>Wa.find(u=>u.id===r)).filter(r=>!!r)}function Ye(r,u){let f=$.indexOf(r),p=f+u;if(f<0||p<0||p>=$.length)return;let g=[...$];g.splice(f,1),g.splice(p,0,r),$=g,yn(window.localStorage,$),Z()}function Ve(r,u){if(r===u)return;let f=$.indexOf(r),p=$.indexOf(u);if(f<0||p<0)return;let g=[...$];g.splice(f,1),g.splice(p,0,r),$=g,yn(window.localStorage,$),Z()}function oe(r){let u=r.status==="closed",f=d.has(r.sessionId)?"checked":"";return`<tr data-id="${i(r.sessionId)}">
|
|
188
|
+
<td><input type="checkbox" class="row-select" ${f} ${u?"disabled":""}></td>
|
|
189
|
+
<td>${i(ye(r))}</td>
|
|
190
|
+
<td><span class="badge cli-${Ja(r.cliId)}">${i(r.cliId??"unknown")}</span></td>
|
|
191
|
+
<td><span class="status status-${i(r.status??"unknown")}">${i(r.status??"unknown")}</span></td>
|
|
192
|
+
<td class="token-cell">${za(r.tokenUsage?.in)}</td>
|
|
193
|
+
<td class="token-cell">${za(r.tokenUsage?.out)}</td>
|
|
194
|
+
<td title="${i(String(r.title??""))}">${i(ve(r.title??"").slice(0,48))}</td>
|
|
195
|
+
<td title="${i(r.workingDir??"")}">${i((r.workingDir??"").slice(-34))}</td>
|
|
196
|
+
<td>${Be(r.spawnedAt)}</td>
|
|
197
|
+
<td>${Be(r.lastMessageAt)}</td>
|
|
198
|
+
<td>${r.adopt?'<span class="badge">adopt</span>':""}</td>
|
|
186
199
|
<td><button class="open" type="button">${t("sessions.details")}</button></td>
|
|
187
|
-
</tr>`}function
|
|
200
|
+
</tr>`}function Ue(r){if(r.scope!=="chat"||!r.feishuChatLink)return null;let u=t("sessions.openChat");return`<a class="card-act" href="${i(r.feishuChatLink)}" target="_blank" rel="noopener" title="${i(u)}" aria-label="${i(u)}">${Ie.feishu}</a>`}function Oe(r){return r.agentAttention?.reason?r.agentAttention.reason:r.agentAttention?t("sessions.board.signalAgent"):r.pendingRepo?t("sessions.board.signalRepo"):r.tuiPromptActive?t("sessions.board.signalPrompt"):r.status==="limited"?t("sessions.board.signalLimited"):""}function E(r){let u=d.has(r.sessionId),f=ve(r.title)||r.sessionId,p=ye(r),g=nt(r),h=An(r),S=Oe(r),C=Ya(r.workingDir);return`<article class="session-card${u?" selected":""}" data-id="${i(r.sessionId)}" aria-pressed="${u}">
|
|
188
201
|
<div class="session-card-top">
|
|
189
|
-
${
|
|
202
|
+
${fe({name:p,larkAppId:r.larkAppId,size:"sm"})}
|
|
190
203
|
<div class="session-card-title">
|
|
191
|
-
<strong title="${
|
|
192
|
-
<span>${
|
|
204
|
+
<strong title="${i(String(r.title??f))}">${i(String(f).slice(0,72))}</strong>
|
|
205
|
+
<span>${i(p)} \xB7 ${i(g??r.cliId??"unknown")}</span>
|
|
193
206
|
</div>
|
|
194
|
-
<span class="status status-${r
|
|
207
|
+
<span class="status status-${i(r.status??"unknown")}">${i(r.status??"unknown")}</span>
|
|
195
208
|
</div>
|
|
196
|
-
${
|
|
197
|
-
${
|
|
198
|
-
${
|
|
209
|
+
${C!=="-"||r.adopt?`<div class="session-card-meta">
|
|
210
|
+
${C!=="-"?`<span title="${i(r.workingDir??"")}">${i(C)}</span>`:""}
|
|
211
|
+
${r.adopt?'<span class="badge">adopt</span>':""}
|
|
199
212
|
</div>`:""}
|
|
200
213
|
<div class="session-card-time">
|
|
201
|
-
<span>${
|
|
214
|
+
<span>${r.agentAttention?.at?`${i(t("sessions.board.waiting"))} ${Be(Le(r))}`:`${i(t("sessions.last"))}: ${Be(r.lastMessageAt)}`}</span>
|
|
202
215
|
</div>
|
|
203
|
-
${
|
|
216
|
+
${S?`<div class="session-signal" title="${i(S)}">${i(S)}</div>`:""}
|
|
204
217
|
<div class="session-card-actions">
|
|
205
|
-
${
|
|
206
|
-
${
|
|
207
|
-
${
|
|
208
|
-
${
|
|
218
|
+
${Ue(r)??Dn("locate",Ie.pin,t("sessions.locate"))}
|
|
219
|
+
${Dn("details",Ie.details,t("sessions.details"))}
|
|
220
|
+
${Va(h)}
|
|
221
|
+
${Dn("close",Ie.close,t("sessions.close"),"danger")}
|
|
209
222
|
</div>
|
|
210
|
-
</article>`}function
|
|
211
|
-
<header draggable="true" title="${
|
|
223
|
+
</article>`}function ie(r,u,f){let p=f==="needs-you"?Le(r):Number(r.lastMessageAt??0),g=f==="needs-you"?Le(u):Number(u.lastMessageAt??0);return p!==g?f==="needs-you"?p-g:g-p:String(r.title??r.sessionId).localeCompare(String(u.title??u.sessionId))}function U(r){let u=new Map(Wa.map(g=>[g.id,[]]));for(let g of r){let h=Js(g);h&&u.get(h).push(g)}let f=it(),p=f.map((g,h)=>{let S=(u.get(g.id)??[]).sort((C,q)=>ie(C,q,g.id));return`<section class="session-board-column session-board-${g.id}" data-col="${g.id}">
|
|
224
|
+
<header draggable="true" title="${i(t("sessions.board.dragHint"))}">
|
|
212
225
|
<div>
|
|
213
|
-
<h2>${
|
|
214
|
-
<p>${
|
|
226
|
+
<h2>${i(t(g.labelKey))}</h2>
|
|
227
|
+
<p>${i(t(g.hintKey))}</p>
|
|
215
228
|
</div>
|
|
216
229
|
<span class="session-board-head-right">
|
|
217
230
|
<span class="session-board-move">
|
|
218
|
-
<button type="button" data-move-col="${
|
|
219
|
-
aria-label="${
|
|
220
|
-
<button type="button" data-move-col="${
|
|
221
|
-
aria-label="${
|
|
231
|
+
<button type="button" data-move-col="${g.id}" data-dir="-1"
|
|
232
|
+
aria-label="${i(t("sessions.board.moveLeft"))}" ${h===0?"disabled":""}>\u2039</button>
|
|
233
|
+
<button type="button" data-move-col="${g.id}" data-dir="1"
|
|
234
|
+
aria-label="${i(t("sessions.board.moveRight"))}" ${h===f.length-1?"disabled":""}>\u203A</button>
|
|
222
235
|
</span>
|
|
223
|
-
<span class="session-board-count">${
|
|
236
|
+
<span class="session-board-count">${S.length}</span>
|
|
224
237
|
</span>
|
|
225
238
|
</header>
|
|
226
239
|
<div class="session-board-list">
|
|
227
|
-
${
|
|
240
|
+
${S.length?S.map(E).join(""):`<div class="session-board-empty">${t("sessions.board.emptyColumn")}</div>`}
|
|
228
241
|
</div>
|
|
229
|
-
</section>`}).join("");
|
|
242
|
+
</section>`}).join("");p!==B&&(B=p,L.innerHTML=p,L.classList.toggle("board-enter",!Q),Q=!0)}function _(r){let u=ve(r.title)||r.sessionId,f=ye(r),p=nt(r),g=Ya(r.workingDir),h=Oe(r),S=[p,g!=="-"?g:null].filter(Boolean).join(" \xB7 "),C=String(r.status??"unknown"),q=typeof r.remoteDeployment=="string"?r.remoteDeployment:"";return`<article class="kanban-card${q?" kanban-card-remote":""}" data-id="${i(r.sessionId)}" tabindex="0" role="button" draggable="true">
|
|
243
|
+
<div class="kanban-card-top">
|
|
244
|
+
<span class="badge cli-${Ja(r.cliId)}">${i(r.cliId??"unknown")}</span>
|
|
245
|
+
${r.adopt?'<span class="badge">adopt</span>':""}
|
|
246
|
+
${q?`<span class="badge kanban-remote-badge" title="${i(t("sessions.kanban.remoteHint",{name:q}))}">${i(q)}</span>`:""}
|
|
247
|
+
<span class="kanban-card-top-right">
|
|
248
|
+
<span class="kanban-card-dot" data-status="${i(C)}" title="${i(C)}"></span>
|
|
249
|
+
${q?"":`<button type="button" class="card-act kanban-card-act" data-action="history" title="${i(t("sessions.history.title"))}" aria-label="${i(t("sessions.history.title"))}">${Ie.history}</button>
|
|
250
|
+
${r.feishuChatLink?`<a class="card-act kanban-card-act" href="${i(r.feishuChatLink)}" target="_blank" rel="noopener" title="${i(t("sessions.kanban.openFeishu"))}" aria-label="${i(t("sessions.kanban.openFeishu"))}">${Ie.feishu}</a>`:""}
|
|
251
|
+
<button type="button" class="card-act kanban-card-act" data-action="details" title="${i(t("sessions.details"))}" aria-label="${i(t("sessions.details"))}">${Ie.details}</button>`}
|
|
252
|
+
</span>
|
|
253
|
+
</div>
|
|
254
|
+
<p class="kanban-card-title" title="${i(String(r.title??u))}">${i(String(u).slice(0,140))}</p>
|
|
255
|
+
${S?`<p class="kanban-card-desc" title="${i(S)}">${i(S)}</p>`:""}
|
|
256
|
+
${h?`<div class="session-signal" title="${i(h)}">${i(h)}</div>`:""}
|
|
257
|
+
<div class="kanban-card-foot">
|
|
258
|
+
<span class="kanban-card-owner">${fe({name:f,larkAppId:r.larkAppId,size:"sm"})}<span>${i(f)}</span></span>
|
|
259
|
+
<span class="kanban-card-updated">${i(t("sessions.kanban.updated",{time:Be(r.lastMessageAt)}))}</span>
|
|
260
|
+
</div>
|
|
261
|
+
</article>`}function he(r){let u=[],f=new Map;for(let h of r){let S=String(h.chatId??h.sessionId),C=f.get(S);C||(C={chatId:S,rows:[]},f.set(S,C),u.push(C)),C.rows.push(h)}let p=[];return{html:u.map(h=>{if(p.push(...h.rows),h.rows.length<2)return _(h.rows[0]);let S=nt(h.rows[0])??h.chatId;return`<div class="kanban-cluster" data-chat="${i(h.chatId)}">
|
|
262
|
+
<header draggable="true" title="${i(S)} \xB7 ${i(t("sessions.kanban.clusterDragHint"))}">
|
|
263
|
+
${Yt({chatId:h.chatId,name:S,size:"sm"})}
|
|
264
|
+
<span class="kanban-cluster-name">${i(S)}</span>
|
|
265
|
+
<span class="kanban-cluster-count">${h.rows.length}</span>
|
|
266
|
+
</header>
|
|
267
|
+
${h.rows.map(_).join("")}
|
|
268
|
+
</div>`}).join(""),flat:p}}function gt(r){let u=new Map;for(let p of r){if(p.status==="closed")continue;let g=String(p.larkAppId||p.botName||"unknown"),h=u.get(g);h||(h={name:ye(p),larkAppId:p.larkAppId,rows:[]},u.set(g,h)),h.rows.push(p)}let f=[...u.values()].sort((p,g)=>p.name.localeCompare(g.name));return f.length?f.map(p=>{let g=p.rows.sort((S,C)=>Number(C.lastMessageAt??0)-Number(S.lastMessageAt??0)),{html:h}=he(g);return`<section class="kanban-column kanban-bot-col" data-bot="${i(p.larkAppId??p.name)}">
|
|
269
|
+
<header>
|
|
270
|
+
<span class="kanban-col-avatar">${fe({name:p.name,larkAppId:p.larkAppId,size:"sm"})}</span>
|
|
271
|
+
<h2>${i(p.name)}</h2>
|
|
272
|
+
<span class="kanban-col-count">${g.length}</span>
|
|
273
|
+
</header>
|
|
274
|
+
<div class="kanban-col-list">${h}</div>
|
|
275
|
+
</section>`}).join(""):`<div class="kanban-col-empty">${t("sessions.board.emptyColumn")}</div>`}function X(r){let u=new Map(Ka.map(p=>[p.id,[]]));for(let p of r)u.get(Ga(p)).push(p);let f=Ka.map(p=>{let g=(u.get(p.id)??[]).sort((q,N)=>rt(q)-rt(N)),h=0;p.id==="done"&&g.length>Cn&&(h=g.length-Cn,g=g.slice(0,Cn));let{html:S,flat:C}=he(g);return u.set(p.id,C),`<section class="kanban-column kanban-${p.id}" data-col="${p.id}">
|
|
276
|
+
<header>
|
|
277
|
+
<span class="kanban-col-icon">${Ks(p.id)}</span>
|
|
278
|
+
<h2>${i(t(p.labelKey))}</h2>
|
|
279
|
+
<span class="kanban-col-count">${g.length+h}</span>
|
|
280
|
+
</header>
|
|
281
|
+
<div class="kanban-col-list">
|
|
282
|
+
${g.length?S:`<div class="kanban-col-empty">${t("sessions.board.emptyColumn")}</div>`}
|
|
283
|
+
${h?`<div class="kanban-col-more">${i(t("sessions.kanban.moreHidden",{count:h}))}</div>`:""}
|
|
284
|
+
</div>
|
|
285
|
+
</section>`}).join("");return J=u,f}function z(r){if(le||Se||Ee)return;T.classList.toggle("kanban-mode-bot",se==="bot");let u;if(se==="bot")u=gt(r),J=new Map;else if(se==="team")if(!de)u=`<div class="kanban-loading">${t("sessions.kanban.teamLoading")}</div>`,J=new Map,R.dataset.loading||(R.dataset.loading="1",R.disabled=!0,R.innerHTML=`<option>${i(t("sessions.kanban.teamLoading"))}</option>`),be();else{let p=ee.find(N=>N.key===ke)??ee[0],g=[],h=new Set;if(p){for(let N of p.groupChats)h.add(N);if(ue)for(let[N,te]of ue){if(h.has(N))continue;let me=!1;for(let Fe of p.botIds)if(te.botIds.has(Fe)){me=!0;break}if(me){for(let Fe of te.observedNames)if(p.botNames.has(Fe)){h.add(N);break}}}g=r.filter(N=>h.has(String(N.chatId)))}p&&Ze(p);let S=(xe===p?.key?re?.board:null)??{},C=(xe===p?.key?re?.remoteRows:null)??[],q=[...g,...C].map(N=>{let te=S[N.sessionId];return te?{...N,kanbanColumn:te.column,kanbanPosition:te.position}:N});M.textContent=t("sessions.kanban.teamScope",{chats:h.size,sessions:q.length}),u=X(q)}else u=X(r);if(u===j)return;j=u;let f=new Map;T.querySelectorAll(".kanban-col-list").forEach(p=>{let g=p.closest(".kanban-column")?.dataset.col;g&&p.scrollTop&&f.set(g,p.scrollTop)}),T.innerHTML=u,f.size&&T.querySelectorAll(".kanban-col-list").forEach(p=>{let g=p.closest(".kanban-column")?.dataset.col,h=g?f.get(g):void 0;h&&(p.scrollTop=h)})}async function F(r,u,f,p){try{let g=await fetch(`/api/sessions/${encodeURIComponent(r.sessionId)}/board`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({column:u,position:f})}),h=await g.json().catch(()=>({}));(!g.ok||h?.ok===!1)&&(r.kanbanColumn=p.column,r.kanbanPosition=p.position,j="",Z(),g.status!==401&&alert(`${t("sessions.kanban.moveFail")}: ${h?.error??g.status}`))}catch(g){r.kanbanColumn=p.column,r.kanbanPosition=p.position,j="",Z(),alert(`${t("sessions.kanban.moveFail")}: ${g}`)}}async function K(r,u){let f=r.title;r.title=u,j="",Z();try{let p=await fetch(`/api/sessions/${encodeURIComponent(r.sessionId)}/rename`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({title:u})}),g=await p.json().catch(()=>({}));(!p.ok||g?.ok===!1)&&(r.title=f,j="",Z(),p.status!==401&&alert(`${t("sessions.kanban.renameFail")}: ${g?.error??p.status}`))}catch(p){r.title=f,j="",Z(),alert(`${t("sessions.kanban.renameFail")}: ${p}`)}}function W(r){if(r==null||r==="")return"";let u=Number(r),f=Number.isFinite(u)&&u>0?new Date(u):new Date(String(r));return Number.isNaN(f.getTime())?"":f.toLocaleString()}function Y(r,u,f){let p=u.senderType==="user",g=p?u.senderName||(f&&u.senderId===f?t("sessions.history.owner"):t("sessions.history.user")):ye(r),h=W(u.createTime),S=String(u.content??"").trim()||`[${u.msgType??"message"}]`,C=p?u.senderAvatar?`<img class="history-avatar-img" src="${i(String(u.senderAvatar))}" alt="" decoding="async" referrerpolicy="no-referrer">`:`<span class="history-avatar-user" aria-hidden="true">${i(String(g).slice(0,1))}</span>`:fe({name:ye(r),larkAppId:r.larkAppId,size:"sm"});return`<div class="history-msg${p?" mine":""}">
|
|
286
|
+
${C}
|
|
287
|
+
<div class="history-msg-main">
|
|
288
|
+
<div class="history-msg-meta"><span>${i(g)}</span><time>${i(h)}</time></div>
|
|
289
|
+
<div class="history-bubble">${i(S)}</div>
|
|
290
|
+
</div>
|
|
291
|
+
</div>`}async function pe(r){let u=ye(r);O.innerHTML=`<div class="term-modal-head">
|
|
292
|
+
<span class="term-modal-title">
|
|
293
|
+
${fe({name:u,larkAppId:r.larkAppId,size:"sm"})}
|
|
294
|
+
<strong title="${i(String(r.title??""))}">${i((ve(r.title)||r.sessionId).slice(0,60))}</strong>
|
|
295
|
+
<span class="history-scope-tag">${i(t("sessions.history.title"))}</span>
|
|
296
|
+
</span>
|
|
297
|
+
<span class="term-modal-actions">
|
|
298
|
+
<button type="button" id="history-close" class="card-act" title="${i(t("sessions.dismiss"))}" aria-label="${i(t("sessions.dismiss"))}">${Ie.close}</button>
|
|
299
|
+
</span>
|
|
300
|
+
</div>
|
|
301
|
+
<div class="history-body"><div class="term-modal-loading">${t("sessions.history.loading")}</div></div>`,O.showModal(),O.querySelector("#history-close").onclick=()=>O.close();try{let f=await fetch(`/api/sessions/${encodeURIComponent(r.sessionId)}/history?limit=80`),p=await f.json().catch(()=>({}));if(!O.open)return;let g=O.querySelector(".history-body");if(!f.ok||p?.ok===!1){let S=String(p?.error??f.status),C=S==="not_found_yet"||S==="not_found";g.innerHTML=`<div class="history-error">${i(t("sessions.history.fail"))}: ${i(S)}${C?`<br><span>${i(t("sessions.history.staleHint"))}</span>`:""}</div>`;return}let h=Array.isArray(p.messages)?p.messages:[];if(!h.length){g.innerHTML=`<div class="history-error">${t("sessions.history.empty")}</div>`;return}g.innerHTML=`<div class="history-list">${h.map(S=>Y(r,S,p.ownerOpenId)).join("")}</div>`,g.scrollTop=g.scrollHeight}catch(f){if(!O.open)return;let p=O.querySelector(".history-body");p&&(p.innerHTML=`<div class="history-error">${i(t("sessions.history.fail"))}: ${i(String(f))}</div>`)}}function Te(r,u){let f=r.querySelector(".kanban-card-title");if(!f||r.querySelector(".kanban-rename-input"))return;Ee=!0;let p=document.createElement("input");p.type="text",p.className="kanban-rename-input",p.maxLength=200,p.value=ve(u.title)||"",f.replaceWith(p),p.focus(),p.select();let g=!1,h=S=>{if(g)return;g=!0,Ee=!1;let C=p.value.trim();S&&C&&C!==(ve(u.title)||"")?K(u,C):(j="",Z())};p.addEventListener("keydown",S=>{S.stopPropagation(),S.key==="Enter"?(S.preventDefault(),h(!0)):S.key==="Escape"&&(S.preventDefault(),h(!1))}),p.addEventListener("blur",()=>h(!0)),p.addEventListener("click",S=>S.stopPropagation())}function tt(r,u){for(let f of r.querySelectorAll(".kanban-card:not(.dragging)")){if(f.closest(".kanban-cluster.dragging"))continue;let p=f.getBoundingClientRect();if(u<p.top+p.height/2)return f}return null}function aa(){T.querySelectorAll(".drag-over, .dragging, .drop-before").forEach(r=>r.classList.remove("drag-over","dragging","drop-before"))}function Vo(r){let u=w.querySelector(".term-modal-name");if(!u||w.querySelector(".term-modal-name-input"))return;let f=document.createElement("input");f.type="text",f.className="term-modal-name-input",f.maxLength=200,f.value=ve(r.title)||"",u.replaceWith(f);let p=()=>{let S=getComputedStyle(f),C=document.createElement("span");C.style.cssText="position:absolute;visibility:hidden;white-space:pre",C.style.fontSize=S.fontSize,C.style.fontFamily=S.fontFamily,C.style.fontWeight=S.fontWeight,C.style.letterSpacing=S.letterSpacing,C.textContent=f.value||" ",document.body.appendChild(C);let q=C.offsetWidth;C.remove();let N=Math.round(window.innerWidth*.6);f.style.width=`${Math.min(Math.max(q+22,80),N)}px`};p(),f.addEventListener("input",p),f.focus(),f.select();let g=!1,h=S=>{if(g)return;g=!0;let C=f.value.trim(),q=ve(r.title)||"";if(S&&C&&C!==q){r.title=C;let N=document.createElement("strong");N.className="term-modal-name",N.title=C,N.textContent=C.slice(0,60),f.replaceWith(N),K(r,C)}else{let N=document.createElement("strong");N.className="term-modal-name",N.title=String(r.title??q),N.textContent=q.slice(0,60),f.replaceWith(N)}};f.addEventListener("keydown",S=>{S.stopPropagation(),S.key==="Enter"?(S.preventDefault(),h(!0)):S.key==="Escape"&&(S.preventDefault(),h(!1))}),f.addEventListener("blur",()=>h(!0))}async function oa(r){let u=An(r);if(!u){qt(r);return}let f=ve(r.title)||r.sessionId,p=r.feishuChatLink?`<a class="card-act" href="${i(r.feishuChatLink)}" target="_blank" rel="noopener" title="${i(t("sessions.kanban.openFeishu"))}" aria-label="${i(t("sessions.kanban.openFeishu"))}">${Ie.feishu}</a>`:"";w.innerHTML=`<div class="term-modal-head">
|
|
302
|
+
<span class="term-modal-title">
|
|
303
|
+
${fe({name:ye(r),larkAppId:r.larkAppId,size:"sm"})}
|
|
304
|
+
<strong class="term-modal-name" title="${i(String(r.title??f))}">${i(String(f).slice(0,60))}</strong>
|
|
305
|
+
<button type="button" id="term-modal-edit" class="card-act" title="${i(t("sessions.kanban.rename"))}" aria-label="${i(t("sessions.kanban.rename"))}">${Ie.edit}</button>
|
|
306
|
+
<span class="status status-${i(r.status??"unknown")}">${i(r.status??"unknown")}</span>
|
|
307
|
+
</span>
|
|
308
|
+
<span class="term-modal-actions">
|
|
309
|
+
${p}
|
|
310
|
+
<a id="term-modal-tab" class="card-act" href="${i(u)}" target="_blank" rel="noopener" title="${i(t("sessions.kanban.openTab"))}" aria-label="${i(t("sessions.kanban.openTab"))}">${Ie.terminal}</a>
|
|
311
|
+
<button type="button" id="term-modal-close" class="card-act" title="${i(t("sessions.dismiss"))}" aria-label="${i(t("sessions.dismiss"))}">${Ie.close}</button>
|
|
312
|
+
</span>
|
|
313
|
+
</div>
|
|
314
|
+
<div class="term-modal-body"><div class="term-modal-loading">${t("sessions.kanban.terminalLoading")}</div></div>`,w.showModal(),w.querySelector("#term-modal-close").onclick=()=>w.close(),w.querySelector("#term-modal-edit").onclick=()=>Vo(r);let g=u;if($e.authed)try{let C=await fetch(`/api/sessions/${encodeURIComponent(r.sessionId)}/write-link`),q=await C.json().catch(()=>({}));C.ok&&q?.ok!==!1&&q?.url&&(g=q.url)}catch{}if(!w.open)return;let h=w.querySelector(".term-modal-body");h.innerHTML=`<iframe class="term-modal-frame" src="${i(g)}" allow="clipboard-read; clipboard-write"></iframe>`;let S=w.querySelector("#term-modal-tab");S&&(S.href=g)}function Pt(){let r=new FormData(a),u=(r.get("q")??"").toLowerCase(),f=r.getAll("cli"),p=f.length>0&&f.length<Xa.length,g=r.get("status"),h=r.get("adopt"),S=!!r.get("active"),C=I==="kanban",q=[...V.sessions.values()].filter(N=>!p||f.includes(N.cliId??"unknown")).filter(N=>!g||N.status===g).filter(N=>!h||h==="yes"==!!N.adopt).filter(N=>!S||C||N.status!=="closed").filter(N=>!u||JSON.stringify(N).toLowerCase().includes(u));return q.sort(Qo),q}function sa(r,u){return u==="spawnedAt"||u==="lastMessageAt"?Number(r[u]??0):u==="tokenIn"?Rn(r.tokenUsage?.in)??-1:u==="tokenOut"?Rn(r.tokenUsage?.out)??-1:u==="adopt"?!!r.adopt:String(r[u]??"").toLowerCase()}function Qo(r,u){let f=sa(r,y),p=sa(u,y),g=0;return typeof f=="number"&&typeof p=="number"?g=f-p:typeof f=="boolean"&&typeof p=="boolean"?g=Number(f)-Number(p):g=String(f).localeCompare(String(p)),g===0&&(g=Number(r.lastMessageAt??0)-Number(u.lastMessageAt??0)),H==="asc"?g:-g}function Xo(){v.querySelectorAll("th[data-sort]").forEach(r=>{let u=r.dataset.sort===y;r.classList.toggle("sorted",u),r.setAttribute("aria-sort",u?H==="asc"?"ascending":"descending":"none");let f=r.dataset.label??r.textContent?.trim()??"";r.textContent=u?`${f} ${H==="asc"?"\u25B2":"\u25BC"}`:f})}function pn(r){l.hidden=d.size===0,c.textContent=t("sessions.selectedCount",{count:d.size});let u=r.filter(p=>p.status!=="closed");if(u.length===0){o.checked=!1,o.indeterminate=!1,o.disabled=!0;return}o.disabled=!1;let f=u.filter(p=>d.has(p.sessionId)).length;o.checked=f===u.length,o.indeterminate=f>0&&f<u.length}function Zo(){x.forEach(r=>{let u=r.dataset.view===I;r.classList.toggle("active",u),r.setAttribute("aria-pressed",String(u))}),D.hidden=I!=="kanban",R.hidden=!(I==="kanban"&&se==="team"),M.hidden=R.hidden||!de,D.querySelectorAll("[data-groupby]").forEach(r=>{let u=r.dataset.groupby===se;r.classList.toggle("active",u),r.setAttribute("aria-pressed",String(u))})}function es(){let r=a.querySelector("#cli-filter-count");if(!r)return;let u=[...a.querySelectorAll('input[name="cli"]')],f=u.filter(p=>p.checked).length;r.textContent=f===u.length?t("common.all"):`${f}/${u.length}`,r.classList.toggle("cli-filter-active",f!==u.length)}function Z(){let r=Pt();for(let p of[...d]){let g=V.sessions.get(p);(!g||g.status==="closed")&&d.delete(p)}let u=r.filter(p=>p.status!=="closed"),f=I==="table"?r:u;if(v.hidden=I!=="table",L.hidden=I!=="board",T.hidden=I!=="kanban",I==="table"){let p=r.length?r.map(oe).join(""):`<tr><td colspan="12" class="empty">${t("sessions.empty")}</td></tr>`;p!==G&&(G=p,n.innerHTML=p)}else I==="kanban"?z(r):U(u);Zo(),Xo(),es(),pn(f)}async function ia(r,u){u&&(u.disabled=!0,u.textContent=t("sessions.locating"));try{let f=await fetch(`/api/sessions/${encodeURIComponent(r.sessionId)}/locate`,{method:"POST"}),p=await f.json();if(p.ok){if(!u)return;let g=30;u.textContent=t("sessions.cooldown",{seconds:g});let h=setInterval(()=>{g-=1,g<=0?(clearInterval(h),u.disabled=!1,u.textContent=t("sessions.locate")):u.textContent=t("sessions.cooldown",{seconds:g})},1e3)}else alert(`Locate failed: ${p.error??f.status}`),u&&(u.disabled=!1,u.textContent=t("sessions.locate"))}catch(f){alert(`Locate error: ${f}`),u&&(u.disabled=!1,u.textContent=t("sessions.locate"))}}async function ra(r,u){if(!confirm(t("sessions.closeConfirm")))return!1;u&&(u.disabled=!0);try{let f=await fetch(`/api/sessions/${encodeURIComponent(r.sessionId)}/close`,{method:"POST"}),p=await f.json().catch(()=>({}));return!f.ok||p?.ok===!1?(f.status!==401&&alert(`Close failed: ${p?.error??f.status}`),!1):!0}catch(f){return alert(`Close error: ${f}`),!1}finally{u&&(u.disabled=!1)}}function qt(r){let u=r.status==="closed",f=An(r);s.innerHTML=`<article>
|
|
230
315
|
<header>
|
|
231
|
-
<h3>${
|
|
232
|
-
<span class="status status-${r
|
|
233
|
-
<p><code>${r
|
|
316
|
+
<h3>${i(ve(r.title)||r.sessionId)}</h3>
|
|
317
|
+
<span class="status status-${i(r.status??"unknown")}">${i(r.status??"unknown")}</span>
|
|
318
|
+
<p><code>${i(r.sessionId)}</code> <button data-copy="${i(r.sessionId)}">${t("sessions.copy")}</button></p>
|
|
234
319
|
</header>
|
|
235
|
-
<p><b>${t("sessions.bot")}:</b> ${
|
|
236
|
-
${
|
|
237
|
-
<p><b>chatId:</b> <code>${r
|
|
238
|
-
<p><b>rootMessageId:</b> <code>${r
|
|
239
|
-
${
|
|
240
|
-
<p><b>${t("sessions.workingDir")}:</b> ${r
|
|
320
|
+
<p><b>${t("sessions.bot")}:</b> ${i(ye(r))} \xB7 <b>${t("sessions.cli")}:</b> ${i(r.cliId??"?")}</p>
|
|
321
|
+
${nt(r)?`<p><b>${t("sessions.chat")}:</b> ${i(nt(r))}</p>`:""}
|
|
322
|
+
<p><b>chatId:</b> <code>${i(r.chatId??"")}</code> <button data-copy="${i(r.chatId??"")}">${t("sessions.copy")}</button></p>
|
|
323
|
+
<p><b>rootMessageId:</b> <code>${i(r.rootMessageId??"")}</code> <button data-copy="${i(r.rootMessageId??"")}">${t("sessions.copy")}</button></p>
|
|
324
|
+
${r.threadId?`<p><b>threadId:</b> <code>${i(r.threadId)}</code></p>`:""}
|
|
325
|
+
<p><b>${t("sessions.workingDir")}:</b> ${i(r.workingDir??"-")}</p>
|
|
241
326
|
<div class="actions">
|
|
242
|
-
${
|
|
243
|
-
|
|
244
|
-
${f
|
|
245
|
-
${
|
|
327
|
+
${Ue(r)??`<button id="locate-btn" type="button">${t("sessions.locate")}</button>`}
|
|
328
|
+
<button id="history-drawer-btn" type="button">${t("sessions.history.title")}</button>
|
|
329
|
+
${Va(f)}
|
|
330
|
+
${u?`<button id="resume-btn" type="button" class="primary">${t("sessions.resume")}</button>`:""}
|
|
331
|
+
${u?"":`<button id="close-btn" type="button" class="contrast">${t("sessions.close")}</button>`}
|
|
246
332
|
<button id="land-btn" type="button">${t("sessions.land")}</button>
|
|
247
333
|
</div>
|
|
248
334
|
<div id="land-area"></div>
|
|
249
335
|
<form method="dialog"><button>${t("sessions.dismiss")}</button></form>
|
|
250
|
-
</article>`,s.querySelectorAll("[data-copy]").forEach(
|
|
251
|
-
\u2026(truncated)`:"");
|
|
252
|
-
<p><b>${
|
|
253
|
-
<pre style="max-height:320px;overflow:auto;white-space:pre-wrap">${
|
|
336
|
+
</article>`,s.querySelectorAll("[data-copy]").forEach(te=>{te.onclick=()=>{navigator.clipboard.writeText(te.dataset.copy??""),te.textContent=t("sessions.copied"),setTimeout(()=>{te.textContent=t("sessions.copy")},800)}});let p=s.querySelector("#locate-btn");p&&(p.onclick=()=>{ia(r,p)});let g=s.querySelector("#history-drawer-btn");g&&(g.onclick=()=>{pe(r)});let h=s.querySelector(".term-write");h&&(h.onclick=()=>{Qa(r,h)});let S=s.querySelector("#resume-btn");S&&(S.onclick=async()=>{S.disabled=!0;try{let te=await fetch(`/api/sessions/${encodeURIComponent(r.sessionId)}/resume`,{method:"POST"}),me=await te.json().catch(()=>({}));if(!te.ok||me.ok===!1){alert(`${t("sessions.resumeFailed")}: ${me?.error??te.status}`),S.disabled=!1;return}s.close()}catch(te){alert(`${t("sessions.resumeFailed")}: ${te}`),S.disabled=!1}});let C=s.querySelector("#close-btn");C&&(C.onclick=async()=>{await ra(r,C)&&s.close()});let q=s.querySelector("#land-btn"),N=s.querySelector("#land-area");q&&N&&(q.onclick=async()=>{q.disabled=!0,N.innerHTML=`<p>${t("sessions.landLoading")}</p>`;try{let te=await fetch(`/api/sessions/${encodeURIComponent(r.sessionId)}/sandbox-diff`),me=await te.json().catch(()=>({}));if(!me.ok){N.innerHTML=`<p>${t("sessions.landUnavailable")}: ${i(me.error??String(te.status))}</p>`,q.disabled=!1;return}if(me.empty){N.innerHTML=`<p>${t("sessions.landEmpty")}</p>`,q.disabled=!1;return}let Fe=String(me.patch??""),mn=Fe.slice(0,2e4)+(Fe.length>2e4?`
|
|
337
|
+
\u2026(truncated)`:"");N.innerHTML=`
|
|
338
|
+
<p><b>${me.files}</b> files (+${me.insertions}/-${me.deletions}) \u2192 <code>${i(String(me.workingDir??""))}</code></p>
|
|
339
|
+
<pre style="max-height:320px;overflow:auto;white-space:pre-wrap">${i(mn)}</pre>
|
|
254
340
|
<div class="actions">
|
|
255
341
|
<button id="land-apply" type="button" class="primary">${t("sessions.landApply")}</button>
|
|
256
342
|
<button id="land-discard" type="button" class="contrast">${t("sessions.landDiscard")}</button>
|
|
257
|
-
</div>`;let
|
|
343
|
+
</div>`;let _e=N.querySelector("#land-apply"),jt=N.querySelector("#land-discard");_e.onclick=async()=>{_e.disabled=!0,jt.disabled=!0;let Qe=await fetch(`/api/sessions/${encodeURIComponent(r.sessionId)}/sandbox-land/apply`,{method:"POST"}),Ce=await Qe.json().catch(()=>({}));N.innerHTML=Ce.ok?`<p>\u2705 ${t("sessions.landApplied")}: ${Ce.files} files (+${Ce.insertions}/-${Ce.deletions}) \u2192 <code>${i(String(Ce.workingDir??""))}</code></p>`:`<p>\u274C ${t("sessions.landFailed")}: ${i(Ce.error??String(Qe.status))}</p>`},jt.onclick=async()=>{await fetch(`/api/sessions/${encodeURIComponent(r.sessionId)}/sandbox-land/discard`,{method:"POST"}),N.innerHTML=`<p>\u{1F5D1} ${t("sessions.landDiscarded")}</p>`}}catch(te){N.innerHTML=`<p>${t("sessions.landUnavailable")}: ${i(String(te))}</p>`,q.disabled=!1}}),s.showModal()}n.addEventListener("click",r=>{let u=r.target;if(u.classList.contains("row-select")){let h=u.closest("tr[data-id]");if(!h)return;u.checked?d.add(h.dataset.id):d.delete(h.dataset.id),pn(Pt());return}let f=u.closest("td");if(f&&f.querySelector(".row-select"))return;let p=u.closest("tr[data-id]");if(!p)return;let g=V.sessions.get(p.dataset.id);g&&qt(g)}),L.addEventListener("click",r=>{let u=r.target,f=u.closest("button[data-move-col]");if(f){Ye(f.dataset.moveCol,Number(f.dataset.dir));return}let p=u.closest(".session-card[data-id]");if(!p)return;let g=V.sessions.get(p.dataset.id);if(!g)return;let h=u.closest("button[data-action]");if(h){let S=h.dataset.action;S==="details"?qt(g):S==="write-link"?Qa(g,h):S==="locate"?ia(g,h):S==="close"&&ra(g,h).then(C=>{C&&(d.delete(g.sessionId),Z())});return}u.closest("a, button, input, label")||(d.has(g.sessionId)?d.delete(g.sessionId):d.add(g.sessionId),p.classList.toggle("selected",d.has(g.sessionId)),p.setAttribute("aria-pressed",String(d.has(g.sessionId))),pn(Pt().filter(S=>S.status!=="closed")))}),L.addEventListener("dragstart",r=>{let f=r.target.closest(".session-board-column > header[draggable]")?.closest(".session-board-column");f?.dataset.col&&(A=f.dataset.col,f.classList.add("dragging"),r.dataTransfer&&(r.dataTransfer.effectAllowed="move",r.dataTransfer.setData("text/plain",A)))}),L.addEventListener("dragover",r=>{if(!A)return;r.preventDefault(),r.dataTransfer&&(r.dataTransfer.dropEffect="move");let u=r.target.closest(".session-board-column");L.querySelectorAll(".drag-over").forEach(f=>f.classList.remove("drag-over")),u&&u.dataset.col!==A&&u.classList.add("drag-over")}),L.addEventListener("drop",r=>{if(!A)return;r.preventDefault();let u=r.target.closest(".session-board-column"),f=A;A=null,u?.dataset.col&&Ve(f,u.dataset.col)}),L.addEventListener("dragend",()=>{A=null,L.querySelectorAll(".drag-over, .dragging").forEach(r=>r.classList.remove("drag-over","dragging"))}),x.forEach(r=>{r.addEventListener("click",()=>{let u=wn(r.dataset.view)??"board";u!==I&&(I=u,ya(window.localStorage,I),Z())})}),D.querySelectorAll("[data-groupby]").forEach(r=>{r.addEventListener("click",()=>{let u=r.dataset.groupby,f=u==="bot"?"bot":u==="team"?"team":"flow";f!==se&&(se=f,$a(window.localStorage,f),j="",Z())})}),R.addEventListener("change",()=>{ke=R.value;try{window.localStorage.setItem(vn,ke)}catch{}j="",Z()});function Ut(){ge!==null&&(clearTimeout(ge),ge=null)}T.addEventListener("click",r=>{let u=r.target,f=u.closest(".kanban-card[data-id]");if(!f)return;let p=V.sessions.get(f.dataset.id);if(!p)return;let g=u.closest("button[data-action]");if(g){g.dataset.action==="details"?qt(p):g.dataset.action==="rename"?Te(f,p):g.dataset.action==="history"&&pe(p);return}u.closest("a, button, input, label")||(Ut(),ge=setTimeout(()=>{ge=null,oa(p)},220))}),T.addEventListener("dblclick",r=>{let u=r.target,f=u.closest(".kanban-card-title"),p=u.closest(".kanban-card[data-id]");if(!f||!p)return;Ut();let g=V.sessions.get(p.dataset.id);g&&Te(p,g)}),T.addEventListener("keydown",r=>{if(r.key!=="Enter"&&r.key!==" ")return;let u=r.target;if(!u.classList?.contains("kanban-card"))return;r.preventDefault();let f=V.sessions.get(u.dataset.id);f&&oa(f)}),T.addEventListener("dragstart",r=>{if(se==="bot")return;let u=r.target,f=u.closest(".kanban-cluster > header[draggable]");if(f){let g=f.closest(".kanban-cluster"),h=g.closest(".kanban-column")?.dataset.col;if(!g.dataset.chat||!h)return;Ut(),Se=g.dataset.chat,Re=h,g.classList.add("dragging"),r.dataTransfer&&(r.dataTransfer.effectAllowed="move",r.dataTransfer.setData("text/plain",`cluster:${Se}`));return}let p=u.closest(".kanban-card[data-id]");p&&(Ut(),le=p.dataset.id,p.classList.add("dragging"),r.dataTransfer&&(r.dataTransfer.effectAllowed="move",r.dataTransfer.setData("text/plain",le)))}),T.addEventListener("dragover",r=>{if(!le&&!Se)return;r.preventDefault(),r.dataTransfer&&(r.dataTransfer.dropEffect="move");let u=r.target.closest(".kanban-column");T.querySelectorAll(".drag-over").forEach(f=>f.classList.remove("drag-over")),T.querySelectorAll(".drop-before").forEach(f=>f.classList.remove("drop-before")),u&&(u.classList.add("drag-over"),tt(u,r.clientY)?.classList.add("drop-before"))}),T.addEventListener("drop",r=>{let u=Se,f=Re,p=le;if(!p&&!u)return;r.preventDefault(),le=null,Se=null,Re=null,aa();let g=r.target.closest(".kanban-column"),h=g?.dataset.col;if(!g||!h)return;let S=tt(g,r.clientY);if(u&&f){let _e=(J.get(f)??[]).filter(we=>String(we.chatId)===u).filter(we=>!(we.status==="closed"&&h!=="done"));if(!_e.length)return;let jt=new Set(_e.map(we=>we.sessionId)),Qe=(J.get(h)??[]).filter(we=>!jt.has(we.sessionId)),Ce=S?Qe.findIndex(we=>we.sessionId===S.dataset.id):Qe.length;Ce<0&&(Ce=Qe.length);let la=Ce>0?Qe[Ce-1]:null,da=Ce<Qe.length?Qe[Ce]:null,ns=Hn(la?rt(la):null,da?rt(da):null);_e.forEach((we,as)=>{let fn=ns+as*.001;if(se==="team")ft(String(we.sessionId),h,fn);else{let os={column:we.kanbanColumn,position:we.kanbanPosition};we.kanbanColumn=h,we.kanbanPosition=fn,F(we,h,fn,os)}}),j="",Z();return}let C=V.sessions.get(p)??je.get(p);if(!C||C.status==="closed"&&h!=="done")return;let q=(J.get(h)??[]).filter(_e=>_e.sessionId!==p),N=S?q.findIndex(_e=>_e.sessionId===S.dataset.id):q.length;N<0&&(N=q.length);let te=N>0?q[N-1]:null,me=N<q.length?q[N]:null,Fe=Hn(te?rt(te):null,me?rt(me):null);if(se==="team"){ft(String(C.sessionId),h,Fe),j="",Z();return}let mn={column:C.kanbanColumn,position:C.kanbanPosition};C.kanbanColumn=h,C.kanbanPosition=Fe,j="",Z(),F(C,h,Fe,mn)}),T.addEventListener("dragend",()=>{le=null,Se=null,Re=null,aa(),j="",Z()}),w.addEventListener("click",r=>{r.target===w&&w.close()}),w.addEventListener("close",()=>{w.innerHTML=""}),O.addEventListener("click",r=>{r.target===O&&O.close()}),O.addEventListener("close",()=>{O.innerHTML=""}),o.addEventListener("change",()=>{let r=Pt().filter(u=>u.status!=="closed");for(let u of r)o.checked?d.add(u.sessionId):d.delete(u.sessionId);Z()}),k.addEventListener("click",()=>{d.clear(),Z()}),m.addEventListener("click",async()=>{let r=[...d];if(r.length===0||!confirm(t("sessions.closeBulkConfirm",{count:r.length})))return;m.disabled=!0,k.disabled=!0;let u=m.textContent,f=0,p=0,g=[...r];m.textContent=`0/${r.length}`;async function h(){for(;g.length;){let S=g.shift();try{let C=await fetch(`/api/sessions/${encodeURIComponent(S)}/close`,{method:"POST"}),q=await C.json().catch(()=>({}));(!C.ok||q?.ok===!1)&&(p+=1)}catch{p+=1}finally{f+=1,m.textContent=`${f}/${r.length}`}}}await Promise.all(Array.from({length:Math.min(6,r.length)},()=>h())),m.textContent=u,m.disabled=!1,k.disabled=!1,d.clear(),Z(),p>0&&alert(`Failed: ${p}/${r.length}`)}),v.querySelectorAll("th[data-sort]").forEach(r=>{r.addEventListener("click",()=>{let u=r.dataset.sort;y===u?H=H==="asc"?"desc":"asc":(y=u,H=u==="spawnedAt"||u==="lastMessageAt"?"desc":"asc"),Z()})}),a.addEventListener("input",Z),V.on(Z);let ts=setInterval(()=>{if(!document.body.contains(T)){clearInterval(ts);return}I==="kanban"&&se==="team"&&(j="",Z())},3e4);Z(),Ge().then(Z)}function Qs(){return`<section class="page">
|
|
258
344
|
<div class="page-heading">
|
|
259
345
|
<div>
|
|
260
346
|
<p class="eyebrow">${t("nav.schedules")}</p>
|
|
@@ -279,19 +365,19 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
279
365
|
</tr></thead>
|
|
280
366
|
<tbody id="schedules-tbody"></tbody>
|
|
281
367
|
</table>
|
|
282
|
-
</section>`}function
|
|
283
|
-
<td>${
|
|
284
|
-
<td>${
|
|
285
|
-
<td><code>${
|
|
286
|
-
<td>${
|
|
287
|
-
<td>${
|
|
288
|
-
<td>${
|
|
289
|
-
<td>${
|
|
368
|
+
</section>`}function eo(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function to(e){e.innerHTML=Qs();let n=e.querySelector("#schedules-tbody"),a=e.querySelector("#sched-filters");function s(){let l=new FormData(a),c=(l.get("q")??"").toLowerCase(),m=l.get("kind"),k=!!l.get("enabled");return[...V.schedules.values()].filter(v=>!m||v.parsed?.kind===m).filter(v=>!k||v.enabled).filter(v=>!c||JSON.stringify(v).toLowerCase().includes(c)).sort((v,L)=>{if(v.enabled!==L.enabled)return v.enabled?-1:1;let T=v.nextRunAt?Date.parse(v.nextRunAt):1/0,w=L.nextRunAt?Date.parse(L.nextRunAt):1/0;return T-w})}function o(){n.innerHTML=s().map(l=>`<tr data-id="${i(l.id)}">
|
|
369
|
+
<td>${i(l.name??l.id)}</td>
|
|
370
|
+
<td>${i(l.botName??l.larkAppId??"-")}</td>
|
|
371
|
+
<td><code>${i(l.parsed?.display??"?")}</code></td>
|
|
372
|
+
<td>${eo(l.nextRunAt)}</td>
|
|
373
|
+
<td>${eo(l.lastRunAt)} ${l.lastStatus==="error"?"\u26A0\uFE0F":""}</td>
|
|
374
|
+
<td>${l.repeat?`${l.repeat.completed}/${l.repeat.times??"\u221E"}`:"\u2014"}</td>
|
|
375
|
+
<td>${l.enabled?"\u2713":"\u2717"}</td>
|
|
290
376
|
<td class="actions-cell">
|
|
291
377
|
<button data-op="run" type="button">${t("schedules.runNow")}</button>
|
|
292
|
-
${
|
|
378
|
+
${l.enabled?`<button data-op="pause" type="button">${t("schedules.pause")}</button>`:`<button data-op="resume" type="button">${t("schedules.resume")}</button>`}
|
|
293
379
|
</td>
|
|
294
|
-
</tr>`).join("")||`<tr><td colspan="8" class="empty">${t("schedules.empty")}</td></tr>`}n.addEventListener("click",async
|
|
380
|
+
</tr>`).join("")||`<tr><td colspan="8" class="empty">${t("schedules.empty")}</td></tr>`}n.addEventListener("click",async l=>{let c=l.target.closest("button[data-op]");if(!c)return;let m=c.closest("tr[data-id]");if(!m)return;let k=m.dataset.id,v=c.dataset.op;c.disabled=!0;let L=c.textContent;c.textContent="...";try{let T=await fetch(`/api/schedules/${encodeURIComponent(k)}/${v}`,{method:"POST"}),w=await T.json().catch(()=>({}));(!T.ok||w.ok===!1)&&alert(`Failed: ${T.status} ${w?.error??""}`.trim())}catch(T){alert("Network error: "+T)}finally{c.disabled=!1,c.textContent=L}}),a.addEventListener("input",o),V.on(o),o()}var Me={chats:[],bots:[]};function Xs(){return`<section class="page">
|
|
295
381
|
<div class="page-heading">
|
|
296
382
|
<div>
|
|
297
383
|
<p class="eyebrow">${t("nav.groups")}</p>
|
|
@@ -305,7 +391,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
305
391
|
<button type="button" id="g-refresh">${t("groups.refresh")}</button>
|
|
306
392
|
<button type="button" id="g-create" class="primary">${t("groups.create")}</button>
|
|
307
393
|
</form>
|
|
308
|
-
<div id="g-loading">${
|
|
394
|
+
<div id="g-loading">${wt()}</div>
|
|
309
395
|
<div class="table-scroll matrix-scroll" id="g-table-wrap" hidden>
|
|
310
396
|
<table>
|
|
311
397
|
<thead id="g-head"></thead>
|
|
@@ -313,12 +399,12 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
313
399
|
</table>
|
|
314
400
|
</div>
|
|
315
401
|
<dialog id="g-drawer"></dialog>
|
|
316
|
-
</section>`}async function
|
|
402
|
+
</section>`}async function yt(){Me=await(await fetch("/api/groups")).json()}async function Zs(){return(await fetch("/api/groups")).json()}function ei(e,n){if(n.size===0)return!0;let a=e?.memberBots??[];for(let s of n)if(!a.some(o=>o.larkAppId===s&&o.inChat))return!1;return!0}function no(e,n){return e.filter(a=>!n||!n.has(a.larkAppId)).map(a=>`
|
|
317
403
|
<label class="checkbox-row">
|
|
318
|
-
<input type="checkbox" name="bot" value="${
|
|
319
|
-
${
|
|
404
|
+
<input type="checkbox" name="bot" value="${i(a.larkAppId)}">
|
|
405
|
+
${i(a.botName??a.larkAppId)} <small>(${i(a.larkAppId)})</small>
|
|
320
406
|
</label>
|
|
321
|
-
`).join("")}async function
|
|
407
|
+
`).join("")}async function ao(e){e.innerHTML=Xs();let n=e.querySelector("#g-head"),a=e.querySelector("#g-body"),s=e.querySelector("#g-filters"),o=e.querySelector("#g-refresh"),l=e.querySelector("#g-drawer");o.onclick=async()=>{o.disabled=!0;try{await yt(),w()}finally{o.disabled=!1}};let c=e.querySelector("#g-create");c.onclick=()=>v();let m=e.querySelector("#g-loading"),k=e.querySelector("#g-table-wrap");try{await yt()}finally{m.remove(),k.hidden=!1}function v(){let D=Me.bots;if(D.length===0){alert(t("groups.noBotsOnline"));return}l.innerHTML=`
|
|
322
408
|
<article>
|
|
323
409
|
<header><h3>${t("groups.createTitle")}</h3></header>
|
|
324
410
|
<p>${t("groups.createHelp")}</p>
|
|
@@ -334,75 +420,75 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
334
420
|
</label>
|
|
335
421
|
<fieldset>
|
|
336
422
|
<legend>${t("groups.botPicker")}</legend>
|
|
337
|
-
${
|
|
423
|
+
${no(D)}
|
|
338
424
|
</fieldset>
|
|
339
425
|
<div class="actions">
|
|
340
426
|
<button type="submit" class="primary">${t("groups.createSubmit")}</button>
|
|
341
427
|
<button type="button" id="g-create-cancel">${t("groups.cancel")}</button>
|
|
342
428
|
</div>
|
|
343
429
|
</form>
|
|
344
|
-
</article>`,
|
|
430
|
+
</article>`,l.showModal(),l.querySelector("#g-create-cancel").onclick=()=>l.close(),l.querySelector("#g-createform").onsubmit=async x=>{x.preventDefault();let d=new FormData(x.target),y=(d.get("name")??"").trim(),H=(d.get("bindWorkingDir")??"").trim(),I=d.getAll("bot");if(I.length===0){alert("Pick at least one bot.");return}let $=x.target.querySelector("button[type=submit]");$&&($.disabled=!0,$.textContent="Creating...");try{let A=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:y||void 0,larkAppIds:I,bindWorkingDir:H||void 0})}),B=await A.json();if(B.ok&&B.chatId){L(B);let G=Array.isArray(B.invalidBotIds)?B.invalidBotIds:[],j=I.filter(le=>!G.includes(le)),Q=new Set(j);typeof B.creator=="string"&&B.creator&&Q.add(B.creator),R(B.chatId,y||B.chatId,j,B.creator),w(),M(B.chatId,Q).catch(()=>{})}else alert(`Failed: ${B.error??A.status}`),l.close()}catch(A){alert("Network error: "+A),l.close()}};function R(x,d,y,H){let I=new Set(y);H&&I.add(H);let $=Me.bots.map(B=>({larkAppId:B.larkAppId,botName:B.botName,inChat:I.has(B.larkAppId),oncallChat:null})),A={chatId:x,name:d,ownerId:H??null,memberBots:$};Me.chats=[A,...Me.chats.filter(B=>B.chatId!==x)]}async function M(x,d){let y=[600,1200,1200,1200,1200,1200];for(let H of y){await new Promise(A=>setTimeout(A,H));let I;try{I=await Zs()}catch{continue}let $=(I.chats??[]).find(A=>A.chatId===x);if($&&ei($,d)){Me=I,w();return}}}}function L(D){let R=String(D.chatId),M=typeof D.shareLink=="string"&&D.shareLink?D.shareLink:`https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(R)}`,x=D.invalidBotIds??[],d=D.invalidUserIds??[],y=D.autoInvitedOpenId,H=!!D.autoInviteRejected,I=D.ownerTransferredTo,$=D.transferError,A=D.notifyMessageId,B=D.notifyError,G=Array.isArray(D.oncallBindings)?D.oncallBindings:[],j=G.filter(J=>J?.ok).length,Q=G.filter(J=>!J?.ok),le=G.length>0?Q.length===0?`<p class="hint-ok">\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1A<code>${i(D.bindResolvedPath??"")}</code>\uFF08${j}/${G.length} bots\uFF09</p>`:`<p class="hint-warn">\u76EE\u5F55\u7ED1\u5B9A\u90E8\u5206\u5931\u8D25\uFF1A\u6210\u529F ${j}/${G.length}\u3002${Q.map(J=>`<br><code>${i(J.larkAppId??"?")}</code>: ${i(J.error??"unknown")}`).join("")}</p>`:"",Ee;if(y){let J=I?"<br><small>\u7FA4\u4E3B\u5DF2\u4ECE\u673A\u5668\u4EBA\u8F6C\u8BA9\u7ED9\u4F60\u3002</small>":$?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08${i($)}\uFF09\uFF0C\u4F60\u73B0\u5728\u662F\u6210\u5458\u4F46\u7FA4\u4E3B\u4ECD\u662F\u673A\u5668\u4EBA\u3002</small>`:"",se=A?`<br><small>\u673A\u5668\u4EBA\u5DF2\u5728\u7FA4\u91CC @ \u4E86\u4F60\uFF08\u6D88\u606F id <code>${i(A)}</code>\uFF09\uFF0C\u770B\u98DE\u4E66\u901A\u77E5\u5C31\u80FD\u8FDB\u7FA4\u3002</small>`:B?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8 @ \u901A\u77E5\u5931\u8D25\uFF08${i(B)}\uFF09\uFF0C\u65B0\u7FA4\u53EF\u80FD\u4E0D\u4F1A\u4E3B\u52A8\u51FA\u73B0\u5728\u4F60\u4FA7\u8FB9\u680F\uFF0C\u5EFA\u8BAE\u4ECE\u4E0B\u9762\u6309\u94AE\u8DF3\u8FDB\u53BB\u3002</small>`:"";Ee=`<p class="hint-ok">\u5DF2\u81EA\u52A8\u9080\u8BF7\u4F60\uFF08<code>${i(y)}</code>\uFF09\u4F5C\u4E3A\u6210\u5458\u3002${J}${se}</p>`}else H?Ee='<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>':Ee='<p class="hint-warn">\u6CA1\u5728 dashboard \u7F13\u5B58\u91CC\u627E\u5230 ownerOpenId\uFF0C<strong>\u6CA1\u6709\u81EA\u52A8\u9080\u8BF7\u4F60</strong>\u3002\u70B9\u5F00\u4E0B\u9762\u94FE\u63A5\u524D\uFF0C\u5148\u8BA9\u7FA4\u91CC\u4EFB\u4E00\u673A\u5668\u4EBA\u624B\u52A8\u628A\u4F60\u52A0\u8FDB\u53BB\u3002</p>';let ge=[x.length?`<li>\u65E0\u6548 bot id: <code>${x.map(i).join(", ")}</code></li>`:"",d.length?`<li>\u65E0\u6548\u7528\u6237 open_id: <code>${d.map(i).join(", ")}</code></li>`:""].filter(Boolean).join("");l.innerHTML=`
|
|
345
431
|
<article>
|
|
346
432
|
<header><h3>${t("groups.successTitle")}</h3></header>
|
|
347
|
-
<p><b>chatId:</b> <code>${
|
|
348
|
-
<p><b>\u521B\u5EFA\u8005:</b> <code>${
|
|
349
|
-
${
|
|
350
|
-
${
|
|
351
|
-
${
|
|
433
|
+
<p><b>chatId:</b> <code>${i(R)}</code> <button type="button" data-copy="${i(R)}">${t("sessions.copy")}</button></p>
|
|
434
|
+
<p><b>\u521B\u5EFA\u8005:</b> <code>${i(D.creator??"?")}</code></p>
|
|
435
|
+
${Ee}
|
|
436
|
+
${le}
|
|
437
|
+
${ge?`<ul>${ge}</ul>`:""}
|
|
352
438
|
<div class="actions">
|
|
353
|
-
<a class="btn-link primary" href="${
|
|
439
|
+
<a class="btn-link primary" href="${M}" target="_blank" rel="noopener">${t("groups.openGroup")}</a>
|
|
354
440
|
<button type="button" id="g-create-close">${t("sessions.dismiss")}</button>
|
|
355
441
|
</div>
|
|
356
|
-
</article>`,
|
|
442
|
+
</article>`,l.querySelectorAll("[data-copy]").forEach(J=>{J.onclick=()=>{navigator.clipboard.writeText(J.dataset.copy??""),J.textContent=t("sessions.copied"),setTimeout(()=>{J.textContent=t("sessions.copy")},800)}}),l.querySelector("#g-create-close").onclick=()=>l.close()}function T(){n.innerHTML=`<tr>
|
|
357
443
|
<th>${t("groups.chat")}</th>
|
|
358
|
-
${
|
|
444
|
+
${Me.bots.map(D=>`<th>${i(D.botName??D.larkAppId)}</th>`).join("")}
|
|
359
445
|
<th>${t("groups.actions")}</th>
|
|
360
|
-
</tr>`}function
|
|
446
|
+
</tr>`}function w(){T();let D=new FormData(s),R=(D.get("q")??"").toLowerCase(),M=!!D.get("missing"),x=Me.chats.filter(d=>!R||(d.name??"").toLowerCase().includes(R)||d.chatId.toLowerCase().includes(R)||(d.ownerId??"").toLowerCase().includes(R)).filter(d=>!M||d.memberBots.some(y=>!y.inChat));if(x.length===0){a.innerHTML=`<tr><td colspan="${Me.bots.length+2}" class="empty">${t("groups.empty")}</td></tr>`;return}a.innerHTML=x.map(d=>`<tr data-chat="${i(d.chatId)}">
|
|
361
447
|
<td>
|
|
362
448
|
<div class="g-chat-cell">
|
|
363
|
-
${
|
|
449
|
+
${Yt({chatId:d.chatId,name:d.name,avatarUrl:d.avatar,size:"sm"})}
|
|
364
450
|
<div class="g-chat-meta">
|
|
365
|
-
<strong>${
|
|
366
|
-
<small><code>${
|
|
451
|
+
<strong>${i(d.name??d.chatId)}</strong><br>
|
|
452
|
+
<small><code>${i(d.chatId)}</code></small>
|
|
367
453
|
</div>
|
|
368
454
|
</div>
|
|
369
455
|
</td>
|
|
370
|
-
${
|
|
456
|
+
${Me.bots.map(y=>{let H=d.memberBots.find(A=>A.larkAppId===y.larkAppId),I=H?H.error?"!":H.inChat?"\u2713":"\u2717":"?";return`<td class="${H?H.error?"cell-error":H.inChat?"cell-in":"cell-out":"cell-unknown"}" title="${i(H?.error??"")}">${I}</td>`}).join("")}
|
|
371
457
|
<td>
|
|
372
458
|
<button class="add-bots" type="button">${t("groups.addBots")}</button>
|
|
373
459
|
<button class="manage-chat" type="button">${t("groups.manage")}</button>
|
|
374
460
|
</td>
|
|
375
|
-
</tr>`).join("")}
|
|
461
|
+
</tr>`).join("")}w(),a.addEventListener("click",async D=>{let R=D.target.closest("button.add-bots");if(!R)return;let x=R.closest("tr[data-chat]").dataset.chat,d=Me.chats.find(I=>I.chatId===x);if(!d)return;let y=new Set(d.memberBots.filter(I=>I.inChat).map(I=>I.larkAppId));if(!Me.bots.filter(I=>!y.has(I.larkAppId)).length){alert("All configured bots are already in this chat.");return}l.innerHTML=`
|
|
376
462
|
<article>
|
|
377
|
-
<header><h3>${t("groups.addBots")} \xB7 ${
|
|
463
|
+
<header><h3>${t("groups.addBots")} \xB7 ${i(d.name??d.chatId)}</h3></header>
|
|
378
464
|
<p>${t("groups.createHelp")}</p>
|
|
379
465
|
<form id="g-addform">
|
|
380
|
-
${
|
|
466
|
+
${no(Me.bots,y)}
|
|
381
467
|
<div class="actions">
|
|
382
468
|
<button type="submit" class="primary">${t("groups.addBots")}</button>
|
|
383
469
|
<button type="button" id="g-cancel">${t("groups.cancel")}</button>
|
|
384
470
|
</div>
|
|
385
471
|
</form>
|
|
386
|
-
</article>`,
|
|
387
|
-
`);alert(
|
|
472
|
+
</article>`,l.showModal(),l.querySelector("#g-cancel").onclick=()=>l.close(),l.querySelector("#g-addform").onsubmit=async I=>{I.preventDefault();let A=new FormData(I.target).getAll("bot");if(A.length===0){alert("Pick at least one bot.");return}try{let G=await(await fetch(`/api/groups/${encodeURIComponent(x)}/add-bots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:A})})).json();if(G.error==="no_proxy_bot")alert("No bot is currently in this chat \u2014 add one manually in Feishu first, then retry.");else if(G.result){let j=G.result.map(Q=>`${Q.id}: ${Q.ok?"OK":`failed (${Q.error??"unknown"})`}`).join(`
|
|
473
|
+
`);alert(j),await yt(),w()}else alert(`Unexpected response: ${JSON.stringify(G)}`)}catch(B){alert("Network error: "+B)}finally{l.close()}}}),a.addEventListener("click",async D=>{let R=D.target.closest("button.manage-chat");if(!R)return;let x=R.closest("tr[data-chat]").dataset.chat,d=Me.chats.find(y=>y.chatId===x);d&&O(d)});function O(D){let R=D.memberBots.filter(x=>x.inChat),M=typeof D.ownerId=="string"?D.ownerId:"";l.innerHTML=`
|
|
388
474
|
<article>
|
|
389
|
-
<header><h3>${t("groups.manageTitle",{name:
|
|
390
|
-
<p><b>chatId:</b> <code>${
|
|
391
|
-
<p><b>${t("groups.owner")}:</b> <code>${
|
|
475
|
+
<header><h3>${t("groups.manageTitle",{name:D.name??D.chatId})}</h3></header>
|
|
476
|
+
<p><b>chatId:</b> <code>${i(D.chatId)}</code></p>
|
|
477
|
+
<p><b>${t("groups.owner")}:</b> <code>${i(D.ownerId??t("common.unknown"))}</code></p>
|
|
392
478
|
|
|
393
479
|
<fieldset>
|
|
394
480
|
<legend>${t("groups.oncall")}</legend>
|
|
395
481
|
<p><small>${t("groups.oncallHelp")}</small></p>
|
|
396
|
-
${
|
|
397
|
-
<div class="oncall-row" data-bot="${
|
|
482
|
+
${R.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':R.map(x=>{let d=!!x.oncallChat,y=x.oncallChat?.workingDir??"";return`
|
|
483
|
+
<div class="oncall-row" data-bot="${i(x.larkAppId)}">
|
|
398
484
|
<label class="checkbox-row">
|
|
399
485
|
<input type="checkbox" data-action="toggle" ${d?"checked":""}>
|
|
400
|
-
<strong>${
|
|
401
|
-
<small>(${
|
|
486
|
+
<strong>${i(x.botName??x.larkAppId)}</strong>
|
|
487
|
+
<small>(${i(x.larkAppId)})</small>
|
|
402
488
|
</label>
|
|
403
489
|
<div class="oncall-row-body">
|
|
404
490
|
<input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
|
|
405
|
-
value="${
|
|
491
|
+
value="${i(y)}" ${d?"":"disabled"}>
|
|
406
492
|
<button type="button" data-action="save">${t("groups.save")}</button>
|
|
407
493
|
<span class="oncall-status" data-status></span>
|
|
408
494
|
</div>
|
|
@@ -412,29 +498,29 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
412
498
|
|
|
413
499
|
<fieldset>
|
|
414
500
|
<legend>${t("groups.leaveTitle")}</legend>
|
|
415
|
-
${
|
|
501
|
+
${R.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':R.map(x=>`
|
|
416
502
|
<label class="checkbox-row">
|
|
417
|
-
<input type="checkbox" name="leave-bot" value="${
|
|
418
|
-
${
|
|
419
|
-
<small>${
|
|
503
|
+
<input type="checkbox" name="leave-bot" value="${i(x.larkAppId)}">
|
|
504
|
+
${i(x.botName??x.larkAppId)}
|
|
505
|
+
<small>${x.larkAppId===M?"\xB7 \u7FA4\u4E3B":""}</small>
|
|
420
506
|
</label>
|
|
421
507
|
`).join("")}
|
|
422
508
|
</fieldset>
|
|
423
509
|
|
|
424
510
|
<div class="actions">
|
|
425
|
-
<button id="g-leave-btn" type="button" ${
|
|
426
|
-
<button id="g-disband-btn" type="button" class="contrast" ${
|
|
511
|
+
<button id="g-leave-btn" type="button" ${R.length===0?"disabled":""}>${t("groups.leaveSelected")}</button>
|
|
512
|
+
<button id="g-disband-btn" type="button" class="contrast" ${R.length===0?"disabled":""}>${t("groups.disband")}</button>
|
|
427
513
|
</div>
|
|
428
514
|
<p class="hint-warn"><small>${t("groups.dangerHint")}</small></p>
|
|
429
515
|
<form method="dialog"><button>${t("sessions.dismiss")}</button></form>
|
|
430
|
-
</article>`,
|
|
431
|
-
`);alert(
|
|
432
|
-
\u5173\u95ED\u4E86 ${
|
|
433
|
-
\u5173\u95ED\u4E86 ${
|
|
516
|
+
</article>`,l.showModal(),l.querySelectorAll(".oncall-row").forEach(x=>{let d=x.dataset.bot,y=x.querySelector("input[data-action=toggle]"),H=x.querySelector("input[data-input=workingDir]"),I=x.querySelector("button[data-action=save]"),$=x.querySelector("[data-status]");y.addEventListener("change",()=>{H.disabled=!y.checked,y.checked&&H.focus()}),I.addEventListener("click",async()=>{$.textContent="",$.className="oncall-status";let A=y.checked,B=H.value.trim();if(A&&!B){$.textContent=t("groups.needWorkingDir"),$.classList.add("hint-warn-inline");return}I.disabled=!0;try{let G=`/api/groups/${encodeURIComponent(D.chatId)}/oncall/${encodeURIComponent(d)}`,j=A?await fetch(G,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({workingDir:B})}):await fetch(G,{method:"DELETE"}),Q=await j.json().catch(()=>({}));if(j.ok&&Q.ok){$.textContent=A?`\u2713 \u5DF2\u7ED1\u5B9A \u2192 ${Q.resolvedPath??B}`:"\u2713 \u5DF2\u89E3\u7ED1",$.classList.add("hint-ok");try{await yt(),w()}catch{}}else $.textContent=`\u2717 ${Q.error??j.status}`,$.classList.add("hint-warn-inline")}catch(G){$.textContent=`\u2717 ${G?.message??G}`,$.classList.add("hint-warn-inline")}finally{I.disabled=!1}})}),l.querySelector("#g-leave-btn").onclick=async()=>{let x=[...l.querySelectorAll("input[name=leave-bot]:checked")].map(d=>d.value);if(x.length===0){alert("\u81F3\u5C11\u9009\u4E00\u4E2A\u673A\u5668\u4EBA");return}if(confirm(`\u786E\u5B9A\u8BA9 ${x.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 y=await(await fetch(`/api/groups/${encodeURIComponent(D.chatId)}/leave`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:x})})).json(),H=(y.result??[]).map(I=>{if(!I.ok)return`${I.larkAppId}: \u5931\u8D25 (${I.error??"unknown"})`;let $=I.closedSessions??[],A=$.filter(j=>!j.ok).length,B=$.length-A,G=$.length===0?"":A===0?`\uFF08\u5173\u95ED ${B} \u4E2A\u4F1A\u8BDD\uFF09`:`\uFF08\u5173\u95ED ${B} \u4E2A\uFF0C${A} \u4E2A\u5931\u8D25\uFF09`;return`${I.larkAppId}: OK${G}`}).join(`
|
|
517
|
+
`);alert(H||`Unexpected: ${JSON.stringify(y)}`),await yt(),w()}catch(d){alert("Network error: "+d)}finally{l.close()}},l.querySelector("#g-disband-btn").onclick=async()=>{if(R.length===0||!confirm(`\u786E\u5B9A\u89E3\u6563\u7FA4\u804A\u300C${D.name??D.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 x=[...R].sort((y,H)=>(H.larkAppId===M?1:0)-(y.larkAppId===M?1:0)),d=[];for(let y of x)try{let H=await fetch(`/api/groups/${encodeURIComponent(D.chatId)}/disband`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppId:y.larkAppId})}),I=await H.json();if(I.ok){let $=I.closedSessions??[],A=$.filter(j=>!j.ok).length,B=$.length-A,G=$.length===0?"":A===0?`
|
|
518
|
+
\u5173\u95ED\u4E86 ${B} \u4E2A\u4F1A\u8BDD\u3002`:`
|
|
519
|
+
\u5173\u95ED\u4E86 ${B} \u4E2A\u4F1A\u8BDD\uFF0C${A} \u4E2A\u4F1A\u8BDD\u5173\u95ED\u5931\u8D25\u3002`;alert(`\u5DF2\u89E3\u6563\uFF08\u7531 ${y.botName??y.larkAppId} \u6267\u884C\uFF09${G}`),await yt(),w(),l.close();return}d.push(`${y.botName??y.larkAppId}: ${I.error??H.status}`)}catch(H){d.push(`${y.botName??y.larkAppId}: ${H}`)}alert(`\u6240\u6709\u5728\u7FA4\u673A\u5668\u4EBA\u5747\u65E0\u6CD5\u89E3\u6563\uFF1A
|
|
434
520
|
${d.join(`
|
|
435
521
|
`)}
|
|
436
522
|
|
|
437
|
-
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",
|
|
523
|
+
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",w)}var Ne={bots:[]},kt=null,vt=null;function oo(e){let n=null;for(let a of V.sessions.values())a.larkAppId!==e||!a.cliId||(!n||Number(a.lastMessageAt??0)>Number(n.lastMessageAt??0))&&(n=a);return n?.cliId??""}function ti(){return`<section class="page">
|
|
438
524
|
<div class="page-heading">
|
|
439
525
|
<div>
|
|
440
526
|
<p class="eyebrow">${t("nav.botDefaults")}</p>
|
|
@@ -450,31 +536,31 @@ ${d.join(`
|
|
|
450
536
|
<aside id="bd-roster" class="bd-roster"></aside>
|
|
451
537
|
<div id="bd-list" class="bd-detail"></div>
|
|
452
538
|
</div>
|
|
453
|
-
</section>`}async function
|
|
454
|
-
${
|
|
539
|
+
</section>`}async function so(){try{let e=await fetch("/api/bots"),n=await e.json().catch(()=>({}));if(!e.ok){kt=n?.error?`HTTP ${e.status}: ${n.error}${n.path?` (${n.path})`:""}`:`HTTP ${e.status}`,Ne={bots:[]};return}if(!n||!Array.isArray(n.bots)){kt="unexpected response shape (no `bots` array)",Ne={bots:[]};return}kt=null,Ne=n}catch(e){kt=e?.message??String(e),Ne={bots:[]}}}function io(e){if(!e)return"\u2014";let n=new Date(e);return Number.isNaN(n.getTime())?"\u2014":n.toLocaleString()}async function ro(e){e.innerHTML=ti();let n=e.querySelector("#bd-list"),a=e.querySelector("#bd-roster"),s=e.querySelector("#bd-filters"),o=e.querySelector("#bd-refresh");o.onclick=async()=>{o.disabled=!0;try{await so(),l()}finally{o.disabled=!1}},n.addEventListener("click",d=>{let y=d.target.closest(".toggle-tx small, small.bd-help");y&&(d.preventDefault(),y.classList.toggle("open"))}),n.innerHTML=wt(),await so();function l(){let y=(new FormData(s).get("q")??"").toLowerCase(),H=Ne.bots.filter($=>!y||($.botName??"").toLowerCase().includes(y)||($.larkAppId??"").toLowerCase().includes(y));if(kt){a.innerHTML="",n.innerHTML=`<p class="hint-warn">\u65E0\u6CD5\u52A0\u8F7D bot \u5217\u8868\uFF1A${i(kt)}<br>\u5E38\u89C1\u539F\u56E0\uFF1Adashboard / daemon \u8FDB\u7A0B\u8FD8\u5728\u8DD1\u65E7\u4EE3\u7801\uFF0C\u6267\u884C <code>botmux restart</code> \u540E\u5237\u65B0\u3002</p>`;return}if(H.length===0){a.innerHTML="",n.innerHTML=`<p class="empty">${t("botDefaults.empty")}</p>`;return}(!vt||!H.some($=>$.larkAppId===vt))&&(vt=H[0].larkAppId),a.innerHTML=H.map(c).join(""),a.querySelectorAll(".bd-roster-item").forEach($=>{$.onclick=()=>{vt=$.dataset.appid,l()}});let I=H.find($=>$.larkAppId===vt);n.innerHTML=m(I),x()}function c(d){let y=d.botName??d.larkAppId,H=oo(d.larkAppId),I=d.defaultOncall?.enabled?'<span class="bd-roster-flag">oncall</span>':"";return`<div class="bd-roster-item${d.larkAppId===vt?" on":""}" data-appid="${i(d.larkAppId)}" role="button" tabindex="0">
|
|
540
|
+
${fe({name:y,larkAppId:d.larkAppId,size:"sm"})}
|
|
455
541
|
<div class="bd-roster-tx">
|
|
456
|
-
<b>${
|
|
457
|
-
<span>${
|
|
542
|
+
<b>${i(y)}</b>
|
|
543
|
+
<span>${i(H||d.larkAppId.slice(0,14))}</span>
|
|
458
544
|
</div>
|
|
459
|
-
${
|
|
460
|
-
</div>`}function
|
|
545
|
+
${I}
|
|
546
|
+
</div>`}function m(d){if(d.error)return`<article class="bd-card bd-profile" data-appid="${i(d.larkAppId)}">
|
|
461
547
|
<header class="bd-profile-head">
|
|
462
|
-
${
|
|
463
|
-
<div class="bd-profile-id"><strong>${
|
|
464
|
-
<code>${
|
|
548
|
+
${fe({name:d.botName??d.larkAppId,larkAppId:d.larkAppId})}
|
|
549
|
+
<div class="bd-profile-id"><strong>${i(d.botName??d.larkAppId)}</strong>
|
|
550
|
+
<code>${i(d.larkAppId)}</code></div>
|
|
465
551
|
</header>
|
|
466
|
-
<p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${
|
|
467
|
-
</article>`;let
|
|
552
|
+
<p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${i(d.error)}</p>
|
|
553
|
+
</article>`;let y=d.defaultOncall??{enabled:!1,workingDir:"",since:0},H=!!y.enabled,I=d.botName??d.larkAppId,$=oo(d.larkAppId);return`<article class="bd-card bd-profile" data-appid="${i(d.larkAppId)}">
|
|
468
554
|
<header class="bd-profile-head">
|
|
469
|
-
${
|
|
555
|
+
${fe({name:I,larkAppId:d.larkAppId,dot:"ok"})}
|
|
470
556
|
<div class="bd-profile-id">
|
|
471
|
-
<strong>${
|
|
472
|
-
${
|
|
473
|
-
<code>${
|
|
557
|
+
<strong>${i(I)}</strong>
|
|
558
|
+
${$?`<span class="mate-role">${i($)}</span>`:""}
|
|
559
|
+
<code>${i(d.larkAppId)}</code>
|
|
474
560
|
</div>
|
|
475
561
|
<div class="bd-profile-meta bd-meta">
|
|
476
562
|
<small class="bd-meta-ok">\u25CF ${t("botDefaults.metaOnline")}</small>
|
|
477
|
-
<small data-oncall-since>${t("botDefaults.lastEnabled")}: ${
|
|
563
|
+
<small data-oncall-since>${t("botDefaults.lastEnabled")}: ${i(io(y.since??0))}</small>
|
|
478
564
|
<small>${t("botDefaults.autobound",{count:d.autoboundChatCount??0})}</small>
|
|
479
565
|
</div>
|
|
480
566
|
</header>
|
|
@@ -483,7 +569,7 @@ ${d.join(`
|
|
|
483
569
|
<section class="bd-section">
|
|
484
570
|
<h3 class="bd-section-title">${t("botDefaults.sectionOncall")}</h3>
|
|
485
571
|
<label class="toggle-row">
|
|
486
|
-
<input type="checkbox" data-action="toggle" ${
|
|
572
|
+
<input type="checkbox" data-action="toggle" ${H?"checked":""}>
|
|
487
573
|
<span class="switch" aria-hidden="true"></span>
|
|
488
574
|
<span class="toggle-tx"><strong>${t("botDefaults.defaultOncall")}</strong>
|
|
489
575
|
<small>${t("botDefaults.defaultOncallHelp")}\u3002${t("botDefaults.warning")}</small></span>
|
|
@@ -492,43 +578,43 @@ ${d.join(`
|
|
|
492
578
|
<label>
|
|
493
579
|
<span>${t("botDefaults.workingDir")}</span>
|
|
494
580
|
<input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
|
|
495
|
-
value="${
|
|
581
|
+
value="${i(y.workingDir??"")}" ${H?"":"disabled"}>
|
|
496
582
|
</label>
|
|
497
583
|
</div>
|
|
498
584
|
<div class="actions">
|
|
499
585
|
<button type="button" class="primary" data-action="save">${t("botDefaults.save")}</button>
|
|
500
586
|
<span class="oncall-status" data-status></span>
|
|
501
587
|
</div>
|
|
502
|
-
${
|
|
588
|
+
${M(d)}
|
|
503
589
|
</section>
|
|
504
|
-
${
|
|
590
|
+
${O(d)}
|
|
505
591
|
</section>
|
|
506
|
-
<section class="bd-tile">${
|
|
507
|
-
<section class="bd-tile">${
|
|
508
|
-
<section class="bd-tile">${
|
|
509
|
-
<section class="bd-tile">${
|
|
592
|
+
<section class="bd-tile">${k(d)}</section>
|
|
593
|
+
<section class="bd-tile">${w(d)}</section>
|
|
594
|
+
<section class="bd-tile">${T(d)}${L(d)}</section>
|
|
595
|
+
<section class="bd-tile">${R(d)}</section>
|
|
510
596
|
</div>
|
|
511
|
-
</article>`}function
|
|
597
|
+
</article>`}function k(d){let y=typeof d.teamRole=="string";return`<section class="bd-section">
|
|
512
598
|
<h3 class="bd-section-title">${t("botDefaults.sectionRole")}</h3>
|
|
513
599
|
<p class="bd-section-note">${t("botDefaults.roleHelp")}</p>
|
|
514
600
|
<textarea data-input="teamRole" rows="6"
|
|
515
|
-
placeholder="${
|
|
516
|
-
style="width:100%;box-sizing:border-box;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px"${
|
|
601
|
+
placeholder="${i(t("botDefaults.rolePlaceholder"))}"
|
|
602
|
+
style="width:100%;box-sizing:border-box;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px"${y?"":" disabled"}>${y?i(d.teamRole):""}</textarea>
|
|
517
603
|
<div class="actions">
|
|
518
|
-
<button type="button" class="primary" data-action="save-role"${
|
|
519
|
-
<button type="button" data-action="delete-role"${
|
|
604
|
+
<button type="button" class="primary" data-action="save-role"${y?"":" disabled"}>${t("botDefaults.roleSave")}</button>
|
|
605
|
+
<button type="button" data-action="delete-role"${y?"":" disabled"}>${t("botDefaults.roleDelete")}</button>
|
|
520
606
|
<span class="oncall-status" data-role-status></span>
|
|
521
607
|
</div>
|
|
522
|
-
</section>`}function
|
|
608
|
+
</section>`}function v(d){return d==null?t("botDefaults.brandStateDefault"):d.trim()===""?t("botDefaults.brandStateOff"):t("botDefaults.brandStateCustom")}function L(d){let y=d.brandLabel??null;return`<section class="bd-section">
|
|
523
609
|
<h3 class="bd-section-title">${t("botDefaults.sectionBrand")}</h3>
|
|
524
610
|
<div class="bd-row bd-brand">
|
|
525
611
|
<label>
|
|
526
612
|
<span>${t("botDefaults.brandLabel")}</span>
|
|
527
613
|
<input type="text" data-input="brandLabel"
|
|
528
|
-
placeholder="${
|
|
529
|
-
value="${
|
|
614
|
+
placeholder="${i(t("botDefaults.brandLabelPlaceholder"))}"
|
|
615
|
+
value="${i(y??"")}">
|
|
530
616
|
</label>
|
|
531
|
-
<small data-brand-state>${
|
|
617
|
+
<small data-brand-state>${i(v(y))}</small>
|
|
532
618
|
<small class="bd-help">${t("botDefaults.brandLabelHelp")}</small>
|
|
533
619
|
<div class="actions">
|
|
534
620
|
<button type="button" class="primary" data-action="save-brand">${t("botDefaults.brandSave")}</button>
|
|
@@ -536,38 +622,38 @@ ${d.join(`
|
|
|
536
622
|
<span class="oncall-status" data-brand-status></span>
|
|
537
623
|
</div>
|
|
538
624
|
</div>
|
|
539
|
-
</section>`}function
|
|
625
|
+
</section>`}function T(d){let y=d.disableStreamingCard===!0,H=d.writableTerminalLinkInCard===!0,I=d.privateCard===!0;return`<section class="bd-section">
|
|
540
626
|
<h3 class="bd-section-title">${t("botDefaults.sectionCard")}</h3>
|
|
541
627
|
<label class="toggle-row">
|
|
542
|
-
<input type="checkbox" data-action="toggle-disable-streaming" ${
|
|
628
|
+
<input type="checkbox" data-action="toggle-disable-streaming" ${y?"checked":""}>
|
|
543
629
|
<span class="switch" aria-hidden="true"></span>
|
|
544
630
|
<span class="toggle-tx"><strong>${t("botDefaults.disableStreaming")}</strong>
|
|
545
631
|
<small>${t("botDefaults.disableStreamingHelp")}</small></span>
|
|
546
632
|
</label>
|
|
547
633
|
<label class="toggle-row">
|
|
548
|
-
<input type="checkbox" data-action="toggle-writable-link" ${
|
|
634
|
+
<input type="checkbox" data-action="toggle-writable-link" ${H?"checked":""} ${y?"disabled":""}>
|
|
549
635
|
<span class="switch" aria-hidden="true"></span>
|
|
550
636
|
<span class="toggle-tx"><strong>${t("botDefaults.writableLink")}</strong>
|
|
551
637
|
<small>${t("botDefaults.writableLinkHelp")}</small></span>
|
|
552
638
|
</label>
|
|
553
639
|
<label class="toggle-row">
|
|
554
|
-
<input type="checkbox" data-action="toggle-private-card" ${
|
|
640
|
+
<input type="checkbox" data-action="toggle-private-card" ${I?"checked":""}>
|
|
555
641
|
<span class="switch" aria-hidden="true"></span>
|
|
556
642
|
<span class="toggle-tx"><strong>${t("botDefaults.privateCard")}</strong>
|
|
557
643
|
<small>${t("botDefaults.privateCardHelp")}</small></span>
|
|
558
644
|
</label>
|
|
559
645
|
<div class="actions">
|
|
560
|
-
<small data-card-pref-moot class="hint-warn-inline" ${
|
|
646
|
+
<small data-card-pref-moot class="hint-warn-inline" ${y?"":"hidden"}>${t("botDefaults.writableLinkMoot")}</small>
|
|
561
647
|
<span class="oncall-status" data-card-pref-status></span>
|
|
562
648
|
</div>
|
|
563
|
-
</section>`}function
|
|
649
|
+
</section>`}function w(d){let y=d.p2pMode==="chat"?"chat":"thread",H=d.regularGroupReplyMode==="new-topic"||d.regularGroupReplyMode==="shared"?d.regularGroupReplyMode:"chat",I=d.regularGroupMentionMode==="topic"||d.regularGroupMentionMode==="never"?d.regularGroupMentionMode:"always",$=(B,G)=>`<option value="${B}" ${H===B?"selected":""}>${i(G)}</option>`,A=(B,G)=>`<option value="${B}" ${I===B?"selected":""}>${i(G)}</option>`;return`<section class="bd-section">
|
|
564
650
|
<h3 class="bd-section-title">${t("botDefaults.sectionSessionMode")}</h3>
|
|
565
651
|
<div class="bd-row">
|
|
566
652
|
<label>
|
|
567
653
|
<span>${t("botDefaults.p2pMode")}</span>
|
|
568
654
|
<select data-input="p2pMode">
|
|
569
|
-
<option value="thread" ${
|
|
570
|
-
<option value="chat" ${
|
|
655
|
+
<option value="thread" ${y==="chat"?"":"selected"}>${i(t("botDefaults.p2pThread"))}</option>
|
|
656
|
+
<option value="chat" ${y==="chat"?"selected":""}>${i(t("botDefaults.p2pChat"))}</option>
|
|
571
657
|
</select>
|
|
572
658
|
</label>
|
|
573
659
|
<small class="bd-help">${t("botDefaults.p2pHelp")}</small>
|
|
@@ -579,9 +665,9 @@ ${d.join(`
|
|
|
579
665
|
<label>
|
|
580
666
|
<span>${t("botDefaults.regularGroupMode")}</span>
|
|
581
667
|
<select data-input="regularGroupMode">
|
|
582
|
-
${
|
|
583
|
-
${
|
|
584
|
-
${
|
|
668
|
+
${$("chat",t("botDefaults.regularGroupModeChat"))}
|
|
669
|
+
${$("new-topic",t("botDefaults.regularGroupModeNewTopic"))}
|
|
670
|
+
${$("shared",t("botDefaults.regularGroupModeShared"))}
|
|
585
671
|
</select>
|
|
586
672
|
</label>
|
|
587
673
|
<small class="bd-help">${t("botDefaults.regularGroupModeHelp")}</small>
|
|
@@ -593,9 +679,9 @@ ${d.join(`
|
|
|
593
679
|
<label>
|
|
594
680
|
<span>${t("botDefaults.mentionMode")}</span>
|
|
595
681
|
<select data-input="regularGroupMentionMode">
|
|
596
|
-
${
|
|
597
|
-
${
|
|
598
|
-
${
|
|
682
|
+
${A("always",t("botDefaults.mentionModeAlways"))}
|
|
683
|
+
${A("topic",t("botDefaults.mentionModeTopic"))}
|
|
684
|
+
${A("never",t("botDefaults.mentionModeNever"))}
|
|
599
685
|
</select>
|
|
600
686
|
</label>
|
|
601
687
|
<small class="bd-help">${t("botDefaults.mentionModeHelp")}</small>
|
|
@@ -603,10 +689,10 @@ ${d.join(`
|
|
|
603
689
|
<span class="oncall-status" data-mention-mode-status></span>
|
|
604
690
|
</div>
|
|
605
691
|
</div>
|
|
606
|
-
</section>`}function
|
|
692
|
+
</section>`}function O(d){let y=d.sandbox===!0;return`<section class="bd-section">
|
|
607
693
|
<h3 class="bd-section-title">${t("botDefaults.sectionSandbox")}</h3>
|
|
608
694
|
<label class="toggle-row">
|
|
609
|
-
<input type="checkbox" data-action="toggle-sandbox" ${
|
|
695
|
+
<input type="checkbox" data-action="toggle-sandbox" ${y?"checked":""}>
|
|
610
696
|
<span class="switch" aria-hidden="true"></span>
|
|
611
697
|
<span class="toggle-tx"><strong>${t("botDefaults.sandboxToggle")}</strong>
|
|
612
698
|
<small>${t("botDefaults.sandboxHelp")}</small></span>
|
|
@@ -614,10 +700,10 @@ ${d.join(`
|
|
|
614
700
|
<div class="actions">
|
|
615
701
|
<span class="oncall-status" data-sandbox-status></span>
|
|
616
702
|
</div>
|
|
617
|
-
</section>`}function
|
|
703
|
+
</section>`}function D(d){return d==null?t("botDefaults.quotaStateOff"):t("botDefaults.quotaStateOn",{count:d})}function R(d){let y=d.restrictGrantCommands===!0,H=typeof d.messageQuotaDefaultLimit=="number"?d.messageQuotaDefaultLimit:null;return`<section class="bd-section">
|
|
618
704
|
<h3 class="bd-section-title">${t("botDefaults.sectionGrant")}</h3>
|
|
619
705
|
<label class="toggle-row">
|
|
620
|
-
<input type="checkbox" data-action="toggle-restrict-grant" ${
|
|
706
|
+
<input type="checkbox" data-action="toggle-restrict-grant" ${y?"checked":""}>
|
|
621
707
|
<span class="switch" aria-hidden="true"></span>
|
|
622
708
|
<span class="toggle-tx"><strong>${t("botDefaults.restrictGrant")}</strong>
|
|
623
709
|
<small>${t("botDefaults.restrictGrantHelp")}</small></span>
|
|
@@ -626,10 +712,10 @@ ${d.join(`
|
|
|
626
712
|
<label>
|
|
627
713
|
<span>${t("botDefaults.quotaDefault")}</span>
|
|
628
714
|
<input type="number" min="1" step="1" data-input="quotaLimit"
|
|
629
|
-
placeholder="${
|
|
630
|
-
value="${
|
|
715
|
+
placeholder="${i(t("botDefaults.quotaPlaceholder"))}"
|
|
716
|
+
value="${H??""}">
|
|
631
717
|
</label>
|
|
632
|
-
<small data-quota-state>${
|
|
718
|
+
<small data-quota-state>${i(D(H))}</small>
|
|
633
719
|
<small class="bd-help">${t("botDefaults.quotaHelp")}</small>
|
|
634
720
|
<div class="actions">
|
|
635
721
|
<button type="button" class="primary" data-action="save-quota">${t("botDefaults.quotaSave")}</button>
|
|
@@ -637,10 +723,10 @@ ${d.join(`
|
|
|
637
723
|
<span class="oncall-status" data-grant-status></span>
|
|
638
724
|
</div>
|
|
639
725
|
</div>
|
|
640
|
-
</section>`}function
|
|
726
|
+
</section>`}function M(d){let y=d.autoStartOnGroupJoin===!0,H=d.autoStartOnNewTopic===!0,I=typeof d.autoStartOnGroupJoinPrompt=="string"?d.autoStartOnGroupJoinPrompt:"";return`<div class="bd-subsection">
|
|
641
727
|
<h4 class="bd-subsection-title">${t("botDefaults.sectionAutoStart")}</h4>
|
|
642
728
|
<label class="toggle-row">
|
|
643
|
-
<input type="checkbox" data-action="toggle-auto-join" ${
|
|
729
|
+
<input type="checkbox" data-action="toggle-auto-join" ${y?"checked":""}>
|
|
644
730
|
<span class="switch" aria-hidden="true"></span>
|
|
645
731
|
<span class="toggle-tx"><strong>${t("botDefaults.autoStartJoin")}</strong>
|
|
646
732
|
<small>${t("botDefaults.autoStartJoinHelp")}</small></span>
|
|
@@ -649,14 +735,14 @@ ${d.join(`
|
|
|
649
735
|
<label>
|
|
650
736
|
<span>${t("botDefaults.autoStartJoinPrompt")}</span>
|
|
651
737
|
<textarea data-input="autoJoinPrompt" rows="3"
|
|
652
|
-
placeholder="${
|
|
738
|
+
placeholder="${i(t("botDefaults.autoStartJoinPromptPlaceholder"))}">${i(I)}</textarea>
|
|
653
739
|
</label>
|
|
654
740
|
<div class="actions">
|
|
655
741
|
<button type="button" class="primary" data-action="save-auto-join-prompt">${t("botDefaults.autoStartJoinPromptSave")}</button>
|
|
656
742
|
</div>
|
|
657
743
|
</div>
|
|
658
744
|
<label class="toggle-row">
|
|
659
|
-
<input type="checkbox" data-action="toggle-auto-topic" ${
|
|
745
|
+
<input type="checkbox" data-action="toggle-auto-topic" ${H?"checked":""}>
|
|
660
746
|
<span class="switch" aria-hidden="true"></span>
|
|
661
747
|
<span class="toggle-tx"><strong>${t("botDefaults.autoStartTopic")}</strong>
|
|
662
748
|
<small>${t("botDefaults.autoStartTopicHelp")}</small></span>
|
|
@@ -664,7 +750,7 @@ ${d.join(`
|
|
|
664
750
|
<div class="actions">
|
|
665
751
|
<span class="oncall-status" data-auto-start-status></span>
|
|
666
752
|
</div>
|
|
667
|
-
</div>`}function $(){n.querySelectorAll(".bd-card").forEach(d=>{let g=d.dataset.appid,M=d.querySelector("input[data-action=toggle]"),L=d.querySelector("input[data-input=workingDir]"),y=d.querySelector("button[data-action=save]"),H=d.querySelector("[data-status]");if(!M||!L||!y||!H)return;M.addEventListener("change",()=>{L.disabled=!M.checked,M.checked&&L.focus()}),y.addEventListener("click",async()=>{H.textContent="",H.className="oncall-status";let Z=M.checked,q=L.value.trim();if(Z&&!q){H.textContent=t("botDefaults.required"),H.classList.add("hint-warn-inline");return}y.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(g)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:Z,workingDir:q})}),F=await N.json().catch(()=>({}));if(N.ok&&F.ok){let U=F.resolvedPath?` \u2192 ${F.resolvedPath}`:"";H.textContent=Z?`\u2713 \u5DF2\u5F00\u542F${U}\uFF08\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8 oncall\uFF09`:"\u2713 \u5DF2\u5173\u95ED\uFF08\u5DF2\u7ED1\u5B9A\u7684\u7FA4\u4E0D\u52A8\uFF09",H.classList.add("hint-ok");let W=ve.bots.find(Te=>Te.larkAppId===g);W&&F.defaultOncall&&(W.defaultOncall=F.defaultOncall);let de=d.querySelector("[data-oncall-since]");de&&F.defaultOncall?.since!=null&&(de.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${po(F.defaultOncall.since)}`)}else H.textContent=`\u2717 ${F.error??N.status}`,H.classList.add("hint-warn-inline")}catch(N){H.textContent=`\u2717 ${N?.message??N}`,H.classList.add("hint-warn-inline")}finally{y.disabled=!1}});let A=d.querySelector("input[data-input=brandLabel]"),B=d.querySelector("button[data-action=save-brand]"),Y=d.querySelector("button[data-action=reset-brand]"),_=d.querySelector("[data-brand-status]"),me=d.querySelector("[data-brand-state]");async function $e(Z,q){if(_){_.textContent="",_.className="oncall-status",q.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(g)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:Z})}),F=await N.json().catch(()=>({}));if(N.ok&&F.ok){let U=F.brandLabel??null;_.textContent="\u2713",_.classList.add("hint-ok"),A&&(A.value=U??""),me&&(me.textContent=b(U));let W=ve.bots.find(de=>de.larkAppId===g);W&&(W.brandLabel=U)}else _.textContent=`\u2717 ${F.error??N.status}`,_.classList.add("hint-warn-inline")}catch(N){_.textContent=`\u2717 ${N?.message??N}`,_.classList.add("hint-warn-inline")}finally{q.disabled=!1}}}A&&B&&B.addEventListener("click",()=>$e(A.value,B)),Y&&Y.addEventListener("click",()=>$e(null,Y));let re=d.querySelector("input[data-action=toggle-disable-streaming]"),Q=d.querySelector("input[data-action=toggle-writable-link]"),fe=d.querySelector("input[data-action=toggle-private-card]"),Ne=d.querySelector("[data-card-pref-status]"),Se=d.querySelector("[data-card-pref-moot]");async function se(Z,q,N=Ne){if(N){N.textContent="",N.className="oncall-status",q.disabled=!0;try{let F=await fetch(`/api/bots/${encodeURIComponent(g)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(Z)}),U=await F.json().catch(()=>({}));if(F.ok&&U.ok){N.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,N.classList.add("hint-ok");let W=ve.bots.find(de=>de.larkAppId===g);W&&(W.disableStreamingCard=U.disableStreamingCard,W.writableTerminalLinkInCard=U.writableTerminalLinkInCard,W.privateCard=U.privateCard,W.autoStartOnGroupJoin=U.autoStartOnGroupJoin,W.autoStartOnGroupJoinPrompt=U.autoStartOnGroupJoinPrompt,W.autoStartOnNewTopic=U.autoStartOnNewTopic,W.regularGroupReplyMode=U.regularGroupReplyMode,W.regularGroupMentionMode=U.regularGroupMentionMode)}else N.textContent=`\u2717 ${U.error??F.status}`,N.classList.add("hint-warn-inline")}catch(F){N.textContent=`\u2717 ${F?.message??F}`,N.classList.add("hint-warn-inline")}finally{q===Q?q.disabled=!!re?.checked:q.disabled=!1}}}re&&re.addEventListener("change",()=>{let Z=re.checked;Q&&(Q.disabled=Z),Se&&(Se.hidden=!Z),se({disableStreamingCard:Z},re)}),Q&&Q.addEventListener("change",()=>{se({writableTerminalLinkInCard:Q.checked},Q)}),fe&&fe.addEventListener("change",()=>{se({privateCard:fe.checked},fe)});let le=d.querySelector("input[data-action=toggle-sandbox]"),X=d.querySelector("[data-sandbox-status]");le&&le.addEventListener("change",async()=>{let Z=le.checked;X&&(X.textContent="",X.className="oncall-status"),le.disabled=!0;try{let q=await fetch(`/api/bots/${encodeURIComponent(g)}/sandbox`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:Z})}),N=await q.json().catch(()=>({}));if(q.ok&&N.ok){X&&(X.textContent=`\u2713 ${t("botDefaults.sandboxSaved")}`,X.classList.add("hint-ok"));let F=ve.bots.find(U=>U.larkAppId===g);F&&(F.sandbox=N.sandbox===!0)}else X&&(X.textContent=`\u2717 ${N.error??q.status}`,X.classList.add("hint-warn-inline")),le.checked=!Z}catch(q){X&&(X.textContent=`\u2717 ${q?.message??q}`,X.classList.add("hint-warn-inline")),le.checked=!Z}finally{le.disabled=!1}});let Ie=d.querySelector("input[data-action=toggle-auto-join]"),Me=d.querySelector("input[data-action=toggle-auto-topic]"),ie=d.querySelector("textarea[data-input=autoJoinPrompt]"),u=d.querySelector("button[data-action=save-auto-join-prompt]"),f=d.querySelector("[data-auto-start-status]");Ie&&Ie.addEventListener("change",()=>{se({autoStartOnGroupJoin:Ie.checked},Ie,f)}),Me&&Me.addEventListener("change",()=>{se({autoStartOnNewTopic:Me.checked},Me,f)}),ie&&u&&u.addEventListener("click",()=>{se({autoStartOnGroupJoinPrompt:ie.value},u,f)});let T=d.querySelector("select[data-input=p2pMode]"),I=d.querySelector("[data-p2p-status]");T&&I&&T.addEventListener("change",async()=>{let Z=T.value==="chat"?"chat":"thread";I.textContent="",I.className="oncall-status",T.disabled=!0;try{let q=await fetch(`/api/bots/${encodeURIComponent(g)}/p2p-mode`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({p2pMode:Z})}),N=await q.json().catch(()=>({}));if(q.ok&&N.ok){I.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,I.classList.add("hint-ok");let F=ve.bots.find(U=>U.larkAppId===g);F&&(F.p2pMode=N.p2pMode==="chat"?"chat":"thread")}else I.textContent=`\u2717 ${N.error??q.status}`,I.classList.add("hint-warn-inline")}catch(q){I.textContent=`\u2717 ${q?.message??q}`,I.classList.add("hint-warn-inline")}finally{T.disabled=!1}});let x=d.querySelector("select[data-input=regularGroupMode]"),j=d.querySelector("[data-regular-group-status]");x&&x.addEventListener("change",()=>{se({regularGroupReplyMode:x.value},x,j)});let G=d.querySelector("select[data-input=regularGroupMentionMode]"),te=d.querySelector("[data-mention-mode-status]");G&&G.addEventListener("change",()=>{se({regularGroupMentionMode:G.value},G,te)});let z=d.querySelector("textarea[data-input=teamRole]"),oe=d.querySelector("button[data-action=save-role]"),ae=d.querySelector("button[data-action=delete-role]"),J=d.querySelector("[data-role-status]");if(z&&oe&&ae&&J){let N=function(U){let W=n.querySelector(`.bd-card[data-appid="${CSS.escape(g)}"]`);if(!W)return;let de=W.querySelector("textarea[data-input=teamRole]"),Te=W.querySelector("button[data-action=save-role]"),ot=W.querySelector("button[data-action=delete-role]");de&&(de.value=U,de.disabled=!1),Te&&(Te.disabled=!1),ot&&(ot.disabled=!1)};var wt=N;let Z=`/api/team/local-bots/${encodeURIComponent(g)}/role`,q=ve.bots.find(U=>U.larkAppId===g);q&&typeof q.teamRole!="string"&&!q.teamRoleLoading&&(q.teamRoleLoading=!0,(async()=>{try{let U=await fetch(Z),W=await U.json().catch(()=>({}));U.ok&&W.ok?(q.teamRole=W.role??"",N(q.teamRole)):(J.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${W.error??U.status}`,J.classList.add("hint-warn-inline"))}catch(U){J.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${U?.message??U}`,J.classList.add("hint-warn-inline")}finally{q.teamRoleLoading=!1}})());async function F(U,W,de){if(J&&!(!q||typeof q.teamRole!="string")){J.textContent="",J.className="oncall-status",oe.disabled=!0,ae.disabled=!0;try{let Te=await fetch(Z,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({role:U})}),ot=await Te.json().catch(()=>({}));Te.ok&&ot.ok?(q&&(q.teamRole=U.trim()),J.textContent=`\u2713 ${de?t("botDefaults.roleDeleted"):t("botDefaults.roleSaved")}`,J.classList.add("hint-ok")):(J.textContent=`\u2717 ${ot.error??Te.status}`,J.classList.add("hint-warn-inline"))}catch(Te){J.textContent=`\u2717 ${Te?.message??Te}`,J.classList.add("hint-warn-inline")}finally{oe.disabled=!1,ae.disabled=!1}}}oe.addEventListener("click",()=>F(z.value,oe,!1)),ae.addEventListener("click",()=>{z.value="",F("",ae,!0)})}let xe=d.querySelector("input[data-action=toggle-restrict-grant]"),we=d.querySelector("input[data-input=quotaLimit]"),S=d.querySelector("button[data-action=save-quota]"),ne=d.querySelector("button[data-action=off-quota]"),R=d.querySelector("[data-grant-status]"),P=d.querySelector("[data-quota-state]");async function ge(Z,q){if(R){R.textContent="",R.className="oncall-status",q.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(g)}/grant-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(Z)}),F=await N.json().catch(()=>({}));if(N.ok&&F.ok){R.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,R.classList.add("hint-ok");let U=typeof F.messageQuotaDefaultLimit=="number"?F.messageQuotaDefaultLimit:null,W=ve.bots.find(de=>de.larkAppId===g);W&&(W.restrictGrantCommands=F.restrictGrantCommands===!0,W.messageQuotaDefaultLimit=U),P&&(P.textContent=E(U)),we&&"messageQuotaDefaultLimit"in Z&&(we.value=U==null?"":String(U))}else R.textContent=`\u2717 ${F.error??N.status}`,R.classList.add("hint-warn-inline")}catch(N){R.textContent=`\u2717 ${N?.message??N}`,R.classList.add("hint-warn-inline")}finally{q.disabled=!1}}}xe&&xe.addEventListener("change",()=>{ge({restrictGrantCommands:xe.checked},xe)}),we&&S&&S.addEventListener("click",()=>{let Z=we.value.trim();if(Z===""){ge({messageQuotaDefaultLimit:null},S);return}if(!/^[1-9]\d*$/.test(Z)){R&&(R.textContent=`\u2717 ${t("botDefaults.quotaInvalid")}`,R.className="oncall-status hint-warn-inline");return}ge({messageQuotaDefaultLimit:Number(Z)},S)}),we&&ne&&ne.addEventListener("click",()=>{we.value="",ge({messageQuotaDefaultLimit:null},ne)})})}i(),Ee().then(i),s.addEventListener("input",i)}var nn=4096,Et=[],Ae=null,De=null,ke="",tt=new Set;function Va(){return`<section class="page roles-page">
|
|
753
|
+
</div>`}function x(){n.querySelectorAll(".bd-card").forEach(d=>{let y=d.dataset.appid,H=d.querySelector("input[data-action=toggle]"),I=d.querySelector("input[data-input=workingDir]"),$=d.querySelector("button[data-action=save]"),A=d.querySelector("[data-status]");if(!H||!I||!$||!A)return;H.addEventListener("change",()=>{I.disabled=!H.checked,H.checked&&I.focus()}),$.addEventListener("click",async()=>{A.textContent="",A.className="oncall-status";let X=H.checked,z=I.value.trim();if(X&&!z){A.textContent=t("botDefaults.required"),A.classList.add("hint-warn-inline");return}$.disabled=!0;try{let F=await fetch(`/api/bots/${encodeURIComponent(y)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:X,workingDir:z})}),K=await F.json().catch(()=>({}));if(F.ok&&K.ok){let W=K.resolvedPath?` \u2192 ${K.resolvedPath}`:"";A.textContent=X?`\u2713 \u5DF2\u5F00\u542F${W}\uFF08\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8 oncall\uFF09`:"\u2713 \u5DF2\u5173\u95ED\uFF08\u5DF2\u7ED1\u5B9A\u7684\u7FA4\u4E0D\u52A8\uFF09",A.classList.add("hint-ok");let Y=Ne.bots.find(Te=>Te.larkAppId===y);Y&&K.defaultOncall&&(Y.defaultOncall=K.defaultOncall);let pe=d.querySelector("[data-oncall-since]");pe&&K.defaultOncall?.since!=null&&(pe.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${io(K.defaultOncall.since)}`)}else A.textContent=`\u2717 ${K.error??F.status}`,A.classList.add("hint-warn-inline")}catch(F){A.textContent=`\u2717 ${F?.message??F}`,A.classList.add("hint-warn-inline")}finally{$.disabled=!1}});let B=d.querySelector("input[data-input=brandLabel]"),G=d.querySelector("button[data-action=save-brand]"),j=d.querySelector("button[data-action=reset-brand]"),Q=d.querySelector("[data-brand-status]"),le=d.querySelector("[data-brand-state]");async function Ee(X,z){if(Q){Q.textContent="",Q.className="oncall-status",z.disabled=!0;try{let F=await fetch(`/api/bots/${encodeURIComponent(y)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:X})}),K=await F.json().catch(()=>({}));if(F.ok&&K.ok){let W=K.brandLabel??null;Q.textContent="\u2713",Q.classList.add("hint-ok"),B&&(B.value=W??""),le&&(le.textContent=v(W));let Y=Ne.bots.find(pe=>pe.larkAppId===y);Y&&(Y.brandLabel=W)}else Q.textContent=`\u2717 ${K.error??F.status}`,Q.classList.add("hint-warn-inline")}catch(F){Q.textContent=`\u2717 ${F?.message??F}`,Q.classList.add("hint-warn-inline")}finally{z.disabled=!1}}}B&&G&&G.addEventListener("click",()=>Ee(B.value,G)),j&&j.addEventListener("click",()=>Ee(null,j));let ge=d.querySelector("input[data-action=toggle-disable-streaming]"),J=d.querySelector("input[data-action=toggle-writable-link]"),se=d.querySelector("input[data-action=toggle-private-card]"),Se=d.querySelector("[data-card-pref-status]"),Re=d.querySelector("[data-card-pref-moot]");async function ee(X,z,F=Se){if(F){F.textContent="",F.className="oncall-status",z.disabled=!0;try{let K=await fetch(`/api/bots/${encodeURIComponent(y)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(X)}),W=await K.json().catch(()=>({}));if(K.ok&&W.ok){F.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,F.classList.add("hint-ok");let Y=Ne.bots.find(pe=>pe.larkAppId===y);Y&&(Y.disableStreamingCard=W.disableStreamingCard,Y.writableTerminalLinkInCard=W.writableTerminalLinkInCard,Y.privateCard=W.privateCard,Y.autoStartOnGroupJoin=W.autoStartOnGroupJoin,Y.autoStartOnGroupJoinPrompt=W.autoStartOnGroupJoinPrompt,Y.autoStartOnNewTopic=W.autoStartOnNewTopic,Y.regularGroupReplyMode=W.regularGroupReplyMode,Y.regularGroupMentionMode=W.regularGroupMentionMode)}else F.textContent=`\u2717 ${W.error??K.status}`,F.classList.add("hint-warn-inline")}catch(K){F.textContent=`\u2717 ${K?.message??K}`,F.classList.add("hint-warn-inline")}finally{z===J?z.disabled=!!ge?.checked:z.disabled=!1}}}ge&&ge.addEventListener("change",()=>{let X=ge.checked;J&&(J.disabled=X),Re&&(Re.hidden=!X),ee({disableStreamingCard:X},ge)}),J&&J.addEventListener("change",()=>{ee({writableTerminalLinkInCard:J.checked},J)}),se&&se.addEventListener("change",()=>{ee({privateCard:se.checked},se)});let ue=d.querySelector("input[data-action=toggle-sandbox]"),de=d.querySelector("[data-sandbox-status]");ue&&ue.addEventListener("change",async()=>{let X=ue.checked;de&&(de.textContent="",de.className="oncall-status"),ue.disabled=!0;try{let z=await fetch(`/api/bots/${encodeURIComponent(y)}/sandbox`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:X})}),F=await z.json().catch(()=>({}));if(z.ok&&F.ok){de&&(de.textContent=`\u2713 ${t("botDefaults.sandboxSaved")}`,de.classList.add("hint-ok"));let K=Ne.bots.find(W=>W.larkAppId===y);K&&(K.sandbox=F.sandbox===!0)}else de&&(de.textContent=`\u2717 ${F.error??z.status}`,de.classList.add("hint-warn-inline")),ue.checked=!X}catch(z){de&&(de.textContent=`\u2717 ${z?.message??z}`,de.classList.add("hint-warn-inline")),ue.checked=!X}finally{ue.disabled=!1}});let qe=d.querySelector("input[data-action=toggle-auto-join]"),ke=d.querySelector("input[data-action=toggle-auto-topic]"),be=d.querySelector("textarea[data-input=autoJoinPrompt]"),re=d.querySelector("button[data-action=save-auto-join-prompt]"),xe=d.querySelector("[data-auto-start-status]");qe&&qe.addEventListener("change",()=>{ee({autoStartOnGroupJoin:qe.checked},qe,xe)}),ke&&ke.addEventListener("change",()=>{ee({autoStartOnNewTopic:ke.checked},ke,xe)}),be&&re&&re.addEventListener("click",()=>{ee({autoStartOnGroupJoinPrompt:be.value},re,xe)});let He=d.querySelector("select[data-input=p2pMode]"),ce=d.querySelector("[data-p2p-status]");He&&ce&&He.addEventListener("change",async()=>{let X=He.value==="chat"?"chat":"thread";ce.textContent="",ce.className="oncall-status",He.disabled=!0;try{let z=await fetch(`/api/bots/${encodeURIComponent(y)}/p2p-mode`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({p2pMode:X})}),F=await z.json().catch(()=>({}));if(z.ok&&F.ok){ce.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,ce.classList.add("hint-ok");let K=Ne.bots.find(W=>W.larkAppId===y);K&&(K.p2pMode=F.p2pMode==="chat"?"chat":"thread")}else ce.textContent=`\u2717 ${F.error??z.status}`,ce.classList.add("hint-warn-inline")}catch(z){ce.textContent=`\u2717 ${z?.message??z}`,ce.classList.add("hint-warn-inline")}finally{He.disabled=!1}});let je=d.querySelector("select[data-input=regularGroupMode]"),Ze=d.querySelector("[data-regular-group-status]");je&&je.addEventListener("change",()=>{ee({regularGroupReplyMode:je.value},je,Ze)});let et=d.querySelector("select[data-input=regularGroupMentionMode]"),ft=d.querySelector("[data-mention-mode-status]");et&&et.addEventListener("change",()=>{ee({regularGroupMentionMode:et.value},et,ft)});let it=d.querySelector("textarea[data-input=teamRole]"),Ye=d.querySelector("button[data-action=save-role]"),Ve=d.querySelector("button[data-action=delete-role]"),oe=d.querySelector("[data-role-status]");if(it&&Ye&&Ve&&oe){let F=function(W){let Y=n.querySelector(`.bd-card[data-appid="${CSS.escape(y)}"]`);if(!Y)return;let pe=Y.querySelector("textarea[data-input=teamRole]"),Te=Y.querySelector("button[data-action=save-role]"),tt=Y.querySelector("button[data-action=delete-role]");pe&&(pe.value=W,pe.disabled=!1),Te&&(Te.disabled=!1),tt&&(tt.disabled=!1)};var gt=F;let X=`/api/team/local-bots/${encodeURIComponent(y)}/role`,z=Ne.bots.find(W=>W.larkAppId===y);z&&typeof z.teamRole!="string"&&!z.teamRoleLoading&&(z.teamRoleLoading=!0,(async()=>{try{let W=await fetch(X),Y=await W.json().catch(()=>({}));W.ok&&Y.ok?(z.teamRole=Y.role??"",F(z.teamRole)):(oe.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${Y.error??W.status}`,oe.classList.add("hint-warn-inline"))}catch(W){oe.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${W?.message??W}`,oe.classList.add("hint-warn-inline")}finally{z.teamRoleLoading=!1}})());async function K(W,Y,pe){if(oe&&!(!z||typeof z.teamRole!="string")){oe.textContent="",oe.className="oncall-status",Ye.disabled=!0,Ve.disabled=!0;try{let Te=await fetch(X,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({role:W})}),tt=await Te.json().catch(()=>({}));Te.ok&&tt.ok?(z&&(z.teamRole=W.trim()),oe.textContent=`\u2713 ${pe?t("botDefaults.roleDeleted"):t("botDefaults.roleSaved")}`,oe.classList.add("hint-ok")):(oe.textContent=`\u2717 ${tt.error??Te.status}`,oe.classList.add("hint-warn-inline"))}catch(Te){oe.textContent=`\u2717 ${Te?.message??Te}`,oe.classList.add("hint-warn-inline")}finally{Ye.disabled=!1,Ve.disabled=!1}}}Ye.addEventListener("click",()=>K(it.value,Ye,!1)),Ve.addEventListener("click",()=>{it.value="",K("",Ve,!0)})}let Ue=d.querySelector("input[data-action=toggle-restrict-grant]"),Oe=d.querySelector("input[data-input=quotaLimit]"),E=d.querySelector("button[data-action=save-quota]"),ie=d.querySelector("button[data-action=off-quota]"),U=d.querySelector("[data-grant-status]"),_=d.querySelector("[data-quota-state]");async function he(X,z){if(U){U.textContent="",U.className="oncall-status",z.disabled=!0;try{let F=await fetch(`/api/bots/${encodeURIComponent(y)}/grant-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(X)}),K=await F.json().catch(()=>({}));if(F.ok&&K.ok){U.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,U.classList.add("hint-ok");let W=typeof K.messageQuotaDefaultLimit=="number"?K.messageQuotaDefaultLimit:null,Y=Ne.bots.find(pe=>pe.larkAppId===y);Y&&(Y.restrictGrantCommands=K.restrictGrantCommands===!0,Y.messageQuotaDefaultLimit=W),_&&(_.textContent=D(W)),Oe&&"messageQuotaDefaultLimit"in X&&(Oe.value=W==null?"":String(W))}else U.textContent=`\u2717 ${K.error??F.status}`,U.classList.add("hint-warn-inline")}catch(F){U.textContent=`\u2717 ${F?.message??F}`,U.classList.add("hint-warn-inline")}finally{z.disabled=!1}}}Ue&&Ue.addEventListener("change",()=>{he({restrictGrantCommands:Ue.checked},Ue)}),Oe&&E&&E.addEventListener("click",()=>{let X=Oe.value.trim();if(X===""){he({messageQuotaDefaultLimit:null},E);return}if(!/^[1-9]\d*$/.test(X)){U&&(U.textContent=`\u2717 ${t("botDefaults.quotaInvalid")}`,U.className="oncall-status hint-warn-inline");return}he({messageQuotaDefaultLimit:Number(X)},E)}),Oe&&ie&&ie.addEventListener("click",()=>{Oe.value="",he({messageQuotaDefaultLimit:null},ie)})})}l(),Ge().then(l),s.addEventListener("input",l)}var On=4096,Zt=[],We=null,Ke=null,Pe="",$t=new Set;function ni(){return`<section class="page roles-page">
|
|
668
754
|
<div class="page-heading">
|
|
669
755
|
<div>
|
|
670
756
|
<p class="eyebrow">${t("nav.roles")}</p>
|
|
@@ -703,40 +789,40 @@ ${d.join(`
|
|
|
703
789
|
</div>
|
|
704
790
|
</div>
|
|
705
791
|
</div>
|
|
706
|
-
</section>`}async function
|
|
707
|
-
<div class="roles-bot-row ${
|
|
708
|
-
data-group-id="${
|
|
709
|
-
data-bot-id="${
|
|
792
|
+
</section>`}async function Xt(){Zt=((await(await fetch("/api/groups")).json()).chats??[]).map(a=>({chatId:a.chatId,name:a.name??a.chatId,memberBots:(a.memberBots??[]).map(s=>({larkAppId:s.larkAppId,botName:s.botName??s.larkAppId,inChat:s.inChat??!1,hasRole:s.hasRole??!1,oncallChat:s.oncallChat??null}))}))}async function co(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`)).json()}async function ai(e,n,a){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({content:a})})).ok}async function oi(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`,{method:"DELETE"})).ok}function uo(e){return e.memberBots.filter(n=>n.inChat&&n.hasRole).length}function si(e){return e.memberBots.filter(n=>n.inChat).length}function lt(e=""){let n=document.getElementById("roles-tree");if(!n)return;let a=e.toLowerCase(),s=Zt.filter(o=>{if(!a)return!0;let l=o.chatId.toLowerCase().includes(a)||(o.name??"").toLowerCase().includes(a),c=o.memberBots.some(m=>m.larkAppId.toLowerCase().includes(a)||(m.botName??"").toLowerCase().includes(a));return l||c});if(s.length===0){n.innerHTML=`<div class="roles-empty">${t("roles.noChats")}</div>`;return}n.innerHTML=s.map(o=>{let l=$t.has(o.chatId),c=o.memberBots.filter(T=>T.inChat),m=l?"\u25BE":"\u25B8",k=uo(o),v=si(o),L=l?c.map(T=>`
|
|
793
|
+
<div class="roles-bot-row ${We===o.chatId&&Ke===T.larkAppId?"selected":""}"
|
|
794
|
+
data-group-id="${i(o.chatId)}"
|
|
795
|
+
data-bot-id="${i(T.larkAppId)}">
|
|
710
796
|
<span class="roles-bot-indent"></span>
|
|
711
|
-
${
|
|
797
|
+
${fe({name:T.botName,larkAppId:T.larkAppId,size:"sm"})}
|
|
712
798
|
<div class="roles-bot-info">
|
|
713
|
-
<div class="roles-bot-name">${
|
|
714
|
-
<div class="roles-bot-id">${
|
|
799
|
+
<div class="roles-bot-name">${i(T.botName)}</div>
|
|
800
|
+
<div class="roles-bot-id">${i(T.larkAppId)}</div>
|
|
715
801
|
</div>
|
|
716
|
-
<span class="roles-badge ${
|
|
717
|
-
${
|
|
802
|
+
<span class="roles-badge ${T.hasRole?"has-role":"no-role"}">
|
|
803
|
+
${T.hasRole?t("roles.configured"):t("roles.unconfigured")}
|
|
718
804
|
</span>
|
|
719
805
|
</div>`).join(""):"";return`
|
|
720
806
|
<div class="roles-group-section">
|
|
721
|
-
<div class="roles-group-row ${
|
|
722
|
-
data-group-id="${
|
|
723
|
-
<span class="roles-group-arrow">${
|
|
807
|
+
<div class="roles-group-row ${l?"expanded":""} ${We===o.chatId&&!Ke?"selected":""}"
|
|
808
|
+
data-group-id="${i(o.chatId)}">
|
|
809
|
+
<span class="roles-group-arrow">${m}</span>
|
|
724
810
|
<span class="roles-group-icon" aria-hidden="true"><svg viewBox="0 0 16 16"><circle cx="5.6" cy="5.8" r="2.4"/><path d="M1.8 13.2c.5-2.4 2-3.6 3.8-3.6s3.3 1.2 3.8 3.6"/><circle cx="11" cy="6.8" r="1.9"/><path d="M9.8 12.6c.4-1.7 1.5-2.6 2.8-2.6 1 0 1.9.5 2.4 1.6"/></svg></span>
|
|
725
811
|
<div class="roles-group-info">
|
|
726
|
-
<div class="roles-group-name">${
|
|
812
|
+
<div class="roles-group-name">${i(o.name??o.chatId)}</div>
|
|
727
813
|
<div class="roles-group-meta">
|
|
728
|
-
${
|
|
814
|
+
${k}/${v} ${t("roles.botsWithRoles")}
|
|
729
815
|
</div>
|
|
730
816
|
</div>
|
|
731
817
|
<span class="roles-group-chevron"></span>
|
|
732
818
|
</div>
|
|
733
|
-
<div class="roles-bot-list">${
|
|
734
|
-
</div>`}).join(""),n.querySelectorAll(".roles-group-row").forEach(
|
|
819
|
+
<div class="roles-bot-list">${L}</div>
|
|
820
|
+
</div>`}).join(""),n.querySelectorAll(".roles-group-row").forEach(o=>{o.addEventListener("click",()=>{let l=o.dataset.groupId;l&&($t.has(l)?$t.delete(l):$t.add(l),lt(document.getElementById("roles-search")?.value??""))})}),n.querySelectorAll(".roles-bot-row").forEach(o=>{o.addEventListener("click",l=>{l.stopPropagation();let c=o.dataset.groupId,m=o.dataset.botId;c&&m&&ii(c,m)})})}async function ii(e,n){We=e,Ke=n;let a=await co(n,e),s=document.getElementById("roles-editor-empty"),o=document.getElementById("roles-editor-form"),l=document.getElementById("roles-editor-textarea"),c=document.getElementById("roles-editor-group-name"),m=document.getElementById("roles-editor-bot-name"),k=document.getElementById("roles-editor-chat-id");s&&(s.style.display="none"),o&&(o.style.display="");let v=Zt.find(w=>w.chatId===e),L=v?.memberBots.find(w=>w.larkAppId===n);c&&(c.textContent=v?.name??e),m&&(m.textContent=L?.botName??n),k&&(k.textContent=`${e} \xB7 ${n}`),Pe=a.content??"",l&&(l.value=Pe,l.focus()),Bn(),Nn(),lt(document.getElementById("roles-search")?.value??"");let T=document.getElementById("roles-delete");T&&(T.style.display=a.hasRole?"":"none")}function Bn(){let e=document.getElementById("roles-editor-bytecount");if(!e)return;let n=new TextEncoder().encode(Pe).length;e.textContent=`${n} / ${On} bytes`,e.className=`roles-bytecount ${n>3800?"warn":""} ${n>On?"over":""}`,ri(n)}function ri(e){let n=document.getElementById("roles-save");if(!n)return;let a=e??new TextEncoder().encode(Pe).length;n.disabled=a>On||Pe.trim().length===0}function Nn(){let e=document.getElementById("roles-preview");e&&(Pe.trim()?e.innerHTML=`<strong>${t("roles.preview")}</strong><pre>${i(Pe)}</pre>`:e.innerHTML=`<small>${t("roles.previewEmpty")}</small>`)}function lo(){We=null,Ke=null,Pe="";let e=document.getElementById("roles-editor-empty"),n=document.getElementById("roles-editor-form"),a=document.getElementById("roles-editor-textarea"),s=document.getElementById("roles-delete");e&&(e.style.display=""),n&&(n.style.display="none"),a&&(a.value=""),s&&(s.style.display="none")}async function po(e){e.innerHTML=ni(),$t.clear(),lo();let n=document.getElementById("roles-tree");n&&(n.innerHTML=wt()),await Xt(),await Ge();for(let a of Zt)uo(a)>0&&$t.add(a.chatId);lt(),document.getElementById("roles-search")?.addEventListener("input",a=>{lt(a.target.value)}),document.getElementById("roles-refresh")?.addEventListener("click",async()=>{if(await Xt(),lt(document.getElementById("roles-search")?.value??""),We&&Ke){let a=await co(Ke,We),s=document.getElementById("roles-editor-textarea");s&&(s.value=a.content??""),Pe=a.content??"",Bn(),Nn();let o=document.getElementById("roles-delete");o&&(o.style.display=a.hasRole?"":"none")}}),document.getElementById("roles-save")?.addEventListener("click",async function(){if(!(!We||!Ke)){this.disabled=!0,this.textContent="...";try{if(await ai(Ke,We,Pe)){await Xt(),lt(document.getElementById("roles-search")?.value??"");let s=document.getElementById("roles-delete");s&&(s.style.display="");let o=document.createElement("span");o.className="roles-saved-flash",o.textContent=` ${t("roles.saved")}`,document.querySelector(".roles-editor-footer")?.appendChild(o),setTimeout(()=>o.remove(),2e3)}else{let s=document.createElement("span");s.className="roles-saved-flash roles-save-error",s.textContent=Pe.trim().length===0?` ${t("roles.emptyError")}`:` ${t("roles.saveFailed")}`,document.querySelector(".roles-editor-footer")?.appendChild(s),setTimeout(()=>s.remove(),3e3)}}finally{this.disabled=!1,this.textContent=t("roles.save")}}}),document.getElementById("roles-delete")?.addEventListener("click",async function(){if(!(!We||!Ke)&&confirm(t("roles.confirmDelete"))){this.disabled=!0,this.textContent="...";try{await oi(Ke,We)&&(await Xt(),lo(),lt(document.getElementById("roles-search")?.value??""))}finally{this.disabled=!1,this.textContent=t("roles.delete")}}}),document.getElementById("roles-editor-textarea")?.addEventListener("input",a=>{Pe=a.target.value,Bn(),Nn()})}async function nn(e){let n=await fetch(e);return{status:n.status,body:await n.json().catch(()=>({}))}}async function an(e,n,a){let s=await fetch(n,{method:e,headers:{"content-type":"application/json"},body:a?JSON.stringify(a):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}var ct=(e,n)=>an("POST",e,n),li=(e,n)=>an("PUT",e,n),Pn=[],mo=[],fo="",en="",qn=new Map,tn=new Map,Et=new Set,xt=new Set;function ne(e){return document.getElementById(e)}function on(){return[...Pn,...mo]}function dt(e){let n=qn.get(e);return n||(n=new Set,qn.set(e,n)),n}function di(e){return on().find(n=>n.key===e)}function go(e){let n=(a,s,o)=>`<a href="${a}" style="padding:6px 14px;border-radius:8px;text-decoration:none;font-size:14px;font-weight:600;${o?"background:var(--accent);color:var(--on-accent)":"color:var(--muted);background:var(--surface-muted)"}">${s}</a>`;return`<div style="display:flex;gap:8px;margin-bottom:14px">${n("#/team",t("team.navHome"),e==="home")}${n("#/team/manage",t("team.navManage"),e==="manage")}</div>`}function ci(){return`<section class="page">
|
|
735
821
|
<div class="page-heading"><div>
|
|
736
822
|
<p class="eyebrow">${t("team.eyebrow")}</p><h1>${t("team.homeTitle")}</h1>
|
|
737
823
|
<p class="tf-lede">${t("team.homeLede")}</p>
|
|
738
824
|
</div></div>
|
|
739
|
-
${
|
|
825
|
+
${go("home")}
|
|
740
826
|
<div class="card" style="margin-bottom:16px">
|
|
741
827
|
<h2 style="margin-top:0">${t("team.localDeployTitle")}</h2>
|
|
742
828
|
<p>${t("team.myIdentity")}<b id="tf-owner">${t("team.unbound")}</b>
|
|
@@ -765,12 +851,12 @@ ${vo("home")}
|
|
|
765
851
|
</div>
|
|
766
852
|
</div>
|
|
767
853
|
</div>
|
|
768
|
-
</section>`}function
|
|
854
|
+
</section>`}function ui(e){let n=(ne("tf-search").value||"").trim().toLowerCase();if(n&&!((e.name||"")+" "+(e.cliId||"")+" "+(e.capability||"")).toLowerCase().includes(n))return!1;let a=ne("tf-cli").value;return!(a&&e.cliId!==a||ne("tf-fcap").checked&&!e.capability||ne("tf-frole").checked&&!e.hasTeamRole)}function pi(e,n){let a=[...e.deployments].sort((o,l)=>o.local===l.local?0:o.local?-1:1),s="";for(let o of a){let l=n.filter(w=>w.deployment.id===o.id);if(!l.length)continue;let c=o.id===fo,m=c?t("team.tagLocal"):o.stale?t("team.tagRemoteStale"):t("team.tagRemote"),k=e.kind==="local"&&!c?` <button class="tf-rmmember ghost" data-team="${i(e.teamId)}" data-dep="${i(o.id)}" data-name="${i(o.name)}" style="font-size:12px">${t("team.removeMember")}</button>`:"",v=`${e.key}::${o.id}`,L=xt.has(v),T=l.filter(w=>dt(e.key).has(w.larkAppId)).length;if(s+=`<div class="tf-dep-h" data-dk="${i(v)}" style="cursor:pointer;margin:10px 0 2px"><b>${L?"\u25BE":"\u25B8"} ${i(o.name)}</b> <span class="muted" style="font-size:12px">${t("team.depTag",{tag:m})} \xB7 ${t("team.depCount",{count:l.length})}${T?t("team.depSelected",{n:T}):""}</span>${k}</div>`,!!L){s+='<table style="width:100%;border-collapse:collapse;font-size:14px"><tbody>';for(let w of l){let O=i(w.larkAppId),D=dt(e.key).has(w.larkAppId)?" checked":"",R=w.deployment.stale?"opacity:.55":"",M=c?`<input class="tf-cap" data-app="${O}" value="${i(w.capability||"")}" placeholder="${t("team.capPh")}" style="width:92%;padding:3px 6px">`:w.capability?i(w.capability):'<span class="muted">\u2014</span>',x=w.hasTeamRole?c?`<button class="tf-role" data-app="${O}" data-name="${i(w.name)}">${t("team.viewRole")}</button>`:t("team.hasRoleShort"):'<span class="muted">\u2014</span>';s+=`<tr style="${R}"><td style="padding:4px 8px"><input type="checkbox" class="tf-pick" data-tk="${i(e.key)}" data-app="${O}"${D}></td><td style="padding:4px 8px">${i(w.name)}</td><td style="padding:4px 8px" class="muted">${i(w.cliId)}</td><td style="padding:4px 8px">${M}</td><td style="padding:4px 8px">${x}</td></tr>`}s+="</tbody></table>"}}return s||(s=`<p class="muted" style="margin:8px 0 0">${t("team.noMatch")}</p>`),s+=`<div style="margin-top:12px;display:flex;gap:8px;flex-wrap:wrap;align-items:center"><input class="tf-gname" data-tk="${i(e.key)}" value="${i(tn.get(e.key)||"")}" placeholder="${t("team.gnamePh")}" style="min-width:200px"><button class="tf-grp primary" data-tk="${i(e.key)}">${t("team.pullGroupBtn")}</button><span class="muted" style="font-size:13px">${t("team.pullGroupHint")}</span><span class="tf-gout" data-tk="${i(e.key)}" style="font-size:13px;display:block;flex-basis:100%"></span></div>`,s}function ot(){let e=ne("tf-teams"),n=on();if(!n.length){e.innerHTML=`<p class="muted">${t("team.noTeams")}</p>`,ne("tf-count").textContent="";return}let a="",s=new Set,o=new Set;for(let m of n){let k=m.bots.filter(ui);k.forEach(w=>s.add(w.larkAppId)),m.bots.forEach(w=>o.add(w.larkAppId));let v=new Set(k.map(w=>w.larkAppId));[...dt(m.key)].forEach(w=>{v.has(w)||dt(m.key).delete(w)});let L=!Et.has(m.key),T=m.kind==="remote"?m.ok?` <span class="ok" style="font-size:12px">${t("team.connected")}</span>`:` <span class="err" style="font-size:12px">${t("team.connectFail",{error:i(m.error||"")})}</span>`:` <span class="muted" style="font-size:12px">${t("team.iHost")}</span>`;a+=`<div class="card" style="margin:0 0 12px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)"><div class="tf-team-h" data-tk="${i(m.key)}" style="cursor:pointer;display:flex;align-items:center;gap:8px;flex-wrap:wrap"><b style="font-size:15px">${L?"\u25B8":"\u25BE"} ${i(m.label)}</b>`+(m.sub?` <span class="muted" style="font-size:12px">${i(m.sub)}</span>`:"")+T+` <span class="muted" style="font-size:12px">\xB7 ${t("team.teamMeta",{deps:m.deployments.length,bots:m.bots.length})}</span></div>`,L||(a+=m.kind==="remote"&&!m.ok?`<p class="muted" style="margin:8px 0 0">${t("team.rosterFail")}</p>`:pi(m,k)),a+="</div>"}e.innerHTML=a;let l=n.length>1?t("team.acrossTeams",{n:n.length}):"",c=s.size===o.size?`${o.size}`:`${s.size} / ${o.size}`;ne("tf-count").textContent=`\xB7 ${c} ${t("team.botsWord")}${l}`,mi()}function mi(){let e=ne("tf-teams");e.querySelectorAll(".tf-team-h").forEach(n=>{n.onclick=()=>{let a=n.dataset.tk;Et.has(a)?Et.delete(a):Et.add(a),ot()}}),e.querySelectorAll(".tf-dep-h").forEach(n=>{n.onclick=()=>{let a=n.dataset.dk;xt.has(a)?xt.delete(a):xt.add(a),ot()}}),e.querySelectorAll(".tf-pick").forEach(n=>{n.onchange=()=>{let a=dt(n.dataset.tk);n.checked?a.add(n.dataset.app):a.delete(n.dataset.app)}}),e.querySelectorAll(".tf-gname").forEach(n=>{n.oninput=()=>{tn.set(n.dataset.tk,n.value)}}),e.querySelectorAll(".tf-cap").forEach(n=>{n.onchange=async()=>{let a=n.dataset.app,s=n.value;await li("/api/team/local-bots/"+encodeURIComponent(a)+"/capability",{capability:s}),on().forEach(o=>{let l=o.bots.find(c=>c.larkAppId===a);l&&(l.capability=s.trim()||null)})}}),e.querySelectorAll(".tf-role").forEach(n=>{n.onclick=()=>gi(n.dataset.app,n.dataset.name||"")}),e.querySelectorAll(".tf-rmmember").forEach(n=>{n.onclick=async a=>{a.stopPropagation(),confirm(t("team.removeMemberConfirm",{name:n.dataset.name||""}))&&(await an("DELETE",`/api/team/hosted/${encodeURIComponent(n.dataset.team)}/members/${encodeURIComponent(n.dataset.dep)}`),Ht())}}),e.querySelectorAll(".tf-grp").forEach(n=>{n.onclick=async()=>{let a=n.dataset.tk,s=di(a);if(!s)return;let o=[...dt(a)],l=e.querySelector(`.tf-gout[data-tk="${CSS.escape(a)}"]`);if(!o.length){l.innerHTML=`<span class="err">${t("team.errPickBot")}</span>`;return}let c=(e.querySelector(`.tf-gname[data-tk="${CSS.escape(a)}"]`)?.value||"").trim()||t("team.defaultGroupName");l.innerHTML=`<span class="muted">${t("team.creatingGroup")}</span>`;let m=s.kind==="local"?await ct("/api/team/federated-group",{name:c,larkAppIds:o,teamId:s.teamId}):await ct("/api/team/remote-group",{hubUrl:s.hubUrl,teamId:s.teamId,name:c,larkAppIds:o});if(fi(l,m.body,m.status),m.body?.ok){dt(a).clear(),tn.delete(a);let k=l.innerHTML,v=()=>{let L=e.querySelector(`.tf-gout[data-tk="${CSS.escape(a)}"]`);L&&(L.innerHTML=k)};s.kind==="local"?Ht().then(v):(ot(),v())}}})}function fi(e,n,a){if(n?.ok&&n.chatId){let s=n.shareLink||"https://applink.feishu.cn/client/chat/open?openChatId="+encodeURIComponent(n.chatId),o=(n.invalidBotIds||[]).length?` <span class="err"> \xB7 ${t("team.invalidBots",{ids:i((n.invalidBotIds||[]).join(", "))})}</span>`:"",l=(n.invalidOwnerUnionIds||[]).length?`<span class="err"> \xB7 ${t("team.invalidOwners",{n:(n.invalidOwnerUnionIds||[]).length})}</span>`:"",c=n.missingOperatorIdentity?`<span class="err"> \xB7 ${t("team.missingIdentity")}</span>`:"",m=(n.skippedNoOwner||[]).length?`<span class="err"> \xB7 ${t("team.skippedNoOwner",{n:(n.skippedNoOwner||[]).length})}</span>`:"",k=n.delegatedTo?t("team.delegatedBy",{name:i(n.delegatedTo)}):"";e.innerHTML=`<span class="ok">${t("team.groupCreated")}</span>${k} \xB7 <a href="${i(s)}" target="_blank">${t("team.openInLark")}</a>${o}${l}${c}${m}`}else{let s=n?.error||a,o=s==="no_local_online_bot"?t("team.errNoLocalBot"):s==="all_bots_skipped_no_owner"?t("team.errAllSkipped"):s==="no_creator_available"?t("team.errNoCreator"):s==="delegation_timeout"?t("team.errDelegationTimeout"):t("team.errGroupCreate",{error:String(s)});e.innerHTML=`<span class="err">${i(String(o))}</span>`}}async function gi(e,n){let a=await nn("/api/team/local-bots/"+encodeURIComponent(e)+"/role");ne("tf-modal-title").textContent=t("team.roleModalTitleName",{name:n}),ne("tf-modal-text").value=a.body?.role||"",ne("tf-modal").dataset.app=e,ne("tf-modal").style.display="flex"}function bo(){let e=Array.from(new Set(on().flatMap(s=>s.bots.map(o=>o.cliId)).filter(Boolean))).sort(),n=ne("tf-cli"),a=n.value;n.innerHTML=`<option value="">${t("team.allCli")}</option>`+e.map(s=>`<option value="${i(s)}">${i(s)}</option>`).join(""),n.value=a}async function Ht(){let n=(await nn("/api/team/hosted")).body;if(!n?.ok){Pn=[],ot();return}fo=n.deployment.deploymentId,en=n.suggestedHubUrl||"",ne("tf-owner").textContent=n.deployment.ownerName||(n.deployment.ownerUnionId?t("team.bound"):t("team.unbound")),Pn=(n.teams||[]).map(a=>({kind:"local",key:`local:${a.teamId}`,teamId:a.teamId,label:a.isDefault?t("team.myHostedTeam"):a.name,sub:"",ok:!0,deployments:a.deployments||[],bots:a.bots||[]})),bo(),ot()}async function bi(){mo=((await nn("/api/team/remote-roster")).body?.memberships||[]).map(a=>{let s=a.roster?.deployments||[],o=s.find(c=>c.local),l=o?.name?t("team.remoteTeamLabel",{name:o.name}):a.teamName||a.teamId;return{kind:"remote",key:`${a.hubUrl}::${a.teamId}`,teamId:a.teamId,label:l,sub:a.hubUrl,ok:!!a.ok,error:a.error,hubUrl:a.hubUrl,deployments:s,bots:a.roster?.bots||[]}}),bo(),ot()}function ho(e){e.innerHTML=ci(),qn.clear(),tn.clear(),Et.clear(),xt.clear(),["tf-search","tf-cli","tf-fcap","tf-frole"].forEach(n=>{let a=ne(n);a.oninput=ot,a.onchange=ot}),ne("tf-modal-cancel").onclick=()=>{ne("tf-modal").style.display="none"},wi(),Ht(),bi()}function hi(){return`<section class="page">
|
|
769
855
|
<div class="page-heading"><div>
|
|
770
856
|
<p class="eyebrow">${t("team.eyebrow")}</p><h1>${t("team.manageTitle")}</h1>
|
|
771
857
|
<p class="tf-lede">${t("team.manageLede")}</p>
|
|
772
858
|
</div></div>
|
|
773
|
-
${
|
|
859
|
+
${go("manage")}
|
|
774
860
|
<div class="card" style="margin-bottom:16px">
|
|
775
861
|
<h2 style="margin-top:0">${t("team.hostedTitle")}</h2>
|
|
776
862
|
<p style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:6px">
|
|
@@ -789,16 +875,16 @@ ${vo("manage")}
|
|
|
789
875
|
</p>
|
|
790
876
|
<div id="tm-join-out" style="display:none;margin-top:6px"></div>
|
|
791
877
|
</div>
|
|
792
|
-
</section>`}async function
|
|
878
|
+
</section>`}async function Un(){let n=(await nn("/api/team/hosted")).body,a=ne("tm-list");en=n?.suggestedHubUrl||en;let s=n?.teams||[];if(!s.length){a.innerHTML=`<p class="muted">${t("team.noTeamsShort")}</p>`;return}a.innerHTML=s.map(o=>{let l=(o.deployments||[]).filter(c=>!c.local).length;return`<div class="card" style="margin:0 0 8px;padding:10px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
793
879
|
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
794
|
-
<b>${
|
|
795
|
-
<span class="muted" style="font-size:12px">\xB7 ${t("team.manageMetaDeps",{count:(
|
|
880
|
+
<b>${i(o.name)}</b>${o.isDefault?` <span class="muted" style="font-size:12px">${t("team.default")}</span>`:""}
|
|
881
|
+
<span class="muted" style="font-size:12px">\xB7 ${t("team.manageMetaDeps",{count:(o.deployments||[]).length})}${l?t("team.manageMetaRemote",{r:l}):""} \xB7 ${t("team.manageMetaBots",{count:(o.bots||[]).length})}</span>
|
|
796
882
|
<span style="margin-left:auto;display:flex;gap:6px">
|
|
797
|
-
<button class="tm-invite ghost" data-team="${
|
|
798
|
-
${
|
|
883
|
+
<button class="tm-invite ghost" data-team="${i(o.teamId)}" style="font-size:12px">${t("team.genInvite")}</button>
|
|
884
|
+
${o.isDefault?"":`<button class="tm-del ghost" data-team="${i(o.teamId)}" data-name="${i(o.name)}" style="font-size:12px">${t("team.delBtn")}</button>`}
|
|
799
885
|
</span>
|
|
800
886
|
</div>
|
|
801
|
-
<div class="tm-inv-out" data-team="${
|
|
887
|
+
<div class="tm-inv-out" data-team="${i(o.teamId)}" style="display:none;margin-top:6px;font-size:13px"></div></div>`}).join(""),a.querySelectorAll(".tm-invite").forEach(o=>{o.onclick=async()=>{let l=o.dataset.team,c=a.querySelector(`.tm-inv-out[data-team="${CSS.escape(l)}"]`);c.style.display="",c.innerHTML=`<span class="muted">${t("team.generating")}</span>`;let m=await ct("/api/team/local-invite",{teamId:l});m.body?.code?c.innerHTML=`${t("team.inviteResultLede")}<br>${t("team.inviteHub")}<code>${i(en)}</code><br>${t("team.inviteCode")}<code style="font-size:15px">${i(m.body.code)}</code>`:c.innerHTML=`<span class="err">${t("team.genFail")}</span>`}}),a.querySelectorAll(".tm-del").forEach(o=>{o.onclick=async()=>{confirm(t("team.delConfirm",{name:o.dataset.name||""}))&&(await an("DELETE","/api/team/hosted/"+encodeURIComponent(o.dataset.team)),Un())}})}function wo(e){e.innerHTML=hi(),ne("tm-create").onclick=async()=>{let n=ne("tm-newname").value.trim(),a=e.querySelector(".tm-cout");if(!n){a.innerHTML=`<span class="err">${t("team.errName")}</span>`;return}a.innerHTML=`<span class="muted">${t("team.creating")}</span>`;let s=await ct("/api/team/hosted",{name:n});s.body?.ok?(a.innerHTML=`<span class="ok">${t("team.created")}</span>`,ne("tm-newname").value="",Un()):a.innerHTML=`<span class="err">${t("team.createFail",{error:i(String(s.body?.error||s.status))})}</span>`},ne("tm-join").onclick=async()=>{let n=ne("tm-hub").value.trim(),a=ne("tm-code").value.trim(),s=ne("tm-join-out");if(s.style.display="",!n||!a){s.innerHTML=`<span class="err">${t("team.errHubCode")}</span>`;return}s.innerHTML=`<span class="muted">${t("team.joining")}</span>`;let o=await ct("/api/team/join-remote",{hubUrl:n,inviteCode:a});if(o.body?.ok)s.innerHTML=`<span class="ok">${t("team.joined",{name:i(o.body.teamName||"")})}</span>`,ne("tm-code").value="";else{let l=o.body?.error||o.status,c=l==="cannot_join_self"?t("team.joinErrSelf"):l==="deployment_already_joined"?t("team.joinErrAlready"):l==="hub_unreachable"?t("team.joinErrUnreachable"):l==="hub_timeout"?t("team.joinErrTimeout"):t("team.joinErrGeneric",{error:String(l)});s.innerHTML=`<span class="err">${i(String(c))}</span>`}},Un()}function wi(){ne("tf-autobind").onclick=async()=>{let e=ne("tf-bind-out");e.style.display="",e.innerHTML=`<span class="muted">${t("team.identifying")}</span>`;let a=(await ct("/api/team/identity/auto-bind")).body;if(a?.ok&&a.owner){e.innerHTML=`<span class="ok">${t("team.bound2",{name:i(a.owner.name||a.owner.unionId)})}</span>`,Ht();return}if(a?.ok&&a.needChoice&&Array.isArray(a.candidates)){let s=a.candidates.map(o=>`<button class="tf-pickowner ghost" data-union="${i(o.unionId)}" style="margin:2px">${i(o.name||o.unionId)}</button>`).join(" ");e.innerHTML=`${t("team.multiCandidate")}<br>${s}`,e.querySelectorAll(".tf-pickowner").forEach(o=>{o.onclick=async()=>{e.innerHTML=`<span class="muted">${t("team.binding")}</span>`;let c=(await ct("/api/team/identity/auto-bind",{unionId:o.dataset.union})).body;c?.ok&&c.owner?(e.innerHTML=`<span class="ok">${t("team.bound2",{name:i(c.owner.name||c.owner.unionId)})}</span>`,Ht()):e.innerHTML=`<span class="err">${t("team.bindFail",{error:i(String(c?.error||"unknown"))})}</span>`}});return}if(a?.error==="no_candidates"){e.innerHTML=`<span class="err">${t("team.noCandidates")}</span>`;return}e.innerHTML=`<span class="err">${t("team.bindFail",{error:i(String(a?.error||"unknown"))})}</span>`}}async function jn(e){let n=await fetch(e);return{status:n.status,body:await n.json().catch(()=>({}))}}async function _n(e,n,a){let s=await fetch(n,{method:e,headers:{"content-type":"application/json"},body:a?JSON.stringify(a):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}function ae(e){return document.getElementById(e)}function ut(e){return(ae(e).value||"").trim()}var Gn=[],Wn=[];function yi(){return`<section class="page">
|
|
802
888
|
<div class="page-heading">
|
|
803
889
|
<div>
|
|
804
890
|
<p class="eyebrow">Webhook</p>
|
|
@@ -860,28 +946,28 @@ ${vo("manage")}
|
|
|
860
946
|
<h2 style="margin-top:0">${t("connectors.listTitle")} <span class="muted" id="cn-count" style="font-size:13px"></span></h2>
|
|
861
947
|
<div id="cn-list">${t("connectors.loading")}</div>
|
|
862
948
|
</div>
|
|
863
|
-
</section>`}function
|
|
949
|
+
</section>`}function Fn(){let e=ae("cn-kind").value,n=ae("cn-mode").value;document.querySelectorAll(".cn-wf").forEach(a=>{a.style.display=e==="workflow"?"":"none"}),document.querySelectorAll(".cn-fixed").forEach(a=>{a.style.display=n==="fixed"?"":"none"}),document.querySelectorAll(".cn-allow").forEach(a=>{a.style.display=n==="fixed"?"none":""}),document.querySelectorAll(".cn-dyn").forEach(a=>{a.style.display=n==="dynamic"?"":"none"}),document.querySelectorAll(".cn-life").forEach(a=>{a.style.display=n==="new-group"?"":"none"})}function yo(e){return`${location.origin}/webhook/${encodeURIComponent(e)}`}function vi(e){return e==="fixed"?t("connectors.modeLabelFixed"):e==="new-group"?t("connectors.modeLabelNewGroup"):t("connectors.modeLabelDynamic")}function ki(e){return e==="workflow"?t("connectors.kindLabelWorkflow"):t("connectors.kindLabelTurn")}function zn(e){return Wn.find(a=>a.chatId===e)?.name||e}function $i(e){return Wn.filter(n=>n.bots.includes(e))}function vo(){let e=ae("cn-bot").value,n=$i(e),a=m=>`<option value="${i(m.chatId)}">${i(m.name||m.chatId)}</option>`,s=ae("cn-chat-sel"),o=s.value;s.innerHTML=n.length?n.map(a).join(""):`<option value="">${t("connectors.noBotGroups")}</option>`,o&&n.some(m=>m.chatId===o)&&(s.value=o);let l=ae("cn-allow-sel"),c=new Set(Array.from(l.selectedOptions).map(m=>m.value));l.innerHTML=n.map(a).join(""),Array.from(l.options).forEach(m=>{c.has(m.value)&&(m.selected=!0)})}function Si(e){let n=ae("cn-list");if(ae("cn-count").textContent=e.length?t("connectors.count",{count:e.length}):"",!e.length){n.innerHTML=`<p class="muted">${t("connectors.empty")}</p>`;return}n.innerHTML=e.map(a=>{let s=Gn.find(k=>k.larkAppId===a.target.botId),o=yo(a.id),l=(a.verify?.type??"token")==="token",c=l?t("connectors.badgeToken"):t("connectors.badgeSign"),m=a.target.mode==="fixed"&&a.target.chatId?` \xB7 ${t("connectors.dest",{name:i(zn(a.target.chatId))})}`:"";return`<div class="card" style="margin:0 0 10px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
864
950
|
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
865
|
-
<b style="font-size:15px">${
|
|
866
|
-
<span class="${
|
|
867
|
-
<span class="muted" style="font-size:12px">\xB7 ${
|
|
951
|
+
<b style="font-size:15px">${i(a.name)}</b>
|
|
952
|
+
<span class="${a.enabled?"ok":"muted"}" style="font-size:12px">${a.enabled?t("connectors.enabled"):t("connectors.disabled")}</span>
|
|
953
|
+
<span class="muted" style="font-size:12px">\xB7 ${i(s?.botName||a.target.botId)} \xB7 ${ki(a.target.kind)} \xB7 ${vi(a.target.mode)}${m} \xB7 ${c}</span>
|
|
868
954
|
<span style="margin-left:auto;display:flex;gap:6px">
|
|
869
|
-
<button class="cn-toggle ghost" data-id="${
|
|
870
|
-
<button class="cn-del ghost" data-id="${
|
|
955
|
+
<button class="cn-toggle ghost" data-id="${i(a.id)}" data-on="${a.enabled}" style="font-size:12px">${a.enabled?t("connectors.btnDisable"):t("connectors.btnEnable")}</button>
|
|
956
|
+
<button class="cn-del ghost" data-id="${i(a.id)}" style="font-size:12px">${t("connectors.btnDel")}</button>
|
|
871
957
|
</span>
|
|
872
958
|
</div>
|
|
873
959
|
<div style="margin-top:6px;font-size:13px;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
874
|
-
<span class="muted">${t("connectors.webhookUrl")}</span><code style="font-size:12px;word-break:break-all">${
|
|
875
|
-
<button class="cn-copy ghost" data-url="${
|
|
876
|
-
</div>${
|
|
877
|
-
<pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${
|
|
878
|
-
<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicNote")}</p>`}else
|
|
879
|
-
<pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${
|
|
880
|
-
<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageTokenNote")}</p
|
|
881
|
-
<p class="ok" style="margin:0 0 6px">${t("connectors.createdPrefix",{name:
|
|
882
|
-
<p style="margin:4px 0;font-size:13px"><span class="muted">${t("connectors.webhookUrl")}</span><code style="word-break:break-all">${
|
|
883
|
-
${
|
|
884
|
-
${
|
|
960
|
+
<span class="muted">${t("connectors.webhookUrl")}</span><code style="font-size:12px;word-break:break-all">${i(o)}${l?"/<token>":""}</code>
|
|
961
|
+
<button class="cn-copy ghost" data-url="${i(o)}" style="font-size:12px">${t("connectors.copy")}</button>
|
|
962
|
+
</div>${l?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.tokenHint")}</div>`:""}${a.target.mode==="dynamic"?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.dynamicReqHint")}</div>`:""}${a.promptEnvelope?.instruction?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.instructionPrefix")}${i(a.promptEnvelope.instruction)}</div>`:""}</div>`}).join(""),n.querySelectorAll(".cn-copy").forEach(a=>{a.onclick=()=>{navigator.clipboard?.writeText(a.dataset.url),a.textContent=t("connectors.copied"),setTimeout(()=>a.textContent=t("connectors.copy"),1200)}}),n.querySelectorAll(".cn-toggle").forEach(a=>{a.onclick=async()=>{await _n("PATCH","/api/connectors/"+encodeURIComponent(a.dataset.id),{enabled:a.dataset.on!=="true"}),sn()}}),n.querySelectorAll(".cn-del").forEach(a=>{a.onclick=async()=>{confirm(t("connectors.delConfirm"))&&(await _n("DELETE","/api/connectors/"+encodeURIComponent(a.dataset.id)),sn())}})}async function sn(){let[e,n,a]=await Promise.all([jn("/api/bots"),jn("/api/connectors"),jn("/api/groups")]);Gn=(e.body?.bots||[]).map(l=>({larkAppId:l.larkAppId,botName:l.botName||l.larkAppId})),Wn=(a.body?.chats||[]).map(l=>({chatId:l.chatId,name:l.name||"",bots:(l.memberBots||[]).filter(c=>c.inChat).map(c=>c.larkAppId)}));let s=ae("cn-bot"),o=s.value;s.innerHTML=Gn.map(l=>`<option value="${i(l.larkAppId)}">${i(l.botName)}</option>`).join("")||`<option value="">${t("connectors.noOnlineBots")}</option>`,o&&(s.value=o),vo(),Si(n.body?.connectors||[])}function ko(e){e.innerHTML=yi(),ae("cn-kind").onchange=Fn,ae("cn-mode").onchange=Fn,ae("cn-bot").onchange=vo,ae("cn-chat-manual").onclick=n=>{n.preventDefault();let a=ae("cn-chat"),s=ae("cn-chat-sel"),o=a.style.display==="none";a.style.display=o?"":"none",s.style.display=o?"none":"",ae("cn-chat-manual").textContent=o?t("connectors.chatListLink"):t("connectors.chatManualLink")},Fn(),ae("cn-create").onclick=async()=>{let n=ae("cn-create-out"),a=ut("cn-name"),s=ae("cn-bot").value;if(!a){n.innerHTML=`<span class="err">${t("connectors.errName")}</span>`;return}if(!s){n.innerHTML=`<span class="err">${t("connectors.errBot")}</span>`;return}let o=ae("cn-kind").value,l=ae("cn-mode").value,c={name:a,enabled:!0,target:{kind:o,mode:l,botId:s},promptEnvelope:{sourceName:a}},m=ut("cn-instruction");if(m&&(c.promptEnvelope.instruction=m),o==="workflow"){if(!ut("cn-wf")){n.innerHTML=`<span class="err">${t("connectors.errWf")}</span>`;return}c.target.workflowId=ut("cn-wf")}if(l==="fixed"){let T=ae("cn-chat").style.display!=="none"?ut("cn-chat"):ae("cn-chat-sel").value;if(!T){n.innerHTML=`<span class="err">${t("connectors.errChat")}</span>`;return}c.target.chatId=T}else{let L=Array.from(ae("cn-allow-sel").selectedOptions).map(T=>T.value).filter(Boolean);L.length&&(c.target.allowChats=L)}if(l==="new-group"){let L=ut("cn-dedup");c.lifecycleExtractors=L?{dedupKey:L}:null}c.verify={type:ae("cn-verify").value};let k=ut("cn-secret");k&&(c.secret=k),n.innerHTML=`<span class="muted">${t("connectors.creating")}</span>`;let v=await _n("POST","/api/connectors",c);if(v.status===201&&v.body?.ok){n.innerHTML="";let L=ae("cn-created");L.style.display="";let T=v.body.webhookUrl||yo(v.body.connector.id),w=v.body.secret,O=(v.body.connector?.verify?.type??"token")==="token",D=l==="dynamic",R=D?c.target.allowChats?.[0]||"<chatId>":"",M=D?`${i(T)}?chatId=${i(R)}`:i(T),x;if(O&&D){let d=R!=="<chatId>"?`\uFF08${i(zn(c.target.allowChats[0]))}\uFF09`:"";x=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicLede",{gn:d})}</p>
|
|
963
|
+
<pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${M}' -H 'content-type: application/json' -d '{}'</code></pre>
|
|
964
|
+
<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicNote")}</p>`}else O?x=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageTokenLede")}</p>
|
|
965
|
+
<pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${M}' -H 'content-type: application/json' -d '{}'</code></pre>
|
|
966
|
+
<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageTokenNote")}</p>`:x=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageHmac")}${D?t("connectors.usageHmacDynamic"):""}</p>`;L.innerHTML=`<div class="card" style="padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
967
|
+
<p class="ok" style="margin:0 0 6px">${t("connectors.createdPrefix",{name:i(a)})}${l==="fixed"&&c.target.chatId?`<span class="muted" style="font-weight:400;font-size:13px"> \xB7 ${t("connectors.createdDest",{name:i(zn(c.target.chatId))})}</span>`:""}</p>
|
|
968
|
+
<p style="margin:4px 0;font-size:13px"><span class="muted">${t("connectors.webhookUrl")}</span><code style="word-break:break-all">${i(T)}</code></p>
|
|
969
|
+
${w?`<p style="margin:4px 0;font-size:13px"><span class="muted">${O?t("connectors.tokenLabel"):t("connectors.signLabel")}${t("connectors.secretOnce")}</span><code>${i(w)}</code></p>`:""}
|
|
970
|
+
${x}</div>`,["cn-name","cn-wf","cn-chat","cn-dedup","cn-secret","cn-instruction"].forEach(d=>{ae(d).value=""}),ae("cn-allow-sel").selectedIndex=-1,sn()}else{let L=v.body?.error||v.status;n.innerHTML=`<span class="err">${t("connectors.createFailed",{error:i(String(L))})}</span>`}},sn()}var Ae=null,At=null,Ct=!0;function $o(e){return{publicReadOnly:e?.publicReadOnly===!0,openTerminalInFeishu:e?.openTerminalInFeishu===!0,maintenance:e?.maintenance&&typeof e.maintenance=="object"?e.maintenance:{},localDevInstall:e?.localDevInstall===!0}}function Ti(e,n){let a=e?.[n]??{};return{enabled:a.enabled===!0,time:typeof a.time=="string"?a.time:"04:00"}}function Li(){return`<section class="page">
|
|
885
971
|
<div class="page-heading">
|
|
886
972
|
<div>
|
|
887
973
|
<p class="eyebrow">${t("nav.settings")}</p>
|
|
@@ -890,7 +976,7 @@ ${vo("manage")}
|
|
|
890
976
|
</div>
|
|
891
977
|
</div>
|
|
892
978
|
<div id="settings-body"></div>
|
|
893
|
-
</section>`}function
|
|
979
|
+
</section>`}function Ii(e){let{enabled:n,time:a}=Ti(Ae.maintenance,"autoUpdate"),s=e?"disabled":"";return`<label class="toggle-row">
|
|
894
980
|
<input type="checkbox" data-maint="autoUpdate" ${n?"checked":""} ${s}>
|
|
895
981
|
<span class="switch" aria-hidden="true"></span>
|
|
896
982
|
<span class="toggle-tx"><strong>${t("settings.autoUpdate")}</strong>
|
|
@@ -898,20 +984,20 @@ ${vo("manage")}
|
|
|
898
984
|
</label>
|
|
899
985
|
<div class="maint-time">
|
|
900
986
|
<label>${t("settings.maintenanceTime")}
|
|
901
|
-
<input type="time" data-maint-time="autoUpdate" value="${
|
|
987
|
+
<input type="time" data-maint-time="autoUpdate" value="${i(a)}" ${s}>
|
|
902
988
|
</label>
|
|
903
|
-
</div>`}function
|
|
904
|
-
<input type="checkbox" data-maint="autoRestart" ${
|
|
989
|
+
</div>`}function Mi(e){return`<label class="toggle-row">
|
|
990
|
+
<input type="checkbox" data-maint="autoRestart" ${Ae.maintenance.autoRestart?.enabled===!0?"checked":""} ${e?"disabled":""}>
|
|
905
991
|
<span class="switch" aria-hidden="true"></span>
|
|
906
992
|
<span class="toggle-tx"><strong>${t("settings.autoRestart")}</strong>
|
|
907
993
|
<small>${t("settings.autoRestartHelp")}</small></span>
|
|
908
|
-
</label>`}function
|
|
994
|
+
</label>`}function Ei(){if(At)return`<p class="hint-warn">${t("settings.loadFailed")}: ${i(At)}</p>`;if(!Ae)return`<p class="empty">${t("settings.loading")}</p>`;let e=Ct?"":"disabled",n=!Ct||Ae.localDevInstall;return`<div class="settings-grid">
|
|
909
995
|
<article class="bd-card settings-card">
|
|
910
|
-
${
|
|
996
|
+
${Ct?"":`<p class="hint-warn">${t("settings.readOnlyVisitor")}</p>`}
|
|
911
997
|
<section class="bd-section">
|
|
912
998
|
<h3 class="bd-section-title">${t("settings.sectionAccess")}</h3>
|
|
913
999
|
<label class="toggle-row">
|
|
914
|
-
<input type="checkbox" data-setting="publicReadOnly" ${
|
|
1000
|
+
<input type="checkbox" data-setting="publicReadOnly" ${Ae.publicReadOnly?"checked":""} ${e}>
|
|
915
1001
|
<span class="switch" aria-hidden="true"></span>
|
|
916
1002
|
<span class="toggle-tx"><strong>${t("settings.publicReadOnly")}</strong>
|
|
917
1003
|
<small>${t("settings.publicReadOnlyHelp")}</small></span>
|
|
@@ -920,7 +1006,7 @@ ${vo("manage")}
|
|
|
920
1006
|
<section class="bd-section">
|
|
921
1007
|
<h3 class="bd-section-title">${t("settings.sectionCards")}</h3>
|
|
922
1008
|
<label class="toggle-row">
|
|
923
|
-
<input type="checkbox" data-setting="openTerminalInFeishu" ${
|
|
1009
|
+
<input type="checkbox" data-setting="openTerminalInFeishu" ${Ae.openTerminalInFeishu?"checked":""} ${e}>
|
|
924
1010
|
<span class="switch" aria-hidden="true"></span>
|
|
925
1011
|
<span class="toggle-tx"><strong>${t("settings.openTerminalInFeishu")}</strong>
|
|
926
1012
|
<small>${t("settings.openTerminalInFeishuHelp")}</small></span>
|
|
@@ -928,50 +1014,50 @@ ${vo("manage")}
|
|
|
928
1014
|
</section>
|
|
929
1015
|
<section class="bd-section">
|
|
930
1016
|
<h3 class="bd-section-title">${t("settings.sectionMaintenance")}</h3>
|
|
931
|
-
${
|
|
932
|
-
${
|
|
933
|
-
${
|
|
1017
|
+
${Ii(n)}
|
|
1018
|
+
${Ae.localDevInstall?`<p class="hint-warn">${t("settings.autoUpdateLocalDev")}</p>`:""}
|
|
1019
|
+
${Mi(!Ct||Ae.maintenance.autoUpdate?.enabled!==!0)}
|
|
934
1020
|
</section>
|
|
935
1021
|
<div class="actions settings-actions">
|
|
936
1022
|
<span class="oncall-status" data-settings-status></span>
|
|
937
1023
|
</div>
|
|
938
1024
|
</article>
|
|
939
|
-
</div>`}async function
|
|
1025
|
+
</div>`}async function xi(){try{let e=await fetch("/api/settings"),n=await e.json().catch(()=>({}));if(!e.ok){Ae=null,At=n?.error??`HTTP ${e.status}`;return}Ae=$o(n.settings),Ct=n.authed===!0,At=null}catch(e){Ae=null,At=e?.message??String(e)}}async function So(e){e.innerHTML=Li();let n=e.querySelector("#settings-body");function a(){n.innerHTML=Ei(),l()}function s(){return n.querySelector("[data-settings-status]")}async function o(c,m,k){if(!Ae)return;k.disabled=!0;let v=s();v&&(v.textContent=t("settings.saving"),v.className="oncall-status");try{let L=await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(c)}),T=await L.json().catch(()=>({}));if(!L.ok||T.ok===!1)throw new Error(T?.error??`HTTP ${L.status}`);Ae=$o(T.settings),v&&(v.textContent=t("settings.saved"),v.classList.add("hint-ok"))}catch(L){m(),v&&(v.textContent=`${t("settings.saveFailed")}: ${L?.message??L}`,v.classList.add("hint-warn-inline"))}finally{k.disabled=!1}}function l(){n.querySelectorAll("input[data-setting]").forEach(m=>{m.addEventListener("change",()=>{let k=m.dataset.setting,v=!m.checked;o({[k]:m.checked},()=>{m.checked=v},m)})});let c=(m,k,v)=>{let T=n.querySelector(`input[data-maint="${m}"]`)?.checked??!1,w;if(m==="autoUpdate"){let O=n.querySelector('input[data-maint-time="autoUpdate"]');w={enabled:T,time:O?.value||"04:00"}}else w={enabled:T};o({maintenance:{[m]:w}},v,k).then(()=>a())};n.querySelectorAll("input[data-maint]").forEach(m=>{m.addEventListener("change",()=>{let k=m.dataset.maint,v=!m.checked;c(k,m,()=>{m.checked=v})})}),n.querySelectorAll("input[data-maint-time]").forEach(m=>{m.addEventListener("change",()=>{let k=m.dataset.maintTime,v=m.defaultValue;c(k,m,()=>{m.value=v})})})}a(),await xi(),a()}function Hi(){let e=[["",t("workflow.filter.nonTerminal")],["all",t("workflow.filter.all")],["pending",st("pending")],["running",st("running")],["waiting",st("waiting")],["succeeded",st("succeeded")],["failed",st("failed")],["cancelled",st("cancelled")]];return`
|
|
940
1026
|
<nav class="wf-subnav">
|
|
941
|
-
<a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${
|
|
942
|
-
<a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${
|
|
1027
|
+
<a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${b(t("workflow.subnav.runs"))}</a>
|
|
1028
|
+
<a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${b(t("workflow.subnav.catalog"))}</a>
|
|
943
1029
|
</nav>
|
|
944
1030
|
<form id="wf-filters" class="filters">
|
|
945
|
-
<input type="search" name="q" placeholder="${
|
|
1031
|
+
<input type="search" name="q" placeholder="${b(t("workflow.searchPlaceholder"))}" />
|
|
946
1032
|
<select name="status">
|
|
947
|
-
${e.map(([n,
|
|
1033
|
+
${e.map(([n,a])=>`<option value="${b(n)}">${b(a)}</option>`).join("")}
|
|
948
1034
|
</select>
|
|
949
1035
|
<span id="wf-last-load" class="muted"></span>
|
|
950
1036
|
</form>
|
|
951
1037
|
<table>
|
|
952
1038
|
<thead><tr>
|
|
953
|
-
<th>${
|
|
954
|
-
<th>${
|
|
955
|
-
<th>${
|
|
1039
|
+
<th>${b(t("workflow.table.run"))}</th><th>${b(t("workflow.table.workflow"))}</th><th>${b(t("workflow.table.status"))}</th>
|
|
1040
|
+
<th>${b(t("workflow.table.lastSeq"))}</th><th>${b(t("workflow.table.dangling"))}</th><th>${b(t("workflow.table.updated"))}</th>
|
|
1041
|
+
<th>${b(t("workflow.table.chatApp"))}</th>
|
|
956
1042
|
</tr></thead>
|
|
957
1043
|
<tbody id="wf-tbody"></tbody>
|
|
958
1044
|
</table>
|
|
959
|
-
`}var
|
|
960
|
-
<td><a href="#/workflows/${encodeURIComponent(
|
|
961
|
-
<td>${
|
|
962
|
-
<td>${
|
|
963
|
-
<td>${
|
|
964
|
-
<td class="${d}">${
|
|
965
|
-
<td title="${
|
|
966
|
-
<td>${
|
|
967
|
-
</tr>`}).join("")}function
|
|
1045
|
+
`}var Ci=5e3,Ai=2e3,Dt=new Set(["succeeded","failed","cancelled"]);function b(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function Di(e){let n=new Date(e),s=Date.now()-e;return s<6e4?t("time.secondsAgo",{value:Math.max(1,Math.floor(s/1e3))}):s<36e5?t("time.minutesAgo",{value:Math.floor(s/6e4)}):s<864e5?t("time.hoursAgo",{value:Math.floor(s/36e5)}):n.toISOString().slice(0,19).replace("T"," ")}function Xe(e){return`<span class="${Dt.has(e)?"wf-status terminal":"wf-status live"} wf-status-${b(e)}">${b(st(e))}</span>`}function st(e){let n=`workflow.status.${e}`,a=t(n);return a===n?e:a}function Mo(e){let n=location.hash.match(/^#\/workflows\/([^?#]+)(?:\?([^#]*))?$/);if(n){let a=new URLSearchParams(n[2]??"");return Oi(e,decodeURIComponent(n[1]),{focusAttemptId:a.get("attempt")??void 0})}return Ri(e)}function Ri(e){e.innerHTML=Hi();let n=e.querySelector("#wf-tbody"),a=e.querySelector("#wf-filters"),s=e.querySelector("#wf-last-load"),o=[],l=null,c=!1,m=null,k=!1;function v(R){let x=(new FormData(a).get("q")??"").trim().toLowerCase();return x?R.filter(d=>d.runId.toLowerCase().includes(x)||d.workflowId.toLowerCase().includes(x)||(d.chatId??"").toLowerCase().includes(x)):R}function L(){let R=v(o);if(R.length===0){n.innerHTML=`<tr><td colspan="7" class="empty">${m?b(t("workflow.list.failedLoad",{error:m})):o.length===0?b(t("workflow.list.noRuns")):b(t("workflow.list.noFilterMatch"))}</td></tr>`;return}n.innerHTML=R.map(M=>{let x=`${M.dEf}/${M.dAct}/${M.dWait}`,d=M.dEf+M.dAct+M.dWait>0?"wf-dangling has":"wf-dangling none",y=[];M.chatId&&y.push(b(M.chatId)),M.larkAppId&&y.push(`<span class="muted">${b(M.larkAppId)}</span>`);let H=y.length>0?y.join("<br/>"):"\u2014",I=Ni(M);return`<tr data-runid="${b(M.runId)}">
|
|
1046
|
+
<td><a href="#/workflows/${encodeURIComponent(M.runId)}"><code>${b(M.runId)}</code></a></td>
|
|
1047
|
+
<td>${b(M.workflowId)}</td>
|
|
1048
|
+
<td>${Xe(M.status)}${M.failedNodeId?` <span class="muted">(${b(M.failedNodeId)})</span>`:""}${I}</td>
|
|
1049
|
+
<td>${M.lastSeq}</td>
|
|
1050
|
+
<td class="${d}">${x}</td>
|
|
1051
|
+
<td title="${b(new Date(M.updatedAt).toISOString())}">${Di(M.updatedAt)}</td>
|
|
1052
|
+
<td>${H}</td>
|
|
1053
|
+
</tr>`}).join("")}function T(){m?(s.textContent=t("workflow.list.error",{error:m}),s.classList.add("error")):(s.textContent=t("workflow.list.loaded",{count:o.length,time:new Date().toLocaleTimeString()}),s.classList.remove("error"))}async function w(){if(!(k||c)&&!document.hidden){c=!0;try{let R=a.elements.namedItem("status")?.value??"",M=new URLSearchParams;R==="all"?M.set("all","1"):R&&M.set("status",R);let x="/api/workflows/runs"+(M.toString()?`?${M}`:""),d=await fetch(x);d.ok?(o=(await d.json()).runs??[],m=null):(m=`HTTP ${d.status}`,o=[])}catch(R){m=R?.message??String(R),o=[]}finally{c=!1,k||(L(),T())}}}function O(){l!==null&&window.clearTimeout(l),l=window.setTimeout(async()=>{await w(),k||O()},Ci)}function D(){document.hidden||w()}return a.addEventListener("input",()=>{L()}),a.addEventListener("change",R=>{R.target.getAttribute("name")==="status"&&w()}),document.addEventListener("visibilitychange",D),w().then(()=>{k||O()}),()=>{k=!0,l!==null&&window.clearTimeout(l),document.removeEventListener("visibilitychange",D)}}function Oi(e,n,a={}){e.innerHTML=`
|
|
968
1054
|
<div class="wf-detail-head">
|
|
969
|
-
<a class="btn-link" href="#/workflows">${
|
|
1055
|
+
<a class="btn-link" href="#/workflows">${b(t("workflow.detail.back"))}</a>
|
|
970
1056
|
<div>
|
|
971
|
-
<h2><code>${
|
|
972
|
-
<div id="wf-detail-subtitle" class="muted">${
|
|
1057
|
+
<h2><code>${b(n)}</code></h2>
|
|
1058
|
+
<div id="wf-detail-subtitle" class="muted">${b(t("workflow.detail.loading"))}</div>
|
|
973
1059
|
</div>
|
|
974
|
-
<button id="wf-cancel-run" type="button" class="contrast" hidden>${
|
|
1060
|
+
<button id="wf-cancel-run" type="button" class="contrast" hidden>${b(t("workflow.detail.cancel"))}</button>
|
|
975
1061
|
<span id="wf-detail-refresh" class="muted"></span>
|
|
976
1062
|
</div>
|
|
977
1063
|
<section id="wf-detail-error" class="hint-warn" hidden></section>
|
|
@@ -980,20 +1066,20 @@ ${vo("manage")}
|
|
|
980
1066
|
<section id="wf-dangling-panel"></section>
|
|
981
1067
|
<section class="wf-panel">
|
|
982
1068
|
<div class="wf-panel-title">
|
|
983
|
-
<h3>${
|
|
1069
|
+
<h3>${b(t("workflow.detail.parallel"))}</h3>
|
|
984
1070
|
<span id="wf-parallel-meta" class="muted"></span>
|
|
985
1071
|
</div>
|
|
986
1072
|
<div id="wf-parallel-view"></div>
|
|
987
1073
|
</section>
|
|
988
1074
|
<section class="wf-panel">
|
|
989
1075
|
<div class="wf-panel-title">
|
|
990
|
-
<h3>${
|
|
1076
|
+
<h3>${b(t("workflow.detail.nodes"))}</h3>
|
|
991
1077
|
</div>
|
|
992
1078
|
<div class="wf-table-scroll">
|
|
993
1079
|
<table>
|
|
994
1080
|
<thead><tr>
|
|
995
|
-
<th>${
|
|
996
|
-
<th>${
|
|
1081
|
+
<th>${b(t("workflow.detail.node"))}</th><th>${b(t("workflow.detail.nodeStatus"))}</th><th>${b(t("workflow.detail.activity"))}</th><th>${b(t("workflow.detail.activityStatus"))}</th>
|
|
1082
|
+
<th>${b(t("workflow.detail.attempts"))}</th><th>${b(t("workflow.detail.current"))}</th><th>${b(t("workflow.detail.detail"))}</th>
|
|
997
1083
|
</tr></thead>
|
|
998
1084
|
<tbody id="wf-node-tbody"></tbody>
|
|
999
1085
|
</table>
|
|
@@ -1001,244 +1087,244 @@ ${vo("manage")}
|
|
|
1001
1087
|
</section>
|
|
1002
1088
|
<section class="wf-panel">
|
|
1003
1089
|
<div class="wf-panel-title">
|
|
1004
|
-
<h3>${
|
|
1090
|
+
<h3>${b(t("workflow.detail.nodeIO"))}</h3>
|
|
1005
1091
|
</div>
|
|
1006
1092
|
<div id="wf-io-list" class="wf-io-list"></div>
|
|
1007
1093
|
</section>
|
|
1008
1094
|
<section class="wf-panel">
|
|
1009
1095
|
<div class="wf-panel-title">
|
|
1010
|
-
<h3>${
|
|
1011
|
-
<button id="wf-load-older" type="button" hidden>${
|
|
1096
|
+
<h3>${b(t("workflow.detail.timeline"))}</h3>
|
|
1097
|
+
<button id="wf-load-older" type="button" hidden>${b(t("workflow.detail.loadOlder"))}</button>
|
|
1012
1098
|
</div>
|
|
1013
1099
|
<div class="wf-table-scroll wf-timeline-scroll">
|
|
1014
1100
|
<table>
|
|
1015
1101
|
<thead><tr>
|
|
1016
|
-
<th>${
|
|
1102
|
+
<th>${b(t("workflow.detail.seq"))}</th><th>${b(t("workflow.detail.event"))}</th><th>${b(t("workflow.detail.actor"))}</th><th>${b(t("workflow.detail.node"))}</th><th>${b(t("workflow.detail.activity"))}</th><th>${b(t("workflow.detail.error"))}</th><th>${b(t("workflow.detail.time"))}</th>
|
|
1017
1103
|
</tr></thead>
|
|
1018
1104
|
<tbody id="wf-event-tbody"></tbody>
|
|
1019
1105
|
</table>
|
|
1020
1106
|
</div>
|
|
1021
1107
|
<div id="wf-event-meta" class="muted"></div>
|
|
1022
1108
|
</section>
|
|
1023
|
-
`;let s=e.querySelector("#wf-detail-subtitle"),
|
|
1024
|
-
<span class="muted error">${
|
|
1025
|
-
</div>`}function
|
|
1109
|
+
`;let s=e.querySelector("#wf-detail-subtitle"),o=e.querySelector("#wf-detail-refresh"),l=e.querySelector("#wf-detail-error"),c=e.querySelector("#wf-cancel-status"),m=e.querySelector("#wf-summary"),k=e.querySelector("#wf-dangling-panel"),v=e.querySelector("#wf-parallel-view"),L=e.querySelector("#wf-parallel-meta"),T=e.querySelector("#wf-node-tbody"),w=e.querySelector("#wf-io-list"),O=e.querySelector(".wf-timeline-scroll"),D=e.querySelector("#wf-event-tbody"),R=e.querySelector("#wf-event-meta"),M=e.querySelector("#wf-cancel-run"),x=e.querySelector("#wf-load-older"),d=null,y=[],H=new Set,I=null,$=null,A=!1,B=0,G=null,j=!1,Q=!1,le=!1,Ee=new Set,ge=new Map,J=new Map,se=new Map,Se=new Set,Re=new Map,ee=new Set,ue=new Map,de=new Map,qe=0,ke=a.focusAttemptId;function be(E){if(!E){l.hidden=!0,l.textContent="";return}l.hidden=!1,l.textContent=E}function re(E){if(!E){c.hidden=!0,c.textContent="";return}c.hidden=!1,c.textContent=E}async function xe(){let E=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/snapshot`);if(E.status===404)throw new Error(t("workflow.detail.unknownRun"));if(!E.ok)throw new Error(t("workflow.detail.snapshotHttp",{status:E.status}));d=await E.json()}async function He(E){let ie=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/events?${E}`);if(ie.status===404)throw new Error(t("workflow.detail.unknownRun"));if(!ie.ok)throw new Error(t("workflow.detail.eventsHttp",{status:ie.status}));return await ie.json()}function ce(E,ie){let U=E.filter(_=>H.has(_.eventId)?!1:(H.add(_.eventId),!0));U.length!==0&&(y=ie==="prepend"?[...U,...y]:[...y,...U],y.sort((_,he)=>Rt(_.eventId)-Rt(he.eventId)))}async function je(){await xe();let E=await He(new URLSearchParams({tail:"100"}));y=[],H=new Set,ce(E.events,"append"),I=E.oldestSeq,$=E.newestSeq,A=E.hasOlder,B=E.totalCount,oe()}async function Ze(){if(!(j||Q||document.hidden)){Q=!0;try{if(await xe(),$!==null){let E=await He(new URLSearchParams({afterSeq:String($),limit:"200"}));ce(E.events,"append"),E.newestSeq!==null&&($=E.newestSeq),I===null&&E.oldestSeq!==null&&(I=E.oldestSeq),B=E.totalCount}else{let E=await He(new URLSearchParams({tail:"1"}));ce(E.events,"append"),I=E.oldestSeq,$=E.newestSeq,A=E.hasOlder,B=E.totalCount}be(null),oe()}catch(E){be(E?.message??String(E))}finally{Q=!1}}}async function et(){if(!(I===null||!A)){x.disabled=!0;try{let E=await He(new URLSearchParams({beforeSeq:String(I),limit:"100"}));ce(E.events,"prepend"),E.oldestSeq!==null&&(I=E.oldestSeq),A=E.hasOlder,B=E.totalCount,be(null),oe()}catch(E){be(E?.message??String(E))}finally{x.disabled=!1}}}async function ft(){if(!d||Dt.has(d.run.status)||le)return;if(!d.chatBinding?.larkAppId){be(t("workflow.detail.cancelUnavailable",{runId:n}));return}let E=Pi(d),ie=t("workflow.detail.cancelConfirm",{runId:n,...E});if(window.confirm(ie)){le=!0,M.disabled=!0;try{let U=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/cancel`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"cancelled via dashboard"})});if(U.status===401)throw new Error(t("workflow.detail.writeAccessCancel"));let _=await U.json().catch(()=>({}));if(!U.ok||!_.ok)throw new Error(_.hint??_.error??t("workflow.detail.cancelHttp",{status:U.status}));re(_.pending?t("workflow.detail.cancelPending"):null),be(null),await Ze()}catch(U){be(U?.message??String(U))}finally{le=!1,M.disabled=!1,oe()}}}async function it(E,ie){if(!ee.has(E)){ee.add(E),ue.delete(E),oe();try{let U=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/attempts/${encodeURIComponent(ie)}/${encodeURIComponent(E)}/resume`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});if(U.status===401)throw new Error(t("workflow.detail.writeAccessResume"));let _=await U.json().catch(()=>({}));if(!U.ok||!_.ok||!_.resumeId||!_.url)throw new Error(_.hint??_.message??_.error??t("workflow.detail.resumeStartFailed",{status:U.status}));Re.set(E,{resumeId:_.resumeId,url:_.url})}catch(U){let _=U?.message??String(U);ue.set(E,_)}finally{ee.delete(E),oe()}}}async function Ye(E,ie){if(!ee.has(E)){ee.add(E),ue.delete(E),oe();try{let U=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/attempts/${encodeURIComponent(ie)}/${encodeURIComponent(E)}/resume/end`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"ended_by_dashboard"})});if(U.status===401)throw new Error(t("workflow.detail.writeAccessResume"));let _=await U.json().catch(()=>({}));if(!U.ok||!_.ok)if(_.error==="resume_not_running")Re.delete(E);else throw new Error(_.hint??_.message??_.error??t("workflow.detail.resumeEndFailed",{status:U.status}));else Re.delete(E)}catch(U){let _=U?.message??String(U);ue.set(E,_)}finally{ee.delete(E),oe()}}}async function Ve(E,ie){if(!Se.has(E)){Se.add(E),se.delete(E),oe();try{let U=J.get(E)?.trim()||void 0,_=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/${ie}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({comment:U})});if(_.status===401)throw new Error(t("workflow.detail.writeAccessApproval"));let he=await _.json().catch(()=>({}));if(!_.ok||!he.ok)throw new Error(he.hint??he.message??he.error??t("workflow.detail.actionHttp",{action:ie,status:_.status}));let gt=ie==="approve"?t("workflow.detail.approved"):t("workflow.detail.rejected");se.set(E,{kind:"ok",text:he.alreadyTerminal?t("workflow.detail.alreadyTerminal",{label:gt}):he.pending?t("workflow.detail.workflowContinue",{label:gt}):t("workflow.detail.workflowRefreshing",{label:gt})}),be(null),await Ze()}catch(U){let _=U?.message??String(U);se.set(E,{kind:"error",text:_}),be(_)}finally{Se.delete(E),oe()}}}function oe(){if(!d)return;qe=O.scrollTop;let E=d.run;Dt.has(E.status)&&re(null),s.innerHTML=`${b(E.workflowId??"?")} \xB7 ${Xe(E.status)} \xB7 lastSeq ${d.lastSeq}`,o.textContent=t("workflow.detail.refreshed",{time:new Date().toLocaleTimeString()}),M.hidden=Dt.has(E.status),M.disabled=le||!d.chatBinding?.larkAppId,M.textContent=d.chatBinding?.larkAppId?t("workflow.detail.cancel"):t("workflow.detail.cliCancelOnly"),M.title=d.chatBinding?.larkAppId?t("workflow.detail.cancelTitle"):t("workflow.detail.cliCancelTitle",{runId:n}),Bi(m,d),qi(k,d),Ui(v,L,d,y),Wi(T,d),Ki(w,d,Ee,ge,{comments:J,statuses:se,resolving:Se,onResolve:Ve},{sessions:Re,pending:ee,errors:ue,onStart:it,onEnd:Ye},ke,de)&&(ke=void 0),yr(D,y),O.scrollTop=qe,x.hidden=!A,R.textContent=t("workflow.detail.eventsLoaded",{loaded:y.length,total:B})}function Ue(){if(G!==null&&window.clearTimeout(G),d&&Dt.has(d.run.status)){G=null;return}G=window.setTimeout(async()=>{await Ze(),j||Ue()},Ai)}function Oe(){document.hidden||Ze().then(()=>{!j&&G===null&&Ue()})}return x.addEventListener("click",()=>{et()}),M.addEventListener("click",()=>{ft()}),document.addEventListener("visibilitychange",Oe),je().then(()=>{be(null),j||Ue()}).catch(E=>{be(E?.message??String(E)),s.textContent=t("workflow.detail.loadFailed")}),()=>{j=!0,G!==null&&window.clearTimeout(G),document.removeEventListener("visibilitychange",Oe)}}function Bi(e,n){let a=n.run,s=[[t("workflow.summary.workflow"),b(a.workflowId??"?")],[t("workflow.summary.status"),Xe(a.status)],[t("workflow.summary.lastSeq"),String(n.lastSeq)],[t("workflow.summary.updated"),b(new Date(n.updatedAt).toLocaleString())],[t("workflow.summary.revision"),b(dn(a.revisionId))],[t("workflow.summary.initiator"),b(a.initiator??"-")]];a.failedNodeId&&s.push([t("workflow.summary.failedNode"),b(a.failedNodeId)]),a.cancelOriginEventId&&s.push([t("workflow.summary.cancelOrigin"),b(a.cancelOriginEventId)]),n.chatBinding&&(s.push([t("workflow.summary.chat"),`<code>${b(n.chatBinding.chatId)}</code>`]),s.push([t("workflow.summary.app"),`<code>${b(n.chatBinding.larkAppId)}</code>`])),e.innerHTML=s.map(([o,l])=>`<div class="wf-summary-item"><span>${o}</span><strong>${l}</strong></div>`).join("")}function Ni(e){if(!e.errorCode)return"";let n=e.errorMessage?` \u2014 ${Sr(e.errorMessage,96)}`:"";return`<div class="wf-run-error">
|
|
1110
|
+
<span class="muted error">${b(e.errorCode)}</span>${b(n)}
|
|
1111
|
+
</div>`}function Pi(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 qi(e,n){let a=n.dangling,s=[[t("workflow.dangling.activities"),a.activities],[t("workflow.dangling.effects"),a.effectAttempted],[t("workflow.dangling.waits"),a.waits],[t("workflow.dangling.cancels"),a.cancels]],o=new Set(s.flatMap(([,l])=>l)).size;if(e.className=o>0?"wf-panel wf-dangling-panel has":"wf-panel wf-dangling-panel",o===0){e.innerHTML=`<div class="wf-panel-title"><h3>${b(t("workflow.detail.dangling"))}</h3></div><div class="muted">${b(t("workflow.detail.noDangling"))}</div>`;return}e.innerHTML=`<div class="wf-panel-title"><h3>${b(t("workflow.detail.dangling"))}</h3><span class="wf-dangling has">${o}</span></div>
|
|
1026
1112
|
<div class="wf-dangling-grid">
|
|
1027
|
-
${s.map(([
|
|
1028
|
-
</div>`}function
|
|
1029
|
-
<span title="${
|
|
1030
|
-
<span title="${
|
|
1113
|
+
${s.map(([l,c])=>`<div><strong>${l}</strong>${c.length===0?`<div class="muted">${b(t("workflow.detail.none"))}</div>`:`<ul>${c.map(m=>`<li><code>${b(m)}</code></li>`).join("")}</ul>`}</div>`).join("")}
|
|
1114
|
+
</div>`}function Ui(e,n,a,s){let o=ji(s,a);if(o.length===0){n.textContent="",e.innerHTML=`<div class="empty">${b(t("workflow.detail.noParallelData"))}</div>`;return}let l=Date.now(),c=Math.min(...o.map(w=>w.startedAt)),m=Math.max(...o.map(w=>w.endedAt??l),c+1e3),k=Math.max(1,m-c),v=_i(o,l),L=o.filter(w=>!w.endedAt&&(w.status==="running"||w.status==="effectAttempting")).length;n.textContent=t("workflow.detail.parallelMeta",{count:o.length,max:v,running:L});let T=o.sort((w,O)=>w.startedAt-O.startedAt||w.activityId.localeCompare(O.activityId)).map(w=>Fi(w,c,k,l)).join("");e.innerHTML=`<div class="wf-parallel-axis">
|
|
1115
|
+
<span title="${b(new Date(c).toISOString())}">${b(ln(c))}</span>
|
|
1116
|
+
<span title="${b(new Date(m).toISOString())}">${b(ln(m))}</span>
|
|
1031
1117
|
</div>
|
|
1032
|
-
<div class="wf-parallel-list">${
|
|
1118
|
+
<div class="wf-parallel-list">${T}</div>`}function ji(e,n){let a=new Map,s=new Map(n.activities.map(o=>[o.activityId,o.ownerNodeId]));for(let o of[...e].sort((l,c)=>Rt(l.eventId)-Rt(c.eventId))){let l=$r(o);if(!l)continue;let c=typeof l.activityId=="string"?l.activityId:void 0,m=typeof l.attemptId=="string"?l.attemptId:void 0;if(!c||!m)continue;let k=a.get(m);if(o.type==="attemptCreated"){let v=typeof l.attemptNumber=="number"?l.attemptNumber:void 0;k={nodeId:typeof l.nodeId=="string"?l.nodeId:s.get(c),activityId:c,attemptId:m,attemptNumber:v,status:"pending",startedAt:o.timestamp},a.set(m,k);continue}k||(k={nodeId:s.get(c),activityId:c,attemptId:m,status:"pending",startedAt:o.timestamp},a.set(m,k)),o.type==="activityRunning"?(k.status="running",k.runningAt=o.timestamp):o.type==="effectAttempted"?k.status="effectAttempting":o.type==="activityWaiting"||o.type==="waitCreated"?k.status="waiting":Gi(o.type)&&(k.status=zi(o.type),k.endedAt=o.timestamp,k.endType=o.type)}return[...a.values()]}function Fi(e,n,a,s){let o=e.endedAt??s,l=Io((e.startedAt-n)/a*100,0,100),c=Io((Math.max(o,e.startedAt+1)-e.startedAt)/a*100,.7,100-l),m=e.nodeId??e.activityId,k=e.attemptNumber!==void 0?`#${e.attemptNumber}`:dn(e.attemptId),v=[`${m} ${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(`
|
|
1033
1119
|
`);return`<div class="wf-parallel-row">
|
|
1034
1120
|
<div class="wf-parallel-label">
|
|
1035
|
-
<code>${
|
|
1036
|
-
<span class="muted">${
|
|
1121
|
+
<code>${b(m)}</code>
|
|
1122
|
+
<span class="muted">${b(e.activityId)} \xB7 ${b(k)}</span>
|
|
1037
1123
|
</div>
|
|
1038
1124
|
<div class="wf-parallel-track">
|
|
1039
|
-
<div class="wf-parallel-bar wf-parallel-${
|
|
1040
|
-
<span>${
|
|
1125
|
+
<div class="wf-parallel-bar wf-parallel-${b(e.status)}" style="left:${l.toFixed(3)}%;width:${c.toFixed(3)}%;" title="${b(v)}">
|
|
1126
|
+
<span>${b(st(e.status))}</span>
|
|
1041
1127
|
</div>
|
|
1042
1128
|
</div>
|
|
1043
|
-
</div>`}function
|
|
1044
|
-
<td>${e?`<code>${
|
|
1045
|
-
<td>${e?
|
|
1046
|
-
<td>${n?`<code>${
|
|
1047
|
-
<td>${n?
|
|
1129
|
+
</div>`}function _i(e,n){let a=[];for(let l of e)a.push({time:l.startedAt,delta:1}),a.push({time:l.endedAt??n,delta:-1});a.sort((l,c)=>l.time-c.time||c.delta-l.delta);let s=0,o=0;for(let l of a)s+=l.delta,o=Math.max(o,s);return o}function Gi(e){return e==="activitySucceeded"||e==="activityFailed"||e==="activityTimedOut"||e==="activityCanceled"}function zi(e){return e==="activitySucceeded"?"succeeded":e==="activityCanceled"?"cancelled":e==="activityTimedOut"?"timedOut":"failed"}function Wi(e,n){let a=new Map(n.activities.map(l=>[l.activityId,l])),s=new Set,o=[];for(let l of n.nodes){let c=(l.activityId?a.get(l.activityId):void 0)??n.activities.find(m=>m.ownerNodeId===l.nodeId);c&&s.add(c.activityId),o.push(To(l,c))}for(let l of n.activities)s.has(l.activityId)||o.push(To(void 0,l));e.innerHTML=o.length>0?o.join(""):`<tr><td colspan="7" class="empty">${b(t("workflow.detail.noNodes"))}</td></tr>`}function To(e,n){let a=n?.attempts[n.attempts.length-1];return`<tr>
|
|
1130
|
+
<td>${e?`<code>${b(e.nodeId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
1131
|
+
<td>${e?Xe(e.status):'<span class="muted">-</span>'}</td>
|
|
1132
|
+
<td>${n?`<code>${b(n.activityId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
1133
|
+
<td>${n?Xe(n.status):'<span class="muted">-</span>'}</td>
|
|
1048
1134
|
<td>${n?.attempts.length??0}</td>
|
|
1049
|
-
<td>${
|
|
1050
|
-
<td>${
|
|
1051
|
-
</tr>`}function
|
|
1135
|
+
<td>${a?`<code>${b(a.attemptId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
1136
|
+
<td>${a?wr(a):`<span class="muted">${b(t("workflow.detail.idle"))}</span>`}</td>
|
|
1137
|
+
</tr>`}function Ki(e,n,a,s,o,l,c,m){pr(e,a,s),lr(e,o.comments);let k=!!(c&&n.attemptIO?.[c]?.terminal);k&&c&&a.add(Kn(c,t("workflow.detail.liveTerminal")));let v=Ji(n),L=new Set;if(m){for(let w of v){L.add(w.key);let O=m.get(w.key);O||(O=Yi(w.key),m.set(w.key,O),e.appendChild(O.article)),Vi(O,w,a,o,l,c)}for(let[w,O]of Array.from(m))L.has(w)||(O.article.remove(),m.delete(w));if(v.length===0){if(!e.querySelector(".wf-io-empty-placeholder")){let w=document.createElement("div");w.className="empty wf-io-empty-placeholder",w.textContent=t("workflow.detail.noNodeIO"),e.appendChild(w)}}else e.querySelector(".wf-io-empty-placeholder")?.remove()}else{let w=[];for(let O of v)w.push(tr(O,a,o,l,c));e.innerHTML=w.length>0?w.join(""):`<div class="empty">${b(t("workflow.detail.noNodeIO"))}</div>`}fr(e,s);let T=ur(e,c);return mr(e,a),gr(e,s),cr(e,o),Bo(e,l),T&&k}function Ji(e){let n=new Map(e.activities.map(o=>[o.activityId,o])),a=new Set,s=[];for(let o of e.nodes){let l=(o.activityId?n.get(o.activityId):void 0)??e.activities.find(c=>c.ownerNodeId===o.nodeId);if(!l){s.push({key:`node:${o.nodeId}`,node:o});continue}a.add(l.activityId),s.push({key:`activity:${l.activityId}`,node:o,activity:l,io:e.attemptIO?.[rn(l)?.attemptId??""]})}for(let o of e.activities)a.has(o.activityId)||s.push({key:`activity:${o.activityId}`,activity:o,io:e.attemptIO?.[rn(o)?.attemptId??""]});return s}function Yi(e){let n=document.createElement("article");n.className="wf-io-card",n.dataset.wfCardKey=e;let a=document.createElement("div");a.className="wf-io-card-head";let s=document.createElement("div");s.className="wf-io-terminal-slot";let o=document.createElement("div");return o.className="wf-io-grid",n.appendChild(a),n.appendChild(s),n.appendChild(o),{article:n,head:a,terminalSlot:s,grid:o,currentTerminalUrl:null}}function Vi(e,n,a,s,o,l){let c=rn(n.activity),m=n.node?.nodeId??n.activity?.ownerNodeId??n.activity?.activityId??"unknown",k=!!(c&&c.attemptId===l);e.article.classList.toggle("is-focused",k),c?e.article.dataset.wfAttemptCard=c.attemptId:delete e.article.dataset.wfAttemptCard;let v=Oo(c,s);e.head.innerHTML=`
|
|
1052
1138
|
<header>
|
|
1053
1139
|
<div>
|
|
1054
|
-
<strong><code>${
|
|
1055
|
-
<span class="muted">${n.activity?
|
|
1140
|
+
<strong><code>${b(m)}</code></strong>
|
|
1141
|
+
<span class="muted">${n.activity?b(n.activity.activityId):b(t("workflow.detail.notDispatched"))}</span>
|
|
1056
1142
|
</div>
|
|
1057
|
-
<div>${n.node?
|
|
1143
|
+
<div>${n.node?Xe(n.node.status):""} ${n.activity?Xe(n.activity.status):""}</div>
|
|
1058
1144
|
</header>
|
|
1059
1145
|
<div class="wf-io-meta">
|
|
1060
|
-
${
|
|
1146
|
+
${c?`${b(t("workflow.detail.attempt"))} <code>${b(c.attemptId)}</code>`:b(t("workflow.detail.noAttempt"))}
|
|
1061
1147
|
</div>
|
|
1062
|
-
${
|
|
1063
|
-
`;let
|
|
1064
|
-
${
|
|
1065
|
-
${
|
|
1066
|
-
${
|
|
1067
|
-
${
|
|
1068
|
-
${n.io?.waitPrompt?
|
|
1069
|
-
`}function
|
|
1070
|
-
<summary>${
|
|
1148
|
+
${v}
|
|
1149
|
+
`;let L=Eo(c,n.activity,n.io?.terminal,o),T=L?.url??null;if(T!==e.currentTerminalUrl)L===null?e.terminalSlot.innerHTML="":e.terminalSlot.innerHTML=xo(n.key,c,n.activity,n.io?.terminal,L,a,o),e.currentTerminalUrl=T;else if(L!==null&&n.io?.terminal){let O=e.terminalSlot.querySelector("details.wf-terminal-block > summary");if(O){let D=Ho(L.kind);O.innerHTML=`${b(D)} ${Ro(c,n.io.terminal)}`}c&&dr(e.terminalSlot,c,n.activity,n.io.terminal,L,o)}let w=c?.attemptId??n.activity?.activityId??n.node?.nodeId??"unknown";e.grid.innerHTML=`
|
|
1150
|
+
${Je(w,t("workflow.detail.authoredInput"),n.io?.input,a)}
|
|
1151
|
+
${Je(w,t("workflow.detail.resolvedInput"),n.io?.resolvedInput,a)}
|
|
1152
|
+
${Je(w,t("workflow.detail.output"),n.io?.output,a)}
|
|
1153
|
+
${Je(w,t("workflow.detail.executionLog"),n.io?.log,a)}
|
|
1154
|
+
${n.io?.waitPrompt?Je(w,t("workflow.detail.waitPrompt"),n.io.waitPrompt,a):""}
|
|
1155
|
+
`}function Eo(e,n,a,s){if(!a||a.error)return null;if(nr(e,a))return{kind:"live",url:or(a)};if(!e||!n||!ar(e,a))return null;let o=ir();if(!o)return null;let l=s?.sessions.get(e.attemptId);return l?{kind:"resume",url:l.url,resumeId:l.resumeId,downloadUrl:Lo(o,n.activityId,e.attemptId)}:{kind:"replay",url:sr(o,n.activityId,e.attemptId,!!a.hasPtyLog),downloadUrl:Lo(o,n.activityId,e.attemptId)}}function xo(e,n,a,s,o,l,c){if(!s)return"";let m=Ho(o.kind),k=Kn(e,m),v=Ro(n,s),L=Qi(o.kind),T=o.kind==="replay"||o.kind==="resume"?`<a class="btn-link" href="${b(o.downloadUrl)}" download>${b(t("workflow.detail.downloadFullLog"))}</a>`:"",w=n?Ao(n,a,s,o,c):"",O=n?Do(n.attemptId,c):"";return`<details class="wf-io-block wf-terminal-block" data-io-key="${b(k)}"${l.has(k)?" open":""}>
|
|
1156
|
+
<summary>${b(m)} ${v}</summary>
|
|
1071
1157
|
<div class="wf-terminal-actions">
|
|
1072
|
-
<a class="btn-link" href="${
|
|
1073
|
-
${
|
|
1074
|
-
${
|
|
1158
|
+
<a class="btn-link" href="${b(o.url)}" target="_blank" rel="noreferrer">${b(L)}</a>
|
|
1159
|
+
${T}
|
|
1160
|
+
${w}
|
|
1075
1161
|
</div>
|
|
1076
|
-
${
|
|
1077
|
-
<iframe class="wf-terminal-frame" src="${
|
|
1078
|
-
</details>`}function
|
|
1162
|
+
${O}
|
|
1163
|
+
<iframe class="wf-terminal-frame" src="${b(o.url)}" title="${b(m)}" loading="lazy"></iframe>
|
|
1164
|
+
</details>`}function Ho(e){return e==="live"?t("workflow.detail.liveTerminal"):e==="resume"?t("workflow.detail.terminalResume"):t("workflow.detail.terminalReplay")}function Qi(e){return e==="live"?t("workflow.detail.openTerminalNewTab"):e==="resume"?t("workflow.detail.openResumeNewTab"):t("workflow.detail.openReplayNewTab")}var Co=new Set(["antigravity","codex-app","cursor","mira"]),Xi=new Set(["aiden","coco","claude-code","seed","codex","mtr","hermes","pi"]);function Zi(e){return!!e&&(Xi.has(e)||Co.has(e))}function er(e){return!!e&&Co.has(e)}function Ao(e,n,a,s,o){if(!o||s.kind==="live"||!n)return"";let l=s.kind==="resume",c=o.pending.has(e.attemptId),m=`data-wf-resume-attempt="${b(e.attemptId)}" data-wf-resume-activity="${b(n.activityId)}"`;return l?`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="end" ${m}${c?" disabled":""}>${b(c?t("workflow.detail.resumeEnding"):t("workflow.detail.endResumeSession"))}</button>`:Zi(a.cliId)?er(a.cliId)&&!a.cliSessionId?`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${b(t("workflow.detail.resumeMissingCliSession"))}">${b(t("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="start" ${m}${c?" disabled":""}>${b(c?t("workflow.detail.resumeStarting"):t("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${b(t("workflow.detail.resumeUnsupportedCli",{cliId:a.cliId??"?"}))}">${b(t("workflow.detail.resumeSession"))}</button>`}function Do(e,n){if(!n)return"";let a=n.errors.get(e);return a?`<div class="hint-warn wf-resume-status" data-wf-resume-status="${b(e)}">${b(a)}</div>`:""}function tr(e,n,a,s,o){let l=rn(e.activity),c=e.node?.nodeId??e.activity?.ownerNodeId??e.activity?.activityId??"unknown",m=l?.attemptId??e.activity?.activityId??e.node?.nodeId??"unknown",k=Oo(l,a),v=l?.attemptId===o?" is-focused":"",L=l?` data-wf-attempt-card="${b(l.attemptId)}"`:"",T=Eo(l,e.activity,e.io?.terminal,s),w=T?xo(m,l,e.activity,e.io?.terminal,T,n,s):"";return`<article class="wf-io-card${v}" data-wf-card-key="${b(e.key)}"${L}>
|
|
1079
1165
|
<div class="wf-io-card-head">
|
|
1080
1166
|
<header>
|
|
1081
1167
|
<div>
|
|
1082
|
-
<strong><code>${
|
|
1083
|
-
<span class="muted">${e.activity?
|
|
1168
|
+
<strong><code>${b(c)}</code></strong>
|
|
1169
|
+
<span class="muted">${e.activity?b(e.activity.activityId):b(t("workflow.detail.notDispatched"))}</span>
|
|
1084
1170
|
</div>
|
|
1085
|
-
<div>${e.node?
|
|
1171
|
+
<div>${e.node?Xe(e.node.status):""} ${e.activity?Xe(e.activity.status):""}</div>
|
|
1086
1172
|
</header>
|
|
1087
1173
|
<div class="wf-io-meta">
|
|
1088
|
-
${
|
|
1174
|
+
${l?`${b(t("workflow.detail.attempt"))} <code>${b(l.attemptId)}</code>`:b(t("workflow.detail.noAttempt"))}
|
|
1089
1175
|
</div>
|
|
1090
|
-
${
|
|
1176
|
+
${k}
|
|
1091
1177
|
</div>
|
|
1092
|
-
<div class="wf-io-terminal-slot">${
|
|
1178
|
+
<div class="wf-io-terminal-slot">${w}</div>
|
|
1093
1179
|
<div class="wf-io-grid">
|
|
1094
|
-
${
|
|
1095
|
-
${
|
|
1096
|
-
${
|
|
1097
|
-
${
|
|
1098
|
-
${e.io?.waitPrompt?
|
|
1180
|
+
${Je(m,t("workflow.detail.authoredInput"),e.io?.input,n)}
|
|
1181
|
+
${Je(m,t("workflow.detail.resolvedInput"),e.io?.resolvedInput,n)}
|
|
1182
|
+
${Je(m,t("workflow.detail.output"),e.io?.output,n)}
|
|
1183
|
+
${Je(m,t("workflow.detail.executionLog"),e.io?.log,n)}
|
|
1184
|
+
${e.io?.waitPrompt?Je(m,t("workflow.detail.waitPrompt"),e.io.waitPrompt,n):""}
|
|
1099
1185
|
</div>
|
|
1100
|
-
</article>`}function
|
|
1186
|
+
</article>`}function rn(e){return e?.attempts[e.attempts.length-1]}function Ro(e,n){let a=[];return n.error?a.push(t("workflow.detail.error")):a.push(n.status==="live"?t("workflow.detail.terminalLive"):t("workflow.detail.terminalClosedShort")),e?.status&&a.push(e.status),n.webPort>0&&a.push(`:${n.webPort}`),`<span class="muted">${b(a.join(" \xB7 "))}</span>`}function nr(e,n){return n.status==="live"&&n.webPort>0&&(e?.status==="pending"||e?.status==="running"||e?.status==="effectAttempting")}function ar(e,n){return e.status==="succeeded"||e.status==="failed"||e.status==="cancelled"||e.status==="timedOut"?!!(n.sessionId||n.startedAt):!1}function or(e){return`http://${window.location.hostname||"127.0.0.1"}:${e.webPort}`}function sr(e,n,a,s){let o=new URLSearchParams({runId:e,activityId:n,attemptId:a});return s&&o.set("hasPtyLog","1"),`/assets/terminal-replay.html?${o.toString()}`}function Lo(e,n,a){return`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(n)}/${encodeURIComponent(a)}/terminal-log/raw?download=1`}function ir(){let e=window.location.hash.match(/^#\/workflows\/([^/?#]+)/);if(!e)return null;try{return decodeURIComponent(e[1])}catch{return null}}function Oo(e,n){if(!rr(e))return"";let a=e.attemptId,s=n.comments.get(a)??"",o=n.resolving.has(a),l=n.statuses.get(a),c=l?.kind==="error"?"hint-warn":"hint-ok";return`<div class="wf-approval-box" data-wf-approval="${b(a)}">
|
|
1101
1187
|
<label>
|
|
1102
|
-
<span>${
|
|
1103
|
-
<textarea class="wf-approval-comment" data-wf-approval-comment="${
|
|
1188
|
+
<span>${b(t("workflow.detail.approvalComment"))}</span>
|
|
1189
|
+
<textarea class="wf-approval-comment" data-wf-approval-comment="${b(a)}" rows="2" placeholder="${b(t("workflow.detail.optionalComment"))}"${o?" disabled":""}>${b(s)}</textarea>
|
|
1104
1190
|
</label>
|
|
1105
1191
|
<div class="wf-approval-actions">
|
|
1106
|
-
<button type="button" class="primary" data-wf-approval-action="approve" data-wf-attempt-id="${
|
|
1107
|
-
<button type="button" data-wf-approval-action="reject" data-wf-attempt-id="${
|
|
1108
|
-
${
|
|
1192
|
+
<button type="button" class="primary" data-wf-approval-action="approve" data-wf-attempt-id="${b(a)}"${o?" disabled":""}>${b(t("workflow.detail.approve"))}</button>
|
|
1193
|
+
<button type="button" data-wf-approval-action="reject" data-wf-attempt-id="${b(a)}"${o?" disabled":""}>${b(t("workflow.detail.reject"))}</button>
|
|
1194
|
+
${o?`<span class="muted">${b(t("workflow.detail.submitting"))}</span>`:""}
|
|
1109
1195
|
</div>
|
|
1110
|
-
${
|
|
1111
|
-
</div>`}function
|
|
1112
|
-
<summary>${
|
|
1113
|
-
${
|
|
1114
|
-
</details>`}function
|
|
1115
|
-
<td>${
|
|
1116
|
-
<td><code>${
|
|
1117
|
-
<td>${
|
|
1118
|
-
<td>${n.nodeId?`<code>${
|
|
1119
|
-
<td>${n.activityId?`<code>${
|
|
1120
|
-
<td>${n.errorCode?`<span class="muted error">${
|
|
1121
|
-
<td title="${
|
|
1122
|
-
</tr>`}function
|
|
1196
|
+
${l?`<div class="${c} wf-approval-status">${b(l.text)}</div>`:""}
|
|
1197
|
+
</div>`}function rr(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function lr(e,n){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(a=>{let s=a.dataset.wfApprovalComment;s&&n.set(s,a.value)})}function Bo(e,n){e.querySelectorAll("button[data-wf-resume-action][data-wf-resume-attempt][data-wf-resume-activity]").forEach(a=>{a.dataset.wfResumeBound!=="1"&&(a.dataset.wfResumeBound="1",a.addEventListener("click",()=>{let s=a.dataset.wfResumeAttempt,o=a.dataset.wfResumeActivity,l=a.dataset.wfResumeAction;!s||!o||(l==="start"?n.onStart(s,o):l==="end"&&n.onEnd(s,o))}))})}function dr(e,n,a,s,o,l){let c=e.querySelector(".wf-terminal-actions");if(!c)return;let m=c.querySelector('button[data-wf-resume-button="1"]'),k=Ao(n,a,s,o,l);m?m.outerHTML=k:k&&c.insertAdjacentHTML("beforeend",k);let v=e.querySelector("details.wf-terminal-block");if(v){let L=v.querySelector(".wf-resume-status"),T=Do(n.attemptId,l);L?L.outerHTML=T:T&&c.insertAdjacentHTML("afterend",T)}Bo(e,l)}function cr(e,n){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(a=>{let s=a.dataset.wfApprovalComment;s&&a.addEventListener("input",()=>{n.comments.set(s,a.value)})}),e.querySelectorAll("button[data-wf-approval-action][data-wf-attempt-id]").forEach(a=>{a.addEventListener("click",()=>{let s=a.dataset.wfAttemptId,o=a.dataset.wfApprovalAction;!s||o!=="approve"&&o!=="reject"||n.onResolve(s,o)})})}function Je(e,n,a,s){let o=Kn(e,n);return`<details class="wf-io-block" data-io-key="${b(o)}"${s.has(o)?" open":""}>
|
|
1198
|
+
<summary>${b(n)} ${br(a)}</summary>
|
|
1199
|
+
${hr(a)}
|
|
1200
|
+
</details>`}function Kn(e,n){return`${e}:${n}`}function ur(e,n){if(!n)return!1;for(let a of e.querySelectorAll("[data-wf-attempt-card]"))if(a.dataset.wfAttemptCard===n)return a.scrollIntoView({block:"center"}),!0;return!1}function pr(e,n,a){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(s=>{let o=s.dataset.ioKey;if(!o)return;s.open?n.add(o):n.delete(o);let l=s.querySelector(".wf-io-pre");l&&a.set(o,l.scrollTop)})}function mr(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(a=>{a.dataset.ioToggleBound!=="1"&&(a.dataset.ioToggleBound="1",a.addEventListener("toggle",()=>{let s=a.dataset.ioKey;s&&(a.open?n.add(s):n.delete(s))}))})}function fr(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(a=>{let s=a.dataset.ioKey;if(!s)return;let o=n.get(s);if(o===void 0)return;let l=a.querySelector(".wf-io-pre");l&&(l.scrollTop=o)})}function gr(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(a=>{let s=a.dataset.ioKey;if(!s)return;let o=a.querySelector(".wf-io-pre");o&&o.dataset.ioScrollBound!=="1"&&(o.dataset.ioScrollBound="1",o.addEventListener("scroll",()=>{n.set(s,o.scrollTop)}))})}function br(e){if(!e)return`<span class="muted">${b(t("workflow.detail.empty"))}</span>`;let n=[];return e.outputBytes!==void 0&&n.push(`${e.outputBytes}B`),e.truncated&&n.push(t("workflow.detail.truncated")),e.error&&n.push(t("workflow.detail.error")),e.outputHash&&n.push(dn(e.outputHash)),n.length?`<span class="muted">${b(n.join(" \xB7 "))}</span>`:""}function hr(e){if(!e)return`<div class="muted wf-io-empty">${b(t("workflow.detail.noData"))}</div>`;let n=e.value!==void 0?JSON.stringify(e.value,null,2):e.text??"",a=e.error?`<div class="muted error">${b(e.error)}</div>`:"";return n?`${a}<pre class="wf-io-pre">${b(n)}</pre>`:`${a}<div class="muted wf-io-empty">${b(t("workflow.detail.noPreview"))}</div>`}function wr(e){let n=[];if(e.effectAttempted&&n.push(`${b(t("workflow.detail.effect"))} ${b(e.effectAttempted.provider)}`),e.wait){let a=e.wait.resolution?`${e.wait.resolution.kind}${e.wait.resolution.resolution?":"+e.wait.resolution.resolution:""}`:t("workflow.detail.open");n.push(`${b(t("workflow.detail.wait"))} ${b(e.wait.waitKind)} ${b(a)}`),e.wait.deadlineAt!==void 0&&n.push(`${b(t("workflow.detail.deadline"))} ${b(ln(e.wait.deadlineAt))}`)}if(e.error){let a=`${e.error.errorCode}${e.error.errorClass?` \xB7 ${e.error.errorClass}`:""}`;n.push(`<span class="muted error">${b(a)}</span>`),e.error.errorMessage&&n.push(`<span class="error wf-error-msg">${b(e.error.errorMessage)}</span>`)}return e.output&&n.push(`${b(t("workflow.detail.output"))} ${b(dn(e.output.outputHash))}`),e.runningMs!==void 0&&n.push(`${e.runningMs}ms`),n.length>0?n.join("<br/>"):'<span class="muted">-</span>'}function yr(e,n){e.innerHTML=n.length>0?n.map(vr).join(""):`<tr><td colspan="7" class="empty">${b(t("workflow.detail.noEvents"))}</td></tr>`}function vr(e){let n=kr(e.payload);return`<tr>
|
|
1201
|
+
<td>${Rt(e.eventId)}</td>
|
|
1202
|
+
<td><code>${b(e.type)}</code></td>
|
|
1203
|
+
<td>${b(e.actor)}</td>
|
|
1204
|
+
<td>${n.nodeId?`<code>${b(n.nodeId)}</code>`:"-"}</td>
|
|
1205
|
+
<td>${n.activityId?`<code>${b(n.activityId)}</code>`:"-"}</td>
|
|
1206
|
+
<td>${n.errorCode?`<span class="muted error">${b(n.errorCode)}</span>`:"-"}</td>
|
|
1207
|
+
<td title="${b(new Date(e.timestamp).toISOString())}">${b(ln(e.timestamp))}</td>
|
|
1208
|
+
</tr>`}function Rt(e){let n=e.lastIndexOf("-");if(n<0)return 0;let a=Number(e.slice(n+1));return Number.isFinite(a)?a:0}function kr(e){if(!e||typeof e!="object"||"ref"in e)return{};let n=e,a={};typeof n.nodeId=="string"&&(a.nodeId=n.nodeId),typeof n.activityId=="string"&&(a.activityId=n.activityId),typeof n.failedNodeId=="string"&&(a.nodeId=n.failedNodeId);let s=n.error;return s&&typeof s=="object"&&"errorCode"in s&&(a.errorCode=String(s.errorCode)),a}function $r(e){return!e.payload||typeof e.payload!="object"||"ref"in e.payload?null:e.payload}function Io(e,n,a){return Math.min(a,Math.max(n,e))}function dn(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function Sr(e,n){return e.length>n?e.slice(0,n-1)+"\u2026":e}function ln(e){return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}function P(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function No(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function Po(e){let n=location.hash.match(/^#\/(?:workflows\/catalog|workflows-catalog)\/([^/?#]+)$/);return n?Lr(e,decodeURIComponent(n[1])):Tr(e)}function Tr(e){e.innerHTML=`
|
|
1123
1209
|
<nav class="wf-subnav">
|
|
1124
|
-
<a href="#/workflows" data-i18n="workflow.subnav.runs">${
|
|
1125
|
-
<a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${
|
|
1210
|
+
<a href="#/workflows" data-i18n="workflow.subnav.runs">${P(t("workflow.subnav.runs"))}</a>
|
|
1211
|
+
<a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${P(t("workflow.subnav.catalog"))}</a>
|
|
1126
1212
|
</nav>
|
|
1127
1213
|
<section class="catalog-head">
|
|
1128
1214
|
<div>
|
|
1129
|
-
<h2>${
|
|
1130
|
-
<p class="muted">${
|
|
1215
|
+
<h2>${P(t("catalog.title"))}</h2>
|
|
1216
|
+
<p class="muted">${P(t("catalog.subtitle"))}</p>
|
|
1131
1217
|
</div>
|
|
1132
|
-
<button id="catalog-refresh" type="button">${
|
|
1218
|
+
<button id="catalog-refresh" type="button">${P(t("catalog.refresh"))}</button>
|
|
1133
1219
|
</section>
|
|
1134
1220
|
<form id="catalog-filters" class="filters">
|
|
1135
|
-
<input type="search" name="q" placeholder="${
|
|
1221
|
+
<input type="search" name="q" placeholder="${P(t("catalog.searchPlaceholder"))}" />
|
|
1136
1222
|
<span id="catalog-status" class="muted"></span>
|
|
1137
1223
|
</form>
|
|
1138
1224
|
<div class="wf-table-scroll">
|
|
1139
1225
|
<table>
|
|
1140
1226
|
<thead><tr>
|
|
1141
|
-
<th>${
|
|
1142
|
-
<th>${
|
|
1143
|
-
<th>${
|
|
1144
|
-
<th>${
|
|
1145
|
-
<th>${
|
|
1146
|
-
<th>${
|
|
1227
|
+
<th>${P(t("catalog.table.workflow"))}</th>
|
|
1228
|
+
<th>${P(t("catalog.table.version"))}</th>
|
|
1229
|
+
<th>${P(t("catalog.table.params"))}</th>
|
|
1230
|
+
<th>${P(t("catalog.table.nodes"))}</th>
|
|
1231
|
+
<th>${P(t("catalog.table.revision"))}</th>
|
|
1232
|
+
<th>${P(t("catalog.table.path"))}</th>
|
|
1147
1233
|
</tr></thead>
|
|
1148
1234
|
<tbody id="catalog-tbody"></tbody>
|
|
1149
1235
|
</table>
|
|
1150
1236
|
</div>
|
|
1151
|
-
`;let n=e.querySelector("#catalog-tbody"),
|
|
1237
|
+
`;let n=e.querySelector("#catalog-tbody"),a=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),o=e.querySelector("#catalog-refresh"),l=[],c=null,m=!1;function k(){let T=(new FormData(s).get("q")??"").trim().toLowerCase();return T?l.filter(w=>w.workflowId.toLowerCase().includes(T)||w.path.toLowerCase().includes(T)):l}function v(){c?(a.textContent=t("catalog.loadFailed",{error:c}),a.classList.add("error")):(a.textContent=`${l.length}`,a.classList.remove("error"));let T=k();if(T.length===0){n.innerHTML=`<tr><td colspan="6" class="empty">${l.length===0?P(t("catalog.noDefinitions")):P(t("catalog.noFilterMatch"))}</td></tr>`;return}n.innerHTML=T.map(w=>`
|
|
1152
1238
|
<tr>
|
|
1153
|
-
<td><a href="#/workflows/catalog/${encodeURIComponent(
|
|
1154
|
-
<td>${
|
|
1155
|
-
<td>${
|
|
1156
|
-
<td>${
|
|
1157
|
-
<td><code>${
|
|
1158
|
-
<td><code>${
|
|
1239
|
+
<td><a href="#/workflows/catalog/${encodeURIComponent(w.workflowId)}"><code>${P(w.workflowId)}</code></a></td>
|
|
1240
|
+
<td>${w.version}</td>
|
|
1241
|
+
<td>${P(t("catalog.paramSummary",{required:w.requiredParamCount,total:w.paramCount}))}</td>
|
|
1242
|
+
<td>${w.nodeCount}</td>
|
|
1243
|
+
<td><code>${P(No(w.revisionId))}</code></td>
|
|
1244
|
+
<td><code>${P(w.path)}</code></td>
|
|
1159
1245
|
</tr>
|
|
1160
|
-
`).join("")}async function
|
|
1246
|
+
`).join("")}async function L(){o.disabled=!0,a.textContent=t("catalog.loading");try{let T=await fetch("/api/workflows/definitions");if(!T.ok)throw new Error(`HTTP ${T.status}`);l=(await T.json()).definitions??[],c=null}catch(T){c=T?.message??String(T),l=[]}finally{o.disabled=!1,m||v()}}return s.addEventListener("input",v),o.addEventListener("click",()=>{L()}),L(),()=>{m=!0}}function Lr(e,n){e.innerHTML=`
|
|
1161
1247
|
<div class="catalog-detail-head">
|
|
1162
|
-
<a class="btn-link" href="#/workflows/catalog">${
|
|
1248
|
+
<a class="btn-link" href="#/workflows/catalog">${P(t("catalog.back"))}</a>
|
|
1163
1249
|
<div>
|
|
1164
|
-
<h2><code>${
|
|
1165
|
-
<div id="catalog-detail-subtitle" class="muted">${
|
|
1250
|
+
<h2><code>${P(n)}</code></h2>
|
|
1251
|
+
<div id="catalog-detail-subtitle" class="muted">${P(t("workflow.detail.loading"))}</div>
|
|
1166
1252
|
</div>
|
|
1167
1253
|
</div>
|
|
1168
1254
|
<section id="catalog-error" class="hint-warn" hidden></section>
|
|
1169
1255
|
<section id="catalog-run-status" class="hint-ok" hidden></section>
|
|
1170
1256
|
<div id="catalog-detail-body"></div>
|
|
1171
|
-
`;let
|
|
1257
|
+
`;let a=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),o=e.querySelector("#catalog-run-status"),l=e.querySelector("#catalog-detail-body"),c=null,m=!1,k=!1;function v(M){s.hidden=!M,s.textContent=M??""}function L(M){o.hidden=!M,o.textContent=M??""}function T(M){let x={};for(let[d,y]of Object.entries(M??{}))"default"in y&&(x[d]=y.default);return x}function w(){if(!c)return;let M=c.definition;a.textContent=`${t("catalog.revision")} ${No(c.revisionId)} \xB7 ${c.path}`;let x=JSON.stringify(T(M.params),null,2);l.innerHTML=`
|
|
1172
1258
|
<section class="wf-panel">
|
|
1173
|
-
<div class="wf-panel-title"><h3>${
|
|
1259
|
+
<div class="wf-panel-title"><h3>${P(t("catalog.summary"))}</h3></div>
|
|
1174
1260
|
<div class="wf-summary-grid">
|
|
1175
|
-
<div class="wf-summary-item"><span>${
|
|
1176
|
-
<div class="wf-summary-item"><span>${
|
|
1177
|
-
<div class="wf-summary-item"><span>${
|
|
1178
|
-
<div class="wf-summary-item"><span>${
|
|
1261
|
+
<div class="wf-summary-item"><span>${P(t("catalog.table.workflow"))}</span><strong><code>${P(M.workflowId)}</code></strong></div>
|
|
1262
|
+
<div class="wf-summary-item"><span>${P(t("catalog.table.version"))}</span><strong>${M.version}</strong></div>
|
|
1263
|
+
<div class="wf-summary-item"><span>${P(t("catalog.nodeCount"))}</span><strong>${Object.keys(M.nodes).length}</strong></div>
|
|
1264
|
+
<div class="wf-summary-item"><span>${P(t("catalog.path"))}</span><strong><code>${P(c.path)}</code></strong></div>
|
|
1179
1265
|
</div>
|
|
1180
1266
|
</section>
|
|
1181
1267
|
|
|
1182
1268
|
<section class="wf-panel">
|
|
1183
|
-
<div class="wf-panel-title"><h3>${
|
|
1269
|
+
<div class="wf-panel-title"><h3>${P(t("catalog.runPanel"))}</h3></div>
|
|
1184
1270
|
<form id="catalog-run-form" class="catalog-run-form">
|
|
1185
1271
|
<label>
|
|
1186
|
-
<span>${
|
|
1187
|
-
<textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${
|
|
1272
|
+
<span>${P(t("catalog.paramsJson"))}</span>
|
|
1273
|
+
<textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${P(t("catalog.paramsPlaceholder"))}">${P(x)}</textarea>
|
|
1188
1274
|
</label>
|
|
1189
1275
|
<div class="catalog-chat-grid">
|
|
1190
1276
|
<label>
|
|
1191
|
-
<span>${
|
|
1277
|
+
<span>${P(t("catalog.chatId"))}</span>
|
|
1192
1278
|
<input id="catalog-chat-id" type="text" autocomplete="off" />
|
|
1193
1279
|
</label>
|
|
1194
1280
|
<label>
|
|
1195
|
-
<span>${
|
|
1281
|
+
<span>${P(t("catalog.larkAppId"))}</span>
|
|
1196
1282
|
<input id="catalog-lark-app-id" type="text" autocomplete="off" />
|
|
1197
1283
|
</label>
|
|
1198
1284
|
</div>
|
|
1199
|
-
<div class="muted">${
|
|
1285
|
+
<div class="muted">${P(t("catalog.chatBindingHint"))}</div>
|
|
1200
1286
|
<div id="catalog-param-errors" class="catalog-param-errors" hidden></div>
|
|
1201
|
-
<button id="catalog-run-btn" type="submit" class="primary">${
|
|
1287
|
+
<button id="catalog-run-btn" type="submit" class="primary">${P(t("catalog.run"))}</button>
|
|
1202
1288
|
</form>
|
|
1203
1289
|
</section>
|
|
1204
1290
|
|
|
1205
1291
|
<section class="wf-panel">
|
|
1206
|
-
<div class="wf-panel-title"><h3>${
|
|
1207
|
-
${
|
|
1292
|
+
<div class="wf-panel-title"><h3>${P(t("catalog.paramsSchema"))}</h3></div>
|
|
1293
|
+
${Ir(M.params)}
|
|
1208
1294
|
</section>
|
|
1209
1295
|
|
|
1210
1296
|
<section class="wf-panel">
|
|
1211
|
-
<div class="wf-panel-title"><h3>${
|
|
1212
|
-
<pre class="wf-io-pre">${
|
|
1297
|
+
<div class="wf-panel-title"><h3>${P(t("catalog.definitionJson"))}</h3></div>
|
|
1298
|
+
<pre class="wf-io-pre">${P(JSON.stringify(M,null,2))}</pre>
|
|
1213
1299
|
</section>
|
|
1214
|
-
`,
|
|
1300
|
+
`,D()}async function O(){if(!c||k)return;let M=l.querySelector("#catalog-params"),x=l.querySelector("#catalog-chat-id"),d=l.querySelector("#catalog-lark-app-id"),y=l.querySelector("#catalog-run-btn"),H=l.querySelector("#catalog-param-errors"),I;try{if(I=JSON.parse(M.value||"{}"),!I||typeof I!="object"||Array.isArray(I))throw new Error(t("catalog.badParamsJson"))}catch($){H.hidden=!1,H.innerHTML=`<div class="muted error">${P($?.message??String($))}</div>`;return}k=!0,y.disabled=!0,y.textContent=t("catalog.running"),H.hidden=!0,v(null),L(null);try{let $=await fetch(`/api/workflows/definitions/${encodeURIComponent(c.definition.workflowId)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({params:I,chatBinding:{chatId:x.value.trim(),larkAppId:d.value.trim()}})});if($.status===401)throw new Error(t("catalog.writeAccess"));let A=await $.json().catch(()=>({}));if(!$.ok||!A.ok)throw A.issues?.length&&(H.hidden=!1,H.innerHTML=`<strong>${P(t("catalog.invalidParams"))}</strong><ul>${A.issues.map(B=>`<li>${P(t("catalog.issue",{path:B.path.length?B.path.join("."):"(root)",message:B.message}))}</li>`).join("")}</ul>`),new Error(A.hint??A.message??A.error??t("catalog.runHttp",{status:$.status}));L(t("catalog.runStarted")),A.runId&&(location.hash=`#/workflows/${encodeURIComponent(A.runId)}`)}catch($){v($?.message??String($))}finally{k=!1,y.disabled=!1,y.textContent=t("catalog.run")}}function D(){l.querySelector("#catalog-run-form")?.addEventListener("submit",x=>{x.preventDefault(),O()})}async function R(){try{let M=await fetch(`/api/workflows/definitions/${encodeURIComponent(n)}`);if(M.status===404)throw new Error("unknown_workflow");if(!M.ok)throw new Error(`HTTP ${M.status}`);c=await M.json(),v(null),w()}catch(M){v(t("catalog.definitionLoadFailed",{error:M?.message??String(M)})),a.textContent=t("workflow.detail.loadFailed")}}return R().then(()=>{}),()=>{m=!0}}function Ir(e){let n=Object.entries(e??{});return n.length===0?`<div class="muted">${P(t("catalog.noParams"))}</div>`:`<div class="catalog-param-list">${n.map(([a,s])=>`
|
|
1215
1301
|
<article class="catalog-param">
|
|
1216
1302
|
<header>
|
|
1217
|
-
<code>${
|
|
1218
|
-
<span class="wf-status">${
|
|
1219
|
-
<span class="muted">${
|
|
1303
|
+
<code>${P(a)}</code>
|
|
1304
|
+
<span class="wf-status">${P(s.required?t("catalog.required"):t("catalog.optional"))}</span>
|
|
1305
|
+
<span class="muted">${P(s.type)}${s.format?` \xB7 ${P(s.format)}`:""}</span>
|
|
1220
1306
|
</header>
|
|
1221
|
-
${s.description?`<div class="muted">${
|
|
1222
|
-
${"default"in s?`<pre class="wf-io-pre">${
|
|
1307
|
+
${s.description?`<div class="muted">${P(t("catalog.description"))}: ${P(s.description)}</div>`:""}
|
|
1308
|
+
${"default"in s?`<pre class="wf-io-pre">${P(`${t("catalog.default")}: ${JSON.stringify(s.default,null,2)}`)}</pre>`:""}
|
|
1223
1309
|
</article>
|
|
1224
|
-
`).join("")}</div>`}var
|
|
1310
|
+
`).join("")}</div>`}var pt=null,cn=null;function Bt(){cn!==null&&(window.clearInterval(cn),cn=null)}function Yn(){return pt||(pt=document.createElement("dialog"),pt.className="onboarding-dialog",document.body.appendChild(pt),pt.addEventListener("close",Bt),pt)}function Mr(e){return e.status==="waiting_for_scan"?t("botOnboarding.waiting"):e.status==="verifying"?t("botOnboarding.verifying"):e.status==="configuring_permissions"?e.permissionStatusMsg?`${t("botOnboarding.configuringPermissions")} ${e.permissionStatusMsg}`:t("botOnboarding.configuringPermissions"):e.status==="waiting_for_platform_scan"?t("botOnboarding.platformScanHint"):e.status==="completed"?t("botOnboarding.completed"):e.status==="failed"?`${t("botOnboarding.failed")}: ${i(e.message??e.error??"unknown")}`:t("botOnboarding.starting")}function Er(e){if(e.status!=="completed"||!e.permission)return"";let n=e.permission;if(n.ok){let s=[t("botOnboarding.permissionOk",{count:n.scopeCount??0})];n.skippedScopeCount&&n.skippedScopeCount>0&&s.push(t("botOnboarding.permissionSkipped",{count:n.skippedScopeCount})),n.versionId&&s.push(t("botOnboarding.permissionVersion",{version:i(n.versionId)}));let o=`<p class="hint-ok">\u2705 ${s.join(" ")}</p>`;return n.scopeWarning&&(o+=`<p class="hint-warn">\u26A0\uFE0F ${i(n.scopeWarning)}</p>`),o}let a=(e.remainingSteps??[]).map(s=>`<li><a href="${i(s.url)}" target="_blank" rel="noopener">${i(s.title)}</a></li>`).join("");return`<p class="hint-warn">\u26A0\uFE0F ${t("botOnboarding.permissionManual")}${n.message?`\uFF08${i(n.message)}\uFF09`:""}</p>`+(a?`<ol class="onboarding-steps">${a}</ol>`:"")}function Ot(e){let n=Yn(),a=e.status==="waiting_for_scan"&&e.qrDataUrl?`<div class="qr-card">
|
|
1225
1311
|
<img class="qr-image" src="${e.qrDataUrl}" alt="${t("botOnboarding.qrAlt")}">
|
|
1226
|
-
${e.qrUrl?`<a class="onboarding-link" href="${
|
|
1312
|
+
${e.qrUrl?`<a class="onboarding-link" href="${i(e.qrUrl)}" target="_blank" rel="noopener">${t("botOnboarding.openLink")}</a>`:""}
|
|
1227
1313
|
</div>`:"",s=e.status==="waiting_for_platform_scan"&&e.platformQrDataUrl?`<div class="qr-card">
|
|
1228
1314
|
<img class="qr-image" src="${e.platformQrDataUrl}" alt="${t("botOnboarding.platformQrAlt")}">
|
|
1229
|
-
</div>`:"",
|
|
1315
|
+
</div>`:"",o=e.appId?`<p><b>App ID:</b> <code>${i(e.appId)}</code>`+(e.cliId?` \uFF5C <b>CLI:</b> <code>${i(e.cliId)}</code>`:"")+(e.workingDir?` \uFF5C <b>${t("botOnboarding.metaDir")}:</b> <code>${i(e.workingDir)}</code>`:"")+"</p>":"",l=e.status==="completed"?`<p class="hint-ok">${t("botOnboarding.restartHint")}</p>`:"";n.innerHTML=`<article>
|
|
1230
1316
|
<header>
|
|
1231
1317
|
<h3>${t("botOnboarding.title")}</h3>
|
|
1232
1318
|
<p>${t("botOnboarding.intro")}</p>
|
|
1233
1319
|
</header>
|
|
1234
|
-
<p class="onboarding-status status-${e.status}">${
|
|
1235
|
-
${o}
|
|
1236
|
-
${s}
|
|
1320
|
+
<p class="onboarding-status status-${e.status}">${Mr(e)}</p>
|
|
1237
1321
|
${a}
|
|
1238
|
-
${
|
|
1239
|
-
${
|
|
1322
|
+
${s}
|
|
1323
|
+
${o}
|
|
1324
|
+
${Er(e)}
|
|
1325
|
+
${l}
|
|
1240
1326
|
<form method="dialog"><button>${t("botOnboarding.close")}</button></form>
|
|
1241
|
-
</article>`}async function
|
|
1327
|
+
</article>`}async function xr(){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 Jn(e,n){let a=Yn(),s=e.map(m=>`<option value="${i(m.id)}">${i(m.label)}\uFF08${i(m.id)}\uFF09</option>`).join(""),o=n?`<p class="form-error">${i(n)}</p>`:"";a.innerHTML=`<article>
|
|
1242
1328
|
<header>
|
|
1243
1329
|
<h3>${t("botOnboarding.title")}</h3>
|
|
1244
1330
|
<p>${t("botOnboarding.intro")}</p>
|
|
@@ -1256,14 +1342,14 @@ ${vo("manage")}
|
|
|
1256
1342
|
<span>${t("botOnboarding.modelLabel")}</span>
|
|
1257
1343
|
<input id="ob-model" type="text" placeholder="${t("botOnboarding.modelPlaceholder")}" autocomplete="off" spellcheck="false">
|
|
1258
1344
|
</label>
|
|
1259
|
-
${
|
|
1345
|
+
${o}
|
|
1260
1346
|
<menu class="onboarding-actions">
|
|
1261
1347
|
<button type="button" id="ob-cancel">${t("botOnboarding.cancel")}</button>
|
|
1262
1348
|
<button type="submit" class="primary">${t("botOnboarding.startScan")}</button>
|
|
1263
1349
|
</menu>
|
|
1264
1350
|
</form>
|
|
1265
|
-
</article>`;let
|
|
1351
|
+
</article>`;let l=a.querySelector("#onboarding-form");a.querySelector("#ob-cancel")?.addEventListener("click",()=>a.close()),l?.addEventListener("submit",m=>{m.preventDefault();let k=a.querySelector("#ob-cli")?.value??"",v=a.querySelector("#ob-dir")?.value??"",L=a.querySelector("#ob-model")?.value??"";Hr({cliId:k,workingDir:v,model:L},e)})}async function Hr(e,n){Bt(),Ot({id:"",status:"starting"});try{let a=await fetch("/api/bot-onboarding/start",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({cliId:e.cliId,workingDir:e.workingDir.trim(),model:e.model.trim()||void 0})}),s=await a.json();if(a.status===400){Jn(n,s?.message??s?.error??"invalid_input");return}if(!a.ok||!s?.job?.id)throw new Error(s?.error??`http_${a.status}`);Ot(s.job),cn=window.setInterval(()=>{Cr(s.job.id).catch(o=>{Bt(),Ot({id:s.job.id,status:"failed",message:o instanceof Error?o.message:String(o)})})},1200)}catch(a){Ot({id:"",status:"failed",message:a instanceof Error?a.message:String(a)})}}async function Cr(e){let n=await fetch(`/api/bot-onboarding/${encodeURIComponent(e)}`),a=await n.json();if(!n.ok||!a?.job)throw new Error(a?.error??`http_${n.status}`);Ot(a.job),(a.job.status==="completed"||a.job.status==="failed")&&Bt()}async function Ar(){Bt();let e=Yn();Jn([{id:"claude-code",label:"Claude"}]),e.open||e.showModal();let n=await xr();e.open&&e.querySelector("#onboarding-form")&&Jn(n)}function qo(){let e=document.getElementById("add-bot-btn");e&&(e.onclick=()=>{Ar()})}var Dr={monitor:'<rect width="20" height="14" x="2" y="3" rx="2"/><line x1="8" x2="16" y1="21" y2="21"/><line x1="12" x2="12" y1="17" y2="21"/>',sun:'<circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/>',moon:'<path d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"/>',cpu:'<path d="M12 20v2"/><path d="M12 2v2"/><path d="M17 20v2"/><path d="M17 2v2"/><path d="M2 12h2"/><path d="M2 17h2"/><path d="M2 7h2"/><path d="M20 12h2"/><path d="M20 17h2"/><path d="M20 7h2"/><path d="M7 20v2"/><path d="M7 2v2"/><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="8" y="8" width="8" height="8" rx="1"/>',sparkles:'<path d="M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z"/><path d="M20 2v4"/><path d="M22 4h-4"/><circle cx="4" cy="20" r="2"/>',zap:'<path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z"/>',terminal:'<path d="M12 19h8"/><path d="m4 17 6-6-6-6"/>',keyRound:'<path d="M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z"/><circle cx="16.5" cy="7.5" r=".5" fill="currentColor"/>',network:'<rect x="16" y="16" width="6" height="6" rx="1"/><rect x="2" y="16" width="6" height="6" rx="1"/><rect x="9" y="2" width="6" height="6" rx="1"/><path d="M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3"/><path d="M12 12V8"/>',swords:'<polyline points="14.5 17.5 3 6 3 3 6 3 17.5 14.5"/><line x1="13" x2="19" y1="19" y2="13"/><line x1="16" x2="20" y1="16" y2="20"/><line x1="19" x2="21" y1="21" y2="19"/><polyline points="14.5 6.5 18 3 21 3 21 6 17.5 9.5"/><line x1="5" x2="9" y1="14" y2="18"/><line x1="7" x2="4" y1="17" y2="20"/><line x1="3" x2="5" y1="19" y2="21"/>',flame:'<path d="M12 3q1 4 4 6.5t3 5.5a1 1 0 0 1-14 0 5 5 0 0 1 1-3 1 1 0 0 0 5 0c0-2-1.5-3-1.5-5q0-2 2.5-4"/>',ball:'<path d="M11 7a16 16 20 0 1 10.98 4.362"/><path d="M12 12a13 13 0 0 1-8.66 5"/><path d="M16.83 13.634a16 16 0 0 1-9.267 7.328"/><path d="M20.66 17A13 13 0 0 0 12 12a13 13 0 0 1 0-10"/><path d="M8.17 15.366a16 16 0 0 1-1.713-11.69"/><circle cx="12" cy="12" r="10"/>',chevron:'<path d="m6 9 6 6 6-6"/>'},jo=[{labelKey:"theme.base",options:[{value:"system",labelKey:"status.system",icon:"monitor"},{value:"light",labelKey:"status.light",icon:"sun"},{value:"dark",labelKey:"status.dark",icon:"moon"}]},{labelKey:"theme.skins",options:[{value:"cyber",labelKey:"skin.cyber",icon:"cpu"},{value:"genshin",labelKey:"skin.genshin",icon:"sparkles"},{value:"fallout",labelKey:"skin.fallout",icon:"zap"},{value:"prts",labelKey:"skin.prts",icon:"terminal"},{value:"bluearchive",labelKey:"skin.bluearchive",icon:"keyRound"},{value:"zzz",labelKey:"skin.zzz",icon:"network"},{value:"dragonball",labelKey:"skin.dragonball",icon:"flame"},{value:"ikun",labelKey:"skin.ikun",icon:"ball"}]}],Uo=jo.flatMap(e=>e.options),mt=!1;function Vn(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">${Dr[e]??""}</svg>`}function Rr(e){return e.replace(/[&<>"]/g,n=>({"&":"&","<":"<",">":">",'"':"""})[n])}function Fo(){let e=document.getElementById("theme-menu"),n=document.getElementById("theme-menu-btn"),a=document.getElementById("theme-menu-pop");if(!e||!n||!a)return;a.innerHTML=jo.map(o=>`<div class="tm-group" data-label-key="${o.labelKey}"></div>`+o.options.map(l=>`<button type="button" class="tm-item" role="option" data-value="${l.value}"><span class="tm-ic">${Vn(l.icon)}</span><span class="tm-label" data-label-key="${l.labelKey}"></span></button>`).join("")).join("");let s=o=>{mt=o,a.hidden=!mt,n.setAttribute("aria-expanded",String(mt)),e.classList.toggle("open",mt)};n.addEventListener("click",o=>{o.stopPropagation(),s(!mt)}),a.addEventListener("click",o=>{let l=o.target.closest(".tm-item");l&&($e.setTheme(l.dataset.value??"system"),s(!1))}),document.addEventListener("click",o=>{mt&&!e.contains(o.target)&&s(!1)}),document.addEventListener("keydown",o=>{o.key==="Escape"&&mt&&s(!1)}),Qn()}function Qn(){let e=document.getElementById("theme-menu-btn");if(!e)return;let n=Uo.find(a=>a.value===$e.theme)??Uo[0];e.innerHTML=`<span class="tm-ic">${Vn(n.icon)}</span><span class="tm-current">${Rr(t(n.labelKey))}</span><span class="tm-chev">${Vn("chevron")}</span>`,document.querySelectorAll("#theme-menu-pop [data-label-key]").forEach(a=>{a.textContent=t(a.dataset.labelKey??"")}),document.querySelectorAll("#theme-menu-pop .tm-item").forEach(a=>{a.classList.toggle("active",a.dataset.value===$e.theme)})}var De=document.getElementById("root"),St=!0,Ko=!1,Jo=["roles","bot-defaults","team","connectors"],Xn=!1;function Or(){if(Xn)return;Xn=!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(),Xn=!1};e.querySelector("#auth-expired-dismiss")?.addEventListener("click",n),e.addEventListener("click",a=>{a.target===e&&n()})}var Zn;function Br(){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",Zn&&window.clearTimeout(Zn),Zn=window.setTimeout(()=>{e.style.display="none"},4e3)}var Nr=window.fetch.bind(window);window.fetch=async function(...n){let a=await Nr(...n);if(a.status===401){let s=(n[1]?.method??"GET").toUpperCase();(s==="GET"||s==="HEAD")&&!Ko?Or():Br()}return a};var ea="";function un(){let e=document.getElementById("attention-strip");if(!e)return;let n=[...V.sessions.values()].map(o=>({s:o,reason:at(o)})).filter(o=>!!o.reason).sort((o,l)=>Le(o.s)-Le(l.s));if(n.length===0){e.hidden=!0,e.innerHTML="",ea="";return}let a=n[0],s=`
|
|
1266
1352
|
<span class="attention-strip-ic" aria-hidden="true">!</span>
|
|
1267
|
-
<b>${
|
|
1268
|
-
<span class="attention-strip-longest">${
|
|
1269
|
-
<a class="attention-strip-go" href="#/sessions">${
|
|
1353
|
+
<b>${i(t("strip.pending",{count:n.length}))}</b>
|
|
1354
|
+
<span class="attention-strip-longest">${i(t("strip.longest",{time:Be(Le(a.s)),bot:ye(a.s),reason:a.reason}))}</span>
|
|
1355
|
+
<a class="attention-strip-go" href="#/sessions">${i(t("strip.handle"))}</a>`;e.hidden=!1,s!==ea&&(ea=s,e.innerHTML=s)}V.on(un);Ge().then(un);async function Pr(){try{let e=await fetch("/api/settings");if(e.ok){let n=await e.json();St=!!n.authed,$e.authed=St,Ko=!!(n.settings&&n.settings.publicReadOnly);let a=Ft(n.lang);a&&$e.setLocale(a)}}catch{}}async function qr(e){if(St)try{await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({lang:e})})}catch{}}function Ur(){for(let n of Jo){let a=document.querySelector(`.sidebar-nav a[data-route="${n}"]`);a&&(a.style.display=St?"":"none")}let e=document.getElementById("add-bot-btn");e&&(e.style.display=St?"":"none")}function jr(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 Nt=null;function _o(e){for(let n of document.querySelectorAll(".sidebar-nav a")){let a=n.getAttribute("href")??"#/";n.classList.toggle("active",a===(e||"#/"))}}function ta(){Nt&&(Nt(),Nt=null);let e=location.hash||"#/";if(!St&&Jo.some(n=>e.startsWith("#/"+n))){jr(De),_o(e);return}e.startsWith("#/workflows/catalog")||e.startsWith("#/workflows-catalog")?Nt=Po(De):e.startsWith("#/workflows")?Nt=Mo(De):e.startsWith("#/groups")?ao(De):e.startsWith("#/settings")?So(De):e.startsWith("#/bot-defaults")?ro(De):e.startsWith("#/connectors")?ko(De):e.startsWith("#/team/manage")?wo(De):e.startsWith("#/team")?ho(De):e.startsWith("#/roles")?po(De):e.startsWith("#/schedules")?to(De):e.startsWith("#/sessions")?Za(De):ja(De),_o(e)}var na=document.getElementById("status");function Yo(){na&&(na.textContent=V.online?t("status.live"):t("status.disconnected"),na.className="connection-status "+(V.online?"online":"offline"))}V.on(Yo);function Go(){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===$e.locale)}),Qn(),Yo()}function Fr(){document.querySelectorAll("[data-locale]").forEach(e=>{e.onclick=()=>{let n=e.dataset.locale;$e.setLocale(n),qr(n)}}),Fo(),Gr()}var zo="botmux.ownerAvatar.v1";function Wo(e,n){let a=document.querySelector(".brand-mark");!a||!e||(a.innerHTML=`<img class="brand-owner-img" src="${i(e)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.remove()">`,n&&(a.title=n))}function _r(){try{let e=JSON.parse(window.localStorage.getItem(zo)??"null");e?.avatarUrl&&Wo(String(e.avatarUrl),e.name?String(e.name):void 0)}catch{}fetch("/api/owner-profile").then(e=>e.ok?e.json():null).then(e=>{if(!(!e?.ok||!e.avatarUrl)){Wo(String(e.avatarUrl),e.name?String(e.name):void 0);try{window.localStorage.setItem(zo,JSON.stringify({avatarUrl:e.avatarUrl,name:e.name??""}))}catch{}}}).catch(()=>{})}function Gr(){let e=document.getElementById("sidebar-toggle");if(!e)return;let n=Ta(window.localStorage),a=()=>{document.documentElement.dataset.sidebar=n,e.title=t(n==="collapsed"?"nav.sidebarExpand":"nav.sidebarCollapse")};a(),e.addEventListener("click",()=>{n=n==="collapsed"?"expanded":"collapsed",La(window.localStorage,n),a()})}(async()=>{$e.init(),Fr(),qo(),$e.on(()=>{Go(),un(),ta()}),Go(),un(),await Pr(),Ur(),_r();try{await ca()}catch(e){console.error("botmux dashboard bootstrap failed",e),V.setOnline(!1)}window.addEventListener("hashchange",ta),ta()})();})();
|