botmux 2.84.1 → 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/bot-registry.d.ts +11 -0
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +7 -0
- package/dist/bot-registry.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +22 -13
- package/dist/cli.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +42 -0
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/startup-commands.d.ts +57 -0
- package/dist/core/startup-commands.d.ts.map +1 -0
- package/dist/core/startup-commands.js +85 -0
- package/dist/core/startup-commands.js.map +1 -0
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +4 -0
- package/dist/core/worker-pool.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 +67 -4
- 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 +22 -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 +446 -425
- package/dist/dashboard.js +76 -35
- package/dist/dashboard.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +1 -0
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +1 -0
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/card-builder.d.ts.map +1 -1
- package/dist/im/lark/card-builder.js +2 -0
- package/dist/im/lark/card-builder.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/services/bot-config-store.d.ts +6 -0
- package/dist/services/bot-config-store.d.ts.map +1 -1
- package/dist/services/bot-config-store.js +5 -1
- package/dist/services/bot-config-store.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/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/worker.js +135 -21
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
"use strict";(()=>{var Cn=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()}},Q=new Cn;async function Sa(){let[e,n]=await Promise.all([fetch("/api/sessions").then(o=>o.json()),fetch("/api/schedules").then(o=>o.json())]);Q.upsertSessions(e.sessions??[]),Q.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);Q.applySse(o,d.body??d)}catch{}});a.onerror=()=>Q.setOnline(!1),a.onopen=()=>Q.setOnline(!0)}var An="botmux.dashboard.locale",ys={"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
|
-
.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","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
|
|
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
|
|
5
5
|
\u4F60\u662F\u672C\u7FA4\u7684\u6280\u672F\u987E\u95EE\uFF0C\u8D1F\u8D23\u56DE\u7B54\u6240\u6709\u6280\u672F\u95EE\u9898...`,"roles.configured":"\u5DF2\u914D\u7F6E","roles.unconfigured":"\u672A\u914D\u7F6E","roles.noChats":"\u6682\u65E0\u7FA4\u7EC4","roles.preview":"\u9884\u89C8","roles.previewEmpty":"\uFF08\u7A7A\u5185\u5BB9\uFF09","roles.saved":"\u5DF2\u4FDD\u5B58","roles.delete":"\u5220\u9664","roles.save":"\u4FDD\u5B58","roles.confirmDelete":"\u786E\u8BA4\u5220\u9664\u8BE5 Bot \u5728\u6B64\u7FA4\u7684\u89D2\u8272\u914D\u7F6E\uFF1F","roles.botsWithRoles":"\u4E2A Bot \u5DF2\u914D\u7F6E\u89D2\u8272","roles.emptyError":"\u89D2\u8272\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u8BF7\u5148\u8F93\u5165\u5185\u5BB9","roles.saveFailed":"\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5","common.none":"\u65E0","common.loading":"\u52A0\u8F7D\u4E2D\u2026","common.unknown":"\u672A\u77E5","common.now":"\u521A\u521A","common.never":"\u4ECE\u672A","common.all":"\u5168\u90E8","nav.workflows":"\u5DE5\u4F5C\u6D41(beta)","nav.workflowCatalog":"\u76EE\u5F55","workflow.subnav.runs":"\u8FD0\u884C","workflow.subnav.catalog":"\u76EE\u5F55","workflow.searchPlaceholder":"\u641C\u7D22 runId / workflowId / chatId","workflow.filter.nonTerminal":"\u975E\u7EC8\u6001","workflow.filter.all":"\u5168\u90E8","workflow.status.pending":"\u5F85\u5F00\u59CB","workflow.status.running":"\u8FD0\u884C\u4E2D","workflow.status.waiting":"\u7B49\u5F85\u4E2D","workflow.status.effectAttempting":"\u526F\u4F5C\u7528\u4E2D","workflow.status.timedOut":"\u5DF2\u8D85\u65F6","workflow.status.succeeded":"\u6210\u529F","workflow.status.failed":"\u5931\u8D25","workflow.status.cancelled":"\u5DF2\u53D6\u6D88","workflow.table.run":"\u8FD0\u884C","workflow.table.workflow":"\u5DE5\u4F5C\u6D41","workflow.table.status":"\u72B6\u6001","workflow.table.lastSeq":"\u6700\u540E\u5E8F\u53F7","workflow.table.dangling":"\u60AC\u6302 dEf/dAct/dWait","workflow.table.updated":"\u66F4\u65B0\u65F6\u95F4","workflow.table.chatApp":"\u7FA4\u804A / \u5E94\u7528","workflow.list.failedLoad":"\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","workflow.list.noRuns":"\u6CA1\u6709\u5339\u914D\u7684\u8FD0\u884C\u3002","workflow.list.noFilterMatch":"\u6CA1\u6709\u7B26\u5408\u7B5B\u9009\u6761\u4EF6\u7684\u8FD0\u884C\u3002","workflow.list.loaded":"{count} \u4E2A\u8FD0\u884C \xB7 \u5237\u65B0\u4E8E {time}","workflow.list.error":"\u9519\u8BEF\uFF1A{error}","workflow.detail.back":"\u8FD4\u56DE","workflow.detail.loading":"\u52A0\u8F7D\u4E2D...","workflow.detail.loadFailed":"\u52A0\u8F7D\u5931\u8D25","workflow.detail.cancel":"\u53D6\u6D88","workflow.detail.cliCancelOnly":"\u4EC5 CLI \u53EF\u53D6\u6D88","workflow.detail.cancelTitle":"\u53D6\u6D88\u8FD9\u4E2A\u5DE5\u4F5C\u6D41\u8FD0\u884C","workflow.detail.cliCancelTitle":"\u65E0\u6CD5\u5728\u9875\u9762\u53D6\u6D88\uFF1A\u8BF7\u4F7F\u7528 botmux workflow cancel {runId}","workflow.detail.nodes":"\u8282\u70B9 / Activity","workflow.detail.parallel":"\u5E76\u53D1\u6267\u884C","workflow.detail.parallelMeta":"{count} \u6B21\u5C1D\u8BD5 \xB7 \u6700\u9AD8\u5E76\u53D1 {max} \xB7 \u8FD0\u884C\u4E2D {running}","workflow.detail.noParallelData":"\u8FD8\u6CA1\u6709 attempt \u65F6\u95F4\u6570\u636E\u3002","workflow.detail.parallelNow":"\u73B0\u5728","workflow.detail.node":"\u8282\u70B9","workflow.detail.nodeStatus":"\u8282\u70B9\u72B6\u6001","workflow.detail.activity":"Activity","workflow.detail.activityStatus":"Activity \u72B6\u6001","workflow.detail.attempts":"\u5C1D\u8BD5\u6B21\u6570","workflow.detail.current":"\u5F53\u524D\u5C1D\u8BD5","workflow.detail.detail":"\u8BE6\u60C5","workflow.detail.nodeIO":"\u8282\u70B9\u8F93\u5165\u8F93\u51FA","workflow.detail.timeline":"\u65F6\u95F4\u7EBF","workflow.detail.loadOlder":"\u52A0\u8F7D\u66F4\u65E9\u4E8B\u4EF6","workflow.detail.seq":"\u5E8F\u53F7","workflow.detail.actor":"\u6267\u884C\u8005","workflow.detail.error":"\u9519\u8BEF","workflow.detail.event":"\u4E8B\u4EF6","workflow.detail.time":"\u65F6\u95F4","workflow.detail.refreshed":"\u5237\u65B0\u4E8E {time}","workflow.detail.unknownRun":"\u672A\u77E5\u8FD0\u884C","workflow.detail.snapshotHttp":"snapshot HTTP {status}","workflow.detail.eventsHttp":"events HTTP {status}","workflow.detail.cancelUnavailable":"\u65E0\u6CD5\u53D6\u6D88\uFF1A\u8BF7\u4F7F\u7528 botmux workflow cancel {runId}","workflow.detail.cancelConfirm":`\u786E\u8BA4\u53D6\u6D88\u5DE5\u4F5C\u6D41\u8FD0\u884C {runId}\uFF1F
|
|
6
6
|
|
|
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
|
-
.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","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.:
|
|
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.:
|
|
14
14
|
You are a code reviewer for this group...`,"roles.configured":"Configured","roles.unconfigured":"None","roles.noChats":"No groups","roles.preview":"Preview","roles.previewEmpty":"(empty)","roles.saved":"Saved","roles.delete":"Delete","roles.save":"Save","roles.confirmDelete":"Delete this bot's role config for this group?","roles.botsWithRoles":"bots configured","roles.emptyError":"Role content cannot be empty","roles.saveFailed":"Save failed, please retry","common.none":"None","common.loading":"Loading\u2026","common.unknown":"Unknown","common.now":"now","common.never":"never","common.all":"All","nav.workflows":"Workflows (beta)","nav.workflowCatalog":"Catalog","workflow.subnav.runs":"Runs","workflow.subnav.catalog":"Catalog","workflow.searchPlaceholder":"search runId / workflowId / chatId","workflow.filter.nonTerminal":"non-terminal","workflow.filter.all":"all","workflow.status.pending":"pending","workflow.status.running":"running","workflow.status.waiting":"waiting","workflow.status.effectAttempting":"effect","workflow.status.timedOut":"timed out","workflow.status.succeeded":"succeeded","workflow.status.failed":"failed","workflow.status.cancelled":"cancelled","workflow.table.run":"run","workflow.table.workflow":"workflow","workflow.table.status":"status","workflow.table.lastSeq":"lastSeq","workflow.table.dangling":"dEf/dAct/dWait","workflow.table.updated":"updated","workflow.table.chatApp":"chat / app","workflow.list.failedLoad":"Failed to load: {error}","workflow.list.noRuns":"No runs match.","workflow.list.noFilterMatch":"No runs match this filter.","workflow.list.loaded":"{count} runs \xB7 refreshed {time}","workflow.list.error":"error: {error}","workflow.detail.back":"Back","workflow.detail.loading":"Loading...","workflow.detail.loadFailed":"Load failed","workflow.detail.cancel":"Cancel","workflow.detail.cliCancelOnly":"CLI cancel only","workflow.detail.cancelTitle":"Cancel this workflow run","workflow.detail.cliCancelTitle":"Cancel unavailable: use botmux workflow cancel {runId}","workflow.detail.nodes":"Nodes / Activities","workflow.detail.parallel":"Parallel execution","workflow.detail.parallelMeta":"{count} attempt(s) \xB7 max parallel {max} \xB7 running {running}","workflow.detail.noParallelData":"No attempt timing data yet.","workflow.detail.parallelNow":"now","workflow.detail.node":"node","workflow.detail.nodeStatus":"node status","workflow.detail.activity":"activity","workflow.detail.activityStatus":"activity status","workflow.detail.attempts":"attempts","workflow.detail.current":"current","workflow.detail.detail":"detail","workflow.detail.nodeIO":"Node I/O","workflow.detail.timeline":"Timeline","workflow.detail.loadOlder":"Load older","workflow.detail.seq":"seq","workflow.detail.actor":"actor","workflow.detail.error":"error","workflow.detail.event":"event","workflow.detail.time":"time","workflow.detail.refreshed":"refreshed {time}","workflow.detail.unknownRun":"unknown run","workflow.detail.snapshotHttp":"snapshot HTTP {status}","workflow.detail.eventsHttp":"events HTTP {status}","workflow.detail.cancelUnavailable":"cancel unavailable: use botmux workflow cancel {runId}","workflow.detail.cancelConfirm":`Cancel workflow run {runId}?
|
|
15
15
|
|
|
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:ys,en:vs};function en(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=en(n);if(a)return a}return"zh"}function tn(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?en(e.getItem(An)):null)??ks(n)}var Dn="botmux.dashboard.theme",Ia="botmux.dashboard.sessions.view";function $s(e){return e==="system"||e==="light"||e==="dark"?e:null}function Rn(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(Dn))??"dark"}function xa(e){return Rn(e?.getItem(Ia))??"board"}var Ha="botmux.dashboard.sessions.boardOrder",Bt=["needs-you","starting","working","idle"];function Ss(e){if(!Array.isArray(e)||e.length!==Bt.length)return null;let n=new Set(e);if(n.size!==e.length)return null;for(let a of Bt)if(!n.has(a))return null;return e.slice()}function Ca(e){try{let n=e?.getItem(Ha);return n?Ss(JSON.parse(n))??[...Bt]:[...Bt]}catch{return[...Bt]}}function Pn(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",Bn="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"],On="botmux.dashboard.skin";function Ms(e){return typeof e=="string"&&Is.includes(e)?e:null}function qa(e){return Ms(e?.getItem(On))??"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%"],qn=[{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,Ot=[],It=0,nn=0;function Fn(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function jn(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=jn(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(Fn())return;let e=document.body,n=()=>{let a=qn[Math.floor(Math.random()*qn.length)],s=`cp-fx-${a.key}`;e.classList.add(s),Ot.push(window.setTimeout(()=>e.classList.remove(s),a.dur)),Ot.push(window.setTimeout(n,2400+Math.random()*4200))};Ot.push(window.setTimeout(n,1800+Math.random()*2600))}function As(){Ot.forEach(e=>window.clearTimeout(e)),Ot=[];for(let e of qn)document.body.classList.remove(`cp-fx-${e.key}`)}function Ds(){if(Fn()||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;It=window.setInterval(()=>{let d=Ua[s];n&&(o<d.length?(o+=1,n.textContent=d.slice(0,o)+jn(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=jn(26,Fa))},50),nn=window.setTimeout(()=>{window.clearInterval(It),It=0,e.remove()},xs)}function Rs(){It&&(window.clearInterval(It),It=0),nn&&(window.clearTimeout(nn),nn=0),document.getElementById("cyber-boot")?.remove()}var Ps=320,Ga=16,Nt=!0,Tt=0,Nn=0,an=!1,on=[],Un=[];function Bs(){if(an)return;an=!0,Nt=!1,Tt=0;let e=Fn(),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"),on.push(window.setTimeout(()=>document.body.classList.remove("cyber-breach-quake"),760)),on.push(window.setTimeout(()=>{a.remove(),an=!1},e?2600:4200))}function Os(){Nt=!0,Tt=0;let e=document.documentElement,n=()=>e.scrollHeight-(window.innerHeight+window.scrollY)<=4,a=k=>{k<=0||!n()||(Tt+=k,Tt>Ps&&Nt&&Bs())},s=k=>a(k.deltaY),o=k=>{Nn=k.touches[0]?.clientY??0},r=k=>{let $=k.touches[0]?.clientY??0,E=Nn-$;Nn=$,a(E)},d=()=>{n()||(Tt=0,Nt=!0)},p=(k,$)=>{window.addEventListener(k,$,{passive:!0}),Un.push([k,$])};p("wheel",s),p("touchstart",o),p("touchmove",r),p("scroll",d)}function Ns(){for(let[e,n]of Un)window.removeEventListener(e,n);Un=[],on.forEach(e=>window.clearTimeout(e)),on=[],document.body.classList.remove("cyber-breach-quake"),document.getElementById("cyber-breach")?.remove(),an=!1,Nt=!0,Tt=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 Wa(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 _n=class{locale="zh";themeMode="system";resolvedTheme="light";skin="default";authed=!0;listeners=new Set;translate=tn(this.locale);mediaQuery=null;init(){let n=typeof window<"u"?window:void 0;this.locale=Ta(n?.localStorage,_s()),this.translate=tn(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=tn(n),window.localStorage.setItem(An,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(Dn,this.themeMode)),o&&(this.skin=s,window.localStorage.setItem(On,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"&&Wa(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 _n;function t(e,n){return Te.t(e,n)}function i(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function je(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 za=[{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}=za[n%za.length];return`--c1:${s};--c2:${o}`}var sn=new Map,rn=new Map;function Ws(e,n){return n?sn.get(n):e?rn.get(String(e)):void 0}function me(e){let n=e.name??"",a=e.avatarUrl??Ws(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 zs(e){return e?cn.get(e):void 0}function ln(e){let n=e.name??e.chatId??"",a=e.avatarUrl??zs(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 qt=new Map,dn=new Map,cn=new Map,Gn=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??{}))sn.set(a,s);for(let[a,s]of Object.entries(n.botByName??{}))rn.set(a,s);for(let[a,s]of Object.entries(n.chatById??{}))cn.set(a,s);for(let[a,s]of Object.entries(n.nameByAppId??{}))qt.set(a,s);for(let[a,s]of Object.entries(n.chatNameById??{}))dn.set(a,s)}catch{}}function Js(){try{if(typeof window>"u")return;window.localStorage.setItem(Ja,JSON.stringify({botByAppId:Object.fromEntries(sn),botByName:Object.fromEntries(rn),chatById:Object.fromEntries(cn),nameByAppId:Object.fromEntries(qt),chatNameById:Object.fromEntries(dn)}))}catch{}}Ks();function Je(){return Gn??=(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&&qt.set(a.larkAppId,String(a.botName)),a.botAvatarUrl&&(a.larkAppId&&sn.set(a.larkAppId,String(a.botAvatarUrl)),a.botName&&rn.set(String(a.botName),String(a.botAvatarUrl)));for(let a of n.chats??[])a.chatId&&a.name&&dn.set(a.chatId,String(a.name)),a.chatId&&a.avatar&&cn.set(a.chatId,String(a.avatar));Js()}catch{Gn=null}})(),Gn}function Va(e){return e?qt.get(e):void 0}function ve(e){let n=e.larkAppId?qt.get(e.larkAppId):void 0;return n||(e.botName&&e.botName!==e.larkAppId?String(e.botName):String(e.botName??e.larkAppId??"-"))}function rt(e){return e.chatId&&dn.get(e.chatId)||null}function ke(e){let n=String(e??"");return n.replace(/^(?:@\S+\s*)+/,"").trim()||n}function lt(e){return`<div class="page-loading" role="status"><i class="page-loading-spin" aria-hidden="true"></i>${i(e??t("common.loading"))}</div>`}function dt(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 He(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 Wn=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),Wn.has(o.status)&&d.busy.push(o),dt(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=p=>p.attention.length?0:p.busy.length?1:p.online||p.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 p=[...e.attention].sort((k,$)=>He(k)-He($))[0];r=`<b>${i((ke(p.title)||p.sessionId).slice(0,60))}</b> \xB7 ${i(dt(p)??"")}`}else if(s){let p=[...e.busy].sort((k,$)=>Number($.lastMessageAt??0)-Number(k.lastMessageAt??0))[0];r=`<b>${i((ke(p.title)||p.sessionId).slice(0,60))}</b>`}else n?r=i(t("overview.botOffline")):r=i(t("overview.botIdle"));let 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
|
-
${
|
|
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>
|
|
@@ -27,33 +27,33 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
27
27
|
<div class="mate-task">${r}</div>
|
|
28
28
|
<div class="mate-foot">
|
|
29
29
|
${d}
|
|
30
|
-
<span>${e.lastActiveAt?i(t("overview.lastActive",{time:
|
|
30
|
+
<span>${e.lastActiveAt?i(t("overview.lastActive",{time:qe(e.lastActiveAt)})):i(t("common.never"))}</span>
|
|
31
31
|
</div>
|
|
32
|
-
</article>`}function
|
|
33
|
-
${
|
|
32
|
+
</article>`}function oi(e){let n=ke(e);return`<article class="qcard" data-id="${i(e.sessionId)}">
|
|
33
|
+
${ue({name:n,larkAppId:e.larkAppId,size:"sm"})}
|
|
34
34
|
<div class="qcard-tx">
|
|
35
|
-
<b>${i(n)} \xB7 ${i((
|
|
36
|
-
<span>${i(
|
|
35
|
+
<b>${i(n)} \xB7 ${i(($e(e.title)||e.sessionId).slice(0,56))}</b>
|
|
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
|
-
</article>`}function ai(e){let n=
|
|
40
|
-
${
|
|
39
|
+
</article>`}function ai(e){let n=ke(e);return`<li class="sess-row">
|
|
40
|
+
${ue({name:n,larkAppId:e.larkAppId,size:"sm"})}
|
|
41
41
|
<div class="sess-tx">
|
|
42
|
-
<b>${i((
|
|
43
|
-
<span>${i(n)} \xB7 ${i(
|
|
42
|
+
<b>${i(($e(e.title)||e.sessionId).slice(0,64))}</b>
|
|
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
|
-
<span>${i(
|
|
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"),
|
|
112
|
-
<span class="pill">${i(t("overview.workingSessions"))} <b>${
|
|
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
|
+
<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>${
|
|
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
|
-
<span><i style="background:var(--accent)"></i>${i(t("overview.workingSessions"))} ${
|
|
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
|
-
<span><i style="background:var(--success)"></i>${i(t("sessions.board.idle"))} ${Math.max(0,
|
|
119
|
-
</div>`;let
|
|
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(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>
|
|
@@ -171,16 +171,16 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
171
171
|
<table id="sessions-table">
|
|
172
172
|
<thead><tr>
|
|
173
173
|
<th><input type="checkbox" id="select-all" title="${t("sessions.activeOnly")}"></th>
|
|
174
|
-
${
|
|
175
|
-
${
|
|
176
|
-
${
|
|
177
|
-
${
|
|
178
|
-
${
|
|
179
|
-
${
|
|
180
|
-
${
|
|
181
|
-
${
|
|
182
|
-
${
|
|
183
|
-
${
|
|
174
|
+
${Je("botName",t("sessions.bot"))}
|
|
175
|
+
${Je("cliId",t("sessions.cli"))}
|
|
176
|
+
${Je("status",t("sessions.status"))}
|
|
177
|
+
${Je("tokenIn",t("sessions.tokenIn"))}
|
|
178
|
+
${Je("tokenOut",t("sessions.tokenOut"))}
|
|
179
|
+
${Je("title",t("sessions.titleCol"))}
|
|
180
|
+
${Je("workingDir",t("sessions.workingDir"))}
|
|
181
|
+
${Je("spawnedAt",t("sessions.created"))}
|
|
182
|
+
${Je("lastMessageAt",t("sessions.last"))}
|
|
183
|
+
${Je("adopt",t("sessions.adopt"))}
|
|
184
184
|
<th>${t("sessions.actions")}</th>
|
|
185
185
|
</tr></thead>
|
|
186
186
|
<tbody></tbody>
|
|
@@ -190,43 +190,43 @@ 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
|
-
<td>${i(
|
|
196
|
-
<td><span class="badge cli-${
|
|
195
|
+
<td>${i(ke(l))}</td>
|
|
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">${
|
|
200
|
-
<td title="${i(String(l.title??""))}">${i(
|
|
198
|
+
<td class="token-cell">${sa(l.tokenUsage?.in)}</td>
|
|
199
|
+
<td class="token-cell">${sa(l.tokenUsage?.out)}</td>
|
|
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
|
-
<td>${
|
|
203
|
-
<td>${
|
|
202
|
+
<td>${qe(l.spawnedAt)}</td>
|
|
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">
|
|
210
210
|
<strong title="${i(String(l.title??g))}">${i(String(g).slice(0,72))}</strong>
|
|
211
|
-
<span>${i(
|
|
211
|
+
<span>${i(f)} \xB7 ${i(b??l.cliId??"unknown")}</span>
|
|
212
212
|
</div>
|
|
213
213
|
<span class="status status-${i(l.status??"unknown")}">${i(l.status??"unknown")}</span>
|
|
214
214
|
</div>
|
|
215
|
-
${
|
|
216
|
-
${
|
|
215
|
+
${D!=="-"||l.adopt?`<div class="session-card-meta">
|
|
216
|
+
${D!=="-"?`<span title="${i(l.workingDir??"")}">${i(D)}</span>`:""}
|
|
217
217
|
${l.adopt?'<span class="badge">adopt</span>':""}
|
|
218
218
|
</div>`:""}
|
|
219
219
|
<div class="session-card-time">
|
|
220
|
-
<span>${l.agentAttention?.at?`${i(t("sessions.board.waiting"))} ${
|
|
220
|
+
<span>${l.agentAttention?.at?`${i(t("sessions.board.waiting"))} ${qe(Ce(l))}`:`${i(t("sessions.last"))}: ${qe(l.lastMessageAt)}`}</span>
|
|
221
221
|
</div>
|
|
222
|
-
${
|
|
222
|
+
${I?`<div class="session-signal" title="${i(I)}">${i(I)}</div>`:""}
|
|
223
223
|
<div class="session-card-actions">
|
|
224
|
-
${
|
|
225
|
-
${
|
|
226
|
-
${
|
|
227
|
-
${
|
|
224
|
+
${rt(l)??Qn("locate",Ae.pin,t("sessions.locate"))}
|
|
225
|
+
${Qn("details",Ae.details,t("sessions.details"))}
|
|
226
|
+
${ca(v)}
|
|
227
|
+
${Qn("close",Ae.close,t("sessions.close"),"danger")}
|
|
228
228
|
</div>
|
|
229
|
-
</article>`}function
|
|
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>
|
|
@@ -235,118 +235,118 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
235
235
|
<span class="session-board-head-right">
|
|
236
236
|
<span class="session-board-move">
|
|
237
237
|
<button type="button" data-move-col="${b.id}" data-dir="-1"
|
|
238
|
-
aria-label="${i(t("sessions.board.moveLeft"))}" ${
|
|
238
|
+
aria-label="${i(t("sessions.board.moveLeft"))}" ${v===0?"disabled":""}>\u2039</button>
|
|
239
239
|
<button type="button" data-move-col="${b.id}" data-dir="1"
|
|
240
|
-
aria-label="${i(t("sessions.board.moveRight"))}" ${
|
|
240
|
+
aria-label="${i(t("sessions.board.moveRight"))}" ${v===g.length-1?"disabled":""}>\u203A</button>
|
|
241
241
|
</span>
|
|
242
|
-
<span class="session-board-count">${
|
|
242
|
+
<span class="session-board-count">${I.length}</span>
|
|
243
243
|
</span>
|
|
244
244
|
</header>
|
|
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("");
|
|
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">
|
|
254
|
-
<span class="kanban-card-dot" data-status="${i(
|
|
255
|
-
${
|
|
256
|
-
${l.feishuChatLink?`<a class="card-act kanban-card-act" href="${i(l.feishuChatLink)}" target="_blank" rel="noopener" title="${i(t("sessions.kanban.openFeishu"))}" aria-label="${i(t("sessions.kanban.openFeishu"))}">${
|
|
257
|
-
<button type="button" class="card-act kanban-card-act" data-action="details" title="${i(t("sessions.details"))}" aria-label="${i(t("sessions.details"))}">${
|
|
254
|
+
<span class="kanban-card-dot" data-status="${i(D)}" title="${i(D)}"></span>
|
|
255
|
+
${W?"":`<button type="button" class="card-act kanban-card-act" data-action="history" title="${i(t("sessions.history.title"))}" aria-label="${i(t("sessions.history.title"))}">${Ae.history}</button>
|
|
256
|
+
${l.feishuChatLink?`<a class="card-act kanban-card-act" href="${i(l.feishuChatLink)}" target="_blank" rel="noopener" title="${i(t("sessions.kanban.openFeishu"))}" aria-label="${i(t("sessions.kanban.openFeishu"))}">${Ae.feishu}</a>`:""}
|
|
257
|
+
<button type="button" class="card-act kanban-card-act" data-action="details" title="${i(t("sessions.details"))}" aria-label="${i(t("sessions.details"))}">${Ae.details}</button>`}
|
|
258
258
|
</span>
|
|
259
259
|
</div>
|
|
260
260
|
<p class="kanban-card-title" title="${i(String(l.title??c))}">${i(String(c).slice(0,140))}</p>
|
|
261
|
-
${
|
|
262
|
-
${
|
|
261
|
+
${I?`<p class="kanban-card-desc" title="${i(I)}">${i(I)}</p>`:""}
|
|
262
|
+
${v?`<div class="session-signal" title="${i(v)}">${i(v)}</div>`:""}
|
|
263
263
|
<div class="kanban-card-foot">
|
|
264
|
-
<span class="kanban-card-owner">${
|
|
265
|
-
<span class="kanban-card-updated">${i(t("sessions.kanban.updated",{time:
|
|
264
|
+
<span class="kanban-card-owner">${ue({name:g,larkAppId:l.larkAppId,size:"sm"})}<span>${i(g)}</span></span>
|
|
265
|
+
<span class="kanban-card-updated">${i(t("sessions.kanban.updated",{time:qe(l.lastMessageAt)}))}</span>
|
|
266
266
|
</div>
|
|
267
|
-
</article>`}function
|
|
268
|
-
<header draggable="true" title="${i(
|
|
269
|
-
${
|
|
270
|
-
<span class="kanban-cluster-name">${i(
|
|
271
|
-
<span class="kanban-cluster-count">${
|
|
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
|
+
<header draggable="true" title="${i(I)} \xB7 ${i(t("sessions.kanban.clusterDragHint"))}">
|
|
269
|
+
${cn({chatId:v.chatId,name:I,size:"sm"})}
|
|
270
|
+
<span class="kanban-cluster-name">${i(I)}</span>
|
|
271
|
+
<span class="kanban-cluster-count">${v.rows.length}</span>
|
|
272
272
|
</header>
|
|
273
|
-
${
|
|
274
|
-
</div>`}).join(""),flat:
|
|
273
|
+
${v.rows.map(K).join("")}
|
|
274
|
+
</div>`}).join(""),flat:f}}function Ge(l){let c=new Map;for(let f of l){if(f.status==="closed")continue;let b=String(f.larkAppId||f.botName||"unknown"),v=c.get(b);v||(v={name:ke(f),larkAppId:f.larkAppId,rows:[]},c.set(b,v)),v.rows.push(f)}let g=[...c.values()].sort((f,b)=>f.name.localeCompare(b.name));return g.length?g.map(f=>{let b=f.rows.sort((I,D)=>Number(D.lastMessageAt??0)-Number(I.lastMessageAt??0)),{html:v}=ge(b);return`<section class="kanban-column kanban-bot-col" data-bot="${i(f.larkAppId??f.name)}">
|
|
275
275
|
<header>
|
|
276
|
-
<span class="kanban-col-avatar">${
|
|
277
|
-
<h2>${i(
|
|
276
|
+
<span class="kanban-col-avatar">${ue({name:f.name,larkAppId:f.larkAppId,size:"sm"})}</span>
|
|
277
|
+
<h2>${i(f.name)}</h2>
|
|
278
278
|
<span class="kanban-col-count">${b.length}</span>
|
|
279
279
|
</header>
|
|
280
|
-
<div class="kanban-col-list">${
|
|
281
|
-
</section>`}).join(""):`<div class="kanban-col-empty">${t("sessions.board.emptyColumn")}</div>`}function
|
|
280
|
+
<div class="kanban-col-list">${v}</div>
|
|
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">${
|
|
284
|
-
<h2>${i(t(
|
|
285
|
-
<span class="kanban-col-count">${b.length+
|
|
283
|
+
<span class="kanban-col-icon">${li(f.id)}</span>
|
|
284
|
+
<h2>${i(t(f.labelKey))}</h2>
|
|
285
|
+
<span class="kanban-col-count">${b.length+v}</span>
|
|
286
286
|
</header>
|
|
287
287
|
<div class="kanban-col-list">
|
|
288
|
-
${b.length?
|
|
289
|
-
${
|
|
288
|
+
${b.length?I:`<div class="kanban-col-empty">${t("sessions.board.emptyColumn")}</div>`}
|
|
289
|
+
${v?`<div class="kanban-col-more">${i(t("sessions.kanban.moreHidden",{count:v}))}</div>`:""}
|
|
290
290
|
</div>
|
|
291
|
-
</section>`}).join("");return
|
|
292
|
-
${
|
|
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
|
+
${D}
|
|
293
293
|
<div class="history-msg-main">
|
|
294
|
-
<div class="history-msg-meta"><span>${i(b)}</span><time>${i(
|
|
295
|
-
<div class="history-bubble">${i(
|
|
294
|
+
<div class="history-msg-meta"><span>${i(b)}</span><time>${i(v)}</time></div>
|
|
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
|
-
${
|
|
300
|
-
<strong title="${i(String(l.title??""))}">${i((
|
|
299
|
+
${ue({name:c,larkAppId:l.larkAppId,size:"sm"})}
|
|
300
|
+
<strong title="${i(String(l.title??""))}">${i(($e(l.title)||l.sessionId).slice(0,60))}</strong>
|
|
301
301
|
<span class="history-scope-tag">${i(t("sessions.history.title"))}</span>
|
|
302
302
|
</span>
|
|
303
303
|
<span class="term-modal-actions">
|
|
304
|
-
<button type="button" id="history-close" class="card-act" title="${i(t("sessions.dismiss"))}" aria-label="${i(t("sessions.dismiss"))}">${
|
|
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`),
|
|
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>
|
|
311
|
-
<button type="button" id="term-modal-edit" class="card-act" title="${i(t("sessions.kanban.rename"))}" aria-label="${i(t("sessions.kanban.rename"))}">${
|
|
311
|
+
<button type="button" id="term-modal-edit" class="card-act" title="${i(t("sessions.kanban.rename"))}" aria-label="${i(t("sessions.kanban.rename"))}">${Ae.edit}</button>
|
|
312
312
|
<span class="status status-${i(l.status??"unknown")}">${i(l.status??"unknown")}</span>
|
|
313
313
|
</span>
|
|
314
314
|
<span class="term-modal-actions">
|
|
315
|
-
${
|
|
316
|
-
<a id="term-modal-tab" class="card-act" href="${i(c)}" target="_blank" rel="noopener" title="${i(t("sessions.kanban.openTab"))}" aria-label="${i(t("sessions.kanban.openTab"))}">${
|
|
317
|
-
<button type="button" id="term-modal-close" class="card-act" title="${i(t("sessions.dismiss"))}" aria-label="${i(t("sessions.dismiss"))}">${
|
|
315
|
+
${f}
|
|
316
|
+
<a id="term-modal-tab" class="card-act" href="${i(c)}" target="_blank" rel="noopener" title="${i(t("sessions.kanban.openTab"))}" aria-label="${i(t("sessions.kanban.openTab"))}">${Ae.terminal}</a>
|
|
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>`,
|
|
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
|
-
<h3>${i(
|
|
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
|
-
<p><b>${t("sessions.bot")}:</b> ${i(
|
|
327
|
-
${
|
|
326
|
+
<p><b>${t("sessions.bot")}:</b> ${i(ke(l))} \xB7 <b>${t("sessions.cli")}:</b> ${i(l.cliId??"?")}</p>
|
|
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>`,
|
|
343
|
-
\u2026(truncated)`:"");
|
|
344
|
-
<p><b>${
|
|
345
|
-
<pre style="max-height:320px;overflow:auto;white-space:pre-wrap">${i(
|
|
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
|
+
\u2026(truncated)`:"");N.innerHTML=`
|
|
344
|
+
<p><b>${we.files}</b> files (+${we.insertions}/-${we.deletions}) \u2192 <code>${i(String(we.workingDir??""))}</code></p>
|
|
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
|
|
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
|
|
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,75 +428,75 @@ 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
|
|
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
|
-
<p><b>chatId:</b> <code>${i(
|
|
442
|
-
<p><b>\u521B\u5EFA\u8005:</b> <code>${i(
|
|
443
|
-
${
|
|
444
|
-
${
|
|
445
|
-
${
|
|
441
|
+
<p><b>chatId:</b> <code>${i(C)}</code> <button type="button" data-copy="${i(C)}">${t("sessions.copy")}</button></p>
|
|
442
|
+
<p><b>\u521B\u5EFA\u8005:</b> <code>${i(E.creator??"?")}</code></p>
|
|
443
|
+
${le}
|
|
444
|
+
${re}
|
|
445
|
+
${te?`<ul>${te}</ul>`:""}
|
|
446
446
|
<div class="actions">
|
|
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(
|
|
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
|
|
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"})}
|
|
458
458
|
<div class="g-chat-meta">
|
|
459
459
|
<strong>${i(T.name??T.chatId)}</strong><br>
|
|
460
460
|
<small><code>${i(T.chatId)}</code></small>
|
|
461
461
|
</div>
|
|
462
462
|
</div>
|
|
463
463
|
</td>
|
|
464
|
-
${
|
|
464
|
+
${De.bots.map(R=>{let q=T.memberBots.find(A=>A.larkAppId===R.larkAppId),u=q?q.error?"!":q.inChat?"\u2713":"\u2717":"?";return`<td class="${q?q.error?"cell-error":q.inChat?"cell-in":"cell-out":"cell-unknown"}" title="${i(q?.error??"")}">${u}</td>`}).join("")}
|
|
465
465
|
<td>
|
|
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("")}
|
|
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
|
|
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
|
-
<header><h3>${t("groups.manageTitle",{name:
|
|
484
|
-
<p><b>chatId:</b> <code>${i(
|
|
485
|
-
<p><b>${t("groups.owner")}:</b> <code>${i(
|
|
483
|
+
<header><h3>${t("groups.manageTitle",{name:E.name??E.chatId})}</h3></header>
|
|
484
|
+
<p><b>chatId:</b> <code>${i(E.chatId)}</code></p>
|
|
485
|
+
<p><b>${t("groups.owner")}:</b> <code>${i(E.ownerId??t("common.unknown"))}</code></p>
|
|
486
486
|
|
|
487
487
|
<fieldset>
|
|
488
488
|
<legend>${t("groups.oncall")}</legend>
|
|
489
489
|
<p><small>${t("groups.oncallHelp")}</small></p>
|
|
490
|
-
${
|
|
491
|
-
<div class="oncall-row" data-bot="${i(
|
|
490
|
+
${C.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':C.map(x=>{let T=!!x.oncallChat,R=x.oncallChat?.workingDir??"";return`
|
|
491
|
+
<div class="oncall-row" data-bot="${i(x.larkAppId)}">
|
|
492
492
|
<label class="checkbox-row">
|
|
493
493
|
<input type="checkbox" data-action="toggle" ${T?"checked":""}>
|
|
494
|
-
<strong>${i(
|
|
495
|
-
<small>(${i(
|
|
494
|
+
<strong>${i(x.botName??x.larkAppId)}</strong>
|
|
495
|
+
<small>(${i(x.larkAppId)})</small>
|
|
496
496
|
</label>
|
|
497
497
|
<div class="oncall-row-body">
|
|
498
498
|
<input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
|
|
499
|
-
value="${i(
|
|
499
|
+
value="${i(R)}" ${T?"":"disabled"}>
|
|
500
500
|
<button type="button" data-action="save">${t("groups.save")}</button>
|
|
501
501
|
<span class="oncall-status" data-status></span>
|
|
502
502
|
</div>
|
|
@@ -506,29 +506,29 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
506
506
|
|
|
507
507
|
<fieldset>
|
|
508
508
|
<legend>${t("groups.leaveTitle")}</legend>
|
|
509
|
-
${
|
|
509
|
+
${C.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':C.map(x=>`
|
|
510
510
|
<label class="checkbox-row">
|
|
511
|
-
<input type="checkbox" name="leave-bot" value="${i(
|
|
512
|
-
${i(
|
|
513
|
-
<small>${
|
|
511
|
+
<input type="checkbox" name="leave-bot" value="${i(x.larkAppId)}">
|
|
512
|
+
${i(x.botName??x.larkAppId)}
|
|
513
|
+
<small>${x.larkAppId===L?"\xB7 \u7FA4\u4E3B":""}</small>
|
|
514
514
|
</label>
|
|
515
515
|
`).join("")}
|
|
516
516
|
</fieldset>
|
|
517
517
|
|
|
518
518
|
<div class="actions">
|
|
519
|
-
<button id="g-leave-btn" type="button" ${
|
|
520
|
-
<button id="g-disband-btn" type="button" class="contrast" ${
|
|
519
|
+
<button id="g-leave-btn" type="button" ${C.length===0?"disabled":""}>${t("groups.leaveSelected")}</button>
|
|
520
|
+
<button id="g-disband-btn" type="button" class="contrast" ${C.length===0?"disabled":""}>${t("groups.disband")}</button>
|
|
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(
|
|
525
|
-
`);alert(
|
|
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,32 +544,32 @@ ${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
|
-
${
|
|
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(
|
|
551
|
-
<span>${i(
|
|
550
|
+
<b>${i(y)}</b>
|
|
551
|
+
<span>${i(A||u.larkAppId.slice(0,14))}</span>
|
|
552
552
|
</div>
|
|
553
|
-
${
|
|
554
|
-
</div>`}function
|
|
553
|
+
${O}
|
|
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
|
-
${
|
|
557
|
-
<div class="bd-profile-id"><strong>${i(
|
|
558
|
-
<code>${i(
|
|
556
|
+
${ue({name:u.botName??u.larkAppId,larkAppId:u.larkAppId})}
|
|
557
|
+
<div class="bd-profile-id"><strong>${i(u.botName??u.larkAppId)}</strong>
|
|
558
|
+
<code>${i(u.larkAppId)}</code></div>
|
|
559
559
|
</header>
|
|
560
|
-
<p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${i(
|
|
561
|
-
</article>`;let
|
|
560
|
+
<p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${i(u.error)}</p>
|
|
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
|
-
${
|
|
563
|
+
${ue({name:O,larkAppId:u.larkAppId,dot:"ok"})}
|
|
564
564
|
<div class="bd-profile-id">
|
|
565
|
-
<strong>${i(
|
|
566
|
-
${
|
|
567
|
-
<code>${i(
|
|
565
|
+
<strong>${i(O)}</strong>
|
|
566
|
+
${U?`<span class="mate-role">${i(U)}</span>`:""}
|
|
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(
|
|
572
|
-
<small>${t("botDefaults.autobound",{count:
|
|
571
|
+
<small data-oncall-since>${t("botDefaults.lastEnabled")}: ${i(ka(y.since??0))}</small>
|
|
572
|
+
<small>${t("botDefaults.autobound",{count:u.autoboundChatCount??0})}</small>
|
|
573
573
|
</div>
|
|
574
574
|
</header>
|
|
575
575
|
<div class="bd-body bd-grid">
|
|
@@ -577,7 +577,7 @@ ${T.join(`
|
|
|
577
577
|
<section class="bd-section">
|
|
578
578
|
<h3 class="bd-section-title">${t("botDefaults.sectionOncall")}</h3>
|
|
579
579
|
<label class="toggle-row">
|
|
580
|
-
<input type="checkbox" data-action="toggle" ${
|
|
580
|
+
<input type="checkbox" data-action="toggle" ${A?"checked":""}>
|
|
581
581
|
<span class="switch" aria-hidden="true"></span>
|
|
582
582
|
<span class="toggle-tx"><strong>${t("botDefaults.defaultOncall")}</strong>
|
|
583
583
|
<small>${t("botDefaults.defaultOncallHelp")}\u3002${t("botDefaults.warning")}</small></span>
|
|
@@ -586,43 +586,43 @@ ${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">
|
|
593
593
|
<button type="button" class="primary" data-action="save">${t("botDefaults.save")}</button>
|
|
594
594
|
<span class="oncall-status" data-status></span>
|
|
595
595
|
</div>
|
|
596
|
-
${
|
|
596
|
+
${R(u)}
|
|
597
597
|
</section>
|
|
598
|
-
${
|
|
598
|
+
${L(u)}
|
|
599
599
|
</section>
|
|
600
|
-
<section class="bd-tile">${k(
|
|
601
|
-
<section class="bd-tile">${u(
|
|
602
|
-
<section class="bd-tile">${w(
|
|
603
|
-
<section class="bd-tile">${
|
|
600
|
+
<section class="bd-tile">${k(u)}</section>
|
|
601
|
+
<section class="bd-tile">${p(u)}${E(u)}${C(u)}</section>
|
|
602
|
+
<section class="bd-tile">${w(u)}${M(u)}</section>
|
|
603
|
+
<section class="bd-tile">${T(u)}</section>
|
|
604
604
|
</div>
|
|
605
|
-
</article>`}function k(
|
|
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 $(
|
|
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 w(
|
|
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" ${
|
|
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 u
|
|
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>
|
|
@@ -687,9 +687,9 @@ ${T.join(`
|
|
|
687
687
|
<label>
|
|
688
688
|
<span>${t("botDefaults.mentionMode")}</span>
|
|
689
689
|
<select data-input="regularGroupMentionMode">
|
|
690
|
-
${
|
|
691
|
-
${
|
|
692
|
-
${
|
|
690
|
+
${Q("always",t("botDefaults.mentionModeAlways"))}
|
|
691
|
+
${Q("topic",t("botDefaults.mentionModeTopic"))}
|
|
692
|
+
${Q("never",t("botDefaults.mentionModeNever"))}
|
|
693
693
|
</select>
|
|
694
694
|
</label>
|
|
695
695
|
<small class="bd-help">${t("botDefaults.mentionModeHelp")}</small>
|
|
@@ -701,8 +701,8 @@ ${T.join(`
|
|
|
701
701
|
<label>
|
|
702
702
|
<span>${t("botDefaults.docSubscribeMode")}</span>
|
|
703
703
|
<select data-input="docSubscribeDefaultMode">
|
|
704
|
-
${
|
|
705
|
-
${
|
|
704
|
+
${re("mention-only",t("botDefaults.docSubscribeModeMention"))}
|
|
705
|
+
${re("all",t("botDefaults.docSubscribeModeAll"))}
|
|
706
706
|
</select>
|
|
707
707
|
</label>
|
|
708
708
|
<small class="bd-help">${t("botDefaults.docSubscribeModeHelp")}</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(
|
|
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,10 +727,20 @@ ${T.join(`
|
|
|
727
727
|
<span class="oncall-status" data-session-cap-status></span>
|
|
728
728
|
</div>
|
|
729
729
|
</div>
|
|
730
|
-
</div>`}function
|
|
730
|
+
</div>`}function C(u){let y=typeof u.startupCommands=="string"?u.startupCommands:"";return`<div class="bd-subsection">
|
|
731
|
+
<h4 class="bd-subsection-title">${t("botDefaults.sectionStartupCommands")}</h4>
|
|
732
|
+
<p class="bd-section-note">${t("botDefaults.startupCommandsHelp")}</p>
|
|
733
|
+
<textarea data-input="startupCommands" rows="3"
|
|
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(y)}</textarea>
|
|
736
|
+
<div class="actions">
|
|
737
|
+
<button type="button" class="primary" data-action="save-startup-commands">${t("botDefaults.startupCommandsSave")}</button>
|
|
738
|
+
<span class="oncall-status" data-startup-commands-status></span>
|
|
739
|
+
</div>
|
|
740
|
+
</div>`}function L(u){let y=u.sandbox===!0;return`<section class="bd-section">
|
|
731
741
|
<h3 class="bd-section-title">${t("botDefaults.sectionSandbox")}</h3>
|
|
732
742
|
<label class="toggle-row">
|
|
733
|
-
<input type="checkbox" data-action="toggle-sandbox" ${
|
|
743
|
+
<input type="checkbox" data-action="toggle-sandbox" ${y?"checked":""}>
|
|
734
744
|
<span class="switch" aria-hidden="true"></span>
|
|
735
745
|
<span class="toggle-tx"><strong>${t("botDefaults.sandboxToggle")}</strong>
|
|
736
746
|
<small>${t("botDefaults.sandboxHelp")}</small></span>
|
|
@@ -738,10 +748,10 @@ ${T.join(`
|
|
|
738
748
|
<div class="actions">
|
|
739
749
|
<span class="oncall-status" data-sandbox-status></span>
|
|
740
750
|
</div>
|
|
741
|
-
</section>`}function
|
|
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">
|
|
742
752
|
<h3 class="bd-section-title">${t("botDefaults.sectionGrant")}</h3>
|
|
743
753
|
<label class="toggle-row">
|
|
744
|
-
<input type="checkbox" data-action="toggle-restrict-grant" ${
|
|
754
|
+
<input type="checkbox" data-action="toggle-restrict-grant" ${y?"checked":""}>
|
|
745
755
|
<span class="switch" aria-hidden="true"></span>
|
|
746
756
|
<span class="toggle-tx"><strong>${t("botDefaults.restrictGrant")}</strong>
|
|
747
757
|
<small>${t("botDefaults.restrictGrantHelp")}</small></span>
|
|
@@ -751,9 +761,9 @@ ${T.join(`
|
|
|
751
761
|
<span>${t("botDefaults.quotaDefault")}</span>
|
|
752
762
|
<input type="number" min="1" step="1" data-input="quotaLimit"
|
|
753
763
|
placeholder="${i(t("botDefaults.quotaPlaceholder"))}"
|
|
754
|
-
value="${
|
|
764
|
+
value="${A??""}">
|
|
755
765
|
</label>
|
|
756
|
-
<small data-quota-state>${i(
|
|
766
|
+
<small data-quota-state>${i(x(A))}</small>
|
|
757
767
|
<small class="bd-help">${t("botDefaults.quotaHelp")}</small>
|
|
758
768
|
<div class="actions">
|
|
759
769
|
<button type="button" class="primary" data-action="save-quota">${t("botDefaults.quotaSave")}</button>
|
|
@@ -761,10 +771,10 @@ ${T.join(`
|
|
|
761
771
|
<span class="oncall-status" data-grant-status></span>
|
|
762
772
|
</div>
|
|
763
773
|
</div>
|
|
764
|
-
</section>`}function
|
|
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">
|
|
765
775
|
<h4 class="bd-subsection-title">${t("botDefaults.sectionAutoStart")}</h4>
|
|
766
776
|
<label class="toggle-row">
|
|
767
|
-
<input type="checkbox" data-action="toggle-auto-join" ${
|
|
777
|
+
<input type="checkbox" data-action="toggle-auto-join" ${y?"checked":""}>
|
|
768
778
|
<span class="switch" aria-hidden="true"></span>
|
|
769
779
|
<span class="toggle-tx"><strong>${t("botDefaults.autoStartJoin")}</strong>
|
|
770
780
|
<small>${t("botDefaults.autoStartJoinHelp")}</small></span>
|
|
@@ -773,14 +783,14 @@ ${T.join(`
|
|
|
773
783
|
<label>
|
|
774
784
|
<span>${t("botDefaults.autoStartJoinPrompt")}</span>
|
|
775
785
|
<textarea data-input="autoJoinPrompt" rows="3"
|
|
776
|
-
placeholder="${i(t("botDefaults.autoStartJoinPromptPlaceholder"))}">${i(
|
|
786
|
+
placeholder="${i(t("botDefaults.autoStartJoinPromptPlaceholder"))}">${i(O)}</textarea>
|
|
777
787
|
</label>
|
|
778
788
|
<div class="actions">
|
|
779
789
|
<button type="button" class="primary" data-action="save-auto-join-prompt">${t("botDefaults.autoStartJoinPromptSave")}</button>
|
|
780
790
|
</div>
|
|
781
791
|
</div>
|
|
782
792
|
<label class="toggle-row">
|
|
783
|
-
<input type="checkbox" data-action="toggle-auto-topic" ${
|
|
793
|
+
<input type="checkbox" data-action="toggle-auto-topic" ${A?"checked":""}>
|
|
784
794
|
<span class="switch" aria-hidden="true"></span>
|
|
785
795
|
<span class="toggle-tx"><strong>${t("botDefaults.autoStartTopic")}</strong>
|
|
786
796
|
<small>${t("botDefaults.autoStartTopicHelp")}</small></span>
|
|
@@ -788,7 +798,7 @@ ${T.join(`
|
|
|
788
798
|
<div class="actions">
|
|
789
799
|
<span class="oncall-status" data-auto-start-status></span>
|
|
790
800
|
</div>
|
|
791
|
-
</div>`}function P(){n.querySelectorAll(".bd-card").forEach(f=>{let v=f.dataset.appid,I=f.querySelector("input[data-action=toggle]"),D=f.querySelector("input[data-input=workingDir]"),B=f.querySelector("button[data-action=save]"),U=f.querySelector("[data-status]");if(!I||!D||!B||!U)return;I.addEventListener("change",()=>{D.disabled=!I.checked,I.checked&&D.focus()}),B.addEventListener("click",async()=>{U.textContent="",U.className="oncall-status";let J=I.checked,W=D.value.trim();if(J&&!W){U.textContent=t("botDefaults.required"),U.classList.add("hint-warn-inline");return}B.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(v)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:J,workingDir:W})}),z=await N.json().catch(()=>({}));if(N.ok&&z.ok){let G=z.resolvedPath?` \u2192 ${z.resolvedPath}`:"";U.textContent=J?`\u2713 \u5DF2\u5F00\u542F${G}\uFF08\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8 oncall\uFF09`:"\u2713 \u5DF2\u5173\u95ED\uFF08\u5DF2\u7ED1\u5B9A\u7684\u7FA4\u4E0D\u52A8\uFF09",U.classList.add("hint-ok");let V=Be.bots.find(Re=>Re.larkAppId===v);V&&z.defaultOncall&&(V.defaultOncall=z.defaultOncall);let pe=f.querySelector("[data-oncall-since]");pe&&z.defaultOncall?.since!=null&&(pe.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${vo(z.defaultOncall.since)}`)}else U.textContent=`\u2717 ${z.error??N.status}`,U.classList.add("hint-warn-inline")}catch(N){U.textContent=`\u2717 ${N?.message??N}`,U.classList.add("hint-warn-inline")}finally{B.disabled=!1}});let q=f.querySelector("input[data-input=brandLabel]"),ae=f.querySelector("button[data-action=save-brand]"),X=f.querySelector("button[data-action=reset-brand]"),oe=f.querySelector("[data-brand-status]"),De=f.querySelector("[data-brand-state]");async function se(J,W){if(oe){oe.textContent="",oe.className="oncall-status",W.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(v)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:J})}),z=await N.json().catch(()=>({}));if(N.ok&&z.ok){let G=z.brandLabel??null;oe.textContent="\u2713",oe.classList.add("hint-ok"),q&&(q.value=G??""),De&&(De.textContent=$(G));let V=Be.bots.find(pe=>pe.larkAppId===v);V&&(V.brandLabel=G)}else oe.textContent=`\u2717 ${z.error??N.status}`,oe.classList.add("hint-warn-inline")}catch(N){oe.textContent=`\u2717 ${N?.message??N}`,oe.classList.add("hint-warn-inline")}finally{W.disabled=!1}}}q&&ae&&ae.addEventListener("click",()=>se(q.value,ae)),X&&X.addEventListener("click",()=>se(null,X));let re=f.querySelector("input[data-action=toggle-disable-streaming]"),ue=f.querySelector("input[data-action=toggle-writable-link]"),Me=f.querySelector("input[data-action=toggle-private-card]"),ce=f.querySelector("[data-card-pref-status]"),Oe=f.querySelector("[data-card-pref-moot]");async function be(J,W,N=ce){if(N){N.textContent="",N.className="oncall-status",W.disabled=!0;try{let z=await fetch(`/api/bots/${encodeURIComponent(v)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(J)}),G=await z.json().catch(()=>({}));if(z.ok&&G.ok){N.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,N.classList.add("hint-ok");let V=Be.bots.find(pe=>pe.larkAppId===v);V&&(V.disableStreamingCard=G.disableStreamingCard,V.writableTerminalLinkInCard=G.writableTerminalLinkInCard,V.privateCard=G.privateCard,V.autoStartOnGroupJoin=G.autoStartOnGroupJoin,V.autoStartOnGroupJoinPrompt=G.autoStartOnGroupJoinPrompt,V.autoStartOnNewTopic=G.autoStartOnNewTopic,V.regularGroupReplyMode=G.regularGroupReplyMode,V.regularGroupMentionMode=G.regularGroupMentionMode,V.docSubscribeDefaultMode=G.docSubscribeDefaultMode)}else N.textContent=`\u2717 ${G.error??z.status}`,N.classList.add("hint-warn-inline")}catch(z){N.textContent=`\u2717 ${z?.message??z}`,N.classList.add("hint-warn-inline")}finally{W===ue?W.disabled=!!re?.checked:W.disabled=!1}}}re&&re.addEventListener("change",()=>{let J=re.checked;ue&&(ue.disabled=J),Oe&&(Oe.hidden=!J),be({disableStreamingCard:J},re)}),ue&&ue.addEventListener("change",()=>{be({writableTerminalLinkInCard:ue.checked},ue)}),Me&&Me.addEventListener("change",()=>{be({privateCard:Me.checked},Me)});let Ee=f.querySelector("input[data-action=toggle-sandbox]"),le=f.querySelector("[data-sandbox-status]");Ee&&Ee.addEventListener("change",async()=>{let J=Ee.checked;le&&(le.textContent="",le.className="oncall-status"),Ee.disabled=!0;try{let W=await fetch(`/api/bots/${encodeURIComponent(v)}/sandbox`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:J})}),N=await W.json().catch(()=>({}));if(W.ok&&N.ok){le&&(le.textContent=`\u2713 ${t("botDefaults.sandboxSaved")}`,le.classList.add("hint-ok"));let z=Be.bots.find(G=>G.larkAppId===v);z&&(z.sandbox=N.sandbox===!0)}else le&&(le.textContent=`\u2717 ${N.error??W.status}`,le.classList.add("hint-warn-inline")),Ee.checked=!J}catch(W){le&&(le.textContent=`\u2717 ${W?.message??W}`,le.classList.add("hint-warn-inline")),Ee.checked=!J}finally{Ee.disabled=!1}});let fe=f.querySelector("input[data-action=toggle-auto-join]"),de=f.querySelector("input[data-action=toggle-auto-topic]"),Ne=f.querySelector("textarea[data-input=autoJoinPrompt]"),Fe=f.querySelector("button[data-action=save-auto-join-prompt]"),qe=f.querySelector("[data-auto-start-status]");fe&&fe.addEventListener("change",()=>{be({autoStartOnGroupJoin:fe.checked},fe,qe)}),de&&de.addEventListener("change",()=>{be({autoStartOnNewTopic:de.checked},de,qe)}),Ne&&Fe&&Fe.addEventListener("click",()=>{be({autoStartOnGroupJoinPrompt:Ne.value},Fe,qe)});let Ge=f.querySelector("select[data-input=p2pMode]"),he=f.querySelector("[data-p2p-status]");Ge&&he&&Ge.addEventListener("change",async()=>{let J=Ge.value==="chat"?"chat":"thread";he.textContent="",he.className="oncall-status",Ge.disabled=!0;try{let W=await fetch(`/api/bots/${encodeURIComponent(v)}/p2p-mode`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({p2pMode:J})}),N=await W.json().catch(()=>({}));if(W.ok&&N.ok){he.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,he.classList.add("hint-ok");let z=Be.bots.find(G=>G.larkAppId===v);z&&(z.p2pMode=N.p2pMode==="chat"?"chat":"thread")}else he.textContent=`\u2717 ${N.error??W.status}`,he.classList.add("hint-warn-inline")}catch(W){he.textContent=`\u2717 ${W?.message??W}`,he.classList.add("hint-warn-inline")}finally{Ge.disabled=!1}});let ot=f.querySelector("select[data-input=regularGroupMode]"),$t=f.querySelector("[data-regular-group-status]");ot&&ot.addEventListener("change",()=>{be({regularGroupReplyMode:ot.value},ot,$t)});let st=f.querySelector("select[data-input=regularGroupMentionMode]"),Dt=f.querySelector("[data-mention-mode-status]");st&&st.addEventListener("change",()=>{be({regularGroupMentionMode:st.value},st,Dt)});let it=f.querySelector("select[data-input=docSubscribeDefaultMode]"),xe=f.querySelector("[data-doc-subscribe-mode-status]");it&&it.addEventListener("change",()=>{be({docSubscribeDefaultMode:it.value},it,xe)});let We=f.querySelector("textarea[data-input=teamRole]"),_e=f.querySelector("button[data-action=save-role]"),C=f.querySelector("button[data-action=delete-role]"),Y=f.querySelector("[data-role-status]");if(We&&_e&&C&&Y){let N=function(G){let V=n.querySelector(`.bd-card[data-appid="${CSS.escape(v)}"]`);if(!V)return;let pe=V.querySelector("textarea[data-input=teamRole]"),Re=V.querySelector("button[data-action=save-role]"),ft=V.querySelector("button[data-action=delete-role]");pe&&(pe.value=G,pe.disabled=!1),Re&&(Re.disabled=!1),ft&&(ft.disabled=!1)};var En=N;let J=`/api/team/local-bots/${encodeURIComponent(v)}/role`,W=Be.bots.find(G=>G.larkAppId===v);W&&typeof W.teamRole!="string"&&!W.teamRoleLoading&&(W.teamRoleLoading=!0,(async()=>{try{let G=await fetch(J),V=await G.json().catch(()=>({}));G.ok&&V.ok?(W.teamRole=V.role??"",N(W.teamRole)):(Y.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${V.error??G.status}`,Y.classList.add("hint-warn-inline"))}catch(G){Y.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${G?.message??G}`,Y.classList.add("hint-warn-inline")}finally{W.teamRoleLoading=!1}})());async function z(G,V,pe){if(Y&&!(!W||typeof W.teamRole!="string")){Y.textContent="",Y.className="oncall-status",_e.disabled=!0,C.disabled=!0;try{let Re=await fetch(J,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({role:G})}),ft=await Re.json().catch(()=>({}));Re.ok&&ft.ok?(W&&(W.teamRole=G.trim()),Y.textContent=`\u2713 ${pe?t("botDefaults.roleDeleted"):t("botDefaults.roleSaved")}`,Y.classList.add("hint-ok")):(Y.textContent=`\u2717 ${ft.error??Re.status}`,Y.classList.add("hint-warn-inline"))}catch(Re){Y.textContent=`\u2717 ${Re?.message??Re}`,Y.classList.add("hint-warn-inline")}finally{_e.disabled=!1,C.disabled=!1}}}_e.addEventListener("click",()=>z(We.value,_e,!1)),C.addEventListener("click",()=>{We.value="",z("",C,!0)})}let K=f.querySelector("input[data-action=toggle-restrict-grant]"),_=f.querySelector("input[data-input=quotaLimit]"),we=f.querySelector("button[data-action=save-quota]"),Ze=f.querySelector("button[data-action=off-quota]"),Se=f.querySelector("[data-grant-status]"),Yt=f.querySelector("[data-quota-state]");async function mt(J,W){if(Se){Se.textContent="",Se.className="oncall-status",W.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(v)}/grant-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(J)}),z=await N.json().catch(()=>({}));if(N.ok&&z.ok){Se.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,Se.classList.add("hint-ok");let G=typeof z.messageQuotaDefaultLimit=="number"?z.messageQuotaDefaultLimit:null,V=Be.bots.find(pe=>pe.larkAppId===v);V&&(V.restrictGrantCommands=z.restrictGrantCommands===!0,V.messageQuotaDefaultLimit=G),Yt&&(Yt.textContent=L(G)),_&&"messageQuotaDefaultLimit"in J&&(_.value=G==null?"":String(G))}else Se.textContent=`\u2717 ${z.error??N.status}`,Se.classList.add("hint-warn-inline")}catch(N){Se.textContent=`\u2717 ${N?.message??N}`,Se.classList.add("hint-warn-inline")}finally{W.disabled=!1}}}K&&K.addEventListener("change",()=>{mt({restrictGrantCommands:K.checked},K)}),_&&we&&we.addEventListener("click",()=>{let J=_.value.trim();if(J===""){mt({messageQuotaDefaultLimit:null},we);return}if(!/^[1-9]\d*$/.test(J)){Se&&(Se.textContent=`\u2717 ${t("botDefaults.quotaInvalid")}`,Se.className="oncall-status hint-warn-inline");return}mt({messageQuotaDefaultLimit:Number(J)},we)}),_&&Ze&&Ze.addEventListener("click",()=>{_.value="",mt({messageQuotaDefaultLimit:null},Ze)});let et=f.querySelector("input[data-input=maxLiveWorkers]"),St=f.querySelector("button[data-action=save-session-cap]"),Rt=f.querySelector("button[data-action=off-session-cap]"),Le=f.querySelector("[data-session-cap-status]"),Pt=f.querySelector("[data-session-cap-state]");async function Lt(J,W){if(Le){Le.textContent="",Le.className="oncall-status",W.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(v)}/max-live-workers`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({maxLiveWorkers:J})}),z=await N.json().catch(()=>({}));if(N.ok&&z.ok){Le.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,Le.classList.add("hint-ok");let G=typeof z.maxLiveWorkers=="number"?z.maxLiveWorkers:null,V=Be.bots.find(pe=>pe.larkAppId===v);V&&(V.maxLiveWorkers=G),Pt&&(Pt.textContent=S(G)),et&&(et.value=G==null?"":String(G))}else Le.textContent=`\u2717 ${z.error??N.status}`,Le.classList.add("hint-warn-inline")}catch(N){Le.textContent=`\u2717 ${N?.message??N}`,Le.classList.add("hint-warn-inline")}finally{W.disabled=!1}}}et&&St&&St.addEventListener("click",()=>{let J=et.value.trim();if(J===""){Lt(null,St);return}if(!/^[1-9]\d*$/.test(J)){Le&&(Le.textContent=`\u2717 ${t("botDefaults.maxLiveWorkersInvalid")}`,Le.className="oncall-status hint-warn-inline");return}Lt(Number(J),St)}),et&&Rt&&Rt.addEventListener("click",()=>{et.value="",Lt(null,Rt)})})}r(),Je().then(r),s.addEventListener("input",r)}var ie={skills:[],bots:[],trustProjectSkills:"off",delivery:"auto"},un=null,bi=2,bt=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">
|
|
792
802
|
<div class="page-heading">
|
|
793
803
|
<div>
|
|
794
804
|
<p class="eyebrow">${t("nav.skills")}</p>
|
|
@@ -798,7 +808,7 @@ ${T.join(`
|
|
|
798
808
|
<button type="button" id="skills-refresh">${t("skills.refresh")}</button>
|
|
799
809
|
</div>
|
|
800
810
|
<div id="skills-body"></div>
|
|
801
|
-
</section>`}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">
|
|
802
812
|
<div class="skills-install-title">
|
|
803
813
|
<h3 class="bd-section-title">${t("skills.install")}</h3>
|
|
804
814
|
<span class="skills-help-tip">
|
|
@@ -825,94 +835,94 @@ ${T.join(`
|
|
|
825
835
|
<button type="button" class="primary" data-action="install">${t("skills.installSubmit")}</button>
|
|
826
836
|
<span class="oncall-status" data-skills-status></span>
|
|
827
837
|
</div>
|
|
828
|
-
</article>`}function
|
|
829
|
-
<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)}">
|
|
830
840
|
<div class="skills-row-body">
|
|
831
|
-
<strong>${i(
|
|
832
|
-
${
|
|
833
|
-
<small>${i(
|
|
841
|
+
<strong>${i(a.name)}</strong>
|
|
842
|
+
${a.description?`<p>${i(a.description)}</p>`:""}
|
|
843
|
+
<small>${i(yi(a))}</small>
|
|
834
844
|
</div>
|
|
835
845
|
<div class="skills-card-actions">
|
|
836
846
|
<button type="button" data-action="update-skill">${t("skills.update")}</button>
|
|
837
847
|
<button type="button" data-action="remove-skill">${t("skills.remove")}</button>
|
|
838
848
|
</div>
|
|
839
|
-
</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">
|
|
840
850
|
${e}
|
|
841
851
|
<div class="skills-pager">
|
|
842
|
-
<button type="button" class="skills-pager-button" data-action="page-installed-skills" data-dir="-1" aria-label="${t("skills.prevPage")}" title="${t("skills.prevPage")}" ${
|
|
843
|
-
<span>${t("skills.pageStatus",{page:
|
|
844
|
-
<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>
|
|
845
855
|
</div>
|
|
846
|
-
</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">
|
|
847
857
|
<h3 class="bd-section-title">${t("skills.globalDefaults")}</h3>
|
|
848
858
|
<div class="skills-control-block">
|
|
849
859
|
<span class="skills-control-label">${t("skills.globalProject")}</span>
|
|
850
860
|
<div class="skills-choice-group skills-choice-group-compact skills-project-group">
|
|
851
|
-
${[["off",t("skills.globalProjectOff"),t("skills.globalProjectOffHelp")],["all",t("skills.globalProjectAll"),t("skills.globalProjectAllHelp")]].map(([n,a
|
|
852
|
-
<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>
|
|
853
863
|
</button>`).join("")}
|
|
854
864
|
</div>
|
|
855
865
|
</div>
|
|
856
866
|
<div class="skills-control-block">
|
|
857
867
|
<span class="skills-control-label">${t("skills.globalDelivery")}</span>
|
|
858
868
|
<div class="skills-choice-group skills-delivery-group">
|
|
859
|
-
${e.map(([n,a
|
|
860
|
-
<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>
|
|
861
871
|
</button>`).join("")}
|
|
862
872
|
</div>
|
|
863
873
|
</div>
|
|
864
|
-
</article>`}function
|
|
865
|
-
${
|
|
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("")}
|
|
866
876
|
</select>
|
|
867
|
-
<button type="button" data-action="attach-skill">${t("skills.attach")}</button>`}function
|
|
868
|
-
<header>${
|
|
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
|
+
<header>${ue({name:e.botName??e.larkAppId,larkAppId:e.larkAppId,size:"sm"})}
|
|
869
879
|
<strong>${i(e.botName??e.larkAppId)}</strong></header>
|
|
870
880
|
<p class="hint-warn-inline">${i(e.error)}</p>
|
|
871
|
-
</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)}">
|
|
872
882
|
<header class="skills-bot-head">
|
|
873
|
-
${
|
|
883
|
+
${ue({name:e.botName??e.larkAppId,larkAppId:e.larkAppId,size:"sm",dot:"ok"})}
|
|
874
884
|
<div><strong>${i(e.botName??e.larkAppId)}</strong><code>${i(e.larkAppId)}</code></div>
|
|
875
885
|
<span class="skills-count-pill">${t("skills.skillCount",{count:n.length})}</span>
|
|
876
886
|
</header>
|
|
877
887
|
<section class="bd-section">
|
|
878
888
|
<h3 class="bd-section-title">${t("skills.priority")}</h3>
|
|
879
|
-
${n.length===0?`<p class="bd-section-note">${t("skills.noPriority")}</p>`:`<div class="skills-chip-list">${n.map(
|
|
880
|
-
<span class="skills-priority-name">${i(
|
|
881
|
-
<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>
|
|
882
892
|
</span>`}).join("")}</div>`}
|
|
883
|
-
<div class="actions skills-attach-row">${
|
|
893
|
+
<div class="actions skills-attach-row">${xi(e)}</div>
|
|
884
894
|
</section>
|
|
885
895
|
<span class="oncall-status" data-bot-status></span>
|
|
886
|
-
</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">
|
|
887
897
|
<div class="skills-overview-copy">
|
|
888
898
|
<h2>${t("skills.overviewTitle")}</h2>
|
|
889
899
|
<p>${t("skills.overviewBody")}</p>
|
|
890
900
|
</div>
|
|
891
901
|
<div class="skills-metric-strip">
|
|
892
|
-
<span><small>${t("skills.metricInstalled")}</small><strong>${
|
|
893
|
-
<span><small>${t("skills.metricBots")}</small><strong>${
|
|
894
|
-
<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>
|
|
895
905
|
</div>
|
|
896
|
-
</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">
|
|
897
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>
|
|
898
908
|
${e}
|
|
899
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>
|
|
900
|
-
</div>`}function
|
|
910
|
+
</div>`}function Oi(){return mn?`<p class="hint-warn">${i(mn)}</p>`:`<div class="skills-page-grid">
|
|
901
911
|
<aside class="skills-side-rail">
|
|
902
|
-
${
|
|
903
|
-
${
|
|
912
|
+
${Ei()}
|
|
913
|
+
${Li()}
|
|
904
914
|
</aside>
|
|
905
915
|
<section class="skills-main-panel">
|
|
906
|
-
${
|
|
916
|
+
${Di()}
|
|
907
917
|
<section class="skills-bots-panel">
|
|
908
918
|
<div class="skills-section-head skills-section-head-row">
|
|
909
919
|
<div>
|
|
910
920
|
<h2>${t("skills.bots")}</h2>
|
|
911
921
|
<p>${t("skills.botsHelp")}</p>
|
|
912
922
|
</div>
|
|
913
|
-
${
|
|
923
|
+
${Ri()}
|
|
914
924
|
</div>
|
|
915
|
-
<div class="skills-bot-grid">${
|
|
925
|
+
<div class="skills-bot-grid">${ae.bots.map(Hi).join("")}</div>
|
|
916
926
|
</section>
|
|
917
927
|
<section class="bd-card skills-installed-panel">
|
|
918
928
|
<div class="skills-section-head skills-section-head-row">
|
|
@@ -920,12 +930,12 @@ ${T.join(`
|
|
|
920
930
|
<h2>${t("skills.installed")}</h2>
|
|
921
931
|
<p>${t("skills.installedHelp")}</p>
|
|
922
932
|
</div>
|
|
923
|
-
${
|
|
933
|
+
${Mi()}
|
|
924
934
|
</div>
|
|
925
|
-
${
|
|
935
|
+
${Ti()}
|
|
926
936
|
</section>
|
|
927
937
|
</section>
|
|
928
|
-
</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">
|
|
929
939
|
<div class="page-heading">
|
|
930
940
|
<div>
|
|
931
941
|
<p class="eyebrow">${t("nav.roles")}</p>
|
|
@@ -964,12 +974,12 @@ ${T.join(`
|
|
|
964
974
|
</div>
|
|
965
975
|
</div>
|
|
966
976
|
</div>
|
|
967
|
-
</section>`}async function
|
|
968
|
-
<div class="roles-bot-row ${
|
|
969
|
-
data-group-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)}"
|
|
970
980
|
data-bot-id="${i(w.larkAppId)}">
|
|
971
981
|
<span class="roles-bot-indent"></span>
|
|
972
|
-
${
|
|
982
|
+
${ue({name:w.botName,larkAppId:w.larkAppId,size:"sm"})}
|
|
973
983
|
<div class="roles-bot-info">
|
|
974
984
|
<div class="roles-bot-name">${i(w.botName)}</div>
|
|
975
985
|
<div class="roles-bot-id">${i(w.larkAppId)}</div>
|
|
@@ -979,25 +989,25 @@ ${T.join(`
|
|
|
979
989
|
</span>
|
|
980
990
|
</div>`).join(""):"";return`
|
|
981
991
|
<div class="roles-group-section">
|
|
982
|
-
<div class="roles-group-row ${r?"expanded":""} ${
|
|
983
|
-
data-group-id="${i(
|
|
984
|
-
<span class="roles-group-arrow">${
|
|
992
|
+
<div class="roles-group-row ${r?"expanded":""} ${Ve===s.chatId&&!Ye?"selected":""}"
|
|
993
|
+
data-group-id="${i(s.chatId)}">
|
|
994
|
+
<span class="roles-group-arrow">${m}</span>
|
|
985
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>
|
|
986
996
|
<div class="roles-group-info">
|
|
987
|
-
<div class="roles-group-name">${i(
|
|
997
|
+
<div class="roles-group-name">${i(s.name??s.chatId)}</div>
|
|
988
998
|
<div class="roles-group-meta">
|
|
989
999
|
${k}/${$} ${t("roles.botsWithRoles")}
|
|
990
1000
|
</div>
|
|
991
1001
|
</div>
|
|
992
1002
|
<span class="roles-group-chevron"></span>
|
|
993
1003
|
</div>
|
|
994
|
-
<div class="roles-bot-list">${
|
|
995
|
-
</div>`}).join(""),n.querySelectorAll(".roles-group-row").forEach(
|
|
1004
|
+
<div class="roles-bot-list">${M}</div>
|
|
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">
|
|
996
1006
|
<div class="page-heading"><div>
|
|
997
1007
|
<p class="eyebrow">${t("team.eyebrow")}</p><h1>${t("team.homeTitle")}</h1>
|
|
998
1008
|
<p class="tf-lede">${t("team.homeLede")}</p>
|
|
999
1009
|
</div></div>
|
|
1000
|
-
${
|
|
1010
|
+
${Aa("home")}
|
|
1001
1011
|
<div class="card" style="margin-bottom:16px">
|
|
1002
1012
|
<h2 style="margin-top:0">${t("team.localDeployTitle")}</h2>
|
|
1003
1013
|
<p>${t("team.myIdentity")}<b id="tf-owner">${t("team.unbound")}</b>
|
|
@@ -1026,12 +1036,12 @@ ${Co("home")}
|
|
|
1026
1036
|
</div>
|
|
1027
1037
|
</div>
|
|
1028
1038
|
</div>
|
|
1029
|
-
</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">
|
|
1030
1040
|
<div class="page-heading"><div>
|
|
1031
1041
|
<p class="eyebrow">${t("team.eyebrow")}</p><h1>${t("team.manageTitle")}</h1>
|
|
1032
1042
|
<p class="tf-lede">${t("team.manageLede")}</p>
|
|
1033
1043
|
</div></div>
|
|
1034
|
-
${
|
|
1044
|
+
${Aa("manage")}
|
|
1035
1045
|
<div class="card" style="margin-bottom:16px">
|
|
1036
1046
|
<h2 style="margin-top:0">${t("team.hostedTitle")}</h2>
|
|
1037
1047
|
<p style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:6px">
|
|
@@ -1050,16 +1060,16 @@ ${Co("manage")}
|
|
|
1050
1060
|
</p>
|
|
1051
1061
|
<div id="tm-join-out" style="display:none;margin-top:6px"></div>
|
|
1052
1062
|
</div>
|
|
1053
|
-
</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)">
|
|
1054
1064
|
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
1055
|
-
<b>${i(
|
|
1056
|
-
<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>
|
|
1057
1067
|
<span style="margin-left:auto;display:flex;gap:6px">
|
|
1058
|
-
<button class="tm-invite ghost" data-team="${i(
|
|
1059
|
-
${
|
|
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>`}
|
|
1060
1070
|
</span>
|
|
1061
1071
|
</div>
|
|
1062
|
-
<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">
|
|
1063
1073
|
<div class="page-heading">
|
|
1064
1074
|
<div>
|
|
1065
1075
|
<p class="eyebrow">Webhook</p>
|
|
@@ -1121,28 +1131,28 @@ ${Co("manage")}
|
|
|
1121
1131
|
<h2 style="margin-top:0">${t("connectors.listTitle")} <span class="muted" id="cn-count" style="font-size:13px"></span></h2>
|
|
1122
1132
|
<div id="cn-list">${t("connectors.loading")}</div>
|
|
1123
1133
|
</div>
|
|
1124
|
-
</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)">
|
|
1125
1135
|
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
1126
|
-
<b style="font-size:15px">${i(
|
|
1127
|
-
<span class="${
|
|
1128
|
-
<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>
|
|
1129
1139
|
<span style="margin-left:auto;display:flex;gap:6px">
|
|
1130
|
-
<button class="cn-toggle ghost" data-id="${i(
|
|
1131
|
-
<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>
|
|
1132
1142
|
</span>
|
|
1133
1143
|
</div>
|
|
1134
1144
|
<div style="margin-top:6px;font-size:13px;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
1135
|
-
<span class="muted">${t("connectors.webhookUrl")}</span><code style="font-size:12px;word-break:break-all">${i(
|
|
1136
|
-
<button class="cn-copy ghost" data-url="${i(
|
|
1137
|
-
</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>
|
|
1138
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>
|
|
1139
|
-
<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageDynamicNote")}</p>`}else S?
|
|
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>
|
|
1140
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>
|
|
1141
|
-
<p class="muted" style="font-size:12px;margin:6px 0 0">${t("connectors.usageTokenNote")}</p>`:
|
|
1142
|
-
<p class="ok" style="margin:0 0 6px">${t("connectors.createdPrefix",{name:i(
|
|
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(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>
|
|
1143
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>
|
|
1144
|
-
${
|
|
1145
|
-
${
|
|
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,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">
|
|
1146
1156
|
<div class="page-heading">
|
|
1147
1157
|
<div>
|
|
1148
1158
|
<p class="eyebrow">${t("nav.settings")}</p>
|
|
@@ -1151,28 +1161,28 @@ ${Co("manage")}
|
|
|
1151
1161
|
</div>
|
|
1152
1162
|
</div>
|
|
1153
1163
|
<div id="settings-body"></div>
|
|
1154
|
-
</section>`}function
|
|
1155
|
-
<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}>
|
|
1156
1166
|
<span class="switch" aria-hidden="true"></span>
|
|
1157
1167
|
<span class="toggle-tx"><strong>${t("settings.autoUpdate")}</strong>
|
|
1158
1168
|
<small>${t("settings.autoUpdateHelp")}</small></span>
|
|
1159
1169
|
</label>
|
|
1160
1170
|
<div class="maint-time">
|
|
1161
1171
|
<label>${t("settings.maintenanceTime")}
|
|
1162
|
-
<input type="time" data-maint-time="autoUpdate" value="${i(
|
|
1172
|
+
<input type="time" data-maint-time="autoUpdate" value="${i(o)}" ${a}>
|
|
1163
1173
|
</label>
|
|
1164
|
-
</div>`}function
|
|
1165
|
-
<input type="checkbox" data-maint="autoRestart" ${
|
|
1174
|
+
</div>`}function dr(e){return`<label class="toggle-row">
|
|
1175
|
+
<input type="checkbox" data-maint="autoRestart" ${Se.maintenance.autoRestart?.enabled===!0?"checked":""} ${e?"disabled":""}>
|
|
1166
1176
|
<span class="switch" aria-hidden="true"></span>
|
|
1167
1177
|
<span class="toggle-tx"><strong>${t("settings.autoRestart")}</strong>
|
|
1168
1178
|
<small>${t("settings.autoRestartHelp")}</small></span>
|
|
1169
|
-
</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">
|
|
1170
1180
|
<article class="bd-card settings-card">
|
|
1171
|
-
${
|
|
1181
|
+
${Vt?"":`<p class="hint-warn">${t("settings.readOnlyVisitor")}</p>`}
|
|
1172
1182
|
<section class="bd-section">
|
|
1173
1183
|
<h3 class="bd-section-title">${t("settings.sectionAccess")}</h3>
|
|
1174
1184
|
<label class="toggle-row">
|
|
1175
|
-
<input type="checkbox" data-setting="publicReadOnly" ${
|
|
1185
|
+
<input type="checkbox" data-setting="publicReadOnly" ${Se.publicReadOnly?"checked":""} ${e}>
|
|
1176
1186
|
<span class="switch" aria-hidden="true"></span>
|
|
1177
1187
|
<span class="toggle-tx"><strong>${t("settings.publicReadOnly")}</strong>
|
|
1178
1188
|
<small>${t("settings.publicReadOnlyHelp")}</small></span>
|
|
@@ -1181,7 +1191,7 @@ ${Co("manage")}
|
|
|
1181
1191
|
<section class="bd-section">
|
|
1182
1192
|
<h3 class="bd-section-title">${t("settings.sectionCards")}</h3>
|
|
1183
1193
|
<label class="toggle-row">
|
|
1184
|
-
<input type="checkbox" data-setting="openTerminalInFeishu" ${
|
|
1194
|
+
<input type="checkbox" data-setting="openTerminalInFeishu" ${Se.openTerminalInFeishu?"checked":""} ${e}>
|
|
1185
1195
|
<span class="switch" aria-hidden="true"></span>
|
|
1186
1196
|
<span class="toggle-tx"><strong>${t("settings.openTerminalInFeishu")}</strong>
|
|
1187
1197
|
<small>${t("settings.openTerminalInFeishuHelp")}</small></span>
|
|
@@ -1192,23 +1202,23 @@ ${Co("manage")}
|
|
|
1192
1202
|
<label class="form-row">
|
|
1193
1203
|
<span>${t("settings.repoPickerMode")}</span>
|
|
1194
1204
|
<select data-select-setting="repoPickerMode" ${e}>
|
|
1195
|
-
<option value="all" ${
|
|
1196
|
-
<option value="repos" ${
|
|
1205
|
+
<option value="all" ${Se.repoPickerMode==="all"?"selected":""}>${t("settings.repoPickerModeAll")}</option>
|
|
1206
|
+
<option value="repos" ${Se.repoPickerMode==="repos"?"selected":""}>${t("settings.repoPickerModeRepos")}</option>
|
|
1197
1207
|
</select>
|
|
1198
1208
|
<small>${t("settings.repoPickerModeHelp")}</small>
|
|
1199
1209
|
</label>
|
|
1200
1210
|
</section>
|
|
1201
1211
|
<section class="bd-section">
|
|
1202
1212
|
<h3 class="bd-section-title">${t("settings.sectionMaintenance")}</h3>
|
|
1203
|
-
${
|
|
1204
|
-
${
|
|
1205
|
-
${
|
|
1213
|
+
${lr(n)}
|
|
1214
|
+
${Se.localDevInstall?`<p class="hint-warn">${t("settings.autoUpdateLocalDev")}</p>`:""}
|
|
1215
|
+
${dr(!Vt||Se.maintenance.autoUpdate?.enabled!==!0)}
|
|
1206
1216
|
</section>
|
|
1207
1217
|
<div class="actions settings-actions">
|
|
1208
1218
|
<span class="oncall-status" data-settings-status></span>
|
|
1209
1219
|
</div>
|
|
1210
1220
|
</article>
|
|
1211
|
-
</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`
|
|
1212
1222
|
<nav class="wf-subnav">
|
|
1213
1223
|
<a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${h(t("workflow.subnav.runs"))}</a>
|
|
1214
1224
|
<a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${h(t("workflow.subnav.catalog"))}</a>
|
|
@@ -1216,7 +1226,7 @@ ${Co("manage")}
|
|
|
1216
1226
|
<form id="wf-filters" class="filters">
|
|
1217
1227
|
<input type="search" name="q" placeholder="${h(t("workflow.searchPlaceholder"))}" />
|
|
1218
1228
|
<select name="status">
|
|
1219
|
-
${e.map(([n,
|
|
1229
|
+
${e.map(([n,o])=>`<option value="${h(n)}">${h(o)}</option>`).join("")}
|
|
1220
1230
|
</select>
|
|
1221
1231
|
<span id="wf-last-load" class="muted"></span>
|
|
1222
1232
|
</form>
|
|
@@ -1228,15 +1238,15 @@ ${Co("manage")}
|
|
|
1228
1238
|
</tr></thead>
|
|
1229
1239
|
<tbody id="wf-tbody"></tbody>
|
|
1230
1240
|
</table>
|
|
1231
|
-
`}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)}">
|
|
1232
1242
|
<td><a href="#/workflows/${encodeURIComponent(L.runId)}"><code>${h(L.runId)}</code></a></td>
|
|
1233
1243
|
<td>${h(L.workflowId)}</td>
|
|
1234
|
-
<td>${at(L.status)}${L.failedNodeId?` <span class="muted">(${h(L.failedNodeId)})</span>`:""}${
|
|
1244
|
+
<td>${at(L.status)}${L.failedNodeId?` <span class="muted">(${h(L.failedNodeId)})</span>`:""}${u}</td>
|
|
1235
1245
|
<td>${L.lastSeq}</td>
|
|
1236
|
-
<td class="${T}">${
|
|
1237
|
-
<td title="${h(new Date(L.updatedAt).toISOString())}">${
|
|
1238
|
-
<td>${
|
|
1239
|
-
</tr>`}).join("")}function w(){
|
|
1246
|
+
<td class="${T}">${x}</td>
|
|
1247
|
+
<td title="${h(new Date(L.updatedAt).toISOString())}">${gr(L.updatedAt)}</td>
|
|
1248
|
+
<td>${q}</td>
|
|
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=`
|
|
1240
1250
|
<div class="wf-detail-head">
|
|
1241
1251
|
<a class="btn-link" href="#/workflows">${h(t("workflow.detail.back"))}</a>
|
|
1242
1252
|
<div>
|
|
@@ -1292,38 +1302,38 @@ ${Co("manage")}
|
|
|
1292
1302
|
</div>
|
|
1293
1303
|
<div id="wf-event-meta" class="muted"></div>
|
|
1294
1304
|
</section>
|
|
1295
|
-
`;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">
|
|
1296
1306
|
<span class="muted error">${h(e.errorCode)}</span>${h(n)}
|
|
1297
|
-
</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>
|
|
1298
1308
|
<div class="wf-dangling-grid">
|
|
1299
|
-
${
|
|
1300
|
-
</div>`}function
|
|
1301
|
-
<span title="${h(new Date(d).toISOString())}">${h(
|
|
1302
|
-
<span title="${h(new Date(
|
|
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
|
+
<span title="${h(new Date(d).toISOString())}">${h(Ln(d))}</span>
|
|
1312
|
+
<span title="${h(new Date(m).toISOString())}">${h(Ln(m))}</span>
|
|
1303
1313
|
</div>
|
|
1304
|
-
<div class="wf-parallel-list">${w}</div>`}function
|
|
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(`
|
|
1305
1315
|
`);return`<div class="wf-parallel-row">
|
|
1306
1316
|
<div class="wf-parallel-label">
|
|
1307
|
-
<code>${h(
|
|
1317
|
+
<code>${h(m)}</code>
|
|
1308
1318
|
<span class="muted">${h(e.activityId)} \xB7 ${h(k)}</span>
|
|
1309
1319
|
</div>
|
|
1310
1320
|
<div class="wf-parallel-track">
|
|
1311
1321
|
<div class="wf-parallel-bar wf-parallel-${h(e.status)}" style="left:${r.toFixed(3)}%;width:${d.toFixed(3)}%;" title="${h($)}">
|
|
1312
|
-
<span>${h(
|
|
1322
|
+
<span>${h(mt(e.status))}</span>
|
|
1313
1323
|
</div>
|
|
1314
1324
|
</div>
|
|
1315
|
-
</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>
|
|
1316
1326
|
<td>${e?`<code>${h(e.nodeId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
1317
1327
|
<td>${e?at(e.status):'<span class="muted">-</span>'}</td>
|
|
1318
1328
|
<td>${n?`<code>${h(n.activityId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
1319
1329
|
<td>${n?at(n.status):'<span class="muted">-</span>'}</td>
|
|
1320
1330
|
<td>${n?.attempts.length??0}</td>
|
|
1321
|
-
<td>${
|
|
1322
|
-
<td>${
|
|
1323
|
-
</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=`
|
|
1324
1334
|
<header>
|
|
1325
1335
|
<div>
|
|
1326
|
-
<strong><code>${h(
|
|
1336
|
+
<strong><code>${h(m)}</code></strong>
|
|
1327
1337
|
<span class="muted">${n.activity?h(n.activity.activityId):h(t("workflow.detail.notDispatched"))}</span>
|
|
1328
1338
|
</div>
|
|
1329
1339
|
<div>${n.node?at(n.node.status):""} ${n.activity?at(n.activity.status):""}</div>
|
|
@@ -1332,22 +1342,22 @@ ${Co("manage")}
|
|
|
1332
1342
|
${d?`${h(t("workflow.detail.attempt"))} <code>${h(d.attemptId)}</code>`:h(t("workflow.detail.noAttempt"))}
|
|
1333
1343
|
</div>
|
|
1334
1344
|
${$}
|
|
1335
|
-
`;let
|
|
1336
|
-
${
|
|
1337
|
-
${
|
|
1338
|
-
${
|
|
1339
|
-
${
|
|
1340
|
-
${n.io?.waitPrompt?
|
|
1341
|
-
`}function
|
|
1342
|
-
<summary>${h(
|
|
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
|
+
<summary>${h(m)} ${$}</summary>
|
|
1343
1353
|
<div class="wf-terminal-actions">
|
|
1344
|
-
<a class="btn-link" href="${h(
|
|
1354
|
+
<a class="btn-link" href="${h(s.url)}" target="_blank" rel="noreferrer">${h(M)}</a>
|
|
1345
1355
|
${w}
|
|
1346
|
-
${
|
|
1356
|
+
${p}
|
|
1347
1357
|
</div>
|
|
1348
1358
|
${S}
|
|
1349
|
-
<iframe class="wf-terminal-frame" src="${h(
|
|
1350
|
-
</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}>
|
|
1351
1361
|
<div class="wf-io-card-head">
|
|
1352
1362
|
<header>
|
|
1353
1363
|
<div>
|
|
@@ -1361,159 +1371,159 @@ ${Co("manage")}
|
|
|
1361
1371
|
</div>
|
|
1362
1372
|
${k}
|
|
1363
1373
|
</div>
|
|
1364
|
-
<div class="wf-io-terminal-slot">${
|
|
1374
|
+
<div class="wf-io-terminal-slot">${p}</div>
|
|
1365
1375
|
<div class="wf-io-grid">
|
|
1366
|
-
${
|
|
1367
|
-
${
|
|
1368
|
-
${
|
|
1369
|
-
${
|
|
1370
|
-
${e.io?.waitPrompt?
|
|
1376
|
+
${Qe(m,t("workflow.detail.authoredInput"),e.io?.input,n)}
|
|
1377
|
+
${Qe(m,t("workflow.detail.resolvedInput"),e.io?.resolvedInput,n)}
|
|
1378
|
+
${Qe(m,t("workflow.detail.output"),e.io?.output,n)}
|
|
1379
|
+
${Qe(m,t("workflow.detail.executionLog"),e.io?.log,n)}
|
|
1380
|
+
${e.io?.waitPrompt?Qe(m,t("workflow.detail.waitPrompt"),e.io.waitPrompt,n):""}
|
|
1371
1381
|
</div>
|
|
1372
|
-
</article>`}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)}">
|
|
1373
1383
|
<label>
|
|
1374
1384
|
<span>${h(t("workflow.detail.approvalComment"))}</span>
|
|
1375
|
-
<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>
|
|
1376
1386
|
</label>
|
|
1377
1387
|
<div class="wf-approval-actions">
|
|
1378
|
-
<button type="button" class="primary" data-wf-approval-action="approve" data-wf-attempt-id="${h(
|
|
1379
|
-
<button type="button" data-wf-approval-action="reject" data-wf-attempt-id="${h(
|
|
1380
|
-
${
|
|
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>`:""}
|
|
1381
1391
|
</div>
|
|
1382
1392
|
${r?`<div class="${d} wf-approval-status">${h(r.text)}</div>`:""}
|
|
1383
|
-
</div>`}function
|
|
1384
|
-
<summary>${h(n)} ${
|
|
1385
|
-
${
|
|
1386
|
-
</details>`}function
|
|
1387
|
-
<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>
|
|
1388
1398
|
<td><code>${h(e.type)}</code></td>
|
|
1389
1399
|
<td>${h(e.actor)}</td>
|
|
1390
1400
|
<td>${n.nodeId?`<code>${h(n.nodeId)}</code>`:"-"}</td>
|
|
1391
1401
|
<td>${n.activityId?`<code>${h(n.activityId)}</code>`:"-"}</td>
|
|
1392
1402
|
<td>${n.errorCode?`<span class="muted error">${h(n.errorCode)}</span>`:"-"}</td>
|
|
1393
|
-
<td title="${h(new Date(e.timestamp).toISOString())}">${h(
|
|
1394
|
-
</tr>`}function
|
|
1403
|
+
<td title="${h(new Date(e.timestamp).toISOString())}">${h(Ln(e.timestamp))}</td>
|
|
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=`
|
|
1395
1405
|
<nav class="wf-subnav">
|
|
1396
|
-
<a href="#/workflows" data-i18n="workflow.subnav.runs">${
|
|
1397
|
-
<a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${
|
|
1406
|
+
<a href="#/workflows" data-i18n="workflow.subnav.runs">${F(t("workflow.subnav.runs"))}</a>
|
|
1407
|
+
<a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${F(t("workflow.subnav.catalog"))}</a>
|
|
1398
1408
|
</nav>
|
|
1399
1409
|
<section class="catalog-head">
|
|
1400
1410
|
<div>
|
|
1401
|
-
<h2>${
|
|
1402
|
-
<p class="muted">${
|
|
1411
|
+
<h2>${F(t("catalog.title"))}</h2>
|
|
1412
|
+
<p class="muted">${F(t("catalog.subtitle"))}</p>
|
|
1403
1413
|
</div>
|
|
1404
|
-
<button id="catalog-refresh" type="button">${
|
|
1414
|
+
<button id="catalog-refresh" type="button">${F(t("catalog.refresh"))}</button>
|
|
1405
1415
|
</section>
|
|
1406
1416
|
<form id="catalog-filters" class="filters">
|
|
1407
|
-
<input type="search" name="q" placeholder="${
|
|
1417
|
+
<input type="search" name="q" placeholder="${F(t("catalog.searchPlaceholder"))}" />
|
|
1408
1418
|
<span id="catalog-status" class="muted"></span>
|
|
1409
1419
|
</form>
|
|
1410
1420
|
<div class="wf-table-scroll">
|
|
1411
1421
|
<table>
|
|
1412
1422
|
<thead><tr>
|
|
1413
|
-
<th>${
|
|
1414
|
-
<th>${
|
|
1415
|
-
<th>${
|
|
1416
|
-
<th>${
|
|
1417
|
-
<th>${
|
|
1418
|
-
<th>${
|
|
1423
|
+
<th>${F(t("catalog.table.workflow"))}</th>
|
|
1424
|
+
<th>${F(t("catalog.table.version"))}</th>
|
|
1425
|
+
<th>${F(t("catalog.table.params"))}</th>
|
|
1426
|
+
<th>${F(t("catalog.table.nodes"))}</th>
|
|
1427
|
+
<th>${F(t("catalog.table.revision"))}</th>
|
|
1428
|
+
<th>${F(t("catalog.table.path"))}</th>
|
|
1419
1429
|
</tr></thead>
|
|
1420
1430
|
<tbody id="catalog-tbody"></tbody>
|
|
1421
1431
|
</table>
|
|
1422
1432
|
</div>
|
|
1423
|
-
`;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=>`
|
|
1424
1434
|
<tr>
|
|
1425
|
-
<td><a href="#/workflows/catalog/${encodeURIComponent(
|
|
1426
|
-
<td>${
|
|
1427
|
-
<td>${
|
|
1428
|
-
<td>${
|
|
1429
|
-
<td><code>${
|
|
1430
|
-
<td><code>${
|
|
1435
|
+
<td><a href="#/workflows/catalog/${encodeURIComponent(p.workflowId)}"><code>${F(p.workflowId)}</code></a></td>
|
|
1436
|
+
<td>${p.version}</td>
|
|
1437
|
+
<td>${F(t("catalog.paramSummary",{required:p.requiredParamCount,total:p.paramCount}))}</td>
|
|
1438
|
+
<td>${p.nodeCount}</td>
|
|
1439
|
+
<td><code>${F(es(p.revisionId))}</code></td>
|
|
1440
|
+
<td><code>${F(p.path)}</code></td>
|
|
1431
1441
|
</tr>
|
|
1432
|
-
`).join("")}async function
|
|
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=`
|
|
1433
1443
|
<div class="catalog-detail-head">
|
|
1434
|
-
<a class="btn-link" href="#/workflows/catalog">${
|
|
1444
|
+
<a class="btn-link" href="#/workflows/catalog">${F(t("catalog.back"))}</a>
|
|
1435
1445
|
<div>
|
|
1436
|
-
<h2><code>${
|
|
1437
|
-
<div id="catalog-detail-subtitle" class="muted">${
|
|
1446
|
+
<h2><code>${F(n)}</code></h2>
|
|
1447
|
+
<div id="catalog-detail-subtitle" class="muted">${F(t("workflow.detail.loading"))}</div>
|
|
1438
1448
|
</div>
|
|
1439
1449
|
</div>
|
|
1440
1450
|
<section id="catalog-error" class="hint-warn" hidden></section>
|
|
1441
1451
|
<section id="catalog-run-status" class="hint-ok" hidden></section>
|
|
1442
1452
|
<div id="catalog-detail-body"></div>
|
|
1443
|
-
`;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=`
|
|
1444
1454
|
<section class="wf-panel">
|
|
1445
|
-
<div class="wf-panel-title"><h3>${
|
|
1455
|
+
<div class="wf-panel-title"><h3>${F(t("catalog.summary"))}</h3></div>
|
|
1446
1456
|
<div class="wf-summary-grid">
|
|
1447
|
-
<div class="wf-summary-item"><span>${
|
|
1448
|
-
<div class="wf-summary-item"><span>${
|
|
1449
|
-
<div class="wf-summary-item"><span>${
|
|
1450
|
-
<div class="wf-summary-item"><span>${
|
|
1457
|
+
<div class="wf-summary-item"><span>${F(t("catalog.table.workflow"))}</span><strong><code>${F(L.workflowId)}</code></strong></div>
|
|
1458
|
+
<div class="wf-summary-item"><span>${F(t("catalog.table.version"))}</span><strong>${L.version}</strong></div>
|
|
1459
|
+
<div class="wf-summary-item"><span>${F(t("catalog.nodeCount"))}</span><strong>${Object.keys(L.nodes).length}</strong></div>
|
|
1460
|
+
<div class="wf-summary-item"><span>${F(t("catalog.path"))}</span><strong><code>${F(d.path)}</code></strong></div>
|
|
1451
1461
|
</div>
|
|
1452
1462
|
</section>
|
|
1453
1463
|
|
|
1454
1464
|
<section class="wf-panel">
|
|
1455
|
-
<div class="wf-panel-title"><h3>${
|
|
1465
|
+
<div class="wf-panel-title"><h3>${F(t("catalog.runPanel"))}</h3></div>
|
|
1456
1466
|
<form id="catalog-run-form" class="catalog-run-form">
|
|
1457
1467
|
<label>
|
|
1458
|
-
<span>${
|
|
1459
|
-
<textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${
|
|
1468
|
+
<span>${F(t("catalog.paramsJson"))}</span>
|
|
1469
|
+
<textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${F(t("catalog.paramsPlaceholder"))}">${F(x)}</textarea>
|
|
1460
1470
|
</label>
|
|
1461
1471
|
<div class="catalog-chat-grid">
|
|
1462
1472
|
<label>
|
|
1463
|
-
<span>${
|
|
1473
|
+
<span>${F(t("catalog.chatId"))}</span>
|
|
1464
1474
|
<input id="catalog-chat-id" type="text" autocomplete="off" />
|
|
1465
1475
|
</label>
|
|
1466
1476
|
<label>
|
|
1467
|
-
<span>${
|
|
1477
|
+
<span>${F(t("catalog.larkAppId"))}</span>
|
|
1468
1478
|
<input id="catalog-lark-app-id" type="text" autocomplete="off" />
|
|
1469
1479
|
</label>
|
|
1470
1480
|
</div>
|
|
1471
|
-
<div class="muted">${
|
|
1481
|
+
<div class="muted">${F(t("catalog.chatBindingHint"))}</div>
|
|
1472
1482
|
<div id="catalog-param-errors" class="catalog-param-errors" hidden></div>
|
|
1473
|
-
<button id="catalog-run-btn" type="submit" class="primary">${
|
|
1483
|
+
<button id="catalog-run-btn" type="submit" class="primary">${F(t("catalog.run"))}</button>
|
|
1474
1484
|
</form>
|
|
1475
1485
|
</section>
|
|
1476
1486
|
|
|
1477
1487
|
<section class="wf-panel">
|
|
1478
|
-
<div class="wf-panel-title"><h3>${
|
|
1479
|
-
${
|
|
1488
|
+
<div class="wf-panel-title"><h3>${F(t("catalog.paramsSchema"))}</h3></div>
|
|
1489
|
+
${ll(L.params)}
|
|
1480
1490
|
</section>
|
|
1481
1491
|
|
|
1482
1492
|
<section class="wf-panel">
|
|
1483
|
-
<div class="wf-panel-title"><h3>${
|
|
1484
|
-
<pre class="wf-io-pre">${
|
|
1493
|
+
<div class="wf-panel-title"><h3>${F(t("catalog.definitionJson"))}</h3></div>
|
|
1494
|
+
<pre class="wf-io-pre">${F(JSON.stringify(L,null,2))}</pre>
|
|
1485
1495
|
</section>
|
|
1486
|
-
`,
|
|
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])=>`
|
|
1487
1497
|
<article class="catalog-param">
|
|
1488
1498
|
<header>
|
|
1489
|
-
<code>${
|
|
1490
|
-
<span class="wf-status">${
|
|
1491
|
-
<span class="muted">${
|
|
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>
|
|
1492
1502
|
</header>
|
|
1493
|
-
${
|
|
1494
|
-
${"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>`:""}
|
|
1495
1505
|
</article>
|
|
1496
|
-
`).join("")}</div>`}var
|
|
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=`
|
|
1497
1507
|
<iframe
|
|
1498
1508
|
src="/game/index.html"
|
|
1499
1509
|
title="HD2D Office"
|
|
1500
1510
|
style="flex:1;width:100%;min-height:0;border:none;display:block;background:#0b0d12;"
|
|
1501
1511
|
allow="autoplay"
|
|
1502
|
-
></iframe>`}function k(
|
|
1512
|
+
></iframe>`}function k(p){let S=p.total||In,E=S?Math.min(100,Math.round(p.received/S*100)):0,C=p.state==="downloading",L=p.state==="error";e.innerHTML=`
|
|
1503
1513
|
<div style="margin:auto;text-align:center;max-width:440px;padding:32px;color:var(--fg,#e6e6e6);">
|
|
1504
1514
|
<div style="font-size:18px;font-weight:600;margin-bottom:8px;">HD2D \u529E\u516C\u5BA4</div>
|
|
1505
1515
|
<div style="font-size:13px;opacity:.7;line-height:1.7;margin-bottom:20px;">
|
|
1506
1516
|
\u628A\u6BCF\u4E2A\u4F1A\u8BDD\u53D8\u6210\u529E\u516C\u5BA4\u91CC\u7684\u4E00\u4E2A\u673A\u5668\u4EBA\uFF0C\u5B9E\u65F6\u6620\u5C04\u5C4F\u5E55\u72B6\u6001\u3002<br>
|
|
1507
1517
|
\u9996\u6B21\u8FDB\u5165\u9700\u4E0B\u8F7D\u7EA6 ${r(S)} MB \u6E38\u620F\u8D44\u6E90\uFF08\u4EC5\u4E00\u6B21\uFF0C\u4E4B\u540E\u672C\u5730\u7F13\u5B58\uFF09\u3002
|
|
1508
1518
|
</div>
|
|
1509
|
-
${L?`<div style="color:#e06c75;font-size:12px;margin-bottom:14px;">\u4E0A\u6B21\u4E0B\u8F7D\u5931\u8D25\uFF1A${i(
|
|
1510
|
-
${
|
|
1519
|
+
${L?`<div style="color:#e06c75;font-size:12px;margin-bottom:14px;">\u4E0A\u6B21\u4E0B\u8F7D\u5931\u8D25\uFF1A${i(p.error??"\u672A\u77E5\u9519\u8BEF")}<br><span style="opacity:.7;">\u586B\u4EE3\u7406\u540E\u70B9\u91CD\u8BD5</span></div>`:""}
|
|
1520
|
+
${C?`
|
|
1511
1521
|
<div style="background:rgba(127,127,127,.2);border-radius:6px;height:10px;overflow:hidden;margin-bottom:10px;">
|
|
1512
|
-
<div style="height:100%;width:${
|
|
1522
|
+
<div style="height:100%;width:${E}%;background:#4a9eff;transition:width .3s;"></div>
|
|
1513
1523
|
</div>
|
|
1514
|
-
<div style="font-size:12px;opacity:.7;">\u4E0B\u8F7D\u4E2D\u2026 ${r(
|
|
1524
|
+
<div style="font-size:12px;opacity:.7;">\u4E0B\u8F7D\u4E2D\u2026 ${r(p.received)} / ${r(S)} MB\uFF08${E}%\uFF09</div>
|
|
1515
1525
|
`:`
|
|
1516
|
-
<input id="hd2d-proxy" type="text" value="${i(
|
|
1526
|
+
<input id="hd2d-proxy" type="text" value="${i(s)}"
|
|
1517
1527
|
placeholder="HTTP \u4EE3\u7406\uFF08\u53EF\u9009\uFF0C\u5982 http://127.0.0.1:7890\uFF09"
|
|
1518
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;" />
|
|
1519
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>
|
|
@@ -1521,24 +1531,35 @@ ${Co("manage")}
|
|
|
1521
1531
|
${L?"\u91CD\u8BD5":"\u52A0\u8F7D\u529E\u516C\u5BA4"}\uFF08\u7EA6 ${r(S)} MB\uFF09
|
|
1522
1532
|
</button>
|
|
1523
1533
|
`}
|
|
1524
|
-
</div>`;let
|
|
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">
|
|
1525
1545
|
<img class="qr-image" src="${e.qrDataUrl}" alt="${t("botOnboarding.qrAlt")}">
|
|
1526
1546
|
${e.qrUrl?`<a class="onboarding-link" href="${i(e.qrUrl)}" target="_blank" rel="noopener">${t("botOnboarding.openLink")}</a>`:""}
|
|
1527
1547
|
</div>`:"",s=e.status==="waiting_for_platform_scan"&&e.platformQrDataUrl?`<div class="qr-card">
|
|
1528
1548
|
<img class="qr-image" src="${e.platformQrDataUrl}" alt="${t("botOnboarding.platformQrAlt")}">
|
|
1529
|
-
</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>
|
|
1530
1550
|
<header>
|
|
1531
1551
|
<h3>${t("botOnboarding.title")}</h3>
|
|
1532
1552
|
<p>${t("botOnboarding.intro")}</p>
|
|
1533
1553
|
</header>
|
|
1534
|
-
<p class="onboarding-status status-${e.status}">${
|
|
1554
|
+
<p class="onboarding-status status-${e.status}">${dl(e)}</p>
|
|
1535
1555
|
${a}
|
|
1536
1556
|
${s}
|
|
1537
|
-
${o}
|
|
1538
|
-
${dl(e)}
|
|
1539
1557
|
${r}
|
|
1558
|
+
${cl(e)}
|
|
1559
|
+
${ul(e,n)}
|
|
1560
|
+
${d}
|
|
1540
1561
|
<form method="dialog"><button>${t("botOnboarding.close")}</button></form>
|
|
1541
|
-
</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>
|
|
1542
1563
|
<header>
|
|
1543
1564
|
<h3>${t("botOnboarding.title")}</h3>
|
|
1544
1565
|
<p>${t("botOnboarding.intro")}</p>
|
|
@@ -1546,7 +1567,7 @@ ${Co("manage")}
|
|
|
1546
1567
|
<form id="onboarding-form" class="onboarding-form">
|
|
1547
1568
|
<label class="onboarding-field">
|
|
1548
1569
|
<span>${t("botOnboarding.cliLabel")}</span>
|
|
1549
|
-
<select id="ob-cli">${
|
|
1570
|
+
<select id="ob-cli">${a}</select>
|
|
1550
1571
|
</label>
|
|
1551
1572
|
<label class="onboarding-field">
|
|
1552
1573
|
<span>${t("botOnboarding.dirLabel")}</span>
|
|
@@ -1557,14 +1578,14 @@ ${Co("manage")}
|
|
|
1557
1578
|
<input id="ob-model" type="text" list="ob-model-suggestions" placeholder="${t("botOnboarding.modelPlaceholder")}" autocomplete="off" spellcheck="false">
|
|
1558
1579
|
<datalist id="ob-model-suggestions"></datalist>
|
|
1559
1580
|
</label>
|
|
1560
|
-
${
|
|
1581
|
+
${s}
|
|
1561
1582
|
<menu class="onboarding-actions">
|
|
1562
1583
|
<button type="button" id="ob-cancel">${t("botOnboarding.cancel")}</button>
|
|
1563
1584
|
<button type="submit" class="primary">${t("botOnboarding.startScan")}</button>
|
|
1564
1585
|
</menu>
|
|
1565
1586
|
</form>
|
|
1566
|
-
</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=`
|
|
1567
1588
|
<span class="attention-strip-ic" aria-hidden="true">!</span>
|
|
1568
1589
|
<b>${i(t("strip.pending",{count:n.length}))}</b>
|
|
1569
|
-
<span class="attention-strip-longest">${i(t("strip.longest",{time:
|
|
1570
|
-
<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()})();})();
|