botmux 2.84.1 → 2.85.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/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/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/dashboard/web/bot-defaults.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults.js +61 -1
- package/dist/dashboard/web/bot-defaults.js.map +1 -1
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +8 -0
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard-web/app.js +371 -361
- package/dist/dashboard.js +19 -0
- 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/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/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/worker.js +125 -20
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
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 a of n)this.sessions.set(a.sessionId,a);this.emit()}upsertSchedules(n){for(let a of n)this.schedules.set(a.id,a);this.emit()}applySse(n,a){if(n==="session.spawned")this.sessions.set(a.session.sessionId,a.session);else if(n==="session.update"){let s=this.sessions.get(a.sessionId);s&&this.sessions.set(a.sessionId,{...s,...a.patch})}else if(n==="session.exited"){let s=this.sessions.get(a.sessionId);s&&this.sessions.set(a.sessionId,{...s,status:"closed"})}else if(n==="schedule.created")this.schedules.set(a.schedule.id,a.schedule);else if(n==="schedule.updated"){let s=this.schedules.get(a.id);s&&this.schedules.set(a.id,{...s,...a.patch})}else if(n==="schedule.deleted")this.schedules.delete(a.id);else return;this.emit()}setOnline(n){this.online!==n&&(this.online=n,this.emit())}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}},Y=new Dn;async function Sa(){let[e,n]=await Promise.all([fetch("/api/sessions").then(o=>o.json()),fetch("/api/schedules").then(o=>o.json())]);Y.upsertSessions(e.sessions??[]),Y.upsertSchedules(n.schedules??[]);let a=new EventSource("/events"),s=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let o of s)a.addEventListener(o,r=>{try{let d=JSON.parse(r.data);Y.applySse(o,d.body??d)}catch{}});a.onerror=()=>Y.setOnline(!1),a.onopen=()=>Y.setOnline(!0)}var Rn="botmux.dashboard.locale",ws={"app.name":"botmux","app.subtitle":"\u98DE\u4E66 AI CLI \u63A7\u5236\u53F0","time.secondsAgo":"{value} \u79D2\u524D","time.minutesAgo":"{value} \u5206\u949F\u524D","time.hoursAgo":"{value} \u5C0F\u65F6\u524D","nav.overview":"\u603B\u89C8","nav.sessions":"\u4F1A\u8BDD","nav.sidebarCollapse":"\u6536\u8D77\u83DC\u5355\u680F","nav.sidebarExpand":"\u5C55\u5F00\u83DC\u5355\u680F","nav.groups":"\u7FA4\u7EC4","nav.schedules":"\u5B9A\u65F6","nav.settings":"\u8BBE\u7F6E","nav.botDefaults":"Bot \u914D\u7F6E","nav.skills":"Skills","status.live":"\u5B9E\u65F6\u8FDE\u63A5","status.disconnected":"\u8FDE\u63A5\u65AD\u5F00","status.system":"\u7CFB\u7EDF","status.light":"\u6D45\u8272","status.dark":"\u6697\u9ED1","status.language":"\u8BED\u8A00","status.theme":"\u4E3B\u9898","theme.base":"\u57FA\u7840","theme.skins":"\u4E3B\u9898\u76AE\u80A4","skin.cyber":"2077","skin.genshin":"\u539F\u795E","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"\u851A\u84DD\u6863\u6848","skin.zzz":"\u7EDD\u533A\u96F6","skin.dragonball":"\u4E03\u9F99\u73E0","skin.ikun":"ikun","botOnboarding.add":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.title":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.intro":"\u9009\u62E9 CLI \u4E0E\u5DE5\u4F5C\u76EE\u5F55\uFF0C\u626B\u7801\u521B\u5EFA PersonalAgent \u5E94\u7528\u540E\u5199\u5165\u672C\u673A bots.json\uFF0C\u5E76\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u3002","botOnboarding.cliLabel":"CLI \u9002\u914D\u5668","botOnboarding.dirLabel":"\u5DE5\u4F5C\u76EE\u5F55","botOnboarding.dirPlaceholder":"\u9ED8\u8BA4 ~\uFF08\u5BB6\u76EE\u5F55\uFF09\uFF0C\u9700\u4E3A daemon \u4E3B\u673A\u4E0A\u5DF2\u5B58\u5728\u7684\u76EE\u5F55","botOnboarding.modelLabel":"\u6A21\u578B\uFF08\u53EF\u9009\uFF09","botOnboarding.modelPlaceholder":"\u7559\u7A7A\u4F7F\u7528\u8BE5 CLI \u7684\u9ED8\u8BA4\u6A21\u578B","botOnboarding.modelTtadkPlaceholder":"ttadk \u7F51\u5173\u6A21\u578B\uFF0C\u9ED8\u8BA4 {model}\uFF0C\u53EF\u6539\uFF08\u968F\u65F6\u5728\u6B64\u8C03\u6574\uFF09","botOnboarding.modelTtadkCocoPlaceholder":"CoCo \u65E0\u9700\u6307\u5B9A\u6A21\u578B","botOnboarding.startScan":"\u5F00\u59CB\u626B\u7801","botOnboarding.cancel":"\u53D6\u6D88","botOnboarding.starting":"\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...","botOnboarding.waiting":"\u8BF7\u7528\u98DE\u4E66 App \u626B\u7801\u786E\u8BA4\u521B\u5EFA\u5E94\u7528\u3002","botOnboarding.verifying":"\u626B\u7801\u6210\u529F\uFF0C\u6B63\u5728\u6821\u9A8C\u51ED\u8BC1...","botOnboarding.configuringPermissions":"\u6B63\u5728\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u2026","botOnboarding.platformScanHint":"\u8BF7\u7528\u98DE\u4E66 App \u518D\u626B\u4E00\u6B21\u7801\u767B\u5F55\u5F00\u653E\u5E73\u53F0\uFF08\u7528\u4E8E\u81EA\u52A8\u5BFC\u5165\u6743\u9650\u3001\u914D\u7F6E\u56DE\u8C03\u3001\u63D0\u4EA4\u7248\u672C\uFF09\u3002","botOnboarding.platformQrAlt":"\u5F00\u653E\u5E73\u53F0\u767B\u5F55\u4E8C\u7EF4\u7801","botOnboarding.completed":"\u673A\u5668\u4EBA\u5DF2\u6DFB\u52A0\u3002","botOnboarding.permissionOk":"\u5DF2\u81EA\u52A8\u5BFC\u5165 {count} \u9879\u6743\u9650\u3002","botOnboarding.permissionSkipped":"\uFF08\u8DF3\u8FC7 {count} \u9879\u5F53\u524D\u79DF\u6237\u76EE\u5F55\u4E2D\u6CA1\u6709\u7684\u6743\u9650\uFF09","botOnboarding.permissionVersion":"\u5DF2\u63D0\u4EA4\u53D1\u5E03\u7248\u672C {version}\u3002","botOnboarding.permissionManual":"\u6743\u9650\u672A\u80FD\u81EA\u52A8\u914D\u7F6E\uFF0C\u8BF7\u624B\u52A8\u5B8C\u6210\u4EE5\u4E0B\u6B65\u9AA4\uFF1A","botOnboarding.metaDir":"\u76EE\u5F55","botOnboarding.failed":"\u6DFB\u52A0\u5931\u8D25","botOnboarding.openLink":"\u6253\u4E0D\u5F00\u626B\u7801\uFF1F\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00","botOnboarding.close":"\u5173\u95ED","botOnboarding.restartHint":"\u5DF2\u5199\u5165 bots.json\u3002\u6267\u884C pnpm daemon:restart \u540E\u65B0\u673A\u5668\u4EBA\u751F\u6548\u3002","botOnboarding.qrAlt":"\u98DE\u4E66\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA\u4E8C\u7EF4\u7801","overview.title":"\u5DE5\u4F5C\u53F0","overview.subtitle":"\u6570\u5B57\u5458\u5DE5\u5B9E\u65F6\u72B6\u6001 \xB7 \u540C\u6B65\u98DE\u4E66\u8BDD\u9898","overview.team":"AI \u56E2\u961F","overview.teamHint":"\u6BCF\u4F4D\u6570\u5B57\u5458\u5DE5\u7684\u5B9E\u65F6\u72B6\u6001","overview.attention":"\u9700\u8981\u4F60\u5904\u7406","overview.attentionHint":"\u5361\u4F4F\u7684\u4EFB\u52A1\uFF0C\u56DE\u4E2A\u8BDD\u5C31\u80FD\u7EE7\u7EED\u8DD1","overview.activeSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.activeSessionsHint":"\u6B63\u5728\u8FD0\u8F6C\u7684\u4F1A\u8BDD","overview.today":"\u6B64\u523B\u6982\u89C8","overview.todayHint":"\u6D3B\u8DC3\u4F1A\u8BDD\u5206\u5E03","overview.viewAll":"\u67E5\u770B\u5168\u90E8 \u2192","overview.botIdle":"\u5F85\u547D\u4E2D\uFF0C\u968F\u65F6\u53EF\u63A5\u65B0\u4EFB\u52A1","overview.botOffline":"\u79BB\u7EBF \u2014 daemon \u672A\u4E0A\u7EBF","overview.botBusy":"\u6267\u884C\u4E2D \xB7 {count} \u4F1A\u8BDD","overview.botNeedsYou":"\u7B49\u4F60\u56DE\u590D","overview.botReady":"\u5C31\u7EEA","overview.botOff":"\u79BB\u7EBF","overview.sessionsCount":"{count} \u4F1A\u8BDD","overview.lastActive":"{time}\u524D\u6D3B\u8DC3","overview.noAttention":"\u6CA1\u6709\u7B49\u4F60\u5904\u7406\u7684\u4E8B\u9879","overview.teamExpand":"\u5C55\u5F00\u5168\u90E8 {count} \u4F4D \u25BE","overview.teamCollapse":"\u6536\u8D77 \u25B4","strip.pending":"{count} \u4EF6\u5F85\u5904\u7406","strip.longest":"\u6700\u4E45\u5DF2\u7B49 {time} \u2014 {bot} {reason}","strip.handle":"\u7ACB\u5373\u5904\u7406","overview.openSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.workingSessions":"\u5DE5\u4F5C\u4E2D","overview.onlineBots":"\u5728\u7EBF Bot","overview.schedules":"\u5B9A\u65F6\u4EFB\u52A1","overview.groups":"\u7FA4\u804A\u8986\u76D6","overview.enabledSchedules":"\u5DF2\u542F\u7528","overview.total":"\u603B\u8BA1","overview.active":"\u6D3B\u8DC3","overview.daemonRegistry":"daemon \u6CE8\u518C\u8868","overview.chatMatrix":"\u7FA4\u804A\u77E9\u9635","overview.recentSessions":"\u6700\u8FD1\u4F1A\u8BDD","overview.nextSchedules":"\u5373\u5C06\u6267\u884C","overview.noSessions":"\u6682\u65E0\u4F1A\u8BDD\u3002","overview.noSchedules":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","sessions.title":"\u4F1A\u8BDD\u63A7\u5236","sessions.subtitle":"\u5B9A\u4F4D\u98DE\u4E66\u8BDD\u9898\u3001\u6253\u5F00 Web Terminal\u3001\u5173\u95ED\u6216\u6062\u590D CLI \u4F1A\u8BDD\u3002","sessions.search":"\u641C\u7D22\u5DE5\u4F5C\u76EE\u5F55 / \u6807\u9898 / ID","sessions.anyStatus":"\u5168\u90E8\u72B6\u6001","sessions.adoptAny":"adopt: \u5168\u90E8","sessions.adoptYes":"adopt: \u662F","sessions.adoptNo":"adopt: \u5426","sessions.activeOnly":"\u4EC5\u6D3B\u8DC3","sessions.closeSelected":"\u5173\u95ED\u9009\u4E2D","sessions.clearSelection":"\u53D6\u6D88\u9009\u62E9","sessions.selectedCount":"\u5DF2\u9009 {count} \u4E2A\u4F1A\u8BDD","sessions.bot":"bot","sessions.cli":"CLI","sessions.chat":"\u7FA4\u804A","sessions.openChat":"\u6253\u5F00\u7FA4\u804A","sessions.status":"\u72B6\u6001","sessions.tokenIn":"Token In","sessions.tokenOut":"Token Out","sessions.titleCol":"\u6807\u9898","sessions.workingDir":"\u5DE5\u4F5C\u76EE\u5F55","sessions.created":"\u521B\u5EFA","sessions.last":"\u6700\u8FD1","sessions.adopt":"\u63A5\u5165","sessions.actions":"\u64CD\u4F5C","sessions.details":"\u8BE6\u60C5","sessions.copy":"\u590D\u5236","sessions.copied":"\u5DF2\u590D\u5236","sessions.locate":"\u5B9A\u4F4D\u8BDD\u9898","sessions.locating":"\u53D1\u9001\u4E2D...","sessions.cooldown":"\u51B7\u5374 {seconds}s","sessions.openTerminal":"\u7EC8\u7AEF","sessions.writeLink":"\u64CD\u4F5C\u94FE\u63A5","sessions.writeLinkHint":"\u83B7\u53D6\u53EF\u64CD\u4F5C\u7EC8\u7AEF\u94FE\u63A5\uFF08\u5E26\u5199\u6743\u9650 token\uFF0C\u65B0\u6807\u7B7E\u6253\u5F00\uFF09","sessions.writeLinkFail":"\u83B7\u53D6\u64CD\u4F5C\u94FE\u63A5\u5931\u8D25","sessions.close":"\u5173\u95ED\u4F1A\u8BDD","sessions.resume":"\u6062\u590D\u4F1A\u8BDD","sessions.dismiss":"\u5173\u95ED","sessions.closeConfirm":"\u5173\u95ED\u8FD9\u4E2A\u4F1A\u8BDD\uFF1F","sessions.resumeFailed":"\u6062\u590D\u5931\u8D25","sessions.land":"\u843D\u76D8","sessions.landLoading":"\u52A0\u8F7D\u6C99\u76D2 diff\u2026","sessions.landUnavailable":"\u65E0\u6CD5\u843D\u76D8","sessions.landEmpty":"\u6C99\u76D2\u526F\u672C\u6CA1\u6709\u6539\u52A8\u3002","sessions.landApply":"\u5E94\u7528\u5230\u78C1\u76D8","sessions.landDiscard":"\u4E22\u5F03","sessions.landApplied":"\u5DF2\u843D\u76D8","sessions.landFailed":"\u843D\u76D8\u5931\u8D25","sessions.landDiscarded":"\u5DF2\u4E22\u5F03\uFF08\u6C99\u76D2\u526F\u672C\u672A\u5E94\u7528\uFF09\u3002","connectors.lede":"\u8BA9\u5916\u90E8\u7CFB\u7EDF\uFF08\u76D1\u63A7\u544A\u8B66\u3001CI\u3001\u5DE5\u5355\u2026\uFF09\u901A\u8FC7\u4E00\u4E2A webhook \u89E6\u53D1\u673A\u5668\u4EBA\u5728\u7FA4\u91CC\u8BF4\u8BDD\u6216\u8DD1\u5DE5\u4F5C\u6D41\u3002","connectors.createTitle":"\u65B0\u5EFA Webhook","connectors.fName":"\u540D\u79F0","connectors.fNamePh":"\u5982\uFF1A\u7EBF\u4E0A\u544A\u8B66","connectors.fBot":"\u89E6\u53D1\u7684\u673A\u5668\u4EBA","connectors.fKind":"\u89E6\u53D1\u65B9\u5F0F","connectors.kindTurn":"\u5355\u8F6E\u5BF9\u8BDD\uFF08\u8BA9\u673A\u5668\u4EBA\u56DE\u5E94\u4E00\u6B21\uFF09","connectors.kindWorkflow":"\u5DE5\u4F5C\u6D41","connectors.fWf":"\u5DE5\u4F5C\u6D41 ID","connectors.fMode":"\u6295\u9012\u5230\u54EA\u4E2A\u7FA4","connectors.modeDynamic":"\u7531\u8BF7\u6C42\u6307\u5B9A\uFF08\u7FA4\u968F\u8BF7\u6C42\u4F20\u5165\uFF09","connectors.modeFixed":"\u56FA\u5B9A\u7FA4","connectors.modeNewGroup":"\u6BCF\u6B21\u65B0\u5EFA\u7FA4","connectors.fFixedChat":"\u6295\u9012\u5230\u7684\u7FA4","connectors.fChatManualPh":"\u624B\u52A8\u586B\u7FA4 ID\uFF1Aoc_\u2026","connectors.chatManualLink":"\u627E\u4E0D\u5230\u7FA4\uFF1F\u624B\u52A8\u586B ID \u2192","connectors.chatListLink":"\u4ECE\u7FA4\u5217\u8868\u9009\u62E9 \u2190","connectors.fAllow":"\u5141\u8BB8\u7684\u7FA4","connectors.optional":"\uFF08\u53EF\u9009\uFF09","connectors.allowHint":"\u6309\u4F4F Ctrl/\u2318 \u591A\u9009\uFF1B\u7559\u7A7A = \u4E0D\u9650\u3002\u53EA\u7528\u4E8E\u6821\u9A8C\u8BF7\u6C42\u4F20\u5165\u7684\u7FA4\u662F\u5426\u88AB\u5141\u8BB8\u3002","connectors.dynamicHint":'<b>\u52A8\u6001\u6A21\u5F0F</b>\uFF1A\u7FA4 ID \u968F\u6BCF\u6B21\u8BF7\u6C42\u4F20\u5165\uFF0C\u4E09\u9009\u4E00 \u2014\u2014 \u67E5\u8BE2\u53C2\u6570 <code>?chatId=<\u7FA4ID></code> \xB7 \u8BF7\u6C42\u5934 <code>x-botmux-chat-id: <\u7FA4ID></code> \xB7 \u8BF7\u6C42\u4F53 <code>{"chatId":"<\u7FA4ID>"}</code>\u3002<br>\u60F3"\u4E00\u4E2A URL \u76F4\u63A5\u89E6\u53D1\u3001\u4E0D\u5E26\u53C2\u6570"\uFF0C\u8BF7\u6539\u9009\u300C\u56FA\u5B9A\u7FA4\u300D\u3002',"connectors.fDedup":"\u53BB\u91CD\u5B57\u6BB5","connectors.fDedupPh":"\u5982 alert.id\uFF08\u4ECE\u4E8B\u4EF6 body \u53D6\u503C\uFF09","connectors.dedupHint":"\u586B\u4E86\uFF1A\u547D\u4E2D\u76F8\u540C\u503C\u7684\u4E8B\u4EF6\u90FD\u6295\u5230<b>\u540C\u4E00\u4E2A\u7FA4</b>\u3002\u7559\u7A7A\uFF1A\u6BCF\u4E2A\u4E8B\u4EF6<b>\u65B0\u5EFA\u4E00\u4E2A\u7FA4</b>\u3002","connectors.fInstruction":"\u5904\u7406\u6307\u4EE4","connectors.fInstructionPh":"\u4E8B\u4EF6\u89E6\u53D1\u65F6\u8BA9\u673A\u5668\u4EBA\u505A\u4EC0\u4E48\u3002\u5982\uFF1A\u603B\u7ED3\u8FD9\u6761\u544A\u8B66\u7684\u4E25\u91CD\u7A0B\u5EA6\uFF0C@\u76F8\u5173 oncall\uFF0C\u7ED9\u51FA\u6392\u67E5\u5EFA\u8BAE\u3002\u7559\u7A7A = \u53EA\u628A\u4E8B\u4EF6\u539F\u6837\u4EA4\u7ED9\u6A21\u578B\u81EA\u7531\u53D1\u6325\u3002","connectors.fVerify":"\u6821\u9A8C\u65B9\u5F0F","connectors.verifyToken":"\u4EE4\u724C\uFF08\u7B80\u5355\uFF1A\u5BC6\u94A5\u653E\u8FDB URL\uFF0C\u4E00\u6761 curl \u5C31\u80FD\u89E6\u53D1\uFF09","connectors.verifyHmac":"HMAC \u7B7E\u540D\uFF08\u9AD8\u7EA7\uFF1A\u66F4\u5B89\u5168\uFF0C\u9700\u81EA\u884C\u5BF9\u8BF7\u6C42\u7B7E\u540D\uFF09","connectors.fSecret":"\u5BC6\u94A5 / \u4EE4\u724C","connectors.fSecretPh":"\u7559\u7A7A\u81EA\u52A8\u751F\u6210\uFF08\u53EA\u663E\u793A\u4E00\u6B21\uFF09","connectors.btnCreate":"\u521B\u5EFA","connectors.listTitle":"\u5DF2\u6709 Webhook","connectors.loading":"\u52A0\u8F7D\u4E2D\u2026","connectors.noBotGroups":"\uFF08\u8BE5\u673A\u5668\u4EBA\u6682\u65E0\u53EF\u89C1\u7FA4\uFF0C\u70B9\u53F3\u4FA7\u624B\u52A8\u586B ID\uFF09","connectors.modeLabelFixed":"\u56FA\u5B9A\u7FA4","connectors.modeLabelNewGroup":"\u6BCF\u6B21\u65B0\u5EFA\u7FA4","connectors.modeLabelDynamic":"\u8BF7\u6C42\u6307\u5B9A\u7FA4","connectors.kindLabelWorkflow":"\u5DE5\u4F5C\u6D41","connectors.kindLabelTurn":"\u5355\u8F6E","connectors.count":"\xB7 {count} \u4E2A","connectors.empty":"\u8FD8\u6CA1\u6709 Webhook\u3002\u7528\u4E0A\u9762\u7684\u8868\u5355\u521B\u5EFA\u4E00\u4E2A\u3002","connectors.enabled":"\u5DF2\u542F\u7528","connectors.disabled":"\u5DF2\u505C\u7528","connectors.badgeToken":"\u4EE4\u724C","connectors.badgeSign":"\u7B7E\u540D","connectors.dest":"\u6295\u9012\u300C{name}\u300D","connectors.btnDisable":"\u505C\u7528","connectors.btnEnable":"\u542F\u7528","connectors.btnDel":"\u5220\u9664","connectors.webhookUrl":"Webhook URL\uFF1A","connectors.copy":"\u590D\u5236","connectors.copied":"\u5DF2\u590D\u5236","connectors.tokenHint":"\u4EE4\u724C\u6A21\u5F0F\uFF1A\u8C03\u7528\u65F6\u5728 URL \u672B\u5C3E\u8FFD\u52A0 <code>/<\u4EE4\u724C></code>\uFF08\u4EE4\u724C\u4EC5\u521B\u5EFA/\u8F6E\u6362\u65F6\u663E\u793A\u4E00\u6B21\uFF09\u3002","connectors.dynamicReqHint":'\u52A8\u6001\u6A21\u5F0F\uFF1A\u8BF7\u6C42\u9700\u5E26\u76EE\u6807\u7FA4 \u2014\u2014 <code>?chatId=<\u7FA4ID></code> \u6216\u5934 <code>x-botmux-chat-id</code> \u6216 body <code>{"chatId":"\u2026"}</code>\u3002',"connectors.instructionPrefix":"\u5904\u7406\u6307\u4EE4\uFF1A","connectors.delConfirm":"\u5220\u9664\u8FD9\u4E2A Webhook\uFF1F\u5B83\u7684 URL \u4F1A\u7ACB\u5373\u5931\u6548\u3002","connectors.errName":"\u8BF7\u586B\u540D\u79F0","connectors.errBot":"\u8BF7\u9009\u673A\u5668\u4EBA","connectors.errWf":"\u8BF7\u586B\u5DE5\u4F5C\u6D41 ID","connectors.errChat":"\u8BF7\u9009\u62E9\uFF08\u6216\u624B\u52A8\u586B\uFF09\u6295\u9012\u7684\u7FA4","connectors.creating":"\u521B\u5EFA\u4E2D\u2026","connectors.usageDynamicLede":"\u52A8\u6001\u6A21\u5F0F\uFF1AURL \u5DF2\u542B\u4EE4\u724C\uFF0C\u8C03\u7528\u65F6\u518D\u5E26\u4E0A\u76EE\u6807\u7FA4 ID{gn}\uFF1A","connectors.usageDynamicNote":'\u7FA4\u4E5F\u53EF\u653E\u8BF7\u6C42\u5934 <code>x-botmux-chat-id</code> \u6216 body <code>{"chatId":"\u2026"}</code>\u3002\u26A0\uFE0F URL \u5373\u51ED\u8BC1\uFF0C\u52FF\u6CC4\u6F0F\u3002',"connectors.usageTokenLede":"\u6B64 URL \u5DF2\u542B\u4EE4\u724C\u3001\u4E14\u56FA\u5B9A\u6295\u9012\u5230\u6240\u9009\u7FA4\uFF0C\u76F4\u63A5 POST \u5373\u53EF\u89E6\u53D1\uFF1A","connectors.usageTokenNote":"\u26A0\uFE0F URL \u5373\u51ED\u8BC1\uFF0C\u8BF7\u52FF\u516C\u5F00\u6CC4\u6F0F\uFF1B\u53EF\u5728\u4E0B\u65B9\u5217\u8868\u5220\u9664\u6216\u8F6E\u6362\u3002","connectors.usageHmac":"\u5916\u90E8\u7CFB\u7EDF\u9700\u5BF9 <code>timestamp.body</code> \u505A HMAC-SHA256 \u7B7E\u540D\uFF0C\u5E76\u5E26\u4E0A <code>x-botmux-timestamp</code> / <code>x-botmux-nonce</code> / <code>x-botmux-signature</code> \u5934\u8C03\u7528","connectors.usageHmacDynamic":"\uFF0C\u540C\u65F6\u6309\u4E0A\u9762\u65B9\u5F0F\u5E26\u76EE\u6807\u7FA4 ID","connectors.createdPrefix":"\u5DF2\u521B\u5EFA\u300C{name}\u300D","connectors.createdDest":"\u6295\u9012\u5230\u300C{name}\u300D","connectors.tokenLabel":"\u8BBF\u95EE\u4EE4\u724C","connectors.signLabel":"\u7B7E\u540D\u5BC6\u94A5","connectors.secretOnce":"\uFF08\u53EA\u663E\u793A\u8FD9\u4E00\u6B21\uFF0C\u8BF7\u4FDD\u5B58\uFF09\uFF1A","connectors.createFailed":"\u521B\u5EFA\u5931\u8D25\uFF1A{error}","connectors.noOnlineBots":"\uFF08\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF09","team.navHome":"\u6211\u7684\u56E2\u961F","team.navManage":"\u56E2\u961F\u7BA1\u7406","team.eyebrow":"\u56E2\u961F","team.homeTitle":"\u56E2\u961F\u534F\u4F5C\uFF08\u8DE8\u90E8\u7F72\uFF09","team.homeLede":"\u628A\u522B\u7684\u90E8\u7F72\uFF08\u540C\u4E8B\u81EA\u5DF1\u8DD1\u7684 botmux\uFF09\u9080\u8BF7\u8FDB\u540C\u4E00\u4E2A\u56E2\u961F\uFF0C\u4E92\u76F8\u53D1\u73B0\u673A\u5668\u4EBA\u3001\u534F\u4F5C\u62C9\u7FA4\u3002","team.localDeployTitle":"\u672C\u90E8\u7F72","team.myIdentity":"\u6211\u7684\u98DE\u4E66\u8EAB\u4EFD\uFF1A","team.unbound":"\u672A\u7ED1\u5B9A","team.bindBtn":"\u7ED1\u5B9A","team.bindHint":"\uFF08\u7528\u673A\u5668\u4EBA\u51ED\u8BC1\u81EA\u52A8\u8BC6\u522B\u4F60\uFF1B\u7ED1\u5B9A\u540E\u62C9\u7FA4\u4F1A\u628A\u4F60\u62C9\u8FDB\u7FA4\u3001\u673A\u5668\u4EBA\u4E5F\u5F52\u5230\u4F60\u540D\u4E0B\uFF09","team.myTeams":"\u6211\u7684\u56E2\u961F","team.searchPh":"\u641C\u7D22 \u540D\u79F0/\u80FD\u529B/CLI\u2026","team.allCli":"\u5168\u90E8 CLI","team.hasCap":"\u6709\u80FD\u529B\u6807\u7B7E","team.hasRole":"\u6709\u9ED8\u8BA4\u89D2\u8272","team.teamsHint":"\u6BCF\u4E2A\u56E2\u961F\u91CC\u52FE\u9009\u673A\u5668\u4EBA\u5373\u53EF\u5355\u72EC\u62C9\u7FA4\uFF08\u81EA\u52A8\u5E26\u4E0A\u5404\u81EA\u8D1F\u8D23\u4EBA\uFF09\u3002\u8981\u65B0\u5EFA\u56E2\u961F / \u751F\u6210\u9080\u8BF7\u7801 / \u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\uFF0C\u53BB\u300C\u56E2\u961F\u7BA1\u7406\u300D\u3002","team.loading":"\u52A0\u8F7D\u4E2D\u2026","team.roleModalTitle":"\u9ED8\u8BA4\u89D2\u8272","team.roleModalHint":"\u8BE5\u673A\u5668\u4EBA\u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF08\u8DE8\u7FA4\u751F\u6548\uFF09\uFF0C\u6B64\u5904\u53EA\u8BFB\u3002\u5982\u9700\u4FEE\u6539\uFF0C\u8BF7\u5230\u300CBot \u914D\u7F6E\u300D\u9875\u3002","team.close":"\u5173\u95ED","team.tagLocal":"\u672C\u90E8\u7F72","team.tagRemoteStale":"\u8FDC\u7AEF\xB7\u79BB\u7EBF\uFF1F","team.tagRemote":"\u8FDC\u7AEF","team.removeMember":"\u79FB\u9664","team.depTag":"\uFF08{tag}\uFF09","team.depCount":"{count} \u4E2A","team.depSelected":"\uFF0C\u5DF2\u9009 {n}","team.capPh":"\u80FD\u529B\u6807\u7B7E\u2026","team.viewRole":"\u67E5\u770B","team.hasRoleShort":"\u6709\u89D2\u8272","team.noMatch":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u673A\u5668\u4EBA\u3002","team.gnamePh":"\u7FA4\u540D\uFF08\u5982\uFF1A\u8DE8\u56E2\u961F\u6392\u969C\uFF09","team.pullGroupBtn":"\u628A\u52FE\u9009\u7684\u673A\u5668\u4EBA\u62C9\u4E00\u4E2A\u7FA4","team.pullGroupHint":"\u52FE\u9009\u673A\u5668\u4EBA \u2192 \u62C9\u5230\u4E00\u4E2A\u98DE\u4E66\u7FA4\uFF08\u81EA\u52A8\u542B owner\uFF09","team.noTeams":"\u8FD8\u6CA1\u6709\u56E2\u961F\u3002\u53BB\u300C\u56E2\u961F\u7BA1\u7406\u300D\u751F\u6210\u9080\u8BF7\u7801\u8BA9\u522B\u4EBA\u52A0\u5165\u4F60\uFF0C\u6216\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\u3002","team.connected":"\u5DF2\u8FDE\u63A5","team.connectFail":"\u8FDE\u63A5\u5931\u8D25\uFF1A{error}","team.iHost":"\u6211\u6258\u7BA1","team.teamMeta":"{deps} \u4E2A\u90E8\u7F72 \xB7 {bots} \u4E2A\u673A\u5668\u4EBA","team.rosterFail":"\u65E0\u6CD5\u83B7\u53D6\u8BE5\u56E2\u961F\u82B1\u540D\u518C\u3002","team.acrossTeams":"\uFF08\u8DE8 {n} \u4E2A\u56E2\u961F\uFF0C\u53BB\u91CD\uFF09","team.botsWord":"\u4E2A\u673A\u5668\u4EBA","team.groupCreated":"\u7FA4\u5DF2\u521B\u5EFA","team.delegatedBy":"\uFF08\u7531\u300C{name}\u300D\u5EFA\u7FA4\uFF09","team.openInLark":"\u5728\u98DE\u4E66\u6253\u5F00","team.invalidBots":"\u672A\u52A0\u5165\u7684\u673A\u5668\u4EBA\uFF1A{ids}","team.invalidOwners":"{n} \u4E2A owner \u672A\u80FD\u62C9\u8FDB","team.missingIdentity":"\u4F60\u672A\u7ED1\u5B9A\u98DE\u4E66\u8EAB\u4EFD\uFF0C\u6CA1\u628A\u4F60\u81EA\u5DF1\u62C9\u8FDB\u7FA4\uFF08\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u7ED1\u5B9A\uFF09","team.skippedNoOwner":"{n} \u4E2A\u673A\u5668\u4EBA\u56E0\u8D1F\u8D23\u4EBA\u672A\u7ED1\u5B9A\u8EAB\u4EFD\u88AB\u8DF3\u8FC7\uFF08\u672A\u52A0\u5165\u7FA4\uFF09","team.errNoLocalBot":"\u8BF7\u81F3\u5C11\u52FE\u9009\u4E00\u4E2A\u4F60\u81EA\u5DF1\uFF08\u672C\u90E8\u7F72\uFF09\u7684\u5728\u7EBF\u673A\u5668\u4EBA\u2014\u2014\u7FA4\u8981\u7531\u5B83\u521B\u5EFA\u5E76\u628A\u4F60\uFF08\u53D1\u8D77\u4EBA\uFF09\u62C9\u8FDB\u7FA4\u3002","team.errAllSkipped":"\u6240\u9009\u673A\u5668\u4EBA\u7684\u8D1F\u8D23\u4EBA\u90FD\u6CA1\u7ED1\u5B9A\u8EAB\u4EFD\uFF0C\u65E0\u6CD5\u62C9\u7FA4\uFF08\u673A\u5668\u4EBA\u4E0D\u80FD\u8FDB\u4E00\u4E2A owner \u4E0D\u5728\u7684\u7FA4\uFF09\u3002\u8BF7\u8BA9\u5BF9\u5E94\u90E8\u7F72\u5148\u7ED1\u5B9A\u8EAB\u4EFD\u3002","team.errNoCreator":"\u6CA1\u6709\u53EF\u7528\u7684\u5EFA\u7FA4\u53D1\u8D77\u65B9\uFF08\u76F8\u5173\u90E8\u7F72\u90FD\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF0C\u6216\u4E0D\u53EF\u8FBE\uFF09","team.errDelegationTimeout":"\u59D4\u6258\u5BF9\u65B9\u90E8\u7F72\u5EFA\u7FA4\u8D85\u65F6\uFF08\u53EF\u80FD\u5DF2\u5EFA\uFF0C\u53BB\u98DE\u4E66\u786E\u8BA4\uFF0C\u52FF\u91CD\u590D\u70B9\uFF09","team.errGroupCreate":"\u5EFA\u7FA4\u5931\u8D25\uFF1A{error}","team.roleModalTitleName":"\u9ED8\u8BA4\u89D2\u8272 \xB7 {name}","team.bound":"\u5DF2\u7ED1\u5B9A","team.myHostedTeam":"\u6211\u6258\u7BA1\u7684\u56E2\u961F","team.remoteTeamLabel":"{name} \u7684\u56E2\u961F","team.manageTitle":"\u56E2\u961F\u7BA1\u7406","team.manageLede":"\u521B\u5EFA\u591A\u4E2A\u56E2\u961F\u3001\u7ED9\u6BCF\u4E2A\u56E2\u961F\u751F\u6210\u9080\u8BF7\u7801\u3001\u6216\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\u3002\u4E00\u4E2A\u56E2\u961F = \u4F60\u672C\u90E8\u7F72\u7684\u673A\u5668\u4EBA + \u52A0\u5165\u8BE5\u56E2\u961F\u7684\u5176\u5B83\u90E8\u7F72\u3002","team.hostedTitle":"\u6211\u6258\u7BA1\u7684\u56E2\u961F","team.newTeamPh":"\u65B0\u56E2\u961F\u540D\u79F0","team.createTeamBtn":"\u521B\u5EFA\u56E2\u961F","team.joinTitle":"\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F","team.hubPh":"Hub \u5730\u5740\uFF0C\u5982 http://10.0.0.5:7891","team.codePh":"\u9080\u8BF7\u7801","team.joinBtn":"\u52A0\u5165","team.noTeamsShort":"\u8FD8\u6CA1\u6709\u56E2\u961F\u3002","team.default":"\u9ED8\u8BA4","team.manageMetaDeps":"{count} \u4E2A\u90E8\u7F72","team.manageMetaRemote":"\uFF08\u542B {r} \u8FDC\u7AEF\uFF09","team.manageMetaBots":"{count} \u4E2A\u673A\u5668\u4EBA","team.genInvite":"\u751F\u6210\u9080\u8BF7\u7801","team.delBtn":"\u5220\u9664","team.generating":"\u751F\u6210\u4E2D\u2026","team.inviteResultLede":"\u628A\u4E0B\u9762\u4E24\u9879\u53D1\u7ED9\u522B\u7684\u90E8\u7F72\u7684\u4EBA\uFF0824 \u5C0F\u65F6\u5185\u3001\u5355\u6B21\u6709\u6548\uFF09\uFF1A","team.inviteHub":"Hub \u5730\u5740\uFF1A","team.inviteCode":"\u9080\u8BF7\u7801\uFF1A","team.genFail":"\u751F\u6210\u5931\u8D25\u3002","team.delConfirm":"\u5220\u9664\u56E2\u961F\u300C{name}\u300D\uFF1F\u5DF2\u52A0\u5165\u5B83\u7684\u90E8\u7F72\u4F1A\u88AB\u79FB\u9664\uFF08\u4E0D\u5F71\u54CD\u4ED6\u4EEC\u81EA\u5DF1\u7684\u90E8\u7F72\uFF09\u3002","team.errName":"\u8BF7\u586B\u56E2\u961F\u540D\u79F0","team.creating":"\u521B\u5EFA\u4E2D\u2026","team.created":"\u5DF2\u521B\u5EFA","team.createFail":"\u521B\u5EFA\u5931\u8D25\uFF1A{error}","team.errHubCode":"\u8BF7\u586B Hub \u5730\u5740\u548C\u9080\u8BF7\u7801\u3002","team.joining":"\u52A0\u5165\u4E2D\u2026","team.joined":"\u5DF2\u52A0\u5165\u300C{name}\u300D\uFF0C\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u67E5\u770B\u3002","team.joinErrSelf":"\u8FD9\u662F\u4F60\u81EA\u5DF1\u7684\u90E8\u7F72\uFF0C\u4E0D\u80FD\u52A0\u5165\u81EA\u5DF1\uFF08\u9080\u8BF7\u7801\u8981\u53D1\u7ED9\u522B\u7684\u90E8\u7F72\u7684\u4EBA\u7528\uFF09","team.joinErrAlready":"\u4F60\u7684\u90E8\u7F72\u5DF2\u7ECF\u52A0\u5165\u8FC7\u8FD9\u4E2A\u56E2\u961F\u4E86","team.joinErrUnreachable":"\u8FDE\u4E0D\u4E0A\u5BF9\u65B9 Hub\uFF08\u68C0\u67E5\u5730\u5740/\u7F51\u7EDC\uFF09","team.joinErrTimeout":"\u5BF9\u65B9 Hub \u54CD\u5E94\u8D85\u65F6","team.joinErrGeneric":"\u52A0\u5165\u5931\u8D25\uFF1A{error}","team.identifying":"\u8BC6\u522B\u4E2D\u2026","team.bound2":"\u5DF2\u7ED1\u5B9A\uFF1A{name}","team.multiCandidate":"\u8BC6\u522B\u5230\u591A\u4E2A\u5019\u9009\uFF0C\u70B9\u4F60\u81EA\u5DF1\uFF1A","team.binding":"\u7ED1\u5B9A\u4E2D\u2026","team.bindFail":"\u7ED1\u5B9A\u5931\u8D25\uFF1A{error}","team.noCandidates":"\u6CA1\u8BC6\u522B\u5230\u8EAB\u4EFD\uFF1A\u8BF7\u786E\u8BA4\u673A\u5668\u4EBA\u914D\u7F6E\u4E86 allowedUsers\uFF08\u5141\u8BB8\u4F7F\u7528\u8005\uFF09\uFF0C\u4E14\u673A\u5668\u4EBA\u6709\u901A\u8BAF\u5F55\u6743\u9650\u3002","team.removeMemberConfirm":"\u628A\u300C{name}\u300D\u79FB\u51FA\u8FD9\u4E2A\u56E2\u961F\uFF1F\u5B83\u7684\u673A\u5668\u4EBA\u5C06\u4ECE\u672C\u56E2\u961F\u82B1\u540D\u518C\u6D88\u5931\uFF08\u4E0D\u5F71\u54CD\u5BF9\u65B9\u81EA\u5DF1\u7684\u90E8\u7F72\uFF09\u3002","team.creatingGroup":"\u5EFA\u7FA4\u4E2D\u2026","team.defaultGroupName":"\u534F\u4F5C\u7FA4","team.errPickBot":"\u8BF7\u5148\u52FE\u9009\u81F3\u5C11\u4E00\u4E2A\u673A\u5668\u4EBA","sessions.closeBulkConfirm":"\u5173\u95ED\u9009\u4E2D\u7684 {count} \u4E2A\u4F1A\u8BDD\uFF1F","sessions.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u4F1A\u8BDD\u3002","sessions.viewMode":"\u4F1A\u8BDD\u89C6\u56FE","sessions.viewKanban":"\u770B\u677F","sessions.viewBoard":"\u72B6\u6001\u677F","sessions.viewTable":"\u8868\u683C","sessions.selectSession":"\u9009\u62E9\u4F1A\u8BDD","sessions.board.needsYou":"\u9700\u8981\u4F60","sessions.board.needsYouHint":"\u7B49\u5F85\u4ED3\u5E93\u3001TUI \u9009\u62E9\u6216\u989D\u5EA6\u5904\u7406","sessions.board.starting":"\u542F\u52A8\u4E2D","sessions.board.startingHint":"CLI \u6B63\u5728\u521B\u5EFA\u6216\u6062\u590D","sessions.board.working":"\u5E72\u6D3B\u4E2D","sessions.board.workingHint":"\u6B63\u5728\u8F93\u51FA\u3001\u5206\u6790\u6216\u6267\u884C\u5DE5\u5177","sessions.board.idle":"\u7A7A\u95F2","sessions.board.idleHint":"\u53EF\u7EE7\u7EED\u5BF9\u8BDD\u6216\u63A5\u65B0\u4EFB\u52A1","sessions.board.emptyColumn":"\u6682\u65E0\u4F1A\u8BDD","sessions.board.signalRepo":"\u5F85\u9009\u4ED3\u5E93","sessions.board.signalPrompt":"\u7B49\u5F85 TUI \u9009\u62E9","sessions.board.signalLimited":"\u989D\u5EA6\u53D7\u9650","sessions.board.signalAgent":"\u9700\u8981\u4EBA\u5DE5\u4ECB\u5165","sessions.board.waiting":"\u7B49\u5F85","sessions.board.dragHint":"\u62D6\u52A8\u5217\u5934\u8C03\u6574\u5217\u987A\u5E8F","sessions.board.moveLeft":"\u5DE6\u79FB\u6B64\u5217","sessions.board.moveRight":"\u53F3\u79FB\u6B64\u5217","sessions.kanban.backlog":"\u5F85\u529E\u6C60","sessions.kanban.todo":"\u5F85\u529E","sessions.kanban.inProgress":"\u8FDB\u884C\u4E2D","sessions.kanban.inReview":"\u5F85\u786E\u8BA4","sessions.kanban.done":"\u5DF2\u5B8C\u6210","sessions.kanban.updated":"\u66F4\u65B0\u4E8E {time}","sessions.kanban.moreHidden":"\u8FD8\u6709 {count} \u4E2A\u672A\u663E\u793A","sessions.kanban.openTab":"\u65B0\u6807\u7B7E\u9875\u6253\u5F00","sessions.kanban.openFeishu":"\u6253\u5F00\u98DE\u4E66","sessions.kanban.terminalLoading":"\u6B63\u5728\u6253\u5F00\u7EC8\u7AEF\u2026","sessions.kanban.rename":"\u91CD\u547D\u540D\uFF08\u53CC\u51FB\u6807\u9898\u4E5F\u53EF\uFF09","sessions.kanban.renameFail":"\u91CD\u547D\u540D\u5931\u8D25","sessions.kanban.moveFail":"\u79FB\u52A8\u5931\u8D25","sessions.kanban.groupBy":"\u5206\u7EC4\u7EF4\u5EA6","sessions.kanban.groupFlow":"\u5DE5\u4F5C\u6D41","sessions.kanban.groupTeam":"\u56E2\u961F","sessions.kanban.groupBot":"\u673A\u5668\u4EBA","sessions.kanban.teamLoading":"\u6B63\u5728\u52A0\u8F7D\u56E2\u961F\u2026","sessions.kanban.noTeam":"\u6682\u65E0\u56E2\u961F","sessions.kanban.teamScope":"{chats} \u4E2A\u534F\u4F5C\u7FA4 \xB7 {sessions} \u4E2A\u4F1A\u8BDD","sessions.kanban.remoteHint":"\u6765\u81EA {name} \u90E8\u7F72\u7684\u4F1A\u8BDD\uFF08\u5FEB\u7167\uFF0C\u7EC8\u7AEF/\u5386\u53F2\u5728\u5BF9\u65B9\u673A\u5668\u4E0A\uFF09","sessions.kanban.clusterDragHint":"\u62D6\u52A8\u6807\u9898\u6574\u7EC4\u79FB\u52A8","sessions.history.title":"\u4F1A\u8BDD\u5386\u53F2","sessions.history.loading":"\u6B63\u5728\u62C9\u53D6\u98DE\u4E66\u6D88\u606F\u2026","sessions.history.fail":"\u5386\u53F2\u62C9\u53D6\u5931\u8D25","sessions.history.empty":"\u6CA1\u6709\u6D88\u606F","sessions.history.user":"\u7528\u6237","sessions.history.owner":"\u521B\u5EFA\u8005","sessions.history.staleHint":"dashboard \u6216 daemon \u8FDB\u7A0B\u53EF\u80FD\u8FD8\u5728\u8DD1\u65E7\u7248\u672C\uFF0Cbotmux restart \u540E\u91CD\u8BD5","groups.title":"\u7FA4\u7EC4\u4E0E Bot","groups.subtitle":"\u67E5\u770B chat x bot \u8986\u76D6\u77E9\u9635\uFF0C\u7BA1\u7406\u62C9\u7FA4\u3001oncall\u3001\u9000\u7FA4\u548C\u89E3\u6563\u3002","groups.search":"\u641C\u7D22\u7FA4\u540D / ID / owner","groups.missingOnly":"\u4EC5\u7F3A bot","groups.refresh":"\u5237\u65B0","groups.create":"\u65B0\u5EFA\u7FA4","groups.chat":"\u7FA4\u804A","groups.actions":"\u64CD\u4F5C","groups.addBots":"\u6DFB\u52A0 bot","groups.manage":"\u7BA1\u7406","groups.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u7FA4\u804A\u3002","groups.createTitle":"\u65B0\u5EFA\u7FA4\u804A","groups.createHelp":"\u9009\u62E9\u8981\u9080\u8BF7\u7684 bot\u3002dashboard \u4F1A\u81EA\u52A8\u9009\u62E9\u5728\u7EBF daemon \u4F5C\u4E3A\u521B\u5EFA\u8005\u3002","groups.name":"\u7FA4\u540D","groups.namePlaceholder":"\u4F8B\u5982 AI ChangeLog","groups.bindDir":"\u7ED1\u5B9A\u76EE\u5F55","groups.bindDirHelp":"\u65B0\u8BDD\u9898\u76F4\u63A5\u7528\u8BE5\u76EE\u5F55\u542F\u52A8 CLI\uFF0C\u8DF3\u8FC7 repo \u9009\u62E9\u3002","groups.botPicker":"Bot","groups.createSubmit":"\u521B\u5EFA","groups.cancel":"\u53D6\u6D88","groups.successTitle":"\u7FA4\u521B\u5EFA\u6210\u529F","groups.openGroup":"\u6253\u5F00\u65B0\u7FA4","groups.manageTitle":"\u7BA1\u7406 {name}","groups.owner":"\u7FA4\u4E3B","groups.oncall":"Oncall \u6A21\u5F0F","groups.oncallHelp":"\u5F00\u542F\u540E\uFF0C\u7FA4\u5185\u6210\u5458\u53EF @ \u673A\u5668\u4EBA\uFF1B\u65B0\u8BDD\u9898\u76F4\u63A5\u4F7F\u7528\u7ED1\u5B9A\u76EE\u5F55\u3002","groups.leaveTitle":"\u9009\u62E9\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.leaveSelected":"\u9009\u4E2D\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.disband":"\u89E3\u6563\u7FA4\u804A","groups.dangerHint":"\u89E3\u6563\u4EC5\u5F53\u5728\u7FA4\u673A\u5668\u4EBA\u662F\u7FA4\u4E3B\u65F6\u624D\u4F1A\u6210\u529F\uFF0C\u5426\u5219\u5EFA\u8BAE\u4F7F\u7528\u9000\u51FA\u7FA4\u804A\u3002","groups.save":"\u4FDD\u5B58","groups.needWorkingDir":"\u8BF7\u586B\u5DE5\u4F5C\u76EE\u5F55","groups.noBotsOnline":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u8BF7\u5148\u91CD\u542F daemon\u3002","schedules.title":"\u5B9A\u65F6\u4EFB\u52A1","schedules.subtitle":"\u8DE8 daemon \u67E5\u770B\u3001\u6682\u505C\u3001\u6062\u590D\u548C\u7ACB\u5373\u89E6\u53D1\u5B9A\u65F6\u4EFB\u52A1\u3002","schedules.search":"\u641C\u7D22\u540D\u79F0 / prompt / \u5DE5\u4F5C\u76EE\u5F55","schedules.anyKind":"\u5168\u90E8\u7C7B\u578B","schedules.enabledOnly":"\u4EC5\u542F\u7528","schedules.name":"\u540D\u79F0","schedules.bot":"bot","schedules.schedule":"\u89C4\u5219","schedules.next":"\u4E0B\u6B21","schedules.last":"\u4E0A\u6B21","schedules.repeat":"\u91CD\u590D","schedules.enabled":"\u542F\u7528","schedules.actions":"\u64CD\u4F5C","schedules.runNow":"\u7ACB\u5373\u8FD0\u884C","schedules.pause":"\u6682\u505C","schedules.resume":"\u6062\u590D","schedules.delivery":"\u6295\u9012","schedules.deliveryOrigin":"\u539F\u8BDD\u9898","schedules.deliveryNewTopic":"\u6BCF\u6B21\u65B0\u8BDD\u9898","schedules.deliveryLocal":"\u4EC5\u8BB0\u5F55","schedules.useNewTopic":"\u6539\u4E3A\u6BCF\u6B21\u65B0\u8BDD\u9898","schedules.useOrigin":"\u6539\u4E3A\u539F\u8BDD\u9898","schedules.empty":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","settings.title":"\u5168\u5C40\u8BBE\u7F6E","settings.subtitle":"\u7BA1\u7406\u672C\u673A botmux dashboard \u4E0E\u6240\u6709 bot \u5171\u4EAB\u7684\u5168\u5C40\u884C\u4E3A\u3002","settings.loading":"\u6B63\u5728\u52A0\u8F7D\u8BBE\u7F6E\u2026","settings.loadFailed":"\u8BBE\u7F6E\u52A0\u8F7D\u5931\u8D25","settings.readOnlyVisitor":"\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u4FEE\u6539\u8BBE\u7F6E\u9700\u8981\u6388\u6743\u94FE\u63A5\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09","settings.sectionAccess":"\u8BBF\u95EE\u6743\u9650","settings.publicReadOnly":"\u5141\u8BB8\u65E0 token \u53EA\u8BFB\u8BBF\u95EE dashboard","settings.publicReadOnlyHelp":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 token \u7684\u8BBF\u95EE\u8005\u53EF\u4EE5\u67E5\u770B dashboard\u3001\u4F1A\u8BDD\u3001\u5B9A\u65F6\u4EFB\u52A1\u548C SSE\uFF1B\u5173\u95ED\u3001\u6682\u505C\u3001\u5BA1\u6279\u7B49\u5199\u64CD\u4F5C\u4ECD\u5FC5\u987B\u901A\u8FC7 token \u9274\u6743\u3002\u654F\u611F\u7EC8\u7AEF\u539F\u59CB\u65E5\u5FD7\u59CB\u7EC8\u9700\u8981 token\u3002","settings.sectionCards":"\u98DE\u4E66\u5361\u7247","settings.openTerminalInFeishu":"\u6D41\u5F0F\u5361\u7247\u7EC8\u7AEF\u6309\u94AE\u5728\u98DE\u4E66\u4FA7\u680F\u6253\u5F00","settings.openTerminalInFeishuHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF1A\u7EC8\u7AEF\u6309\u94AE\u76F4\u63A5\u6253\u5F00 Web Terminal URL\u3002\u5F00\u542F\u540E\u4F7F\u7528\u98DE\u4E66 web_url/open \u5305\u88C5\uFF0C\u5728\u98DE\u4E66 PC \u4FA7\u680F\u91CC\u6253\u5F00\uFF1B\u5199\u6743\u9650\u4ECD\u7531\u7EC8\u7AEF token \u63A7\u5236\u3002","settings.sectionRepoPicker":"\u4ED3\u5E93\u9009\u62E9","settings.repoPickerMode":"\u4ED3\u5E93\u9009\u62E9\u5361\u6A21\u5F0F","settings.repoPickerModeAll":"\u4ED3\u5E93 + worktree","settings.repoPickerModeRepos":"\u4EC5\u4E3B\u4ED3\u5E93","settings.repoPickerModeHelp":"\u9ED8\u8BA4\u663E\u793A\u4ED3\u5E93\u548C linked worktree\u3002\u9009\u62E9\u300C\u4EC5\u4E3B\u4ED3\u5E93\u300D\u540E\uFF0C\u521D\u59CB\u5316\u548C\u88F8 /repo \u7684\u9009\u62E9\u5361\u53EA\u5217\u4E3B\u4ED3\u5E93\uFF1B\u663E\u5F0F /repo /abs/path/to/worktree \u4ECD\u53EF\u76F4\u8FBE worktree\u3002","settings.saving":"\u4FDD\u5B58\u4E2D\u2026","settings.saved":"\u5DF2\u4FDD\u5B58","settings.saveFailed":"\u4FDD\u5B58\u5931\u8D25","settings.sectionMaintenance":"\u81EA\u52A8\u7EF4\u62A4","settings.autoUpdate":"\u81EA\u52A8\u66F4\u65B0","settings.autoUpdateHelp":"\u9ED8\u8BA4\u5173\u95ED\u3002\u5230\u70B9\u6267\u884C npm install -g botmux@latest \u5B89\u88C5\u6700\u65B0\u7248\u672C\uFF08\u53EA\u4E0B\u8F7D\u5B89\u88C5\u3001\u672C\u8EAB\u4E0D\u91CD\u542F\uFF09\u3002\u4EC5 npm \u5168\u5C40\u5B89\u88C5\u53EF\u7528\u3002","settings.autoRestart":"\u81EA\u52A8\u91CD\u542F","settings.autoRestartHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF0C\u9700\u5148\u5F00\u542F\u81EA\u52A8\u66F4\u65B0\u3002\u81EA\u52A8\u66F4\u65B0\u88C5\u5230\u65B0\u7248\u672C\u540E\uFF0C\u82E5\u6CA1\u6709\u8FDB\u884C\u4E2D\u7684\u4F1A\u8BDD\u5219\u81EA\u52A8\u91CD\u542F\u4EE5\u751F\u6548\uFF08\u649E\u4E0A\u5FD9\u788C\u4F1A\u8BDD\u5219\u8DF3\u5230\u6B21\u65E5\uFF09\u3002","settings.autoUpdateLocalDev":"\u5F53\u524D\u4E3A\u672C\u5730\u5F00\u53D1\u5B89\u88C5\uFF08\u4ECE\u6E90\u7801\u8FD0\u884C\uFF09\uFF0C\u81EA\u52A8\u66F4\u65B0\u4E0D\u53EF\u7528\u3002","settings.maintenanceTime":"\u65F6\u95F4","skills.title":"Skill \u7BA1\u7406","skills.subtitle":"\u7BA1\u7406 botmux \u7684 CLI \u65E0\u5173 Skill \u8D44\u4EA7\uFF0C\u5E76\u6309 bot \u9009\u62E9\u4F18\u5148\u62AB\u9732\u3002","skills.installed":"\u5DF2\u5B89\u88C5 Skills","skills.installedHelp":"\u672C\u673A registry \u4E2D\u53EF\u88AB bot \u4F18\u5148\u62AB\u9732\u7684 Skill \u8D44\u4EA7\u3002","skills.overviewTitle":"\u6309 Bot \u7EC4\u7EC7 Skill \u8D44\u4EA7","skills.overviewBody":"\u5168\u5C40 Skill \u6CE8\u5165\u914D\u7F6E\u63A7\u5236\u4F1A\u8BDD\u6CE8\u5165\u7B56\u7565\uFF1B\u6BCF\u4E2A bot \u53EA\u7EF4\u62A4\u81EA\u5DF1\u7684\u4F18\u5148\u62AB\u9732\u5217\u8868\u3002","skills.metricInstalled":"\u5DF2\u5B89\u88C5 Skills","skills.metricBots":"\u5DF2\u914D\u7F6E Bot","skills.metricAttached":"\u4F18\u5148\u5F15\u7528","skills.install":"\u5B89\u88C5 Skill","skills.installInfoLabel":"\u5B89\u88C5\u4F4D\u7F6E\u8BF4\u660E","skills.installInfo":`\u6CE8\u518C: ~/.botmux/skills/registry.json
|
|
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
|
|
@@ -10,15 +10,15 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
10
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
|
|
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"},La={zh:ws,en:vs};function nn(e){if(typeof e!="string")return null;let n=e.trim().toLowerCase();return n==="zh"||n.startsWith("zh-")?"zh":n==="en"||n.startsWith("en-")?"en":null}function ks(e=[]){for(let n of e){let a=nn(n);if(a)return a}return"zh"}function an(e){return(n,a)=>{let s=La[e][n]??La.zh[n]??n;return a?s.replace(/\{(\w+)\}/g,(o,r)=>{let d=a[r];return d==null?`{${r}}`:String(d)}):s}}function Ta(e,n){return(e?nn(e.getItem(Rn)):null)??ks(n)}var Pn="botmux.dashboard.theme",Ia="botmux.dashboard.sessions.view";function $s(e){return e==="system"||e==="light"||e==="dark"?e:null}function Bn(e){return e==="kanban"||e==="board"||e==="table"?e:null}function Ma(e,n){return e==="system"?n?"dark":"light":e}function Ea(e){return $s(e?.getItem(Pn))??"dark"}function xa(e){return Bn(e?.getItem(Ia))??"board"}var Ha="botmux.dashboard.sessions.boardOrder",jt=["needs-you","starting","working","idle"];function Ss(e){if(!Array.isArray(e)||e.length!==jt.length)return null;let n=new Set(e);if(n.size!==e.length)return null;for(let a of jt)if(!n.has(a))return null;return e.slice()}function Ca(e){try{let n=e?.getItem(Ha);return n?Ss(JSON.parse(n))??[...jt]:[...jt]}catch{return[...jt]}}function On(e,n){try{e?.setItem(Ha,JSON.stringify(n))}catch{}}function Aa(e,n){try{e?.setItem(Ia,n)}catch{}}var Da="botmux.dashboard.sessions.kanbanGroupBy",Nn="botmux.dashboard.sessions.kanbanTeam";function Ls(e){return e==="flow"||e==="team"||e==="bot"?e:null}function Ra(e){return Ls(e?.getItem(Da))??"flow"}function Pa(e,n){try{e?.setItem(Da,n)}catch{}}var Ba="botmux.dashboard.sidebar";function Ts(e){return e==="expanded"||e==="collapsed"?e:null}function Oa(e){return Ts(e?.getItem(Ba))??"expanded"}function Na(e,n){try{e?.setItem(Ba,n)}catch{}}var Is=["default","cyber","genshin","fallout","prts","bluearchive","zzz","dragonball","ikun"],qn="botmux.dashboard.skin";function Ms(e){return typeof e=="string"&&Is.includes(e)?e:null}function qa(e){return Ms(e?.getItem(qn))??"default"}var Es="\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF830123456789\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E$#%&@*+=<>/\\",ja=["186 100% 60%","56 97% 60%","330 100% 64%","150 80% 58%"],Un=[{key:"shake",dur:280},{key:"rgb",dur:340},{key:"tear",dur:400},{key:"invert",dur:220},{key:"slice",dur:320},{key:"blackout",dur:260}],Ua=["ESTABLISHING NETLINK","BYPASSING ICE","DECRYPTING DATAFLOW","SYNCING BOTMUX TELEMETRY","ACCESS GRANTED"],Fa="0123456789ABCDEF#<>*/=+\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C",xs=3200,Ut=[],Et=0,on=0;function _n(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function Fn(e,n){let a="";for(let s=0;s<e;s++)a+=n[Math.floor(Math.random()*n.length)];return a}function Hs(e){let n=document.createElement("div");n.className="cyber-rain";let a=Math.max(10,Math.min(26,Math.round(window.innerWidth/70)));for(let s=0;s<a;s++){let o=document.createElement("span");o.className="cyber-rain-col",o.textContent=Fn(28+Math.floor(Math.random()*22),Es);let r=ja[Math.floor(Math.random()*ja.length)];o.style.cssText=`left:${(s+.5)/a*100}%;--rc:${r};--sz:${10+Math.floor(Math.random()*9)}px;--op:${(.25+Math.random()*.45).toFixed(2)};--dur:${(6+Math.random()*9).toFixed(1)}s;--delay:${(-Math.random()*12).toFixed(1)}s;`,n.appendChild(o)}e.appendChild(n)}function Cs(){if(_n())return;let e=document.body,n=()=>{let a=Un[Math.floor(Math.random()*Un.length)],s=`cp-fx-${a.key}`;e.classList.add(s),Ut.push(window.setTimeout(()=>e.classList.remove(s),a.dur)),Ut.push(window.setTimeout(n,2400+Math.random()*4200))};Ut.push(window.setTimeout(n,1800+Math.random()*2600))}function As(){Ut.forEach(e=>window.clearTimeout(e)),Ut=[];for(let e of Un)document.body.classList.remove(`cp-fx-${e.key}`)}function Ds(){if(_n()||document.getElementById("cyber-boot"))return;let e=document.createElement("div");e.id="cyber-boot",e.className="cyber-boot",e.setAttribute("aria-hidden","true"),e.innerHTML='<div class="cyber-boot-grid"></div><div class="cyber-loader"><div class="cyber-loader-frame"><div class="cyber-loader-head"><span>KIROSHI NETLINK</span><span class="cyber-loader-jp">\u4FB5\u5165\u4E2D</span></div><div class="cyber-loader-line"><span class="cyber-loader-prompt">></span><span class="cyber-loader-text"></span><span class="cyber-loader-cursor">_</span></div><div class="cyber-loader-stream"></div></div></div>',document.body.appendChild(e);let n=e.querySelector(".cyber-loader-text"),a=e.querySelector(".cyber-loader-stream"),s=0,o=0,r=0;Et=window.setInterval(()=>{let d=Ua[s];n&&(o<d.length?(o+=1,n.textContent=d.slice(0,o)+Fn(d.length-o,Fa),n.classList.remove("done")):r<16?(r+=1,n.textContent=d,n.classList.add("done")):(s=(s+1)%Ua.length,o=0,r=0)),a&&(a.textContent=Fn(26,Fa))},50),on=window.setTimeout(()=>{window.clearInterval(Et),Et=0,e.remove()},xs)}function Rs(){Et&&(window.clearInterval(Et),Et=0),on&&(window.clearTimeout(on),on=0),document.getElementById("cyber-boot")?.remove()}var Ps=320,Ga=16,Ft=!0,Mt=0,jn=0,sn=!1,rn=[],Gn=[];function Bs(){if(sn)return;sn=!0,Ft=!1,Mt=0;let e=_n(),n="";for(let s=0;s<Ga;s++){let o=s%3===0?"186 100% 52%":s%3===1?"330 100% 58%":"56 97% 52%",r=(s%2===0?1:-1)*(8+s%5*7);n+=`<span class="cyber-breach-shard" style="top:${s/Ga*100}%;height:${2+s%4*3}%;--shift:${r}px;--delay:${s%8*.09}s;--dur:${(.36+s%5*.12).toFixed(2)}s;--hue:${o}"></span>`}let a=document.createElement("div");a.id="cyber-breach",a.className="cyber-breach",a.setAttribute("aria-hidden","true"),a.innerHTML=`<span class="cyber-breach-flash"></span><span class="cyber-breach-grid"></span><div class="cyber-breach-shards">${n}</div><div class="cyber-breach-banner"><span class="cyber-breach-tag">// BREACH PROTOCOL \u2014 SYSTEM OVERRIDE</span><span class="cyber-breach-caption" data-text="SYSTEM BREACH">SYSTEM BREACH</span><span class="cyber-breach-sub" data-text="NETWATCH OVERRIDE ENGAGED">NETWATCH OVERRIDE ENGAGED</span></div>`,document.body.appendChild(a),e||document.body.classList.add("cyber-breach-quake"),rn.push(window.setTimeout(()=>document.body.classList.remove("cyber-breach-quake"),760)),rn.push(window.setTimeout(()=>{a.remove(),sn=!1},e?2600:4200))}function Os(){Ft=!0,Mt=0;let e=document.documentElement,n=()=>e.scrollHeight-(window.innerHeight+window.scrollY)<=4,a=k=>{k<=0||!n()||(Mt+=k,Mt>Ps&&Ft&&Bs())},s=k=>a(k.deltaY),o=k=>{jn=k.touches[0]?.clientY??0},r=k=>{let $=k.touches[0]?.clientY??0,M=jn-$;jn=$,a(M)},d=()=>{n()||(Mt=0,Ft=!0)},m=(k,$)=>{window.addEventListener(k,$,{passive:!0}),Gn.push([k,$])};m("wheel",s),m("touchstart",o),m("touchmove",r),m("scroll",d)}function Ns(){for(let[e,n]of Gn)window.removeEventListener(e,n);Gn=[],rn.forEach(e=>window.clearTimeout(e)),rn=[],document.body.classList.remove("cyber-breach-quake"),document.getElementById("cyber-breach")?.remove(),sn=!1,Ft=!0,Mt=0}function _a(e,n=!1){if(!(typeof document>"u")){if(!e){document.getElementById("cyber-fx")?.remove(),document.getElementById("cyber-hud")?.remove(),document.getElementById("cyber-glitch")?.remove(),As(),Rs(),Ns();return}if(!document.getElementById("cyber-fx")){let a=document.createElement("div");a.id="cyber-fx",a.className="cyber-fx",a.setAttribute("aria-hidden","true"),a.innerHTML='<div class="cyber-fx-grid"></div><div class="cyber-fx-scan"></div><span class="cyber-flicker"></span><span class="cyber-rollline"></span>',Hs(a),document.body.appendChild(a);let s=document.createElement("div");s.id="cyber-hud",s.className="cyber-hud",s.setAttribute("aria-hidden","true"),s.innerHTML='<span class="cyber-hud-corner tl"></span><span class="cyber-hud-corner tr"></span><span class="cyber-hud-corner bl"></span><span class="cyber-hud-corner br"></span><span class="cyber-hud-tag">NIGHT CITY // NETWATCH</span>',document.body.appendChild(s);let o=document.createElement("div");o.id="cyber-glitch",o.className="cyber-glitch",o.setAttribute("aria-hidden","true"),document.body.appendChild(o),Cs(),Os()}n&&Ds()}}var qs={genshin:2e3,zzz:1900,dragonball:1900,ikun:1900},js='<span class="si-bball" aria-hidden="true"><span class="si-bball-seams"><svg viewBox="0 0 100 100"><g fill="none" stroke="#3a1d08" stroke-width="3.4" stroke-linecap="round"><path d="M50 4V96"/><path d="M4 50H96"/><path d="M50 4 Q14 50 50 96"/><path d="M50 4 Q86 50 50 96"/></g></svg></span></span>';function Us(e){switch(e){case"genshin":return'<span class="si-gi-shine" aria-hidden="true"></span><span class="si-gi-text">\u539F\u795E\uFF0C\u542F\u52A8</span>';case"zzz":return'<span class="si-static" aria-hidden="true"></span><span class="si-roll" aria-hidden="true"></span><span class="si-now">NOW LOADING</span>';case"dragonball":return'<span class="si-speed" aria-hidden="true"></span><img class="si-cloud" src="/assets/skins/dragonball-wukong.webp" alt="">';case"ikun":return js;default:return""}}function Fs(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function za(e){if(typeof document>"u"||Fs())return;let n=qs[e];if(!n)return;document.getElementById("skin-intro")?.remove();let a=document.createElement("div");a.id="skin-intro",a.className=`skin-intro si-${e}`,a.setAttribute("aria-hidden","true"),a.style.setProperty("--si-dur",`${n}ms`),a.innerHTML=Us(e),document.body.appendChild(a),window.setTimeout(()=>a.remove(),n+80)}var Wn=class{locale="zh";themeMode="system";resolvedTheme="light";skin="default";authed=!0;listeners=new Set;translate=an(this.locale);mediaQuery=null;init(){let n=typeof window<"u"?window:void 0;this.locale=Ta(n?.localStorage,_s()),this.translate=an(this.locale),this.themeMode=Ea(n?.localStorage),this.skin=qa(n?.localStorage),this.mediaQuery=n?.matchMedia?.("(prefers-color-scheme: dark)")??null,this.mediaQuery?.addEventListener("change",()=>{this.applyTheme(),this.emit()}),this.applyTheme(),this.applySkin(),this.applyLocale()}t(n,a){return this.translate(n,a)}setLocale(n){this.locale!==n&&(this.locale=n,this.translate=an(n),window.localStorage.setItem(Rn,n),this.applyLocale(),this.emit())}get theme(){return this.skin==="default"?this.themeMode:this.skin}setTheme(n){let a=n==="system"||n==="light"||n==="dark",s=a?"default":n,o=s!==this.skin;a&&this.themeMode!==n&&(this.themeMode=n,window.localStorage.setItem(Pn,this.themeMode)),o&&(this.skin=s,window.localStorage.setItem(qn,this.skin)),this.applyTheme(),this.applySkin(o),this.emit()}on(n){return this.listeners.add(n),()=>this.listeners.delete(n)}emit(){for(let n of this.listeners)n()}applyTheme(){this.resolvedTheme=Ma(this.themeMode,!!this.mediaQuery?.matches);let n=this.skin==="default"?this.resolvedTheme:Gs[this.skin];document.documentElement.dataset.theme=n,document.documentElement.dataset.themeMode=this.themeMode}applySkin(n=!1){document.documentElement.dataset.skin=this.skin,_a(this.skin==="cyber",n),n&&this.skin!=="cyber"&&this.skin!=="default"&&za(this.skin)}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}},Gs={default:"light",cyber:"dark",genshin:"light",fallout:"dark",prts:"dark",bluearchive:"dark",zzz:"dark",dragonball:"light",ikun:"dark"};function _s(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var Te=new Wn;function t(e,n){return Te.t(e,n)}function i(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function qe(e){if(!e)return"-";let n=Date.now()-e;return n<6e4?t("common.now"):n<36e5?Math.floor(n/6e4)+"m":n<864e5?Math.floor(n/36e5)+"h":Math.floor(n/864e5)+"d"}var Wa=[{c1:"#5be3ff",c2:"#4f8bff"},{c1:"#b89bff",c2:"#6b4df0"},{c1:"#7ce0c3",c2:"#2e9e8f"},{c1:"#8fb4ff",c2:"#3b62d8"},{c1:"#ffd28f",c2:"#d8783b"},{c1:"#7df0a8",c2:"#1f9e63"},{c1:"#9fd0ff",c2:"#4878c8"},{c1:"#ff9fb8",c2:"#d84a78"}];function Ka(e){let n=0,a=String(e??"");for(let r=0;r<a.length;r++)n=n*31+a.charCodeAt(r)>>>0;let{c1:s,c2:o}=Wa[n%Wa.length];return`--c1:${s};--c2:${o}`}var ln=new Map,dn=new Map;function zs(e,n){return n?ln.get(n):e?dn.get(String(e)):void 0}function ue(e){let n=e.name??"",a=e.avatarUrl??zs(e.name,e.larkAppId),s=e.size==="sm"?" orb-avatar-sm":"",o=a?" orb-has-img":"",r=e.dot?`<i class="orb-dot orb-dot-${e.dot}"></i>`:"",d=a?`<img class="orb-img" src="${i(a)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar${s}${o}" style="${Ka(n)}" aria-hidden="true">${d}${r}</span>`}function Ws(e){return e?pn.get(e):void 0}function cn(e){let n=e.name??e.chatId??"",a=e.avatarUrl??Ws(e.chatId),s=e.size==="sm"?" orb-avatar-sm":"",o=a?" orb-has-img":"",r=a?`<img class="orb-img" src="${i(a)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.closest('.orb-avatar')?.classList.remove('orb-has-img');this.remove()"/>`:"";return`<span class="orb-avatar orb-square${s}${o}" style="${Ka(n)}" aria-hidden="true">${r}</span>`}var Gt=new Map,un=new Map,pn=new Map,zn=null,Ja="botmux.avatarCache.v1";function Ks(){try{let e=typeof window<"u"?window.localStorage.getItem(Ja):null;if(!e)return;let n=JSON.parse(e);for(let[a,s]of Object.entries(n.botByAppId??{}))ln.set(a,s);for(let[a,s]of Object.entries(n.botByName??{}))dn.set(a,s);for(let[a,s]of Object.entries(n.chatById??{}))pn.set(a,s);for(let[a,s]of Object.entries(n.nameByAppId??{}))Gt.set(a,s);for(let[a,s]of Object.entries(n.chatNameById??{}))un.set(a,s)}catch{}}function Js(){try{if(typeof window>"u")return;window.localStorage.setItem(Ja,JSON.stringify({botByAppId:Object.fromEntries(ln),botByName:Object.fromEntries(dn),chatById:Object.fromEntries(pn),nameByAppId:Object.fromEntries(Gt),chatNameById:Object.fromEntries(un)}))}catch{}}Ks();function Ke(){return zn??=(async()=>{try{let e=await fetch("/api/groups");if(!e.ok)throw new Error(`HTTP ${e.status}`);let n=await e.json();for(let a of n.bots??[])a.larkAppId&&a.botName&&a.botName!==a.larkAppId&&Gt.set(a.larkAppId,String(a.botName)),a.botAvatarUrl&&(a.larkAppId&&ln.set(a.larkAppId,String(a.botAvatarUrl)),a.botName&&dn.set(String(a.botName),String(a.botAvatarUrl)));for(let a of n.chats??[])a.chatId&&a.name&&un.set(a.chatId,String(a.name)),a.chatId&&a.avatar&&pn.set(a.chatId,String(a.avatar));Js()}catch{zn=null}})(),zn}function Va(e){return e?Gt.get(e):void 0}function ke(e){let n=e.larkAppId?Gt.get(e.larkAppId):void 0;return n||(e.botName&&e.botName!==e.larkAppId?String(e.botName):String(e.botName??e.larkAppId??"-"))}function lt(e){return e.chatId&&un.get(e.chatId)||null}function $e(e){let n=String(e??"");return n.replace(/^(?:@\S+\s*)+/,"").trim()||n}function dt(e){return`<div class="page-loading" role="status"><i class="page-loading-spin" aria-hidden="true"></i>${i(e??t("common.loading"))}</div>`}function ct(e){return e.status==="closed"?null:e.agentAttention?.reason?e.agentAttention.reason:e.agentAttention?t("sessions.board.signalAgent"):e.pendingRepo?t("sessions.board.signalRepo"):e.tuiPromptActive?t("sessions.board.signalPrompt"):e.status==="limited"?t("sessions.board.signalLimited"):null}function Ce(e){let n=Number(e.agentAttention?.at??e.lastMessageAt??0);if(Number.isFinite(n))return n;let a=Number(e.lastMessageAt??0);return Number.isFinite(a)?a:0}var Xa={chats:[],bots:[]};async function Vs(){try{let e=await fetch("/api/groups");if(!e.ok)return;Xa=await e.json()}catch{}}var Kn=new Set(["working","analyzing","active","starting"]);function Ys(e){let n=new Map,a=o=>{let r=n.get(o);return r||(r={botName:o,larkAppId:o,cliId:"unknown",online:!1,sessions:[],active:[],busy:[],attention:[],lastActiveAt:0},n.set(o,r)),r};for(let o of Xa.bots??[]){let r=a(o.larkAppId??o.botName??"-");r.online=!0,o.botName&&(r.botName=o.botName),o.botAvatarUrl&&(r.botAvatarUrl=o.botAvatarUrl)}let s=[...e].sort((o,r)=>+(o.status==="closed")-+(r.status==="closed"));for(let o of s){let r=o.larkAppId??o.botName??"-";if(o.status==="closed"&&!n.has(r))continue;let d=a(r);o.botName&&(d.botName===d.larkAppId||!d.botName)&&(d.botName=o.botName),d.sessions.push(o),o.cliId&&d.cliId==="unknown"&&(d.cliId=o.cliId),d.lastActiveAt=Math.max(d.lastActiveAt,Number(o.lastMessageAt??0)),o.status!=="closed"&&(d.active.push(o),Kn.has(o.status)&&d.busy.push(o),ct(o)&&d.attention.push(o))}for(let o of n.values())if(o.botName===o.larkAppId){let r=Va(o.larkAppId);r&&(o.botName=r)}return[...n.values()].sort((o,r)=>{let d=m=>m.attention.length?0:m.busy.length?1:m.online||m.active.length?2:3;return d(o)!==d(r)?d(o)-d(r):r.lastActiveAt-o.lastActiveAt})}var Za="botmux.overview.teamExpanded",Qs=230,Ya=13,Qa=2;function Xs(e){let n=e.clientWidth;return n?Math.max(1,Math.floor((n+Ya)/(Qs+Ya)))*Qa:Qa*3}function Zs(){try{return window.localStorage.getItem(Za)==="1"}catch{return!1}}function ei(e){try{window.localStorage.setItem(Za,e?"1":"0")}catch{}}function ti(e){let n=!e.online&&e.active.length===0,a=e.attention.length>0,s=e.busy.length>0,o=a?"warn":s?"busy":n?"off":"ok",r;if(a){let m=[...e.attention].sort((k,$)=>Ce(k)-Ce($))[0];r=`<b>${i(($e(m.title)||m.sessionId).slice(0,60))}</b> \xB7 ${i(ct(m)??"")}`}else if(s){let m=[...e.busy].sort((k,$)=>Number($.lastMessageAt??0)-Number(k.lastMessageAt??0))[0];r=`<b>${i(($e(m.title)||m.sessionId).slice(0,60))}</b>`}else n?r=i(t("overview.botOffline")):r=i(t("overview.botIdle"));let d=a?`<span class="tag tag-warn">${i(t("overview.botNeedsYou"))}</span>`:s?`<span class="tag tag-run">${i(t("overview.botBusy",{count:e.busy.length}))}</span>`:n?`<span class="tag tag-off">${i(t("overview.botOff"))}</span>`:`<span class="tag tag-ok">${i(t("overview.botReady"))}</span>`;return`<article class="mate${a?" mate-attn":""}${n?" mate-off":""}">
|
|
20
20
|
<div class="mate-top">
|
|
21
|
-
${
|
|
21
|
+
${ue({name:e.botName,larkAppId:e.larkAppId,avatarUrl:e.botAvatarUrl,dot:o})}
|
|
22
22
|
<div class="mate-id">
|
|
23
23
|
<b>${i(e.botName)}</b>
|
|
24
24
|
<span class="mate-role">${i(e.cliId)}</span>
|
|
@@ -27,26 +27,26 @@ 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 ni(e){let n=
|
|
33
|
-
${
|
|
32
|
+
</article>`}function ni(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(ct(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(lt(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
46
|
</li>`}function oi(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
52
|
</li>`}function si(e,n,a){let s=e+n+a;if(s===0)return`<div class="donut-wrap"><div class="donut" style="background:conic-gradient(var(--border) 0 360deg)"></div>
|
|
@@ -108,15 +108,15 @@ 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"),a=e.querySelector("#team-grid"),s=e.querySelector("#team-toggle"),o=Zs();s.onclick=()=>{o=!o,ei(o),$()};let r=e.querySelector("#attention-list"),d=e.querySelector("#recent-sessions"),
|
|
112
|
-
<span class="pill">${i(t("overview.workingSessions"))} <b>${
|
|
111
|
+
</section>`;let n=e.querySelector("#overview-pills"),a=e.querySelector("#team-grid"),s=e.querySelector("#team-toggle"),o=Zs();s.onclick=()=>{o=!o,ei(o),$()};let r=e.querySelector("#attention-list"),d=e.querySelector("#recent-sessions"),m=e.querySelector("#today-donut"),k=e.querySelector("#next-schedules");function $(){let y=[...Y.sessions.values()],p=y.filter(w=>w.status!=="closed"),S=p.filter(w=>ct(w)).sort((w,A)=>Ce(w)-Ce(A)),E=p.filter(w=>Kn.has(w.status)&&!ct(w)),C=p.length-S.length-E.length,L=Ys(y),x=L.filter(w=>w.online||w.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=Xs(a),R=o?L:L.slice(0,T);a.innerHTML=R.length?R.map(ti).join(""):`<div class="empty">${t("overview.noSessions")}</div>`,L.length>T?(s.hidden=!1,s.textContent=o?t("overview.teamCollapse"):t("overview.teamExpand",{count:L.length})):s.hidden=!0,r.innerHTML=S.length?S.map(ni).join(""):`<div class="qcard qcard-empty">${t("overview.noAttention")}</div>`;let q=p.filter(w=>Kn.has(w.status)||w.status==="idle").sort((w,A)=>Number(A.lastMessageAt??0)-Number(w.lastMessageAt??0)).slice(0,7);d.innerHTML=q.length?q.map(ai).join(""):`<li class="empty">${t("overview.noSessions")}</li>`,m.innerHTML=`${si(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(w=>w.nextRunAt).sort((w,A)=>Date.parse(w.nextRunAt)-Date.parse(A.nextRunAt)).slice(0,5);k.innerHTML=u.length?u.map(oi).join(""):`<li class="empty">${t("overview.noSchedules")}</li>`}let M=()=>{if(!document.body.contains(a)){window.removeEventListener("resize",M);return}o||$()};window.addEventListener("resize",M),Y.on($),$(),Vs().then($),Ke().then($)}var to=["backlog","todo","in_progress","in_review","done"];function no(e){return typeof e=="string"&&to.includes(e)?e:null}function ao(e){if(e.status==="closed")return"done";let n=no(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 ii=1e15;function bt(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 ii-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 oo(e){let n=Xn(e);return n===null?"-":n.toLocaleString("en-US")}var po=["claude-code","seed","relay","codex","codex-app","cursor","gemini","opencode","mtr","hermes","mira","pi","copilot","aiden","coco","oh-my-pi","unknown"],so=[{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"}],io=[{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 ri(e){let n=(a="")=>`<svg viewBox="0 0 14 14" aria-hidden="true"><circle cx="7" cy="7" r="5.4" fill="none" stroke="currentColor" stroke-width="1.6"${a}/>`;switch(e){case"backlog":return`${n(' stroke-dasharray="1.6 2.1"')}</svg>`;case"in_progress":return`${n()}<path d="M7,7 L7,3.6 A3.4,3.4 0 0 1 7,10.4 Z" fill="currentColor"/></svg>`;case"in_review":return`${n()}<path d="M7,7 L7,3.6 A3.4,3.4 0 1 1 3.6,7 Z" fill="currentColor"/></svg>`;case"done":return'<svg viewBox="0 0 14 14" aria-hidden="true"><circle cx="7" cy="7" r="6.2" fill="currentColor"/><path d="M4.4 7.2 6.2 9 9.7 5.4" fill="none" stroke="var(--surface)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>';default:return`${n()}</svg>`}}function ro(e){return String(e??"unknown").toLowerCase().replace(/[^a-z0-9_-]/g,"-")}function lo(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,a=e.proxyPort?`/s/${encodeURIComponent(e.sessionId)}`:"";return`http://${location.hostname}:${n}${a}`}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,a,s=""){return`<button type="button" class="card-act${s?" "+s:""}" data-action="${e}" title="${i(a)}" aria-label="${i(a)}">${n}</button>`}function co(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 a=`<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}${a}</span>`}async function uo(e,n){let a=window.open("about:blank","_blank");a&&(a.opener=null),n&&(n.disabled=!0);try{let s=await fetch(`/api/sessions/${encodeURIComponent(e.sessionId)}/write-link`),o=await s.json().catch(()=>({}));if(!s.ok||o?.ok===!1||!o?.url){a?.close(),s.status!==401&&alert(`${t("sessions.writeLinkFail")}: ${o?.error??s.status}`);return}a?a.location.href=o.url:window.open(o.url,"_blank","noopener")}catch(s){a?.close(),alert(`${t("sessions.writeLinkFail")}: ${s}`)}finally{n&&(n.disabled=!1)}}function li(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 di(){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
|
${po.map(e=>`
|
|
@@ -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 mo(e){e.innerHTML=ci();let n=e.querySelector("#sessions-table tbody"),a=e.querySelector("#filters"),s=e.querySelector("#drawer"),o=e.querySelector("#select-all"),r=e.querySelector("#bulk-bar"),d=e.querySelector("#bulk-count"),
|
|
193
|
+
</section>`}function mo(e){e.innerHTML=ci();let n=e.querySelector("#sessions-table tbody"),a=e.querySelector("#filters"),s=e.querySelector("#drawer"),o=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"),y=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=xa(window.localStorage),w=Ca(window.localStorage),A=null,P="",U="",O="",Q=!1,re=null,le=!1,te=null,ne=new Map,ce=Ra(window.localStorage),me=null,be=null,ie=[],Ue=null,Xe=!1,we=!1,fe=(()=>{try{return window.localStorage.getItem(Nn)??""}catch{return""}})();async function ae(){if(!(we||Xe)){we=!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,we=!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>`,O="",B()}}let de=null,Me="",Fe=0,Oe=!1,Ze=new Map;async function Ne(l){let c=Me===l.key&&Date.now()-Fe<3e4;if(!(Oe||c)){Oe=!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(),O="",B()}catch{}finally{Oe=!1}}}async function Pe(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]),O="",B(),I.status!==401&&alert(`${t("sessions.kanban.moveFail")}: ${D?.error??I.status}`))}catch(v){de&&(b?de.board[c]=b:delete de.board[c]),O="",B(),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},Pe(f.key,l,c,g,b)}function Pt(){return w.map(l=>so.find(c=>c.id===l)).filter(l=>!!l)}function st(l,c){let g=w.indexOf(l),f=g+c;if(g<0||f<0||f>=w.length)return;let b=[...w];b.splice(g,1),b.splice(f,0,l),w=b,On(window.localStorage,w),B()}function Bt(l,c){if(l===c)return;let g=w.indexOf(l),f=w.indexOf(c);if(g<0||f<0)return;let b=[...w];b.splice(g,1),b.splice(f,0,l),w=b,On(window.localStorage,w),B()}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(
|
|
195
|
+
<td>${i(ke(l))}</td>
|
|
196
196
|
<td><span class="badge cli-${ro(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
198
|
<td class="token-cell">${oo(l.tokenUsage?.in)}</td>
|
|
199
199
|
<td class="token-cell">${oo(l.tokenUsage?.out)}</td>
|
|
200
|
-
<td title="${i(String(l.title??""))}">${i(
|
|
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 it(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=lt(l),v=Yn(l),I=tt(l),D=lo(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
|
-
${co(
|
|
227
|
-
${
|
|
224
|
+
${it(l)??Qn("locate",Ae.pin,t("sessions.locate"))}
|
|
225
|
+
${Qn("details",Ae.details,t("sessions.details"))}
|
|
226
|
+
${co(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(so.map(b=>[b.id,[]]));for(let b of l){let v=li(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,102 +235,102 @@ 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!==P&&(P=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=lt(l),b=lo(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
250
|
<span class="badge cli-${ro(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=lt(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 St(l){let c=new Map(io.map(f=>[f.id,[]]));for(let f of l)c.get(ao(f)).push(f);let g=io.map(f=>{let b=(c.get(f.id)??[]).sort((W,N)=>bt(W)-bt(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">${ri(
|
|
284
|
-
<h2>${i(t(
|
|
285
|
-
<span class="kanban-col-count">${b.length+
|
|
283
|
+
<span class="kanban-col-icon">${ri(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;y.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>`),ae();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 ye=!1;for(let ze of f.botIds)if(X.botIds.has(ze)){ye=!0;break}if(ye){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=St(W)}else c=St(l);if(c===O)return;O=c;let g=new Map;y.querySelectorAll(".kanban-col-list").forEach(f=>{let b=f.closest(".kanban-column")?.dataset.col;b&&f.scrollTop&&g.set(b,f.scrollTop)}),y.innerHTML=c,g.size&&y.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 Ot(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,O="",B(),b.status!==401&&alert(`${t("sessions.kanban.moveFail")}: ${v?.error??b.status}`))}catch(b){l.kanbanColumn=f.column,l.kanbanPosition=f.position,O="",B(),alert(`${t("sessions.kanban.moveFail")}: ${b}`)}}async function ft(l,c){let g=l.title;l.title=c,O="",B();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,O="",B(),f.status!==401&&alert(`${t("sessions.kanban.renameFail")}: ${b?.error??f.status}`))}catch(f){l.title=g,O="",B(),alert(`${t("sessions.kanban.renameFail")}: ${f}`)}}function rt(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 Lt(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=rt(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 Tt(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=>Lt(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)||"")?ft(c,D):(O="",B())};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 Nt(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 It(){y.querySelectorAll(".drag-over, .dragging, .drop-before").forEach(l=>l.classList.remove("drag-over","dragging","drop-before"))}function qt(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),ft(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 gt(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=()=>qt(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(a),c=(l.get("q")??"").toLowerCase(),g=l.getAll("cli"),f=g.length>0&&g.length<po.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){o.checked=!1,o.indeterminate=!1,o.disabled=!0;return}o.disabled=!1;let g=c.filter(f=>T.has(f.sessionId)).length;o.checked=g===c.length,o.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=a.querySelector("#cli-filter-count");if(!l)return;let c=[...a.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 B(){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",y.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);s.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
|
+
${lt(l)?`<p><b>${t("sessions.chat")}:</b> ${i(lt(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
|
+
${it(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
|
${co(g)}
|
|
336
336
|
${c?`<button id="resume-btn" type="button" class="primary">${t("sessions.resume")}</button>`:""}
|
|
@@ -339,14 +339,14 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
339
339
|
</div>
|
|
340
340
|
<div id="land-area"></div>
|
|
341
341
|
<form method="dialog"><button>${t("sessions.dismiss")}</button></form>
|
|
342
|
-
</article>`,s.querySelectorAll("[data-copy]").forEach(
|
|
343
|
-
\u2026(truncated)`:"");
|
|
344
|
-
<p><b>${
|
|
345
|
-
<pre style="max-height:320px;overflow:auto;white-space:pre-wrap">${i(
|
|
342
|
+
</article>`,s.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=s.querySelector("#locate-btn");f&&(f.onclick=()=>{pe(l,f)});let b=s.querySelector("#history-drawer-btn");b&&(b.onclick=()=>{Tt(l)});let v=s.querySelector(".term-write");v&&(v.onclick=()=>{uo(l,v)});let I=s.querySelector("#resume-btn");I&&(I.onclick=async()=>{I.disabled=!0;try{let X=await fetch(`/api/sessions/${encodeURIComponent(l.sessionId)}/resume`,{method:"POST"}),ye=await X.json().catch(()=>({}));if(!X.ok||ye.ok===!1){alert(`${t("sessions.resumeFailed")}: ${ye?.error??X.status}`),I.disabled=!1;return}s.close()}catch(X){alert(`${t("sessions.resumeFailed")}: ${X}`),I.disabled=!1}});let D=s.querySelector("#close-btn");D&&(D.onclick=async()=>{await He(l,D)&&s.close()});let W=s.querySelector("#land-btn"),N=s.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`),ye=await X.json().catch(()=>({}));if(!ye.ok){N.innerHTML=`<p>${t("sessions.landUnavailable")}: ${i(ye.error??String(X.status))}</p>`,W.disabled=!1;return}if(ye.empty){N.innerHTML=`<p>${t("sessions.landEmpty")}</p>`,W.disabled=!1;return}let ze=String(ye.patch??""),Cn=ze.slice(0,2e4)+(ze.length>2e4?`
|
|
343
|
+
\u2026(truncated)`:"");N.innerHTML=`
|
|
344
|
+
<p><b>${ye.files}</b> files (+${ye.insertions}/-${ye.deletions}) \u2192 <code>${i(String(ye.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"}),Be=await nt.json().catch(()=>({}));N.innerHTML=Be.ok?`<p>\u2705 ${t("sessions.landApplied")}: ${Be.files} files (+${Be.insertions}/-${Be.deletions}) \u2192 <code>${i(String(Be.workingDir??""))}</code></p>`:`<p>\u274C ${t("sessions.landFailed")}: ${i(Be.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}}),s.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){st(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"?uo(b,v):I==="locate"?pe(b,v):I==="close"&&He(b,v).then(D=>{D&&(T.delete(b.sessionId),B())});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=Bn(l.dataset.view)??"board";c!==u&&(u=c,Aa(window.localStorage,u),B())})}),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,Pa(window.localStorage,g),O="",B())})}),C.addEventListener("change",()=>{fe=C.value;try{window.localStorage.setItem(Nn,fe)}catch{}O="",B()});function en(){te!==null&&(clearTimeout(te),te=null)}y.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"&&Tt(f);return}c.closest("a, button, input, label")||(en(),te=setTimeout(()=>{te=null,gt(f)},220))}),y.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)}),y.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&>(g)}),y.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)))}),y.addEventListener("dragover",l=>{if(!re&&!me)return;l.preventDefault(),l.dataTransfer&&(l.dataTransfer.dropEffect="move");let c=l.target.closest(".kanban-column");y.querySelectorAll(".drag-over").forEach(g=>g.classList.remove("drag-over")),y.querySelectorAll(".drop-before").forEach(g=>g.classList.remove("drop-before")),c&&(c.classList.add("drag-over"),Nt(c,l.clientY)?.classList.add("drop-before"))}),y.addEventListener("drop",l=>{let c=me,g=be,f=re;if(!f&&!c)return;l.preventDefault(),re=null,me=null,be=null,It();let b=l.target.closest(".kanban-column"),v=b?.dataset.col;if(!b||!v)return;let I=Nt(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)),Be=I?nt.findIndex(ve=>ve.sessionId===I.dataset.id):nt.length;Be<0&&(Be=nt.length);let ka=Be>0?nt[Be-1]:null,$a=Be<nt.length?nt[Be]:null,bs=Jn(ka?bt(ka):null,$a?bt($a):null);We.forEach((ve,hs)=>{let An=bs+hs*.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,Ot(ve,v,An,ys)}}),O="",B();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,ye=N<W.length?W[N]:null,ze=Jn(X?bt(X):null,ye?bt(ye):null);if(ce==="team"){et(String(D.sessionId),v,ze),O="",B();return}let Cn={column:D.kanbanColumn,position:D.kanbanPosition};D.kanbanColumn=v,D.kanbanPosition=ze,O="",B(),Ot(D,v,ze,Cn)}),y.addEventListener("dragend",()=>{re=null,me=null,be=null,It(),O="",B()}),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=""}),o.addEventListener("change",()=>{let l=xe().filter(c=>c.status!=="closed");for(let c of l)o.checked?T.add(c.sessionId):T.delete(c.sessionId);B()}),k.addEventListener("click",()=>{T.clear(),B()}),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(),B(),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"),B()})}),a.addEventListener("input",B),Y.on(B);let gs=setInterval(()=>{if(!document.body.contains(y)){clearInterval(gs);return}u==="kanban"&&ce==="team"&&(O="",B())},3e4);B(),Ke().then(B)}function ui(){return`<section class="page">
|
|
350
350
|
<div class="page-heading">
|
|
351
351
|
<div>
|
|
352
352
|
<p class="eyebrow">${t("nav.schedules")}</p>
|
|
@@ -371,7 +371,7 @@ 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 fo(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function go(e){e.innerHTML=ui();let n=e.querySelector("#schedules-tbody"),a=e.querySelector("#sched-filters");function s(){let r=new FormData(a),d=(r.get("q")??"").toLowerCase(),
|
|
374
|
+
</section>`}function fo(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function go(e){e.innerHTML=ui();let n=e.querySelector("#schedules-tbody"),a=e.querySelector("#sched-filters");function s(){let r=new FormData(a),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 y=$.nextRunAt?Date.parse($.nextRunAt):1/0,p=M.nextRunAt?Date.parse(M.nextRunAt):1/0;return y-p})}function o(){n.innerHTML=s().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>
|
|
@@ -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 y=await fetch(`/api/schedules/${encodeURIComponent(k)}/${$}`,{method:"POST"}),p=await y.json().catch(()=>({}));(!y.ok||p.ok===!1)&&alert(`Failed: ${y.status} ${p?.error??""}`.trim())}catch(y){alert("Network error: "+y)}finally{d.disabled=!1,d.textContent=M}}),a.addEventListener("input",o),Y.on(o),o()}var De={chats:[],bots:[]};function pi(){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">${dt()}</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 xt(){De=await(await fetch("/api/groups")).json()}async function mi(){return(await fetch("/api/groups")).json()}function fi(e,n){if(n.size===0)return!0;let a=e?.memberBots??[];for(let s of n)if(!a.some(o=>o.larkAppId===s&&o.inChat))return!1;return!0}function bo(e,n){return e.filter(a=>!n||!n.has(a.larkAppId)).map(a=>`
|
|
411
411
|
<label class="checkbox-row">
|
|
412
412
|
<input type="checkbox" name="bot" value="${i(a.larkAppId)}">
|
|
413
413
|
${i(a.botName??a.larkAppId)} <small>(${i(a.larkAppId)})</small>
|
|
414
414
|
</label>
|
|
415
|
-
`).join("")}async function ho(e){e.innerHTML=pi();let n=e.querySelector("#g-head"),a=e.querySelector("#g-body"),s=e.querySelector("#g-filters"),o=e.querySelector("#g-refresh"),r=e.querySelector("#g-drawer");o.onclick=async()=>{o.disabled=!0;try{await
|
|
415
|
+
`).join("")}async function ho(e){e.innerHTML=pi();let n=e.querySelector("#g-head"),a=e.querySelector("#g-body"),s=e.querySelector("#g-filters"),o=e.querySelector("#g-refresh"),r=e.querySelector("#g-drawer");o.onclick=async()=>{o.disabled=!0;try{await xt(),p()}finally{o.disabled=!1}};let d=e.querySelector("#g-create");d.onclick=()=>$();let m=e.querySelector("#g-loading"),k=e.querySelector("#g-table-wrap");try{await xt()}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
|
-
${bo(
|
|
431
|
+
${bo(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 w=x.target.querySelector("button[type=submit]");w&&(w.disabled=!0,w.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})}),P=await A.json();if(P.ok&&P.chatId){M(P);let U=Array.isArray(P.invalidBotIds)?P.invalidBotIds:[],O=u.filter(re=>!U.includes(re)),Q=new Set(O);typeof P.creator=="string"&&P.creator&&Q.add(P.creator),C(P.chatId,R||P.chatId,O,P.creator),p(),L(P.chatId,Q).catch(()=>{})}else alert(`Failed: ${P.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 w=De.bots.map(P=>({larkAppId:P.larkAppId,botName:P.botName,inChat:u.has(P.larkAppId),oncallChat:null})),A={chatId:x,name:T,ownerId:q??null,memberBots:w};De.chats=[A,...De.chats.filter(P=>P.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 mi()}catch{continue}let w=(u.chats??[]).find(A=>A.chatId===x);if(w&&fi(w,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,w=E.transferError,A=E.notifyMessageId,P=E.notifyError,U=Array.isArray(E.oncallBindings)?E.oncallBindings:[],O=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${O}/${U.length} bots\uFF09</p>`:`<p class="hint-warn">\u76EE\u5F55\u7ED1\u5B9A\u90E8\u5206\u5931\u8D25\uFF1A\u6210\u529F ${O}/${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>":w?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08${i(w)}\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>`:P?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8 @ \u901A\u77E5\u5931\u8D25\uFF08${i(P)}\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 y(){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(){y();let E=new FormData(s),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){a.innerHTML=`<tr><td colspan="${De.bots.length+2}" class="empty">${t("groups.empty")}</td></tr>`;return}a.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(),a.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
|
-
${bo(
|
|
474
|
+
${bo(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 O=U.result.map(Q=>`${Q.id}: ${Q.ok?"OK":`failed (${Q.error??"unknown"})`}`).join(`
|
|
481
|
+
`);alert(O),await xt(),p()}else alert(`Unexpected response: ${JSON.stringify(U)}`)}catch(P){alert("Network error: "+P)}finally{r.close()}}}),a.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]"),w=x.querySelector("[data-status]");R.addEventListener("change",()=>{q.disabled=!R.checked,R.checked&&q.focus()}),u.addEventListener("click",async()=>{w.textContent="",w.className="oncall-status";let A=R.checked,P=q.value.trim();if(A&&!P){w.textContent=t("groups.needWorkingDir"),w.classList.add("hint-warn-inline");return}u.disabled=!0;try{let U=`/api/groups/${encodeURIComponent(E.chatId)}/oncall/${encodeURIComponent(T)}`,O=A?await fetch(U,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({workingDir:P})}):await fetch(U,{method:"DELETE"}),Q=await O.json().catch(()=>({}));if(O.ok&&Q.ok){w.textContent=A?`\u2713 \u5DF2\u7ED1\u5B9A \u2192 ${Q.resolvedPath??P}`:"\u2713 \u5DF2\u89E3\u7ED1",w.classList.add("hint-ok");try{await xt(),p()}catch{}}else w.textContent=`\u2717 ${Q.error??O.status}`,w.classList.add("hint-warn-inline")}catch(U){w.textContent=`\u2717 ${U?.message??U}`,w.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 w=u.closedSessions??[],A=w.filter(O=>!O.ok).length,P=w.length-A,U=w.length===0?"":A===0?`\uFF08\u5173\u95ED ${P} \u4E2A\u4F1A\u8BDD\uFF09`:`\uFF08\u5173\u95ED ${P} \u4E2A\uFF0C${A} \u4E2A\u5931\u8D25\uFF09`;return`${u.larkAppId}: OK${U}`}).join(`
|
|
525
|
+
`);alert(q||`Unexpected: ${JSON.stringify(R)}`),await xt(),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 w=u.closedSessions??[],A=w.filter(O=>!O.ok).length,P=w.length-A,U=w.length===0?"":A===0?`
|
|
526
|
+
\u5173\u95ED\u4E86 ${P} \u4E2A\u4F1A\u8BDD\u3002`:`
|
|
527
|
+
\u5173\u95ED\u4E86 ${P} \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 xt(),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`)}}s.addEventListener("input",
|
|
531
|
+
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",p)}var Re={bots:[]},Ct=null,Ht=null;function yo(e){let n=null;for(let a of Y.sessions.values())a.larkAppId!==e||!a.cliId||(!n||Number(a.lastMessageAt??0)>Number(n.lastMessageAt??0))&&(n=a);return n?.cliId??""}function gi(){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 wo(){try{let e=await fetch("/api/bots"),n=await e.json().catch(()=>({}));if(!e.ok){Ct=n?.error?`HTTP ${e.status}: ${n.error}${n.path?` (${n.path})`:""}`:`HTTP ${e.status}`,Re={bots:[]};return}if(!n||!Array.isArray(n.bots)){Ct="unexpected response shape (no `bots` array)",Re={bots:[]};return}Ct=null,Re=n}catch(e){Ct=e?.message??String(e),Re={bots:[]}}}function vo(e){if(!e)return"\u2014";let n=new Date(e);return Number.isNaN(n.getTime())?"\u2014":n.toLocaleString()}async function ko(e){e.innerHTML=gi();let n=e.querySelector("#bd-list"),a=e.querySelector("#bd-roster"),s=e.querySelector("#bd-filters"),o=e.querySelector("#bd-refresh");o.onclick=async()=>{o.disabled=!0;try{await wo(),r()}finally{o.disabled=!1}},n.addEventListener("click",u=>{let w=u.target.closest(".toggle-tx small, small.bd-help");w&&(u.preventDefault(),w.classList.toggle("open"))}),n.innerHTML=dt(),await wo();function r(){let w=(new FormData(s).get("q")??"").toLowerCase(),A=Re.bots.filter(U=>!w||(U.botName??"").toLowerCase().includes(w)||(U.larkAppId??"").toLowerCase().includes(w));if(Ct){a.innerHTML="",n.innerHTML=`<p class="hint-warn">\u65E0\u6CD5\u52A0\u8F7D bot \u5217\u8868\uFF1A${i(Ct)}<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){a.innerHTML="",n.innerHTML=`<p class="empty">${t("botDefaults.empty")}</p>`;return}(!Ht||!A.some(U=>U.larkAppId===Ht))&&(Ht=A[0].larkAppId),a.innerHTML=A.map(d).join(""),a.querySelectorAll(".bd-roster-item").forEach(U=>{U.onclick=()=>{Ht=U.dataset.appid,r()}});let P=A.find(U=>U.larkAppId===Ht);n.innerHTML=m(P),q()}function d(u){let w=u.botName??u.larkAppId,A=yo(u.larkAppId),P=u.defaultOncall?.enabled?'<span class="bd-roster-flag">oncall</span>':"";return`<div class="bd-roster-item${u.larkAppId===Ht?" on":""}" data-appid="${i(u.larkAppId)}" role="button" tabindex="0">
|
|
548
|
+
${ue({name:w,larkAppId:u.larkAppId,size:"sm"})}
|
|
549
549
|
<div class="bd-roster-tx">
|
|
550
|
-
<b>${i(
|
|
551
|
-
<span>${i(
|
|
550
|
+
<b>${i(w)}</b>
|
|
551
|
+
<span>${i(A||u.larkAppId.slice(0,14))}</span>
|
|
552
552
|
</div>
|
|
553
|
-
${
|
|
554
|
-
</div>`}function
|
|
553
|
+
${P}
|
|
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 w=u.defaultOncall??{enabled:!1,workingDir:"",since:0},A=!!w.enabled,P=u.botName??u.larkAppId,U=yo(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:P,larkAppId:u.larkAppId,dot:"ok"})}
|
|
564
564
|
<div class="bd-profile-id">
|
|
565
|
-
<strong>${i(
|
|
566
|
-
${
|
|
567
|
-
<code>${i(
|
|
565
|
+
<strong>${i(P)}</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(vo(
|
|
572
|
-
<small>${t("botDefaults.autobound",{count:
|
|
571
|
+
<small data-oncall-since>${t("botDefaults.lastEnabled")}: ${i(vo(w.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(w.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">${
|
|
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">${y(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 w=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"${w?"":" disabled"}>${w?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"${w?"":" disabled"}>${t("botDefaults.roleSave")}</button>
|
|
613
|
+
<button type="button" data-action="delete-role"${w?"":" 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 w=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(w??"")}">
|
|
624
624
|
</label>
|
|
625
|
-
<small data-brand-state>${i($(
|
|
625
|
+
<small data-brand-state>${i($(w))}</small>
|
|
626
626
|
<small class="bd-help">${t("botDefaults.brandLabelHelp")}</small>
|
|
627
627
|
<div class="actions">
|
|
628
628
|
<button type="button" class="primary" data-action="save-brand">${t("botDefaults.brandSave")}</button>
|
|
@@ -630,38 +630,38 @@ ${T.join(`
|
|
|
630
630
|
<span class="oncall-status" data-brand-status></span>
|
|
631
631
|
</div>
|
|
632
632
|
</div>
|
|
633
|
-
</section>`}function
|
|
633
|
+
</section>`}function y(u){let w=u.disableStreamingCard===!0,A=u.writableTerminalLinkInCard===!0,P=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" ${w?"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":""} ${w?"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" ${P?"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" ${w?"":"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 w=u.p2pMode==="chat"?"chat":"thread",A=u.regularGroupReplyMode==="new-topic"||u.regularGroupReplyMode==="shared"?u.regularGroupReplyMode:"chat",P=u.regularGroupMentionMode==="topic"||u.regularGroupMentionMode==="never"?u.regularGroupMentionMode:"always",U=u.docSubscribeDefaultMode==="all"?"all":"mention-only",O=(le,te)=>`<option value="${le}" ${A===le?"selected":""}>${i(te)}</option>`,Q=(le,te)=>`<option value="${le}" ${P===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" ${w==="chat"?"":"selected"}>${i(t("botDefaults.p2pThread"))}</option>
|
|
664
|
+
<option value="chat" ${w==="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
|
+
${O("chat",t("botDefaults.regularGroupModeChat"))}
|
|
677
|
+
${O("new-topic",t("botDefaults.regularGroupModeNewTopic"))}
|
|
678
|
+
${O("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 w=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="${w??""}">
|
|
721
721
|
</label>
|
|
722
|
-
<small data-session-cap-state>${i(S(
|
|
722
|
+
<small data-session-cap-state>${i(S(w))}</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 w=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(w)}</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 w=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" ${w?"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 w=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" ${w?"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 w=u.autoStartOnGroupJoin===!0,A=u.autoStartOnNewTopic===!0,P=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" ${w?"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(P)}</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 w=u.dataset.appid,A=u.querySelector("input[data-action=toggle]"),P=u.querySelector("input[data-input=workingDir]"),U=u.querySelector("button[data-action=save]"),O=u.querySelector("[data-status]");if(!A||!P||!U||!O)return;A.addEventListener("change",()=>{P.disabled=!A.checked,A.checked&&P.focus()}),U.addEventListener("click",async()=>{O.textContent="",O.className="oncall-status";let V=A.checked,_=P.value.trim();if(V&&!_){O.textContent=t("botDefaults.required"),O.classList.add("hint-warn-inline");return}U.disabled=!0;try{let j=await fetch(`/api/bots/${encodeURIComponent(w)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:V,workingDir:_})}),J=await j.json().catch(()=>({}));if(j.ok&&J.ok){let z=J.resolvedPath?` \u2192 ${J.resolvedPath}`:"";O.textContent=V?`\u2713 \u5DF2\u5F00\u542F${z}\uFF08\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8 oncall\uFF09`:"\u2713 \u5DF2\u5173\u95ED\uFF08\u5DF2\u7ED1\u5B9A\u7684\u7FA4\u4E0D\u52A8\uFF09",O.classList.add("hint-ok");let B=Re.bots.find(He=>He.larkAppId===w);B&&J.defaultOncall&&(B.defaultOncall=J.defaultOncall);let pe=u.querySelector("[data-oncall-since]");pe&&J.defaultOncall?.since!=null&&(pe.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${vo(J.defaultOncall.since)}`)}else O.textContent=`\u2717 ${J.error??j.status}`,O.classList.add("hint-warn-inline")}catch(j){O.textContent=`\u2717 ${j?.message??j}`,O.classList.add("hint-warn-inline")}finally{U.disabled=!1}});let Q=u.querySelector("input[data-input=brandLabel]"),re=u.querySelector("button[data-action=save-brand]"),le=u.querySelector("button[data-action=reset-brand]"),te=u.querySelector("[data-brand-status]"),ne=u.querySelector("[data-brand-state]");async function ce(V,_){if(te){te.textContent="",te.className="oncall-status",_.disabled=!0;try{let j=await fetch(`/api/bots/${encodeURIComponent(w)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:V})}),J=await j.json().catch(()=>({}));if(j.ok&&J.ok){let z=J.brandLabel??null;te.textContent="\u2713",te.classList.add("hint-ok"),Q&&(Q.value=z??""),ne&&(ne.textContent=$(z));let B=Re.bots.find(pe=>pe.larkAppId===w);B&&(B.brandLabel=z)}else te.textContent=`\u2717 ${J.error??j.status}`,te.classList.add("hint-warn-inline")}catch(j){te.textContent=`\u2717 ${j?.message??j}`,te.classList.add("hint-warn-inline")}finally{_.disabled=!1}}}Q&&re&&re.addEventListener("click",()=>ce(Q.value,re)),le&&le.addEventListener("click",()=>ce(null,le));let me=u.querySelector("input[data-action=toggle-disable-streaming]"),be=u.querySelector("input[data-action=toggle-writable-link]"),ie=u.querySelector("input[data-action=toggle-private-card]"),Ue=u.querySelector("[data-card-pref-status]"),Xe=u.querySelector("[data-card-pref-moot]");async function we(V,_,j=Ue){if(j){j.textContent="",j.className="oncall-status",_.disabled=!0;try{let J=await fetch(`/api/bots/${encodeURIComponent(w)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(V)}),z=await J.json().catch(()=>({}));if(J.ok&&z.ok){j.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,j.classList.add("hint-ok");let B=Re.bots.find(pe=>pe.larkAppId===w);B&&(B.disableStreamingCard=z.disableStreamingCard,B.writableTerminalLinkInCard=z.writableTerminalLinkInCard,B.privateCard=z.privateCard,B.autoStartOnGroupJoin=z.autoStartOnGroupJoin,B.autoStartOnGroupJoinPrompt=z.autoStartOnGroupJoinPrompt,B.autoStartOnNewTopic=z.autoStartOnNewTopic,B.regularGroupReplyMode=z.regularGroupReplyMode,B.regularGroupMentionMode=z.regularGroupMentionMode,B.docSubscribeDefaultMode=z.docSubscribeDefaultMode)}else j.textContent=`\u2717 ${z.error??J.status}`,j.classList.add("hint-warn-inline")}catch(J){j.textContent=`\u2717 ${J?.message??J}`,j.classList.add("hint-warn-inline")}finally{_===be?_.disabled=!!me?.checked:_.disabled=!1}}}me&&me.addEventListener("change",()=>{let V=me.checked;be&&(be.disabled=V),Xe&&(Xe.hidden=!V),we({disableStreamingCard:V},me)}),be&&be.addEventListener("change",()=>{we({writableTerminalLinkInCard:be.checked},be)}),ie&&ie.addEventListener("change",()=>{we({privateCard:ie.checked},ie)});let fe=u.querySelector("input[data-action=toggle-sandbox]"),ae=u.querySelector("[data-sandbox-status]");fe&&fe.addEventListener("change",async()=>{let V=fe.checked;ae&&(ae.textContent="",ae.className="oncall-status"),fe.disabled=!0;try{let _=await fetch(`/api/bots/${encodeURIComponent(w)}/sandbox`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:V})}),j=await _.json().catch(()=>({}));if(_.ok&&j.ok){ae&&(ae.textContent=`\u2713 ${t("botDefaults.sandboxSaved")}`,ae.classList.add("hint-ok"));let J=Re.bots.find(z=>z.larkAppId===w);J&&(J.sandbox=j.sandbox===!0)}else ae&&(ae.textContent=`\u2717 ${j.error??_.status}`,ae.classList.add("hint-warn-inline")),fe.checked=!V}catch(_){ae&&(ae.textContent=`\u2717 ${_?.message??_}`,ae.classList.add("hint-warn-inline")),fe.checked=!V}finally{fe.disabled=!1}});let de=u.querySelector("input[data-action=toggle-auto-join]"),Me=u.querySelector("input[data-action=toggle-auto-topic]"),Fe=u.querySelector("textarea[data-input=autoJoinPrompt]"),Oe=u.querySelector("button[data-action=save-auto-join-prompt]"),Ze=u.querySelector("[data-auto-start-status]");de&&de.addEventListener("change",()=>{we({autoStartOnGroupJoin:de.checked},de,Ze)}),Me&&Me.addEventListener("change",()=>{we({autoStartOnNewTopic:Me.checked},Me,Ze)}),Fe&&Oe&&Oe.addEventListener("click",()=>{we({autoStartOnGroupJoinPrompt:Fe.value},Oe,Ze)});let Ne=u.querySelector("select[data-input=p2pMode]"),Pe=u.querySelector("[data-p2p-status]");Ne&&Pe&&Ne.addEventListener("change",async()=>{let V=Ne.value==="chat"?"chat":"thread";Pe.textContent="",Pe.className="oncall-status",Ne.disabled=!0;try{let _=await fetch(`/api/bots/${encodeURIComponent(w)}/p2p-mode`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({p2pMode:V})}),j=await _.json().catch(()=>({}));if(_.ok&&j.ok){Pe.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,Pe.classList.add("hint-ok");let J=Re.bots.find(z=>z.larkAppId===w);J&&(J.p2pMode=j.p2pMode==="chat"?"chat":"thread")}else Pe.textContent=`\u2717 ${j.error??_.status}`,Pe.classList.add("hint-warn-inline")}catch(_){Pe.textContent=`\u2717 ${_?.message??_}`,Pe.classList.add("hint-warn-inline")}finally{Ne.disabled=!1}});let et=u.querySelector("select[data-input=regularGroupMode]"),Pt=u.querySelector("[data-regular-group-status]");et&&et.addEventListener("change",()=>{we({regularGroupReplyMode:et.value},et,Pt)});let st=u.querySelector("select[data-input=regularGroupMentionMode]"),Bt=u.querySelector("[data-mention-mode-status]");st&&st.addEventListener("change",()=>{we({regularGroupMentionMode:st.value},st,Bt)});let he=u.querySelector("select[data-input=docSubscribeDefaultMode]"),it=u.querySelector("[data-doc-subscribe-mode-status]");he&&he.addEventListener("change",()=>{we({docSubscribeDefaultMode:he.value},he,it)});let tt=u.querySelector("textarea[data-input=teamRole]"),H=u.querySelector("button[data-action=save-role]"),se=u.querySelector("button[data-action=delete-role]"),G=u.querySelector("[data-role-status]");if(tt&&H&&se&&G){let j=function(z){let B=n.querySelector(`.bd-card[data-appid="${CSS.escape(w)}"]`);if(!B)return;let pe=B.querySelector("textarea[data-input=teamRole]"),He=B.querySelector("button[data-action=save-role]"),_e=B.querySelector("button[data-action=delete-role]");pe&&(pe.value=z,pe.disabled=!1),He&&(He.disabled=!1),_e&&(_e.disabled=!1)};var Hn=j;let V=`/api/team/local-bots/${encodeURIComponent(w)}/role`,_=Re.bots.find(z=>z.larkAppId===w);_&&typeof _.teamRole!="string"&&!_.teamRoleLoading&&(_.teamRoleLoading=!0,(async()=>{try{let z=await fetch(V),B=await z.json().catch(()=>({}));z.ok&&B.ok?(_.teamRole=B.role??"",j(_.teamRole)):(G.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${B.error??z.status}`,G.classList.add("hint-warn-inline"))}catch(z){G.textContent=`\u2717 ${t("botDefaults.roleLoadErr")}: ${z?.message??z}`,G.classList.add("hint-warn-inline")}finally{_.teamRoleLoading=!1}})());async function J(z,B,pe){if(G&&!(!_||typeof _.teamRole!="string")){G.textContent="",G.className="oncall-status",H.disabled=!0,se.disabled=!0;try{let He=await fetch(V,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({role:z})}),_e=await He.json().catch(()=>({}));He.ok&&_e.ok?(_&&(_.teamRole=z.trim()),G.textContent=`\u2713 ${pe?t("botDefaults.roleDeleted"):t("botDefaults.roleSaved")}`,G.classList.add("hint-ok")):(G.textContent=`\u2717 ${_e.error??He.status}`,G.classList.add("hint-warn-inline"))}catch(He){G.textContent=`\u2717 ${He?.message??He}`,G.classList.add("hint-warn-inline")}finally{H.disabled=!1,se.disabled=!1}}}H.addEventListener("click",()=>J(tt.value,H,!1)),se.addEventListener("click",()=>{tt.value="",J("",se,!0)})}let K=u.querySelector("input[data-action=toggle-restrict-grant]"),ge=u.querySelector("input[data-input=quotaLimit]"),Ge=u.querySelector("button[data-action=save-quota]"),St=u.querySelector("button[data-action=off-quota]"),Ee=u.querySelector("[data-grant-status]"),Ot=u.querySelector("[data-quota-state]");async function ft(V,_){if(Ee){Ee.textContent="",Ee.className="oncall-status",_.disabled=!0;try{let j=await fetch(`/api/bots/${encodeURIComponent(w)}/grant-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(V)}),J=await j.json().catch(()=>({}));if(j.ok&&J.ok){Ee.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,Ee.classList.add("hint-ok");let z=typeof J.messageQuotaDefaultLimit=="number"?J.messageQuotaDefaultLimit:null,B=Re.bots.find(pe=>pe.larkAppId===w);B&&(B.restrictGrantCommands=J.restrictGrantCommands===!0,B.messageQuotaDefaultLimit=z),Ot&&(Ot.textContent=x(z)),ge&&"messageQuotaDefaultLimit"in V&&(ge.value=z==null?"":String(z))}else Ee.textContent=`\u2717 ${J.error??j.status}`,Ee.classList.add("hint-warn-inline")}catch(j){Ee.textContent=`\u2717 ${j?.message??j}`,Ee.classList.add("hint-warn-inline")}finally{_.disabled=!1}}}K&&K.addEventListener("change",()=>{ft({restrictGrantCommands:K.checked},K)}),ge&&Ge&&Ge.addEventListener("click",()=>{let V=ge.value.trim();if(V===""){ft({messageQuotaDefaultLimit:null},Ge);return}if(!/^[1-9]\d*$/.test(V)){Ee&&(Ee.textContent=`\u2717 ${t("botDefaults.quotaInvalid")}`,Ee.className="oncall-status hint-warn-inline");return}ft({messageQuotaDefaultLimit:Number(V)},Ge)}),ge&&St&&St.addEventListener("click",()=>{ge.value="",ft({messageQuotaDefaultLimit:null},St)});let rt=u.querySelector("input[data-input=maxLiveWorkers]"),Lt=u.querySelector("button[data-action=save-session-cap]"),Tt=u.querySelector("button[data-action=off-session-cap]"),Le=u.querySelector("[data-session-cap-status]"),Nt=u.querySelector("[data-session-cap-state]");async function It(V,_){if(Le){Le.textContent="",Le.className="oncall-status",_.disabled=!0;try{let j=await fetch(`/api/bots/${encodeURIComponent(w)}/max-live-workers`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({maxLiveWorkers:V})}),J=await j.json().catch(()=>({}));if(j.ok&&J.ok){Le.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,Le.classList.add("hint-ok");let z=typeof J.maxLiveWorkers=="number"?J.maxLiveWorkers:null,B=Re.bots.find(pe=>pe.larkAppId===w);B&&(B.maxLiveWorkers=z),Nt&&(Nt.textContent=S(z)),rt&&(rt.value=z==null?"":String(z))}else Le.textContent=`\u2717 ${J.error??j.status}`,Le.classList.add("hint-warn-inline")}catch(j){Le.textContent=`\u2717 ${j?.message??j}`,Le.classList.add("hint-warn-inline")}finally{_.disabled=!1}}}rt&&Lt&&Lt.addEventListener("click",()=>{let V=rt.value.trim();if(V===""){It(null,Lt);return}if(!/^[1-9]\d*$/.test(V)){Le&&(Le.textContent=`\u2717 ${t("botDefaults.maxLiveWorkersInvalid")}`,Le.className="oncall-status hint-warn-inline");return}It(Number(V),Lt)}),rt&&Tt&&Tt.addEventListener("click",()=>{rt.value="",It(null,Tt)});let qt=u.querySelector("textarea[data-input=startupCommands]"),gt=u.querySelector("button[data-action=save-startup-commands]"),xe=u.querySelector("[data-startup-commands-status]");qt&>&>.addEventListener("click",async()=>{if(xe){xe.textContent="",xe.className="oncall-status",gt.disabled=!0;try{let V=await fetch(`/api/bots/${encodeURIComponent(w)}/startup-commands`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({startupCommands:qt.value})}),_=await V.json().catch(()=>({}));if(V.ok&&_.ok){xe.textContent=`\u2713 ${t("botDefaults.cardPrefSaved")}`,xe.classList.add("hint-ok");let j=typeof _.startupCommands=="string"?_.startupCommands:"";qt.value=j;let J=Re.bots.find(z=>z.larkAppId===w);J&&(J.startupCommands=j)}else xe.textContent=`\u2717 ${_.error??V.status}`,xe.classList.add("hint-warn-inline")}catch(V){xe.textContent=`\u2717 ${V?.message??V}`,xe.classList.add("hint-warn-inline")}finally{gt.disabled=!1}}})})}r(),Ke().then(r),s.addEventListener("input",r)}var oe={skills:[],bots:[],trustProjectSkills:"off",delivery:"auto"},mn=null,bi=2,ht=0;function hi(){return`<section class="page">
|
|
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 _t(e){return(e?.include??[]).filter(n=>n.startsWith("skill:")).map(n=>n.slice(6))}function wi(e){return _t(e).length}function vi(e){return _t(e).length>0}function ki(){return new Set(oe.skills.map(e=>e.name))}function $i(e){return oe.bots.filter(n=>_t(n.skills).includes(e)).map(n=>n.botName??n.larkAppId)}function Si(){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,30 +835,30 @@ ${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 Li(){if(
|
|
838
|
+
</article>`}function Li(){if(oe.skills.length===0)return`<p class="empty">${t("skills.empty")}</p>`;fn();let e=$o(),n=ht*e;return`<div class="skills-list">${oe.skills.slice(n,n+e).map(s=>`
|
|
829
839
|
<article class="skills-row skills-installed-card" data-skill="${i(s.name)}">
|
|
830
840
|
<div class="skills-row-body">
|
|
831
841
|
<strong>${i(s.name)}</strong>
|
|
832
842
|
${s.description?`<p>${i(s.description)}</p>`:""}
|
|
833
|
-
<small>${i(
|
|
843
|
+
<small>${i(yi(s))}</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 Ti(){let e=typeof window>"u"?1440:window.innerWidth;return e>=1600?4:e<=620?1:e<=980?2:3}function $o(){return Ti()*bi}function So(){return Math.max(1,Math.ceil(
|
|
849
|
+
</article>`).join("")}</div>`}function Ti(){let e=typeof window>"u"?1440:window.innerWidth;return e>=1600?4:e<=620?1:e<=980?2:3}function $o(){return Ti()*bi}function So(){return Math.max(1,Math.ceil(oe.skills.length/$o()))}function fn(){ht=Math.min(Math.max(0,ht),So()-1)}function Ii(){fn();let e=`<span class="skills-count-pill">${t("skills.skillCount",{count:oe.skills.length})}</span>`,n=So();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")}" ${ht===0?"disabled":""}>‹</button>
|
|
853
|
+
<span>${t("skills.pageStatus",{page:ht+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")}" ${ht>=n-1?"disabled":""}>›</button>
|
|
845
855
|
</div>
|
|
846
856
|
</div>`}function Mi(){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,s])=>`<button type="button" class="skills-choice${
|
|
861
|
+
${[["off",t("skills.globalProjectOff"),t("skills.globalProjectOffHelp")],["all",t("skills.globalProjectAll"),t("skills.globalProjectAllHelp")]].map(([n,a,s])=>`<button type="button" class="skills-choice${oe.trustProjectSkills===n?" selected":""}" data-global-project-value="${n}" aria-pressed="${oe.trustProjectSkills===n?"true":"false"}">
|
|
852
862
|
<strong>${a}</strong><small>${s}</small>
|
|
853
863
|
</button>`).join("")}
|
|
854
864
|
</div>
|
|
@@ -856,21 +866,21 @@ ${T.join(`
|
|
|
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,s])=>`<button type="button" class="skills-choice${
|
|
869
|
+
${e.map(([n,a,s])=>`<button type="button" class="skills-choice${oe.delivery===n?" selected":""}" data-global-delivery-value="${n}" aria-pressed="${oe.delivery===n?"true":"false"}">
|
|
860
870
|
<strong>${a}</strong><small>${s}</small>
|
|
861
871
|
</button>`).join("")}
|
|
862
872
|
</div>
|
|
863
873
|
</div>
|
|
864
|
-
</article>`}function Ei(e){let n=new Set(
|
|
874
|
+
</article>`}function Ei(e){let n=new Set(_t(e.skills)),a=oe.skills.filter(s=>!n.has(s.name));return a.length===0?`<button type="button" disabled>${t("skills.attach")}</button>`:`<select data-attach-picker>
|
|
865
875
|
${a.map(s=>`<option value="${i(s.name)}">${i(s.name)}</option>`).join("")}
|
|
866
876
|
</select>
|
|
867
877
|
<button type="button" data-action="attach-skill">${t("skills.attach")}</button>`}function xi(e){if(e.error)return`<article class="bd-card skills-bot-card" data-appid="${i(e.larkAppId)}">
|
|
868
|
-
<header>${
|
|
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=_t(e.skills),a=ki();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>
|
|
@@ -883,21 +893,21 @@ ${T.join(`
|
|
|
883
893
|
<div class="actions skills-attach-row">${Ei(e)}</div>
|
|
884
894
|
</section>
|
|
885
895
|
<span class="oncall-status" data-bot-status></span>
|
|
886
|
-
</article>`}function Hi(){return
|
|
896
|
+
</article>`}function Hi(){return oe.bots.reduce((e,n)=>e+wi(n.skills),0)}function Ci(){return oe.bots.filter(e=>vi(e.skills)).length}function Ai(){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>${Ci()}/${
|
|
902
|
+
<span><small>${t("skills.metricInstalled")}</small><strong>${oe.skills.length}</strong></span>
|
|
903
|
+
<span><small>${t("skills.metricBots")}</small><strong>${Ci()}/${oe.bots.length}</strong></span>
|
|
894
904
|
<span><small>${t("skills.metricAttached")}</small><strong>${Hi()}</strong></span>
|
|
895
905
|
</div>
|
|
896
|
-
</section>`}function Di(){let e=`<span class="skills-count-pill">${t("skills.botCount",{count:
|
|
906
|
+
</section>`}function Di(){let e=`<span class="skills-count-pill">${t("skills.botCount",{count:oe.bots.length})}</span>`;return oe.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 Ri(){return
|
|
910
|
+
</div>`}function Ri(){return mn?`<p class="hint-warn">${i(mn)}</p>`:`<div class="skills-page-grid">
|
|
901
911
|
<aside class="skills-side-rail">
|
|
902
912
|
${Mi()}
|
|
903
913
|
${Si()}
|
|
@@ -912,7 +922,7 @@ ${T.join(`
|
|
|
912
922
|
</div>
|
|
913
923
|
${Di()}
|
|
914
924
|
</div>
|
|
915
|
-
<div class="skills-bot-grid">${
|
|
925
|
+
<div class="skills-bot-grid">${oe.bots.map(xi).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">
|
|
@@ -925,7 +935,7 @@ ${T.join(`
|
|
|
925
935
|
${Li()}
|
|
926
936
|
</section>
|
|
927
937
|
</section>
|
|
928
|
-
</div>`}async function Pi(){try{let[e,n]=await Promise.all([fetch("/api/skills"),fetch("/api/bots")]),a=await e.json().catch(()=>({})),s=await n.json().catch(()=>({}));if(!e.ok)throw new Error(a?.error??`skills HTTP ${e.status}`);if(!n.ok)throw new Error(s?.error??`bots HTTP ${n.status}`);
|
|
938
|
+
</div>`}async function Pi(){try{let[e,n]=await Promise.all([fetch("/api/skills"),fetch("/api/bots")]),a=await e.json().catch(()=>({})),s=await n.json().catch(()=>({}));if(!e.ok)throw new Error(a?.error??`skills HTTP ${e.status}`);if(!n.ok)throw new Error(s?.error??`bots HTTP ${n.status}`);oe={skills:Array.isArray(a.skills)?a.skills:[],bots:Array.isArray(s.bots)?s.bots:[],trustProjectSkills:a.trustProjectSkills==="all"?"all":"off",delivery:a.delivery==="prompt"||a.delivery==="native"?a.delivery:"auto"},fn(),mn=null}catch(e){mn=e?.message??String(e)}}async function at(e,n){let a=await fetch(e,{...n,headers:{"content-type":"application/json",...n.headers??{}}}),s=await a.json().catch(()=>({}));if(!a.ok||s.ok===!1){let o=new Error(s?.error??`HTTP ${a.status}`);throw o.status=a.status,o.body=s,o}return s}function Bi(e){return new Promise(n=>setTimeout(n,e))}async function Lo(e){e.innerHTML=hi();let n=e.querySelector("#skills-body"),a=e.querySelector("#skills-refresh");async function s(){n.innerHTML=dt(),await Pi(),k()}function o(y){return y?.querySelector("[data-skills-status], [data-bot-status]")??null}function r(y,p,S){y&&(y.textContent=p,y.className=`oncall-status ${S?"hint-ok":"hint-warn-inline"}`)}function d(y,p){n.querySelectorAll(y).forEach(S=>{S.disabled=p})}function m(y,p,S){n.querySelectorAll(y).forEach(E=>{let C=E.dataset[p]===S;E.classList.toggle("selected",C),E.setAttribute("aria-pressed",C?"true":"false")})}function k(){n.innerHTML=Ri(),M()}async function $(y,p){let S=y;for(r(p,t("skills.jobRunning"),!0);;){if(S.status==="succeeded"){r(p,t("skills.saved"),!0),await s();return}if(S.status==="failed")throw new Error(S.error??"job_failed");await Bi(800),S=(await at(`/api/skills/jobs/${encodeURIComponent(S.id)}`,{method:"GET"})).job}}function M(){n.querySelector('[data-action="install"]')?.addEventListener("click",async()=>{let y=n.querySelector(".skills-install-panel"),p=o(y),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 at("/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(y=>y.addEventListener("click",async()=>{let p=y.dataset.globalProjectValue==="all"?"all":"off";if(oe.trustProjectSkills!==p)try{d("[data-global-project-value]",!0);let S=await at("/api/skills/global",{method:"PUT",body:JSON.stringify({trustProjectSkills:p})});oe.trustProjectSkills=S.trustProjectSkills==="all"?"all":p,m("[data-global-project-value]","globalProjectValue",oe.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(y=>y.addEventListener("click",async()=>{let p=y.dataset.globalDeliveryValue==="prompt"||y.dataset.globalDeliveryValue==="native"?y.dataset.globalDeliveryValue:"auto";if(oe.delivery!==p)try{d("[data-global-delivery-value]",!0);let S=await at("/api/skills/global",{method:"PUT",body:JSON.stringify({delivery:p})});oe.delivery=S.delivery==="prompt"||S.delivery==="native"?S.delivery:p,m("[data-global-delivery-value]","globalDeliveryValue",oe.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(y=>y.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=y.dataset.dir==="-1"?-1:1;p.scrollBy({left:L*(S.getBoundingClientRect().width+C),behavior:"smooth"})})),n.querySelectorAll('[data-action="page-installed-skills"]').forEach(y=>y.addEventListener("click",()=>{let p=y.dataset.dir==="-1"?-1:1;ht+=p,fn(),k()})),n.querySelectorAll(".skills-row").forEach(y=>{let p=y.dataset.skill??"";y.querySelector('[data-action="update-skill"]')?.addEventListener("click",async()=>{let S=y.querySelector('[data-action="update-skill"]'),E=n.querySelector(".skills-install-panel"),C=o(E);try{S&&(S.disabled=!0);let L=await at(`/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)}}),y.querySelector('[data-action="remove-skill"]')?.addEventListener("click",async()=>{if(window.confirm(`${t("skills.remove")} ${p}?`))try{await at(`/api/skills/${encodeURIComponent(p)}`,{method:"DELETE",body:"{}"}),await s()}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):$i(p),C=[E.length?`Bot: ${E.join(", ")}`:""].filter(Boolean).join("; ")||"-";if(!window.confirm(t("skills.removeInUse",{skill:p,refs:C})))return;try{await at(`/api/skills/${encodeURIComponent(p)}?force=1`,{method:"DELETE",body:"{}"}),await s();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(y=>{let p=y.dataset.appid??"",S=oe.bots.find(E=>E.larkAppId===p);S&&(y.querySelector('[data-action="attach-skill"]')?.addEventListener("click",async()=>{let E=y.querySelector("[data-attach-picker]")?.value;if(E)try{let C=await at(`/api/bots/${encodeURIComponent(p)}/skills`,{method:"PUT",body:JSON.stringify({action:"attach",name:E})});S.skills=C.skills??null,k()}catch(C){r(o(y),`${t("skills.failed")}: ${C?.message??C}`,!1)}}),y.querySelectorAll('[data-action="detach-skill"]').forEach(E=>{E.addEventListener("click",async()=>{let C=E.dataset.name;if(C)try{let L=await at(`/api/bots/${encodeURIComponent(p)}/skills`,{method:"PUT",body:JSON.stringify({action:"detach",name:C})});S.skills=L.skills??null,k()}catch(L){r(o(y),`${t("skills.failed")}: ${L?.message??L}`,!1)}})}))})}a.onclick=()=>{s()},await s()}var Zn=4096,bn=[],Ve=null,Ye=null,je="",At=new Set;function Oi(){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,24 +974,24 @@ ${T.join(`
|
|
|
964
974
|
</div>
|
|
965
975
|
</div>
|
|
966
976
|
</div>
|
|
967
|
-
</section>`}async function
|
|
968
|
-
<div class="roles-bot-row ${
|
|
977
|
+
</section>`}async function gn(){bn=((await(await fetch("/api/groups")).json()).chats??[]).map(a=>({chatId:a.chatId,name:a.name??a.chatId,memberBots:(a.memberBots??[]).map(s=>({larkAppId:s.larkAppId,botName:s.botName??s.larkAppId,inChat:s.inChat??!1,hasRole:s.hasRole??!1,oncallChat:s.oncallChat??null}))}))}async function Io(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`)).json()}async function Ni(e,n,a){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({content:a})})).ok}async function qi(e,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(n)}`,{method:"DELETE"})).ok}function Mo(e){return e.memberBots.filter(n=>n.inChat&&n.hasRole).length}function ji(e){return e.memberBots.filter(n=>n.inChat).length}function yt(e=""){let n=document.getElementById("roles-tree");if(!n)return;let a=e.toLowerCase(),s=bn.filter(o=>{if(!a)return!0;let r=o.chatId.toLowerCase().includes(a)||(o.name??"").toLowerCase().includes(a),d=o.memberBots.some(m=>m.larkAppId.toLowerCase().includes(a)||(m.botName??"").toLowerCase().includes(a));return r||d});if(s.length===0){n.innerHTML=`<div class="roles-empty">${t("roles.noChats")}</div>`;return}n.innerHTML=s.map(o=>{let r=At.has(o.chatId),d=o.memberBots.filter(y=>y.inChat),m=r?"\u25BE":"\u25B8",k=Mo(o),$=ji(o),M=r?d.map(y=>`
|
|
978
|
+
<div class="roles-bot-row ${Ve===o.chatId&&Ye===y.larkAppId?"selected":""}"
|
|
969
979
|
data-group-id="${i(o.chatId)}"
|
|
970
|
-
data-bot-id="${i(
|
|
980
|
+
data-bot-id="${i(y.larkAppId)}">
|
|
971
981
|
<span class="roles-bot-indent"></span>
|
|
972
|
-
${
|
|
982
|
+
${ue({name:y.botName,larkAppId:y.larkAppId,size:"sm"})}
|
|
973
983
|
<div class="roles-bot-info">
|
|
974
|
-
<div class="roles-bot-name">${i(
|
|
975
|
-
<div class="roles-bot-id">${i(
|
|
984
|
+
<div class="roles-bot-name">${i(y.botName)}</div>
|
|
985
|
+
<div class="roles-bot-id">${i(y.larkAppId)}</div>
|
|
976
986
|
</div>
|
|
977
|
-
<span class="roles-badge ${
|
|
978
|
-
${
|
|
987
|
+
<span class="roles-badge ${y.hasRole?"has-role":"no-role"}">
|
|
988
|
+
${y.hasRole?t("roles.configured"):t("roles.unconfigured")}
|
|
979
989
|
</span>
|
|
980
990
|
</div>`).join(""):"";return`
|
|
981
991
|
<div class="roles-group-section">
|
|
982
|
-
<div class="roles-group-row ${r?"expanded":""} ${
|
|
992
|
+
<div class="roles-group-row ${r?"expanded":""} ${Ve===o.chatId&&!Ye?"selected":""}"
|
|
983
993
|
data-group-id="${i(o.chatId)}">
|
|
984
|
-
<span class="roles-group-arrow">${
|
|
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
997
|
<div class="roles-group-name">${i(o.name??o.chatId)}</div>
|
|
@@ -991,8 +1001,8 @@ ${T.join(`
|
|
|
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(o=>{o.addEventListener("click",()=>{let r=o.dataset.groupId;r&&(
|
|
1004
|
+
<div class="roles-bot-list">${M}</div>
|
|
1005
|
+
</div>`}).join(""),n.querySelectorAll(".roles-group-row").forEach(o=>{o.addEventListener("click",()=>{let r=o.dataset.groupId;r&&(At.has(r)?At.delete(r):At.add(r),yt(document.getElementById("roles-search")?.value??""))})}),n.querySelectorAll(".roles-bot-row").forEach(o=>{o.addEventListener("click",r=>{r.stopPropagation();let d=o.dataset.groupId,m=o.dataset.botId;d&&m&&Ui(d,m)})})}async function Ui(e,n){Ve=e,Ye=n;let a=await Io(n,e),s=document.getElementById("roles-editor-empty"),o=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");s&&(s.style.display="none"),o&&(o.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=a.content??"",r&&(r.value=je,r.focus()),ea(),ta(),yt(document.getElementById("roles-search")?.value??"");let y=document.getElementById("roles-delete");y&&(y.style.display=a.hasRole?"":"none")}function ea(){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":""}`,Fi(n)}function Fi(e){let n=document.getElementById("roles-save");if(!n)return;let a=e??new TextEncoder().encode(je).length;n.disabled=a>Zn||je.trim().length===0}function ta(){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 To(){Ve=null,Ye=null,je="";let e=document.getElementById("roles-editor-empty"),n=document.getElementById("roles-editor-form"),a=document.getElementById("roles-editor-textarea"),s=document.getElementById("roles-delete");e&&(e.style.display=""),n&&(n.style.display="none"),a&&(a.value=""),s&&(s.style.display="none")}async function Eo(e){e.innerHTML=Oi(),At.clear(),To();let n=document.getElementById("roles-tree");n&&(n.innerHTML=dt()),await gn(),await Ke();for(let a of bn)Mo(a)>0&&At.add(a.chatId);yt(),document.getElementById("roles-search")?.addEventListener("input",a=>{yt(a.target.value)}),document.getElementById("roles-refresh")?.addEventListener("click",async()=>{if(await gn(),yt(document.getElementById("roles-search")?.value??""),Ve&&Ye){let a=await Io(Ye,Ve),s=document.getElementById("roles-editor-textarea");s&&(s.value=a.content??""),je=a.content??"",ea(),ta();let o=document.getElementById("roles-delete");o&&(o.style.display=a.hasRole?"":"none")}}),document.getElementById("roles-save")?.addEventListener("click",async function(){if(!(!Ve||!Ye)){this.disabled=!0,this.textContent="...";try{if(await Ni(Ye,Ve,je)){await gn(),yt(document.getElementById("roles-search")?.value??"");let s=document.getElementById("roles-delete");s&&(s.style.display="");let o=document.createElement("span");o.className="roles-saved-flash",o.textContent=` ${t("roles.saved")}`,document.querySelector(".roles-editor-footer")?.appendChild(o),setTimeout(()=>o.remove(),2e3)}else{let s=document.createElement("span");s.className="roles-saved-flash roles-save-error",s.textContent=je.trim().length===0?` ${t("roles.emptyError")}`:` ${t("roles.saveFailed")}`,document.querySelector(".roles-editor-footer")?.appendChild(s),setTimeout(()=>s.remove(),3e3)}}finally{this.disabled=!1,this.textContent=t("roles.save")}}}),document.getElementById("roles-delete")?.addEventListener("click",async function(){if(!(!Ve||!Ye)&&confirm(t("roles.confirmDelete"))){this.disabled=!0,this.textContent="...";try{await qi(Ye,Ve)&&(await gn(),To(),yt(document.getElementById("roles-search")?.value??""))}finally{this.disabled=!1,this.textContent=t("roles.delete")}}}),document.getElementById("roles-editor-textarea")?.addEventListener("input",a=>{je=a.target.value,ea(),ta()})}async function wn(e){let n=await fetch(e);return{status:n.status,body:await n.json().catch(()=>({}))}}async function vn(e,n,a){let s=await fetch(n,{method:e,headers:{"content-type":"application/json"},body:a?JSON.stringify(a):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}var vt=(e,n)=>vn("POST",e,n),Gi=(e,n)=>vn("PUT",e,n),na=[],xo=[],Ho="",hn="",aa=new Map,yn=new Map,zt=new Set,Wt=new Set;function Z(e){return document.getElementById(e)}function kn(){return[...na,...xo]}function wt(e){let n=aa.get(e);return n||(n=new Set,aa.set(e,n)),n}function _i(e){return kn().find(n=>n.key===e)}function Co(e){let n=(a,s,o)=>`<a href="${a}" style="padding:6px 14px;border-radius:8px;text-decoration:none;font-size:14px;font-weight:600;${o?"background:var(--accent);color:var(--on-accent)":"color:var(--muted);background:var(--surface-muted)"}">${s}</a>`;return`<div style="display:flex;gap:8px;margin-bottom:14px">${n("#/team",t("team.navHome"),e==="home")}${n("#/team/manage",t("team.navManage"),e==="manage")}</div>`}function zi(){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>
|
|
@@ -1026,7 +1036,7 @@ ${Co("home")}
|
|
|
1026
1036
|
</div>
|
|
1027
1037
|
</div>
|
|
1028
1038
|
</div>
|
|
1029
|
-
</section>`}function
|
|
1039
|
+
</section>`}function Wi(e){let n=(Z("tf-search").value||"").trim().toLowerCase();if(n&&!((e.name||"")+" "+(e.cliId||"")+" "+(e.capability||"")).toLowerCase().includes(n))return!1;let a=Z("tf-cli").value;return!(a&&e.cliId!==a||Z("tf-fcap").checked&&!e.capability||Z("tf-frole").checked&&!e.hasTeamRole)}function Ki(e,n){let a=[...e.deployments].sort((o,r)=>o.local===r.local?0:o.local?-1:1),s="";for(let o of a){let r=n.filter(p=>p.deployment.id===o.id);if(!r.length)continue;let d=o.id===Ho,m=d?t("team.tagLocal"):o.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(o.id)}" data-name="${i(o.name)}" style="font-size:12px">${t("team.removeMember")}</button>`:"",$=`${e.key}::${o.id}`,M=Wt.has($),y=r.filter(p=>wt(e.key).has(p.larkAppId)).length;if(s+=`<div class="tf-dep-h" data-dk="${i($)}" style="cursor:pointer;margin:10px 0 2px"><b>${M?"\u25BE":"\u25B8"} ${i(o.name)}</b> <span class="muted" style="font-size:12px">${t("team.depTag",{tag:m})} \xB7 ${t("team.depCount",{count:r.length})}${y?t("team.depSelected",{n:y}):""}</span>${k}</div>`,!!M){s+='<table style="width:100%;border-collapse:collapse;font-size:14px"><tbody>';for(let p of r){let S=i(p.larkAppId),E=wt(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>';s+=`<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>`}s+="</tbody></table>"}}return s||(s=`<p class="muted" style="margin:8px 0 0">${t("team.noMatch")}</p>`),s+=`<div style="margin-top:12px;display:flex;gap:8px;flex-wrap:wrap;align-items:center"><input class="tf-gname" data-tk="${i(e.key)}" value="${i(yn.get(e.key)||"")}" placeholder="${t("team.gnamePh")}" style="min-width:200px"><button class="tf-grp primary" data-tk="${i(e.key)}">${t("team.pullGroupBtn")}</button><span class="muted" style="font-size:13px">${t("team.pullGroupHint")}</span><span class="tf-gout" data-tk="${i(e.key)}" style="font-size:13px;display:block;flex-basis:100%"></span></div>`,s}function ut(){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 a="",s=new Set,o=new Set;for(let m of n){let k=m.bots.filter(Wi);k.forEach(p=>s.add(p.larkAppId)),m.bots.forEach(p=>o.add(p.larkAppId));let $=new Set(k.map(p=>p.larkAppId));[...wt(m.key)].forEach(p=>{$.has(p)||wt(m.key).delete(p)});let M=!zt.has(m.key),y=m.kind==="remote"?m.ok?` <span class="ok" style="font-size:12px">${t("team.connected")}</span>`:` <span class="err" style="font-size:12px">${t("team.connectFail",{error:i(m.error||"")})}</span>`:` <span class="muted" style="font-size:12px">${t("team.iHost")}</span>`;a+=`<div class="card" style="margin:0 0 12px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)"><div class="tf-team-h" data-tk="${i(m.key)}" style="cursor:pointer;display:flex;align-items:center;gap:8px;flex-wrap:wrap"><b style="font-size:15px">${M?"\u25B8":"\u25BE"} ${i(m.label)}</b>`+(m.sub?` <span class="muted" style="font-size:12px">${i(m.sub)}</span>`:"")+y+` <span class="muted" style="font-size:12px">\xB7 ${t("team.teamMeta",{deps:m.deployments.length,bots:m.bots.length})}</span></div>`,M||(a+=m.kind==="remote"&&!m.ok?`<p class="muted" style="margin:8px 0 0">${t("team.rosterFail")}</p>`:Ki(m,k)),a+="</div>"}e.innerHTML=a;let r=n.length>1?t("team.acrossTeams",{n:n.length}):"",d=s.size===o.size?`${o.size}`:`${s.size} / ${o.size}`;Z("tf-count").textContent=`\xB7 ${d} ${t("team.botsWord")}${r}`,Ji()}function Ji(){let e=Z("tf-teams");e.querySelectorAll(".tf-team-h").forEach(n=>{n.onclick=()=>{let a=n.dataset.tk;zt.has(a)?zt.delete(a):zt.add(a),ut()}}),e.querySelectorAll(".tf-dep-h").forEach(n=>{n.onclick=()=>{let a=n.dataset.dk;Wt.has(a)?Wt.delete(a):Wt.add(a),ut()}}),e.querySelectorAll(".tf-pick").forEach(n=>{n.onchange=()=>{let a=wt(n.dataset.tk);n.checked?a.add(n.dataset.app):a.delete(n.dataset.app)}}),e.querySelectorAll(".tf-gname").forEach(n=>{n.oninput=()=>{yn.set(n.dataset.tk,n.value)}}),e.querySelectorAll(".tf-cap").forEach(n=>{n.onchange=async()=>{let a=n.dataset.app,s=n.value;await Gi("/api/team/local-bots/"+encodeURIComponent(a)+"/capability",{capability:s}),kn().forEach(o=>{let r=o.bots.find(d=>d.larkAppId===a);r&&(r.capability=s.trim()||null)})}}),e.querySelectorAll(".tf-role").forEach(n=>{n.onclick=()=>Yi(n.dataset.app,n.dataset.name||"")}),e.querySelectorAll(".tf-rmmember").forEach(n=>{n.onclick=async a=>{a.stopPropagation(),confirm(t("team.removeMemberConfirm",{name:n.dataset.name||""}))&&(await vn("DELETE",`/api/team/hosted/${encodeURIComponent(n.dataset.team)}/members/${encodeURIComponent(n.dataset.dep)}`),Kt())}}),e.querySelectorAll(".tf-grp").forEach(n=>{n.onclick=async()=>{let a=n.dataset.tk,s=_i(a);if(!s)return;let o=[...wt(a)],r=e.querySelector(`.tf-gout[data-tk="${CSS.escape(a)}"]`);if(!o.length){r.innerHTML=`<span class="err">${t("team.errPickBot")}</span>`;return}let d=(e.querySelector(`.tf-gname[data-tk="${CSS.escape(a)}"]`)?.value||"").trim()||t("team.defaultGroupName");r.innerHTML=`<span class="muted">${t("team.creatingGroup")}</span>`;let m=s.kind==="local"?await vt("/api/team/federated-group",{name:d,larkAppIds:o,teamId:s.teamId}):await vt("/api/team/remote-group",{hubUrl:s.hubUrl,teamId:s.teamId,name:d,larkAppIds:o});if(Vi(r,m.body,m.status),m.body?.ok){wt(a).clear(),yn.delete(a);let k=r.innerHTML,$=()=>{let M=e.querySelector(`.tf-gout[data-tk="${CSS.escape(a)}"]`);M&&(M.innerHTML=k)};s.kind==="local"?Kt().then($):(ut(),$())}}})}function Vi(e,n,a){if(n?.ok&&n.chatId){let s=n.shareLink||"https://applink.feishu.cn/client/chat/open?openChatId="+encodeURIComponent(n.chatId),o=(n.invalidBotIds||[]).length?` <span class="err"> \xB7 ${t("team.invalidBots",{ids:i((n.invalidBotIds||[]).join(", "))})}</span>`:"",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(s)}" target="_blank">${t("team.openInLark")}</a>${o}${r}${d}${m}`}else{let s=n?.error||a,o=s==="no_local_online_bot"?t("team.errNoLocalBot"):s==="all_bots_skipped_no_owner"?t("team.errAllSkipped"):s==="no_creator_available"?t("team.errNoCreator"):s==="delegation_timeout"?t("team.errDelegationTimeout"):t("team.errGroupCreate",{error:String(s)});e.innerHTML=`<span class="err">${i(String(o))}</span>`}}async function Yi(e,n){let a=await wn("/api/team/local-bots/"+encodeURIComponent(e)+"/role");Z("tf-modal-title").textContent=t("team.roleModalTitleName",{name:n}),Z("tf-modal-text").value=a.body?.role||"",Z("tf-modal").dataset.app=e,Z("tf-modal").style.display="flex"}function Ao(){let e=Array.from(new Set(kn().flatMap(s=>s.bots.map(o=>o.cliId)).filter(Boolean))).sort(),n=Z("tf-cli"),a=n.value;n.innerHTML=`<option value="">${t("team.allCli")}</option>`+e.map(s=>`<option value="${i(s)}">${i(s)}</option>`).join(""),n.value=a}async function Kt(){let n=(await wn("/api/team/hosted")).body;if(!n?.ok){na=[],ut();return}Ho=n.deployment.deploymentId,hn=n.suggestedHubUrl||"",Z("tf-owner").textContent=n.deployment.ownerName||(n.deployment.ownerUnionId?t("team.bound"):t("team.unbound")),na=(n.teams||[]).map(a=>({kind:"local",key:`local:${a.teamId}`,teamId:a.teamId,label:a.isDefault?t("team.myHostedTeam"):a.name,sub:"",ok:!0,deployments:a.deployments||[],bots:a.bots||[]})),Ao(),ut()}async function Qi(){xo=((await wn("/api/team/remote-roster")).body?.memberships||[]).map(a=>{let s=a.roster?.deployments||[],o=s.find(d=>d.local),r=o?.name?t("team.remoteTeamLabel",{name:o.name}):a.teamName||a.teamId;return{kind:"remote",key:`${a.hubUrl}::${a.teamId}`,teamId:a.teamId,label:r,sub:a.hubUrl,ok:!!a.ok,error:a.error,hubUrl:a.hubUrl,deployments:s,bots:a.roster?.bots||[]}}),Ao(),ut()}function Do(e){e.innerHTML=zi(),aa.clear(),yn.clear(),zt.clear(),Wt.clear(),["tf-search","tf-cli","tf-fcap","tf-frole"].forEach(n=>{let a=Z(n);a.oninput=ut,a.onchange=ut}),Z("tf-modal-cancel").onclick=()=>{Z("tf-modal").style.display="none"},Zi(),Kt(),Qi()}function Xi(){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>
|
|
@@ -1050,7 +1060,7 @@ ${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 oa(){let n=(await wn("/api/team/hosted")).body,a=Z("tm-list");hn=n?.suggestedHubUrl||hn;let s=n?.teams||[];if(!s.length){a.innerHTML=`<p class="muted">${t("team.noTeamsShort")}</p>`;return}a.innerHTML=s.map(o=>{let r=(o.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
1065
|
<b>${i(o.name)}</b>${o.isDefault?` <span class="muted" style="font-size:12px">${t("team.default")}</span>`:""}
|
|
1056
1066
|
<span class="muted" style="font-size:12px">\xB7 ${t("team.manageMetaDeps",{count:(o.deployments||[]).length})}${r?t("team.manageMetaRemote",{r}):""} \xB7 ${t("team.manageMetaBots",{count:(o.bots||[]).length})}</span>
|
|
@@ -1059,7 +1069,7 @@ ${Co("manage")}
|
|
|
1059
1069
|
${o.isDefault?"":`<button class="tm-del ghost" data-team="${i(o.teamId)}" data-name="${i(o.name)}" style="font-size:12px">${t("team.delBtn")}</button>`}
|
|
1060
1070
|
</span>
|
|
1061
1071
|
</div>
|
|
1062
|
-
<div class="tm-inv-out" data-team="${i(o.teamId)}" style="display:none;margin-top:6px;font-size:13px"></div></div>`}).join(""),a.querySelectorAll(".tm-invite").forEach(o=>{o.onclick=async()=>{let r=o.dataset.team,d=a.querySelector(`.tm-inv-out[data-team="${CSS.escape(r)}"]`);d.style.display="",d.innerHTML=`<span class="muted">${t("team.generating")}</span>`;let
|
|
1072
|
+
<div class="tm-inv-out" data-team="${i(o.teamId)}" style="display:none;margin-top:6px;font-size:13px"></div></div>`}).join(""),a.querySelectorAll(".tm-invite").forEach(o=>{o.onclick=async()=>{let r=o.dataset.team,d=a.querySelector(`.tm-inv-out[data-team="${CSS.escape(r)}"]`);d.style.display="",d.innerHTML=`<span class="muted">${t("team.generating")}</span>`;let m=await vt("/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>`}}),a.querySelectorAll(".tm-del").forEach(o=>{o.onclick=async()=>{confirm(t("team.delConfirm",{name:o.dataset.name||""}))&&(await vn("DELETE","/api/team/hosted/"+encodeURIComponent(o.dataset.team)),oa())}})}function Ro(e){e.innerHTML=Xi(),Z("tm-create").onclick=async()=>{let n=Z("tm-newname").value.trim(),a=e.querySelector(".tm-cout");if(!n){a.innerHTML=`<span class="err">${t("team.errName")}</span>`;return}a.innerHTML=`<span class="muted">${t("team.creating")}</span>`;let s=await vt("/api/team/hosted",{name:n});s.body?.ok?(a.innerHTML=`<span class="ok">${t("team.created")}</span>`,Z("tm-newname").value="",oa()):a.innerHTML=`<span class="err">${t("team.createFail",{error:i(String(s.body?.error||s.status))})}</span>`},Z("tm-join").onclick=async()=>{let n=Z("tm-hub").value.trim(),a=Z("tm-code").value.trim(),s=Z("tm-join-out");if(s.style.display="",!n||!a){s.innerHTML=`<span class="err">${t("team.errHubCode")}</span>`;return}s.innerHTML=`<span class="muted">${t("team.joining")}</span>`;let o=await vt("/api/team/join-remote",{hubUrl:n,inviteCode:a});if(o.body?.ok)s.innerHTML=`<span class="ok">${t("team.joined",{name:i(o.body.teamName||"")})}</span>`,Z("tm-code").value="";else{let r=o.body?.error||o.status,d=r==="cannot_join_self"?t("team.joinErrSelf"):r==="deployment_already_joined"?t("team.joinErrAlready"):r==="hub_unreachable"?t("team.joinErrUnreachable"):r==="hub_timeout"?t("team.joinErrTimeout"):t("team.joinErrGeneric",{error:String(r)});s.innerHTML=`<span class="err">${i(String(d))}</span>`}},oa()}function Zi(){Z("tf-autobind").onclick=async()=>{let e=Z("tf-bind-out");e.style.display="",e.innerHTML=`<span class="muted">${t("team.identifying")}</span>`;let a=(await vt("/api/team/identity/auto-bind")).body;if(a?.ok&&a.owner){e.innerHTML=`<span class="ok">${t("team.bound2",{name:i(a.owner.name||a.owner.unionId)})}</span>`,Kt();return}if(a?.ok&&a.needChoice&&Array.isArray(a.candidates)){let s=a.candidates.map(o=>`<button class="tf-pickowner ghost" data-union="${i(o.unionId)}" style="margin:2px">${i(o.name||o.unionId)}</button>`).join(" ");e.innerHTML=`${t("team.multiCandidate")}<br>${s}`,e.querySelectorAll(".tf-pickowner").forEach(o=>{o.onclick=async()=>{e.innerHTML=`<span class="muted">${t("team.binding")}</span>`;let d=(await vt("/api/team/identity/auto-bind",{unionId:o.dataset.union})).body;d?.ok&&d.owner?(e.innerHTML=`<span class="ok">${t("team.bound2",{name:i(d.owner.name||d.owner.unionId)})}</span>`,Kt()):e.innerHTML=`<span class="err">${t("team.bindFail",{error:i(String(d?.error||"unknown"))})}</span>`}});return}if(a?.error==="no_candidates"){e.innerHTML=`<span class="err">${t("team.noCandidates")}</span>`;return}e.innerHTML=`<span class="err">${t("team.bindFail",{error:i(String(a?.error||"unknown"))})}</span>`}}async function sa(e){let n=await fetch(e);return{status:n.status,body:await n.json().catch(()=>({}))}}async function ra(e,n,a){let s=await fetch(n,{method:e,headers:{"content-type":"application/json"},body:a?JSON.stringify(a):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}function ee(e){return document.getElementById(e)}function kt(e){return(ee(e).value||"").trim()}var la=[],ca=[];function er(){return`<section class="page">
|
|
1063
1073
|
<div class="page-heading">
|
|
1064
1074
|
<div>
|
|
1065
1075
|
<p class="eyebrow">Webhook</p>
|
|
@@ -1121,11 +1131,11 @@ ${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 ia(){let e=ee("cn-kind").value,n=ee("cn-mode").value;document.querySelectorAll(".cn-wf").forEach(a=>{a.style.display=e==="workflow"?"":"none"}),document.querySelectorAll(".cn-fixed").forEach(a=>{a.style.display=n==="fixed"?"":"none"}),document.querySelectorAll(".cn-allow").forEach(a=>{a.style.display=n==="fixed"?"none":""}),document.querySelectorAll(".cn-dyn").forEach(a=>{a.style.display=n==="dynamic"?"":"none"}),document.querySelectorAll(".cn-life").forEach(a=>{a.style.display=n==="new-group"?"":"none"})}function Po(e){return`${location.origin}/webhook/${encodeURIComponent(e)}`}function tr(e){return e==="fixed"?t("connectors.modeLabelFixed"):e==="new-group"?t("connectors.modeLabelNewGroup"):t("connectors.modeLabelDynamic")}function nr(e){return e==="workflow"?t("connectors.kindLabelWorkflow"):t("connectors.kindLabelTurn")}function da(e){return ca.find(a=>a.chatId===e)?.name||e}function ar(e){return ca.filter(n=>n.bots.includes(e))}function Bo(){let e=ee("cn-bot").value,n=ar(e),a=m=>`<option value="${i(m.chatId)}">${i(m.name||m.chatId)}</option>`,s=ee("cn-chat-sel"),o=s.value;s.innerHTML=n.length?n.map(a).join(""):`<option value="">${t("connectors.noBotGroups")}</option>`,o&&n.some(m=>m.chatId===o)&&(s.value=o);let r=ee("cn-allow-sel"),d=new Set(Array.from(r.selectedOptions).map(m=>m.value));r.innerHTML=n.map(a).join(""),Array.from(r.options).forEach(m=>{d.has(m.value)&&(m.selected=!0)})}function or(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(a=>{let s=la.find(k=>k.larkAppId===a.target.botId),o=Po(a.id),r=(a.verify?.type??"token")==="token",d=r?t("connectors.badgeToken"):t("connectors.badgeSign"),m=a.target.mode==="fixed"&&a.target.chatId?` \xB7 ${t("connectors.dest",{name:i(da(a.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
1136
|
<b style="font-size:15px">${i(a.name)}</b>
|
|
1127
1137
|
<span class="${a.enabled?"ok":"muted"}" style="font-size:12px">${a.enabled?t("connectors.enabled"):t("connectors.disabled")}</span>
|
|
1128
|
-
<span class="muted" style="font-size:12px">\xB7 ${i(s?.botName||a.target.botId)} \xB7 ${nr(a.target.kind)} \xB7 ${tr(a.target.mode)}${
|
|
1138
|
+
<span class="muted" style="font-size:12px">\xB7 ${i(s?.botName||a.target.botId)} \xB7 ${nr(a.target.kind)} \xB7 ${tr(a.target.mode)}${m} \xB7 ${d}</span>
|
|
1129
1139
|
<span style="margin-left:auto;display:flex;gap:6px">
|
|
1130
1140
|
<button class="cn-toggle ghost" data-id="${i(a.id)}" data-on="${a.enabled}" style="font-size:12px">${a.enabled?t("connectors.btnDisable"):t("connectors.btnEnable")}</button>
|
|
1131
1141
|
<button class="cn-del ghost" data-id="${i(a.id)}" style="font-size:12px">${t("connectors.btnDel")}</button>
|
|
@@ -1134,15 +1144,15 @@ ${Co("manage")}
|
|
|
1134
1144
|
<div style="margin-top:6px;font-size:13px;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
1135
1145
|
<span class="muted">${t("connectors.webhookUrl")}</span><code style="font-size:12px;word-break:break-all">${i(o)}${r?"/<token>":""}</code>
|
|
1136
1146
|
<button class="cn-copy ghost" data-url="${i(o)}" style="font-size:12px">${t("connectors.copy")}</button>
|
|
1137
|
-
</div>${r?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.tokenHint")}</div>`:""}${a.target.mode==="dynamic"?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.dynamicReqHint")}</div>`:""}${a.promptEnvelope?.instruction?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.instructionPrefix")}${i(a.promptEnvelope.instruction)}</div>`:""}</div>`}).join(""),n.querySelectorAll(".cn-copy").forEach(a=>{a.onclick=()=>{navigator.clipboard?.writeText(a.dataset.url),a.textContent=t("connectors.copied"),setTimeout(()=>a.textContent=t("connectors.copy"),1200)}}),n.querySelectorAll(".cn-toggle").forEach(a=>{a.onclick=async()=>{await
|
|
1147
|
+
</div>${r?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.tokenHint")}</div>`:""}${a.target.mode==="dynamic"?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.dynamicReqHint")}</div>`:""}${a.promptEnvelope?.instruction?`<div class="muted" style="font-size:12px;margin-top:4px">${t("connectors.instructionPrefix")}${i(a.promptEnvelope.instruction)}</div>`:""}</div>`}).join(""),n.querySelectorAll(".cn-copy").forEach(a=>{a.onclick=()=>{navigator.clipboard?.writeText(a.dataset.url),a.textContent=t("connectors.copied"),setTimeout(()=>a.textContent=t("connectors.copy"),1200)}}),n.querySelectorAll(".cn-toggle").forEach(a=>{a.onclick=async()=>{await ra("PATCH","/api/connectors/"+encodeURIComponent(a.dataset.id),{enabled:a.dataset.on!=="true"}),$n()}}),n.querySelectorAll(".cn-del").forEach(a=>{a.onclick=async()=>{confirm(t("connectors.delConfirm"))&&(await ra("DELETE","/api/connectors/"+encodeURIComponent(a.dataset.id)),$n())}})}async function $n(){let[e,n,a]=await Promise.all([sa("/api/bots"),sa("/api/connectors"),sa("/api/groups")]);la=(e.body?.bots||[]).map(r=>({larkAppId:r.larkAppId,botName:r.botName||r.larkAppId})),ca=(a.body?.chats||[]).map(r=>({chatId:r.chatId,name:r.name||"",bots:(r.memberBots||[]).filter(d=>d.inChat).map(d=>d.larkAppId)}));let s=ee("cn-bot"),o=s.value;s.innerHTML=la.map(r=>`<option value="${i(r.larkAppId)}">${i(r.botName)}</option>`).join("")||`<option value="">${t("connectors.noOnlineBots")}</option>`,o&&(s.value=o),Bo(),or(n.body?.connectors||[])}function Oo(e){e.innerHTML=er(),ee("cn-kind").onchange=ia,ee("cn-mode").onchange=ia,ee("cn-bot").onchange=Bo,ee("cn-chat-manual").onclick=n=>{n.preventDefault();let a=ee("cn-chat"),s=ee("cn-chat-sel"),o=a.style.display==="none";a.style.display=o?"":"none",s.style.display=o?"none":"",ee("cn-chat-manual").textContent=o?t("connectors.chatListLink"):t("connectors.chatManualLink")},ia(),ee("cn-create").onclick=async()=>{let n=ee("cn-create-out"),a=kt("cn-name"),s=ee("cn-bot").value;if(!a){n.innerHTML=`<span class="err">${t("connectors.errName")}</span>`;return}if(!s){n.innerHTML=`<span class="err">${t("connectors.errBot")}</span>`;return}let o=ee("cn-kind").value,r=ee("cn-mode").value,d={name:a,enabled:!0,target:{kind:o,mode:r,botId:s},promptEnvelope:{sourceName:a}},m=kt("cn-instruction");if(m&&(d.promptEnvelope.instruction=m),o==="workflow"){if(!kt("cn-wf")){n.innerHTML=`<span class="err">${t("connectors.errWf")}</span>`;return}d.target.workflowId=kt("cn-wf")}if(r==="fixed"){let y=ee("cn-chat").style.display!=="none"?kt("cn-chat"):ee("cn-chat-sel").value;if(!y){n.innerHTML=`<span class="err">${t("connectors.errChat")}</span>`;return}d.target.chatId=y}else{let M=Array.from(ee("cn-allow-sel").selectedOptions).map(y=>y.value).filter(Boolean);M.length&&(d.target.allowChats=M)}if(r==="new-group"){let M=kt("cn-dedup");d.lifecycleExtractors=M?{dedupKey:M}:null}d.verify={type:ee("cn-verify").value};let k=kt("cn-secret");k&&(d.secret=k),n.innerHTML=`<span class="muted">${t("connectors.creating")}</span>`;let $=await ra("POST","/api/connectors",d);if($.status===201&&$.body?.ok){n.innerHTML="";let M=ee("cn-created");M.style.display="";let y=$.body.webhookUrl||Po($.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(y)}?chatId=${i(C)}`:i(y),x;if(S&&E){let T=C!=="<chatId>"?`\uFF08${i(da(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(a)})}${r==="fixed"&&d.target.chatId?`<span class="muted" style="font-weight:400;font-size:13px"> \xB7 ${t("connectors.createdDest",{name:i(
|
|
1143
|
-
<p style="margin:4px 0;font-size:13px"><span class="muted">${t("connectors.webhookUrl")}</span><code style="word-break:break-all">${i(
|
|
1144
|
-
${
|
|
1145
|
-
${
|
|
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(a)})}${r==="fixed"&&d.target.chatId?`<span class="muted" style="font-weight:400;font-size:13px"> \xB7 ${t("connectors.createdDest",{name:i(da(d.target.chatId))})}</span>`:""}</p>
|
|
1153
|
+
<p style="margin:4px 0;font-size:13px"><span class="muted">${t("connectors.webhookUrl")}</span><code style="word-break:break-all">${i(y)}</code></p>
|
|
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,Vt=null,Jt=!0;function No(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 sr(e,n){let a=e?.[n]??{};return{enabled:a.enabled===!0,time:typeof a.time=="string"?a.time:"04:00"}}function ir(){return`<section class="page">
|
|
1146
1156
|
<div class="page-heading">
|
|
1147
1157
|
<div>
|
|
1148
1158
|
<p class="eyebrow">${t("nav.settings")}</p>
|
|
@@ -1151,7 +1161,7 @@ ${Co("manage")}
|
|
|
1151
1161
|
</div>
|
|
1152
1162
|
</div>
|
|
1153
1163
|
<div id="settings-body"></div>
|
|
1154
|
-
</section>`}function rr(e){let{enabled:n,time:a}=sr(
|
|
1164
|
+
</section>`}function rr(e){let{enabled:n,time:a}=sr(Se.maintenance,"autoUpdate"),s=e?"disabled":"";return`<label class="toggle-row">
|
|
1155
1165
|
<input type="checkbox" data-maint="autoUpdate" ${n?"checked":""} ${s}>
|
|
1156
1166
|
<span class="switch" aria-hidden="true"></span>
|
|
1157
1167
|
<span class="toggle-tx"><strong>${t("settings.autoUpdate")}</strong>
|
|
@@ -1162,17 +1172,17 @@ ${Co("manage")}
|
|
|
1162
1172
|
<input type="time" data-maint-time="autoUpdate" value="${i(a)}" ${s}>
|
|
1163
1173
|
</label>
|
|
1164
1174
|
</div>`}function lr(e){return`<label class="toggle-row">
|
|
1165
|
-
<input type="checkbox" data-maint="autoRestart" ${
|
|
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 dr(){if(
|
|
1179
|
+
</label>`}function dr(){if(Vt)return`<p class="hint-warn">${t("settings.loadFailed")}: ${i(Vt)}</p>`;if(!Se)return`<p class="empty">${t("settings.loading")}</p>`;let e=Jt?"":"disabled",n=!Jt||Se.localDevInstall;return`<div class="settings-grid">
|
|
1170
1180
|
<article class="bd-card settings-card">
|
|
1171
|
-
${
|
|
1181
|
+
${Jt?"":`<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,8 +1202,8 @@ ${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>
|
|
@@ -1201,14 +1211,14 @@ ${Co("manage")}
|
|
|
1201
1211
|
<section class="bd-section">
|
|
1202
1212
|
<h3 class="bd-section-title">${t("settings.sectionMaintenance")}</h3>
|
|
1203
1213
|
${rr(n)}
|
|
1204
|
-
${
|
|
1205
|
-
${lr(!
|
|
1214
|
+
${Se.localDevInstall?`<p class="hint-warn">${t("settings.autoUpdateLocalDev")}</p>`:""}
|
|
1215
|
+
${lr(!Jt||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 cr(){try{let e=await fetch("/api/settings"),n=await e.json().catch(()=>({}));if(!e.ok){
|
|
1221
|
+
</div>`}async function cr(){try{let e=await fetch("/api/settings"),n=await e.json().catch(()=>({}));if(!e.ok){Se=null,Vt=n?.error??`HTTP ${e.status}`;return}Se=No(n.settings),Jt=n.authed===!0,Vt=null}catch(e){Se=null,Vt=e?.message??String(e)}}async function qo(e){e.innerHTML=ir();let n=e.querySelector("#settings-body");function a(){n.innerHTML=dr(),r()}function s(){return n.querySelector("[data-settings-status]")}async function o(d,m,k){if(!Se)return;k.disabled=!0;let $=s();$&&($.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)}),y=await M.json().catch(()=>({}));if(!M.ok||y.ok===!1)throw new Error(y?.error??`HTTP ${M.status}`);Se=No(y.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;o({[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";o({[k]:m.value},()=>{m.value=$},m)})});let d=(m,k,$)=>{let y=n.querySelector(`input[data-maint="${m}"]`)?.checked??!1,p;if(m==="autoUpdate"){let S=n.querySelector('input[data-maint-time="autoUpdate"]');p={enabled:y,time:S?.value||"04:00"}}else p={enabled:y};o({maintenance:{[m]:p}},$,k).then(()=>a())};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=$})})})}a(),await cr(),a()}function ur(){let e=[["",t("workflow.filter.nonTerminal")],["all",t("workflow.filter.all")],["pending",pt("pending")],["running",pt("running")],["waiting",pt("waiting")],["succeeded",pt("succeeded")],["failed",pt("failed")],["cancelled",pt("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>
|
|
@@ -1228,15 +1238,15 @@ ${Co("manage")}
|
|
|
1228
1238
|
</tr></thead>
|
|
1229
1239
|
<tbody id="wf-tbody"></tbody>
|
|
1230
1240
|
</table>
|
|
1231
|
-
`}var pr=5e3,mr=2e3,
|
|
1241
|
+
`}var pr=5e3,mr=2e3,Yt=new Set(["succeeded","failed","cancelled"]);function h(e){return e.replace(/[&<>"']/g,n=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[n])}function fr(e){let n=new Date(e),s=Date.now()-e;return s<6e4?t("time.secondsAgo",{value:Math.max(1,Math.floor(s/1e3))}):s<36e5?t("time.minutesAgo",{value:Math.floor(s/6e4)}):s<864e5?t("time.hoursAgo",{value:Math.floor(s/36e5)}):n.toISOString().slice(0,19).replace("T"," ")}function ot(e){return`<span class="${Yt.has(e)?"wf-status terminal":"wf-status live"} wf-status-${h(e)}">${h(pt(e))}</span>`}function pt(e){let n=`workflow.status.${e}`,a=t(n);return a===n?e:a}function Go(e){let n=location.hash.match(/^#\/workflows\/([^?#]+)(?:\?([^#]*))?$/);if(n){let a=new URLSearchParams(n[2]??"");return br(e,decodeURIComponent(n[1]),{focusAttemptId:a.get("attempt")??void 0})}return gr(e)}function gr(e){e.innerHTML=ur();let n=e.querySelector("#wf-tbody"),a=e.querySelector("#wf-filters"),s=e.querySelector("#wf-last-load"),o=[],r=null,d=!1,m=null,k=!1;function $(C){let x=(new FormData(a).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=$(o);if(C.length===0){n.innerHTML=`<tr><td colspan="7" class="empty">${m?h(t("workflow.list.failedLoad",{error:m})):o.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>${
|
|
1244
|
+
<td>${ot(L.status)}${L.failedNodeId?` <span class="muted">(${h(L.failedNodeId)})</span>`:""}${u}</td>
|
|
1235
1245
|
<td>${L.lastSeq}</td>
|
|
1236
|
-
<td class="${T}">${
|
|
1246
|
+
<td class="${T}">${x}</td>
|
|
1237
1247
|
<td title="${h(new Date(L.updatedAt).toISOString())}">${fr(L.updatedAt)}</td>
|
|
1238
|
-
<td>${
|
|
1239
|
-
</tr>`}).join("")}function
|
|
1248
|
+
<td>${q}</td>
|
|
1249
|
+
</tr>`}).join("")}function y(){m?(s.textContent=t("workflow.list.error",{error:m}),s.classList.add("error")):(s.textContent=t("workflow.list.loaded",{count:o.length,time:new Date().toLocaleTimeString()}),s.classList.remove("error"))}async function p(){if(!(k||d)&&!document.hidden){d=!0;try{let C=a.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?(o=(await T.json()).runs??[],m=null):(m=`HTTP ${T.status}`,o=[])}catch(C){m=C?.message??String(C),o=[]}finally{d=!1,k||(M(),y())}}}function S(){r!==null&&window.clearTimeout(r),r=window.setTimeout(async()=>{await p(),k||S()},pr)}function E(){document.hidden||p()}return a.addEventListener("input",()=>{M()}),a.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 br(e,n,a={}){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,84 +1302,84 @@ ${Co("manage")}
|
|
|
1292
1302
|
</div>
|
|
1293
1303
|
<div id="wf-event-meta" class="muted"></div>
|
|
1294
1304
|
</section>
|
|
1295
|
-
`;let s=e.querySelector("#wf-detail-subtitle"),o=e.querySelector("#wf-detail-refresh"),r=e.querySelector("#wf-detail-error"),d=e.querySelector("#wf-cancel-status"),
|
|
1305
|
+
`;let s=e.querySelector("#wf-detail-subtitle"),o=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"),y=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,w=null,A=!1,P=0,U=null,O=!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,we=0,fe=a.focusAttemptId;function ae(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 Oe(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)=>Qt(K.eventId)-Qt(ge.eventId)))}async function Ze(){await Me();let H=await Fe(new URLSearchParams({tail:"100"}));R=[],q=new Set,Oe(H.events,"append"),u=H.oldestSeq,w=H.newestSeq,A=H.hasOlder,P=H.totalCount,he()}async function Ne(){if(!(O||Q||document.hidden)){Q=!0;try{if(await Me(),w!==null){let H=await Fe(new URLSearchParams({afterSeq:String(w),limit:"200"}));Oe(H.events,"append"),H.newestSeq!==null&&(w=H.newestSeq),u===null&&H.oldestSeq!==null&&(u=H.oldestSeq),P=H.totalCount}else{let H=await Fe(new URLSearchParams({tail:"1"}));Oe(H.events,"append"),u=H.oldestSeq,w=H.newestSeq,A=H.hasOlder,P=H.totalCount}ae(null),he()}catch(H){ae(H?.message??String(H))}finally{Q=!1}}}async function Pe(){if(!(u===null||!A)){x.disabled=!0;try{let H=await Fe(new URLSearchParams({beforeSeq:String(u),limit:"100"}));Oe(H.events,"prepend"),H.oldestSeq!==null&&(u=H.oldestSeq),A=H.hasOlder,P=H.totalCount,ae(null),he()}catch(H){ae(H?.message??String(H))}finally{x.disabled=!1}}}async function et(){if(!T||Yt.has(T.run.status)||re)return;if(!T.chatBinding?.larkAppId){ae(t("workflow.detail.cancelUnavailable",{runId:n}));return}let H=wr(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),ae(null),await Ne()}catch(G){ae(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 st(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})}),ae(null),await Ne()}catch(G){let K=G?.message??String(G);ce.set(H,{kind:"error",text:K}),ae(K)}finally{me.delete(H),he()}}}function he(){if(!T)return;we=S.scrollTop;let H=T.run;Yt.has(H.status)&&de(null),s.innerHTML=`${h(H.workflowId??"?")} \xB7 ${ot(H.status)} \xB7 lastSeq ${T.lastSeq}`,o.textContent=t("workflow.detail.refreshed",{time:new Date().toLocaleTimeString()}),L.hidden=Yt.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}),hr(m,T),vr(k,T),kr($,M,T,R),Mr(y,T),Er(p,T,le,te,{comments:ne,statuses:ce,resolving:me,onResolve:Bt},{sessions:be,pending:ie,errors:Ue,onStart:Pt,onEnd:st},fe,Xe)&&(fe=void 0),el(E,R),S.scrollTop=we,x.hidden=!A,C.textContent=t("workflow.detail.eventsLoaded",{loaded:R.length,total:P})}function it(){if(U!==null&&window.clearTimeout(U),T&&Yt.has(T.run.status)){U=null;return}U=window.setTimeout(async()=>{await Ne(),O||it()},mr)}function tt(){document.hidden||Ne().then(()=>{!O&&U===null&&it()})}return x.addEventListener("click",()=>{Pe()}),L.addEventListener("click",()=>{et()}),document.addEventListener("visibilitychange",tt),Ze().then(()=>{ae(null),O||it()}).catch(H=>{ae(H?.message??String(H)),s.textContent=t("workflow.detail.loadFailed")}),()=>{O=!0,U!==null&&window.clearTimeout(U),document.removeEventListener("visibilitychange",tt)}}function hr(e,n){let a=n.run,s=[[t("workflow.summary.workflow"),h(a.workflowId??"?")],[t("workflow.summary.status"),ot(a.status)],[t("workflow.summary.lastSeq"),String(n.lastSeq)],[t("workflow.summary.updated"),h(new Date(n.updatedAt).toLocaleString())],[t("workflow.summary.revision"),h(Tn(a.revisionId))],[t("workflow.summary.initiator"),h(a.initiator??"-")]];a.failedNodeId&&s.push([t("workflow.summary.failedNode"),h(a.failedNodeId)]),a.cancelOriginEventId&&s.push([t("workflow.summary.cancelOrigin"),h(a.cancelOriginEventId)]),n.chatBinding&&(s.push([t("workflow.summary.chat"),`<code>${h(n.chatBinding.chatId)}</code>`]),s.push([t("workflow.summary.app"),`<code>${h(n.chatBinding.larkAppId)}</code>`])),e.innerHTML=s.map(([o,r])=>`<div class="wf-summary-item"><span>${o}</span><strong>${r}</strong></div>`).join("")}function yr(e){if(!e.errorCode)return"";let n=e.errorMessage?` \u2014 ${ol(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 wr(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 vr(e,n){let a=n.dangling,s=[[t("workflow.dangling.activities"),a.activities],[t("workflow.dangling.effects"),a.effectAttempted],[t("workflow.dangling.waits"),a.waits],[t("workflow.dangling.cancels"),a.cancels]],o=new Set(s.flatMap(([,r])=>r)).size;if(e.className=o>0?"wf-panel wf-dangling-panel has":"wf-panel wf-dangling-panel",o===0){e.innerHTML=`<div class="wf-panel-title"><h3>${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">${o}</span></div>
|
|
1298
1308
|
<div class="wf-dangling-grid">
|
|
1299
|
-
${s.map(([r,d])=>`<div><strong>${r}</strong>${d.length===0?`<div class="muted">${h(t("workflow.detail.none"))}</div>`:`<ul>${d.map(
|
|
1300
|
-
</div>`}function kr(e,n,a,s){let o=$r(s,a);if(o.length===0){n.textContent="",e.innerHTML=`<div class="empty">${h(t("workflow.detail.noParallelData"))}</div>`;return}let r=Date.now(),d=Math.min(...o.map(
|
|
1301
|
-
<span title="${h(new Date(d).toISOString())}">${h(
|
|
1302
|
-
<span title="${h(new Date(
|
|
1309
|
+
${s.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 kr(e,n,a,s){let o=$r(s,a);if(o.length===0){n.textContent="",e.innerHTML=`<div class="empty">${h(t("workflow.detail.noParallelData"))}</div>`;return}let r=Date.now(),d=Math.min(...o.map(p=>p.startedAt)),m=Math.max(...o.map(p=>p.endedAt??r),d+1e3),k=Math.max(1,m-d),$=Lr(o,r),M=o.filter(p=>!p.endedAt&&(p.status==="running"||p.status==="effectAttempting")).length;n.textContent=t("workflow.detail.parallelMeta",{count:o.length,max:$,running:M});let y=o.sort((p,S)=>p.startedAt-S.startedAt||p.activityId.localeCompare(S.activityId)).map(p=>Sr(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">${
|
|
1314
|
+
<div class="wf-parallel-list">${y}</div>`}function $r(e,n){let a=new Map,s=new Map(n.activities.map(o=>[o.activityId,o.ownerNodeId]));for(let o of[...e].sort((r,d)=>Qt(r.eventId)-Qt(d.eventId))){let r=al(o);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=a.get(m);if(o.type==="attemptCreated"){let $=typeof r.attemptNumber=="number"?r.attemptNumber:void 0;k={nodeId:typeof r.nodeId=="string"?r.nodeId:s.get(d),activityId:d,attemptId:m,attemptNumber:$,status:"pending",startedAt:o.timestamp},a.set(m,k);continue}k||(k={nodeId:s.get(d),activityId:d,attemptId:m,status:"pending",startedAt:o.timestamp},a.set(m,k)),o.type==="activityRunning"?(k.status="running",k.runningAt=o.timestamp):o.type==="effectAttempted"?k.status="effectAttempting":o.type==="activityWaiting"||o.type==="waitCreated"?k.status="waiting":Tr(o.type)&&(k.status=Ir(o.type),k.endedAt=o.timestamp,k.endType=o.type)}return[...a.values()]}function Sr(e,n,a,s){let o=e.endedAt??s,r=Fo((e.startedAt-n)/a*100,0,100),d=Fo((Math.max(o,e.startedAt+1)-e.startedAt)/a*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(pt(e.status))}</span>
|
|
1313
1323
|
</div>
|
|
1314
1324
|
</div>
|
|
1315
|
-
</div>`}function Lr(e,n){let a=[];for(let r of e)a.push({time:r.startedAt,delta:1}),a.push({time:r.endedAt??n,delta:-1});a.sort((r,d)=>r.time-d.time||d.delta-r.delta);let s=0,o=0;for(let r of a)s+=r.delta,o=Math.max(o,s);return o}function Tr(e){return e==="activitySucceeded"||e==="activityFailed"||e==="activityTimedOut"||e==="activityCanceled"}function Ir(e){return e==="activitySucceeded"?"succeeded":e==="activityCanceled"?"cancelled":e==="activityTimedOut"?"timedOut":"failed"}function Mr(e,n){let a=new Map(n.activities.map(r=>[r.activityId,r])),s=new Set,o=[];for(let r of n.nodes){let d=(r.activityId?a.get(r.activityId):void 0)??n.activities.find(
|
|
1325
|
+
</div>`}function Lr(e,n){let a=[];for(let r of e)a.push({time:r.startedAt,delta:1}),a.push({time:r.endedAt??n,delta:-1});a.sort((r,d)=>r.time-d.time||d.delta-r.delta);let s=0,o=0;for(let r of a)s+=r.delta,o=Math.max(o,s);return o}function Tr(e){return e==="activitySucceeded"||e==="activityFailed"||e==="activityTimedOut"||e==="activityCanceled"}function Ir(e){return e==="activitySucceeded"?"succeeded":e==="activityCanceled"?"cancelled":e==="activityTimedOut"?"timedOut":"failed"}function Mr(e,n){let a=new Map(n.activities.map(r=>[r.activityId,r])),s=new Set,o=[];for(let r of n.nodes){let d=(r.activityId?a.get(r.activityId):void 0)??n.activities.find(m=>m.ownerNodeId===r.nodeId);d&&s.add(d.activityId),o.push(jo(r,d))}for(let r of n.activities)s.has(r.activityId)||o.push(jo(void 0,r));e.innerHTML=o.length>0?o.join(""):`<tr><td colspan="7" class="empty">${h(t("workflow.detail.noNodes"))}</td></tr>`}function jo(e,n){let a=n?.attempts[n.attempts.length-1];return`<tr>
|
|
1316
1326
|
<td>${e?`<code>${h(e.nodeId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
1317
|
-
<td>${e?
|
|
1327
|
+
<td>${e?ot(e.status):'<span class="muted">-</span>'}</td>
|
|
1318
1328
|
<td>${n?`<code>${h(n.activityId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
1319
|
-
<td>${n?
|
|
1329
|
+
<td>${n?ot(n.status):'<span class="muted">-</span>'}</td>
|
|
1320
1330
|
<td>${n?.attempts.length??0}</td>
|
|
1321
1331
|
<td>${a?`<code>${h(a.attemptId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
1322
1332
|
<td>${a?Zr(a):`<span class="muted">${h(t("workflow.detail.idle"))}</span>`}</td>
|
|
1323
|
-
</tr>`}function Er(e,n,a,s,o,r,d,
|
|
1333
|
+
</tr>`}function Er(e,n,a,s,o,r,d,m){Kr(e,a,s),Gr(e,o.comments);let k=!!(d&&n.attemptIO?.[d]?.terminal);k&&d&&a.add(ua(d,t("workflow.detail.liveTerminal")));let $=xr(n),M=new Set;if(m){for(let p of $){M.add(p.key);let S=m.get(p.key);S||(S=Hr(p.key),m.set(p.key,S),e.appendChild(S.article)),Cr(S,p,a,o,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,a,o,r,d));e.innerHTML=p.length>0?p.join(""):`<div class="empty">${h(t("workflow.detail.noNodeIO"))}</div>`}Vr(e,s);let y=Wr(e,d);return Jr(e,a),Yr(e,s),zr(e,o),Xo(e,r),y&&k}function xr(e){let n=new Map(e.activities.map(o=>[o.activityId,o])),a=new Set,s=[];for(let o of e.nodes){let r=(o.activityId?n.get(o.activityId):void 0)??e.activities.find(d=>d.ownerNodeId===o.nodeId);if(!r){s.push({key:`node:${o.nodeId}`,node:o});continue}a.add(r.activityId),s.push({key:`activity:${r.activityId}`,node:o,activity:r,io:e.attemptIO?.[Sn(r)?.attemptId??""]})}for(let o of e.activities)a.has(o.activityId)||s.push({key:`activity:${o.activityId}`,activity:o,io:e.attemptIO?.[Sn(o)?.attemptId??""]});return s}function Hr(e){let n=document.createElement("article");n.className="wf-io-card",n.dataset.wfCardKey=e;let a=document.createElement("div");a.className="wf-io-card-head";let s=document.createElement("div");s.className="wf-io-terminal-slot";let o=document.createElement("div");return o.className="wf-io-grid",n.appendChild(a),n.appendChild(s),n.appendChild(o),{article:n,head:a,terminalSlot:s,grid:o,currentTerminalUrl:null}}function Cr(e,n,a,s,o,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 $=Qo(d,s);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
|
-
<div>${n.node?
|
|
1339
|
+
<div>${n.node?ot(n.node.status):""} ${n.activity?ot(n.activity.status):""}</div>
|
|
1330
1340
|
</header>
|
|
1331
1341
|
<div class="wf-io-meta">
|
|
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 _o(e,n,a,s){if(!a||a.error)return null;if(Or(e,a))return{kind:"live",url:qr(a)};if(!e||!n||!Nr(e,a))return null;let o=Ur();if(!o)return null;let r=s?.sessions.get(e.attemptId);return r?{kind:"resume",url:r.url,resumeId:r.resumeId,downloadUrl:Uo(o,n.activityId,e.attemptId)}:{kind:"replay",url:jr(o,n.activityId,e.attemptId,!!a.hasPtyLog),downloadUrl:Uo(o,n.activityId,e.attemptId)}}function
|
|
1342
|
-
<summary>${h(
|
|
1345
|
+
`;let M=_o(d,n.activity,n.io?.terminal,o),y=M?.url??null;if(y!==e.currentTerminalUrl)M===null?e.terminalSlot.innerHTML="":e.terminalSlot.innerHTML=zo(n.key,d,n.activity,n.io?.terminal,M,a,o),e.currentTerminalUrl=y;else if(M!==null&&n.io?.terminal){let S=e.terminalSlot.querySelector("details.wf-terminal-block > summary");if(S){let E=Wo(M.kind);S.innerHTML=`${h(E)} ${Yo(d,n.io.terminal)}`}d&&_r(e.terminalSlot,d,n.activity,n.io.terminal,M,o)}let p=d?.attemptId??n.activity?.activityId??n.node?.nodeId??"unknown";e.grid.innerHTML=`
|
|
1346
|
+
${Qe(p,t("workflow.detail.authoredInput"),n.io?.input,a)}
|
|
1347
|
+
${Qe(p,t("workflow.detail.resolvedInput"),n.io?.resolvedInput,a)}
|
|
1348
|
+
${Qe(p,t("workflow.detail.output"),n.io?.output,a)}
|
|
1349
|
+
${Qe(p,t("workflow.detail.executionLog"),n.io?.log,a)}
|
|
1350
|
+
${n.io?.waitPrompt?Qe(p,t("workflow.detail.waitPrompt"),n.io.waitPrompt,a):""}
|
|
1351
|
+
`}function _o(e,n,a,s){if(!a||a.error)return null;if(Or(e,a))return{kind:"live",url:qr(a)};if(!e||!n||!Nr(e,a))return null;let o=Ur();if(!o)return null;let r=s?.sessions.get(e.attemptId);return r?{kind:"resume",url:r.url,resumeId:r.resumeId,downloadUrl:Uo(o,n.activityId,e.attemptId)}:{kind:"replay",url:jr(o,n.activityId,e.attemptId,!!a.hasPtyLog),downloadUrl:Uo(o,n.activityId,e.attemptId)}}function zo(e,n,a,s,o,r,d){if(!s)return"";let m=Wo(o.kind),k=ua(e,m),$=Yo(n,s),M=Ar(o.kind),y=o.kind==="replay"||o.kind==="resume"?`<a class="btn-link" href="${h(o.downloadUrl)}" download>${h(t("workflow.detail.downloadFullLog"))}</a>`:"",p=n?Jo(n,a,s,o,d):"",S=n?Vo(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(o.url)}" target="_blank" rel="noreferrer">${h(
|
|
1345
|
-
${
|
|
1346
|
-
${
|
|
1354
|
+
<a class="btn-link" href="${h(o.url)}" target="_blank" rel="noreferrer">${h(M)}</a>
|
|
1355
|
+
${y}
|
|
1356
|
+
${p}
|
|
1347
1357
|
</div>
|
|
1348
1358
|
${S}
|
|
1349
|
-
<iframe class="wf-terminal-frame" src="${h(o.url)}" title="${h(
|
|
1350
|
-
</details>`}function
|
|
1359
|
+
<iframe class="wf-terminal-frame" src="${h(o.url)}" title="${h(m)}" loading="lazy"></iframe>
|
|
1360
|
+
</details>`}function Wo(e){return e==="live"?t("workflow.detail.liveTerminal"):e==="resume"?t("workflow.detail.terminalResume"):t("workflow.detail.terminalReplay")}function Ar(e){return e==="live"?t("workflow.detail.openTerminalNewTab"):e==="resume"?t("workflow.detail.openResumeNewTab"):t("workflow.detail.openReplayNewTab")}var Ko=new Set(["antigravity","codex-app","cursor","mira"]),Dr=new Set(["aiden","coco","claude-code","seed","relay","codex","mtr","hermes","pi","mir"]);function Rr(e){return!!e&&(Dr.has(e)||Ko.has(e))}function Pr(e){return!!e&&Ko.has(e)}function Jo(e,n,a,s,o){if(!o||s.kind==="live"||!n)return"";let r=s.kind==="resume",d=o.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>`:Rr(a.cliId)?Pr(a.cliId)&&!a.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:a.cliId??"?"}))}">${h(t("workflow.detail.resumeSession"))}</button>`}function Vo(e,n){if(!n)return"";let a=n.errors.get(e);return a?`<div class="hint-warn wf-resume-status" data-wf-resume-status="${h(e)}">${h(a)}</div>`:""}function Br(e,n,a,s,o){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=Qo(r,a),$=r?.attemptId===o?" is-focused":"",M=r?` data-wf-attempt-card="${h(r.attemptId)}"`:"",y=_o(r,e.activity,e.io?.terminal,s),p=y?zo(m,r,e.activity,e.io?.terminal,y,n,s):"";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>
|
|
1354
1364
|
<strong><code>${h(d)}</code></strong>
|
|
1355
1365
|
<span class="muted">${e.activity?h(e.activity.activityId):h(t("workflow.detail.notDispatched"))}</span>
|
|
1356
1366
|
</div>
|
|
1357
|
-
<div>${e.node?
|
|
1367
|
+
<div>${e.node?ot(e.node.status):""} ${e.activity?ot(e.activity.status):""}</div>
|
|
1358
1368
|
</header>
|
|
1359
1369
|
<div class="wf-io-meta">
|
|
1360
1370
|
${r?`${h(t("workflow.detail.attempt"))} <code>${h(r.attemptId)}</code>`:h(t("workflow.detail.noAttempt"))}
|
|
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 Yo(e,n){let a=[];return n.error?a.push(t("workflow.detail.error")):a.push(n.status==="live"?t("workflow.detail.terminalLive"):t("workflow.detail.terminalClosedShort")),e?.status&&a.push(e.status),n.webPort>0&&a.push(`:${n.webPort}`),`<span class="muted">${h(a.join(" \xB7 "))}</span>`}function Or(e,n){return n.status==="live"&&n.webPort>0&&(e?.status==="pending"||e?.status==="running"||e?.status==="effectAttempting")}function Nr(e,n){return e.status==="succeeded"||e.status==="failed"||e.status==="cancelled"||e.status==="timedOut"?!!(n.sessionId||n.startedAt):!1}function qr(e){return`http://${window.location.hostname||"127.0.0.1"}:${e.webPort}`}function jr(e,n,a,s){let o=new URLSearchParams({runId:e,activityId:n,attemptId:a});return s&&o.set("hasPtyLog","1"),`/assets/terminal-replay.html?${o.toString()}`}function Uo(e,n,a){return`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(n)}/${encodeURIComponent(a)}/terminal-log/raw?download=1`}function Ur(){let e=window.location.hash.match(/^#\/workflows\/([^/?#]+)/);if(!e)return null;try{return decodeURIComponent(e[1])}catch{return null}}function Qo(e,n){if(!Fr(e))return"";let a=e.attemptId,s=n.comments.get(a)??"",o=n.resolving.has(a),r=n.statuses.get(a),d=r?.kind==="error"?"hint-warn":"hint-ok";return`<div class="wf-approval-box" data-wf-approval="${h(a)}">
|
|
1373
1383
|
<label>
|
|
1374
1384
|
<span>${h(t("workflow.detail.approvalComment"))}</span>
|
|
1375
1385
|
<textarea class="wf-approval-comment" data-wf-approval-comment="${h(a)}" rows="2" placeholder="${h(t("workflow.detail.optionalComment"))}"${o?" disabled":""}>${h(s)}</textarea>
|
|
@@ -1380,138 +1390,138 @@ ${Co("manage")}
|
|
|
1380
1390
|
${o?`<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 Fr(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function Gr(e,n){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(a=>{let s=a.dataset.wfApprovalComment;s&&n.set(s,a.value)})}function Xo(e,n){e.querySelectorAll("button[data-wf-resume-action][data-wf-resume-attempt][data-wf-resume-activity]").forEach(a=>{a.dataset.wfResumeBound!=="1"&&(a.dataset.wfResumeBound="1",a.addEventListener("click",()=>{let s=a.dataset.wfResumeAttempt,o=a.dataset.wfResumeActivity,r=a.dataset.wfResumeAction;!s||!o||(r==="start"?n.onStart(s,o):r==="end"&&n.onEnd(s,o))}))})}function _r(e,n,a,s,o,r){let d=e.querySelector(".wf-terminal-actions");if(!d)return;let
|
|
1393
|
+
</div>`}function Fr(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function Gr(e,n){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(a=>{let s=a.dataset.wfApprovalComment;s&&n.set(s,a.value)})}function Xo(e,n){e.querySelectorAll("button[data-wf-resume-action][data-wf-resume-attempt][data-wf-resume-activity]").forEach(a=>{a.dataset.wfResumeBound!=="1"&&(a.dataset.wfResumeBound="1",a.addEventListener("click",()=>{let s=a.dataset.wfResumeAttempt,o=a.dataset.wfResumeActivity,r=a.dataset.wfResumeAction;!s||!o||(r==="start"?n.onStart(s,o):r==="end"&&n.onEnd(s,o))}))})}function _r(e,n,a,s,o,r){let d=e.querySelector(".wf-terminal-actions");if(!d)return;let m=d.querySelector('button[data-wf-resume-button="1"]'),k=Jo(n,a,s,o,r);m?m.outerHTML=k:k&&d.insertAdjacentHTML("beforeend",k);let $=e.querySelector("details.wf-terminal-block");if($){let M=$.querySelector(".wf-resume-status"),y=Vo(n.attemptId,r);M?M.outerHTML=y:y&&d.insertAdjacentHTML("afterend",y)}Xo(e,r)}function zr(e,n){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(a=>{let s=a.dataset.wfApprovalComment;s&&a.addEventListener("input",()=>{n.comments.set(s,a.value)})}),e.querySelectorAll("button[data-wf-approval-action][data-wf-attempt-id]").forEach(a=>{a.addEventListener("click",()=>{let s=a.dataset.wfAttemptId,o=a.dataset.wfApprovalAction;!s||o!=="approve"&&o!=="reject"||n.onResolve(s,o)})})}function Qe(e,n,a,s){let o=ua(e,n);return`<details class="wf-io-block" data-io-key="${h(o)}"${s.has(o)?" open":""}>
|
|
1384
1394
|
<summary>${h(n)} ${Qr(a)}</summary>
|
|
1385
1395
|
${Xr(a)}
|
|
1386
|
-
</details>`}function
|
|
1387
|
-
<td>${
|
|
1396
|
+
</details>`}function ua(e,n){return`${e}:${n}`}function Wr(e,n){if(!n)return!1;for(let a of e.querySelectorAll("[data-wf-attempt-card]"))if(a.dataset.wfAttemptCard===n)return a.scrollIntoView({block:"center"}),!0;return!1}function Kr(e,n,a){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(s=>{let o=s.dataset.ioKey;if(!o)return;s.open?n.add(o):n.delete(o);let r=s.querySelector(".wf-io-pre");r&&a.set(o,r.scrollTop)})}function Jr(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(a=>{a.dataset.ioToggleBound!=="1"&&(a.dataset.ioToggleBound="1",a.addEventListener("toggle",()=>{let s=a.dataset.ioKey;s&&(a.open?n.add(s):n.delete(s))}))})}function Vr(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(a=>{let s=a.dataset.ioKey;if(!s)return;let o=n.get(s);if(o===void 0)return;let r=a.querySelector(".wf-io-pre");r&&(r.scrollTop=o)})}function Yr(e,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(a=>{let s=a.dataset.ioKey;if(!s)return;let o=a.querySelector(".wf-io-pre");o&&o.dataset.ioScrollBound!=="1"&&(o.dataset.ioScrollBound="1",o.addEventListener("scroll",()=>{n.set(s,o.scrollTop)}))})}function Qr(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 Xr(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??"",a=e.error?`<div class="muted error">${h(e.error)}</div>`:"";return n?`${a}<pre class="wf-io-pre">${h(n)}</pre>`:`${a}<div class="muted wf-io-empty">${h(t("workflow.detail.noPreview"))}</div>`}function Zr(e){let n=[];if(e.effectAttempted&&n.push(`${h(t("workflow.detail.effect"))} ${h(e.effectAttempted.provider)}`),e.wait){let a=e.wait.resolution?`${e.wait.resolution.kind}${e.wait.resolution.resolution?":"+e.wait.resolution.resolution:""}`:t("workflow.detail.open");n.push(`${h(t("workflow.detail.wait"))} ${h(e.wait.waitKind)} ${h(a)}`),e.wait.deadlineAt!==void 0&&n.push(`${h(t("workflow.detail.deadline"))} ${h(Ln(e.wait.deadlineAt))}`)}if(e.error){let a=`${e.error.errorCode}${e.error.errorClass?` \xB7 ${e.error.errorClass}`:""}`;n.push(`<span class="muted error">${h(a)}</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 el(e,n){e.innerHTML=n.length>0?n.map(tl).join(""):`<tr><td colspan="7" class="empty">${h(t("workflow.detail.noEvents"))}</td></tr>`}function tl(e){let n=nl(e.payload);return`<tr>
|
|
1397
|
+
<td>${Qt(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 Qt(e){let n=e.lastIndexOf("-");if(n<0)return 0;let a=Number(e.slice(n+1));return Number.isFinite(a)?a:0}function nl(e){if(!e||typeof e!="object"||"ref"in e)return{};let n=e,a={};typeof n.nodeId=="string"&&(a.nodeId=n.nodeId),typeof n.activityId=="string"&&(a.activityId=n.activityId),typeof n.failedNodeId=="string"&&(a.nodeId=n.failedNodeId);let s=n.error;return s&&typeof s=="object"&&"errorCode"in s&&(a.errorCode=String(s.errorCode)),a}function al(e){return!e.payload||typeof e.payload!="object"||"ref"in e.payload?null:e.payload}function Fo(e,n,a){return Math.min(a,Math.max(n,e))}function Tn(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function ol(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 Zo(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function es(e){let n=location.hash.match(/^#\/(?:workflows\/catalog|workflows-catalog)\/([^/?#]+)$/);return n?il(e,decodeURIComponent(n[1])):sl(e)}function sl(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"),a=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),o=e.querySelector("#catalog-refresh"),r=[],d=null,
|
|
1433
|
+
`;let n=e.querySelector("#catalog-tbody"),a=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),o=e.querySelector("#catalog-refresh"),r=[],d=null,m=!1;function k(){let y=(new FormData(s).get("q")??"").trim().toLowerCase();return y?r.filter(p=>p.workflowId.toLowerCase().includes(y)||p.path.toLowerCase().includes(y)):r}function $(){d?(a.textContent=t("catalog.loadFailed",{error:d}),a.classList.add("error")):(a.textContent=`${r.length}`,a.classList.remove("error"));let y=k();if(y.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=y.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(Zo(p.revisionId))}</code></td>
|
|
1440
|
+
<td><code>${F(p.path)}</code></td>
|
|
1431
1441
|
</tr>
|
|
1432
|
-
`).join("")}async function
|
|
1442
|
+
`).join("")}async function M(){o.disabled=!0,a.textContent=t("catalog.loading");try{let y=await fetch("/api/workflows/definitions");if(!y.ok)throw new Error(`HTTP ${y.status}`);r=(await y.json()).definitions??[],d=null}catch(y){d=y?.message??String(y),r=[]}finally{o.disabled=!1,m||$()}}return s.addEventListener("input",$),o.addEventListener("click",()=>{M()}),M(),()=>{m=!0}}function il(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 a=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),o=e.querySelector("#catalog-run-status"),r=e.querySelector("#catalog-detail-body"),d=null,
|
|
1453
|
+
`;let a=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),o=e.querySelector("#catalog-run-status"),r=e.querySelector("#catalog-detail-body"),d=null,m=!1,k=!1;function $(L){s.hidden=!L,s.textContent=L??""}function M(L){o.hidden=!L,o.textContent=L??""}function y(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;a.textContent=`${t("catalog.revision")} ${Zo(d.revisionId)} \xB7 ${d.path}`;let x=JSON.stringify(y(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>${
|
|
1488
|
+
<div class="wf-panel-title"><h3>${F(t("catalog.paramsSchema"))}</h3></div>
|
|
1479
1489
|
${rl(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(w){q.hidden=!1,q.innerHTML=`<div class="muted error">${F(w?.message??String(w))}</div>`;return}k=!0,R.disabled=!0,R.textContent=t("catalog.running"),q.hidden=!0,$(null),M(null);try{let w=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(w.status===401)throw new Error(t("catalog.writeAccess"));let A=await w.json().catch(()=>({}));if(!w.ok||!A.ok)throw A.issues?.length&&(q.hidden=!1,q.innerHTML=`<strong>${F(t("catalog.invalidParams"))}</strong><ul>${A.issues.map(P=>`<li>${F(t("catalog.issue",{path:P.path.length?P.path.join("."):"(root)",message:P.message}))}</li>`).join("")}</ul>`),new Error(A.hint??A.message??A.error??t("catalog.runHttp",{status:w.status}));M(t("catalog.runStarted")),A.runId&&(location.hash=`#/workflows/${encodeURIComponent(A.runId)}`)}catch(w){$(w?.message??String(w))}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)})),a.textContent=t("workflow.detail.loadFailed")}}return C().then(()=>{}),()=>{m=!0}}function rl(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(([a,s])=>`
|
|
1487
1497
|
<article class="catalog-param">
|
|
1488
1498
|
<header>
|
|
1489
|
-
<code>${
|
|
1490
|
-
<span class="wf-status">${
|
|
1491
|
-
<span class="muted">${
|
|
1499
|
+
<code>${F(a)}</code>
|
|
1500
|
+
<span class="wf-status">${F(s.required?t("catalog.required"):t("catalog.optional"))}</span>
|
|
1501
|
+
<span class="muted">${F(s.type)}${s.format?` \xB7 ${F(s.format)}`:""}</span>
|
|
1492
1502
|
</header>
|
|
1493
|
-
${s.description?`<div class="muted">${
|
|
1494
|
-
${"default"in s?`<pre class="wf-io-pre">${
|
|
1503
|
+
${s.description?`<div class="muted">${F(t("catalog.description"))}: ${F(s.description)}</div>`:""}
|
|
1504
|
+
${"default"in s?`<pre class="wf-io-pre">${F(`${t("catalog.default")}: ${JSON.stringify(s.default,null,2)}`)}</pre>`:""}
|
|
1495
1505
|
</article>
|
|
1496
|
-
`).join("")}</div>`}var
|
|
1506
|
+
`).join("")}</div>`}var In=78222186;function ts(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 a=!1,s,o="",r=p=>(p/1048576).toFixed(0);function d(){s&&(clearTimeout(s),s=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
1526
|
<input id="hd2d-proxy" type="text" value="${i(o)}"
|
|
1517
1527
|
placeholder="HTTP \u4EE3\u7406\uFF08\u53EF\u9009\uFF0C\u5982 http://127.0.0.1:7890\uFF09"
|
|
@@ -1521,7 +1531,7 @@ ${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=()=>{o=e.querySelector("#hd2d-proxy")?.value.trim()??"",M()})}function $(p){if(!a){if(typeof p.proxy=="string"&&(o=p.proxy),p.state==="ready"){m();return}k(p),p.state==="downloading"&&(s=setTimeout(()=>{y()},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:o})});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 y(){if(!a)try{let p=await fetch("/api/game/status");if(!p.ok){k({state:"absent",received:0,total:In});return}$(await p.json())}catch{a||(s=setTimeout(()=>{y()},1500))}}return y(),()=>{a=!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 mt=null,Mn=null,En="glm-5.1",as=[];function Zt(){Mn!==null&&(window.clearInterval(Mn),Mn=null)}function ma(){return mt||(mt=document.createElement("dialog"),mt.className="onboarding-dialog",document.body.appendChild(mt),mt.addEventListener("close",Zt),mt)}function ll(e){return e.status==="waiting_for_scan"?t("botOnboarding.waiting"):e.status==="verifying"?t("botOnboarding.verifying"):e.status==="configuring_permissions"?e.permissionStatusMsg?`${t("botOnboarding.configuringPermissions")} ${e.permissionStatusMsg}`:t("botOnboarding.configuringPermissions"):e.status==="waiting_for_platform_scan"?t("botOnboarding.platformScanHint"):e.status==="completed"?t("botOnboarding.completed"):e.status==="failed"?`${t("botOnboarding.failed")}: ${i(e.message??e.error??"unknown")}`:t("botOnboarding.starting")}function dl(e){if(e.status!=="completed"||!e.permission)return"";let n=e.permission;if(n.ok){let s=[t("botOnboarding.permissionOk",{count:n.scopeCount??0})];n.skippedScopeCount&&n.skippedScopeCount>0&&s.push(t("botOnboarding.permissionSkipped",{count:n.skippedScopeCount})),n.versionId&&s.push(t("botOnboarding.permissionVersion",{version:i(n.versionId)}));let o=`<p class="hint-ok">\u2705 ${s.join(" ")}</p>`;return n.scopeWarning&&(o+=`<p class="hint-warn">\u26A0\uFE0F ${i(n.scopeWarning)}</p>`),o}let a=(e.remainingSteps??[]).map(s=>`<li><a href="${i(s.url)}" target="_blank" rel="noopener">${i(s.title)}</a></li>`).join("");return`<p class="hint-warn">\u26A0\uFE0F ${t("botOnboarding.permissionManual")}${n.message?`\uFF08${i(n.message)}\uFF09`:""}</p>`+(a?`<ol class="onboarding-steps">${a}</ol>`:"")}function Xt(e){let n=ma(),a=e.status==="waiting_for_scan"&&e.qrDataUrl?`<div class="qr-card">
|
|
1525
1535
|
<img class="qr-image" src="${e.qrDataUrl}" alt="${t("botOnboarding.qrAlt")}">
|
|
1526
1536
|
${e.qrUrl?`<a class="onboarding-link" href="${i(e.qrUrl)}" target="_blank" rel="noopener">${t("botOnboarding.openLink")}</a>`:""}
|
|
1527
1537
|
</div>`:"",s=e.status==="waiting_for_platform_scan"&&e.platformQrDataUrl?`<div class="qr-card">
|
|
@@ -1538,7 +1548,7 @@ ${Co("manage")}
|
|
|
1538
1548
|
${dl(e)}
|
|
1539
1549
|
${r}
|
|
1540
1550
|
<form method="dialog"><button>${t("botOnboarding.close")}</button></form>
|
|
1541
|
-
</article>`}async function cl(){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()&&(
|
|
1551
|
+
</article>`}async function cl(){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(a=>typeof a=="string")),n.options}catch{}return[{id:"claude-code",label:"Claude"}]}function ns(e){let n=mt;if(!n)return;let a=n.querySelector("#ob-cli"),s=n.querySelector("#ob-model"),o=n.querySelector("#ob-model-suggestions");if(!a||!s)return;let r=e.find(k=>k.id===a.value),d=r?.gateway==="ttadk",m=d&&r?.acceptsModel!==!1;if(d&&!m){s.value="",s.disabled=!0,s.placeholder=t("botOnboarding.modelTtadkCocoPlaceholder");return}s.disabled=!1,m?(o&&(o.innerHTML=as.map(k=>`<option value="${i(k)}"></option>`).join("")),s.placeholder=t("botOnboarding.modelTtadkPlaceholder").replace("{model}",En),s.value.trim()||(s.value=En)):(o&&(o.innerHTML=""),s.placeholder=t("botOnboarding.modelPlaceholder"),s.value.trim()===En&&(s.value=""))}function pa(e,n){let a=ma(),s=e.map(k=>`<option value="${i(k.id)}">${i(k.label)}\uFF08${i(k.id)}\uFF09</option>`).join(""),o=n?`<p class="form-error">${i(n)}</p>`:"";a.innerHTML=`<article>
|
|
1542
1552
|
<header>
|
|
1543
1553
|
<h3>${t("botOnboarding.title")}</h3>
|
|
1544
1554
|
<p>${t("botOnboarding.intro")}</p>
|
|
@@ -1563,8 +1573,8 @@ ${Co("manage")}
|
|
|
1563
1573
|
<button type="submit" class="primary">${t("botOnboarding.startScan")}</button>
|
|
1564
1574
|
</menu>
|
|
1565
1575
|
</form>
|
|
1566
|
-
</article>`;let r=a.querySelector("#onboarding-form");a.querySelector("#ob-cancel")?.addEventListener("click",()=>a.close()),a.querySelector("#ob-cli")?.addEventListener("change",()=>ns(e)),ns(e),r?.addEventListener("submit",k=>{k.preventDefault();let $=a.querySelector("#ob-cli")?.value??"",
|
|
1576
|
+
</article>`;let r=a.querySelector("#onboarding-form");a.querySelector("#ob-cancel")?.addEventListener("click",()=>a.close()),a.querySelector("#ob-cli")?.addEventListener("change",()=>ns(e)),ns(e),r?.addEventListener("submit",k=>{k.preventDefault();let $=a.querySelector("#ob-cli")?.value??"",M=a.querySelector("#ob-dir")?.value??"",y=a.querySelector("#ob-model")?.value??"";ul({cliId:$,workingDir:M,model:y},e)})}async function ul(e,n){Zt(),Xt({id:"",status:"starting"});try{let a=await fetch("/api/bot-onboarding/start",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({cliId:e.cliId,workingDir:e.workingDir.trim(),model:e.model.trim()||void 0})}),s=await a.json();if(a.status===400){pa(n,s?.message??s?.error??"invalid_input");return}if(!a.ok||!s?.job?.id)throw new Error(s?.error??`http_${a.status}`);Xt(s.job),Mn=window.setInterval(()=>{pl(s.job.id).catch(o=>{Zt(),Xt({id:s.job.id,status:"failed",message:o instanceof Error?o.message:String(o)})})},1200)}catch(a){Xt({id:"",status:"failed",message:a instanceof Error?a.message:String(a)})}}async function pl(e){let n=await fetch(`/api/bot-onboarding/${encodeURIComponent(e)}`),a=await n.json();if(!n.ok||!a?.job)throw new Error(a?.error??`http_${n.status}`);Xt(a.job),(a.job.status==="completed"||a.job.status==="failed")&&Zt()}async function ml(){Zt();let e=ma();pa([{id:"claude-code",label:"Claude"}]),e.open||e.showModal();let n=await cl();e.open&&e.querySelector("#onboarding-form")&&pa(n)}function os(){let e=document.getElementById("add-bot-btn");e&&(e.onclick=()=>{ml()})}var fl={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"/>'},is=[{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"}]}],ss=is.flatMap(e=>e.options),$t=!1;function fa(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">${fl[e]??""}</svg>`}function gl(e){return e.replace(/[&<>"]/g,n=>({"&":"&","<":"<",">":">",'"':"""})[n])}function rs(){let e=document.getElementById("theme-menu"),n=document.getElementById("theme-menu-btn"),a=document.getElementById("theme-menu-pop");if(!e||!n||!a)return;a.innerHTML=is.map(o=>`<div class="tm-group" data-label-key="${o.labelKey}"></div>`+o.options.map(r=>`<button type="button" class="tm-item" role="option" data-value="${r.value}"><span class="tm-ic">${fa(r.icon)}</span><span class="tm-label" data-label-key="${r.labelKey}"></span></button>`).join("")).join("");let s=o=>{$t=o,a.hidden=!$t,n.setAttribute("aria-expanded",String($t)),e.classList.toggle("open",$t)};n.addEventListener("click",o=>{o.stopPropagation(),s(!$t)}),a.addEventListener("click",o=>{let r=o.target.closest(".tm-item");r&&(Te.setTheme(r.dataset.value??"system"),s(!1))}),document.addEventListener("click",o=>{$t&&!e.contains(o.target)&&s(!1)}),document.addEventListener("keydown",o=>{o.key==="Escape"&&$t&&s(!1)}),ga()}function ga(){let e=document.getElementById("theme-menu-btn");if(!e)return;let n=ss.find(a=>a.value===Te.theme)??ss[0];e.innerHTML=`<span class="tm-ic">${fa(n.icon)}</span><span class="tm-current">${gl(t(n.labelKey))}</span><span class="tm-chev">${fa("chevron")}</span>`,document.querySelectorAll("#theme-menu-pop [data-label-key]").forEach(a=>{a.textContent=t(a.dataset.labelKey??"")}),document.querySelectorAll("#theme-menu-pop .tm-item").forEach(a=>{a.classList.toggle("active",a.dataset.value===Te.theme)})}var Ie=document.getElementById("root"),Rt=!0,ps=!1,ms=["roles","bot-defaults","skills","team","connectors"],ba=!1;function bl(){if(ba)return;ba=!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(),ba=!1};e.querySelector("#auth-expired-dismiss")?.addEventListener("click",n),e.addEventListener("click",a=>{a.target===e&&n()})}var ha;function hl(){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",ha&&window.clearTimeout(ha),ha=window.setTimeout(()=>{e.style.display="none"},4e3)}var yl=window.fetch.bind(window);window.fetch=async function(...n){let a=await yl(...n);if(a.status===401){let s=(n[1]?.method??"GET").toUpperCase();(s==="GET"||s==="HEAD")&&!ps?bl():hl()}return a};var ya="";function xn(){let e=document.getElementById("attention-strip");if(!e)return;let n=[...Y.sessions.values()].map(o=>({s:o,reason:ct(o)})).filter(o=>!!o.reason).sort((o,r)=>Ce(o.s)-Ce(r.s));if(n.length===0){e.hidden=!0,e.innerHTML="",ya="";return}let a=n[0],s=`
|
|
1567
1577
|
<span class="attention-strip-ic" aria-hidden="true">!</span>
|
|
1568
1578
|
<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,s!==
|
|
1579
|
+
<span class="attention-strip-longest">${i(t("strip.longest",{time:qe(Ce(a.s)),bot:ke(a.s),reason:a.reason}))}</span>
|
|
1580
|
+
<a class="attention-strip-go" href="#/sessions">${i(t("strip.handle"))}</a>`;e.hidden=!1,s!==ya&&(ya=s,e.innerHTML=s)}Y.on(xn);Ke().then(xn);async function wl(){try{let e=await fetch("/api/settings");if(e.ok){let n=await e.json();Rt=!!n.authed,Te.authed=Rt,ps=!!(n.settings&&n.settings.publicReadOnly);let a=nn(n.lang);a&&Te.setLocale(a)}}catch{}}async function vl(e){if(Rt)try{await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({lang:e})})}catch{}}function kl(){for(let n of ms){let a=document.querySelector(`.sidebar-nav a[data-route="${n}"]`);a&&(a.style.display=Rt?"":"none")}let e=document.getElementById("add-bot-btn");e&&(e.style.display=Rt?"":"none")}function $l(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 Dt=null;function ls(e){for(let n of document.querySelectorAll(".sidebar-nav a")){let a=n.getAttribute("href")??"#/";n.classList.toggle("active",a===(e||"#/"))}}function wa(){Dt&&(Dt(),Dt=null);let e=location.hash||"#/";if(!Rt&&ms.some(n=>e.startsWith("#/"+n))){$l(Ie),ls(e);return}e.startsWith("#/workflows/catalog")||e.startsWith("#/workflows-catalog")?Dt=es(Ie):e.startsWith("#/workflows")?Dt=Go(Ie):e.startsWith("#/groups")?ho(Ie):e.startsWith("#/settings")?qo(Ie):e.startsWith("#/bot-defaults")?ko(Ie):e.startsWith("#/skills")?Lo(Ie):e.startsWith("#/connectors")?Oo(Ie):e.startsWith("#/team/manage")?Ro(Ie):e.startsWith("#/team")?Do(Ie):e.startsWith("#/roles")?Eo(Ie):e.startsWith("#/schedules")?go(Ie):e.startsWith("#/sessions")?mo(Ie):e.startsWith("#/office")?Dt=ts(Ie)??null:eo(Ie),ls(e)}var va=document.getElementById("status");function fs(){va&&(va.textContent=Y.online?t("status.live"):t("status.disconnected"),va.className="connection-status "+(Y.online?"online":"offline"))}Y.on(fs);function ds(){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)}),ga(),fs()}function Sl(){document.querySelectorAll("[data-locale]").forEach(e=>{e.onclick=()=>{let n=e.dataset.locale;Te.setLocale(n),vl(n)}}),rs(),Tl()}var cs="botmux.ownerAvatar.v1";function us(e,n){let a=document.querySelector(".brand-mark");!a||!e||(a.innerHTML=`<img class="brand-owner-img" src="${i(e)}" alt="" decoding="async" referrerpolicy="no-referrer" onerror="this.remove()">`,n&&(a.title=n))}function Ll(){try{let e=JSON.parse(window.localStorage.getItem(cs)??"null");e?.avatarUrl&&us(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)){us(String(e.avatarUrl),e.name?String(e.name):void 0);try{window.localStorage.setItem(cs,JSON.stringify({avatarUrl:e.avatarUrl,name:e.name??""}))}catch{}}}).catch(()=>{})}function Tl(){let e=document.getElementById("sidebar-toggle");if(!e)return;let n=Oa(window.localStorage),a=()=>{document.documentElement.dataset.sidebar=n,e.title=t(n==="collapsed"?"nav.sidebarExpand":"nav.sidebarCollapse")};a(),e.addEventListener("click",()=>{n=n==="collapsed"?"expanded":"collapsed",Na(window.localStorage,n),a()})}(async()=>{Te.init(),Sl(),os(),Te.on(()=>{ds(),xn(),wa()}),ds(),xn(),await wl(),kl(),Ll();try{await Sa()}catch(e){console.error("botmux dashboard bootstrap failed",e),Y.setOnline(!1)}window.addEventListener("hashchange",wa),wa()})();})();
|