botmux 2.81.1 → 2.82.1
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-backend.d.ts +30 -6
- package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-backend.js +40 -6
- package/dist/adapters/backend/tmux-backend.js.map +1 -1
- package/dist/adapters/backend/zellij-backend.d.ts +11 -0
- package/dist/adapters/backend/zellij-backend.d.ts.map +1 -1
- package/dist/adapters/backend/zellij-backend.js +16 -0
- package/dist/adapters/backend/zellij-backend.js.map +1 -1
- package/dist/adapters/cli/relay.d.ts +16 -22
- package/dist/adapters/cli/relay.d.ts.map +1 -1
- package/dist/adapters/cli/relay.js +27 -42
- package/dist/adapters/cli/relay.js.map +1 -1
- package/dist/adapters/cli/seed.d.ts.map +1 -1
- package/dist/adapters/cli/seed.js +4 -1
- package/dist/adapters/cli/seed.js.map +1 -1
- package/dist/adapters/cli/traex.d.ts.map +1 -1
- package/dist/adapters/cli/traex.js +4 -1
- package/dist/adapters/cli/traex.js.map +1 -1
- package/dist/bot-registry.d.ts +12 -0
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +5 -0
- package/dist/bot-registry.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1 -84
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +17 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +31 -0
- package/dist/config.js.map +1 -1
- package/dist/core/closed-session-card.d.ts.map +1 -1
- package/dist/core/closed-session-card.js +3 -1
- package/dist/core/closed-session-card.js.map +1 -1
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +19 -6
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/cost-calculator.js +2 -2
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +47 -1
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/idle-worker-sweeper.d.ts +30 -4
- package/dist/core/idle-worker-sweeper.d.ts.map +1 -1
- package/dist/core/idle-worker-sweeper.js +32 -12
- package/dist/core/idle-worker-sweeper.js.map +1 -1
- package/dist/core/persistent-backend.d.ts +12 -0
- package/dist/core/persistent-backend.d.ts.map +1 -1
- package/dist/core/persistent-backend.js +18 -0
- package/dist/core/persistent-backend.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +37 -4
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +18 -1
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +7 -3
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults.js +100 -1
- package/dist/dashboard/web/bot-defaults.js.map +1 -1
- package/dist/dashboard/web/bot-onboarding.d.ts.map +1 -1
- package/dist/dashboard/web/bot-onboarding.js +61 -2
- package/dist/dashboard/web/bot-onboarding.js.map +1 -1
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +22 -0
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard-web/app.js +371 -353
- package/dist/dashboard.js +34 -2
- package/dist/dashboard.js.map +1 -1
- package/dist/global-config.d.ts +0 -7
- package/dist/global-config.d.ts.map +1 -1
- package/dist/global-config.js +0 -21
- package/dist/global-config.js.map +1 -1
- package/dist/i18n/en.js +2 -2
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.js +2 -2
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/card-handler.d.ts.map +1 -1
- package/dist/im/lark/card-handler.js +9 -1
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/services/bot-config-store.d.ts +4 -4
- package/dist/services/bot-config-store.d.ts.map +1 -1
- package/dist/services/bot-config-store.js +5 -0
- package/dist/services/bot-config-store.js.map +1 -1
- package/dist/services/git-worktree.d.ts +19 -4
- package/dist/services/git-worktree.d.ts.map +1 -1
- package/dist/services/git-worktree.js +47 -2
- package/dist/services/git-worktree.js.map +1 -1
- package/dist/services/worktree-slug-ai.d.ts +3 -0
- package/dist/services/worktree-slug-ai.d.ts.map +1 -0
- package/dist/services/worktree-slug-ai.js +80 -0
- package/dist/services/worktree-slug-ai.js.map +1 -0
- package/dist/setup/cli-selection.d.ts +33 -4
- package/dist/setup/cli-selection.d.ts.map +1 -1
- package/dist/setup/cli-selection.js +101 -4
- package/dist/setup/cli-selection.js.map +1 -1
- package/dist/skills/definitions.d.ts.map +1 -1
- package/dist/skills/definitions.js +4 -25
- package/dist/skills/definitions.js.map +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/worker.js +26 -5
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
- package/dist/core/worker-budget.d.ts +0 -19
- package/dist/core/worker-budget.d.ts.map +0 -1
- package/dist/core/worker-budget.js +0 -50
- package/dist/core/worker-budget.js.map +0 -1
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
"use strict";(()=>{var hn=class{sessions=new Map;schedules=new Map;online=!0;listeners=new Set;upsertSessions(n){for(let o of n)this.sessions.set(o.sessionId,o);this.emit()}upsertSchedules(n){for(let o of n)this.schedules.set(o.id,o);this.emit()}applySse(n,o){if(n==="session.spawned")this.sessions.set(o.session.sessionId,o.session);else if(n==="session.update"){let s=this.sessions.get(o.sessionId);s&&this.sessions.set(o.sessionId,{...s,...o.patch})}else if(n==="session.exited"){let s=this.sessions.get(o.sessionId);s&&this.sessions.set(o.sessionId,{...s,status:"closed"})}else if(n==="schedule.created")this.schedules.set(o.schedule.id,o.schedule);else if(n==="schedule.updated"){let s=this.schedules.get(o.id);s&&this.schedules.set(o.id,{...s,...o.patch})}else if(n==="schedule.deleted")this.schedules.delete(o.id);else return;this.emit()}setOnline(n){this.online!==n&&(this.online=n,this.emit())}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}},Q=new hn;async function mo(){let[e,n]=await Promise.all([fetch("/api/sessions").then(a=>a.json()),fetch("/api/schedules").then(a=>a.json())]);Q.upsertSessions(e.sessions??[]),Q.upsertSchedules(n.schedules??[]);let o=new EventSource("/events"),s=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let a of s)o.addEventListener(a,r=>{try{let c=JSON.parse(r.data);Q.applySse(a,c.body??c)}catch{}});o.onerror=()=>Q.setOnline(!1),o.onopen=()=>Q.setOnline(!0)}var wn="botmux.dashboard.locale",rs={"app.name":"botmux","app.subtitle":"\u98DE\u4E66 AI CLI \u63A7\u5236\u53F0","time.secondsAgo":"{value} \u79D2\u524D","time.minutesAgo":"{value} \u5206\u949F\u524D","time.hoursAgo":"{value} \u5C0F\u65F6\u524D","nav.overview":"\u603B\u89C8","nav.sessions":"\u4F1A\u8BDD","nav.sidebarCollapse":"\u6536\u8D77\u83DC\u5355\u680F","nav.sidebarExpand":"\u5C55\u5F00\u83DC\u5355\u680F","nav.groups":"\u7FA4\u7EC4","nav.schedules":"\u5B9A\u65F6","nav.settings":"\u8BBE\u7F6E","nav.botDefaults":"Bot \u914D\u7F6E","status.live":"\u5B9E\u65F6\u8FDE\u63A5","status.disconnected":"\u8FDE\u63A5\u65AD\u5F00","status.system":"\u7CFB\u7EDF","status.light":"\u6D45\u8272","status.dark":"\u6697\u9ED1","status.language":"\u8BED\u8A00","status.theme":"\u4E3B\u9898","theme.base":"\u57FA\u7840","theme.skins":"\u4E3B\u9898\u76AE\u80A4","skin.cyber":"2077","skin.genshin":"\u539F\u795E","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"\u851A\u84DD\u6863\u6848","skin.zzz":"\u7EDD\u533A\u96F6","skin.dragonball":"\u4E03\u9F99\u73E0","skin.ikun":"ikun","botOnboarding.add":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.title":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.intro":"\u9009\u62E9 CLI \u4E0E\u5DE5\u4F5C\u76EE\u5F55\uFF0C\u626B\u7801\u521B\u5EFA PersonalAgent \u5E94\u7528\u540E\u5199\u5165\u672C\u673A bots.json\uFF0C\u5E76\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u3002","botOnboarding.cliLabel":"CLI \u9002\u914D\u5668","botOnboarding.dirLabel":"\u5DE5\u4F5C\u76EE\u5F55","botOnboarding.dirPlaceholder":"\u9ED8\u8BA4 ~\uFF08\u5BB6\u76EE\u5F55\uFF09\uFF0C\u9700\u4E3A daemon \u4E3B\u673A\u4E0A\u5DF2\u5B58\u5728\u7684\u76EE\u5F55","botOnboarding.modelLabel":"\u6A21\u578B\uFF08\u53EF\u9009\uFF09","botOnboarding.modelPlaceholder":"\u7559\u7A7A\u4F7F\u7528\u8BE5 CLI \u7684\u9ED8\u8BA4\u6A21\u578B","botOnboarding.startScan":"\u5F00\u59CB\u626B\u7801","botOnboarding.cancel":"\u53D6\u6D88","botOnboarding.starting":"\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...","botOnboarding.waiting":"\u8BF7\u7528\u98DE\u4E66 App \u626B\u7801\u786E\u8BA4\u521B\u5EFA\u5E94\u7528\u3002","botOnboarding.verifying":"\u626B\u7801\u6210\u529F\uFF0C\u6B63\u5728\u6821\u9A8C\u51ED\u8BC1...","botOnboarding.configuringPermissions":"\u6B63\u5728\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u2026","botOnboarding.platformScanHint":"\u8BF7\u7528\u98DE\u4E66 App \u518D\u626B\u4E00\u6B21\u7801\u767B\u5F55\u5F00\u653E\u5E73\u53F0\uFF08\u7528\u4E8E\u81EA\u52A8\u5BFC\u5165\u6743\u9650\u3001\u914D\u7F6E\u56DE\u8C03\u3001\u63D0\u4EA4\u7248\u672C\uFF09\u3002","botOnboarding.platformQrAlt":"\u5F00\u653E\u5E73\u53F0\u767B\u5F55\u4E8C\u7EF4\u7801","botOnboarding.completed":"\u673A\u5668\u4EBA\u5DF2\u6DFB\u52A0\u3002","botOnboarding.permissionOk":"\u5DF2\u81EA\u52A8\u5BFC\u5165 {count} \u9879\u6743\u9650\u3002","botOnboarding.permissionSkipped":"\uFF08\u8DF3\u8FC7 {count} \u9879\u5F53\u524D\u79DF\u6237\u76EE\u5F55\u4E2D\u6CA1\u6709\u7684\u6743\u9650\uFF09","botOnboarding.permissionVersion":"\u5DF2\u63D0\u4EA4\u53D1\u5E03\u7248\u672C {version}\u3002","botOnboarding.permissionManual":"\u6743\u9650\u672A\u80FD\u81EA\u52A8\u914D\u7F6E\uFF0C\u8BF7\u624B\u52A8\u5B8C\u6210\u4EE5\u4E0B\u6B65\u9AA4\uFF1A","botOnboarding.metaDir":"\u76EE\u5F55","botOnboarding.failed":"\u6DFB\u52A0\u5931\u8D25","botOnboarding.openLink":"\u6253\u4E0D\u5F00\u626B\u7801\uFF1F\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00","botOnboarding.close":"\u5173\u95ED","botOnboarding.restartHint":"\u5DF2\u5199\u5165 bots.json\u3002\u6267\u884C pnpm daemon:restart \u540E\u65B0\u673A\u5668\u4EBA\u751F\u6548\u3002","botOnboarding.qrAlt":"\u98DE\u4E66\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA\u4E8C\u7EF4\u7801","overview.title":"\u5DE5\u4F5C\u53F0","overview.subtitle":"\u6570\u5B57\u5458\u5DE5\u5B9E\u65F6\u72B6\u6001 \xB7 \u540C\u6B65\u98DE\u4E66\u8BDD\u9898","overview.team":"AI \u56E2\u961F","overview.teamHint":"\u6BCF\u4F4D\u6570\u5B57\u5458\u5DE5\u7684\u5B9E\u65F6\u72B6\u6001","overview.attention":"\u9700\u8981\u4F60\u5904\u7406","overview.attentionHint":"\u5361\u4F4F\u7684\u4EFB\u52A1\uFF0C\u56DE\u4E2A\u8BDD\u5C31\u80FD\u7EE7\u7EED\u8DD1","overview.activeSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.activeSessionsHint":"\u6B63\u5728\u8FD0\u8F6C\u7684\u4F1A\u8BDD","overview.today":"\u6B64\u523B\u6982\u89C8","overview.todayHint":"\u6D3B\u8DC3\u4F1A\u8BDD\u5206\u5E03","overview.viewAll":"\u67E5\u770B\u5168\u90E8 \u2192","overview.botIdle":"\u5F85\u547D\u4E2D\uFF0C\u968F\u65F6\u53EF\u63A5\u65B0\u4EFB\u52A1","overview.botOffline":"\u79BB\u7EBF \u2014 daemon \u672A\u4E0A\u7EBF","overview.botBusy":"\u6267\u884C\u4E2D \xB7 {count} \u4F1A\u8BDD","overview.botNeedsYou":"\u7B49\u4F60\u56DE\u590D","overview.botReady":"\u5C31\u7EEA","overview.botOff":"\u79BB\u7EBF","overview.sessionsCount":"{count} \u4F1A\u8BDD","overview.lastActive":"{time}\u524D\u6D3B\u8DC3","overview.noAttention":"\u6CA1\u6709\u7B49\u4F60\u5904\u7406\u7684\u4E8B\u9879","overview.teamExpand":"\u5C55\u5F00\u5168\u90E8 {count} \u4F4D \u25BE","overview.teamCollapse":"\u6536\u8D77 \u25B4","strip.pending":"{count} \u4EF6\u5F85\u5904\u7406","strip.longest":"\u6700\u4E45\u5DF2\u7B49 {time} \u2014 {bot} {reason}","strip.handle":"\u7ACB\u5373\u5904\u7406","overview.openSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.workingSessions":"\u5DE5\u4F5C\u4E2D","overview.onlineBots":"\u5728\u7EBF Bot","overview.schedules":"\u5B9A\u65F6\u4EFB\u52A1","overview.groups":"\u7FA4\u804A\u8986\u76D6","overview.enabledSchedules":"\u5DF2\u542F\u7528","overview.total":"\u603B\u8BA1","overview.active":"\u6D3B\u8DC3","overview.daemonRegistry":"daemon \u6CE8\u518C\u8868","overview.chatMatrix":"\u7FA4\u804A\u77E9\u9635","overview.recentSessions":"\u6700\u8FD1\u4F1A\u8BDD","overview.nextSchedules":"\u5373\u5C06\u6267\u884C","overview.noSessions":"\u6682\u65E0\u4F1A\u8BDD\u3002","overview.noSchedules":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","sessions.title":"\u4F1A\u8BDD\u63A7\u5236","sessions.subtitle":"\u5B9A\u4F4D\u98DE\u4E66\u8BDD\u9898\u3001\u6253\u5F00 Web Terminal\u3001\u5173\u95ED\u6216\u6062\u590D CLI \u4F1A\u8BDD\u3002","sessions.search":"\u641C\u7D22\u5DE5\u4F5C\u76EE\u5F55 / \u6807\u9898 / ID","sessions.anyStatus":"\u5168\u90E8\u72B6\u6001","sessions.adoptAny":"adopt: \u5168\u90E8","sessions.adoptYes":"adopt: \u662F","sessions.adoptNo":"adopt: \u5426","sessions.activeOnly":"\u4EC5\u6D3B\u8DC3","sessions.closeSelected":"\u5173\u95ED\u9009\u4E2D","sessions.clearSelection":"\u53D6\u6D88\u9009\u62E9","sessions.selectedCount":"\u5DF2\u9009 {count} \u4E2A\u4F1A\u8BDD","sessions.bot":"bot","sessions.cli":"CLI","sessions.chat":"\u7FA4\u804A","sessions.openChat":"\u6253\u5F00\u7FA4\u804A","sessions.status":"\u72B6\u6001","sessions.tokenIn":"Token In","sessions.tokenOut":"Token Out","sessions.titleCol":"\u6807\u9898","sessions.workingDir":"\u5DE5\u4F5C\u76EE\u5F55","sessions.created":"\u521B\u5EFA","sessions.last":"\u6700\u8FD1","sessions.adopt":"\u63A5\u5165","sessions.actions":"\u64CD\u4F5C","sessions.details":"\u8BE6\u60C5","sessions.copy":"\u590D\u5236","sessions.copied":"\u5DF2\u590D\u5236","sessions.locate":"\u5B9A\u4F4D\u8BDD\u9898","sessions.locating":"\u53D1\u9001\u4E2D...","sessions.cooldown":"\u51B7\u5374 {seconds}s","sessions.openTerminal":"\u7EC8\u7AEF","sessions.writeLink":"\u64CD\u4F5C\u94FE\u63A5","sessions.writeLinkHint":"\u83B7\u53D6\u53EF\u64CD\u4F5C\u7EC8\u7AEF\u94FE\u63A5\uFF08\u5E26\u5199\u6743\u9650 token\uFF0C\u65B0\u6807\u7B7E\u6253\u5F00\uFF09","sessions.writeLinkFail":"\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u5931\u8D25","sessions.close":"\u5173\u95ED\u4F1A\u8BDD","sessions.resume":"\u6062\u590D\u4F1A\u8BDD","sessions.dismiss":"\u5173\u95ED","sessions.closeConfirm":"\u5173\u95ED\u8FD9\u4E2A\u4F1A\u8BDD\uFF1F","sessions.resumeFailed":"\u6062\u590D\u5931\u8D25","sessions.land":"\u843D\u76D8","sessions.landLoading":"\u52A0\u8F7D\u6C99\u76D2 diff\u2026","sessions.landUnavailable":"\u65E0\u6CD5\u843D\u76D8","sessions.landEmpty":"\u6C99\u76D2\u526F\u672C\u6CA1\u6709\u6539\u52A8\u3002","sessions.landApply":"\u5E94\u7528\u5230\u78C1\u76D8","sessions.landDiscard":"\u4E22\u5F03","sessions.landApplied":"\u5DF2\u843D\u76D8","sessions.landFailed":"\u843D\u76D8\u5931\u8D25","sessions.landDiscarded":"\u5DF2\u4E22\u5F03\uFF08\u6C99\u76D2\u526F\u672C\u672A\u5E94\u7528\uFF09\u3002","connectors.lede":"\u8BA9\u5916\u90E8\u7CFB\u7EDF\uFF08\u76D1\u63A7\u544A\u8B66\u3001CI\u3001\u5DE5\u5355\u2026\uFF09\u901A\u8FC7\u4E00\u4E2A webhook \u89E6\u53D1\u673A\u5668\u4EBA\u5728\u7FA4\u91CC\u8BF4\u8BDD\u6216\u8DD1\u5DE5\u4F5C\u6D41\u3002","connectors.createTitle":"\u65B0\u5EFA Webhook","connectors.fName":"\u540D\u79F0","connectors.fNamePh":"\u5982\uFF1A\u7EBF\u4E0A\u544A\u8B66","connectors.fBot":"\u89E6\u53D1\u7684\u673A\u5668\u4EBA","connectors.fKind":"\u89E6\u53D1\u65B9\u5F0F","connectors.kindTurn":"\u5355\u8F6E\u5BF9\u8BDD\uFF08\u8BA9\u673A\u5668\u4EBA\u56DE\u5E94\u4E00\u6B21\uFF09","connectors.kindWorkflow":"\u5DE5\u4F5C\u6D41","connectors.fWf":"\u5DE5\u4F5C\u6D41 ID","connectors.fMode":"\u6295\u9012\u5230\u54EA\u4E2A\u7FA4","connectors.modeDynamic":"\u7531\u8BF7\u6C42\u6307\u5B9A\uFF08\u7FA4\u968F\u8BF7\u6C42\u4F20\u5165\uFF09","connectors.modeFixed":"\u56FA\u5B9A\u7FA4","connectors.modeNewGroup":"\u6BCF\u6B21\u65B0\u5EFA\u7FA4","connectors.fFixedChat":"\u6295\u9012\u5230\u7684\u7FA4","connectors.fChatManualPh":"\u624B\u52A8\u586B\u7FA4 ID\uFF1Aoc_\u2026","connectors.chatManualLink":"\u627E\u4E0D\u5230\u7FA4\uFF1F\u624B\u52A8\u586B ID \u2192","connectors.chatListLink":"\u4ECE\u7FA4\u5217\u8868\u9009\u62E9 \u2190","connectors.fAllow":"\u5141\u8BB8\u7684\u7FA4","connectors.optional":"\uFF08\u53EF\u9009\uFF09","connectors.allowHint":"\u6309\u4F4F Ctrl/\u2318 \u591A\u9009\uFF1B\u7559\u7A7A = \u4E0D\u9650\u3002\u53EA\u7528\u4E8E\u6821\u9A8C\u8BF7\u6C42\u4F20\u5165\u7684\u7FA4\u662F\u5426\u88AB\u5141\u8BB8\u3002","connectors.dynamicHint":'<b>\u52A8\u6001\u6A21\u5F0F</b>\uFF1A\u7FA4 ID \u968F\u6BCF\u6B21\u8BF7\u6C42\u4F20\u5165\uFF0C\u4E09\u9009\u4E00 \u2014\u2014 \u67E5\u8BE2\u53C2\u6570 <code>?chatId=<\u7FA4ID></code> \xB7 \u8BF7\u6C42\u5934 <code>x-botmux-chat-id: <\u7FA4ID></code> \xB7 \u8BF7\u6C42\u4F53 <code>{"chatId":"<\u7FA4ID>"}</code>\u3002<br>\u60F3"\u4E00\u4E2A URL \u76F4\u63A5\u89E6\u53D1\u3001\u4E0D\u5E26\u53C2\u6570"\uFF0C\u8BF7\u6539\u9009\u300C\u56FA\u5B9A\u7FA4\u300D\u3002',"connectors.fDedup":"\u53BB\u91CD\u5B57\u6BB5","connectors.fDedupPh":"\u5982 alert.id\uFF08\u4ECE\u4E8B\u4EF6 body \u53D6\u503C\uFF09","connectors.dedupHint":"\u586B\u4E86\uFF1A\u547D\u4E2D\u76F8\u540C\u503C\u7684\u4E8B\u4EF6\u90FD\u6295\u5230<b>\u540C\u4E00\u4E2A\u7FA4</b>\u3002\u7559\u7A7A\uFF1A\u6BCF\u4E2A\u4E8B\u4EF6<b>\u65B0\u5EFA\u4E00\u4E2A\u7FA4</b>\u3002","connectors.fInstruction":"\u5904\u7406\u6307\u4EE4","connectors.fInstructionPh":"\u4E8B\u4EF6\u89E6\u53D1\u65F6\u8BA9\u673A\u5668\u4EBA\u505A\u4EC0\u4E48\u3002\u5982\uFF1A\u603B\u7ED3\u8FD9\u6761\u544A\u8B66\u7684\u4E25\u91CD\u7A0B\u5EA6\uFF0C@\u76F8\u5173 oncall\uFF0C\u7ED9\u51FA\u6392\u67E5\u5EFA\u8BAE\u3002\u7559\u7A7A = \u53EA\u628A\u4E8B\u4EF6\u539F\u6837\u4EA4\u7ED9\u6A21\u578B\u81EA\u7531\u53D1\u6325\u3002","connectors.fVerify":"\u6821\u9A8C\u65B9\u5F0F","connectors.verifyToken":"\u4EE4\u724C\uFF08\u7B80\u5355\uFF1A\u5BC6\u94A5\u653E\u8FDB URL\uFF0C\u4E00\u6761 curl \u5C31\u80FD\u89E6\u53D1\uFF09","connectors.verifyHmac":"HMAC \u7B7E\u540D\uFF08\u9AD8\u7EA7\uFF1A\u66F4\u5B89\u5168\uFF0C\u9700\u81EA\u884C\u5BF9\u8BF7\u6C42\u7B7E\u540D\uFF09","connectors.fSecret":"\u5BC6\u94A5 / \u4EE4\u724C","connectors.fSecretPh":"\u7559\u7A7A\u81EA\u52A8\u751F\u6210\uFF08\u53EA\u663E\u793A\u4E00\u6B21\uFF09","connectors.btnCreate":"\u521B\u5EFA","connectors.listTitle":"\u5DF2\u6709 Webhook","connectors.loading":"\u52A0\u8F7D\u4E2D\u2026","connectors.noBotGroups":"\uFF08\u8BE5\u673A\u5668\u4EBA\u6682\u65E0\u53EF\u89C1\u7FA4\uFF0C\u70B9\u53F3\u4FA7\u624B\u52A8\u586B ID\uFF09","connectors.modeLabelFixed":"\u56FA\u5B9A\u7FA4","connectors.modeLabelNewGroup":"\u6BCF\u6B21\u65B0\u5EFA\u7FA4","connectors.modeLabelDynamic":"\u8BF7\u6C42\u6307\u5B9A\u7FA4","connectors.kindLabelWorkflow":"\u5DE5\u4F5C\u6D41","connectors.kindLabelTurn":"\u5355\u8F6E","connectors.count":"\xB7 {count} \u4E2A","connectors.empty":"\u8FD8\u6CA1\u6709 Webhook\u3002\u7528\u4E0A\u9762\u7684\u8868\u5355\u521B\u5EFA\u4E00\u4E2A\u3002","connectors.enabled":"\u5DF2\u542F\u7528","connectors.disabled":"\u5DF2\u505C\u7528","connectors.badgeToken":"\u4EE4\u724C","connectors.badgeSign":"\u7B7E\u540D","connectors.dest":"\u6295\u9012\u300C{name}\u300D","connectors.btnDisable":"\u505C\u7528","connectors.btnEnable":"\u542F\u7528","connectors.btnDel":"\u5220\u9664","connectors.webhookUrl":"Webhook URL\uFF1A","connectors.copy":"\u590D\u5236","connectors.copied":"\u5DF2\u590D\u5236","connectors.tokenHint":"\u4EE4\u724C\u6A21\u5F0F\uFF1A\u8C03\u7528\u65F6\u5728 URL \u672B\u5C3E\u8FFD\u52A0 <code>/<\u4EE4\u724C></code>\uFF08\u4EE4\u724C\u4EC5\u521B\u5EFA/\u8F6E\u6362\u65F6\u663E\u793A\u4E00\u6B21\uFF09\u3002","connectors.dynamicReqHint":'\u52A8\u6001\u6A21\u5F0F\uFF1A\u8BF7\u6C42\u9700\u5E26\u76EE\u6807\u7FA4 \u2014\u2014 <code>?chatId=<\u7FA4ID></code> \u6216\u5934 <code>x-botmux-chat-id</code> \u6216 body <code>{"chatId":"\u2026"}</code>\u3002',"connectors.instructionPrefix":"\u5904\u7406\u6307\u4EE4\uFF1A","connectors.delConfirm":"\u5220\u9664\u8FD9\u4E2A Webhook\uFF1F\u5B83\u7684 URL \u4F1A\u7ACB\u5373\u5931\u6548\u3002","connectors.errName":"\u8BF7\u586B\u540D\u79F0","connectors.errBot":"\u8BF7\u9009\u673A\u5668\u4EBA","connectors.errWf":"\u8BF7\u586B\u5DE5\u4F5C\u6D41 ID","connectors.errChat":"\u8BF7\u9009\u62E9\uFF08\u6216\u624B\u52A8\u586B\uFF09\u6295\u9012\u7684\u7FA4","connectors.creating":"\u521B\u5EFA\u4E2D\u2026","connectors.usageDynamicLede":"\u52A8\u6001\u6A21\u5F0F\uFF1AURL \u5DF2\u542B\u4EE4\u724C\uFF0C\u8C03\u7528\u65F6\u518D\u5E26\u4E0A\u76EE\u6807\u7FA4 ID{gn}\uFF1A","connectors.usageDynamicNote":'\u7FA4\u4E5F\u53EF\u653E\u8BF7\u6C42\u5934 <code>x-botmux-chat-id</code> \u6216 body <code>{"chatId":"\u2026"}</code>\u3002\u26A0\uFE0F URL \u5373\u51ED\u8BC1\uFF0C\u52FF\u6CC4\u6F0F\u3002',"connectors.usageTokenLede":"\u6B64 URL \u5DF2\u542B\u4EE4\u724C\u3001\u4E14\u56FA\u5B9A\u6295\u9012\u5230\u6240\u9009\u7FA4\uFF0C\u76F4\u63A5 POST \u5373\u53EF\u89E6\u53D1\uFF1A","connectors.usageTokenNote":"\u26A0\uFE0F URL \u5373\u51ED\u8BC1\uFF0C\u8BF7\u52FF\u516C\u5F00\u6CC4\u6F0F\uFF1B\u53EF\u5728\u4E0B\u65B9\u5217\u8868\u5220\u9664\u6216\u8F6E\u6362\u3002","connectors.usageHmac":"\u5916\u90E8\u7CFB\u7EDF\u9700\u5BF9 <code>timestamp.body</code> \u505A HMAC-SHA256 \u7B7E\u540D\uFF0C\u5E76\u5E26\u4E0A <code>x-botmux-timestamp</code> / <code>x-botmux-nonce</code> / <code>x-botmux-signature</code> \u5934\u8C03\u7528","connectors.usageHmacDynamic":"\uFF0C\u540C\u65F6\u6309\u4E0A\u9762\u65B9\u5F0F\u5E26\u76EE\u6807\u7FA4 ID","connectors.createdPrefix":"\u5DF2\u521B\u5EFA\u300C{name}\u300D","connectors.createdDest":"\u6295\u9012\u5230\u300C{name}\u300D","connectors.tokenLabel":"\u8BBF\u95EE\u4EE4\u724C","connectors.signLabel":"\u7B7E\u540D\u5BC6\u94A5","connectors.secretOnce":"\uFF08\u53EA\u663E\u793A\u8FD9\u4E00\u6B21\uFF0C\u8BF7\u4FDD\u5B58\uFF09\uFF1A","connectors.createFailed":"\u521B\u5EFA\u5931\u8D25\uFF1A{error}","connectors.noOnlineBots":"\uFF08\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF09","team.navHome":"\u6211\u7684\u56E2\u961F","team.navManage":"\u56E2\u961F\u7BA1\u7406","team.eyebrow":"\u56E2\u961F","team.homeTitle":"\u56E2\u961F\u534F\u4F5C\uFF08\u8DE8\u90E8\u7F72\uFF09","team.homeLede":"\u628A\u522B\u7684\u90E8\u7F72\uFF08\u540C\u4E8B\u81EA\u5DF1\u8DD1\u7684 botmux\uFF09\u9080\u8BF7\u8FDB\u540C\u4E00\u4E2A\u56E2\u961F\uFF0C\u4E92\u76F8\u53D1\u73B0\u673A\u5668\u4EBA\u3001\u534F\u4F5C\u62C9\u7FA4\u3002","team.localDeployTitle":"\u672C\u90E8\u7F72","team.myIdentity":"\u6211\u7684\u98DE\u4E66\u8EAB\u4EFD\uFF1A","team.unbound":"\u672A\u7ED1\u5B9A","team.bindBtn":"\u7ED1\u5B9A","team.bindHint":"\uFF08\u7528\u673A\u5668\u4EBA\u51ED\u8BC1\u81EA\u52A8\u8BC6\u522B\u4F60\uFF1B\u7ED1\u5B9A\u540E\u62C9\u7FA4\u4F1A\u628A\u4F60\u62C9\u8FDB\u7FA4\u3001\u673A\u5668\u4EBA\u4E5F\u5F52\u5230\u4F60\u540D\u4E0B\uFF09","team.myTeams":"\u6211\u7684\u56E2\u961F","team.searchPh":"\u641C\u7D22 \u540D\u79F0/\u80FD\u529B/CLI\u2026","team.allCli":"\u5168\u90E8 CLI","team.hasCap":"\u6709\u80FD\u529B\u6807\u7B7E","team.hasRole":"\u6709\u9ED8\u8BA4\u89D2\u8272","team.teamsHint":"\u6BCF\u4E2A\u56E2\u961F\u91CC\u52FE\u9009\u673A\u5668\u4EBA\u5373\u53EF\u5355\u72EC\u62C9\u7FA4\uFF08\u81EA\u52A8\u5E26\u4E0A\u5404\u81EA\u8D1F\u8D23\u4EBA\uFF09\u3002\u8981\u65B0\u5EFA\u56E2\u961F / \u751F\u6210\u9080\u8BF7\u7801 / \u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\uFF0C\u53BB\u300C\u56E2\u961F\u7BA1\u7406\u300D\u3002","team.loading":"\u52A0\u8F7D\u4E2D\u2026","team.roleModalTitle":"\u9ED8\u8BA4\u89D2\u8272","team.roleModalHint":"\u8BE5\u673A\u5668\u4EBA\u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF08\u8DE8\u7FA4\u751F\u6548\uFF09\uFF0C\u6B64\u5904\u53EA\u8BFB\u3002\u5982\u9700\u4FEE\u6539\uFF0C\u8BF7\u5230\u300CBot \u914D\u7F6E\u300D\u9875\u3002","team.close":"\u5173\u95ED","team.tagLocal":"\u672C\u90E8\u7F72","team.tagRemoteStale":"\u8FDC\u7AEF\xB7\u79BB\u7EBF\uFF1F","team.tagRemote":"\u8FDC\u7AEF","team.removeMember":"\u79FB\u9664","team.depTag":"\uFF08{tag}\uFF09","team.depCount":"{count} \u4E2A","team.depSelected":"\uFF0C\u5DF2\u9009 {n}","team.capPh":"\u80FD\u529B\u6807\u7B7E\u2026","team.viewRole":"\u67E5\u770B","team.hasRoleShort":"\u6709\u89D2\u8272","team.noMatch":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u673A\u5668\u4EBA\u3002","team.gnamePh":"\u7FA4\u540D\uFF08\u5982\uFF1A\u8DE8\u56E2\u961F\u6392\u969C\uFF09","team.pullGroupBtn":"\u628A\u52FE\u9009\u7684\u673A\u5668\u4EBA\u62C9\u4E00\u4E2A\u7FA4","team.pullGroupHint":"\u52FE\u9009\u673A\u5668\u4EBA \u2192 \u62C9\u5230\u4E00\u4E2A\u98DE\u4E66\u7FA4\uFF08\u81EA\u52A8\u542B owner\uFF09","team.noTeams":"\u8FD8\u6CA1\u6709\u56E2\u961F\u3002\u53BB\u300C\u56E2\u961F\u7BA1\u7406\u300D\u751F\u6210\u9080\u8BF7\u7801\u8BA9\u522B\u4EBA\u52A0\u5165\u4F60\uFF0C\u6216\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\u3002","team.connected":"\u5DF2\u8FDE\u63A5","team.connectFail":"\u8FDE\u63A5\u5931\u8D25\uFF1A{error}","team.iHost":"\u6211\u6258\u7BA1","team.teamMeta":"{deps} \u4E2A\u90E8\u7F72 \xB7 {bots} \u4E2A\u673A\u5668\u4EBA","team.rosterFail":"\u65E0\u6CD5\u83B7\u53D6\u8BE5\u56E2\u961F\u82B1\u540D\u518C\u3002","team.acrossTeams":"\uFF08\u8DE8 {n} \u4E2A\u56E2\u961F\uFF0C\u53BB\u91CD\uFF09","team.botsWord":"\u4E2A\u673A\u5668\u4EBA","team.groupCreated":"\u7FA4\u5DF2\u521B\u5EFA","team.delegatedBy":"\uFF08\u7531\u300C{name}\u300D\u5EFA\u7FA4\uFF09","team.openInLark":"\u5728\u98DE\u4E66\u6253\u5F00","team.invalidBots":"\u672A\u52A0\u5165\u7684\u673A\u5668\u4EBA\uFF1A{ids}","team.invalidOwners":"{n} \u4E2A owner \u672A\u80FD\u62C9\u8FDB","team.missingIdentity":"\u4F60\u672A\u7ED1\u5B9A\u98DE\u4E66\u8EAB\u4EFD\uFF0C\u6CA1\u628A\u4F60\u81EA\u5DF1\u62C9\u8FDB\u7FA4\uFF08\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u7ED1\u5B9A\uFF09","team.skippedNoOwner":"{n} \u4E2A\u673A\u5668\u4EBA\u56E0\u8D1F\u8D23\u4EBA\u672A\u7ED1\u5B9A\u8EAB\u4EFD\u88AB\u8DF3\u8FC7\uFF08\u672A\u52A0\u5165\u7FA4\uFF09","team.errNoLocalBot":"\u8BF7\u81F3\u5C11\u52FE\u9009\u4E00\u4E2A\u4F60\u81EA\u5DF1\uFF08\u672C\u90E8\u7F72\uFF09\u7684\u5728\u7EBF\u673A\u5668\u4EBA\u2014\u2014\u7FA4\u8981\u7531\u5B83\u521B\u5EFA\u5E76\u628A\u4F60\uFF08\u53D1\u8D77\u4EBA\uFF09\u62C9\u8FDB\u7FA4\u3002","team.errAllSkipped":"\u6240\u9009\u673A\u5668\u4EBA\u7684\u8D1F\u8D23\u4EBA\u90FD\u6CA1\u7ED1\u5B9A\u8EAB\u4EFD\uFF0C\u65E0\u6CD5\u62C9\u7FA4\uFF08\u673A\u5668\u4EBA\u4E0D\u80FD\u8FDB\u4E00\u4E2A owner \u4E0D\u5728\u7684\u7FA4\uFF09\u3002\u8BF7\u8BA9\u5BF9\u5E94\u90E8\u7F72\u5148\u7ED1\u5B9A\u8EAB\u4EFD\u3002","team.errNoCreator":"\u6CA1\u6709\u53EF\u7528\u7684\u5EFA\u7FA4\u53D1\u8D77\u65B9\uFF08\u76F8\u5173\u90E8\u7F72\u90FD\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF0C\u6216\u4E0D\u53EF\u8FBE\uFF09","team.errDelegationTimeout":"\u59D4\u6258\u5BF9\u65B9\u90E8\u7F72\u5EFA\u7FA4\u8D85\u65F6\uFF08\u53EF\u80FD\u5DF2\u5EFA\uFF0C\u53BB\u98DE\u4E66\u786E\u8BA4\uFF0C\u52FF\u91CD\u590D\u70B9\uFF09","team.errGroupCreate":"\u5EFA\u7FA4\u5931\u8D25\uFF1A{error}","team.roleModalTitleName":"\u9ED8\u8BA4\u89D2\u8272 \xB7 {name}","team.bound":"\u5DF2\u7ED1\u5B9A","team.myHostedTeam":"\u6211\u6258\u7BA1\u7684\u56E2\u961F","team.remoteTeamLabel":"{name} \u7684\u56E2\u961F","team.manageTitle":"\u56E2\u961F\u7BA1\u7406","team.manageLede":"\u521B\u5EFA\u591A\u4E2A\u56E2\u961F\u3001\u7ED9\u6BCF\u4E2A\u56E2\u961F\u751F\u6210\u9080\u8BF7\u7801\u3001\u6216\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\u3002\u4E00\u4E2A\u56E2\u961F = \u4F60\u672C\u90E8\u7F72\u7684\u673A\u5668\u4EBA + \u52A0\u5165\u8BE5\u56E2\u961F\u7684\u5176\u5B83\u90E8\u7F72\u3002","team.hostedTitle":"\u6211\u6258\u7BA1\u7684\u56E2\u961F","team.newTeamPh":"\u65B0\u56E2\u961F\u540D\u79F0","team.createTeamBtn":"\u521B\u5EFA\u56E2\u961F","team.joinTitle":"\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F","team.hubPh":"Hub \u5730\u5740\uFF0C\u5982 http://10.0.0.5:7891","team.codePh":"\u9080\u8BF7\u7801","team.joinBtn":"\u52A0\u5165","team.noTeamsShort":"\u8FD8\u6CA1\u6709\u56E2\u961F\u3002","team.default":"\u9ED8\u8BA4","team.manageMetaDeps":"{count} \u4E2A\u90E8\u7F72","team.manageMetaRemote":"\uFF08\u542B {r} \u8FDC\u7AEF\uFF09","team.manageMetaBots":"{count} \u4E2A\u673A\u5668\u4EBA","team.genInvite":"\u751F\u6210\u9080\u8BF7\u7801","team.delBtn":"\u5220\u9664","team.generating":"\u751F\u6210\u4E2D\u2026","team.inviteResultLede":"\u628A\u4E0B\u9762\u4E24\u9879\u53D1\u7ED9\u522B\u7684\u90E8\u7F72\u7684\u4EBA\uFF0824 \u5C0F\u65F6\u5185\u3001\u5355\u6B21\u6709\u6548\uFF09\uFF1A","team.inviteHub":"Hub \u5730\u5740\uFF1A","team.inviteCode":"\u9080\u8BF7\u7801\uFF1A","team.genFail":"\u751F\u6210\u5931\u8D25\u3002","team.delConfirm":"\u5220\u9664\u56E2\u961F\u300C{name}\u300D\uFF1F\u5DF2\u52A0\u5165\u5B83\u7684\u90E8\u7F72\u4F1A\u88AB\u79FB\u9664\uFF08\u4E0D\u5F71\u54CD\u4ED6\u4EEC\u81EA\u5DF1\u7684\u90E8\u7F72\uFF09\u3002","team.errName":"\u8BF7\u586B\u56E2\u961F\u540D\u79F0","team.creating":"\u521B\u5EFA\u4E2D\u2026","team.created":"\u5DF2\u521B\u5EFA","team.createFail":"\u521B\u5EFA\u5931\u8D25\uFF1A{error}","team.errHubCode":"\u8BF7\u586B Hub \u5730\u5740\u548C\u9080\u8BF7\u7801\u3002","team.joining":"\u52A0\u5165\u4E2D\u2026","team.joined":"\u5DF2\u52A0\u5165\u300C{name}\u300D\uFF0C\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u67E5\u770B\u3002","team.joinErrSelf":"\u8FD9\u662F\u4F60\u81EA\u5DF1\u7684\u90E8\u7F72\uFF0C\u4E0D\u80FD\u52A0\u5165\u81EA\u5DF1\uFF08\u9080\u8BF7\u7801\u8981\u53D1\u7ED9\u522B\u7684\u90E8\u7F72\u7684\u4EBA\u7528\uFF09","team.joinErrAlready":"\u4F60\u7684\u90E8\u7F72\u5DF2\u7ECF\u52A0\u5165\u8FC7\u8FD9\u4E2A\u56E2\u961F\u4E86","team.joinErrUnreachable":"\u8FDE\u4E0D\u4E0A\u5BF9\u65B9 Hub\uFF08\u68C0\u67E5\u5730\u5740/\u7F51\u7EDC\uFF09","team.joinErrTimeout":"\u5BF9\u65B9 Hub \u54CD\u5E94\u8D85\u65F6","team.joinErrGeneric":"\u52A0\u5165\u5931\u8D25\uFF1A{error}","team.identifying":"\u8BC6\u522B\u4E2D\u2026","team.bound2":"\u5DF2\u7ED1\u5B9A\uFF1A{name}","team.multiCandidate":"\u8BC6\u522B\u5230\u591A\u4E2A\u5019\u9009\uFF0C\u70B9\u4F60\u81EA\u5DF1\uFF1A","team.binding":"\u7ED1\u5B9A\u4E2D\u2026","team.bindFail":"\u7ED1\u5B9A\u5931\u8D25\uFF1A{error}","team.noCandidates":"\u6CA1\u8BC6\u522B\u5230\u8EAB\u4EFD\uFF1A\u8BF7\u786E\u8BA4\u673A\u5668\u4EBA\u914D\u7F6E\u4E86 allowedUsers\uFF08\u5141\u8BB8\u4F7F\u7528\u8005\uFF09\uFF0C\u4E14\u673A\u5668\u4EBA\u6709\u901A\u8BAF\u5F55\u6743\u9650\u3002","team.removeMemberConfirm":"\u628A\u300C{name}\u300D\u79FB\u51FA\u8FD9\u4E2A\u56E2\u961F\uFF1F\u5B83\u7684\u673A\u5668\u4EBA\u5C06\u4ECE\u672C\u56E2\u961F\u82B1\u540D\u518C\u6D88\u5931\uFF08\u4E0D\u5F71\u54CD\u5BF9\u65B9\u81EA\u5DF1\u7684\u90E8\u7F72\uFF09\u3002","team.creatingGroup":"\u5EFA\u7FA4\u4E2D\u2026","team.defaultGroupName":"\u534F\u4F5C\u7FA4","team.errPickBot":"\u8BF7\u5148\u52FE\u9009\u81F3\u5C11\u4E00\u4E2A\u673A\u5668\u4EBA","sessions.closeBulkConfirm":"\u5173\u95ED\u9009\u4E2D\u7684 {count} \u4E2A\u4F1A\u8BDD\uFF1F","sessions.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u4F1A\u8BDD\u3002","sessions.viewMode":"\u4F1A\u8BDD\u89C6\u56FE","sessions.viewKanban":"\u770B\u677F","sessions.viewBoard":"\u72B6\u6001\u677F","sessions.viewTable":"\u8868\u683C","sessions.selectSession":"\u9009\u62E9\u4F1A\u8BDD","sessions.board.needsYou":"\u9700\u8981\u4F60","sessions.board.needsYouHint":"\u7B49\u5F85\u4ED3\u5E93\u3001TUI \u9009\u62E9\u6216\u989D\u5EA6\u5904\u7406","sessions.board.starting":"\u542F\u52A8\u4E2D","sessions.board.startingHint":"CLI \u6B63\u5728\u521B\u5EFA\u6216\u6062\u590D","sessions.board.working":"\u5E72\u6D3B\u4E2D","sessions.board.workingHint":"\u6B63\u5728\u8F93\u51FA\u3001\u5206\u6790\u6216\u6267\u884C\u5DE5\u5177","sessions.board.idle":"\u7A7A\u95F2","sessions.board.idleHint":"\u53EF\u7EE7\u7EED\u5BF9\u8BDD\u6216\u63A5\u65B0\u4EFB\u52A1","sessions.board.emptyColumn":"\u6682\u65E0\u4F1A\u8BDD","sessions.board.signalRepo":"\u5F85\u9009\u4ED3\u5E93","sessions.board.signalPrompt":"\u7B49\u5F85 TUI \u9009\u62E9","sessions.board.signalLimited":"\u989D\u5EA6\u53D7\u9650","sessions.board.signalAgent":"\u9700\u8981\u4EBA\u5DE5\u4ECB\u5165","sessions.board.waiting":"\u7B49\u5F85","sessions.board.dragHint":"\u62D6\u52A8\u5217\u5934\u8C03\u6574\u5217\u987A\u5E8F","sessions.board.moveLeft":"\u5DE6\u79FB\u6B64\u5217","sessions.board.moveRight":"\u53F3\u79FB\u6B64\u5217","sessions.kanban.backlog":"\u5F85\u529E\u6C60","sessions.kanban.todo":"\u5F85\u529E","sessions.kanban.inProgress":"\u8FDB\u884C\u4E2D","sessions.kanban.inReview":"\u5F85\u786E\u8BA4","sessions.kanban.done":"\u5DF2\u5B8C\u6210","sessions.kanban.updated":"\u66F4\u65B0\u4E8E {time}","sessions.kanban.moreHidden":"\u8FD8\u6709 {count} \u4E2A\u672A\u663E\u793A","sessions.kanban.openTab":"\u65B0\u6807\u7B7E\u9875\u6253\u5F00","sessions.kanban.openFeishu":"\u6253\u5F00\u98DE\u4E66","sessions.kanban.terminalLoading":"\u6B63\u5728\u6253\u5F00\u7EC8\u7AEF\u2026","sessions.kanban.rename":"\u91CD\u547D\u540D\uFF08\u53CC\u51FB\u6807\u9898\u4E5F\u53EF\uFF09","sessions.kanban.renameFail":"\u91CD\u547D\u540D\u5931\u8D25","sessions.kanban.moveFail":"\u79FB\u52A8\u5931\u8D25","sessions.kanban.groupBy":"\u5206\u7EC4\u7EF4\u5EA6","sessions.kanban.groupFlow":"\u5DE5\u4F5C\u6D41","sessions.kanban.groupTeam":"\u56E2\u961F","sessions.kanban.groupBot":"\u673A\u5668\u4EBA","sessions.kanban.teamLoading":"\u6B63\u5728\u52A0\u8F7D\u56E2\u961F\u2026","sessions.kanban.noTeam":"\u6682\u65E0\u56E2\u961F","sessions.kanban.teamScope":"{chats} \u4E2A\u534F\u4F5C\u7FA4 \xB7 {sessions} \u4E2A\u4F1A\u8BDD","sessions.kanban.remoteHint":"\u6765\u81EA {name} \u90E8\u7F72\u7684\u4F1A\u8BDD\uFF08\u5FEB\u7167\uFF0C\u7EC8\u7AEF/\u5386\u53F2\u5728\u5BF9\u65B9\u673A\u5668\u4E0A\uFF09","sessions.kanban.clusterDragHint":"\u62D6\u52A8\u6807\u9898\u6574\u7EC4\u79FB\u52A8","sessions.history.title":"\u4F1A\u8BDD\u5386\u53F2","sessions.history.loading":"\u6B63\u5728\u62C9\u53D6\u98DE\u4E66\u6D88\u606F\u2026","sessions.history.fail":"\u5386\u53F2\u62C9\u53D6\u5931\u8D25","sessions.history.empty":"\u6CA1\u6709\u6D88\u606F","sessions.history.user":"\u7528\u6237","sessions.history.owner":"\u521B\u5EFA\u8005","sessions.history.staleHint":"dashboard \u6216 daemon \u8FDB\u7A0B\u53EF\u80FD\u8FD8\u5728\u8DD1\u65E7\u7248\u672C\uFF0Cbotmux restart \u540E\u91CD\u8BD5","groups.title":"\u7FA4\u7EC4\u4E0E Bot","groups.subtitle":"\u67E5\u770B chat x bot \u8986\u76D6\u77E9\u9635\uFF0C\u7BA1\u7406\u62C9\u7FA4\u3001oncall\u3001\u9000\u7FA4\u548C\u89E3\u6563\u3002","groups.search":"\u641C\u7D22\u7FA4\u540D / ID / owner","groups.missingOnly":"\u4EC5\u7F3A bot","groups.refresh":"\u5237\u65B0","groups.create":"\u65B0\u5EFA\u7FA4","groups.chat":"\u7FA4\u804A","groups.actions":"\u64CD\u4F5C","groups.addBots":"\u6DFB\u52A0 bot","groups.manage":"\u7BA1\u7406","groups.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u7FA4\u804A\u3002","groups.createTitle":"\u65B0\u5EFA\u7FA4\u804A","groups.createHelp":"\u9009\u62E9\u8981\u9080\u8BF7\u7684 bot\u3002dashboard \u4F1A\u81EA\u52A8\u9009\u62E9\u5728\u7EBF daemon \u4F5C\u4E3A\u521B\u5EFA\u8005\u3002","groups.name":"\u7FA4\u540D","groups.namePlaceholder":"\u4F8B\u5982 AI ChangeLog","groups.bindDir":"\u7ED1\u5B9A\u76EE\u5F55","groups.bindDirHelp":"\u65B0\u8BDD\u9898\u76F4\u63A5\u7528\u8BE5\u76EE\u5F55\u542F\u52A8 CLI\uFF0C\u8DF3\u8FC7 repo \u9009\u62E9\u3002","groups.botPicker":"Bot","groups.createSubmit":"\u521B\u5EFA","groups.cancel":"\u53D6\u6D88","groups.successTitle":"\u7FA4\u521B\u5EFA\u6210\u529F","groups.openGroup":"\u6253\u5F00\u65B0\u7FA4","groups.manageTitle":"\u7BA1\u7406 {name}","groups.owner":"\u7FA4\u4E3B","groups.oncall":"Oncall \u6A21\u5F0F","groups.oncallHelp":"\u5F00\u542F\u540E\uFF0C\u7FA4\u5185\u6210\u5458\u53EF @ \u673A\u5668\u4EBA\uFF1B\u65B0\u8BDD\u9898\u76F4\u63A5\u4F7F\u7528\u7ED1\u5B9A\u76EE\u5F55\u3002","groups.leaveTitle":"\u9009\u62E9\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.leaveSelected":"\u9009\u4E2D\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.disband":"\u89E3\u6563\u7FA4\u804A","groups.dangerHint":"\u89E3\u6563\u4EC5\u5F53\u5728\u7FA4\u673A\u5668\u4EBA\u662F\u7FA4\u4E3B\u65F6\u624D\u4F1A\u6210\u529F\uFF0C\u5426\u5219\u5EFA\u8BAE\u4F7F\u7528\u9000\u51FA\u7FA4\u804A\u3002","groups.save":"\u4FDD\u5B58","groups.needWorkingDir":"\u8BF7\u586B\u5DE5\u4F5C\u76EE\u5F55","groups.noBotsOnline":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u8BF7\u5148\u91CD\u542F daemon\u3002","schedules.title":"\u5B9A\u65F6\u4EFB\u52A1","schedules.subtitle":"\u8DE8 daemon \u67E5\u770B\u3001\u6682\u505C\u3001\u6062\u590D\u548C\u7ACB\u5373\u89E6\u53D1\u5B9A\u65F6\u4EFB\u52A1\u3002","schedules.search":"\u641C\u7D22\u540D\u79F0 / prompt / \u5DE5\u4F5C\u76EE\u5F55","schedules.anyKind":"\u5168\u90E8\u7C7B\u578B","schedules.enabledOnly":"\u4EC5\u542F\u7528","schedules.name":"\u540D\u79F0","schedules.bot":"bot","schedules.schedule":"\u89C4\u5219","schedules.next":"\u4E0B\u6B21","schedules.last":"\u4E0A\u6B21","schedules.repeat":"\u91CD\u590D","schedules.enabled":"\u542F\u7528","schedules.actions":"\u64CD\u4F5C","schedules.runNow":"\u7ACB\u5373\u8FD0\u884C","schedules.pause":"\u6682\u505C","schedules.resume":"\u6062\u590D","schedules.empty":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","settings.title":"\u5168\u5C40\u8BBE\u7F6E","settings.subtitle":"\u7BA1\u7406\u672C\u673A botmux dashboard \u4E0E\u6240\u6709 bot \u5171\u4EAB\u7684\u5168\u5C40\u884C\u4E3A\u3002","settings.loading":"\u6B63\u5728\u52A0\u8F7D\u8BBE\u7F6E\u2026","settings.loadFailed":"\u8BBE\u7F6E\u52A0\u8F7D\u5931\u8D25","settings.readOnlyVisitor":"\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u4FEE\u6539\u8BBE\u7F6E\u9700\u8981\u6388\u6743\u94FE\u63A5\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09","settings.sectionAccess":"\u8BBF\u95EE\u6743\u9650","settings.publicReadOnly":"\u5141\u8BB8\u65E0 token \u53EA\u8BFB\u8BBF\u95EE dashboard","settings.publicReadOnlyHelp":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 token \u7684\u8BBF\u95EE\u8005\u53EF\u4EE5\u67E5\u770B dashboard\u3001\u4F1A\u8BDD\u3001\u5B9A\u65F6\u4EFB\u52A1\u548C SSE\uFF1B\u5173\u95ED\u3001\u6682\u505C\u3001\u5BA1\u6279\u7B49\u5199\u64CD\u4F5C\u4ECD\u5FC5\u987B\u901A\u8FC7 token \u9274\u6743\u3002\u654F\u611F\u7EC8\u7AEF\u539F\u59CB\u65E5\u5FD7\u59CB\u7EC8\u9700\u8981 token\u3002","settings.sectionCards":"\u98DE\u4E66\u5361\u7247","settings.openTerminalInFeishu":"\u6D41\u5F0F\u5361\u7247\u7EC8\u7AEF\u6309\u94AE\u5728\u98DE\u4E66\u4FA7\u680F\u6253\u5F00","settings.openTerminalInFeishuHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF1A\u7EC8\u7AEF\u6309\u94AE\u76F4\u63A5\u6253\u5F00 Web Terminal URL\u3002\u5F00\u542F\u540E\u4F7F\u7528\u98DE\u4E66 web_url/open \u5305\u88C5\uFF0C\u5728\u98DE\u4E66 PC \u4FA7\u680F\u91CC\u6253\u5F00\uFF1B\u5199\u6743\u9650\u4ECD\u7531\u7EC8\u7AEF token \u63A7\u5236\u3002","settings.sectionRepoPicker":"\u4ED3\u5E93\u9009\u62E9","settings.repoPickerMode":"\u4ED3\u5E93\u9009\u62E9\u5361\u6A21\u5F0F","settings.repoPickerModeAll":"\u4ED3\u5E93 + worktree","settings.repoPickerModeRepos":"\u4EC5\u4E3B\u4ED3\u5E93","settings.repoPickerModeHelp":"\u9ED8\u8BA4\u663E\u793A\u4ED3\u5E93\u548C linked worktree\u3002\u9009\u62E9\u300C\u4EC5\u4E3B\u4ED3\u5E93\u300D\u540E\uFF0C\u521D\u59CB\u5316\u548C\u88F8 /repo \u7684\u9009\u62E9\u5361\u53EA\u5217\u4E3B\u4ED3\u5E93\uFF1B\u663E\u5F0F /repo /abs/path/to/worktree \u4ECD\u53EF\u76F4\u8FBE worktree\u3002","settings.saving":"\u4FDD\u5B58\u4E2D\u2026","settings.saved":"\u5DF2\u4FDD\u5B58","settings.saveFailed":"\u4FDD\u5B58\u5931\u8D25","settings.sectionMaintenance":"\u81EA\u52A8\u7EF4\u62A4","settings.autoUpdate":"\u81EA\u52A8\u66F4\u65B0","settings.autoUpdateHelp":"\u9ED8\u8BA4\u5173\u95ED\u3002\u5230\u70B9\u6267\u884C npm install -g botmux@latest \u5B89\u88C5\u6700\u65B0\u7248\u672C\uFF08\u53EA\u4E0B\u8F7D\u5B89\u88C5\u3001\u672C\u8EAB\u4E0D\u91CD\u542F\uFF09\u3002\u4EC5 npm \u5168\u5C40\u5B89\u88C5\u53EF\u7528\u3002","settings.autoRestart":"\u81EA\u52A8\u91CD\u542F","settings.autoRestartHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF0C\u9700\u5148\u5F00\u542F\u81EA\u52A8\u66F4\u65B0\u3002\u81EA\u52A8\u66F4\u65B0\u88C5\u5230\u65B0\u7248\u672C\u540E\uFF0C\u82E5\u6CA1\u6709\u8FDB\u884C\u4E2D\u7684\u4F1A\u8BDD\u5219\u81EA\u52A8\u91CD\u542F\u4EE5\u751F\u6548\uFF08\u649E\u4E0A\u5FD9\u788C\u4F1A\u8BDD\u5219\u8DF3\u5230\u6B21\u65E5\uFF09\u3002","settings.autoUpdateLocalDev":"\u5F53\u524D\u4E3A\u672C\u5730\u5F00\u53D1\u5B89\u88C5\uFF08\u4ECE\u6E90\u7801\u8FD0\u884C\uFF09\uFF0C\u81EA\u52A8\u66F4\u65B0\u4E0D\u53EF\u7528\u3002","settings.maintenanceTime":"\u65F6\u95F4","botDefaults.title":"\u6570\u5B57\u5458\u5DE5\u6863\u6848","botDefaults.subtitle":"\u6BCF\u4F4D\u5458\u5DE5\u7684\u9ED8\u8BA4\u884C\u4E3A\uFF1Aoncall\u3001\u4E3B\u52A8\u5F00\u5DE5\u3001\u4EBA\u8BBE\u89D2\u8272\u3001\u5361\u7247\u4E0E\u6388\u6743\u3002","botDefaults.metaOnline":"\u5728\u7EBF \xB7 daemon \u6B63\u5E38","botDefaults.search":"\u641C\u7D22 bot \u540D / app id","botDefaults.refresh":"\u5237\u65B0","botDefaults.sectionOncall":"\u65B0\u7FA4 Oncall","botDefaults.sectionBrand":"\u5361\u7247\u7B7E\u540D","botDefaults.warning":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 oncall binding \u7684\u7FA4\u4F1A\u5728\u4E0B\u6B21\u5F00\u65B0\u8BDD\u9898\u65F6\u81EA\u52A8\u7ED1\u5B9A\u5230\u8BE5\u76EE\u5F55\uFF1B\u624B\u52A8\u7ED1\u5B9A\u6216\u624B\u52A8\u89E3\u7ED1\u8FC7\u7684\u7FA4\u4E0D\u4F1A\u88AB\u8986\u76D6\u3002","botDefaults.empty":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u5148 botmux restart \u8BA9 daemon \u4E0A\u7EBF\u3002","botDefaults.defaultOncall":"\u9ED8\u8BA4\u8FDB\u5165 oncall \u6A21\u5F0F","botDefaults.defaultOncallHelp":"\u6240\u6709\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8\u7ED1\u5B9A","botDefaults.workingDir":"\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55","botDefaults.lastEnabled":"\u4E0A\u6B21\u542F\u7528\u65F6\u95F4","botDefaults.autobound":"\u5DF2\u81EA\u52A8\u7ED1\u5B9A {count} \u4E2A\u7FA4","botDefaults.save":"\u4FDD\u5B58","botDefaults.required":"\u5F00\u542F\u65F6\u5FC5\u987B\u586B\u5DE5\u4F5C\u76EE\u5F55","botDefaults.brandLabel":"\u4E2A\u6027\u7B7E\u540D\uFF08\u5361\u7247\u9875\u811A\uFF09","botDefaults.brandLabelHelp":"\u8BE5 bot \u53D1\u51FA\u7684\u5361\u7247\u9875\u811A\u7B7E\u540D\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u4E0D\u663E\u793A\uFF1B\u586B\u5199\uFF1D\u81EA\u5B9A\u4E49\uFF08\u652F\u6301 markdown\uFF0C\u5982 [Acme](https://\u2026)\uFF09\uFF1B\u6062\u590D\u9ED8\u8BA4\uFF1D\u663E\u793A botmux\u3002","botDefaults.brandLabelPlaceholder":"\u9ED8\u8BA4\uFF1Abotmux\uFF08\u7559\u7A7A\u5219\u4E0D\u663E\u793A\uFF09","botDefaults.sectionSandbox":"\u6587\u4EF6\u6C99\u76D2\uFF08oncall\uFF09","botDefaults.sandboxToggle":"\u5F00\u542F\u6587\u4EF6\u6C99\u76D2","botDefaults.sandboxHelp":"\u5F00\u542F\u540E\uFF0C\u8BE5 bot \u7684\u6BCF\u4E2A\u4F1A\u8BDD\u90FD\u8DD1\u5728\u6309\u4F1A\u8BDD\u9694\u79BB\u7684\u6C99\u76D2\u91CC\uFF1A\u53EA\u770B\u5F97\u5230\u4E00\u4EFD\u9879\u76EE\u526F\u672C\uFF0C\u78B0\u4E0D\u5230\u4F60\u78C1\u76D8\u4E0A\u7684\u771F\u5B9E\u6587\u4EF6\u3001\u5BC6\u94A5\u3001\u522B\u7684\u4F1A\u8BDD\u6570\u636E\u3002\u9002\u5408\u628A\u673A\u5668\u4EBA\u5206\u4EAB\u7ED9\u534A\u53D7\u4FE1\u4EFB\u7684\u4EBA\uFF08oncall\uFF09\u3002\u4EC5 Linux \u751F\u6548\uFF0C\u4E0B\u4E2A\u65B0\u4F1A\u8BDD\u8D77\u6548\u3002","botDefaults.sandboxSaved":"\u5DF2\u4FDD\u5B58\uFF08\u4E0B\u4E2A\u65B0\u4F1A\u8BDD\u751F\u6548\uFF09","botDefaults.brandSave":"\u4FDD\u5B58\u7B7E\u540D","botDefaults.brandReset":"\u6062\u590D\u9ED8\u8BA4","botDefaults.brandStateDefault":"\u5F53\u524D\uFF1A\u9ED8\u8BA4 botmux","botDefaults.brandStateOff":"\u5F53\u524D\uFF1A\u5DF2\u5173\u95ED","botDefaults.brandStateCustom":"\u5F53\u524D\uFF1A\u81EA\u5B9A\u4E49","botDefaults.sectionCard":"\u5361\u7247\u884C\u4E3A","botDefaults.disableStreaming":"\u5173\u95ED\u98DE\u4E66\u6D41\u5F0F\u5361\u7247","botDefaults.disableStreamingHelp":"\u4E0D\u518D\u53D1\u5B9E\u65F6\u5237\u65B0\u7684\u4F1A\u8BDD\u72B6\u6001\u5361\uFF08\u542B\u300C\u6253\u5F00\u7EC8\u7AEF\u300D\u5165\u53E3\uFF09\uFF1B\u4EFB\u52A1\u6700\u7EC8\u7ED3\u679C\u4ECD\u901A\u8FC7\u6D88\u606F\u9001\u8FBE\u3002\u9002\u5408\u5ACC\u6D41\u5F0F\u5361\u7247\u70E6\u7684\u573A\u666F\u3002","botDefaults.writableLink":"\u5361\u7247\u4E0A\u76F4\u63A5\u7ED9\u53EF\u64CD\u4F5C\uFF08\u53EF\u5199\uFF09\u7EC8\u7AEF\u94FE\u63A5","botDefaults.writableLinkHelp":"\u26A0\uFE0F \u5728\u6D41\u5F0F\u5361\u7247\u6B63\u6587\u76F4\u63A5\u8D34\u51FA\u53EF\u5199\u7EC8\u7AEF\u94FE\u63A5\uFF0C\u7FA4\u5185\u4EFB\u4F55\u4EBA\u90FD\u80FD\u70B9\u5F00\u5E76\u64CD\u63A7\u7EC8\u7AEF\u3002\u4E0D\u52FE\uFF1D\u4FDD\u6301\u73B0\u72B6\uFF08\u8D70\u300C\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u300D\u6309\u94AE\u79C1\u804A\u53D1\u7ED9\u70B9\u51FB\u8005\uFF09\u3002","botDefaults.writableLinkMoot":"\u5DF2\u5173\u95ED\u6D41\u5F0F\u5361\u7247","botDefaults.privateCard":"/card \u53D1\u79C1\u5BC6\u5361\u7247\uFF08\u4EC5\u6388\u6743\u4EBA\u53EF\u89C1\uFF09","botDefaults.privateCardHelp":"\u5F00\u542F\u540E /card \u6539\u7528\u300C\u4EC5\u7279\u5B9A\u4EBA\u53EF\u89C1\u300D\u7684\u4E34\u65F6\u5361\u7247\uFF1A\u53EA\u53D1\u7ED9 owner\uFF08allowedUsers\uFF09\uFF0C/grant \u6388\u6743\u5BF9\u8BDD\u7684\u4EBA\u548C\u7FA4\u91CC\u5176\u4ED6\u4EBA\u90FD\u770B\u4E0D\u5230\u3002\u4EE3\u4EF7\uFF1A\u662F\u9759\u6001\u5FEB\u7167\u3001\u4E0D\u4F1A\u5B9E\u65F6\u5237\u65B0\uFF1B\u4E14\u4EC5\u666E\u901A\u7FA4\u53EF\u7528\uFF08\u8BDD\u9898\u7FA4 / \u5355\u804A\u4F1A\u5931\u8D25\uFF0C\u4E0D\u964D\u7EA7\uFF09\u3002\u53EA\u5F71\u54CD /card \u547D\u4EE4\uFF0C\u81EA\u52A8\u6D41\u5F0F\u5361\u4E0D\u53D8\u3002","botDefaults.cardPrefSaved":"\u5DF2\u4FDD\u5B58","botDefaults.sectionRole":"\u9ED8\u8BA4\u89D2\u8272","botDefaults.roleHelp":"\u8BE5 bot \u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF08\u8DE8\u7FA4\u751F\u6548\uFF09\uFF0C\u4F1A\u6CE8\u5165\u5230\u8BE5 bot \u5728\u5404\u7FA4\u7684\u4F1A\u8BDD\u91CC\uFF1B\u5355\u4E2A\u7FA4\u53EF\u5728\u300C\u89D2\u8272\u300D\u9875\u5355\u72EC\u8986\u76D6\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u5220\u9664\u3002","botDefaults.rolePlaceholder":"\u4F8B\u5982\uFF1A\u4F60\u662F\u540E\u7AEF\u6392\u969C\u52A9\u624B\uFF0C\u56DE\u7B54\u7B80\u6D01\u3001\u4F18\u5148\u7ED9\u53EF\u6267\u884C\u547D\u4EE4\u2026","botDefaults.roleSave":"\u4FDD\u5B58\u89D2\u8272","botDefaults.roleDelete":"\u5220\u9664","botDefaults.roleSaved":"\u5DF2\u4FDD\u5B58","botDefaults.roleDeleted":"\u5DF2\u5220\u9664","botDefaults.roleLoadErr":"\u89D2\u8272\u52A0\u8F7D\u5931\u8D25","botDefaults.sectionAutoStart":"\u4E3B\u52A8\u5F00\u5DE5","botDefaults.autoStartJoin":"\u88AB\u62C9\u8FDB\u65B0\u7FA4\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartJoinHelp":"\u5F00\u542F\u540E\uFF0C\u673A\u5668\u4EBA\u4E00\u88AB\u62C9\u8FDB\u65B0\u7FA4\uFF08\u7FA4\u91CC\u6709\u6388\u6743\u7528\u6237 allowedUsers \u65F6\uFF09\u5C31\u81EA\u52A8\u5F00\u4E00\u4E2A\u4F1A\u8BDD\u5F00\u59CB\u5DE5\u4F5C\uFF0C\u65E0\u9700 @\u3002\u5728\u673A\u5668\u4EBA\u7684\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55\u542F\u52A8\uFF1B\u672A\u914D\u7F6E\u9ED8\u8BA4\u76EE\u5F55\u65F6\u5148\u5F39\u4ED3\u5E93\u9009\u62E9\u5361\u8BA9\u4F60\u9009\u3002\u524D\u63D0\uFF1A\u9700\u5728\u98DE\u4E66\u5F00\u653E\u5E73\u53F0\u4E3A\u672C\u5E94\u7528\u8BA2\u9605\u300C\u673A\u5668\u4EBA\u8FDB\u7FA4\u300D\u4E8B\u4EF6 im.chat.member.bot.added_v1\uFF0C\u5E76\u5F00\u901A\u7FA4\u6210\u5458\u8BFB\u53D6\u6743\u9650\u3002","botDefaults.autoStartJoinPrompt":"\u5165\u7FA4\u9996\u8F6E prompt\uFF08\u53EF\u9009\uFF09","botDefaults.autoStartJoinPromptPlaceholder":"\u586B\u4E86\uFF1D\u4F5C\u4E3A\u5165\u7FA4\u540E\u7684\u7B2C\u4E00\u6761\u4EFB\u52A1\uFF1B\u7559\u7A7A\uFF1D\u673A\u5668\u4EBA\u81EA\u5DF1\u770B\u7FA4\u91CC\u4FE1\u606F\u51B3\u5B9A\u505A\u4EC0\u4E48","botDefaults.autoStartJoinPromptSave":"\u4FDD\u5B58 prompt","botDefaults.autoStartTopic":"\u8BDD\u9898\u7FA4\u65B0\u8BDD\u9898\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartTopicHelp":"\u5F00\u542F\u540E\uFF0C\u5728\u8BDD\u9898\u7FA4\u91CC\u6BCF\u5F53\u6709\u4EBA\u65B0\u5F00\u4E00\u4E2A\u8BDD\u9898\uFF0C\u673A\u5668\u4EBA\u5C31\u4F1A\u81EA\u52A8\u63A5\u5165\u8BE5\u8BDD\u9898\u3001\u628A\u9996\u6761\u6D88\u606F\u5F53\u4F5C\u4EFB\u52A1\u5F00\u59CB\u5904\u7406\uFF0C\u65E0\u9700 @\u3002\u4EC5\u5BF9\u8BDD\u9898\u7FA4\u751F\u6548\uFF0C\u666E\u901A\u7FA4\u4E0D\u53D7\u5F71\u54CD\u3002","botDefaults.sectionSessionMode":"\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.p2pMode":"\u79C1\u804A\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.p2pThread":"thread\uFF08\u6BCF\u6761 DM \u72EC\u7ACB\u4F1A\u8BDD\uFF09","botDefaults.p2pChat":"chat\uFF08\u6241\u5E73\u8FDE\u7EED\u5355\u804A\u4F1A\u8BDD\uFF09","botDefaults.p2pHelp":"\u79C1\u804A\uFF081:1 DM\uFF09\u7684\u4F1A\u8BDD\u65B9\u5F0F\uFF1Athread = \u6BCF\u6761\u9876\u5C42\u6D88\u606F\u5404\u81EA\u8D77\u72EC\u7ACB\u4F1A\u8BDD\uFF08\u907F\u514D\u628A\u5BF9\u8BDD\u5806\u8FDB\u540C\u4E00\u4E2A CLI \u8FDB\u7A0B\uFF09\uFF1Bchat = \u6574\u6BB5 DM \u5171\u7528\u4E00\u4E2A\u8FDE\u7EED\u4F1A\u8BDD\u3001\u5171\u4EAB\u4E0A\u4E0B\u6587\uFF08\u7C7B Hermes\uFF09\u3002\u6539\u540E\u7ACB\u5373\u751F\u6548\u3002","botDefaults.regularGroupMode":"\u666E\u901A\u7FA4\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.regularGroupModeChat":"chat\uFF08\u6241\u5E73\u8FDE\u7EED\u5355\u804A\u4F1A\u8BDD\uFF0C\u9ED8\u8BA4\uFF09","botDefaults.regularGroupModeNewTopic":"new-topic\uFF08\u6BCF\u6761\u9876\u5C42 @ \u5404\u5F00\u72EC\u7ACB\u8BDD\u9898\u4E0E\u4F1A\u8BDD\uFF09","botDefaults.regularGroupModeShared":"shared\uFF08\u8BDD\u9898\u6A21\u5F0F\u4F46\u590D\u7528\u540C\u4E00\u4E2A session\uFF09","botDefaults.regularGroupModeHelp":"\u666E\u901A\u7FA4\uFF08\u975E\u8BDD\u9898\u7FA4\uFF09\u91CC @ \u8BE5 bot \u7684\u65B0\u9876\u5C42\u6D88\u606F\u600E\u4E48\u5F00\u4F1A\u8BDD\uFF1Achat = \u6574\u7FA4\u5171\u7528\u4E00\u4E2A\u8FDE\u7EED\u4F1A\u8BDD\uFF08\u9ED8\u8BA4\uFF09\uFF1Bnew-topic = \u6BCF\u6761\u9876\u5C42 @ \u5728\u539F\u6D88\u606F\u4E0B\u5F00\u72EC\u7ACB\u8BDD\u9898\u3001\u5404\u81EA\u72EC\u7ACB\u4F1A\u8BDD\uFF1Bshared = \u8BDD\u9898\u6A21\u5F0F\u4F46\u590D\u7528\u540C\u4E00\u4E2A session\uFF08\u56DE\u590D\u843D\u5728\u8BDD\u9898\u91CC\u3001\u4F46\u5171\u7528\u672C\u7FA4\u4F1A\u8BDD\u4E0E\u4E0A\u4E0B\u6587\uFF09\u3002\u8FD9\u662F per-bot \u9ED8\u8BA4\uFF0C\u5177\u4F53\u67D0\u4E2A\u7FA4\u53EF\u7528 /reply-mode \u5355\u72EC\u8986\u76D6\u3002\u6539\u540E\u7ACB\u5373\u751F\u6548\u3002","botDefaults.mentionMode":"\u7FA4\u804A @ \u7B56\u7565","botDefaults.mentionModeAlways":"\u90FD\u9700\u8981 @\uFF08\u9ED8\u8BA4\uFF09","botDefaults.mentionModeTopic":"\u4EC5\u8BDD\u9898\u5185\u4E0D\u9700\u8981 @","botDefaults.mentionModeNever":"\u6240\u6709\u6D88\u606F\u90FD\u4E0D\u9700\u8981 @","botDefaults.mentionModeHelp":"\u8BE5 bot \u5168\u5C40\u751F\u6548\uFF0C\u51B3\u5B9A\u7FA4\u91CC\u8981\u4E0D\u8981 @ \u624D\u56DE\uFF1A\u300C\u90FD\u9700\u8981 @\u300D= \u4EFB\u4F55\u6D88\u606F\u90FD\u5F97 @\uFF08\u9ED8\u8BA4\uFF0C\u6700\u5B89\u5168\uFF1B\u591A\u4EBA\u7FA4\u91CC\u8BDD\u9898\u5185\u4E5F\u8981 @\uFF09\uFF1B\u300C\u4EC5\u8BDD\u9898\u5185\u4E0D\u9700\u8981 @\u300D= \u8D77\u65B0\u5BF9\u8BDD / \u9876\u5C42\u4ECD\u8981 @\uFF0C\u4F46\u5728\u8BE5 bot \u5DF2\u5F00\u7684\u4EFB\u4F55\u8BDD\u9898\u91CC\uFF08new-topic / shared / \u8BDD\u9898\u7FA4\uFF09\u540E\u7EED\u6D88\u606F\u514D @ \u7EED\u804A\uFF1B\u300C\u6240\u6709\u6D88\u606F\u90FD\u4E0D\u9700\u8981 @\u300D= \u8BE5 bot \u6709\u5BF9\u8BDD\u6743\u9650\u7684\u7FA4\u91CC\u975E @ \u6D88\u606F\u4E5F\u56DE\uFF08\u542B\u5168\u65B0\u6D88\u606F\u51B7\u542F\u52A8\uFF0C\u4EC5\u9002\u5408\u4E13\u7528 / \u503C\u73ED\u5C0F\u7FA4\uFF0C\u591A\u4EBA\u7FA4\u91CC\u4F1A\u89C1\u6D88\u606F\u5C31\u56DE\uFF09\u3002\u6CE8\uFF1A\u7FA4\u91CC\u53EA\u6709\u4F60\u548C\u8BE5 bot\uFF081 \u5BF9 1\uFF09\u65F6\u4E00\u76F4\u514D @\uFF0C\u4E0E\u672C\u8BBE\u7F6E\u65E0\u5173\u3002","botDefaults.docSubscribeMode":"\u6587\u6863\u8BA2\u9605\u89E6\u53D1\u8303\u56F4\uFF08\u9ED8\u8BA4\uFF09","botDefaults.docSubscribeModeMention":"\u4EC5\u8BC4\u8BBA @ \u6211\u624D\u89E6\u53D1","botDefaults.docSubscribeModeAll":"\u6240\u6709\u65B0\u8BC4\u8BBA\u90FD\u89E6\u53D1","botDefaults.docSubscribeModeHelp":"\u7528 /subscribe-lark-doc \u8BA2\u9605\u98DE\u4E66\u6587\u6863\u540E\uFF0C\u6587\u6863\u8BC4\u8BBA\u4F1A\u5582\u8FDB\u4F1A\u8BDD\u3001bot \u56DE\u590D\u53D1\u56DE\u8BC4\u8BBA\u3002\u8FD9\u91CC\u8BBE\u65B0\u8BA2\u9605\u7684\u9ED8\u8BA4\u89E6\u53D1\u8303\u56F4\uFF1A\u300C\u4EC5\u8BC4\u8BBA @ \u6211\u300D\u6700\u5B89\u5168\uFF08\u9632\u5237\u5C4F\uFF09\uFF1B\u300C\u6240\u6709\u65B0\u8BC4\u8BBA\u300D\u9002\u5408\u4E13\u7528\u6587\u6863\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 Ln=class{sessions=new Map;schedules=new Map;online=!0;listeners=new Set;upsertSessions(n){for(let o of n)this.sessions.set(o.sessionId,o);this.emit()}upsertSchedules(n){for(let o of n)this.schedules.set(o.id,o);this.emit()}applySse(n,o){if(n==="session.spawned")this.sessions.set(o.session.sessionId,o.session);else if(n==="session.update"){let s=this.sessions.get(o.sessionId);s&&this.sessions.set(o.sessionId,{...s,...o.patch})}else if(n==="session.exited"){let s=this.sessions.get(o.sessionId);s&&this.sessions.set(o.sessionId,{...s,status:"closed"})}else if(n==="schedule.created")this.schedules.set(o.schedule.id,o.schedule);else if(n==="schedule.updated"){let s=this.schedules.get(o.id);s&&this.schedules.set(o.id,{...s,...o.patch})}else if(n==="schedule.deleted")this.schedules.delete(o.id);else return;this.emit()}setOnline(n){this.online!==n&&(this.online=n,this.emit())}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}},Q=new Ln;async function wo(){let[e,n]=await Promise.all([fetch("/api/sessions").then(a=>a.json()),fetch("/api/schedules").then(a=>a.json())]);Q.upsertSessions(e.sessions??[]),Q.upsertSchedules(n.schedules??[]);let o=new EventSource("/events"),s=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let a of s)o.addEventListener(a,r=>{try{let d=JSON.parse(r.data);Q.applySse(a,d.body??d)}catch{}});o.onerror=()=>Q.setOnline(!1),o.onopen=()=>Q.setOnline(!0)}var In="botmux.dashboard.locale",cs={"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.modelTtadkPlaceholder":"ttadk \u7F51\u5173\u6A21\u578B\uFF0C\u9ED8\u8BA4 {model}\uFF0C\u53EF\u6539\uFF08\u968F\u65F6\u5728\u6B64\u8C03\u6574\uFF09","botOnboarding.modelTtadkCocoPlaceholder":"CoCo \u65E0\u9700\u6307\u5B9A\u6A21\u578B","botOnboarding.startScan":"\u5F00\u59CB\u626B\u7801","botOnboarding.cancel":"\u53D6\u6D88","botOnboarding.starting":"\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...","botOnboarding.waiting":"\u8BF7\u7528\u98DE\u4E66 App \u626B\u7801\u786E\u8BA4\u521B\u5EFA\u5E94\u7528\u3002","botOnboarding.verifying":"\u626B\u7801\u6210\u529F\uFF0C\u6B63\u5728\u6821\u9A8C\u51ED\u8BC1...","botOnboarding.configuringPermissions":"\u6B63\u5728\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u2026","botOnboarding.platformScanHint":"\u8BF7\u7528\u98DE\u4E66 App \u518D\u626B\u4E00\u6B21\u7801\u767B\u5F55\u5F00\u653E\u5E73\u53F0\uFF08\u7528\u4E8E\u81EA\u52A8\u5BFC\u5165\u6743\u9650\u3001\u914D\u7F6E\u56DE\u8C03\u3001\u63D0\u4EA4\u7248\u672C\uFF09\u3002","botOnboarding.platformQrAlt":"\u5F00\u653E\u5E73\u53F0\u767B\u5F55\u4E8C\u7EF4\u7801","botOnboarding.completed":"\u673A\u5668\u4EBA\u5DF2\u6DFB\u52A0\u3002","botOnboarding.permissionOk":"\u5DF2\u81EA\u52A8\u5BFC\u5165 {count} \u9879\u6743\u9650\u3002","botOnboarding.permissionSkipped":"\uFF08\u8DF3\u8FC7 {count} \u9879\u5F53\u524D\u79DF\u6237\u76EE\u5F55\u4E2D\u6CA1\u6709\u7684\u6743\u9650\uFF09","botOnboarding.permissionVersion":"\u5DF2\u63D0\u4EA4\u53D1\u5E03\u7248\u672C {version}\u3002","botOnboarding.permissionManual":"\u6743\u9650\u672A\u80FD\u81EA\u52A8\u914D\u7F6E\uFF0C\u8BF7\u624B\u52A8\u5B8C\u6210\u4EE5\u4E0B\u6B65\u9AA4\uFF1A","botOnboarding.metaDir":"\u76EE\u5F55","botOnboarding.failed":"\u6DFB\u52A0\u5931\u8D25","botOnboarding.openLink":"\u6253\u4E0D\u5F00\u626B\u7801\uFF1F\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00","botOnboarding.close":"\u5173\u95ED","botOnboarding.restartHint":"\u5DF2\u5199\u5165 bots.json\u3002\u6267\u884C pnpm daemon:restart \u540E\u65B0\u673A\u5668\u4EBA\u751F\u6548\u3002","botOnboarding.qrAlt":"\u98DE\u4E66\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA\u4E8C\u7EF4\u7801","overview.title":"\u5DE5\u4F5C\u53F0","overview.subtitle":"\u6570\u5B57\u5458\u5DE5\u5B9E\u65F6\u72B6\u6001 \xB7 \u540C\u6B65\u98DE\u4E66\u8BDD\u9898","overview.team":"AI \u56E2\u961F","overview.teamHint":"\u6BCF\u4F4D\u6570\u5B57\u5458\u5DE5\u7684\u5B9E\u65F6\u72B6\u6001","overview.attention":"\u9700\u8981\u4F60\u5904\u7406","overview.attentionHint":"\u5361\u4F4F\u7684\u4EFB\u52A1\uFF0C\u56DE\u4E2A\u8BDD\u5C31\u80FD\u7EE7\u7EED\u8DD1","overview.activeSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.activeSessionsHint":"\u6B63\u5728\u8FD0\u8F6C\u7684\u4F1A\u8BDD","overview.today":"\u6B64\u523B\u6982\u89C8","overview.todayHint":"\u6D3B\u8DC3\u4F1A\u8BDD\u5206\u5E03","overview.viewAll":"\u67E5\u770B\u5168\u90E8 \u2192","overview.botIdle":"\u5F85\u547D\u4E2D\uFF0C\u968F\u65F6\u53EF\u63A5\u65B0\u4EFB\u52A1","overview.botOffline":"\u79BB\u7EBF \u2014 daemon \u672A\u4E0A\u7EBF","overview.botBusy":"\u6267\u884C\u4E2D \xB7 {count} \u4F1A\u8BDD","overview.botNeedsYou":"\u7B49\u4F60\u56DE\u590D","overview.botReady":"\u5C31\u7EEA","overview.botOff":"\u79BB\u7EBF","overview.sessionsCount":"{count} \u4F1A\u8BDD","overview.lastActive":"{time}\u524D\u6D3B\u8DC3","overview.noAttention":"\u6CA1\u6709\u7B49\u4F60\u5904\u7406\u7684\u4E8B\u9879","overview.teamExpand":"\u5C55\u5F00\u5168\u90E8 {count} \u4F4D \u25BE","overview.teamCollapse":"\u6536\u8D77 \u25B4","strip.pending":"{count} \u4EF6\u5F85\u5904\u7406","strip.longest":"\u6700\u4E45\u5DF2\u7B49 {time} \u2014 {bot} {reason}","strip.handle":"\u7ACB\u5373\u5904\u7406","overview.openSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.workingSessions":"\u5DE5\u4F5C\u4E2D","overview.onlineBots":"\u5728\u7EBF Bot","overview.schedules":"\u5B9A\u65F6\u4EFB\u52A1","overview.groups":"\u7FA4\u804A\u8986\u76D6","overview.enabledSchedules":"\u5DF2\u542F\u7528","overview.total":"\u603B\u8BA1","overview.active":"\u6D3B\u8DC3","overview.daemonRegistry":"daemon \u6CE8\u518C\u8868","overview.chatMatrix":"\u7FA4\u804A\u77E9\u9635","overview.recentSessions":"\u6700\u8FD1\u4F1A\u8BDD","overview.nextSchedules":"\u5373\u5C06\u6267\u884C","overview.noSessions":"\u6682\u65E0\u4F1A\u8BDD\u3002","overview.noSchedules":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","sessions.title":"\u4F1A\u8BDD\u63A7\u5236","sessions.subtitle":"\u5B9A\u4F4D\u98DE\u4E66\u8BDD\u9898\u3001\u6253\u5F00 Web Terminal\u3001\u5173\u95ED\u6216\u6062\u590D CLI \u4F1A\u8BDD\u3002","sessions.search":"\u641C\u7D22\u5DE5\u4F5C\u76EE\u5F55 / \u6807\u9898 / ID","sessions.anyStatus":"\u5168\u90E8\u72B6\u6001","sessions.adoptAny":"adopt: \u5168\u90E8","sessions.adoptYes":"adopt: \u662F","sessions.adoptNo":"adopt: \u5426","sessions.activeOnly":"\u4EC5\u6D3B\u8DC3","sessions.closeSelected":"\u5173\u95ED\u9009\u4E2D","sessions.clearSelection":"\u53D6\u6D88\u9009\u62E9","sessions.selectedCount":"\u5DF2\u9009 {count} \u4E2A\u4F1A\u8BDD","sessions.bot":"bot","sessions.cli":"CLI","sessions.chat":"\u7FA4\u804A","sessions.openChat":"\u6253\u5F00\u7FA4\u804A","sessions.status":"\u72B6\u6001","sessions.tokenIn":"Token In","sessions.tokenOut":"Token Out","sessions.titleCol":"\u6807\u9898","sessions.workingDir":"\u5DE5\u4F5C\u76EE\u5F55","sessions.created":"\u521B\u5EFA","sessions.last":"\u6700\u8FD1","sessions.adopt":"\u63A5\u5165","sessions.actions":"\u64CD\u4F5C","sessions.details":"\u8BE6\u60C5","sessions.copy":"\u590D\u5236","sessions.copied":"\u5DF2\u590D\u5236","sessions.locate":"\u5B9A\u4F4D\u8BDD\u9898","sessions.locating":"\u53D1\u9001\u4E2D...","sessions.cooldown":"\u51B7\u5374 {seconds}s","sessions.openTerminal":"\u7EC8\u7AEF","sessions.writeLink":"\u64CD\u4F5C\u94FE\u63A5","sessions.writeLinkHint":"\u83B7\u53D6\u53EF\u64CD\u4F5C\u7EC8\u7AEF\u94FE\u63A5\uFF08\u5E26\u5199\u6743\u9650 token\uFF0C\u65B0\u6807\u7B7E\u6253\u5F00\uFF09","sessions.writeLinkFail":"\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u5931\u8D25","sessions.close":"\u5173\u95ED\u4F1A\u8BDD","sessions.resume":"\u6062\u590D\u4F1A\u8BDD","sessions.dismiss":"\u5173\u95ED","sessions.closeConfirm":"\u5173\u95ED\u8FD9\u4E2A\u4F1A\u8BDD\uFF1F","sessions.resumeFailed":"\u6062\u590D\u5931\u8D25","sessions.land":"\u843D\u76D8","sessions.landLoading":"\u52A0\u8F7D\u6C99\u76D2 diff\u2026","sessions.landUnavailable":"\u65E0\u6CD5\u843D\u76D8","sessions.landEmpty":"\u6C99\u76D2\u526F\u672C\u6CA1\u6709\u6539\u52A8\u3002","sessions.landApply":"\u5E94\u7528\u5230\u78C1\u76D8","sessions.landDiscard":"\u4E22\u5F03","sessions.landApplied":"\u5DF2\u843D\u76D8","sessions.landFailed":"\u843D\u76D8\u5931\u8D25","sessions.landDiscarded":"\u5DF2\u4E22\u5F03\uFF08\u6C99\u76D2\u526F\u672C\u672A\u5E94\u7528\uFF09\u3002","connectors.lede":"\u8BA9\u5916\u90E8\u7CFB\u7EDF\uFF08\u76D1\u63A7\u544A\u8B66\u3001CI\u3001\u5DE5\u5355\u2026\uFF09\u901A\u8FC7\u4E00\u4E2A webhook \u89E6\u53D1\u673A\u5668\u4EBA\u5728\u7FA4\u91CC\u8BF4\u8BDD\u6216\u8DD1\u5DE5\u4F5C\u6D41\u3002","connectors.createTitle":"\u65B0\u5EFA Webhook","connectors.fName":"\u540D\u79F0","connectors.fNamePh":"\u5982\uFF1A\u7EBF\u4E0A\u544A\u8B66","connectors.fBot":"\u89E6\u53D1\u7684\u673A\u5668\u4EBA","connectors.fKind":"\u89E6\u53D1\u65B9\u5F0F","connectors.kindTurn":"\u5355\u8F6E\u5BF9\u8BDD\uFF08\u8BA9\u673A\u5668\u4EBA\u56DE\u5E94\u4E00\u6B21\uFF09","connectors.kindWorkflow":"\u5DE5\u4F5C\u6D41","connectors.fWf":"\u5DE5\u4F5C\u6D41 ID","connectors.fMode":"\u6295\u9012\u5230\u54EA\u4E2A\u7FA4","connectors.modeDynamic":"\u7531\u8BF7\u6C42\u6307\u5B9A\uFF08\u7FA4\u968F\u8BF7\u6C42\u4F20\u5165\uFF09","connectors.modeFixed":"\u56FA\u5B9A\u7FA4","connectors.modeNewGroup":"\u6BCF\u6B21\u65B0\u5EFA\u7FA4","connectors.fFixedChat":"\u6295\u9012\u5230\u7684\u7FA4","connectors.fChatManualPh":"\u624B\u52A8\u586B\u7FA4 ID\uFF1Aoc_\u2026","connectors.chatManualLink":"\u627E\u4E0D\u5230\u7FA4\uFF1F\u624B\u52A8\u586B ID \u2192","connectors.chatListLink":"\u4ECE\u7FA4\u5217\u8868\u9009\u62E9 \u2190","connectors.fAllow":"\u5141\u8BB8\u7684\u7FA4","connectors.optional":"\uFF08\u53EF\u9009\uFF09","connectors.allowHint":"\u6309\u4F4F Ctrl/\u2318 \u591A\u9009\uFF1B\u7559\u7A7A = \u4E0D\u9650\u3002\u53EA\u7528\u4E8E\u6821\u9A8C\u8BF7\u6C42\u4F20\u5165\u7684\u7FA4\u662F\u5426\u88AB\u5141\u8BB8\u3002","connectors.dynamicHint":'<b>\u52A8\u6001\u6A21\u5F0F</b>\uFF1A\u7FA4 ID \u968F\u6BCF\u6B21\u8BF7\u6C42\u4F20\u5165\uFF0C\u4E09\u9009\u4E00 \u2014\u2014 \u67E5\u8BE2\u53C2\u6570 <code>?chatId=<\u7FA4ID></code> \xB7 \u8BF7\u6C42\u5934 <code>x-botmux-chat-id: <\u7FA4ID></code> \xB7 \u8BF7\u6C42\u4F53 <code>{"chatId":"<\u7FA4ID>"}</code>\u3002<br>\u60F3"\u4E00\u4E2A URL \u76F4\u63A5\u89E6\u53D1\u3001\u4E0D\u5E26\u53C2\u6570"\uFF0C\u8BF7\u6539\u9009\u300C\u56FA\u5B9A\u7FA4\u300D\u3002',"connectors.fDedup":"\u53BB\u91CD\u5B57\u6BB5","connectors.fDedupPh":"\u5982 alert.id\uFF08\u4ECE\u4E8B\u4EF6 body \u53D6\u503C\uFF09","connectors.dedupHint":"\u586B\u4E86\uFF1A\u547D\u4E2D\u76F8\u540C\u503C\u7684\u4E8B\u4EF6\u90FD\u6295\u5230<b>\u540C\u4E00\u4E2A\u7FA4</b>\u3002\u7559\u7A7A\uFF1A\u6BCF\u4E2A\u4E8B\u4EF6<b>\u65B0\u5EFA\u4E00\u4E2A\u7FA4</b>\u3002","connectors.fInstruction":"\u5904\u7406\u6307\u4EE4","connectors.fInstructionPh":"\u4E8B\u4EF6\u89E6\u53D1\u65F6\u8BA9\u673A\u5668\u4EBA\u505A\u4EC0\u4E48\u3002\u5982\uFF1A\u603B\u7ED3\u8FD9\u6761\u544A\u8B66\u7684\u4E25\u91CD\u7A0B\u5EA6\uFF0C@\u76F8\u5173 oncall\uFF0C\u7ED9\u51FA\u6392\u67E5\u5EFA\u8BAE\u3002\u7559\u7A7A = \u53EA\u628A\u4E8B\u4EF6\u539F\u6837\u4EA4\u7ED9\u6A21\u578B\u81EA\u7531\u53D1\u6325\u3002","connectors.fVerify":"\u6821\u9A8C\u65B9\u5F0F","connectors.verifyToken":"\u4EE4\u724C\uFF08\u7B80\u5355\uFF1A\u5BC6\u94A5\u653E\u8FDB URL\uFF0C\u4E00\u6761 curl \u5C31\u80FD\u89E6\u53D1\uFF09","connectors.verifyHmac":"HMAC \u7B7E\u540D\uFF08\u9AD8\u7EA7\uFF1A\u66F4\u5B89\u5168\uFF0C\u9700\u81EA\u884C\u5BF9\u8BF7\u6C42\u7B7E\u540D\uFF09","connectors.fSecret":"\u5BC6\u94A5 / \u4EE4\u724C","connectors.fSecretPh":"\u7559\u7A7A\u81EA\u52A8\u751F\u6210\uFF08\u53EA\u663E\u793A\u4E00\u6B21\uFF09","connectors.btnCreate":"\u521B\u5EFA","connectors.listTitle":"\u5DF2\u6709 Webhook","connectors.loading":"\u52A0\u8F7D\u4E2D\u2026","connectors.noBotGroups":"\uFF08\u8BE5\u673A\u5668\u4EBA\u6682\u65E0\u53EF\u89C1\u7FA4\uFF0C\u70B9\u53F3\u4FA7\u624B\u52A8\u586B ID\uFF09","connectors.modeLabelFixed":"\u56FA\u5B9A\u7FA4","connectors.modeLabelNewGroup":"\u6BCF\u6B21\u65B0\u5EFA\u7FA4","connectors.modeLabelDynamic":"\u8BF7\u6C42\u6307\u5B9A\u7FA4","connectors.kindLabelWorkflow":"\u5DE5\u4F5C\u6D41","connectors.kindLabelTurn":"\u5355\u8F6E","connectors.count":"\xB7 {count} \u4E2A","connectors.empty":"\u8FD8\u6CA1\u6709 Webhook\u3002\u7528\u4E0A\u9762\u7684\u8868\u5355\u521B\u5EFA\u4E00\u4E2A\u3002","connectors.enabled":"\u5DF2\u542F\u7528","connectors.disabled":"\u5DF2\u505C\u7528","connectors.badgeToken":"\u4EE4\u724C","connectors.badgeSign":"\u7B7E\u540D","connectors.dest":"\u6295\u9012\u300C{name}\u300D","connectors.btnDisable":"\u505C\u7528","connectors.btnEnable":"\u542F\u7528","connectors.btnDel":"\u5220\u9664","connectors.webhookUrl":"Webhook URL\uFF1A","connectors.copy":"\u590D\u5236","connectors.copied":"\u5DF2\u590D\u5236","connectors.tokenHint":"\u4EE4\u724C\u6A21\u5F0F\uFF1A\u8C03\u7528\u65F6\u5728 URL \u672B\u5C3E\u8FFD\u52A0 <code>/<\u4EE4\u724C></code>\uFF08\u4EE4\u724C\u4EC5\u521B\u5EFA/\u8F6E\u6362\u65F6\u663E\u793A\u4E00\u6B21\uFF09\u3002","connectors.dynamicReqHint":'\u52A8\u6001\u6A21\u5F0F\uFF1A\u8BF7\u6C42\u9700\u5E26\u76EE\u6807\u7FA4 \u2014\u2014 <code>?chatId=<\u7FA4ID></code> \u6216\u5934 <code>x-botmux-chat-id</code> \u6216 body <code>{"chatId":"\u2026"}</code>\u3002',"connectors.instructionPrefix":"\u5904\u7406\u6307\u4EE4\uFF1A","connectors.delConfirm":"\u5220\u9664\u8FD9\u4E2A Webhook\uFF1F\u5B83\u7684 URL \u4F1A\u7ACB\u5373\u5931\u6548\u3002","connectors.errName":"\u8BF7\u586B\u540D\u79F0","connectors.errBot":"\u8BF7\u9009\u673A\u5668\u4EBA","connectors.errWf":"\u8BF7\u586B\u5DE5\u4F5C\u6D41 ID","connectors.errChat":"\u8BF7\u9009\u62E9\uFF08\u6216\u624B\u52A8\u586B\uFF09\u6295\u9012\u7684\u7FA4","connectors.creating":"\u521B\u5EFA\u4E2D\u2026","connectors.usageDynamicLede":"\u52A8\u6001\u6A21\u5F0F\uFF1AURL \u5DF2\u542B\u4EE4\u724C\uFF0C\u8C03\u7528\u65F6\u518D\u5E26\u4E0A\u76EE\u6807\u7FA4 ID{gn}\uFF1A","connectors.usageDynamicNote":'\u7FA4\u4E5F\u53EF\u653E\u8BF7\u6C42\u5934 <code>x-botmux-chat-id</code> \u6216 body <code>{"chatId":"\u2026"}</code>\u3002\u26A0\uFE0F URL \u5373\u51ED\u8BC1\uFF0C\u52FF\u6CC4\u6F0F\u3002',"connectors.usageTokenLede":"\u6B64 URL \u5DF2\u542B\u4EE4\u724C\u3001\u4E14\u56FA\u5B9A\u6295\u9012\u5230\u6240\u9009\u7FA4\uFF0C\u76F4\u63A5 POST \u5373\u53EF\u89E6\u53D1\uFF1A","connectors.usageTokenNote":"\u26A0\uFE0F URL \u5373\u51ED\u8BC1\uFF0C\u8BF7\u52FF\u516C\u5F00\u6CC4\u6F0F\uFF1B\u53EF\u5728\u4E0B\u65B9\u5217\u8868\u5220\u9664\u6216\u8F6E\u6362\u3002","connectors.usageHmac":"\u5916\u90E8\u7CFB\u7EDF\u9700\u5BF9 <code>timestamp.body</code> \u505A HMAC-SHA256 \u7B7E\u540D\uFF0C\u5E76\u5E26\u4E0A <code>x-botmux-timestamp</code> / <code>x-botmux-nonce</code> / <code>x-botmux-signature</code> \u5934\u8C03\u7528","connectors.usageHmacDynamic":"\uFF0C\u540C\u65F6\u6309\u4E0A\u9762\u65B9\u5F0F\u5E26\u76EE\u6807\u7FA4 ID","connectors.createdPrefix":"\u5DF2\u521B\u5EFA\u300C{name}\u300D","connectors.createdDest":"\u6295\u9012\u5230\u300C{name}\u300D","connectors.tokenLabel":"\u8BBF\u95EE\u4EE4\u724C","connectors.signLabel":"\u7B7E\u540D\u5BC6\u94A5","connectors.secretOnce":"\uFF08\u53EA\u663E\u793A\u8FD9\u4E00\u6B21\uFF0C\u8BF7\u4FDD\u5B58\uFF09\uFF1A","connectors.createFailed":"\u521B\u5EFA\u5931\u8D25\uFF1A{error}","connectors.noOnlineBots":"\uFF08\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF09","team.navHome":"\u6211\u7684\u56E2\u961F","team.navManage":"\u56E2\u961F\u7BA1\u7406","team.eyebrow":"\u56E2\u961F","team.homeTitle":"\u56E2\u961F\u534F\u4F5C\uFF08\u8DE8\u90E8\u7F72\uFF09","team.homeLede":"\u628A\u522B\u7684\u90E8\u7F72\uFF08\u540C\u4E8B\u81EA\u5DF1\u8DD1\u7684 botmux\uFF09\u9080\u8BF7\u8FDB\u540C\u4E00\u4E2A\u56E2\u961F\uFF0C\u4E92\u76F8\u53D1\u73B0\u673A\u5668\u4EBA\u3001\u534F\u4F5C\u62C9\u7FA4\u3002","team.localDeployTitle":"\u672C\u90E8\u7F72","team.myIdentity":"\u6211\u7684\u98DE\u4E66\u8EAB\u4EFD\uFF1A","team.unbound":"\u672A\u7ED1\u5B9A","team.bindBtn":"\u7ED1\u5B9A","team.bindHint":"\uFF08\u7528\u673A\u5668\u4EBA\u51ED\u8BC1\u81EA\u52A8\u8BC6\u522B\u4F60\uFF1B\u7ED1\u5B9A\u540E\u62C9\u7FA4\u4F1A\u628A\u4F60\u62C9\u8FDB\u7FA4\u3001\u673A\u5668\u4EBA\u4E5F\u5F52\u5230\u4F60\u540D\u4E0B\uFF09","team.myTeams":"\u6211\u7684\u56E2\u961F","team.searchPh":"\u641C\u7D22 \u540D\u79F0/\u80FD\u529B/CLI\u2026","team.allCli":"\u5168\u90E8 CLI","team.hasCap":"\u6709\u80FD\u529B\u6807\u7B7E","team.hasRole":"\u6709\u9ED8\u8BA4\u89D2\u8272","team.teamsHint":"\u6BCF\u4E2A\u56E2\u961F\u91CC\u52FE\u9009\u673A\u5668\u4EBA\u5373\u53EF\u5355\u72EC\u62C9\u7FA4\uFF08\u81EA\u52A8\u5E26\u4E0A\u5404\u81EA\u8D1F\u8D23\u4EBA\uFF09\u3002\u8981\u65B0\u5EFA\u56E2\u961F / \u751F\u6210\u9080\u8BF7\u7801 / \u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\uFF0C\u53BB\u300C\u56E2\u961F\u7BA1\u7406\u300D\u3002","team.loading":"\u52A0\u8F7D\u4E2D\u2026","team.roleModalTitle":"\u9ED8\u8BA4\u89D2\u8272","team.roleModalHint":"\u8BE5\u673A\u5668\u4EBA\u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF08\u8DE8\u7FA4\u751F\u6548\uFF09\uFF0C\u6B64\u5904\u53EA\u8BFB\u3002\u5982\u9700\u4FEE\u6539\uFF0C\u8BF7\u5230\u300CBot \u914D\u7F6E\u300D\u9875\u3002","team.close":"\u5173\u95ED","team.tagLocal":"\u672C\u90E8\u7F72","team.tagRemoteStale":"\u8FDC\u7AEF\xB7\u79BB\u7EBF\uFF1F","team.tagRemote":"\u8FDC\u7AEF","team.removeMember":"\u79FB\u9664","team.depTag":"\uFF08{tag}\uFF09","team.depCount":"{count} \u4E2A","team.depSelected":"\uFF0C\u5DF2\u9009 {n}","team.capPh":"\u80FD\u529B\u6807\u7B7E\u2026","team.viewRole":"\u67E5\u770B","team.hasRoleShort":"\u6709\u89D2\u8272","team.noMatch":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u673A\u5668\u4EBA\u3002","team.gnamePh":"\u7FA4\u540D\uFF08\u5982\uFF1A\u8DE8\u56E2\u961F\u6392\u969C\uFF09","team.pullGroupBtn":"\u628A\u52FE\u9009\u7684\u673A\u5668\u4EBA\u62C9\u4E00\u4E2A\u7FA4","team.pullGroupHint":"\u52FE\u9009\u673A\u5668\u4EBA \u2192 \u62C9\u5230\u4E00\u4E2A\u98DE\u4E66\u7FA4\uFF08\u81EA\u52A8\u542B owner\uFF09","team.noTeams":"\u8FD8\u6CA1\u6709\u56E2\u961F\u3002\u53BB\u300C\u56E2\u961F\u7BA1\u7406\u300D\u751F\u6210\u9080\u8BF7\u7801\u8BA9\u522B\u4EBA\u52A0\u5165\u4F60\uFF0C\u6216\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\u3002","team.connected":"\u5DF2\u8FDE\u63A5","team.connectFail":"\u8FDE\u63A5\u5931\u8D25\uFF1A{error}","team.iHost":"\u6211\u6258\u7BA1","team.teamMeta":"{deps} \u4E2A\u90E8\u7F72 \xB7 {bots} \u4E2A\u673A\u5668\u4EBA","team.rosterFail":"\u65E0\u6CD5\u83B7\u53D6\u8BE5\u56E2\u961F\u82B1\u540D\u518C\u3002","team.acrossTeams":"\uFF08\u8DE8 {n} \u4E2A\u56E2\u961F\uFF0C\u53BB\u91CD\uFF09","team.botsWord":"\u4E2A\u673A\u5668\u4EBA","team.groupCreated":"\u7FA4\u5DF2\u521B\u5EFA","team.delegatedBy":"\uFF08\u7531\u300C{name}\u300D\u5EFA\u7FA4\uFF09","team.openInLark":"\u5728\u98DE\u4E66\u6253\u5F00","team.invalidBots":"\u672A\u52A0\u5165\u7684\u673A\u5668\u4EBA\uFF1A{ids}","team.invalidOwners":"{n} \u4E2A owner \u672A\u80FD\u62C9\u8FDB","team.missingIdentity":"\u4F60\u672A\u7ED1\u5B9A\u98DE\u4E66\u8EAB\u4EFD\uFF0C\u6CA1\u628A\u4F60\u81EA\u5DF1\u62C9\u8FDB\u7FA4\uFF08\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u7ED1\u5B9A\uFF09","team.skippedNoOwner":"{n} \u4E2A\u673A\u5668\u4EBA\u56E0\u8D1F\u8D23\u4EBA\u672A\u7ED1\u5B9A\u8EAB\u4EFD\u88AB\u8DF3\u8FC7\uFF08\u672A\u52A0\u5165\u7FA4\uFF09","team.errNoLocalBot":"\u8BF7\u81F3\u5C11\u52FE\u9009\u4E00\u4E2A\u4F60\u81EA\u5DF1\uFF08\u672C\u90E8\u7F72\uFF09\u7684\u5728\u7EBF\u673A\u5668\u4EBA\u2014\u2014\u7FA4\u8981\u7531\u5B83\u521B\u5EFA\u5E76\u628A\u4F60\uFF08\u53D1\u8D77\u4EBA\uFF09\u62C9\u8FDB\u7FA4\u3002","team.errAllSkipped":"\u6240\u9009\u673A\u5668\u4EBA\u7684\u8D1F\u8D23\u4EBA\u90FD\u6CA1\u7ED1\u5B9A\u8EAB\u4EFD\uFF0C\u65E0\u6CD5\u62C9\u7FA4\uFF08\u673A\u5668\u4EBA\u4E0D\u80FD\u8FDB\u4E00\u4E2A owner \u4E0D\u5728\u7684\u7FA4\uFF09\u3002\u8BF7\u8BA9\u5BF9\u5E94\u90E8\u7F72\u5148\u7ED1\u5B9A\u8EAB\u4EFD\u3002","team.errNoCreator":"\u6CA1\u6709\u53EF\u7528\u7684\u5EFA\u7FA4\u53D1\u8D77\u65B9\uFF08\u76F8\u5173\u90E8\u7F72\u90FD\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF0C\u6216\u4E0D\u53EF\u8FBE\uFF09","team.errDelegationTimeout":"\u59D4\u6258\u5BF9\u65B9\u90E8\u7F72\u5EFA\u7FA4\u8D85\u65F6\uFF08\u53EF\u80FD\u5DF2\u5EFA\uFF0C\u53BB\u98DE\u4E66\u786E\u8BA4\uFF0C\u52FF\u91CD\u590D\u70B9\uFF09","team.errGroupCreate":"\u5EFA\u7FA4\u5931\u8D25\uFF1A{error}","team.roleModalTitleName":"\u9ED8\u8BA4\u89D2\u8272 \xB7 {name}","team.bound":"\u5DF2\u7ED1\u5B9A","team.myHostedTeam":"\u6211\u6258\u7BA1\u7684\u56E2\u961F","team.remoteTeamLabel":"{name} \u7684\u56E2\u961F","team.manageTitle":"\u56E2\u961F\u7BA1\u7406","team.manageLede":"\u521B\u5EFA\u591A\u4E2A\u56E2\u961F\u3001\u7ED9\u6BCF\u4E2A\u56E2\u961F\u751F\u6210\u9080\u8BF7\u7801\u3001\u6216\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\u3002\u4E00\u4E2A\u56E2\u961F = \u4F60\u672C\u90E8\u7F72\u7684\u673A\u5668\u4EBA + \u52A0\u5165\u8BE5\u56E2\u961F\u7684\u5176\u5B83\u90E8\u7F72\u3002","team.hostedTitle":"\u6211\u6258\u7BA1\u7684\u56E2\u961F","team.newTeamPh":"\u65B0\u56E2\u961F\u540D\u79F0","team.createTeamBtn":"\u521B\u5EFA\u56E2\u961F","team.joinTitle":"\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F","team.hubPh":"Hub \u5730\u5740\uFF0C\u5982 http://10.0.0.5:7891","team.codePh":"\u9080\u8BF7\u7801","team.joinBtn":"\u52A0\u5165","team.noTeamsShort":"\u8FD8\u6CA1\u6709\u56E2\u961F\u3002","team.default":"\u9ED8\u8BA4","team.manageMetaDeps":"{count} \u4E2A\u90E8\u7F72","team.manageMetaRemote":"\uFF08\u542B {r} \u8FDC\u7AEF\uFF09","team.manageMetaBots":"{count} \u4E2A\u673A\u5668\u4EBA","team.genInvite":"\u751F\u6210\u9080\u8BF7\u7801","team.delBtn":"\u5220\u9664","team.generating":"\u751F\u6210\u4E2D\u2026","team.inviteResultLede":"\u628A\u4E0B\u9762\u4E24\u9879\u53D1\u7ED9\u522B\u7684\u90E8\u7F72\u7684\u4EBA\uFF0824 \u5C0F\u65F6\u5185\u3001\u5355\u6B21\u6709\u6548\uFF09\uFF1A","team.inviteHub":"Hub \u5730\u5740\uFF1A","team.inviteCode":"\u9080\u8BF7\u7801\uFF1A","team.genFail":"\u751F\u6210\u5931\u8D25\u3002","team.delConfirm":"\u5220\u9664\u56E2\u961F\u300C{name}\u300D\uFF1F\u5DF2\u52A0\u5165\u5B83\u7684\u90E8\u7F72\u4F1A\u88AB\u79FB\u9664\uFF08\u4E0D\u5F71\u54CD\u4ED6\u4EEC\u81EA\u5DF1\u7684\u90E8\u7F72\uFF09\u3002","team.errName":"\u8BF7\u586B\u56E2\u961F\u540D\u79F0","team.creating":"\u521B\u5EFA\u4E2D\u2026","team.created":"\u5DF2\u521B\u5EFA","team.createFail":"\u521B\u5EFA\u5931\u8D25\uFF1A{error}","team.errHubCode":"\u8BF7\u586B Hub \u5730\u5740\u548C\u9080\u8BF7\u7801\u3002","team.joining":"\u52A0\u5165\u4E2D\u2026","team.joined":"\u5DF2\u52A0\u5165\u300C{name}\u300D\uFF0C\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u67E5\u770B\u3002","team.joinErrSelf":"\u8FD9\u662F\u4F60\u81EA\u5DF1\u7684\u90E8\u7F72\uFF0C\u4E0D\u80FD\u52A0\u5165\u81EA\u5DF1\uFF08\u9080\u8BF7\u7801\u8981\u53D1\u7ED9\u522B\u7684\u90E8\u7F72\u7684\u4EBA\u7528\uFF09","team.joinErrAlready":"\u4F60\u7684\u90E8\u7F72\u5DF2\u7ECF\u52A0\u5165\u8FC7\u8FD9\u4E2A\u56E2\u961F\u4E86","team.joinErrUnreachable":"\u8FDE\u4E0D\u4E0A\u5BF9\u65B9 Hub\uFF08\u68C0\u67E5\u5730\u5740/\u7F51\u7EDC\uFF09","team.joinErrTimeout":"\u5BF9\u65B9 Hub \u54CD\u5E94\u8D85\u65F6","team.joinErrGeneric":"\u52A0\u5165\u5931\u8D25\uFF1A{error}","team.identifying":"\u8BC6\u522B\u4E2D\u2026","team.bound2":"\u5DF2\u7ED1\u5B9A\uFF1A{name}","team.multiCandidate":"\u8BC6\u522B\u5230\u591A\u4E2A\u5019\u9009\uFF0C\u70B9\u4F60\u81EA\u5DF1\uFF1A","team.binding":"\u7ED1\u5B9A\u4E2D\u2026","team.bindFail":"\u7ED1\u5B9A\u5931\u8D25\uFF1A{error}","team.noCandidates":"\u6CA1\u8BC6\u522B\u5230\u8EAB\u4EFD\uFF1A\u8BF7\u786E\u8BA4\u673A\u5668\u4EBA\u914D\u7F6E\u4E86 allowedUsers\uFF08\u5141\u8BB8\u4F7F\u7528\u8005\uFF09\uFF0C\u4E14\u673A\u5668\u4EBA\u6709\u901A\u8BAF\u5F55\u6743\u9650\u3002","team.removeMemberConfirm":"\u628A\u300C{name}\u300D\u79FB\u51FA\u8FD9\u4E2A\u56E2\u961F\uFF1F\u5B83\u7684\u673A\u5668\u4EBA\u5C06\u4ECE\u672C\u56E2\u961F\u82B1\u540D\u518C\u6D88\u5931\uFF08\u4E0D\u5F71\u54CD\u5BF9\u65B9\u81EA\u5DF1\u7684\u90E8\u7F72\uFF09\u3002","team.creatingGroup":"\u5EFA\u7FA4\u4E2D\u2026","team.defaultGroupName":"\u534F\u4F5C\u7FA4","team.errPickBot":"\u8BF7\u5148\u52FE\u9009\u81F3\u5C11\u4E00\u4E2A\u673A\u5668\u4EBA","sessions.closeBulkConfirm":"\u5173\u95ED\u9009\u4E2D\u7684 {count} \u4E2A\u4F1A\u8BDD\uFF1F","sessions.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u4F1A\u8BDD\u3002","sessions.viewMode":"\u4F1A\u8BDD\u89C6\u56FE","sessions.viewKanban":"\u770B\u677F","sessions.viewBoard":"\u72B6\u6001\u677F","sessions.viewTable":"\u8868\u683C","sessions.selectSession":"\u9009\u62E9\u4F1A\u8BDD","sessions.board.needsYou":"\u9700\u8981\u4F60","sessions.board.needsYouHint":"\u7B49\u5F85\u4ED3\u5E93\u3001TUI \u9009\u62E9\u6216\u989D\u5EA6\u5904\u7406","sessions.board.starting":"\u542F\u52A8\u4E2D","sessions.board.startingHint":"CLI \u6B63\u5728\u521B\u5EFA\u6216\u6062\u590D","sessions.board.working":"\u5E72\u6D3B\u4E2D","sessions.board.workingHint":"\u6B63\u5728\u8F93\u51FA\u3001\u5206\u6790\u6216\u6267\u884C\u5DE5\u5177","sessions.board.idle":"\u7A7A\u95F2","sessions.board.idleHint":"\u53EF\u7EE7\u7EED\u5BF9\u8BDD\u6216\u63A5\u65B0\u4EFB\u52A1","sessions.board.emptyColumn":"\u6682\u65E0\u4F1A\u8BDD","sessions.board.signalRepo":"\u5F85\u9009\u4ED3\u5E93","sessions.board.signalPrompt":"\u7B49\u5F85 TUI \u9009\u62E9","sessions.board.signalLimited":"\u989D\u5EA6\u53D7\u9650","sessions.board.signalAgent":"\u9700\u8981\u4EBA\u5DE5\u4ECB\u5165","sessions.board.waiting":"\u7B49\u5F85","sessions.board.dragHint":"\u62D6\u52A8\u5217\u5934\u8C03\u6574\u5217\u987A\u5E8F","sessions.board.moveLeft":"\u5DE6\u79FB\u6B64\u5217","sessions.board.moveRight":"\u53F3\u79FB\u6B64\u5217","sessions.kanban.backlog":"\u5F85\u529E\u6C60","sessions.kanban.todo":"\u5F85\u529E","sessions.kanban.inProgress":"\u8FDB\u884C\u4E2D","sessions.kanban.inReview":"\u5F85\u786E\u8BA4","sessions.kanban.done":"\u5DF2\u5B8C\u6210","sessions.kanban.updated":"\u66F4\u65B0\u4E8E {time}","sessions.kanban.moreHidden":"\u8FD8\u6709 {count} \u4E2A\u672A\u663E\u793A","sessions.kanban.openTab":"\u65B0\u6807\u7B7E\u9875\u6253\u5F00","sessions.kanban.openFeishu":"\u6253\u5F00\u98DE\u4E66","sessions.kanban.terminalLoading":"\u6B63\u5728\u6253\u5F00\u7EC8\u7AEF\u2026","sessions.kanban.rename":"\u91CD\u547D\u540D\uFF08\u53CC\u51FB\u6807\u9898\u4E5F\u53EF\uFF09","sessions.kanban.renameFail":"\u91CD\u547D\u540D\u5931\u8D25","sessions.kanban.moveFail":"\u79FB\u52A8\u5931\u8D25","sessions.kanban.groupBy":"\u5206\u7EC4\u7EF4\u5EA6","sessions.kanban.groupFlow":"\u5DE5\u4F5C\u6D41","sessions.kanban.groupTeam":"\u56E2\u961F","sessions.kanban.groupBot":"\u673A\u5668\u4EBA","sessions.kanban.teamLoading":"\u6B63\u5728\u52A0\u8F7D\u56E2\u961F\u2026","sessions.kanban.noTeam":"\u6682\u65E0\u56E2\u961F","sessions.kanban.teamScope":"{chats} \u4E2A\u534F\u4F5C\u7FA4 \xB7 {sessions} \u4E2A\u4F1A\u8BDD","sessions.kanban.remoteHint":"\u6765\u81EA {name} \u90E8\u7F72\u7684\u4F1A\u8BDD\uFF08\u5FEB\u7167\uFF0C\u7EC8\u7AEF/\u5386\u53F2\u5728\u5BF9\u65B9\u673A\u5668\u4E0A\uFF09","sessions.kanban.clusterDragHint":"\u62D6\u52A8\u6807\u9898\u6574\u7EC4\u79FB\u52A8","sessions.history.title":"\u4F1A\u8BDD\u5386\u53F2","sessions.history.loading":"\u6B63\u5728\u62C9\u53D6\u98DE\u4E66\u6D88\u606F\u2026","sessions.history.fail":"\u5386\u53F2\u62C9\u53D6\u5931\u8D25","sessions.history.empty":"\u6CA1\u6709\u6D88\u606F","sessions.history.user":"\u7528\u6237","sessions.history.owner":"\u521B\u5EFA\u8005","sessions.history.staleHint":"dashboard \u6216 daemon \u8FDB\u7A0B\u53EF\u80FD\u8FD8\u5728\u8DD1\u65E7\u7248\u672C\uFF0Cbotmux restart \u540E\u91CD\u8BD5","groups.title":"\u7FA4\u7EC4\u4E0E Bot","groups.subtitle":"\u67E5\u770B chat x bot \u8986\u76D6\u77E9\u9635\uFF0C\u7BA1\u7406\u62C9\u7FA4\u3001oncall\u3001\u9000\u7FA4\u548C\u89E3\u6563\u3002","groups.search":"\u641C\u7D22\u7FA4\u540D / ID / owner","groups.missingOnly":"\u4EC5\u7F3A bot","groups.refresh":"\u5237\u65B0","groups.create":"\u65B0\u5EFA\u7FA4","groups.chat":"\u7FA4\u804A","groups.actions":"\u64CD\u4F5C","groups.addBots":"\u6DFB\u52A0 bot","groups.manage":"\u7BA1\u7406","groups.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u7FA4\u804A\u3002","groups.createTitle":"\u65B0\u5EFA\u7FA4\u804A","groups.createHelp":"\u9009\u62E9\u8981\u9080\u8BF7\u7684 bot\u3002dashboard \u4F1A\u81EA\u52A8\u9009\u62E9\u5728\u7EBF daemon \u4F5C\u4E3A\u521B\u5EFA\u8005\u3002","groups.name":"\u7FA4\u540D","groups.namePlaceholder":"\u4F8B\u5982 AI ChangeLog","groups.bindDir":"\u7ED1\u5B9A\u76EE\u5F55","groups.bindDirHelp":"\u65B0\u8BDD\u9898\u76F4\u63A5\u7528\u8BE5\u76EE\u5F55\u542F\u52A8 CLI\uFF0C\u8DF3\u8FC7 repo \u9009\u62E9\u3002","groups.botPicker":"Bot","groups.createSubmit":"\u521B\u5EFA","groups.cancel":"\u53D6\u6D88","groups.successTitle":"\u7FA4\u521B\u5EFA\u6210\u529F","groups.openGroup":"\u6253\u5F00\u65B0\u7FA4","groups.manageTitle":"\u7BA1\u7406 {name}","groups.owner":"\u7FA4\u4E3B","groups.oncall":"Oncall \u6A21\u5F0F","groups.oncallHelp":"\u5F00\u542F\u540E\uFF0C\u7FA4\u5185\u6210\u5458\u53EF @ \u673A\u5668\u4EBA\uFF1B\u65B0\u8BDD\u9898\u76F4\u63A5\u4F7F\u7528\u7ED1\u5B9A\u76EE\u5F55\u3002","groups.leaveTitle":"\u9009\u62E9\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.leaveSelected":"\u9009\u4E2D\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.disband":"\u89E3\u6563\u7FA4\u804A","groups.dangerHint":"\u89E3\u6563\u4EC5\u5F53\u5728\u7FA4\u673A\u5668\u4EBA\u662F\u7FA4\u4E3B\u65F6\u624D\u4F1A\u6210\u529F\uFF0C\u5426\u5219\u5EFA\u8BAE\u4F7F\u7528\u9000\u51FA\u7FA4\u804A\u3002","groups.save":"\u4FDD\u5B58","groups.needWorkingDir":"\u8BF7\u586B\u5DE5\u4F5C\u76EE\u5F55","groups.noBotsOnline":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u8BF7\u5148\u91CD\u542F daemon\u3002","schedules.title":"\u5B9A\u65F6\u4EFB\u52A1","schedules.subtitle":"\u8DE8 daemon \u67E5\u770B\u3001\u6682\u505C\u3001\u6062\u590D\u548C\u7ACB\u5373\u89E6\u53D1\u5B9A\u65F6\u4EFB\u52A1\u3002","schedules.search":"\u641C\u7D22\u540D\u79F0 / prompt / \u5DE5\u4F5C\u76EE\u5F55","schedules.anyKind":"\u5168\u90E8\u7C7B\u578B","schedules.enabledOnly":"\u4EC5\u542F\u7528","schedules.name":"\u540D\u79F0","schedules.bot":"bot","schedules.schedule":"\u89C4\u5219","schedules.next":"\u4E0B\u6B21","schedules.last":"\u4E0A\u6B21","schedules.repeat":"\u91CD\u590D","schedules.enabled":"\u542F\u7528","schedules.actions":"\u64CD\u4F5C","schedules.runNow":"\u7ACB\u5373\u8FD0\u884C","schedules.pause":"\u6682\u505C","schedules.resume":"\u6062\u590D","schedules.empty":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","settings.title":"\u5168\u5C40\u8BBE\u7F6E","settings.subtitle":"\u7BA1\u7406\u672C\u673A botmux dashboard \u4E0E\u6240\u6709 bot \u5171\u4EAB\u7684\u5168\u5C40\u884C\u4E3A\u3002","settings.loading":"\u6B63\u5728\u52A0\u8F7D\u8BBE\u7F6E\u2026","settings.loadFailed":"\u8BBE\u7F6E\u52A0\u8F7D\u5931\u8D25","settings.readOnlyVisitor":"\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u4FEE\u6539\u8BBE\u7F6E\u9700\u8981\u6388\u6743\u94FE\u63A5\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09","settings.sectionAccess":"\u8BBF\u95EE\u6743\u9650","settings.publicReadOnly":"\u5141\u8BB8\u65E0 token \u53EA\u8BFB\u8BBF\u95EE dashboard","settings.publicReadOnlyHelp":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 token \u7684\u8BBF\u95EE\u8005\u53EF\u4EE5\u67E5\u770B dashboard\u3001\u4F1A\u8BDD\u3001\u5B9A\u65F6\u4EFB\u52A1\u548C SSE\uFF1B\u5173\u95ED\u3001\u6682\u505C\u3001\u5BA1\u6279\u7B49\u5199\u64CD\u4F5C\u4ECD\u5FC5\u987B\u901A\u8FC7 token \u9274\u6743\u3002\u654F\u611F\u7EC8\u7AEF\u539F\u59CB\u65E5\u5FD7\u59CB\u7EC8\u9700\u8981 token\u3002","settings.sectionCards":"\u98DE\u4E66\u5361\u7247","settings.openTerminalInFeishu":"\u6D41\u5F0F\u5361\u7247\u7EC8\u7AEF\u6309\u94AE\u5728\u98DE\u4E66\u4FA7\u680F\u6253\u5F00","settings.openTerminalInFeishuHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF1A\u7EC8\u7AEF\u6309\u94AE\u76F4\u63A5\u6253\u5F00 Web Terminal URL\u3002\u5F00\u542F\u540E\u4F7F\u7528\u98DE\u4E66 web_url/open \u5305\u88C5\uFF0C\u5728\u98DE\u4E66 PC \u4FA7\u680F\u91CC\u6253\u5F00\uFF1B\u5199\u6743\u9650\u4ECD\u7531\u7EC8\u7AEF token \u63A7\u5236\u3002","settings.sectionRepoPicker":"\u4ED3\u5E93\u9009\u62E9","settings.repoPickerMode":"\u4ED3\u5E93\u9009\u62E9\u5361\u6A21\u5F0F","settings.repoPickerModeAll":"\u4ED3\u5E93 + worktree","settings.repoPickerModeRepos":"\u4EC5\u4E3B\u4ED3\u5E93","settings.repoPickerModeHelp":"\u9ED8\u8BA4\u663E\u793A\u4ED3\u5E93\u548C linked worktree\u3002\u9009\u62E9\u300C\u4EC5\u4E3B\u4ED3\u5E93\u300D\u540E\uFF0C\u521D\u59CB\u5316\u548C\u88F8 /repo \u7684\u9009\u62E9\u5361\u53EA\u5217\u4E3B\u4ED3\u5E93\uFF1B\u663E\u5F0F /repo /abs/path/to/worktree \u4ECD\u53EF\u76F4\u8FBE worktree\u3002","settings.saving":"\u4FDD\u5B58\u4E2D\u2026","settings.saved":"\u5DF2\u4FDD\u5B58","settings.saveFailed":"\u4FDD\u5B58\u5931\u8D25","settings.sectionMaintenance":"\u81EA\u52A8\u7EF4\u62A4","settings.autoUpdate":"\u81EA\u52A8\u66F4\u65B0","settings.autoUpdateHelp":"\u9ED8\u8BA4\u5173\u95ED\u3002\u5230\u70B9\u6267\u884C npm install -g botmux@latest \u5B89\u88C5\u6700\u65B0\u7248\u672C\uFF08\u53EA\u4E0B\u8F7D\u5B89\u88C5\u3001\u672C\u8EAB\u4E0D\u91CD\u542F\uFF09\u3002\u4EC5 npm \u5168\u5C40\u5B89\u88C5\u53EF\u7528\u3002","settings.autoRestart":"\u81EA\u52A8\u91CD\u542F","settings.autoRestartHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF0C\u9700\u5148\u5F00\u542F\u81EA\u52A8\u66F4\u65B0\u3002\u81EA\u52A8\u66F4\u65B0\u88C5\u5230\u65B0\u7248\u672C\u540E\uFF0C\u82E5\u6CA1\u6709\u8FDB\u884C\u4E2D\u7684\u4F1A\u8BDD\u5219\u81EA\u52A8\u91CD\u542F\u4EE5\u751F\u6548\uFF08\u649E\u4E0A\u5FD9\u788C\u4F1A\u8BDD\u5219\u8DF3\u5230\u6B21\u65E5\uFF09\u3002","settings.autoUpdateLocalDev":"\u5F53\u524D\u4E3A\u672C\u5730\u5F00\u53D1\u5B89\u88C5\uFF08\u4ECE\u6E90\u7801\u8FD0\u884C\uFF09\uFF0C\u81EA\u52A8\u66F4\u65B0\u4E0D\u53EF\u7528\u3002","settings.maintenanceTime":"\u65F6\u95F4","botDefaults.title":"\u6570\u5B57\u5458\u5DE5\u6863\u6848","botDefaults.subtitle":"\u6BCF\u4F4D\u5458\u5DE5\u7684\u9ED8\u8BA4\u884C\u4E3A\uFF1Aoncall\u3001\u4E3B\u52A8\u5F00\u5DE5\u3001\u4EBA\u8BBE\u89D2\u8272\u3001\u5361\u7247\u4E0E\u6388\u6743\u3002","botDefaults.metaOnline":"\u5728\u7EBF \xB7 daemon \u6B63\u5E38","botDefaults.search":"\u641C\u7D22 bot \u540D / app id","botDefaults.refresh":"\u5237\u65B0","botDefaults.sectionOncall":"\u65B0\u7FA4 Oncall","botDefaults.sectionBrand":"\u5361\u7247\u7B7E\u540D","botDefaults.warning":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 oncall binding \u7684\u7FA4\u4F1A\u5728\u4E0B\u6B21\u5F00\u65B0\u8BDD\u9898\u65F6\u81EA\u52A8\u7ED1\u5B9A\u5230\u8BE5\u76EE\u5F55\uFF1B\u624B\u52A8\u7ED1\u5B9A\u6216\u624B\u52A8\u89E3\u7ED1\u8FC7\u7684\u7FA4\u4E0D\u4F1A\u88AB\u8986\u76D6\u3002","botDefaults.empty":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u5148 botmux restart \u8BA9 daemon \u4E0A\u7EBF\u3002","botDefaults.defaultOncall":"\u9ED8\u8BA4\u8FDB\u5165 oncall \u6A21\u5F0F","botDefaults.defaultOncallHelp":"\u6240\u6709\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8\u7ED1\u5B9A","botDefaults.workingDir":"\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55","botDefaults.lastEnabled":"\u4E0A\u6B21\u542F\u7528\u65F6\u95F4","botDefaults.autobound":"\u5DF2\u81EA\u52A8\u7ED1\u5B9A {count} \u4E2A\u7FA4","botDefaults.save":"\u4FDD\u5B58","botDefaults.required":"\u5F00\u542F\u65F6\u5FC5\u987B\u586B\u5DE5\u4F5C\u76EE\u5F55","botDefaults.brandLabel":"\u4E2A\u6027\u7B7E\u540D\uFF08\u5361\u7247\u9875\u811A\uFF09","botDefaults.brandLabelHelp":"\u8BE5 bot \u53D1\u51FA\u7684\u5361\u7247\u9875\u811A\u7B7E\u540D\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u4E0D\u663E\u793A\uFF1B\u586B\u5199\uFF1D\u81EA\u5B9A\u4E49\uFF08\u652F\u6301 markdown\uFF0C\u5982 [Acme](https://\u2026)\uFF09\uFF1B\u6062\u590D\u9ED8\u8BA4\uFF1D\u663E\u793A botmux\u3002","botDefaults.brandLabelPlaceholder":"\u9ED8\u8BA4\uFF1Abotmux\uFF08\u7559\u7A7A\u5219\u4E0D\u663E\u793A\uFF09","botDefaults.sectionSandbox":"\u6587\u4EF6\u6C99\u76D2\uFF08oncall\uFF09","botDefaults.sandboxToggle":"\u5F00\u542F\u6587\u4EF6\u6C99\u76D2","botDefaults.sandboxHelp":"\u5F00\u542F\u540E\uFF0C\u8BE5 bot \u7684\u6BCF\u4E2A\u4F1A\u8BDD\u90FD\u8DD1\u5728\u6309\u4F1A\u8BDD\u9694\u79BB\u7684\u6C99\u76D2\u91CC\uFF1A\u53EA\u770B\u5F97\u5230\u4E00\u4EFD\u9879\u76EE\u526F\u672C\uFF0C\u78B0\u4E0D\u5230\u4F60\u78C1\u76D8\u4E0A\u7684\u771F\u5B9E\u6587\u4EF6\u3001\u5BC6\u94A5\u3001\u522B\u7684\u4F1A\u8BDD\u6570\u636E\u3002\u9002\u5408\u628A\u673A\u5668\u4EBA\u5206\u4EAB\u7ED9\u534A\u53D7\u4FE1\u4EFB\u7684\u4EBA\uFF08oncall\uFF09\u3002\u4EC5 Linux \u751F\u6548\uFF0C\u4E0B\u4E2A\u65B0\u4F1A\u8BDD\u8D77\u6548\u3002","botDefaults.sandboxSaved":"\u5DF2\u4FDD\u5B58\uFF08\u4E0B\u4E2A\u65B0\u4F1A\u8BDD\u751F\u6548\uFF09","botDefaults.brandSave":"\u4FDD\u5B58\u7B7E\u540D","botDefaults.brandReset":"\u6062\u590D\u9ED8\u8BA4","botDefaults.brandStateDefault":"\u5F53\u524D\uFF1A\u9ED8\u8BA4 botmux","botDefaults.brandStateOff":"\u5F53\u524D\uFF1A\u5DF2\u5173\u95ED","botDefaults.brandStateCustom":"\u5F53\u524D\uFF1A\u81EA\u5B9A\u4E49","botDefaults.sectionCard":"\u5361\u7247\u884C\u4E3A","botDefaults.disableStreaming":"\u5173\u95ED\u98DE\u4E66\u6D41\u5F0F\u5361\u7247","botDefaults.disableStreamingHelp":"\u4E0D\u518D\u53D1\u5B9E\u65F6\u5237\u65B0\u7684\u4F1A\u8BDD\u72B6\u6001\u5361\uFF08\u542B\u300C\u6253\u5F00\u7EC8\u7AEF\u300D\u5165\u53E3\uFF09\uFF1B\u4EFB\u52A1\u6700\u7EC8\u7ED3\u679C\u4ECD\u901A\u8FC7\u6D88\u606F\u9001\u8FBE\u3002\u9002\u5408\u5ACC\u6D41\u5F0F\u5361\u7247\u70E6\u7684\u573A\u666F\u3002","botDefaults.writableLink":"\u5361\u7247\u4E0A\u76F4\u63A5\u7ED9\u53EF\u64CD\u4F5C\uFF08\u53EF\u5199\uFF09\u7EC8\u7AEF\u94FE\u63A5","botDefaults.writableLinkHelp":"\u26A0\uFE0F \u5728\u6D41\u5F0F\u5361\u7247\u6B63\u6587\u76F4\u63A5\u8D34\u51FA\u53EF\u5199\u7EC8\u7AEF\u94FE\u63A5\uFF0C\u7FA4\u5185\u4EFB\u4F55\u4EBA\u90FD\u80FD\u70B9\u5F00\u5E76\u64CD\u63A7\u7EC8\u7AEF\u3002\u4E0D\u52FE\uFF1D\u4FDD\u6301\u73B0\u72B6\uFF08\u8D70\u300C\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u300D\u6309\u94AE\u79C1\u804A\u53D1\u7ED9\u70B9\u51FB\u8005\uFF09\u3002","botDefaults.writableLinkMoot":"\u5DF2\u5173\u95ED\u6D41\u5F0F\u5361\u7247","botDefaults.privateCard":"/card \u53D1\u79C1\u5BC6\u5361\u7247\uFF08\u4EC5\u6388\u6743\u4EBA\u53EF\u89C1\uFF09","botDefaults.privateCardHelp":"\u5F00\u542F\u540E /card \u6539\u7528\u300C\u4EC5\u7279\u5B9A\u4EBA\u53EF\u89C1\u300D\u7684\u4E34\u65F6\u5361\u7247\uFF1A\u53EA\u53D1\u7ED9 owner\uFF08allowedUsers\uFF09\uFF0C/grant \u6388\u6743\u5BF9\u8BDD\u7684\u4EBA\u548C\u7FA4\u91CC\u5176\u4ED6\u4EBA\u90FD\u770B\u4E0D\u5230\u3002\u4EE3\u4EF7\uFF1A\u662F\u9759\u6001\u5FEB\u7167\u3001\u4E0D\u4F1A\u5B9E\u65F6\u5237\u65B0\uFF1B\u4E14\u4EC5\u666E\u901A\u7FA4\u53EF\u7528\uFF08\u8BDD\u9898\u7FA4 / \u5355\u804A\u4F1A\u5931\u8D25\uFF0C\u4E0D\u964D\u7EA7\uFF09\u3002\u53EA\u5F71\u54CD /card \u547D\u4EE4\uFF0C\u81EA\u52A8\u6D41\u5F0F\u5361\u4E0D\u53D8\u3002","botDefaults.cardPrefSaved":"\u5DF2\u4FDD\u5B58","botDefaults.sectionRole":"\u9ED8\u8BA4\u89D2\u8272","botDefaults.roleHelp":"\u8BE5 bot \u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF08\u8DE8\u7FA4\u751F\u6548\uFF09\uFF0C\u4F1A\u6CE8\u5165\u5230\u8BE5 bot \u5728\u5404\u7FA4\u7684\u4F1A\u8BDD\u91CC\uFF1B\u5355\u4E2A\u7FA4\u53EF\u5728\u300C\u89D2\u8272\u300D\u9875\u5355\u72EC\u8986\u76D6\u3002\u7559\u7A7A\u4FDD\u5B58\uFF1D\u5220\u9664\u3002","botDefaults.rolePlaceholder":"\u4F8B\u5982\uFF1A\u4F60\u662F\u540E\u7AEF\u6392\u969C\u52A9\u624B\uFF0C\u56DE\u7B54\u7B80\u6D01\u3001\u4F18\u5148\u7ED9\u53EF\u6267\u884C\u547D\u4EE4\u2026","botDefaults.roleSave":"\u4FDD\u5B58\u89D2\u8272","botDefaults.roleDelete":"\u5220\u9664","botDefaults.roleSaved":"\u5DF2\u4FDD\u5B58","botDefaults.roleDeleted":"\u5DF2\u5220\u9664","botDefaults.roleLoadErr":"\u89D2\u8272\u52A0\u8F7D\u5931\u8D25","botDefaults.sectionAutoStart":"\u4E3B\u52A8\u5F00\u5DE5","botDefaults.autoStartJoin":"\u88AB\u62C9\u8FDB\u65B0\u7FA4\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartJoinHelp":"\u5F00\u542F\u540E\uFF0C\u673A\u5668\u4EBA\u4E00\u88AB\u62C9\u8FDB\u65B0\u7FA4\uFF08\u7FA4\u91CC\u6709\u6388\u6743\u7528\u6237 allowedUsers \u65F6\uFF09\u5C31\u81EA\u52A8\u5F00\u4E00\u4E2A\u4F1A\u8BDD\u5F00\u59CB\u5DE5\u4F5C\uFF0C\u65E0\u9700 @\u3002\u5728\u673A\u5668\u4EBA\u7684\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55\u542F\u52A8\uFF1B\u672A\u914D\u7F6E\u9ED8\u8BA4\u76EE\u5F55\u65F6\u5148\u5F39\u4ED3\u5E93\u9009\u62E9\u5361\u8BA9\u4F60\u9009\u3002\u524D\u63D0\uFF1A\u9700\u5728\u98DE\u4E66\u5F00\u653E\u5E73\u53F0\u4E3A\u672C\u5E94\u7528\u8BA2\u9605\u300C\u673A\u5668\u4EBA\u8FDB\u7FA4\u300D\u4E8B\u4EF6 im.chat.member.bot.added_v1\uFF0C\u5E76\u5F00\u901A\u7FA4\u6210\u5458\u8BFB\u53D6\u6743\u9650\u3002","botDefaults.autoStartJoinPrompt":"\u5165\u7FA4\u9996\u8F6E prompt\uFF08\u53EF\u9009\uFF09","botDefaults.autoStartJoinPromptPlaceholder":"\u586B\u4E86\uFF1D\u4F5C\u4E3A\u5165\u7FA4\u540E\u7684\u7B2C\u4E00\u6761\u4EFB\u52A1\uFF1B\u7559\u7A7A\uFF1D\u673A\u5668\u4EBA\u81EA\u5DF1\u770B\u7FA4\u91CC\u4FE1\u606F\u51B3\u5B9A\u505A\u4EC0\u4E48","botDefaults.autoStartJoinPromptSave":"\u4FDD\u5B58 prompt","botDefaults.autoStartTopic":"\u8BDD\u9898\u7FA4\u65B0\u8BDD\u9898\u81EA\u52A8\u5F00\u5DE5","botDefaults.autoStartTopicHelp":"\u5F00\u542F\u540E\uFF0C\u5728\u8BDD\u9898\u7FA4\u91CC\u6BCF\u5F53\u6709\u4EBA\u65B0\u5F00\u4E00\u4E2A\u8BDD\u9898\uFF0C\u673A\u5668\u4EBA\u5C31\u4F1A\u81EA\u52A8\u63A5\u5165\u8BE5\u8BDD\u9898\u3001\u628A\u9996\u6761\u6D88\u606F\u5F53\u4F5C\u4EFB\u52A1\u5F00\u59CB\u5904\u7406\uFF0C\u65E0\u9700 @\u3002\u4EC5\u5BF9\u8BDD\u9898\u7FA4\u751F\u6548\uFF0C\u666E\u901A\u7FA4\u4E0D\u53D7\u5F71\u54CD\u3002","botDefaults.sectionSessionMode":"\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.p2pMode":"\u79C1\u804A\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.p2pThread":"thread\uFF08\u6BCF\u6761 DM \u72EC\u7ACB\u4F1A\u8BDD\uFF09","botDefaults.p2pChat":"chat\uFF08\u6241\u5E73\u8FDE\u7EED\u5355\u804A\u4F1A\u8BDD\uFF09","botDefaults.p2pHelp":"\u79C1\u804A\uFF081:1 DM\uFF09\u7684\u4F1A\u8BDD\u65B9\u5F0F\uFF1Athread = \u6BCF\u6761\u9876\u5C42\u6D88\u606F\u5404\u81EA\u8D77\u72EC\u7ACB\u4F1A\u8BDD\uFF08\u907F\u514D\u628A\u5BF9\u8BDD\u5806\u8FDB\u540C\u4E00\u4E2A CLI \u8FDB\u7A0B\uFF09\uFF1Bchat = \u6574\u6BB5 DM \u5171\u7528\u4E00\u4E2A\u8FDE\u7EED\u4F1A\u8BDD\u3001\u5171\u4EAB\u4E0A\u4E0B\u6587\uFF08\u7C7B Hermes\uFF09\u3002\u6539\u540E\u7ACB\u5373\u751F\u6548\u3002","botDefaults.regularGroupMode":"\u666E\u901A\u7FA4\u4F1A\u8BDD\u6A21\u5F0F","botDefaults.regularGroupModeChat":"chat\uFF08\u6241\u5E73\u8FDE\u7EED\u5355\u804A\u4F1A\u8BDD\uFF0C\u9ED8\u8BA4\uFF09","botDefaults.regularGroupModeNewTopic":"new-topic\uFF08\u6BCF\u6761\u9876\u5C42 @ \u5404\u5F00\u72EC\u7ACB\u8BDD\u9898\u4E0E\u4F1A\u8BDD\uFF09","botDefaults.regularGroupModeShared":"shared\uFF08\u8BDD\u9898\u6A21\u5F0F\u4F46\u590D\u7528\u540C\u4E00\u4E2A session\uFF09","botDefaults.regularGroupModeHelp":"\u666E\u901A\u7FA4\uFF08\u975E\u8BDD\u9898\u7FA4\uFF09\u91CC @ \u8BE5 bot \u7684\u65B0\u9876\u5C42\u6D88\u606F\u600E\u4E48\u5F00\u4F1A\u8BDD\uFF1Achat = \u6574\u7FA4\u5171\u7528\u4E00\u4E2A\u8FDE\u7EED\u4F1A\u8BDD\uFF08\u9ED8\u8BA4\uFF09\uFF1Bnew-topic = \u6BCF\u6761\u9876\u5C42 @ \u5728\u539F\u6D88\u606F\u4E0B\u5F00\u72EC\u7ACB\u8BDD\u9898\u3001\u5404\u81EA\u72EC\u7ACB\u4F1A\u8BDD\uFF1Bshared = \u8BDD\u9898\u6A21\u5F0F\u4F46\u590D\u7528\u540C\u4E00\u4E2A session\uFF08\u56DE\u590D\u843D\u5728\u8BDD\u9898\u91CC\u3001\u4F46\u5171\u7528\u672C\u7FA4\u4F1A\u8BDD\u4E0E\u4E0A\u4E0B\u6587\uFF09\u3002\u8FD9\u662F per-bot \u9ED8\u8BA4\uFF0C\u5177\u4F53\u67D0\u4E2A\u7FA4\u53EF\u7528 /reply-mode \u5355\u72EC\u8986\u76D6\u3002\u6539\u540E\u7ACB\u5373\u751F\u6548\u3002","botDefaults.mentionMode":"\u7FA4\u804A @ \u7B56\u7565","botDefaults.mentionModeAlways":"\u90FD\u9700\u8981 @\uFF08\u9ED8\u8BA4\uFF09","botDefaults.mentionModeTopic":"\u4EC5\u8BDD\u9898\u5185\u4E0D\u9700\u8981 @","botDefaults.mentionModeNever":"\u6240\u6709\u6D88\u606F\u90FD\u4E0D\u9700\u8981 @","botDefaults.mentionModeHelp":"\u8BE5 bot \u5168\u5C40\u751F\u6548\uFF0C\u51B3\u5B9A\u7FA4\u91CC\u8981\u4E0D\u8981 @ \u624D\u56DE\uFF1A\u300C\u90FD\u9700\u8981 @\u300D= \u4EFB\u4F55\u6D88\u606F\u90FD\u5F97 @\uFF08\u9ED8\u8BA4\uFF0C\u6700\u5B89\u5168\uFF1B\u591A\u4EBA\u7FA4\u91CC\u8BDD\u9898\u5185\u4E5F\u8981 @\uFF09\uFF1B\u300C\u4EC5\u8BDD\u9898\u5185\u4E0D\u9700\u8981 @\u300D= \u8D77\u65B0\u5BF9\u8BDD / \u9876\u5C42\u4ECD\u8981 @\uFF0C\u4F46\u5728\u8BE5 bot \u5DF2\u5F00\u7684\u4EFB\u4F55\u8BDD\u9898\u91CC\uFF08new-topic / shared / \u8BDD\u9898\u7FA4\uFF09\u540E\u7EED\u6D88\u606F\u514D @ \u7EED\u804A\uFF1B\u300C\u6240\u6709\u6D88\u606F\u90FD\u4E0D\u9700\u8981 @\u300D= \u8BE5 bot \u6709\u5BF9\u8BDD\u6743\u9650\u7684\u7FA4\u91CC\u975E @ \u6D88\u606F\u4E5F\u56DE\uFF08\u542B\u5168\u65B0\u6D88\u606F\u51B7\u542F\u52A8\uFF0C\u4EC5\u9002\u5408\u4E13\u7528 / \u503C\u73ED\u5C0F\u7FA4\uFF0C\u591A\u4EBA\u7FA4\u91CC\u4F1A\u89C1\u6D88\u606F\u5C31\u56DE\uFF09\u3002\u6CE8\uFF1A\u7FA4\u91CC\u53EA\u6709\u4F60\u548C\u8BE5 bot\uFF081 \u5BF9 1\uFF09\u65F6\u4E00\u76F4\u514D @\uFF0C\u4E0E\u672C\u8BBE\u7F6E\u65E0\u5173\u3002","botDefaults.docSubscribeMode":"\u6587\u6863\u8BA2\u9605\u89E6\u53D1\u8303\u56F4\uFF08\u9ED8\u8BA4\uFF09","botDefaults.docSubscribeModeMention":"\u4EC5\u8BC4\u8BBA @ \u6211\u624D\u89E6\u53D1","botDefaults.docSubscribeModeAll":"\u6240\u6709\u65B0\u8BC4\u8BBA\u90FD\u89E6\u53D1","botDefaults.docSubscribeModeHelp":"\u7528 /subscribe-lark-doc \u8BA2\u9605\u98DE\u4E66\u6587\u6863\u540E\uFF0C\u6587\u6863\u8BC4\u8BBA\u4F1A\u5582\u8FDB\u4F1A\u8BDD\u3001bot \u56DE\u590D\u53D1\u56DE\u8BC4\u8BBA\u3002\u8FD9\u91CC\u8BBE\u65B0\u8BA2\u9605\u7684\u9ED8\u8BA4\u89E6\u53D1\u8303\u56F4\uFF1A\u300C\u4EC5\u8BC4\u8BBA @ \u6211\u300D\u6700\u5B89\u5168\uFF08\u9632\u5237\u5C4F\uFF09\uFF1B\u300C\u6240\u6709\u65B0\u8BC4\u8BBA\u300D\u9002\u5408\u4E13\u7528\u6587\u6863\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","botDefaults.sectionSessionCap":"\u4F1A\u8BDD\u6570\u4E0A\u9650","botDefaults.maxLiveWorkers":"\u6700\u5927\u540C\u65F6\u6D3B\u8DC3\u4F1A\u8BDD\u6570","botDefaults.maxLiveWorkersPlaceholder":"\u7559\u7A7A\uFF1D\u9ED8\u8BA4 30","botDefaults.maxLiveWorkersHelp":"\u672C Bot \u540C\u65F6\u4FDD\u6D3B\u7684\u4F1A\u8BDD\u6570\u4E0A\u9650\uFF0C\u7528\u4E8E\u63A7\u5236\u5185\u5B58\u3002\u8D85\u8FC7\u540E\u6700\u4E45\u672A\u7528\u7684\u4F1A\u8BDD\u81EA\u52A8\u4F11\u7720\uFF1Aworker \u548C CLI \u8FDB\u7A0B\u4E00\u8D77\u6740\u6389\u3001\u56DE\u6536\u5168\u90E8\u5185\u5B58\uFF0C\u4E0B\u6761\u6D88\u606F\u65F6\u4ECE\u78C1\u76D8 transcript \u51B7\u6062\u590D\uFF08--resume \u91CD\u5EFA\u4E0A\u4E0B\u6587\uFF0C\u51E0\u79D2\uFF0C\u4E0D\u518D\u5E38\u9A7B\u5360\u5185\u5B58\uFF09\u3002\u7559\u7A7A\uFF1D\u7528\u9ED8\u8BA4 30\uFF1B\u586B\u6570\u5B57\uFF1D\u672C Bot \u81EA\u5B9A\u4E49\uFF08\u60F3\u8981\u66F4\u591A\u5C31\u586B\u5927\u6570\u5B57\uFF09\u3002\u6CE8\u610F\uFF1A\u4F11\u7720\u53EA\u5BF9\u53EF\u6062\u590D\u540E\u7AEF\uFF08tmux/herdr/zellij\uFF09\u751F\u6548\uFF0C\u7EAF PTY \u4F1A\u8BDD\u4E0D\u53D7\u5F71\u54CD\uFF1B\u6B63\u5728\u51FA\u7B54\u6848\u7684\u4F1A\u8BDD\u4E0D\u4F1A\u88AB\u6253\u65AD\u3002","botDefaults.maxLiveWorkersSave":"\u4FDD\u5B58\u4E0A\u9650","botDefaults.maxLiveWorkersOff":"\u6062\u590D\u9ED8\u8BA4","botDefaults.maxLiveWorkersInvalid":"\u4E0A\u9650\u5FC5\u987B\u662F\u6B63\u6574\u6570","botDefaults.maxLiveWorkersStateDefault":"\u5F53\u524D\uFF1A\u9ED8\u8BA4 30 \u4E2A\u6D3B\u8DC3\u4F1A\u8BDD","botDefaults.maxLiveWorkersStateOn":"\u5F53\u524D\uFF1A\u6700\u591A {count} \u4E2A\u6D3B\u8DC3\u4F1A\u8BDD","nav.roles":"\u89D2\u8272\u7BA1\u7406","roles.title":"\u89D2\u8272\u7BA1\u7406","roles.subtitle":"\u4E3A\u6BCF\u4E2A\u7FA4\u7EC4\u7684\u6BCF\u4E2A Bot \u5355\u72EC\u8BBE\u7F6E\u89D2\u8272\u63D0\u793A\u8BCD\uFF0CBot \u5728\u8BE5\u7FA4\u4E2D\u4F1A\u4EE5\u6B64\u89D2\u8272\u884C\u4E8B\u3002","roles.search":"\u641C\u7D22\u7FA4\u540D/Bot/ID","roles.refresh":"\u5237\u65B0","roles.selectHint":"\u2190 \u5C55\u5F00\u7FA4\u7EC4\uFF0C\u9009\u62E9\u4E00\u4E2A Bot \u6765\u7F16\u8F91\u89D2\u8272","roles.editorPlaceholder":`\u8F93\u5165\u89D2\u8272\u63CF\u8FF0\uFF0C\u4F8B\u5982\uFF1A
|
|
2
2
|
\u4F60\u662F\u672C\u7FA4\u7684\u6280\u672F\u987E\u95EE\uFF0C\u8D1F\u8D23\u56DE\u7B54\u6240\u6709\u6280\u672F\u95EE\u9898...`,"roles.configured":"\u5DF2\u914D\u7F6E","roles.unconfigured":"\u672A\u914D\u7F6E","roles.noChats":"\u6682\u65E0\u7FA4\u7EC4","roles.preview":"\u9884\u89C8","roles.previewEmpty":"\uFF08\u7A7A\u5185\u5BB9\uFF09","roles.saved":"\u5DF2\u4FDD\u5B58","roles.delete":"\u5220\u9664","roles.save":"\u4FDD\u5B58","roles.confirmDelete":"\u786E\u8BA4\u5220\u9664\u8BE5 Bot \u5728\u6B64\u7FA4\u7684\u89D2\u8272\u914D\u7F6E\uFF1F","roles.botsWithRoles":"\u4E2A Bot \u5DF2\u914D\u7F6E\u89D2\u8272","roles.emptyError":"\u89D2\u8272\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u8BF7\u5148\u8F93\u5165\u5185\u5BB9","roles.saveFailed":"\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5","common.none":"\u65E0","common.loading":"\u52A0\u8F7D\u4E2D\u2026","common.unknown":"\u672A\u77E5","common.now":"\u521A\u521A","common.never":"\u4ECE\u672A","common.all":"\u5168\u90E8","nav.workflows":"\u5DE5\u4F5C\u6D41(beta)","nav.workflowCatalog":"\u76EE\u5F55","workflow.subnav.runs":"\u8FD0\u884C","workflow.subnav.catalog":"\u76EE\u5F55","workflow.searchPlaceholder":"\u641C\u7D22 runId / workflowId / chatId","workflow.filter.nonTerminal":"\u975E\u7EC8\u6001","workflow.filter.all":"\u5168\u90E8","workflow.status.pending":"\u5F85\u5F00\u59CB","workflow.status.running":"\u8FD0\u884C\u4E2D","workflow.status.waiting":"\u7B49\u5F85\u4E2D","workflow.status.effectAttempting":"\u526F\u4F5C\u7528\u4E2D","workflow.status.timedOut":"\u5DF2\u8D85\u65F6","workflow.status.succeeded":"\u6210\u529F","workflow.status.failed":"\u5931\u8D25","workflow.status.cancelled":"\u5DF2\u53D6\u6D88","workflow.table.run":"\u8FD0\u884C","workflow.table.workflow":"\u5DE5\u4F5C\u6D41","workflow.table.status":"\u72B6\u6001","workflow.table.lastSeq":"\u6700\u540E\u5E8F\u53F7","workflow.table.dangling":"\u60AC\u6302 dEf/dAct/dWait","workflow.table.updated":"\u66F4\u65B0\u65F6\u95F4","workflow.table.chatApp":"\u7FA4\u804A / \u5E94\u7528","workflow.list.failedLoad":"\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","workflow.list.noRuns":"\u6CA1\u6709\u5339\u914D\u7684\u8FD0\u884C\u3002","workflow.list.noFilterMatch":"\u6CA1\u6709\u7B26\u5408\u7B5B\u9009\u6761\u4EF6\u7684\u8FD0\u884C\u3002","workflow.list.loaded":"{count} \u4E2A\u8FD0\u884C \xB7 \u5237\u65B0\u4E8E {time}","workflow.list.error":"\u9519\u8BEF\uFF1A{error}","workflow.detail.back":"\u8FD4\u56DE","workflow.detail.loading":"\u52A0\u8F7D\u4E2D...","workflow.detail.loadFailed":"\u52A0\u8F7D\u5931\u8D25","workflow.detail.cancel":"\u53D6\u6D88","workflow.detail.cliCancelOnly":"\u4EC5 CLI \u53EF\u53D6\u6D88","workflow.detail.cancelTitle":"\u53D6\u6D88\u8FD9\u4E2A\u5DE5\u4F5C\u6D41\u8FD0\u884C","workflow.detail.cliCancelTitle":"\u65E0\u6CD5\u5728\u9875\u9762\u53D6\u6D88\uFF1A\u8BF7\u4F7F\u7528 botmux workflow cancel {runId}","workflow.detail.nodes":"\u8282\u70B9 / Activity","workflow.detail.parallel":"\u5E76\u53D1\u6267\u884C","workflow.detail.parallelMeta":"{count} \u6B21\u5C1D\u8BD5 \xB7 \u6700\u9AD8\u5E76\u53D1 {max} \xB7 \u8FD0\u884C\u4E2D {running}","workflow.detail.noParallelData":"\u8FD8\u6CA1\u6709 attempt \u65F6\u95F4\u6570\u636E\u3002","workflow.detail.parallelNow":"\u73B0\u5728","workflow.detail.node":"\u8282\u70B9","workflow.detail.nodeStatus":"\u8282\u70B9\u72B6\u6001","workflow.detail.activity":"Activity","workflow.detail.activityStatus":"Activity \u72B6\u6001","workflow.detail.attempts":"\u5C1D\u8BD5\u6B21\u6570","workflow.detail.current":"\u5F53\u524D\u5C1D\u8BD5","workflow.detail.detail":"\u8BE6\u60C5","workflow.detail.nodeIO":"\u8282\u70B9\u8F93\u5165\u8F93\u51FA","workflow.detail.timeline":"\u65F6\u95F4\u7EBF","workflow.detail.loadOlder":"\u52A0\u8F7D\u66F4\u65E9\u4E8B\u4EF6","workflow.detail.seq":"\u5E8F\u53F7","workflow.detail.actor":"\u6267\u884C\u8005","workflow.detail.error":"\u9519\u8BEF","workflow.detail.event":"\u4E8B\u4EF6","workflow.detail.time":"\u65F6\u95F4","workflow.detail.refreshed":"\u5237\u65B0\u4E8E {time}","workflow.detail.unknownRun":"\u672A\u77E5\u8FD0\u884C","workflow.detail.snapshotHttp":"snapshot HTTP {status}","workflow.detail.eventsHttp":"events HTTP {status}","workflow.detail.cancelUnavailable":"\u65E0\u6CD5\u53D6\u6D88\uFF1A\u8BF7\u4F7F\u7528 botmux workflow cancel {runId}","workflow.detail.cancelConfirm":`\u786E\u8BA4\u53D6\u6D88\u5DE5\u4F5C\u6D41\u8FD0\u884C {runId}\uFF1F
|
|
3
3
|
|
|
4
4
|
{total} \u4E2A\u60AC\u6302\u9879\u4F1A\u7531 cancel recovery \u5904\u7406\u3002
|
|
5
5
|
effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"workflow.detail.writeAccessCancel":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u70B9\u51FB\u53D6\u6D88\u3002","workflow.detail.cancelHttp":"cancel HTTP {status}","workflow.detail.cancelPending":"\u53D6\u6D88\u5DF2\u63D0\u4EA4\uFF1B\u7B49\u5F85\u8FD0\u884C\u4E2D\u7684 activity \u6536\u655B","workflow.detail.writeAccessApproval":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u5BA1\u6279\u3002","workflow.detail.actionHttp":"{action} HTTP {status}","workflow.detail.approved":"\u5DF2\u901A\u8FC7","workflow.detail.rejected":"\u5DF2\u62D2\u7EDD","workflow.detail.alreadyTerminal":"\u8FD0\u884C\u5DF2\u7EC8\u6001\uFF1B\u672A\u5E94\u7528\u201C{label}\u201D\u3002","workflow.detail.workflowContinue":"{label}\uFF1B\u7B49\u5F85\u5DE5\u4F5C\u6D41\u7EE7\u7EED\u6267\u884C\u3002","workflow.detail.workflowRefreshing":"{label}\uFF1B\u6B63\u5728\u5237\u65B0\u5DE5\u4F5C\u6D41\u72B6\u6001\u3002","workflow.detail.eventsLoaded":"\u5DF2\u52A0\u8F7D {loaded}/{total} \u4E2A\u4E8B\u4EF6","workflow.detail.dangling":"\u60AC\u6302\u9879","workflow.detail.noDangling":"\u6CA1\u6709\u60AC\u6302\u5DE5\u4F5C\u3002","workflow.detail.none":"\u65E0","workflow.detail.noNodes":"\u8FD8\u6CA1\u6709\u8282\u70B9\u3002","workflow.detail.idle":"\u7A7A\u95F2","workflow.detail.noNodeIO":"\u8FD8\u6CA1\u6709\u8282\u70B9\u8F93\u5165\u8F93\u51FA\u3002","workflow.detail.notDispatched":"\u5C1A\u672A\u6D3E\u53D1","workflow.detail.noAttempt":"\u8FD8\u6CA1\u6709\u5C1D\u8BD5","workflow.detail.attempt":"\u5C1D\u8BD5","workflow.detail.authoredInput":"\u539F\u59CB\u8F93\u5165","workflow.detail.resolvedInput":"\u89E3\u6790\u540E\u8F93\u5165","workflow.detail.output":"\u8F93\u51FA","workflow.detail.executionLog":"\u6267\u884C\u65E5\u5FD7","workflow.detail.liveTerminal":"\u5B9E\u65F6\u7EC8\u7AEF","workflow.detail.terminalLive":"\u5728\u7EBF","workflow.detail.terminalClosedShort":"\u5DF2\u5173\u95ED","workflow.detail.terminalClosed":"\u7EC8\u7AEF\u5DF2\u5173\u95ED\u3002\u8BF7\u67E5\u770B\u4E0B\u65B9\u6267\u884C\u65E5\u5FD7\u83B7\u53D6\u6700\u7EC8\u8BB0\u5F55\u3002","workflow.detail.openTerminalNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u7EC8\u7AEF","workflow.detail.terminalReplay":"\u7EC8\u7AEF\u56DE\u653E","workflow.detail.openReplayNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u56DE\u653E","workflow.detail.downloadFullLog":"\u4E0B\u8F7D\u5B8C\u6574\u65E5\u5FD7","workflow.detail.terminalResume":"\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.openResumeNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.resumeSession":"\u7EE7\u7EED\u4F1A\u8BDD","workflow.detail.resumeStarting":"\u6B63\u5728\u542F\u52A8\u2026","workflow.detail.endResumeSession":"\u7ED3\u675F\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.resumeEnding":"\u7ED3\u675F\u4E2D\u2026","workflow.detail.resumeUnsupportedCli":"{cliId} CLI \u4E0D\u652F\u6301 resume","workflow.detail.resumeMissingCliSession":"\u7F3A\u5C11 cliSessionId\uFF0C\u65E0\u6CD5 resume","workflow.detail.resumeStartFailed":"\u542F\u52A8\u8C03\u8BD5\u4F1A\u8BDD\u5931\u8D25 (HTTP {status})","workflow.detail.resumeEndFailed":"\u7ED3\u675F\u8C03\u8BD5\u4F1A\u8BDD\u5931\u8D25 (HTTP {status})","workflow.detail.writeAccessResume":"\u9700\u8981\u5199\u5165\u6743\u9650\u624D\u80FD resume \u4F1A\u8BDD\u3002","workflow.detail.waitPrompt":"\u7B49\u5F85\u63D0\u793A","workflow.detail.approvalComment":"\u5BA1\u6279\u5907\u6CE8","workflow.detail.optionalComment":"\u53EF\u9009\u5907\u6CE8","workflow.detail.approve":"\u901A\u8FC7","workflow.detail.reject":"\u62D2\u7EDD","workflow.detail.submitting":"\u63D0\u4EA4\u4E2D...","workflow.detail.empty":"\u7A7A","workflow.detail.truncated":"\u5DF2\u622A\u65AD","workflow.detail.noData":"\u6CA1\u6709\u6570\u636E\u3002","workflow.detail.noPreview":"\u6CA1\u6709\u9884\u89C8\u3002","workflow.detail.open":"\u6253\u5F00","workflow.detail.deadline":"\u622A\u6B62","workflow.detail.effect":"\u526F\u4F5C\u7528","workflow.detail.wait":"\u7B49\u5F85","workflow.detail.noEvents":"\u8FD8\u6CA1\u6709\u4E8B\u4EF6\u3002","workflow.summary.workflow":"\u5DE5\u4F5C\u6D41","workflow.summary.status":"\u72B6\u6001","workflow.summary.lastSeq":"\u6700\u540E\u5E8F\u53F7","workflow.summary.updated":"\u66F4\u65B0\u65F6\u95F4","workflow.summary.revision":"\u4FEE\u8BA2","workflow.summary.initiator":"\u53D1\u8D77\u4EBA","workflow.summary.failedNode":"\u5931\u8D25\u8282\u70B9","workflow.summary.cancelOrigin":"\u53D6\u6D88\u6765\u6E90","workflow.summary.chat":"\u7FA4\u804A","workflow.summary.app":"\u5E94\u7528","workflow.dangling.activities":"Activities","workflow.dangling.effects":"Effects","workflow.dangling.waits":"Waits","workflow.dangling.cancels":"Cancels","catalog.title":"\u5DE5\u4F5C\u6D41\u76EE\u5F55","catalog.subtitle":"\u4ECE\u5DF2\u4FDD\u5B58\u7684 workflow \u5B9A\u4E49\u521B\u5EFA\u4E00\u6B21\u8FD0\u884C\u3002","catalog.searchPlaceholder":"\u641C\u7D22 workflowId / \u8DEF\u5F84","catalog.refresh":"\u5237\u65B0","catalog.loading":"\u6B63\u5728\u52A0\u8F7D\u76EE\u5F55...","catalog.loadFailed":"\u76EE\u5F55\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","catalog.noDefinitions":"\u6CA1\u6709\u627E\u5230 workflow \u5B9A\u4E49\u3002","catalog.noFilterMatch":"\u6CA1\u6709\u7B26\u5408\u7B5B\u9009\u6761\u4EF6\u7684\u5B9A\u4E49\u3002","catalog.table.workflow":"\u5DE5\u4F5C\u6D41","catalog.table.version":"\u7248\u672C","catalog.table.params":"\u53C2\u6570","catalog.table.nodes":"\u8282\u70B9","catalog.table.revision":"\u4FEE\u8BA2","catalog.table.path":"\u8DEF\u5F84","catalog.paramSummary":"{required}/{total} \u5FC5\u586B","catalog.back":"\u8FD4\u56DE\u76EE\u5F55","catalog.detailTitle":"\u5DE5\u4F5C\u6D41\u5B9A\u4E49","catalog.definitionLoadFailed":"\u5B9A\u4E49\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","catalog.summary":"\u6458\u8981","catalog.paramsSchema":"\u53C2\u6570 Schema","catalog.definitionJson":"\u5B9A\u4E49 JSON","catalog.runPanel":"\u8FD0\u884C\u5DE5\u4F5C\u6D41","catalog.paramsJson":"\u53C2\u6570 JSON","catalog.paramsPlaceholder":`{
|
|
6
6
|
"city": "\u5317\u4EAC"
|
|
7
|
-
}`,"catalog.chatId":"\u7FA4\u804A ID","catalog.larkAppId":"\u98DE\u4E66\u5E94\u7528 ID","catalog.chatBindingHint":"\u5FC5\u586B\uFF0C\u7528\u4E8E\u786E\u5B9A humanGate \u5361\u7247\u53D1\u9001\u5230\u54EA\u4E2A\u98DE\u4E66\u7FA4\uFF0C\u4EE5\u53CA\u53D6\u6D88\u8DEF\u7531\u5F52\u5C5E\u3002","catalog.run":"\u8FD0\u884C","catalog.running":"\u542F\u52A8\u4E2D...","catalog.badParamsJson":"\u53C2\u6570\u5FC5\u987B\u662F JSON object\u3002","catalog.writeAccess":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u8FD0\u884C\u3002","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"\u8FD0\u884C\u5DF2\u542F\u52A8\uFF1B\u6B63\u5728\u6253\u5F00\u8BE6\u60C5\u9875...","catalog.invalidParams":"\u53C2\u6570\u65E0\u6548","catalog.issue":"{path}: {message}","catalog.noParams":"\u6CA1\u6709\u58F0\u660E\u53C2\u6570\u3002","catalog.required":"\u5FC5\u586B","catalog.optional":"\u53EF\u9009","catalog.default":"\u9ED8\u8BA4\u503C","catalog.description":"\u8BF4\u660E","catalog.path":"\u8DEF\u5F84","catalog.revision":"\u4FEE\u8BA2","catalog.nodeCount":"\u8282\u70B9\u6570"},ls={"app.name":"botmux","app.subtitle":"Feishu AI CLI Control","time.secondsAgo":"{value}s ago","time.minutesAgo":"{value}m ago","time.hoursAgo":"{value}h ago","nav.overview":"Overview","nav.sessions":"Sessions","nav.sidebarCollapse":"Collapse sidebar","nav.sidebarExpand":"Expand sidebar","nav.groups":"Groups","nav.schedules":"Schedules","nav.settings":"Settings","nav.botDefaults":"Bot Defaults","status.live":"Live","status.disconnected":"Disconnected","status.system":"System","status.light":"Light","status.dark":"Dark","status.language":"Language","status.theme":"Theme","theme.base":"Basic","theme.skins":"Skins","skin.cyber":"2077","skin.genshin":"Genshin","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"Blue Archive","skin.zzz":"ZZZ","skin.dragonball":"Dragon Ball","skin.ikun":"ikun","botOnboarding.add":"Add Bot","botOnboarding.title":"Add Bot","botOnboarding.intro":"Pick a CLI and working directory, scan to create a PersonalAgent app \u2014 the dashboard writes it to local bots.json and auto-configures Open Platform permissions.","botOnboarding.cliLabel":"CLI adapter","botOnboarding.dirLabel":"Working directory","botOnboarding.dirPlaceholder":"Default ~ (home); must exist on the daemon host","botOnboarding.modelLabel":"Model (optional)","botOnboarding.modelPlaceholder":"Leave empty for the CLI default model","botOnboarding.startScan":"Start scan","botOnboarding.cancel":"Cancel","botOnboarding.starting":"Generating QR code...","botOnboarding.waiting":"Scan with the Feishu app to create the app.","botOnboarding.verifying":"Scan accepted. Verifying credentials...","botOnboarding.configuringPermissions":"Auto-configuring Open Platform permissions\u2026","botOnboarding.platformScanHint":"Scan once more with the Feishu app to sign in to the Open Platform (to auto-import permissions, set the callback, and submit a version).","botOnboarding.platformQrAlt":"Open Platform login QR code","botOnboarding.completed":"Bot added.","botOnboarding.permissionOk":"Auto-imported {count} permissions.","botOnboarding.permissionSkipped":"({count} skipped \u2014 not in the tenant catalog)","botOnboarding.permissionVersion":"Submitted version {version}.","botOnboarding.permissionManual":"Permissions could not be auto-configured. Complete these steps manually:","botOnboarding.metaDir":"Dir","botOnboarding.failed":"Add failed","botOnboarding.openLink":"Open scan link in browser","botOnboarding.close":"Close","botOnboarding.restartHint":"bots.json has been updated. Run pnpm daemon:restart for the new bot to take effect.","botOnboarding.qrAlt":"Feishu bot onboarding QR code","overview.title":"Workbench","overview.subtitle":"Live status of your AI teammates \xB7 synced with Feishu topics","overview.team":"AI Team","overview.teamHint":"Live status of every digital teammate","overview.attention":"Needs You","overview.attentionHint":"Blocked tasks \u2014 one reply gets them moving again","overview.activeSessions":"Active Sessions","overview.activeSessionsHint":"Sessions currently running","overview.today":"Right Now","overview.todayHint":"Active session distribution","overview.viewAll":"View all \u2192","overview.botIdle":"Standing by, ready for new tasks","overview.botOffline":"Offline \u2014 daemon not running","overview.botBusy":"Working \xB7 {count} sessions","overview.botNeedsYou":"Waiting on you","overview.botReady":"Ready","overview.botOff":"Offline","overview.sessionsCount":"{count} sessions","overview.lastActive":"active {time} ago","overview.noAttention":"Nothing waiting on you","overview.teamExpand":"Show all {count} \u25BE","overview.teamCollapse":"Collapse \u25B4","strip.pending":"{count} pending","strip.longest":"waiting {time} \u2014 {bot} {reason}","strip.handle":"Handle now","overview.openSessions":"Active Sessions","overview.workingSessions":"Working","overview.onlineBots":"Online Bots","overview.schedules":"Schedules","overview.groups":"Groups Seen","overview.enabledSchedules":"Enabled","overview.total":"total","overview.active":"active","overview.daemonRegistry":"daemon registry","overview.chatMatrix":"chat matrix","overview.recentSessions":"Recent Sessions","overview.nextSchedules":"Next Runs","overview.noSessions":"No sessions yet.","overview.noSchedules":"No schedules yet.","sessions.title":"Session Control","sessions.subtitle":"Locate Feishu topics, open Web Terminal, close or resume CLI sessions.","sessions.search":"Search working dir / title / IDs","sessions.anyStatus":"Any status","sessions.adoptAny":"adopt: any","sessions.adoptYes":"adopt: yes","sessions.adoptNo":"adopt: no","sessions.activeOnly":"Active only","sessions.closeSelected":"Close selected","sessions.clearSelection":"Clear","sessions.selectedCount":"{count} sessions selected","sessions.bot":"Bot","sessions.cli":"CLI","sessions.chat":"Chat","sessions.openChat":"Open chat","sessions.status":"Status","sessions.tokenIn":"Token In","sessions.tokenOut":"Token Out","sessions.titleCol":"Title","sessions.workingDir":"Working Dir","sessions.created":"Created","sessions.last":"Last","sessions.adopt":"Adopt","sessions.actions":"Actions","sessions.details":"Details","sessions.copy":"Copy","sessions.copied":"Copied","sessions.locate":"Locate Topic","sessions.locating":"Sending...","sessions.cooldown":"Cooldown {seconds}s","sessions.openTerminal":"Terminal","sessions.writeLink":"Write Link","sessions.writeLinkHint":"Get a writable terminal link (carries a write-access token; opens in a new tab)","sessions.writeLinkFail":"Failed to get write link","sessions.close":"Close Session","sessions.resume":"Resume Session","sessions.dismiss":"Close","sessions.closeConfirm":"Close this session?","sessions.resumeFailed":"Resume failed","sessions.land":"Land","sessions.landLoading":"Loading sandbox diff\u2026","sessions.landUnavailable":"Cannot land","sessions.landEmpty":"No changes in the sandbox clone.","sessions.landApply":"Apply to disk","sessions.landDiscard":"Discard","sessions.landApplied":"Landed","sessions.landFailed":"Land failed","sessions.landDiscarded":"Discarded (sandbox clone not applied).","connectors.lede":"Let external systems (alerts, CI, tickets\u2026) trigger a bot to speak in a group or run a workflow via one webhook.","connectors.createTitle":"New Webhook","connectors.fName":"Name","connectors.fNamePh":"e.g. Prod alerts","connectors.fBot":"Trigger bot","connectors.fKind":"Trigger type","connectors.kindTurn":"Single turn (bot responds once)","connectors.kindWorkflow":"Workflow","connectors.fWf":"Workflow ID","connectors.fMode":"Deliver to which group","connectors.modeDynamic":"Specified per request (chat passed in)","connectors.modeFixed":"Fixed group","connectors.modeNewGroup":"New group each time","connectors.fFixedChat":"Target group","connectors.fChatManualPh":"Enter chat ID manually: oc_\u2026","connectors.chatManualLink":"Group not listed? Enter ID manually \u2192","connectors.chatListLink":"\u2190 Pick from group list","connectors.fAllow":"Allowed groups","connectors.optional":" (optional)","connectors.allowHint":"Hold Ctrl/\u2318 to multi-select; empty = unrestricted. Only validates the chat passed in the request.","connectors.dynamicHint":'<b>Dynamic mode</b>: the chat ID is passed per request, one of three ways \u2014 query <code>?chatId=<chatId></code> \xB7 header <code>x-botmux-chat-id: <chatId></code> \xB7 body <code>{"chatId":"<chatId>"}</code>.<br>For "one URL triggers directly, no params", choose Fixed group instead.',"connectors.fDedup":"Dedup field","connectors.fDedupPh":"e.g. alert.id (read from event body)","connectors.dedupHint":"Set: events with the same value go to the <b>same group</b>. Empty: each event <b>creates a new group</b>.","connectors.fInstruction":"Instruction","connectors.fInstructionPh":"What the bot should do on the event. e.g. Summarize the severity, @ the oncall, suggest next steps. Empty = hand the raw event to the model.","connectors.fVerify":"Verification","connectors.verifyToken":"Token (simple: secret in the URL, one curl triggers it)","connectors.verifyHmac":"HMAC signature (advanced: more secure, sign the request yourself)","connectors.fSecret":"Secret / token","connectors.fSecretPh":"Leave empty to auto-generate (shown once)","connectors.btnCreate":"Create","connectors.listTitle":"Existing Webhooks","connectors.loading":"Loading\u2026","connectors.noBotGroups":"(This bot has no visible groups; enter an ID manually on the right)","connectors.modeLabelFixed":"Fixed group","connectors.modeLabelNewGroup":"New group each time","connectors.modeLabelDynamic":"Per-request group","connectors.kindLabelWorkflow":"Workflow","connectors.kindLabelTurn":"Single turn","connectors.count":"\xB7 {count}","connectors.empty":"No webhooks yet. Create one with the form above.","connectors.enabled":"Enabled","connectors.disabled":"Disabled","connectors.badgeToken":"Token","connectors.badgeSign":"Signed","connectors.dest":'to "{name}"',"connectors.btnDisable":"Disable","connectors.btnEnable":"Enable","connectors.btnDel":"Delete","connectors.webhookUrl":"Webhook URL: ","connectors.copy":"Copy","connectors.copied":"Copied","connectors.tokenHint":"Token mode: append <code>/<token></code> to the URL when calling (the token is shown only on create/rotate).","connectors.dynamicReqHint":'Dynamic mode: the request must carry the target chat \u2014 <code>?chatId=<chatId></code> or header <code>x-botmux-chat-id</code> or body <code>{"chatId":"\u2026"}</code>.',"connectors.instructionPrefix":"Instruction: ","connectors.delConfirm":"Delete this webhook? Its URL stops working immediately.","connectors.errName":"Enter a name","connectors.errBot":"Pick a bot","connectors.errWf":"Enter a workflow ID","connectors.errChat":"Pick (or enter) a target group","connectors.creating":"Creating\u2026","connectors.usageDynamicLede":"Dynamic mode: the URL already has the token; pass the target chat ID when calling{gn}:","connectors.usageDynamicNote":'The chat can also go in header <code>x-botmux-chat-id</code> or body <code>{"chatId":"\u2026"}</code>. \u26A0\uFE0F The URL is the credential \u2014 keep it secret.',"connectors.usageTokenLede":"This URL already has the token and a fixed target group; just POST to trigger:","connectors.usageTokenNote":"\u26A0\uFE0F The URL is the credential \u2014 keep it private; delete or rotate it in the list below.","connectors.usageHmac":"The external system must HMAC-SHA256-sign <code>timestamp.body</code> and call with <code>x-botmux-timestamp</code> / <code>x-botmux-nonce</code> / <code>x-botmux-signature</code> headers","connectors.usageHmacDynamic":", and also pass the target chat ID as above","connectors.createdPrefix":'Created "{name}"',"connectors.createdDest":'to "{name}"',"connectors.tokenLabel":"Access token","connectors.signLabel":"Signing secret","connectors.secretOnce":" (shown once \u2014 save it): ","connectors.createFailed":"Create failed: {error}","connectors.noOnlineBots":"(No online bots)","team.navHome":"My team","team.navManage":"Team management","team.eyebrow":"Team","team.homeTitle":"Team collaboration (cross-deployment)","team.homeLede":"Invite other deployments (botmux instances teammates run) into one team to discover bots across deployments and pull collaborative groups.","team.localDeployTitle":"This deployment","team.myIdentity":"My Lark identity: ","team.unbound":"Not bound","team.bindBtn":"Bind","team.bindHint":" (auto-identifies you via the bot credentials; once bound, pulling a group adds you and attributes the bots to you)","team.myTeams":"My teams","team.searchPh":"Search name / capability / CLI\u2026","team.allCli":"All CLIs","team.hasCap":"Has capability tag","team.hasRole":"Has default role","team.teamsHint":"Tick bots in any team to pull them into a group (each with its owner). To create a team / generate an invite code / join another team, go to Team management.","team.loading":"Loading\u2026","team.roleModalTitle":"Default role","team.roleModalHint":"The bot default persona (applies across groups), read-only here. To edit, go to the Bot Defaults page.","team.close":"Close","team.tagLocal":"This deployment","team.tagRemoteStale":"Remote \xB7 offline?","team.tagRemote":"Remote","team.removeMember":"Remove","team.depTag":"({tag})","team.depCount":"{count}","team.depSelected":", {n} selected","team.capPh":"Capability tag\u2026","team.viewRole":"View","team.hasRoleShort":"Has role","team.noMatch":"No bots match the filters.","team.gnamePh":"Group name (e.g. cross-team triage)","team.pullGroupBtn":"Pull ticked bots into a group","team.pullGroupHint":"Tick bots \u2192 pull into a Lark group (owner included automatically)","team.noTeams":"No teams yet. Go to Team management to generate an invite code for others to join you, or join another team.","team.connected":"Connected","team.connectFail":"Connection failed: {error}","team.iHost":"I host","team.teamMeta":"{deps} deployments \xB7 {bots} bots","team.rosterFail":"Could not fetch this team roster.","team.acrossTeams":" (across {n} teams, deduped)","team.botsWord":"bots","team.groupCreated":"Group created","team.delegatedBy":' (created by "{name}")',"team.openInLark":"Open in Lark","team.invalidBots":"Bots not added: {ids}","team.invalidOwners":"{n} owner(s) could not be added","team.missingIdentity":"You have not bound a Lark identity, so you were not added to the group (bind it in My team)","team.skippedNoOwner":"{n} bot(s) skipped because their owner has no bound identity (not added)","team.errNoLocalBot":"Tick at least one of your own (this deployment) online bots \u2014 the group is created by it and adds you (the initiator).","team.errAllSkipped":"None of the selected bot owners have a bound identity, so the group cannot be pulled (a bot cannot join a group without its owner). Have those deployments bind an identity first.","team.errNoCreator":"No available group creator (the relevant deployments have no online bot, or are unreachable)","team.errDelegationTimeout":"Timed out delegating group creation to the other deployment (it may have succeeded \u2014 check Lark, do not retry)","team.errGroupCreate":"Group creation failed: {error}","team.roleModalTitleName":"Default role \xB7 {name}","team.bound":"Bound","team.myHostedTeam":"My hosted team","team.remoteTeamLabel":"{name} team","team.manageTitle":"Team management","team.manageLede":"Create multiple teams, generate an invite code per team, or join another team. A team = this deployment bots + the other deployments that joined it.","team.hostedTitle":"Teams I host","team.newTeamPh":"New team name","team.createTeamBtn":"Create team","team.joinTitle":"Join another team","team.hubPh":"Hub address, e.g. http://10.0.0.5:7891","team.codePh":"Invite code","team.joinBtn":"Join","team.noTeamsShort":"No teams yet.","team.default":"Default","team.manageMetaDeps":"{count} deployments","team.manageMetaRemote":" (incl. {r} remote)","team.manageMetaBots":"{count} bots","team.genInvite":"Generate invite code","team.delBtn":"Delete","team.generating":"Generating\u2026","team.inviteResultLede":"Send the two items below to someone on another deployment (valid once, within 24h):","team.inviteHub":"Hub address: ","team.inviteCode":"Invite code: ","team.genFail":"Generation failed.","team.delConfirm":'Delete team "{name}"? Deployments that joined it will be removed (their own deployments are unaffected).',"team.errName":"Enter a team name","team.creating":"Creating\u2026","team.created":"Created","team.createFail":"Create failed: {error}","team.errHubCode":"Enter the hub address and invite code.","team.joining":"Joining\u2026","team.joined":'Joined "{name}" \u2014 see it in My team.',"team.joinErrSelf":"This is your own deployment; you cannot join yourself (the invite code is for someone on another deployment).","team.joinErrAlready":"Your deployment already joined this team.","team.joinErrUnreachable":"Cannot reach the hub (check the address/network).","team.joinErrTimeout":"The hub timed out.","team.joinErrGeneric":"Join failed: {error}","team.identifying":"Identifying\u2026","team.bound2":"Bound: {name}","team.multiCandidate":"Multiple candidates found \u2014 click yourself:","team.binding":"Binding\u2026","team.bindFail":"Bind failed: {error}","team.noCandidates":"No identity found: make sure the bot has allowedUsers configured and contacts permission.","team.removeMemberConfirm":'Remove "{name}" from this team? Its bots disappear from this team roster (their own deployment is unaffected).',"team.creatingGroup":"Creating group\u2026","team.defaultGroupName":"Collaboration group","team.errPickBot":"Tick at least one bot first","sessions.closeBulkConfirm":"Close {count} selected sessions?","sessions.empty":"No sessions match the filters.","sessions.viewMode":"Session view","sessions.viewKanban":"Kanban","sessions.viewBoard":"Board","sessions.viewTable":"Table","sessions.selectSession":"Select session","sessions.board.needsYou":"Needs You","sessions.board.needsYouHint":"Repo, TUI, or usage limit waiting","sessions.board.starting":"Starting","sessions.board.startingHint":"CLI is spawning or resuming","sessions.board.working":"Working","sessions.board.workingHint":"Streaming, analyzing, or using tools","sessions.board.idle":"Idle","sessions.board.idleHint":"Ready for the next message","sessions.board.emptyColumn":"No sessions","sessions.board.signalRepo":"Repo needed","sessions.board.signalPrompt":"TUI choice needed","sessions.board.signalLimited":"Usage limited","sessions.board.signalAgent":"Needs human input","sessions.board.waiting":"Waiting","sessions.board.dragHint":"Drag header to reorder columns","sessions.board.moveLeft":"Move column left","sessions.board.moveRight":"Move column right","sessions.kanban.backlog":"Backlog","sessions.kanban.todo":"Todo","sessions.kanban.inProgress":"In Progress","sessions.kanban.inReview":"In Review","sessions.kanban.done":"Done","sessions.kanban.updated":"Updated {time}","sessions.kanban.moreHidden":"{count} more hidden","sessions.kanban.openTab":"Open in new tab","sessions.kanban.openFeishu":"Open in Feishu","sessions.kanban.terminalLoading":"Opening terminal\u2026","sessions.kanban.rename":"Rename (double-click title works too)","sessions.kanban.renameFail":"Rename failed","sessions.kanban.moveFail":"Move failed","sessions.kanban.groupBy":"Group by","sessions.kanban.groupFlow":"Workflow","sessions.kanban.groupTeam":"Team","sessions.kanban.groupBot":"Bots","sessions.kanban.teamLoading":"Loading teams\u2026","sessions.kanban.noTeam":"No teams","sessions.kanban.teamScope":"{chats} collab chats \xB7 {sessions} sessions","sessions.kanban.remoteHint":"Session from the {name} deployment (snapshot; terminal/history live on their machine)","sessions.kanban.clusterDragHint":"Drag header to move the whole group","sessions.history.title":"History","sessions.history.loading":"Fetching Feishu messages\u2026","sessions.history.fail":"Failed to load history","sessions.history.empty":"No messages","sessions.history.user":"User","sessions.history.owner":"Owner","sessions.history.staleHint":"The dashboard or daemon process may still run an old build \u2014 botmux restart and retry","groups.title":"Groups & Bots","groups.subtitle":"Inspect the chat x bot matrix and manage group creation, oncall, leave, and disband flows.","groups.search":"Search chat name / ID / owner","groups.missingOnly":"Missing bot only","groups.refresh":"Refresh","groups.create":"New Group","groups.chat":"Chat","groups.actions":"Actions","groups.addBots":"Add Bots","groups.manage":"Manage","groups.empty":"No chats match the filters.","groups.createTitle":"Create New Group","groups.createHelp":"Pick bots to invite. The dashboard chooses an online daemon as creator.","groups.name":"Group Name","groups.namePlaceholder":"e.g. AI ChangeLog","groups.bindDir":"Bind Directory","groups.bindDirHelp":"New topics start the CLI here and skip repo selection.","groups.botPicker":"Bots","groups.createSubmit":"Create","groups.cancel":"Cancel","groups.successTitle":"Group Created","groups.openGroup":"Open Group","groups.manageTitle":"Manage {name}","groups.owner":"Owner","groups.oncall":"Oncall Mode","groups.oncallHelp":"When enabled, group members can @ the bot; new topics use the bound directory.","groups.leaveTitle":"Select Bots to Leave","groups.leaveSelected":"Selected Bots Leave","groups.disband":"Disband Group","groups.dangerHint":"Disband only works when an in-chat bot is the owner. Otherwise prefer leaving the chat.","groups.save":"Save","groups.needWorkingDir":"Working directory is required","groups.noBotsOnline":"No bots online. Restart the daemon first.","schedules.title":"Schedules","schedules.subtitle":"View, pause, resume, and run scheduled tasks across daemons.","schedules.search":"Search name / prompt / working dir","schedules.anyKind":"Any kind","schedules.enabledOnly":"Enabled only","schedules.name":"Name","schedules.bot":"Bot","schedules.schedule":"Schedule","schedules.next":"Next","schedules.last":"Last","schedules.repeat":"Repeat","schedules.enabled":"Enabled","schedules.actions":"Actions","schedules.runNow":"Run Now","schedules.pause":"Pause","schedules.resume":"Resume","schedules.empty":"No schedules.","settings.title":"Global Settings","settings.subtitle":"Manage machine-wide botmux dashboard behavior shared by every bot.","settings.loading":"Loading settings\u2026","settings.loadFailed":"Failed to load settings","settings.readOnlyVisitor":"Read-only access \u2014 changing settings requires an authorized link (run botmux dashboard).","settings.sectionAccess":"Access","settings.publicReadOnly":"Allow tokenless read-only dashboard access","settings.publicReadOnlyHelp":"When enabled, visitors without a token can view the dashboard, sessions, schedules, and SSE. Writes such as close, pause, and approvals still require token auth. Sensitive raw terminal logs always require a token.","settings.sectionCards":"Feishu Cards","settings.openTerminalInFeishu":"Open streaming-card terminals in the Feishu sidebar","settings.openTerminalInFeishuHelp":"Off by default: terminal buttons open the Web Terminal URL directly. When enabled, botmux wraps the URL with Feishu web_url/open so Feishu PC opens it in a sidebar. Terminal write access is still controlled by its token.","settings.sectionRepoPicker":"Repo Picker","settings.repoPickerMode":"Repo picker card mode","settings.repoPickerModeAll":"Repos + worktrees","settings.repoPickerModeRepos":"Main repos only","settings.repoPickerModeHelp":"Default shows repositories and linked worktrees. Main repos only hides linked worktrees from initialization and bare /repo cards; explicit /repo /abs/path/to/worktree still works.","settings.saving":"Saving\u2026","settings.saved":"Saved","settings.saveFailed":"Save failed","settings.sectionMaintenance":"Auto Maintenance","settings.autoUpdate":"Auto update","settings.autoUpdateHelp":"Off by default. At the set time, runs npm install -g botmux@latest to install the latest version (download/install only \u2014 no restart). npm-global installs only.","settings.autoRestart":"Auto restart","settings.autoRestartHelp":"Off by default; requires auto-update. After auto-update installs a newer version, restart to apply it if no session is in progress (busy \u21D2 slips to the next day).","settings.autoUpdateLocalDev":"This is a local-dev install (running from source); auto-update is unavailable.","settings.maintenanceTime":"Time","botDefaults.title":"Bot Profiles","botDefaults.subtitle":"Per-bot defaults: oncall, proactive start, persona role, cards and grants.","botDefaults.metaOnline":"Online \xB7 daemon healthy","botDefaults.search":"Search bot name / app id","botDefaults.refresh":"Refresh","botDefaults.sectionOncall":"New-chat Oncall","botDefaults.sectionBrand":"Card Signature","botDefaults.warning":"When enabled, chats without an oncall binding auto-bind to this directory on their next new topic. Manually bound or unbound chats are preserved.","botDefaults.empty":"No bots online. Run botmux restart first.","botDefaults.defaultOncall":"Default to oncall mode","botDefaults.defaultOncallHelp":"Unbound chats auto-bind on the next new topic","botDefaults.workingDir":"Default Working Directory","botDefaults.lastEnabled":"Last Enabled","botDefaults.autobound":"{count} chats auto-bound","botDefaults.save":"Save","botDefaults.required":"Working directory is required when enabled","botDefaults.brandLabel":"Signature (card footer)","botDefaults.brandLabelHelp":"Footer signature on cards this bot sends. Save empty = hide; fill in = custom (markdown ok, e.g. [Acme](https://\u2026)); Reset = show botmux.","botDefaults.brandLabelPlaceholder":"Default: botmux (empty = hidden)","botDefaults.sectionSandbox":"File sandbox (oncall)","botDefaults.sandboxToggle":"Enable file sandbox","botDefaults.sandboxHelp":"When on, every session of this bot runs in a per-session sandbox: only a project copy is visible \u2014 your real files, secrets, and other sessions are not. For sharing the bot with semi-trusted users (oncall). Linux only; applies to the next new session.","botDefaults.sandboxSaved":"Saved (applies to the next new session)","botDefaults.brandSave":"Save Signature","botDefaults.brandReset":"Reset to default","botDefaults.brandStateDefault":"Current: default botmux","botDefaults.brandStateOff":"Current: off","botDefaults.brandStateCustom":"Current: custom","botDefaults.sectionCard":"Card Behavior","botDefaults.disableStreaming":"Disable streaming card","botDefaults.disableStreamingHelp":"Stop posting the live session status card (and its Open Terminal entry). The task's final result still arrives as a message. For those who find the live card noisy.","botDefaults.writableLink":"Put a writable terminal link on the card","botDefaults.writableLinkHelp":'\u26A0\uFE0F Embeds a writable terminal link in the streaming card body \u2014 anyone in the chat can open and drive the terminal. Off = current behavior (private DM via the "Get Write Link" button).',"botDefaults.writableLinkMoot":"Streaming card disabled \u2014 this has no effect","botDefaults.privateCard":"/card sends a private card (authorized users only)","botDefaults.privateCardHelp":'Makes /card send an ephemeral "visible-to-specific-people" card: delivered only to the owner (allowedUsers); /grant-authorized talk users and everyone else in the chat cannot see it. Trade-off: it is a static snapshot (no live updates) and only works in regular group chats (topic groups / DMs fail, with no fallback). Affects only the /card command; the auto streaming card is unchanged.',"botDefaults.cardPrefSaved":"Saved","botDefaults.sectionRole":"Default Role","botDefaults.roleHelp":"This bot's default persona (applies across all chats), injected into the bot's sessions in every chat; a single group can override it on the Roles page. Save empty = delete.","botDefaults.rolePlaceholder":"e.g. You are a backend triage assistant; answer concisely, prefer runnable commands\u2026","botDefaults.roleSave":"Save role","botDefaults.roleDelete":"Delete","botDefaults.roleSaved":"Saved","botDefaults.roleDeleted":"Deleted","botDefaults.roleLoadErr":"Failed to load role","botDefaults.sectionAutoStart":"Proactive Start","botDefaults.autoStartJoin":"Auto-start when added to a new chat","botDefaults.autoStartJoinHelp":'When enabled, the bot auto-starts a session and gets to work the moment it is added to a new chat (when an authorized user / allowedUsers is a member), no @ needed. It launches in the bot default working dir; if none is configured it shows a repo-select card first. Prerequisite: subscribe the "bot joined chat" event im.chat.member.bot.added_v1 for this app and grant the member-read scope in the Feishu console.',"botDefaults.autoStartJoinPrompt":"First-turn prompt on join (optional)","botDefaults.autoStartJoinPromptPlaceholder":"Filled = used as the first task after joining; blank = the bot reads the chat and decides what to do","botDefaults.autoStartJoinPromptSave":"Save prompt","botDefaults.autoStartTopic":"Auto-start on new topics in topic groups","botDefaults.autoStartTopicHelp":"When enabled, in a topic group the bot automatically joins each newly opened topic and starts working on its first message, no @ needed. Topic groups only \u2014 regular groups are unaffected.","botDefaults.sectionSessionMode":"Session mode","botDefaults.p2pMode":"Private chat session mode","botDefaults.p2pThread":"thread (separate session per DM)","botDefaults.p2pChat":"chat (flat continuous session)","botDefaults.p2pHelp":"How 1:1 DMs are sessioned: thread = each top-level message starts its own session (keeps chatter out of one CLI process); chat = the whole DM shares one continuous session and context (Hermes-like). Takes effect immediately.","botDefaults.regularGroupMode":"Regular group session mode","botDefaults.regularGroupModeChat":"chat (flat continuous session, default)","botDefaults.regularGroupModeNewTopic":"new-topic (each top-level @ opens its own topic & session)","botDefaults.regularGroupModeShared":"shared (topic display, reusing one session)","botDefaults.regularGroupModeHelp":"How new top-level @mentions in regular (non-topic) groups are sessioned: chat = the whole group shares one continuous session (default); new-topic = each top-level @ opens its own topic with a separate session; shared = topic display but reuse the same session (replies fold into a topic yet share the group session & context). This is the per-bot default; a specific group can override it via /reply-mode. Takes effect immediately.","botDefaults.mentionMode":"Group @ policy","botDefaults.mentionModeAlways":"Always require @ (default)","botDefaults.mentionModeTopic":"No @ needed inside topics","botDefaults.mentionModeNever":"Never require @","botDefaults.mentionModeHelp":'Bot-global: controls when an @ is required to get a reply in groups. "Always require @" = every message needs an @ (default, safest; inside topics too, in multi-person groups); "No @ needed inside topics" = starting a new conversation / top-level still needs @, but follow-ups inside ANY topic this bot already drives (new-topic / shared / topic-group) continue without @; "Never require @" = non-@ messages are answered too wherever the bot has talk access (including cold-starting on a brand-new message \u2014 only suitable for dedicated / on-call small groups; in busy multi-person groups it replies to everything). Note: when you are alone with this bot (1:1) replies never need an @, independent of this setting.',"botDefaults.docSubscribeMode":"Doc subscription trigger (default)","botDefaults.docSubscribeModeMention":"Only when a comment @s me","botDefaults.docSubscribeModeAll":"Every new comment","botDefaults.docSubscribeModeHelp":'After subscribing to a Feishu doc with /subscribe-lark-doc, its comments feed into the session and the bot replies back into the comment. This sets the default trigger range for new subscriptions: "only when a comment @s me" is safest (avoids noise); "every new comment" suits dedicated docs.',"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"},us={"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.modelTtadkPlaceholder":"ttadk gateway model, default {model}, editable anytime","botOnboarding.modelTtadkCocoPlaceholder":"CoCo needs no model","botOnboarding.startScan":"Start scan","botOnboarding.cancel":"Cancel","botOnboarding.starting":"Generating QR code...","botOnboarding.waiting":"Scan with the Feishu app to create the app.","botOnboarding.verifying":"Scan accepted. Verifying credentials...","botOnboarding.configuringPermissions":"Auto-configuring Open Platform permissions\u2026","botOnboarding.platformScanHint":"Scan once more with the Feishu app to sign in to the Open Platform (to auto-import permissions, set the callback, and submit a version).","botOnboarding.platformQrAlt":"Open Platform login QR code","botOnboarding.completed":"Bot added.","botOnboarding.permissionOk":"Auto-imported {count} permissions.","botOnboarding.permissionSkipped":"({count} skipped \u2014 not in the tenant catalog)","botOnboarding.permissionVersion":"Submitted version {version}.","botOnboarding.permissionManual":"Permissions could not be auto-configured. Complete these steps manually:","botOnboarding.metaDir":"Dir","botOnboarding.failed":"Add failed","botOnboarding.openLink":"Open scan link in browser","botOnboarding.close":"Close","botOnboarding.restartHint":"bots.json has been updated. Run pnpm daemon:restart for the new bot to take effect.","botOnboarding.qrAlt":"Feishu bot onboarding QR code","overview.title":"Workbench","overview.subtitle":"Live status of your AI teammates \xB7 synced with Feishu topics","overview.team":"AI Team","overview.teamHint":"Live status of every digital teammate","overview.attention":"Needs You","overview.attentionHint":"Blocked tasks \u2014 one reply gets them moving again","overview.activeSessions":"Active Sessions","overview.activeSessionsHint":"Sessions currently running","overview.today":"Right Now","overview.todayHint":"Active session distribution","overview.viewAll":"View all \u2192","overview.botIdle":"Standing by, ready for new tasks","overview.botOffline":"Offline \u2014 daemon not running","overview.botBusy":"Working \xB7 {count} sessions","overview.botNeedsYou":"Waiting on you","overview.botReady":"Ready","overview.botOff":"Offline","overview.sessionsCount":"{count} sessions","overview.lastActive":"active {time} ago","overview.noAttention":"Nothing waiting on you","overview.teamExpand":"Show all {count} \u25BE","overview.teamCollapse":"Collapse \u25B4","strip.pending":"{count} pending","strip.longest":"waiting {time} \u2014 {bot} {reason}","strip.handle":"Handle now","overview.openSessions":"Active Sessions","overview.workingSessions":"Working","overview.onlineBots":"Online Bots","overview.schedules":"Schedules","overview.groups":"Groups Seen","overview.enabledSchedules":"Enabled","overview.total":"total","overview.active":"active","overview.daemonRegistry":"daemon registry","overview.chatMatrix":"chat matrix","overview.recentSessions":"Recent Sessions","overview.nextSchedules":"Next Runs","overview.noSessions":"No sessions yet.","overview.noSchedules":"No schedules yet.","sessions.title":"Session Control","sessions.subtitle":"Locate Feishu topics, open Web Terminal, close or resume CLI sessions.","sessions.search":"Search working dir / title / IDs","sessions.anyStatus":"Any status","sessions.adoptAny":"adopt: any","sessions.adoptYes":"adopt: yes","sessions.adoptNo":"adopt: no","sessions.activeOnly":"Active only","sessions.closeSelected":"Close selected","sessions.clearSelection":"Clear","sessions.selectedCount":"{count} sessions selected","sessions.bot":"Bot","sessions.cli":"CLI","sessions.chat":"Chat","sessions.openChat":"Open chat","sessions.status":"Status","sessions.tokenIn":"Token In","sessions.tokenOut":"Token Out","sessions.titleCol":"Title","sessions.workingDir":"Working Dir","sessions.created":"Created","sessions.last":"Last","sessions.adopt":"Adopt","sessions.actions":"Actions","sessions.details":"Details","sessions.copy":"Copy","sessions.copied":"Copied","sessions.locate":"Locate Topic","sessions.locating":"Sending...","sessions.cooldown":"Cooldown {seconds}s","sessions.openTerminal":"Terminal","sessions.writeLink":"Write Link","sessions.writeLinkHint":"Get a writable terminal link (carries a write-access token; opens in a new tab)","sessions.writeLinkFail":"Failed to get write link","sessions.close":"Close Session","sessions.resume":"Resume Session","sessions.dismiss":"Close","sessions.closeConfirm":"Close this session?","sessions.resumeFailed":"Resume failed","sessions.land":"Land","sessions.landLoading":"Loading sandbox diff\u2026","sessions.landUnavailable":"Cannot land","sessions.landEmpty":"No changes in the sandbox clone.","sessions.landApply":"Apply to disk","sessions.landDiscard":"Discard","sessions.landApplied":"Landed","sessions.landFailed":"Land failed","sessions.landDiscarded":"Discarded (sandbox clone not applied).","connectors.lede":"Let external systems (alerts, CI, tickets\u2026) trigger a bot to speak in a group or run a workflow via one webhook.","connectors.createTitle":"New Webhook","connectors.fName":"Name","connectors.fNamePh":"e.g. Prod alerts","connectors.fBot":"Trigger bot","connectors.fKind":"Trigger type","connectors.kindTurn":"Single turn (bot responds once)","connectors.kindWorkflow":"Workflow","connectors.fWf":"Workflow ID","connectors.fMode":"Deliver to which group","connectors.modeDynamic":"Specified per request (chat passed in)","connectors.modeFixed":"Fixed group","connectors.modeNewGroup":"New group each time","connectors.fFixedChat":"Target group","connectors.fChatManualPh":"Enter chat ID manually: oc_\u2026","connectors.chatManualLink":"Group not listed? Enter ID manually \u2192","connectors.chatListLink":"\u2190 Pick from group list","connectors.fAllow":"Allowed groups","connectors.optional":" (optional)","connectors.allowHint":"Hold Ctrl/\u2318 to multi-select; empty = unrestricted. Only validates the chat passed in the request.","connectors.dynamicHint":'<b>Dynamic mode</b>: the chat ID is passed per request, one of three ways \u2014 query <code>?chatId=<chatId></code> \xB7 header <code>x-botmux-chat-id: <chatId></code> \xB7 body <code>{"chatId":"<chatId>"}</code>.<br>For "one URL triggers directly, no params", choose Fixed group instead.',"connectors.fDedup":"Dedup field","connectors.fDedupPh":"e.g. alert.id (read from event body)","connectors.dedupHint":"Set: events with the same value go to the <b>same group</b>. Empty: each event <b>creates a new group</b>.","connectors.fInstruction":"Instruction","connectors.fInstructionPh":"What the bot should do on the event. e.g. Summarize the severity, @ the oncall, suggest next steps. Empty = hand the raw event to the model.","connectors.fVerify":"Verification","connectors.verifyToken":"Token (simple: secret in the URL, one curl triggers it)","connectors.verifyHmac":"HMAC signature (advanced: more secure, sign the request yourself)","connectors.fSecret":"Secret / token","connectors.fSecretPh":"Leave empty to auto-generate (shown once)","connectors.btnCreate":"Create","connectors.listTitle":"Existing Webhooks","connectors.loading":"Loading\u2026","connectors.noBotGroups":"(This bot has no visible groups; enter an ID manually on the right)","connectors.modeLabelFixed":"Fixed group","connectors.modeLabelNewGroup":"New group each time","connectors.modeLabelDynamic":"Per-request group","connectors.kindLabelWorkflow":"Workflow","connectors.kindLabelTurn":"Single turn","connectors.count":"\xB7 {count}","connectors.empty":"No webhooks yet. Create one with the form above.","connectors.enabled":"Enabled","connectors.disabled":"Disabled","connectors.badgeToken":"Token","connectors.badgeSign":"Signed","connectors.dest":'to "{name}"',"connectors.btnDisable":"Disable","connectors.btnEnable":"Enable","connectors.btnDel":"Delete","connectors.webhookUrl":"Webhook URL: ","connectors.copy":"Copy","connectors.copied":"Copied","connectors.tokenHint":"Token mode: append <code>/<token></code> to the URL when calling (the token is shown only on create/rotate).","connectors.dynamicReqHint":'Dynamic mode: the request must carry the target chat \u2014 <code>?chatId=<chatId></code> or header <code>x-botmux-chat-id</code> or body <code>{"chatId":"\u2026"}</code>.',"connectors.instructionPrefix":"Instruction: ","connectors.delConfirm":"Delete this webhook? Its URL stops working immediately.","connectors.errName":"Enter a name","connectors.errBot":"Pick a bot","connectors.errWf":"Enter a workflow ID","connectors.errChat":"Pick (or enter) a target group","connectors.creating":"Creating\u2026","connectors.usageDynamicLede":"Dynamic mode: the URL already has the token; pass the target chat ID when calling{gn}:","connectors.usageDynamicNote":'The chat can also go in header <code>x-botmux-chat-id</code> or body <code>{"chatId":"\u2026"}</code>. \u26A0\uFE0F The URL is the credential \u2014 keep it secret.',"connectors.usageTokenLede":"This URL already has the token and a fixed target group; just POST to trigger:","connectors.usageTokenNote":"\u26A0\uFE0F The URL is the credential \u2014 keep it private; delete or rotate it in the list below.","connectors.usageHmac":"The external system must HMAC-SHA256-sign <code>timestamp.body</code> and call with <code>x-botmux-timestamp</code> / <code>x-botmux-nonce</code> / <code>x-botmux-signature</code> headers","connectors.usageHmacDynamic":", and also pass the target chat ID as above","connectors.createdPrefix":'Created "{name}"',"connectors.createdDest":'to "{name}"',"connectors.tokenLabel":"Access token","connectors.signLabel":"Signing secret","connectors.secretOnce":" (shown once \u2014 save it): ","connectors.createFailed":"Create failed: {error}","connectors.noOnlineBots":"(No online bots)","team.navHome":"My team","team.navManage":"Team management","team.eyebrow":"Team","team.homeTitle":"Team collaboration (cross-deployment)","team.homeLede":"Invite other deployments (botmux instances teammates run) into one team to discover bots across deployments and pull collaborative groups.","team.localDeployTitle":"This deployment","team.myIdentity":"My Lark identity: ","team.unbound":"Not bound","team.bindBtn":"Bind","team.bindHint":" (auto-identifies you via the bot credentials; once bound, pulling a group adds you and attributes the bots to you)","team.myTeams":"My teams","team.searchPh":"Search name / capability / CLI\u2026","team.allCli":"All CLIs","team.hasCap":"Has capability tag","team.hasRole":"Has default role","team.teamsHint":"Tick bots in any team to pull them into a group (each with its owner). To create a team / generate an invite code / join another team, go to Team management.","team.loading":"Loading\u2026","team.roleModalTitle":"Default role","team.roleModalHint":"The bot default persona (applies across groups), read-only here. To edit, go to the Bot Defaults page.","team.close":"Close","team.tagLocal":"This deployment","team.tagRemoteStale":"Remote \xB7 offline?","team.tagRemote":"Remote","team.removeMember":"Remove","team.depTag":"({tag})","team.depCount":"{count}","team.depSelected":", {n} selected","team.capPh":"Capability tag\u2026","team.viewRole":"View","team.hasRoleShort":"Has role","team.noMatch":"No bots match the filters.","team.gnamePh":"Group name (e.g. cross-team triage)","team.pullGroupBtn":"Pull ticked bots into a group","team.pullGroupHint":"Tick bots \u2192 pull into a Lark group (owner included automatically)","team.noTeams":"No teams yet. Go to Team management to generate an invite code for others to join you, or join another team.","team.connected":"Connected","team.connectFail":"Connection failed: {error}","team.iHost":"I host","team.teamMeta":"{deps} deployments \xB7 {bots} bots","team.rosterFail":"Could not fetch this team roster.","team.acrossTeams":" (across {n} teams, deduped)","team.botsWord":"bots","team.groupCreated":"Group created","team.delegatedBy":' (created by "{name}")',"team.openInLark":"Open in Lark","team.invalidBots":"Bots not added: {ids}","team.invalidOwners":"{n} owner(s) could not be added","team.missingIdentity":"You have not bound a Lark identity, so you were not added to the group (bind it in My team)","team.skippedNoOwner":"{n} bot(s) skipped because their owner has no bound identity (not added)","team.errNoLocalBot":"Tick at least one of your own (this deployment) online bots \u2014 the group is created by it and adds you (the initiator).","team.errAllSkipped":"None of the selected bot owners have a bound identity, so the group cannot be pulled (a bot cannot join a group without its owner). Have those deployments bind an identity first.","team.errNoCreator":"No available group creator (the relevant deployments have no online bot, or are unreachable)","team.errDelegationTimeout":"Timed out delegating group creation to the other deployment (it may have succeeded \u2014 check Lark, do not retry)","team.errGroupCreate":"Group creation failed: {error}","team.roleModalTitleName":"Default role \xB7 {name}","team.bound":"Bound","team.myHostedTeam":"My hosted team","team.remoteTeamLabel":"{name} team","team.manageTitle":"Team management","team.manageLede":"Create multiple teams, generate an invite code per team, or join another team. A team = this deployment bots + the other deployments that joined it.","team.hostedTitle":"Teams I host","team.newTeamPh":"New team name","team.createTeamBtn":"Create team","team.joinTitle":"Join another team","team.hubPh":"Hub address, e.g. http://10.0.0.5:7891","team.codePh":"Invite code","team.joinBtn":"Join","team.noTeamsShort":"No teams yet.","team.default":"Default","team.manageMetaDeps":"{count} deployments","team.manageMetaRemote":" (incl. {r} remote)","team.manageMetaBots":"{count} bots","team.genInvite":"Generate invite code","team.delBtn":"Delete","team.generating":"Generating\u2026","team.inviteResultLede":"Send the two items below to someone on another deployment (valid once, within 24h):","team.inviteHub":"Hub address: ","team.inviteCode":"Invite code: ","team.genFail":"Generation failed.","team.delConfirm":'Delete team "{name}"? Deployments that joined it will be removed (their own deployments are unaffected).',"team.errName":"Enter a team name","team.creating":"Creating\u2026","team.created":"Created","team.createFail":"Create failed: {error}","team.errHubCode":"Enter the hub address and invite code.","team.joining":"Joining\u2026","team.joined":'Joined "{name}" \u2014 see it in My team.',"team.joinErrSelf":"This is your own deployment; you cannot join yourself (the invite code is for someone on another deployment).","team.joinErrAlready":"Your deployment already joined this team.","team.joinErrUnreachable":"Cannot reach the hub (check the address/network).","team.joinErrTimeout":"The hub timed out.","team.joinErrGeneric":"Join failed: {error}","team.identifying":"Identifying\u2026","team.bound2":"Bound: {name}","team.multiCandidate":"Multiple candidates found \u2014 click yourself:","team.binding":"Binding\u2026","team.bindFail":"Bind failed: {error}","team.noCandidates":"No identity found: make sure the bot has allowedUsers configured and contacts permission.","team.removeMemberConfirm":'Remove "{name}" from this team? Its bots disappear from this team roster (their own deployment is unaffected).',"team.creatingGroup":"Creating group\u2026","team.defaultGroupName":"Collaboration group","team.errPickBot":"Tick at least one bot first","sessions.closeBulkConfirm":"Close {count} selected sessions?","sessions.empty":"No sessions match the filters.","sessions.viewMode":"Session view","sessions.viewKanban":"Kanban","sessions.viewBoard":"Board","sessions.viewTable":"Table","sessions.selectSession":"Select session","sessions.board.needsYou":"Needs You","sessions.board.needsYouHint":"Repo, TUI, or usage limit waiting","sessions.board.starting":"Starting","sessions.board.startingHint":"CLI is spawning or resuming","sessions.board.working":"Working","sessions.board.workingHint":"Streaming, analyzing, or using tools","sessions.board.idle":"Idle","sessions.board.idleHint":"Ready for the next message","sessions.board.emptyColumn":"No sessions","sessions.board.signalRepo":"Repo needed","sessions.board.signalPrompt":"TUI choice needed","sessions.board.signalLimited":"Usage limited","sessions.board.signalAgent":"Needs human input","sessions.board.waiting":"Waiting","sessions.board.dragHint":"Drag header to reorder columns","sessions.board.moveLeft":"Move column left","sessions.board.moveRight":"Move column right","sessions.kanban.backlog":"Backlog","sessions.kanban.todo":"Todo","sessions.kanban.inProgress":"In Progress","sessions.kanban.inReview":"In Review","sessions.kanban.done":"Done","sessions.kanban.updated":"Updated {time}","sessions.kanban.moreHidden":"{count} more hidden","sessions.kanban.openTab":"Open in new tab","sessions.kanban.openFeishu":"Open in Feishu","sessions.kanban.terminalLoading":"Opening terminal\u2026","sessions.kanban.rename":"Rename (double-click title works too)","sessions.kanban.renameFail":"Rename failed","sessions.kanban.moveFail":"Move failed","sessions.kanban.groupBy":"Group by","sessions.kanban.groupFlow":"Workflow","sessions.kanban.groupTeam":"Team","sessions.kanban.groupBot":"Bots","sessions.kanban.teamLoading":"Loading teams\u2026","sessions.kanban.noTeam":"No teams","sessions.kanban.teamScope":"{chats} collab chats \xB7 {sessions} sessions","sessions.kanban.remoteHint":"Session from the {name} deployment (snapshot; terminal/history live on their machine)","sessions.kanban.clusterDragHint":"Drag header to move the whole group","sessions.history.title":"History","sessions.history.loading":"Fetching Feishu messages\u2026","sessions.history.fail":"Failed to load history","sessions.history.empty":"No messages","sessions.history.user":"User","sessions.history.owner":"Owner","sessions.history.staleHint":"The dashboard or daemon process may still run an old build \u2014 botmux restart and retry","groups.title":"Groups & Bots","groups.subtitle":"Inspect the chat x bot matrix and manage group creation, oncall, leave, and disband flows.","groups.search":"Search chat name / ID / owner","groups.missingOnly":"Missing bot only","groups.refresh":"Refresh","groups.create":"New Group","groups.chat":"Chat","groups.actions":"Actions","groups.addBots":"Add Bots","groups.manage":"Manage","groups.empty":"No chats match the filters.","groups.createTitle":"Create New Group","groups.createHelp":"Pick bots to invite. The dashboard chooses an online daemon as creator.","groups.name":"Group Name","groups.namePlaceholder":"e.g. AI ChangeLog","groups.bindDir":"Bind Directory","groups.bindDirHelp":"New topics start the CLI here and skip repo selection.","groups.botPicker":"Bots","groups.createSubmit":"Create","groups.cancel":"Cancel","groups.successTitle":"Group Created","groups.openGroup":"Open Group","groups.manageTitle":"Manage {name}","groups.owner":"Owner","groups.oncall":"Oncall Mode","groups.oncallHelp":"When enabled, group members can @ the bot; new topics use the bound directory.","groups.leaveTitle":"Select Bots to Leave","groups.leaveSelected":"Selected Bots Leave","groups.disband":"Disband Group","groups.dangerHint":"Disband only works when an in-chat bot is the owner. Otherwise prefer leaving the chat.","groups.save":"Save","groups.needWorkingDir":"Working directory is required","groups.noBotsOnline":"No bots online. Restart the daemon first.","schedules.title":"Schedules","schedules.subtitle":"View, pause, resume, and run scheduled tasks across daemons.","schedules.search":"Search name / prompt / working dir","schedules.anyKind":"Any kind","schedules.enabledOnly":"Enabled only","schedules.name":"Name","schedules.bot":"Bot","schedules.schedule":"Schedule","schedules.next":"Next","schedules.last":"Last","schedules.repeat":"Repeat","schedules.enabled":"Enabled","schedules.actions":"Actions","schedules.runNow":"Run Now","schedules.pause":"Pause","schedules.resume":"Resume","schedules.empty":"No schedules.","settings.title":"Global Settings","settings.subtitle":"Manage machine-wide botmux dashboard behavior shared by every bot.","settings.loading":"Loading settings\u2026","settings.loadFailed":"Failed to load settings","settings.readOnlyVisitor":"Read-only access \u2014 changing settings requires an authorized link (run botmux dashboard).","settings.sectionAccess":"Access","settings.publicReadOnly":"Allow tokenless read-only dashboard access","settings.publicReadOnlyHelp":"When enabled, visitors without a token can view the dashboard, sessions, schedules, and SSE. Writes such as close, pause, and approvals still require token auth. Sensitive raw terminal logs always require a token.","settings.sectionCards":"Feishu Cards","settings.openTerminalInFeishu":"Open streaming-card terminals in the Feishu sidebar","settings.openTerminalInFeishuHelp":"Off by default: terminal buttons open the Web Terminal URL directly. When enabled, botmux wraps the URL with Feishu web_url/open so Feishu PC opens it in a sidebar. Terminal write access is still controlled by its token.","settings.sectionRepoPicker":"Repo Picker","settings.repoPickerMode":"Repo picker card mode","settings.repoPickerModeAll":"Repos + worktrees","settings.repoPickerModeRepos":"Main repos only","settings.repoPickerModeHelp":"Default shows repositories and linked worktrees. Main repos only hides linked worktrees from initialization and bare /repo cards; explicit /repo /abs/path/to/worktree still works.","settings.saving":"Saving\u2026","settings.saved":"Saved","settings.saveFailed":"Save failed","settings.sectionMaintenance":"Auto Maintenance","settings.autoUpdate":"Auto update","settings.autoUpdateHelp":"Off by default. At the set time, runs npm install -g botmux@latest to install the latest version (download/install only \u2014 no restart). npm-global installs only.","settings.autoRestart":"Auto restart","settings.autoRestartHelp":"Off by default; requires auto-update. After auto-update installs a newer version, restart to apply it if no session is in progress (busy \u21D2 slips to the next day).","settings.autoUpdateLocalDev":"This is a local-dev install (running from source); auto-update is unavailable.","settings.maintenanceTime":"Time","botDefaults.title":"Bot Profiles","botDefaults.subtitle":"Per-bot defaults: oncall, proactive start, persona role, cards and grants.","botDefaults.metaOnline":"Online \xB7 daemon healthy","botDefaults.search":"Search bot name / app id","botDefaults.refresh":"Refresh","botDefaults.sectionOncall":"New-chat Oncall","botDefaults.sectionBrand":"Card Signature","botDefaults.warning":"When enabled, chats without an oncall binding auto-bind to this directory on their next new topic. Manually bound or unbound chats are preserved.","botDefaults.empty":"No bots online. Run botmux restart first.","botDefaults.defaultOncall":"Default to oncall mode","botDefaults.defaultOncallHelp":"Unbound chats auto-bind on the next new topic","botDefaults.workingDir":"Default Working Directory","botDefaults.lastEnabled":"Last Enabled","botDefaults.autobound":"{count} chats auto-bound","botDefaults.save":"Save","botDefaults.required":"Working directory is required when enabled","botDefaults.brandLabel":"Signature (card footer)","botDefaults.brandLabelHelp":"Footer signature on cards this bot sends. Save empty = hide; fill in = custom (markdown ok, e.g. [Acme](https://\u2026)); Reset = show botmux.","botDefaults.brandLabelPlaceholder":"Default: botmux (empty = hidden)","botDefaults.sectionSandbox":"File sandbox (oncall)","botDefaults.sandboxToggle":"Enable file sandbox","botDefaults.sandboxHelp":"When on, every session of this bot runs in a per-session sandbox: only a project copy is visible \u2014 your real files, secrets, and other sessions are not. For sharing the bot with semi-trusted users (oncall). Linux only; applies to the next new session.","botDefaults.sandboxSaved":"Saved (applies to the next new session)","botDefaults.brandSave":"Save Signature","botDefaults.brandReset":"Reset to default","botDefaults.brandStateDefault":"Current: default botmux","botDefaults.brandStateOff":"Current: off","botDefaults.brandStateCustom":"Current: custom","botDefaults.sectionCard":"Card Behavior","botDefaults.disableStreaming":"Disable streaming card","botDefaults.disableStreamingHelp":"Stop posting the live session status card (and its Open Terminal entry). The task's final result still arrives as a message. For those who find the live card noisy.","botDefaults.writableLink":"Put a writable terminal link on the card","botDefaults.writableLinkHelp":'\u26A0\uFE0F Embeds a writable terminal link in the streaming card body \u2014 anyone in the chat can open and drive the terminal. Off = current behavior (private DM via the "Get Write Link" button).',"botDefaults.writableLinkMoot":"Streaming card disabled \u2014 this has no effect","botDefaults.privateCard":"/card sends a private card (authorized users only)","botDefaults.privateCardHelp":'Makes /card send an ephemeral "visible-to-specific-people" card: delivered only to the owner (allowedUsers); /grant-authorized talk users and everyone else in the chat cannot see it. Trade-off: it is a static snapshot (no live updates) and only works in regular group chats (topic groups / DMs fail, with no fallback). Affects only the /card command; the auto streaming card is unchanged.',"botDefaults.cardPrefSaved":"Saved","botDefaults.sectionRole":"Default Role","botDefaults.roleHelp":"This bot's default persona (applies across all chats), injected into the bot's sessions in every chat; a single group can override it on the Roles page. Save empty = delete.","botDefaults.rolePlaceholder":"e.g. You are a backend triage assistant; answer concisely, prefer runnable commands\u2026","botDefaults.roleSave":"Save role","botDefaults.roleDelete":"Delete","botDefaults.roleSaved":"Saved","botDefaults.roleDeleted":"Deleted","botDefaults.roleLoadErr":"Failed to load role","botDefaults.sectionAutoStart":"Proactive Start","botDefaults.autoStartJoin":"Auto-start when added to a new chat","botDefaults.autoStartJoinHelp":'When enabled, the bot auto-starts a session and gets to work the moment it is added to a new chat (when an authorized user / allowedUsers is a member), no @ needed. It launches in the bot default working dir; if none is configured it shows a repo-select card first. Prerequisite: subscribe the "bot joined chat" event im.chat.member.bot.added_v1 for this app and grant the member-read scope in the Feishu console.',"botDefaults.autoStartJoinPrompt":"First-turn prompt on join (optional)","botDefaults.autoStartJoinPromptPlaceholder":"Filled = used as the first task after joining; blank = the bot reads the chat and decides what to do","botDefaults.autoStartJoinPromptSave":"Save prompt","botDefaults.autoStartTopic":"Auto-start on new topics in topic groups","botDefaults.autoStartTopicHelp":"When enabled, in a topic group the bot automatically joins each newly opened topic and starts working on its first message, no @ needed. Topic groups only \u2014 regular groups are unaffected.","botDefaults.sectionSessionMode":"Session mode","botDefaults.p2pMode":"Private chat session mode","botDefaults.p2pThread":"thread (separate session per DM)","botDefaults.p2pChat":"chat (flat continuous session)","botDefaults.p2pHelp":"How 1:1 DMs are sessioned: thread = each top-level message starts its own session (keeps chatter out of one CLI process); chat = the whole DM shares one continuous session and context (Hermes-like). Takes effect immediately.","botDefaults.regularGroupMode":"Regular group session mode","botDefaults.regularGroupModeChat":"chat (flat continuous session, default)","botDefaults.regularGroupModeNewTopic":"new-topic (each top-level @ opens its own topic & session)","botDefaults.regularGroupModeShared":"shared (topic display, reusing one session)","botDefaults.regularGroupModeHelp":"How new top-level @mentions in regular (non-topic) groups are sessioned: chat = the whole group shares one continuous session (default); new-topic = each top-level @ opens its own topic with a separate session; shared = topic display but reuse the same session (replies fold into a topic yet share the group session & context). This is the per-bot default; a specific group can override it via /reply-mode. Takes effect immediately.","botDefaults.mentionMode":"Group @ policy","botDefaults.mentionModeAlways":"Always require @ (default)","botDefaults.mentionModeTopic":"No @ needed inside topics","botDefaults.mentionModeNever":"Never require @","botDefaults.mentionModeHelp":'Bot-global: controls when an @ is required to get a reply in groups. "Always require @" = every message needs an @ (default, safest; inside topics too, in multi-person groups); "No @ needed inside topics" = starting a new conversation / top-level still needs @, but follow-ups inside ANY topic this bot already drives (new-topic / shared / topic-group) continue without @; "Never require @" = non-@ messages are answered too wherever the bot has talk access (including cold-starting on a brand-new message \u2014 only suitable for dedicated / on-call small groups; in busy multi-person groups it replies to everything). Note: when you are alone with this bot (1:1) replies never need an @, independent of this setting.',"botDefaults.docSubscribeMode":"Doc subscription trigger (default)","botDefaults.docSubscribeModeMention":"Only when a comment @s me","botDefaults.docSubscribeModeAll":"Every new comment","botDefaults.docSubscribeModeHelp":'After subscribing to a Feishu doc with /subscribe-lark-doc, its comments feed into the session and the bot replies back into the comment. This sets the default trigger range for new subscriptions: "only when a comment @s me" is safest (avoids noise); "every new comment" suits dedicated docs.',"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","botDefaults.sectionSessionCap":"Session limit","botDefaults.maxLiveWorkers":"Max live sessions","botDefaults.maxLiveWorkersPlaceholder":"Empty = default 30","botDefaults.maxLiveWorkersHelp":"Cap on this bot's simultaneously-live sessions, to bound memory. Beyond it, the least-recently-used sessions are suspended: both the worker AND the CLI process are killed to reclaim all their memory, and the session cold-resumes from its on-disk transcript on the next message (--resume rebuilds context in a few seconds \u2014 nothing stays resident). Empty = use the default of 30; a number = a per-bot override (set a larger number if you want more). Note: suspension only applies to resumable backends (tmux/herdr/zellij), never plain PTY; a session that is mid-reply is never interrupted.","botDefaults.maxLiveWorkersSave":"Save limit","botDefaults.maxLiveWorkersOff":"Reset to default","botDefaults.maxLiveWorkersInvalid":"Limit must be a positive integer","botDefaults.maxLiveWorkersStateDefault":"Current: default 30 live sessions","botDefaults.maxLiveWorkersStateOn":"Current: up to {count} live sessions","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"},fo={zh:rs,en:ls};function Gt(e){if(typeof e!="string")return null;let n=e.trim().toLowerCase();return n==="zh"||n.startsWith("zh-")?"zh":n==="en"||n.startsWith("en-")?"en":null}function ds(e=[]){for(let n of e){let o=Gt(n);if(o)return o}return"zh"}function _t(e){return(n,o)=>{let s=fo[e][n]??fo.zh[n]??n;return o?s.replace(/\{(\w+)\}/g,(a,r)=>{let c=o[r];return c==null?`{${r}}`:String(c)}):s}}function go(e,n){return(e?Gt(e.getItem(wn)):null)??ds(n)}var yn="botmux.dashboard.theme",bo="botmux.dashboard.sessions.view";function cs(e){return e==="system"||e==="light"||e==="dark"?e:null}function vn(e){return e==="kanban"||e==="board"||e==="table"?e:null}function ho(e,n){return e==="system"?n?"dark":"light":e}function wo(e){return cs(e?.getItem(yn))??"dark"}function yo(e){return vn(e?.getItem(bo))??"board"}var vo="botmux.dashboard.sessions.boardOrder",It=["needs-you","starting","working","idle"];function us(e){if(!Array.isArray(e)||e.length!==It.length)return null;let n=new Set(e);if(n.size!==e.length)return null;for(let o of It)if(!n.has(o))return null;return e.slice()}function ko(e){try{let n=e?.getItem(vo);return n?us(JSON.parse(n))??[...It]:[...It]}catch{return[...It]}}function kn(e,n){try{e?.setItem(vo,JSON.stringify(n))}catch{}}function $o(e,n){try{e?.setItem(bo,n)}catch{}}var So="botmux.dashboard.sessions.kanbanGroupBy",$n="botmux.dashboard.sessions.kanbanTeam";function ps(e){return e==="flow"||e==="team"||e==="bot"?e:null}function To(e){return ps(e?.getItem(So))??"flow"}function Lo(e,n){try{e?.setItem(So,n)}catch{}}var Io="botmux.dashboard.sidebar";function ms(e){return e==="expanded"||e==="collapsed"?e:null}function Mo(e){return ms(e?.getItem(Io))??"expanded"}function Eo(e,n){try{e?.setItem(Io,n)}catch{}}var fs=["default","cyber","genshin","fallout","prts","bluearchive","zzz","dragonball","ikun"],Sn="botmux.dashboard.skin";function gs(e){return typeof e=="string"&&fs.includes(e)?e:null}function xo(e){return gs(e?.getItem(Sn))??"default"}var bs="\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF830123456789\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E$#%&@*+=<>/\\",Ho=["186 100% 60%","56 97% 60%","330 100% 64%","150 80% 58%"],Ln=[{key:"shake",dur:280},{key:"rgb",dur:340},{key:"tear",dur:400},{key:"invert",dur:220},{key:"slice",dur:320},{key:"blackout",dur:260}],Co=["ESTABLISHING NETLINK","BYPASSING ICE","DECRYPTING DATAFLOW","SYNCING BOTMUX TELEMETRY","ACCESS GRANTED"],Ao="0123456789ABCDEF#<>*/=+\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C",hs=3200,Mt=[],ht=0,zt=0;function En(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function In(e,n){let o="";for(let s=0;s<e;s++)o+=n[Math.floor(Math.random()*n.length)];return o}function ws(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=In(28+Math.floor(Math.random()*22),bs);let r=Ho[Math.floor(Math.random()*Ho.length)];a.style.cssText=`left:${(s+.5)/o*100}%;--rc:${r};--sz:${10+Math.floor(Math.random()*9)}px;--op:${(.25+Math.random()*.45).toFixed(2)};--dur:${(6+Math.random()*9).toFixed(1)}s;--delay:${(-Math.random()*12).toFixed(1)}s;`,n.appendChild(a)}e.appendChild(n)}function ys(){if(En())return;let e=document.body,n=()=>{let o=Ln[Math.floor(Math.random()*Ln.length)],s=`cp-fx-${o.key}`;e.classList.add(s),Mt.push(window.setTimeout(()=>e.classList.remove(s),o.dur)),Mt.push(window.setTimeout(n,2400+Math.random()*4200))};Mt.push(window.setTimeout(n,1800+Math.random()*2600))}function vs(){Mt.forEach(e=>window.clearTimeout(e)),Mt=[];for(let e of Ln)document.body.classList.remove(`cp-fx-${e.key}`)}function ks(){if(En()||document.getElementById("cyber-boot"))return;let e=document.createElement("div");e.id="cyber-boot",e.className="cyber-boot",e.setAttribute("aria-hidden","true"),e.innerHTML='<div class="cyber-boot-grid"></div><div class="cyber-loader"><div class="cyber-loader-frame"><div class="cyber-loader-head"><span>KIROSHI NETLINK</span><span class="cyber-loader-jp">\u4FB5\u5165\u4E2D</span></div><div class="cyber-loader-line"><span class="cyber-loader-prompt">></span><span class="cyber-loader-text"></span><span class="cyber-loader-cursor">_</span></div><div class="cyber-loader-stream"></div></div></div>',document.body.appendChild(e);let n=e.querySelector(".cyber-loader-text"),o=e.querySelector(".cyber-loader-stream"),s=0,a=0,r=0;ht=window.setInterval(()=>{let c=Co[s];n&&(a<c.length?(a+=1,n.textContent=c.slice(0,a)+In(c.length-a,Ao),n.classList.remove("done")):r<16?(r+=1,n.textContent=c,n.classList.add("done")):(s=(s+1)%Co.length,a=0,r=0)),o&&(o.textContent=In(26,Ao))},50),zt=window.setTimeout(()=>{window.clearInterval(ht),ht=0,e.remove()},hs)}function $s(){ht&&(window.clearInterval(ht),ht=0),zt&&(window.clearTimeout(zt),zt=0),document.getElementById("cyber-boot")?.remove()}var Ss=320,Do=16,Et=!0,bt=0,Tn=0,Wt=!1,Kt=[],Mn=[];function Ts(){if(Wt)return;Wt=!0,Et=!1,bt=0;let e=En(),n="";for(let s=0;s<Do;s++){let a=s%3===0?"186 100% 52%":s%3===1?"330 100% 58%":"56 97% 52%",r=(s%2===0?1:-1)*(8+s%5*7);n+=`<span class="cyber-breach-shard" style="top:${s/Do*100}%;height:${2+s%4*3}%;--shift:${r}px;--delay:${s%8*.09}s;--dur:${(.36+s%5*.12).toFixed(2)}s;--hue:${a}"></span>`}let o=document.createElement("div");o.id="cyber-breach",o.className="cyber-breach",o.setAttribute("aria-hidden","true"),o.innerHTML=`<span class="cyber-breach-flash"></span><span class="cyber-breach-grid"></span><div class="cyber-breach-shards">${n}</div><div class="cyber-breach-banner"><span class="cyber-breach-tag">// BREACH PROTOCOL \u2014 SYSTEM OVERRIDE</span><span class="cyber-breach-caption" data-text="SYSTEM BREACH">SYSTEM BREACH</span><span class="cyber-breach-sub" data-text="NETWATCH OVERRIDE ENGAGED">NETWATCH OVERRIDE ENGAGED</span></div>`,document.body.appendChild(o),e||document.body.classList.add("cyber-breach-quake"),Kt.push(window.setTimeout(()=>document.body.classList.remove("cyber-breach-quake"),760)),Kt.push(window.setTimeout(()=>{o.remove(),Wt=!1},e?2600:4200))}function Ls(){Et=!0,bt=0;let e=document.documentElement,n=()=>e.scrollHeight-(window.innerHeight+window.scrollY)<=4,o=k=>{k<=0||!n()||(bt+=k,bt>Ss&&Et&&Ts())},s=k=>o(k.deltaY),a=k=>{Tn=k.touches[0]?.clientY??0},r=k=>{let v=k.touches[0]?.clientY??0,L=Tn-v;Tn=v,o(L)},c=()=>{n()||(bt=0,Et=!0)},p=(k,v)=>{window.addEventListener(k,v,{passive:!0}),Mn.push([k,v])};p("wheel",s),p("touchstart",a),p("touchmove",r),p("scroll",c)}function Is(){for(let[e,n]of Mn)window.removeEventListener(e,n);Mn=[],Kt.forEach(e=>window.clearTimeout(e)),Kt=[],document.body.classList.remove("cyber-breach-quake"),document.getElementById("cyber-breach")?.remove(),Wt=!1,Et=!0,bt=0}function Ro(e,n=!1){if(!(typeof document>"u")){if(!e){document.getElementById("cyber-fx")?.remove(),document.getElementById("cyber-hud")?.remove(),document.getElementById("cyber-glitch")?.remove(),vs(),$s(),Is();return}if(!document.getElementById("cyber-fx")){let 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>',ws(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),ys(),Ls()}n&&ks()}}var Ms={genshin:2e3,zzz:1900,dragonball:1900,ikun:1900},Es='<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 xs(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 Es;default:return""}}function Hs(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Oo(e){if(typeof document>"u"||Hs())return;let n=Ms[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=xs(e),document.body.appendChild(o),window.setTimeout(()=>o.remove(),n+80)}var Hn=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=go(n?.localStorage,As()),this.translate=_t(this.locale),this.themeMode=wo(n?.localStorage),this.skin=xo(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=_t(n),window.localStorage.setItem(wn,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(yn,this.themeMode)),a&&(this.skin=s,window.localStorage.setItem(Sn,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=ho(this.themeMode,!!this.mediaQuery?.matches);let n=this.skin==="default"?this.resolvedTheme:Cs[this.skin];document.documentElement.dataset.theme=n,document.documentElement.dataset.themeMode=this.themeMode}applySkin(n=!1){document.documentElement.dataset.skin=this.skin,Ro(this.skin==="cyber",n),n&&this.skin!=="cyber"&&this.skin!=="default"&&Oo(this.skin)}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}},Cs={default:"light",cyber:"dark",genshin:"light",fallout:"dark",prts:"dark",bluearchive:"dark",zzz:"dark",dragonball:"light",ikun:"dark"};function As(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var Te=new Hn;function t(e,n){return Te.t(e,n)}function i(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function Ne(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 Bo=[{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 No(e){let n=0,o=String(e??"");for(let r=0;r<o.length;r++)n=n*31+o.charCodeAt(r)>>>0;let{c1:s,c2:a}=Bo[n%Bo.length];return`--c1:${s};--c2:${a}`}var Jt=new Map,Yt=new Map;function Ds(e,n){return n?Jt.get(n):e?Yt.get(String(e)):void 0}function be(e){let n=e.name??"",o=e.avatarUrl??Ds(e.name,e.larkAppId),s=e.size==="sm"?" orb-avatar-sm":"",a=o?" orb-has-img":"",r=e.dot?`<i class="orb-dot orb-dot-${e.dot}"></i>`:"",c=o?`<img class="orb-img" src="${i(o)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar${s}${a}" style="${No(n)}" aria-hidden="true">${c}${r}</span>`}function Rs(e){return e?Xt.get(e):void 0}function Vt(e){let n=e.name??e.chatId??"",o=e.avatarUrl??Rs(e.chatId),s=e.size==="sm"?" orb-avatar-sm":"",a=o?" orb-has-img":"",r=o?`<img class="orb-img" src="${i(o)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar orb-square${s}${a}" style="${No(n)}" aria-hidden="true">${r}</span>`}var xt=new Map,Qt=new Map,Xt=new Map,xn=null,Po="botmux.avatarCache.v1";function Os(){try{let e=typeof window<"u"?window.localStorage.getItem(Po):null;if(!e)return;let n=JSON.parse(e);for(let[o,s]of Object.entries(n.botByAppId??{}))Jt.set(o,s);for(let[o,s]of Object.entries(n.botByName??{}))Yt.set(o,s);for(let[o,s]of Object.entries(n.chatById??{}))Xt.set(o,s);for(let[o,s]of Object.entries(n.nameByAppId??{}))xt.set(o,s);for(let[o,s]of Object.entries(n.chatNameById??{}))Qt.set(o,s)}catch{}}function Bs(){try{if(typeof window>"u")return;window.localStorage.setItem(Po,JSON.stringify({botByAppId:Object.fromEntries(Jt),botByName:Object.fromEntries(Yt),chatById:Object.fromEntries(Xt),nameByAppId:Object.fromEntries(xt),chatNameById:Object.fromEntries(Qt)}))}catch{}}Os();function _e(){return xn??=(async()=>{try{let e=await fetch("/api/groups");if(!e.ok)throw new Error(`HTTP ${e.status}`);let n=await e.json();for(let o of n.bots??[])o.larkAppId&&o.botName&&o.botName!==o.larkAppId&&xt.set(o.larkAppId,String(o.botName)),o.botAvatarUrl&&(o.larkAppId&&Jt.set(o.larkAppId,String(o.botAvatarUrl)),o.botName&&Yt.set(String(o.botName),String(o.botAvatarUrl)));for(let o of n.chats??[])o.chatId&&o.name&&Qt.set(o.chatId,String(o.name)),o.chatId&&o.avatar&&Xt.set(o.chatId,String(o.avatar));Bs()}catch{xn=null}})(),xn}function qo(e){return e?xt.get(e):void 0}function ve(e){let n=e.larkAppId?xt.get(e.larkAppId):void 0;return n||(e.botName&&e.botName!==e.larkAppId?String(e.botName):String(e.botName??e.larkAppId??"-"))}function tt(e){return e.chatId&&Qt.get(e.chatId)||null}function ke(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 nt(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 Me(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 Fo={chats:[],bots:[]};async function Ns(){try{let e=await fetch("/api/groups");if(!e.ok)return;Fo=await e.json()}catch{}}var Cn=new Set(["working","analyzing","active","starting"]);function Ps(e){let n=new Map,o=a=>{let r=n.get(a);return r||(r={botName:a,larkAppId:a,cliId:"unknown",online:!1,sessions:[],active:[],busy:[],attention:[],lastActiveAt:0},n.set(a,r)),r};for(let a of Fo.bots??[]){let r=o(a.larkAppId??a.botName??"-");r.online=!0,a.botName&&(r.botName=a.botName),a.botAvatarUrl&&(r.botAvatarUrl=a.botAvatarUrl)}let s=[...e].sort((a,r)=>+(a.status==="closed")-+(r.status==="closed"));for(let a of s){let r=a.larkAppId??a.botName??"-";if(a.status==="closed"&&!n.has(r))continue;let c=o(r);a.botName&&(c.botName===c.larkAppId||!c.botName)&&(c.botName=a.botName),c.sessions.push(a),a.cliId&&c.cliId==="unknown"&&(c.cliId=a.cliId),c.lastActiveAt=Math.max(c.lastActiveAt,Number(a.lastMessageAt??0)),a.status!=="closed"&&(c.active.push(a),Cn.has(a.status)&&c.busy.push(a),nt(a)&&c.attention.push(a))}for(let a of n.values())if(a.botName===a.larkAppId){let r=qo(a.larkAppId);r&&(a.botName=r)}return[...n.values()].sort((a,r)=>{let c=p=>p.attention.length?0:p.busy.length?1:p.online||p.active.length?2:3;return c(a)!==c(r)?c(a)-c(r):r.lastActiveAt-a.lastActiveAt})}var Go="botmux.overview.teamExpanded",qs=230,Uo=13,jo=2;function Us(e){let n=e.clientWidth;return n?Math.max(1,Math.floor((n+Uo)/(qs+Uo)))*jo:jo*3}function js(){try{return window.localStorage.getItem(Go)==="1"}catch{return!1}}function Fs(e){try{window.localStorage.setItem(Go,e?"1":"0")}catch{}}function Gs(e){let n=!e.online&&e.active.length===0,o=e.attention.length>0,s=e.busy.length>0,a=o?"warn":s?"busy":n?"off":"ok",r;if(o){let p=[...e.attention].sort((k,v)=>Me(k)-Me(v))[0];r=`<b>${i((ke(p.title)||p.sessionId).slice(0,60))}</b> \xB7 ${i(nt(p)??"")}`}else if(s){let p=[...e.busy].sort((k,v)=>Number(v.lastMessageAt??0)-Number(k.lastMessageAt??0))[0];r=`<b>${i((ke(p.title)||p.sessionId).slice(0,60))}</b>`}else n?r=i(t("overview.botOffline")):r=i(t("overview.botIdle"));let c=o?`<span class="tag tag-warn">${i(t("overview.botNeedsYou"))}</span>`:s?`<span class="tag tag-run">${i(t("overview.botBusy",{count:e.busy.length}))}</span>`:n?`<span class="tag tag-off">${i(t("overview.botOff"))}</span>`:`<span class="tag tag-ok">${i(t("overview.botReady"))}</span>`;return`<article class="mate${o?" mate-attn":""}${n?" mate-off":""}">
|
|
13
|
+
}`,"catalog.chatId":"Chat ID","catalog.larkAppId":"Lark app ID","catalog.chatBindingHint":"Required so humanGate cards and cancel routing know which Lark chat owns the run.","catalog.run":"Run","catalog.running":"Starting...","catalog.badParamsJson":"Params must be a JSON object.","catalog.writeAccess":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and run again.","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"Run started; opening detail page...","catalog.invalidParams":"Invalid params","catalog.issue":"{path}: {message}","catalog.noParams":"No params declared.","catalog.required":"required","catalog.optional":"optional","catalog.default":"default","catalog.description":"description","catalog.path":"path","catalog.revision":"revision","catalog.nodeCount":"nodes"},yo={zh:cs,en:us};function Vt(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 ps(e=[]){for(let n of e){let o=Vt(n);if(o)return o}return"zh"}function Qt(e){return(n,o)=>{let s=yo[e][n]??yo.zh[n]??n;return o?s.replace(/\{(\w+)\}/g,(a,r)=>{let d=o[r];return d==null?`{${r}}`:String(d)}):s}}function vo(e,n){return(e?Vt(e.getItem(In)):null)??ps(n)}var Mn="botmux.dashboard.theme",ko="botmux.dashboard.sessions.view";function ms(e){return e==="system"||e==="light"||e==="dark"?e:null}function xn(e){return e==="kanban"||e==="board"||e==="table"?e:null}function $o(e,n){return e==="system"?n?"dark":"light":e}function So(e){return ms(e?.getItem(Mn))??"dark"}function To(e){return xn(e?.getItem(ko))??"board"}var Lo="botmux.dashboard.sessions.boardOrder",Dt=["needs-you","starting","working","idle"];function fs(e){if(!Array.isArray(e)||e.length!==Dt.length)return null;let n=new Set(e);if(n.size!==e.length)return null;for(let o of Dt)if(!n.has(o))return null;return e.slice()}function Io(e){try{let n=e?.getItem(Lo);return n?fs(JSON.parse(n))??[...Dt]:[...Dt]}catch{return[...Dt]}}function En(e,n){try{e?.setItem(Lo,JSON.stringify(n))}catch{}}function Mo(e,n){try{e?.setItem(ko,n)}catch{}}var xo="botmux.dashboard.sessions.kanbanGroupBy",Hn="botmux.dashboard.sessions.kanbanTeam";function gs(e){return e==="flow"||e==="team"||e==="bot"?e:null}function Eo(e){return gs(e?.getItem(xo))??"flow"}function Ho(e,n){try{e?.setItem(xo,n)}catch{}}var Co="botmux.dashboard.sidebar";function bs(e){return e==="expanded"||e==="collapsed"?e:null}function Ao(e){return bs(e?.getItem(Co))??"expanded"}function Do(e,n){try{e?.setItem(Co,n)}catch{}}var hs=["default","cyber","genshin","fallout","prts","bluearchive","zzz","dragonball","ikun"],Cn="botmux.dashboard.skin";function ws(e){return typeof e=="string"&&hs.includes(e)?e:null}function Ro(e){return ws(e?.getItem(Cn))??"default"}var ys="\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF830123456789\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E$#%&@*+=<>/\\",Oo=["186 100% 60%","56 97% 60%","330 100% 64%","150 80% 58%"],Dn=[{key:"shake",dur:280},{key:"rgb",dur:340},{key:"tear",dur:400},{key:"invert",dur:220},{key:"slice",dur:320},{key:"blackout",dur:260}],Bo=["ESTABLISHING NETLINK","BYPASSING ICE","DECRYPTING DATAFLOW","SYNCING BOTMUX TELEMETRY","ACCESS GRANTED"],No="0123456789ABCDEF#<>*/=+\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C",vs=3200,Rt=[],$t=0,Xt=0;function Bn(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Rn(e,n){let o="";for(let s=0;s<e;s++)o+=n[Math.floor(Math.random()*n.length)];return o}function ks(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=Rn(28+Math.floor(Math.random()*22),ys);let r=Oo[Math.floor(Math.random()*Oo.length)];a.style.cssText=`left:${(s+.5)/o*100}%;--rc:${r};--sz:${10+Math.floor(Math.random()*9)}px;--op:${(.25+Math.random()*.45).toFixed(2)};--dur:${(6+Math.random()*9).toFixed(1)}s;--delay:${(-Math.random()*12).toFixed(1)}s;`,n.appendChild(a)}e.appendChild(n)}function $s(){if(Bn())return;let e=document.body,n=()=>{let o=Dn[Math.floor(Math.random()*Dn.length)],s=`cp-fx-${o.key}`;e.classList.add(s),Rt.push(window.setTimeout(()=>e.classList.remove(s),o.dur)),Rt.push(window.setTimeout(n,2400+Math.random()*4200))};Rt.push(window.setTimeout(n,1800+Math.random()*2600))}function Ss(){Rt.forEach(e=>window.clearTimeout(e)),Rt=[];for(let e of Dn)document.body.classList.remove(`cp-fx-${e.key}`)}function Ts(){if(Bn()||document.getElementById("cyber-boot"))return;let e=document.createElement("div");e.id="cyber-boot",e.className="cyber-boot",e.setAttribute("aria-hidden","true"),e.innerHTML='<div class="cyber-boot-grid"></div><div class="cyber-loader"><div class="cyber-loader-frame"><div class="cyber-loader-head"><span>KIROSHI NETLINK</span><span class="cyber-loader-jp">\u4FB5\u5165\u4E2D</span></div><div class="cyber-loader-line"><span class="cyber-loader-prompt">></span><span class="cyber-loader-text"></span><span class="cyber-loader-cursor">_</span></div><div class="cyber-loader-stream"></div></div></div>',document.body.appendChild(e);let n=e.querySelector(".cyber-loader-text"),o=e.querySelector(".cyber-loader-stream"),s=0,a=0,r=0;$t=window.setInterval(()=>{let d=Bo[s];n&&(a<d.length?(a+=1,n.textContent=d.slice(0,a)+Rn(d.length-a,No),n.classList.remove("done")):r<16?(r+=1,n.textContent=d,n.classList.add("done")):(s=(s+1)%Bo.length,a=0,r=0)),o&&(o.textContent=Rn(26,No))},50),Xt=window.setTimeout(()=>{window.clearInterval($t),$t=0,e.remove()},vs)}function Ls(){$t&&(window.clearInterval($t),$t=0),Xt&&(window.clearTimeout(Xt),Xt=0),document.getElementById("cyber-boot")?.remove()}var Is=320,Po=16,Ot=!0,kt=0,An=0,Zt=!1,en=[],On=[];function Ms(){if(Zt)return;Zt=!0,Ot=!1,kt=0;let e=Bn(),n="";for(let s=0;s<Po;s++){let a=s%3===0?"186 100% 52%":s%3===1?"330 100% 58%":"56 97% 52%",r=(s%2===0?1:-1)*(8+s%5*7);n+=`<span class="cyber-breach-shard" style="top:${s/Po*100}%;height:${2+s%4*3}%;--shift:${r}px;--delay:${s%8*.09}s;--dur:${(.36+s%5*.12).toFixed(2)}s;--hue:${a}"></span>`}let o=document.createElement("div");o.id="cyber-breach",o.className="cyber-breach",o.setAttribute("aria-hidden","true"),o.innerHTML=`<span class="cyber-breach-flash"></span><span class="cyber-breach-grid"></span><div class="cyber-breach-shards">${n}</div><div class="cyber-breach-banner"><span class="cyber-breach-tag">// BREACH PROTOCOL \u2014 SYSTEM OVERRIDE</span><span class="cyber-breach-caption" data-text="SYSTEM BREACH">SYSTEM BREACH</span><span class="cyber-breach-sub" data-text="NETWATCH OVERRIDE ENGAGED">NETWATCH OVERRIDE ENGAGED</span></div>`,document.body.appendChild(o),e||document.body.classList.add("cyber-breach-quake"),en.push(window.setTimeout(()=>document.body.classList.remove("cyber-breach-quake"),760)),en.push(window.setTimeout(()=>{o.remove(),Zt=!1},e?2600:4200))}function xs(){Ot=!0,kt=0;let e=document.documentElement,n=()=>e.scrollHeight-(window.innerHeight+window.scrollY)<=4,o=v=>{v<=0||!n()||(kt+=v,kt>Is&&Ot&&Ms())},s=v=>o(v.deltaY),a=v=>{An=v.touches[0]?.clientY??0},r=v=>{let k=v.touches[0]?.clientY??0,I=An-k;An=k,o(I)},d=()=>{n()||(kt=0,Ot=!0)},p=(v,k)=>{window.addEventListener(v,k,{passive:!0}),On.push([v,k])};p("wheel",s),p("touchstart",a),p("touchmove",r),p("scroll",d)}function Es(){for(let[e,n]of On)window.removeEventListener(e,n);On=[],en.forEach(e=>window.clearTimeout(e)),en=[],document.body.classList.remove("cyber-breach-quake"),document.getElementById("cyber-breach")?.remove(),Zt=!1,Ot=!0,kt=0}function qo(e,n=!1){if(!(typeof document>"u")){if(!e){document.getElementById("cyber-fx")?.remove(),document.getElementById("cyber-hud")?.remove(),document.getElementById("cyber-glitch")?.remove(),Ss(),Ls(),Es();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>',ks(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),$s(),xs()}n&&Ts()}}var Hs={genshin:2e3,zzz:1900,dragonball:1900,ikun:1900},Cs='<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 As(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 Cs;default:return""}}function Ds(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Uo(e){if(typeof document>"u"||Ds())return;let n=Hs[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=As(e),document.body.appendChild(o),window.setTimeout(()=>o.remove(),n+80)}var Pn=class{locale="zh";themeMode="system";resolvedTheme="light";skin="default";authed=!0;listeners=new Set;translate=Qt(this.locale);mediaQuery=null;init(){let n=typeof window<"u"?window:void 0;this.locale=vo(n?.localStorage,Os()),this.translate=Qt(this.locale),this.themeMode=So(n?.localStorage),this.skin=Ro(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=Qt(n),window.localStorage.setItem(In,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(Mn,this.themeMode)),a&&(this.skin=s,window.localStorage.setItem(Cn,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=$o(this.themeMode,!!this.mediaQuery?.matches);let n=this.skin==="default"?this.resolvedTheme:Rs[this.skin];document.documentElement.dataset.theme=n,document.documentElement.dataset.themeMode=this.themeMode}applySkin(n=!1){document.documentElement.dataset.skin=this.skin,qo(this.skin==="cyber",n),n&&this.skin!=="cyber"&&this.skin!=="default"&&Uo(this.skin)}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}},Rs={default:"light",cyber:"dark",genshin:"light",fallout:"dark",prts:"dark",bluearchive:"dark",zzz:"dark",dragonball:"light",ikun:"dark"};function Os(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var Te=new Pn;function t(e,n){return Te.t(e,n)}function i(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function qe(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 jo=[{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 Fo(e){let n=0,o=String(e??"");for(let r=0;r<o.length;r++)n=n*31+o.charCodeAt(r)>>>0;let{c1:s,c2:a}=jo[n%jo.length];return`--c1:${s};--c2:${a}`}var tn=new Map,nn=new Map;function Bs(e,n){return n?tn.get(n):e?nn.get(String(e)):void 0}function fe(e){let n=e.name??"",o=e.avatarUrl??Bs(e.name,e.larkAppId),s=e.size==="sm"?" orb-avatar-sm":"",a=o?" orb-has-img":"",r=e.dot?`<i class="orb-dot orb-dot-${e.dot}"></i>`:"",d=o?`<img class="orb-img" src="${i(o)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar${s}${a}" style="${Fo(n)}" aria-hidden="true">${d}${r}</span>`}function Ns(e){return e?sn.get(e):void 0}function on(e){let n=e.name??e.chatId??"",o=e.avatarUrl??Ns(e.chatId),s=e.size==="sm"?" orb-avatar-sm":"",a=o?" orb-has-img":"",r=o?`<img class="orb-img" src="${i(o)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar orb-square${s}${a}" style="${Fo(n)}" aria-hidden="true">${r}</span>`}var Bt=new Map,an=new Map,sn=new Map,Nn=null,Go="botmux.avatarCache.v1";function Ps(){try{let e=typeof window<"u"?window.localStorage.getItem(Go):null;if(!e)return;let n=JSON.parse(e);for(let[o,s]of Object.entries(n.botByAppId??{}))tn.set(o,s);for(let[o,s]of Object.entries(n.botByName??{}))nn.set(o,s);for(let[o,s]of Object.entries(n.chatById??{}))sn.set(o,s);for(let[o,s]of Object.entries(n.nameByAppId??{}))Bt.set(o,s);for(let[o,s]of Object.entries(n.chatNameById??{}))an.set(o,s)}catch{}}function qs(){try{if(typeof window>"u")return;window.localStorage.setItem(Go,JSON.stringify({botByAppId:Object.fromEntries(tn),botByName:Object.fromEntries(nn),chatById:Object.fromEntries(sn),nameByAppId:Object.fromEntries(Bt),chatNameById:Object.fromEntries(an)}))}catch{}}Ps();function Ke(){return Nn??=(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&&Bt.set(o.larkAppId,String(o.botName)),o.botAvatarUrl&&(o.larkAppId&&tn.set(o.larkAppId,String(o.botAvatarUrl)),o.botName&&nn.set(String(o.botName),String(o.botAvatarUrl)));for(let o of n.chats??[])o.chatId&&o.name&&an.set(o.chatId,String(o.name)),o.chatId&&o.avatar&&sn.set(o.chatId,String(o.avatar));qs()}catch{Nn=null}})(),Nn}function _o(e){return e?Bt.get(e):void 0}function ye(e){let n=e.larkAppId?Bt.get(e.larkAppId):void 0;return n||(e.botName&&e.botName!==e.larkAppId?String(e.botName):String(e.botName??e.larkAppId??"-"))}function st(e){return e.chatId&&an.get(e.chatId)||null}function ve(e){let n=String(e??"");return n.replace(/^(?:@\S+\s*)+/,"").trim()||n}function St(e){return`<div class="page-loading" role="status"><i class="page-loading-spin" aria-hidden="true"></i>${i(e??t("common.loading"))}</div>`}function it(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 xe(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 Ko={chats:[],bots:[]};async function Us(){try{let e=await fetch("/api/groups");if(!e.ok)return;Ko=await e.json()}catch{}}var qn=new Set(["working","analyzing","active","starting"]);function js(e){let n=new Map,o=a=>{let r=n.get(a);return r||(r={botName:a,larkAppId:a,cliId:"unknown",online:!1,sessions:[],active:[],busy:[],attention:[],lastActiveAt:0},n.set(a,r)),r};for(let a of Ko.bots??[]){let r=o(a.larkAppId??a.botName??"-");r.online=!0,a.botName&&(r.botName=a.botName),a.botAvatarUrl&&(r.botAvatarUrl=a.botAvatarUrl)}let s=[...e].sort((a,r)=>+(a.status==="closed")-+(r.status==="closed"));for(let a of s){let r=a.larkAppId??a.botName??"-";if(a.status==="closed"&&!n.has(r))continue;let d=o(r);a.botName&&(d.botName===d.larkAppId||!d.botName)&&(d.botName=a.botName),d.sessions.push(a),a.cliId&&d.cliId==="unknown"&&(d.cliId=a.cliId),d.lastActiveAt=Math.max(d.lastActiveAt,Number(a.lastMessageAt??0)),a.status!=="closed"&&(d.active.push(a),qn.has(a.status)&&d.busy.push(a),it(a)&&d.attention.push(a))}for(let a of n.values())if(a.botName===a.larkAppId){let r=_o(a.larkAppId);r&&(a.botName=r)}return[...n.values()].sort((a,r)=>{let d=p=>p.attention.length?0:p.busy.length?1:p.online||p.active.length?2:3;return d(a)!==d(r)?d(a)-d(r):r.lastActiveAt-a.lastActiveAt})}var Jo="botmux.overview.teamExpanded",Fs=230,zo=13,Wo=2;function Gs(e){let n=e.clientWidth;return n?Math.max(1,Math.floor((n+zo)/(Fs+zo)))*Wo:Wo*3}function _s(){try{return window.localStorage.getItem(Jo)==="1"}catch{return!1}}function zs(e){try{window.localStorage.setItem(Jo,e?"1":"0")}catch{}}function Ws(e){let n=!e.online&&e.active.length===0,o=e.attention.length>0,s=e.busy.length>0,a=o?"warn":s?"busy":n?"off":"ok",r;if(o){let p=[...e.attention].sort((v,k)=>xe(v)-xe(k))[0];r=`<b>${i((ve(p.title)||p.sessionId).slice(0,60))}</b> \xB7 ${i(it(p)??"")}`}else if(s){let p=[...e.busy].sort((v,k)=>Number(k.lastMessageAt??0)-Number(v.lastMessageAt??0))[0];r=`<b>${i((ve(p.title)||p.sessionId).slice(0,60))}</b>`}else n?r=i(t("overview.botOffline")):r=i(t("overview.botIdle"));let d=o?`<span class="tag tag-warn">${i(t("overview.botNeedsYou"))}</span>`:s?`<span class="tag tag-run">${i(t("overview.botBusy",{count:e.busy.length}))}</span>`:n?`<span class="tag tag-off">${i(t("overview.botOff"))}</span>`:`<span class="tag tag-ok">${i(t("overview.botReady"))}</span>`;return`<article class="mate${o?" mate-attn":""}${n?" mate-off":""}">
|
|
14
14
|
<div class="mate-top">
|
|
15
|
-
${
|
|
15
|
+
${fe({name:e.botName,larkAppId:e.larkAppId,avatarUrl:e.botAvatarUrl,dot:a})}
|
|
16
16
|
<div class="mate-id">
|
|
17
17
|
<b>${i(e.botName)}</b>
|
|
18
18
|
<span class="mate-role">${i(e.cliId)}</span>
|
|
@@ -20,34 +20,34 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
20
20
|
</div>
|
|
21
21
|
<div class="mate-task">${r}</div>
|
|
22
22
|
<div class="mate-foot">
|
|
23
|
-
${
|
|
24
|
-
<span>${e.lastActiveAt?i(t("overview.lastActive",{time:
|
|
23
|
+
${d}
|
|
24
|
+
<span>${e.lastActiveAt?i(t("overview.lastActive",{time:qe(e.lastActiveAt)})):i(t("common.never"))}</span>
|
|
25
25
|
</div>
|
|
26
|
-
</article>`}function
|
|
27
|
-
${
|
|
26
|
+
</article>`}function Ks(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>${i(n)} \xB7 ${i((
|
|
30
|
-
<span>${i(
|
|
29
|
+
<b>${i(n)} \xB7 ${i((ve(e.title)||e.sessionId).slice(0,56))}</b>
|
|
30
|
+
<span>${i(it(e)??"")} \xB7 ${qe(xe(e))}</span>
|
|
31
31
|
</div>
|
|
32
32
|
<a class="qcard-go" href="#/sessions">${i(t("strip.handle"))}</a>
|
|
33
|
-
</article>`}function
|
|
34
|
-
${
|
|
33
|
+
</article>`}function Js(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>${i((
|
|
37
|
-
<span>${i(n)} \xB7 ${i(
|
|
36
|
+
<b>${i((ve(e.title)||e.sessionId).slice(0,64))}</b>
|
|
37
|
+
<span>${i(n)} \xB7 ${i(st(e)??e.cliId??"unknown")} \xB7 ${qe(e.lastMessageAt)}</span>
|
|
38
38
|
</div>
|
|
39
39
|
<span class="status status-${i(e.status??"unknown")}">${i(e.status??"unknown")}</span>
|
|
40
|
-
</li>`}function
|
|
40
|
+
</li>`}function Ys(e){let n=e.nextRunAt?new Date(e.nextRunAt).toLocaleString():"-";return`<li class="overview-list-row">
|
|
41
41
|
<div>
|
|
42
42
|
<strong>${i(e.name??e.id)}</strong>
|
|
43
|
-
<span>${i(
|
|
43
|
+
<span>${i(ye(e))} \xB7 ${i(e.parsed?.display??"")}</span>
|
|
44
44
|
</div>
|
|
45
45
|
<span>${i(n)}</span>
|
|
46
|
-
</li>`}function
|
|
46
|
+
</li>`}function Vs(e,n,o){let s=e+n+o;if(s===0)return`<div class="donut-wrap"><div class="donut" style="background:conic-gradient(var(--border) 0 360deg)"></div>
|
|
47
47
|
<div class="donut-center"><b>0</b><span>${i(t("overview.openSessions"))}</span></div></div>`;let a=e/s*360,r=a+n/s*360;return`<div class="donut-wrap">
|
|
48
48
|
<div class="donut" style="background:conic-gradient(var(--accent) 0 ${a}deg, var(--warning) ${a}deg ${r}deg, var(--success) ${r}deg 360deg)"></div>
|
|
49
49
|
<div class="donut-center"><b>${s}</b><span>${i(t("overview.openSessions"))}</span></div>
|
|
50
|
-
</div>`}async function
|
|
50
|
+
</div>`}async function Yo(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,25 +102,25 @@ 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"),o=e.querySelector("#team-grid"),s=e.querySelector("#team-toggle"),a=
|
|
106
|
-
<span class="pill">${i(t("overview.workingSessions"))} <b>${
|
|
107
|
-
<span class="pill${
|
|
108
|
-
<span class="pill">${i(t("overview.onlineBots"))} <b>${
|
|
105
|
+
</section>`;let n=e.querySelector("#overview-pills"),o=e.querySelector("#team-grid"),s=e.querySelector("#team-toggle"),a=_s();s.onclick=()=>{a=!a,zs(a),k()};let r=e.querySelector("#attention-list"),d=e.querySelector("#recent-sessions"),p=e.querySelector("#today-donut"),v=e.querySelector("#next-schedules");function k(){let T=[...Q.sessions.values()],g=T.filter(S=>S.status!=="closed"),R=g.filter(S=>it(S)).sort((S,H)=>xe(S)-xe(H)),A=g.filter(S=>qn.has(S.status)&&!it(S)),O=g.length-R.length-A.length,M=js(T),E=M.filter(S=>S.online||S.active.length>0).length;n.innerHTML=`
|
|
106
|
+
<span class="pill">${i(t("overview.workingSessions"))} <b>${A.length}</b></span>
|
|
107
|
+
<span class="pill${R.length?" pill-hot":""}">${i(t("overview.attention"))} <b>${R.length}</b></span>
|
|
108
|
+
<span class="pill">${i(t("overview.onlineBots"))} <b>${E}</b></span>`;let $=Gs(o),D=a?M:M.slice(0,$);o.innerHTML=D.length?D.map(Ws).join(""):`<div class="empty">${t("overview.noSessions")}</div>`,M.length>$?(s.hidden=!1,s.textContent=a?t("overview.teamCollapse"):t("overview.teamExpand",{count:M.length})):s.hidden=!0,r.innerHTML=R.length?R.map(Ks).join(""):`<div class="qcard qcard-empty">${t("overview.noAttention")}</div>`;let m=g.filter(S=>qn.has(S.status)||S.status==="idle").sort((S,H)=>Number(H.lastMessageAt??0)-Number(S.lastMessageAt??0)).slice(0,7);d.innerHTML=m.length?m.map(Js).join(""):`<li class="empty">${t("overview.noSessions")}</li>`,p.innerHTML=`${Vs(A.length,R.length,Math.max(0,O))}
|
|
109
109
|
<div class="donut-legend">
|
|
110
|
-
<span><i style="background:var(--accent)"></i>${i(t("overview.workingSessions"))} ${
|
|
111
|
-
<span><i style="background:var(--warning)"></i>${i(t("overview.attention"))} ${
|
|
112
|
-
<span><i style="background:var(--success)"></i>${i(t("sessions.board.idle"))} ${Math.max(0,
|
|
113
|
-
</div>`;let
|
|
110
|
+
<span><i style="background:var(--accent)"></i>${i(t("overview.workingSessions"))} ${A.length}</span>
|
|
111
|
+
<span><i style="background:var(--warning)"></i>${i(t("overview.attention"))} ${R.length}</span>
|
|
112
|
+
<span><i style="background:var(--success)"></i>${i(t("sessions.board.idle"))} ${Math.max(0,O)}</span>
|
|
113
|
+
</div>`;let y=[...Q.schedules.values()].filter(S=>S.nextRunAt).sort((S,H)=>Date.parse(S.nextRunAt)-Date.parse(H.nextRunAt)).slice(0,5);v.innerHTML=y.length?y.map(Ys).join(""):`<li class="empty">${t("overview.noSchedules")}</li>`}let I=()=>{if(!document.body.contains(o)){window.removeEventListener("resize",I);return}a||k()};window.addEventListener("resize",I),Q.on(k),k(),Us().then(k),Ke().then(k)}var Vo=["backlog","todo","in_progress","in_review","done"];function Qo(e){return typeof e=="string"&&Vo.includes(e)?e:null}function Xo(e){if(e.status==="closed")return"done";let n=Qo(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 Qs=1e15;function pt(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 Qs-n}function Un(e,n){return e!==null&&n!==null?(e+n)/2:e!==null?e+1024:n!==null?n-1024:1024}function Je(e,n){return`<th data-sort="${e}" data-label="${i(n)}">${i(n)}</th>`}function _n(e){return typeof e=="number"&&Number.isFinite(e)?e:null}function Zo(e){let n=_n(e);return n===null?"-":n.toLocaleString("en-US")}var ia=["claude-code","seed","relay","codex","codex-app","cursor","gemini","opencode","mtr","hermes","mira","pi","copilot","aiden","coco","oh-my-pi","unknown"],ea=[{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"}],ta=[{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"}],jn=50;function Xs(e){let n=(o="")=>`<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"${o}/>`;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 na(e){return String(e??"unknown").toLowerCase().replace(/[^a-z0-9_-]/g,"-")}function oa(e){let n=String(e??"").trim();return n?n.replace(/\\/g,"/").split("/").filter(Boolean).at(-1)??n:"-"}function Fn(e){if(!e.webPort)return null;let n=e.proxyPort??e.webPort,o=e.proxyPort?`/s/${encodeURIComponent(e.sessionId)}`:"";return`http://${location.hostname}:${n}${o}`}var Ee={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 Gn(e,n,o,s=""){return`<button type="button" class="card-act${s?" "+s:""}" data-action="${e}" title="${i(o)}" aria-label="${i(o)}">${n}</button>`}function aa(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"))}">${Ee.terminal}</a>`;if(!Te.authed)return`<span class="term-pill solo">${n}</span>`;let o=`<button type="button" class="term-btn term-write" data-action="write-link" title="${i(t("sessions.writeLinkHint"))}" aria-label="${i(t("sessions.writeLink"))}">${Ee.key}</button>`;return`<span class="term-pill">${n}${o}</span>`}async function sa(e,n){let o=window.open("about:blank","_blank");o&&(o.opener=null),n&&(n.disabled=!0);try{let s=await fetch(`/api/sessions/${encodeURIComponent(e.sessionId)}/write-link`),a=await s.json().catch(()=>({}));if(!s.ok||a?.ok===!1||!a?.url){o?.close(),s.status!==401&&alert(`${t("sessions.writeLinkFail")}: ${a?.error??s.status}`);return}o?o.location.href=a.url:window.open(a.url,"_blank","noopener")}catch(s){o?.close(),alert(`${t("sessions.writeLinkFail")}: ${s}`)}finally{n&&(n.disabled=!1)}}function Zs(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 ei(){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
|
+
${ia.map(e=>`
|
|
117
117
|
<label class="filter-check">
|
|
118
118
|
<input type="checkbox" name="cli" value="${i(e)}" checked>
|
|
119
119
|
<span>${i(e)}</span>
|
|
120
120
|
</label>
|
|
121
121
|
`).join("")}
|
|
122
122
|
</div>
|
|
123
|
-
</details>`}function
|
|
123
|
+
</details>`}function ti(){return`<section class="page">
|
|
124
124
|
<div class="page-heading">
|
|
125
125
|
<div>
|
|
126
126
|
<p class="eyebrow">${t("nav.sessions")}</p>
|
|
@@ -154,7 +154,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
154
154
|
<option value="yes">${t("sessions.adoptYes")}</option>
|
|
155
155
|
<option value="no">${t("sessions.adoptNo")}</option>
|
|
156
156
|
</select>
|
|
157
|
-
${
|
|
157
|
+
${ei()}
|
|
158
158
|
<label class="filter-toggle"><input type="checkbox" name="active" checked> <span>${t("sessions.activeOnly")}</span></label>
|
|
159
159
|
</form>
|
|
160
160
|
<div id="bulk-bar" class="bulk-bar" hidden>
|
|
@@ -165,16 +165,16 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
165
165
|
<table id="sessions-table">
|
|
166
166
|
<thead><tr>
|
|
167
167
|
<th><input type="checkbox" id="select-all" title="${t("sessions.activeOnly")}"></th>
|
|
168
|
-
${
|
|
169
|
-
${
|
|
170
|
-
${
|
|
171
|
-
${
|
|
172
|
-
${
|
|
173
|
-
${
|
|
174
|
-
${
|
|
175
|
-
${
|
|
176
|
-
${
|
|
177
|
-
${
|
|
168
|
+
${Je("botName",t("sessions.bot"))}
|
|
169
|
+
${Je("cliId",t("sessions.cli"))}
|
|
170
|
+
${Je("status",t("sessions.status"))}
|
|
171
|
+
${Je("tokenIn",t("sessions.tokenIn"))}
|
|
172
|
+
${Je("tokenOut",t("sessions.tokenOut"))}
|
|
173
|
+
${Je("title",t("sessions.titleCol"))}
|
|
174
|
+
${Je("workingDir",t("sessions.workingDir"))}
|
|
175
|
+
${Je("spawnedAt",t("sessions.created"))}
|
|
176
|
+
${Je("lastMessageAt",t("sessions.last"))}
|
|
177
|
+
${Je("adopt",t("sessions.adopt"))}
|
|
178
178
|
<th>${t("sessions.actions")}</th>
|
|
179
179
|
</tr></thead>
|
|
180
180
|
<tbody></tbody>
|
|
@@ -184,25 +184,25 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
184
184
|
<dialog id="drawer"></dialog>
|
|
185
185
|
<dialog id="term-modal" class="term-modal"></dialog>
|
|
186
186
|
<dialog id="history-modal" class="history-modal"></dialog>
|
|
187
|
-
</section>`}function
|
|
188
|
-
<td><input type="checkbox" class="row-select" ${f} ${
|
|
189
|
-
<td>${i(
|
|
190
|
-
<td><span class="badge cli-${
|
|
187
|
+
</section>`}function ra(e){e.innerHTML=ti();let n=e.querySelector("#sessions-table tbody"),o=e.querySelector("#filters"),s=e.querySelector("#drawer"),a=e.querySelector("#select-all"),r=e.querySelector("#bulk-bar"),d=e.querySelector("#bulk-count"),p=e.querySelector("#bulk-close"),v=e.querySelector("#bulk-clear"),k=e.querySelector("#sessions-table"),I=e.querySelector("#sessions-board"),T=e.querySelector("#sessions-kanban"),g=e.querySelector("#term-modal"),R=e.querySelector("#history-modal"),A=e.querySelector("#kanban-groupby"),O=e.querySelector("#kanban-team"),M=e.querySelector("#kanban-team-stats"),E=e.querySelectorAll(".sessions-view-toggle [data-view]"),$=new Set,D="lastMessageAt",m="desc",y=To(window.localStorage),S=Io(window.localStorage),H=null,B="",j="",q="",oe=!1,X=null,ae=!1,Ae=null,se=new Map,ie=Eo(window.localStorage),ce=null,Le=null,de=[],Be=null,ge=!1,Ie=!1,re=(()=>{try{return window.localStorage.getItem(Hn)??""}catch{return""}})();async function pe(){if(!(Ie||ge)){Ie=!0;try{let[l,c,f]=await Promise.all([fetch("/api/team/hosted").then(w=>w.json()).catch(()=>null),fetch("/api/team/remote-roster").then(w=>w.json()).catch(()=>null),fetch("/api/groups").then(w=>w.json()).catch(()=>null)]);Array.isArray(f?.chats)&&(Be=new Map(f.chats.map(w=>[String(w.chatId),{botIds:new Set((w.memberBots??[]).filter(L=>L.inChat).map(L=>String(L.larkAppId))),observedNames:new Set((w.observedBotNames??[]).map(L=>String(L)))}])));let u=w=>({ids:new Set(w.map(L=>String(L.larkAppId))),names:new Set(w.map(L=>String(L.name??"")).filter(Boolean))}),b=[];for(let w of l?.teams??[]){let{ids:L,names:C}=u(w.bots??[]);b.push({key:`local:${w.teamId}`,label:w.isDefault?t("team.myHostedTeam"):String(w.name??w.teamId),botIds:L,botNames:C,groupChats:new Set((w.groupChatIds??[]).map(F=>String(F)))})}for(let w of c?.memberships??[]){let{ids:L,names:C}=u(w.roster?.bots??[]);b.push({key:`${w.hubUrl}::${w.teamId}`,label:String(w.teamName??w.teamId??w.hubUrl),botIds:L,botNames:C,groupChats:new Set})}de=b}finally{ge=!0,Ie=!1}de.length&&!de.some(l=>l.key===re)&&(re=de[0].key),delete O.dataset.loading,O.disabled=de.length===0,O.innerHTML=de.length?de.map(l=>`<option value="${i(l.key)}"${l.key===re?" selected":""}>${i(l.label)}</option>`).join(""):`<option value="">${i(t("sessions.kanban.noTeam"))}</option>`,q="",Z()}}let le=null,Ne="",je=0,Pe=!1,Fe=new Map;async function be(l){let c=Ne===l.key&&Date.now()-je<3e4;if(!(Pe||c)){Pe=!0;try{let u=l.key.startsWith("local:")?`/api/team/board/local/${encodeURIComponent(l.key.slice(6))}`:`/api/team/remote-board?key=${encodeURIComponent(l.key)}`,b=await fetch(u),w=await b.json().catch(()=>({}));if(!b.ok||w?.ok===!1)return;let L=typeof w.deploymentId=="string"?w.deploymentId:null,C=[];Fe=new Map;for(let F of Array.isArray(w.reports)?w.reports:[])if(!(L&&F.deploymentId===L))for(let N of Array.isArray(F.sessions)?F.sessions:[]){let ee={...N,remoteDeployment:F.deploymentName||F.deploymentId};C.push(ee),Fe.set(String(N.sessionId),ee)}le={board:w.board&&typeof w.board=="object"?w.board:{},remoteRows:C},Ne=l.key,je=Date.now(),q="",Z()}catch{}finally{Pe=!1}}}async function nt(l,c,f,u,b){try{let L=l.startsWith("local:")?await fetch(`/api/team/board/local/${encodeURIComponent(l.slice(6))}/move`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({sessionId:c,column:f,position:u})}):await fetch("/api/team/remote-board-move",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({key:l,sessionId:c,column:f,position:u})}),C=await L.json().catch(()=>({}));(!L.ok||C?.ok===!1)&&(le&&(b?le.board[c]=b:delete le.board[c]),q="",Z(),L.status!==401&&alert(`${t("sessions.kanban.moveFail")}: ${C?.error??L.status}`))}catch(w){le&&(b?le.board[c]=b:delete le.board[c]),q="",Z(),alert(`${t("sessions.kanban.moveFail")}: ${w}`)}}function wt(l,c,f){let u=de.find(w=>w.key===re)??de[0];if(!u)return;(!le||Ne!==u.key)&&(le={board:{},remoteRows:le?.remoteRows??[]},Ne=u.key);let b=le.board[l];le.board[l]={column:c,position:f},nt(u.key,l,c,f,b)}function ot(){return S.map(l=>ea.find(c=>c.id===l)).filter(l=>!!l)}function Ht(l,c){let f=S.indexOf(l),u=f+c;if(f<0||u<0||u>=S.length)return;let b=[...S];b.splice(f,1),b.splice(u,0,l),S=b,En(window.localStorage,S),Z()}function at(l,c){if(l===c)return;let f=S.indexOf(l),u=S.indexOf(c);if(f<0||u<0)return;let b=[...S];b.splice(f,1),b.splice(u,0,l),S=b,En(window.localStorage,S),Z()}function Me(l){let c=l.status==="closed",f=$.has(l.sessionId)?"checked":"";return`<tr data-id="${i(l.sessionId)}">
|
|
188
|
+
<td><input type="checkbox" class="row-select" ${f} ${c?"disabled":""}></td>
|
|
189
|
+
<td>${i(ye(l))}</td>
|
|
190
|
+
<td><span class="badge cli-${na(l.cliId)}">${i(l.cliId??"unknown")}</span></td>
|
|
191
191
|
<td><span class="status status-${i(l.status??"unknown")}">${i(l.status??"unknown")}</span></td>
|
|
192
|
-
<td class="token-cell">${
|
|
193
|
-
<td class="token-cell">${
|
|
194
|
-
<td title="${i(String(l.title??""))}">${i(
|
|
192
|
+
<td class="token-cell">${Zo(l.tokenUsage?.in)}</td>
|
|
193
|
+
<td class="token-cell">${Zo(l.tokenUsage?.out)}</td>
|
|
194
|
+
<td title="${i(String(l.title??""))}">${i(ve(l.title??"").slice(0,48))}</td>
|
|
195
195
|
<td title="${i(l.workingDir??"")}">${i((l.workingDir??"").slice(-34))}</td>
|
|
196
|
-
<td>${
|
|
197
|
-
<td>${
|
|
196
|
+
<td>${qe(l.spawnedAt)}</td>
|
|
197
|
+
<td>${qe(l.lastMessageAt)}</td>
|
|
198
198
|
<td>${l.adopt?'<span class="badge">adopt</span>':""}</td>
|
|
199
199
|
<td><button class="open" type="button">${t("sessions.details")}</button></td>
|
|
200
|
-
</tr>`}function
|
|
200
|
+
</tr>`}function _e(l){if(l.scope!=="chat"||!l.feishuChatLink)return null;let c=t("sessions.openChat");return`<a class="card-act" href="${i(l.feishuChatLink)}" target="_blank" rel="noopener" title="${i(c)}" aria-label="${i(c)}">${Ee.feishu}</a>`}function Ge(l){return l.agentAttention?.reason?l.agentAttention.reason:l.agentAttention?t("sessions.board.signalAgent"):l.pendingRepo?t("sessions.board.signalRepo"):l.tuiPromptActive?t("sessions.board.signalPrompt"):l.status==="limited"?t("sessions.board.signalLimited"):""}function x(l){let c=$.has(l.sessionId),f=ve(l.title)||l.sessionId,u=ye(l),b=st(l),w=Fn(l),L=Ge(l),C=oa(l.workingDir);return`<article class="session-card${c?" selected":""}" data-id="${i(l.sessionId)}" aria-pressed="${c}">
|
|
201
201
|
<div class="session-card-top">
|
|
202
|
-
${
|
|
202
|
+
${fe({name:u,larkAppId:l.larkAppId,size:"sm"})}
|
|
203
203
|
<div class="session-card-title">
|
|
204
204
|
<strong title="${i(String(l.title??f))}">${i(String(f).slice(0,72))}</strong>
|
|
205
|
-
<span>${i(
|
|
205
|
+
<span>${i(u)} \xB7 ${i(b??l.cliId??"unknown")}</span>
|
|
206
206
|
</div>
|
|
207
207
|
<span class="status status-${i(l.status??"unknown")}">${i(l.status??"unknown")}</span>
|
|
208
208
|
</div>
|
|
@@ -211,16 +211,16 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
211
211
|
${l.adopt?'<span class="badge">adopt</span>':""}
|
|
212
212
|
</div>`:""}
|
|
213
213
|
<div class="session-card-time">
|
|
214
|
-
<span>${l.agentAttention?.at?`${i(t("sessions.board.waiting"))} ${
|
|
214
|
+
<span>${l.agentAttention?.at?`${i(t("sessions.board.waiting"))} ${qe(xe(l))}`:`${i(t("sessions.last"))}: ${qe(l.lastMessageAt)}`}</span>
|
|
215
215
|
</div>
|
|
216
|
-
${
|
|
216
|
+
${L?`<div class="session-signal" title="${i(L)}">${i(L)}</div>`:""}
|
|
217
217
|
<div class="session-card-actions">
|
|
218
|
-
${
|
|
219
|
-
${
|
|
220
|
-
${
|
|
221
|
-
${
|
|
218
|
+
${_e(l)??Gn("locate",Ee.pin,t("sessions.locate"))}
|
|
219
|
+
${Gn("details",Ee.details,t("sessions.details"))}
|
|
220
|
+
${aa(w)}
|
|
221
|
+
${Gn("close",Ee.close,t("sessions.close"),"danger")}
|
|
222
222
|
</div>
|
|
223
|
-
</article>`}function
|
|
223
|
+
</article>`}function V(l,c,f){let u=f==="needs-you"?xe(l):Number(l.lastMessageAt??0),b=f==="needs-you"?xe(c):Number(c.lastMessageAt??0);return u!==b?f==="needs-you"?u-b:b-u:String(l.title??l.sessionId).localeCompare(String(c.title??c.sessionId))}function K(l){let c=new Map(ea.map(b=>[b.id,[]]));for(let b of l){let w=Zs(b);w&&c.get(w).push(b)}let f=ot(),u=f.map((b,w)=>{let L=(c.get(b.id)??[]).sort((C,F)=>V(C,F,b.id));return`<section class="session-board-column session-board-${b.id}" data-col="${b.id}">
|
|
224
224
|
<header draggable="true" title="${i(t("sessions.board.dragHint"))}">
|
|
225
225
|
<div>
|
|
226
226
|
<h2>${i(t(b.labelKey))}</h2>
|
|
@@ -233,114 +233,114 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
233
233
|
<button type="button" data-move-col="${b.id}" data-dir="1"
|
|
234
234
|
aria-label="${i(t("sessions.board.moveRight"))}" ${w===f.length-1?"disabled":""}>\u203A</button>
|
|
235
235
|
</span>
|
|
236
|
-
<span class="session-board-count">${
|
|
236
|
+
<span class="session-board-count">${L.length}</span>
|
|
237
237
|
</span>
|
|
238
238
|
</header>
|
|
239
239
|
<div class="session-board-list">
|
|
240
|
-
${
|
|
240
|
+
${L.length?L.map(x).join(""):`<div class="session-board-empty">${t("sessions.board.emptyColumn")}</div>`}
|
|
241
241
|
</div>
|
|
242
|
-
</section>`}).join("");
|
|
242
|
+
</section>`}).join("");u!==B&&(B=u,I.innerHTML=u,I.classList.toggle("board-enter",!oe),oe=!0)}function _(l){let c=ve(l.title)||l.sessionId,f=ye(l),u=st(l),b=oa(l.workingDir),w=Ge(l),L=[u,b!=="-"?b:null].filter(Boolean).join(" \xB7 "),C=String(l.status??"unknown"),F=typeof l.remoteDeployment=="string"?l.remoteDeployment:"";return`<article class="kanban-card${F?" kanban-card-remote":""}" data-id="${i(l.sessionId)}" tabindex="0" role="button" draggable="true">
|
|
243
243
|
<div class="kanban-card-top">
|
|
244
|
-
<span class="badge cli-${
|
|
244
|
+
<span class="badge cli-${na(l.cliId)}">${i(l.cliId??"unknown")}</span>
|
|
245
245
|
${l.adopt?'<span class="badge">adopt</span>':""}
|
|
246
|
-
${
|
|
246
|
+
${F?`<span class="badge kanban-remote-badge" title="${i(t("sessions.kanban.remoteHint",{name:F}))}">${i(F)}</span>`:""}
|
|
247
247
|
<span class="kanban-card-top-right">
|
|
248
248
|
<span class="kanban-card-dot" data-status="${i(C)}" title="${i(C)}"></span>
|
|
249
|
-
${
|
|
249
|
+
${F?"":`<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"))}">${Ee.history}</button>
|
|
250
250
|
${l.feishuChatLink?`<a class="card-act kanban-card-act" href="${i(l.feishuChatLink)}" target="_blank" rel="noopener" title="${i(t("sessions.kanban.openFeishu"))}" aria-label="${i(t("sessions.kanban.openFeishu"))}">${Ee.feishu}</a>`:""}
|
|
251
251
|
<button type="button" class="card-act kanban-card-act" data-action="details" title="${i(t("sessions.details"))}" aria-label="${i(t("sessions.details"))}">${Ee.details}</button>`}
|
|
252
252
|
</span>
|
|
253
253
|
</div>
|
|
254
|
-
<p class="kanban-card-title" title="${i(String(l.title??
|
|
255
|
-
${
|
|
254
|
+
<p class="kanban-card-title" title="${i(String(l.title??c))}">${i(String(c).slice(0,140))}</p>
|
|
255
|
+
${L?`<p class="kanban-card-desc" title="${i(L)}">${i(L)}</p>`:""}
|
|
256
256
|
${w?`<div class="session-signal" title="${i(w)}">${i(w)}</div>`:""}
|
|
257
257
|
<div class="kanban-card-foot">
|
|
258
|
-
<span class="kanban-card-owner">${
|
|
259
|
-
<span class="kanban-card-updated">${i(t("sessions.kanban.updated",{time:
|
|
258
|
+
<span class="kanban-card-owner">${fe({name:f,larkAppId:l.larkAppId,size:"sm"})}<span>${i(f)}</span></span>
|
|
259
|
+
<span class="kanban-card-updated">${i(t("sessions.kanban.updated",{time:qe(l.lastMessageAt)}))}</span>
|
|
260
260
|
</div>
|
|
261
|
-
</article>`}function
|
|
262
|
-
<header draggable="true" title="${i(
|
|
263
|
-
${
|
|
264
|
-
<span class="kanban-cluster-name">${i(
|
|
261
|
+
</article>`}function he(l){let c=[],f=new Map;for(let w of l){let L=String(w.chatId??w.sessionId),C=f.get(L);C||(C={chatId:L,rows:[]},f.set(L,C),c.push(C)),C.rows.push(w)}let u=[];return{html:c.map(w=>{if(u.push(...w.rows),w.rows.length<2)return _(w.rows[0]);let L=st(w.rows[0])??w.chatId;return`<div class="kanban-cluster" data-chat="${i(w.chatId)}">
|
|
262
|
+
<header draggable="true" title="${i(L)} \xB7 ${i(t("sessions.kanban.clusterDragHint"))}">
|
|
263
|
+
${on({chatId:w.chatId,name:L,size:"sm"})}
|
|
264
|
+
<span class="kanban-cluster-name">${i(L)}</span>
|
|
265
265
|
<span class="kanban-cluster-count">${w.rows.length}</span>
|
|
266
266
|
</header>
|
|
267
|
-
${w.rows.map(
|
|
268
|
-
</div>`}).join(""),flat:
|
|
267
|
+
${w.rows.map(_).join("")}
|
|
268
|
+
</div>`}).join(""),flat:u}}function Xe(l){let c=new Map;for(let u of l){if(u.status==="closed")continue;let b=String(u.larkAppId||u.botName||"unknown"),w=c.get(b);w||(w={name:ye(u),larkAppId:u.larkAppId,rows:[]},c.set(b,w)),w.rows.push(u)}let f=[...c.values()].sort((u,b)=>u.name.localeCompare(b.name));return f.length?f.map(u=>{let b=u.rows.sort((L,C)=>Number(C.lastMessageAt??0)-Number(L.lastMessageAt??0)),{html:w}=he(b);return`<section class="kanban-column kanban-bot-col" data-bot="${i(u.larkAppId??u.name)}">
|
|
269
269
|
<header>
|
|
270
|
-
<span class="kanban-col-avatar">${
|
|
271
|
-
<h2>${i(
|
|
270
|
+
<span class="kanban-col-avatar">${fe({name:u.name,larkAppId:u.larkAppId,size:"sm"})}</span>
|
|
271
|
+
<h2>${i(u.name)}</h2>
|
|
272
272
|
<span class="kanban-col-count">${b.length}</span>
|
|
273
273
|
</header>
|
|
274
274
|
<div class="kanban-col-list">${w}</div>
|
|
275
|
-
</section>`}).join(""):`<div class="kanban-col-empty">${t("sessions.board.emptyColumn")}</div>`}function
|
|
275
|
+
</section>`}).join(""):`<div class="kanban-col-empty">${t("sessions.board.emptyColumn")}</div>`}function $e(l){let c=new Map(ta.map(u=>[u.id,[]]));for(let u of l)c.get(Xo(u)).push(u);let f=ta.map(u=>{let b=(c.get(u.id)??[]).sort((F,N)=>pt(F)-pt(N)),w=0;u.id==="done"&&b.length>jn&&(w=b.length-jn,b=b.slice(0,jn));let{html:L,flat:C}=he(b);return c.set(u.id,C),`<section class="kanban-column kanban-${u.id}" data-col="${u.id}">
|
|
276
276
|
<header>
|
|
277
|
-
<span class="kanban-col-icon">${
|
|
278
|
-
<h2>${i(t(
|
|
277
|
+
<span class="kanban-col-icon">${Xs(u.id)}</span>
|
|
278
|
+
<h2>${i(t(u.labelKey))}</h2>
|
|
279
279
|
<span class="kanban-col-count">${b.length+w}</span>
|
|
280
280
|
</header>
|
|
281
281
|
<div class="kanban-col-list">
|
|
282
|
-
${b.length?
|
|
282
|
+
${b.length?L:`<div class="kanban-col-empty">${t("sessions.board.emptyColumn")}</div>`}
|
|
283
283
|
${w?`<div class="kanban-col-more">${i(t("sessions.kanban.moreHidden",{count:w}))}</div>`:""}
|
|
284
284
|
</div>
|
|
285
|
-
</section>`}).join("");return
|
|
285
|
+
</section>`}).join("");return se=c,f}function Wt(l){if(X||ce||ae)return;T.classList.toggle("kanban-mode-bot",ie==="bot");let c;if(ie==="bot")c=Xe(l),se=new Map;else if(ie==="team")if(!ge)c=`<div class="kanban-loading">${t("sessions.kanban.teamLoading")}</div>`,se=new Map,O.dataset.loading||(O.dataset.loading="1",O.disabled=!0,O.innerHTML=`<option>${i(t("sessions.kanban.teamLoading"))}</option>`),pe();else{let u=de.find(N=>N.key===re)??de[0],b=[],w=new Set;if(u){for(let N of u.groupChats)w.add(N);if(Be)for(let[N,ee]of Be){if(w.has(N))continue;let me=!1;for(let ze of u.botIds)if(ee.botIds.has(ze)){me=!0;break}if(me){for(let ze of ee.observedNames)if(u.botNames.has(ze)){w.add(N);break}}}b=l.filter(N=>w.has(String(N.chatId)))}u&&be(u);let L=(Ne===u?.key?le?.board:null)??{},C=(Ne===u?.key?le?.remoteRows:null)??[],F=[...b,...C].map(N=>{let ee=L[N.sessionId];return ee?{...N,kanbanColumn:ee.column,kanbanPosition:ee.position}:N});M.textContent=t("sessions.kanban.teamScope",{chats:w.size,sessions:F.length}),c=$e(F)}else c=$e(l);if(c===q)return;q=c;let f=new Map;T.querySelectorAll(".kanban-col-list").forEach(u=>{let b=u.closest(".kanban-column")?.dataset.col;b&&u.scrollTop&&f.set(b,u.scrollTop)}),T.innerHTML=c,f.size&&T.querySelectorAll(".kanban-col-list").forEach(u=>{let b=u.closest(".kanban-column")?.dataset.col,w=b?f.get(b):void 0;w&&(u.scrollTop=w)})}async function ct(l,c,f,u){try{let b=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/board`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({column:c,position:f})}),w=await b.json().catch(()=>({}));(!b.ok||w?.ok===!1)&&(l.kanbanColumn=u.column,l.kanbanPosition=u.position,q="",Z(),b.status!==401&&alert(`${t("sessions.kanban.moveFail")}: ${w?.error??b.status}`))}catch(b){l.kanbanColumn=u.column,l.kanbanPosition=u.position,q="",Z(),alert(`${t("sessions.kanban.moveFail")}: ${b}`)}}async function Ze(l,c){let f=l.title;l.title=c,q="",Z();try{let u=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/rename`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({title:c})}),b=await u.json().catch(()=>({}));(!u.ok||b?.ok===!1)&&(l.title=f,q="",Z(),u.status!==401&&alert(`${t("sessions.kanban.renameFail")}: ${b?.error??u.status}`))}catch(u){l.title=f,q="",Z(),alert(`${t("sessions.kanban.renameFail")}: ${u}`)}}function yt(l){if(l==null||l==="")return"";let c=Number(l),f=Number.isFinite(c)&&c>0?new Date(c):new Date(String(l));return Number.isNaN(f.getTime())?"":f.toLocaleString()}function Ct(l,c,f){let u=c.senderType==="user",b=u?c.senderName||(f&&c.senderId===f?t("sessions.history.owner"):t("sessions.history.user")):ye(l),w=yt(c.createTime),L=String(c.content??"").trim()||`[${c.msgType??"message"}]`,C=u?c.senderAvatar?`<img class="history-avatar-img" src="${i(String(c.senderAvatar))}" alt="" decoding="async" referrerpolicy="no-referrer">`:`<span class="history-avatar-user" aria-hidden="true">${i(String(b).slice(0,1))}</span>`:fe({name:ye(l),larkAppId:l.larkAppId,size:"sm"});return`<div class="history-msg${u?" mine":""}">
|
|
286
286
|
${C}
|
|
287
287
|
<div class="history-msg-main">
|
|
288
288
|
<div class="history-msg-meta"><span>${i(b)}</span><time>${i(w)}</time></div>
|
|
289
|
-
<div class="history-bubble">${i(
|
|
289
|
+
<div class="history-bubble">${i(L)}</div>
|
|
290
290
|
</div>
|
|
291
|
-
</div>`}async function
|
|
291
|
+
</div>`}async function Se(l){let c=ye(l);R.innerHTML=`<div class="term-modal-head">
|
|
292
292
|
<span class="term-modal-title">
|
|
293
|
-
${
|
|
294
|
-
<strong title="${i(String(l.title??""))}">${i((
|
|
293
|
+
${fe({name:c,larkAppId:l.larkAppId,size:"sm"})}
|
|
294
|
+
<strong title="${i(String(l.title??""))}">${i((ve(l.title)||l.sessionId).slice(0,60))}</strong>
|
|
295
295
|
<span class="history-scope-tag">${i(t("sessions.history.title"))}</span>
|
|
296
296
|
</span>
|
|
297
297
|
<span class="term-modal-actions">
|
|
298
298
|
<button type="button" id="history-close" class="card-act" title="${i(t("sessions.dismiss"))}" aria-label="${i(t("sessions.dismiss"))}">${Ee.close}</button>
|
|
299
299
|
</span>
|
|
300
300
|
</div>
|
|
301
|
-
<div class="history-body"><div class="term-modal-loading">${t("sessions.history.loading")}</div></div>`,
|
|
301
|
+
<div class="history-body"><div class="term-modal-loading">${t("sessions.history.loading")}</div></div>`,R.showModal(),R.querySelector("#history-close").onclick=()=>R.close();try{let f=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/history?limit=80`),u=await f.json().catch(()=>({}));if(!R.open)return;let b=R.querySelector(".history-body");if(!f.ok||u?.ok===!1){let L=String(u?.error??f.status),C=L==="not_found_yet"||L==="not_found";b.innerHTML=`<div class="history-error">${i(t("sessions.history.fail"))}: ${i(L)}${C?`<br><span>${i(t("sessions.history.staleHint"))}</span>`:""}</div>`;return}let w=Array.isArray(u.messages)?u.messages:[];if(!w.length){b.innerHTML=`<div class="history-error">${t("sessions.history.empty")}</div>`;return}b.innerHTML=`<div class="history-list">${w.map(L=>Ct(l,L,u.ownerOpenId)).join("")}</div>`,b.scrollTop=b.scrollHeight}catch(f){if(!R.open)return;let u=R.querySelector(".history-body");u&&(u.innerHTML=`<div class="history-error">${i(t("sessions.history.fail"))}: ${i(String(f))}</div>`)}}function At(l,c){let f=l.querySelector(".kanban-card-title");if(!f||l.querySelector(".kanban-rename-input"))return;ae=!0;let u=document.createElement("input");u.type="text",u.className="kanban-rename-input",u.maxLength=200,u.value=ve(c.title)||"",f.replaceWith(u),u.focus(),u.select();let b=!1,w=L=>{if(b)return;b=!0,ae=!1;let C=u.value.trim();L&&C&&C!==(ve(c.title)||"")?Ze(c,C):(q="",Z())};u.addEventListener("keydown",L=>{L.stopPropagation(),L.key==="Enter"?(L.preventDefault(),w(!0)):L.key==="Escape"&&(L.preventDefault(),w(!1))}),u.addEventListener("blur",()=>w(!0)),u.addEventListener("click",L=>L.stopPropagation())}function vt(l,c){for(let f of l.querySelectorAll(".kanban-card:not(.dragging)")){if(f.closest(".kanban-cluster.dragging"))continue;let u=f.getBoundingClientRect();if(c<u.top+u.height/2)return f}return null}function $n(){T.querySelectorAll(".drag-over, .dragging, .drop-before").forEach(l=>l.classList.remove("drag-over","dragging","drop-before"))}function J(l){let c=g.querySelector(".term-modal-name");if(!c||g.querySelector(".term-modal-name-input"))return;let f=document.createElement("input");f.type="text",f.className="term-modal-name-input",f.maxLength=200,f.value=ve(l.title)||"",c.replaceWith(f);let u=()=>{let L=getComputedStyle(f),C=document.createElement("span");C.style.cssText="position:absolute;visibility:hidden;white-space:pre",C.style.fontSize=L.fontSize,C.style.fontFamily=L.fontFamily,C.style.fontWeight=L.fontWeight,C.style.letterSpacing=L.letterSpacing,C.textContent=f.value||" ",document.body.appendChild(C);let F=C.offsetWidth;C.remove();let N=Math.round(window.innerWidth*.6);f.style.width=`${Math.min(Math.max(F+22,80),N)}px`};u(),f.addEventListener("input",u),f.focus(),f.select();let b=!1,w=L=>{if(b)return;b=!0;let C=f.value.trim(),F=ve(l.title)||"";if(L&&C&&C!==F){l.title=C;let N=document.createElement("strong");N.className="term-modal-name",N.title=C,N.textContent=C.slice(0,60),f.replaceWith(N),Ze(l,C)}else{let N=document.createElement("strong");N.className="term-modal-name",N.title=String(l.title??F),N.textContent=F.slice(0,60),f.replaceWith(N)}};f.addEventListener("keydown",L=>{L.stopPropagation(),L.key==="Enter"?(L.preventDefault(),w(!0)):L.key==="Escape"&&(L.preventDefault(),w(!1))}),f.addEventListener("blur",()=>w(!0))}async function z(l){let c=Fn(l);if(!c){Kt(l);return}let f=ve(l.title)||l.sessionId,u=l.feishuChatLink?`<a class="card-act" href="${i(l.feishuChatLink)}" target="_blank" rel="noopener" title="${i(t("sessions.kanban.openFeishu"))}" aria-label="${i(t("sessions.kanban.openFeishu"))}">${Ee.feishu}</a>`:"";g.innerHTML=`<div class="term-modal-head">
|
|
302
302
|
<span class="term-modal-title">
|
|
303
|
-
${
|
|
303
|
+
${fe({name:ye(l),larkAppId:l.larkAppId,size:"sm"})}
|
|
304
304
|
<strong class="term-modal-name" title="${i(String(l.title??f))}">${i(String(f).slice(0,60))}</strong>
|
|
305
305
|
<button type="button" id="term-modal-edit" class="card-act" title="${i(t("sessions.kanban.rename"))}" aria-label="${i(t("sessions.kanban.rename"))}">${Ee.edit}</button>
|
|
306
306
|
<span class="status status-${i(l.status??"unknown")}">${i(l.status??"unknown")}</span>
|
|
307
307
|
</span>
|
|
308
308
|
<span class="term-modal-actions">
|
|
309
|
-
${
|
|
310
|
-
<a id="term-modal-tab" class="card-act" href="${i(
|
|
309
|
+
${u}
|
|
310
|
+
<a id="term-modal-tab" class="card-act" href="${i(c)}" target="_blank" rel="noopener" title="${i(t("sessions.kanban.openTab"))}" aria-label="${i(t("sessions.kanban.openTab"))}">${Ee.terminal}</a>
|
|
311
311
|
<button type="button" id="term-modal-close" class="card-act" title="${i(t("sessions.dismiss"))}" aria-label="${i(t("sessions.dismiss"))}">${Ee.close}</button>
|
|
312
312
|
</span>
|
|
313
313
|
</div>
|
|
314
|
-
<div class="term-modal-body"><div class="term-modal-loading">${t("sessions.kanban.terminalLoading")}</div></div>`,g.showModal(),g.querySelector("#term-modal-close").onclick=()=>g.close(),g.querySelector("#term-modal-edit").onclick=()=>
|
|
314
|
+
<div class="term-modal-body"><div class="term-modal-loading">${t("sessions.kanban.terminalLoading")}</div></div>`,g.showModal(),g.querySelector("#term-modal-close").onclick=()=>g.close(),g.querySelector("#term-modal-edit").onclick=()=>J(l);let b=c;if(Te.authed)try{let C=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/write-link`),F=await C.json().catch(()=>({}));C.ok&&F?.ok!==!1&&F?.url&&(b=F.url)}catch{}if(!g.open)return;let w=g.querySelector(".term-modal-body");w.innerHTML=`<iframe class="term-modal-frame" src="${i(b)}" allow="clipboard-read; clipboard-write"></iframe>`;let L=g.querySelector("#term-modal-tab");L&&(L.href=b)}function P(){let l=new FormData(o),c=(l.get("q")??"").toLowerCase(),f=l.getAll("cli"),u=f.length>0&&f.length<ia.length,b=l.get("status"),w=l.get("adopt"),L=!!l.get("active"),C=y==="kanban",F=[...Q.sessions.values()].filter(N=>!u||f.includes(N.cliId??"unknown")).filter(N=>!b||N.status===b).filter(N=>!w||w==="yes"==!!N.adopt).filter(N=>!L||C||N.status!=="closed").filter(N=>!c||JSON.stringify(N).toLowerCase().includes(c));return F.sort(G),F}function W(l,c){return c==="spawnedAt"||c==="lastMessageAt"?Number(l[c]??0):c==="tokenIn"?_n(l.tokenUsage?.in)??-1:c==="tokenOut"?_n(l.tokenUsage?.out)??-1:c==="adopt"?!!l.adopt:String(l[c]??"").toLowerCase()}function G(l,c){let f=W(l,D),u=W(c,D),b=0;return typeof f=="number"&&typeof u=="number"?b=f-u:typeof f=="boolean"&&typeof u=="boolean"?b=Number(f)-Number(u):b=String(f).localeCompare(String(u)),b===0&&(b=Number(l.lastMessageAt??0)-Number(c.lastMessageAt??0)),m==="asc"?b:-b}function Y(){k.querySelectorAll("th[data-sort]").forEach(l=>{let c=l.dataset.sort===D;l.classList.toggle("sorted",c),l.setAttribute("aria-sort",c?m==="asc"?"ascending":"descending":"none");let f=l.dataset.label??l.textContent?.trim()??"";l.textContent=c?`${f} ${m==="asc"?"\u25B2":"\u25BC"}`:f})}function ue(l){r.hidden=$.size===0,d.textContent=t("sessions.selectedCount",{count:$.size});let c=l.filter(u=>u.status!=="closed");if(c.length===0){a.checked=!1,a.indeterminate=!1,a.disabled=!0;return}a.disabled=!1;let f=c.filter(u=>$.has(u.sessionId)).length;a.checked=f===c.length,a.indeterminate=f>0&&f<c.length}function De(){E.forEach(l=>{let c=l.dataset.view===y;l.classList.toggle("active",c),l.setAttribute("aria-pressed",String(c))}),A.hidden=y!=="kanban",O.hidden=!(y==="kanban"&&ie==="team"),M.hidden=O.hidden||!ge,A.querySelectorAll("[data-groupby]").forEach(l=>{let c=l.dataset.groupby===ie;l.classList.toggle("active",c),l.setAttribute("aria-pressed",String(c))})}function ut(){let l=o.querySelector("#cli-filter-count");if(!l)return;let c=[...o.querySelectorAll('input[name="cli"]')],f=c.filter(u=>u.checked).length;l.textContent=f===c.length?t("common.all"):`${f}/${c.length}`,l.classList.toggle("cli-filter-active",f!==c.length)}function Z(){let l=P();for(let u of[...$]){let b=Q.sessions.get(u);(!b||b.status==="closed")&&$.delete(u)}let c=l.filter(u=>u.status!=="closed"),f=y==="table"?l:c;if(k.hidden=y!=="table",I.hidden=y!=="board",T.hidden=y!=="kanban",y==="table"){let u=l.length?l.map(Me).join(""):`<tr><td colspan="12" class="empty">${t("sessions.empty")}</td></tr>`;u!==j&&(j=u,n.innerHTML=u)}else y==="kanban"?Wt(l):K(c);De(),Y(),ut(),ue(f)}async function fo(l,c){c&&(c.disabled=!0,c.textContent=t("sessions.locating"));try{let f=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/locate`,{method:"POST"}),u=await f.json();if(u.ok){if(!c)return;let b=30;c.textContent=t("sessions.cooldown",{seconds:b});let w=setInterval(()=>{b-=1,b<=0?(clearInterval(w),c.disabled=!1,c.textContent=t("sessions.locate")):c.textContent=t("sessions.cooldown",{seconds:b})},1e3)}else alert(`Locate failed: ${u.error??f.status}`),c&&(c.disabled=!1,c.textContent=t("sessions.locate"))}catch(f){alert(`Locate error: ${f}`),c&&(c.disabled=!1,c.textContent=t("sessions.locate"))}}async function go(l,c){if(!confirm(t("sessions.closeConfirm")))return!1;c&&(c.disabled=!0);try{let f=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/close`,{method:"POST"}),u=await f.json().catch(()=>({}));return!f.ok||u?.ok===!1?(f.status!==401&&alert(`Close failed: ${u?.error??f.status}`),!1):!0}catch(f){return alert(`Close error: ${f}`),!1}finally{c&&(c.disabled=!1)}}function Kt(l){let c=l.status==="closed",f=Fn(l);s.innerHTML=`<article>
|
|
315
315
|
<header>
|
|
316
|
-
<h3>${i(
|
|
316
|
+
<h3>${i(ve(l.title)||l.sessionId)}</h3>
|
|
317
317
|
<span class="status status-${i(l.status??"unknown")}">${i(l.status??"unknown")}</span>
|
|
318
318
|
<p><code>${i(l.sessionId)}</code> <button data-copy="${i(l.sessionId)}">${t("sessions.copy")}</button></p>
|
|
319
319
|
</header>
|
|
320
|
-
<p><b>${t("sessions.bot")}:</b> ${i(
|
|
321
|
-
${
|
|
320
|
+
<p><b>${t("sessions.bot")}:</b> ${i(ye(l))} \xB7 <b>${t("sessions.cli")}:</b> ${i(l.cliId??"?")}</p>
|
|
321
|
+
${st(l)?`<p><b>${t("sessions.chat")}:</b> ${i(st(l))}</p>`:""}
|
|
322
322
|
<p><b>chatId:</b> <code>${i(l.chatId??"")}</code> <button data-copy="${i(l.chatId??"")}">${t("sessions.copy")}</button></p>
|
|
323
323
|
<p><b>rootMessageId:</b> <code>${i(l.rootMessageId??"")}</code> <button data-copy="${i(l.rootMessageId??"")}">${t("sessions.copy")}</button></p>
|
|
324
324
|
${l.threadId?`<p><b>threadId:</b> <code>${i(l.threadId)}</code></p>`:""}
|
|
325
325
|
<p><b>${t("sessions.workingDir")}:</b> ${i(l.workingDir??"-")}</p>
|
|
326
326
|
<div class="actions">
|
|
327
|
-
${
|
|
327
|
+
${_e(l)??`<button id="locate-btn" type="button">${t("sessions.locate")}</button>`}
|
|
328
328
|
<button id="history-drawer-btn" type="button">${t("sessions.history.title")}</button>
|
|
329
|
-
${
|
|
330
|
-
${
|
|
331
|
-
${
|
|
329
|
+
${aa(f)}
|
|
330
|
+
${c?`<button id="resume-btn" type="button" class="primary">${t("sessions.resume")}</button>`:""}
|
|
331
|
+
${c?"":`<button id="close-btn" type="button" class="contrast">${t("sessions.close")}</button>`}
|
|
332
332
|
<button id="land-btn" type="button">${t("sessions.land")}</button>
|
|
333
333
|
</div>
|
|
334
334
|
<div id="land-area"></div>
|
|
335
335
|
<form method="dialog"><button>${t("sessions.dismiss")}</button></form>
|
|
336
|
-
</article>`,s.querySelectorAll("[data-copy]").forEach(
|
|
336
|
+
</article>`,s.querySelectorAll("[data-copy]").forEach(ee=>{ee.onclick=()=>{navigator.clipboard.writeText(ee.dataset.copy??""),ee.textContent=t("sessions.copied"),setTimeout(()=>{ee.textContent=t("sessions.copy")},800)}});let u=s.querySelector("#locate-btn");u&&(u.onclick=()=>{fo(l,u)});let b=s.querySelector("#history-drawer-btn");b&&(b.onclick=()=>{Se(l)});let w=s.querySelector(".term-write");w&&(w.onclick=()=>{sa(l,w)});let L=s.querySelector("#resume-btn");L&&(L.onclick=async()=>{L.disabled=!0;try{let ee=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/resume`,{method:"POST"}),me=await ee.json().catch(()=>({}));if(!ee.ok||me.ok===!1){alert(`${t("sessions.resumeFailed")}: ${me?.error??ee.status}`),L.disabled=!1;return}s.close()}catch(ee){alert(`${t("sessions.resumeFailed")}: ${ee}`),L.disabled=!1}});let C=s.querySelector("#close-btn");C&&(C.onclick=async()=>{await go(l,C)&&s.close()});let F=s.querySelector("#land-btn"),N=s.querySelector("#land-area");F&&N&&(F.onclick=async()=>{F.disabled=!0,N.innerHTML=`<p>${t("sessions.landLoading")}</p>`;try{let ee=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/sandbox-diff`),me=await ee.json().catch(()=>({}));if(!me.ok){N.innerHTML=`<p>${t("sessions.landUnavailable")}: ${i(me.error??String(ee.status))}</p>`,F.disabled=!1;return}if(me.empty){N.innerHTML=`<p>${t("sessions.landEmpty")}</p>`,F.disabled=!1;return}let ze=String(me.patch??""),Sn=ze.slice(0,2e4)+(ze.length>2e4?`
|
|
337
337
|
\u2026(truncated)`:"");N.innerHTML=`
|
|
338
|
-
<p><b>${
|
|
339
|
-
<pre style="max-height:320px;overflow:auto;white-space:pre-wrap">${i(
|
|
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(Sn)}</pre>
|
|
340
340
|
<div class="actions">
|
|
341
341
|
<button id="land-apply" type="button" class="primary">${t("sessions.landApply")}</button>
|
|
342
342
|
<button id="land-discard" type="button" class="contrast">${t("sessions.landDiscard")}</button>
|
|
343
|
-
</div>`;let
|
|
343
|
+
</div>`;let We=N.querySelector("#land-apply"),Yt=N.querySelector("#land-discard");We.onclick=async()=>{We.disabled=!0,Yt.disabled=!0;let et=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/sandbox-land/apply`,{method:"POST"}),Re=await et.json().catch(()=>({}));N.innerHTML=Re.ok?`<p>\u2705 ${t("sessions.landApplied")}: ${Re.files} files (+${Re.insertions}/-${Re.deletions}) \u2192 <code>${i(String(Re.workingDir??""))}</code></p>`:`<p>\u274C ${t("sessions.landFailed")}: ${i(Re.error??String(et.status))}</p>`},Yt.onclick=async()=>{await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/sandbox-land/discard`,{method:"POST"}),N.innerHTML=`<p>\u{1F5D1} ${t("sessions.landDiscarded")}</p>`}}catch(ee){N.innerHTML=`<p>${t("sessions.landUnavailable")}: ${i(String(ee))}</p>`,F.disabled=!1}}),s.showModal()}n.addEventListener("click",l=>{let c=l.target;if(c.classList.contains("row-select")){let w=c.closest("tr[data-id]");if(!w)return;c.checked?$.add(w.dataset.id):$.delete(w.dataset.id),ue(P());return}let f=c.closest("td");if(f&&f.querySelector(".row-select"))return;let u=c.closest("tr[data-id]");if(!u)return;let b=Q.sessions.get(u.dataset.id);b&&Kt(b)}),I.addEventListener("click",l=>{let c=l.target,f=c.closest("button[data-move-col]");if(f){Ht(f.dataset.moveCol,Number(f.dataset.dir));return}let u=c.closest(".session-card[data-id]");if(!u)return;let b=Q.sessions.get(u.dataset.id);if(!b)return;let w=c.closest("button[data-action]");if(w){let L=w.dataset.action;L==="details"?Kt(b):L==="write-link"?sa(b,w):L==="locate"?fo(b,w):L==="close"&&go(b,w).then(C=>{C&&($.delete(b.sessionId),Z())});return}c.closest("a, button, input, label")||($.has(b.sessionId)?$.delete(b.sessionId):$.add(b.sessionId),u.classList.toggle("selected",$.has(b.sessionId)),u.setAttribute("aria-pressed",String($.has(b.sessionId))),ue(P().filter(L=>L.status!=="closed")))}),I.addEventListener("dragstart",l=>{let f=l.target.closest(".session-board-column > header[draggable]")?.closest(".session-board-column");f?.dataset.col&&(H=f.dataset.col,f.classList.add("dragging"),l.dataTransfer&&(l.dataTransfer.effectAllowed="move",l.dataTransfer.setData("text/plain",H)))}),I.addEventListener("dragover",l=>{if(!H)return;l.preventDefault(),l.dataTransfer&&(l.dataTransfer.dropEffect="move");let c=l.target.closest(".session-board-column");I.querySelectorAll(".drag-over").forEach(f=>f.classList.remove("drag-over")),c&&c.dataset.col!==H&&c.classList.add("drag-over")}),I.addEventListener("drop",l=>{if(!H)return;l.preventDefault();let c=l.target.closest(".session-board-column"),f=H;H=null,c?.dataset.col&&at(f,c.dataset.col)}),I.addEventListener("dragend",()=>{H=null,I.querySelectorAll(".drag-over, .dragging").forEach(l=>l.classList.remove("drag-over","dragging"))}),E.forEach(l=>{l.addEventListener("click",()=>{let c=xn(l.dataset.view)??"board";c!==y&&(y=c,Mo(window.localStorage,y),Z())})}),A.querySelectorAll("[data-groupby]").forEach(l=>{l.addEventListener("click",()=>{let c=l.dataset.groupby,f=c==="bot"?"bot":c==="team"?"team":"flow";f!==ie&&(ie=f,Ho(window.localStorage,f),q="",Z())})}),O.addEventListener("change",()=>{re=O.value;try{window.localStorage.setItem(Hn,re)}catch{}q="",Z()});function Jt(){Ae!==null&&(clearTimeout(Ae),Ae=null)}T.addEventListener("click",l=>{let c=l.target,f=c.closest(".kanban-card[data-id]");if(!f)return;let u=Q.sessions.get(f.dataset.id);if(!u)return;let b=c.closest("button[data-action]");if(b){b.dataset.action==="details"?Kt(u):b.dataset.action==="rename"?At(f,u):b.dataset.action==="history"&&Se(u);return}c.closest("a, button, input, label")||(Jt(),Ae=setTimeout(()=>{Ae=null,z(u)},220))}),T.addEventListener("dblclick",l=>{let c=l.target,f=c.closest(".kanban-card-title"),u=c.closest(".kanban-card[data-id]");if(!f||!u)return;Jt();let b=Q.sessions.get(u.dataset.id);b&&At(u,b)}),T.addEventListener("keydown",l=>{if(l.key!=="Enter"&&l.key!==" ")return;let c=l.target;if(!c.classList?.contains("kanban-card"))return;l.preventDefault();let f=Q.sessions.get(c.dataset.id);f&&z(f)}),T.addEventListener("dragstart",l=>{if(ie==="bot")return;let c=l.target,f=c.closest(".kanban-cluster > header[draggable]");if(f){let b=f.closest(".kanban-cluster"),w=b.closest(".kanban-column")?.dataset.col;if(!b.dataset.chat||!w)return;Jt(),ce=b.dataset.chat,Le=w,b.classList.add("dragging"),l.dataTransfer&&(l.dataTransfer.effectAllowed="move",l.dataTransfer.setData("text/plain",`cluster:${ce}`));return}let u=c.closest(".kanban-card[data-id]");u&&(Jt(),X=u.dataset.id,u.classList.add("dragging"),l.dataTransfer&&(l.dataTransfer.effectAllowed="move",l.dataTransfer.setData("text/plain",X)))}),T.addEventListener("dragover",l=>{if(!X&&!ce)return;l.preventDefault(),l.dataTransfer&&(l.dataTransfer.dropEffect="move");let c=l.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")),c&&(c.classList.add("drag-over"),vt(c,l.clientY)?.classList.add("drop-before"))}),T.addEventListener("drop",l=>{let c=ce,f=Le,u=X;if(!u&&!c)return;l.preventDefault(),X=null,ce=null,Le=null,$n();let b=l.target.closest(".kanban-column"),w=b?.dataset.col;if(!b||!w)return;let L=vt(b,l.clientY);if(c&&f){let We=(se.get(f)??[]).filter(we=>String(we.chatId)===c).filter(we=>!(we.status==="closed"&&w!=="done"));if(!We.length)return;let Yt=new Set(We.map(we=>we.sessionId)),et=(se.get(w)??[]).filter(we=>!Yt.has(we.sessionId)),Re=L?et.findIndex(we=>we.sessionId===L.dataset.id):et.length;Re<0&&(Re=et.length);let bo=Re>0?et[Re-1]:null,ho=Re<et.length?et[Re]:null,rs=Un(bo?pt(bo):null,ho?pt(ho):null);We.forEach((we,ls)=>{let Tn=rs+ls*.001;if(ie==="team")wt(String(we.sessionId),w,Tn);else{let ds={column:we.kanbanColumn,position:we.kanbanPosition};we.kanbanColumn=w,we.kanbanPosition=Tn,ct(we,w,Tn,ds)}}),q="",Z();return}let C=Q.sessions.get(u)??Fe.get(u);if(!C||C.status==="closed"&&w!=="done")return;let F=(se.get(w)??[]).filter(We=>We.sessionId!==u),N=L?F.findIndex(We=>We.sessionId===L.dataset.id):F.length;N<0&&(N=F.length);let ee=N>0?F[N-1]:null,me=N<F.length?F[N]:null,ze=Un(ee?pt(ee):null,me?pt(me):null);if(ie==="team"){wt(String(C.sessionId),w,ze),q="",Z();return}let Sn={column:C.kanbanColumn,position:C.kanbanPosition};C.kanbanColumn=w,C.kanbanPosition=ze,q="",Z(),ct(C,w,ze,Sn)}),T.addEventListener("dragend",()=>{X=null,ce=null,Le=null,$n(),q="",Z()}),g.addEventListener("click",l=>{l.target===g&&g.close()}),g.addEventListener("close",()=>{g.innerHTML=""}),R.addEventListener("click",l=>{l.target===R&&R.close()}),R.addEventListener("close",()=>{R.innerHTML=""}),a.addEventListener("change",()=>{let l=P().filter(c=>c.status!=="closed");for(let c of l)a.checked?$.add(c.sessionId):$.delete(c.sessionId);Z()}),v.addEventListener("click",()=>{$.clear(),Z()}),p.addEventListener("click",async()=>{let l=[...$];if(l.length===0||!confirm(t("sessions.closeBulkConfirm",{count:l.length})))return;p.disabled=!0,v.disabled=!0;let c=p.textContent,f=0,u=0,b=[...l];p.textContent=`0/${l.length}`;async function w(){for(;b.length;){let L=b.shift();try{let C=await fetch(`/api/sessions/${encodeURIComponent(L)}/close`,{method:"POST"}),F=await C.json().catch(()=>({}));(!C.ok||F?.ok===!1)&&(u+=1)}catch{u+=1}finally{f+=1,p.textContent=`${f}/${l.length}`}}}await Promise.all(Array.from({length:Math.min(6,l.length)},()=>w())),p.textContent=c,p.disabled=!1,v.disabled=!1,$.clear(),Z(),u>0&&alert(`Failed: ${u}/${l.length}`)}),k.querySelectorAll("th[data-sort]").forEach(l=>{l.addEventListener("click",()=>{let c=l.dataset.sort;D===c?m=m==="asc"?"desc":"asc":(D=c,m=c==="spawnedAt"||c==="lastMessageAt"?"desc":"asc"),Z()})}),o.addEventListener("input",Z),Q.on(Z);let is=setInterval(()=>{if(!document.body.contains(T)){clearInterval(is);return}y==="kanban"&&ie==="team"&&(q="",Z())},3e4);Z(),Ke().then(Z)}function ni(){return`<section class="page">
|
|
344
344
|
<div class="page-heading">
|
|
345
345
|
<div>
|
|
346
346
|
<p class="eyebrow">${t("nav.schedules")}</p>
|
|
@@ -365,19 +365,19 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
365
365
|
</tr></thead>
|
|
366
366
|
<tbody id="schedules-tbody"></tbody>
|
|
367
367
|
</table>
|
|
368
|
-
</section>`}function
|
|
368
|
+
</section>`}function la(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function da(e){e.innerHTML=ni();let n=e.querySelector("#schedules-tbody"),o=e.querySelector("#sched-filters");function s(){let r=new FormData(o),d=(r.get("q")??"").toLowerCase(),p=r.get("kind"),v=!!r.get("enabled");return[...Q.schedules.values()].filter(k=>!p||k.parsed?.kind===p).filter(k=>!v||k.enabled).filter(k=>!d||JSON.stringify(k).toLowerCase().includes(d)).sort((k,I)=>{if(k.enabled!==I.enabled)return k.enabled?-1:1;let T=k.nextRunAt?Date.parse(k.nextRunAt):1/0,g=I.nextRunAt?Date.parse(I.nextRunAt):1/0;return T-g})}function a(){n.innerHTML=s().map(r=>`<tr data-id="${i(r.id)}">
|
|
369
369
|
<td>${i(r.name??r.id)}</td>
|
|
370
370
|
<td>${i(r.botName??r.larkAppId??"-")}</td>
|
|
371
371
|
<td><code>${i(r.parsed?.display??"?")}</code></td>
|
|
372
|
-
<td>${
|
|
373
|
-
<td>${
|
|
372
|
+
<td>${la(r.nextRunAt)}</td>
|
|
373
|
+
<td>${la(r.lastRunAt)} ${r.lastStatus==="error"?"\u26A0\uFE0F":""}</td>
|
|
374
374
|
<td>${r.repeat?`${r.repeat.completed}/${r.repeat.times??"\u221E"}`:"\u2014"}</td>
|
|
375
375
|
<td>${r.enabled?"\u2713":"\u2717"}</td>
|
|
376
376
|
<td class="actions-cell">
|
|
377
377
|
<button data-op="run" type="button">${t("schedules.runNow")}</button>
|
|
378
378
|
${r.enabled?`<button data-op="pause" type="button">${t("schedules.pause")}</button>`:`<button data-op="resume" type="button">${t("schedules.resume")}</button>`}
|
|
379
379
|
</td>
|
|
380
|
-
</tr>`).join("")||`<tr><td colspan="8" class="empty">${t("schedules.empty")}</td></tr>`}n.addEventListener("click",async r=>{let
|
|
380
|
+
</tr>`).join("")||`<tr><td colspan="8" class="empty">${t("schedules.empty")}</td></tr>`}n.addEventListener("click",async r=>{let d=r.target.closest("button[data-op]");if(!d)return;let p=d.closest("tr[data-id]");if(!p)return;let v=p.dataset.id,k=d.dataset.op;d.disabled=!0;let I=d.textContent;d.textContent="...";try{let T=await fetch(`/api/schedules/${encodeURIComponent(v)}/${k}`,{method:"POST"}),g=await T.json().catch(()=>({}));(!T.ok||g.ok===!1)&&alert(`Failed: ${T.status} ${g?.error??""}`.trim())}catch(T){alert("Network error: "+T)}finally{d.disabled=!1,d.textContent=I}}),o.addEventListener("input",a),Q.on(a),a()}var He={chats:[],bots:[]};function oi(){return`<section class="page">
|
|
381
381
|
<div class="page-heading">
|
|
382
382
|
<div>
|
|
383
383
|
<p class="eyebrow">${t("nav.groups")}</p>
|
|
@@ -391,7 +391,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
391
391
|
<button type="button" id="g-refresh">${t("groups.refresh")}</button>
|
|
392
392
|
<button type="button" id="g-create" class="primary">${t("groups.create")}</button>
|
|
393
393
|
</form>
|
|
394
|
-
<div id="g-loading">${
|
|
394
|
+
<div id="g-loading">${St()}</div>
|
|
395
395
|
<div class="table-scroll matrix-scroll" id="g-table-wrap" hidden>
|
|
396
396
|
<table>
|
|
397
397
|
<thead id="g-head"></thead>
|
|
@@ -399,12 +399,12 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
399
399
|
</table>
|
|
400
400
|
</div>
|
|
401
401
|
<dialog id="g-drawer"></dialog>
|
|
402
|
-
</section>`}async function
|
|
402
|
+
</section>`}async function Tt(){He=await(await fetch("/api/groups")).json()}async function ai(){return(await fetch("/api/groups")).json()}function si(e,n){if(n.size===0)return!0;let o=e?.memberBots??[];for(let s of n)if(!o.some(a=>a.larkAppId===s&&a.inChat))return!1;return!0}function ca(e,n){return e.filter(o=>!n||!n.has(o.larkAppId)).map(o=>`
|
|
403
403
|
<label class="checkbox-row">
|
|
404
404
|
<input type="checkbox" name="bot" value="${i(o.larkAppId)}">
|
|
405
405
|
${i(o.botName??o.larkAppId)} <small>(${i(o.larkAppId)})</small>
|
|
406
406
|
</label>
|
|
407
|
-
`).join("")}async function
|
|
407
|
+
`).join("")}async function ua(e){e.innerHTML=oi();let n=e.querySelector("#g-head"),o=e.querySelector("#g-body"),s=e.querySelector("#g-filters"),a=e.querySelector("#g-refresh"),r=e.querySelector("#g-drawer");a.onclick=async()=>{a.disabled=!0;try{await Tt(),g()}finally{a.disabled=!1}};let d=e.querySelector("#g-create");d.onclick=()=>k();let p=e.querySelector("#g-loading"),v=e.querySelector("#g-table-wrap");try{await Tt()}finally{p.remove(),v.hidden=!1}function k(){let A=He.bots;if(A.length===0){alert(t("groups.noBotsOnline"));return}r.innerHTML=`
|
|
408
408
|
<article>
|
|
409
409
|
<header><h3>${t("groups.createTitle")}</h3></header>
|
|
410
410
|
<p>${t("groups.createHelp")}</p>
|
|
@@ -420,75 +420,75 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
420
420
|
</label>
|
|
421
421
|
<fieldset>
|
|
422
422
|
<legend>${t("groups.botPicker")}</legend>
|
|
423
|
-
${
|
|
423
|
+
${ca(A)}
|
|
424
424
|
</fieldset>
|
|
425
425
|
<div class="actions">
|
|
426
426
|
<button type="submit" class="primary">${t("groups.createSubmit")}</button>
|
|
427
427
|
<button type="button" id="g-create-cancel">${t("groups.cancel")}</button>
|
|
428
428
|
</div>
|
|
429
429
|
</form>
|
|
430
|
-
</article>`,r.showModal(),r.querySelector("#g-create-cancel").onclick=()=>r.close(),r.querySelector("#g-createform").onsubmit=async
|
|
430
|
+
</article>`,r.showModal(),r.querySelector("#g-create-cancel").onclick=()=>r.close(),r.querySelector("#g-createform").onsubmit=async E=>{E.preventDefault();let $=new FormData(E.target),D=($.get("name")??"").trim(),m=($.get("bindWorkingDir")??"").trim(),y=$.getAll("bot");if(y.length===0){alert("Pick at least one bot.");return}let S=E.target.querySelector("button[type=submit]");S&&(S.disabled=!0,S.textContent="Creating...");try{let H=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:D||void 0,larkAppIds:y,bindWorkingDir:m||void 0})}),B=await H.json();if(B.ok&&B.chatId){I(B);let j=Array.isArray(B.invalidBotIds)?B.invalidBotIds:[],q=y.filter(X=>!j.includes(X)),oe=new Set(q);typeof B.creator=="string"&&B.creator&&oe.add(B.creator),O(B.chatId,D||B.chatId,q,B.creator),g(),M(B.chatId,oe).catch(()=>{})}else alert(`Failed: ${B.error??H.status}`),r.close()}catch(H){alert("Network error: "+H),r.close()}};function O(E,$,D,m){let y=new Set(D);m&&y.add(m);let S=He.bots.map(B=>({larkAppId:B.larkAppId,botName:B.botName,inChat:y.has(B.larkAppId),oncallChat:null})),H={chatId:E,name:$,ownerId:m??null,memberBots:S};He.chats=[H,...He.chats.filter(B=>B.chatId!==E)]}async function M(E,$){let D=[600,1200,1200,1200,1200,1200];for(let m of D){await new Promise(H=>setTimeout(H,m));let y;try{y=await ai()}catch{continue}let S=(y.chats??[]).find(H=>H.chatId===E);if(S&&si(S,$)){He=y,g();return}}}}function I(A){let O=String(A.chatId),M=typeof A.shareLink=="string"&&A.shareLink?A.shareLink:`https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(O)}`,E=A.invalidBotIds??[],$=A.invalidUserIds??[],D=A.autoInvitedOpenId,m=!!A.autoInviteRejected,y=A.ownerTransferredTo,S=A.transferError,H=A.notifyMessageId,B=A.notifyError,j=Array.isArray(A.oncallBindings)?A.oncallBindings:[],q=j.filter(se=>se?.ok).length,oe=j.filter(se=>!se?.ok),X=j.length>0?oe.length===0?`<p class="hint-ok">\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1A<code>${i(A.bindResolvedPath??"")}</code>\uFF08${q}/${j.length} bots\uFF09</p>`:`<p class="hint-warn">\u76EE\u5F55\u7ED1\u5B9A\u90E8\u5206\u5931\u8D25\uFF1A\u6210\u529F ${q}/${j.length}\u3002${oe.map(se=>`<br><code>${i(se.larkAppId??"?")}</code>: ${i(se.error??"unknown")}`).join("")}</p>`:"",ae;if(D){let se=y?"<br><small>\u7FA4\u4E3B\u5DF2\u4ECE\u673A\u5668\u4EBA\u8F6C\u8BA9\u7ED9\u4F60\u3002</small>":S?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08${i(S)}\uFF09\uFF0C\u4F60\u73B0\u5728\u662F\u6210\u5458\u4F46\u7FA4\u4E3B\u4ECD\u662F\u673A\u5668\u4EBA\u3002</small>`:"",ie=H?`<br><small>\u673A\u5668\u4EBA\u5DF2\u5728\u7FA4\u91CC @ \u4E86\u4F60\uFF08\u6D88\u606F id <code>${i(H)}</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>`:"";ae=`<p class="hint-ok">\u5DF2\u81EA\u52A8\u9080\u8BF7\u4F60\uFF08<code>${i(D)}</code>\uFF09\u4F5C\u4E3A\u6210\u5458\u3002${se}${ie}</p>`}else m?ae='<p class="hint-warn">\u98DE\u4E66\u62D2\u7EDD\u4E86\u81EA\u52A8\u9080\u8BF7\uFF08\u4F60\u7684 open_id \u5728\u521B\u5EFA\u8005 bot \u7684 scope \u4E0B\u4E0D\u53EF\u7528\uFF09\u3002<strong>\u4F60\u76EE\u524D\u4E0D\u662F\u65B0\u7FA4\u6210\u5458</strong>\uFF0C\u9700\u8981\u8BA9\u7FA4\u91CC\u7684\u67D0\u4E2A\u673A\u5668\u4EBA\u624B\u52A8\u628A\u4F60\u52A0\u8FDB\u6765\u3002</p>':ae='<p class="hint-warn">\u6CA1\u5728 dashboard \u7F13\u5B58\u91CC\u627E\u5230 ownerOpenId\uFF0C<strong>\u6CA1\u6709\u81EA\u52A8\u9080\u8BF7\u4F60</strong>\u3002\u70B9\u5F00\u4E0B\u9762\u94FE\u63A5\u524D\uFF0C\u5148\u8BA9\u7FA4\u91CC\u4EFB\u4E00\u673A\u5668\u4EBA\u624B\u52A8\u628A\u4F60\u52A0\u8FDB\u53BB\u3002</p>';let Ae=[E.length?`<li>\u65E0\u6548 bot id: <code>${E.map(i).join(", ")}</code></li>`:"",$.length?`<li>\u65E0\u6548\u7528\u6237 open_id: <code>${$.map(i).join(", ")}</code></li>`:""].filter(Boolean).join("");r.innerHTML=`
|
|
431
431
|
<article>
|
|
432
432
|
<header><h3>${t("groups.successTitle")}</h3></header>
|
|
433
|
-
<p><b>chatId:</b> <code>${i(
|
|
434
|
-
<p><b>\u521B\u5EFA\u8005:</b> <code>${i(
|
|
435
|
-
${
|
|
436
|
-
${
|
|
437
|
-
${
|
|
433
|
+
<p><b>chatId:</b> <code>${i(O)}</code> <button type="button" data-copy="${i(O)}">${t("sessions.copy")}</button></p>
|
|
434
|
+
<p><b>\u521B\u5EFA\u8005:</b> <code>${i(A.creator??"?")}</code></p>
|
|
435
|
+
${ae}
|
|
436
|
+
${X}
|
|
437
|
+
${Ae?`<ul>${Ae}</ul>`:""}
|
|
438
438
|
<div class="actions">
|
|
439
|
-
<a class="btn-link primary" href="${
|
|
439
|
+
<a class="btn-link primary" href="${M}" target="_blank" rel="noopener">${t("groups.openGroup")}</a>
|
|
440
440
|
<button type="button" id="g-create-close">${t("sessions.dismiss")}</button>
|
|
441
441
|
</div>
|
|
442
|
-
</article>`,r.querySelectorAll("[data-copy]").forEach(
|
|
442
|
+
</article>`,r.querySelectorAll("[data-copy]").forEach(se=>{se.onclick=()=>{navigator.clipboard.writeText(se.dataset.copy??""),se.textContent=t("sessions.copied"),setTimeout(()=>{se.textContent=t("sessions.copy")},800)}}),r.querySelector("#g-create-close").onclick=()=>r.close()}function T(){n.innerHTML=`<tr>
|
|
443
443
|
<th>${t("groups.chat")}</th>
|
|
444
|
-
${
|
|
444
|
+
${He.bots.map(A=>`<th>${i(A.botName??A.larkAppId)}</th>`).join("")}
|
|
445
445
|
<th>${t("groups.actions")}</th>
|
|
446
|
-
</tr>`}function g(){
|
|
446
|
+
</tr>`}function g(){T();let A=new FormData(s),O=(A.get("q")??"").toLowerCase(),M=!!A.get("missing"),E=He.chats.filter($=>!O||($.name??"").toLowerCase().includes(O)||$.chatId.toLowerCase().includes(O)||($.ownerId??"").toLowerCase().includes(O)).filter($=>!M||$.memberBots.some(D=>!D.inChat));if(E.length===0){o.innerHTML=`<tr><td colspan="${He.bots.length+2}" class="empty">${t("groups.empty")}</td></tr>`;return}o.innerHTML=E.map($=>`<tr data-chat="${i($.chatId)}">
|
|
447
447
|
<td>
|
|
448
448
|
<div class="g-chat-cell">
|
|
449
|
-
${
|
|
449
|
+
${on({chatId:$.chatId,name:$.name,avatarUrl:$.avatar,size:"sm"})}
|
|
450
450
|
<div class="g-chat-meta">
|
|
451
|
-
<strong>${i(
|
|
452
|
-
<small><code>${i(
|
|
451
|
+
<strong>${i($.name??$.chatId)}</strong><br>
|
|
452
|
+
<small><code>${i($.chatId)}</code></small>
|
|
453
453
|
</div>
|
|
454
454
|
</div>
|
|
455
455
|
</td>
|
|
456
|
-
${
|
|
456
|
+
${He.bots.map(D=>{let m=$.memberBots.find(H=>H.larkAppId===D.larkAppId),y=m?m.error?"!":m.inChat?"\u2713":"\u2717":"?";return`<td class="${m?m.error?"cell-error":m.inChat?"cell-in":"cell-out":"cell-unknown"}" title="${i(m?.error??"")}">${y}</td>`}).join("")}
|
|
457
457
|
<td>
|
|
458
458
|
<button class="add-bots" type="button">${t("groups.addBots")}</button>
|
|
459
459
|
<button class="manage-chat" type="button">${t("groups.manage")}</button>
|
|
460
460
|
</td>
|
|
461
|
-
</tr>`).join("")}g(),o.addEventListener("click",async
|
|
461
|
+
</tr>`).join("")}g(),o.addEventListener("click",async A=>{let O=A.target.closest("button.add-bots");if(!O)return;let E=O.closest("tr[data-chat]").dataset.chat,$=He.chats.find(y=>y.chatId===E);if(!$)return;let D=new Set($.memberBots.filter(y=>y.inChat).map(y=>y.larkAppId));if(!He.bots.filter(y=>!D.has(y.larkAppId)).length){alert("All configured bots are already in this chat.");return}r.innerHTML=`
|
|
462
462
|
<article>
|
|
463
|
-
<header><h3>${t("groups.addBots")} \xB7 ${i(
|
|
463
|
+
<header><h3>${t("groups.addBots")} \xB7 ${i($.name??$.chatId)}</h3></header>
|
|
464
464
|
<p>${t("groups.createHelp")}</p>
|
|
465
465
|
<form id="g-addform">
|
|
466
|
-
${
|
|
466
|
+
${ca(He.bots,D)}
|
|
467
467
|
<div class="actions">
|
|
468
468
|
<button type="submit" class="primary">${t("groups.addBots")}</button>
|
|
469
469
|
<button type="button" id="g-cancel">${t("groups.cancel")}</button>
|
|
470
470
|
</div>
|
|
471
471
|
</form>
|
|
472
|
-
</article>`,r.showModal(),r.querySelector("#g-cancel").onclick=()=>r.close(),r.querySelector("#g-addform").onsubmit=async
|
|
473
|
-
`);alert(
|
|
472
|
+
</article>`,r.showModal(),r.querySelector("#g-cancel").onclick=()=>r.close(),r.querySelector("#g-addform").onsubmit=async y=>{y.preventDefault();let H=new FormData(y.target).getAll("bot");if(H.length===0){alert("Pick at least one bot.");return}try{let j=await(await fetch(`/api/groups/${encodeURIComponent(E)}/add-bots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:H})})).json();if(j.error==="no_proxy_bot")alert("No bot is currently in this chat \u2014 add one manually in Feishu first, then retry.");else if(j.result){let q=j.result.map(oe=>`${oe.id}: ${oe.ok?"OK":`failed (${oe.error??"unknown"})`}`).join(`
|
|
473
|
+
`);alert(q),await Tt(),g()}else alert(`Unexpected response: ${JSON.stringify(j)}`)}catch(B){alert("Network error: "+B)}finally{r.close()}}}),o.addEventListener("click",async A=>{let O=A.target.closest("button.manage-chat");if(!O)return;let E=O.closest("tr[data-chat]").dataset.chat,$=He.chats.find(D=>D.chatId===E);$&&R($)});function R(A){let O=A.memberBots.filter(E=>E.inChat),M=typeof A.ownerId=="string"?A.ownerId:"";r.innerHTML=`
|
|
474
474
|
<article>
|
|
475
|
-
<header><h3>${t("groups.manageTitle",{name:
|
|
476
|
-
<p><b>chatId:</b> <code>${i(
|
|
477
|
-
<p><b>${t("groups.owner")}:</b> <code>${i(
|
|
475
|
+
<header><h3>${t("groups.manageTitle",{name:A.name??A.chatId})}</h3></header>
|
|
476
|
+
<p><b>chatId:</b> <code>${i(A.chatId)}</code></p>
|
|
477
|
+
<p><b>${t("groups.owner")}:</b> <code>${i(A.ownerId??t("common.unknown"))}</code></p>
|
|
478
478
|
|
|
479
479
|
<fieldset>
|
|
480
480
|
<legend>${t("groups.oncall")}</legend>
|
|
481
481
|
<p><small>${t("groups.oncallHelp")}</small></p>
|
|
482
|
-
${
|
|
483
|
-
<div class="oncall-row" data-bot="${i(
|
|
482
|
+
${O.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':O.map(E=>{let $=!!E.oncallChat,D=E.oncallChat?.workingDir??"";return`
|
|
483
|
+
<div class="oncall-row" data-bot="${i(E.larkAppId)}">
|
|
484
484
|
<label class="checkbox-row">
|
|
485
|
-
<input type="checkbox" data-action="toggle" ${
|
|
486
|
-
<strong>${i(
|
|
487
|
-
<small>(${i(
|
|
485
|
+
<input type="checkbox" data-action="toggle" ${$?"checked":""}>
|
|
486
|
+
<strong>${i(E.botName??E.larkAppId)}</strong>
|
|
487
|
+
<small>(${i(E.larkAppId)})</small>
|
|
488
488
|
</label>
|
|
489
489
|
<div class="oncall-row-body">
|
|
490
490
|
<input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
|
|
491
|
-
value="${i(
|
|
491
|
+
value="${i(D)}" ${$?"":"disabled"}>
|
|
492
492
|
<button type="button" data-action="save">${t("groups.save")}</button>
|
|
493
493
|
<span class="oncall-status" data-status></span>
|
|
494
494
|
</div>
|
|
@@ -498,29 +498,29 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
498
498
|
|
|
499
499
|
<fieldset>
|
|
500
500
|
<legend>${t("groups.leaveTitle")}</legend>
|
|
501
|
-
${
|
|
501
|
+
${O.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':O.map(E=>`
|
|
502
502
|
<label class="checkbox-row">
|
|
503
|
-
<input type="checkbox" name="leave-bot" value="${i(
|
|
504
|
-
${i(
|
|
505
|
-
<small>${
|
|
503
|
+
<input type="checkbox" name="leave-bot" value="${i(E.larkAppId)}">
|
|
504
|
+
${i(E.botName??E.larkAppId)}
|
|
505
|
+
<small>${E.larkAppId===M?"\xB7 \u7FA4\u4E3B":""}</small>
|
|
506
506
|
</label>
|
|
507
507
|
`).join("")}
|
|
508
508
|
</fieldset>
|
|
509
509
|
|
|
510
510
|
<div class="actions">
|
|
511
|
-
<button id="g-leave-btn" type="button" ${
|
|
512
|
-
<button id="g-disband-btn" type="button" class="contrast" ${
|
|
511
|
+
<button id="g-leave-btn" type="button" ${O.length===0?"disabled":""}>${t("groups.leaveSelected")}</button>
|
|
512
|
+
<button id="g-disband-btn" type="button" class="contrast" ${O.length===0?"disabled":""}>${t("groups.disband")}</button>
|
|
513
513
|
</div>
|
|
514
514
|
<p class="hint-warn"><small>${t("groups.dangerHint")}</small></p>
|
|
515
515
|
<form method="dialog"><button>${t("sessions.dismiss")}</button></form>
|
|
516
|
-
</article>`,r.showModal(),r.querySelectorAll(".oncall-row").forEach(
|
|
517
|
-
`);alert(
|
|
516
|
+
</article>`,r.showModal(),r.querySelectorAll(".oncall-row").forEach(E=>{let $=E.dataset.bot,D=E.querySelector("input[data-action=toggle]"),m=E.querySelector("input[data-input=workingDir]"),y=E.querySelector("button[data-action=save]"),S=E.querySelector("[data-status]");D.addEventListener("change",()=>{m.disabled=!D.checked,D.checked&&m.focus()}),y.addEventListener("click",async()=>{S.textContent="",S.className="oncall-status";let H=D.checked,B=m.value.trim();if(H&&!B){S.textContent=t("groups.needWorkingDir"),S.classList.add("hint-warn-inline");return}y.disabled=!0;try{let j=`/api/groups/${encodeURIComponent(A.chatId)}/oncall/${encodeURIComponent($)}`,q=H?await fetch(j,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({workingDir:B})}):await fetch(j,{method:"DELETE"}),oe=await q.json().catch(()=>({}));if(q.ok&&oe.ok){S.textContent=H?`\u2713 \u5DF2\u7ED1\u5B9A \u2192 ${oe.resolvedPath??B}`:"\u2713 \u5DF2\u89E3\u7ED1",S.classList.add("hint-ok");try{await Tt(),g()}catch{}}else S.textContent=`\u2717 ${oe.error??q.status}`,S.classList.add("hint-warn-inline")}catch(j){S.textContent=`\u2717 ${j?.message??j}`,S.classList.add("hint-warn-inline")}finally{y.disabled=!1}})}),r.querySelector("#g-leave-btn").onclick=async()=>{let E=[...r.querySelectorAll("input[name=leave-bot]:checked")].map($=>$.value);if(E.length===0){alert("\u81F3\u5C11\u9009\u4E00\u4E2A\u673A\u5668\u4EBA");return}if(confirm(`\u786E\u5B9A\u8BA9 ${E.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 D=await(await fetch(`/api/groups/${encodeURIComponent(A.chatId)}/leave`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:E})})).json(),m=(D.result??[]).map(y=>{if(!y.ok)return`${y.larkAppId}: \u5931\u8D25 (${y.error??"unknown"})`;let S=y.closedSessions??[],H=S.filter(q=>!q.ok).length,B=S.length-H,j=S.length===0?"":H===0?`\uFF08\u5173\u95ED ${B} \u4E2A\u4F1A\u8BDD\uFF09`:`\uFF08\u5173\u95ED ${B} \u4E2A\uFF0C${H} \u4E2A\u5931\u8D25\uFF09`;return`${y.larkAppId}: OK${j}`}).join(`
|
|
517
|
+
`);alert(m||`Unexpected: ${JSON.stringify(D)}`),await Tt(),g()}catch($){alert("Network error: "+$)}finally{r.close()}},r.querySelector("#g-disband-btn").onclick=async()=>{if(O.length===0||!confirm(`\u786E\u5B9A\u89E3\u6563\u7FA4\u804A\u300C${A.name??A.chatId}\u300D\uFF1F\u6B64\u64CD\u4F5C\u4E0D\u53EF\u6062\u590D\uFF0C\u672C\u7FA4\u6240\u6709\u673A\u5668\u4EBA\u4F1A\u8BDD\u4E5F\u4F1A\u4E00\u5E76\u5173\u95ED\u3002`))return;let E=[...O].sort((D,m)=>(m.larkAppId===M?1:0)-(D.larkAppId===M?1:0)),$=[];for(let D of E)try{let m=await fetch(`/api/groups/${encodeURIComponent(A.chatId)}/disband`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppId:D.larkAppId})}),y=await m.json();if(y.ok){let S=y.closedSessions??[],H=S.filter(q=>!q.ok).length,B=S.length-H,j=S.length===0?"":H===0?`
|
|
518
518
|
\u5173\u95ED\u4E86 ${B} \u4E2A\u4F1A\u8BDD\u3002`:`
|
|
519
|
-
\u5173\u95ED\u4E86 ${B} \u4E2A\u4F1A\u8BDD\uFF0C${
|
|
520
|
-
${
|
|
519
|
+
\u5173\u95ED\u4E86 ${B} \u4E2A\u4F1A\u8BDD\uFF0C${H} \u4E2A\u4F1A\u8BDD\u5173\u95ED\u5931\u8D25\u3002`;alert(`\u5DF2\u89E3\u6563\uFF08\u7531 ${D.botName??D.larkAppId} \u6267\u884C\uFF09${j}`),await Tt(),g(),r.close();return}$.push(`${D.botName??D.larkAppId}: ${y.error??m.status}`)}catch(m){$.push(`${D.botName??D.larkAppId}: ${m}`)}alert(`\u6240\u6709\u5728\u7FA4\u673A\u5668\u4EBA\u5747\u65E0\u6CD5\u89E3\u6563\uFF1A
|
|
520
|
+
${$.join(`
|
|
521
521
|
`)}
|
|
522
522
|
|
|
523
|
-
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",g)}var
|
|
523
|
+
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",g)}var Oe={bots:[]},It=null,Lt=null;function pa(e){let n=null;for(let o of Q.sessions.values())o.larkAppId!==e||!o.cliId||(!n||Number(o.lastMessageAt??0)>Number(n.lastMessageAt??0))&&(n=o);return n?.cliId??""}function ii(){return`<section class="page">
|
|
524
524
|
<div class="page-heading">
|
|
525
525
|
<div>
|
|
526
526
|
<p class="eyebrow">${t("nav.botDefaults")}</p>
|
|
@@ -536,32 +536,32 @@ ${d.join(`
|
|
|
536
536
|
<aside id="bd-roster" class="bd-roster"></aside>
|
|
537
537
|
<div id="bd-list" class="bd-detail"></div>
|
|
538
538
|
</div>
|
|
539
|
-
</section>`}async function
|
|
540
|
-
${
|
|
539
|
+
</section>`}async function ma(){try{let e=await fetch("/api/bots"),n=await e.json().catch(()=>({}));if(!e.ok){It=n?.error?`HTTP ${e.status}: ${n.error}${n.path?` (${n.path})`:""}`:`HTTP ${e.status}`,Oe={bots:[]};return}if(!n||!Array.isArray(n.bots)){It="unexpected response shape (no `bots` array)",Oe={bots:[]};return}It=null,Oe=n}catch(e){It=e?.message??String(e),Oe={bots:[]}}}function fa(e){if(!e)return"\u2014";let n=new Date(e);return Number.isNaN(n.getTime())?"\u2014":n.toLocaleString()}async function ga(e){e.innerHTML=ii();let n=e.querySelector("#bd-list"),o=e.querySelector("#bd-roster"),s=e.querySelector("#bd-filters"),a=e.querySelector("#bd-refresh");a.onclick=async()=>{a.disabled=!0;try{await ma(),r()}finally{a.disabled=!1}},n.addEventListener("click",m=>{let y=m.target.closest(".toggle-tx small, small.bd-help");y&&(m.preventDefault(),y.classList.toggle("open"))}),n.innerHTML=St(),await ma();function r(){let y=(new FormData(s).get("q")??"").toLowerCase(),S=Oe.bots.filter(B=>!y||(B.botName??"").toLowerCase().includes(y)||(B.larkAppId??"").toLowerCase().includes(y));if(It){o.innerHTML="",n.innerHTML=`<p class="hint-warn">\u65E0\u6CD5\u52A0\u8F7D bot \u5217\u8868\uFF1A${i(It)}<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(S.length===0){o.innerHTML="",n.innerHTML=`<p class="empty">${t("botDefaults.empty")}</p>`;return}(!Lt||!S.some(B=>B.larkAppId===Lt))&&(Lt=S[0].larkAppId),o.innerHTML=S.map(d).join(""),o.querySelectorAll(".bd-roster-item").forEach(B=>{B.onclick=()=>{Lt=B.dataset.appid,r()}});let H=S.find(B=>B.larkAppId===Lt);n.innerHTML=p(H),D()}function d(m){let y=m.botName??m.larkAppId,S=pa(m.larkAppId),H=m.defaultOncall?.enabled?'<span class="bd-roster-flag">oncall</span>':"";return`<div class="bd-roster-item${m.larkAppId===Lt?" on":""}" data-appid="${i(m.larkAppId)}" role="button" tabindex="0">
|
|
540
|
+
${fe({name:y,larkAppId:m.larkAppId,size:"sm"})}
|
|
541
541
|
<div class="bd-roster-tx">
|
|
542
542
|
<b>${i(y)}</b>
|
|
543
|
-
<span>${i(
|
|
543
|
+
<span>${i(S||m.larkAppId.slice(0,14))}</span>
|
|
544
544
|
</div>
|
|
545
|
-
${
|
|
546
|
-
</div>`}function p(
|
|
545
|
+
${H}
|
|
546
|
+
</div>`}function p(m){if(m.error)return`<article class="bd-card bd-profile" data-appid="${i(m.larkAppId)}">
|
|
547
547
|
<header class="bd-profile-head">
|
|
548
|
-
${
|
|
549
|
-
<div class="bd-profile-id"><strong>${i(
|
|
550
|
-
<code>${i(
|
|
548
|
+
${fe({name:m.botName??m.larkAppId,larkAppId:m.larkAppId})}
|
|
549
|
+
<div class="bd-profile-id"><strong>${i(m.botName??m.larkAppId)}</strong>
|
|
550
|
+
<code>${i(m.larkAppId)}</code></div>
|
|
551
551
|
</header>
|
|
552
|
-
<p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${i(
|
|
553
|
-
</article>`;let y=
|
|
552
|
+
<p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${i(m.error)}</p>
|
|
553
|
+
</article>`;let y=m.defaultOncall??{enabled:!1,workingDir:"",since:0},S=!!y.enabled,H=m.botName??m.larkAppId,B=pa(m.larkAppId);return`<article class="bd-card bd-profile" data-appid="${i(m.larkAppId)}">
|
|
554
554
|
<header class="bd-profile-head">
|
|
555
|
-
${
|
|
555
|
+
${fe({name:H,larkAppId:m.larkAppId,dot:"ok"})}
|
|
556
556
|
<div class="bd-profile-id">
|
|
557
|
-
<strong>${i(
|
|
558
|
-
${
|
|
559
|
-
<code>${i(
|
|
557
|
+
<strong>${i(H)}</strong>
|
|
558
|
+
${B?`<span class="mate-role">${i(B)}</span>`:""}
|
|
559
|
+
<code>${i(m.larkAppId)}</code>
|
|
560
560
|
</div>
|
|
561
561
|
<div class="bd-profile-meta bd-meta">
|
|
562
562
|
<small class="bd-meta-ok">\u25CF ${t("botDefaults.metaOnline")}</small>
|
|
563
|
-
<small data-oncall-since>${t("botDefaults.lastEnabled")}: ${i(
|
|
564
|
-
<small>${t("botDefaults.autobound",{count:
|
|
563
|
+
<small data-oncall-since>${t("botDefaults.lastEnabled")}: ${i(fa(y.since??0))}</small>
|
|
564
|
+
<small>${t("botDefaults.autobound",{count:m.autoboundChatCount??0})}</small>
|
|
565
565
|
</div>
|
|
566
566
|
</header>
|
|
567
567
|
<div class="bd-body bd-grid">
|
|
@@ -569,7 +569,7 @@ ${d.join(`
|
|
|
569
569
|
<section class="bd-section">
|
|
570
570
|
<h3 class="bd-section-title">${t("botDefaults.sectionOncall")}</h3>
|
|
571
571
|
<label class="toggle-row">
|
|
572
|
-
<input type="checkbox" data-action="toggle" ${
|
|
572
|
+
<input type="checkbox" data-action="toggle" ${S?"checked":""}>
|
|
573
573
|
<span class="switch" aria-hidden="true"></span>
|
|
574
574
|
<span class="toggle-tx"><strong>${t("botDefaults.defaultOncall")}</strong>
|
|
575
575
|
<small>${t("botDefaults.defaultOncallHelp")}\u3002${t("botDefaults.warning")}</small></span>
|
|
@@ -578,34 +578,34 @@ ${d.join(`
|
|
|
578
578
|
<label>
|
|
579
579
|
<span>${t("botDefaults.workingDir")}</span>
|
|
580
580
|
<input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
|
|
581
|
-
value="${i(y.workingDir??"")}" ${
|
|
581
|
+
value="${i(y.workingDir??"")}" ${S?"":"disabled"}>
|
|
582
582
|
</label>
|
|
583
583
|
</div>
|
|
584
584
|
<div class="actions">
|
|
585
585
|
<button type="button" class="primary" data-action="save">${t("botDefaults.save")}</button>
|
|
586
586
|
<span class="oncall-status" data-status></span>
|
|
587
587
|
</div>
|
|
588
|
-
${
|
|
588
|
+
${$(m)}
|
|
589
589
|
</section>
|
|
590
|
-
${O(
|
|
590
|
+
${O(m)}
|
|
591
591
|
</section>
|
|
592
|
-
<section class="bd-tile">${
|
|
593
|
-
<section class="bd-tile">${g(
|
|
594
|
-
<section class="bd-tile">${
|
|
595
|
-
<section class="bd-tile">${
|
|
592
|
+
<section class="bd-tile">${v(m)}</section>
|
|
593
|
+
<section class="bd-tile">${g(m)}${A(m)}</section>
|
|
594
|
+
<section class="bd-tile">${T(m)}${I(m)}</section>
|
|
595
|
+
<section class="bd-tile">${E(m)}</section>
|
|
596
596
|
</div>
|
|
597
|
-
</article>`}function
|
|
597
|
+
</article>`}function v(m){let y=typeof m.teamRole=="string";return`<section class="bd-section">
|
|
598
598
|
<h3 class="bd-section-title">${t("botDefaults.sectionRole")}</h3>
|
|
599
599
|
<p class="bd-section-note">${t("botDefaults.roleHelp")}</p>
|
|
600
600
|
<textarea data-input="teamRole" rows="6"
|
|
601
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(
|
|
602
|
+
style="width:100%;box-sizing:border-box;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px"${y?"":" disabled"}>${y?i(m.teamRole):""}</textarea>
|
|
603
603
|
<div class="actions">
|
|
604
604
|
<button type="button" class="primary" data-action="save-role"${y?"":" disabled"}>${t("botDefaults.roleSave")}</button>
|
|
605
605
|
<button type="button" data-action="delete-role"${y?"":" disabled"}>${t("botDefaults.roleDelete")}</button>
|
|
606
606
|
<span class="oncall-status" data-role-status></span>
|
|
607
607
|
</div>
|
|
608
|
-
</section>`}function
|
|
608
|
+
</section>`}function k(m){return m==null?t("botDefaults.brandStateDefault"):m.trim()===""?t("botDefaults.brandStateOff"):t("botDefaults.brandStateCustom")}function I(m){let y=m.brandLabel??null;return`<section class="bd-section">
|
|
609
609
|
<h3 class="bd-section-title">${t("botDefaults.sectionBrand")}</h3>
|
|
610
610
|
<div class="bd-row bd-brand">
|
|
611
611
|
<label>
|
|
@@ -614,7 +614,7 @@ ${d.join(`
|
|
|
614
614
|
placeholder="${i(t("botDefaults.brandLabelPlaceholder"))}"
|
|
615
615
|
value="${i(y??"")}">
|
|
616
616
|
</label>
|
|
617
|
-
<small data-brand-state>${i(
|
|
617
|
+
<small data-brand-state>${i(k(y))}</small>
|
|
618
618
|
<small class="bd-help">${t("botDefaults.brandLabelHelp")}</small>
|
|
619
619
|
<div class="actions">
|
|
620
620
|
<button type="button" class="primary" data-action="save-brand">${t("botDefaults.brandSave")}</button>
|
|
@@ -622,7 +622,7 @@ ${d.join(`
|
|
|
622
622
|
<span class="oncall-status" data-brand-status></span>
|
|
623
623
|
</div>
|
|
624
624
|
</div>
|
|
625
|
-
</section>`}function
|
|
625
|
+
</section>`}function T(m){let y=m.disableStreamingCard===!0,S=m.writableTerminalLinkInCard===!0,H=m.privateCard===!0;return`<section class="bd-section">
|
|
626
626
|
<h3 class="bd-section-title">${t("botDefaults.sectionCard")}</h3>
|
|
627
627
|
<label class="toggle-row">
|
|
628
628
|
<input type="checkbox" data-action="toggle-disable-streaming" ${y?"checked":""}>
|
|
@@ -631,13 +631,13 @@ ${d.join(`
|
|
|
631
631
|
<small>${t("botDefaults.disableStreamingHelp")}</small></span>
|
|
632
632
|
</label>
|
|
633
633
|
<label class="toggle-row">
|
|
634
|
-
<input type="checkbox" data-action="toggle-writable-link" ${
|
|
634
|
+
<input type="checkbox" data-action="toggle-writable-link" ${S?"checked":""} ${y?"disabled":""}>
|
|
635
635
|
<span class="switch" aria-hidden="true"></span>
|
|
636
636
|
<span class="toggle-tx"><strong>${t("botDefaults.writableLink")}</strong>
|
|
637
637
|
<small>${t("botDefaults.writableLinkHelp")}</small></span>
|
|
638
638
|
</label>
|
|
639
639
|
<label class="toggle-row">
|
|
640
|
-
<input type="checkbox" data-action="toggle-private-card" ${
|
|
640
|
+
<input type="checkbox" data-action="toggle-private-card" ${H?"checked":""}>
|
|
641
641
|
<span class="switch" aria-hidden="true"></span>
|
|
642
642
|
<span class="toggle-tx"><strong>${t("botDefaults.privateCard")}</strong>
|
|
643
643
|
<small>${t("botDefaults.privateCardHelp")}</small></span>
|
|
@@ -646,7 +646,7 @@ ${d.join(`
|
|
|
646
646
|
<small data-card-pref-moot class="hint-warn-inline" ${y?"":"hidden"}>${t("botDefaults.writableLinkMoot")}</small>
|
|
647
647
|
<span class="oncall-status" data-card-pref-status></span>
|
|
648
648
|
</div>
|
|
649
|
-
</section>`}function g(
|
|
649
|
+
</section>`}function g(m){let y=m.p2pMode==="chat"?"chat":"thread",S=m.regularGroupReplyMode==="new-topic"||m.regularGroupReplyMode==="shared"?m.regularGroupReplyMode:"chat",H=m.regularGroupMentionMode==="topic"||m.regularGroupMentionMode==="never"?m.regularGroupMentionMode:"always",B=m.docSubscribeDefaultMode==="all"?"all":"mention-only",j=(X,ae)=>`<option value="${X}" ${S===X?"selected":""}>${i(ae)}</option>`,q=(X,ae)=>`<option value="${X}" ${H===X?"selected":""}>${i(ae)}</option>`,oe=(X,ae)=>`<option value="${X}" ${B===X?"selected":""}>${i(ae)}</option>`;return`<section class="bd-section">
|
|
650
650
|
<h3 class="bd-section-title">${t("botDefaults.sectionSessionMode")}</h3>
|
|
651
651
|
<div class="bd-row">
|
|
652
652
|
<label>
|
|
@@ -665,9 +665,9 @@ ${d.join(`
|
|
|
665
665
|
<label>
|
|
666
666
|
<span>${t("botDefaults.regularGroupMode")}</span>
|
|
667
667
|
<select data-input="regularGroupMode">
|
|
668
|
-
${
|
|
669
|
-
${
|
|
670
|
-
${
|
|
668
|
+
${j("chat",t("botDefaults.regularGroupModeChat"))}
|
|
669
|
+
${j("new-topic",t("botDefaults.regularGroupModeNewTopic"))}
|
|
670
|
+
${j("shared",t("botDefaults.regularGroupModeShared"))}
|
|
671
671
|
</select>
|
|
672
672
|
</label>
|
|
673
673
|
<small class="bd-help">${t("botDefaults.regularGroupModeHelp")}</small>
|
|
@@ -679,9 +679,9 @@ ${d.join(`
|
|
|
679
679
|
<label>
|
|
680
680
|
<span>${t("botDefaults.mentionMode")}</span>
|
|
681
681
|
<select data-input="regularGroupMentionMode">
|
|
682
|
-
${
|
|
683
|
-
${
|
|
684
|
-
${
|
|
682
|
+
${q("always",t("botDefaults.mentionModeAlways"))}
|
|
683
|
+
${q("topic",t("botDefaults.mentionModeTopic"))}
|
|
684
|
+
${q("never",t("botDefaults.mentionModeNever"))}
|
|
685
685
|
</select>
|
|
686
686
|
</label>
|
|
687
687
|
<small class="bd-help">${t("botDefaults.mentionModeHelp")}</small>
|
|
@@ -693,8 +693,8 @@ ${d.join(`
|
|
|
693
693
|
<label>
|
|
694
694
|
<span>${t("botDefaults.docSubscribeMode")}</span>
|
|
695
695
|
<select data-input="docSubscribeDefaultMode">
|
|
696
|
-
${
|
|
697
|
-
${
|
|
696
|
+
${oe("mention-only",t("botDefaults.docSubscribeModeMention"))}
|
|
697
|
+
${oe("all",t("botDefaults.docSubscribeModeAll"))}
|
|
698
698
|
</select>
|
|
699
699
|
</label>
|
|
700
700
|
<small class="bd-help">${t("botDefaults.docSubscribeModeHelp")}</small>
|
|
@@ -702,7 +702,24 @@ ${d.join(`
|
|
|
702
702
|
<span class="oncall-status" data-doc-subscribe-mode-status></span>
|
|
703
703
|
</div>
|
|
704
704
|
</div>
|
|
705
|
-
</section>`}function
|
|
705
|
+
</section>`}function R(m){return m==null?t("botDefaults.maxLiveWorkersStateDefault"):t("botDefaults.maxLiveWorkersStateOn",{count:m})}function A(m){let y=typeof m.maxLiveWorkers=="number"?m.maxLiveWorkers:null;return`<div class="bd-subsection">
|
|
706
|
+
<h4 class="bd-subsection-title">${t("botDefaults.sectionSessionCap")}</h4>
|
|
707
|
+
<div class="bd-row bd-quota">
|
|
708
|
+
<label>
|
|
709
|
+
<span>${t("botDefaults.maxLiveWorkers")}</span>
|
|
710
|
+
<input type="number" min="1" step="1" data-input="maxLiveWorkers"
|
|
711
|
+
placeholder="${i(t("botDefaults.maxLiveWorkersPlaceholder"))}"
|
|
712
|
+
value="${y??""}">
|
|
713
|
+
</label>
|
|
714
|
+
<small data-session-cap-state>${i(R(y))}</small>
|
|
715
|
+
<small class="bd-help">${t("botDefaults.maxLiveWorkersHelp")}</small>
|
|
716
|
+
<div class="actions">
|
|
717
|
+
<button type="button" class="primary" data-action="save-session-cap">${t("botDefaults.maxLiveWorkersSave")}</button>
|
|
718
|
+
<button type="button" data-action="off-session-cap">${t("botDefaults.maxLiveWorkersOff")}</button>
|
|
719
|
+
<span class="oncall-status" data-session-cap-status></span>
|
|
720
|
+
</div>
|
|
721
|
+
</div>
|
|
722
|
+
</div>`}function O(m){let y=m.sandbox===!0;return`<section class="bd-section">
|
|
706
723
|
<h3 class="bd-section-title">${t("botDefaults.sectionSandbox")}</h3>
|
|
707
724
|
<label class="toggle-row">
|
|
708
725
|
<input type="checkbox" data-action="toggle-sandbox" ${y?"checked":""}>
|
|
@@ -713,7 +730,7 @@ ${d.join(`
|
|
|
713
730
|
<div class="actions">
|
|
714
731
|
<span class="oncall-status" data-sandbox-status></span>
|
|
715
732
|
</div>
|
|
716
|
-
</section>`}function
|
|
733
|
+
</section>`}function M(m){return m==null?t("botDefaults.quotaStateOff"):t("botDefaults.quotaStateOn",{count:m})}function E(m){let y=m.restrictGrantCommands===!0,S=typeof m.messageQuotaDefaultLimit=="number"?m.messageQuotaDefaultLimit:null;return`<section class="bd-section">
|
|
717
734
|
<h3 class="bd-section-title">${t("botDefaults.sectionGrant")}</h3>
|
|
718
735
|
<label class="toggle-row">
|
|
719
736
|
<input type="checkbox" data-action="toggle-restrict-grant" ${y?"checked":""}>
|
|
@@ -726,9 +743,9 @@ ${d.join(`
|
|
|
726
743
|
<span>${t("botDefaults.quotaDefault")}</span>
|
|
727
744
|
<input type="number" min="1" step="1" data-input="quotaLimit"
|
|
728
745
|
placeholder="${i(t("botDefaults.quotaPlaceholder"))}"
|
|
729
|
-
value="${
|
|
746
|
+
value="${S??""}">
|
|
730
747
|
</label>
|
|
731
|
-
<small data-quota-state>${i(
|
|
748
|
+
<small data-quota-state>${i(M(S))}</small>
|
|
732
749
|
<small class="bd-help">${t("botDefaults.quotaHelp")}</small>
|
|
733
750
|
<div class="actions">
|
|
734
751
|
<button type="button" class="primary" data-action="save-quota">${t("botDefaults.quotaSave")}</button>
|
|
@@ -736,7 +753,7 @@ ${d.join(`
|
|
|
736
753
|
<span class="oncall-status" data-grant-status></span>
|
|
737
754
|
</div>
|
|
738
755
|
</div>
|
|
739
|
-
</section>`}function
|
|
756
|
+
</section>`}function $(m){let y=m.autoStartOnGroupJoin===!0,S=m.autoStartOnNewTopic===!0,H=typeof m.autoStartOnGroupJoinPrompt=="string"?m.autoStartOnGroupJoinPrompt:"";return`<div class="bd-subsection">
|
|
740
757
|
<h4 class="bd-subsection-title">${t("botDefaults.sectionAutoStart")}</h4>
|
|
741
758
|
<label class="toggle-row">
|
|
742
759
|
<input type="checkbox" data-action="toggle-auto-join" ${y?"checked":""}>
|
|
@@ -748,14 +765,14 @@ ${d.join(`
|
|
|
748
765
|
<label>
|
|
749
766
|
<span>${t("botDefaults.autoStartJoinPrompt")}</span>
|
|
750
767
|
<textarea data-input="autoJoinPrompt" rows="3"
|
|
751
|
-
placeholder="${i(t("botDefaults.autoStartJoinPromptPlaceholder"))}">${i(
|
|
768
|
+
placeholder="${i(t("botDefaults.autoStartJoinPromptPlaceholder"))}">${i(H)}</textarea>
|
|
752
769
|
</label>
|
|
753
770
|
<div class="actions">
|
|
754
771
|
<button type="button" class="primary" data-action="save-auto-join-prompt">${t("botDefaults.autoStartJoinPromptSave")}</button>
|
|
755
772
|
</div>
|
|
756
773
|
</div>
|
|
757
774
|
<label class="toggle-row">
|
|
758
|
-
<input type="checkbox" data-action="toggle-auto-topic" ${
|
|
775
|
+
<input type="checkbox" data-action="toggle-auto-topic" ${S?"checked":""}>
|
|
759
776
|
<span class="switch" aria-hidden="true"></span>
|
|
760
777
|
<span class="toggle-tx"><strong>${t("botDefaults.autoStartTopic")}</strong>
|
|
761
778
|
<small>${t("botDefaults.autoStartTopicHelp")}</small></span>
|
|
@@ -763,7 +780,7 @@ ${d.join(`
|
|
|
763
780
|
<div class="actions">
|
|
764
781
|
<span class="oncall-status" data-auto-start-status></span>
|
|
765
782
|
</div>
|
|
766
|
-
</div>`}function x(){n.querySelectorAll(".bd-card").forEach(d=>{let y=d.dataset.appid,H=d.querySelector("input[data-action=toggle]"),M=d.querySelector("input[data-input=workingDir]"),T=d.querySelector("button[data-action=save]"),A=d.querySelector("[data-status]");if(!H||!M||!T||!A)return;H.addEventListener("change",()=>{M.disabled=!H.checked,H.checked&&M.focus()}),T.addEventListener("click",async()=>{A.textContent="",A.className="oncall-status";let X=H.checked,_=M.value.trim();if(X&&!_){A.textContent=t("botDefaults.required"),A.classList.add("hint-warn-inline");return}T.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:_})}),J=await F.json().catch(()=>({}));if(F.ok&&J.ok){let G=J.resolvedPath?` \u2192 ${J.resolvedPath}`:"";A.textContent=X?`\u2713 \u5DF2\u5F00\u542F${G}\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=Pe.bots.find(Ie=>Ie.larkAppId===y);Y&&J.defaultOncall&&(Y.defaultOncall=J.defaultOncall);let fe=d.querySelector("[data-oncall-since]");fe&&J.defaultOncall?.since!=null&&(fe.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${da(J.defaultOncall.since)}`)}else A.textContent=`\u2717 ${J.error??F.status}`,A.classList.add("hint-warn-inline")}catch(F){A.textContent=`\u2717 ${F?.message??F}`,A.classList.add("hint-warn-inline")}finally{T.disabled=!1}});let B=d.querySelector("input[data-input=brandLabel]"),z=d.querySelector("button[data-action=save-brand]"),P=d.querySelector("button[data-action=reset-brand]"),K=d.querySelector("[data-brand-status]"),de=d.querySelector("[data-brand-state]");async function Ce(X,_){if(K){K.textContent="",K.className="oncall-status",_.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})}),J=await F.json().catch(()=>({}));if(F.ok&&J.ok){let G=J.brandLabel??null;K.textContent="\u2713",K.classList.add("hint-ok"),B&&(B.value=G??""),de&&(de.textContent=v(G));let Y=Pe.bots.find(fe=>fe.larkAppId===y);Y&&(Y.brandLabel=G)}else K.textContent=`\u2717 ${J.error??F.status}`,K.classList.add("hint-warn-inline")}catch(F){K.textContent=`\u2717 ${F?.message??F}`,K.classList.add("hint-warn-inline")}finally{_.disabled=!1}}}B&&z&&z.addEventListener("click",()=>Ce(B.value,z)),P&&P.addEventListener("click",()=>Ce(null,P));let he=d.querySelector("input[data-action=toggle-disable-streaming]"),V=d.querySelector("input[data-action=toggle-writable-link]"),ie=d.querySelector("input[data-action=toggle-private-card]"),Le=d.querySelector("[data-card-pref-status]"),Oe=d.querySelector("[data-card-pref-moot]");async function Z(X,_,F=Le){if(F){F.textContent="",F.className="oncall-status",_.disabled=!0;try{let J=await fetch(`/api/bots/${encodeURIComponent(y)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(X)}),G=await J.json().catch(()=>({}));if(J.ok&&G.ok){F.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,F.classList.add("hint-ok");let Y=Pe.bots.find(fe=>fe.larkAppId===y);Y&&(Y.disableStreamingCard=G.disableStreamingCard,Y.writableTerminalLinkInCard=G.writableTerminalLinkInCard,Y.privateCard=G.privateCard,Y.autoStartOnGroupJoin=G.autoStartOnGroupJoin,Y.autoStartOnGroupJoinPrompt=G.autoStartOnGroupJoinPrompt,Y.autoStartOnNewTopic=G.autoStartOnNewTopic,Y.regularGroupReplyMode=G.regularGroupReplyMode,Y.regularGroupMentionMode=G.regularGroupMentionMode,Y.docSubscribeDefaultMode=G.docSubscribeDefaultMode)}else F.textContent=`\u2717 ${G.error??J.status}`,F.classList.add("hint-warn-inline")}catch(J){F.textContent=`\u2717 ${J?.message??J}`,F.classList.add("hint-warn-inline")}finally{_===V?_.disabled=!!he?.checked:_.disabled=!1}}}he&&he.addEventListener("change",()=>{let X=he.checked;V&&(V.disabled=X),Oe&&(Oe.hidden=!X),Z({disableStreamingCard:X},he)}),V&&V.addEventListener("change",()=>{Z({writableTerminalLinkInCard:V.checked},V)}),ie&&ie.addEventListener("change",()=>{Z({privateCard:ie.checked},ie)});let me=d.querySelector("input[data-action=toggle-sandbox]"),ce=d.querySelector("[data-sandbox-status]");me&&me.addEventListener("change",async()=>{let X=me.checked;ce&&(ce.textContent="",ce.className="oncall-status"),me.disabled=!0;try{let _=await fetch(`/api/bots/${encodeURIComponent(y)}/sandbox`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:X})}),F=await _.json().catch(()=>({}));if(_.ok&&F.ok){ce&&(ce.textContent=`\u2713 ${t("botDefaults.sandboxSaved")}`,ce.classList.add("hint-ok"));let J=Pe.bots.find(G=>G.larkAppId===y);J&&(J.sandbox=F.sandbox===!0)}else ce&&(ce.textContent=`\u2717 ${F.error??_.status}`,ce.classList.add("hint-warn-inline")),me.checked=!X}catch(_){ce&&(ce.textContent=`\u2717 ${_?.message??_}`,ce.classList.add("hint-warn-inline")),me.checked=!X}finally{me.disabled=!1}});let Ue=d.querySelector("input[data-action=toggle-auto-join]"),Se=d.querySelector("input[data-action=toggle-auto-topic]"),we=d.querySelector("textarea[data-input=autoJoinPrompt]"),re=d.querySelector("button[data-action=save-auto-join-prompt]"),Ae=d.querySelector("[data-auto-start-status]");Ue&&Ue.addEventListener("change",()=>{Z({autoStartOnGroupJoin:Ue.checked},Ue,Ae)}),Se&&Se.addEventListener("change",()=>{Z({autoStartOnNewTopic:Se.checked},Se,Ae)}),we&&re&&re.addEventListener("click",()=>{Z({autoStartOnGroupJoinPrompt:we.value},re,Ae)});let De=d.querySelector("select[data-input=p2pMode]"),ue=d.querySelector("[data-p2p-status]");De&&ue&&De.addEventListener("change",async()=>{let X=De.value==="chat"?"chat":"thread";ue.textContent="",ue.className="oncall-status",De.disabled=!0;try{let _=await fetch(`/api/bots/${encodeURIComponent(y)}/p2p-mode`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({p2pMode:X})}),F=await _.json().catch(()=>({}));if(_.ok&&F.ok){ue.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,ue.classList.add("hint-ok");let J=Pe.bots.find(G=>G.larkAppId===y);J&&(J.p2pMode=F.p2pMode==="chat"?"chat":"thread")}else ue.textContent=`\u2717 ${F.error??_.status}`,ue.classList.add("hint-warn-inline")}catch(_){ue.textContent=`\u2717 ${_?.message??_}`,ue.classList.add("hint-warn-inline")}finally{De.disabled=!1}});let je=d.querySelector("select[data-input=regularGroupMode]"),Qe=d.querySelector("[data-regular-group-status]");je&&je.addEventListener("change",()=>{Z({regularGroupReplyMode:je.value},je,Qe)});let Xe=d.querySelector("select[data-input=regularGroupMentionMode]"),gt=d.querySelector("[data-mention-mode-status]");Xe&&Xe.addEventListener("change",()=>{Z({regularGroupMentionMode:Xe.value},Xe,gt)});let Ze=d.querySelector("select[data-input=docSubscribeDefaultMode]"),Lt=d.querySelector("[data-doc-subscribe-mode-status]");Ze&&Ze.addEventListener("change",()=>{Z({docSubscribeDefaultMode:Ze.value},Ze,Lt)});let st=d.querySelector("textarea[data-input=teamRole]"),pe=d.querySelector("button[data-action=save-role]"),Be=d.querySelector("button[data-action=delete-role]"),le=d.querySelector("[data-role-status]");if(st&&pe&&Be&&le){let F=function(G){let Y=n.querySelector(`.bd-card[data-appid="${CSS.escape(y)}"]`);if(!Y)return;let fe=Y.querySelector("textarea[data-input=teamRole]"),Ie=Y.querySelector("button[data-action=save-role]"),rt=Y.querySelector("button[data-action=delete-role]");fe&&(fe.value=G,fe.disabled=!1),Ie&&(Ie.disabled=!1),rt&&(rt.disabled=!1)};var so=F;let X=`/api/team/local-bots/${encodeURIComponent(y)}/role`,_=Pe.bots.find(G=>G.larkAppId===y);_&&typeof _.teamRole!="string"&&!_.teamRoleLoading&&(_.teamRoleLoading=!0,(async()=>{try{let G=await fetch(X),Y=await G.json().catch(()=>({}));G.ok&&Y.ok?(_.teamRole=Y.role??"",F(_.teamRole)):(le.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${Y.error??G.status}`,le.classList.add("hint-warn-inline"))}catch(G){le.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${G?.message??G}`,le.classList.add("hint-warn-inline")}finally{_.teamRoleLoading=!1}})());async function J(G,Y,fe){if(le&&!(!_||typeof _.teamRole!="string")){le.textContent="",le.className="oncall-status",pe.disabled=!0,Be.disabled=!0;try{let Ie=await fetch(X,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({role:G})}),rt=await Ie.json().catch(()=>({}));Ie.ok&&rt.ok?(_&&(_.teamRole=G.trim()),le.textContent=`\u2713 ${fe?t("botDefaults.roleDeleted"):t("botDefaults.roleSaved")}`,le.classList.add("hint-ok")):(le.textContent=`\u2717 ${rt.error??Ie.status}`,le.classList.add("hint-warn-inline"))}catch(Ie){le.textContent=`\u2717 ${Ie?.message??Ie}`,le.classList.add("hint-warn-inline")}finally{pe.disabled=!1,Be.disabled=!1}}}pe.addEventListener("click",()=>J(st.value,pe,!1)),Be.addEventListener("click",()=>{st.value="",J("",Be,!0)})}let E=d.querySelector("input[data-action=toggle-restrict-grant]"),ae=d.querySelector("input[data-input=quotaLimit]"),W=d.querySelector("button[data-action=save-quota]"),j=d.querySelector("button[data-action=off-quota]"),se=d.querySelector("[data-grant-status]"),et=d.querySelector("[data-quota-state]");async function it(X,_){if(se){se.textContent="",se.className="oncall-status",_.disabled=!0;try{let F=await fetch(`/api/bots/${encodeURIComponent(y)}/grant-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(X)}),J=await F.json().catch(()=>({}));if(F.ok&&J.ok){se.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,se.classList.add("hint-ok");let G=typeof J.messageQuotaDefaultLimit=="number"?J.messageQuotaDefaultLimit:null,Y=Pe.bots.find(fe=>fe.larkAppId===y);Y&&(Y.restrictGrantCommands=J.restrictGrantCommands===!0,Y.messageQuotaDefaultLimit=G),et&&(et.textContent=D(G)),ae&&"messageQuotaDefaultLimit"in X&&(ae.value=G==null?"":String(G))}else se.textContent=`\u2717 ${J.error??F.status}`,se.classList.add("hint-warn-inline")}catch(F){se.textContent=`\u2717 ${F?.message??F}`,se.classList.add("hint-warn-inline")}finally{_.disabled=!1}}}E&&E.addEventListener("change",()=>{it({restrictGrantCommands:E.checked},E)}),ae&&W&&W.addEventListener("click",()=>{let X=ae.value.trim();if(X===""){it({messageQuotaDefaultLimit:null},W);return}if(!/^[1-9]\d*$/.test(X)){se&&(se.textContent=`\u2717 ${t("botDefaults.quotaInvalid")}`,se.className="oncall-status hint-warn-inline");return}it({messageQuotaDefaultLimit:Number(X)},W)}),ae&&j&&j.addEventListener("click",()=>{ae.value="",it({messageQuotaDefaultLimit:null},j)})})}r(),_e().then(r),s.addEventListener("input",r)}var Nn=4096,en=[],We=null,Ke=null,qe="",$t=new Set;function ai(){return`<section class="page roles-page">
|
|
783
|
+
</div>`}function D(){n.querySelectorAll(".bd-card").forEach(m=>{let y=m.dataset.appid,S=m.querySelector("input[data-action=toggle]"),H=m.querySelector("input[data-input=workingDir]"),B=m.querySelector("button[data-action=save]"),j=m.querySelector("[data-status]");if(!S||!H||!B||!j)return;S.addEventListener("change",()=>{H.disabled=!S.checked,S.checked&&H.focus()}),B.addEventListener("click",async()=>{j.textContent="",j.className="oncall-status";let J=S.checked,z=H.value.trim();if(J&&!z){j.textContent=t("botDefaults.required"),j.classList.add("hint-warn-inline");return}B.disabled=!0;try{let P=await fetch(`/api/bots/${encodeURIComponent(y)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:J,workingDir:z})}),W=await P.json().catch(()=>({}));if(P.ok&&W.ok){let G=W.resolvedPath?` \u2192 ${W.resolvedPath}`:"";j.textContent=J?`\u2713 \u5DF2\u5F00\u542F${G}\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",j.classList.add("hint-ok");let Y=Oe.bots.find(De=>De.larkAppId===y);Y&&W.defaultOncall&&(Y.defaultOncall=W.defaultOncall);let ue=m.querySelector("[data-oncall-since]");ue&&W.defaultOncall?.since!=null&&(ue.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${fa(W.defaultOncall.since)}`)}else j.textContent=`\u2717 ${W.error??P.status}`,j.classList.add("hint-warn-inline")}catch(P){j.textContent=`\u2717 ${P?.message??P}`,j.classList.add("hint-warn-inline")}finally{B.disabled=!1}});let q=m.querySelector("input[data-input=brandLabel]"),oe=m.querySelector("button[data-action=save-brand]"),X=m.querySelector("button[data-action=reset-brand]"),ae=m.querySelector("[data-brand-status]"),Ae=m.querySelector("[data-brand-state]");async function se(J,z){if(ae){ae.textContent="",ae.className="oncall-status",z.disabled=!0;try{let P=await fetch(`/api/bots/${encodeURIComponent(y)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:J})}),W=await P.json().catch(()=>({}));if(P.ok&&W.ok){let G=W.brandLabel??null;ae.textContent="\u2713",ae.classList.add("hint-ok"),q&&(q.value=G??""),Ae&&(Ae.textContent=k(G));let Y=Oe.bots.find(ue=>ue.larkAppId===y);Y&&(Y.brandLabel=G)}else ae.textContent=`\u2717 ${W.error??P.status}`,ae.classList.add("hint-warn-inline")}catch(P){ae.textContent=`\u2717 ${P?.message??P}`,ae.classList.add("hint-warn-inline")}finally{z.disabled=!1}}}q&&oe&&oe.addEventListener("click",()=>se(q.value,oe)),X&&X.addEventListener("click",()=>se(null,X));let ie=m.querySelector("input[data-action=toggle-disable-streaming]"),ce=m.querySelector("input[data-action=toggle-writable-link]"),Le=m.querySelector("input[data-action=toggle-private-card]"),de=m.querySelector("[data-card-pref-status]"),Be=m.querySelector("[data-card-pref-moot]");async function ge(J,z,P=de){if(P){P.textContent="",P.className="oncall-status",z.disabled=!0;try{let W=await fetch(`/api/bots/${encodeURIComponent(y)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(J)}),G=await W.json().catch(()=>({}));if(W.ok&&G.ok){P.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,P.classList.add("hint-ok");let Y=Oe.bots.find(ue=>ue.larkAppId===y);Y&&(Y.disableStreamingCard=G.disableStreamingCard,Y.writableTerminalLinkInCard=G.writableTerminalLinkInCard,Y.privateCard=G.privateCard,Y.autoStartOnGroupJoin=G.autoStartOnGroupJoin,Y.autoStartOnGroupJoinPrompt=G.autoStartOnGroupJoinPrompt,Y.autoStartOnNewTopic=G.autoStartOnNewTopic,Y.regularGroupReplyMode=G.regularGroupReplyMode,Y.regularGroupMentionMode=G.regularGroupMentionMode,Y.docSubscribeDefaultMode=G.docSubscribeDefaultMode)}else P.textContent=`\u2717 ${G.error??W.status}`,P.classList.add("hint-warn-inline")}catch(W){P.textContent=`\u2717 ${W?.message??W}`,P.classList.add("hint-warn-inline")}finally{z===ce?z.disabled=!!ie?.checked:z.disabled=!1}}}ie&&ie.addEventListener("change",()=>{let J=ie.checked;ce&&(ce.disabled=J),Be&&(Be.hidden=!J),ge({disableStreamingCard:J},ie)}),ce&&ce.addEventListener("change",()=>{ge({writableTerminalLinkInCard:ce.checked},ce)}),Le&&Le.addEventListener("change",()=>{ge({privateCard:Le.checked},Le)});let Ie=m.querySelector("input[data-action=toggle-sandbox]"),re=m.querySelector("[data-sandbox-status]");Ie&&Ie.addEventListener("change",async()=>{let J=Ie.checked;re&&(re.textContent="",re.className="oncall-status"),Ie.disabled=!0;try{let z=await fetch(`/api/bots/${encodeURIComponent(y)}/sandbox`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:J})}),P=await z.json().catch(()=>({}));if(z.ok&&P.ok){re&&(re.textContent=`\u2713 ${t("botDefaults.sandboxSaved")}`,re.classList.add("hint-ok"));let W=Oe.bots.find(G=>G.larkAppId===y);W&&(W.sandbox=P.sandbox===!0)}else re&&(re.textContent=`\u2717 ${P.error??z.status}`,re.classList.add("hint-warn-inline")),Ie.checked=!J}catch(z){re&&(re.textContent=`\u2717 ${z?.message??z}`,re.classList.add("hint-warn-inline")),Ie.checked=!J}finally{Ie.disabled=!1}});let pe=m.querySelector("input[data-action=toggle-auto-join]"),le=m.querySelector("input[data-action=toggle-auto-topic]"),Ne=m.querySelector("textarea[data-input=autoJoinPrompt]"),je=m.querySelector("button[data-action=save-auto-join-prompt]"),Pe=m.querySelector("[data-auto-start-status]");pe&&pe.addEventListener("change",()=>{ge({autoStartOnGroupJoin:pe.checked},pe,Pe)}),le&&le.addEventListener("change",()=>{ge({autoStartOnNewTopic:le.checked},le,Pe)}),Ne&&je&&je.addEventListener("click",()=>{ge({autoStartOnGroupJoinPrompt:Ne.value},je,Pe)});let Fe=m.querySelector("select[data-input=p2pMode]"),be=m.querySelector("[data-p2p-status]");Fe&&be&&Fe.addEventListener("change",async()=>{let J=Fe.value==="chat"?"chat":"thread";be.textContent="",be.className="oncall-status",Fe.disabled=!0;try{let z=await fetch(`/api/bots/${encodeURIComponent(y)}/p2p-mode`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({p2pMode:J})}),P=await z.json().catch(()=>({}));if(z.ok&&P.ok){be.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,be.classList.add("hint-ok");let W=Oe.bots.find(G=>G.larkAppId===y);W&&(W.p2pMode=P.p2pMode==="chat"?"chat":"thread")}else be.textContent=`\u2717 ${P.error??z.status}`,be.classList.add("hint-warn-inline")}catch(z){be.textContent=`\u2717 ${z?.message??z}`,be.classList.add("hint-warn-inline")}finally{Fe.disabled=!1}});let nt=m.querySelector("select[data-input=regularGroupMode]"),wt=m.querySelector("[data-regular-group-status]");nt&&nt.addEventListener("change",()=>{ge({regularGroupReplyMode:nt.value},nt,wt)});let ot=m.querySelector("select[data-input=regularGroupMentionMode]"),Ht=m.querySelector("[data-mention-mode-status]");ot&&ot.addEventListener("change",()=>{ge({regularGroupMentionMode:ot.value},ot,Ht)});let at=m.querySelector("select[data-input=docSubscribeDefaultMode]"),Me=m.querySelector("[data-doc-subscribe-mode-status]");at&&at.addEventListener("change",()=>{ge({docSubscribeDefaultMode:at.value},at,Me)});let _e=m.querySelector("textarea[data-input=teamRole]"),Ge=m.querySelector("button[data-action=save-role]"),x=m.querySelector("button[data-action=delete-role]"),V=m.querySelector("[data-role-status]");if(_e&&Ge&&x&&V){let P=function(G){let Y=n.querySelector(`.bd-card[data-appid="${CSS.escape(y)}"]`);if(!Y)return;let ue=Y.querySelector("textarea[data-input=teamRole]"),De=Y.querySelector("button[data-action=save-role]"),ut=Y.querySelector("button[data-action=delete-role]");ue&&(ue.value=G,ue.disabled=!1),De&&(De.disabled=!1),ut&&(ut.disabled=!1)};var $n=P;let J=`/api/team/local-bots/${encodeURIComponent(y)}/role`,z=Oe.bots.find(G=>G.larkAppId===y);z&&typeof z.teamRole!="string"&&!z.teamRoleLoading&&(z.teamRoleLoading=!0,(async()=>{try{let G=await fetch(J),Y=await G.json().catch(()=>({}));G.ok&&Y.ok?(z.teamRole=Y.role??"",P(z.teamRole)):(V.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${Y.error??G.status}`,V.classList.add("hint-warn-inline"))}catch(G){V.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${G?.message??G}`,V.classList.add("hint-warn-inline")}finally{z.teamRoleLoading=!1}})());async function W(G,Y,ue){if(V&&!(!z||typeof z.teamRole!="string")){V.textContent="",V.className="oncall-status",Ge.disabled=!0,x.disabled=!0;try{let De=await fetch(J,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({role:G})}),ut=await De.json().catch(()=>({}));De.ok&&ut.ok?(z&&(z.teamRole=G.trim()),V.textContent=`\u2713 ${ue?t("botDefaults.roleDeleted"):t("botDefaults.roleSaved")}`,V.classList.add("hint-ok")):(V.textContent=`\u2717 ${ut.error??De.status}`,V.classList.add("hint-warn-inline"))}catch(De){V.textContent=`\u2717 ${De?.message??De}`,V.classList.add("hint-warn-inline")}finally{Ge.disabled=!1,x.disabled=!1}}}Ge.addEventListener("click",()=>W(_e.value,Ge,!1)),x.addEventListener("click",()=>{_e.value="",W("",x,!0)})}let K=m.querySelector("input[data-action=toggle-restrict-grant]"),_=m.querySelector("input[data-input=quotaLimit]"),he=m.querySelector("button[data-action=save-quota]"),Xe=m.querySelector("button[data-action=off-quota]"),$e=m.querySelector("[data-grant-status]"),Wt=m.querySelector("[data-quota-state]");async function ct(J,z){if($e){$e.textContent="",$e.className="oncall-status",z.disabled=!0;try{let P=await fetch(`/api/bots/${encodeURIComponent(y)}/grant-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(J)}),W=await P.json().catch(()=>({}));if(P.ok&&W.ok){$e.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,$e.classList.add("hint-ok");let G=typeof W.messageQuotaDefaultLimit=="number"?W.messageQuotaDefaultLimit:null,Y=Oe.bots.find(ue=>ue.larkAppId===y);Y&&(Y.restrictGrantCommands=W.restrictGrantCommands===!0,Y.messageQuotaDefaultLimit=G),Wt&&(Wt.textContent=M(G)),_&&"messageQuotaDefaultLimit"in J&&(_.value=G==null?"":String(G))}else $e.textContent=`\u2717 ${W.error??P.status}`,$e.classList.add("hint-warn-inline")}catch(P){$e.textContent=`\u2717 ${P?.message??P}`,$e.classList.add("hint-warn-inline")}finally{z.disabled=!1}}}K&&K.addEventListener("change",()=>{ct({restrictGrantCommands:K.checked},K)}),_&&he&&he.addEventListener("click",()=>{let J=_.value.trim();if(J===""){ct({messageQuotaDefaultLimit:null},he);return}if(!/^[1-9]\d*$/.test(J)){$e&&($e.textContent=`\u2717 ${t("botDefaults.quotaInvalid")}`,$e.className="oncall-status hint-warn-inline");return}ct({messageQuotaDefaultLimit:Number(J)},he)}),_&&Xe&&Xe.addEventListener("click",()=>{_.value="",ct({messageQuotaDefaultLimit:null},Xe)});let Ze=m.querySelector("input[data-input=maxLiveWorkers]"),yt=m.querySelector("button[data-action=save-session-cap]"),Ct=m.querySelector("button[data-action=off-session-cap]"),Se=m.querySelector("[data-session-cap-status]"),At=m.querySelector("[data-session-cap-state]");async function vt(J,z){if(Se){Se.textContent="",Se.className="oncall-status",z.disabled=!0;try{let P=await fetch(`/api/bots/${encodeURIComponent(y)}/max-live-workers`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({maxLiveWorkers:J})}),W=await P.json().catch(()=>({}));if(P.ok&&W.ok){Se.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,Se.classList.add("hint-ok");let G=typeof W.maxLiveWorkers=="number"?W.maxLiveWorkers:null,Y=Oe.bots.find(ue=>ue.larkAppId===y);Y&&(Y.maxLiveWorkers=G),At&&(At.textContent=R(G)),Ze&&(Ze.value=G==null?"":String(G))}else Se.textContent=`\u2717 ${W.error??P.status}`,Se.classList.add("hint-warn-inline")}catch(P){Se.textContent=`\u2717 ${P?.message??P}`,Se.classList.add("hint-warn-inline")}finally{z.disabled=!1}}}Ze&&yt&&yt.addEventListener("click",()=>{let J=Ze.value.trim();if(J===""){vt(null,yt);return}if(!/^[1-9]\d*$/.test(J)){Se&&(Se.textContent=`\u2717 ${t("botDefaults.maxLiveWorkersInvalid")}`,Se.className="oncall-status hint-warn-inline");return}vt(Number(J),yt)}),Ze&&Ct&&Ct.addEventListener("click",()=>{Ze.value="",vt(null,Ct)})})}r(),Ke().then(r),s.addEventListener("input",r)}var zn=4096,ln=[],Ye=null,Ve=null,Ue="",Mt=new Set;function ri(){return`<section class="page roles-page">
|
|
767
784
|
<div class="page-heading">
|
|
768
785
|
<div>
|
|
769
786
|
<p class="eyebrow">${t("nav.roles")}</p>
|
|
@@ -802,40 +819,40 @@ ${d.join(`
|
|
|
802
819
|
</div>
|
|
803
820
|
</div>
|
|
804
821
|
</div>
|
|
805
|
-
</section>`}async function
|
|
806
|
-
<div class="roles-bot-row ${
|
|
822
|
+
</section>`}async function rn(){ln=((await(await fetch("/api/groups")).json()).chats??[]).map(o=>({chatId:o.chatId,name:o.name??o.chatId,memberBots:(o.memberBots??[]).map(s=>({larkAppId:s.larkAppId,botName:s.botName??s.larkAppId,inChat:s.inChat??!1,hasRole:s.hasRole??!1,oncallChat:s.oncallChat??null}))}))}async function ha(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`)).json()}async function li(e,n,o){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({content:o})})).ok}async function di(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`,{method:"DELETE"})).ok}function wa(e){return e.memberBots.filter(n=>n.inChat&&n.hasRole).length}function ci(e){return e.memberBots.filter(n=>n.inChat).length}function mt(e=""){let n=document.getElementById("roles-tree");if(!n)return;let o=e.toLowerCase(),s=ln.filter(a=>{if(!o)return!0;let r=a.chatId.toLowerCase().includes(o)||(a.name??"").toLowerCase().includes(o),d=a.memberBots.some(p=>p.larkAppId.toLowerCase().includes(o)||(p.botName??"").toLowerCase().includes(o));return r||d});if(s.length===0){n.innerHTML=`<div class="roles-empty">${t("roles.noChats")}</div>`;return}n.innerHTML=s.map(a=>{let r=Mt.has(a.chatId),d=a.memberBots.filter(T=>T.inChat),p=r?"\u25BE":"\u25B8",v=wa(a),k=ci(a),I=r?d.map(T=>`
|
|
823
|
+
<div class="roles-bot-row ${Ye===a.chatId&&Ve===T.larkAppId?"selected":""}"
|
|
807
824
|
data-group-id="${i(a.chatId)}"
|
|
808
|
-
data-bot-id="${i(
|
|
825
|
+
data-bot-id="${i(T.larkAppId)}">
|
|
809
826
|
<span class="roles-bot-indent"></span>
|
|
810
|
-
${
|
|
827
|
+
${fe({name:T.botName,larkAppId:T.larkAppId,size:"sm"})}
|
|
811
828
|
<div class="roles-bot-info">
|
|
812
|
-
<div class="roles-bot-name">${i(
|
|
813
|
-
<div class="roles-bot-id">${i(
|
|
829
|
+
<div class="roles-bot-name">${i(T.botName)}</div>
|
|
830
|
+
<div class="roles-bot-id">${i(T.larkAppId)}</div>
|
|
814
831
|
</div>
|
|
815
|
-
<span class="roles-badge ${
|
|
816
|
-
${
|
|
832
|
+
<span class="roles-badge ${T.hasRole?"has-role":"no-role"}">
|
|
833
|
+
${T.hasRole?t("roles.configured"):t("roles.unconfigured")}
|
|
817
834
|
</span>
|
|
818
835
|
</div>`).join(""):"";return`
|
|
819
836
|
<div class="roles-group-section">
|
|
820
|
-
<div class="roles-group-row ${r?"expanded":""} ${
|
|
837
|
+
<div class="roles-group-row ${r?"expanded":""} ${Ye===a.chatId&&!Ve?"selected":""}"
|
|
821
838
|
data-group-id="${i(a.chatId)}">
|
|
822
839
|
<span class="roles-group-arrow">${p}</span>
|
|
823
840
|
<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>
|
|
824
841
|
<div class="roles-group-info">
|
|
825
842
|
<div class="roles-group-name">${i(a.name??a.chatId)}</div>
|
|
826
843
|
<div class="roles-group-meta">
|
|
827
|
-
${
|
|
844
|
+
${v}/${k} ${t("roles.botsWithRoles")}
|
|
828
845
|
</div>
|
|
829
846
|
</div>
|
|
830
847
|
<span class="roles-group-chevron"></span>
|
|
831
848
|
</div>
|
|
832
|
-
<div class="roles-bot-list">${
|
|
833
|
-
</div>`}).join(""),n.querySelectorAll(".roles-group-row").forEach(a=>{a.addEventListener("click",()=>{let r=a.dataset.groupId;r&&(
|
|
849
|
+
<div class="roles-bot-list">${I}</div>
|
|
850
|
+
</div>`}).join(""),n.querySelectorAll(".roles-group-row").forEach(a=>{a.addEventListener("click",()=>{let r=a.dataset.groupId;r&&(Mt.has(r)?Mt.delete(r):Mt.add(r),mt(document.getElementById("roles-search")?.value??""))})}),n.querySelectorAll(".roles-bot-row").forEach(a=>{a.addEventListener("click",r=>{r.stopPropagation();let d=a.dataset.groupId,p=a.dataset.botId;d&&p&&ui(d,p)})})}async function ui(e,n){Ye=e,Ve=n;let o=await ha(n,e),s=document.getElementById("roles-editor-empty"),a=document.getElementById("roles-editor-form"),r=document.getElementById("roles-editor-textarea"),d=document.getElementById("roles-editor-group-name"),p=document.getElementById("roles-editor-bot-name"),v=document.getElementById("roles-editor-chat-id");s&&(s.style.display="none"),a&&(a.style.display="");let k=ln.find(g=>g.chatId===e),I=k?.memberBots.find(g=>g.larkAppId===n);d&&(d.textContent=k?.name??e),p&&(p.textContent=I?.botName??n),v&&(v.textContent=`${e} \xB7 ${n}`),Ue=o.content??"",r&&(r.value=Ue,r.focus()),Wn(),Kn(),mt(document.getElementById("roles-search")?.value??"");let T=document.getElementById("roles-delete");T&&(T.style.display=o.hasRole?"":"none")}function Wn(){let e=document.getElementById("roles-editor-bytecount");if(!e)return;let n=new TextEncoder().encode(Ue).length;e.textContent=`${n} / ${zn} bytes`,e.className=`roles-bytecount ${n>3800?"warn":""} ${n>zn?"over":""}`,pi(n)}function pi(e){let n=document.getElementById("roles-save");if(!n)return;let o=e??new TextEncoder().encode(Ue).length;n.disabled=o>zn||Ue.trim().length===0}function Kn(){let e=document.getElementById("roles-preview");e&&(Ue.trim()?e.innerHTML=`<strong>${t("roles.preview")}</strong><pre>${i(Ue)}</pre>`:e.innerHTML=`<small>${t("roles.previewEmpty")}</small>`)}function ba(){Ye=null,Ve=null,Ue="";let e=document.getElementById("roles-editor-empty"),n=document.getElementById("roles-editor-form"),o=document.getElementById("roles-editor-textarea"),s=document.getElementById("roles-delete");e&&(e.style.display=""),n&&(n.style.display="none"),o&&(o.value=""),s&&(s.style.display="none")}async function ya(e){e.innerHTML=ri(),Mt.clear(),ba();let n=document.getElementById("roles-tree");n&&(n.innerHTML=St()),await rn(),await Ke();for(let o of ln)wa(o)>0&&Mt.add(o.chatId);mt(),document.getElementById("roles-search")?.addEventListener("input",o=>{mt(o.target.value)}),document.getElementById("roles-refresh")?.addEventListener("click",async()=>{if(await rn(),mt(document.getElementById("roles-search")?.value??""),Ye&&Ve){let o=await ha(Ve,Ye),s=document.getElementById("roles-editor-textarea");s&&(s.value=o.content??""),Ue=o.content??"",Wn(),Kn();let a=document.getElementById("roles-delete");a&&(a.style.display=o.hasRole?"":"none")}}),document.getElementById("roles-save")?.addEventListener("click",async function(){if(!(!Ye||!Ve)){this.disabled=!0,this.textContent="...";try{if(await li(Ve,Ye,Ue)){await rn(),mt(document.getElementById("roles-search")?.value??"");let s=document.getElementById("roles-delete");s&&(s.style.display="");let a=document.createElement("span");a.className="roles-saved-flash",a.textContent=` ${t("roles.saved")}`,document.querySelector(".roles-editor-footer")?.appendChild(a),setTimeout(()=>a.remove(),2e3)}else{let s=document.createElement("span");s.className="roles-saved-flash roles-save-error",s.textContent=Ue.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(!(!Ye||!Ve)&&confirm(t("roles.confirmDelete"))){this.disabled=!0,this.textContent="...";try{await di(Ve,Ye)&&(await rn(),ba(),mt(document.getElementById("roles-search")?.value??""))}finally{this.disabled=!1,this.textContent=t("roles.delete")}}}),document.getElementById("roles-editor-textarea")?.addEventListener("input",o=>{Ue=o.target.value,Wn(),Kn()})}async function un(e){let n=await fetch(e);return{status:n.status,body:await n.json().catch(()=>({}))}}async function pn(e,n,o){let s=await fetch(n,{method:e,headers:{"content-type":"application/json"},body:o?JSON.stringify(o):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}var gt=(e,n)=>pn("POST",e,n),mi=(e,n)=>pn("PUT",e,n),Jn=[],va=[],ka="",dn="",Yn=new Map,cn=new Map,Nt=new Set,Pt=new Set;function te(e){return document.getElementById(e)}function mn(){return[...Jn,...va]}function ft(e){let n=Yn.get(e);return n||(n=new Set,Yn.set(e,n)),n}function fi(e){return mn().find(n=>n.key===e)}function $a(e){let n=(o,s,a)=>`<a href="${o}" style="padding:6px 14px;border-radius:8px;text-decoration:none;font-size:14px;font-weight:600;${a?"background:var(--accent);color:var(--on-accent)":"color:var(--muted);background:var(--surface-muted)"}">${s}</a>`;return`<div style="display:flex;gap:8px;margin-bottom:14px">${n("#/team",t("team.navHome"),e==="home")}${n("#/team/manage",t("team.navManage"),e==="manage")}</div>`}function gi(){return`<section class="page">
|
|
834
851
|
<div class="page-heading"><div>
|
|
835
852
|
<p class="eyebrow">${t("team.eyebrow")}</p><h1>${t("team.homeTitle")}</h1>
|
|
836
853
|
<p class="tf-lede">${t("team.homeLede")}</p>
|
|
837
854
|
</div></div>
|
|
838
|
-
${
|
|
855
|
+
${$a("home")}
|
|
839
856
|
<div class="card" style="margin-bottom:16px">
|
|
840
857
|
<h2 style="margin-top:0">${t("team.localDeployTitle")}</h2>
|
|
841
858
|
<p>${t("team.myIdentity")}<b id="tf-owner">${t("team.unbound")}</b>
|
|
@@ -864,12 +881,12 @@ ${ha("home")}
|
|
|
864
881
|
</div>
|
|
865
882
|
</div>
|
|
866
883
|
</div>
|
|
867
|
-
</section>`}function
|
|
884
|
+
</section>`}function bi(e){let n=(te("tf-search").value||"").trim().toLowerCase();if(n&&!((e.name||"")+" "+(e.cliId||"")+" "+(e.capability||"")).toLowerCase().includes(n))return!1;let o=te("tf-cli").value;return!(o&&e.cliId!==o||te("tf-fcap").checked&&!e.capability||te("tf-frole").checked&&!e.hasTeamRole)}function hi(e,n){let o=[...e.deployments].sort((a,r)=>a.local===r.local?0:a.local?-1:1),s="";for(let a of o){let r=n.filter(g=>g.deployment.id===a.id);if(!r.length)continue;let d=a.id===ka,p=d?t("team.tagLocal"):a.stale?t("team.tagRemoteStale"):t("team.tagRemote"),v=e.kind==="local"&&!d?` <button class="tf-rmmember ghost" data-team="${i(e.teamId)}" data-dep="${i(a.id)}" data-name="${i(a.name)}" style="font-size:12px">${t("team.removeMember")}</button>`:"",k=`${e.key}::${a.id}`,I=Pt.has(k),T=r.filter(g=>ft(e.key).has(g.larkAppId)).length;if(s+=`<div class="tf-dep-h" data-dk="${i(k)}" style="cursor:pointer;margin:10px 0 2px"><b>${I?"\u25BE":"\u25B8"} ${i(a.name)}</b> <span class="muted" style="font-size:12px">${t("team.depTag",{tag:p})} \xB7 ${t("team.depCount",{count:r.length})}${T?t("team.depSelected",{n:T}):""}</span>${v}</div>`,!!I){s+='<table style="width:100%;border-collapse:collapse;font-size:14px"><tbody>';for(let g of r){let R=i(g.larkAppId),A=ft(e.key).has(g.larkAppId)?" checked":"",O=g.deployment.stale?"opacity:.55":"",M=d?`<input class="tf-cap" data-app="${R}" value="${i(g.capability||"")}" placeholder="${t("team.capPh")}" style="width:92%;padding:3px 6px">`:g.capability?i(g.capability):'<span class="muted">\u2014</span>',E=g.hasTeamRole?d?`<button class="tf-role" data-app="${R}" data-name="${i(g.name)}">${t("team.viewRole")}</button>`:t("team.hasRoleShort"):'<span class="muted">\u2014</span>';s+=`<tr style="${O}"><td style="padding:4px 8px"><input type="checkbox" class="tf-pick" data-tk="${i(e.key)}" data-app="${R}"${A}></td><td style="padding:4px 8px">${i(g.name)}</td><td style="padding:4px 8px" class="muted">${i(g.cliId)}</td><td style="padding:4px 8px">${M}</td><td style="padding:4px 8px">${E}</td></tr>`}s+="</tbody></table>"}}return s||(s=`<p class="muted" style="margin:8px 0 0">${t("team.noMatch")}</p>`),s+=`<div style="margin-top:12px;display:flex;gap:8px;flex-wrap:wrap;align-items:center"><input class="tf-gname" data-tk="${i(e.key)}" value="${i(cn.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 rt(){let e=te("tf-teams"),n=mn();if(!n.length){e.innerHTML=`<p class="muted">${t("team.noTeams")}</p>`,te("tf-count").textContent="";return}let o="",s=new Set,a=new Set;for(let p of n){let v=p.bots.filter(bi);v.forEach(g=>s.add(g.larkAppId)),p.bots.forEach(g=>a.add(g.larkAppId));let k=new Set(v.map(g=>g.larkAppId));[...ft(p.key)].forEach(g=>{k.has(g)||ft(p.key).delete(g)});let I=!Nt.has(p.key),T=p.kind==="remote"?p.ok?` <span class="ok" style="font-size:12px">${t("team.connected")}</span>`:` <span class="err" style="font-size:12px">${t("team.connectFail",{error:i(p.error||"")})}</span>`:` <span class="muted" style="font-size:12px">${t("team.iHost")}</span>`;o+=`<div class="card" style="margin:0 0 12px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)"><div class="tf-team-h" data-tk="${i(p.key)}" style="cursor:pointer;display:flex;align-items:center;gap:8px;flex-wrap:wrap"><b style="font-size:15px">${I?"\u25B8":"\u25BE"} ${i(p.label)}</b>`+(p.sub?` <span class="muted" style="font-size:12px">${i(p.sub)}</span>`:"")+T+` <span class="muted" style="font-size:12px">\xB7 ${t("team.teamMeta",{deps:p.deployments.length,bots:p.bots.length})}</span></div>`,I||(o+=p.kind==="remote"&&!p.ok?`<p class="muted" style="margin:8px 0 0">${t("team.rosterFail")}</p>`:hi(p,v)),o+="</div>"}e.innerHTML=o;let r=n.length>1?t("team.acrossTeams",{n:n.length}):"",d=s.size===a.size?`${a.size}`:`${s.size} / ${a.size}`;te("tf-count").textContent=`\xB7 ${d} ${t("team.botsWord")}${r}`,wi()}function wi(){let e=te("tf-teams");e.querySelectorAll(".tf-team-h").forEach(n=>{n.onclick=()=>{let o=n.dataset.tk;Nt.has(o)?Nt.delete(o):Nt.add(o),rt()}}),e.querySelectorAll(".tf-dep-h").forEach(n=>{n.onclick=()=>{let o=n.dataset.dk;Pt.has(o)?Pt.delete(o):Pt.add(o),rt()}}),e.querySelectorAll(".tf-pick").forEach(n=>{n.onchange=()=>{let o=ft(n.dataset.tk);n.checked?o.add(n.dataset.app):o.delete(n.dataset.app)}}),e.querySelectorAll(".tf-gname").forEach(n=>{n.oninput=()=>{cn.set(n.dataset.tk,n.value)}}),e.querySelectorAll(".tf-cap").forEach(n=>{n.onchange=async()=>{let o=n.dataset.app,s=n.value;await mi("/api/team/local-bots/"+encodeURIComponent(o)+"/capability",{capability:s}),mn().forEach(a=>{let r=a.bots.find(d=>d.larkAppId===o);r&&(r.capability=s.trim()||null)})}}),e.querySelectorAll(".tf-role").forEach(n=>{n.onclick=()=>vi(n.dataset.app,n.dataset.name||"")}),e.querySelectorAll(".tf-rmmember").forEach(n=>{n.onclick=async o=>{o.stopPropagation(),confirm(t("team.removeMemberConfirm",{name:n.dataset.name||""}))&&(await pn("DELETE",`/api/team/hosted/${encodeURIComponent(n.dataset.team)}/members/${encodeURIComponent(n.dataset.dep)}`),qt())}}),e.querySelectorAll(".tf-grp").forEach(n=>{n.onclick=async()=>{let o=n.dataset.tk,s=fi(o);if(!s)return;let a=[...ft(o)],r=e.querySelector(`.tf-gout[data-tk="${CSS.escape(o)}"]`);if(!a.length){r.innerHTML=`<span class="err">${t("team.errPickBot")}</span>`;return}let d=(e.querySelector(`.tf-gname[data-tk="${CSS.escape(o)}"]`)?.value||"").trim()||t("team.defaultGroupName");r.innerHTML=`<span class="muted">${t("team.creatingGroup")}</span>`;let p=s.kind==="local"?await gt("/api/team/federated-group",{name:d,larkAppIds:a,teamId:s.teamId}):await gt("/api/team/remote-group",{hubUrl:s.hubUrl,teamId:s.teamId,name:d,larkAppIds:a});if(yi(r,p.body,p.status),p.body?.ok){ft(o).clear(),cn.delete(o);let v=r.innerHTML,k=()=>{let I=e.querySelector(`.tf-gout[data-tk="${CSS.escape(o)}"]`);I&&(I.innerHTML=v)};s.kind==="local"?qt().then(k):(rt(),k())}}})}function yi(e,n,o){if(n?.ok&&n.chatId){let s=n.shareLink||"https://applink.feishu.cn/client/chat/open?openChatId="+encodeURIComponent(n.chatId),a=(n.invalidBotIds||[]).length?` <span class="err"> \xB7 ${t("team.invalidBots",{ids:i((n.invalidBotIds||[]).join(", "))})}</span>`:"",r=(n.invalidOwnerUnionIds||[]).length?`<span class="err"> \xB7 ${t("team.invalidOwners",{n:(n.invalidOwnerUnionIds||[]).length})}</span>`:"",d=n.missingOperatorIdentity?`<span class="err"> \xB7 ${t("team.missingIdentity")}</span>`:"",p=(n.skippedNoOwner||[]).length?`<span class="err"> \xB7 ${t("team.skippedNoOwner",{n:(n.skippedNoOwner||[]).length})}</span>`:"",v=n.delegatedTo?t("team.delegatedBy",{name:i(n.delegatedTo)}):"";e.innerHTML=`<span class="ok">${t("team.groupCreated")}</span>${v} \xB7 <a href="${i(s)}" target="_blank">${t("team.openInLark")}</a>${a}${r}${d}${p}`}else{let s=n?.error||o,a=s==="no_local_online_bot"?t("team.errNoLocalBot"):s==="all_bots_skipped_no_owner"?t("team.errAllSkipped"):s==="no_creator_available"?t("team.errNoCreator"):s==="delegation_timeout"?t("team.errDelegationTimeout"):t("team.errGroupCreate",{error:String(s)});e.innerHTML=`<span class="err">${i(String(a))}</span>`}}async function vi(e,n){let o=await un("/api/team/local-bots/"+encodeURIComponent(e)+"/role");te("tf-modal-title").textContent=t("team.roleModalTitleName",{name:n}),te("tf-modal-text").value=o.body?.role||"",te("tf-modal").dataset.app=e,te("tf-modal").style.display="flex"}function Sa(){let e=Array.from(new Set(mn().flatMap(s=>s.bots.map(a=>a.cliId)).filter(Boolean))).sort(),n=te("tf-cli"),o=n.value;n.innerHTML=`<option value="">${t("team.allCli")}</option>`+e.map(s=>`<option value="${i(s)}">${i(s)}</option>`).join(""),n.value=o}async function qt(){let n=(await un("/api/team/hosted")).body;if(!n?.ok){Jn=[],rt();return}ka=n.deployment.deploymentId,dn=n.suggestedHubUrl||"",te("tf-owner").textContent=n.deployment.ownerName||(n.deployment.ownerUnionId?t("team.bound"):t("team.unbound")),Jn=(n.teams||[]).map(o=>({kind:"local",key:`local:${o.teamId}`,teamId:o.teamId,label:o.isDefault?t("team.myHostedTeam"):o.name,sub:"",ok:!0,deployments:o.deployments||[],bots:o.bots||[]})),Sa(),rt()}async function ki(){va=((await un("/api/team/remote-roster")).body?.memberships||[]).map(o=>{let s=o.roster?.deployments||[],a=s.find(d=>d.local),r=a?.name?t("team.remoteTeamLabel",{name:a.name}):o.teamName||o.teamId;return{kind:"remote",key:`${o.hubUrl}::${o.teamId}`,teamId:o.teamId,label:r,sub:o.hubUrl,ok:!!o.ok,error:o.error,hubUrl:o.hubUrl,deployments:s,bots:o.roster?.bots||[]}}),Sa(),rt()}function Ta(e){e.innerHTML=gi(),Yn.clear(),cn.clear(),Nt.clear(),Pt.clear(),["tf-search","tf-cli","tf-fcap","tf-frole"].forEach(n=>{let o=te(n);o.oninput=rt,o.onchange=rt}),te("tf-modal-cancel").onclick=()=>{te("tf-modal").style.display="none"},Si(),qt(),ki()}function $i(){return`<section class="page">
|
|
868
885
|
<div class="page-heading"><div>
|
|
869
886
|
<p class="eyebrow">${t("team.eyebrow")}</p><h1>${t("team.manageTitle")}</h1>
|
|
870
887
|
<p class="tf-lede">${t("team.manageLede")}</p>
|
|
871
888
|
</div></div>
|
|
872
|
-
${
|
|
889
|
+
${$a("manage")}
|
|
873
890
|
<div class="card" style="margin-bottom:16px">
|
|
874
891
|
<h2 style="margin-top:0">${t("team.hostedTitle")}</h2>
|
|
875
892
|
<p style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:6px">
|
|
@@ -888,7 +905,7 @@ ${ha("manage")}
|
|
|
888
905
|
</p>
|
|
889
906
|
<div id="tm-join-out" style="display:none;margin-top:6px"></div>
|
|
890
907
|
</div>
|
|
891
|
-
</section>`}async function
|
|
908
|
+
</section>`}async function Vn(){let n=(await un("/api/team/hosted")).body,o=te("tm-list");dn=n?.suggestedHubUrl||dn;let s=n?.teams||[];if(!s.length){o.innerHTML=`<p class="muted">${t("team.noTeamsShort")}</p>`;return}o.innerHTML=s.map(a=>{let r=(a.deployments||[]).filter(d=>!d.local).length;return`<div class="card" style="margin:0 0 8px;padding:10px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
892
909
|
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
893
910
|
<b>${i(a.name)}</b>${a.isDefault?` <span class="muted" style="font-size:12px">${t("team.default")}</span>`:""}
|
|
894
911
|
<span class="muted" style="font-size:12px">\xB7 ${t("team.manageMetaDeps",{count:(a.deployments||[]).length})}${r?t("team.manageMetaRemote",{r}):""} \xB7 ${t("team.manageMetaBots",{count:(a.bots||[]).length})}</span>
|
|
@@ -897,7 +914,7 @@ ${ha("manage")}
|
|
|
897
914
|
${a.isDefault?"":`<button class="tm-del ghost" data-team="${i(a.teamId)}" data-name="${i(a.name)}" style="font-size:12px">${t("team.delBtn")}</button>`}
|
|
898
915
|
</span>
|
|
899
916
|
</div>
|
|
900
|
-
<div class="tm-inv-out" data-team="${i(a.teamId)}" style="display:none;margin-top:6px;font-size:13px"></div></div>`}).join(""),o.querySelectorAll(".tm-invite").forEach(a=>{a.onclick=async()=>{let r=a.dataset.team,
|
|
917
|
+
<div class="tm-inv-out" data-team="${i(a.teamId)}" style="display:none;margin-top:6px;font-size:13px"></div></div>`}).join(""),o.querySelectorAll(".tm-invite").forEach(a=>{a.onclick=async()=>{let r=a.dataset.team,d=o.querySelector(`.tm-inv-out[data-team="${CSS.escape(r)}"]`);d.style.display="",d.innerHTML=`<span class="muted">${t("team.generating")}</span>`;let p=await gt("/api/team/local-invite",{teamId:r});p.body?.code?d.innerHTML=`${t("team.inviteResultLede")}<br>${t("team.inviteHub")}<code>${i(dn)}</code><br>${t("team.inviteCode")}<code style="font-size:15px">${i(p.body.code)}</code>`:d.innerHTML=`<span class="err">${t("team.genFail")}</span>`}}),o.querySelectorAll(".tm-del").forEach(a=>{a.onclick=async()=>{confirm(t("team.delConfirm",{name:a.dataset.name||""}))&&(await pn("DELETE","/api/team/hosted/"+encodeURIComponent(a.dataset.team)),Vn())}})}function La(e){e.innerHTML=$i(),te("tm-create").onclick=async()=>{let n=te("tm-newname").value.trim(),o=e.querySelector(".tm-cout");if(!n){o.innerHTML=`<span class="err">${t("team.errName")}</span>`;return}o.innerHTML=`<span class="muted">${t("team.creating")}</span>`;let s=await gt("/api/team/hosted",{name:n});s.body?.ok?(o.innerHTML=`<span class="ok">${t("team.created")}</span>`,te("tm-newname").value="",Vn()):o.innerHTML=`<span class="err">${t("team.createFail",{error:i(String(s.body?.error||s.status))})}</span>`},te("tm-join").onclick=async()=>{let n=te("tm-hub").value.trim(),o=te("tm-code").value.trim(),s=te("tm-join-out");if(s.style.display="",!n||!o){s.innerHTML=`<span class="err">${t("team.errHubCode")}</span>`;return}s.innerHTML=`<span class="muted">${t("team.joining")}</span>`;let a=await gt("/api/team/join-remote",{hubUrl:n,inviteCode:o});if(a.body?.ok)s.innerHTML=`<span class="ok">${t("team.joined",{name:i(a.body.teamName||"")})}</span>`,te("tm-code").value="";else{let r=a.body?.error||a.status,d=r==="cannot_join_self"?t("team.joinErrSelf"):r==="deployment_already_joined"?t("team.joinErrAlready"):r==="hub_unreachable"?t("team.joinErrUnreachable"):r==="hub_timeout"?t("team.joinErrTimeout"):t("team.joinErrGeneric",{error:String(r)});s.innerHTML=`<span class="err">${i(String(d))}</span>`}},Vn()}function Si(){te("tf-autobind").onclick=async()=>{let e=te("tf-bind-out");e.style.display="",e.innerHTML=`<span class="muted">${t("team.identifying")}</span>`;let o=(await gt("/api/team/identity/auto-bind")).body;if(o?.ok&&o.owner){e.innerHTML=`<span class="ok">${t("team.bound2",{name:i(o.owner.name||o.owner.unionId)})}</span>`,qt();return}if(o?.ok&&o.needChoice&&Array.isArray(o.candidates)){let s=o.candidates.map(a=>`<button class="tf-pickowner ghost" data-union="${i(a.unionId)}" style="margin:2px">${i(a.name||a.unionId)}</button>`).join(" ");e.innerHTML=`${t("team.multiCandidate")}<br>${s}`,e.querySelectorAll(".tf-pickowner").forEach(a=>{a.onclick=async()=>{e.innerHTML=`<span class="muted">${t("team.binding")}</span>`;let d=(await gt("/api/team/identity/auto-bind",{unionId:a.dataset.union})).body;d?.ok&&d.owner?(e.innerHTML=`<span class="ok">${t("team.bound2",{name:i(d.owner.name||d.owner.unionId)})}</span>`,qt()):e.innerHTML=`<span class="err">${t("team.bindFail",{error:i(String(d?.error||"unknown"))})}</span>`}});return}if(o?.error==="no_candidates"){e.innerHTML=`<span class="err">${t("team.noCandidates")}</span>`;return}e.innerHTML=`<span class="err">${t("team.bindFail",{error:i(String(o?.error||"unknown"))})}</span>`}}async function Qn(e){let n=await fetch(e);return{status:n.status,body:await n.json().catch(()=>({}))}}async function Zn(e,n,o){let s=await fetch(n,{method:e,headers:{"content-type":"application/json"},body:o?JSON.stringify(o):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}function ne(e){return document.getElementById(e)}function bt(e){return(ne(e).value||"").trim()}var eo=[],no=[];function Ti(){return`<section class="page">
|
|
901
918
|
<div class="page-heading">
|
|
902
919
|
<div>
|
|
903
920
|
<p class="eyebrow">Webhook</p>
|
|
@@ -959,11 +976,11 @@ ${ha("manage")}
|
|
|
959
976
|
<h2 style="margin-top:0">${t("connectors.listTitle")} <span class="muted" id="cn-count" style="font-size:13px"></span></h2>
|
|
960
977
|
<div id="cn-list">${t("connectors.loading")}</div>
|
|
961
978
|
</div>
|
|
962
|
-
</section>`}function
|
|
979
|
+
</section>`}function Xn(){let e=ne("cn-kind").value,n=ne("cn-mode").value;document.querySelectorAll(".cn-wf").forEach(o=>{o.style.display=e==="workflow"?"":"none"}),document.querySelectorAll(".cn-fixed").forEach(o=>{o.style.display=n==="fixed"?"":"none"}),document.querySelectorAll(".cn-allow").forEach(o=>{o.style.display=n==="fixed"?"none":""}),document.querySelectorAll(".cn-dyn").forEach(o=>{o.style.display=n==="dynamic"?"":"none"}),document.querySelectorAll(".cn-life").forEach(o=>{o.style.display=n==="new-group"?"":"none"})}function Ia(e){return`${location.origin}/webhook/${encodeURIComponent(e)}`}function Li(e){return e==="fixed"?t("connectors.modeLabelFixed"):e==="new-group"?t("connectors.modeLabelNewGroup"):t("connectors.modeLabelDynamic")}function Ii(e){return e==="workflow"?t("connectors.kindLabelWorkflow"):t("connectors.kindLabelTurn")}function to(e){return no.find(o=>o.chatId===e)?.name||e}function Mi(e){return no.filter(n=>n.bots.includes(e))}function Ma(){let e=ne("cn-bot").value,n=Mi(e),o=p=>`<option value="${i(p.chatId)}">${i(p.name||p.chatId)}</option>`,s=ne("cn-chat-sel"),a=s.value;s.innerHTML=n.length?n.map(o).join(""):`<option value="">${t("connectors.noBotGroups")}</option>`,a&&n.some(p=>p.chatId===a)&&(s.value=a);let r=ne("cn-allow-sel"),d=new Set(Array.from(r.selectedOptions).map(p=>p.value));r.innerHTML=n.map(o).join(""),Array.from(r.options).forEach(p=>{d.has(p.value)&&(p.selected=!0)})}function xi(e){let n=ne("cn-list");if(ne("cn-count").textContent=e.length?t("connectors.count",{count:e.length}):"",!e.length){n.innerHTML=`<p class="muted">${t("connectors.empty")}</p>`;return}n.innerHTML=e.map(o=>{let s=eo.find(v=>v.larkAppId===o.target.botId),a=Ia(o.id),r=(o.verify?.type??"token")==="token",d=r?t("connectors.badgeToken"):t("connectors.badgeSign"),p=o.target.mode==="fixed"&&o.target.chatId?` \xB7 ${t("connectors.dest",{name:i(to(o.target.chatId))})}`:"";return`<div class="card" style="margin:0 0 10px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
963
980
|
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
964
981
|
<b style="font-size:15px">${i(o.name)}</b>
|
|
965
982
|
<span class="${o.enabled?"ok":"muted"}" style="font-size:12px">${o.enabled?t("connectors.enabled"):t("connectors.disabled")}</span>
|
|
966
|
-
<span class="muted" style="font-size:12px">\xB7 ${i(s?.botName||o.target.botId)} \xB7 ${
|
|
983
|
+
<span class="muted" style="font-size:12px">\xB7 ${i(s?.botName||o.target.botId)} \xB7 ${Ii(o.target.kind)} \xB7 ${Li(o.target.mode)}${p} \xB7 ${d}</span>
|
|
967
984
|
<span style="margin-left:auto;display:flex;gap:6px">
|
|
968
985
|
<button class="cn-toggle ghost" data-id="${i(o.id)}" data-on="${o.enabled}" style="font-size:12px">${o.enabled?t("connectors.btnDisable"):t("connectors.btnEnable")}</button>
|
|
969
986
|
<button class="cn-del ghost" data-id="${i(o.id)}" style="font-size:12px">${t("connectors.btnDel")}</button>
|
|
@@ -972,15 +989,15 @@ ${ha("manage")}
|
|
|
972
989
|
<div style="margin-top:6px;font-size:13px;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
973
990
|
<span class="muted">${t("connectors.webhookUrl")}</span><code style="font-size:12px;word-break:break-all">${i(a)}${r?"/<token>":""}</code>
|
|
974
991
|
<button class="cn-copy ghost" data-url="${i(a)}" style="font-size:12px">${t("connectors.copy")}</button>
|
|
975
|
-
</div>${r?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.tokenHint")}</div>`:""}${o.target.mode==="dynamic"?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.dynamicReqHint")}</div>`:""}${o.promptEnvelope?.instruction?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.instructionPrefix")}${i(o.promptEnvelope.instruction)}</div>`:""}</div>`}).join(""),n.querySelectorAll(".cn-copy").forEach(o=>{o.onclick=()=>{navigator.clipboard?.writeText(o.dataset.url),o.textContent=t("connectors.copied"),setTimeout(()=>o.textContent=t("connectors.copy"),1200)}}),n.querySelectorAll(".cn-toggle").forEach(o=>{o.onclick=async()=>{await
|
|
976
|
-
<pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${
|
|
977
|
-
<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicNote")}</p>`}else
|
|
978
|
-
<pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${
|
|
979
|
-
<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageTokenNote")}</p>`:
|
|
980
|
-
<p class="ok" style="margin:0 0 6px">${t("connectors.createdPrefix",{name:i(o)})}${r==="fixed"&&
|
|
981
|
-
<p style="margin:4px 0;font-size:13px"><span class="muted">${t("connectors.webhookUrl")}</span><code style="word-break:break-all">${i(
|
|
982
|
-
${g?`<p style="margin:4px 0;font-size:13px"><span class="muted">${
|
|
983
|
-
${
|
|
992
|
+
</div>${r?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.tokenHint")}</div>`:""}${o.target.mode==="dynamic"?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.dynamicReqHint")}</div>`:""}${o.promptEnvelope?.instruction?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.instructionPrefix")}${i(o.promptEnvelope.instruction)}</div>`:""}</div>`}).join(""),n.querySelectorAll(".cn-copy").forEach(o=>{o.onclick=()=>{navigator.clipboard?.writeText(o.dataset.url),o.textContent=t("connectors.copied"),setTimeout(()=>o.textContent=t("connectors.copy"),1200)}}),n.querySelectorAll(".cn-toggle").forEach(o=>{o.onclick=async()=>{await Zn("PATCH","/api/connectors/"+encodeURIComponent(o.dataset.id),{enabled:o.dataset.on!=="true"}),fn()}}),n.querySelectorAll(".cn-del").forEach(o=>{o.onclick=async()=>{confirm(t("connectors.delConfirm"))&&(await Zn("DELETE","/api/connectors/"+encodeURIComponent(o.dataset.id)),fn())}})}async function fn(){let[e,n,o]=await Promise.all([Qn("/api/bots"),Qn("/api/connectors"),Qn("/api/groups")]);eo=(e.body?.bots||[]).map(r=>({larkAppId:r.larkAppId,botName:r.botName||r.larkAppId})),no=(o.body?.chats||[]).map(r=>({chatId:r.chatId,name:r.name||"",bots:(r.memberBots||[]).filter(d=>d.inChat).map(d=>d.larkAppId)}));let s=ne("cn-bot"),a=s.value;s.innerHTML=eo.map(r=>`<option value="${i(r.larkAppId)}">${i(r.botName)}</option>`).join("")||`<option value="">${t("connectors.noOnlineBots")}</option>`,a&&(s.value=a),Ma(),xi(n.body?.connectors||[])}function xa(e){e.innerHTML=Ti(),ne("cn-kind").onchange=Xn,ne("cn-mode").onchange=Xn,ne("cn-bot").onchange=Ma,ne("cn-chat-manual").onclick=n=>{n.preventDefault();let o=ne("cn-chat"),s=ne("cn-chat-sel"),a=o.style.display==="none";o.style.display=a?"":"none",s.style.display=a?"none":"",ne("cn-chat-manual").textContent=a?t("connectors.chatListLink"):t("connectors.chatManualLink")},Xn(),ne("cn-create").onclick=async()=>{let n=ne("cn-create-out"),o=bt("cn-name"),s=ne("cn-bot").value;if(!o){n.innerHTML=`<span class="err">${t("connectors.errName")}</span>`;return}if(!s){n.innerHTML=`<span class="err">${t("connectors.errBot")}</span>`;return}let a=ne("cn-kind").value,r=ne("cn-mode").value,d={name:o,enabled:!0,target:{kind:a,mode:r,botId:s},promptEnvelope:{sourceName:o}},p=bt("cn-instruction");if(p&&(d.promptEnvelope.instruction=p),a==="workflow"){if(!bt("cn-wf")){n.innerHTML=`<span class="err">${t("connectors.errWf")}</span>`;return}d.target.workflowId=bt("cn-wf")}if(r==="fixed"){let T=ne("cn-chat").style.display!=="none"?bt("cn-chat"):ne("cn-chat-sel").value;if(!T){n.innerHTML=`<span class="err">${t("connectors.errChat")}</span>`;return}d.target.chatId=T}else{let I=Array.from(ne("cn-allow-sel").selectedOptions).map(T=>T.value).filter(Boolean);I.length&&(d.target.allowChats=I)}if(r==="new-group"){let I=bt("cn-dedup");d.lifecycleExtractors=I?{dedupKey:I}:null}d.verify={type:ne("cn-verify").value};let v=bt("cn-secret");v&&(d.secret=v),n.innerHTML=`<span class="muted">${t("connectors.creating")}</span>`;let k=await Zn("POST","/api/connectors",d);if(k.status===201&&k.body?.ok){n.innerHTML="";let I=ne("cn-created");I.style.display="";let T=k.body.webhookUrl||Ia(k.body.connector.id),g=k.body.secret,R=(k.body.connector?.verify?.type??"token")==="token",A=r==="dynamic",O=A?d.target.allowChats?.[0]||"<chatId>":"",M=A?`${i(T)}?chatId=${i(O)}`:i(T),E;if(R&&A){let $=O!=="<chatId>"?`\uFF08${i(to(d.target.allowChats[0]))}\uFF09`:"";E=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicLede",{gn:$})}</p>
|
|
993
|
+
<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>
|
|
994
|
+
<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicNote")}</p>`}else R?E=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageTokenLede")}</p>
|
|
995
|
+
<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>
|
|
996
|
+
<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageTokenNote")}</p>`:E=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageHmac")}${A?t("connectors.usageHmacDynamic"):""}</p>`;I.innerHTML=`<div class="card" style="padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
997
|
+
<p class="ok" style="margin:0 0 6px">${t("connectors.createdPrefix",{name:i(o)})}${r==="fixed"&&d.target.chatId?`<span class="muted" style="font-weight:400;font-size:13px"> \xB7 ${t("connectors.createdDest",{name:i(to(d.target.chatId))})}</span>`:""}</p>
|
|
998
|
+
<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>
|
|
999
|
+
${g?`<p style="margin:4px 0;font-size:13px"><span class="muted">${R?t("connectors.tokenLabel"):t("connectors.signLabel")}${t("connectors.secretOnce")}</span><code>${i(g)}</code></p>`:""}
|
|
1000
|
+
${E}</div>`,["cn-name","cn-wf","cn-chat","cn-dedup","cn-secret","cn-instruction"].forEach($=>{ne($).value=""}),ne("cn-allow-sel").selectedIndex=-1,fn()}else{let I=k.body?.error||k.status;n.innerHTML=`<span class="err">${t("connectors.createFailed",{error:i(String(I))})}</span>`}},fn()}var ke=null,jt=null,Ut=!0;function Ea(e){return{publicReadOnly:e?.publicReadOnly===!0,openTerminalInFeishu:e?.openTerminalInFeishu===!0,repoPickerMode:e?.repoPickerMode==="repos"?"repos":"all",maintenance:e?.maintenance&&typeof e.maintenance=="object"?e.maintenance:{},localDevInstall:e?.localDevInstall===!0}}function Ei(e,n){let o=e?.[n]??{};return{enabled:o.enabled===!0,time:typeof o.time=="string"?o.time:"04:00"}}function Hi(){return`<section class="page">
|
|
984
1001
|
<div class="page-heading">
|
|
985
1002
|
<div>
|
|
986
1003
|
<p class="eyebrow">${t("nav.settings")}</p>
|
|
@@ -989,7 +1006,7 @@ ${ha("manage")}
|
|
|
989
1006
|
</div>
|
|
990
1007
|
</div>
|
|
991
1008
|
<div id="settings-body"></div>
|
|
992
|
-
</section>`}function
|
|
1009
|
+
</section>`}function Ci(e){let{enabled:n,time:o}=Ei(ke.maintenance,"autoUpdate"),s=e?"disabled":"";return`<label class="toggle-row">
|
|
993
1010
|
<input type="checkbox" data-maint="autoUpdate" ${n?"checked":""} ${s}>
|
|
994
1011
|
<span class="switch" aria-hidden="true"></span>
|
|
995
1012
|
<span class="toggle-tx"><strong>${t("settings.autoUpdate")}</strong>
|
|
@@ -999,18 +1016,18 @@ ${ha("manage")}
|
|
|
999
1016
|
<label>${t("settings.maintenanceTime")}
|
|
1000
1017
|
<input type="time" data-maint-time="autoUpdate" value="${i(o)}" ${s}>
|
|
1001
1018
|
</label>
|
|
1002
|
-
</div>`}function
|
|
1003
|
-
<input type="checkbox" data-maint="autoRestart" ${
|
|
1019
|
+
</div>`}function Ai(e){return`<label class="toggle-row">
|
|
1020
|
+
<input type="checkbox" data-maint="autoRestart" ${ke.maintenance.autoRestart?.enabled===!0?"checked":""} ${e?"disabled":""}>
|
|
1004
1021
|
<span class="switch" aria-hidden="true"></span>
|
|
1005
1022
|
<span class="toggle-tx"><strong>${t("settings.autoRestart")}</strong>
|
|
1006
1023
|
<small>${t("settings.autoRestartHelp")}</small></span>
|
|
1007
|
-
</label>`}function
|
|
1024
|
+
</label>`}function Di(){if(jt)return`<p class="hint-warn">${t("settings.loadFailed")}: ${i(jt)}</p>`;if(!ke)return`<p class="empty">${t("settings.loading")}</p>`;let e=Ut?"":"disabled",n=!Ut||ke.localDevInstall;return`<div class="settings-grid">
|
|
1008
1025
|
<article class="bd-card settings-card">
|
|
1009
|
-
${
|
|
1026
|
+
${Ut?"":`<p class="hint-warn">${t("settings.readOnlyVisitor")}</p>`}
|
|
1010
1027
|
<section class="bd-section">
|
|
1011
1028
|
<h3 class="bd-section-title">${t("settings.sectionAccess")}</h3>
|
|
1012
1029
|
<label class="toggle-row">
|
|
1013
|
-
<input type="checkbox" data-setting="publicReadOnly" ${
|
|
1030
|
+
<input type="checkbox" data-setting="publicReadOnly" ${ke.publicReadOnly?"checked":""} ${e}>
|
|
1014
1031
|
<span class="switch" aria-hidden="true"></span>
|
|
1015
1032
|
<span class="toggle-tx"><strong>${t("settings.publicReadOnly")}</strong>
|
|
1016
1033
|
<small>${t("settings.publicReadOnlyHelp")}</small></span>
|
|
@@ -1019,7 +1036,7 @@ ${ha("manage")}
|
|
|
1019
1036
|
<section class="bd-section">
|
|
1020
1037
|
<h3 class="bd-section-title">${t("settings.sectionCards")}</h3>
|
|
1021
1038
|
<label class="toggle-row">
|
|
1022
|
-
<input type="checkbox" data-setting="openTerminalInFeishu" ${
|
|
1039
|
+
<input type="checkbox" data-setting="openTerminalInFeishu" ${ke.openTerminalInFeishu?"checked":""} ${e}>
|
|
1023
1040
|
<span class="switch" aria-hidden="true"></span>
|
|
1024
1041
|
<span class="toggle-tx"><strong>${t("settings.openTerminalInFeishu")}</strong>
|
|
1025
1042
|
<small>${t("settings.openTerminalInFeishuHelp")}</small></span>
|
|
@@ -1030,23 +1047,23 @@ ${ha("manage")}
|
|
|
1030
1047
|
<label class="form-row">
|
|
1031
1048
|
<span>${t("settings.repoPickerMode")}</span>
|
|
1032
1049
|
<select data-select-setting="repoPickerMode" ${e}>
|
|
1033
|
-
<option value="all" ${
|
|
1034
|
-
<option value="repos" ${
|
|
1050
|
+
<option value="all" ${ke.repoPickerMode==="all"?"selected":""}>${t("settings.repoPickerModeAll")}</option>
|
|
1051
|
+
<option value="repos" ${ke.repoPickerMode==="repos"?"selected":""}>${t("settings.repoPickerModeRepos")}</option>
|
|
1035
1052
|
</select>
|
|
1036
1053
|
<small>${t("settings.repoPickerModeHelp")}</small>
|
|
1037
1054
|
</label>
|
|
1038
1055
|
</section>
|
|
1039
1056
|
<section class="bd-section">
|
|
1040
1057
|
<h3 class="bd-section-title">${t("settings.sectionMaintenance")}</h3>
|
|
1041
|
-
${
|
|
1042
|
-
${
|
|
1043
|
-
${
|
|
1058
|
+
${Ci(n)}
|
|
1059
|
+
${ke.localDevInstall?`<p class="hint-warn">${t("settings.autoUpdateLocalDev")}</p>`:""}
|
|
1060
|
+
${Ai(!Ut||ke.maintenance.autoUpdate?.enabled!==!0)}
|
|
1044
1061
|
</section>
|
|
1045
1062
|
<div class="actions settings-actions">
|
|
1046
1063
|
<span class="oncall-status" data-settings-status></span>
|
|
1047
1064
|
</div>
|
|
1048
1065
|
</article>
|
|
1049
|
-
</div>`}async function
|
|
1066
|
+
</div>`}async function Ri(){try{let e=await fetch("/api/settings"),n=await e.json().catch(()=>({}));if(!e.ok){ke=null,jt=n?.error??`HTTP ${e.status}`;return}ke=Ea(n.settings),Ut=n.authed===!0,jt=null}catch(e){ke=null,jt=e?.message??String(e)}}async function Ha(e){e.innerHTML=Hi();let n=e.querySelector("#settings-body");function o(){n.innerHTML=Di(),r()}function s(){return n.querySelector("[data-settings-status]")}async function a(d,p,v){if(!ke)return;v.disabled=!0;let k=s();k&&(k.textContent=t("settings.saving"),k.className="oncall-status");try{let I=await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(d)}),T=await I.json().catch(()=>({}));if(!I.ok||T.ok===!1)throw new Error(T?.error??`HTTP ${I.status}`);ke=Ea(T.settings),k&&(k.textContent=t("settings.saved"),k.classList.add("hint-ok"))}catch(I){p(),k&&(k.textContent=`${t("settings.saveFailed")}: ${I?.message??I}`,k.classList.add("hint-warn-inline"))}finally{v.disabled=!1}}function r(){n.querySelectorAll("input[data-setting]").forEach(p=>{p.addEventListener("change",()=>{let v=p.dataset.setting,k=!p.checked;a({[v]:p.checked},()=>{p.checked=k},p)})}),n.querySelectorAll("select[data-select-setting]").forEach(p=>{p.addEventListener("change",()=>{let v=p.dataset.selectSetting,k=ke?.[v]??"all";a({[v]:p.value},()=>{p.value=k},p)})});let d=(p,v,k)=>{let T=n.querySelector(`input[data-maint="${p}"]`)?.checked??!1,g;if(p==="autoUpdate"){let R=n.querySelector('input[data-maint-time="autoUpdate"]');g={enabled:T,time:R?.value||"04:00"}}else g={enabled:T};a({maintenance:{[p]:g}},k,v).then(()=>o())};n.querySelectorAll("input[data-maint]").forEach(p=>{p.addEventListener("change",()=>{let v=p.dataset.maint,k=!p.checked;d(v,p,()=>{p.checked=k})})}),n.querySelectorAll("input[data-maint-time]").forEach(p=>{p.addEventListener("change",()=>{let v=p.dataset.maintTime,k=p.defaultValue;d(v,p,()=>{p.value=k})})})}o(),await Ri(),o()}function Oi(){let e=[["",t("workflow.filter.nonTerminal")],["all",t("workflow.filter.all")],["pending",lt("pending")],["running",lt("running")],["waiting",lt("waiting")],["succeeded",lt("succeeded")],["failed",lt("failed")],["cancelled",lt("cancelled")]];return`
|
|
1050
1067
|
<nav class="wf-subnav">
|
|
1051
1068
|
<a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${h(t("workflow.subnav.runs"))}</a>
|
|
1052
1069
|
<a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${h(t("workflow.subnav.catalog"))}</a>
|
|
@@ -1066,15 +1083,15 @@ ${ha("manage")}
|
|
|
1066
1083
|
</tr></thead>
|
|
1067
1084
|
<tbody id="wf-tbody"></tbody>
|
|
1068
1085
|
</table>
|
|
1069
|
-
`}var
|
|
1070
|
-
<td><a href="#/workflows/${encodeURIComponent(
|
|
1071
|
-
<td>${h(
|
|
1072
|
-
<td>${
|
|
1073
|
-
<td>${
|
|
1074
|
-
<td class="${
|
|
1075
|
-
<td title="${h(new Date(
|
|
1076
|
-
<td>${
|
|
1077
|
-
</tr>`}).join("")}function
|
|
1086
|
+
`}var Bi=5e3,Ni=2e3,Ft=new Set(["succeeded","failed","cancelled"]);function h(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function Pi(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 tt(e){return`<span class="${Ft.has(e)?"wf-status terminal":"wf-status live"} wf-status-${h(e)}">${h(lt(e))}</span>`}function lt(e){let n=`workflow.status.${e}`,o=t(n);return o===n?e:o}function Ra(e){let n=location.hash.match(/^#\/workflows\/([^?#]+)(?:\?([^#]*))?$/);if(n){let o=new URLSearchParams(n[2]??"");return Ui(e,decodeURIComponent(n[1]),{focusAttemptId:o.get("attempt")??void 0})}return qi(e)}function qi(e){e.innerHTML=Oi();let n=e.querySelector("#wf-tbody"),o=e.querySelector("#wf-filters"),s=e.querySelector("#wf-last-load"),a=[],r=null,d=!1,p=null,v=!1;function k(O){let E=(new FormData(o).get("q")??"").trim().toLowerCase();return E?O.filter($=>$.runId.toLowerCase().includes(E)||$.workflowId.toLowerCase().includes(E)||($.chatId??"").toLowerCase().includes(E)):O}function I(){let O=k(a);if(O.length===0){n.innerHTML=`<tr><td colspan="7" class="empty">${p?h(t("workflow.list.failedLoad",{error:p})):a.length===0?h(t("workflow.list.noRuns")):h(t("workflow.list.noFilterMatch"))}</td></tr>`;return}n.innerHTML=O.map(M=>{let E=`${M.dEf}/${M.dAct}/${M.dWait}`,$=M.dEf+M.dAct+M.dWait>0?"wf-dangling has":"wf-dangling none",D=[];M.chatId&&D.push(h(M.chatId)),M.larkAppId&&D.push(`<span class="muted">${h(M.larkAppId)}</span>`);let m=D.length>0?D.join("<br/>"):"\u2014",y=Fi(M);return`<tr data-runid="${h(M.runId)}">
|
|
1087
|
+
<td><a href="#/workflows/${encodeURIComponent(M.runId)}"><code>${h(M.runId)}</code></a></td>
|
|
1088
|
+
<td>${h(M.workflowId)}</td>
|
|
1089
|
+
<td>${tt(M.status)}${M.failedNodeId?` <span class="muted">(${h(M.failedNodeId)})</span>`:""}${y}</td>
|
|
1090
|
+
<td>${M.lastSeq}</td>
|
|
1091
|
+
<td class="${$}">${E}</td>
|
|
1092
|
+
<td title="${h(new Date(M.updatedAt).toISOString())}">${Pi(M.updatedAt)}</td>
|
|
1093
|
+
<td>${m}</td>
|
|
1094
|
+
</tr>`}).join("")}function T(){p?(s.textContent=t("workflow.list.error",{error:p}),s.classList.add("error")):(s.textContent=t("workflow.list.loaded",{count:a.length,time:new Date().toLocaleTimeString()}),s.classList.remove("error"))}async function g(){if(!(v||d)&&!document.hidden){d=!0;try{let O=o.elements.namedItem("status")?.value??"",M=new URLSearchParams;O==="all"?M.set("all","1"):O&&M.set("status",O);let E="/api/workflows/runs"+(M.toString()?`?${M}`:""),$=await fetch(E);$.ok?(a=(await $.json()).runs??[],p=null):(p=`HTTP ${$.status}`,a=[])}catch(O){p=O?.message??String(O),a=[]}finally{d=!1,v||(I(),T())}}}function R(){r!==null&&window.clearTimeout(r),r=window.setTimeout(async()=>{await g(),v||R()},Bi)}function A(){document.hidden||g()}return o.addEventListener("input",()=>{I()}),o.addEventListener("change",O=>{O.target.getAttribute("name")==="status"&&g()}),document.addEventListener("visibilitychange",A),g().then(()=>{v||R()}),()=>{v=!0,r!==null&&window.clearTimeout(r),document.removeEventListener("visibilitychange",A)}}function Ui(e,n,o={}){e.innerHTML=`
|
|
1078
1095
|
<div class="wf-detail-head">
|
|
1079
1096
|
<a class="btn-link" href="#/workflows">${h(t("workflow.detail.back"))}</a>
|
|
1080
1097
|
<div>
|
|
@@ -1130,84 +1147,84 @@ ${ha("manage")}
|
|
|
1130
1147
|
</div>
|
|
1131
1148
|
<div id="wf-event-meta" class="muted"></div>
|
|
1132
1149
|
</section>
|
|
1133
|
-
`;let s=e.querySelector("#wf-detail-subtitle"),a=e.querySelector("#wf-detail-refresh"),r=e.querySelector("#wf-detail-error"),
|
|
1150
|
+
`;let s=e.querySelector("#wf-detail-subtitle"),a=e.querySelector("#wf-detail-refresh"),r=e.querySelector("#wf-detail-error"),d=e.querySelector("#wf-cancel-status"),p=e.querySelector("#wf-summary"),v=e.querySelector("#wf-dangling-panel"),k=e.querySelector("#wf-parallel-view"),I=e.querySelector("#wf-parallel-meta"),T=e.querySelector("#wf-node-tbody"),g=e.querySelector("#wf-io-list"),R=e.querySelector(".wf-timeline-scroll"),A=e.querySelector("#wf-event-tbody"),O=e.querySelector("#wf-event-meta"),M=e.querySelector("#wf-cancel-run"),E=e.querySelector("#wf-load-older"),$=null,D=[],m=new Set,y=null,S=null,H=!1,B=0,j=null,q=!1,oe=!1,X=!1,ae=new Set,Ae=new Map,se=new Map,ie=new Map,ce=new Set,Le=new Map,de=new Set,Be=new Map,ge=new Map,Ie=0,re=o.focusAttemptId;function pe(x){if(!x){r.hidden=!0,r.textContent="";return}r.hidden=!1,r.textContent=x}function le(x){if(!x){d.hidden=!0,d.textContent="";return}d.hidden=!1,d.textContent=x}async function Ne(){let x=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/snapshot`);if(x.status===404)throw new Error(t("workflow.detail.unknownRun"));if(!x.ok)throw new Error(t("workflow.detail.snapshotHttp",{status:x.status}));$=await x.json()}async function je(x){let V=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/events?${x}`);if(V.status===404)throw new Error(t("workflow.detail.unknownRun"));if(!V.ok)throw new Error(t("workflow.detail.eventsHttp",{status:V.status}));return await V.json()}function Pe(x,V){let K=x.filter(_=>m.has(_.eventId)?!1:(m.add(_.eventId),!0));K.length!==0&&(D=V==="prepend"?[...K,...D]:[...D,...K],D.sort((_,he)=>Gt(_.eventId)-Gt(he.eventId)))}async function Fe(){await Ne();let x=await je(new URLSearchParams({tail:"100"}));D=[],m=new Set,Pe(x.events,"append"),y=x.oldestSeq,S=x.newestSeq,H=x.hasOlder,B=x.totalCount,Me()}async function be(){if(!(q||oe||document.hidden)){oe=!0;try{if(await Ne(),S!==null){let x=await je(new URLSearchParams({afterSeq:String(S),limit:"200"}));Pe(x.events,"append"),x.newestSeq!==null&&(S=x.newestSeq),y===null&&x.oldestSeq!==null&&(y=x.oldestSeq),B=x.totalCount}else{let x=await je(new URLSearchParams({tail:"1"}));Pe(x.events,"append"),y=x.oldestSeq,S=x.newestSeq,H=x.hasOlder,B=x.totalCount}pe(null),Me()}catch(x){pe(x?.message??String(x))}finally{oe=!1}}}async function nt(){if(!(y===null||!H)){E.disabled=!0;try{let x=await je(new URLSearchParams({beforeSeq:String(y),limit:"100"}));Pe(x.events,"prepend"),x.oldestSeq!==null&&(y=x.oldestSeq),H=x.hasOlder,B=x.totalCount,pe(null),Me()}catch(x){pe(x?.message??String(x))}finally{E.disabled=!1}}}async function wt(){if(!$||Ft.has($.run.status)||X)return;if(!$.chatBinding?.larkAppId){pe(t("workflow.detail.cancelUnavailable",{runId:n}));return}let x=Gi($),V=t("workflow.detail.cancelConfirm",{runId:n,...x});if(window.confirm(V)){X=!0,M.disabled=!0;try{let K=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/cancel`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"cancelled via dashboard"})});if(K.status===401)throw new Error(t("workflow.detail.writeAccessCancel"));let _=await K.json().catch(()=>({}));if(!K.ok||!_.ok)throw new Error(_.hint??_.error??t("workflow.detail.cancelHttp",{status:K.status}));le(_.pending?t("workflow.detail.cancelPending"):null),pe(null),await be()}catch(K){pe(K?.message??String(K))}finally{X=!1,M.disabled=!1,Me()}}}async function ot(x,V){if(!de.has(x)){de.add(x),Be.delete(x),Me();try{let K=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/attempts/${encodeURIComponent(V)}/${encodeURIComponent(x)}/resume`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});if(K.status===401)throw new Error(t("workflow.detail.writeAccessResume"));let _=await K.json().catch(()=>({}));if(!K.ok||!_.ok||!_.resumeId||!_.url)throw new Error(_.hint??_.message??_.error??t("workflow.detail.resumeStartFailed",{status:K.status}));Le.set(x,{resumeId:_.resumeId,url:_.url})}catch(K){let _=K?.message??String(K);Be.set(x,_)}finally{de.delete(x),Me()}}}async function Ht(x,V){if(!de.has(x)){de.add(x),Be.delete(x),Me();try{let K=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/attempts/${encodeURIComponent(V)}/${encodeURIComponent(x)}/resume/end`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"ended_by_dashboard"})});if(K.status===401)throw new Error(t("workflow.detail.writeAccessResume"));let _=await K.json().catch(()=>({}));if(!K.ok||!_.ok)if(_.error==="resume_not_running")Le.delete(x);else throw new Error(_.hint??_.message??_.error??t("workflow.detail.resumeEndFailed",{status:K.status}));else Le.delete(x)}catch(K){let _=K?.message??String(K);Be.set(x,_)}finally{de.delete(x),Me()}}}async function at(x,V){if(!ce.has(x)){ce.add(x),ie.delete(x),Me();try{let K=se.get(x)?.trim()||void 0,_=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/${V}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({comment:K})});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:V,status:_.status}));let Xe=V==="approve"?t("workflow.detail.approved"):t("workflow.detail.rejected");ie.set(x,{kind:"ok",text:he.alreadyTerminal?t("workflow.detail.alreadyTerminal",{label:Xe}):he.pending?t("workflow.detail.workflowContinue",{label:Xe}):t("workflow.detail.workflowRefreshing",{label:Xe})}),pe(null),await be()}catch(K){let _=K?.message??String(K);ie.set(x,{kind:"error",text:_}),pe(_)}finally{ce.delete(x),Me()}}}function Me(){if(!$)return;Ie=R.scrollTop;let x=$.run;Ft.has(x.status)&&le(null),s.innerHTML=`${h(x.workflowId??"?")} \xB7 ${tt(x.status)} \xB7 lastSeq ${$.lastSeq}`,a.textContent=t("workflow.detail.refreshed",{time:new Date().toLocaleTimeString()}),M.hidden=Ft.has(x.status),M.disabled=X||!$.chatBinding?.larkAppId,M.textContent=$.chatBinding?.larkAppId?t("workflow.detail.cancel"):t("workflow.detail.cliCancelOnly"),M.title=$.chatBinding?.larkAppId?t("workflow.detail.cancelTitle"):t("workflow.detail.cliCancelTitle",{runId:n}),ji(p,$),_i(v,$),zi(k,I,$,D),Qi(T,$),Xi(g,$,ae,Ae,{comments:se,statuses:ie,resolving:ce,onResolve:at},{sessions:Le,pending:de,errors:Be,onStart:ot,onEnd:Ht},re,ge)&&(re=void 0),Tr(A,D),R.scrollTop=Ie,E.hidden=!H,O.textContent=t("workflow.detail.eventsLoaded",{loaded:D.length,total:B})}function _e(){if(j!==null&&window.clearTimeout(j),$&&Ft.has($.run.status)){j=null;return}j=window.setTimeout(async()=>{await be(),q||_e()},Ni)}function Ge(){document.hidden||be().then(()=>{!q&&j===null&&_e()})}return E.addEventListener("click",()=>{nt()}),M.addEventListener("click",()=>{wt()}),document.addEventListener("visibilitychange",Ge),Fe().then(()=>{pe(null),q||_e()}).catch(x=>{pe(x?.message??String(x)),s.textContent=t("workflow.detail.loadFailed")}),()=>{q=!0,j!==null&&window.clearTimeout(j),document.removeEventListener("visibilitychange",Ge)}}function ji(e,n){let o=n.run,s=[[t("workflow.summary.workflow"),h(o.workflowId??"?")],[t("workflow.summary.status"),tt(o.status)],[t("workflow.summary.lastSeq"),String(n.lastSeq)],[t("workflow.summary.updated"),h(new Date(n.updatedAt).toLocaleString())],[t("workflow.summary.revision"),h(hn(o.revisionId))],[t("workflow.summary.initiator"),h(o.initiator??"-")]];o.failedNodeId&&s.push([t("workflow.summary.failedNode"),h(o.failedNodeId)]),o.cancelOriginEventId&&s.push([t("workflow.summary.cancelOrigin"),h(o.cancelOriginEventId)]),n.chatBinding&&(s.push([t("workflow.summary.chat"),`<code>${h(n.chatBinding.chatId)}</code>`]),s.push([t("workflow.summary.app"),`<code>${h(n.chatBinding.larkAppId)}</code>`])),e.innerHTML=s.map(([a,r])=>`<div class="wf-summary-item"><span>${a}</span><strong>${r}</strong></div>`).join("")}function Fi(e){if(!e.errorCode)return"";let n=e.errorMessage?` \u2014 ${xr(e.errorMessage,96)}`:"";return`<div class="wf-run-error">
|
|
1134
1151
|
<span class="muted error">${h(e.errorCode)}</span>${h(n)}
|
|
1135
|
-
</div>`}function
|
|
1152
|
+
</div>`}function Gi(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 _i(e,n){let o=n.dangling,s=[[t("workflow.dangling.activities"),o.activities],[t("workflow.dangling.effects"),o.effectAttempted],[t("workflow.dangling.waits"),o.waits],[t("workflow.dangling.cancels"),o.cancels]],a=new Set(s.flatMap(([,r])=>r)).size;if(e.className=a>0?"wf-panel wf-dangling-panel has":"wf-panel wf-dangling-panel",a===0){e.innerHTML=`<div class="wf-panel-title"><h3>${h(t("workflow.detail.dangling"))}</h3></div><div class="muted">${h(t("workflow.detail.noDangling"))}</div>`;return}e.innerHTML=`<div class="wf-panel-title"><h3>${h(t("workflow.detail.dangling"))}</h3><span class="wf-dangling has">${a}</span></div>
|
|
1136
1153
|
<div class="wf-dangling-grid">
|
|
1137
|
-
${s.map(([r,
|
|
1138
|
-
</div>`}function
|
|
1139
|
-
<span title="${h(new Date(
|
|
1140
|
-
<span title="${h(new Date(p).toISOString())}">${h(
|
|
1154
|
+
${s.map(([r,d])=>`<div><strong>${r}</strong>${d.length===0?`<div class="muted">${h(t("workflow.detail.none"))}</div>`:`<ul>${d.map(p=>`<li><code>${h(p)}</code></li>`).join("")}</ul>`}</div>`).join("")}
|
|
1155
|
+
</div>`}function zi(e,n,o,s){let a=Wi(s,o);if(a.length===0){n.textContent="",e.innerHTML=`<div class="empty">${h(t("workflow.detail.noParallelData"))}</div>`;return}let r=Date.now(),d=Math.min(...a.map(g=>g.startedAt)),p=Math.max(...a.map(g=>g.endedAt??r),d+1e3),v=Math.max(1,p-d),k=Ji(a,r),I=a.filter(g=>!g.endedAt&&(g.status==="running"||g.status==="effectAttempting")).length;n.textContent=t("workflow.detail.parallelMeta",{count:a.length,max:k,running:I});let T=a.sort((g,R)=>g.startedAt-R.startedAt||g.activityId.localeCompare(R.activityId)).map(g=>Ki(g,d,v,r)).join("");e.innerHTML=`<div class="wf-parallel-axis">
|
|
1156
|
+
<span title="${h(new Date(d).toISOString())}">${h(bn(d))}</span>
|
|
1157
|
+
<span title="${h(new Date(p).toISOString())}">${h(bn(p))}</span>
|
|
1141
1158
|
</div>
|
|
1142
|
-
<div class="wf-parallel-list">${
|
|
1159
|
+
<div class="wf-parallel-list">${T}</div>`}function Wi(e,n){let o=new Map,s=new Map(n.activities.map(a=>[a.activityId,a.ownerNodeId]));for(let a of[...e].sort((r,d)=>Gt(r.eventId)-Gt(d.eventId))){let r=Mr(a);if(!r)continue;let d=typeof r.activityId=="string"?r.activityId:void 0,p=typeof r.attemptId=="string"?r.attemptId:void 0;if(!d||!p)continue;let v=o.get(p);if(a.type==="attemptCreated"){let k=typeof r.attemptNumber=="number"?r.attemptNumber:void 0;v={nodeId:typeof r.nodeId=="string"?r.nodeId:s.get(d),activityId:d,attemptId:p,attemptNumber:k,status:"pending",startedAt:a.timestamp},o.set(p,v);continue}v||(v={nodeId:s.get(d),activityId:d,attemptId:p,status:"pending",startedAt:a.timestamp},o.set(p,v)),a.type==="activityRunning"?(v.status="running",v.runningAt=a.timestamp):a.type==="effectAttempted"?v.status="effectAttempting":a.type==="activityWaiting"||a.type==="waitCreated"?v.status="waiting":Yi(a.type)&&(v.status=Vi(a.type),v.endedAt=a.timestamp,v.endType=a.type)}return[...o.values()]}function Ki(e,n,o,s){let a=e.endedAt??s,r=Da((e.startedAt-n)/o*100,0,100),d=Da((Math.max(a,e.startedAt+1)-e.startedAt)/o*100,.7,100-r),p=e.nodeId??e.activityId,v=e.attemptNumber!==void 0?`#${e.attemptNumber}`:hn(e.attemptId),k=[`${p} ${e.status}`,`${new Date(e.startedAt).toISOString()} \u2192 ${e.endedAt?new Date(e.endedAt).toISOString():t("workflow.detail.parallelNow")}`,e.endType?`end: ${e.endType}`:void 0].filter(Boolean).join(`
|
|
1143
1160
|
`);return`<div class="wf-parallel-row">
|
|
1144
1161
|
<div class="wf-parallel-label">
|
|
1145
1162
|
<code>${h(p)}</code>
|
|
1146
|
-
<span class="muted">${h(e.activityId)} \xB7 ${h(
|
|
1163
|
+
<span class="muted">${h(e.activityId)} \xB7 ${h(v)}</span>
|
|
1147
1164
|
</div>
|
|
1148
1165
|
<div class="wf-parallel-track">
|
|
1149
|
-
<div class="wf-parallel-bar wf-parallel-${h(e.status)}" style="left:${r.toFixed(3)}%;width:${
|
|
1150
|
-
<span>${h(
|
|
1166
|
+
<div class="wf-parallel-bar wf-parallel-${h(e.status)}" style="left:${r.toFixed(3)}%;width:${d.toFixed(3)}%;" title="${h(k)}">
|
|
1167
|
+
<span>${h(lt(e.status))}</span>
|
|
1151
1168
|
</div>
|
|
1152
1169
|
</div>
|
|
1153
|
-
</div>`}function
|
|
1170
|
+
</div>`}function Ji(e,n){let o=[];for(let r of e)o.push({time:r.startedAt,delta:1}),o.push({time:r.endedAt??n,delta:-1});o.sort((r,d)=>r.time-d.time||d.delta-r.delta);let s=0,a=0;for(let r of o)s+=r.delta,a=Math.max(a,s);return a}function Yi(e){return e==="activitySucceeded"||e==="activityFailed"||e==="activityTimedOut"||e==="activityCanceled"}function Vi(e){return e==="activitySucceeded"?"succeeded":e==="activityCanceled"?"cancelled":e==="activityTimedOut"?"timedOut":"failed"}function Qi(e,n){let o=new Map(n.activities.map(r=>[r.activityId,r])),s=new Set,a=[];for(let r of n.nodes){let d=(r.activityId?o.get(r.activityId):void 0)??n.activities.find(p=>p.ownerNodeId===r.nodeId);d&&s.add(d.activityId),a.push(Ca(r,d))}for(let r of n.activities)s.has(r.activityId)||a.push(Ca(void 0,r));e.innerHTML=a.length>0?a.join(""):`<tr><td colspan="7" class="empty">${h(t("workflow.detail.noNodes"))}</td></tr>`}function Ca(e,n){let o=n?.attempts[n.attempts.length-1];return`<tr>
|
|
1154
1171
|
<td>${e?`<code>${h(e.nodeId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
1155
|
-
<td>${e?
|
|
1172
|
+
<td>${e?tt(e.status):'<span class="muted">-</span>'}</td>
|
|
1156
1173
|
<td>${n?`<code>${h(n.activityId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
1157
|
-
<td>${n?
|
|
1174
|
+
<td>${n?tt(n.status):'<span class="muted">-</span>'}</td>
|
|
1158
1175
|
<td>${n?.attempts.length??0}</td>
|
|
1159
1176
|
<td>${o?`<code>${h(o.attemptId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
1160
|
-
<td>${o?
|
|
1161
|
-
</tr>`}function
|
|
1177
|
+
<td>${o?Sr(o):`<span class="muted">${h(t("workflow.detail.idle"))}</span>`}</td>
|
|
1178
|
+
</tr>`}function Xi(e,n,o,s,a,r,d,p){hr(e,o,s),mr(e,a.comments);let v=!!(d&&n.attemptIO?.[d]?.terminal);v&&d&&o.add(oo(d,t("workflow.detail.liveTerminal")));let k=Zi(n),I=new Set;if(p){for(let g of k){I.add(g.key);let R=p.get(g.key);R||(R=er(g.key),p.set(g.key,R),e.appendChild(R.article)),tr(R,g,o,a,r,d)}for(let[g,R]of Array.from(p))I.has(g)||(R.article.remove(),p.delete(g));if(k.length===0){if(!e.querySelector(".wf-io-empty-placeholder")){let g=document.createElement("div");g.className="empty wf-io-empty-placeholder",g.textContent=t("workflow.detail.noNodeIO"),e.appendChild(g)}}else e.querySelector(".wf-io-empty-placeholder")?.remove()}else{let g=[];for(let R of k)g.push(ir(R,o,a,r,d));e.innerHTML=g.length>0?g.join(""):`<div class="empty">${h(t("workflow.detail.noNodeIO"))}</div>`}yr(e,s);let T=br(e,d);return wr(e,o),vr(e,s),gr(e,a),Ga(e,r),T&&v}function Zi(e){let n=new Map(e.activities.map(a=>[a.activityId,a])),o=new Set,s=[];for(let a of e.nodes){let r=(a.activityId?n.get(a.activityId):void 0)??e.activities.find(d=>d.ownerNodeId===a.nodeId);if(!r){s.push({key:`node:${a.nodeId}`,node:a});continue}o.add(r.activityId),s.push({key:`activity:${r.activityId}`,node:a,activity:r,io:e.attemptIO?.[gn(r)?.attemptId??""]})}for(let a of e.activities)o.has(a.activityId)||s.push({key:`activity:${a.activityId}`,activity:a,io:e.attemptIO?.[gn(a)?.attemptId??""]});return s}function er(e){let n=document.createElement("article");n.className="wf-io-card",n.dataset.wfCardKey=e;let o=document.createElement("div");o.className="wf-io-card-head";let s=document.createElement("div");s.className="wf-io-terminal-slot";let a=document.createElement("div");return a.className="wf-io-grid",n.appendChild(o),n.appendChild(s),n.appendChild(a),{article:n,head:o,terminalSlot:s,grid:a,currentTerminalUrl:null}}function tr(e,n,o,s,a,r){let d=gn(n.activity),p=n.node?.nodeId??n.activity?.ownerNodeId??n.activity?.activityId??"unknown",v=!!(d&&d.attemptId===r);e.article.classList.toggle("is-focused",v),d?e.article.dataset.wfAttemptCard=d.attemptId:delete e.article.dataset.wfAttemptCard;let k=Fa(d,s);e.head.innerHTML=`
|
|
1162
1179
|
<header>
|
|
1163
1180
|
<div>
|
|
1164
1181
|
<strong><code>${h(p)}</code></strong>
|
|
1165
1182
|
<span class="muted">${n.activity?h(n.activity.activityId):h(t("workflow.detail.notDispatched"))}</span>
|
|
1166
1183
|
</div>
|
|
1167
|
-
<div>${n.node?
|
|
1184
|
+
<div>${n.node?tt(n.node.status):""} ${n.activity?tt(n.activity.status):""}</div>
|
|
1168
1185
|
</header>
|
|
1169
1186
|
<div class="wf-io-meta">
|
|
1170
|
-
${
|
|
1187
|
+
${d?`${h(t("workflow.detail.attempt"))} <code>${h(d.attemptId)}</code>`:h(t("workflow.detail.noAttempt"))}
|
|
1171
1188
|
</div>
|
|
1172
|
-
${
|
|
1173
|
-
`;let
|
|
1174
|
-
${
|
|
1175
|
-
${
|
|
1176
|
-
${
|
|
1177
|
-
${
|
|
1178
|
-
${n.io?.waitPrompt?
|
|
1179
|
-
`}function
|
|
1180
|
-
<summary>${h(p)} ${
|
|
1189
|
+
${k}
|
|
1190
|
+
`;let I=Oa(d,n.activity,n.io?.terminal,a),T=I?.url??null;if(T!==e.currentTerminalUrl)I===null?e.terminalSlot.innerHTML="":e.terminalSlot.innerHTML=Ba(n.key,d,n.activity,n.io?.terminal,I,o,a),e.currentTerminalUrl=T;else if(I!==null&&n.io?.terminal){let R=e.terminalSlot.querySelector("details.wf-terminal-block > summary");if(R){let A=Na(I.kind);R.innerHTML=`${h(A)} ${ja(d,n.io.terminal)}`}d&&fr(e.terminalSlot,d,n.activity,n.io.terminal,I,a)}let g=d?.attemptId??n.activity?.activityId??n.node?.nodeId??"unknown";e.grid.innerHTML=`
|
|
1191
|
+
${Qe(g,t("workflow.detail.authoredInput"),n.io?.input,o)}
|
|
1192
|
+
${Qe(g,t("workflow.detail.resolvedInput"),n.io?.resolvedInput,o)}
|
|
1193
|
+
${Qe(g,t("workflow.detail.output"),n.io?.output,o)}
|
|
1194
|
+
${Qe(g,t("workflow.detail.executionLog"),n.io?.log,o)}
|
|
1195
|
+
${n.io?.waitPrompt?Qe(g,t("workflow.detail.waitPrompt"),n.io.waitPrompt,o):""}
|
|
1196
|
+
`}function Oa(e,n,o,s){if(!o||o.error)return null;if(rr(e,o))return{kind:"live",url:dr(o)};if(!e||!n||!lr(e,o))return null;let a=ur();if(!a)return null;let r=s?.sessions.get(e.attemptId);return r?{kind:"resume",url:r.url,resumeId:r.resumeId,downloadUrl:Aa(a,n.activityId,e.attemptId)}:{kind:"replay",url:cr(a,n.activityId,e.attemptId,!!o.hasPtyLog),downloadUrl:Aa(a,n.activityId,e.attemptId)}}function Ba(e,n,o,s,a,r,d){if(!s)return"";let p=Na(a.kind),v=oo(e,p),k=ja(n,s),I=nr(a.kind),T=a.kind==="replay"||a.kind==="resume"?`<a class="btn-link" href="${h(a.downloadUrl)}" download>${h(t("workflow.detail.downloadFullLog"))}</a>`:"",g=n?qa(n,o,s,a,d):"",R=n?Ua(n.attemptId,d):"";return`<details class="wf-io-block wf-terminal-block" data-io-key="${h(v)}"${r.has(v)?" open":""}>
|
|
1197
|
+
<summary>${h(p)} ${k}</summary>
|
|
1181
1198
|
<div class="wf-terminal-actions">
|
|
1182
|
-
<a class="btn-link" href="${h(a.url)}" target="_blank" rel="noreferrer">${h(
|
|
1183
|
-
${
|
|
1199
|
+
<a class="btn-link" href="${h(a.url)}" target="_blank" rel="noreferrer">${h(I)}</a>
|
|
1200
|
+
${T}
|
|
1184
1201
|
${g}
|
|
1185
1202
|
</div>
|
|
1186
|
-
${
|
|
1203
|
+
${R}
|
|
1187
1204
|
<iframe class="wf-terminal-frame" src="${h(a.url)}" title="${h(p)}" loading="lazy"></iframe>
|
|
1188
|
-
</details>`}function
|
|
1205
|
+
</details>`}function Na(e){return e==="live"?t("workflow.detail.liveTerminal"):e==="resume"?t("workflow.detail.terminalResume"):t("workflow.detail.terminalReplay")}function nr(e){return e==="live"?t("workflow.detail.openTerminalNewTab"):e==="resume"?t("workflow.detail.openResumeNewTab"):t("workflow.detail.openReplayNewTab")}var Pa=new Set(["antigravity","codex-app","cursor","mira"]),or=new Set(["aiden","coco","claude-code","seed","relay","codex","mtr","hermes","pi"]);function ar(e){return!!e&&(or.has(e)||Pa.has(e))}function sr(e){return!!e&&Pa.has(e)}function qa(e,n,o,s,a){if(!a||s.kind==="live"||!n)return"";let r=s.kind==="resume",d=a.pending.has(e.attemptId),p=`data-wf-resume-attempt="${h(e.attemptId)}" data-wf-resume-activity="${h(n.activityId)}"`;return r?`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="end" ${p}${d?" disabled":""}>${h(d?t("workflow.detail.resumeEnding"):t("workflow.detail.endResumeSession"))}</button>`:ar(o.cliId)?sr(o.cliId)&&!o.cliSessionId?`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${h(t("workflow.detail.resumeMissingCliSession"))}">${h(t("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="start" ${p}${d?" disabled":""}>${h(d?t("workflow.detail.resumeStarting"):t("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${h(t("workflow.detail.resumeUnsupportedCli",{cliId:o.cliId??"?"}))}">${h(t("workflow.detail.resumeSession"))}</button>`}function Ua(e,n){if(!n)return"";let o=n.errors.get(e);return o?`<div class="hint-warn wf-resume-status" data-wf-resume-status="${h(e)}">${h(o)}</div>`:""}function ir(e,n,o,s,a){let r=gn(e.activity),d=e.node?.nodeId??e.activity?.ownerNodeId??e.activity?.activityId??"unknown",p=r?.attemptId??e.activity?.activityId??e.node?.nodeId??"unknown",v=Fa(r,o),k=r?.attemptId===a?" is-focused":"",I=r?` data-wf-attempt-card="${h(r.attemptId)}"`:"",T=Oa(r,e.activity,e.io?.terminal,s),g=T?Ba(p,r,e.activity,e.io?.terminal,T,n,s):"";return`<article class="wf-io-card${k}" data-wf-card-key="${h(e.key)}"${I}>
|
|
1189
1206
|
<div class="wf-io-card-head">
|
|
1190
1207
|
<header>
|
|
1191
1208
|
<div>
|
|
1192
|
-
<strong><code>${h(
|
|
1209
|
+
<strong><code>${h(d)}</code></strong>
|
|
1193
1210
|
<span class="muted">${e.activity?h(e.activity.activityId):h(t("workflow.detail.notDispatched"))}</span>
|
|
1194
1211
|
</div>
|
|
1195
|
-
<div>${e.node?
|
|
1212
|
+
<div>${e.node?tt(e.node.status):""} ${e.activity?tt(e.activity.status):""}</div>
|
|
1196
1213
|
</header>
|
|
1197
1214
|
<div class="wf-io-meta">
|
|
1198
1215
|
${r?`${h(t("workflow.detail.attempt"))} <code>${h(r.attemptId)}</code>`:h(t("workflow.detail.noAttempt"))}
|
|
1199
1216
|
</div>
|
|
1200
|
-
${
|
|
1217
|
+
${v}
|
|
1201
1218
|
</div>
|
|
1202
1219
|
<div class="wf-io-terminal-slot">${g}</div>
|
|
1203
1220
|
<div class="wf-io-grid">
|
|
1204
|
-
${
|
|
1205
|
-
${
|
|
1206
|
-
${
|
|
1207
|
-
${
|
|
1208
|
-
${e.io?.waitPrompt?
|
|
1221
|
+
${Qe(p,t("workflow.detail.authoredInput"),e.io?.input,n)}
|
|
1222
|
+
${Qe(p,t("workflow.detail.resolvedInput"),e.io?.resolvedInput,n)}
|
|
1223
|
+
${Qe(p,t("workflow.detail.output"),e.io?.output,n)}
|
|
1224
|
+
${Qe(p,t("workflow.detail.executionLog"),e.io?.log,n)}
|
|
1225
|
+
${e.io?.waitPrompt?Qe(p,t("workflow.detail.waitPrompt"),e.io.waitPrompt,n):""}
|
|
1209
1226
|
</div>
|
|
1210
|
-
</article>`}function
|
|
1227
|
+
</article>`}function gn(e){return e?.attempts[e.attempts.length-1]}function ja(e,n){let o=[];return n.error?o.push(t("workflow.detail.error")):o.push(n.status==="live"?t("workflow.detail.terminalLive"):t("workflow.detail.terminalClosedShort")),e?.status&&o.push(e.status),n.webPort>0&&o.push(`:${n.webPort}`),`<span class="muted">${h(o.join(" \xB7 "))}</span>`}function rr(e,n){return n.status==="live"&&n.webPort>0&&(e?.status==="pending"||e?.status==="running"||e?.status==="effectAttempting")}function lr(e,n){return e.status==="succeeded"||e.status==="failed"||e.status==="cancelled"||e.status==="timedOut"?!!(n.sessionId||n.startedAt):!1}function dr(e){return`http://${window.location.hostname||"127.0.0.1"}:${e.webPort}`}function cr(e,n,o,s){let a=new URLSearchParams({runId:e,activityId:n,attemptId:o});return s&&a.set("hasPtyLog","1"),`/assets/terminal-replay.html?${a.toString()}`}function Aa(e,n,o){return`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(n)}/${encodeURIComponent(o)}/terminal-log/raw?download=1`}function ur(){let e=window.location.hash.match(/^#\/workflows\/([^/?#]+)/);if(!e)return null;try{return decodeURIComponent(e[1])}catch{return null}}function Fa(e,n){if(!pr(e))return"";let o=e.attemptId,s=n.comments.get(o)??"",a=n.resolving.has(o),r=n.statuses.get(o),d=r?.kind==="error"?"hint-warn":"hint-ok";return`<div class="wf-approval-box" data-wf-approval="${h(o)}">
|
|
1211
1228
|
<label>
|
|
1212
1229
|
<span>${h(t("workflow.detail.approvalComment"))}</span>
|
|
1213
1230
|
<textarea class="wf-approval-comment" data-wf-approval-comment="${h(o)}" rows="2" placeholder="${h(t("workflow.detail.optionalComment"))}"${a?" disabled":""}>${h(s)}</textarea>
|
|
@@ -1217,149 +1234,149 @@ ${ha("manage")}
|
|
|
1217
1234
|
<button type="button" data-wf-approval-action="reject" data-wf-attempt-id="${h(o)}"${a?" disabled":""}>${h(t("workflow.detail.reject"))}</button>
|
|
1218
1235
|
${a?`<span class="muted">${h(t("workflow.detail.submitting"))}</span>`:""}
|
|
1219
1236
|
</div>
|
|
1220
|
-
${r?`<div class="${
|
|
1221
|
-
</div>`}function
|
|
1222
|
-
<summary>${h(n)} ${
|
|
1223
|
-
${
|
|
1224
|
-
</details>`}function
|
|
1225
|
-
<td>${
|
|
1237
|
+
${r?`<div class="${d} wf-approval-status">${h(r.text)}</div>`:""}
|
|
1238
|
+
</div>`}function pr(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function mr(e,n){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(o=>{let s=o.dataset.wfApprovalComment;s&&n.set(s,o.value)})}function Ga(e,n){e.querySelectorAll("button[data-wf-resume-action][data-wf-resume-attempt][data-wf-resume-activity]").forEach(o=>{o.dataset.wfResumeBound!=="1"&&(o.dataset.wfResumeBound="1",o.addEventListener("click",()=>{let s=o.dataset.wfResumeAttempt,a=o.dataset.wfResumeActivity,r=o.dataset.wfResumeAction;!s||!a||(r==="start"?n.onStart(s,a):r==="end"&&n.onEnd(s,a))}))})}function fr(e,n,o,s,a,r){let d=e.querySelector(".wf-terminal-actions");if(!d)return;let p=d.querySelector('button[data-wf-resume-button="1"]'),v=qa(n,o,s,a,r);p?p.outerHTML=v:v&&d.insertAdjacentHTML("beforeend",v);let k=e.querySelector("details.wf-terminal-block");if(k){let I=k.querySelector(".wf-resume-status"),T=Ua(n.attemptId,r);I?I.outerHTML=T:T&&d.insertAdjacentHTML("afterend",T)}Ga(e,r)}function gr(e,n){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(o=>{let s=o.dataset.wfApprovalComment;s&&o.addEventListener("input",()=>{n.comments.set(s,o.value)})}),e.querySelectorAll("button[data-wf-approval-action][data-wf-attempt-id]").forEach(o=>{o.addEventListener("click",()=>{let s=o.dataset.wfAttemptId,a=o.dataset.wfApprovalAction;!s||a!=="approve"&&a!=="reject"||n.onResolve(s,a)})})}function Qe(e,n,o,s){let a=oo(e,n);return`<details class="wf-io-block" data-io-key="${h(a)}"${s.has(a)?" open":""}>
|
|
1239
|
+
<summary>${h(n)} ${kr(o)}</summary>
|
|
1240
|
+
${$r(o)}
|
|
1241
|
+
</details>`}function oo(e,n){return`${e}:${n}`}function br(e,n){if(!n)return!1;for(let o of e.querySelectorAll("[data-wf-attempt-card]"))if(o.dataset.wfAttemptCard===n)return o.scrollIntoView({block:"center"}),!0;return!1}function hr(e,n,o){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(s=>{let a=s.dataset.ioKey;if(!a)return;s.open?n.add(a):n.delete(a);let r=s.querySelector(".wf-io-pre");r&&o.set(a,r.scrollTop)})}function wr(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(o=>{o.dataset.ioToggleBound!=="1"&&(o.dataset.ioToggleBound="1",o.addEventListener("toggle",()=>{let s=o.dataset.ioKey;s&&(o.open?n.add(s):n.delete(s))}))})}function yr(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(o=>{let s=o.dataset.ioKey;if(!s)return;let a=n.get(s);if(a===void 0)return;let r=o.querySelector(".wf-io-pre");r&&(r.scrollTop=a)})}function vr(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(o=>{let s=o.dataset.ioKey;if(!s)return;let a=o.querySelector(".wf-io-pre");a&&a.dataset.ioScrollBound!=="1"&&(a.dataset.ioScrollBound="1",a.addEventListener("scroll",()=>{n.set(s,a.scrollTop)}))})}function kr(e){if(!e)return`<span class="muted">${h(t("workflow.detail.empty"))}</span>`;let n=[];return e.outputBytes!==void 0&&n.push(`${e.outputBytes}B`),e.truncated&&n.push(t("workflow.detail.truncated")),e.error&&n.push(t("workflow.detail.error")),e.outputHash&&n.push(hn(e.outputHash)),n.length?`<span class="muted">${h(n.join(" \xB7 "))}</span>`:""}function $r(e){if(!e)return`<div class="muted wf-io-empty">${h(t("workflow.detail.noData"))}</div>`;let n=e.value!==void 0?JSON.stringify(e.value,null,2):e.text??"",o=e.error?`<div class="muted error">${h(e.error)}</div>`:"";return n?`${o}<pre class="wf-io-pre">${h(n)}</pre>`:`${o}<div class="muted wf-io-empty">${h(t("workflow.detail.noPreview"))}</div>`}function Sr(e){let n=[];if(e.effectAttempted&&n.push(`${h(t("workflow.detail.effect"))} ${h(e.effectAttempted.provider)}`),e.wait){let o=e.wait.resolution?`${e.wait.resolution.kind}${e.wait.resolution.resolution?":"+e.wait.resolution.resolution:""}`:t("workflow.detail.open");n.push(`${h(t("workflow.detail.wait"))} ${h(e.wait.waitKind)} ${h(o)}`),e.wait.deadlineAt!==void 0&&n.push(`${h(t("workflow.detail.deadline"))} ${h(bn(e.wait.deadlineAt))}`)}if(e.error){let o=`${e.error.errorCode}${e.error.errorClass?` \xB7 ${e.error.errorClass}`:""}`;n.push(`<span class="muted error">${h(o)}</span>`),e.error.errorMessage&&n.push(`<span class="error wf-error-msg">${h(e.error.errorMessage)}</span>`)}return e.output&&n.push(`${h(t("workflow.detail.output"))} ${h(hn(e.output.outputHash))}`),e.runningMs!==void 0&&n.push(`${e.runningMs}ms`),n.length>0?n.join("<br/>"):'<span class="muted">-</span>'}function Tr(e,n){e.innerHTML=n.length>0?n.map(Lr).join(""):`<tr><td colspan="7" class="empty">${h(t("workflow.detail.noEvents"))}</td></tr>`}function Lr(e){let n=Ir(e.payload);return`<tr>
|
|
1242
|
+
<td>${Gt(e.eventId)}</td>
|
|
1226
1243
|
<td><code>${h(e.type)}</code></td>
|
|
1227
1244
|
<td>${h(e.actor)}</td>
|
|
1228
1245
|
<td>${n.nodeId?`<code>${h(n.nodeId)}</code>`:"-"}</td>
|
|
1229
1246
|
<td>${n.activityId?`<code>${h(n.activityId)}</code>`:"-"}</td>
|
|
1230
1247
|
<td>${n.errorCode?`<span class="muted error">${h(n.errorCode)}</span>`:"-"}</td>
|
|
1231
|
-
<td title="${h(new Date(e.timestamp).toISOString())}">${h(
|
|
1232
|
-
</tr>`}function
|
|
1248
|
+
<td title="${h(new Date(e.timestamp).toISOString())}">${h(bn(e.timestamp))}</td>
|
|
1249
|
+
</tr>`}function Gt(e){let n=e.lastIndexOf("-");if(n<0)return 0;let o=Number(e.slice(n+1));return Number.isFinite(o)?o:0}function Ir(e){if(!e||typeof e!="object"||"ref"in e)return{};let n=e,o={};typeof n.nodeId=="string"&&(o.nodeId=n.nodeId),typeof n.activityId=="string"&&(o.activityId=n.activityId),typeof n.failedNodeId=="string"&&(o.nodeId=n.failedNodeId);let s=n.error;return s&&typeof s=="object"&&"errorCode"in s&&(o.errorCode=String(s.errorCode)),o}function Mr(e){return!e.payload||typeof e.payload!="object"||"ref"in e.payload?null:e.payload}function Da(e,n,o){return Math.min(o,Math.max(n,e))}function hn(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function xr(e,n){return e.length>n?e.slice(0,n-1)+"\u2026":e}function bn(e){return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}function U(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function _a(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function za(e){let n=location.hash.match(/^#\/(?:workflows\/catalog|workflows-catalog)\/([^/?#]+)$/);return n?Hr(e,decodeURIComponent(n[1])):Er(e)}function Er(e){e.innerHTML=`
|
|
1233
1250
|
<nav class="wf-subnav">
|
|
1234
|
-
<a href="#/workflows" data-i18n="workflow.subnav.runs">${
|
|
1235
|
-
<a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${
|
|
1251
|
+
<a href="#/workflows" data-i18n="workflow.subnav.runs">${U(t("workflow.subnav.runs"))}</a>
|
|
1252
|
+
<a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${U(t("workflow.subnav.catalog"))}</a>
|
|
1236
1253
|
</nav>
|
|
1237
1254
|
<section class="catalog-head">
|
|
1238
1255
|
<div>
|
|
1239
|
-
<h2>${
|
|
1240
|
-
<p class="muted">${
|
|
1256
|
+
<h2>${U(t("catalog.title"))}</h2>
|
|
1257
|
+
<p class="muted">${U(t("catalog.subtitle"))}</p>
|
|
1241
1258
|
</div>
|
|
1242
|
-
<button id="catalog-refresh" type="button">${
|
|
1259
|
+
<button id="catalog-refresh" type="button">${U(t("catalog.refresh"))}</button>
|
|
1243
1260
|
</section>
|
|
1244
1261
|
<form id="catalog-filters" class="filters">
|
|
1245
|
-
<input type="search" name="q" placeholder="${
|
|
1262
|
+
<input type="search" name="q" placeholder="${U(t("catalog.searchPlaceholder"))}" />
|
|
1246
1263
|
<span id="catalog-status" class="muted"></span>
|
|
1247
1264
|
</form>
|
|
1248
1265
|
<div class="wf-table-scroll">
|
|
1249
1266
|
<table>
|
|
1250
1267
|
<thead><tr>
|
|
1251
|
-
<th>${
|
|
1252
|
-
<th>${
|
|
1253
|
-
<th>${
|
|
1254
|
-
<th>${
|
|
1255
|
-
<th>${
|
|
1256
|
-
<th>${
|
|
1268
|
+
<th>${U(t("catalog.table.workflow"))}</th>
|
|
1269
|
+
<th>${U(t("catalog.table.version"))}</th>
|
|
1270
|
+
<th>${U(t("catalog.table.params"))}</th>
|
|
1271
|
+
<th>${U(t("catalog.table.nodes"))}</th>
|
|
1272
|
+
<th>${U(t("catalog.table.revision"))}</th>
|
|
1273
|
+
<th>${U(t("catalog.table.path"))}</th>
|
|
1257
1274
|
</tr></thead>
|
|
1258
1275
|
<tbody id="catalog-tbody"></tbody>
|
|
1259
1276
|
</table>
|
|
1260
1277
|
</div>
|
|
1261
|
-
`;let n=e.querySelector("#catalog-tbody"),o=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),a=e.querySelector("#catalog-refresh"),r=[],
|
|
1278
|
+
`;let n=e.querySelector("#catalog-tbody"),o=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),a=e.querySelector("#catalog-refresh"),r=[],d=null,p=!1;function v(){let T=(new FormData(s).get("q")??"").trim().toLowerCase();return T?r.filter(g=>g.workflowId.toLowerCase().includes(T)||g.path.toLowerCase().includes(T)):r}function k(){d?(o.textContent=t("catalog.loadFailed",{error:d}),o.classList.add("error")):(o.textContent=`${r.length}`,o.classList.remove("error"));let T=v();if(T.length===0){n.innerHTML=`<tr><td colspan="6" class="empty">${r.length===0?U(t("catalog.noDefinitions")):U(t("catalog.noFilterMatch"))}</td></tr>`;return}n.innerHTML=T.map(g=>`
|
|
1262
1279
|
<tr>
|
|
1263
|
-
<td><a href="#/workflows/catalog/${encodeURIComponent(g.workflowId)}"><code>${
|
|
1280
|
+
<td><a href="#/workflows/catalog/${encodeURIComponent(g.workflowId)}"><code>${U(g.workflowId)}</code></a></td>
|
|
1264
1281
|
<td>${g.version}</td>
|
|
1265
|
-
<td>${
|
|
1282
|
+
<td>${U(t("catalog.paramSummary",{required:g.requiredParamCount,total:g.paramCount}))}</td>
|
|
1266
1283
|
<td>${g.nodeCount}</td>
|
|
1267
|
-
<td><code>${
|
|
1268
|
-
<td><code>${
|
|
1284
|
+
<td><code>${U(_a(g.revisionId))}</code></td>
|
|
1285
|
+
<td><code>${U(g.path)}</code></td>
|
|
1269
1286
|
</tr>
|
|
1270
|
-
`).join("")}async function
|
|
1287
|
+
`).join("")}async function I(){a.disabled=!0,o.textContent=t("catalog.loading");try{let T=await fetch("/api/workflows/definitions");if(!T.ok)throw new Error(`HTTP ${T.status}`);r=(await T.json()).definitions??[],d=null}catch(T){d=T?.message??String(T),r=[]}finally{a.disabled=!1,p||k()}}return s.addEventListener("input",k),a.addEventListener("click",()=>{I()}),I(),()=>{p=!0}}function Hr(e,n){e.innerHTML=`
|
|
1271
1288
|
<div class="catalog-detail-head">
|
|
1272
|
-
<a class="btn-link" href="#/workflows/catalog">${
|
|
1289
|
+
<a class="btn-link" href="#/workflows/catalog">${U(t("catalog.back"))}</a>
|
|
1273
1290
|
<div>
|
|
1274
|
-
<h2><code>${
|
|
1275
|
-
<div id="catalog-detail-subtitle" class="muted">${
|
|
1291
|
+
<h2><code>${U(n)}</code></h2>
|
|
1292
|
+
<div id="catalog-detail-subtitle" class="muted">${U(t("workflow.detail.loading"))}</div>
|
|
1276
1293
|
</div>
|
|
1277
1294
|
</div>
|
|
1278
1295
|
<section id="catalog-error" class="hint-warn" hidden></section>
|
|
1279
1296
|
<section id="catalog-run-status" class="hint-ok" hidden></section>
|
|
1280
1297
|
<div id="catalog-detail-body"></div>
|
|
1281
|
-
`;let o=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),a=e.querySelector("#catalog-run-status"),r=e.querySelector("#catalog-detail-body"),
|
|
1298
|
+
`;let o=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),a=e.querySelector("#catalog-run-status"),r=e.querySelector("#catalog-detail-body"),d=null,p=!1,v=!1;function k(M){s.hidden=!M,s.textContent=M??""}function I(M){a.hidden=!M,a.textContent=M??""}function T(M){let E={};for(let[$,D]of Object.entries(M??{}))"default"in D&&(E[$]=D.default);return E}function g(){if(!d)return;let M=d.definition;o.textContent=`${t("catalog.revision")} ${_a(d.revisionId)} \xB7 ${d.path}`;let E=JSON.stringify(T(M.params),null,2);r.innerHTML=`
|
|
1282
1299
|
<section class="wf-panel">
|
|
1283
|
-
<div class="wf-panel-title"><h3>${
|
|
1300
|
+
<div class="wf-panel-title"><h3>${U(t("catalog.summary"))}</h3></div>
|
|
1284
1301
|
<div class="wf-summary-grid">
|
|
1285
|
-
<div class="wf-summary-item"><span>${
|
|
1286
|
-
<div class="wf-summary-item"><span>${
|
|
1287
|
-
<div class="wf-summary-item"><span>${
|
|
1288
|
-
<div class="wf-summary-item"><span>${
|
|
1302
|
+
<div class="wf-summary-item"><span>${U(t("catalog.table.workflow"))}</span><strong><code>${U(M.workflowId)}</code></strong></div>
|
|
1303
|
+
<div class="wf-summary-item"><span>${U(t("catalog.table.version"))}</span><strong>${M.version}</strong></div>
|
|
1304
|
+
<div class="wf-summary-item"><span>${U(t("catalog.nodeCount"))}</span><strong>${Object.keys(M.nodes).length}</strong></div>
|
|
1305
|
+
<div class="wf-summary-item"><span>${U(t("catalog.path"))}</span><strong><code>${U(d.path)}</code></strong></div>
|
|
1289
1306
|
</div>
|
|
1290
1307
|
</section>
|
|
1291
1308
|
|
|
1292
1309
|
<section class="wf-panel">
|
|
1293
|
-
<div class="wf-panel-title"><h3>${
|
|
1310
|
+
<div class="wf-panel-title"><h3>${U(t("catalog.runPanel"))}</h3></div>
|
|
1294
1311
|
<form id="catalog-run-form" class="catalog-run-form">
|
|
1295
1312
|
<label>
|
|
1296
|
-
<span>${
|
|
1297
|
-
<textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${
|
|
1313
|
+
<span>${U(t("catalog.paramsJson"))}</span>
|
|
1314
|
+
<textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${U(t("catalog.paramsPlaceholder"))}">${U(E)}</textarea>
|
|
1298
1315
|
</label>
|
|
1299
1316
|
<div class="catalog-chat-grid">
|
|
1300
1317
|
<label>
|
|
1301
|
-
<span>${
|
|
1318
|
+
<span>${U(t("catalog.chatId"))}</span>
|
|
1302
1319
|
<input id="catalog-chat-id" type="text" autocomplete="off" />
|
|
1303
1320
|
</label>
|
|
1304
1321
|
<label>
|
|
1305
|
-
<span>${
|
|
1322
|
+
<span>${U(t("catalog.larkAppId"))}</span>
|
|
1306
1323
|
<input id="catalog-lark-app-id" type="text" autocomplete="off" />
|
|
1307
1324
|
</label>
|
|
1308
1325
|
</div>
|
|
1309
|
-
<div class="muted">${
|
|
1326
|
+
<div class="muted">${U(t("catalog.chatBindingHint"))}</div>
|
|
1310
1327
|
<div id="catalog-param-errors" class="catalog-param-errors" hidden></div>
|
|
1311
|
-
<button id="catalog-run-btn" type="submit" class="primary">${
|
|
1328
|
+
<button id="catalog-run-btn" type="submit" class="primary">${U(t("catalog.run"))}</button>
|
|
1312
1329
|
</form>
|
|
1313
1330
|
</section>
|
|
1314
1331
|
|
|
1315
1332
|
<section class="wf-panel">
|
|
1316
|
-
<div class="wf-panel-title"><h3>${
|
|
1317
|
-
${
|
|
1333
|
+
<div class="wf-panel-title"><h3>${U(t("catalog.paramsSchema"))}</h3></div>
|
|
1334
|
+
${Cr(M.params)}
|
|
1318
1335
|
</section>
|
|
1319
1336
|
|
|
1320
1337
|
<section class="wf-panel">
|
|
1321
|
-
<div class="wf-panel-title"><h3>${
|
|
1322
|
-
<pre class="wf-io-pre">${
|
|
1338
|
+
<div class="wf-panel-title"><h3>${U(t("catalog.definitionJson"))}</h3></div>
|
|
1339
|
+
<pre class="wf-io-pre">${U(JSON.stringify(M,null,2))}</pre>
|
|
1323
1340
|
</section>
|
|
1324
|
-
`,
|
|
1341
|
+
`,A()}async function R(){if(!d||v)return;let M=r.querySelector("#catalog-params"),E=r.querySelector("#catalog-chat-id"),$=r.querySelector("#catalog-lark-app-id"),D=r.querySelector("#catalog-run-btn"),m=r.querySelector("#catalog-param-errors"),y;try{if(y=JSON.parse(M.value||"{}"),!y||typeof y!="object"||Array.isArray(y))throw new Error(t("catalog.badParamsJson"))}catch(S){m.hidden=!1,m.innerHTML=`<div class="muted error">${U(S?.message??String(S))}</div>`;return}v=!0,D.disabled=!0,D.textContent=t("catalog.running"),m.hidden=!0,k(null),I(null);try{let S=await fetch(`/api/workflows/definitions/${encodeURIComponent(d.definition.workflowId)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({params:y,chatBinding:{chatId:E.value.trim(),larkAppId:$.value.trim()}})});if(S.status===401)throw new Error(t("catalog.writeAccess"));let H=await S.json().catch(()=>({}));if(!S.ok||!H.ok)throw H.issues?.length&&(m.hidden=!1,m.innerHTML=`<strong>${U(t("catalog.invalidParams"))}</strong><ul>${H.issues.map(B=>`<li>${U(t("catalog.issue",{path:B.path.length?B.path.join("."):"(root)",message:B.message}))}</li>`).join("")}</ul>`),new Error(H.hint??H.message??H.error??t("catalog.runHttp",{status:S.status}));I(t("catalog.runStarted")),H.runId&&(location.hash=`#/workflows/${encodeURIComponent(H.runId)}`)}catch(S){k(S?.message??String(S))}finally{v=!1,D.disabled=!1,D.textContent=t("catalog.run")}}function A(){r.querySelector("#catalog-run-form")?.addEventListener("submit",E=>{E.preventDefault(),R()})}async function O(){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}`);d=await M.json(),k(null),g()}catch(M){k(t("catalog.definitionLoadFailed",{error:M?.message??String(M)})),o.textContent=t("workflow.detail.loadFailed")}}return O().then(()=>{}),()=>{p=!0}}function Cr(e){let n=Object.entries(e??{});return n.length===0?`<div class="muted">${U(t("catalog.noParams"))}</div>`:`<div class="catalog-param-list">${n.map(([o,s])=>`
|
|
1325
1342
|
<article class="catalog-param">
|
|
1326
1343
|
<header>
|
|
1327
|
-
<code>${
|
|
1328
|
-
<span class="wf-status">${
|
|
1329
|
-
<span class="muted">${
|
|
1344
|
+
<code>${U(o)}</code>
|
|
1345
|
+
<span class="wf-status">${U(s.required?t("catalog.required"):t("catalog.optional"))}</span>
|
|
1346
|
+
<span class="muted">${U(s.type)}${s.format?` \xB7 ${U(s.format)}`:""}</span>
|
|
1330
1347
|
</header>
|
|
1331
|
-
${s.description?`<div class="muted">${
|
|
1332
|
-
${"default"in s?`<pre class="wf-io-pre">${
|
|
1348
|
+
${s.description?`<div class="muted">${U(t("catalog.description"))}: ${U(s.description)}</div>`:""}
|
|
1349
|
+
${"default"in s?`<pre class="wf-io-pre">${U(`${t("catalog.default")}: ${JSON.stringify(s.default,null,2)}`)}</pre>`:""}
|
|
1333
1350
|
</article>
|
|
1334
|
-
`).join("")}</div>`}var
|
|
1351
|
+
`).join("")}</div>`}var wn=78222186;function Wa(e){let n={maxWidth:e.style.maxWidth,padding:e.style.padding,flex:e.style.flex,minHeight:e.style.minHeight,display:e.style.display};e.style.maxWidth="none",e.style.padding="0",e.style.flex="1 1 auto",e.style.minHeight="0",e.style.display="flex";let o=!1,s,a="",r=g=>(g/1048576).toFixed(0);function d(){s&&(clearTimeout(s),s=void 0)}function p(){d(),e.innerHTML=`
|
|
1335
1352
|
<iframe
|
|
1336
1353
|
src="/game/index.html"
|
|
1337
1354
|
title="HD2D Office"
|
|
1338
1355
|
style="flex:1;width:100%;min-height:0;border:none;display:block;background:#0b0d12;"
|
|
1339
1356
|
allow="autoplay"
|
|
1340
|
-
></iframe>`}function
|
|
1357
|
+
></iframe>`}function v(g){let R=g.total||wn,A=R?Math.min(100,Math.round(g.received/R*100)):0,O=g.state==="downloading",M=g.state==="error";e.innerHTML=`
|
|
1341
1358
|
<div style="margin:auto;text-align:center;max-width:440px;padding:32px;color:var(--fg,#e6e6e6);">
|
|
1342
1359
|
<div style="font-size:18px;font-weight:600;margin-bottom:8px;">HD2D \u529E\u516C\u5BA4</div>
|
|
1343
1360
|
<div style="font-size:13px;opacity:.7;line-height:1.7;margin-bottom:20px;">
|
|
1344
1361
|
\u628A\u6BCF\u4E2A\u4F1A\u8BDD\u53D8\u6210\u529E\u516C\u5BA4\u91CC\u7684\u4E00\u4E2A\u673A\u5668\u4EBA\uFF0C\u5B9E\u65F6\u6620\u5C04\u5C4F\u5E55\u72B6\u6001\u3002<br>
|
|
1345
|
-
\u9996\u6B21\u8FDB\u5165\u9700\u4E0B\u8F7D\u7EA6 ${r(
|
|
1362
|
+
\u9996\u6B21\u8FDB\u5165\u9700\u4E0B\u8F7D\u7EA6 ${r(R)} MB \u6E38\u620F\u8D44\u6E90\uFF08\u4EC5\u4E00\u6B21\uFF0C\u4E4B\u540E\u672C\u5730\u7F13\u5B58\uFF09\u3002
|
|
1346
1363
|
</div>
|
|
1347
|
-
${
|
|
1348
|
-
${
|
|
1364
|
+
${M?`<div style="color:#e06c75;font-size:12px;margin-bottom:14px;">\u4E0A\u6B21\u4E0B\u8F7D\u5931\u8D25\uFF1A${i(g.error??"\u672A\u77E5\u9519\u8BEF")}<br><span style="opacity:.7;">\u586B\u4EE3\u7406\u540E\u70B9\u91CD\u8BD5</span></div>`:""}
|
|
1365
|
+
${O?`
|
|
1349
1366
|
<div style="background:rgba(127,127,127,.2);border-radius:6px;height:10px;overflow:hidden;margin-bottom:10px;">
|
|
1350
|
-
<div style="height:100%;width:${
|
|
1367
|
+
<div style="height:100%;width:${A}%;background:#4a9eff;transition:width .3s;"></div>
|
|
1351
1368
|
</div>
|
|
1352
|
-
<div style="font-size:12px;opacity:.7;">\u4E0B\u8F7D\u4E2D\u2026 ${r(g.received)} / ${r(
|
|
1369
|
+
<div style="font-size:12px;opacity:.7;">\u4E0B\u8F7D\u4E2D\u2026 ${r(g.received)} / ${r(R)} MB\uFF08${A}%\uFF09</div>
|
|
1353
1370
|
`:`
|
|
1354
1371
|
<input id="hd2d-proxy" type="text" value="${i(a)}"
|
|
1355
1372
|
placeholder="HTTP \u4EE3\u7406\uFF08\u53EF\u9009\uFF0C\u5982 http://127.0.0.1:7890\uFF09"
|
|
1356
1373
|
style="width:100%;box-sizing:border-box;margin-bottom:12px;padding:8px 10px;border-radius:6px;border:1px solid rgba(127,127,127,.4);background:transparent;color:inherit;font-size:12px;" />
|
|
1357
1374
|
<div style="font-size:11px;opacity:.5;margin-bottom:14px;text-align:left;">\u8FDE\u4E0D\u4E0A GitHub \u65F6\u586B\u4EE3\u7406\uFF08\u4EC5\u7528\u4E8E\u4E0B\u8F7D\u672C\u8D44\u6E90\uFF0C\u4F1A\u8BB0\u4F4F\uFF09\u3002\u7559\u7A7A\u8D70\u76F4\u8FDE/\u7CFB\u7EDF\u4EE3\u7406\u73AF\u5883\u53D8\u91CF\u3002</div>
|
|
1358
1375
|
<button id="hd2d-load" style="cursor:pointer;border:none;border-radius:8px;padding:10px 22px;font-size:14px;font-weight:600;background:#4a9eff;color:#fff;">
|
|
1359
|
-
${
|
|
1376
|
+
${M?"\u91CD\u8BD5":"\u52A0\u8F7D\u529E\u516C\u5BA4"}\uFF08\u7EA6 ${r(R)} MB\uFF09
|
|
1360
1377
|
</button>
|
|
1361
1378
|
`}
|
|
1362
|
-
</div>`;let
|
|
1379
|
+
</div>`;let E=e.querySelector("#hd2d-load");E&&(E.onclick=()=>{a=e.querySelector("#hd2d-proxy")?.value.trim()??"",I()})}function k(g){if(!o){if(typeof g.proxy=="string"&&(a=g.proxy),g.state==="ready"){p();return}v(g),g.state==="downloading"&&(s=setTimeout(()=>{T()},700))}}async function I(){v({state:"downloading",received:0,total:wn});try{let g=await fetch("/api/game/download",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({proxy:a})});if(!g.ok)throw new Error(`HTTP ${g.status}`);k(await g.json())}catch(g){v({state:"error",received:0,total:wn,error:g instanceof Error?g.message:String(g)})}}async function T(){if(!o)try{let g=await fetch("/api/game/status");if(!g.ok){v({state:"absent",received:0,total:wn});return}k(await g.json())}catch{o||(s=setTimeout(()=>{T()},1500))}}return T(),()=>{o=!0,d(),e.innerHTML="",e.style.maxWidth=n.maxWidth,e.style.padding=n.padding,e.style.flex=n.flex,e.style.minHeight=n.minHeight,e.style.display=n.display}}var dt=null,yn=null,vn="glm-5.1",Ja=[];function zt(){yn!==null&&(window.clearInterval(yn),yn=null)}function so(){return dt||(dt=document.createElement("dialog"),dt.className="onboarding-dialog",document.body.appendChild(dt),dt.addEventListener("close",zt),dt)}function Ar(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 Dr(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 a=`<p class="hint-ok">\u2705 ${s.join(" ")}</p>`;return n.scopeWarning&&(a+=`<p class="hint-warn">\u26A0\uFE0F ${i(n.scopeWarning)}</p>`),a}let o=(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>`+(o?`<ol class="onboarding-steps">${o}</ol>`:"")}function _t(e){let n=so(),o=e.status==="waiting_for_scan"&&e.qrDataUrl?`<div class="qr-card">
|
|
1363
1380
|
<img class="qr-image" src="${e.qrDataUrl}" alt="${t("botOnboarding.qrAlt")}">
|
|
1364
1381
|
${e.qrUrl?`<a class="onboarding-link" href="${i(e.qrUrl)}" target="_blank" rel="noopener">${t("botOnboarding.openLink")}</a>`:""}
|
|
1365
1382
|
</div>`:"",s=e.status==="waiting_for_platform_scan"&&e.platformQrDataUrl?`<div class="qr-card">
|
|
@@ -1369,14 +1386,14 @@ ${ha("manage")}
|
|
|
1369
1386
|
<h3>${t("botOnboarding.title")}</h3>
|
|
1370
1387
|
<p>${t("botOnboarding.intro")}</p>
|
|
1371
1388
|
</header>
|
|
1372
|
-
<p class="onboarding-status status-${e.status}">${
|
|
1389
|
+
<p class="onboarding-status status-${e.status}">${Ar(e)}</p>
|
|
1373
1390
|
${o}
|
|
1374
1391
|
${s}
|
|
1375
1392
|
${a}
|
|
1376
|
-
${
|
|
1393
|
+
${Dr(e)}
|
|
1377
1394
|
${r}
|
|
1378
1395
|
<form method="dialog"><button>${t("botOnboarding.close")}</button></form>
|
|
1379
|
-
</article>`}async function
|
|
1396
|
+
</article>`}async function Rr(){try{let e=await fetch("/api/cli-options"),n=await e.json();if(e.ok&&Array.isArray(n?.options))return typeof n.ttadkModelDefault=="string"&&n.ttadkModelDefault.trim()&&(vn=n.ttadkModelDefault.trim()),Array.isArray(n.ttadkModelSuggestions)&&(Ja=n.ttadkModelSuggestions.filter(o=>typeof o=="string")),n.options}catch{}return[{id:"claude-code",label:"Claude"}]}function Ka(e){let n=dt;if(!n)return;let o=n.querySelector("#ob-cli"),s=n.querySelector("#ob-model"),a=n.querySelector("#ob-model-suggestions");if(!o||!s)return;let r=e.find(v=>v.id===o.value),d=r?.gateway==="ttadk",p=d&&r?.acceptsModel!==!1;if(d&&!p){s.value="",s.disabled=!0,s.placeholder=t("botOnboarding.modelTtadkCocoPlaceholder");return}s.disabled=!1,p?(a&&(a.innerHTML=Ja.map(v=>`<option value="${i(v)}"></option>`).join("")),s.placeholder=t("botOnboarding.modelTtadkPlaceholder").replace("{model}",vn),s.value.trim()||(s.value=vn)):(a&&(a.innerHTML=""),s.placeholder=t("botOnboarding.modelPlaceholder"),s.value.trim()===vn&&(s.value=""))}function ao(e,n){let o=so(),s=e.map(v=>`<option value="${i(v.id)}">${i(v.label)}\uFF08${i(v.id)}\uFF09</option>`).join(""),a=n?`<p class="form-error">${i(n)}</p>`:"";o.innerHTML=`<article>
|
|
1380
1397
|
<header>
|
|
1381
1398
|
<h3>${t("botOnboarding.title")}</h3>
|
|
1382
1399
|
<p>${t("botOnboarding.intro")}</p>
|
|
@@ -1392,7 +1409,8 @@ ${ha("manage")}
|
|
|
1392
1409
|
</label>
|
|
1393
1410
|
<label class="onboarding-field">
|
|
1394
1411
|
<span>${t("botOnboarding.modelLabel")}</span>
|
|
1395
|
-
<input id="ob-model" type="text" placeholder="${t("botOnboarding.modelPlaceholder")}" autocomplete="off" spellcheck="false">
|
|
1412
|
+
<input id="ob-model" type="text" list="ob-model-suggestions" placeholder="${t("botOnboarding.modelPlaceholder")}" autocomplete="off" spellcheck="false">
|
|
1413
|
+
<datalist id="ob-model-suggestions"></datalist>
|
|
1396
1414
|
</label>
|
|
1397
1415
|
${a}
|
|
1398
1416
|
<menu class="onboarding-actions">
|
|
@@ -1400,8 +1418,8 @@ ${ha("manage")}
|
|
|
1400
1418
|
<button type="submit" class="primary">${t("botOnboarding.startScan")}</button>
|
|
1401
1419
|
</menu>
|
|
1402
1420
|
</form>
|
|
1403
|
-
</article>`;let r=o.querySelector("#onboarding-form");o.querySelector("#ob-cancel")?.addEventListener("click",()=>o.close()),r?.addEventListener("submit",
|
|
1421
|
+
</article>`;let r=o.querySelector("#onboarding-form");o.querySelector("#ob-cancel")?.addEventListener("click",()=>o.close()),o.querySelector("#ob-cli")?.addEventListener("change",()=>Ka(e)),Ka(e),r?.addEventListener("submit",v=>{v.preventDefault();let k=o.querySelector("#ob-cli")?.value??"",I=o.querySelector("#ob-dir")?.value??"",T=o.querySelector("#ob-model")?.value??"";Or({cliId:k,workingDir:I,model:T},e)})}async function Or(e,n){zt(),_t({id:"",status:"starting"});try{let o=await fetch("/api/bot-onboarding/start",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({cliId:e.cliId,workingDir:e.workingDir.trim(),model:e.model.trim()||void 0})}),s=await o.json();if(o.status===400){ao(n,s?.message??s?.error??"invalid_input");return}if(!o.ok||!s?.job?.id)throw new Error(s?.error??`http_${o.status}`);_t(s.job),yn=window.setInterval(()=>{Br(s.job.id).catch(a=>{zt(),_t({id:s.job.id,status:"failed",message:a instanceof Error?a.message:String(a)})})},1200)}catch(o){_t({id:"",status:"failed",message:o instanceof Error?o.message:String(o)})}}async function Br(e){let n=await fetch(`/api/bot-onboarding/${encodeURIComponent(e)}`),o=await n.json();if(!n.ok||!o?.job)throw new Error(o?.error??`http_${n.status}`);_t(o.job),(o.job.status==="completed"||o.job.status==="failed")&&zt()}async function Nr(){zt();let e=so();ao([{id:"claude-code",label:"Claude"}]),e.open||e.showModal();let n=await Rr();e.open&&e.querySelector("#onboarding-form")&&ao(n)}function Ya(){let e=document.getElementById("add-bot-btn");e&&(e.onclick=()=>{Nr()})}var Pr={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"/>'},Qa=[{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"}]}],Va=Qa.flatMap(e=>e.options),ht=!1;function io(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">${Pr[e]??""}</svg>`}function qr(e){return e.replace(/[&<>"]/g,n=>({"&":"&","<":"<",">":">",'"':"""})[n])}function Xa(){let e=document.getElementById("theme-menu"),n=document.getElementById("theme-menu-btn"),o=document.getElementById("theme-menu-pop");if(!e||!n||!o)return;o.innerHTML=Qa.map(a=>`<div class="tm-group" data-label-key="${a.labelKey}"></div>`+a.options.map(r=>`<button type="button" class="tm-item" role="option" data-value="${r.value}"><span class="tm-ic">${io(r.icon)}</span><span class="tm-label" data-label-key="${r.labelKey}"></span></button>`).join("")).join("");let s=a=>{ht=a,o.hidden=!ht,n.setAttribute("aria-expanded",String(ht)),e.classList.toggle("open",ht)};n.addEventListener("click",a=>{a.stopPropagation(),s(!ht)}),o.addEventListener("click",a=>{let r=a.target.closest(".tm-item");r&&(Te.setTheme(r.dataset.value??"system"),s(!1))}),document.addEventListener("click",a=>{ht&&!e.contains(a.target)&&s(!1)}),document.addEventListener("keydown",a=>{a.key==="Escape"&&ht&&s(!1)}),ro()}function ro(){let e=document.getElementById("theme-menu-btn");if(!e)return;let n=Va.find(o=>o.value===Te.theme)??Va[0];e.innerHTML=`<span class="tm-ic">${io(n.icon)}</span><span class="tm-current">${qr(t(n.labelKey))}</span><span class="tm-chev">${io("chevron")}</span>`,document.querySelectorAll("#theme-menu-pop [data-label-key]").forEach(o=>{o.textContent=t(o.dataset.labelKey??"")}),document.querySelectorAll("#theme-menu-pop .tm-item").forEach(o=>{o.classList.toggle("active",o.dataset.value===Te.theme)})}var Ce=document.getElementById("root"),Et=!0,os=!1,as=["roles","bot-defaults","team","connectors"],lo=!1;function Ur(){if(lo)return;lo=!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(),lo=!1};e.querySelector("#auth-expired-dismiss")?.addEventListener("click",n),e.addEventListener("click",o=>{o.target===e&&n()})}var co;function jr(){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",co&&window.clearTimeout(co),co=window.setTimeout(()=>{e.style.display="none"},4e3)}var Fr=window.fetch.bind(window);window.fetch=async function(...n){let o=await Fr(...n);if(o.status===401){let s=(n[1]?.method??"GET").toUpperCase();(s==="GET"||s==="HEAD")&&!os?Ur():jr()}return o};var uo="";function kn(){let e=document.getElementById("attention-strip");if(!e)return;let n=[...Q.sessions.values()].map(a=>({s:a,reason:it(a)})).filter(a=>!!a.reason).sort((a,r)=>xe(a.s)-xe(r.s));if(n.length===0){e.hidden=!0,e.innerHTML="",uo="";return}let o=n[0],s=`
|
|
1404
1422
|
<span class="attention-strip-ic" aria-hidden="true">!</span>
|
|
1405
1423
|
<b>${i(t("strip.pending",{count:n.length}))}</b>
|
|
1406
|
-
<span class="attention-strip-longest">${i(t("strip.longest",{time:
|
|
1407
|
-
<a class="attention-strip-go" href="#/sessions">${i(t("strip.handle"))}</a>`;e.hidden=!1,s!==
|
|
1424
|
+
<span class="attention-strip-longest">${i(t("strip.longest",{time:qe(xe(o.s)),bot:ye(o.s),reason:o.reason}))}</span>
|
|
1425
|
+
<a class="attention-strip-go" href="#/sessions">${i(t("strip.handle"))}</a>`;e.hidden=!1,s!==uo&&(uo=s,e.innerHTML=s)}Q.on(kn);Ke().then(kn);async function Gr(){try{let e=await fetch("/api/settings");if(e.ok){let n=await e.json();Et=!!n.authed,Te.authed=Et,os=!!(n.settings&&n.settings.publicReadOnly);let o=Vt(n.lang);o&&Te.setLocale(o)}}catch{}}async function _r(e){if(Et)try{await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({lang:e})})}catch{}}function zr(){for(let n of as){let o=document.querySelector(`.sidebar-nav a[data-route="${n}"]`);o&&(o.style.display=Et?"":"none")}let e=document.getElementById("add-bot-btn");e&&(e.style.display=Et?"":"none")}function Wr(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 xt=null;function Za(e){for(let n of document.querySelectorAll(".sidebar-nav a")){let o=n.getAttribute("href")??"#/";n.classList.toggle("active",o===(e||"#/"))}}function po(){xt&&(xt(),xt=null);let e=location.hash||"#/";if(!Et&&as.some(n=>e.startsWith("#/"+n))){Wr(Ce),Za(e);return}e.startsWith("#/workflows/catalog")||e.startsWith("#/workflows-catalog")?xt=za(Ce):e.startsWith("#/workflows")?xt=Ra(Ce):e.startsWith("#/groups")?ua(Ce):e.startsWith("#/settings")?Ha(Ce):e.startsWith("#/bot-defaults")?ga(Ce):e.startsWith("#/connectors")?xa(Ce):e.startsWith("#/team/manage")?La(Ce):e.startsWith("#/team")?Ta(Ce):e.startsWith("#/roles")?ya(Ce):e.startsWith("#/schedules")?da(Ce):e.startsWith("#/sessions")?ra(Ce):e.startsWith("#/office")?xt=Wa(Ce)??null:Yo(Ce),Za(e)}var mo=document.getElementById("status");function ss(){mo&&(mo.textContent=Q.online?t("status.live"):t("status.disconnected"),mo.className="connection-status "+(Q.online?"online":"offline"))}Q.on(ss);function es(){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===Te.locale)}),ro(),ss()}function Kr(){document.querySelectorAll("[data-locale]").forEach(e=>{e.onclick=()=>{let n=e.dataset.locale;Te.setLocale(n),_r(n)}}),Xa(),Yr()}var ts="botmux.ownerAvatar.v1";function ns(e,n){let o=document.querySelector(".brand-mark");!o||!e||(o.innerHTML=`<img class="brand-owner-img" src="${i(e)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.remove()">`,n&&(o.title=n))}function Jr(){try{let e=JSON.parse(window.localStorage.getItem(ts)??"null");e?.avatarUrl&&ns(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)){ns(String(e.avatarUrl),e.name?String(e.name):void 0);try{window.localStorage.setItem(ts,JSON.stringify({avatarUrl:e.avatarUrl,name:e.name??""}))}catch{}}}).catch(()=>{})}function Yr(){let e=document.getElementById("sidebar-toggle");if(!e)return;let n=Ao(window.localStorage),o=()=>{document.documentElement.dataset.sidebar=n,e.title=t(n==="collapsed"?"nav.sidebarExpand":"nav.sidebarCollapse")};o(),e.addEventListener("click",()=>{n=n==="collapsed"?"expanded":"collapsed",Do(window.localStorage,n),o()})}(async()=>{Te.init(),Kr(),Ya(),Te.on(()=>{es(),kn(),po()}),es(),kn(),await Gr(),zr(),Jr();try{await wo()}catch(e){console.error("botmux dashboard bootstrap failed",e),Q.setOnline(!1)}window.addEventListener("hashchange",po),po()})();})();
|