botmux 2.85.0 → 2.85.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/cli.d.ts.map +1 -1
- package/dist/cli.js +22 -13
- package/dist/cli.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +4 -1
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/bot-onboarding.d.ts +24 -8
- package/dist/dashboard/bot-onboarding.d.ts.map +1 -1
- package/dist/dashboard/bot-onboarding.js +170 -49
- package/dist/dashboard/bot-onboarding.js.map +1 -1
- package/dist/dashboard/bot-payload.d.ts +43 -0
- package/dist/dashboard/bot-payload.d.ts.map +1 -0
- package/dist/dashboard/bot-payload.js +44 -0
- package/dist/dashboard/bot-payload.js.map +1 -0
- package/dist/dashboard/registry.d.ts +2 -0
- package/dist/dashboard/registry.d.ts.map +1 -1
- package/dist/dashboard/registry.js.map +1 -1
- package/dist/dashboard/web/bot-defaults.d.ts +1 -0
- package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults.js +6 -3
- 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 +60 -4
- 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 +14 -0
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/overview.d.ts +22 -0
- package/dist/dashboard/web/overview.d.ts.map +1 -1
- package/dist/dashboard/web/overview.js +6 -1
- package/dist/dashboard/web/overview.js.map +1 -1
- package/dist/dashboard-web/app.js +261 -250
- package/dist/dashboard.js +58 -36
- package/dist/dashboard.js.map +1 -1
- package/dist/im/lark/client.d.ts.map +1 -1
- package/dist/im/lark/client.js +23 -1
- package/dist/im/lark/client.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +16 -9
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/setup/cli-selection.d.ts +20 -1
- package/dist/setup/cli-selection.d.ts.map +1 -1
- package/dist/setup/cli-selection.js +45 -5
- package/dist/setup/cli-selection.js.map +1 -1
- package/dist/worker.js +10 -1
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";(()=>{var Dn=class{sessions=new Map;schedules=new Map;online=!0;listeners=new Set;upsertSessions(n){for(let a of n)this.sessions.set(a.sessionId,a);this.emit()}upsertSchedules(n){for(let a of n)this.schedules.set(a.id,a);this.emit()}applySse(n,a){if(n==="session.spawned")this.sessions.set(a.session.sessionId,a.session);else if(n==="session.update"){let s=this.sessions.get(a.sessionId);s&&this.sessions.set(a.sessionId,{...s,...a.patch})}else if(n==="session.exited"){let s=this.sessions.get(a.sessionId);s&&this.sessions.set(a.sessionId,{...s,status:"closed"})}else if(n==="schedule.created")this.schedules.set(a.schedule.id,a.schedule);else if(n==="schedule.updated"){let s=this.schedules.get(a.id);s&&this.schedules.set(a.id,{...s,...a.patch})}else if(n==="schedule.deleted")this.schedules.delete(a.id);else return;this.emit()}setOnline(n){this.online!==n&&(this.online=n,this.emit())}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}},Y=new Dn;async function Sa(){let[e,n]=await Promise.all([fetch("/api/sessions").then(o=>o.json()),fetch("/api/schedules").then(o=>o.json())]);Y.upsertSessions(e.sessions??[]),Y.upsertSchedules(n.schedules??[]);let a=new EventSource("/events"),s=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let o of s)a.addEventListener(o,r=>{try{let d=JSON.parse(r.data);Y.applySse(o,d.body??d)}catch{}});a.onerror=()=>Y.setOnline(!1),a.onopen=()=>Y.setOnline(!0)}var Rn="botmux.dashboard.locale",ws={"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","nav.skills":"Skills","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.delivery":"\u6295\u9012","schedules.deliveryOrigin":"\u539F\u8BDD\u9898","schedules.deliveryNewTopic":"\u6BCF\u6B21\u65B0\u8BDD\u9898","schedules.deliveryLocal":"\u4EC5\u8BB0\u5F55","schedules.useNewTopic":"\u6539\u4E3A\u6BCF\u6B21\u65B0\u8BDD\u9898","schedules.useOrigin":"\u6539\u4E3A\u539F\u8BDD\u9898","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","skills.title":"Skill \u7BA1\u7406","skills.subtitle":"\u7BA1\u7406 botmux \u7684 CLI \u65E0\u5173 Skill \u8D44\u4EA7\uFF0C\u5E76\u6309 bot \u9009\u62E9\u4F18\u5148\u62AB\u9732\u3002","skills.installed":"\u5DF2\u5B89\u88C5 Skills","skills.installedHelp":"\u672C\u673A registry \u4E2D\u53EF\u88AB bot \u4F18\u5148\u62AB\u9732\u7684 Skill \u8D44\u4EA7\u3002","skills.overviewTitle":"\u6309 Bot \u7EC4\u7EC7 Skill \u8D44\u4EA7","skills.overviewBody":"\u5168\u5C40 Skill \u6CE8\u5165\u914D\u7F6E\u63A7\u5236\u4F1A\u8BDD\u6CE8\u5165\u7B56\u7565\uFF1B\u6BCF\u4E2A bot \u53EA\u7EF4\u62A4\u81EA\u5DF1\u7684\u4F18\u5148\u62AB\u9732\u5217\u8868\u3002","skills.metricInstalled":"\u5DF2\u5B89\u88C5 Skills","skills.metricBots":"\u5DF2\u914D\u7F6E Bot","skills.metricAttached":"\u4F18\u5148\u5F15\u7528","skills.install":"\u5B89\u88C5 Skill","skills.installInfoLabel":"\u5B89\u88C5\u4F4D\u7F6E\u8BF4\u660E","skills.installInfo":`\u6CE8\u518C: ~/.botmux/skills/registry.json
|
|
1
|
+
"use strict";(()=>{var Dn=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 a=this.sessions.get(o.sessionId);a&&this.sessions.set(o.sessionId,{...a,...o.patch})}else if(n==="session.exited"){let a=this.sessions.get(o.sessionId);a&&this.sessions.set(o.sessionId,{...a,status:"closed"})}else if(n==="schedule.created")this.schedules.set(o.schedule.id,o.schedule);else if(n==="schedule.updated"){let a=this.schedules.get(o.id);a&&this.schedules.set(o.id,{...a,...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()}},Y=new Dn;async function Lo(){let[e,n]=await Promise.all([fetch("/api/sessions").then(s=>s.json()),fetch("/api/schedules").then(s=>s.json())]);Y.upsertSessions(e.sessions??[]),Y.upsertSchedules(n.schedules??[]);let o=new EventSource("/events"),a=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let s of a)o.addEventListener(s,r=>{try{let d=JSON.parse(r.data);Y.applySse(s,d.body??d)}catch{}});o.onerror=()=>Y.setOnline(!1),o.onopen=()=>Y.setOnline(!0)}var Rn="botmux.dashboard.locale",vs={"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","nav.skills":"Skills","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.needsOwner":"\u65E0\u6CD5\u81EA\u52A8\u786E\u8BA4\u626B\u7801\u4EBA\u8EAB\u4EFD\uFF0C\u8BF7\u624B\u52A8\u586B\u5199 owner \u540E\u518D\u5B8C\u6210\u3002","botOnboarding.ownerLabel":"Owner\uFF08\u673A\u5668\u4EBA\u7BA1\u7406\u8005\uFF09","botOnboarding.ownerPlaceholder":"\u5B8C\u6574\u90AE\u7BB1 / union_id(on_) / open_id(ou_)\uFF0C\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694","botOnboarding.ownerHint":"\u4E3A\u907F\u514D\u300C\u65E0\u4EBA\u662F owner \u65F6\u4EFB\u4F55\u4EBA\u90FD\u80FD\u505A\u7BA1\u7406\u64CD\u4F5C\u300D\uFF0C\u5FC5\u987B\u6307\u5B9A\u81F3\u5C11\u4E00\u4E2A owner\u3002\u5EFA\u8BAE\u7528\u672C\u4F01\u4E1A\u90AE\u7BB1\u6216 union_id(on_)\u3002","botOnboarding.ownerSubmit":"\u4FDD\u5B58 owner \u5E76\u5B8C\u6210","botOnboarding.ownerEmpty":"\u8BF7\u586B\u5199\u81F3\u5C11\u4E00\u4E2A owner\u3002","botOnboarding.ownerInvalid":"owner \u6821\u9A8C\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5\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.delivery":"\u6295\u9012","schedules.deliveryOrigin":"\u539F\u8BDD\u9898","schedules.deliveryNewTopic":"\u6BCF\u6B21\u65B0\u8BDD\u9898","schedules.deliveryLocal":"\u4EC5\u8BB0\u5F55","schedules.useNewTopic":"\u6539\u4E3A\u6BCF\u6B21\u65B0\u8BDD\u9898","schedules.useOrigin":"\u6539\u4E3A\u539F\u8BDD\u9898","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","skills.title":"Skill \u7BA1\u7406","skills.subtitle":"\u7BA1\u7406 botmux \u7684 CLI \u65E0\u5173 Skill \u8D44\u4EA7\uFF0C\u5E76\u6309 bot \u9009\u62E9\u4F18\u5148\u62AB\u9732\u3002","skills.installed":"\u5DF2\u5B89\u88C5 Skills","skills.installedHelp":"\u672C\u673A registry \u4E2D\u53EF\u88AB bot \u4F18\u5148\u62AB\u9732\u7684 Skill \u8D44\u4EA7\u3002","skills.overviewTitle":"\u6309 Bot \u7EC4\u7EC7 Skill \u8D44\u4EA7","skills.overviewBody":"\u5168\u5C40 Skill \u6CE8\u5165\u914D\u7F6E\u63A7\u5236\u4F1A\u8BDD\u6CE8\u5165\u7B56\u7565\uFF1B\u6BCF\u4E2A bot \u53EA\u7EF4\u62A4\u81EA\u5DF1\u7684\u4F18\u5148\u62AB\u9732\u5217\u8868\u3002","skills.metricInstalled":"\u5DF2\u5B89\u88C5 Skills","skills.metricBots":"\u5DF2\u914D\u7F6E Bot","skills.metricAttached":"\u4F18\u5148\u5F15\u7528","skills.install":"\u5B89\u88C5 Skill","skills.installInfoLabel":"\u5B89\u88C5\u4F4D\u7F6E\u8BF4\u660E","skills.installInfo":`\u6CE8\u518C: ~/.botmux/skills/registry.json
|
|
2
2
|
\u5B89\u88C5: ~/.botmux/skills/store/\u6280\u80FD\u540D\uFF1BGit \u7F13\u5B58: ~/.botmux/skills/sources
|
|
3
3
|
\u9694\u79BB: \u4E0D\u5199\u5165 Codex/Claude \u5168\u5C40\u76EE\u5F55\uFF1B\u672C\u673A CLI Skill \u76F4\u63A5\u5F15\u7528\u539F\u5730\u5740`,"skills.source":"\u5BFC\u5165\u5730\u5740","skills.sourcePlaceholder":"\u7C98\u8D34 GitHub Skill \u9875\u9762\u3001Git URL \u6216\u672C\u673A Skill \u76EE\u5F55","skills.sourceHelpRemoteLabel":"GitHub / Git: ","skills.sourceHelpRemote":"\u53EF\u7C98\u8D34 Skill \u76EE\u5F55\u9875\u9762\u6216\u4ED3\u5E93\u5730\u5740\uFF1B\u4ED3\u5E93\u5730\u5740\u9700\u586B\u5199\u4ED3\u5E93\u5185\u8DEF\u5F84\u3002","skills.sourceHelpLocalLabel":"\u672C\u673A CLI Skill \u76EE\u5F55: ","skills.sourceHelpLocal":"\u76F4\u63A5\u5F15\u7528\u539F\u5730\u5740\uFF0C\u4E0D\u590D\u5236\u5230 botmux store\u3002","skills.path":"\u4ED3\u5E93\u5185\u8DEF\u5F84\uFF08\u53EF\u9009\uFF09","skills.pathPlaceholder":"\u7559\u7A7A\u5219\u4F7F\u7528 GitHub URL \u4E2D\u7684\u8DEF\u5F84","skills.ref":"Ref\uFF08\u53EF\u9009\uFF09","skills.refPlaceholder":"\u7559\u7A7A\u5219\u4F7F\u7528 GitHub URL \u4E2D\u7684\u5206\u652F\u6216\u9ED8\u8BA4 HEAD","skills.link":"\u672C\u5730\u94FE\u63A5\uFF08\u4E0D\u590D\u5236\uFF09","skills.installSubmit":"\u5B89\u88C5","skills.update":"\u66F4\u65B0","skills.remove":"\u5220\u9664","skills.pageStatus":"{page} / {pages}","skills.prevPage":"\u4E0A\u4E00\u9875","skills.nextPage":"\u4E0B\u4E00\u9875","skills.empty":"\u6682\u65E0\u5DF2\u5B89\u88C5 skill\u3002\u53EF\u4EE5\u4ECE\u672C\u673A\u76EE\u5F55\u3001Git \u6216 GitHub \u5B89\u88C5\u3002","skills.globalDefaults":"\u5168\u5C40 Skill \u6CE8\u5165\u914D\u7F6E","skills.globalProject":"\u5DE5\u4F5C\u533A Skill","skills.globalProjectOff":"\u5FFD\u7565\u5DE5\u4F5C\u533A Skill","skills.globalProjectOffHelp":"\u4EC5\u8BFB\u53D6\u5168\u5C40 CLI Skill \u548C botmux Skill","skills.globalProjectAll":"\u8BFB\u53D6\u5DE5\u4F5C\u533A Skill","skills.globalProjectAllHelp":`\u8BFB\u53D6 .agents/skills \u4E0E
|
|
4
4
|
.botmux/skills`,"skills.globalDelivery":"Skill \u6CE8\u5165\u65B9\u5F0F","skills.bots":"Bot Skill \u914D\u7F6E","skills.botsHelp":"\u4E3A\u6BCF\u4E2A bot \u9009\u62E9\u6700\u9700\u8981\u4F18\u5148\u62AB\u9732\u7684 Skill\u3002","skills.botCount":"{count} \u4E2A Bot","skills.scrollBotsPrev":"\u5411\u5DE6\u67E5\u770B Bot","skills.scrollBotsNext":"\u5411\u53F3\u67E5\u770B Bot","skills.skillCount":"{count} \u4E2A Skill","skills.attach":"\u52A0\u5165\u4F18\u5148\u62AB\u9732","skills.detach":"\u79FB\u9664","skills.detachNamed":"\u79FB\u9664 {skill}","skills.delivery":"\u6CE8\u5165\u65B9\u5F0F","skills.deliveryAuto":"\u81EA\u52A8","skills.deliveryAutoHelp":"\u4F18\u5148\u7528 CLI \u539F\u751F\u901A\u9053\uFF1B\u4E0D\u652F\u6301\u65F6\u81EA\u52A8\u6539\u7528\u63D0\u793A\u8BCD\u6CE8\u5165","skills.deliveryPrompt":"\u63D0\u793A\u8BCD","skills.deliveryPromptHelp":"\u628A Skill \u6E05\u5355\u5199\u5165\u4F1A\u8BDD\u63D0\u793A\u8BCD\uFF0C\u517C\u5BB9\u6240\u6709 CLI","skills.deliveryNative":"\u539F\u751F","skills.deliveryNativeHelp":"\u53EA\u4EA4\u7ED9 CLI \u81EA\u5DF1\u7684 Skill \u673A\u5236\uFF0C\u4E0D\u505A\u63D0\u793A\u8BCD\u515C\u5E95","skills.projectMode":"\u5DE5\u4F5C\u533A Skills","skills.projectDefault":"\u8DDF\u968F\u5168\u5C40","skills.projectDefaultHelp":"\u4F7F\u7528\u5DE6\u4FA7\u9879\u76EE Skill \u9ED8\u8BA4\u503C","skills.projectOff":"\u4E0D\u8BFB\u53D6","skills.projectOffHelp":"\u8FD9\u4E2A bot \u4E0D\u8BFB\u53D6\u5DE5\u4F5C\u533A skill","skills.projectAll":"\u8BFB\u53D6","skills.projectAllHelp":"\u8FD9\u4E2A bot \u52A0\u5165\u5DE5\u4F5C\u533A skill \u5019\u9009","skills.priority":"\u4F18\u5148 skills","skills.noPriority":"\u672A\u914D\u7F6E\uFF0C\u4FDD\u6301 CLI \u9ED8\u8BA4\u884C\u4E3A","skills.dangling":"\u672A\u5B89\u88C5","skills.removeInUse":'Skill "{skill}" \u4ECD\u88AB\u4EE5\u4E0B\u914D\u7F6E\u5F15\u7528\uFF1A{refs}\u3002\u5220\u9664\u53EA\u4F1A\u79FB\u9664 registry \u6587\u4EF6\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u6E05\u7406\u5F15\u7528\u3002\u7EE7\u7EED\u5220\u9664\uFF1F',"skills.saved":"\u5DF2\u4FDD\u5B58","skills.failed":"\u5931\u8D25","skills.jobRunning":"\u5904\u7406\u4E2D...","skills.refresh":"\u5237\u65B0","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","botDefaults.sectionStartupCommands":"\u542F\u52A8\u547D\u4EE4","botDefaults.startupCommandsHelp":"\u5F00\u4F1A\u8BDD\u540E\u3001\u9996\u6761\u6D88\u606F\u4E4B\u524D\uFF0C\u81EA\u52A8\u6309\u987A\u5E8F\u53D1\u7ED9 CLI \u7684\u547D\u4EE4\uFF08\u6BCF\u6761\u72EC\u7ACB\u56DE\u8F66\uFF09\uFF0C\u5982 /effort ultracode\u3002\u9017\u53F7\u6216\u6362\u884C\u5206\u9694\uFF0C\u6BCF\u884C\u4E00\u6761\uFF0C\u53EF\u5E26\u53C2\u6570\uFF1B\u7559\u7A7A\uFF1D\u4E0D\u53D1\u3002\u4E0B\u4E2A\u65B0\u4F1A\u8BDD\u8D77\u6548\uFF0C\u4E14\u6BCF\u6B21\u65B0\u4F1A\u8BDD\uFF08\u542B resume\uFF09\u90FD\u91CD\u653E\u2014\u2014\u6240\u4EE5 /effort ultracode \u8FD9\u7C7B\u53EA\u5BF9\u5F53\u524D\u4F1A\u8BDD\u751F\u6548\u7684\u8BBE\u7F6E\u4E0D\u4F1A\u56E0 resume \u4E22\u5931\u3002\u4EC5\u5BF9\u539F\u751F CLI \u4F1A\u8BDD\u751F\u6548\uFF0Cadopt \u63A5\u7BA1\u7684\u4F1A\u8BDD\u4E0D\u53D1\u3002","botDefaults.startupCommandsPlaceholder":"\u6BCF\u884C\u4E00\u6761\uFF0C\u5982 /effort ultracode","botDefaults.startupCommandsSave":"\u4FDD\u5B58\u542F\u52A8\u547D\u4EE4","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
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
{total} \u4E2A\u60AC\u6302\u9879\u4F1A\u7531 cancel recovery \u5904\u7406\u3002
|
|
8
8
|
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":`{
|
|
9
9
|
"city": "\u5317\u4EAC"
|
|
10
|
-
}`,"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"},vs={"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","nav.skills":"Skills","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.delivery":"Delivery","schedules.deliveryOrigin":"Original thread","schedules.deliveryNewTopic":"New topic each run","schedules.deliveryLocal":"Log only","schedules.useNewTopic":"Switch to new-topic","schedules.useOrigin":"Switch to original","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","skills.title":"Skill Management","skills.subtitle":"Manage CLI-neutral botmux Skill assets and choose priority disclosure per bot.","skills.installed":"Installed Skills","skills.installedHelp":"Skill assets in the local registry that bots can disclose first.","skills.overviewTitle":"Organize Skill assets by bot","skills.overviewBody":"Global Skill delivery settings control session injection; each bot only manages its priority disclosure list.","skills.metricInstalled":"Installed Skills","skills.metricBots":"Configured Bots","skills.metricAttached":"Priority refs","skills.install":"Install Skill","skills.installInfoLabel":"Install location details","skills.installInfo":`Registry: ~/.botmux/skills/registry.json
|
|
10
|
+
}`,"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"},ks={"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","nav.skills":"Skills","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.needsOwner":"Could not auto-confirm the scanner identity. Enter an owner manually to finish.","botOnboarding.ownerLabel":"Owner (bot administrator)","botOnboarding.ownerPlaceholder":"Full email / union_id (on_) / open_id (ou_), comma-separated","botOnboarding.ownerHint":"An owner is required so the bot is not left open for anyone to run admin actions. Prefer a company email or union_id (on_).","botOnboarding.ownerSubmit":"Save owner & finish","botOnboarding.ownerEmpty":"Enter at least one owner.","botOnboarding.ownerInvalid":"Owner validation failed. Please check and retry.","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.delivery":"Delivery","schedules.deliveryOrigin":"Original thread","schedules.deliveryNewTopic":"New topic each run","schedules.deliveryLocal":"Log only","schedules.useNewTopic":"Switch to new-topic","schedules.useOrigin":"Switch to original","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","skills.title":"Skill Management","skills.subtitle":"Manage CLI-neutral botmux Skill assets and choose priority disclosure per bot.","skills.installed":"Installed Skills","skills.installedHelp":"Skill assets in the local registry that bots can disclose first.","skills.overviewTitle":"Organize Skill assets by bot","skills.overviewBody":"Global Skill delivery settings control session injection; each bot only manages its priority disclosure list.","skills.metricInstalled":"Installed Skills","skills.metricBots":"Configured Bots","skills.metricAttached":"Priority refs","skills.install":"Install Skill","skills.installInfoLabel":"Install location details","skills.installInfo":`Registry: ~/.botmux/skills/registry.json
|
|
11
11
|
Install: ~/.botmux/skills/store/skill-name; Git cache: ~/.botmux/skills/sources
|
|
12
12
|
Isolation: Codex/Claude global directories are not modified; local CLI Skills are referenced in place`,"skills.source":"Import Address","skills.sourcePlaceholder":"Paste a GitHub Skill page, Git URL, or local Skill directory","skills.sourceHelpRemoteLabel":"GitHub / Git: ","skills.sourceHelpRemote":"Paste a Skill directory page or repository URL; repository URLs need a repo path.","skills.sourceHelpLocalLabel":"Local CLI Skill directory: ","skills.sourceHelpLocal":"Referenced in place without copying into the botmux store.","skills.path":"Repo Path (optional)","skills.pathPlaceholder":"Blank uses the path from the GitHub URL","skills.ref":"Ref (optional)","skills.refPlaceholder":"Blank uses the GitHub URL ref or default HEAD","skills.link":"Local link (no copy)","skills.installSubmit":"Install","skills.update":"Update","skills.remove":"Remove","skills.pageStatus":"{page} / {pages}","skills.prevPage":"Previous page","skills.nextPage":"Next page","skills.empty":"No installed skills yet. Install from a local directory, Git, or GitHub.","skills.globalDefaults":"Global Skill Delivery","skills.globalProject":"Workspace Skills","skills.globalProjectOff":"Ignore workspace Skills","skills.globalProjectOffHelp":"Read global CLI Skills and botmux Skills only","skills.globalProjectAll":"Read workspace Skills","skills.globalProjectAllHelp":`Read .agents/skills and
|
|
13
13
|
.botmux/skills`,"skills.globalDelivery":"Skill Delivery","skills.bots":"Bot Skill Settings","skills.botsHelp":"Choose the Skills each bot should disclose first.","skills.botCount":"{count} Bots","skills.scrollBotsPrev":"Scroll bots left","skills.scrollBotsNext":"Scroll bots right","skills.skillCount":"{count} Skills","skills.attach":"Add to priority","skills.detach":"Remove","skills.detachNamed":"Remove {skill}","skills.delivery":"Injection","skills.deliveryAuto":"Auto","skills.deliveryAutoHelp":"Use native CLI delivery first; fall back to Prompt when unsupported","skills.deliveryPrompt":"Prompt","skills.deliveryPromptHelp":"Inject the Skill catalog into the session prompt; works with every CLI","skills.deliveryNative":"Native","skills.deliveryNativeHelp":"Use only the CLI native Skill mechanism; no Prompt fallback","skills.projectMode":"Workspace Skills","skills.projectDefault":"Follow global","skills.projectDefaultHelp":"Use the project default on the left","skills.projectOff":"Do not read","skills.projectOffHelp":"This bot ignores workspace skills","skills.projectAll":"Read","skills.projectAllHelp":"This bot includes workspace skill candidates","skills.priority":"Priority skills","skills.noPriority":"Not configured, keeping CLI default behavior","skills.dangling":"Not installed","skills.removeInUse":'Skill "{skill}" is still referenced by: {refs}. Removing it deletes the registry package but does not automatically clean references. Continue?',"skills.saved":"Saved","skills.failed":"Failed","skills.jobRunning":"Working...","skills.refresh":"Refresh","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","botDefaults.sectionStartupCommands":"Startup commands","botDefaults.startupCommandsHelp":"Commands auto-sent to the CLI in order after launch, before the first message (each its own Enter), e.g. /effort ultracode. Comma- or newline-separated, one per line, arguments allowed; empty = none. Takes effect from the next session, and replays on every new session (incl. resume) \u2014 so session-only settings like /effort ultracode survive a resume. Native CLI sessions only; adopted sessions are not driven.","botDefaults.startupCommandsPlaceholder":"One per line, e.g. /effort ultracode","botDefaults.startupCommandsSave":"Save startup commands","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.:
|
|
@@ -16,9 +16,9 @@ You are a code reviewer for this group...`,"roles.configured":"Configured","role
|
|
|
16
16
|
{total} dangling item(s) will be handled by cancel-driven recovery.
|
|
17
17
|
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":`{
|
|
18
18
|
"city": "\u5317\u4EAC"
|
|
19
|
-
}`,"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"},La={zh:ws,en:vs};function nn(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 ks(e=[]){for(let n of e){let a=nn(n);if(a)return a}return"zh"}function an(e){return(n,a)=>{let s=La[e][n]??La.zh[n]??n;return a?s.replace(/\{(\w+)\}/g,(o,r)=>{let d=a[r];return d==null?`{${r}}`:String(d)}):s}}function Ta(e,n){return(e?nn(e.getItem(Rn)):null)??ks(n)}var Pn="botmux.dashboard.theme",Ia="botmux.dashboard.sessions.view";function $s(e){return e==="system"||e==="light"||e==="dark"?e:null}function Bn(e){return e==="kanban"||e==="board"||e==="table"?e:null}function Ma(e,n){return e==="system"?n?"dark":"light":e}function Ea(e){return $s(e?.getItem(Pn))??"dark"}function xa(e){return Bn(e?.getItem(Ia))??"board"}var Ha="botmux.dashboard.sessions.boardOrder",jt=["needs-you","starting","working","idle"];function Ss(e){if(!Array.isArray(e)||e.length!==jt.length)return null;let n=new Set(e);if(n.size!==e.length)return null;for(let a of jt)if(!n.has(a))return null;return e.slice()}function Ca(e){try{let n=e?.getItem(Ha);return n?Ss(JSON.parse(n))??[...jt]:[...jt]}catch{return[...jt]}}function On(e,n){try{e?.setItem(Ha,JSON.stringify(n))}catch{}}function Aa(e,n){try{e?.setItem(Ia,n)}catch{}}var Da="botmux.dashboard.sessions.kanbanGroupBy",Nn="botmux.dashboard.sessions.kanbanTeam";function Ls(e){return e==="flow"||e==="team"||e==="bot"?e:null}function Ra(e){return Ls(e?.getItem(Da))??"flow"}function Pa(e,n){try{e?.setItem(Da,n)}catch{}}var Ba="botmux.dashboard.sidebar";function Ts(e){return e==="expanded"||e==="collapsed"?e:null}function Oa(e){return Ts(e?.getItem(Ba))??"expanded"}function Na(e,n){try{e?.setItem(Ba,n)}catch{}}var Is=["default","cyber","genshin","fallout","prts","bluearchive","zzz","dragonball","ikun"],qn="botmux.dashboard.skin";function Ms(e){return typeof e=="string"&&Is.includes(e)?e:null}function qa(e){return Ms(e?.getItem(qn))??"default"}var Es="\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF830123456789\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E$#%&@*+=<>/\\",ja=["186 100% 60%","56 97% 60%","330 100% 64%","150 80% 58%"],Un=[{key:"shake",dur:280},{key:"rgb",dur:340},{key:"tear",dur:400},{key:"invert",dur:220},{key:"slice",dur:320},{key:"blackout",dur:260}],Ua=["ESTABLISHING NETLINK","BYPASSING ICE","DECRYPTING DATAFLOW","SYNCING BOTMUX TELEMETRY","ACCESS GRANTED"],Fa="0123456789ABCDEF#<>*/=+\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C",xs=3200,Ut=[],Et=0,on=0;function _n(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Fn(e,n){let a="";for(let s=0;s<e;s++)a+=n[Math.floor(Math.random()*n.length)];return a}function Hs(e){let n=document.createElement("div");n.className="cyber-rain";let a=Math.max(10,Math.min(26,Math.round(window.innerWidth/70)));for(let s=0;s<a;s++){let o=document.createElement("span");o.className="cyber-rain-col",o.textContent=Fn(28+Math.floor(Math.random()*22),Es);let r=ja[Math.floor(Math.random()*ja.length)];o.style.cssText=`left:${(s+.5)/a*100}%;--rc:${r};--sz:${10+Math.floor(Math.random()*9)}px;--op:${(.25+Math.random()*.45).toFixed(2)};--dur:${(6+Math.random()*9).toFixed(1)}s;--delay:${(-Math.random()*12).toFixed(1)}s;`,n.appendChild(o)}e.appendChild(n)}function Cs(){if(_n())return;let e=document.body,n=()=>{let a=Un[Math.floor(Math.random()*Un.length)],s=`cp-fx-${a.key}`;e.classList.add(s),Ut.push(window.setTimeout(()=>e.classList.remove(s),a.dur)),Ut.push(window.setTimeout(n,2400+Math.random()*4200))};Ut.push(window.setTimeout(n,1800+Math.random()*2600))}function As(){Ut.forEach(e=>window.clearTimeout(e)),Ut=[];for(let e of Un)document.body.classList.remove(`cp-fx-${e.key}`)}function Ds(){if(_n()||document.getElementById("cyber-boot"))return;let e=document.createElement("div");e.id="cyber-boot",e.className="cyber-boot",e.setAttribute("aria-hidden","true"),e.innerHTML='<div class="cyber-boot-grid"></div><div class="cyber-loader"><div class="cyber-loader-frame"><div class="cyber-loader-head"><span>KIROSHI NETLINK</span><span class="cyber-loader-jp">\u4FB5\u5165\u4E2D</span></div><div class="cyber-loader-line"><span class="cyber-loader-prompt">></span><span class="cyber-loader-text"></span><span class="cyber-loader-cursor">_</span></div><div class="cyber-loader-stream"></div></div></div>',document.body.appendChild(e);let n=e.querySelector(".cyber-loader-text"),a=e.querySelector(".cyber-loader-stream"),s=0,o=0,r=0;Et=window.setInterval(()=>{let d=Ua[s];n&&(o<d.length?(o+=1,n.textContent=d.slice(0,o)+Fn(d.length-o,Fa),n.classList.remove("done")):r<16?(r+=1,n.textContent=d,n.classList.add("done")):(s=(s+1)%Ua.length,o=0,r=0)),a&&(a.textContent=Fn(26,Fa))},50),on=window.setTimeout(()=>{window.clearInterval(Et),Et=0,e.remove()},xs)}function Rs(){Et&&(window.clearInterval(Et),Et=0),on&&(window.clearTimeout(on),on=0),document.getElementById("cyber-boot")?.remove()}var Ps=320,Ga=16,Ft=!0,Mt=0,jn=0,sn=!1,rn=[],Gn=[];function Bs(){if(sn)return;sn=!0,Ft=!1,Mt=0;let e=_n(),n="";for(let s=0;s<Ga;s++){let o=s%3===0?"186 100% 52%":s%3===1?"330 100% 58%":"56 97% 52%",r=(s%2===0?1:-1)*(8+s%5*7);n+=`<span class="cyber-breach-shard" style="top:${s/Ga*100}%;height:${2+s%4*3}%;--shift:${r}px;--delay:${s%8*.09}s;--dur:${(.36+s%5*.12).toFixed(2)}s;--hue:${o}"></span>`}let a=document.createElement("div");a.id="cyber-breach",a.className="cyber-breach",a.setAttribute("aria-hidden","true"),a.innerHTML=`<span class="cyber-breach-flash"></span><span class="cyber-breach-grid"></span><div class="cyber-breach-shards">${n}</div><div class="cyber-breach-banner"><span class="cyber-breach-tag">// BREACH PROTOCOL \u2014 SYSTEM OVERRIDE</span><span class="cyber-breach-caption" data-text="SYSTEM BREACH">SYSTEM BREACH</span><span class="cyber-breach-sub" data-text="NETWATCH OVERRIDE ENGAGED">NETWATCH OVERRIDE ENGAGED</span></div>`,document.body.appendChild(a),e||document.body.classList.add("cyber-breach-quake"),rn.push(window.setTimeout(()=>document.body.classList.remove("cyber-breach-quake"),760)),rn.push(window.setTimeout(()=>{a.remove(),sn=!1},e?2600:4200))}function Os(){Ft=!0,Mt=0;let e=document.documentElement,n=()=>e.scrollHeight-(window.innerHeight+window.scrollY)<=4,a=k=>{k<=0||!n()||(Mt+=k,Mt>Ps&&Ft&&Bs())},s=k=>a(k.deltaY),o=k=>{jn=k.touches[0]?.clientY??0},r=k=>{let $=k.touches[0]?.clientY??0,M=jn-$;jn=$,a(M)},d=()=>{n()||(Mt=0,Ft=!0)},m=(k,$)=>{window.addEventListener(k,$,{passive:!0}),Gn.push([k,$])};m("wheel",s),m("touchstart",o),m("touchmove",r),m("scroll",d)}function Ns(){for(let[e,n]of Gn)window.removeEventListener(e,n);Gn=[],rn.forEach(e=>window.clearTimeout(e)),rn=[],document.body.classList.remove("cyber-breach-quake"),document.getElementById("cyber-breach")?.remove(),sn=!1,Ft=!0,Mt=0}function _a(e,n=!1){if(!(typeof document>"u")){if(!e){document.getElementById("cyber-fx")?.remove(),document.getElementById("cyber-hud")?.remove(),document.getElementById("cyber-glitch")?.remove(),As(),Rs(),Ns();return}if(!document.getElementById("cyber-fx")){let a=document.createElement("div");a.id="cyber-fx",a.className="cyber-fx",a.setAttribute("aria-hidden","true"),a.innerHTML='<div class="cyber-fx-grid"></div><div class="cyber-fx-scan"></div><span class="cyber-flicker"></span><span class="cyber-rollline"></span>',Hs(a),document.body.appendChild(a);let s=document.createElement("div");s.id="cyber-hud",s.className="cyber-hud",s.setAttribute("aria-hidden","true"),s.innerHTML='<span class="cyber-hud-corner tl"></span><span class="cyber-hud-corner tr"></span><span class="cyber-hud-corner bl"></span><span class="cyber-hud-corner br"></span><span class="cyber-hud-tag">NIGHT CITY // NETWATCH</span>',document.body.appendChild(s);let o=document.createElement("div");o.id="cyber-glitch",o.className="cyber-glitch",o.setAttribute("aria-hidden","true"),document.body.appendChild(o),Cs(),Os()}n&&Ds()}}var qs={genshin:2e3,zzz:1900,dragonball:1900,ikun:1900},js='<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 Us(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 js;default:return""}}function Fs(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function za(e){if(typeof document>"u"||Fs())return;let n=qs[e];if(!n)return;document.getElementById("skin-intro")?.remove();let a=document.createElement("div");a.id="skin-intro",a.className=`skin-intro si-${e}`,a.setAttribute("aria-hidden","true"),a.style.setProperty("--si-dur",`${n}ms`),a.innerHTML=Us(e),document.body.appendChild(a),window.setTimeout(()=>a.remove(),n+80)}var Wn=class{locale="zh";themeMode="system";resolvedTheme="light";skin="default";authed=!0;listeners=new Set;translate=an(this.locale);mediaQuery=null;init(){let n=typeof window<"u"?window:void 0;this.locale=Ta(n?.localStorage,_s()),this.translate=an(this.locale),this.themeMode=Ea(n?.localStorage),this.skin=qa(n?.localStorage),this.mediaQuery=n?.matchMedia?.("(prefers-color-scheme: dark)")??null,this.mediaQuery?.addEventListener("change",()=>{this.applyTheme(),this.emit()}),this.applyTheme(),this.applySkin(),this.applyLocale()}t(n,a){return this.translate(n,a)}setLocale(n){this.locale!==n&&(this.locale=n,this.translate=an(n),window.localStorage.setItem(Rn,n),this.applyLocale(),this.emit())}get theme(){return this.skin==="default"?this.themeMode:this.skin}setTheme(n){let a=n==="system"||n==="light"||n==="dark",s=a?"default":n,o=s!==this.skin;a&&this.themeMode!==n&&(this.themeMode=n,window.localStorage.setItem(Pn,this.themeMode)),o&&(this.skin=s,window.localStorage.setItem(qn,this.skin)),this.applyTheme(),this.applySkin(o),this.emit()}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}applyTheme(){this.resolvedTheme=Ma(this.themeMode,!!this.mediaQuery?.matches);let n=this.skin==="default"?this.resolvedTheme:Gs[this.skin];document.documentElement.dataset.theme=n,document.documentElement.dataset.themeMode=this.themeMode}applySkin(n=!1){document.documentElement.dataset.skin=this.skin,_a(this.skin==="cyber",n),n&&this.skin!=="cyber"&&this.skin!=="default"&&za(this.skin)}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}},Gs={default:"light",cyber:"dark",genshin:"light",fallout:"dark",prts:"dark",bluearchive:"dark",zzz:"dark",dragonball:"light",ikun:"dark"};function _s(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var Te=new Wn;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 Wa=[{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 Ka(e){let n=0,a=String(e??"");for(let r=0;r<a.length;r++)n=n*31+a.charCodeAt(r)>>>0;let{c1:s,c2:o}=Wa[n%Wa.length];return`--c1:${s};--c2:${o}`}var ln=new Map,dn=new Map;function zs(e,n){return n?ln.get(n):e?dn.get(String(e)):void 0}function ue(e){let n=e.name??"",a=e.avatarUrl??zs(e.name,e.larkAppId),s=e.size==="sm"?" orb-avatar-sm":"",o=a?" orb-has-img":"",r=e.dot?`<i class="orb-dot orb-dot-${e.dot}"></i>`:"",d=a?`<img class="orb-img" src="${i(a)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar${s}${o}" style="${Ka(n)}" aria-hidden="true">${d}${r}</span>`}function Ws(e){return e?pn.get(e):void 0}function cn(e){let n=e.name??e.chatId??"",a=e.avatarUrl??Ws(e.chatId),s=e.size==="sm"?" orb-avatar-sm":"",o=a?" orb-has-img":"",r=a?`<img class="orb-img" src="${i(a)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar orb-square${s}${o}" style="${Ka(n)}" aria-hidden="true">${r}</span>`}var Gt=new Map,un=new Map,pn=new Map,zn=null,Ja="botmux.avatarCache.v1";function Ks(){try{let e=typeof window<"u"?window.localStorage.getItem(Ja):null;if(!e)return;let n=JSON.parse(e);for(let[a,s]of Object.entries(n.botByAppId??{}))ln.set(a,s);for(let[a,s]of Object.entries(n.botByName??{}))dn.set(a,s);for(let[a,s]of Object.entries(n.chatById??{}))pn.set(a,s);for(let[a,s]of Object.entries(n.nameByAppId??{}))Gt.set(a,s);for(let[a,s]of Object.entries(n.chatNameById??{}))un.set(a,s)}catch{}}function Js(){try{if(typeof window>"u")return;window.localStorage.setItem(Ja,JSON.stringify({botByAppId:Object.fromEntries(ln),botByName:Object.fromEntries(dn),chatById:Object.fromEntries(pn),nameByAppId:Object.fromEntries(Gt),chatNameById:Object.fromEntries(un)}))}catch{}}Ks();function Ke(){return zn??=(async()=>{try{let e=await fetch("/api/groups");if(!e.ok)throw new Error(`HTTP ${e.status}`);let n=await e.json();for(let a of n.bots??[])a.larkAppId&&a.botName&&a.botName!==a.larkAppId&&Gt.set(a.larkAppId,String(a.botName)),a.botAvatarUrl&&(a.larkAppId&&ln.set(a.larkAppId,String(a.botAvatarUrl)),a.botName&&dn.set(String(a.botName),String(a.botAvatarUrl)));for(let a of n.chats??[])a.chatId&&a.name&&un.set(a.chatId,String(a.name)),a.chatId&&a.avatar&&pn.set(a.chatId,String(a.avatar));Js()}catch{zn=null}})(),zn}function Va(e){return e?Gt.get(e):void 0}function ke(e){let n=e.larkAppId?Gt.get(e.larkAppId):void 0;return n||(e.botName&&e.botName!==e.larkAppId?String(e.botName):String(e.botName??e.larkAppId??"-"))}function lt(e){return e.chatId&&un.get(e.chatId)||null}function $e(e){let n=String(e??"");return n.replace(/^(?:@\S+\s*)+/,"").trim()||n}function dt(e){return`<div class="page-loading" role="status"><i class="page-loading-spin" aria-hidden="true"></i>${i(e??t("common.loading"))}</div>`}function ct(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 Ce(e){let n=Number(e.agentAttention?.at??e.lastMessageAt??0);if(Number.isFinite(n))return n;let a=Number(e.lastMessageAt??0);return Number.isFinite(a)?a:0}var Xa={chats:[],bots:[]};async function Vs(){try{let e=await fetch("/api/groups");if(!e.ok)return;Xa=await e.json()}catch{}}var Kn=new Set(["working","analyzing","active","starting"]);function Ys(e){let n=new Map,a=o=>{let r=n.get(o);return r||(r={botName:o,larkAppId:o,cliId:"unknown",online:!1,sessions:[],active:[],busy:[],attention:[],lastActiveAt:0},n.set(o,r)),r};for(let o of Xa.bots??[]){let r=a(o.larkAppId??o.botName??"-");r.online=!0,o.botName&&(r.botName=o.botName),o.botAvatarUrl&&(r.botAvatarUrl=o.botAvatarUrl)}let s=[...e].sort((o,r)=>+(o.status==="closed")-+(r.status==="closed"));for(let o of s){let r=o.larkAppId??o.botName??"-";if(o.status==="closed"&&!n.has(r))continue;let d=a(r);o.botName&&(d.botName===d.larkAppId||!d.botName)&&(d.botName=o.botName),d.sessions.push(o),o.cliId&&d.cliId==="unknown"&&(d.cliId=o.cliId),d.lastActiveAt=Math.max(d.lastActiveAt,Number(o.lastMessageAt??0)),o.status!=="closed"&&(d.active.push(o),Kn.has(o.status)&&d.busy.push(o),ct(o)&&d.attention.push(o))}for(let o of n.values())if(o.botName===o.larkAppId){let r=Va(o.larkAppId);r&&(o.botName=r)}return[...n.values()].sort((o,r)=>{let d=m=>m.attention.length?0:m.busy.length?1:m.online||m.active.length?2:3;return d(o)!==d(r)?d(o)-d(r):r.lastActiveAt-o.lastActiveAt})}var Za="botmux.overview.teamExpanded",Qs=230,Ya=13,Qa=2;function Xs(e){let n=e.clientWidth;return n?Math.max(1,Math.floor((n+Ya)/(Qs+Ya)))*Qa:Qa*3}function Zs(){try{return window.localStorage.getItem(Za)==="1"}catch{return!1}}function ei(e){try{window.localStorage.setItem(Za,e?"1":"0")}catch{}}function ti(e){let n=!e.online&&e.active.length===0,a=e.attention.length>0,s=e.busy.length>0,o=a?"warn":s?"busy":n?"off":"ok",r;if(a){let m=[...e.attention].sort((k,$)=>Ce(k)-Ce($))[0];r=`<b>${i(($e(m.title)||m.sessionId).slice(0,60))}</b> \xB7 ${i(ct(m)??"")}`}else if(s){let m=[...e.busy].sort((k,$)=>Number($.lastMessageAt??0)-Number(k.lastMessageAt??0))[0];r=`<b>${i(($e(m.title)||m.sessionId).slice(0,60))}</b>`}else n?r=i(t("overview.botOffline")):r=i(t("overview.botIdle"));let d=a?`<span class="tag tag-warn">${i(t("overview.botNeedsYou"))}</span>`:s?`<span class="tag tag-run">${i(t("overview.botBusy",{count:e.busy.length}))}</span>`:n?`<span class="tag tag-off">${i(t("overview.botOff"))}</span>`:`<span class="tag tag-ok">${i(t("overview.botReady"))}</span>`;return`<article class="mate${a?" mate-attn":""}${n?" mate-off":""}">
|
|
19
|
+
}`,"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"},To={zh:vs,en:ks};function nn(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 $s(e=[]){for(let n of e){let o=nn(n);if(o)return o}return"zh"}function on(e){return(n,o)=>{let a=To[e][n]??To.zh[n]??n;return o?a.replace(/\{(\w+)\}/g,(s,r)=>{let d=o[r];return d==null?`{${r}}`:String(d)}):a}}function Io(e,n){return(e?nn(e.getItem(Rn)):null)??$s(n)}var On="botmux.dashboard.theme",Mo="botmux.dashboard.sessions.view";function Ss(e){return e==="system"||e==="light"||e==="dark"?e:null}function Pn(e){return e==="kanban"||e==="board"||e==="table"?e:null}function Eo(e,n){return e==="system"?n?"dark":"light":e}function xo(e){return Ss(e?.getItem(On))??"dark"}function Ho(e){return Pn(e?.getItem(Mo))??"board"}var Co="botmux.dashboard.sessions.boardOrder",Ut=["needs-you","starting","working","idle"];function Ls(e){if(!Array.isArray(e)||e.length!==Ut.length)return null;let n=new Set(e);if(n.size!==e.length)return null;for(let o of Ut)if(!n.has(o))return null;return e.slice()}function Ao(e){try{let n=e?.getItem(Co);return n?Ls(JSON.parse(n))??[...Ut]:[...Ut]}catch{return[...Ut]}}function Bn(e,n){try{e?.setItem(Co,JSON.stringify(n))}catch{}}function Do(e,n){try{e?.setItem(Mo,n)}catch{}}var Ro="botmux.dashboard.sessions.kanbanGroupBy",Nn="botmux.dashboard.sessions.kanbanTeam";function Ts(e){return e==="flow"||e==="team"||e==="bot"?e:null}function Oo(e){return Ts(e?.getItem(Ro))??"flow"}function Po(e,n){try{e?.setItem(Ro,n)}catch{}}var Bo="botmux.dashboard.sidebar";function Is(e){return e==="expanded"||e==="collapsed"?e:null}function No(e){return Is(e?.getItem(Bo))??"expanded"}function qo(e,n){try{e?.setItem(Bo,n)}catch{}}var Ms=["default","cyber","genshin","fallout","prts","bluearchive","zzz","dragonball","ikun"],qn="botmux.dashboard.skin";function Es(e){return typeof e=="string"&&Ms.includes(e)?e:null}function jo(e){return Es(e?.getItem(qn))??"default"}var xs="\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF830123456789\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E$#%&@*+=<>/\\",Uo=["186 100% 60%","56 97% 60%","330 100% 64%","150 80% 58%"],Un=[{key:"shake",dur:280},{key:"rgb",dur:340},{key:"tear",dur:400},{key:"invert",dur:220},{key:"slice",dur:320},{key:"blackout",dur:260}],Fo=["ESTABLISHING NETLINK","BYPASSING ICE","DECRYPTING DATAFLOW","SYNCING BOTMUX TELEMETRY","ACCESS GRANTED"],Go="0123456789ABCDEF#<>*/=+\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C",Hs=3200,Ft=[],xt=0,an=0;function _n(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Fn(e,n){let o="";for(let a=0;a<e;a++)o+=n[Math.floor(Math.random()*n.length)];return o}function Cs(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 a=0;a<o;a++){let s=document.createElement("span");s.className="cyber-rain-col",s.textContent=Fn(28+Math.floor(Math.random()*22),xs);let r=Uo[Math.floor(Math.random()*Uo.length)];s.style.cssText=`left:${(a+.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(s)}e.appendChild(n)}function As(){if(_n())return;let e=document.body,n=()=>{let o=Un[Math.floor(Math.random()*Un.length)],a=`cp-fx-${o.key}`;e.classList.add(a),Ft.push(window.setTimeout(()=>e.classList.remove(a),o.dur)),Ft.push(window.setTimeout(n,2400+Math.random()*4200))};Ft.push(window.setTimeout(n,1800+Math.random()*2600))}function Ds(){Ft.forEach(e=>window.clearTimeout(e)),Ft=[];for(let e of Un)document.body.classList.remove(`cp-fx-${e.key}`)}function Rs(){if(_n()||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"),a=0,s=0,r=0;xt=window.setInterval(()=>{let d=Fo[a];n&&(s<d.length?(s+=1,n.textContent=d.slice(0,s)+Fn(d.length-s,Go),n.classList.remove("done")):r<16?(r+=1,n.textContent=d,n.classList.add("done")):(a=(a+1)%Fo.length,s=0,r=0)),o&&(o.textContent=Fn(26,Go))},50),an=window.setTimeout(()=>{window.clearInterval(xt),xt=0,e.remove()},Hs)}function Os(){xt&&(window.clearInterval(xt),xt=0),an&&(window.clearTimeout(an),an=0),document.getElementById("cyber-boot")?.remove()}var Ps=320,_o=16,Gt=!0,Et=0,jn=0,sn=!1,rn=[],Gn=[];function Bs(){if(sn)return;sn=!0,Gt=!1,Et=0;let e=_n(),n="";for(let a=0;a<_o;a++){let s=a%3===0?"186 100% 52%":a%3===1?"330 100% 58%":"56 97% 52%",r=(a%2===0?1:-1)*(8+a%5*7);n+=`<span class="cyber-breach-shard" style="top:${a/_o*100}%;height:${2+a%4*3}%;--shift:${r}px;--delay:${a%8*.09}s;--dur:${(.36+a%5*.12).toFixed(2)}s;--hue:${s}"></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"),rn.push(window.setTimeout(()=>document.body.classList.remove("cyber-breach-quake"),760)),rn.push(window.setTimeout(()=>{o.remove(),sn=!1},e?2600:4200))}function Ns(){Gt=!0,Et=0;let e=document.documentElement,n=()=>e.scrollHeight-(window.innerHeight+window.scrollY)<=4,o=k=>{k<=0||!n()||(Et+=k,Et>Ps&&Gt&&Bs())},a=k=>o(k.deltaY),s=k=>{jn=k.touches[0]?.clientY??0},r=k=>{let $=k.touches[0]?.clientY??0,M=jn-$;jn=$,o(M)},d=()=>{n()||(Et=0,Gt=!0)},m=(k,$)=>{window.addEventListener(k,$,{passive:!0}),Gn.push([k,$])};m("wheel",a),m("touchstart",s),m("touchmove",r),m("scroll",d)}function qs(){for(let[e,n]of Gn)window.removeEventListener(e,n);Gn=[],rn.forEach(e=>window.clearTimeout(e)),rn=[],document.body.classList.remove("cyber-breach-quake"),document.getElementById("cyber-breach")?.remove(),sn=!1,Gt=!0,Et=0}function zo(e,n=!1){if(!(typeof document>"u")){if(!e){document.getElementById("cyber-fx")?.remove(),document.getElementById("cyber-hud")?.remove(),document.getElementById("cyber-glitch")?.remove(),Ds(),Os(),qs();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>',Cs(o),document.body.appendChild(o);let a=document.createElement("div");a.id="cyber-hud",a.className="cyber-hud",a.setAttribute("aria-hidden","true"),a.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(a);let s=document.createElement("div");s.id="cyber-glitch",s.className="cyber-glitch",s.setAttribute("aria-hidden","true"),document.body.appendChild(s),As(),Ns()}n&&Rs()}}var js={genshin:2e3,zzz:1900,dragonball:1900,ikun:1900},Us='<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 Fs(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 Us;default:return""}}function Gs(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Wo(e){if(typeof document>"u"||Gs())return;let n=js[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=Fs(e),document.body.appendChild(o),window.setTimeout(()=>o.remove(),n+80)}var Wn=class{locale="zh";themeMode="system";resolvedTheme="light";skin="default";authed=!0;listeners=new Set;translate=on(this.locale);mediaQuery=null;init(){let n=typeof window<"u"?window:void 0;this.locale=Io(n?.localStorage,zs()),this.translate=on(this.locale),this.themeMode=xo(n?.localStorage),this.skin=jo(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=on(n),window.localStorage.setItem(Rn,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",a=o?"default":n,s=a!==this.skin;o&&this.themeMode!==n&&(this.themeMode=n,window.localStorage.setItem(On,this.themeMode)),s&&(this.skin=a,window.localStorage.setItem(qn,this.skin)),this.applyTheme(),this.applySkin(s),this.emit()}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}applyTheme(){this.resolvedTheme=Eo(this.themeMode,!!this.mediaQuery?.matches);let n=this.skin==="default"?this.resolvedTheme:_s[this.skin];document.documentElement.dataset.theme=n,document.documentElement.dataset.themeMode=this.themeMode}applySkin(n=!1){document.documentElement.dataset.skin=this.skin,zo(this.skin==="cyber",n),n&&this.skin!=="cyber"&&this.skin!=="default"&&Wo(this.skin)}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}},_s={default:"light",cyber:"dark",genshin:"light",fallout:"dark",prts:"dark",bluearchive:"dark",zzz:"dark",dragonball:"light",ikun:"dark"};function zs(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var Te=new Wn;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 Ko=[{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 Jo(e){let n=0,o=String(e??"");for(let r=0;r<o.length;r++)n=n*31+o.charCodeAt(r)>>>0;let{c1:a,c2:s}=Ko[n%Ko.length];return`--c1:${a};--c2:${s}`}var ln=new Map,dn=new Map;function Ws(e,n){return n?ln.get(n):e?dn.get(String(e)):void 0}function ue(e){let n=e.name??"",o=e.avatarUrl??Ws(e.name,e.larkAppId),a=e.size==="sm"?" orb-avatar-sm":"",s=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${a}${s}" style="${Jo(n)}" aria-hidden="true">${d}${r}</span>`}function Ks(e){return e?pn.get(e):void 0}function cn(e){let n=e.name??e.chatId??"",o=e.avatarUrl??Ks(e.chatId),a=e.size==="sm"?" orb-avatar-sm":"",s=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${a}${s}" style="${Jo(n)}" aria-hidden="true">${r}</span>`}var _t=new Map,un=new Map,pn=new Map,zn=null,Vo="botmux.avatarCache.v1";function Js(){try{let e=typeof window<"u"?window.localStorage.getItem(Vo):null;if(!e)return;let n=JSON.parse(e);for(let[o,a]of Object.entries(n.botByAppId??{}))ln.set(o,a);for(let[o,a]of Object.entries(n.botByName??{}))dn.set(o,a);for(let[o,a]of Object.entries(n.chatById??{}))pn.set(o,a);for(let[o,a]of Object.entries(n.nameByAppId??{}))_t.set(o,a);for(let[o,a]of Object.entries(n.chatNameById??{}))un.set(o,a)}catch{}}function Vs(){try{if(typeof window>"u")return;window.localStorage.setItem(Vo,JSON.stringify({botByAppId:Object.fromEntries(ln),botByName:Object.fromEntries(dn),chatById:Object.fromEntries(pn),nameByAppId:Object.fromEntries(_t),chatNameById:Object.fromEntries(un)}))}catch{}}Js();function Ke(){return zn??=(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&&_t.set(o.larkAppId,String(o.botName)),o.botAvatarUrl&&(o.larkAppId&&ln.set(o.larkAppId,String(o.botAvatarUrl)),o.botName&&dn.set(String(o.botName),String(o.botAvatarUrl)));for(let o of n.chats??[])o.chatId&&o.name&&un.set(o.chatId,String(o.name)),o.chatId&&o.avatar&&pn.set(o.chatId,String(o.avatar));Vs()}catch{zn=null}})(),zn}function Yo(e){return e?_t.get(e):void 0}function ke(e){let n=e.larkAppId?_t.get(e.larkAppId):void 0;return n||(e.botName&&e.botName!==e.larkAppId?String(e.botName):String(e.botName??e.larkAppId??"-"))}function dt(e){return e.chatId&&un.get(e.chatId)||null}function $e(e){let n=String(e??"");return n.replace(/^(?:@\S+\s*)+/,"").trim()||n}function ct(e){return`<div class="page-loading" role="status"><i class="page-loading-spin" aria-hidden="true"></i>${i(e??t("common.loading"))}</div>`}function ut(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 Ce(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 Zo={chats:[],bots:[]};async function Ys(){try{let e=await fetch("/api/groups");if(!e.ok)return;Zo=await e.json()}catch{}}var Kn=new Set(["working","analyzing","active","starting"]);function Qs(e){let n=new Map,o=s=>{let r=n.get(s);return r||(r={botName:s,larkAppId:s,cliId:"unknown",online:!1,sessions:[],active:[],busy:[],attention:[],lastActiveAt:0},n.set(s,r)),r};for(let s of Zo.bots??[]){let r=o(s.larkAppId??s.botName??"-");r.online=!0,s.botName&&(r.botName=s.botName),s.botAvatarUrl&&(r.botAvatarUrl=s.botAvatarUrl),s.cliId&&(r.cliId=s.cliId)}let a=[...e].sort((s,r)=>+(s.status==="closed")-+(r.status==="closed"));for(let s of a){let r=s.larkAppId??s.botName??"-";if(s.status==="closed"&&!n.has(r))continue;let d=o(r);s.botName&&(d.botName===d.larkAppId||!d.botName)&&(d.botName=s.botName),d.sessions.push(s),s.cliId&&d.cliId==="unknown"&&(d.cliId=s.cliId),d.lastActiveAt=Math.max(d.lastActiveAt,Number(s.lastMessageAt??0)),s.status!=="closed"&&(d.active.push(s),Kn.has(s.status)&&d.busy.push(s),ut(s)&&d.attention.push(s))}for(let s of n.values())if(s.botName===s.larkAppId){let r=Yo(s.larkAppId);r&&(s.botName=r)}return[...n.values()].sort((s,r)=>{let d=m=>m.attention.length?0:m.busy.length?1:m.online||m.active.length?2:3;return d(s)!==d(r)?d(s)-d(r):r.lastActiveAt-s.lastActiveAt})}var ea="botmux.overview.teamExpanded",Xs=230,Qo=13,Xo=2;function Zs(e){let n=e.clientWidth;return n?Math.max(1,Math.floor((n+Qo)/(Xs+Qo)))*Xo:Xo*3}function ei(){try{return window.localStorage.getItem(ea)==="1"}catch{return!1}}function ti(e){try{window.localStorage.setItem(ea,e?"1":"0")}catch{}}function ni(e){let n=!e.online&&e.active.length===0,o=e.attention.length>0,a=e.busy.length>0,s=o?"warn":a?"busy":n?"off":"ok",r;if(o){let m=[...e.attention].sort((k,$)=>Ce(k)-Ce($))[0];r=`<b>${i(($e(m.title)||m.sessionId).slice(0,60))}</b> \xB7 ${i(ut(m)??"")}`}else if(a){let m=[...e.busy].sort((k,$)=>Number($.lastMessageAt??0)-Number(k.lastMessageAt??0))[0];r=`<b>${i(($e(m.title)||m.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>`:a?`<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":""}">
|
|
20
20
|
<div class="mate-top">
|
|
21
|
-
${ue({name:e.botName,larkAppId:e.larkAppId,avatarUrl:e.botAvatarUrl,dot:
|
|
21
|
+
${ue({name:e.botName,larkAppId:e.larkAppId,avatarUrl:e.botAvatarUrl,dot:s})}
|
|
22
22
|
<div class="mate-id">
|
|
23
23
|
<b>${i(e.botName)}</b>
|
|
24
24
|
<span class="mate-role">${i(e.cliId)}</span>
|
|
@@ -29,31 +29,31 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
29
29
|
${d}
|
|
30
30
|
<span>${e.lastActiveAt?i(t("overview.lastActive",{time:qe(e.lastActiveAt)})):i(t("common.never"))}</span>
|
|
31
31
|
</div>
|
|
32
|
-
</article>`}function
|
|
32
|
+
</article>`}function oi(e){let n=ke(e);return`<article class="qcard" data-id="${i(e.sessionId)}">
|
|
33
33
|
${ue({name:n,larkAppId:e.larkAppId,size:"sm"})}
|
|
34
34
|
<div class="qcard-tx">
|
|
35
35
|
<b>${i(n)} \xB7 ${i(($e(e.title)||e.sessionId).slice(0,56))}</b>
|
|
36
|
-
<span>${i(
|
|
36
|
+
<span>${i(ut(e)??"")} \xB7 ${qe(Ce(e))}</span>
|
|
37
37
|
</div>
|
|
38
38
|
<a class="qcard-go" href="#/sessions">${i(t("strip.handle"))}</a>
|
|
39
39
|
</article>`}function ai(e){let n=ke(e);return`<li class="sess-row">
|
|
40
40
|
${ue({name:n,larkAppId:e.larkAppId,size:"sm"})}
|
|
41
41
|
<div class="sess-tx">
|
|
42
42
|
<b>${i(($e(e.title)||e.sessionId).slice(0,64))}</b>
|
|
43
|
-
<span>${i(n)} \xB7 ${i(
|
|
43
|
+
<span>${i(n)} \xB7 ${i(dt(e)??e.cliId??"unknown")} \xB7 ${qe(e.lastMessageAt)}</span>
|
|
44
44
|
</div>
|
|
45
45
|
<span class="status status-${i(e.status??"unknown")}">${i(e.status??"unknown")}</span>
|
|
46
|
-
</li>`}function
|
|
46
|
+
</li>`}function si(e){let n=e.nextRunAt?new Date(e.nextRunAt).toLocaleString():"-";return`<li class="overview-list-row">
|
|
47
47
|
<div>
|
|
48
48
|
<strong>${i(e.name??e.id)}</strong>
|
|
49
49
|
<span>${i(ke(e))} \xB7 ${i(e.parsed?.display??"")}</span>
|
|
50
50
|
</div>
|
|
51
51
|
<span>${i(n)}</span>
|
|
52
|
-
</li>`}function
|
|
53
|
-
<div class="donut-center"><b>0</b><span>${i(t("overview.openSessions"))}</span></div></div>`;let
|
|
54
|
-
<div class="donut" style="background:conic-gradient(var(--accent) 0 ${
|
|
55
|
-
<div class="donut-center"><b>${
|
|
56
|
-
</div>`}async function
|
|
52
|
+
</li>`}function ii(e,n,o){let a=e+n+o;if(a===0)return`<div class="donut-wrap"><div class="donut" style="background:conic-gradient(var(--border) 0 360deg)"></div>
|
|
53
|
+
<div class="donut-center"><b>0</b><span>${i(t("overview.openSessions"))}</span></div></div>`;let s=e/a*360,r=s+n/a*360;return`<div class="donut-wrap">
|
|
54
|
+
<div class="donut" style="background:conic-gradient(var(--accent) 0 ${s}deg, var(--warning) ${s}deg ${r}deg, var(--success) ${r}deg 360deg)"></div>
|
|
55
|
+
<div class="donut-center"><b>${a}</b><span>${i(t("overview.openSessions"))}</span></div>
|
|
56
|
+
</div>`}async function ta(e){e.innerHTML=`<section class="page hero-page">
|
|
57
57
|
<div class="page-heading">
|
|
58
58
|
<div>
|
|
59
59
|
<p class="eyebrow">${t("app.subtitle")}</p>
|
|
@@ -108,25 +108,25 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
108
108
|
</section>
|
|
109
109
|
</div>
|
|
110
110
|
</div>
|
|
111
|
-
</section>`;let n=e.querySelector("#overview-pills"),
|
|
111
|
+
</section>`;let n=e.querySelector("#overview-pills"),o=e.querySelector("#team-grid"),a=e.querySelector("#team-toggle"),s=ei();a.onclick=()=>{s=!s,ti(s),$()};let r=e.querySelector("#attention-list"),d=e.querySelector("#recent-sessions"),m=e.querySelector("#today-donut"),k=e.querySelector("#next-schedules");function $(){let w=[...Y.sessions.values()],p=w.filter(y=>y.status!=="closed"),S=p.filter(y=>ut(y)).sort((y,A)=>Ce(y)-Ce(A)),E=p.filter(y=>Kn.has(y.status)&&!ut(y)),C=p.length-S.length-E.length,L=Qs(w),x=L.filter(y=>y.online||y.active.length>0).length;n.innerHTML=`
|
|
112
112
|
<span class="pill">${i(t("overview.workingSessions"))} <b>${E.length}</b></span>
|
|
113
113
|
<span class="pill${S.length?" pill-hot":""}">${i(t("overview.attention"))} <b>${S.length}</b></span>
|
|
114
|
-
<span class="pill">${i(t("overview.onlineBots"))} <b>${x}</b></span>`;let T=
|
|
114
|
+
<span class="pill">${i(t("overview.onlineBots"))} <b>${x}</b></span>`;let T=Zs(o),R=s?L:L.slice(0,T);o.innerHTML=R.length?R.map(ni).join(""):`<div class="empty">${t("overview.noSessions")}</div>`,L.length>T?(a.hidden=!1,a.textContent=s?t("overview.teamCollapse"):t("overview.teamExpand",{count:L.length})):a.hidden=!0,r.innerHTML=S.length?S.map(oi).join(""):`<div class="qcard qcard-empty">${t("overview.noAttention")}</div>`;let q=p.filter(y=>Kn.has(y.status)||y.status==="idle").sort((y,A)=>Number(A.lastMessageAt??0)-Number(y.lastMessageAt??0)).slice(0,7);d.innerHTML=q.length?q.map(ai).join(""):`<li class="empty">${t("overview.noSessions")}</li>`,m.innerHTML=`${ii(E.length,S.length,Math.max(0,C))}
|
|
115
115
|
<div class="donut-legend">
|
|
116
116
|
<span><i style="background:var(--accent)"></i>${i(t("overview.workingSessions"))} ${E.length}</span>
|
|
117
117
|
<span><i style="background:var(--warning)"></i>${i(t("overview.attention"))} ${S.length}</span>
|
|
118
118
|
<span><i style="background:var(--success)"></i>${i(t("sessions.board.idle"))} ${Math.max(0,C)}</span>
|
|
119
|
-
</div>`;let u=[...Y.schedules.values()].filter(
|
|
119
|
+
</div>`;let u=[...Y.schedules.values()].filter(y=>y.nextRunAt).sort((y,A)=>Date.parse(y.nextRunAt)-Date.parse(A.nextRunAt)).slice(0,5);k.innerHTML=u.length?u.map(si).join(""):`<li class="empty">${t("overview.noSchedules")}</li>`}let M=()=>{if(!document.body.contains(o)){window.removeEventListener("resize",M);return}s||$()};window.addEventListener("resize",M),Y.on($),$(),Ys().then($),Ke().then($)}var na=["backlog","todo","in_progress","in_review","done"];function oa(e){return typeof e=="string"&&na.includes(e)?e:null}function aa(e){if(e.status==="closed")return"done";let n=oa(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 ri=1e15;function ht(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 ri-n}function Jn(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 Xn(e){return typeof e=="number"&&Number.isFinite(e)?e:null}function sa(e){let n=Xn(e);return n===null?"-":n.toLocaleString("en-US")}var pa=["claude-code","seed","relay","codex","codex-app","cursor","gemini","opencode","mtr","hermes","mira","pi","copilot","aiden","coco","oh-my-pi","unknown"],ia=[{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"}],ra=[{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"}],Vn=50;function li(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 la(e){return String(e??"unknown").toLowerCase().replace(/[^a-z0-9_-]/g,"-")}function da(e){let n=String(e??"").trim();return n?n.replace(/\\/g,"/").split("/").filter(Boolean).at(-1)??n:"-"}function Yn(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 Ae={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 Qn(e,n,o,a=""){return`<button type="button" class="card-act${a?" "+a:""}" data-action="${e}" title="${i(o)}" aria-label="${i(o)}">${n}</button>`}function ca(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"))}">${Ae.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"))}">${Ae.key}</button>`;return`<span class="term-pill">${n}${o}</span>`}async function ua(e,n){let o=window.open("about:blank","_blank");o&&(o.opener=null),n&&(n.disabled=!0);try{let a=await fetch(`/api/sessions/${encodeURIComponent(e.sessionId)}/write-link`),s=await a.json().catch(()=>({}));if(!a.ok||s?.ok===!1||!s?.url){o?.close(),a.status!==401&&alert(`${t("sessions.writeLinkFail")}: ${s?.error??a.status}`);return}o?o.location.href=s.url:window.open(s.url,"_blank","noopener")}catch(a){o?.close(),alert(`${t("sessions.writeLinkFail")}: ${a}`)}finally{n&&(n.disabled=!1)}}function di(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 ci(){return`<details class="filter-cli">
|
|
120
120
|
<summary>${t("sessions.cli")} \xB7 <b id="cli-filter-count">${t("common.all")}</b></summary>
|
|
121
121
|
<div class="filter-cli-pop" role="group" aria-label="${t("sessions.cli")}">
|
|
122
|
-
${
|
|
122
|
+
${pa.map(e=>`
|
|
123
123
|
<label class="filter-check">
|
|
124
124
|
<input type="checkbox" name="cli" value="${i(e)}" checked>
|
|
125
125
|
<span>${i(e)}</span>
|
|
126
126
|
</label>
|
|
127
127
|
`).join("")}
|
|
128
128
|
</div>
|
|
129
|
-
</details>`}function
|
|
129
|
+
</details>`}function ui(){return`<section class="page">
|
|
130
130
|
<div class="page-heading">
|
|
131
131
|
<div>
|
|
132
132
|
<p class="eyebrow">${t("nav.sessions")}</p>
|
|
@@ -160,7 +160,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
160
160
|
<option value="yes">${t("sessions.adoptYes")}</option>
|
|
161
161
|
<option value="no">${t("sessions.adoptNo")}</option>
|
|
162
162
|
</select>
|
|
163
|
-
${
|
|
163
|
+
${ci()}
|
|
164
164
|
<label class="filter-toggle"><input type="checkbox" name="active" checked> <span>${t("sessions.activeOnly")}</span></label>
|
|
165
165
|
</form>
|
|
166
166
|
<div id="bulk-bar" class="bulk-bar" hidden>
|
|
@@ -190,20 +190,20 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
190
190
|
<dialog id="drawer"></dialog>
|
|
191
191
|
<dialog id="term-modal" class="term-modal"></dialog>
|
|
192
192
|
<dialog id="history-modal" class="history-modal"></dialog>
|
|
193
|
-
</section>`}function
|
|
193
|
+
</section>`}function ma(e){e.innerHTML=ui();let n=e.querySelector("#sessions-table tbody"),o=e.querySelector("#filters"),a=e.querySelector("#drawer"),s=e.querySelector("#select-all"),r=e.querySelector("#bulk-bar"),d=e.querySelector("#bulk-count"),m=e.querySelector("#bulk-close"),k=e.querySelector("#bulk-clear"),$=e.querySelector("#sessions-table"),M=e.querySelector("#sessions-board"),w=e.querySelector("#sessions-kanban"),p=e.querySelector("#term-modal"),S=e.querySelector("#history-modal"),E=e.querySelector("#kanban-groupby"),C=e.querySelector("#kanban-team"),L=e.querySelector("#kanban-team-stats"),x=e.querySelectorAll(".sessions-view-toggle [data-view]"),T=new Set,R="lastMessageAt",q="desc",u=Ho(window.localStorage),y=Ao(window.localStorage),A=null,O="",U="",B="",Q=!1,re=null,le=!1,te=null,ne=new Map,ce=Oo(window.localStorage),me=null,be=null,ie=[],Ue=null,Xe=!1,ye=!1,fe=(()=>{try{return window.localStorage.getItem(Nn)??""}catch{return""}})();async function oe(){if(!(ye||Xe)){ye=!0;try{let[l,c,g]=await Promise.all([fetch("/api/team/hosted").then(v=>v.json()).catch(()=>null),fetch("/api/team/remote-roster").then(v=>v.json()).catch(()=>null),fetch("/api/groups").then(v=>v.json()).catch(()=>null)]);Array.isArray(g?.chats)&&(Ue=new Map(g.chats.map(v=>[String(v.chatId),{botIds:new Set((v.memberBots??[]).filter(I=>I.inChat).map(I=>String(I.larkAppId))),observedNames:new Set((v.observedBotNames??[]).map(I=>String(I)))}])));let f=v=>({ids:new Set(v.map(I=>String(I.larkAppId))),names:new Set(v.map(I=>String(I.name??"")).filter(Boolean))}),b=[];for(let v of l?.teams??[]){let{ids:I,names:D}=f(v.bots??[]);b.push({key:`local:${v.teamId}`,label:v.isDefault?t("team.myHostedTeam"):String(v.name??v.teamId),botIds:I,botNames:D,groupChats:new Set((v.groupChatIds??[]).map(W=>String(W)))})}for(let v of c?.memberships??[]){let{ids:I,names:D}=f(v.roster?.bots??[]);b.push({key:`${v.hubUrl}::${v.teamId}`,label:String(v.teamName??v.teamId??v.hubUrl),botIds:I,botNames:D,groupChats:new Set})}ie=b}finally{Xe=!0,ye=!1}ie.length&&!ie.some(l=>l.key===fe)&&(fe=ie[0].key),delete C.dataset.loading,C.disabled=ie.length===0,C.innerHTML=ie.length?ie.map(l=>`<option value="${i(l.key)}"${l.key===fe?" selected":""}>${i(l.label)}</option>`).join(""):`<option value="">${i(t("sessions.kanban.noTeam"))}</option>`,B="",P()}}let de=null,Me="",Fe=0,Be=!1,Ze=new Map;async function Ne(l){let c=Me===l.key&&Date.now()-Fe<3e4;if(!(Be||c)){Be=!0;try{let f=l.key.startsWith("local:")?`/api/team/board/local/${encodeURIComponent(l.key.slice(6))}`:`/api/team/remote-board?key=${encodeURIComponent(l.key)}`,b=await fetch(f),v=await b.json().catch(()=>({}));if(!b.ok||v?.ok===!1)return;let I=typeof v.deploymentId=="string"?v.deploymentId:null,D=[];Ze=new Map;for(let W of Array.isArray(v.reports)?v.reports:[])if(!(I&&W.deploymentId===I))for(let N of Array.isArray(W.sessions)?W.sessions:[]){let X={...N,remoteDeployment:W.deploymentName||W.deploymentId};D.push(X),Ze.set(String(N.sessionId),X)}de={board:v.board&&typeof v.board=="object"?v.board:{},remoteRows:D},Me=l.key,Fe=Date.now(),B="",P()}catch{}finally{Be=!1}}}async function Oe(l,c,g,f,b){try{let I=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:g,position:f})}):await fetch("/api/team/remote-board-move",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({key:l,sessionId:c,column:g,position:f})}),D=await I.json().catch(()=>({}));(!I.ok||D?.ok===!1)&&(de&&(b?de.board[c]=b:delete de.board[c]),B="",P(),I.status!==401&&alert(`${t("sessions.kanban.moveFail")}: ${D?.error??I.status}`))}catch(v){de&&(b?de.board[c]=b:delete de.board[c]),B="",P(),alert(`${t("sessions.kanban.moveFail")}: ${v}`)}}function et(l,c,g){let f=ie.find(v=>v.key===fe)??ie[0];if(!f)return;(!de||Me!==f.key)&&(de={board:{},remoteRows:de?.remoteRows??[]},Me=f.key);let b=de.board[l];de.board[l]={column:c,position:g},Oe(f.key,l,c,g,b)}function Pt(){return y.map(l=>ia.find(c=>c.id===l)).filter(l=>!!l)}function it(l,c){let g=y.indexOf(l),f=g+c;if(g<0||f<0||f>=y.length)return;let b=[...y];b.splice(g,1),b.splice(f,0,l),y=b,Bn(window.localStorage,y),P()}function Bt(l,c){if(l===c)return;let g=y.indexOf(l),f=y.indexOf(c);if(g<0||f<0)return;let b=[...y];b.splice(g,1),b.splice(f,0,l),y=b,Bn(window.localStorage,y),P()}function he(l){let c=l.status==="closed",g=T.has(l.sessionId)?"checked":"";return`<tr data-id="${i(l.sessionId)}">
|
|
194
194
|
<td><input type="checkbox" class="row-select" ${g} ${c?"disabled":""}></td>
|
|
195
195
|
<td>${i(ke(l))}</td>
|
|
196
|
-
<td><span class="badge cli-${
|
|
196
|
+
<td><span class="badge cli-${la(l.cliId)}">${i(l.cliId??"unknown")}</span></td>
|
|
197
197
|
<td><span class="status status-${i(l.status??"unknown")}">${i(l.status??"unknown")}</span></td>
|
|
198
|
-
<td class="token-cell">${
|
|
199
|
-
<td class="token-cell">${
|
|
198
|
+
<td class="token-cell">${sa(l.tokenUsage?.in)}</td>
|
|
199
|
+
<td class="token-cell">${sa(l.tokenUsage?.out)}</td>
|
|
200
200
|
<td title="${i(String(l.title??""))}">${i($e(l.title??"").slice(0,48))}</td>
|
|
201
201
|
<td title="${i(l.workingDir??"")}">${i((l.workingDir??"").slice(-34))}</td>
|
|
202
202
|
<td>${qe(l.spawnedAt)}</td>
|
|
203
203
|
<td>${qe(l.lastMessageAt)}</td>
|
|
204
204
|
<td>${l.adopt?'<span class="badge">adopt</span>':""}</td>
|
|
205
205
|
<td><button class="open" type="button">${t("sessions.details")}</button></td>
|
|
206
|
-
</tr>`}function
|
|
206
|
+
</tr>`}function rt(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)}">${Ae.feishu}</a>`}function tt(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 H(l){let c=T.has(l.sessionId),g=$e(l.title)||l.sessionId,f=ke(l),b=dt(l),v=Yn(l),I=tt(l),D=da(l.workingDir);return`<article class="session-card${c?" selected":""}" data-id="${i(l.sessionId)}" aria-pressed="${c}">
|
|
207
207
|
<div class="session-card-top">
|
|
208
208
|
${ue({name:f,larkAppId:l.larkAppId,size:"sm"})}
|
|
209
209
|
<div class="session-card-title">
|
|
@@ -221,12 +221,12 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
221
221
|
</div>
|
|
222
222
|
${I?`<div class="session-signal" title="${i(I)}">${i(I)}</div>`:""}
|
|
223
223
|
<div class="session-card-actions">
|
|
224
|
-
${
|
|
224
|
+
${rt(l)??Qn("locate",Ae.pin,t("sessions.locate"))}
|
|
225
225
|
${Qn("details",Ae.details,t("sessions.details"))}
|
|
226
|
-
${
|
|
226
|
+
${ca(v)}
|
|
227
227
|
${Qn("close",Ae.close,t("sessions.close"),"danger")}
|
|
228
228
|
</div>
|
|
229
|
-
</article>`}function se(l,c,g){let f=g==="needs-you"?Ce(l):Number(l.lastMessageAt??0),b=g==="needs-you"?Ce(c):Number(c.lastMessageAt??0);return f!==b?g==="needs-you"?f-b:b-f:String(l.title??l.sessionId).localeCompare(String(c.title??c.sessionId))}function G(l){let c=new Map(
|
|
229
|
+
</article>`}function se(l,c,g){let f=g==="needs-you"?Ce(l):Number(l.lastMessageAt??0),b=g==="needs-you"?Ce(c):Number(c.lastMessageAt??0);return f!==b?g==="needs-you"?f-b:b-f:String(l.title??l.sessionId).localeCompare(String(c.title??c.sessionId))}function G(l){let c=new Map(ia.map(b=>[b.id,[]]));for(let b of l){let v=di(b);v&&c.get(v).push(b)}let g=Pt(),f=g.map((b,v)=>{let I=(c.get(b.id)??[]).sort((D,W)=>se(D,W,b.id));return`<section class="session-board-column session-board-${b.id}" data-col="${b.id}">
|
|
230
230
|
<header draggable="true" title="${i(t("sessions.board.dragHint"))}">
|
|
231
231
|
<div>
|
|
232
232
|
<h2>${i(t(b.labelKey))}</h2>
|
|
@@ -245,9 +245,9 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
245
245
|
<div class="session-board-list">
|
|
246
246
|
${I.length?I.map(H).join(""):`<div class="session-board-empty">${t("sessions.board.emptyColumn")}</div>`}
|
|
247
247
|
</div>
|
|
248
|
-
</section>`}).join("");f!==
|
|
248
|
+
</section>`}).join("");f!==O&&(O=f,M.innerHTML=f,M.classList.toggle("board-enter",!Q),Q=!0)}function K(l){let c=$e(l.title)||l.sessionId,g=ke(l),f=dt(l),b=da(l.workingDir),v=tt(l),I=[f,b!=="-"?b:null].filter(Boolean).join(" \xB7 "),D=String(l.status??"unknown"),W=typeof l.remoteDeployment=="string"?l.remoteDeployment:"";return`<article class="kanban-card${W?" kanban-card-remote":""}" data-id="${i(l.sessionId)}" tabindex="0" role="button" draggable="true">
|
|
249
249
|
<div class="kanban-card-top">
|
|
250
|
-
<span class="badge cli-${
|
|
250
|
+
<span class="badge cli-${la(l.cliId)}">${i(l.cliId??"unknown")}</span>
|
|
251
251
|
${l.adopt?'<span class="badge">adopt</span>':""}
|
|
252
252
|
${W?`<span class="badge kanban-remote-badge" title="${i(t("sessions.kanban.remoteHint",{name:W}))}">${i(W)}</span>`:""}
|
|
253
253
|
<span class="kanban-card-top-right">
|
|
@@ -264,7 +264,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
264
264
|
<span class="kanban-card-owner">${ue({name:g,larkAppId:l.larkAppId,size:"sm"})}<span>${i(g)}</span></span>
|
|
265
265
|
<span class="kanban-card-updated">${i(t("sessions.kanban.updated",{time:qe(l.lastMessageAt)}))}</span>
|
|
266
266
|
</div>
|
|
267
|
-
</article>`}function ge(l){let c=[],g=new Map;for(let v of l){let I=String(v.chatId??v.sessionId),D=g.get(I);D||(D={chatId:I,rows:[]},g.set(I,D),c.push(D)),D.rows.push(v)}let f=[];return{html:c.map(v=>{if(f.push(...v.rows),v.rows.length<2)return K(v.rows[0]);let I=
|
|
267
|
+
</article>`}function ge(l){let c=[],g=new Map;for(let v of l){let I=String(v.chatId??v.sessionId),D=g.get(I);D||(D={chatId:I,rows:[]},g.set(I,D),c.push(D)),D.rows.push(v)}let f=[];return{html:c.map(v=>{if(f.push(...v.rows),v.rows.length<2)return K(v.rows[0]);let I=dt(v.rows[0])??v.chatId;return`<div class="kanban-cluster" data-chat="${i(v.chatId)}">
|
|
268
268
|
<header draggable="true" title="${i(I)} \xB7 ${i(t("sessions.kanban.clusterDragHint"))}">
|
|
269
269
|
${cn({chatId:v.chatId,name:I,size:"sm"})}
|
|
270
270
|
<span class="kanban-cluster-name">${i(I)}</span>
|
|
@@ -278,9 +278,9 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
278
278
|
<span class="kanban-col-count">${b.length}</span>
|
|
279
279
|
</header>
|
|
280
280
|
<div class="kanban-col-list">${v}</div>
|
|
281
|
-
</section>`}).join(""):`<div class="kanban-col-empty">${t("sessions.board.emptyColumn")}</div>`}function
|
|
281
|
+
</section>`}).join(""):`<div class="kanban-col-empty">${t("sessions.board.emptyColumn")}</div>`}function Lt(l){let c=new Map(ra.map(f=>[f.id,[]]));for(let f of l)c.get(aa(f)).push(f);let g=ra.map(f=>{let b=(c.get(f.id)??[]).sort((W,N)=>ht(W)-ht(N)),v=0;f.id==="done"&&b.length>Vn&&(v=b.length-Vn,b=b.slice(0,Vn));let{html:I,flat:D}=ge(b);return c.set(f.id,D),`<section class="kanban-column kanban-${f.id}" data-col="${f.id}">
|
|
282
282
|
<header>
|
|
283
|
-
<span class="kanban-col-icon">${
|
|
283
|
+
<span class="kanban-col-icon">${li(f.id)}</span>
|
|
284
284
|
<h2>${i(t(f.labelKey))}</h2>
|
|
285
285
|
<span class="kanban-col-count">${b.length+v}</span>
|
|
286
286
|
</header>
|
|
@@ -288,13 +288,13 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
288
288
|
${b.length?I:`<div class="kanban-col-empty">${t("sessions.board.emptyColumn")}</div>`}
|
|
289
289
|
${v?`<div class="kanban-col-more">${i(t("sessions.kanban.moreHidden",{count:v}))}</div>`:""}
|
|
290
290
|
</div>
|
|
291
|
-
</section>`}).join("");return ne=c,g}function Ee(l){if(re||me||le)return;
|
|
291
|
+
</section>`}).join("");return ne=c,g}function Ee(l){if(re||me||le)return;w.classList.toggle("kanban-mode-bot",ce==="bot");let c;if(ce==="bot")c=Ge(l),ne=new Map;else if(ce==="team")if(!Xe)c=`<div class="kanban-loading">${t("sessions.kanban.teamLoading")}</div>`,ne=new Map,C.dataset.loading||(C.dataset.loading="1",C.disabled=!0,C.innerHTML=`<option>${i(t("sessions.kanban.teamLoading"))}</option>`),oe();else{let f=ie.find(N=>N.key===fe)??ie[0],b=[],v=new Set;if(f){for(let N of f.groupChats)v.add(N);if(Ue)for(let[N,X]of Ue){if(v.has(N))continue;let we=!1;for(let ze of f.botIds)if(X.botIds.has(ze)){we=!0;break}if(we){for(let ze of X.observedNames)if(f.botNames.has(ze)){v.add(N);break}}}b=l.filter(N=>v.has(String(N.chatId)))}f&&Ne(f);let I=(Me===f?.key?de?.board:null)??{},D=(Me===f?.key?de?.remoteRows:null)??[],W=[...b,...D].map(N=>{let X=I[N.sessionId];return X?{...N,kanbanColumn:X.column,kanbanPosition:X.position}:N});L.textContent=t("sessions.kanban.teamScope",{chats:v.size,sessions:W.length}),c=Lt(W)}else c=Lt(l);if(c===B)return;B=c;let g=new Map;w.querySelectorAll(".kanban-col-list").forEach(f=>{let b=f.closest(".kanban-column")?.dataset.col;b&&f.scrollTop&&g.set(b,f.scrollTop)}),w.innerHTML=c,g.size&&w.querySelectorAll(".kanban-col-list").forEach(f=>{let b=f.closest(".kanban-column")?.dataset.col,v=b?g.get(b):void 0;v&&(f.scrollTop=v)})}async function Nt(l,c,g,f){try{let b=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/board`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({column:c,position:g})}),v=await b.json().catch(()=>({}));(!b.ok||v?.ok===!1)&&(l.kanbanColumn=f.column,l.kanbanPosition=f.position,B="",P(),b.status!==401&&alert(`${t("sessions.kanban.moveFail")}: ${v?.error??b.status}`))}catch(b){l.kanbanColumn=f.column,l.kanbanPosition=f.position,B="",P(),alert(`${t("sessions.kanban.moveFail")}: ${b}`)}}async function gt(l,c){let g=l.title;l.title=c,B="",P();try{let f=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/rename`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({title:c})}),b=await f.json().catch(()=>({}));(!f.ok||b?.ok===!1)&&(l.title=g,B="",P(),f.status!==401&&alert(`${t("sessions.kanban.renameFail")}: ${b?.error??f.status}`))}catch(f){l.title=g,B="",P(),alert(`${t("sessions.kanban.renameFail")}: ${f}`)}}function lt(l){if(l==null||l==="")return"";let c=Number(l),g=Number.isFinite(c)&&c>0?new Date(c):new Date(String(l));return Number.isNaN(g.getTime())?"":g.toLocaleString()}function Tt(l,c,g){let f=c.senderType==="user",b=f?c.senderName||(g&&c.senderId===g?t("sessions.history.owner"):t("sessions.history.user")):ke(l),v=lt(c.createTime),I=String(c.content??"").trim()||`[${c.msgType??"message"}]`,D=f?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>`:ue({name:ke(l),larkAppId:l.larkAppId,size:"sm"});return`<div class="history-msg${f?" mine":""}">
|
|
292
292
|
${D}
|
|
293
293
|
<div class="history-msg-main">
|
|
294
294
|
<div class="history-msg-meta"><span>${i(b)}</span><time>${i(v)}</time></div>
|
|
295
295
|
<div class="history-bubble">${i(I)}</div>
|
|
296
296
|
</div>
|
|
297
|
-
</div>`}async function
|
|
297
|
+
</div>`}async function It(l){let c=ke(l);S.innerHTML=`<div class="term-modal-head">
|
|
298
298
|
<span class="term-modal-title">
|
|
299
299
|
${ue({name:c,larkAppId:l.larkAppId,size:"sm"})}
|
|
300
300
|
<strong title="${i(String(l.title??""))}">${i(($e(l.title)||l.sessionId).slice(0,60))}</strong>
|
|
@@ -304,7 +304,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
304
304
|
<button type="button" id="history-close" class="card-act" title="${i(t("sessions.dismiss"))}" aria-label="${i(t("sessions.dismiss"))}">${Ae.close}</button>
|
|
305
305
|
</span>
|
|
306
306
|
</div>
|
|
307
|
-
<div class="history-body"><div class="term-modal-loading">${t("sessions.history.loading")}</div></div>`,S.showModal(),S.querySelector("#history-close").onclick=()=>S.close();try{let g=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/history?limit=80`),f=await g.json().catch(()=>({}));if(!S.open)return;let b=S.querySelector(".history-body");if(!g.ok||f?.ok===!1){let I=String(f?.error??g.status),D=I==="not_found_yet"||I==="not_found";b.innerHTML=`<div class="history-error">${i(t("sessions.history.fail"))}: ${i(I)}${D?`<br><span>${i(t("sessions.history.staleHint"))}</span>`:""}</div>`;return}let v=Array.isArray(f.messages)?f.messages:[];if(!v.length){b.innerHTML=`<div class="history-error">${t("sessions.history.empty")}</div>`;return}b.innerHTML=`<div class="history-list">${v.map(I=>
|
|
307
|
+
<div class="history-body"><div class="term-modal-loading">${t("sessions.history.loading")}</div></div>`,S.showModal(),S.querySelector("#history-close").onclick=()=>S.close();try{let g=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/history?limit=80`),f=await g.json().catch(()=>({}));if(!S.open)return;let b=S.querySelector(".history-body");if(!g.ok||f?.ok===!1){let I=String(f?.error??g.status),D=I==="not_found_yet"||I==="not_found";b.innerHTML=`<div class="history-error">${i(t("sessions.history.fail"))}: ${i(I)}${D?`<br><span>${i(t("sessions.history.staleHint"))}</span>`:""}</div>`;return}let v=Array.isArray(f.messages)?f.messages:[];if(!v.length){b.innerHTML=`<div class="history-error">${t("sessions.history.empty")}</div>`;return}b.innerHTML=`<div class="history-list">${v.map(I=>Tt(l,I,f.ownerOpenId)).join("")}</div>`,b.scrollTop=b.scrollHeight}catch(g){if(!S.open)return;let f=S.querySelector(".history-body");f&&(f.innerHTML=`<div class="history-error">${i(t("sessions.history.fail"))}: ${i(String(g))}</div>`)}}function Le(l,c){let g=l.querySelector(".kanban-card-title");if(!g||l.querySelector(".kanban-rename-input"))return;le=!0;let f=document.createElement("input");f.type="text",f.className="kanban-rename-input",f.maxLength=200,f.value=$e(c.title)||"",g.replaceWith(f),f.focus(),f.select();let b=!1,v=I=>{if(b)return;b=!0,le=!1;let D=f.value.trim();I&&D&&D!==($e(c.title)||"")?gt(c,D):(B="",P())};f.addEventListener("keydown",I=>{I.stopPropagation(),I.key==="Enter"?(I.preventDefault(),v(!0)):I.key==="Escape"&&(I.preventDefault(),v(!1))}),f.addEventListener("blur",()=>v(!0)),f.addEventListener("click",I=>I.stopPropagation())}function qt(l,c){for(let g of l.querySelectorAll(".kanban-card:not(.dragging)")){if(g.closest(".kanban-cluster.dragging"))continue;let f=g.getBoundingClientRect();if(c<f.top+f.height/2)return g}return null}function Mt(){w.querySelectorAll(".drag-over, .dragging, .drop-before").forEach(l=>l.classList.remove("drag-over","dragging","drop-before"))}function jt(l){let c=p.querySelector(".term-modal-name");if(!c||p.querySelector(".term-modal-name-input"))return;let g=document.createElement("input");g.type="text",g.className="term-modal-name-input",g.maxLength=200,g.value=$e(l.title)||"",c.replaceWith(g);let f=()=>{let I=getComputedStyle(g),D=document.createElement("span");D.style.cssText="position:absolute;visibility:hidden;white-space:pre",D.style.fontSize=I.fontSize,D.style.fontFamily=I.fontFamily,D.style.fontWeight=I.fontWeight,D.style.letterSpacing=I.letterSpacing,D.textContent=g.value||" ",document.body.appendChild(D);let W=D.offsetWidth;D.remove();let N=Math.round(window.innerWidth*.6);g.style.width=`${Math.min(Math.max(W+22,80),N)}px`};f(),g.addEventListener("input",f),g.focus(),g.select();let b=!1,v=I=>{if(b)return;b=!0;let D=g.value.trim(),W=$e(l.title)||"";if(I&&D&&D!==W){l.title=D;let N=document.createElement("strong");N.className="term-modal-name",N.title=D,N.textContent=D.slice(0,60),g.replaceWith(N),gt(l,D)}else{let N=document.createElement("strong");N.className="term-modal-name",N.title=String(l.title??W),N.textContent=W.slice(0,60),g.replaceWith(N)}};g.addEventListener("keydown",I=>{I.stopPropagation(),I.key==="Enter"?(I.preventDefault(),v(!0)):I.key==="Escape"&&(I.preventDefault(),v(!1))}),g.addEventListener("blur",()=>v(!0))}async function bt(l){let c=Yn(l);if(!c){_e(l);return}let g=$e(l.title)||l.sessionId,f=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"))}">${Ae.feishu}</a>`:"";p.innerHTML=`<div class="term-modal-head">
|
|
308
308
|
<span class="term-modal-title">
|
|
309
309
|
${ue({name:ke(l),larkAppId:l.larkAppId,size:"sm"})}
|
|
310
310
|
<strong class="term-modal-name" title="${i(String(l.title??g))}">${i(String(g).slice(0,60))}</strong>
|
|
@@ -317,36 +317,36 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
317
317
|
<button type="button" id="term-modal-close" class="card-act" title="${i(t("sessions.dismiss"))}" aria-label="${i(t("sessions.dismiss"))}">${Ae.close}</button>
|
|
318
318
|
</span>
|
|
319
319
|
</div>
|
|
320
|
-
<div class="term-modal-body"><div class="term-modal-loading">${t("sessions.kanban.terminalLoading")}</div></div>`,p.showModal(),p.querySelector("#term-modal-close").onclick=()=>p.close(),p.querySelector("#term-modal-edit").onclick=()=>
|
|
320
|
+
<div class="term-modal-body"><div class="term-modal-loading">${t("sessions.kanban.terminalLoading")}</div></div>`,p.showModal(),p.querySelector("#term-modal-close").onclick=()=>p.close(),p.querySelector("#term-modal-edit").onclick=()=>jt(l);let b=c;if(Te.authed)try{let D=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/write-link`),W=await D.json().catch(()=>({}));D.ok&&W?.ok!==!1&&W?.url&&(b=W.url)}catch{}if(!p.open)return;let v=p.querySelector(".term-modal-body");v.innerHTML=`<iframe class="term-modal-frame" src="${i(b)}" allow="clipboard-read; clipboard-write"></iframe>`;let I=p.querySelector("#term-modal-tab");I&&(I.href=b)}function xe(){let l=new FormData(o),c=(l.get("q")??"").toLowerCase(),g=l.getAll("cli"),f=g.length>0&&g.length<pa.length,b=l.get("status"),v=l.get("adopt"),I=!!l.get("active"),D=u==="kanban",W=[...Y.sessions.values()].filter(N=>!f||g.includes(N.cliId??"unknown")).filter(N=>!b||N.status===b).filter(N=>!v||v==="yes"==!!N.adopt).filter(N=>!I||D||N.status!=="closed").filter(N=>!c||JSON.stringify(N).toLowerCase().includes(c));return W.sort(V),W}function Hn(l,c){return c==="spawnedAt"||c==="lastMessageAt"?Number(l[c]??0):c==="tokenIn"?Xn(l.tokenUsage?.in)??-1:c==="tokenOut"?Xn(l.tokenUsage?.out)??-1:c==="adopt"?!!l.adopt:String(l[c]??"").toLowerCase()}function V(l,c){let g=Hn(l,R),f=Hn(c,R),b=0;return typeof g=="number"&&typeof f=="number"?b=g-f:typeof g=="boolean"&&typeof f=="boolean"?b=Number(g)-Number(f):b=String(g).localeCompare(String(f)),b===0&&(b=Number(l.lastMessageAt??0)-Number(c.lastMessageAt??0)),q==="asc"?b:-b}function _(){$.querySelectorAll("th[data-sort]").forEach(l=>{let c=l.dataset.sort===R;l.classList.toggle("sorted",c),l.setAttribute("aria-sort",c?q==="asc"?"ascending":"descending":"none");let g=l.dataset.label??l.textContent?.trim()??"";l.textContent=c?`${g} ${q==="asc"?"\u25B2":"\u25BC"}`:g})}function j(l){r.hidden=T.size===0,d.textContent=t("sessions.selectedCount",{count:T.size});let c=l.filter(f=>f.status!=="closed");if(c.length===0){s.checked=!1,s.indeterminate=!1,s.disabled=!0;return}s.disabled=!1;let g=c.filter(f=>T.has(f.sessionId)).length;s.checked=g===c.length,s.indeterminate=g>0&&g<c.length}function J(){x.forEach(l=>{let c=l.dataset.view===u;l.classList.toggle("active",c),l.setAttribute("aria-pressed",String(c))}),E.hidden=u!=="kanban",C.hidden=!(u==="kanban"&&ce==="team"),L.hidden=C.hidden||!Xe,E.querySelectorAll("[data-groupby]").forEach(l=>{let c=l.dataset.groupby===ce;l.classList.toggle("active",c),l.setAttribute("aria-pressed",String(c))})}function z(){let l=o.querySelector("#cli-filter-count");if(!l)return;let c=[...o.querySelectorAll('input[name="cli"]')],g=c.filter(f=>f.checked).length;l.textContent=g===c.length?t("common.all"):`${g}/${c.length}`,l.classList.toggle("cli-filter-active",g!==c.length)}function P(){let l=xe();for(let f of[...T]){let b=Y.sessions.get(f);(!b||b.status==="closed")&&T.delete(f)}let c=l.filter(f=>f.status!=="closed"),g=u==="table"?l:c;if($.hidden=u!=="table",M.hidden=u!=="board",w.hidden=u!=="kanban",u==="table"){let f=l.length?l.map(he).join(""):`<tr><td colspan="12" class="empty">${t("sessions.empty")}</td></tr>`;f!==U&&(U=f,n.innerHTML=f)}else u==="kanban"?Ee(l):G(c);J(),_(),z(),j(g)}async function pe(l,c){c&&(c.disabled=!0,c.textContent=t("sessions.locating"));try{let g=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/locate`,{method:"POST"}),f=await g.json();if(f.ok){if(!c)return;let b=30;c.textContent=t("sessions.cooldown",{seconds:b});let v=setInterval(()=>{b-=1,b<=0?(clearInterval(v),c.disabled=!1,c.textContent=t("sessions.locate")):c.textContent=t("sessions.cooldown",{seconds:b})},1e3)}else alert(`Locate failed: ${f.error??g.status}`),c&&(c.disabled=!1,c.textContent=t("sessions.locate"))}catch(g){alert(`Locate error: ${g}`),c&&(c.disabled=!1,c.textContent=t("sessions.locate"))}}async function He(l,c){if(!confirm(t("sessions.closeConfirm")))return!1;c&&(c.disabled=!0);try{let g=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/close`,{method:"POST"}),f=await g.json().catch(()=>({}));return!g.ok||f?.ok===!1?(g.status!==401&&alert(`Close failed: ${f?.error??g.status}`),!1):!0}catch(g){return alert(`Close error: ${g}`),!1}finally{c&&(c.disabled=!1)}}function _e(l){let c=l.status==="closed",g=Yn(l);a.innerHTML=`<article>
|
|
321
321
|
<header>
|
|
322
322
|
<h3>${i($e(l.title)||l.sessionId)}</h3>
|
|
323
323
|
<span class="status status-${i(l.status??"unknown")}">${i(l.status??"unknown")}</span>
|
|
324
324
|
<p><code>${i(l.sessionId)}</code> <button data-copy="${i(l.sessionId)}">${t("sessions.copy")}</button></p>
|
|
325
325
|
</header>
|
|
326
326
|
<p><b>${t("sessions.bot")}:</b> ${i(ke(l))} \xB7 <b>${t("sessions.cli")}:</b> ${i(l.cliId??"?")}</p>
|
|
327
|
-
${
|
|
327
|
+
${dt(l)?`<p><b>${t("sessions.chat")}:</b> ${i(dt(l))}</p>`:""}
|
|
328
328
|
<p><b>chatId:</b> <code>${i(l.chatId??"")}</code> <button data-copy="${i(l.chatId??"")}">${t("sessions.copy")}</button></p>
|
|
329
329
|
<p><b>rootMessageId:</b> <code>${i(l.rootMessageId??"")}</code> <button data-copy="${i(l.rootMessageId??"")}">${t("sessions.copy")}</button></p>
|
|
330
330
|
${l.threadId?`<p><b>threadId:</b> <code>${i(l.threadId)}</code></p>`:""}
|
|
331
331
|
<p><b>${t("sessions.workingDir")}:</b> ${i(l.workingDir??"-")}</p>
|
|
332
332
|
<div class="actions">
|
|
333
|
-
${
|
|
333
|
+
${rt(l)??`<button id="locate-btn" type="button">${t("sessions.locate")}</button>`}
|
|
334
334
|
<button id="history-drawer-btn" type="button">${t("sessions.history.title")}</button>
|
|
335
|
-
${
|
|
335
|
+
${ca(g)}
|
|
336
336
|
${c?`<button id="resume-btn" type="button" class="primary">${t("sessions.resume")}</button>`:""}
|
|
337
337
|
${c?"":`<button id="close-btn" type="button" class="contrast">${t("sessions.close")}</button>`}
|
|
338
338
|
<button id="land-btn" type="button">${t("sessions.land")}</button>
|
|
339
339
|
</div>
|
|
340
340
|
<div id="land-area"></div>
|
|
341
341
|
<form method="dialog"><button>${t("sessions.dismiss")}</button></form>
|
|
342
|
-
</article>`,
|
|
342
|
+
</article>`,a.querySelectorAll("[data-copy]").forEach(X=>{X.onclick=()=>{navigator.clipboard.writeText(X.dataset.copy??""),X.textContent=t("sessions.copied"),setTimeout(()=>{X.textContent=t("sessions.copy")},800)}});let f=a.querySelector("#locate-btn");f&&(f.onclick=()=>{pe(l,f)});let b=a.querySelector("#history-drawer-btn");b&&(b.onclick=()=>{It(l)});let v=a.querySelector(".term-write");v&&(v.onclick=()=>{ua(l,v)});let I=a.querySelector("#resume-btn");I&&(I.onclick=async()=>{I.disabled=!0;try{let X=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/resume`,{method:"POST"}),we=await X.json().catch(()=>({}));if(!X.ok||we.ok===!1){alert(`${t("sessions.resumeFailed")}: ${we?.error??X.status}`),I.disabled=!1;return}a.close()}catch(X){alert(`${t("sessions.resumeFailed")}: ${X}`),I.disabled=!1}});let D=a.querySelector("#close-btn");D&&(D.onclick=async()=>{await He(l,D)&&a.close()});let W=a.querySelector("#land-btn"),N=a.querySelector("#land-area");W&&N&&(W.onclick=async()=>{W.disabled=!0,N.innerHTML=`<p>${t("sessions.landLoading")}</p>`;try{let X=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/sandbox-diff`),we=await X.json().catch(()=>({}));if(!we.ok){N.innerHTML=`<p>${t("sessions.landUnavailable")}: ${i(we.error??String(X.status))}</p>`,W.disabled=!1;return}if(we.empty){N.innerHTML=`<p>${t("sessions.landEmpty")}</p>`,W.disabled=!1;return}let ze=String(we.patch??""),Cn=ze.slice(0,2e4)+(ze.length>2e4?`
|
|
343
343
|
\u2026(truncated)`:"");N.innerHTML=`
|
|
344
|
-
<p><b>${
|
|
344
|
+
<p><b>${we.files}</b> files (+${we.insertions}/-${we.deletions}) \u2192 <code>${i(String(we.workingDir??""))}</code></p>
|
|
345
345
|
<pre style="max-height:320px;overflow:auto;white-space:pre-wrap">${i(Cn)}</pre>
|
|
346
346
|
<div class="actions">
|
|
347
347
|
<button id="land-apply" type="button" class="primary">${t("sessions.landApply")}</button>
|
|
348
348
|
<button id="land-discard" type="button" class="contrast">${t("sessions.landDiscard")}</button>
|
|
349
|
-
</div>`;let We=N.querySelector("#land-apply"),tn=N.querySelector("#land-discard");We.onclick=async()=>{We.disabled=!0,tn.disabled=!0;let nt=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/sandbox-land/apply`,{method:"POST"}),
|
|
349
|
+
</div>`;let We=N.querySelector("#land-apply"),tn=N.querySelector("#land-discard");We.onclick=async()=>{We.disabled=!0,tn.disabled=!0;let nt=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/sandbox-land/apply`,{method:"POST"}),Pe=await nt.json().catch(()=>({}));N.innerHTML=Pe.ok?`<p>\u2705 ${t("sessions.landApplied")}: ${Pe.files} files (+${Pe.insertions}/-${Pe.deletions}) \u2192 <code>${i(String(Pe.workingDir??""))}</code></p>`:`<p>\u274C ${t("sessions.landFailed")}: ${i(Pe.error??String(nt.status))}</p>`},tn.onclick=async()=>{await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/sandbox-land/discard`,{method:"POST"}),N.innerHTML=`<p>\u{1F5D1} ${t("sessions.landDiscarded")}</p>`}}catch(X){N.innerHTML=`<p>${t("sessions.landUnavailable")}: ${i(String(X))}</p>`,W.disabled=!1}}),a.showModal()}n.addEventListener("click",l=>{let c=l.target;if(c.classList.contains("row-select")){let v=c.closest("tr[data-id]");if(!v)return;c.checked?T.add(v.dataset.id):T.delete(v.dataset.id),j(xe());return}let g=c.closest("td");if(g&&g.querySelector(".row-select"))return;let f=c.closest("tr[data-id]");if(!f)return;let b=Y.sessions.get(f.dataset.id);b&&_e(b)}),M.addEventListener("click",l=>{let c=l.target,g=c.closest("button[data-move-col]");if(g){it(g.dataset.moveCol,Number(g.dataset.dir));return}let f=c.closest(".session-card[data-id]");if(!f)return;let b=Y.sessions.get(f.dataset.id);if(!b)return;let v=c.closest("button[data-action]");if(v){let I=v.dataset.action;I==="details"?_e(b):I==="write-link"?ua(b,v):I==="locate"?pe(b,v):I==="close"&&He(b,v).then(D=>{D&&(T.delete(b.sessionId),P())});return}c.closest("a, button, input, label")||(T.has(b.sessionId)?T.delete(b.sessionId):T.add(b.sessionId),f.classList.toggle("selected",T.has(b.sessionId)),f.setAttribute("aria-pressed",String(T.has(b.sessionId))),j(xe().filter(I=>I.status!=="closed")))}),M.addEventListener("dragstart",l=>{let g=l.target.closest(".session-board-column > header[draggable]")?.closest(".session-board-column");g?.dataset.col&&(A=g.dataset.col,g.classList.add("dragging"),l.dataTransfer&&(l.dataTransfer.effectAllowed="move",l.dataTransfer.setData("text/plain",A)))}),M.addEventListener("dragover",l=>{if(!A)return;l.preventDefault(),l.dataTransfer&&(l.dataTransfer.dropEffect="move");let c=l.target.closest(".session-board-column");M.querySelectorAll(".drag-over").forEach(g=>g.classList.remove("drag-over")),c&&c.dataset.col!==A&&c.classList.add("drag-over")}),M.addEventListener("drop",l=>{if(!A)return;l.preventDefault();let c=l.target.closest(".session-board-column"),g=A;A=null,c?.dataset.col&&Bt(g,c.dataset.col)}),M.addEventListener("dragend",()=>{A=null,M.querySelectorAll(".drag-over, .dragging").forEach(l=>l.classList.remove("drag-over","dragging"))}),x.forEach(l=>{l.addEventListener("click",()=>{let c=Pn(l.dataset.view)??"board";c!==u&&(u=c,Do(window.localStorage,u),P())})}),E.querySelectorAll("[data-groupby]").forEach(l=>{l.addEventListener("click",()=>{let c=l.dataset.groupby,g=c==="bot"?"bot":c==="team"?"team":"flow";g!==ce&&(ce=g,Po(window.localStorage,g),B="",P())})}),C.addEventListener("change",()=>{fe=C.value;try{window.localStorage.setItem(Nn,fe)}catch{}B="",P()});function en(){te!==null&&(clearTimeout(te),te=null)}w.addEventListener("click",l=>{let c=l.target,g=c.closest(".kanban-card[data-id]");if(!g)return;let f=Y.sessions.get(g.dataset.id);if(!f)return;let b=c.closest("button[data-action]");if(b){b.dataset.action==="details"?_e(f):b.dataset.action==="rename"?Le(g,f):b.dataset.action==="history"&&It(f);return}c.closest("a, button, input, label")||(en(),te=setTimeout(()=>{te=null,bt(f)},220))}),w.addEventListener("dblclick",l=>{let c=l.target,g=c.closest(".kanban-card-title"),f=c.closest(".kanban-card[data-id]");if(!g||!f)return;en();let b=Y.sessions.get(f.dataset.id);b&&Le(f,b)}),w.addEventListener("keydown",l=>{if(l.key!=="Enter"&&l.key!==" ")return;let c=l.target;if(!c.classList?.contains("kanban-card"))return;l.preventDefault();let g=Y.sessions.get(c.dataset.id);g&&bt(g)}),w.addEventListener("dragstart",l=>{if(ce==="bot")return;let c=l.target,g=c.closest(".kanban-cluster > header[draggable]");if(g){let b=g.closest(".kanban-cluster"),v=b.closest(".kanban-column")?.dataset.col;if(!b.dataset.chat||!v)return;en(),me=b.dataset.chat,be=v,b.classList.add("dragging"),l.dataTransfer&&(l.dataTransfer.effectAllowed="move",l.dataTransfer.setData("text/plain",`cluster:${me}`));return}let f=c.closest(".kanban-card[data-id]");f&&(en(),re=f.dataset.id,f.classList.add("dragging"),l.dataTransfer&&(l.dataTransfer.effectAllowed="move",l.dataTransfer.setData("text/plain",re)))}),w.addEventListener("dragover",l=>{if(!re&&!me)return;l.preventDefault(),l.dataTransfer&&(l.dataTransfer.dropEffect="move");let c=l.target.closest(".kanban-column");w.querySelectorAll(".drag-over").forEach(g=>g.classList.remove("drag-over")),w.querySelectorAll(".drop-before").forEach(g=>g.classList.remove("drop-before")),c&&(c.classList.add("drag-over"),qt(c,l.clientY)?.classList.add("drop-before"))}),w.addEventListener("drop",l=>{let c=me,g=be,f=re;if(!f&&!c)return;l.preventDefault(),re=null,me=null,be=null,Mt();let b=l.target.closest(".kanban-column"),v=b?.dataset.col;if(!b||!v)return;let I=qt(b,l.clientY);if(c&&g){let We=(ne.get(g)??[]).filter(ve=>String(ve.chatId)===c).filter(ve=>!(ve.status==="closed"&&v!=="done"));if(!We.length)return;let tn=new Set(We.map(ve=>ve.sessionId)),nt=(ne.get(v)??[]).filter(ve=>!tn.has(ve.sessionId)),Pe=I?nt.findIndex(ve=>ve.sessionId===I.dataset.id):nt.length;Pe<0&&(Pe=nt.length);let $o=Pe>0?nt[Pe-1]:null,So=Pe<nt.length?nt[Pe]:null,hs=Jn($o?ht($o):null,So?ht(So):null);We.forEach((ve,ws)=>{let An=hs+ws*.001;if(ce==="team")et(String(ve.sessionId),v,An);else{let ys={column:ve.kanbanColumn,position:ve.kanbanPosition};ve.kanbanColumn=v,ve.kanbanPosition=An,Nt(ve,v,An,ys)}}),B="",P();return}let D=Y.sessions.get(f)??Ze.get(f);if(!D||D.status==="closed"&&v!=="done")return;let W=(ne.get(v)??[]).filter(We=>We.sessionId!==f),N=I?W.findIndex(We=>We.sessionId===I.dataset.id):W.length;N<0&&(N=W.length);let X=N>0?W[N-1]:null,we=N<W.length?W[N]:null,ze=Jn(X?ht(X):null,we?ht(we):null);if(ce==="team"){et(String(D.sessionId),v,ze),B="",P();return}let Cn={column:D.kanbanColumn,position:D.kanbanPosition};D.kanbanColumn=v,D.kanbanPosition=ze,B="",P(),Nt(D,v,ze,Cn)}),w.addEventListener("dragend",()=>{re=null,me=null,be=null,Mt(),B="",P()}),p.addEventListener("click",l=>{l.target===p&&p.close()}),p.addEventListener("close",()=>{p.innerHTML=""}),S.addEventListener("click",l=>{l.target===S&&S.close()}),S.addEventListener("close",()=>{S.innerHTML=""}),s.addEventListener("change",()=>{let l=xe().filter(c=>c.status!=="closed");for(let c of l)s.checked?T.add(c.sessionId):T.delete(c.sessionId);P()}),k.addEventListener("click",()=>{T.clear(),P()}),m.addEventListener("click",async()=>{let l=[...T];if(l.length===0||!confirm(t("sessions.closeBulkConfirm",{count:l.length})))return;m.disabled=!0,k.disabled=!0;let c=m.textContent,g=0,f=0,b=[...l];m.textContent=`0/${l.length}`;async function v(){for(;b.length;){let I=b.shift();try{let D=await fetch(`/api/sessions/${encodeURIComponent(I)}/close`,{method:"POST"}),W=await D.json().catch(()=>({}));(!D.ok||W?.ok===!1)&&(f+=1)}catch{f+=1}finally{g+=1,m.textContent=`${g}/${l.length}`}}}await Promise.all(Array.from({length:Math.min(6,l.length)},()=>v())),m.textContent=c,m.disabled=!1,k.disabled=!1,T.clear(),P(),f>0&&alert(`Failed: ${f}/${l.length}`)}),$.querySelectorAll("th[data-sort]").forEach(l=>{l.addEventListener("click",()=>{let c=l.dataset.sort;R===c?q=q==="asc"?"desc":"asc":(R=c,q=c==="spawnedAt"||c==="lastMessageAt"?"desc":"asc"),P()})}),o.addEventListener("input",P),Y.on(P);let bs=setInterval(()=>{if(!document.body.contains(w)){clearInterval(bs);return}u==="kanban"&&ce==="team"&&(B="",P())},3e4);P(),Ke().then(P)}function pi(){return`<section class="page">
|
|
350
350
|
<div class="page-heading">
|
|
351
351
|
<div>
|
|
352
352
|
<p class="eyebrow">${t("nav.schedules")}</p>
|
|
@@ -371,13 +371,13 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
371
371
|
</tr></thead>
|
|
372
372
|
<tbody id="schedules-tbody"></tbody>
|
|
373
373
|
</table>
|
|
374
|
-
</section>`}function
|
|
374
|
+
</section>`}function fa(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function ga(e){e.innerHTML=pi();let n=e.querySelector("#schedules-tbody"),o=e.querySelector("#sched-filters");function a(){let r=new FormData(o),d=(r.get("q")??"").toLowerCase(),m=r.get("kind"),k=!!r.get("enabled");return[...Y.schedules.values()].filter($=>!m||$.parsed?.kind===m).filter($=>!k||$.enabled).filter($=>!d||JSON.stringify($).toLowerCase().includes(d)).sort(($,M)=>{if($.enabled!==M.enabled)return $.enabled?-1:1;let w=$.nextRunAt?Date.parse($.nextRunAt):1/0,p=M.nextRunAt?Date.parse(M.nextRunAt):1/0;return w-p})}function s(){n.innerHTML=a().map(r=>`<tr data-id="${i(r.id)}">
|
|
375
375
|
<td>${i(r.name??r.id)}</td>
|
|
376
376
|
<td>${i(r.botName??r.larkAppId??"-")}</td>
|
|
377
377
|
<td><code>${i(r.parsed?.display??"?")}</code></td>
|
|
378
378
|
<td>${r.deliver==="new-topic"?`\u{1F195} ${t("schedules.deliveryNewTopic")}`:r.deliver==="local"?`\u{1F515} ${t("schedules.deliveryLocal")}`:t("schedules.deliveryOrigin")}</td>
|
|
379
|
-
<td>${
|
|
380
|
-
<td>${
|
|
379
|
+
<td>${fa(r.nextRunAt)}</td>
|
|
380
|
+
<td>${fa(r.lastRunAt)} ${r.lastStatus==="error"?"\u26A0\uFE0F":""}</td>
|
|
381
381
|
<td>${r.repeat?`${r.repeat.completed}/${r.repeat.times??"\u221E"}`:"\u2014"}</td>
|
|
382
382
|
<td>${r.enabled?"\u2713":"\u2717"}</td>
|
|
383
383
|
<td class="actions-cell">
|
|
@@ -385,7 +385,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
385
385
|
${r.enabled?`<button data-op="pause" type="button">${t("schedules.pause")}</button>`:`<button data-op="resume" type="button">${t("schedules.resume")}</button>`}
|
|
386
386
|
${r.deliver==="local"?"":`<button data-op="delivery" type="button">${r.deliver==="new-topic"?t("schedules.useOrigin"):t("schedules.useNewTopic")}</button>`}
|
|
387
387
|
</td>
|
|
388
|
-
</tr>`).join("")||`<tr><td colspan="9" class="empty">${t("schedules.empty")}</td></tr>`}n.addEventListener("click",async r=>{let d=r.target.closest("button[data-op]");if(!d)return;let m=d.closest("tr[data-id]");if(!m)return;let k=m.dataset.id,$=d.dataset.op;d.disabled=!0;let M=d.textContent;d.textContent="...";try{let
|
|
388
|
+
</tr>`).join("")||`<tr><td colspan="9" class="empty">${t("schedules.empty")}</td></tr>`}n.addEventListener("click",async r=>{let d=r.target.closest("button[data-op]");if(!d)return;let m=d.closest("tr[data-id]");if(!m)return;let k=m.dataset.id,$=d.dataset.op;d.disabled=!0;let M=d.textContent;d.textContent="...";try{let w=await fetch(`/api/schedules/${encodeURIComponent(k)}/${$}`,{method:"POST"}),p=await w.json().catch(()=>({}));(!w.ok||p.ok===!1)&&alert(`Failed: ${w.status} ${p?.error??""}`.trim())}catch(w){alert("Network error: "+w)}finally{d.disabled=!1,d.textContent=M}}),o.addEventListener("input",s),Y.on(s),s()}var De={chats:[],bots:[]};function mi(){return`<section class="page">
|
|
389
389
|
<div class="page-heading">
|
|
390
390
|
<div>
|
|
391
391
|
<p class="eyebrow">${t("nav.groups")}</p>
|
|
@@ -399,7 +399,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
399
399
|
<button type="button" id="g-refresh">${t("groups.refresh")}</button>
|
|
400
400
|
<button type="button" id="g-create" class="primary">${t("groups.create")}</button>
|
|
401
401
|
</form>
|
|
402
|
-
<div id="g-loading">${
|
|
402
|
+
<div id="g-loading">${ct()}</div>
|
|
403
403
|
<div class="table-scroll matrix-scroll" id="g-table-wrap" hidden>
|
|
404
404
|
<table>
|
|
405
405
|
<thead id="g-head"></thead>
|
|
@@ -407,12 +407,12 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
407
407
|
</table>
|
|
408
408
|
</div>
|
|
409
409
|
<dialog id="g-drawer"></dialog>
|
|
410
|
-
</section>`}async function
|
|
410
|
+
</section>`}async function Ht(){De=await(await fetch("/api/groups")).json()}async function fi(){return(await fetch("/api/groups")).json()}function gi(e,n){if(n.size===0)return!0;let o=e?.memberBots??[];for(let a of n)if(!o.some(s=>s.larkAppId===a&&s.inChat))return!1;return!0}function ba(e,n){return e.filter(o=>!n||!n.has(o.larkAppId)).map(o=>`
|
|
411
411
|
<label class="checkbox-row">
|
|
412
|
-
<input type="checkbox" name="bot" value="${i(
|
|
413
|
-
${i(
|
|
412
|
+
<input type="checkbox" name="bot" value="${i(o.larkAppId)}">
|
|
413
|
+
${i(o.botName??o.larkAppId)} <small>(${i(o.larkAppId)})</small>
|
|
414
414
|
</label>
|
|
415
|
-
`).join("")}async function
|
|
415
|
+
`).join("")}async function ha(e){e.innerHTML=mi();let n=e.querySelector("#g-head"),o=e.querySelector("#g-body"),a=e.querySelector("#g-filters"),s=e.querySelector("#g-refresh"),r=e.querySelector("#g-drawer");s.onclick=async()=>{s.disabled=!0;try{await Ht(),p()}finally{s.disabled=!1}};let d=e.querySelector("#g-create");d.onclick=()=>$();let m=e.querySelector("#g-loading"),k=e.querySelector("#g-table-wrap");try{await Ht()}finally{m.remove(),k.hidden=!1}function $(){let E=De.bots;if(E.length===0){alert(t("groups.noBotsOnline"));return}r.innerHTML=`
|
|
416
416
|
<article>
|
|
417
417
|
<header><h3>${t("groups.createTitle")}</h3></header>
|
|
418
418
|
<p>${t("groups.createHelp")}</p>
|
|
@@ -428,14 +428,14 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
428
428
|
</label>
|
|
429
429
|
<fieldset>
|
|
430
430
|
<legend>${t("groups.botPicker")}</legend>
|
|
431
|
-
${
|
|
431
|
+
${ba(E)}
|
|
432
432
|
</fieldset>
|
|
433
433
|
<div class="actions">
|
|
434
434
|
<button type="submit" class="primary">${t("groups.createSubmit")}</button>
|
|
435
435
|
<button type="button" id="g-create-cancel">${t("groups.cancel")}</button>
|
|
436
436
|
</div>
|
|
437
437
|
</form>
|
|
438
|
-
</article>`,r.showModal(),r.querySelector("#g-create-cancel").onclick=()=>r.close(),r.querySelector("#g-createform").onsubmit=async x=>{x.preventDefault();let T=new FormData(x.target),R=(T.get("name")??"").trim(),q=(T.get("bindWorkingDir")??"").trim(),u=T.getAll("bot");if(u.length===0){alert("Pick at least one bot.");return}let
|
|
438
|
+
</article>`,r.showModal(),r.querySelector("#g-create-cancel").onclick=()=>r.close(),r.querySelector("#g-createform").onsubmit=async x=>{x.preventDefault();let T=new FormData(x.target),R=(T.get("name")??"").trim(),q=(T.get("bindWorkingDir")??"").trim(),u=T.getAll("bot");if(u.length===0){alert("Pick at least one bot.");return}let y=x.target.querySelector("button[type=submit]");y&&(y.disabled=!0,y.textContent="Creating...");try{let A=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:R||void 0,larkAppIds:u,bindWorkingDir:q||void 0})}),O=await A.json();if(O.ok&&O.chatId){M(O);let U=Array.isArray(O.invalidBotIds)?O.invalidBotIds:[],B=u.filter(re=>!U.includes(re)),Q=new Set(B);typeof O.creator=="string"&&O.creator&&Q.add(O.creator),C(O.chatId,R||O.chatId,B,O.creator),p(),L(O.chatId,Q).catch(()=>{})}else alert(`Failed: ${O.error??A.status}`),r.close()}catch(A){alert("Network error: "+A),r.close()}};function C(x,T,R,q){let u=new Set(R);q&&u.add(q);let y=De.bots.map(O=>({larkAppId:O.larkAppId,botName:O.botName,inChat:u.has(O.larkAppId),oncallChat:null})),A={chatId:x,name:T,ownerId:q??null,memberBots:y};De.chats=[A,...De.chats.filter(O=>O.chatId!==x)]}async function L(x,T){let R=[600,1200,1200,1200,1200,1200];for(let q of R){await new Promise(A=>setTimeout(A,q));let u;try{u=await fi()}catch{continue}let y=(u.chats??[]).find(A=>A.chatId===x);if(y&&gi(y,T)){De=u,p();return}}}}function M(E){let C=String(E.chatId),L=typeof E.shareLink=="string"&&E.shareLink?E.shareLink:`https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(C)}`,x=E.invalidBotIds??[],T=E.invalidUserIds??[],R=E.autoInvitedOpenId,q=!!E.autoInviteRejected,u=E.ownerTransferredTo,y=E.transferError,A=E.notifyMessageId,O=E.notifyError,U=Array.isArray(E.oncallBindings)?E.oncallBindings:[],B=U.filter(ne=>ne?.ok).length,Q=U.filter(ne=>!ne?.ok),re=U.length>0?Q.length===0?`<p class="hint-ok">\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1A<code>${i(E.bindResolvedPath??"")}</code>\uFF08${B}/${U.length} bots\uFF09</p>`:`<p class="hint-warn">\u76EE\u5F55\u7ED1\u5B9A\u90E8\u5206\u5931\u8D25\uFF1A\u6210\u529F ${B}/${U.length}\u3002${Q.map(ne=>`<br><code>${i(ne.larkAppId??"?")}</code>: ${i(ne.error??"unknown")}`).join("")}</p>`:"",le;if(R){let ne=u?"<br><small>\u7FA4\u4E3B\u5DF2\u4ECE\u673A\u5668\u4EBA\u8F6C\u8BA9\u7ED9\u4F60\u3002</small>":y?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08${i(y)}\uFF09\uFF0C\u4F60\u73B0\u5728\u662F\u6210\u5458\u4F46\u7FA4\u4E3B\u4ECD\u662F\u673A\u5668\u4EBA\u3002</small>`:"",ce=A?`<br><small>\u673A\u5668\u4EBA\u5DF2\u5728\u7FA4\u91CC @ \u4E86\u4F60\uFF08\u6D88\u606F id <code>${i(A)}</code>\uFF09\uFF0C\u770B\u98DE\u4E66\u901A\u77E5\u5C31\u80FD\u8FDB\u7FA4\u3002</small>`:O?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8 @ \u901A\u77E5\u5931\u8D25\uFF08${i(O)}\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>`:"";le=`<p class="hint-ok">\u5DF2\u81EA\u52A8\u9080\u8BF7\u4F60\uFF08<code>${i(R)}</code>\uFF09\u4F5C\u4E3A\u6210\u5458\u3002${ne}${ce}</p>`}else q?le='<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>':le='<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 te=[x.length?`<li>\u65E0\u6548 bot id: <code>${x.map(i).join(", ")}</code></li>`:"",T.length?`<li>\u65E0\u6548\u7528\u6237 open_id: <code>${T.map(i).join(", ")}</code></li>`:""].filter(Boolean).join("");r.innerHTML=`
|
|
439
439
|
<article>
|
|
440
440
|
<header><h3>${t("groups.successTitle")}</h3></header>
|
|
441
441
|
<p><b>chatId:</b> <code>${i(C)}</code> <button type="button" data-copy="${i(C)}">${t("sessions.copy")}</button></p>
|
|
@@ -447,11 +447,11 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
447
447
|
<a class="btn-link primary" href="${L}" target="_blank" rel="noopener">${t("groups.openGroup")}</a>
|
|
448
448
|
<button type="button" id="g-create-close">${t("sessions.dismiss")}</button>
|
|
449
449
|
</div>
|
|
450
|
-
</article>`,r.querySelectorAll("[data-copy]").forEach(ne=>{ne.onclick=()=>{navigator.clipboard.writeText(ne.dataset.copy??""),ne.textContent=t("sessions.copied"),setTimeout(()=>{ne.textContent=t("sessions.copy")},800)}}),r.querySelector("#g-create-close").onclick=()=>r.close()}function
|
|
450
|
+
</article>`,r.querySelectorAll("[data-copy]").forEach(ne=>{ne.onclick=()=>{navigator.clipboard.writeText(ne.dataset.copy??""),ne.textContent=t("sessions.copied"),setTimeout(()=>{ne.textContent=t("sessions.copy")},800)}}),r.querySelector("#g-create-close").onclick=()=>r.close()}function w(){n.innerHTML=`<tr>
|
|
451
451
|
<th>${t("groups.chat")}</th>
|
|
452
452
|
${De.bots.map(E=>`<th>${i(E.botName??E.larkAppId)}</th>`).join("")}
|
|
453
453
|
<th>${t("groups.actions")}</th>
|
|
454
|
-
</tr>`}function p(){
|
|
454
|
+
</tr>`}function p(){w();let E=new FormData(a),C=(E.get("q")??"").toLowerCase(),L=!!E.get("missing"),x=De.chats.filter(T=>!C||(T.name??"").toLowerCase().includes(C)||T.chatId.toLowerCase().includes(C)||(T.ownerId??"").toLowerCase().includes(C)).filter(T=>!L||T.memberBots.some(R=>!R.inChat));if(x.length===0){o.innerHTML=`<tr><td colspan="${De.bots.length+2}" class="empty">${t("groups.empty")}</td></tr>`;return}o.innerHTML=x.map(T=>`<tr data-chat="${i(T.chatId)}">
|
|
455
455
|
<td>
|
|
456
456
|
<div class="g-chat-cell">
|
|
457
457
|
${cn({chatId:T.chatId,name:T.name,avatarUrl:T.avatar,size:"sm"})}
|
|
@@ -466,19 +466,19 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
466
466
|
<button class="add-bots" type="button">${t("groups.addBots")}</button>
|
|
467
467
|
<button class="manage-chat" type="button">${t("groups.manage")}</button>
|
|
468
468
|
</td>
|
|
469
|
-
</tr>`).join("")}p(),
|
|
469
|
+
</tr>`).join("")}p(),o.addEventListener("click",async E=>{let C=E.target.closest("button.add-bots");if(!C)return;let x=C.closest("tr[data-chat]").dataset.chat,T=De.chats.find(u=>u.chatId===x);if(!T)return;let R=new Set(T.memberBots.filter(u=>u.inChat).map(u=>u.larkAppId));if(!De.bots.filter(u=>!R.has(u.larkAppId)).length){alert("All configured bots are already in this chat.");return}r.innerHTML=`
|
|
470
470
|
<article>
|
|
471
471
|
<header><h3>${t("groups.addBots")} \xB7 ${i(T.name??T.chatId)}</h3></header>
|
|
472
472
|
<p>${t("groups.createHelp")}</p>
|
|
473
473
|
<form id="g-addform">
|
|
474
|
-
${
|
|
474
|
+
${ba(De.bots,R)}
|
|
475
475
|
<div class="actions">
|
|
476
476
|
<button type="submit" class="primary">${t("groups.addBots")}</button>
|
|
477
477
|
<button type="button" id="g-cancel">${t("groups.cancel")}</button>
|
|
478
478
|
</div>
|
|
479
479
|
</form>
|
|
480
|
-
</article>`,r.showModal(),r.querySelector("#g-cancel").onclick=()=>r.close(),r.querySelector("#g-addform").onsubmit=async u=>{u.preventDefault();let A=new FormData(u.target).getAll("bot");if(A.length===0){alert("Pick at least one bot.");return}try{let U=await(await fetch(`/api/groups/${encodeURIComponent(x)}/add-bots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:A})})).json();if(U.error==="no_proxy_bot")alert("No bot is currently in this chat \u2014 add one manually in Feishu first, then retry.");else if(U.result){let
|
|
481
|
-
`);alert(
|
|
480
|
+
</article>`,r.showModal(),r.querySelector("#g-cancel").onclick=()=>r.close(),r.querySelector("#g-addform").onsubmit=async u=>{u.preventDefault();let A=new FormData(u.target).getAll("bot");if(A.length===0){alert("Pick at least one bot.");return}try{let U=await(await fetch(`/api/groups/${encodeURIComponent(x)}/add-bots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:A})})).json();if(U.error==="no_proxy_bot")alert("No bot is currently in this chat \u2014 add one manually in Feishu first, then retry.");else if(U.result){let B=U.result.map(Q=>`${Q.id}: ${Q.ok?"OK":`failed (${Q.error??"unknown"})`}`).join(`
|
|
481
|
+
`);alert(B),await Ht(),p()}else alert(`Unexpected response: ${JSON.stringify(U)}`)}catch(O){alert("Network error: "+O)}finally{r.close()}}}),o.addEventListener("click",async E=>{let C=E.target.closest("button.manage-chat");if(!C)return;let x=C.closest("tr[data-chat]").dataset.chat,T=De.chats.find(R=>R.chatId===x);T&&S(T)});function S(E){let C=E.memberBots.filter(x=>x.inChat),L=typeof E.ownerId=="string"?E.ownerId:"";r.innerHTML=`
|
|
482
482
|
<article>
|
|
483
483
|
<header><h3>${t("groups.manageTitle",{name:E.name??E.chatId})}</h3></header>
|
|
484
484
|
<p><b>chatId:</b> <code>${i(E.chatId)}</code></p>
|
|
@@ -521,14 +521,14 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
521
521
|
</div>
|
|
522
522
|
<p class="hint-warn"><small>${t("groups.dangerHint")}</small></p>
|
|
523
523
|
<form method="dialog"><button>${t("sessions.dismiss")}</button></form>
|
|
524
|
-
</article>`,r.showModal(),r.querySelectorAll(".oncall-row").forEach(x=>{let T=x.dataset.bot,R=x.querySelector("input[data-action=toggle]"),q=x.querySelector("input[data-input=workingDir]"),u=x.querySelector("button[data-action=save]"),
|
|
525
|
-
`);alert(q||`Unexpected: ${JSON.stringify(R)}`),await
|
|
526
|
-
\u5173\u95ED\u4E86 ${
|
|
527
|
-
\u5173\u95ED\u4E86 ${
|
|
524
|
+
</article>`,r.showModal(),r.querySelectorAll(".oncall-row").forEach(x=>{let T=x.dataset.bot,R=x.querySelector("input[data-action=toggle]"),q=x.querySelector("input[data-input=workingDir]"),u=x.querySelector("button[data-action=save]"),y=x.querySelector("[data-status]");R.addEventListener("change",()=>{q.disabled=!R.checked,R.checked&&q.focus()}),u.addEventListener("click",async()=>{y.textContent="",y.className="oncall-status";let A=R.checked,O=q.value.trim();if(A&&!O){y.textContent=t("groups.needWorkingDir"),y.classList.add("hint-warn-inline");return}u.disabled=!0;try{let U=`/api/groups/${encodeURIComponent(E.chatId)}/oncall/${encodeURIComponent(T)}`,B=A?await fetch(U,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({workingDir:O})}):await fetch(U,{method:"DELETE"}),Q=await B.json().catch(()=>({}));if(B.ok&&Q.ok){y.textContent=A?`\u2713 \u5DF2\u7ED1\u5B9A \u2192 ${Q.resolvedPath??O}`:"\u2713 \u5DF2\u89E3\u7ED1",y.classList.add("hint-ok");try{await Ht(),p()}catch{}}else y.textContent=`\u2717 ${Q.error??B.status}`,y.classList.add("hint-warn-inline")}catch(U){y.textContent=`\u2717 ${U?.message??U}`,y.classList.add("hint-warn-inline")}finally{u.disabled=!1}})}),r.querySelector("#g-leave-btn").onclick=async()=>{let x=[...r.querySelectorAll("input[name=leave-bot]:checked")].map(T=>T.value);if(x.length===0){alert("\u81F3\u5C11\u9009\u4E00\u4E2A\u673A\u5668\u4EBA");return}if(confirm(`\u786E\u5B9A\u8BA9 ${x.length} \u4E2A\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A\uFF1F\u8BE5 bot \u5728\u6B64\u7FA4\u7684\u4F1A\u8BDD\u4F1A\u4E00\u5E76\u5173\u95ED\u3002`))try{let R=await(await fetch(`/api/groups/${encodeURIComponent(E.chatId)}/leave`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:x})})).json(),q=(R.result??[]).map(u=>{if(!u.ok)return`${u.larkAppId}: \u5931\u8D25 (${u.error??"unknown"})`;let y=u.closedSessions??[],A=y.filter(B=>!B.ok).length,O=y.length-A,U=y.length===0?"":A===0?`\uFF08\u5173\u95ED ${O} \u4E2A\u4F1A\u8BDD\uFF09`:`\uFF08\u5173\u95ED ${O} \u4E2A\uFF0C${A} \u4E2A\u5931\u8D25\uFF09`;return`${u.larkAppId}: OK${U}`}).join(`
|
|
525
|
+
`);alert(q||`Unexpected: ${JSON.stringify(R)}`),await Ht(),p()}catch(T){alert("Network error: "+T)}finally{r.close()}},r.querySelector("#g-disband-btn").onclick=async()=>{if(C.length===0||!confirm(`\u786E\u5B9A\u89E3\u6563\u7FA4\u804A\u300C${E.name??E.chatId}\u300D\uFF1F\u6B64\u64CD\u4F5C\u4E0D\u53EF\u6062\u590D\uFF0C\u672C\u7FA4\u6240\u6709\u673A\u5668\u4EBA\u4F1A\u8BDD\u4E5F\u4F1A\u4E00\u5E76\u5173\u95ED\u3002`))return;let x=[...C].sort((R,q)=>(q.larkAppId===L?1:0)-(R.larkAppId===L?1:0)),T=[];for(let R of x)try{let q=await fetch(`/api/groups/${encodeURIComponent(E.chatId)}/disband`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppId:R.larkAppId})}),u=await q.json();if(u.ok){let y=u.closedSessions??[],A=y.filter(B=>!B.ok).length,O=y.length-A,U=y.length===0?"":A===0?`
|
|
526
|
+
\u5173\u95ED\u4E86 ${O} \u4E2A\u4F1A\u8BDD\u3002`:`
|
|
527
|
+
\u5173\u95ED\u4E86 ${O} \u4E2A\u4F1A\u8BDD\uFF0C${A} \u4E2A\u4F1A\u8BDD\u5173\u95ED\u5931\u8D25\u3002`;alert(`\u5DF2\u89E3\u6563\uFF08\u7531 ${R.botName??R.larkAppId} \u6267\u884C\uFF09${U}`),await Ht(),p(),r.close();return}T.push(`${R.botName??R.larkAppId}: ${u.error??q.status}`)}catch(q){T.push(`${R.botName??R.larkAppId}: ${q}`)}alert(`\u6240\u6709\u5728\u7FA4\u673A\u5668\u4EBA\u5747\u65E0\u6CD5\u89E3\u6563\uFF1A
|
|
528
528
|
${T.join(`
|
|
529
529
|
`)}
|
|
530
530
|
|
|
531
|
-
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}
|
|
531
|
+
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}a.addEventListener("input",p)}var Re={bots:[]},At=null,Ct=null;function wa(e,n){return typeof e?.cliId=="string"&&e.cliId?e.cliId:n}function ya(e){let n=null;for(let o of Y.sessions.values())o.larkAppId!==e||!o.cliId||(!n||Number(o.lastMessageAt??0)>Number(n.lastMessageAt??0))&&(n=o);return n?.cliId??""}function bi(){return`<section class="page">
|
|
532
532
|
<div class="page-heading">
|
|
533
533
|
<div>
|
|
534
534
|
<p class="eyebrow">${t("nav.botDefaults")}</p>
|
|
@@ -544,13 +544,13 @@ ${T.join(`
|
|
|
544
544
|
<aside id="bd-roster" class="bd-roster"></aside>
|
|
545
545
|
<div id="bd-list" class="bd-detail"></div>
|
|
546
546
|
</div>
|
|
547
|
-
</section>`}async function
|
|
548
|
-
${ue({name:
|
|
547
|
+
</section>`}async function va(){try{let e=await fetch("/api/bots"),n=await e.json().catch(()=>({}));if(!e.ok){At=n?.error?`HTTP ${e.status}: ${n.error}${n.path?` (${n.path})`:""}`:`HTTP ${e.status}`,Re={bots:[]};return}if(!n||!Array.isArray(n.bots)){At="unexpected response shape (no `bots` array)",Re={bots:[]};return}At=null,Re=n}catch(e){At=e?.message??String(e),Re={bots:[]}}}function ka(e){if(!e)return"\u2014";let n=new Date(e);return Number.isNaN(n.getTime())?"\u2014":n.toLocaleString()}async function $a(e){e.innerHTML=bi();let n=e.querySelector("#bd-list"),o=e.querySelector("#bd-roster"),a=e.querySelector("#bd-filters"),s=e.querySelector("#bd-refresh");s.onclick=async()=>{s.disabled=!0;try{await va(),r()}finally{s.disabled=!1}},n.addEventListener("click",u=>{let y=u.target.closest(".toggle-tx small, small.bd-help");y&&(u.preventDefault(),y.classList.toggle("open"))}),n.innerHTML=ct(),await va();function r(){let y=(new FormData(a).get("q")??"").toLowerCase(),A=Re.bots.filter(U=>!y||(U.botName??"").toLowerCase().includes(y)||(U.larkAppId??"").toLowerCase().includes(y));if(At){o.innerHTML="",n.innerHTML=`<p class="hint-warn">\u65E0\u6CD5\u52A0\u8F7D bot \u5217\u8868\uFF1A${i(At)}<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(A.length===0){o.innerHTML="",n.innerHTML=`<p class="empty">${t("botDefaults.empty")}</p>`;return}(!Ct||!A.some(U=>U.larkAppId===Ct))&&(Ct=A[0].larkAppId),o.innerHTML=A.map(d).join(""),o.querySelectorAll(".bd-roster-item").forEach(U=>{U.onclick=()=>{Ct=U.dataset.appid,r()}});let O=A.find(U=>U.larkAppId===Ct);n.innerHTML=m(O),q()}function d(u){let y=u.botName??u.larkAppId,A=wa(u,ya(u.larkAppId)),O=u.defaultOncall?.enabled?'<span class="bd-roster-flag">oncall</span>':"";return`<div class="bd-roster-item${u.larkAppId===Ct?" on":""}" data-appid="${i(u.larkAppId)}" role="button" tabindex="0">
|
|
548
|
+
${ue({name:y,larkAppId:u.larkAppId,size:"sm"})}
|
|
549
549
|
<div class="bd-roster-tx">
|
|
550
|
-
<b>${i(
|
|
550
|
+
<b>${i(y)}</b>
|
|
551
551
|
<span>${i(A||u.larkAppId.slice(0,14))}</span>
|
|
552
552
|
</div>
|
|
553
|
-
${
|
|
553
|
+
${O}
|
|
554
554
|
</div>`}function m(u){if(u.error)return`<article class="bd-card bd-profile" data-appid="${i(u.larkAppId)}">
|
|
555
555
|
<header class="bd-profile-head">
|
|
556
556
|
${ue({name:u.botName??u.larkAppId,larkAppId:u.larkAppId})}
|
|
@@ -558,17 +558,17 @@ ${T.join(`
|
|
|
558
558
|
<code>${i(u.larkAppId)}</code></div>
|
|
559
559
|
</header>
|
|
560
560
|
<p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${i(u.error)}</p>
|
|
561
|
-
</article>`;let
|
|
561
|
+
</article>`;let y=u.defaultOncall??{enabled:!1,workingDir:"",since:0},A=!!y.enabled,O=u.botName??u.larkAppId,U=wa(u,ya(u.larkAppId));return`<article class="bd-card bd-profile" data-appid="${i(u.larkAppId)}">
|
|
562
562
|
<header class="bd-profile-head">
|
|
563
|
-
${ue({name:
|
|
563
|
+
${ue({name:O,larkAppId:u.larkAppId,dot:"ok"})}
|
|
564
564
|
<div class="bd-profile-id">
|
|
565
|
-
<strong>${i(
|
|
565
|
+
<strong>${i(O)}</strong>
|
|
566
566
|
${U?`<span class="mate-role">${i(U)}</span>`:""}
|
|
567
567
|
<code>${i(u.larkAppId)}</code>
|
|
568
568
|
</div>
|
|
569
569
|
<div class="bd-profile-meta bd-meta">
|
|
570
570
|
<small class="bd-meta-ok">\u25CF ${t("botDefaults.metaOnline")}</small>
|
|
571
|
-
<small data-oncall-since>${t("botDefaults.lastEnabled")}: ${i(
|
|
571
|
+
<small data-oncall-since>${t("botDefaults.lastEnabled")}: ${i(ka(y.since??0))}</small>
|
|
572
572
|
<small>${t("botDefaults.autobound",{count:u.autoboundChatCount??0})}</small>
|
|
573
573
|
</div>
|
|
574
574
|
</header>
|
|
@@ -586,7 +586,7 @@ ${T.join(`
|
|
|
586
586
|
<label>
|
|
587
587
|
<span>${t("botDefaults.workingDir")}</span>
|
|
588
588
|
<input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
|
|
589
|
-
value="${i(
|
|
589
|
+
value="${i(y.workingDir??"")}" ${A?"":"disabled"}>
|
|
590
590
|
</label>
|
|
591
591
|
</div>
|
|
592
592
|
<div class="actions">
|
|
@@ -599,30 +599,30 @@ ${T.join(`
|
|
|
599
599
|
</section>
|
|
600
600
|
<section class="bd-tile">${k(u)}</section>
|
|
601
601
|
<section class="bd-tile">${p(u)}${E(u)}${C(u)}</section>
|
|
602
|
-
<section class="bd-tile">${
|
|
602
|
+
<section class="bd-tile">${w(u)}${M(u)}</section>
|
|
603
603
|
<section class="bd-tile">${T(u)}</section>
|
|
604
604
|
</div>
|
|
605
|
-
</article>`}function k(u){let
|
|
605
|
+
</article>`}function k(u){let y=typeof u.teamRole=="string";return`<section class="bd-section">
|
|
606
606
|
<h3 class="bd-section-title">${t("botDefaults.sectionRole")}</h3>
|
|
607
607
|
<p class="bd-section-note">${t("botDefaults.roleHelp")}</p>
|
|
608
608
|
<textarea data-input="teamRole" rows="6"
|
|
609
609
|
placeholder="${i(t("botDefaults.rolePlaceholder"))}"
|
|
610
|
-
style="width:100%;box-sizing:border-box;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px"${
|
|
610
|
+
style="width:100%;box-sizing:border-box;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px"${y?"":" disabled"}>${y?i(u.teamRole):""}</textarea>
|
|
611
611
|
<div class="actions">
|
|
612
|
-
<button type="button" class="primary" data-action="save-role"${
|
|
613
|
-
<button type="button" data-action="delete-role"${
|
|
612
|
+
<button type="button" class="primary" data-action="save-role"${y?"":" disabled"}>${t("botDefaults.roleSave")}</button>
|
|
613
|
+
<button type="button" data-action="delete-role"${y?"":" disabled"}>${t("botDefaults.roleDelete")}</button>
|
|
614
614
|
<span class="oncall-status" data-role-status></span>
|
|
615
615
|
</div>
|
|
616
|
-
</section>`}function $(u){return u==null?t("botDefaults.brandStateDefault"):u.trim()===""?t("botDefaults.brandStateOff"):t("botDefaults.brandStateCustom")}function M(u){let
|
|
616
|
+
</section>`}function $(u){return u==null?t("botDefaults.brandStateDefault"):u.trim()===""?t("botDefaults.brandStateOff"):t("botDefaults.brandStateCustom")}function M(u){let y=u.brandLabel??null;return`<section class="bd-section">
|
|
617
617
|
<h3 class="bd-section-title">${t("botDefaults.sectionBrand")}</h3>
|
|
618
618
|
<div class="bd-row bd-brand">
|
|
619
619
|
<label>
|
|
620
620
|
<span>${t("botDefaults.brandLabel")}</span>
|
|
621
621
|
<input type="text" data-input="brandLabel"
|
|
622
622
|
placeholder="${i(t("botDefaults.brandLabelPlaceholder"))}"
|
|
623
|
-
value="${i(
|
|
623
|
+
value="${i(y??"")}">
|
|
624
624
|
</label>
|
|
625
|
-
<small data-brand-state>${i($(
|
|
625
|
+
<small data-brand-state>${i($(y))}</small>
|
|
626
626
|
<small class="bd-help">${t("botDefaults.brandLabelHelp")}</small>
|
|
627
627
|
<div class="actions">
|
|
628
628
|
<button type="button" class="primary" data-action="save-brand">${t("botDefaults.brandSave")}</button>
|
|
@@ -630,38 +630,38 @@ ${T.join(`
|
|
|
630
630
|
<span class="oncall-status" data-brand-status></span>
|
|
631
631
|
</div>
|
|
632
632
|
</div>
|
|
633
|
-
</section>`}function
|
|
633
|
+
</section>`}function w(u){let y=u.disableStreamingCard===!0,A=u.writableTerminalLinkInCard===!0,O=u.privateCard===!0;return`<section class="bd-section">
|
|
634
634
|
<h3 class="bd-section-title">${t("botDefaults.sectionCard")}</h3>
|
|
635
635
|
<label class="toggle-row">
|
|
636
|
-
<input type="checkbox" data-action="toggle-disable-streaming" ${
|
|
636
|
+
<input type="checkbox" data-action="toggle-disable-streaming" ${y?"checked":""}>
|
|
637
637
|
<span class="switch" aria-hidden="true"></span>
|
|
638
638
|
<span class="toggle-tx"><strong>${t("botDefaults.disableStreaming")}</strong>
|
|
639
639
|
<small>${t("botDefaults.disableStreamingHelp")}</small></span>
|
|
640
640
|
</label>
|
|
641
641
|
<label class="toggle-row">
|
|
642
|
-
<input type="checkbox" data-action="toggle-writable-link" ${A?"checked":""} ${
|
|
642
|
+
<input type="checkbox" data-action="toggle-writable-link" ${A?"checked":""} ${y?"disabled":""}>
|
|
643
643
|
<span class="switch" aria-hidden="true"></span>
|
|
644
644
|
<span class="toggle-tx"><strong>${t("botDefaults.writableLink")}</strong>
|
|
645
645
|
<small>${t("botDefaults.writableLinkHelp")}</small></span>
|
|
646
646
|
</label>
|
|
647
647
|
<label class="toggle-row">
|
|
648
|
-
<input type="checkbox" data-action="toggle-private-card" ${
|
|
648
|
+
<input type="checkbox" data-action="toggle-private-card" ${O?"checked":""}>
|
|
649
649
|
<span class="switch" aria-hidden="true"></span>
|
|
650
650
|
<span class="toggle-tx"><strong>${t("botDefaults.privateCard")}</strong>
|
|
651
651
|
<small>${t("botDefaults.privateCardHelp")}</small></span>
|
|
652
652
|
</label>
|
|
653
653
|
<div class="actions">
|
|
654
|
-
<small data-card-pref-moot class="hint-warn-inline" ${
|
|
654
|
+
<small data-card-pref-moot class="hint-warn-inline" ${y?"":"hidden"}>${t("botDefaults.writableLinkMoot")}</small>
|
|
655
655
|
<span class="oncall-status" data-card-pref-status></span>
|
|
656
656
|
</div>
|
|
657
|
-
</section>`}function p(u){let
|
|
657
|
+
</section>`}function p(u){let y=u.p2pMode==="chat"?"chat":"thread",A=u.regularGroupReplyMode==="new-topic"||u.regularGroupReplyMode==="shared"?u.regularGroupReplyMode:"chat",O=u.regularGroupMentionMode==="topic"||u.regularGroupMentionMode==="never"?u.regularGroupMentionMode:"always",U=u.docSubscribeDefaultMode==="all"?"all":"mention-only",B=(le,te)=>`<option value="${le}" ${A===le?"selected":""}>${i(te)}</option>`,Q=(le,te)=>`<option value="${le}" ${O===le?"selected":""}>${i(te)}</option>`,re=(le,te)=>`<option value="${le}" ${U===le?"selected":""}>${i(te)}</option>`;return`<section class="bd-section">
|
|
658
658
|
<h3 class="bd-section-title">${t("botDefaults.sectionSessionMode")}</h3>
|
|
659
659
|
<div class="bd-row">
|
|
660
660
|
<label>
|
|
661
661
|
<span>${t("botDefaults.p2pMode")}</span>
|
|
662
662
|
<select data-input="p2pMode">
|
|
663
|
-
<option value="thread" ${
|
|
664
|
-
<option value="chat" ${
|
|
663
|
+
<option value="thread" ${y==="chat"?"":"selected"}>${i(t("botDefaults.p2pThread"))}</option>
|
|
664
|
+
<option value="chat" ${y==="chat"?"selected":""}>${i(t("botDefaults.p2pChat"))}</option>
|
|
665
665
|
</select>
|
|
666
666
|
</label>
|
|
667
667
|
<small class="bd-help">${t("botDefaults.p2pHelp")}</small>
|
|
@@ -673,9 +673,9 @@ ${T.join(`
|
|
|
673
673
|
<label>
|
|
674
674
|
<span>${t("botDefaults.regularGroupMode")}</span>
|
|
675
675
|
<select data-input="regularGroupMode">
|
|
676
|
-
${
|
|
677
|
-
${
|
|
678
|
-
${
|
|
676
|
+
${B("chat",t("botDefaults.regularGroupModeChat"))}
|
|
677
|
+
${B("new-topic",t("botDefaults.regularGroupModeNewTopic"))}
|
|
678
|
+
${B("shared",t("botDefaults.regularGroupModeShared"))}
|
|
679
679
|
</select>
|
|
680
680
|
</label>
|
|
681
681
|
<small class="bd-help">${t("botDefaults.regularGroupModeHelp")}</small>
|
|
@@ -710,16 +710,16 @@ ${T.join(`
|
|
|
710
710
|
<span class="oncall-status" data-doc-subscribe-mode-status></span>
|
|
711
711
|
</div>
|
|
712
712
|
</div>
|
|
713
|
-
</section>`}function S(u){return u==null?t("botDefaults.maxLiveWorkersStateDefault"):t("botDefaults.maxLiveWorkersStateOn",{count:u})}function E(u){let
|
|
713
|
+
</section>`}function S(u){return u==null?t("botDefaults.maxLiveWorkersStateDefault"):t("botDefaults.maxLiveWorkersStateOn",{count:u})}function E(u){let y=typeof u.maxLiveWorkers=="number"?u.maxLiveWorkers:null;return`<div class="bd-subsection">
|
|
714
714
|
<h4 class="bd-subsection-title">${t("botDefaults.sectionSessionCap")}</h4>
|
|
715
715
|
<div class="bd-row bd-quota">
|
|
716
716
|
<label>
|
|
717
717
|
<span>${t("botDefaults.maxLiveWorkers")}</span>
|
|
718
718
|
<input type="number" min="1" step="1" data-input="maxLiveWorkers"
|
|
719
719
|
placeholder="${i(t("botDefaults.maxLiveWorkersPlaceholder"))}"
|
|
720
|
-
value="${
|
|
720
|
+
value="${y??""}">
|
|
721
721
|
</label>
|
|
722
|
-
<small data-session-cap-state>${i(S(
|
|
722
|
+
<small data-session-cap-state>${i(S(y))}</small>
|
|
723
723
|
<small class="bd-help">${t("botDefaults.maxLiveWorkersHelp")}</small>
|
|
724
724
|
<div class="actions">
|
|
725
725
|
<button type="button" class="primary" data-action="save-session-cap">${t("botDefaults.maxLiveWorkersSave")}</button>
|
|
@@ -727,20 +727,20 @@ ${T.join(`
|
|
|
727
727
|
<span class="oncall-status" data-session-cap-status></span>
|
|
728
728
|
</div>
|
|
729
729
|
</div>
|
|
730
|
-
</div>`}function C(u){let
|
|
730
|
+
</div>`}function C(u){let y=typeof u.startupCommands=="string"?u.startupCommands:"";return`<div class="bd-subsection">
|
|
731
731
|
<h4 class="bd-subsection-title">${t("botDefaults.sectionStartupCommands")}</h4>
|
|
732
732
|
<p class="bd-section-note">${t("botDefaults.startupCommandsHelp")}</p>
|
|
733
733
|
<textarea data-input="startupCommands" rows="3"
|
|
734
734
|
placeholder="${i(t("botDefaults.startupCommandsPlaceholder"))}"
|
|
735
|
-
style="width:100%;box-sizing:border-box;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px">${i(
|
|
735
|
+
style="width:100%;box-sizing:border-box;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px">${i(y)}</textarea>
|
|
736
736
|
<div class="actions">
|
|
737
737
|
<button type="button" class="primary" data-action="save-startup-commands">${t("botDefaults.startupCommandsSave")}</button>
|
|
738
738
|
<span class="oncall-status" data-startup-commands-status></span>
|
|
739
739
|
</div>
|
|
740
|
-
</div>`}function L(u){let
|
|
740
|
+
</div>`}function L(u){let y=u.sandbox===!0;return`<section class="bd-section">
|
|
741
741
|
<h3 class="bd-section-title">${t("botDefaults.sectionSandbox")}</h3>
|
|
742
742
|
<label class="toggle-row">
|
|
743
|
-
<input type="checkbox" data-action="toggle-sandbox" ${
|
|
743
|
+
<input type="checkbox" data-action="toggle-sandbox" ${y?"checked":""}>
|
|
744
744
|
<span class="switch" aria-hidden="true"></span>
|
|
745
745
|
<span class="toggle-tx"><strong>${t("botDefaults.sandboxToggle")}</strong>
|
|
746
746
|
<small>${t("botDefaults.sandboxHelp")}</small></span>
|
|
@@ -748,10 +748,10 @@ ${T.join(`
|
|
|
748
748
|
<div class="actions">
|
|
749
749
|
<span class="oncall-status" data-sandbox-status></span>
|
|
750
750
|
</div>
|
|
751
|
-
</section>`}function x(u){return u==null?t("botDefaults.quotaStateOff"):t("botDefaults.quotaStateOn",{count:u})}function T(u){let
|
|
751
|
+
</section>`}function x(u){return u==null?t("botDefaults.quotaStateOff"):t("botDefaults.quotaStateOn",{count:u})}function T(u){let y=u.restrictGrantCommands===!0,A=typeof u.messageQuotaDefaultLimit=="number"?u.messageQuotaDefaultLimit:null;return`<section class="bd-section">
|
|
752
752
|
<h3 class="bd-section-title">${t("botDefaults.sectionGrant")}</h3>
|
|
753
753
|
<label class="toggle-row">
|
|
754
|
-
<input type="checkbox" data-action="toggle-restrict-grant" ${
|
|
754
|
+
<input type="checkbox" data-action="toggle-restrict-grant" ${y?"checked":""}>
|
|
755
755
|
<span class="switch" aria-hidden="true"></span>
|
|
756
756
|
<span class="toggle-tx"><strong>${t("botDefaults.restrictGrant")}</strong>
|
|
757
757
|
<small>${t("botDefaults.restrictGrantHelp")}</small></span>
|
|
@@ -771,10 +771,10 @@ ${T.join(`
|
|
|
771
771
|
<span class="oncall-status" data-grant-status></span>
|
|
772
772
|
</div>
|
|
773
773
|
</div>
|
|
774
|
-
</section>`}function R(u){let
|
|
774
|
+
</section>`}function R(u){let y=u.autoStartOnGroupJoin===!0,A=u.autoStartOnNewTopic===!0,O=typeof u.autoStartOnGroupJoinPrompt=="string"?u.autoStartOnGroupJoinPrompt:"";return`<div class="bd-subsection">
|
|
775
775
|
<h4 class="bd-subsection-title">${t("botDefaults.sectionAutoStart")}</h4>
|
|
776
776
|
<label class="toggle-row">
|
|
777
|
-
<input type="checkbox" data-action="toggle-auto-join" ${
|
|
777
|
+
<input type="checkbox" data-action="toggle-auto-join" ${y?"checked":""}>
|
|
778
778
|
<span class="switch" aria-hidden="true"></span>
|
|
779
779
|
<span class="toggle-tx"><strong>${t("botDefaults.autoStartJoin")}</strong>
|
|
780
780
|
<small>${t("botDefaults.autoStartJoinHelp")}</small></span>
|
|
@@ -783,7 +783,7 @@ ${T.join(`
|
|
|
783
783
|
<label>
|
|
784
784
|
<span>${t("botDefaults.autoStartJoinPrompt")}</span>
|
|
785
785
|
<textarea data-input="autoJoinPrompt" rows="3"
|
|
786
|
-
placeholder="${i(t("botDefaults.autoStartJoinPromptPlaceholder"))}">${i(
|
|
786
|
+
placeholder="${i(t("botDefaults.autoStartJoinPromptPlaceholder"))}">${i(O)}</textarea>
|
|
787
787
|
</label>
|
|
788
788
|
<div class="actions">
|
|
789
789
|
<button type="button" class="primary" data-action="save-auto-join-prompt">${t("botDefaults.autoStartJoinPromptSave")}</button>
|
|
@@ -798,7 +798,7 @@ ${T.join(`
|
|
|
798
798
|
<div class="actions">
|
|
799
799
|
<span class="oncall-status" data-auto-start-status></span>
|
|
800
800
|
</div>
|
|
801
|
-
</div>`}function q(){n.querySelectorAll(".bd-card").forEach(u=>{let w=u.dataset.appid,A=u.querySelector("input[data-action=toggle]"),P=u.querySelector("input[data-input=workingDir]"),U=u.querySelector("button[data-action=save]"),O=u.querySelector("[data-status]");if(!A||!P||!U||!O)return;A.addEventListener("change",()=>{P.disabled=!A.checked,A.checked&&P.focus()}),U.addEventListener("click",async()=>{O.textContent="",O.className="oncall-status";let V=A.checked,_=P.value.trim();if(V&&!_){O.textContent=t("botDefaults.required"),O.classList.add("hint-warn-inline");return}U.disabled=!0;try{let j=await fetch(`/api/bots/${encodeURIComponent(w)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:V,workingDir:_})}),J=await j.json().catch(()=>({}));if(j.ok&&J.ok){let z=J.resolvedPath?` \u2192 ${J.resolvedPath}`:"";O.textContent=V?`\u2713 \u5DF2\u5F00\u542F${z}\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",O.classList.add("hint-ok");let B=Re.bots.find(He=>He.larkAppId===w);B&&J.defaultOncall&&(B.defaultOncall=J.defaultOncall);let pe=u.querySelector("[data-oncall-since]");pe&&J.defaultOncall?.since!=null&&(pe.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${vo(J.defaultOncall.since)}`)}else O.textContent=`\u2717 ${J.error??j.status}`,O.classList.add("hint-warn-inline")}catch(j){O.textContent=`\u2717 ${j?.message??j}`,O.classList.add("hint-warn-inline")}finally{U.disabled=!1}});let Q=u.querySelector("input[data-input=brandLabel]"),re=u.querySelector("button[data-action=save-brand]"),le=u.querySelector("button[data-action=reset-brand]"),te=u.querySelector("[data-brand-status]"),ne=u.querySelector("[data-brand-state]");async function ce(V,_){if(te){te.textContent="",te.className="oncall-status",_.disabled=!0;try{let j=await fetch(`/api/bots/${encodeURIComponent(w)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:V})}),J=await j.json().catch(()=>({}));if(j.ok&&J.ok){let z=J.brandLabel??null;te.textContent="\u2713",te.classList.add("hint-ok"),Q&&(Q.value=z??""),ne&&(ne.textContent=$(z));let B=Re.bots.find(pe=>pe.larkAppId===w);B&&(B.brandLabel=z)}else te.textContent=`\u2717 ${J.error??j.status}`,te.classList.add("hint-warn-inline")}catch(j){te.textContent=`\u2717 ${j?.message??j}`,te.classList.add("hint-warn-inline")}finally{_.disabled=!1}}}Q&&re&&re.addEventListener("click",()=>ce(Q.value,re)),le&&le.addEventListener("click",()=>ce(null,le));let me=u.querySelector("input[data-action=toggle-disable-streaming]"),be=u.querySelector("input[data-action=toggle-writable-link]"),ie=u.querySelector("input[data-action=toggle-private-card]"),Ue=u.querySelector("[data-card-pref-status]"),Xe=u.querySelector("[data-card-pref-moot]");async function we(V,_,j=Ue){if(j){j.textContent="",j.className="oncall-status",_.disabled=!0;try{let J=await fetch(`/api/bots/${encodeURIComponent(w)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(V)}),z=await J.json().catch(()=>({}));if(J.ok&&z.ok){j.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,j.classList.add("hint-ok");let B=Re.bots.find(pe=>pe.larkAppId===w);B&&(B.disableStreamingCard=z.disableStreamingCard,B.writableTerminalLinkInCard=z.writableTerminalLinkInCard,B.privateCard=z.privateCard,B.autoStartOnGroupJoin=z.autoStartOnGroupJoin,B.autoStartOnGroupJoinPrompt=z.autoStartOnGroupJoinPrompt,B.autoStartOnNewTopic=z.autoStartOnNewTopic,B.regularGroupReplyMode=z.regularGroupReplyMode,B.regularGroupMentionMode=z.regularGroupMentionMode,B.docSubscribeDefaultMode=z.docSubscribeDefaultMode)}else j.textContent=`\u2717 ${z.error??J.status}`,j.classList.add("hint-warn-inline")}catch(J){j.textContent=`\u2717 ${J?.message??J}`,j.classList.add("hint-warn-inline")}finally{_===be?_.disabled=!!me?.checked:_.disabled=!1}}}me&&me.addEventListener("change",()=>{let V=me.checked;be&&(be.disabled=V),Xe&&(Xe.hidden=!V),we({disableStreamingCard:V},me)}),be&&be.addEventListener("change",()=>{we({writableTerminalLinkInCard:be.checked},be)}),ie&&ie.addEventListener("change",()=>{we({privateCard:ie.checked},ie)});let fe=u.querySelector("input[data-action=toggle-sandbox]"),ae=u.querySelector("[data-sandbox-status]");fe&&fe.addEventListener("change",async()=>{let V=fe.checked;ae&&(ae.textContent="",ae.className="oncall-status"),fe.disabled=!0;try{let _=await fetch(`/api/bots/${encodeURIComponent(w)}/sandbox`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:V})}),j=await _.json().catch(()=>({}));if(_.ok&&j.ok){ae&&(ae.textContent=`\u2713 ${t("botDefaults.sandboxSaved")}`,ae.classList.add("hint-ok"));let J=Re.bots.find(z=>z.larkAppId===w);J&&(J.sandbox=j.sandbox===!0)}else ae&&(ae.textContent=`\u2717 ${j.error??_.status}`,ae.classList.add("hint-warn-inline")),fe.checked=!V}catch(_){ae&&(ae.textContent=`\u2717 ${_?.message??_}`,ae.classList.add("hint-warn-inline")),fe.checked=!V}finally{fe.disabled=!1}});let de=u.querySelector("input[data-action=toggle-auto-join]"),Me=u.querySelector("input[data-action=toggle-auto-topic]"),Fe=u.querySelector("textarea[data-input=autoJoinPrompt]"),Oe=u.querySelector("button[data-action=save-auto-join-prompt]"),Ze=u.querySelector("[data-auto-start-status]");de&&de.addEventListener("change",()=>{we({autoStartOnGroupJoin:de.checked},de,Ze)}),Me&&Me.addEventListener("change",()=>{we({autoStartOnNewTopic:Me.checked},Me,Ze)}),Fe&&Oe&&Oe.addEventListener("click",()=>{we({autoStartOnGroupJoinPrompt:Fe.value},Oe,Ze)});let Ne=u.querySelector("select[data-input=p2pMode]"),Pe=u.querySelector("[data-p2p-status]");Ne&&Pe&&Ne.addEventListener("change",async()=>{let V=Ne.value==="chat"?"chat":"thread";Pe.textContent="",Pe.className="oncall-status",Ne.disabled=!0;try{let _=await fetch(`/api/bots/${encodeURIComponent(w)}/p2p-mode`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({p2pMode:V})}),j=await _.json().catch(()=>({}));if(_.ok&&j.ok){Pe.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,Pe.classList.add("hint-ok");let J=Re.bots.find(z=>z.larkAppId===w);J&&(J.p2pMode=j.p2pMode==="chat"?"chat":"thread")}else Pe.textContent=`\u2717 ${j.error??_.status}`,Pe.classList.add("hint-warn-inline")}catch(_){Pe.textContent=`\u2717 ${_?.message??_}`,Pe.classList.add("hint-warn-inline")}finally{Ne.disabled=!1}});let et=u.querySelector("select[data-input=regularGroupMode]"),Pt=u.querySelector("[data-regular-group-status]");et&&et.addEventListener("change",()=>{we({regularGroupReplyMode:et.value},et,Pt)});let st=u.querySelector("select[data-input=regularGroupMentionMode]"),Bt=u.querySelector("[data-mention-mode-status]");st&&st.addEventListener("change",()=>{we({regularGroupMentionMode:st.value},st,Bt)});let he=u.querySelector("select[data-input=docSubscribeDefaultMode]"),it=u.querySelector("[data-doc-subscribe-mode-status]");he&&he.addEventListener("change",()=>{we({docSubscribeDefaultMode:he.value},he,it)});let tt=u.querySelector("textarea[data-input=teamRole]"),H=u.querySelector("button[data-action=save-role]"),se=u.querySelector("button[data-action=delete-role]"),G=u.querySelector("[data-role-status]");if(tt&&H&&se&&G){let j=function(z){let B=n.querySelector(`.bd-card[data-appid="${CSS.escape(w)}"]`);if(!B)return;let pe=B.querySelector("textarea[data-input=teamRole]"),He=B.querySelector("button[data-action=save-role]"),_e=B.querySelector("button[data-action=delete-role]");pe&&(pe.value=z,pe.disabled=!1),He&&(He.disabled=!1),_e&&(_e.disabled=!1)};var Hn=j;let V=`/api/team/local-bots/${encodeURIComponent(w)}/role`,_=Re.bots.find(z=>z.larkAppId===w);_&&typeof _.teamRole!="string"&&!_.teamRoleLoading&&(_.teamRoleLoading=!0,(async()=>{try{let z=await fetch(V),B=await z.json().catch(()=>({}));z.ok&&B.ok?(_.teamRole=B.role??"",j(_.teamRole)):(G.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${B.error??z.status}`,G.classList.add("hint-warn-inline"))}catch(z){G.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${z?.message??z}`,G.classList.add("hint-warn-inline")}finally{_.teamRoleLoading=!1}})());async function J(z,B,pe){if(G&&!(!_||typeof _.teamRole!="string")){G.textContent="",G.className="oncall-status",H.disabled=!0,se.disabled=!0;try{let He=await fetch(V,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({role:z})}),_e=await He.json().catch(()=>({}));He.ok&&_e.ok?(_&&(_.teamRole=z.trim()),G.textContent=`\u2713 ${pe?t("botDefaults.roleDeleted"):t("botDefaults.roleSaved")}`,G.classList.add("hint-ok")):(G.textContent=`\u2717 ${_e.error??He.status}`,G.classList.add("hint-warn-inline"))}catch(He){G.textContent=`\u2717 ${He?.message??He}`,G.classList.add("hint-warn-inline")}finally{H.disabled=!1,se.disabled=!1}}}H.addEventListener("click",()=>J(tt.value,H,!1)),se.addEventListener("click",()=>{tt.value="",J("",se,!0)})}let K=u.querySelector("input[data-action=toggle-restrict-grant]"),ge=u.querySelector("input[data-input=quotaLimit]"),Ge=u.querySelector("button[data-action=save-quota]"),St=u.querySelector("button[data-action=off-quota]"),Ee=u.querySelector("[data-grant-status]"),Ot=u.querySelector("[data-quota-state]");async function ft(V,_){if(Ee){Ee.textContent="",Ee.className="oncall-status",_.disabled=!0;try{let j=await fetch(`/api/bots/${encodeURIComponent(w)}/grant-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(V)}),J=await j.json().catch(()=>({}));if(j.ok&&J.ok){Ee.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,Ee.classList.add("hint-ok");let z=typeof J.messageQuotaDefaultLimit=="number"?J.messageQuotaDefaultLimit:null,B=Re.bots.find(pe=>pe.larkAppId===w);B&&(B.restrictGrantCommands=J.restrictGrantCommands===!0,B.messageQuotaDefaultLimit=z),Ot&&(Ot.textContent=x(z)),ge&&"messageQuotaDefaultLimit"in V&&(ge.value=z==null?"":String(z))}else Ee.textContent=`\u2717 ${J.error??j.status}`,Ee.classList.add("hint-warn-inline")}catch(j){Ee.textContent=`\u2717 ${j?.message??j}`,Ee.classList.add("hint-warn-inline")}finally{_.disabled=!1}}}K&&K.addEventListener("change",()=>{ft({restrictGrantCommands:K.checked},K)}),ge&&Ge&&Ge.addEventListener("click",()=>{let V=ge.value.trim();if(V===""){ft({messageQuotaDefaultLimit:null},Ge);return}if(!/^[1-9]\d*$/.test(V)){Ee&&(Ee.textContent=`\u2717 ${t("botDefaults.quotaInvalid")}`,Ee.className="oncall-status hint-warn-inline");return}ft({messageQuotaDefaultLimit:Number(V)},Ge)}),ge&&St&&St.addEventListener("click",()=>{ge.value="",ft({messageQuotaDefaultLimit:null},St)});let rt=u.querySelector("input[data-input=maxLiveWorkers]"),Lt=u.querySelector("button[data-action=save-session-cap]"),Tt=u.querySelector("button[data-action=off-session-cap]"),Le=u.querySelector("[data-session-cap-status]"),Nt=u.querySelector("[data-session-cap-state]");async function It(V,_){if(Le){Le.textContent="",Le.className="oncall-status",_.disabled=!0;try{let j=await fetch(`/api/bots/${encodeURIComponent(w)}/max-live-workers`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({maxLiveWorkers:V})}),J=await j.json().catch(()=>({}));if(j.ok&&J.ok){Le.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,Le.classList.add("hint-ok");let z=typeof J.maxLiveWorkers=="number"?J.maxLiveWorkers:null,B=Re.bots.find(pe=>pe.larkAppId===w);B&&(B.maxLiveWorkers=z),Nt&&(Nt.textContent=S(z)),rt&&(rt.value=z==null?"":String(z))}else Le.textContent=`\u2717 ${J.error??j.status}`,Le.classList.add("hint-warn-inline")}catch(j){Le.textContent=`\u2717 ${j?.message??j}`,Le.classList.add("hint-warn-inline")}finally{_.disabled=!1}}}rt&&Lt&&Lt.addEventListener("click",()=>{let V=rt.value.trim();if(V===""){It(null,Lt);return}if(!/^[1-9]\d*$/.test(V)){Le&&(Le.textContent=`\u2717 ${t("botDefaults.maxLiveWorkersInvalid")}`,Le.className="oncall-status hint-warn-inline");return}It(Number(V),Lt)}),rt&&Tt&&Tt.addEventListener("click",()=>{rt.value="",It(null,Tt)});let qt=u.querySelector("textarea[data-input=startupCommands]"),gt=u.querySelector("button[data-action=save-startup-commands]"),xe=u.querySelector("[data-startup-commands-status]");qt&>&>.addEventListener("click",async()=>{if(xe){xe.textContent="",xe.className="oncall-status",gt.disabled=!0;try{let V=await fetch(`/api/bots/${encodeURIComponent(w)}/startup-commands`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({startupCommands:qt.value})}),_=await V.json().catch(()=>({}));if(V.ok&&_.ok){xe.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,xe.classList.add("hint-ok");let j=typeof _.startupCommands=="string"?_.startupCommands:"";qt.value=j;let J=Re.bots.find(z=>z.larkAppId===w);J&&(J.startupCommands=j)}else xe.textContent=`\u2717 ${_.error??V.status}`,xe.classList.add("hint-warn-inline")}catch(V){xe.textContent=`\u2717 ${V?.message??V}`,xe.classList.add("hint-warn-inline")}finally{gt.disabled=!1}}})})}r(),Ke().then(r),s.addEventListener("input",r)}var oe={skills:[],bots:[],trustProjectSkills:"off",delivery:"auto"},mn=null,bi=2,ht=0;function hi(){return`<section class="page">
|
|
801
|
+
</div>`}function q(){n.querySelectorAll(".bd-card").forEach(u=>{let y=u.dataset.appid,A=u.querySelector("input[data-action=toggle]"),O=u.querySelector("input[data-input=workingDir]"),U=u.querySelector("button[data-action=save]"),B=u.querySelector("[data-status]");if(!A||!O||!U||!B)return;A.addEventListener("change",()=>{O.disabled=!A.checked,A.checked&&O.focus()}),U.addEventListener("click",async()=>{B.textContent="",B.className="oncall-status";let V=A.checked,_=O.value.trim();if(V&&!_){B.textContent=t("botDefaults.required"),B.classList.add("hint-warn-inline");return}U.disabled=!0;try{let j=await fetch(`/api/bots/${encodeURIComponent(y)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:V,workingDir:_})}),J=await j.json().catch(()=>({}));if(j.ok&&J.ok){let z=J.resolvedPath?` \u2192 ${J.resolvedPath}`:"";B.textContent=V?`\u2713 \u5DF2\u5F00\u542F${z}\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",B.classList.add("hint-ok");let P=Re.bots.find(He=>He.larkAppId===y);P&&J.defaultOncall&&(P.defaultOncall=J.defaultOncall);let pe=u.querySelector("[data-oncall-since]");pe&&J.defaultOncall?.since!=null&&(pe.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${ka(J.defaultOncall.since)}`)}else B.textContent=`\u2717 ${J.error??j.status}`,B.classList.add("hint-warn-inline")}catch(j){B.textContent=`\u2717 ${j?.message??j}`,B.classList.add("hint-warn-inline")}finally{U.disabled=!1}});let Q=u.querySelector("input[data-input=brandLabel]"),re=u.querySelector("button[data-action=save-brand]"),le=u.querySelector("button[data-action=reset-brand]"),te=u.querySelector("[data-brand-status]"),ne=u.querySelector("[data-brand-state]");async function ce(V,_){if(te){te.textContent="",te.className="oncall-status",_.disabled=!0;try{let j=await fetch(`/api/bots/${encodeURIComponent(y)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:V})}),J=await j.json().catch(()=>({}));if(j.ok&&J.ok){let z=J.brandLabel??null;te.textContent="\u2713",te.classList.add("hint-ok"),Q&&(Q.value=z??""),ne&&(ne.textContent=$(z));let P=Re.bots.find(pe=>pe.larkAppId===y);P&&(P.brandLabel=z)}else te.textContent=`\u2717 ${J.error??j.status}`,te.classList.add("hint-warn-inline")}catch(j){te.textContent=`\u2717 ${j?.message??j}`,te.classList.add("hint-warn-inline")}finally{_.disabled=!1}}}Q&&re&&re.addEventListener("click",()=>ce(Q.value,re)),le&&le.addEventListener("click",()=>ce(null,le));let me=u.querySelector("input[data-action=toggle-disable-streaming]"),be=u.querySelector("input[data-action=toggle-writable-link]"),ie=u.querySelector("input[data-action=toggle-private-card]"),Ue=u.querySelector("[data-card-pref-status]"),Xe=u.querySelector("[data-card-pref-moot]");async function ye(V,_,j=Ue){if(j){j.textContent="",j.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(V)}),z=await J.json().catch(()=>({}));if(J.ok&&z.ok){j.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,j.classList.add("hint-ok");let P=Re.bots.find(pe=>pe.larkAppId===y);P&&(P.disableStreamingCard=z.disableStreamingCard,P.writableTerminalLinkInCard=z.writableTerminalLinkInCard,P.privateCard=z.privateCard,P.autoStartOnGroupJoin=z.autoStartOnGroupJoin,P.autoStartOnGroupJoinPrompt=z.autoStartOnGroupJoinPrompt,P.autoStartOnNewTopic=z.autoStartOnNewTopic,P.regularGroupReplyMode=z.regularGroupReplyMode,P.regularGroupMentionMode=z.regularGroupMentionMode,P.docSubscribeDefaultMode=z.docSubscribeDefaultMode)}else j.textContent=`\u2717 ${z.error??J.status}`,j.classList.add("hint-warn-inline")}catch(J){j.textContent=`\u2717 ${J?.message??J}`,j.classList.add("hint-warn-inline")}finally{_===be?_.disabled=!!me?.checked:_.disabled=!1}}}me&&me.addEventListener("change",()=>{let V=me.checked;be&&(be.disabled=V),Xe&&(Xe.hidden=!V),ye({disableStreamingCard:V},me)}),be&&be.addEventListener("change",()=>{ye({writableTerminalLinkInCard:be.checked},be)}),ie&&ie.addEventListener("change",()=>{ye({privateCard:ie.checked},ie)});let fe=u.querySelector("input[data-action=toggle-sandbox]"),oe=u.querySelector("[data-sandbox-status]");fe&&fe.addEventListener("change",async()=>{let V=fe.checked;oe&&(oe.textContent="",oe.className="oncall-status"),fe.disabled=!0;try{let _=await fetch(`/api/bots/${encodeURIComponent(y)}/sandbox`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:V})}),j=await _.json().catch(()=>({}));if(_.ok&&j.ok){oe&&(oe.textContent=`\u2713 ${t("botDefaults.sandboxSaved")}`,oe.classList.add("hint-ok"));let J=Re.bots.find(z=>z.larkAppId===y);J&&(J.sandbox=j.sandbox===!0)}else oe&&(oe.textContent=`\u2717 ${j.error??_.status}`,oe.classList.add("hint-warn-inline")),fe.checked=!V}catch(_){oe&&(oe.textContent=`\u2717 ${_?.message??_}`,oe.classList.add("hint-warn-inline")),fe.checked=!V}finally{fe.disabled=!1}});let de=u.querySelector("input[data-action=toggle-auto-join]"),Me=u.querySelector("input[data-action=toggle-auto-topic]"),Fe=u.querySelector("textarea[data-input=autoJoinPrompt]"),Be=u.querySelector("button[data-action=save-auto-join-prompt]"),Ze=u.querySelector("[data-auto-start-status]");de&&de.addEventListener("change",()=>{ye({autoStartOnGroupJoin:de.checked},de,Ze)}),Me&&Me.addEventListener("change",()=>{ye({autoStartOnNewTopic:Me.checked},Me,Ze)}),Fe&&Be&&Be.addEventListener("click",()=>{ye({autoStartOnGroupJoinPrompt:Fe.value},Be,Ze)});let Ne=u.querySelector("select[data-input=p2pMode]"),Oe=u.querySelector("[data-p2p-status]");Ne&&Oe&&Ne.addEventListener("change",async()=>{let V=Ne.value==="chat"?"chat":"thread";Oe.textContent="",Oe.className="oncall-status",Ne.disabled=!0;try{let _=await fetch(`/api/bots/${encodeURIComponent(y)}/p2p-mode`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({p2pMode:V})}),j=await _.json().catch(()=>({}));if(_.ok&&j.ok){Oe.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,Oe.classList.add("hint-ok");let J=Re.bots.find(z=>z.larkAppId===y);J&&(J.p2pMode=j.p2pMode==="chat"?"chat":"thread")}else Oe.textContent=`\u2717 ${j.error??_.status}`,Oe.classList.add("hint-warn-inline")}catch(_){Oe.textContent=`\u2717 ${_?.message??_}`,Oe.classList.add("hint-warn-inline")}finally{Ne.disabled=!1}});let et=u.querySelector("select[data-input=regularGroupMode]"),Pt=u.querySelector("[data-regular-group-status]");et&&et.addEventListener("change",()=>{ye({regularGroupReplyMode:et.value},et,Pt)});let it=u.querySelector("select[data-input=regularGroupMentionMode]"),Bt=u.querySelector("[data-mention-mode-status]");it&&it.addEventListener("change",()=>{ye({regularGroupMentionMode:it.value},it,Bt)});let he=u.querySelector("select[data-input=docSubscribeDefaultMode]"),rt=u.querySelector("[data-doc-subscribe-mode-status]");he&&he.addEventListener("change",()=>{ye({docSubscribeDefaultMode:he.value},he,rt)});let tt=u.querySelector("textarea[data-input=teamRole]"),H=u.querySelector("button[data-action=save-role]"),se=u.querySelector("button[data-action=delete-role]"),G=u.querySelector("[data-role-status]");if(tt&&H&&se&&G){let j=function(z){let P=n.querySelector(`.bd-card[data-appid="${CSS.escape(y)}"]`);if(!P)return;let pe=P.querySelector("textarea[data-input=teamRole]"),He=P.querySelector("button[data-action=save-role]"),_e=P.querySelector("button[data-action=delete-role]");pe&&(pe.value=z,pe.disabled=!1),He&&(He.disabled=!1),_e&&(_e.disabled=!1)};var Hn=j;let V=`/api/team/local-bots/${encodeURIComponent(y)}/role`,_=Re.bots.find(z=>z.larkAppId===y);_&&typeof _.teamRole!="string"&&!_.teamRoleLoading&&(_.teamRoleLoading=!0,(async()=>{try{let z=await fetch(V),P=await z.json().catch(()=>({}));z.ok&&P.ok?(_.teamRole=P.role??"",j(_.teamRole)):(G.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${P.error??z.status}`,G.classList.add("hint-warn-inline"))}catch(z){G.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${z?.message??z}`,G.classList.add("hint-warn-inline")}finally{_.teamRoleLoading=!1}})());async function J(z,P,pe){if(G&&!(!_||typeof _.teamRole!="string")){G.textContent="",G.className="oncall-status",H.disabled=!0,se.disabled=!0;try{let He=await fetch(V,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({role:z})}),_e=await He.json().catch(()=>({}));He.ok&&_e.ok?(_&&(_.teamRole=z.trim()),G.textContent=`\u2713 ${pe?t("botDefaults.roleDeleted"):t("botDefaults.roleSaved")}`,G.classList.add("hint-ok")):(G.textContent=`\u2717 ${_e.error??He.status}`,G.classList.add("hint-warn-inline"))}catch(He){G.textContent=`\u2717 ${He?.message??He}`,G.classList.add("hint-warn-inline")}finally{H.disabled=!1,se.disabled=!1}}}H.addEventListener("click",()=>J(tt.value,H,!1)),se.addEventListener("click",()=>{tt.value="",J("",se,!0)})}let K=u.querySelector("input[data-action=toggle-restrict-grant]"),ge=u.querySelector("input[data-input=quotaLimit]"),Ge=u.querySelector("button[data-action=save-quota]"),Lt=u.querySelector("button[data-action=off-quota]"),Ee=u.querySelector("[data-grant-status]"),Nt=u.querySelector("[data-quota-state]");async function gt(V,_){if(Ee){Ee.textContent="",Ee.className="oncall-status",_.disabled=!0;try{let j=await fetch(`/api/bots/${encodeURIComponent(y)}/grant-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(V)}),J=await j.json().catch(()=>({}));if(j.ok&&J.ok){Ee.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,Ee.classList.add("hint-ok");let z=typeof J.messageQuotaDefaultLimit=="number"?J.messageQuotaDefaultLimit:null,P=Re.bots.find(pe=>pe.larkAppId===y);P&&(P.restrictGrantCommands=J.restrictGrantCommands===!0,P.messageQuotaDefaultLimit=z),Nt&&(Nt.textContent=x(z)),ge&&"messageQuotaDefaultLimit"in V&&(ge.value=z==null?"":String(z))}else Ee.textContent=`\u2717 ${J.error??j.status}`,Ee.classList.add("hint-warn-inline")}catch(j){Ee.textContent=`\u2717 ${j?.message??j}`,Ee.classList.add("hint-warn-inline")}finally{_.disabled=!1}}}K&&K.addEventListener("change",()=>{gt({restrictGrantCommands:K.checked},K)}),ge&&Ge&&Ge.addEventListener("click",()=>{let V=ge.value.trim();if(V===""){gt({messageQuotaDefaultLimit:null},Ge);return}if(!/^[1-9]\d*$/.test(V)){Ee&&(Ee.textContent=`\u2717 ${t("botDefaults.quotaInvalid")}`,Ee.className="oncall-status hint-warn-inline");return}gt({messageQuotaDefaultLimit:Number(V)},Ge)}),ge&&Lt&&Lt.addEventListener("click",()=>{ge.value="",gt({messageQuotaDefaultLimit:null},Lt)});let lt=u.querySelector("input[data-input=maxLiveWorkers]"),Tt=u.querySelector("button[data-action=save-session-cap]"),It=u.querySelector("button[data-action=off-session-cap]"),Le=u.querySelector("[data-session-cap-status]"),qt=u.querySelector("[data-session-cap-state]");async function Mt(V,_){if(Le){Le.textContent="",Le.className="oncall-status",_.disabled=!0;try{let j=await fetch(`/api/bots/${encodeURIComponent(y)}/max-live-workers`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({maxLiveWorkers:V})}),J=await j.json().catch(()=>({}));if(j.ok&&J.ok){Le.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,Le.classList.add("hint-ok");let z=typeof J.maxLiveWorkers=="number"?J.maxLiveWorkers:null,P=Re.bots.find(pe=>pe.larkAppId===y);P&&(P.maxLiveWorkers=z),qt&&(qt.textContent=S(z)),lt&&(lt.value=z==null?"":String(z))}else Le.textContent=`\u2717 ${J.error??j.status}`,Le.classList.add("hint-warn-inline")}catch(j){Le.textContent=`\u2717 ${j?.message??j}`,Le.classList.add("hint-warn-inline")}finally{_.disabled=!1}}}lt&&Tt&&Tt.addEventListener("click",()=>{let V=lt.value.trim();if(V===""){Mt(null,Tt);return}if(!/^[1-9]\d*$/.test(V)){Le&&(Le.textContent=`\u2717 ${t("botDefaults.maxLiveWorkersInvalid")}`,Le.className="oncall-status hint-warn-inline");return}Mt(Number(V),Tt)}),lt&&It&&It.addEventListener("click",()=>{lt.value="",Mt(null,It)});let jt=u.querySelector("textarea[data-input=startupCommands]"),bt=u.querySelector("button[data-action=save-startup-commands]"),xe=u.querySelector("[data-startup-commands-status]");jt&&bt&&bt.addEventListener("click",async()=>{if(xe){xe.textContent="",xe.className="oncall-status",bt.disabled=!0;try{let V=await fetch(`/api/bots/${encodeURIComponent(y)}/startup-commands`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({startupCommands:jt.value})}),_=await V.json().catch(()=>({}));if(V.ok&&_.ok){xe.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,xe.classList.add("hint-ok");let j=typeof _.startupCommands=="string"?_.startupCommands:"";jt.value=j;let J=Re.bots.find(z=>z.larkAppId===y);J&&(J.startupCommands=j)}else xe.textContent=`\u2717 ${_.error??V.status}`,xe.classList.add("hint-warn-inline")}catch(V){xe.textContent=`\u2717 ${V?.message??V}`,xe.classList.add("hint-warn-inline")}finally{bt.disabled=!1}}})})}r(),Ke().then(r),a.addEventListener("input",r)}var ae={skills:[],bots:[],trustProjectSkills:"off",delivery:"auto"},mn=null,hi=2,wt=0;function wi(){return`<section class="page">
|
|
802
802
|
<div class="page-heading">
|
|
803
803
|
<div>
|
|
804
804
|
<p class="eyebrow">${t("nav.skills")}</p>
|
|
@@ -808,7 +808,7 @@ ${T.join(`
|
|
|
808
808
|
<button type="button" id="skills-refresh">${t("skills.refresh")}</button>
|
|
809
809
|
</div>
|
|
810
810
|
<div id="skills-body"></div>
|
|
811
|
-
</section>`}function yi(e){let n=e.source??{};return n.type==="github"?`github:${n.owner}/${n.repo}/${n.path??""}`:n.type==="git"?`${n.url??"git"}#${n.path??""}`:n.type==="local-link"?"local-link":n.type==="local-copy"?"local-copy":String(n.type??"unknown")}function
|
|
811
|
+
</section>`}function yi(e){let n=e.source??{};return n.type==="github"?`github:${n.owner}/${n.repo}/${n.path??""}`:n.type==="git"?`${n.url??"git"}#${n.path??""}`:n.type==="local-link"?"local-link":n.type==="local-copy"?"local-copy":String(n.type??"unknown")}function zt(e){return(e?.include??[]).filter(n=>n.startsWith("skill:")).map(n=>n.slice(6))}function vi(e){return zt(e).length}function ki(e){return zt(e).length>0}function $i(){return new Set(ae.skills.map(e=>e.name))}function Si(e){return ae.bots.filter(n=>zt(n.skills).includes(e)).map(n=>n.botName??n.larkAppId)}function Li(){return`<article class="bd-card skills-install-panel">
|
|
812
812
|
<div class="skills-install-title">
|
|
813
813
|
<h3 class="bd-section-title">${t("skills.install")}</h3>
|
|
814
814
|
<span class="skills-help-tip">
|
|
@@ -835,50 +835,50 @@ ${T.join(`
|
|
|
835
835
|
<button type="button" class="primary" data-action="install">${t("skills.installSubmit")}</button>
|
|
836
836
|
<span class="oncall-status" data-skills-status></span>
|
|
837
837
|
</div>
|
|
838
|
-
</article>`}function
|
|
839
|
-
<article class="skills-row skills-installed-card" data-skill="${i(
|
|
838
|
+
</article>`}function Ti(){if(ae.skills.length===0)return`<p class="empty">${t("skills.empty")}</p>`;fn();let e=Sa(),n=wt*e;return`<div class="skills-list">${ae.skills.slice(n,n+e).map(a=>`
|
|
839
|
+
<article class="skills-row skills-installed-card" data-skill="${i(a.name)}">
|
|
840
840
|
<div class="skills-row-body">
|
|
841
|
-
<strong>${i(
|
|
842
|
-
${
|
|
843
|
-
<small>${i(yi(
|
|
841
|
+
<strong>${i(a.name)}</strong>
|
|
842
|
+
${a.description?`<p>${i(a.description)}</p>`:""}
|
|
843
|
+
<small>${i(yi(a))}</small>
|
|
844
844
|
</div>
|
|
845
845
|
<div class="skills-card-actions">
|
|
846
846
|
<button type="button" data-action="update-skill">${t("skills.update")}</button>
|
|
847
847
|
<button type="button" data-action="remove-skill">${t("skills.remove")}</button>
|
|
848
848
|
</div>
|
|
849
|
-
</article>`).join("")}</div>`}function
|
|
849
|
+
</article>`).join("")}</div>`}function Ii(){let e=typeof window>"u"?1440:window.innerWidth;return e>=1600?4:e<=620?1:e<=980?2:3}function Sa(){return Ii()*hi}function La(){return Math.max(1,Math.ceil(ae.skills.length/Sa()))}function fn(){wt=Math.min(Math.max(0,wt),La()-1)}function Mi(){fn();let e=`<span class="skills-count-pill">${t("skills.skillCount",{count:ae.skills.length})}</span>`,n=La();return n<=1?e:`<div class="skills-installed-toolbar">
|
|
850
850
|
${e}
|
|
851
851
|
<div class="skills-pager">
|
|
852
|
-
<button type="button" class="skills-pager-button" data-action="page-installed-skills" data-dir="-1" aria-label="${t("skills.prevPage")}" title="${t("skills.prevPage")}" ${
|
|
853
|
-
<span>${t("skills.pageStatus",{page:
|
|
854
|
-
<button type="button" class="skills-pager-button" data-action="page-installed-skills" data-dir="1" aria-label="${t("skills.nextPage")}" title="${t("skills.nextPage")}" ${
|
|
852
|
+
<button type="button" class="skills-pager-button" data-action="page-installed-skills" data-dir="-1" aria-label="${t("skills.prevPage")}" title="${t("skills.prevPage")}" ${wt===0?"disabled":""}>‹</button>
|
|
853
|
+
<span>${t("skills.pageStatus",{page:wt+1,pages:n})}</span>
|
|
854
|
+
<button type="button" class="skills-pager-button" data-action="page-installed-skills" data-dir="1" aria-label="${t("skills.nextPage")}" title="${t("skills.nextPage")}" ${wt>=n-1?"disabled":""}>›</button>
|
|
855
855
|
</div>
|
|
856
|
-
</div>`}function
|
|
856
|
+
</div>`}function Ei(){let e=[["auto",t("skills.deliveryAuto"),t("skills.deliveryAutoHelp")],["prompt",t("skills.deliveryPrompt"),t("skills.deliveryPromptHelp")],["native",t("skills.deliveryNative"),t("skills.deliveryNativeHelp")]];return`<article class="bd-card skills-defaults-panel">
|
|
857
857
|
<h3 class="bd-section-title">${t("skills.globalDefaults")}</h3>
|
|
858
858
|
<div class="skills-control-block">
|
|
859
859
|
<span class="skills-control-label">${t("skills.globalProject")}</span>
|
|
860
860
|
<div class="skills-choice-group skills-choice-group-compact skills-project-group">
|
|
861
|
-
${[["off",t("skills.globalProjectOff"),t("skills.globalProjectOffHelp")],["all",t("skills.globalProjectAll"),t("skills.globalProjectAllHelp")]].map(([n,a
|
|
862
|
-
<strong>${
|
|
861
|
+
${[["off",t("skills.globalProjectOff"),t("skills.globalProjectOffHelp")],["all",t("skills.globalProjectAll"),t("skills.globalProjectAllHelp")]].map(([n,o,a])=>`<button type="button" class="skills-choice${ae.trustProjectSkills===n?" selected":""}" data-global-project-value="${n}" aria-pressed="${ae.trustProjectSkills===n?"true":"false"}">
|
|
862
|
+
<strong>${o}</strong><small>${a}</small>
|
|
863
863
|
</button>`).join("")}
|
|
864
864
|
</div>
|
|
865
865
|
</div>
|
|
866
866
|
<div class="skills-control-block">
|
|
867
867
|
<span class="skills-control-label">${t("skills.globalDelivery")}</span>
|
|
868
868
|
<div class="skills-choice-group skills-delivery-group">
|
|
869
|
-
${e.map(([n,a
|
|
870
|
-
<strong>${
|
|
869
|
+
${e.map(([n,o,a])=>`<button type="button" class="skills-choice${ae.delivery===n?" selected":""}" data-global-delivery-value="${n}" aria-pressed="${ae.delivery===n?"true":"false"}">
|
|
870
|
+
<strong>${o}</strong><small>${a}</small>
|
|
871
871
|
</button>`).join("")}
|
|
872
872
|
</div>
|
|
873
873
|
</div>
|
|
874
|
-
</article>`}function
|
|
875
|
-
${
|
|
874
|
+
</article>`}function xi(e){let n=new Set(zt(e.skills)),o=ae.skills.filter(a=>!n.has(a.name));return o.length===0?`<button type="button" disabled>${t("skills.attach")}</button>`:`<select data-attach-picker>
|
|
875
|
+
${o.map(a=>`<option value="${i(a.name)}">${i(a.name)}</option>`).join("")}
|
|
876
876
|
</select>
|
|
877
|
-
<button type="button" data-action="attach-skill">${t("skills.attach")}</button>`}function
|
|
877
|
+
<button type="button" data-action="attach-skill">${t("skills.attach")}</button>`}function Hi(e){if(e.error)return`<article class="bd-card skills-bot-card" data-appid="${i(e.larkAppId)}">
|
|
878
878
|
<header>${ue({name:e.botName??e.larkAppId,larkAppId:e.larkAppId,size:"sm"})}
|
|
879
879
|
<strong>${i(e.botName??e.larkAppId)}</strong></header>
|
|
880
880
|
<p class="hint-warn-inline">${i(e.error)}</p>
|
|
881
|
-
</article>`;let n=
|
|
881
|
+
</article>`;let n=zt(e.skills),o=$i();return`<article class="bd-card skills-bot-card" data-appid="${i(e.larkAppId)}">
|
|
882
882
|
<header class="skills-bot-head">
|
|
883
883
|
${ue({name:e.botName??e.larkAppId,larkAppId:e.larkAppId,size:"sm",dot:"ok"})}
|
|
884
884
|
<div><strong>${i(e.botName??e.larkAppId)}</strong><code>${i(e.larkAppId)}</code></div>
|
|
@@ -886,43 +886,43 @@ ${T.join(`
|
|
|
886
886
|
</header>
|
|
887
887
|
<section class="bd-section">
|
|
888
888
|
<h3 class="bd-section-title">${t("skills.priority")}</h3>
|
|
889
|
-
${n.length===0?`<p class="bd-section-note">${t("skills.noPriority")}</p>`:`<div class="skills-chip-list">${n.map(
|
|
890
|
-
<span class="skills-priority-name">${i(
|
|
891
|
-
<button type="button" class="skills-priority-remove" data-action="detach-skill" data-name="${i(
|
|
889
|
+
${n.length===0?`<p class="bd-section-note">${t("skills.noPriority")}</p>`:`<div class="skills-chip-list">${n.map(a=>{let s=!o.has(a);return`<span class="skills-priority-row${s?" skills-priority-dangling":""}" title="${s?i(t("skills.dangling")):""}">
|
|
890
|
+
<span class="skills-priority-name">${i(a)}${s?`<small>${t("skills.dangling")}</small>`:""}</span>
|
|
891
|
+
<button type="button" class="skills-priority-remove" data-action="detach-skill" data-name="${i(a)}" aria-label="${i(t("skills.detachNamed",{skill:a}))}">×</button>
|
|
892
892
|
</span>`}).join("")}</div>`}
|
|
893
|
-
<div class="actions skills-attach-row">${
|
|
893
|
+
<div class="actions skills-attach-row">${xi(e)}</div>
|
|
894
894
|
</section>
|
|
895
895
|
<span class="oncall-status" data-bot-status></span>
|
|
896
|
-
</article>`}function
|
|
896
|
+
</article>`}function Ci(){return ae.bots.reduce((e,n)=>e+vi(n.skills),0)}function Ai(){return ae.bots.filter(e=>ki(e.skills)).length}function Di(){return`<section class="skills-overview">
|
|
897
897
|
<div class="skills-overview-copy">
|
|
898
898
|
<h2>${t("skills.overviewTitle")}</h2>
|
|
899
899
|
<p>${t("skills.overviewBody")}</p>
|
|
900
900
|
</div>
|
|
901
901
|
<div class="skills-metric-strip">
|
|
902
|
-
<span><small>${t("skills.metricInstalled")}</small><strong>${
|
|
903
|
-
<span><small>${t("skills.metricBots")}</small><strong>${
|
|
904
|
-
<span><small>${t("skills.metricAttached")}</small><strong>${
|
|
902
|
+
<span><small>${t("skills.metricInstalled")}</small><strong>${ae.skills.length}</strong></span>
|
|
903
|
+
<span><small>${t("skills.metricBots")}</small><strong>${Ai()}/${ae.bots.length}</strong></span>
|
|
904
|
+
<span><small>${t("skills.metricAttached")}</small><strong>${Ci()}</strong></span>
|
|
905
905
|
</div>
|
|
906
|
-
</section>`}function
|
|
906
|
+
</section>`}function Ri(){let e=`<span class="skills-count-pill">${t("skills.botCount",{count:ae.bots.length})}</span>`;return ae.bots.length<=3?e:`<div class="skills-bot-rail-actions">
|
|
907
907
|
<button type="button" class="skills-rail-button" data-action="scroll-bots" data-dir="-1" aria-label="${t("skills.scrollBotsPrev")}" title="${t("skills.scrollBotsPrev")}">‹</button>
|
|
908
908
|
${e}
|
|
909
909
|
<button type="button" class="skills-rail-button" data-action="scroll-bots" data-dir="1" aria-label="${t("skills.scrollBotsNext")}" title="${t("skills.scrollBotsNext")}">›</button>
|
|
910
|
-
</div>`}function
|
|
910
|
+
</div>`}function Oi(){return mn?`<p class="hint-warn">${i(mn)}</p>`:`<div class="skills-page-grid">
|
|
911
911
|
<aside class="skills-side-rail">
|
|
912
|
-
${
|
|
913
|
-
${
|
|
912
|
+
${Ei()}
|
|
913
|
+
${Li()}
|
|
914
914
|
</aside>
|
|
915
915
|
<section class="skills-main-panel">
|
|
916
|
-
${
|
|
916
|
+
${Di()}
|
|
917
917
|
<section class="skills-bots-panel">
|
|
918
918
|
<div class="skills-section-head skills-section-head-row">
|
|
919
919
|
<div>
|
|
920
920
|
<h2>${t("skills.bots")}</h2>
|
|
921
921
|
<p>${t("skills.botsHelp")}</p>
|
|
922
922
|
</div>
|
|
923
|
-
${
|
|
923
|
+
${Ri()}
|
|
924
924
|
</div>
|
|
925
|
-
<div class="skills-bot-grid">${
|
|
925
|
+
<div class="skills-bot-grid">${ae.bots.map(Hi).join("")}</div>
|
|
926
926
|
</section>
|
|
927
927
|
<section class="bd-card skills-installed-panel">
|
|
928
928
|
<div class="skills-section-head skills-section-head-row">
|
|
@@ -930,12 +930,12 @@ ${T.join(`
|
|
|
930
930
|
<h2>${t("skills.installed")}</h2>
|
|
931
931
|
<p>${t("skills.installedHelp")}</p>
|
|
932
932
|
</div>
|
|
933
|
-
${
|
|
933
|
+
${Mi()}
|
|
934
934
|
</div>
|
|
935
|
-
${
|
|
935
|
+
${Ti()}
|
|
936
936
|
</section>
|
|
937
937
|
</section>
|
|
938
|
-
</div>`}async function Pi(){try{let[e,n]=await Promise.all([fetch("/api/skills"),fetch("/api/bots")]),
|
|
938
|
+
</div>`}async function Pi(){try{let[e,n]=await Promise.all([fetch("/api/skills"),fetch("/api/bots")]),o=await e.json().catch(()=>({})),a=await n.json().catch(()=>({}));if(!e.ok)throw new Error(o?.error??`skills HTTP ${e.status}`);if(!n.ok)throw new Error(a?.error??`bots HTTP ${n.status}`);ae={skills:Array.isArray(o.skills)?o.skills:[],bots:Array.isArray(a.bots)?a.bots:[],trustProjectSkills:o.trustProjectSkills==="all"?"all":"off",delivery:o.delivery==="prompt"||o.delivery==="native"?o.delivery:"auto"},fn(),mn=null}catch(e){mn=e?.message??String(e)}}async function ot(e,n){let o=await fetch(e,{...n,headers:{"content-type":"application/json",...n.headers??{}}}),a=await o.json().catch(()=>({}));if(!o.ok||a.ok===!1){let s=new Error(a?.error??`HTTP ${o.status}`);throw s.status=o.status,s.body=a,s}return a}function Bi(e){return new Promise(n=>setTimeout(n,e))}async function Ta(e){e.innerHTML=wi();let n=e.querySelector("#skills-body"),o=e.querySelector("#skills-refresh");async function a(){n.innerHTML=ct(),await Pi(),k()}function s(w){return w?.querySelector("[data-skills-status], [data-bot-status]")??null}function r(w,p,S){w&&(w.textContent=p,w.className=`oncall-status ${S?"hint-ok":"hint-warn-inline"}`)}function d(w,p){n.querySelectorAll(w).forEach(S=>{S.disabled=p})}function m(w,p,S){n.querySelectorAll(w).forEach(E=>{let C=E.dataset[p]===S;E.classList.toggle("selected",C),E.setAttribute("aria-pressed",C?"true":"false")})}function k(){n.innerHTML=Oi(),M()}async function $(w,p){let S=w;for(r(p,t("skills.jobRunning"),!0);;){if(S.status==="succeeded"){r(p,t("skills.saved"),!0),await a();return}if(S.status==="failed")throw new Error(S.error??"job_failed");await Bi(800),S=(await ot(`/api/skills/jobs/${encodeURIComponent(S.id)}`,{method:"GET"})).job}}function M(){n.querySelector('[data-action="install"]')?.addEventListener("click",async()=>{let w=n.querySelector(".skills-install-panel"),p=s(w),S=n.querySelector('[data-action="install"]'),E=n.querySelector('[data-install="source"]')?.value.trim()??"",C=n.querySelector('[data-install="path"]')?.value.trim()??"",L=n.querySelector('[data-install="ref"]')?.value.trim()??"";try{S&&(S.disabled=!0);let x=await ot("/api/skills/install",{method:"POST",body:JSON.stringify({source:E,path:C||void 0,ref:L||void 0})});await $(x.job,p)}catch(x){r(p,`${t("skills.failed")}: ${x?.message??x}`,!1)}finally{S&&(S.disabled=!1)}}),n.querySelectorAll("[data-global-project-value]").forEach(w=>w.addEventListener("click",async()=>{let p=w.dataset.globalProjectValue==="all"?"all":"off";if(ae.trustProjectSkills!==p)try{d("[data-global-project-value]",!0);let S=await ot("/api/skills/global",{method:"PUT",body:JSON.stringify({trustProjectSkills:p})});ae.trustProjectSkills=S.trustProjectSkills==="all"?"all":p,m("[data-global-project-value]","globalProjectValue",ae.trustProjectSkills)}catch(S){window.alert(`${t("skills.failed")}: ${S?.message??S}`)}finally{d("[data-global-project-value]",!1)}})),n.querySelectorAll("[data-global-delivery-value]").forEach(w=>w.addEventListener("click",async()=>{let p=w.dataset.globalDeliveryValue==="prompt"||w.dataset.globalDeliveryValue==="native"?w.dataset.globalDeliveryValue:"auto";if(ae.delivery!==p)try{d("[data-global-delivery-value]",!0);let S=await ot("/api/skills/global",{method:"PUT",body:JSON.stringify({delivery:p})});ae.delivery=S.delivery==="prompt"||S.delivery==="native"?S.delivery:p,m("[data-global-delivery-value]","globalDeliveryValue",ae.delivery)}catch(S){window.alert(`${t("skills.failed")}: ${S?.message??S}`)}finally{d("[data-global-delivery-value]",!1)}})),n.querySelectorAll('[data-action="scroll-bots"]').forEach(w=>w.addEventListener("click",()=>{let p=n.querySelector(".skills-bot-grid"),S=p?.querySelector(".skills-bot-card");if(!p||!S)return;let E=window.getComputedStyle(p),C=Number.parseFloat(E.columnGap||E.gap||"0")||0,L=w.dataset.dir==="-1"?-1:1;p.scrollBy({left:L*(S.getBoundingClientRect().width+C),behavior:"smooth"})})),n.querySelectorAll('[data-action="page-installed-skills"]').forEach(w=>w.addEventListener("click",()=>{let p=w.dataset.dir==="-1"?-1:1;wt+=p,fn(),k()})),n.querySelectorAll(".skills-row").forEach(w=>{let p=w.dataset.skill??"";w.querySelector('[data-action="update-skill"]')?.addEventListener("click",async()=>{let S=w.querySelector('[data-action="update-skill"]'),E=n.querySelector(".skills-install-panel"),C=s(E);try{S&&(S.disabled=!0);let L=await ot(`/api/skills/${encodeURIComponent(p)}/update`,{method:"POST",body:"{}"});await $(L.job,C)}catch(L){window.alert(`${t("skills.failed")}: ${L?.message??L}`)}finally{S&&(S.disabled=!1)}}),w.querySelector('[data-action="remove-skill"]')?.addEventListener("click",async()=>{if(window.confirm(`${t("skills.remove")} ${p}?`))try{await ot(`/api/skills/${encodeURIComponent(p)}`,{method:"DELETE",body:"{}"}),await a()}catch(S){if(S?.status===409&&S?.body?.error==="skill_in_use"){let E=Array.isArray(S.body.affectedBots)?S.body.affectedBots.map(L=>{let x=L?.botName||L?.larkAppId;return x?`${x}`:""}).filter(Boolean):Si(p),C=[E.length?`Bot: ${E.join(", ")}`:""].filter(Boolean).join("; ")||"-";if(!window.confirm(t("skills.removeInUse",{skill:p,refs:C})))return;try{await ot(`/api/skills/${encodeURIComponent(p)}?force=1`,{method:"DELETE",body:"{}"}),await a();return}catch(L){window.alert(`${t("skills.failed")}: ${L?.message??L}`);return}}window.alert(`${t("skills.failed")}: ${S?.message??S}`)}})}),n.querySelectorAll(".skills-bot-card").forEach(w=>{let p=w.dataset.appid??"",S=ae.bots.find(E=>E.larkAppId===p);S&&(w.querySelector('[data-action="attach-skill"]')?.addEventListener("click",async()=>{let E=w.querySelector("[data-attach-picker]")?.value;if(E)try{let C=await ot(`/api/bots/${encodeURIComponent(p)}/skills`,{method:"PUT",body:JSON.stringify({action:"attach",name:E})});S.skills=C.skills??null,k()}catch(C){r(s(w),`${t("skills.failed")}: ${C?.message??C}`,!1)}}),w.querySelectorAll('[data-action="detach-skill"]').forEach(E=>{E.addEventListener("click",async()=>{let C=E.dataset.name;if(C)try{let L=await ot(`/api/bots/${encodeURIComponent(p)}/skills`,{method:"PUT",body:JSON.stringify({action:"detach",name:C})});S.skills=L.skills??null,k()}catch(L){r(s(w),`${t("skills.failed")}: ${L?.message??L}`,!1)}})}))})}o.onclick=()=>{a()},await a()}var Zn=4096,bn=[],Ve=null,Ye=null,je="",Dt=new Set;function Ni(){return`<section class="page roles-page">
|
|
939
939
|
<div class="page-heading">
|
|
940
940
|
<div>
|
|
941
941
|
<p class="eyebrow">${t("nav.roles")}</p>
|
|
@@ -974,27 +974,27 @@ ${T.join(`
|
|
|
974
974
|
</div>
|
|
975
975
|
</div>
|
|
976
976
|
</div>
|
|
977
|
-
</section>`}async function gn(){bn=((await(await fetch("/api/groups")).json()).chats??[]).map(
|
|
978
|
-
<div class="roles-bot-row ${Ve===
|
|
979
|
-
data-group-id="${i(
|
|
980
|
-
data-bot-id="${i(
|
|
977
|
+
</section>`}async function gn(){bn=((await(await fetch("/api/groups")).json()).chats??[]).map(o=>({chatId:o.chatId,name:o.name??o.chatId,memberBots:(o.memberBots??[]).map(a=>({larkAppId:a.larkAppId,botName:a.botName??a.larkAppId,inChat:a.inChat??!1,hasRole:a.hasRole??!1,oncallChat:a.oncallChat??null}))}))}async function Ma(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`)).json()}async function qi(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 ji(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`,{method:"DELETE"})).ok}function Ea(e){return e.memberBots.filter(n=>n.inChat&&n.hasRole).length}function Ui(e){return e.memberBots.filter(n=>n.inChat).length}function yt(e=""){let n=document.getElementById("roles-tree");if(!n)return;let o=e.toLowerCase(),a=bn.filter(s=>{if(!o)return!0;let r=s.chatId.toLowerCase().includes(o)||(s.name??"").toLowerCase().includes(o),d=s.memberBots.some(m=>m.larkAppId.toLowerCase().includes(o)||(m.botName??"").toLowerCase().includes(o));return r||d});if(a.length===0){n.innerHTML=`<div class="roles-empty">${t("roles.noChats")}</div>`;return}n.innerHTML=a.map(s=>{let r=Dt.has(s.chatId),d=s.memberBots.filter(w=>w.inChat),m=r?"\u25BE":"\u25B8",k=Ea(s),$=Ui(s),M=r?d.map(w=>`
|
|
978
|
+
<div class="roles-bot-row ${Ve===s.chatId&&Ye===w.larkAppId?"selected":""}"
|
|
979
|
+
data-group-id="${i(s.chatId)}"
|
|
980
|
+
data-bot-id="${i(w.larkAppId)}">
|
|
981
981
|
<span class="roles-bot-indent"></span>
|
|
982
|
-
${ue({name:
|
|
982
|
+
${ue({name:w.botName,larkAppId:w.larkAppId,size:"sm"})}
|
|
983
983
|
<div class="roles-bot-info">
|
|
984
|
-
<div class="roles-bot-name">${i(
|
|
985
|
-
<div class="roles-bot-id">${i(
|
|
984
|
+
<div class="roles-bot-name">${i(w.botName)}</div>
|
|
985
|
+
<div class="roles-bot-id">${i(w.larkAppId)}</div>
|
|
986
986
|
</div>
|
|
987
|
-
<span class="roles-badge ${
|
|
988
|
-
${
|
|
987
|
+
<span class="roles-badge ${w.hasRole?"has-role":"no-role"}">
|
|
988
|
+
${w.hasRole?t("roles.configured"):t("roles.unconfigured")}
|
|
989
989
|
</span>
|
|
990
990
|
</div>`).join(""):"";return`
|
|
991
991
|
<div class="roles-group-section">
|
|
992
|
-
<div class="roles-group-row ${r?"expanded":""} ${Ve===
|
|
993
|
-
data-group-id="${i(
|
|
992
|
+
<div class="roles-group-row ${r?"expanded":""} ${Ve===s.chatId&&!Ye?"selected":""}"
|
|
993
|
+
data-group-id="${i(s.chatId)}">
|
|
994
994
|
<span class="roles-group-arrow">${m}</span>
|
|
995
995
|
<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>
|
|
996
996
|
<div class="roles-group-info">
|
|
997
|
-
<div class="roles-group-name">${i(
|
|
997
|
+
<div class="roles-group-name">${i(s.name??s.chatId)}</div>
|
|
998
998
|
<div class="roles-group-meta">
|
|
999
999
|
${k}/${$} ${t("roles.botsWithRoles")}
|
|
1000
1000
|
</div>
|
|
@@ -1002,12 +1002,12 @@ ${T.join(`
|
|
|
1002
1002
|
<span class="roles-group-chevron"></span>
|
|
1003
1003
|
</div>
|
|
1004
1004
|
<div class="roles-bot-list">${M}</div>
|
|
1005
|
-
</div>`}).join(""),n.querySelectorAll(".roles-group-row").forEach(
|
|
1005
|
+
</div>`}).join(""),n.querySelectorAll(".roles-group-row").forEach(s=>{s.addEventListener("click",()=>{let r=s.dataset.groupId;r&&(Dt.has(r)?Dt.delete(r):Dt.add(r),yt(document.getElementById("roles-search")?.value??""))})}),n.querySelectorAll(".roles-bot-row").forEach(s=>{s.addEventListener("click",r=>{r.stopPropagation();let d=s.dataset.groupId,m=s.dataset.botId;d&&m&&Fi(d,m)})})}async function Fi(e,n){Ve=e,Ye=n;let o=await Ma(n,e),a=document.getElementById("roles-editor-empty"),s=document.getElementById("roles-editor-form"),r=document.getElementById("roles-editor-textarea"),d=document.getElementById("roles-editor-group-name"),m=document.getElementById("roles-editor-bot-name"),k=document.getElementById("roles-editor-chat-id");a&&(a.style.display="none"),s&&(s.style.display="");let $=bn.find(p=>p.chatId===e),M=$?.memberBots.find(p=>p.larkAppId===n);d&&(d.textContent=$?.name??e),m&&(m.textContent=M?.botName??n),k&&(k.textContent=`${e} \xB7 ${n}`),je=o.content??"",r&&(r.value=je,r.focus()),eo(),to(),yt(document.getElementById("roles-search")?.value??"");let w=document.getElementById("roles-delete");w&&(w.style.display=o.hasRole?"":"none")}function eo(){let e=document.getElementById("roles-editor-bytecount");if(!e)return;let n=new TextEncoder().encode(je).length;e.textContent=`${n} / ${Zn} bytes`,e.className=`roles-bytecount ${n>3800?"warn":""} ${n>Zn?"over":""}`,Gi(n)}function Gi(e){let n=document.getElementById("roles-save");if(!n)return;let o=e??new TextEncoder().encode(je).length;n.disabled=o>Zn||je.trim().length===0}function to(){let e=document.getElementById("roles-preview");e&&(je.trim()?e.innerHTML=`<strong>${t("roles.preview")}</strong><pre>${i(je)}</pre>`:e.innerHTML=`<small>${t("roles.previewEmpty")}</small>`)}function Ia(){Ve=null,Ye=null,je="";let e=document.getElementById("roles-editor-empty"),n=document.getElementById("roles-editor-form"),o=document.getElementById("roles-editor-textarea"),a=document.getElementById("roles-delete");e&&(e.style.display=""),n&&(n.style.display="none"),o&&(o.value=""),a&&(a.style.display="none")}async function xa(e){e.innerHTML=Ni(),Dt.clear(),Ia();let n=document.getElementById("roles-tree");n&&(n.innerHTML=ct()),await gn(),await Ke();for(let o of bn)Ea(o)>0&&Dt.add(o.chatId);yt(),document.getElementById("roles-search")?.addEventListener("input",o=>{yt(o.target.value)}),document.getElementById("roles-refresh")?.addEventListener("click",async()=>{if(await gn(),yt(document.getElementById("roles-search")?.value??""),Ve&&Ye){let o=await Ma(Ye,Ve),a=document.getElementById("roles-editor-textarea");a&&(a.value=o.content??""),je=o.content??"",eo(),to();let s=document.getElementById("roles-delete");s&&(s.style.display=o.hasRole?"":"none")}}),document.getElementById("roles-save")?.addEventListener("click",async function(){if(!(!Ve||!Ye)){this.disabled=!0,this.textContent="...";try{if(await qi(Ye,Ve,je)){await gn(),yt(document.getElementById("roles-search")?.value??"");let a=document.getElementById("roles-delete");a&&(a.style.display="");let s=document.createElement("span");s.className="roles-saved-flash",s.textContent=` ${t("roles.saved")}`,document.querySelector(".roles-editor-footer")?.appendChild(s),setTimeout(()=>s.remove(),2e3)}else{let a=document.createElement("span");a.className="roles-saved-flash roles-save-error",a.textContent=je.trim().length===0?` ${t("roles.emptyError")}`:` ${t("roles.saveFailed")}`,document.querySelector(".roles-editor-footer")?.appendChild(a),setTimeout(()=>a.remove(),3e3)}}finally{this.disabled=!1,this.textContent=t("roles.save")}}}),document.getElementById("roles-delete")?.addEventListener("click",async function(){if(!(!Ve||!Ye)&&confirm(t("roles.confirmDelete"))){this.disabled=!0,this.textContent="...";try{await ji(Ye,Ve)&&(await gn(),Ia(),yt(document.getElementById("roles-search")?.value??""))}finally{this.disabled=!1,this.textContent=t("roles.delete")}}}),document.getElementById("roles-editor-textarea")?.addEventListener("input",o=>{je=o.target.value,eo(),to()})}async function yn(e){let n=await fetch(e);return{status:n.status,body:await n.json().catch(()=>({}))}}async function vn(e,n,o){let a=await fetch(n,{method:e,headers:{"content-type":"application/json"},body:o?JSON.stringify(o):void 0});return{status:a.status,body:await a.json().catch(()=>({}))}}var kt=(e,n)=>vn("POST",e,n),_i=(e,n)=>vn("PUT",e,n),no=[],Ha=[],Ca="",hn="",oo=new Map,wn=new Map,Wt=new Set,Kt=new Set;function Z(e){return document.getElementById(e)}function kn(){return[...no,...Ha]}function vt(e){let n=oo.get(e);return n||(n=new Set,oo.set(e,n)),n}function zi(e){return kn().find(n=>n.key===e)}function Aa(e){let n=(o,a,s)=>`<a href="${o}" style="padding:6px 14px;border-radius:8px;text-decoration:none;font-size:14px;font-weight:600;${s?"background:var(--accent);color:var(--on-accent)":"color:var(--muted);background:var(--surface-muted)"}">${a}</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 Wi(){return`<section class="page">
|
|
1006
1006
|
<div class="page-heading"><div>
|
|
1007
1007
|
<p class="eyebrow">${t("team.eyebrow")}</p><h1>${t("team.homeTitle")}</h1>
|
|
1008
1008
|
<p class="tf-lede">${t("team.homeLede")}</p>
|
|
1009
1009
|
</div></div>
|
|
1010
|
-
${
|
|
1010
|
+
${Aa("home")}
|
|
1011
1011
|
<div class="card" style="margin-bottom:16px">
|
|
1012
1012
|
<h2 style="margin-top:0">${t("team.localDeployTitle")}</h2>
|
|
1013
1013
|
<p>${t("team.myIdentity")}<b id="tf-owner">${t("team.unbound")}</b>
|
|
@@ -1036,12 +1036,12 @@ ${Co("home")}
|
|
|
1036
1036
|
</div>
|
|
1037
1037
|
</div>
|
|
1038
1038
|
</div>
|
|
1039
|
-
</section>`}function
|
|
1039
|
+
</section>`}function Ki(e){let n=(Z("tf-search").value||"").trim().toLowerCase();if(n&&!((e.name||"")+" "+(e.cliId||"")+" "+(e.capability||"")).toLowerCase().includes(n))return!1;let o=Z("tf-cli").value;return!(o&&e.cliId!==o||Z("tf-fcap").checked&&!e.capability||Z("tf-frole").checked&&!e.hasTeamRole)}function Ji(e,n){let o=[...e.deployments].sort((s,r)=>s.local===r.local?0:s.local?-1:1),a="";for(let s of o){let r=n.filter(p=>p.deployment.id===s.id);if(!r.length)continue;let d=s.id===Ca,m=d?t("team.tagLocal"):s.stale?t("team.tagRemoteStale"):t("team.tagRemote"),k=e.kind==="local"&&!d?` <button class="tf-rmmember ghost" data-team="${i(e.teamId)}" data-dep="${i(s.id)}" data-name="${i(s.name)}" style="font-size:12px">${t("team.removeMember")}</button>`:"",$=`${e.key}::${s.id}`,M=Kt.has($),w=r.filter(p=>vt(e.key).has(p.larkAppId)).length;if(a+=`<div class="tf-dep-h" data-dk="${i($)}" style="cursor:pointer;margin:10px 0 2px"><b>${M?"\u25BE":"\u25B8"} ${i(s.name)}</b> <span class="muted" style="font-size:12px">${t("team.depTag",{tag:m})} \xB7 ${t("team.depCount",{count:r.length})}${w?t("team.depSelected",{n:w}):""}</span>${k}</div>`,!!M){a+='<table style="width:100%;border-collapse:collapse;font-size:14px"><tbody>';for(let p of r){let S=i(p.larkAppId),E=vt(e.key).has(p.larkAppId)?" checked":"",C=p.deployment.stale?"opacity:.55":"",L=d?`<input class="tf-cap" data-app="${S}" value="${i(p.capability||"")}" placeholder="${t("team.capPh")}" style="width:92%;padding:3px 6px">`:p.capability?i(p.capability):'<span class="muted">\u2014</span>',x=p.hasTeamRole?d?`<button class="tf-role" data-app="${S}" data-name="${i(p.name)}">${t("team.viewRole")}</button>`:t("team.hasRoleShort"):'<span class="muted">\u2014</span>';a+=`<tr style="${C}"><td style="padding:4px 8px"><input type="checkbox" class="tf-pick" data-tk="${i(e.key)}" data-app="${S}"${E}></td><td style="padding:4px 8px">${i(p.name)}</td><td style="padding:4px 8px" class="muted">${i(p.cliId)}</td><td style="padding:4px 8px">${L}</td><td style="padding:4px 8px">${x}</td></tr>`}a+="</tbody></table>"}}return a||(a=`<p class="muted" style="margin:8px 0 0">${t("team.noMatch")}</p>`),a+=`<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(wn.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>`,a}function pt(){let e=Z("tf-teams"),n=kn();if(!n.length){e.innerHTML=`<p class="muted">${t("team.noTeams")}</p>`,Z("tf-count").textContent="";return}let o="",a=new Set,s=new Set;for(let m of n){let k=m.bots.filter(Ki);k.forEach(p=>a.add(p.larkAppId)),m.bots.forEach(p=>s.add(p.larkAppId));let $=new Set(k.map(p=>p.larkAppId));[...vt(m.key)].forEach(p=>{$.has(p)||vt(m.key).delete(p)});let M=!Wt.has(m.key),w=m.kind==="remote"?m.ok?` <span class="ok" style="font-size:12px">${t("team.connected")}</span>`:` <span class="err" style="font-size:12px">${t("team.connectFail",{error:i(m.error||"")})}</span>`:` <span class="muted" style="font-size:12px">${t("team.iHost")}</span>`;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(m.key)}" style="cursor:pointer;display:flex;align-items:center;gap:8px;flex-wrap:wrap"><b style="font-size:15px">${M?"\u25B8":"\u25BE"} ${i(m.label)}</b>`+(m.sub?` <span class="muted" style="font-size:12px">${i(m.sub)}</span>`:"")+w+` <span class="muted" style="font-size:12px">\xB7 ${t("team.teamMeta",{deps:m.deployments.length,bots:m.bots.length})}</span></div>`,M||(o+=m.kind==="remote"&&!m.ok?`<p class="muted" style="margin:8px 0 0">${t("team.rosterFail")}</p>`:Ji(m,k)),o+="</div>"}e.innerHTML=o;let r=n.length>1?t("team.acrossTeams",{n:n.length}):"",d=a.size===s.size?`${s.size}`:`${a.size} / ${s.size}`;Z("tf-count").textContent=`\xB7 ${d} ${t("team.botsWord")}${r}`,Vi()}function Vi(){let e=Z("tf-teams");e.querySelectorAll(".tf-team-h").forEach(n=>{n.onclick=()=>{let o=n.dataset.tk;Wt.has(o)?Wt.delete(o):Wt.add(o),pt()}}),e.querySelectorAll(".tf-dep-h").forEach(n=>{n.onclick=()=>{let o=n.dataset.dk;Kt.has(o)?Kt.delete(o):Kt.add(o),pt()}}),e.querySelectorAll(".tf-pick").forEach(n=>{n.onchange=()=>{let o=vt(n.dataset.tk);n.checked?o.add(n.dataset.app):o.delete(n.dataset.app)}}),e.querySelectorAll(".tf-gname").forEach(n=>{n.oninput=()=>{wn.set(n.dataset.tk,n.value)}}),e.querySelectorAll(".tf-cap").forEach(n=>{n.onchange=async()=>{let o=n.dataset.app,a=n.value;await _i("/api/team/local-bots/"+encodeURIComponent(o)+"/capability",{capability:a}),kn().forEach(s=>{let r=s.bots.find(d=>d.larkAppId===o);r&&(r.capability=a.trim()||null)})}}),e.querySelectorAll(".tf-role").forEach(n=>{n.onclick=()=>Qi(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 vn("DELETE",`/api/team/hosted/${encodeURIComponent(n.dataset.team)}/members/${encodeURIComponent(n.dataset.dep)}`),Jt())}}),e.querySelectorAll(".tf-grp").forEach(n=>{n.onclick=async()=>{let o=n.dataset.tk,a=zi(o);if(!a)return;let s=[...vt(o)],r=e.querySelector(`.tf-gout[data-tk="${CSS.escape(o)}"]`);if(!s.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 m=a.kind==="local"?await kt("/api/team/federated-group",{name:d,larkAppIds:s,teamId:a.teamId}):await kt("/api/team/remote-group",{hubUrl:a.hubUrl,teamId:a.teamId,name:d,larkAppIds:s});if(Yi(r,m.body,m.status),m.body?.ok){vt(o).clear(),wn.delete(o);let k=r.innerHTML,$=()=>{let M=e.querySelector(`.tf-gout[data-tk="${CSS.escape(o)}"]`);M&&(M.innerHTML=k)};a.kind==="local"?Jt().then($):(pt(),$())}}})}function Yi(e,n,o){if(n?.ok&&n.chatId){let a=n.shareLink||"https://applink.feishu.cn/client/chat/open?openChatId="+encodeURIComponent(n.chatId),s=(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>`:"",m=(n.skippedNoOwner||[]).length?`<span class="err"> \xB7 ${t("team.skippedNoOwner",{n:(n.skippedNoOwner||[]).length})}</span>`:"",k=n.delegatedTo?t("team.delegatedBy",{name:i(n.delegatedTo)}):"";e.innerHTML=`<span class="ok">${t("team.groupCreated")}</span>${k} \xB7 <a href="${i(a)}" target="_blank">${t("team.openInLark")}</a>${s}${r}${d}${m}`}else{let a=n?.error||o,s=a==="no_local_online_bot"?t("team.errNoLocalBot"):a==="all_bots_skipped_no_owner"?t("team.errAllSkipped"):a==="no_creator_available"?t("team.errNoCreator"):a==="delegation_timeout"?t("team.errDelegationTimeout"):t("team.errGroupCreate",{error:String(a)});e.innerHTML=`<span class="err">${i(String(s))}</span>`}}async function Qi(e,n){let o=await yn("/api/team/local-bots/"+encodeURIComponent(e)+"/role");Z("tf-modal-title").textContent=t("team.roleModalTitleName",{name:n}),Z("tf-modal-text").value=o.body?.role||"",Z("tf-modal").dataset.app=e,Z("tf-modal").style.display="flex"}function Da(){let e=Array.from(new Set(kn().flatMap(a=>a.bots.map(s=>s.cliId)).filter(Boolean))).sort(),n=Z("tf-cli"),o=n.value;n.innerHTML=`<option value="">${t("team.allCli")}</option>`+e.map(a=>`<option value="${i(a)}">${i(a)}</option>`).join(""),n.value=o}async function Jt(){let n=(await yn("/api/team/hosted")).body;if(!n?.ok){no=[],pt();return}Ca=n.deployment.deploymentId,hn=n.suggestedHubUrl||"",Z("tf-owner").textContent=n.deployment.ownerName||(n.deployment.ownerUnionId?t("team.bound"):t("team.unbound")),no=(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||[]})),Da(),pt()}async function Xi(){Ha=((await yn("/api/team/remote-roster")).body?.memberships||[]).map(o=>{let a=o.roster?.deployments||[],s=a.find(d=>d.local),r=s?.name?t("team.remoteTeamLabel",{name:s.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:a,bots:o.roster?.bots||[]}}),Da(),pt()}function Ra(e){e.innerHTML=Wi(),oo.clear(),wn.clear(),Wt.clear(),Kt.clear(),["tf-search","tf-cli","tf-fcap","tf-frole"].forEach(n=>{let o=Z(n);o.oninput=pt,o.onchange=pt}),Z("tf-modal-cancel").onclick=()=>{Z("tf-modal").style.display="none"},er(),Jt(),Xi()}function Zi(){return`<section class="page">
|
|
1040
1040
|
<div class="page-heading"><div>
|
|
1041
1041
|
<p class="eyebrow">${t("team.eyebrow")}</p><h1>${t("team.manageTitle")}</h1>
|
|
1042
1042
|
<p class="tf-lede">${t("team.manageLede")}</p>
|
|
1043
1043
|
</div></div>
|
|
1044
|
-
${
|
|
1044
|
+
${Aa("manage")}
|
|
1045
1045
|
<div class="card" style="margin-bottom:16px">
|
|
1046
1046
|
<h2 style="margin-top:0">${t("team.hostedTitle")}</h2>
|
|
1047
1047
|
<p style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:6px">
|
|
@@ -1060,16 +1060,16 @@ ${Co("manage")}
|
|
|
1060
1060
|
</p>
|
|
1061
1061
|
<div id="tm-join-out" style="display:none;margin-top:6px"></div>
|
|
1062
1062
|
</div>
|
|
1063
|
-
</section>`}async function
|
|
1063
|
+
</section>`}async function ao(){let n=(await yn("/api/team/hosted")).body,o=Z("tm-list");hn=n?.suggestedHubUrl||hn;let a=n?.teams||[];if(!a.length){o.innerHTML=`<p class="muted">${t("team.noTeamsShort")}</p>`;return}o.innerHTML=a.map(s=>{let r=(s.deployments||[]).filter(d=>!d.local).length;return`<div class="card" style="margin:0 0 8px;padding:10px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
1064
1064
|
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
1065
|
-
<b>${i(
|
|
1066
|
-
<span class="muted" style="font-size:12px">\xB7 ${t("team.manageMetaDeps",{count:(
|
|
1065
|
+
<b>${i(s.name)}</b>${s.isDefault?` <span class="muted" style="font-size:12px">${t("team.default")}</span>`:""}
|
|
1066
|
+
<span class="muted" style="font-size:12px">\xB7 ${t("team.manageMetaDeps",{count:(s.deployments||[]).length})}${r?t("team.manageMetaRemote",{r}):""} \xB7 ${t("team.manageMetaBots",{count:(s.bots||[]).length})}</span>
|
|
1067
1067
|
<span style="margin-left:auto;display:flex;gap:6px">
|
|
1068
|
-
<button class="tm-invite ghost" data-team="${i(
|
|
1069
|
-
${
|
|
1068
|
+
<button class="tm-invite ghost" data-team="${i(s.teamId)}" style="font-size:12px">${t("team.genInvite")}</button>
|
|
1069
|
+
${s.isDefault?"":`<button class="tm-del ghost" data-team="${i(s.teamId)}" data-name="${i(s.name)}" style="font-size:12px">${t("team.delBtn")}</button>`}
|
|
1070
1070
|
</span>
|
|
1071
1071
|
</div>
|
|
1072
|
-
<div class="tm-inv-out" data-team="${i(
|
|
1072
|
+
<div class="tm-inv-out" data-team="${i(s.teamId)}" style="display:none;margin-top:6px;font-size:13px"></div></div>`}).join(""),o.querySelectorAll(".tm-invite").forEach(s=>{s.onclick=async()=>{let r=s.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 m=await kt("/api/team/local-invite",{teamId:r});m.body?.code?d.innerHTML=`${t("team.inviteResultLede")}<br>${t("team.inviteHub")}<code>${i(hn)}</code><br>${t("team.inviteCode")}<code style="font-size:15px">${i(m.body.code)}</code>`:d.innerHTML=`<span class="err">${t("team.genFail")}</span>`}}),o.querySelectorAll(".tm-del").forEach(s=>{s.onclick=async()=>{confirm(t("team.delConfirm",{name:s.dataset.name||""}))&&(await vn("DELETE","/api/team/hosted/"+encodeURIComponent(s.dataset.team)),ao())}})}function Oa(e){e.innerHTML=Zi(),Z("tm-create").onclick=async()=>{let n=Z("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 a=await kt("/api/team/hosted",{name:n});a.body?.ok?(o.innerHTML=`<span class="ok">${t("team.created")}</span>`,Z("tm-newname").value="",ao()):o.innerHTML=`<span class="err">${t("team.createFail",{error:i(String(a.body?.error||a.status))})}</span>`},Z("tm-join").onclick=async()=>{let n=Z("tm-hub").value.trim(),o=Z("tm-code").value.trim(),a=Z("tm-join-out");if(a.style.display="",!n||!o){a.innerHTML=`<span class="err">${t("team.errHubCode")}</span>`;return}a.innerHTML=`<span class="muted">${t("team.joining")}</span>`;let s=await kt("/api/team/join-remote",{hubUrl:n,inviteCode:o});if(s.body?.ok)a.innerHTML=`<span class="ok">${t("team.joined",{name:i(s.body.teamName||"")})}</span>`,Z("tm-code").value="";else{let r=s.body?.error||s.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)});a.innerHTML=`<span class="err">${i(String(d))}</span>`}},ao()}function er(){Z("tf-autobind").onclick=async()=>{let e=Z("tf-bind-out");e.style.display="",e.innerHTML=`<span class="muted">${t("team.identifying")}</span>`;let o=(await kt("/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>`,Jt();return}if(o?.ok&&o.needChoice&&Array.isArray(o.candidates)){let a=o.candidates.map(s=>`<button class="tf-pickowner ghost" data-union="${i(s.unionId)}" style="margin:2px">${i(s.name||s.unionId)}</button>`).join(" ");e.innerHTML=`${t("team.multiCandidate")}<br>${a}`,e.querySelectorAll(".tf-pickowner").forEach(s=>{s.onclick=async()=>{e.innerHTML=`<span class="muted">${t("team.binding")}</span>`;let d=(await kt("/api/team/identity/auto-bind",{unionId:s.dataset.union})).body;d?.ok&&d.owner?(e.innerHTML=`<span class="ok">${t("team.bound2",{name:i(d.owner.name||d.owner.unionId)})}</span>`,Jt()):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 so(e){let n=await fetch(e);return{status:n.status,body:await n.json().catch(()=>({}))}}async function ro(e,n,o){let a=await fetch(n,{method:e,headers:{"content-type":"application/json"},body:o?JSON.stringify(o):void 0});return{status:a.status,body:await a.json().catch(()=>({}))}}function ee(e){return document.getElementById(e)}function $t(e){return(ee(e).value||"").trim()}var lo=[],uo=[];function tr(){return`<section class="page">
|
|
1073
1073
|
<div class="page-heading">
|
|
1074
1074
|
<div>
|
|
1075
1075
|
<p class="eyebrow">Webhook</p>
|
|
@@ -1131,28 +1131,28 @@ ${Co("manage")}
|
|
|
1131
1131
|
<h2 style="margin-top:0">${t("connectors.listTitle")} <span class="muted" id="cn-count" style="font-size:13px"></span></h2>
|
|
1132
1132
|
<div id="cn-list">${t("connectors.loading")}</div>
|
|
1133
1133
|
</div>
|
|
1134
|
-
</section>`}function
|
|
1134
|
+
</section>`}function io(){let e=ee("cn-kind").value,n=ee("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 Pa(e){return`${location.origin}/webhook/${encodeURIComponent(e)}`}function nr(e){return e==="fixed"?t("connectors.modeLabelFixed"):e==="new-group"?t("connectors.modeLabelNewGroup"):t("connectors.modeLabelDynamic")}function or(e){return e==="workflow"?t("connectors.kindLabelWorkflow"):t("connectors.kindLabelTurn")}function co(e){return uo.find(o=>o.chatId===e)?.name||e}function ar(e){return uo.filter(n=>n.bots.includes(e))}function Ba(){let e=ee("cn-bot").value,n=ar(e),o=m=>`<option value="${i(m.chatId)}">${i(m.name||m.chatId)}</option>`,a=ee("cn-chat-sel"),s=a.value;a.innerHTML=n.length?n.map(o).join(""):`<option value="">${t("connectors.noBotGroups")}</option>`,s&&n.some(m=>m.chatId===s)&&(a.value=s);let r=ee("cn-allow-sel"),d=new Set(Array.from(r.selectedOptions).map(m=>m.value));r.innerHTML=n.map(o).join(""),Array.from(r.options).forEach(m=>{d.has(m.value)&&(m.selected=!0)})}function sr(e){let n=ee("cn-list");if(ee("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 a=lo.find(k=>k.larkAppId===o.target.botId),s=Pa(o.id),r=(o.verify?.type??"token")==="token",d=r?t("connectors.badgeToken"):t("connectors.badgeSign"),m=o.target.mode==="fixed"&&o.target.chatId?` \xB7 ${t("connectors.dest",{name:i(co(o.target.chatId))})}`:"";return`<div class="card" style="margin:0 0 10px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
1135
1135
|
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
1136
|
-
<b style="font-size:15px">${i(
|
|
1137
|
-
<span class="${
|
|
1138
|
-
<span class="muted" style="font-size:12px">\xB7 ${i(
|
|
1136
|
+
<b style="font-size:15px">${i(o.name)}</b>
|
|
1137
|
+
<span class="${o.enabled?"ok":"muted"}" style="font-size:12px">${o.enabled?t("connectors.enabled"):t("connectors.disabled")}</span>
|
|
1138
|
+
<span class="muted" style="font-size:12px">\xB7 ${i(a?.botName||o.target.botId)} \xB7 ${or(o.target.kind)} \xB7 ${nr(o.target.mode)}${m} \xB7 ${d}</span>
|
|
1139
1139
|
<span style="margin-left:auto;display:flex;gap:6px">
|
|
1140
|
-
<button class="cn-toggle ghost" data-id="${i(
|
|
1141
|
-
<button class="cn-del ghost" data-id="${i(
|
|
1140
|
+
<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>
|
|
1141
|
+
<button class="cn-del ghost" data-id="${i(o.id)}" style="font-size:12px">${t("connectors.btnDel")}</button>
|
|
1142
1142
|
</span>
|
|
1143
1143
|
</div>
|
|
1144
1144
|
<div style="margin-top:6px;font-size:13px;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
1145
|
-
<span class="muted">${t("connectors.webhookUrl")}</span><code style="font-size:12px;word-break:break-all">${i(
|
|
1146
|
-
<button class="cn-copy ghost" data-url="${i(
|
|
1147
|
-
</div>${r?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.tokenHint")}</div>`:""}${
|
|
1145
|
+
<span class="muted">${t("connectors.webhookUrl")}</span><code style="font-size:12px;word-break:break-all">${i(s)}${r?"/<token>":""}</code>
|
|
1146
|
+
<button class="cn-copy ghost" data-url="${i(s)}" style="font-size:12px">${t("connectors.copy")}</button>
|
|
1147
|
+
</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 ro("PATCH","/api/connectors/"+encodeURIComponent(o.dataset.id),{enabled:o.dataset.on!=="true"}),$n()}}),n.querySelectorAll(".cn-del").forEach(o=>{o.onclick=async()=>{confirm(t("connectors.delConfirm"))&&(await ro("DELETE","/api/connectors/"+encodeURIComponent(o.dataset.id)),$n())}})}async function $n(){let[e,n,o]=await Promise.all([so("/api/bots"),so("/api/connectors"),so("/api/groups")]);lo=(e.body?.bots||[]).map(r=>({larkAppId:r.larkAppId,botName:r.botName||r.larkAppId})),uo=(o.body?.chats||[]).map(r=>({chatId:r.chatId,name:r.name||"",bots:(r.memberBots||[]).filter(d=>d.inChat).map(d=>d.larkAppId)}));let a=ee("cn-bot"),s=a.value;a.innerHTML=lo.map(r=>`<option value="${i(r.larkAppId)}">${i(r.botName)}</option>`).join("")||`<option value="">${t("connectors.noOnlineBots")}</option>`,s&&(a.value=s),Ba(),sr(n.body?.connectors||[])}function Na(e){e.innerHTML=tr(),ee("cn-kind").onchange=io,ee("cn-mode").onchange=io,ee("cn-bot").onchange=Ba,ee("cn-chat-manual").onclick=n=>{n.preventDefault();let o=ee("cn-chat"),a=ee("cn-chat-sel"),s=o.style.display==="none";o.style.display=s?"":"none",a.style.display=s?"none":"",ee("cn-chat-manual").textContent=s?t("connectors.chatListLink"):t("connectors.chatManualLink")},io(),ee("cn-create").onclick=async()=>{let n=ee("cn-create-out"),o=$t("cn-name"),a=ee("cn-bot").value;if(!o){n.innerHTML=`<span class="err">${t("connectors.errName")}</span>`;return}if(!a){n.innerHTML=`<span class="err">${t("connectors.errBot")}</span>`;return}let s=ee("cn-kind").value,r=ee("cn-mode").value,d={name:o,enabled:!0,target:{kind:s,mode:r,botId:a},promptEnvelope:{sourceName:o}},m=$t("cn-instruction");if(m&&(d.promptEnvelope.instruction=m),s==="workflow"){if(!$t("cn-wf")){n.innerHTML=`<span class="err">${t("connectors.errWf")}</span>`;return}d.target.workflowId=$t("cn-wf")}if(r==="fixed"){let w=ee("cn-chat").style.display!=="none"?$t("cn-chat"):ee("cn-chat-sel").value;if(!w){n.innerHTML=`<span class="err">${t("connectors.errChat")}</span>`;return}d.target.chatId=w}else{let M=Array.from(ee("cn-allow-sel").selectedOptions).map(w=>w.value).filter(Boolean);M.length&&(d.target.allowChats=M)}if(r==="new-group"){let M=$t("cn-dedup");d.lifecycleExtractors=M?{dedupKey:M}:null}d.verify={type:ee("cn-verify").value};let k=$t("cn-secret");k&&(d.secret=k),n.innerHTML=`<span class="muted">${t("connectors.creating")}</span>`;let $=await ro("POST","/api/connectors",d);if($.status===201&&$.body?.ok){n.innerHTML="";let M=ee("cn-created");M.style.display="";let w=$.body.webhookUrl||Pa($.body.connector.id),p=$.body.secret,S=($.body.connector?.verify?.type??"token")==="token",E=r==="dynamic",C=E?d.target.allowChats?.[0]||"<chatId>":"",L=E?`${i(w)}?chatId=${i(C)}`:i(w),x;if(S&&E){let T=C!=="<chatId>"?`\uFF08${i(co(d.target.allowChats[0]))}\uFF09`:"";x=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicLede",{gn:T})}</p>
|
|
1148
1148
|
<pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${L}' -H 'content-type: application/json' -d '{}'</code></pre>
|
|
1149
1149
|
<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicNote")}</p>`}else S?x=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageTokenLede")}</p>
|
|
1150
1150
|
<pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${L}' -H 'content-type: application/json' -d '{}'</code></pre>
|
|
1151
1151
|
<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageTokenNote")}</p>`:x=`<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageHmac")}${E?t("connectors.usageHmacDynamic"):""}</p>`;M.innerHTML=`<div class="card" style="padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
1152
|
-
<p class="ok" style="margin:0 0 6px">${t("connectors.createdPrefix",{name:i(
|
|
1153
|
-
<p style="margin:4px 0;font-size:13px"><span class="muted">${t("connectors.webhookUrl")}</span><code style="word-break:break-all">${i(
|
|
1152
|
+
<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(co(d.target.chatId))})}</span>`:""}</p>
|
|
1153
|
+
<p style="margin:4px 0;font-size:13px"><span class="muted">${t("connectors.webhookUrl")}</span><code style="word-break:break-all">${i(w)}</code></p>
|
|
1154
1154
|
${p?`<p style="margin:4px 0;font-size:13px"><span class="muted">${S?t("connectors.tokenLabel"):t("connectors.signLabel")}${t("connectors.secretOnce")}</span><code>${i(p)}</code></p>`:""}
|
|
1155
|
-
${x}</div>`,["cn-name","cn-wf","cn-chat","cn-dedup","cn-secret","cn-instruction"].forEach(T=>{ee(T).value=""}),ee("cn-allow-sel").selectedIndex=-1,$n()}else{let M=$.body?.error||$.status;n.innerHTML=`<span class="err">${t("connectors.createFailed",{error:i(String(M))})}</span>`}},$n()}var Se=null,
|
|
1155
|
+
${x}</div>`,["cn-name","cn-wf","cn-chat","cn-dedup","cn-secret","cn-instruction"].forEach(T=>{ee(T).value=""}),ee("cn-allow-sel").selectedIndex=-1,$n()}else{let M=$.body?.error||$.status;n.innerHTML=`<span class="err">${t("connectors.createFailed",{error:i(String(M))})}</span>`}},$n()}var Se=null,Yt=null,Vt=!0;function qa(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 ir(e,n){let o=e?.[n]??{};return{enabled:o.enabled===!0,time:typeof o.time=="string"?o.time:"04:00"}}function rr(){return`<section class="page">
|
|
1156
1156
|
<div class="page-heading">
|
|
1157
1157
|
<div>
|
|
1158
1158
|
<p class="eyebrow">${t("nav.settings")}</p>
|
|
@@ -1161,24 +1161,24 @@ ${Co("manage")}
|
|
|
1161
1161
|
</div>
|
|
1162
1162
|
</div>
|
|
1163
1163
|
<div id="settings-body"></div>
|
|
1164
|
-
</section>`}function
|
|
1165
|
-
<input type="checkbox" data-maint="autoUpdate" ${n?"checked":""} ${
|
|
1164
|
+
</section>`}function lr(e){let{enabled:n,time:o}=ir(Se.maintenance,"autoUpdate"),a=e?"disabled":"";return`<label class="toggle-row">
|
|
1165
|
+
<input type="checkbox" data-maint="autoUpdate" ${n?"checked":""} ${a}>
|
|
1166
1166
|
<span class="switch" aria-hidden="true"></span>
|
|
1167
1167
|
<span class="toggle-tx"><strong>${t("settings.autoUpdate")}</strong>
|
|
1168
1168
|
<small>${t("settings.autoUpdateHelp")}</small></span>
|
|
1169
1169
|
</label>
|
|
1170
1170
|
<div class="maint-time">
|
|
1171
1171
|
<label>${t("settings.maintenanceTime")}
|
|
1172
|
-
<input type="time" data-maint-time="autoUpdate" value="${i(
|
|
1172
|
+
<input type="time" data-maint-time="autoUpdate" value="${i(o)}" ${a}>
|
|
1173
1173
|
</label>
|
|
1174
|
-
</div>`}function
|
|
1174
|
+
</div>`}function dr(e){return`<label class="toggle-row">
|
|
1175
1175
|
<input type="checkbox" data-maint="autoRestart" ${Se.maintenance.autoRestart?.enabled===!0?"checked":""} ${e?"disabled":""}>
|
|
1176
1176
|
<span class="switch" aria-hidden="true"></span>
|
|
1177
1177
|
<span class="toggle-tx"><strong>${t("settings.autoRestart")}</strong>
|
|
1178
1178
|
<small>${t("settings.autoRestartHelp")}</small></span>
|
|
1179
|
-
</label>`}function
|
|
1179
|
+
</label>`}function cr(){if(Yt)return`<p class="hint-warn">${t("settings.loadFailed")}: ${i(Yt)}</p>`;if(!Se)return`<p class="empty">${t("settings.loading")}</p>`;let e=Vt?"":"disabled",n=!Vt||Se.localDevInstall;return`<div class="settings-grid">
|
|
1180
1180
|
<article class="bd-card settings-card">
|
|
1181
|
-
${
|
|
1181
|
+
${Vt?"":`<p class="hint-warn">${t("settings.readOnlyVisitor")}</p>`}
|
|
1182
1182
|
<section class="bd-section">
|
|
1183
1183
|
<h3 class="bd-section-title">${t("settings.sectionAccess")}</h3>
|
|
1184
1184
|
<label class="toggle-row">
|
|
@@ -1210,15 +1210,15 @@ ${Co("manage")}
|
|
|
1210
1210
|
</section>
|
|
1211
1211
|
<section class="bd-section">
|
|
1212
1212
|
<h3 class="bd-section-title">${t("settings.sectionMaintenance")}</h3>
|
|
1213
|
-
${
|
|
1213
|
+
${lr(n)}
|
|
1214
1214
|
${Se.localDevInstall?`<p class="hint-warn">${t("settings.autoUpdateLocalDev")}</p>`:""}
|
|
1215
|
-
${
|
|
1215
|
+
${dr(!Vt||Se.maintenance.autoUpdate?.enabled!==!0)}
|
|
1216
1216
|
</section>
|
|
1217
1217
|
<div class="actions settings-actions">
|
|
1218
1218
|
<span class="oncall-status" data-settings-status></span>
|
|
1219
1219
|
</div>
|
|
1220
1220
|
</article>
|
|
1221
|
-
</div>`}async function
|
|
1221
|
+
</div>`}async function ur(){try{let e=await fetch("/api/settings"),n=await e.json().catch(()=>({}));if(!e.ok){Se=null,Yt=n?.error??`HTTP ${e.status}`;return}Se=qa(n.settings),Vt=n.authed===!0,Yt=null}catch(e){Se=null,Yt=e?.message??String(e)}}async function ja(e){e.innerHTML=rr();let n=e.querySelector("#settings-body");function o(){n.innerHTML=cr(),r()}function a(){return n.querySelector("[data-settings-status]")}async function s(d,m,k){if(!Se)return;k.disabled=!0;let $=a();$&&($.textContent=t("settings.saving"),$.className="oncall-status");try{let M=await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(d)}),w=await M.json().catch(()=>({}));if(!M.ok||w.ok===!1)throw new Error(w?.error??`HTTP ${M.status}`);Se=qa(w.settings),$&&($.textContent=t("settings.saved"),$.classList.add("hint-ok"))}catch(M){m(),$&&($.textContent=`${t("settings.saveFailed")}: ${M?.message??M}`,$.classList.add("hint-warn-inline"))}finally{k.disabled=!1}}function r(){n.querySelectorAll("input[data-setting]").forEach(m=>{m.addEventListener("change",()=>{let k=m.dataset.setting,$=!m.checked;s({[k]:m.checked},()=>{m.checked=$},m)})}),n.querySelectorAll("select[data-select-setting]").forEach(m=>{m.addEventListener("change",()=>{let k=m.dataset.selectSetting,$=Se?.[k]??"all";s({[k]:m.value},()=>{m.value=$},m)})});let d=(m,k,$)=>{let w=n.querySelector(`input[data-maint="${m}"]`)?.checked??!1,p;if(m==="autoUpdate"){let S=n.querySelector('input[data-maint-time="autoUpdate"]');p={enabled:w,time:S?.value||"04:00"}}else p={enabled:w};s({maintenance:{[m]:p}},$,k).then(()=>o())};n.querySelectorAll("input[data-maint]").forEach(m=>{m.addEventListener("change",()=>{let k=m.dataset.maint,$=!m.checked;d(k,m,()=>{m.checked=$})})}),n.querySelectorAll("input[data-maint-time]").forEach(m=>{m.addEventListener("change",()=>{let k=m.dataset.maintTime,$=m.defaultValue;d(k,m,()=>{m.value=$})})})}o(),await ur(),o()}function pr(){let e=[["",t("workflow.filter.nonTerminal")],["all",t("workflow.filter.all")],["pending",mt("pending")],["running",mt("running")],["waiting",mt("waiting")],["succeeded",mt("succeeded")],["failed",mt("failed")],["cancelled",mt("cancelled")]];return`
|
|
1222
1222
|
<nav class="wf-subnav">
|
|
1223
1223
|
<a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${h(t("workflow.subnav.runs"))}</a>
|
|
1224
1224
|
<a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${h(t("workflow.subnav.catalog"))}</a>
|
|
@@ -1226,7 +1226,7 @@ ${Co("manage")}
|
|
|
1226
1226
|
<form id="wf-filters" class="filters">
|
|
1227
1227
|
<input type="search" name="q" placeholder="${h(t("workflow.searchPlaceholder"))}" />
|
|
1228
1228
|
<select name="status">
|
|
1229
|
-
${e.map(([n,
|
|
1229
|
+
${e.map(([n,o])=>`<option value="${h(n)}">${h(o)}</option>`).join("")}
|
|
1230
1230
|
</select>
|
|
1231
1231
|
<span id="wf-last-load" class="muted"></span>
|
|
1232
1232
|
</form>
|
|
@@ -1238,15 +1238,15 @@ ${Co("manage")}
|
|
|
1238
1238
|
</tr></thead>
|
|
1239
1239
|
<tbody id="wf-tbody"></tbody>
|
|
1240
1240
|
</table>
|
|
1241
|
-
`}var
|
|
1241
|
+
`}var mr=5e3,fr=2e3,Qt=new Set(["succeeded","failed","cancelled"]);function h(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function gr(e){let n=new Date(e),a=Date.now()-e;return a<6e4?t("time.secondsAgo",{value:Math.max(1,Math.floor(a/1e3))}):a<36e5?t("time.minutesAgo",{value:Math.floor(a/6e4)}):a<864e5?t("time.hoursAgo",{value:Math.floor(a/36e5)}):n.toISOString().slice(0,19).replace("T"," ")}function at(e){return`<span class="${Qt.has(e)?"wf-status terminal":"wf-status live"} wf-status-${h(e)}">${h(mt(e))}</span>`}function mt(e){let n=`workflow.status.${e}`,o=t(n);return o===n?e:o}function _a(e){let n=location.hash.match(/^#\/workflows\/([^?#]+)(?:\?([^#]*))?$/);if(n){let o=new URLSearchParams(n[2]??"");return hr(e,decodeURIComponent(n[1]),{focusAttemptId:o.get("attempt")??void 0})}return br(e)}function br(e){e.innerHTML=pr();let n=e.querySelector("#wf-tbody"),o=e.querySelector("#wf-filters"),a=e.querySelector("#wf-last-load"),s=[],r=null,d=!1,m=null,k=!1;function $(C){let x=(new FormData(o).get("q")??"").trim().toLowerCase();return x?C.filter(T=>T.runId.toLowerCase().includes(x)||T.workflowId.toLowerCase().includes(x)||(T.chatId??"").toLowerCase().includes(x)):C}function M(){let C=$(s);if(C.length===0){n.innerHTML=`<tr><td colspan="7" class="empty">${m?h(t("workflow.list.failedLoad",{error:m})):s.length===0?h(t("workflow.list.noRuns")):h(t("workflow.list.noFilterMatch"))}</td></tr>`;return}n.innerHTML=C.map(L=>{let x=`${L.dEf}/${L.dAct}/${L.dWait}`,T=L.dEf+L.dAct+L.dWait>0?"wf-dangling has":"wf-dangling none",R=[];L.chatId&&R.push(h(L.chatId)),L.larkAppId&&R.push(`<span class="muted">${h(L.larkAppId)}</span>`);let q=R.length>0?R.join("<br/>"):"\u2014",u=yr(L);return`<tr data-runid="${h(L.runId)}">
|
|
1242
1242
|
<td><a href="#/workflows/${encodeURIComponent(L.runId)}"><code>${h(L.runId)}</code></a></td>
|
|
1243
1243
|
<td>${h(L.workflowId)}</td>
|
|
1244
|
-
<td>${
|
|
1244
|
+
<td>${at(L.status)}${L.failedNodeId?` <span class="muted">(${h(L.failedNodeId)})</span>`:""}${u}</td>
|
|
1245
1245
|
<td>${L.lastSeq}</td>
|
|
1246
1246
|
<td class="${T}">${x}</td>
|
|
1247
|
-
<td title="${h(new Date(L.updatedAt).toISOString())}">${
|
|
1247
|
+
<td title="${h(new Date(L.updatedAt).toISOString())}">${gr(L.updatedAt)}</td>
|
|
1248
1248
|
<td>${q}</td>
|
|
1249
|
-
</tr>`}).join("")}function
|
|
1249
|
+
</tr>`}).join("")}function w(){m?(a.textContent=t("workflow.list.error",{error:m}),a.classList.add("error")):(a.textContent=t("workflow.list.loaded",{count:s.length,time:new Date().toLocaleTimeString()}),a.classList.remove("error"))}async function p(){if(!(k||d)&&!document.hidden){d=!0;try{let C=o.elements.namedItem("status")?.value??"",L=new URLSearchParams;C==="all"?L.set("all","1"):C&&L.set("status",C);let x="/api/workflows/runs"+(L.toString()?`?${L}`:""),T=await fetch(x);T.ok?(s=(await T.json()).runs??[],m=null):(m=`HTTP ${T.status}`,s=[])}catch(C){m=C?.message??String(C),s=[]}finally{d=!1,k||(M(),w())}}}function S(){r!==null&&window.clearTimeout(r),r=window.setTimeout(async()=>{await p(),k||S()},mr)}function E(){document.hidden||p()}return o.addEventListener("input",()=>{M()}),o.addEventListener("change",C=>{C.target.getAttribute("name")==="status"&&p()}),document.addEventListener("visibilitychange",E),p().then(()=>{k||S()}),()=>{k=!0,r!==null&&window.clearTimeout(r),document.removeEventListener("visibilitychange",E)}}function hr(e,n,o={}){e.innerHTML=`
|
|
1250
1250
|
<div class="wf-detail-head">
|
|
1251
1251
|
<a class="btn-link" href="#/workflows">${h(t("workflow.detail.back"))}</a>
|
|
1252
1252
|
<div>
|
|
@@ -1302,16 +1302,16 @@ ${Co("manage")}
|
|
|
1302
1302
|
</div>
|
|
1303
1303
|
<div id="wf-event-meta" class="muted"></div>
|
|
1304
1304
|
</section>
|
|
1305
|
-
`;let
|
|
1305
|
+
`;let a=e.querySelector("#wf-detail-subtitle"),s=e.querySelector("#wf-detail-refresh"),r=e.querySelector("#wf-detail-error"),d=e.querySelector("#wf-cancel-status"),m=e.querySelector("#wf-summary"),k=e.querySelector("#wf-dangling-panel"),$=e.querySelector("#wf-parallel-view"),M=e.querySelector("#wf-parallel-meta"),w=e.querySelector("#wf-node-tbody"),p=e.querySelector("#wf-io-list"),S=e.querySelector(".wf-timeline-scroll"),E=e.querySelector("#wf-event-tbody"),C=e.querySelector("#wf-event-meta"),L=e.querySelector("#wf-cancel-run"),x=e.querySelector("#wf-load-older"),T=null,R=[],q=new Set,u=null,y=null,A=!1,O=0,U=null,B=!1,Q=!1,re=!1,le=new Set,te=new Map,ne=new Map,ce=new Map,me=new Set,be=new Map,ie=new Set,Ue=new Map,Xe=new Map,ye=0,fe=o.focusAttemptId;function oe(H){if(!H){r.hidden=!0,r.textContent="";return}r.hidden=!1,r.textContent=H}function de(H){if(!H){d.hidden=!0,d.textContent="";return}d.hidden=!1,d.textContent=H}async function Me(){let H=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/snapshot`);if(H.status===404)throw new Error(t("workflow.detail.unknownRun"));if(!H.ok)throw new Error(t("workflow.detail.snapshotHttp",{status:H.status}));T=await H.json()}async function Fe(H){let se=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/events?${H}`);if(se.status===404)throw new Error(t("workflow.detail.unknownRun"));if(!se.ok)throw new Error(t("workflow.detail.eventsHttp",{status:se.status}));return await se.json()}function Be(H,se){let G=H.filter(K=>q.has(K.eventId)?!1:(q.add(K.eventId),!0));G.length!==0&&(R=se==="prepend"?[...G,...R]:[...R,...G],R.sort((K,ge)=>Xt(K.eventId)-Xt(ge.eventId)))}async function Ze(){await Me();let H=await Fe(new URLSearchParams({tail:"100"}));R=[],q=new Set,Be(H.events,"append"),u=H.oldestSeq,y=H.newestSeq,A=H.hasOlder,O=H.totalCount,he()}async function Ne(){if(!(B||Q||document.hidden)){Q=!0;try{if(await Me(),y!==null){let H=await Fe(new URLSearchParams({afterSeq:String(y),limit:"200"}));Be(H.events,"append"),H.newestSeq!==null&&(y=H.newestSeq),u===null&&H.oldestSeq!==null&&(u=H.oldestSeq),O=H.totalCount}else{let H=await Fe(new URLSearchParams({tail:"1"}));Be(H.events,"append"),u=H.oldestSeq,y=H.newestSeq,A=H.hasOlder,O=H.totalCount}oe(null),he()}catch(H){oe(H?.message??String(H))}finally{Q=!1}}}async function Oe(){if(!(u===null||!A)){x.disabled=!0;try{let H=await Fe(new URLSearchParams({beforeSeq:String(u),limit:"100"}));Be(H.events,"prepend"),H.oldestSeq!==null&&(u=H.oldestSeq),A=H.hasOlder,O=H.totalCount,oe(null),he()}catch(H){oe(H?.message??String(H))}finally{x.disabled=!1}}}async function et(){if(!T||Qt.has(T.run.status)||re)return;if(!T.chatBinding?.larkAppId){oe(t("workflow.detail.cancelUnavailable",{runId:n}));return}let H=vr(T),se=t("workflow.detail.cancelConfirm",{runId:n,...H});if(window.confirm(se)){re=!0,L.disabled=!0;try{let G=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/cancel`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"cancelled via dashboard"})});if(G.status===401)throw new Error(t("workflow.detail.writeAccessCancel"));let K=await G.json().catch(()=>({}));if(!G.ok||!K.ok)throw new Error(K.hint??K.error??t("workflow.detail.cancelHttp",{status:G.status}));de(K.pending?t("workflow.detail.cancelPending"):null),oe(null),await Ne()}catch(G){oe(G?.message??String(G))}finally{re=!1,L.disabled=!1,he()}}}async function Pt(H,se){if(!ie.has(H)){ie.add(H),Ue.delete(H),he();try{let G=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/attempts/${encodeURIComponent(se)}/${encodeURIComponent(H)}/resume`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});if(G.status===401)throw new Error(t("workflow.detail.writeAccessResume"));let K=await G.json().catch(()=>({}));if(!G.ok||!K.ok||!K.resumeId||!K.url)throw new Error(K.hint??K.message??K.error??t("workflow.detail.resumeStartFailed",{status:G.status}));be.set(H,{resumeId:K.resumeId,url:K.url})}catch(G){let K=G?.message??String(G);Ue.set(H,K)}finally{ie.delete(H),he()}}}async function it(H,se){if(!ie.has(H)){ie.add(H),Ue.delete(H),he();try{let G=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/attempts/${encodeURIComponent(se)}/${encodeURIComponent(H)}/resume/end`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"ended_by_dashboard"})});if(G.status===401)throw new Error(t("workflow.detail.writeAccessResume"));let K=await G.json().catch(()=>({}));if(!G.ok||!K.ok)if(K.error==="resume_not_running")be.delete(H);else throw new Error(K.hint??K.message??K.error??t("workflow.detail.resumeEndFailed",{status:G.status}));else be.delete(H)}catch(G){let K=G?.message??String(G);Ue.set(H,K)}finally{ie.delete(H),he()}}}async function Bt(H,se){if(!me.has(H)){me.add(H),ce.delete(H),he();try{let G=ne.get(H)?.trim()||void 0,K=await fetch(`/api/workflows/runs/${encodeURIComponent(n)}/${se}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({comment:G})});if(K.status===401)throw new Error(t("workflow.detail.writeAccessApproval"));let ge=await K.json().catch(()=>({}));if(!K.ok||!ge.ok)throw new Error(ge.hint??ge.message??ge.error??t("workflow.detail.actionHttp",{action:se,status:K.status}));let Ge=se==="approve"?t("workflow.detail.approved"):t("workflow.detail.rejected");ce.set(H,{kind:"ok",text:ge.alreadyTerminal?t("workflow.detail.alreadyTerminal",{label:Ge}):ge.pending?t("workflow.detail.workflowContinue",{label:Ge}):t("workflow.detail.workflowRefreshing",{label:Ge})}),oe(null),await Ne()}catch(G){let K=G?.message??String(G);ce.set(H,{kind:"error",text:K}),oe(K)}finally{me.delete(H),he()}}}function he(){if(!T)return;ye=S.scrollTop;let H=T.run;Qt.has(H.status)&&de(null),a.innerHTML=`${h(H.workflowId??"?")} \xB7 ${at(H.status)} \xB7 lastSeq ${T.lastSeq}`,s.textContent=t("workflow.detail.refreshed",{time:new Date().toLocaleTimeString()}),L.hidden=Qt.has(H.status),L.disabled=re||!T.chatBinding?.larkAppId,L.textContent=T.chatBinding?.larkAppId?t("workflow.detail.cancel"):t("workflow.detail.cliCancelOnly"),L.title=T.chatBinding?.larkAppId?t("workflow.detail.cancelTitle"):t("workflow.detail.cliCancelTitle",{runId:n}),wr(m,T),kr(k,T),$r($,M,T,R),Er(w,T),xr(p,T,le,te,{comments:ne,statuses:ce,resolving:me,onResolve:Bt},{sessions:be,pending:ie,errors:Ue,onStart:Pt,onEnd:it},fe,Xe)&&(fe=void 0),tl(E,R),S.scrollTop=ye,x.hidden=!A,C.textContent=t("workflow.detail.eventsLoaded",{loaded:R.length,total:O})}function rt(){if(U!==null&&window.clearTimeout(U),T&&Qt.has(T.run.status)){U=null;return}U=window.setTimeout(async()=>{await Ne(),B||rt()},fr)}function tt(){document.hidden||Ne().then(()=>{!B&&U===null&&rt()})}return x.addEventListener("click",()=>{Oe()}),L.addEventListener("click",()=>{et()}),document.addEventListener("visibilitychange",tt),Ze().then(()=>{oe(null),B||rt()}).catch(H=>{oe(H?.message??String(H)),a.textContent=t("workflow.detail.loadFailed")}),()=>{B=!0,U!==null&&window.clearTimeout(U),document.removeEventListener("visibilitychange",tt)}}function wr(e,n){let o=n.run,a=[[t("workflow.summary.workflow"),h(o.workflowId??"?")],[t("workflow.summary.status"),at(o.status)],[t("workflow.summary.lastSeq"),String(n.lastSeq)],[t("workflow.summary.updated"),h(new Date(n.updatedAt).toLocaleString())],[t("workflow.summary.revision"),h(Tn(o.revisionId))],[t("workflow.summary.initiator"),h(o.initiator??"-")]];o.failedNodeId&&a.push([t("workflow.summary.failedNode"),h(o.failedNodeId)]),o.cancelOriginEventId&&a.push([t("workflow.summary.cancelOrigin"),h(o.cancelOriginEventId)]),n.chatBinding&&(a.push([t("workflow.summary.chat"),`<code>${h(n.chatBinding.chatId)}</code>`]),a.push([t("workflow.summary.app"),`<code>${h(n.chatBinding.larkAppId)}</code>`])),e.innerHTML=a.map(([s,r])=>`<div class="wf-summary-item"><span>${s}</span><strong>${r}</strong></div>`).join("")}function yr(e){if(!e.errorCode)return"";let n=e.errorMessage?` \u2014 ${sl(e.errorMessage,96)}`:"";return`<div class="wf-run-error">
|
|
1306
1306
|
<span class="muted error">${h(e.errorCode)}</span>${h(n)}
|
|
1307
|
-
</div>`}function
|
|
1307
|
+
</div>`}function vr(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 kr(e,n){let o=n.dangling,a=[[t("workflow.dangling.activities"),o.activities],[t("workflow.dangling.effects"),o.effectAttempted],[t("workflow.dangling.waits"),o.waits],[t("workflow.dangling.cancels"),o.cancels]],s=new Set(a.flatMap(([,r])=>r)).size;if(e.className=s>0?"wf-panel wf-dangling-panel has":"wf-panel wf-dangling-panel",s===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">${s}</span></div>
|
|
1308
1308
|
<div class="wf-dangling-grid">
|
|
1309
|
-
${
|
|
1310
|
-
</div>`}function
|
|
1309
|
+
${a.map(([r,d])=>`<div><strong>${r}</strong>${d.length===0?`<div class="muted">${h(t("workflow.detail.none"))}</div>`:`<ul>${d.map(m=>`<li><code>${h(m)}</code></li>`).join("")}</ul>`}</div>`).join("")}
|
|
1310
|
+
</div>`}function $r(e,n,o,a){let s=Sr(a,o);if(s.length===0){n.textContent="",e.innerHTML=`<div class="empty">${h(t("workflow.detail.noParallelData"))}</div>`;return}let r=Date.now(),d=Math.min(...s.map(p=>p.startedAt)),m=Math.max(...s.map(p=>p.endedAt??r),d+1e3),k=Math.max(1,m-d),$=Tr(s,r),M=s.filter(p=>!p.endedAt&&(p.status==="running"||p.status==="effectAttempting")).length;n.textContent=t("workflow.detail.parallelMeta",{count:s.length,max:$,running:M});let w=s.sort((p,S)=>p.startedAt-S.startedAt||p.activityId.localeCompare(S.activityId)).map(p=>Lr(p,d,k,r)).join("");e.innerHTML=`<div class="wf-parallel-axis">
|
|
1311
1311
|
<span title="${h(new Date(d).toISOString())}">${h(Ln(d))}</span>
|
|
1312
1312
|
<span title="${h(new Date(m).toISOString())}">${h(Ln(m))}</span>
|
|
1313
1313
|
</div>
|
|
1314
|
-
<div class="wf-parallel-list">${
|
|
1314
|
+
<div class="wf-parallel-list">${w}</div>`}function Sr(e,n){let o=new Map,a=new Map(n.activities.map(s=>[s.activityId,s.ownerNodeId]));for(let s of[...e].sort((r,d)=>Xt(r.eventId)-Xt(d.eventId))){let r=al(s);if(!r)continue;let d=typeof r.activityId=="string"?r.activityId:void 0,m=typeof r.attemptId=="string"?r.attemptId:void 0;if(!d||!m)continue;let k=o.get(m);if(s.type==="attemptCreated"){let $=typeof r.attemptNumber=="number"?r.attemptNumber:void 0;k={nodeId:typeof r.nodeId=="string"?r.nodeId:a.get(d),activityId:d,attemptId:m,attemptNumber:$,status:"pending",startedAt:s.timestamp},o.set(m,k);continue}k||(k={nodeId:a.get(d),activityId:d,attemptId:m,status:"pending",startedAt:s.timestamp},o.set(m,k)),s.type==="activityRunning"?(k.status="running",k.runningAt=s.timestamp):s.type==="effectAttempted"?k.status="effectAttempting":s.type==="activityWaiting"||s.type==="waitCreated"?k.status="waiting":Ir(s.type)&&(k.status=Mr(s.type),k.endedAt=s.timestamp,k.endType=s.type)}return[...o.values()]}function Lr(e,n,o,a){let s=e.endedAt??a,r=Ga((e.startedAt-n)/o*100,0,100),d=Ga((Math.max(s,e.startedAt+1)-e.startedAt)/o*100,.7,100-r),m=e.nodeId??e.activityId,k=e.attemptNumber!==void 0?`#${e.attemptNumber}`:Tn(e.attemptId),$=[`${m} ${e.status}`,`${new Date(e.startedAt).toISOString()} \u2192 ${e.endedAt?new Date(e.endedAt).toISOString():t("workflow.detail.parallelNow")}`,e.endType?`end: ${e.endType}`:void 0].filter(Boolean).join(`
|
|
1315
1315
|
`);return`<div class="wf-parallel-row">
|
|
1316
1316
|
<div class="wf-parallel-label">
|
|
1317
1317
|
<code>${h(m)}</code>
|
|
@@ -1319,52 +1319,52 @@ ${Co("manage")}
|
|
|
1319
1319
|
</div>
|
|
1320
1320
|
<div class="wf-parallel-track">
|
|
1321
1321
|
<div class="wf-parallel-bar wf-parallel-${h(e.status)}" style="left:${r.toFixed(3)}%;width:${d.toFixed(3)}%;" title="${h($)}">
|
|
1322
|
-
<span>${h(
|
|
1322
|
+
<span>${h(mt(e.status))}</span>
|
|
1323
1323
|
</div>
|
|
1324
1324
|
</div>
|
|
1325
|
-
</div>`}function
|
|
1325
|
+
</div>`}function Tr(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 a=0,s=0;for(let r of o)a+=r.delta,s=Math.max(s,a);return s}function Ir(e){return e==="activitySucceeded"||e==="activityFailed"||e==="activityTimedOut"||e==="activityCanceled"}function Mr(e){return e==="activitySucceeded"?"succeeded":e==="activityCanceled"?"cancelled":e==="activityTimedOut"?"timedOut":"failed"}function Er(e,n){let o=new Map(n.activities.map(r=>[r.activityId,r])),a=new Set,s=[];for(let r of n.nodes){let d=(r.activityId?o.get(r.activityId):void 0)??n.activities.find(m=>m.ownerNodeId===r.nodeId);d&&a.add(d.activityId),s.push(Ua(r,d))}for(let r of n.activities)a.has(r.activityId)||s.push(Ua(void 0,r));e.innerHTML=s.length>0?s.join(""):`<tr><td colspan="7" class="empty">${h(t("workflow.detail.noNodes"))}</td></tr>`}function Ua(e,n){let o=n?.attempts[n.attempts.length-1];return`<tr>
|
|
1326
1326
|
<td>${e?`<code>${h(e.nodeId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
1327
|
-
<td>${e?
|
|
1327
|
+
<td>${e?at(e.status):'<span class="muted">-</span>'}</td>
|
|
1328
1328
|
<td>${n?`<code>${h(n.activityId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
1329
|
-
<td>${n?
|
|
1329
|
+
<td>${n?at(n.status):'<span class="muted">-</span>'}</td>
|
|
1330
1330
|
<td>${n?.attempts.length??0}</td>
|
|
1331
|
-
<td>${
|
|
1332
|
-
<td>${
|
|
1333
|
-
</tr>`}function
|
|
1331
|
+
<td>${o?`<code>${h(o.attemptId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
1332
|
+
<td>${o?el(o):`<span class="muted">${h(t("workflow.detail.idle"))}</span>`}</td>
|
|
1333
|
+
</tr>`}function xr(e,n,o,a,s,r,d,m){Jr(e,o,a),_r(e,s.comments);let k=!!(d&&n.attemptIO?.[d]?.terminal);k&&d&&o.add(po(d,t("workflow.detail.liveTerminal")));let $=Hr(n),M=new Set;if(m){for(let p of $){M.add(p.key);let S=m.get(p.key);S||(S=Cr(p.key),m.set(p.key,S),e.appendChild(S.article)),Ar(S,p,o,s,r,d)}for(let[p,S]of Array.from(m))M.has(p)||(S.article.remove(),m.delete(p));if($.length===0){if(!e.querySelector(".wf-io-empty-placeholder")){let p=document.createElement("div");p.className="empty wf-io-empty-placeholder",p.textContent=t("workflow.detail.noNodeIO"),e.appendChild(p)}}else e.querySelector(".wf-io-empty-placeholder")?.remove()}else{let p=[];for(let S of $)p.push(Br(S,o,s,r,d));e.innerHTML=p.length>0?p.join(""):`<div class="empty">${h(t("workflow.detail.noNodeIO"))}</div>`}Yr(e,a);let w=Kr(e,d);return Vr(e,o),Qr(e,a),Wr(e,s),Za(e,r),w&&k}function Hr(e){let n=new Map(e.activities.map(s=>[s.activityId,s])),o=new Set,a=[];for(let s of e.nodes){let r=(s.activityId?n.get(s.activityId):void 0)??e.activities.find(d=>d.ownerNodeId===s.nodeId);if(!r){a.push({key:`node:${s.nodeId}`,node:s});continue}o.add(r.activityId),a.push({key:`activity:${r.activityId}`,node:s,activity:r,io:e.attemptIO?.[Sn(r)?.attemptId??""]})}for(let s of e.activities)o.has(s.activityId)||a.push({key:`activity:${s.activityId}`,activity:s,io:e.attemptIO?.[Sn(s)?.attemptId??""]});return a}function Cr(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 a=document.createElement("div");a.className="wf-io-terminal-slot";let s=document.createElement("div");return s.className="wf-io-grid",n.appendChild(o),n.appendChild(a),n.appendChild(s),{article:n,head:o,terminalSlot:a,grid:s,currentTerminalUrl:null}}function Ar(e,n,o,a,s,r){let d=Sn(n.activity),m=n.node?.nodeId??n.activity?.ownerNodeId??n.activity?.activityId??"unknown",k=!!(d&&d.attemptId===r);e.article.classList.toggle("is-focused",k),d?e.article.dataset.wfAttemptCard=d.attemptId:delete e.article.dataset.wfAttemptCard;let $=Xa(d,a);e.head.innerHTML=`
|
|
1334
1334
|
<header>
|
|
1335
1335
|
<div>
|
|
1336
1336
|
<strong><code>${h(m)}</code></strong>
|
|
1337
1337
|
<span class="muted">${n.activity?h(n.activity.activityId):h(t("workflow.detail.notDispatched"))}</span>
|
|
1338
1338
|
</div>
|
|
1339
|
-
<div>${n.node?
|
|
1339
|
+
<div>${n.node?at(n.node.status):""} ${n.activity?at(n.activity.status):""}</div>
|
|
1340
1340
|
</header>
|
|
1341
1341
|
<div class="wf-io-meta">
|
|
1342
1342
|
${d?`${h(t("workflow.detail.attempt"))} <code>${h(d.attemptId)}</code>`:h(t("workflow.detail.noAttempt"))}
|
|
1343
1343
|
</div>
|
|
1344
1344
|
${$}
|
|
1345
|
-
`;let M=
|
|
1346
|
-
${Qe(p,t("workflow.detail.authoredInput"),n.io?.input,
|
|
1347
|
-
${Qe(p,t("workflow.detail.resolvedInput"),n.io?.resolvedInput,
|
|
1348
|
-
${Qe(p,t("workflow.detail.output"),n.io?.output,
|
|
1349
|
-
${Qe(p,t("workflow.detail.executionLog"),n.io?.log,
|
|
1350
|
-
${n.io?.waitPrompt?Qe(p,t("workflow.detail.waitPrompt"),n.io.waitPrompt,
|
|
1351
|
-
`}function
|
|
1345
|
+
`;let M=za(d,n.activity,n.io?.terminal,s),w=M?.url??null;if(w!==e.currentTerminalUrl)M===null?e.terminalSlot.innerHTML="":e.terminalSlot.innerHTML=Wa(n.key,d,n.activity,n.io?.terminal,M,o,s),e.currentTerminalUrl=w;else if(M!==null&&n.io?.terminal){let S=e.terminalSlot.querySelector("details.wf-terminal-block > summary");if(S){let E=Ka(M.kind);S.innerHTML=`${h(E)} ${Qa(d,n.io.terminal)}`}d&&zr(e.terminalSlot,d,n.activity,n.io.terminal,M,s)}let p=d?.attemptId??n.activity?.activityId??n.node?.nodeId??"unknown";e.grid.innerHTML=`
|
|
1346
|
+
${Qe(p,t("workflow.detail.authoredInput"),n.io?.input,o)}
|
|
1347
|
+
${Qe(p,t("workflow.detail.resolvedInput"),n.io?.resolvedInput,o)}
|
|
1348
|
+
${Qe(p,t("workflow.detail.output"),n.io?.output,o)}
|
|
1349
|
+
${Qe(p,t("workflow.detail.executionLog"),n.io?.log,o)}
|
|
1350
|
+
${n.io?.waitPrompt?Qe(p,t("workflow.detail.waitPrompt"),n.io.waitPrompt,o):""}
|
|
1351
|
+
`}function za(e,n,o,a){if(!o||o.error)return null;if(Nr(e,o))return{kind:"live",url:jr(o)};if(!e||!n||!qr(e,o))return null;let s=Fr();if(!s)return null;let r=a?.sessions.get(e.attemptId);return r?{kind:"resume",url:r.url,resumeId:r.resumeId,downloadUrl:Fa(s,n.activityId,e.attemptId)}:{kind:"replay",url:Ur(s,n.activityId,e.attemptId,!!o.hasPtyLog),downloadUrl:Fa(s,n.activityId,e.attemptId)}}function Wa(e,n,o,a,s,r,d){if(!a)return"";let m=Ka(s.kind),k=po(e,m),$=Qa(n,a),M=Dr(s.kind),w=s.kind==="replay"||s.kind==="resume"?`<a class="btn-link" href="${h(s.downloadUrl)}" download>${h(t("workflow.detail.downloadFullLog"))}</a>`:"",p=n?Va(n,o,a,s,d):"",S=n?Ya(n.attemptId,d):"";return`<details class="wf-io-block wf-terminal-block" data-io-key="${h(k)}"${r.has(k)?" open":""}>
|
|
1352
1352
|
<summary>${h(m)} ${$}</summary>
|
|
1353
1353
|
<div class="wf-terminal-actions">
|
|
1354
|
-
<a class="btn-link" href="${h(
|
|
1355
|
-
${
|
|
1354
|
+
<a class="btn-link" href="${h(s.url)}" target="_blank" rel="noreferrer">${h(M)}</a>
|
|
1355
|
+
${w}
|
|
1356
1356
|
${p}
|
|
1357
1357
|
</div>
|
|
1358
1358
|
${S}
|
|
1359
|
-
<iframe class="wf-terminal-frame" src="${h(
|
|
1360
|
-
</details>`}function
|
|
1359
|
+
<iframe class="wf-terminal-frame" src="${h(s.url)}" title="${h(m)}" loading="lazy"></iframe>
|
|
1360
|
+
</details>`}function Ka(e){return e==="live"?t("workflow.detail.liveTerminal"):e==="resume"?t("workflow.detail.terminalResume"):t("workflow.detail.terminalReplay")}function Dr(e){return e==="live"?t("workflow.detail.openTerminalNewTab"):e==="resume"?t("workflow.detail.openResumeNewTab"):t("workflow.detail.openReplayNewTab")}var Ja=new Set(["antigravity","codex-app","cursor","mira"]),Rr=new Set(["aiden","coco","claude-code","seed","relay","codex","mtr","hermes","pi","mir"]);function Or(e){return!!e&&(Rr.has(e)||Ja.has(e))}function Pr(e){return!!e&&Ja.has(e)}function Va(e,n,o,a,s){if(!s||a.kind==="live"||!n)return"";let r=a.kind==="resume",d=s.pending.has(e.attemptId),m=`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" ${m}${d?" disabled":""}>${h(d?t("workflow.detail.resumeEnding"):t("workflow.detail.endResumeSession"))}</button>`:Or(o.cliId)?Pr(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" ${m}${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 Ya(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 Br(e,n,o,a,s){let r=Sn(e.activity),d=e.node?.nodeId??e.activity?.ownerNodeId??e.activity?.activityId??"unknown",m=r?.attemptId??e.activity?.activityId??e.node?.nodeId??"unknown",k=Xa(r,o),$=r?.attemptId===s?" is-focused":"",M=r?` data-wf-attempt-card="${h(r.attemptId)}"`:"",w=za(r,e.activity,e.io?.terminal,a),p=w?Wa(m,r,e.activity,e.io?.terminal,w,n,a):"";return`<article class="wf-io-card${$}" data-wf-card-key="${h(e.key)}"${M}>
|
|
1361
1361
|
<div class="wf-io-card-head">
|
|
1362
1362
|
<header>
|
|
1363
1363
|
<div>
|
|
1364
1364
|
<strong><code>${h(d)}</code></strong>
|
|
1365
1365
|
<span class="muted">${e.activity?h(e.activity.activityId):h(t("workflow.detail.notDispatched"))}</span>
|
|
1366
1366
|
</div>
|
|
1367
|
-
<div>${e.node?
|
|
1367
|
+
<div>${e.node?at(e.node.status):""} ${e.activity?at(e.activity.status):""}</div>
|
|
1368
1368
|
</header>
|
|
1369
1369
|
<div class="wf-io-meta">
|
|
1370
1370
|
${r?`${h(t("workflow.detail.attempt"))} <code>${h(r.attemptId)}</code>`:h(t("workflow.detail.noAttempt"))}
|
|
@@ -1379,29 +1379,29 @@ ${Co("manage")}
|
|
|
1379
1379
|
${Qe(m,t("workflow.detail.executionLog"),e.io?.log,n)}
|
|
1380
1380
|
${e.io?.waitPrompt?Qe(m,t("workflow.detail.waitPrompt"),e.io.waitPrompt,n):""}
|
|
1381
1381
|
</div>
|
|
1382
|
-
</article>`}function Sn(e){return e?.attempts[e.attempts.length-1]}function
|
|
1382
|
+
</article>`}function Sn(e){return e?.attempts[e.attempts.length-1]}function Qa(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 Nr(e,n){return n.status==="live"&&n.webPort>0&&(e?.status==="pending"||e?.status==="running"||e?.status==="effectAttempting")}function qr(e,n){return e.status==="succeeded"||e.status==="failed"||e.status==="cancelled"||e.status==="timedOut"?!!(n.sessionId||n.startedAt):!1}function jr(e){return`http://${window.location.hostname||"127.0.0.1"}:${e.webPort}`}function Ur(e,n,o,a){let s=new URLSearchParams({runId:e,activityId:n,attemptId:o});return a&&s.set("hasPtyLog","1"),`/assets/terminal-replay.html?${s.toString()}`}function Fa(e,n,o){return`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(n)}/${encodeURIComponent(o)}/terminal-log/raw?download=1`}function Fr(){let e=window.location.hash.match(/^#\/workflows\/([^/?#]+)/);if(!e)return null;try{return decodeURIComponent(e[1])}catch{return null}}function Xa(e,n){if(!Gr(e))return"";let o=e.attemptId,a=n.comments.get(o)??"",s=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)}">
|
|
1383
1383
|
<label>
|
|
1384
1384
|
<span>${h(t("workflow.detail.approvalComment"))}</span>
|
|
1385
|
-
<textarea class="wf-approval-comment" data-wf-approval-comment="${h(
|
|
1385
|
+
<textarea class="wf-approval-comment" data-wf-approval-comment="${h(o)}" rows="2" placeholder="${h(t("workflow.detail.optionalComment"))}"${s?" disabled":""}>${h(a)}</textarea>
|
|
1386
1386
|
</label>
|
|
1387
1387
|
<div class="wf-approval-actions">
|
|
1388
|
-
<button type="button" class="primary" data-wf-approval-action="approve" data-wf-attempt-id="${h(
|
|
1389
|
-
<button type="button" data-wf-approval-action="reject" data-wf-attempt-id="${h(
|
|
1390
|
-
${
|
|
1388
|
+
<button type="button" class="primary" data-wf-approval-action="approve" data-wf-attempt-id="${h(o)}"${s?" disabled":""}>${h(t("workflow.detail.approve"))}</button>
|
|
1389
|
+
<button type="button" data-wf-approval-action="reject" data-wf-attempt-id="${h(o)}"${s?" disabled":""}>${h(t("workflow.detail.reject"))}</button>
|
|
1390
|
+
${s?`<span class="muted">${h(t("workflow.detail.submitting"))}</span>`:""}
|
|
1391
1391
|
</div>
|
|
1392
1392
|
${r?`<div class="${d} wf-approval-status">${h(r.text)}</div>`:""}
|
|
1393
|
-
</div>`}function
|
|
1394
|
-
<summary>${h(n)} ${
|
|
1395
|
-
${
|
|
1396
|
-
</details>`}function
|
|
1397
|
-
<td>${
|
|
1393
|
+
</div>`}function Gr(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function _r(e,n){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(o=>{let a=o.dataset.wfApprovalComment;a&&n.set(a,o.value)})}function Za(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 a=o.dataset.wfResumeAttempt,s=o.dataset.wfResumeActivity,r=o.dataset.wfResumeAction;!a||!s||(r==="start"?n.onStart(a,s):r==="end"&&n.onEnd(a,s))}))})}function zr(e,n,o,a,s,r){let d=e.querySelector(".wf-terminal-actions");if(!d)return;let m=d.querySelector('button[data-wf-resume-button="1"]'),k=Va(n,o,a,s,r);m?m.outerHTML=k:k&&d.insertAdjacentHTML("beforeend",k);let $=e.querySelector("details.wf-terminal-block");if($){let M=$.querySelector(".wf-resume-status"),w=Ya(n.attemptId,r);M?M.outerHTML=w:w&&d.insertAdjacentHTML("afterend",w)}Za(e,r)}function Wr(e,n){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(o=>{let a=o.dataset.wfApprovalComment;a&&o.addEventListener("input",()=>{n.comments.set(a,o.value)})}),e.querySelectorAll("button[data-wf-approval-action][data-wf-attempt-id]").forEach(o=>{o.addEventListener("click",()=>{let a=o.dataset.wfAttemptId,s=o.dataset.wfApprovalAction;!a||s!=="approve"&&s!=="reject"||n.onResolve(a,s)})})}function Qe(e,n,o,a){let s=po(e,n);return`<details class="wf-io-block" data-io-key="${h(s)}"${a.has(s)?" open":""}>
|
|
1394
|
+
<summary>${h(n)} ${Xr(o)}</summary>
|
|
1395
|
+
${Zr(o)}
|
|
1396
|
+
</details>`}function po(e,n){return`${e}:${n}`}function Kr(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 Jr(e,n,o){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(a=>{let s=a.dataset.ioKey;if(!s)return;a.open?n.add(s):n.delete(s);let r=a.querySelector(".wf-io-pre");r&&o.set(s,r.scrollTop)})}function Vr(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 a=o.dataset.ioKey;a&&(o.open?n.add(a):n.delete(a))}))})}function Yr(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(o=>{let a=o.dataset.ioKey;if(!a)return;let s=n.get(a);if(s===void 0)return;let r=o.querySelector(".wf-io-pre");r&&(r.scrollTop=s)})}function Qr(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(o=>{let a=o.dataset.ioKey;if(!a)return;let s=o.querySelector(".wf-io-pre");s&&s.dataset.ioScrollBound!=="1"&&(s.dataset.ioScrollBound="1",s.addEventListener("scroll",()=>{n.set(a,s.scrollTop)}))})}function Xr(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(Tn(e.outputHash)),n.length?`<span class="muted">${h(n.join(" \xB7 "))}</span>`:""}function Zr(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 el(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(Ln(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(Tn(e.output.outputHash))}`),e.runningMs!==void 0&&n.push(`${e.runningMs}ms`),n.length>0?n.join("<br/>"):'<span class="muted">-</span>'}function tl(e,n){e.innerHTML=n.length>0?n.map(nl).join(""):`<tr><td colspan="7" class="empty">${h(t("workflow.detail.noEvents"))}</td></tr>`}function nl(e){let n=ol(e.payload);return`<tr>
|
|
1397
|
+
<td>${Xt(e.eventId)}</td>
|
|
1398
1398
|
<td><code>${h(e.type)}</code></td>
|
|
1399
1399
|
<td>${h(e.actor)}</td>
|
|
1400
1400
|
<td>${n.nodeId?`<code>${h(n.nodeId)}</code>`:"-"}</td>
|
|
1401
1401
|
<td>${n.activityId?`<code>${h(n.activityId)}</code>`:"-"}</td>
|
|
1402
1402
|
<td>${n.errorCode?`<span class="muted error">${h(n.errorCode)}</span>`:"-"}</td>
|
|
1403
1403
|
<td title="${h(new Date(e.timestamp).toISOString())}">${h(Ln(e.timestamp))}</td>
|
|
1404
|
-
</tr>`}function
|
|
1404
|
+
</tr>`}function Xt(e){let n=e.lastIndexOf("-");if(n<0)return 0;let o=Number(e.slice(n+1));return Number.isFinite(o)?o:0}function ol(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 a=n.error;return a&&typeof a=="object"&&"errorCode"in a&&(o.errorCode=String(a.errorCode)),o}function al(e){return!e.payload||typeof e.payload!="object"||"ref"in e.payload?null:e.payload}function Ga(e,n,o){return Math.min(o,Math.max(n,e))}function Tn(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function sl(e,n){return e.length>n?e.slice(0,n-1)+"\u2026":e}function Ln(e){return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}function F(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function es(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function ts(e){let n=location.hash.match(/^#\/(?:workflows\/catalog|workflows-catalog)\/([^/?#]+)$/);return n?rl(e,decodeURIComponent(n[1])):il(e)}function il(e){e.innerHTML=`
|
|
1405
1405
|
<nav class="wf-subnav">
|
|
1406
1406
|
<a href="#/workflows" data-i18n="workflow.subnav.runs">${F(t("workflow.subnav.runs"))}</a>
|
|
1407
1407
|
<a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${F(t("workflow.subnav.catalog"))}</a>
|
|
@@ -1430,16 +1430,16 @@ ${Co("manage")}
|
|
|
1430
1430
|
<tbody id="catalog-tbody"></tbody>
|
|
1431
1431
|
</table>
|
|
1432
1432
|
</div>
|
|
1433
|
-
`;let n=e.querySelector("#catalog-tbody"),
|
|
1433
|
+
`;let n=e.querySelector("#catalog-tbody"),o=e.querySelector("#catalog-status"),a=e.querySelector("#catalog-filters"),s=e.querySelector("#catalog-refresh"),r=[],d=null,m=!1;function k(){let w=(new FormData(a).get("q")??"").trim().toLowerCase();return w?r.filter(p=>p.workflowId.toLowerCase().includes(w)||p.path.toLowerCase().includes(w)):r}function $(){d?(o.textContent=t("catalog.loadFailed",{error:d}),o.classList.add("error")):(o.textContent=`${r.length}`,o.classList.remove("error"));let w=k();if(w.length===0){n.innerHTML=`<tr><td colspan="6" class="empty">${r.length===0?F(t("catalog.noDefinitions")):F(t("catalog.noFilterMatch"))}</td></tr>`;return}n.innerHTML=w.map(p=>`
|
|
1434
1434
|
<tr>
|
|
1435
1435
|
<td><a href="#/workflows/catalog/${encodeURIComponent(p.workflowId)}"><code>${F(p.workflowId)}</code></a></td>
|
|
1436
1436
|
<td>${p.version}</td>
|
|
1437
1437
|
<td>${F(t("catalog.paramSummary",{required:p.requiredParamCount,total:p.paramCount}))}</td>
|
|
1438
1438
|
<td>${p.nodeCount}</td>
|
|
1439
|
-
<td><code>${F(
|
|
1439
|
+
<td><code>${F(es(p.revisionId))}</code></td>
|
|
1440
1440
|
<td><code>${F(p.path)}</code></td>
|
|
1441
1441
|
</tr>
|
|
1442
|
-
`).join("")}async function M(){
|
|
1442
|
+
`).join("")}async function M(){s.disabled=!0,o.textContent=t("catalog.loading");try{let w=await fetch("/api/workflows/definitions");if(!w.ok)throw new Error(`HTTP ${w.status}`);r=(await w.json()).definitions??[],d=null}catch(w){d=w?.message??String(w),r=[]}finally{s.disabled=!1,m||$()}}return a.addEventListener("input",$),s.addEventListener("click",()=>{M()}),M(),()=>{m=!0}}function rl(e,n){e.innerHTML=`
|
|
1443
1443
|
<div class="catalog-detail-head">
|
|
1444
1444
|
<a class="btn-link" href="#/workflows/catalog">${F(t("catalog.back"))}</a>
|
|
1445
1445
|
<div>
|
|
@@ -1450,7 +1450,7 @@ ${Co("manage")}
|
|
|
1450
1450
|
<section id="catalog-error" class="hint-warn" hidden></section>
|
|
1451
1451
|
<section id="catalog-run-status" class="hint-ok" hidden></section>
|
|
1452
1452
|
<div id="catalog-detail-body"></div>
|
|
1453
|
-
`;let
|
|
1453
|
+
`;let o=e.querySelector("#catalog-detail-subtitle"),a=e.querySelector("#catalog-error"),s=e.querySelector("#catalog-run-status"),r=e.querySelector("#catalog-detail-body"),d=null,m=!1,k=!1;function $(L){a.hidden=!L,a.textContent=L??""}function M(L){s.hidden=!L,s.textContent=L??""}function w(L){let x={};for(let[T,R]of Object.entries(L??{}))"default"in R&&(x[T]=R.default);return x}function p(){if(!d)return;let L=d.definition;o.textContent=`${t("catalog.revision")} ${es(d.revisionId)} \xB7 ${d.path}`;let x=JSON.stringify(w(L.params),null,2);r.innerHTML=`
|
|
1454
1454
|
<section class="wf-panel">
|
|
1455
1455
|
<div class="wf-panel-title"><h3>${F(t("catalog.summary"))}</h3></div>
|
|
1456
1456
|
<div class="wf-summary-grid">
|
|
@@ -1486,24 +1486,24 @@ ${Co("manage")}
|
|
|
1486
1486
|
|
|
1487
1487
|
<section class="wf-panel">
|
|
1488
1488
|
<div class="wf-panel-title"><h3>${F(t("catalog.paramsSchema"))}</h3></div>
|
|
1489
|
-
${
|
|
1489
|
+
${ll(L.params)}
|
|
1490
1490
|
</section>
|
|
1491
1491
|
|
|
1492
1492
|
<section class="wf-panel">
|
|
1493
1493
|
<div class="wf-panel-title"><h3>${F(t("catalog.definitionJson"))}</h3></div>
|
|
1494
1494
|
<pre class="wf-io-pre">${F(JSON.stringify(L,null,2))}</pre>
|
|
1495
1495
|
</section>
|
|
1496
|
-
`,E()}async function S(){if(!d||k)return;let L=r.querySelector("#catalog-params"),x=r.querySelector("#catalog-chat-id"),T=r.querySelector("#catalog-lark-app-id"),R=r.querySelector("#catalog-run-btn"),q=r.querySelector("#catalog-param-errors"),u;try{if(u=JSON.parse(L.value||"{}"),!u||typeof u!="object"||Array.isArray(u))throw new Error(t("catalog.badParamsJson"))}catch(
|
|
1496
|
+
`,E()}async function S(){if(!d||k)return;let L=r.querySelector("#catalog-params"),x=r.querySelector("#catalog-chat-id"),T=r.querySelector("#catalog-lark-app-id"),R=r.querySelector("#catalog-run-btn"),q=r.querySelector("#catalog-param-errors"),u;try{if(u=JSON.parse(L.value||"{}"),!u||typeof u!="object"||Array.isArray(u))throw new Error(t("catalog.badParamsJson"))}catch(y){q.hidden=!1,q.innerHTML=`<div class="muted error">${F(y?.message??String(y))}</div>`;return}k=!0,R.disabled=!0,R.textContent=t("catalog.running"),q.hidden=!0,$(null),M(null);try{let y=await fetch(`/api/workflows/definitions/${encodeURIComponent(d.definition.workflowId)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({params:u,chatBinding:{chatId:x.value.trim(),larkAppId:T.value.trim()}})});if(y.status===401)throw new Error(t("catalog.writeAccess"));let A=await y.json().catch(()=>({}));if(!y.ok||!A.ok)throw A.issues?.length&&(q.hidden=!1,q.innerHTML=`<strong>${F(t("catalog.invalidParams"))}</strong><ul>${A.issues.map(O=>`<li>${F(t("catalog.issue",{path:O.path.length?O.path.join("."):"(root)",message:O.message}))}</li>`).join("")}</ul>`),new Error(A.hint??A.message??A.error??t("catalog.runHttp",{status:y.status}));M(t("catalog.runStarted")),A.runId&&(location.hash=`#/workflows/${encodeURIComponent(A.runId)}`)}catch(y){$(y?.message??String(y))}finally{k=!1,R.disabled=!1,R.textContent=t("catalog.run")}}function E(){r.querySelector("#catalog-run-form")?.addEventListener("submit",x=>{x.preventDefault(),S()})}async function C(){try{let L=await fetch(`/api/workflows/definitions/${encodeURIComponent(n)}`);if(L.status===404)throw new Error("unknown_workflow");if(!L.ok)throw new Error(`HTTP ${L.status}`);d=await L.json(),$(null),p()}catch(L){$(t("catalog.definitionLoadFailed",{error:L?.message??String(L)})),o.textContent=t("workflow.detail.loadFailed")}}return C().then(()=>{}),()=>{m=!0}}function ll(e){let n=Object.entries(e??{});return n.length===0?`<div class="muted">${F(t("catalog.noParams"))}</div>`:`<div class="catalog-param-list">${n.map(([o,a])=>`
|
|
1497
1497
|
<article class="catalog-param">
|
|
1498
1498
|
<header>
|
|
1499
|
-
<code>${F(
|
|
1500
|
-
<span class="wf-status">${F(
|
|
1501
|
-
<span class="muted">${F(
|
|
1499
|
+
<code>${F(o)}</code>
|
|
1500
|
+
<span class="wf-status">${F(a.required?t("catalog.required"):t("catalog.optional"))}</span>
|
|
1501
|
+
<span class="muted">${F(a.type)}${a.format?` \xB7 ${F(a.format)}`:""}</span>
|
|
1502
1502
|
</header>
|
|
1503
|
-
${
|
|
1504
|
-
${"default"in
|
|
1503
|
+
${a.description?`<div class="muted">${F(t("catalog.description"))}: ${F(a.description)}</div>`:""}
|
|
1504
|
+
${"default"in a?`<pre class="wf-io-pre">${F(`${t("catalog.default")}: ${JSON.stringify(a.default,null,2)}`)}</pre>`:""}
|
|
1505
1505
|
</article>
|
|
1506
|
-
`).join("")}</div>`}var In=78222186;function
|
|
1506
|
+
`).join("")}</div>`}var In=78222186;function ns(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,a,s="",r=p=>(p/1048576).toFixed(0);function d(){a&&(clearTimeout(a),a=void 0)}function m(){d(),e.innerHTML=`
|
|
1507
1507
|
<iframe
|
|
1508
1508
|
src="/game/index.html"
|
|
1509
1509
|
title="HD2D Office"
|
|
@@ -1523,7 +1523,7 @@ ${Co("manage")}
|
|
|
1523
1523
|
</div>
|
|
1524
1524
|
<div style="font-size:12px;opacity:.7;">\u4E0B\u8F7D\u4E2D\u2026 ${r(p.received)} / ${r(S)} MB\uFF08${E}%\uFF09</div>
|
|
1525
1525
|
`:`
|
|
1526
|
-
<input id="hd2d-proxy" type="text" value="${i(
|
|
1526
|
+
<input id="hd2d-proxy" type="text" value="${i(s)}"
|
|
1527
1527
|
placeholder="HTTP \u4EE3\u7406\uFF08\u53EF\u9009\uFF0C\u5982 http://127.0.0.1:7890\uFF09"
|
|
1528
1528
|
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;" />
|
|
1529
1529
|
<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>
|
|
@@ -1531,24 +1531,35 @@ ${Co("manage")}
|
|
|
1531
1531
|
${L?"\u91CD\u8BD5":"\u52A0\u8F7D\u529E\u516C\u5BA4"}\uFF08\u7EA6 ${r(S)} MB\uFF09
|
|
1532
1532
|
</button>
|
|
1533
1533
|
`}
|
|
1534
|
-
</div>`;let x=e.querySelector("#hd2d-load");x&&(x.onclick=()=>{
|
|
1534
|
+
</div>`;let x=e.querySelector("#hd2d-load");x&&(x.onclick=()=>{s=e.querySelector("#hd2d-proxy")?.value.trim()??"",M()})}function $(p){if(!o){if(typeof p.proxy=="string"&&(s=p.proxy),p.state==="ready"){m();return}k(p),p.state==="downloading"&&(a=setTimeout(()=>{w()},700))}}async function M(){k({state:"downloading",received:0,total:In});try{let p=await fetch("/api/game/download",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({proxy:s})});if(!p.ok)throw new Error(`HTTP ${p.status}`);$(await p.json())}catch(p){k({state:"error",received:0,total:In,error:p instanceof Error?p.message:String(p)})}}async function w(){if(!o)try{let p=await fetch("/api/game/status");if(!p.ok){k({state:"absent",received:0,total:In});return}$(await p.json())}catch{o||(a=setTimeout(()=>{w()},1500))}}return w(),()=>{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 ft=null,Mn=null,En="glm-5.1",as=[];function Zt(){Mn!==null&&(window.clearInterval(Mn),Mn=null)}function fo(){return ft||(ft=document.createElement("dialog"),ft.className="onboarding-dialog",document.body.appendChild(ft),ft.addEventListener("close",Zt),ft)}function dl(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==="needs_owner"?t("botOnboarding.needsOwner"):e.status==="completed"?t("botOnboarding.completed"):e.status==="failed"?`${t("botOnboarding.failed")}: ${i(e.message??e.error??"unknown")}`:t("botOnboarding.starting")}function cl(e){if(e.status!=="completed"&&e.status!=="needs_owner"||!e.permission)return"";let n=e.permission;if(n.ok){let a=[t("botOnboarding.permissionOk",{count:n.scopeCount??0})];n.skippedScopeCount&&n.skippedScopeCount>0&&a.push(t("botOnboarding.permissionSkipped",{count:n.skippedScopeCount})),n.versionId&&a.push(t("botOnboarding.permissionVersion",{version:i(n.versionId)}));let s=`<p class="hint-ok">\u2705 ${a.join(" ")}</p>`;return n.scopeWarning&&(s+=`<p class="hint-warn">\u26A0\uFE0F ${i(n.scopeWarning)}</p>`),s}let o=(e.remainingSteps??[]).map(a=>`<li><a href="${i(a.url)}" target="_blank" rel="noopener">${i(a.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 ul(e,n){if(e.status!=="needs_owner")return"";let o=n?`<p class="form-error">${i(n)}</p>`:"";return`<form id="ob-owner-form" class="onboarding-form">
|
|
1535
|
+
<label class="onboarding-field">
|
|
1536
|
+
<span>${t("botOnboarding.ownerLabel")}</span>
|
|
1537
|
+
<input id="ob-owner" type="text" placeholder="${t("botOnboarding.ownerPlaceholder")}" autocomplete="off" spellcheck="false">
|
|
1538
|
+
</label>
|
|
1539
|
+
<p class="hint-warn">${t("botOnboarding.ownerHint")}</p>
|
|
1540
|
+
${o}
|
|
1541
|
+
<menu class="onboarding-actions">
|
|
1542
|
+
<button type="submit" class="primary">${t("botOnboarding.ownerSubmit")}</button>
|
|
1543
|
+
</menu>
|
|
1544
|
+
</form>`}function st(e,n){let o=fo(),a=e.status==="waiting_for_scan"&&e.qrDataUrl?`<div class="qr-card">
|
|
1535
1545
|
<img class="qr-image" src="${e.qrDataUrl}" alt="${t("botOnboarding.qrAlt")}">
|
|
1536
1546
|
${e.qrUrl?`<a class="onboarding-link" href="${i(e.qrUrl)}" target="_blank" rel="noopener">${t("botOnboarding.openLink")}</a>`:""}
|
|
1537
1547
|
</div>`:"",s=e.status==="waiting_for_platform_scan"&&e.platformQrDataUrl?`<div class="qr-card">
|
|
1538
1548
|
<img class="qr-image" src="${e.platformQrDataUrl}" alt="${t("botOnboarding.platformQrAlt")}">
|
|
1539
|
-
</div>`:"",
|
|
1549
|
+
</div>`:"",r=e.appId?`<p><b>App ID:</b> <code>${i(e.appId)}</code>`+(e.cliId?` \uFF5C <b>CLI:</b> <code>${i(e.cliId)}</code>`:"")+(e.workingDir?` \uFF5C <b>${t("botOnboarding.metaDir")}:</b> <code>${i(e.workingDir)}</code>`:"")+"</p>":"",d=e.status==="completed"?`<p class="hint-ok">${t("botOnboarding.restartHint")}</p>`:"";o.innerHTML=`<article>
|
|
1540
1550
|
<header>
|
|
1541
1551
|
<h3>${t("botOnboarding.title")}</h3>
|
|
1542
1552
|
<p>${t("botOnboarding.intro")}</p>
|
|
1543
1553
|
</header>
|
|
1544
|
-
<p class="onboarding-status status-${e.status}">${
|
|
1554
|
+
<p class="onboarding-status status-${e.status}">${dl(e)}</p>
|
|
1545
1555
|
${a}
|
|
1546
1556
|
${s}
|
|
1547
|
-
${o}
|
|
1548
|
-
${dl(e)}
|
|
1549
1557
|
${r}
|
|
1558
|
+
${cl(e)}
|
|
1559
|
+
${ul(e,n)}
|
|
1560
|
+
${d}
|
|
1550
1561
|
<form method="dialog"><button>${t("botOnboarding.close")}</button></form>
|
|
1551
|
-
</article
|
|
1562
|
+
</article>`,e.status==="needs_owner"&&o.querySelector("#ob-owner-form")?.addEventListener("submit",k=>{k.preventDefault();let $=o.querySelector("#ob-owner")?.value??"";pl(e,$)})}async function pl(e,n){if(!n.trim()){st(e,t("botOnboarding.ownerEmpty"));return}try{let o=await fetch(`/api/bot-onboarding/${encodeURIComponent(e.id)}/owner`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({owner:n.trim()})}),a=await o.json();if(!o.ok){st(e,a?.message??a?.error??t("botOnboarding.ownerInvalid"));return}a?.job&&st(a.job)}catch(o){st(e,o instanceof Error?o.message:String(o))}}async function ml(){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()&&(En=n.ttadkModelDefault.trim()),Array.isArray(n.ttadkModelSuggestions)&&(as=n.ttadkModelSuggestions.filter(o=>typeof o=="string")),n.options}catch{}return[{id:"claude-code",label:"Claude"}]}function os(e){let n=ft;if(!n)return;let o=n.querySelector("#ob-cli"),a=n.querySelector("#ob-model"),s=n.querySelector("#ob-model-suggestions");if(!o||!a)return;let r=e.find(k=>k.id===o.value),d=r?.gateway==="ttadk",m=d&&r?.acceptsModel!==!1;if(d&&!m){a.value="",a.disabled=!0,a.placeholder=t("botOnboarding.modelTtadkCocoPlaceholder");return}a.disabled=!1,m?(s&&(s.innerHTML=as.map(k=>`<option value="${i(k)}"></option>`).join("")),a.placeholder=t("botOnboarding.modelTtadkPlaceholder").replace("{model}",En),a.value.trim()||(a.value=En)):(s&&(s.innerHTML=""),a.placeholder=t("botOnboarding.modelPlaceholder"),a.value.trim()===En&&(a.value=""))}function mo(e,n){let o=fo(),a=e.map(k=>`<option value="${i(k.id)}">${i(k.label)}\uFF08${i(k.id)}\uFF09</option>`).join(""),s=n?`<p class="form-error">${i(n)}</p>`:"";o.innerHTML=`<article>
|
|
1552
1563
|
<header>
|
|
1553
1564
|
<h3>${t("botOnboarding.title")}</h3>
|
|
1554
1565
|
<p>${t("botOnboarding.intro")}</p>
|
|
@@ -1556,7 +1567,7 @@ ${Co("manage")}
|
|
|
1556
1567
|
<form id="onboarding-form" class="onboarding-form">
|
|
1557
1568
|
<label class="onboarding-field">
|
|
1558
1569
|
<span>${t("botOnboarding.cliLabel")}</span>
|
|
1559
|
-
<select id="ob-cli">${
|
|
1570
|
+
<select id="ob-cli">${a}</select>
|
|
1560
1571
|
</label>
|
|
1561
1572
|
<label class="onboarding-field">
|
|
1562
1573
|
<span>${t("botOnboarding.dirLabel")}</span>
|
|
@@ -1567,14 +1578,14 @@ ${Co("manage")}
|
|
|
1567
1578
|
<input id="ob-model" type="text" list="ob-model-suggestions" placeholder="${t("botOnboarding.modelPlaceholder")}" autocomplete="off" spellcheck="false">
|
|
1568
1579
|
<datalist id="ob-model-suggestions"></datalist>
|
|
1569
1580
|
</label>
|
|
1570
|
-
${
|
|
1581
|
+
${s}
|
|
1571
1582
|
<menu class="onboarding-actions">
|
|
1572
1583
|
<button type="button" id="ob-cancel">${t("botOnboarding.cancel")}</button>
|
|
1573
1584
|
<button type="submit" class="primary">${t("botOnboarding.startScan")}</button>
|
|
1574
1585
|
</menu>
|
|
1575
1586
|
</form>
|
|
1576
|
-
</article>`;let r=
|
|
1587
|
+
</article>`;let r=o.querySelector("#onboarding-form");o.querySelector("#ob-cancel")?.addEventListener("click",()=>o.close()),o.querySelector("#ob-cli")?.addEventListener("change",()=>os(e)),os(e),r?.addEventListener("submit",k=>{k.preventDefault();let $=o.querySelector("#ob-cli")?.value??"",M=o.querySelector("#ob-dir")?.value??"",w=o.querySelector("#ob-model")?.value??"";fl({cliId:$,workingDir:M,model:w},e)})}async function fl(e,n){Zt(),st({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})}),a=await o.json();if(o.status===400){mo(n,a?.message??a?.error??"invalid_input");return}if(!o.ok||!a?.job?.id)throw new Error(a?.error??`http_${o.status}`);st(a.job),Mn=window.setInterval(()=>{gl(a.job.id).catch(s=>{Zt(),st({id:a.job.id,status:"failed",message:s instanceof Error?s.message:String(s)})})},1200)}catch(o){st({id:"",status:"failed",message:o instanceof Error?o.message:String(o)})}}async function gl(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}`);st(o.job),(o.job.status==="completed"||o.job.status==="failed"||o.job.status==="needs_owner")&&Zt()}async function bl(){Zt();let e=fo();mo([{id:"claude-code",label:"Claude"}]),e.open||e.showModal();let n=await ml();e.open&&e.querySelector("#onboarding-form")&&mo(n)}function ss(){let e=document.getElementById("add-bot-btn");e&&(e.onclick=()=>{bl()})}var hl={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"/>'},rs=[{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"}]}],is=rs.flatMap(e=>e.options),St=!1;function go(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">${hl[e]??""}</svg>`}function wl(e){return e.replace(/[&<>"]/g,n=>({"&":"&","<":"<",">":">",'"':"""})[n])}function ls(){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=rs.map(s=>`<div class="tm-group" data-label-key="${s.labelKey}"></div>`+s.options.map(r=>`<button type="button" class="tm-item" role="option" data-value="${r.value}"><span class="tm-ic">${go(r.icon)}</span><span class="tm-label" data-label-key="${r.labelKey}"></span></button>`).join("")).join("");let a=s=>{St=s,o.hidden=!St,n.setAttribute("aria-expanded",String(St)),e.classList.toggle("open",St)};n.addEventListener("click",s=>{s.stopPropagation(),a(!St)}),o.addEventListener("click",s=>{let r=s.target.closest(".tm-item");r&&(Te.setTheme(r.dataset.value??"system"),a(!1))}),document.addEventListener("click",s=>{St&&!e.contains(s.target)&&a(!1)}),document.addEventListener("keydown",s=>{s.key==="Escape"&&St&&a(!1)}),bo()}function bo(){let e=document.getElementById("theme-menu-btn");if(!e)return;let n=is.find(o=>o.value===Te.theme)??is[0];e.innerHTML=`<span class="tm-ic">${go(n.icon)}</span><span class="tm-current">${wl(t(n.labelKey))}</span><span class="tm-chev">${go("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 Ie=document.getElementById("root"),Ot=!0,ms=!1,fs=["roles","bot-defaults","skills","team","connectors"],ho=!1;function yl(){if(ho)return;ho=!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(),ho=!1};e.querySelector("#auth-expired-dismiss")?.addEventListener("click",n),e.addEventListener("click",o=>{o.target===e&&n()})}var wo;function vl(){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",wo&&window.clearTimeout(wo),wo=window.setTimeout(()=>{e.style.display="none"},4e3)}var kl=window.fetch.bind(window);window.fetch=async function(...n){let o=await kl(...n);if(o.status===401){let a=(n[1]?.method??"GET").toUpperCase();(a==="GET"||a==="HEAD")&&!ms?yl():vl()}return o};var yo="";function xn(){let e=document.getElementById("attention-strip");if(!e)return;let n=[...Y.sessions.values()].map(s=>({s,reason:ut(s)})).filter(s=>!!s.reason).sort((s,r)=>Ce(s.s)-Ce(r.s));if(n.length===0){e.hidden=!0,e.innerHTML="",yo="";return}let o=n[0],a=`
|
|
1577
1588
|
<span class="attention-strip-ic" aria-hidden="true">!</span>
|
|
1578
1589
|
<b>${i(t("strip.pending",{count:n.length}))}</b>
|
|
1579
|
-
<span class="attention-strip-longest">${i(t("strip.longest",{time:qe(Ce(
|
|
1580
|
-
<a class="attention-strip-go" href="#/sessions">${i(t("strip.handle"))}</a>`;e.hidden=!1,
|
|
1590
|
+
<span class="attention-strip-longest">${i(t("strip.longest",{time:qe(Ce(o.s)),bot:ke(o.s),reason:o.reason}))}</span>
|
|
1591
|
+
<a class="attention-strip-go" href="#/sessions">${i(t("strip.handle"))}</a>`;e.hidden=!1,a!==yo&&(yo=a,e.innerHTML=a)}Y.on(xn);Ke().then(xn);async function $l(){try{let e=await fetch("/api/settings");if(e.ok){let n=await e.json();Ot=!!n.authed,Te.authed=Ot,ms=!!(n.settings&&n.settings.publicReadOnly);let o=nn(n.lang);o&&Te.setLocale(o)}}catch{}}async function Sl(e){if(Ot)try{await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({lang:e})})}catch{}}function Ll(){for(let n of fs){let o=document.querySelector(`.sidebar-nav a[data-route="${n}"]`);o&&(o.style.display=Ot?"":"none")}let e=document.getElementById("add-bot-btn");e&&(e.style.display=Ot?"":"none")}function Tl(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 Rt=null;function ds(e){for(let n of document.querySelectorAll(".sidebar-nav a")){let o=n.getAttribute("href")??"#/";n.classList.toggle("active",o===(e||"#/"))}}function vo(){Rt&&(Rt(),Rt=null);let e=location.hash||"#/";if(!Ot&&fs.some(n=>e.startsWith("#/"+n))){Tl(Ie),ds(e);return}e.startsWith("#/workflows/catalog")||e.startsWith("#/workflows-catalog")?Rt=ts(Ie):e.startsWith("#/workflows")?Rt=_a(Ie):e.startsWith("#/groups")?ha(Ie):e.startsWith("#/settings")?ja(Ie):e.startsWith("#/bot-defaults")?$a(Ie):e.startsWith("#/skills")?Ta(Ie):e.startsWith("#/connectors")?Na(Ie):e.startsWith("#/team/manage")?Oa(Ie):e.startsWith("#/team")?Ra(Ie):e.startsWith("#/roles")?xa(Ie):e.startsWith("#/schedules")?ga(Ie):e.startsWith("#/sessions")?ma(Ie):e.startsWith("#/office")?Rt=ns(Ie)??null:ta(Ie),ds(e)}var ko=document.getElementById("status");function gs(){ko&&(ko.textContent=Y.online?t("status.live"):t("status.disconnected"),ko.className="connection-status "+(Y.online?"online":"offline"))}Y.on(gs);function cs(){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)}),bo(),gs()}function Il(){document.querySelectorAll("[data-locale]").forEach(e=>{e.onclick=()=>{let n=e.dataset.locale;Te.setLocale(n),Sl(n)}}),ls(),El()}var us="botmux.ownerAvatar.v1";function ps(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 Ml(){try{let e=JSON.parse(window.localStorage.getItem(us)??"null");e?.avatarUrl&&ps(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)){ps(String(e.avatarUrl),e.name?String(e.name):void 0);try{window.localStorage.setItem(us,JSON.stringify({avatarUrl:e.avatarUrl,name:e.name??""}))}catch{}}}).catch(()=>{})}function El(){let e=document.getElementById("sidebar-toggle");if(!e)return;let n=No(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",qo(window.localStorage,n),o()})}(async()=>{Te.init(),Il(),ss(),Te.on(()=>{cs(),xn(),vo()}),cs(),xn(),await $l(),Ll(),Ml();try{await Lo()}catch(e){console.error("botmux dashboard bootstrap failed",e),Y.setOnline(!1)}window.addEventListener("hashchange",vo),vo()})();})();
|