botmux 2.62.0 → 2.63.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -6
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +12 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +12 -0
- package/dist/config.js.map +1 -1
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +5 -1
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/dashboard-rows.d.ts +11 -0
- package/dist/core/dashboard-rows.d.ts.map +1 -1
- package/dist/core/dashboard-rows.js +4 -0
- package/dist/core/dashboard-rows.js.map +1 -1
- package/dist/core/session-activity.d.ts +16 -0
- package/dist/core/session-activity.d.ts.map +1 -1
- package/dist/core/session-activity.js +35 -0
- package/dist/core/session-activity.js.map +1 -1
- package/dist/core/trigger-session.d.ts.map +1 -1
- package/dist/core/trigger-session.js +9 -10
- package/dist/core/trigger-session.js.map +1 -1
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +3 -0
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +8 -1
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/auth.d.ts +6 -0
- package/dist/dashboard/auth.d.ts.map +1 -1
- package/dist/dashboard/auth.js +33 -12
- package/dist/dashboard/auth.js.map +1 -1
- package/dist/dashboard/connector-api.d.ts.map +1 -1
- package/dist/dashboard/connector-api.js +22 -17
- package/dist/dashboard/connector-api.js.map +1 -1
- package/dist/dashboard/public-redact.d.ts +16 -0
- package/dist/dashboard/public-redact.d.ts.map +1 -0
- package/dist/dashboard/public-redact.js +62 -0
- package/dist/dashboard/public-redact.js.map +1 -0
- package/dist/dashboard/web/app.d.ts +1 -0
- package/dist/dashboard/web/app.d.ts.map +1 -1
- package/dist/dashboard/web/app.js +171 -25
- package/dist/dashboard/web/app.js.map +1 -1
- package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults.js +136 -64
- package/dist/dashboard/web/bot-defaults.js.map +1 -1
- package/dist/dashboard/web/connectors.d.ts.map +1 -1
- package/dist/dashboard/web/connectors.js +120 -25
- package/dist/dashboard/web/connectors.js.map +1 -1
- package/dist/dashboard/web/cyber-fx.d.ts +6 -0
- package/dist/dashboard/web/cyber-fx.d.ts.map +1 -0
- package/dist/dashboard/web/cyber-fx.js +289 -0
- package/dist/dashboard/web/cyber-fx.js.map +1 -0
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +146 -8
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/overview.d.ts.map +1 -1
- package/dist/dashboard/web/overview.js +206 -48
- package/dist/dashboard/web/overview.js.map +1 -1
- package/dist/dashboard/web/preferences.d.ts +16 -0
- package/dist/dashboard/web/preferences.d.ts.map +1 -1
- package/dist/dashboard/web/preferences.js +72 -1
- package/dist/dashboard/web/preferences.js.map +1 -1
- package/dist/dashboard/web/roles.js +3 -3
- package/dist/dashboard/web/roles.js.map +1 -1
- package/dist/dashboard/web/sessions.d.ts.map +1 -1
- package/dist/dashboard/web/sessions.js +404 -64
- package/dist/dashboard/web/sessions.js.map +1 -1
- package/dist/dashboard/web/settings.d.ts +2 -0
- package/dist/dashboard/web/settings.d.ts.map +1 -0
- package/dist/dashboard/web/settings.js +135 -0
- package/dist/dashboard/web/settings.js.map +1 -0
- package/dist/dashboard/web/skin-intro.d.ts +4 -0
- package/dist/dashboard/web/skin-intro.d.ts.map +1 -0
- package/dist/dashboard/web/skin-intro.js +49 -0
- package/dist/dashboard/web/skin-intro.js.map +1 -0
- package/dist/dashboard/web/team-federation.js +4 -4
- package/dist/dashboard/web/team-federation.js.map +1 -1
- package/dist/dashboard/web/theme-menu.d.ts +3 -0
- package/dist/dashboard/web/theme-menu.d.ts.map +1 -0
- package/dist/dashboard/web/theme-menu.js +97 -0
- package/dist/dashboard/web/theme-menu.js.map +1 -0
- package/dist/dashboard/web/ui.d.ts +16 -2
- package/dist/dashboard/web/ui.d.ts.map +1 -1
- package/dist/dashboard/web/ui.js +137 -7
- package/dist/dashboard/web/ui.js.map +1 -1
- package/dist/dashboard/webhook-routes.d.ts +1 -5
- package/dist/dashboard/webhook-routes.d.ts.map +1 -1
- package/dist/dashboard/webhook-routes.js +127 -76
- package/dist/dashboard/webhook-routes.js.map +1 -1
- package/dist/dashboard-web/app.js +704 -512
- package/dist/dashboard-web/index.html +19 -14
- package/dist/dashboard-web/skins/bluearchive-hero.webp +0 -0
- package/dist/dashboard-web/skins/dragonball-goku.webp +0 -0
- package/dist/dashboard-web/skins/dragonball-wukong.webp +0 -0
- package/dist/dashboard-web/skins/fallout-vaultboy.webp +0 -0
- package/dist/dashboard-web/skins/genshin-breeze.webp +0 -0
- package/dist/dashboard-web/skins/ikun-hero.webp +0 -0
- package/dist/dashboard-web/skins/prts-priestess.webp +0 -0
- package/dist/dashboard-web/skins/zzz-hero.webp +0 -0
- package/dist/dashboard-web/skins/zzz-pattern.svg +25 -0
- package/dist/dashboard-web/style.css +2870 -16
- package/dist/dashboard.js +91 -31
- package/dist/dashboard.js.map +1 -1
- package/dist/global-config.d.ts +15 -0
- package/dist/global-config.d.ts.map +1 -1
- package/dist/global-config.js +51 -2
- package/dist/global-config.js.map +1 -1
- package/dist/im/lark/card-builder.d.ts.map +1 -1
- package/dist/im/lark/card-builder.js +17 -3
- package/dist/im/lark/card-builder.js.map +1 -1
- package/dist/im/lark/card-handler.d.ts.map +1 -1
- package/dist/im/lark/card-handler.js +5 -0
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/services/bridge-fallback-gate.d.ts +1 -1
- package/dist/services/bridge-fallback-gate.d.ts.map +1 -1
- package/dist/services/bridge-fallback-gate.js +26 -13
- package/dist/services/bridge-fallback-gate.js.map +1 -1
- package/dist/services/connector-store.d.ts +2 -3
- package/dist/services/connector-store.d.ts.map +1 -1
- package/dist/services/connector-store.js.map +1 -1
- package/dist/services/trigger-types.d.ts +1 -0
- package/dist/services/trigger-types.d.ts.map +1 -1
- package/dist/services/trigger-types.js.map +1 -1
- package/dist/services/webhook-lifecycle-extractors.d.ts +4 -13
- package/dist/services/webhook-lifecycle-extractors.d.ts.map +1 -1
- package/dist/services/webhook-lifecycle-extractors.js +8 -23
- package/dist/services/webhook-lifecycle-extractors.js.map +1 -1
- package/dist/utils/screen-analyzer.d.ts +8 -0
- package/dist/utils/screen-analyzer.d.ts.map +1 -1
- package/dist/utils/screen-analyzer.js +32 -11
- package/dist/utils/screen-analyzer.js.map +1 -1
- package/dist/worker.js +2 -2
- package/dist/worker.js.map +1 -1
- package/dist/workflows/trigger-from-envelope.d.ts.map +1 -1
- package/dist/workflows/trigger-from-envelope.js +1 -0
- package/dist/workflows/trigger-from-envelope.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,285 +1,387 @@
|
|
|
1
|
-
"use strict";(()=>{var tt=class{sessions=new Map;schedules=new Map;online=!0;listeners=new Set;upsertSessions(t){for(let o of t)this.sessions.set(o.sessionId,o);this.emit()}upsertSchedules(t){for(let o of t)this.schedules.set(o.id,o);this.emit()}applySse(t,o){if(t==="session.spawned")this.sessions.set(o.session.sessionId,o.session);else if(t==="session.update"){let s=this.sessions.get(o.sessionId);s&&this.sessions.set(o.sessionId,{...s,...o.patch})}else if(t==="session.exited"){let s=this.sessions.get(o.sessionId);s&&this.sessions.set(o.sessionId,{...s,status:"closed"})}else if(t==="schedule.created")this.schedules.set(o.schedule.id,o.schedule);else if(t==="schedule.updated"){let s=this.schedules.get(o.id);s&&this.schedules.set(o.id,{...s,...o.patch})}else if(t==="schedule.deleted")this.schedules.delete(o.id);else return;this.emit()}setOnline(t){this.online!==t&&(this.online=t,this.emit())}on(t){return this.listeners.add(t),()=>this.listeners.delete(t)}emit(){for(let t of this.listeners)t()}},z=new tt;async function kt(){let[e,t]=await Promise.all([fetch("/api/sessions").then(a=>a.json()),fetch("/api/schedules").then(a=>a.json())]);z.upsertSessions(e.sessions??[]),z.upsertSchedules(t.schedules??[]);let o=new EventSource("/events"),s=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let a of s)o.addEventListener(a,r=>{try{let i=JSON.parse(r.data);z.applySse(a,i.body??i)}catch{}});o.onerror=()=>z.setOnline(!1),o.onopen=()=>z.setOnline(!0)}var nt="botmux.dashboard.locale",wn={"app.name":"botmux","app.subtitle":"\u98DE\u4E66 AI CLI \u63A7\u5236\u53F0","time.secondsAgo":"{value} \u79D2\u524D","time.minutesAgo":"{value} \u5206\u949F\u524D","time.hoursAgo":"{value} \u5C0F\u65F6\u524D","nav.overview":"\u603B\u89C8","nav.sessions":"\u4F1A\u8BDD","nav.groups":"\u7FA4\u7EC4","nav.schedules":"\u5B9A\u65F6","nav.botDefaults":"Bot \u914D\u7F6E","status.live":"\u5B9E\u65F6\u8FDE\u63A5","status.disconnected":"\u8FDE\u63A5\u65AD\u5F00","status.system":"\u7CFB\u7EDF","status.light":"\u6D45\u8272","status.dark":"\u6697\u9ED1","status.language":"\u8BED\u8A00","status.theme":"\u4E3B\u9898","botOnboarding.add":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.title":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.intro":"\u9009\u62E9 CLI \u4E0E\u5DE5\u4F5C\u76EE\u5F55\uFF0C\u626B\u7801\u521B\u5EFA PersonalAgent \u5E94\u7528\u540E\u5199\u5165\u672C\u673A bots.json\uFF0C\u5E76\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u3002","botOnboarding.cliLabel":"CLI \u9002\u914D\u5668","botOnboarding.dirLabel":"\u5DE5\u4F5C\u76EE\u5F55","botOnboarding.dirPlaceholder":"\u9ED8\u8BA4 ~\uFF08\u5BB6\u76EE\u5F55\uFF09\uFF0C\u9700\u4E3A daemon \u4E3B\u673A\u4E0A\u5DF2\u5B58\u5728\u7684\u76EE\u5F55","botOnboarding.modelLabel":"\u6A21\u578B\uFF08\u53EF\u9009\uFF09","botOnboarding.modelPlaceholder":"\u7559\u7A7A\u4F7F\u7528\u8BE5 CLI \u7684\u9ED8\u8BA4\u6A21\u578B","botOnboarding.startScan":"\u5F00\u59CB\u626B\u7801","botOnboarding.cancel":"\u53D6\u6D88","botOnboarding.starting":"\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...","botOnboarding.waiting":"\u8BF7\u7528\u98DE\u4E66 App \u626B\u7801\u786E\u8BA4\u521B\u5EFA\u5E94\u7528\u3002","botOnboarding.verifying":"\u626B\u7801\u6210\u529F\uFF0C\u6B63\u5728\u6821\u9A8C\u51ED\u8BC1...","botOnboarding.configuringPermissions":"\u6B63\u5728\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u2026","botOnboarding.platformScanHint":"\u8BF7\u7528\u98DE\u4E66 App \u518D\u626B\u4E00\u6B21\u7801\u767B\u5F55\u5F00\u653E\u5E73\u53F0\uFF08\u7528\u4E8E\u81EA\u52A8\u5BFC\u5165\u6743\u9650\u3001\u914D\u7F6E\u56DE\u8C03\u3001\u63D0\u4EA4\u7248\u672C\uFF09\u3002","botOnboarding.platformQrAlt":"\u5F00\u653E\u5E73\u53F0\u767B\u5F55\u4E8C\u7EF4\u7801","botOnboarding.completed":"\u673A\u5668\u4EBA\u5DF2\u6DFB\u52A0\u3002","botOnboarding.permissionOk":"\u5DF2\u81EA\u52A8\u5BFC\u5165 {count} \u9879\u6743\u9650\u3002","botOnboarding.permissionSkipped":"\uFF08\u8DF3\u8FC7 {count} \u9879\u5F53\u524D\u79DF\u6237\u76EE\u5F55\u4E2D\u6CA1\u6709\u7684\u6743\u9650\uFF09","botOnboarding.permissionVersion":"\u5DF2\u63D0\u4EA4\u53D1\u5E03\u7248\u672C {version}\u3002","botOnboarding.permissionManual":"\u6743\u9650\u672A\u80FD\u81EA\u52A8\u914D\u7F6E\uFF0C\u8BF7\u624B\u52A8\u5B8C\u6210\u4EE5\u4E0B\u6B65\u9AA4\uFF1A","botOnboarding.metaDir":"\u76EE\u5F55","botOnboarding.failed":"\u6DFB\u52A0\u5931\u8D25","botOnboarding.openLink":"\u6253\u4E0D\u5F00\u626B\u7801\uFF1F\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00","botOnboarding.close":"\u5173\u95ED","botOnboarding.restartHint":"\u5DF2\u5199\u5165 bots.json\u3002\u6267\u884C pnpm daemon:restart \u540E\u65B0\u673A\u5668\u4EBA\u751F\u6548\u3002","botOnboarding.qrAlt":"\u98DE\u4E66\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA\u4E8C\u7EF4\u7801","overview.title":"\u63A7\u5236\u53F0\u603B\u89C8","overview.subtitle":"\u8DE8 bot\u3001\u7FA4\u804A\u3001\u4F1A\u8BDD\u548C\u5B9A\u65F6\u4EFB\u52A1\u7684\u5B9E\u65F6\u7BA1\u63A7\u9762\u3002","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.status":"\u72B6\u6001","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.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.closeBulkConfirm":"\u5173\u95ED\u9009\u4E2D\u7684 {count} \u4E2A\u4F1A\u8BDD\uFF1F","sessions.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u4F1A\u8BDD\u3002","groups.title":"\u7FA4\u7EC4\u4E0E Bot","groups.subtitle":"\u67E5\u770B chat x bot \u8986\u76D6\u77E9\u9635\uFF0C\u7BA1\u7406\u62C9\u7FA4\u3001oncall\u3001\u9000\u7FA4\u548C\u89E3\u6563\u3002","groups.search":"\u641C\u7D22\u7FA4\u540D / ID / owner","groups.missingOnly":"\u4EC5\u7F3A bot","groups.refresh":"\u5237\u65B0","groups.create":"\u65B0\u5EFA\u7FA4","groups.chat":"\u7FA4\u804A","groups.actions":"\u64CD\u4F5C","groups.addBots":"\u6DFB\u52A0 bot","groups.manage":"\u7BA1\u7406","groups.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u7FA4\u804A\u3002","groups.createTitle":"\u65B0\u5EFA\u7FA4\u804A","groups.createHelp":"\u9009\u62E9\u8981\u9080\u8BF7\u7684 bot\u3002dashboard \u4F1A\u81EA\u52A8\u9009\u62E9\u5728\u7EBF daemon \u4F5C\u4E3A\u521B\u5EFA\u8005\u3002","groups.name":"\u7FA4\u540D","groups.namePlaceholder":"\u4F8B\u5982 AI ChangeLog","groups.bindDir":"\u7ED1\u5B9A\u76EE\u5F55","groups.bindDirHelp":"\u65B0\u8BDD\u9898\u76F4\u63A5\u7528\u8BE5\u76EE\u5F55\u542F\u52A8 CLI\uFF0C\u8DF3\u8FC7 repo \u9009\u62E9\u3002","groups.botPicker":"Bot","groups.createSubmit":"\u521B\u5EFA","groups.cancel":"\u53D6\u6D88","groups.successTitle":"\u7FA4\u521B\u5EFA\u6210\u529F","groups.openGroup":"\u6253\u5F00\u65B0\u7FA4","groups.manageTitle":"\u7BA1\u7406 {name}","groups.owner":"\u7FA4\u4E3B","groups.oncall":"Oncall \u6A21\u5F0F","groups.oncallHelp":"\u5F00\u542F\u540E\uFF0C\u7FA4\u5185\u6210\u5458\u53EF @ \u673A\u5668\u4EBA\uFF1B\u65B0\u8BDD\u9898\u76F4\u63A5\u4F7F\u7528\u7ED1\u5B9A\u76EE\u5F55\u3002","groups.leaveTitle":"\u9009\u62E9\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.leaveSelected":"\u9009\u4E2D\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.disband":"\u89E3\u6563\u7FA4\u804A","groups.dangerHint":"\u89E3\u6563\u4EC5\u5F53\u5728\u7FA4\u673A\u5668\u4EBA\u662F\u7FA4\u4E3B\u65F6\u624D\u4F1A\u6210\u529F\uFF0C\u5426\u5219\u5EFA\u8BAE\u4F7F\u7528\u9000\u51FA\u7FA4\u804A\u3002","groups.save":"\u4FDD\u5B58","groups.needWorkingDir":"\u8BF7\u586B\u5DE5\u4F5C\u76EE\u5F55","groups.noBotsOnline":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u8BF7\u5148\u91CD\u542F daemon\u3002","schedules.title":"\u5B9A\u65F6\u4EFB\u52A1","schedules.subtitle":"\u8DE8 daemon \u67E5\u770B\u3001\u6682\u505C\u3001\u6062\u590D\u548C\u7ACB\u5373\u89E6\u53D1\u5B9A\u65F6\u4EFB\u52A1\u3002","schedules.search":"\u641C\u7D22\u540D\u79F0 / prompt / \u5DE5\u4F5C\u76EE\u5F55","schedules.anyKind":"\u5168\u90E8\u7C7B\u578B","schedules.enabledOnly":"\u4EC5\u542F\u7528","schedules.name":"\u540D\u79F0","schedules.bot":"bot","schedules.schedule":"\u89C4\u5219","schedules.next":"\u4E0B\u6B21","schedules.last":"\u4E0A\u6B21","schedules.repeat":"\u91CD\u590D","schedules.enabled":"\u542F\u7528","schedules.actions":"\u64CD\u4F5C","schedules.runNow":"\u7ACB\u5373\u8FD0\u884C","schedules.pause":"\u6682\u505C","schedules.resume":"\u6062\u590D","schedules.empty":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","botDefaults.title":"Bot \u9ED8\u8BA4\u914D\u7F6E","botDefaults.subtitle":"\u7BA1\u7406\u6BCF\u4E2A bot \u7684\u9ED8\u8BA4\u884C\u4E3A\uFF1A\u65B0\u7FA4 oncall \u81EA\u52A8\u7ED1\u5B9A\u3001\u5361\u7247\u7B7E\u540D\u7B49\u3002","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.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.sectionGrant":"\u6388\u6743\u4E0E\u989D\u5EA6","botDefaults.restrictGrant":"\u9650\u5236\u88AB\u6388\u6743\u4EBA\u53EA\u80FD\u7EAF\u5BF9\u8BDD","botDefaults.restrictGrantHelp":"\u5F00\u542F\u540E\uFF0C\u88AB /grant \u6388\u6743\u7684\u4EBA\uFF08owner \u81EA\u5DF1\u4E0D\u53D7\u9650\uFF09\u53EA\u80FD\u53D1\u666E\u901A\u5BF9\u8BDD\uFF0C\u6240\u6709 slash \u547D\u4EE4\u4E00\u5F8B\u62E6\u622A\uFF1Abotmux \u81EA\u5E26\u547D\u4EE4\u3001\u900F\u4F20\u547D\u4EE4\u3001/workflow\u3001/introduce\u3001/t \u4EE5\u53CA CLI \u539F\u751F\u547D\u4EE4\uFF08/help \u7B49\uFF09\u3002\u5F62\u5982 /path/to/file \u7684\u5185\u5BB9\u4E0D\u4F1A\u88AB\u8BEF\u5224\u3002","botDefaults.quotaDefault":"\u9ED8\u8BA4\u6D88\u606F\u989D\u5EA6","botDefaults.quotaPlaceholder":"\u7559\u7A7A\uFF1D\u4E0D\u914D\u7F6E\u9ED8\u8BA4\u989D\u5EA6","botDefaults.quotaHelp":"\u4E0D\u5E26\u6570\u5B57\u7684 /grant @x \u9ED8\u8BA4\u7ED9\u7684\u6D88\u606F\u6761\u6570\u3002\u7559\u7A7A\u6216\u70B9\u300C\u5173\u95ED\u300D\u53EA\u662F\u4E0D\u518D\u7ED9\u88F8 /grant \u5957\u9ED8\u8BA4\u989D\u5EA6\uFF0C\u4E0D\u4F1A\u6E05\u6389\u5DF2\u6709\u7684\u989D\u5EA6\u8BA1\u6570\uFF0C\u4E5F\u4E0D\u5F71\u54CD\u663E\u5F0F /grant @x N\u2014\u2014\u5B83\u4EEC\u7167\u5E38\u7EE7\u7EED enforce\u3002\u989D\u5EA6\u7528\u5C3D\u4F1A\u81EA\u52A8\u64A4\u9500\u8BE5\u4EBA\u6388\u6743\u3002","botDefaults.quotaSave":"\u4FDD\u5B58\u989D\u5EA6","botDefaults.quotaOff":"\u5173\u95ED","botDefaults.quotaInvalid":"\u989D\u5EA6\u5FC5\u987B\u662F\u6B63\u6574\u6570","botDefaults.quotaStateOff":"\u5F53\u524D\uFF1A\u672A\u914D\u7F6E\u9ED8\u8BA4\u989D\u5EA6","botDefaults.quotaStateOn":"\u5F53\u524D\uFF1A\u6BCF\u4EBA {count} \u6761","nav.roles":"\u89D2\u8272\u7BA1\u7406","roles.title":"\u89D2\u8272\u7BA1\u7406","roles.subtitle":"\u4E3A\u6BCF\u4E2A\u7FA4\u7EC4\u7684\u6BCF\u4E2A Bot \u5355\u72EC\u8BBE\u7F6E\u89D2\u8272\u63D0\u793A\u8BCD\uFF0CBot \u5728\u8BE5\u7FA4\u4E2D\u4F1A\u4EE5\u6B64\u89D2\u8272\u884C\u4E8B\u3002","roles.search":"\u641C\u7D22\u7FA4\u540D/Bot/ID","roles.refresh":"\u5237\u65B0","roles.selectHint":"\u2190 \u5C55\u5F00\u7FA4\u7EC4\uFF0C\u9009\u62E9\u4E00\u4E2A Bot \u6765\u7F16\u8F91\u89D2\u8272","roles.editorPlaceholder":`\u8F93\u5165\u89D2\u8272\u63CF\u8FF0\uFF0C\u4F8B\u5982\uFF1A
|
|
2
|
-
\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.unknown":"\u672A\u77E5","common.now":"\u521A\u521A","common.never":"\u4ECE\u672A","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
|
|
1
|
+
"use strict";(()=>{var kt=class{sessions=new Map;schedules=new Map;online=!0;listeners=new Set;upsertSessions(t){for(let n of t)this.sessions.set(n.sessionId,n);this.emit()}upsertSchedules(t){for(let n of t)this.schedules.set(n.id,n);this.emit()}applySse(t,n){if(t==="session.spawned")this.sessions.set(n.session.sessionId,n.session);else if(t==="session.update"){let s=this.sessions.get(n.sessionId);s&&this.sessions.set(n.sessionId,{...s,...n.patch})}else if(t==="session.exited"){let s=this.sessions.get(n.sessionId);s&&this.sessions.set(n.sessionId,{...s,status:"closed"})}else if(t==="schedule.created")this.schedules.set(n.schedule.id,n.schedule);else if(t==="schedule.updated"){let s=this.schedules.get(n.id);s&&this.schedules.set(n.id,{...s,...n.patch})}else if(t==="schedule.deleted")this.schedules.delete(n.id);else return;this.emit()}setOnline(t){this.online!==t&&(this.online=t,this.emit())}on(t){return this.listeners.add(t),()=>this.listeners.delete(t)}emit(){for(let t of this.listeners)t()}},G=new kt;async function an(){let[e,t]=await Promise.all([fetch("/api/sessions").then(a=>a.json()),fetch("/api/schedules").then(a=>a.json())]);G.upsertSessions(e.sessions??[]),G.upsertSchedules(t.schedules??[]);let n=new EventSource("/events"),s=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let a of s)n.addEventListener(a,i=>{try{let l=JSON.parse(i.data);G.applySse(a,l.body??l)}catch{}});n.onerror=()=>G.setOnline(!1),n.onopen=()=>G.setOnline(!0)}var $t="botmux.dashboard.locale",Io={"app.name":"botmux","app.subtitle":"\u98DE\u4E66 AI CLI \u63A7\u5236\u53F0","time.secondsAgo":"{value} \u79D2\u524D","time.minutesAgo":"{value} \u5206\u949F\u524D","time.hoursAgo":"{value} \u5C0F\u65F6\u524D","nav.overview":"\u603B\u89C8","nav.sessions":"\u4F1A\u8BDD","nav.groups":"\u7FA4\u7EC4","nav.schedules":"\u5B9A\u65F6","nav.settings":"\u8BBE\u7F6E","nav.botDefaults":"Bot \u914D\u7F6E","status.live":"\u5B9E\u65F6\u8FDE\u63A5","status.disconnected":"\u8FDE\u63A5\u65AD\u5F00","status.system":"\u7CFB\u7EDF","status.light":"\u6D45\u8272","status.dark":"\u6697\u9ED1","status.language":"\u8BED\u8A00","status.theme":"\u4E3B\u9898","theme.base":"\u57FA\u7840","theme.skins":"\u4E3B\u9898\u76AE\u80A4","skin.cyber":"2077","skin.genshin":"\u539F\u795E","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"\u851A\u84DD\u6863\u6848","skin.zzz":"\u7EDD\u533A\u96F6","skin.dragonball":"\u4E03\u9F99\u73E0","skin.ikun":"ikun","botOnboarding.add":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.title":"\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.intro":"\u9009\u62E9 CLI \u4E0E\u5DE5\u4F5C\u76EE\u5F55\uFF0C\u626B\u7801\u521B\u5EFA PersonalAgent \u5E94\u7528\u540E\u5199\u5165\u672C\u673A bots.json\uFF0C\u5E76\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u3002","botOnboarding.cliLabel":"CLI \u9002\u914D\u5668","botOnboarding.dirLabel":"\u5DE5\u4F5C\u76EE\u5F55","botOnboarding.dirPlaceholder":"\u9ED8\u8BA4 ~\uFF08\u5BB6\u76EE\u5F55\uFF09\uFF0C\u9700\u4E3A daemon \u4E3B\u673A\u4E0A\u5DF2\u5B58\u5728\u7684\u76EE\u5F55","botOnboarding.modelLabel":"\u6A21\u578B\uFF08\u53EF\u9009\uFF09","botOnboarding.modelPlaceholder":"\u7559\u7A7A\u4F7F\u7528\u8BE5 CLI \u7684\u9ED8\u8BA4\u6A21\u578B","botOnboarding.startScan":"\u5F00\u59CB\u626B\u7801","botOnboarding.cancel":"\u53D6\u6D88","botOnboarding.starting":"\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...","botOnboarding.waiting":"\u8BF7\u7528\u98DE\u4E66 App \u626B\u7801\u786E\u8BA4\u521B\u5EFA\u5E94\u7528\u3002","botOnboarding.verifying":"\u626B\u7801\u6210\u529F\uFF0C\u6B63\u5728\u6821\u9A8C\u51ED\u8BC1...","botOnboarding.configuringPermissions":"\u6B63\u5728\u81EA\u52A8\u914D\u7F6E\u5F00\u653E\u5E73\u53F0\u6743\u9650\u2026","botOnboarding.platformScanHint":"\u8BF7\u7528\u98DE\u4E66 App \u518D\u626B\u4E00\u6B21\u7801\u767B\u5F55\u5F00\u653E\u5E73\u53F0\uFF08\u7528\u4E8E\u81EA\u52A8\u5BFC\u5165\u6743\u9650\u3001\u914D\u7F6E\u56DE\u8C03\u3001\u63D0\u4EA4\u7248\u672C\uFF09\u3002","botOnboarding.platformQrAlt":"\u5F00\u653E\u5E73\u53F0\u767B\u5F55\u4E8C\u7EF4\u7801","botOnboarding.completed":"\u673A\u5668\u4EBA\u5DF2\u6DFB\u52A0\u3002","botOnboarding.permissionOk":"\u5DF2\u81EA\u52A8\u5BFC\u5165 {count} \u9879\u6743\u9650\u3002","botOnboarding.permissionSkipped":"\uFF08\u8DF3\u8FC7 {count} \u9879\u5F53\u524D\u79DF\u6237\u76EE\u5F55\u4E2D\u6CA1\u6709\u7684\u6743\u9650\uFF09","botOnboarding.permissionVersion":"\u5DF2\u63D0\u4EA4\u53D1\u5E03\u7248\u672C {version}\u3002","botOnboarding.permissionManual":"\u6743\u9650\u672A\u80FD\u81EA\u52A8\u914D\u7F6E\uFF0C\u8BF7\u624B\u52A8\u5B8C\u6210\u4EE5\u4E0B\u6B65\u9AA4\uFF1A","botOnboarding.metaDir":"\u76EE\u5F55","botOnboarding.failed":"\u6DFB\u52A0\u5931\u8D25","botOnboarding.openLink":"\u6253\u4E0D\u5F00\u626B\u7801\uFF1F\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00","botOnboarding.close":"\u5173\u95ED","botOnboarding.restartHint":"\u5DF2\u5199\u5165 bots.json\u3002\u6267\u884C pnpm daemon:restart \u540E\u65B0\u673A\u5668\u4EBA\u751F\u6548\u3002","botOnboarding.qrAlt":"\u98DE\u4E66\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA\u4E8C\u7EF4\u7801","overview.title":"\u5DE5\u4F5C\u53F0","overview.subtitle":"\u6570\u5B57\u5458\u5DE5\u5B9E\u65F6\u72B6\u6001 \xB7 \u540C\u6B65\u98DE\u4E66\u8BDD\u9898","overview.team":"AI \u56E2\u961F","overview.teamHint":"\u6BCF\u4F4D\u6570\u5B57\u5458\u5DE5\u7684\u5B9E\u65F6\u72B6\u6001","overview.attention":"\u9700\u8981\u4F60\u5904\u7406","overview.attentionHint":"\u5361\u4F4F\u7684\u4EFB\u52A1\uFF0C\u56DE\u4E2A\u8BDD\u5C31\u80FD\u7EE7\u7EED\u8DD1","overview.activeSessions":"\u6D3B\u8DC3\u4F1A\u8BDD","overview.activeSessionsHint":"\u6B63\u5728\u8FD0\u8F6C\u7684\u4F1A\u8BDD","overview.today":"\u6B64\u523B\u6982\u89C8","overview.todayHint":"\u6D3B\u8DC3\u4F1A\u8BDD\u5206\u5E03","overview.viewAll":"\u67E5\u770B\u5168\u90E8 \u2192","overview.botIdle":"\u5F85\u547D\u4E2D\uFF0C\u968F\u65F6\u53EF\u63A5\u65B0\u4EFB\u52A1","overview.botOffline":"\u79BB\u7EBF \u2014 daemon \u672A\u4E0A\u7EBF","overview.botBusy":"\u6267\u884C\u4E2D \xB7 {count} \u4F1A\u8BDD","overview.botNeedsYou":"\u7B49\u4F60\u56DE\u590D","overview.botReady":"\u5C31\u7EEA","overview.botOff":"\u79BB\u7EBF","overview.sessionsCount":"{count} \u4F1A\u8BDD","overview.lastActive":"{time}\u524D\u6D3B\u8DC3","overview.noAttention":"\u6CA1\u6709\u7B49\u4F60\u5904\u7406\u7684\u4E8B\u9879","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.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.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.closeBulkConfirm":"\u5173\u95ED\u9009\u4E2D\u7684 {count} \u4E2A\u4F1A\u8BDD\uFF1F","sessions.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u4F1A\u8BDD\u3002","sessions.viewMode":"\u4F1A\u8BDD\u89C6\u56FE","sessions.viewBoard":"\u72B6\u6001\u677F","sessions.viewTable":"\u8868\u683C","sessions.selectSession":"\u9009\u62E9\u4F1A\u8BDD","sessions.board.needsYou":"\u9700\u8981\u4F60","sessions.board.needsYouHint":"\u7B49\u5F85\u4ED3\u5E93\u3001TUI \u9009\u62E9\u6216\u989D\u5EA6\u5904\u7406","sessions.board.starting":"\u542F\u52A8\u4E2D","sessions.board.startingHint":"CLI \u6B63\u5728\u521B\u5EFA\u6216\u6062\u590D","sessions.board.working":"\u5E72\u6D3B\u4E2D","sessions.board.workingHint":"\u6B63\u5728\u8F93\u51FA\u3001\u5206\u6790\u6216\u6267\u884C\u5DE5\u5177","sessions.board.idle":"\u7A7A\u95F2","sessions.board.idleHint":"\u53EF\u7EE7\u7EED\u5BF9\u8BDD\u6216\u63A5\u65B0\u4EFB\u52A1","sessions.board.emptyColumn":"\u6682\u65E0\u4F1A\u8BDD","sessions.board.signalRepo":"\u5F85\u9009\u4ED3\u5E93","sessions.board.signalPrompt":"\u7B49\u5F85 TUI \u9009\u62E9","sessions.board.signalLimited":"\u989D\u5EA6\u53D7\u9650","sessions.board.dragHint":"\u62D6\u52A8\u5217\u5934\u8C03\u6574\u5217\u987A\u5E8F","sessions.board.moveLeft":"\u5DE6\u79FB\u6B64\u5217","sessions.board.moveRight":"\u53F3\u79FB\u6B64\u5217","groups.title":"\u7FA4\u7EC4\u4E0E Bot","groups.subtitle":"\u67E5\u770B chat x bot \u8986\u76D6\u77E9\u9635\uFF0C\u7BA1\u7406\u62C9\u7FA4\u3001oncall\u3001\u9000\u7FA4\u548C\u89E3\u6563\u3002","groups.search":"\u641C\u7D22\u7FA4\u540D / ID / owner","groups.missingOnly":"\u4EC5\u7F3A bot","groups.refresh":"\u5237\u65B0","groups.create":"\u65B0\u5EFA\u7FA4","groups.chat":"\u7FA4\u804A","groups.actions":"\u64CD\u4F5C","groups.addBots":"\u6DFB\u52A0 bot","groups.manage":"\u7BA1\u7406","groups.empty":"\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u7FA4\u804A\u3002","groups.createTitle":"\u65B0\u5EFA\u7FA4\u804A","groups.createHelp":"\u9009\u62E9\u8981\u9080\u8BF7\u7684 bot\u3002dashboard \u4F1A\u81EA\u52A8\u9009\u62E9\u5728\u7EBF daemon \u4F5C\u4E3A\u521B\u5EFA\u8005\u3002","groups.name":"\u7FA4\u540D","groups.namePlaceholder":"\u4F8B\u5982 AI ChangeLog","groups.bindDir":"\u7ED1\u5B9A\u76EE\u5F55","groups.bindDirHelp":"\u65B0\u8BDD\u9898\u76F4\u63A5\u7528\u8BE5\u76EE\u5F55\u542F\u52A8 CLI\uFF0C\u8DF3\u8FC7 repo \u9009\u62E9\u3002","groups.botPicker":"Bot","groups.createSubmit":"\u521B\u5EFA","groups.cancel":"\u53D6\u6D88","groups.successTitle":"\u7FA4\u521B\u5EFA\u6210\u529F","groups.openGroup":"\u6253\u5F00\u65B0\u7FA4","groups.manageTitle":"\u7BA1\u7406 {name}","groups.owner":"\u7FA4\u4E3B","groups.oncall":"Oncall \u6A21\u5F0F","groups.oncallHelp":"\u5F00\u542F\u540E\uFF0C\u7FA4\u5185\u6210\u5458\u53EF @ \u673A\u5668\u4EBA\uFF1B\u65B0\u8BDD\u9898\u76F4\u63A5\u4F7F\u7528\u7ED1\u5B9A\u76EE\u5F55\u3002","groups.leaveTitle":"\u9009\u62E9\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.leaveSelected":"\u9009\u4E2D\u673A\u5668\u4EBA\u9000\u51FA\u7FA4\u804A","groups.disband":"\u89E3\u6563\u7FA4\u804A","groups.dangerHint":"\u89E3\u6563\u4EC5\u5F53\u5728\u7FA4\u673A\u5668\u4EBA\u662F\u7FA4\u4E3B\u65F6\u624D\u4F1A\u6210\u529F\uFF0C\u5426\u5219\u5EFA\u8BAE\u4F7F\u7528\u9000\u51FA\u7FA4\u804A\u3002","groups.save":"\u4FDD\u5B58","groups.needWorkingDir":"\u8BF7\u586B\u5DE5\u4F5C\u76EE\u5F55","groups.noBotsOnline":"\u6CA1\u6709\u5728\u7EBF bot\u3002\u8BF7\u5148\u91CD\u542F daemon\u3002","schedules.title":"\u5B9A\u65F6\u4EFB\u52A1","schedules.subtitle":"\u8DE8 daemon \u67E5\u770B\u3001\u6682\u505C\u3001\u6062\u590D\u548C\u7ACB\u5373\u89E6\u53D1\u5B9A\u65F6\u4EFB\u52A1\u3002","schedules.search":"\u641C\u7D22\u540D\u79F0 / prompt / \u5DE5\u4F5C\u76EE\u5F55","schedules.anyKind":"\u5168\u90E8\u7C7B\u578B","schedules.enabledOnly":"\u4EC5\u542F\u7528","schedules.name":"\u540D\u79F0","schedules.bot":"bot","schedules.schedule":"\u89C4\u5219","schedules.next":"\u4E0B\u6B21","schedules.last":"\u4E0A\u6B21","schedules.repeat":"\u91CD\u590D","schedules.enabled":"\u542F\u7528","schedules.actions":"\u64CD\u4F5C","schedules.runNow":"\u7ACB\u5373\u8FD0\u884C","schedules.pause":"\u6682\u505C","schedules.resume":"\u6062\u590D","schedules.empty":"\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\u3002","settings.title":"\u5168\u5C40\u8BBE\u7F6E","settings.subtitle":"\u7BA1\u7406\u672C\u673A botmux dashboard \u4E0E\u6240\u6709 bot \u5171\u4EAB\u7684\u5168\u5C40\u884C\u4E3A\u3002","settings.loading":"\u6B63\u5728\u52A0\u8F7D\u8BBE\u7F6E\u2026","settings.loadFailed":"\u8BBE\u7F6E\u52A0\u8F7D\u5931\u8D25","settings.readOnlyVisitor":"\u5F53\u524D\u662F\u53EA\u8BFB\u8BBF\u95EE\uFF0C\u4FEE\u6539\u8BBE\u7F6E\u9700\u8981\u6388\u6743\u94FE\u63A5\uFF08\u8FD0\u884C botmux dashboard \u83B7\u53D6\uFF09","settings.sectionAccess":"\u8BBF\u95EE\u6743\u9650","settings.publicReadOnly":"\u5141\u8BB8\u65E0 token \u53EA\u8BFB\u8BBF\u95EE dashboard","settings.publicReadOnlyHelp":"\u5F00\u542F\u540E\uFF0C\u6CA1\u6709 token \u7684\u8BBF\u95EE\u8005\u53EF\u4EE5\u67E5\u770B dashboard\u3001\u4F1A\u8BDD\u3001\u5B9A\u65F6\u4EFB\u52A1\u548C SSE\uFF1B\u5173\u95ED\u3001\u6682\u505C\u3001\u5BA1\u6279\u7B49\u5199\u64CD\u4F5C\u4ECD\u5FC5\u987B\u901A\u8FC7 token \u9274\u6743\u3002\u654F\u611F\u7EC8\u7AEF\u539F\u59CB\u65E5\u5FD7\u59CB\u7EC8\u9700\u8981 token\u3002","settings.sectionCards":"\u98DE\u4E66\u5361\u7247","settings.openTerminalInFeishu":"\u6D41\u5F0F\u5361\u7247\u7EC8\u7AEF\u6309\u94AE\u5728\u98DE\u4E66\u4FA7\u680F\u6253\u5F00","settings.openTerminalInFeishuHelp":"\u9ED8\u8BA4\u5173\u95ED\uFF1A\u7EC8\u7AEF\u6309\u94AE\u76F4\u63A5\u6253\u5F00 Web Terminal URL\u3002\u5F00\u542F\u540E\u4F7F\u7528\u98DE\u4E66 web_url/open \u5305\u88C5\uFF0C\u5728\u98DE\u4E66 PC \u4FA7\u680F\u91CC\u6253\u5F00\uFF1B\u5199\u6743\u9650\u4ECD\u7531\u7EC8\u7AEF token \u63A7\u5236\u3002","settings.saving":"\u4FDD\u5B58\u4E2D\u2026","settings.saved":"\u5DF2\u4FDD\u5B58","settings.saveFailed":"\u4FDD\u5B58\u5931\u8D25","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.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.sectionGrant":"\u6388\u6743\u4E0E\u989D\u5EA6","botDefaults.restrictGrant":"\u9650\u5236\u88AB\u6388\u6743\u4EBA\u53EA\u80FD\u7EAF\u5BF9\u8BDD","botDefaults.restrictGrantHelp":"\u5F00\u542F\u540E\uFF0C\u88AB /grant \u6388\u6743\u7684\u4EBA\uFF08owner \u81EA\u5DF1\u4E0D\u53D7\u9650\uFF09\u53EA\u80FD\u53D1\u666E\u901A\u5BF9\u8BDD\uFF0C\u6240\u6709 slash \u547D\u4EE4\u4E00\u5F8B\u62E6\u622A\uFF1Abotmux \u81EA\u5E26\u547D\u4EE4\u3001\u900F\u4F20\u547D\u4EE4\u3001/workflow\u3001/introduce\u3001/t \u4EE5\u53CA CLI \u539F\u751F\u547D\u4EE4\uFF08/help \u7B49\uFF09\u3002\u5F62\u5982 /path/to/file \u7684\u5185\u5BB9\u4E0D\u4F1A\u88AB\u8BEF\u5224\u3002","botDefaults.quotaDefault":"\u9ED8\u8BA4\u6D88\u606F\u989D\u5EA6","botDefaults.quotaPlaceholder":"\u7559\u7A7A\uFF1D\u4E0D\u914D\u7F6E\u9ED8\u8BA4\u989D\u5EA6","botDefaults.quotaHelp":"\u4E0D\u5E26\u6570\u5B57\u7684 /grant @x \u9ED8\u8BA4\u7ED9\u7684\u6D88\u606F\u6761\u6570\u3002\u7559\u7A7A\u6216\u70B9\u300C\u5173\u95ED\u300D\u53EA\u662F\u4E0D\u518D\u7ED9\u88F8 /grant \u5957\u9ED8\u8BA4\u989D\u5EA6\uFF0C\u4E0D\u4F1A\u6E05\u6389\u5DF2\u6709\u7684\u989D\u5EA6\u8BA1\u6570\uFF0C\u4E5F\u4E0D\u5F71\u54CD\u663E\u5F0F /grant @x N\u2014\u2014\u5B83\u4EEC\u7167\u5E38\u7EE7\u7EED enforce\u3002\u989D\u5EA6\u7528\u5C3D\u4F1A\u81EA\u52A8\u64A4\u9500\u8BE5\u4EBA\u6388\u6743\u3002","botDefaults.quotaSave":"\u4FDD\u5B58\u989D\u5EA6","botDefaults.quotaOff":"\u5173\u95ED","botDefaults.quotaInvalid":"\u989D\u5EA6\u5FC5\u987B\u662F\u6B63\u6574\u6570","botDefaults.quotaStateOff":"\u5F53\u524D\uFF1A\u672A\u914D\u7F6E\u9ED8\u8BA4\u989D\u5EA6","botDefaults.quotaStateOn":"\u5F53\u524D\uFF1A\u6BCF\u4EBA {count} \u6761","nav.roles":"\u89D2\u8272\u7BA1\u7406","roles.title":"\u89D2\u8272\u7BA1\u7406","roles.subtitle":"\u4E3A\u6BCF\u4E2A\u7FA4\u7EC4\u7684\u6BCF\u4E2A Bot \u5355\u72EC\u8BBE\u7F6E\u89D2\u8272\u63D0\u793A\u8BCD\uFF0CBot \u5728\u8BE5\u7FA4\u4E2D\u4F1A\u4EE5\u6B64\u89D2\u8272\u884C\u4E8B\u3002","roles.search":"\u641C\u7D22\u7FA4\u540D/Bot/ID","roles.refresh":"\u5237\u65B0","roles.selectHint":"\u2190 \u5C55\u5F00\u7FA4\u7EC4\uFF0C\u9009\u62E9\u4E00\u4E2A Bot \u6765\u7F16\u8F91\u89D2\u8272","roles.editorPlaceholder":`\u8F93\u5165\u89D2\u8272\u63CF\u8FF0\uFF0C\u4F8B\u5982\uFF1A
|
|
2
|
+
\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.unknown":"\u672A\u77E5","common.now":"\u521A\u521A","common.never":"\u4ECE\u672A","common.all":"\u5168\u90E8","nav.workflows":"\u5DE5\u4F5C\u6D41(beta)","nav.workflowCatalog":"\u76EE\u5F55","workflow.subnav.runs":"\u8FD0\u884C","workflow.subnav.catalog":"\u76EE\u5F55","workflow.searchPlaceholder":"\u641C\u7D22 runId / workflowId / chatId","workflow.filter.nonTerminal":"\u975E\u7EC8\u6001","workflow.filter.all":"\u5168\u90E8","workflow.status.pending":"\u5F85\u5F00\u59CB","workflow.status.running":"\u8FD0\u884C\u4E2D","workflow.status.waiting":"\u7B49\u5F85\u4E2D","workflow.status.effectAttempting":"\u526F\u4F5C\u7528\u4E2D","workflow.status.timedOut":"\u5DF2\u8D85\u65F6","workflow.status.succeeded":"\u6210\u529F","workflow.status.failed":"\u5931\u8D25","workflow.status.cancelled":"\u5DF2\u53D6\u6D88","workflow.table.run":"\u8FD0\u884C","workflow.table.workflow":"\u5DE5\u4F5C\u6D41","workflow.table.status":"\u72B6\u6001","workflow.table.lastSeq":"\u6700\u540E\u5E8F\u53F7","workflow.table.dangling":"\u60AC\u6302 dEf/dAct/dWait","workflow.table.updated":"\u66F4\u65B0\u65F6\u95F4","workflow.table.chatApp":"\u7FA4\u804A / \u5E94\u7528","workflow.list.failedLoad":"\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","workflow.list.noRuns":"\u6CA1\u6709\u5339\u914D\u7684\u8FD0\u884C\u3002","workflow.list.noFilterMatch":"\u6CA1\u6709\u7B26\u5408\u7B5B\u9009\u6761\u4EF6\u7684\u8FD0\u884C\u3002","workflow.list.loaded":"{count} \u4E2A\u8FD0\u884C \xB7 \u5237\u65B0\u4E8E {time}","workflow.list.error":"\u9519\u8BEF\uFF1A{error}","workflow.detail.back":"\u8FD4\u56DE","workflow.detail.loading":"\u52A0\u8F7D\u4E2D...","workflow.detail.loadFailed":"\u52A0\u8F7D\u5931\u8D25","workflow.detail.cancel":"\u53D6\u6D88","workflow.detail.cliCancelOnly":"\u4EC5 CLI \u53EF\u53D6\u6D88","workflow.detail.cancelTitle":"\u53D6\u6D88\u8FD9\u4E2A\u5DE5\u4F5C\u6D41\u8FD0\u884C","workflow.detail.cliCancelTitle":"\u65E0\u6CD5\u5728\u9875\u9762\u53D6\u6D88\uFF1A\u8BF7\u4F7F\u7528 botmux workflow cancel {runId}","workflow.detail.nodes":"\u8282\u70B9 / Activity","workflow.detail.parallel":"\u5E76\u53D1\u6267\u884C","workflow.detail.parallelMeta":"{count} \u6B21\u5C1D\u8BD5 \xB7 \u6700\u9AD8\u5E76\u53D1 {max} \xB7 \u8FD0\u884C\u4E2D {running}","workflow.detail.noParallelData":"\u8FD8\u6CA1\u6709 attempt \u65F6\u95F4\u6570\u636E\u3002","workflow.detail.parallelNow":"\u73B0\u5728","workflow.detail.node":"\u8282\u70B9","workflow.detail.nodeStatus":"\u8282\u70B9\u72B6\u6001","workflow.detail.activity":"Activity","workflow.detail.activityStatus":"Activity \u72B6\u6001","workflow.detail.attempts":"\u5C1D\u8BD5\u6B21\u6570","workflow.detail.current":"\u5F53\u524D\u5C1D\u8BD5","workflow.detail.detail":"\u8BE6\u60C5","workflow.detail.nodeIO":"\u8282\u70B9\u8F93\u5165\u8F93\u51FA","workflow.detail.timeline":"\u65F6\u95F4\u7EBF","workflow.detail.loadOlder":"\u52A0\u8F7D\u66F4\u65E9\u4E8B\u4EF6","workflow.detail.seq":"\u5E8F\u53F7","workflow.detail.actor":"\u6267\u884C\u8005","workflow.detail.error":"\u9519\u8BEF","workflow.detail.event":"\u4E8B\u4EF6","workflow.detail.time":"\u65F6\u95F4","workflow.detail.refreshed":"\u5237\u65B0\u4E8E {time}","workflow.detail.unknownRun":"\u672A\u77E5\u8FD0\u884C","workflow.detail.snapshotHttp":"snapshot HTTP {status}","workflow.detail.eventsHttp":"events HTTP {status}","workflow.detail.cancelUnavailable":"\u65E0\u6CD5\u53D6\u6D88\uFF1A\u8BF7\u4F7F\u7528 botmux workflow cancel {runId}","workflow.detail.cancelConfirm":`\u786E\u8BA4\u53D6\u6D88\u5DE5\u4F5C\u6D41\u8FD0\u884C {runId}\uFF1F
|
|
3
3
|
|
|
4
4
|
{total} \u4E2A\u60AC\u6302\u9879\u4F1A\u7531 cancel recovery \u5904\u7406\u3002
|
|
5
5
|
effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"workflow.detail.writeAccessCancel":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u70B9\u51FB\u53D6\u6D88\u3002","workflow.detail.cancelHttp":"cancel HTTP {status}","workflow.detail.cancelPending":"\u53D6\u6D88\u5DF2\u63D0\u4EA4\uFF1B\u7B49\u5F85\u8FD0\u884C\u4E2D\u7684 activity \u6536\u655B","workflow.detail.writeAccessApproval":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u5BA1\u6279\u3002","workflow.detail.actionHttp":"{action} HTTP {status}","workflow.detail.approved":"\u5DF2\u901A\u8FC7","workflow.detail.rejected":"\u5DF2\u62D2\u7EDD","workflow.detail.alreadyTerminal":"\u8FD0\u884C\u5DF2\u7EC8\u6001\uFF1B\u672A\u5E94\u7528\u201C{label}\u201D\u3002","workflow.detail.workflowContinue":"{label}\uFF1B\u7B49\u5F85\u5DE5\u4F5C\u6D41\u7EE7\u7EED\u6267\u884C\u3002","workflow.detail.workflowRefreshing":"{label}\uFF1B\u6B63\u5728\u5237\u65B0\u5DE5\u4F5C\u6D41\u72B6\u6001\u3002","workflow.detail.eventsLoaded":"\u5DF2\u52A0\u8F7D {loaded}/{total} \u4E2A\u4E8B\u4EF6","workflow.detail.dangling":"\u60AC\u6302\u9879","workflow.detail.noDangling":"\u6CA1\u6709\u60AC\u6302\u5DE5\u4F5C\u3002","workflow.detail.none":"\u65E0","workflow.detail.noNodes":"\u8FD8\u6CA1\u6709\u8282\u70B9\u3002","workflow.detail.idle":"\u7A7A\u95F2","workflow.detail.noNodeIO":"\u8FD8\u6CA1\u6709\u8282\u70B9\u8F93\u5165\u8F93\u51FA\u3002","workflow.detail.notDispatched":"\u5C1A\u672A\u6D3E\u53D1","workflow.detail.noAttempt":"\u8FD8\u6CA1\u6709\u5C1D\u8BD5","workflow.detail.attempt":"\u5C1D\u8BD5","workflow.detail.authoredInput":"\u539F\u59CB\u8F93\u5165","workflow.detail.resolvedInput":"\u89E3\u6790\u540E\u8F93\u5165","workflow.detail.output":"\u8F93\u51FA","workflow.detail.executionLog":"\u6267\u884C\u65E5\u5FD7","workflow.detail.liveTerminal":"\u5B9E\u65F6\u7EC8\u7AEF","workflow.detail.terminalLive":"\u5728\u7EBF","workflow.detail.terminalClosedShort":"\u5DF2\u5173\u95ED","workflow.detail.terminalClosed":"\u7EC8\u7AEF\u5DF2\u5173\u95ED\u3002\u8BF7\u67E5\u770B\u4E0B\u65B9\u6267\u884C\u65E5\u5FD7\u83B7\u53D6\u6700\u7EC8\u8BB0\u5F55\u3002","workflow.detail.openTerminalNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u7EC8\u7AEF","workflow.detail.terminalReplay":"\u7EC8\u7AEF\u56DE\u653E","workflow.detail.openReplayNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u56DE\u653E","workflow.detail.downloadFullLog":"\u4E0B\u8F7D\u5B8C\u6574\u65E5\u5FD7","workflow.detail.terminalResume":"\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.openResumeNewTab":"\u5728\u65B0\u6807\u7B7E\u9875\u6253\u5F00\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.resumeSession":"\u7EE7\u7EED\u4F1A\u8BDD","workflow.detail.resumeStarting":"\u6B63\u5728\u542F\u52A8\u2026","workflow.detail.endResumeSession":"\u7ED3\u675F\u8C03\u8BD5\u4F1A\u8BDD","workflow.detail.resumeEnding":"\u7ED3\u675F\u4E2D\u2026","workflow.detail.resumeUnsupportedCli":"{cliId} CLI \u4E0D\u652F\u6301 resume","workflow.detail.resumeMissingCliSession":"\u7F3A\u5C11 cliSessionId\uFF0C\u65E0\u6CD5 resume","workflow.detail.resumeStartFailed":"\u542F\u52A8\u8C03\u8BD5\u4F1A\u8BDD\u5931\u8D25 (HTTP {status})","workflow.detail.resumeEndFailed":"\u7ED3\u675F\u8C03\u8BD5\u4F1A\u8BDD\u5931\u8D25 (HTTP {status})","workflow.detail.writeAccessResume":"\u9700\u8981\u5199\u5165\u6743\u9650\u624D\u80FD resume \u4F1A\u8BDD\u3002","workflow.detail.waitPrompt":"\u7B49\u5F85\u63D0\u793A","workflow.detail.approvalComment":"\u5BA1\u6279\u5907\u6CE8","workflow.detail.optionalComment":"\u53EF\u9009\u5907\u6CE8","workflow.detail.approve":"\u901A\u8FC7","workflow.detail.reject":"\u62D2\u7EDD","workflow.detail.submitting":"\u63D0\u4EA4\u4E2D...","workflow.detail.empty":"\u7A7A","workflow.detail.truncated":"\u5DF2\u622A\u65AD","workflow.detail.noData":"\u6CA1\u6709\u6570\u636E\u3002","workflow.detail.noPreview":"\u6CA1\u6709\u9884\u89C8\u3002","workflow.detail.open":"\u6253\u5F00","workflow.detail.deadline":"\u622A\u6B62","workflow.detail.effect":"\u526F\u4F5C\u7528","workflow.detail.wait":"\u7B49\u5F85","workflow.detail.noEvents":"\u8FD8\u6CA1\u6709\u4E8B\u4EF6\u3002","workflow.summary.workflow":"\u5DE5\u4F5C\u6D41","workflow.summary.status":"\u72B6\u6001","workflow.summary.lastSeq":"\u6700\u540E\u5E8F\u53F7","workflow.summary.updated":"\u66F4\u65B0\u65F6\u95F4","workflow.summary.revision":"\u4FEE\u8BA2","workflow.summary.initiator":"\u53D1\u8D77\u4EBA","workflow.summary.failedNode":"\u5931\u8D25\u8282\u70B9","workflow.summary.cancelOrigin":"\u53D6\u6D88\u6765\u6E90","workflow.summary.chat":"\u7FA4\u804A","workflow.summary.app":"\u5E94\u7528","workflow.dangling.activities":"Activities","workflow.dangling.effects":"Effects","workflow.dangling.waits":"Waits","workflow.dangling.cancels":"Cancels","catalog.title":"\u5DE5\u4F5C\u6D41\u76EE\u5F55","catalog.subtitle":"\u4ECE\u5DF2\u4FDD\u5B58\u7684 workflow \u5B9A\u4E49\u521B\u5EFA\u4E00\u6B21\u8FD0\u884C\u3002","catalog.searchPlaceholder":"\u641C\u7D22 workflowId / \u8DEF\u5F84","catalog.refresh":"\u5237\u65B0","catalog.loading":"\u6B63\u5728\u52A0\u8F7D\u76EE\u5F55...","catalog.loadFailed":"\u76EE\u5F55\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","catalog.noDefinitions":"\u6CA1\u6709\u627E\u5230 workflow \u5B9A\u4E49\u3002","catalog.noFilterMatch":"\u6CA1\u6709\u7B26\u5408\u7B5B\u9009\u6761\u4EF6\u7684\u5B9A\u4E49\u3002","catalog.table.workflow":"\u5DE5\u4F5C\u6D41","catalog.table.version":"\u7248\u672C","catalog.table.params":"\u53C2\u6570","catalog.table.nodes":"\u8282\u70B9","catalog.table.revision":"\u4FEE\u8BA2","catalog.table.path":"\u8DEF\u5F84","catalog.paramSummary":"{required}/{total} \u5FC5\u586B","catalog.back":"\u8FD4\u56DE\u76EE\u5F55","catalog.detailTitle":"\u5DE5\u4F5C\u6D41\u5B9A\u4E49","catalog.definitionLoadFailed":"\u5B9A\u4E49\u52A0\u8F7D\u5931\u8D25\uFF1A{error}","catalog.summary":"\u6458\u8981","catalog.paramsSchema":"\u53C2\u6570 Schema","catalog.definitionJson":"\u5B9A\u4E49 JSON","catalog.runPanel":"\u8FD0\u884C\u5DE5\u4F5C\u6D41","catalog.paramsJson":"\u53C2\u6570 JSON","catalog.paramsPlaceholder":`{
|
|
6
6
|
"city": "\u5317\u4EAC"
|
|
7
|
-
}`,"catalog.chatId":"\u7FA4\u804A ID","catalog.larkAppId":"\u98DE\u4E66\u5E94\u7528 ID","catalog.chatBindingHint":"\u5FC5\u586B\uFF0C\u7528\u4E8E\u786E\u5B9A humanGate \u5361\u7247\u53D1\u9001\u5230\u54EA\u4E2A\u98DE\u4E66\u7FA4\uFF0C\u4EE5\u53CA\u53D6\u6D88\u8DEF\u7531\u5F52\u5C5E\u3002","catalog.run":"\u8FD0\u884C","catalog.running":"\u542F\u52A8\u4E2D...","catalog.badParamsJson":"\u53C2\u6570\u5FC5\u987B\u662F JSON object\u3002","catalog.writeAccess":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u8FD0\u884C\u3002","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"\u8FD0\u884C\u5DF2\u542F\u52A8\uFF1B\u6B63\u5728\u6253\u5F00\u8BE6\u60C5\u9875...","catalog.invalidParams":"\u53C2\u6570\u65E0\u6548","catalog.issue":"{path}: {message}","catalog.noParams":"\u6CA1\u6709\u58F0\u660E\u53C2\u6570\u3002","catalog.required":"\u5FC5\u586B","catalog.optional":"\u53EF\u9009","catalog.default":"\u9ED8\u8BA4\u503C","catalog.description":"\u8BF4\u660E","catalog.path":"\u8DEF\u5F84","catalog.revision":"\u4FEE\u8BA2","catalog.nodeCount":"\u8282\u70B9\u6570"},bn={"app.name":"botmux","app.subtitle":"Feishu AI CLI Control","time.secondsAgo":"{value}s ago","time.minutesAgo":"{value}m ago","time.hoursAgo":"{value}h ago","nav.overview":"Overview","nav.sessions":"Sessions","nav.groups":"Groups","nav.schedules":"Schedules","nav.botDefaults":"Bot Defaults","status.live":"Live","status.disconnected":"Disconnected","status.system":"System","status.light":"Light","status.dark":"Dark","status.language":"Language","status.theme":"Theme","botOnboarding.add":"Add Bot","botOnboarding.title":"Add Bot","botOnboarding.intro":"Pick a CLI and working directory, scan to create a PersonalAgent app \u2014 the dashboard writes it to local bots.json and auto-configures Open Platform permissions.","botOnboarding.cliLabel":"CLI adapter","botOnboarding.dirLabel":"Working directory","botOnboarding.dirPlaceholder":"Default ~ (home); must exist on the daemon host","botOnboarding.modelLabel":"Model (optional)","botOnboarding.modelPlaceholder":"Leave empty for the CLI default model","botOnboarding.startScan":"Start scan","botOnboarding.cancel":"Cancel","botOnboarding.starting":"Generating QR code...","botOnboarding.waiting":"Scan with the Feishu app to create the app.","botOnboarding.verifying":"Scan accepted. Verifying credentials...","botOnboarding.configuringPermissions":"Auto-configuring Open Platform permissions\u2026","botOnboarding.platformScanHint":"Scan once more with the Feishu app to sign in to the Open Platform (to auto-import permissions, set the callback, and submit a version).","botOnboarding.platformQrAlt":"Open Platform login QR code","botOnboarding.completed":"Bot added.","botOnboarding.permissionOk":"Auto-imported {count} permissions.","botOnboarding.permissionSkipped":"({count} skipped \u2014 not in the tenant catalog)","botOnboarding.permissionVersion":"Submitted version {version}.","botOnboarding.permissionManual":"Permissions could not be auto-configured. Complete these steps manually:","botOnboarding.metaDir":"Dir","botOnboarding.failed":"Add failed","botOnboarding.openLink":"Open scan link in browser","botOnboarding.close":"Close","botOnboarding.restartHint":"bots.json has been updated. Run pnpm daemon:restart for the new bot to take effect.","botOnboarding.qrAlt":"Feishu bot onboarding QR code","overview.title":"Control Overview","overview.subtitle":"A realtime control plane across bots, chats, CLI sessions, and schedules.","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.status":"Status","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.close":"Close Session","sessions.resume":"Resume Session","sessions.dismiss":"Close","sessions.closeConfirm":"Close this session?","sessions.resumeFailed":"Resume failed","sessions.closeBulkConfirm":"Close {count} selected sessions?","sessions.empty":"No sessions match the filters.","groups.title":"Groups & Bots","groups.subtitle":"Inspect the chat x bot matrix and manage group creation, oncall, leave, and disband flows.","groups.search":"Search chat name / ID / owner","groups.missingOnly":"Missing bot only","groups.refresh":"Refresh","groups.create":"New Group","groups.chat":"Chat","groups.actions":"Actions","groups.addBots":"Add Bots","groups.manage":"Manage","groups.empty":"No chats match the filters.","groups.createTitle":"Create New Group","groups.createHelp":"Pick bots to invite. The dashboard chooses an online daemon as creator.","groups.name":"Group Name","groups.namePlaceholder":"e.g. AI ChangeLog","groups.bindDir":"Bind Directory","groups.bindDirHelp":"New topics start the CLI here and skip repo selection.","groups.botPicker":"Bots","groups.createSubmit":"Create","groups.cancel":"Cancel","groups.successTitle":"Group Created","groups.openGroup":"Open Group","groups.manageTitle":"Manage {name}","groups.owner":"Owner","groups.oncall":"Oncall Mode","groups.oncallHelp":"When enabled, group members can @ the bot; new topics use the bound directory.","groups.leaveTitle":"Select Bots to Leave","groups.leaveSelected":"Selected Bots Leave","groups.disband":"Disband Group","groups.dangerHint":"Disband only works when an in-chat bot is the owner. Otherwise prefer leaving the chat.","groups.save":"Save","groups.needWorkingDir":"Working directory is required","groups.noBotsOnline":"No bots online. Restart the daemon first.","schedules.title":"Schedules","schedules.subtitle":"View, pause, resume, and run scheduled tasks across daemons.","schedules.search":"Search name / prompt / working dir","schedules.anyKind":"Any kind","schedules.enabledOnly":"Enabled only","schedules.name":"Name","schedules.bot":"Bot","schedules.schedule":"Schedule","schedules.next":"Next","schedules.last":"Last","schedules.repeat":"Repeat","schedules.enabled":"Enabled","schedules.actions":"Actions","schedules.runNow":"Run Now","schedules.pause":"Pause","schedules.resume":"Resume","schedules.empty":"No schedules.","botDefaults.title":"Bot Defaults","botDefaults.subtitle":"Manage each bot's defaults: new-chat oncall auto-binding, card signature, and more.","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.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.sectionGrant":"Authorization & Quota","botDefaults.restrictGrant":"Restrict grantees to plain conversation","botDefaults.restrictGrantHelp":"When enabled, /grant-authorized users (the owner is exempt) can only send plain messages; every slash command is blocked: botmux built-in commands, passthrough commands, /workflow, /introduce, /t, and CLI-native commands (/help, etc.). Text like /path/to/file is not misclassified.","botDefaults.quotaDefault":"Default message quota","botDefaults.quotaPlaceholder":"Empty = no default quota","botDefaults.quotaHelp":'Message count a bare /grant @x (no number) hands out. Empty or "Turn off" merely stops applying a default to bare /grant \u2014 it does NOT clear existing quota counters, nor affect an explicit /grant @x N; those keep being enforced. Authorization is auto-revoked once a quota runs out.',"botDefaults.quotaSave":"Save quota","botDefaults.quotaOff":"Turn off","botDefaults.quotaInvalid":"Quota must be a positive integer","botDefaults.quotaStateOff":"Current: no default quota","botDefaults.quotaStateOn":"Current: {count} per grantee","nav.roles":"Roles","roles.title":"Role Management","roles.subtitle":"Set per-bot role prompts for each group. Each bot adopts its own persona in the selected group.","roles.search":"Search group / bot / ID","roles.refresh":"Refresh","roles.selectHint":"\u2190 Expand a group and select a bot to edit its role","roles.editorPlaceholder":`Enter role description, e.g.:
|
|
8
|
-
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.unknown":"Unknown","common.now":"now","common.never":"never","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}?
|
|
7
|
+
}`,"catalog.chatId":"\u7FA4\u804A ID","catalog.larkAppId":"\u98DE\u4E66\u5E94\u7528 ID","catalog.chatBindingHint":"\u5FC5\u586B\uFF0C\u7528\u4E8E\u786E\u5B9A humanGate \u5361\u7247\u53D1\u9001\u5230\u54EA\u4E2A\u98DE\u4E66\u7FA4\uFF0C\u4EE5\u53CA\u53D6\u6D88\u8DEF\u7531\u5F52\u5C5E\u3002","catalog.run":"\u8FD0\u884C","catalog.running":"\u542F\u52A8\u4E2D...","catalog.badParamsJson":"\u53C2\u6570\u5FC5\u987B\u662F JSON object\u3002","catalog.writeAccess":"\u9700\u8981\u5199\u6743\u9650\uFF1A\u8BF7\u5728\u7EC8\u7AEF\u8FD0\u884C `botmux dashboard` \u83B7\u53D6\u4E00\u6B21\u6027 URL\uFF0C\u6253\u5F00\u540E\u5199\u5165 cookie\uFF0C\u518D\u56DE\u6765\u8FD0\u884C\u3002","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"\u8FD0\u884C\u5DF2\u542F\u52A8\uFF1B\u6B63\u5728\u6253\u5F00\u8BE6\u60C5\u9875...","catalog.invalidParams":"\u53C2\u6570\u65E0\u6548","catalog.issue":"{path}: {message}","catalog.noParams":"\u6CA1\u6709\u58F0\u660E\u53C2\u6570\u3002","catalog.required":"\u5FC5\u586B","catalog.optional":"\u53EF\u9009","catalog.default":"\u9ED8\u8BA4\u503C","catalog.description":"\u8BF4\u660E","catalog.path":"\u8DEF\u5F84","catalog.revision":"\u4FEE\u8BA2","catalog.nodeCount":"\u8282\u70B9\u6570"},Lo={"app.name":"botmux","app.subtitle":"Feishu AI CLI Control","time.secondsAgo":"{value}s ago","time.minutesAgo":"{value}m ago","time.hoursAgo":"{value}h ago","nav.overview":"Overview","nav.sessions":"Sessions","nav.groups":"Groups","nav.schedules":"Schedules","nav.settings":"Settings","nav.botDefaults":"Bot Defaults","status.live":"Live","status.disconnected":"Disconnected","status.system":"System","status.light":"Light","status.dark":"Dark","status.language":"Language","status.theme":"Theme","theme.base":"Basic","theme.skins":"Skins","skin.cyber":"2077","skin.genshin":"Genshin","skin.fallout":"Fallout","skin.prts":"PRTS","skin.bluearchive":"Blue Archive","skin.zzz":"ZZZ","skin.dragonball":"Dragon Ball","skin.ikun":"ikun","botOnboarding.add":"Add Bot","botOnboarding.title":"Add Bot","botOnboarding.intro":"Pick a CLI and working directory, scan to create a PersonalAgent app \u2014 the dashboard writes it to local bots.json and auto-configures Open Platform permissions.","botOnboarding.cliLabel":"CLI adapter","botOnboarding.dirLabel":"Working directory","botOnboarding.dirPlaceholder":"Default ~ (home); must exist on the daemon host","botOnboarding.modelLabel":"Model (optional)","botOnboarding.modelPlaceholder":"Leave empty for the CLI default model","botOnboarding.startScan":"Start scan","botOnboarding.cancel":"Cancel","botOnboarding.starting":"Generating QR code...","botOnboarding.waiting":"Scan with the Feishu app to create the app.","botOnboarding.verifying":"Scan accepted. Verifying credentials...","botOnboarding.configuringPermissions":"Auto-configuring Open Platform permissions\u2026","botOnboarding.platformScanHint":"Scan once more with the Feishu app to sign in to the Open Platform (to auto-import permissions, set the callback, and submit a version).","botOnboarding.platformQrAlt":"Open Platform login QR code","botOnboarding.completed":"Bot added.","botOnboarding.permissionOk":"Auto-imported {count} permissions.","botOnboarding.permissionSkipped":"({count} skipped \u2014 not in the tenant catalog)","botOnboarding.permissionVersion":"Submitted version {version}.","botOnboarding.permissionManual":"Permissions could not be auto-configured. Complete these steps manually:","botOnboarding.metaDir":"Dir","botOnboarding.failed":"Add failed","botOnboarding.openLink":"Open scan link in browser","botOnboarding.close":"Close","botOnboarding.restartHint":"bots.json has been updated. Run pnpm daemon:restart for the new bot to take effect.","botOnboarding.qrAlt":"Feishu bot onboarding QR code","overview.title":"Workbench","overview.subtitle":"Live status of your AI teammates \xB7 synced with Feishu topics","overview.team":"AI Team","overview.teamHint":"Live status of every digital teammate","overview.attention":"Needs You","overview.attentionHint":"Blocked tasks \u2014 one reply gets them moving again","overview.activeSessions":"Active Sessions","overview.activeSessionsHint":"Sessions currently running","overview.today":"Right Now","overview.todayHint":"Active session distribution","overview.viewAll":"View all \u2192","overview.botIdle":"Standing by, ready for new tasks","overview.botOffline":"Offline \u2014 daemon not running","overview.botBusy":"Working \xB7 {count} sessions","overview.botNeedsYou":"Waiting on you","overview.botReady":"Ready","overview.botOff":"Offline","overview.sessionsCount":"{count} sessions","overview.lastActive":"active {time} ago","overview.noAttention":"Nothing waiting on you","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.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.close":"Close Session","sessions.resume":"Resume Session","sessions.dismiss":"Close","sessions.closeConfirm":"Close this session?","sessions.resumeFailed":"Resume failed","sessions.closeBulkConfirm":"Close {count} selected sessions?","sessions.empty":"No sessions match the filters.","sessions.viewMode":"Session view","sessions.viewBoard":"Board","sessions.viewTable":"Table","sessions.selectSession":"Select session","sessions.board.needsYou":"Needs You","sessions.board.needsYouHint":"Repo, TUI, or usage limit waiting","sessions.board.starting":"Starting","sessions.board.startingHint":"CLI is spawning or resuming","sessions.board.working":"Working","sessions.board.workingHint":"Streaming, analyzing, or using tools","sessions.board.idle":"Idle","sessions.board.idleHint":"Ready for the next message","sessions.board.emptyColumn":"No sessions","sessions.board.signalRepo":"Repo needed","sessions.board.signalPrompt":"TUI choice needed","sessions.board.signalLimited":"Usage limited","sessions.board.dragHint":"Drag header to reorder columns","sessions.board.moveLeft":"Move column left","sessions.board.moveRight":"Move column right","groups.title":"Groups & Bots","groups.subtitle":"Inspect the chat x bot matrix and manage group creation, oncall, leave, and disband flows.","groups.search":"Search chat name / ID / owner","groups.missingOnly":"Missing bot only","groups.refresh":"Refresh","groups.create":"New Group","groups.chat":"Chat","groups.actions":"Actions","groups.addBots":"Add Bots","groups.manage":"Manage","groups.empty":"No chats match the filters.","groups.createTitle":"Create New Group","groups.createHelp":"Pick bots to invite. The dashboard chooses an online daemon as creator.","groups.name":"Group Name","groups.namePlaceholder":"e.g. AI ChangeLog","groups.bindDir":"Bind Directory","groups.bindDirHelp":"New topics start the CLI here and skip repo selection.","groups.botPicker":"Bots","groups.createSubmit":"Create","groups.cancel":"Cancel","groups.successTitle":"Group Created","groups.openGroup":"Open Group","groups.manageTitle":"Manage {name}","groups.owner":"Owner","groups.oncall":"Oncall Mode","groups.oncallHelp":"When enabled, group members can @ the bot; new topics use the bound directory.","groups.leaveTitle":"Select Bots to Leave","groups.leaveSelected":"Selected Bots Leave","groups.disband":"Disband Group","groups.dangerHint":"Disband only works when an in-chat bot is the owner. Otherwise prefer leaving the chat.","groups.save":"Save","groups.needWorkingDir":"Working directory is required","groups.noBotsOnline":"No bots online. Restart the daemon first.","schedules.title":"Schedules","schedules.subtitle":"View, pause, resume, and run scheduled tasks across daemons.","schedules.search":"Search name / prompt / working dir","schedules.anyKind":"Any kind","schedules.enabledOnly":"Enabled only","schedules.name":"Name","schedules.bot":"Bot","schedules.schedule":"Schedule","schedules.next":"Next","schedules.last":"Last","schedules.repeat":"Repeat","schedules.enabled":"Enabled","schedules.actions":"Actions","schedules.runNow":"Run Now","schedules.pause":"Pause","schedules.resume":"Resume","schedules.empty":"No schedules.","settings.title":"Global Settings","settings.subtitle":"Manage machine-wide botmux dashboard behavior shared by every bot.","settings.loading":"Loading settings\u2026","settings.loadFailed":"Failed to load settings","settings.readOnlyVisitor":"Read-only access \u2014 changing settings requires an authorized link (run botmux dashboard).","settings.sectionAccess":"Access","settings.publicReadOnly":"Allow tokenless read-only dashboard access","settings.publicReadOnlyHelp":"When enabled, visitors without a token can view the dashboard, sessions, schedules, and SSE. Writes such as close, pause, and approvals still require token auth. Sensitive raw terminal logs always require a token.","settings.sectionCards":"Feishu Cards","settings.openTerminalInFeishu":"Open streaming-card terminals in the Feishu sidebar","settings.openTerminalInFeishuHelp":"Off by default: terminal buttons open the Web Terminal URL directly. When enabled, botmux wraps the URL with Feishu web_url/open so Feishu PC opens it in a sidebar. Terminal write access is still controlled by its token.","settings.saving":"Saving\u2026","settings.saved":"Saved","settings.saveFailed":"Save failed","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.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.sectionGrant":"Authorization & Quota","botDefaults.restrictGrant":"Restrict grantees to plain conversation","botDefaults.restrictGrantHelp":"When enabled, /grant-authorized users (the owner is exempt) can only send plain messages; every slash command is blocked: botmux built-in commands, passthrough commands, /workflow, /introduce, /t, and CLI-native commands (/help, etc.). Text like /path/to/file is not misclassified.","botDefaults.quotaDefault":"Default message quota","botDefaults.quotaPlaceholder":"Empty = no default quota","botDefaults.quotaHelp":'Message count a bare /grant @x (no number) hands out. Empty or "Turn off" merely stops applying a default to bare /grant \u2014 it does NOT clear existing quota counters, nor affect an explicit /grant @x N; those keep being enforced. Authorization is auto-revoked once a quota runs out.',"botDefaults.quotaSave":"Save quota","botDefaults.quotaOff":"Turn off","botDefaults.quotaInvalid":"Quota must be a positive integer","botDefaults.quotaStateOff":"Current: no default quota","botDefaults.quotaStateOn":"Current: {count} per grantee","nav.roles":"Roles","roles.title":"Role Management","roles.subtitle":"Set per-bot role prompts for each group. Each bot adopts its own persona in the selected group.","roles.search":"Search group / bot / ID","roles.refresh":"Refresh","roles.selectHint":"\u2190 Expand a group and select a bot to edit its role","roles.editorPlaceholder":`Enter role description, e.g.:
|
|
8
|
+
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.unknown":"Unknown","common.now":"now","common.never":"never","common.all":"All","nav.workflows":"Workflows (beta)","nav.workflowCatalog":"Catalog","workflow.subnav.runs":"Runs","workflow.subnav.catalog":"Catalog","workflow.searchPlaceholder":"search runId / workflowId / chatId","workflow.filter.nonTerminal":"non-terminal","workflow.filter.all":"all","workflow.status.pending":"pending","workflow.status.running":"running","workflow.status.waiting":"waiting","workflow.status.effectAttempting":"effect","workflow.status.timedOut":"timed out","workflow.status.succeeded":"succeeded","workflow.status.failed":"failed","workflow.status.cancelled":"cancelled","workflow.table.run":"run","workflow.table.workflow":"workflow","workflow.table.status":"status","workflow.table.lastSeq":"lastSeq","workflow.table.dangling":"dEf/dAct/dWait","workflow.table.updated":"updated","workflow.table.chatApp":"chat / app","workflow.list.failedLoad":"Failed to load: {error}","workflow.list.noRuns":"No runs match.","workflow.list.noFilterMatch":"No runs match this filter.","workflow.list.loaded":"{count} runs \xB7 refreshed {time}","workflow.list.error":"error: {error}","workflow.detail.back":"Back","workflow.detail.loading":"Loading...","workflow.detail.loadFailed":"Load failed","workflow.detail.cancel":"Cancel","workflow.detail.cliCancelOnly":"CLI cancel only","workflow.detail.cancelTitle":"Cancel this workflow run","workflow.detail.cliCancelTitle":"Cancel unavailable: use botmux workflow cancel {runId}","workflow.detail.nodes":"Nodes / Activities","workflow.detail.parallel":"Parallel execution","workflow.detail.parallelMeta":"{count} attempt(s) \xB7 max parallel {max} \xB7 running {running}","workflow.detail.noParallelData":"No attempt timing data yet.","workflow.detail.parallelNow":"now","workflow.detail.node":"node","workflow.detail.nodeStatus":"node status","workflow.detail.activity":"activity","workflow.detail.activityStatus":"activity status","workflow.detail.attempts":"attempts","workflow.detail.current":"current","workflow.detail.detail":"detail","workflow.detail.nodeIO":"Node I/O","workflow.detail.timeline":"Timeline","workflow.detail.loadOlder":"Load older","workflow.detail.seq":"seq","workflow.detail.actor":"actor","workflow.detail.error":"error","workflow.detail.event":"event","workflow.detail.time":"time","workflow.detail.refreshed":"refreshed {time}","workflow.detail.unknownRun":"unknown run","workflow.detail.snapshotHttp":"snapshot HTTP {status}","workflow.detail.eventsHttp":"events HTTP {status}","workflow.detail.cancelUnavailable":"cancel unavailable: use botmux workflow cancel {runId}","workflow.detail.cancelConfirm":`Cancel workflow run {runId}?
|
|
9
9
|
|
|
10
10
|
{total} dangling item(s) will be handled by cancel-driven recovery.
|
|
11
11
|
effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"workflow.detail.writeAccessCancel":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and click cancel again.","workflow.detail.cancelHttp":"cancel HTTP {status}","workflow.detail.cancelPending":"cancel pending; waiting for running activity to drain","workflow.detail.writeAccessApproval":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and approve/reject again.","workflow.detail.actionHttp":"{action} HTTP {status}","workflow.detail.approved":"approved","workflow.detail.rejected":"rejected","workflow.detail.alreadyTerminal":"Run already terminal; {label} was not applied.","workflow.detail.workflowContinue":"{label}; waiting for workflow to continue.","workflow.detail.workflowRefreshing":"{label}; refreshing workflow state.","workflow.detail.eventsLoaded":"{loaded}/{total} events loaded","workflow.detail.dangling":"Dangling","workflow.detail.noDangling":"No dangling work.","workflow.detail.none":"none","workflow.detail.noNodes":"No nodes yet.","workflow.detail.idle":"idle","workflow.detail.noNodeIO":"No node I/O yet.","workflow.detail.notDispatched":"not dispatched","workflow.detail.noAttempt":"No attempt yet","workflow.detail.attempt":"attempt","workflow.detail.authoredInput":"Authored input","workflow.detail.resolvedInput":"Resolved input","workflow.detail.output":"Output","workflow.detail.executionLog":"Execution log","workflow.detail.liveTerminal":"Live terminal","workflow.detail.terminalLive":"live","workflow.detail.terminalClosedShort":"closed","workflow.detail.terminalClosed":"Terminal is closed. Use the execution log below for the final transcript.","workflow.detail.openTerminalNewTab":"Open terminal in new tab","workflow.detail.terminalReplay":"Terminal replay","workflow.detail.openReplayNewTab":"Open replay in new tab","workflow.detail.downloadFullLog":"Download full log","workflow.detail.terminalResume":"Debug session","workflow.detail.openResumeNewTab":"Open debug session in new tab","workflow.detail.resumeSession":"Resume session","workflow.detail.resumeStarting":"Starting\u2026","workflow.detail.endResumeSession":"End debug session","workflow.detail.resumeEnding":"Ending\u2026","workflow.detail.resumeUnsupportedCli":'CLI "{cliId}" does not support resume',"workflow.detail.resumeMissingCliSession":"Missing cliSessionId \u2014 cannot resume","workflow.detail.resumeStartFailed":"Failed to start debug session (HTTP {status})","workflow.detail.resumeEndFailed":"Failed to end debug session (HTTP {status})","workflow.detail.writeAccessResume":"Resume requires dashboard write access.","workflow.detail.waitPrompt":"Wait prompt","workflow.detail.approvalComment":"Approval comment","workflow.detail.optionalComment":"Optional comment","workflow.detail.approve":"Approve","workflow.detail.reject":"Reject","workflow.detail.submitting":"Submitting...","workflow.detail.empty":"empty","workflow.detail.truncated":"truncated","workflow.detail.noData":"No data.","workflow.detail.noPreview":"No preview.","workflow.detail.open":"open","workflow.detail.deadline":"deadline","workflow.detail.effect":"effect","workflow.detail.wait":"wait","workflow.detail.noEvents":"No events.","workflow.summary.workflow":"workflow","workflow.summary.status":"status","workflow.summary.lastSeq":"lastSeq","workflow.summary.updated":"updated","workflow.summary.revision":"revision","workflow.summary.initiator":"initiator","workflow.summary.failedNode":"failedNode","workflow.summary.cancelOrigin":"cancelOrigin","workflow.summary.chat":"chat","workflow.summary.app":"app","workflow.dangling.activities":"activities","workflow.dangling.effects":"effects","workflow.dangling.waits":"waits","workflow.dangling.cancels":"cancels","catalog.title":"Workflow catalog","catalog.subtitle":"Create a workflow run from a saved workflow definition.","catalog.searchPlaceholder":"search workflowId / path","catalog.refresh":"Refresh","catalog.loading":"Loading catalog...","catalog.loadFailed":"Failed to load catalog: {error}","catalog.noDefinitions":"No workflow definitions found.","catalog.noFilterMatch":"No definitions match this filter.","catalog.table.workflow":"workflow","catalog.table.version":"version","catalog.table.params":"params","catalog.table.nodes":"nodes","catalog.table.revision":"revision","catalog.table.path":"path","catalog.paramSummary":"{required}/{total} required","catalog.back":"Back to catalog","catalog.detailTitle":"Workflow definition","catalog.definitionLoadFailed":"Failed to load definition: {error}","catalog.summary":"Summary","catalog.paramsSchema":"Params schema","catalog.definitionJson":"Definition JSON","catalog.runPanel":"Run workflow","catalog.paramsJson":"Params JSON","catalog.paramsPlaceholder":`{
|
|
12
12
|
"city": "\u5317\u4EAC"
|
|
13
|
-
}`,"catalog.chatId":"Chat ID","catalog.larkAppId":"Lark app ID","catalog.chatBindingHint":"Required so humanGate cards and cancel routing know which Lark chat owns the run.","catalog.run":"Run","catalog.running":"Starting...","catalog.badParamsJson":"Params must be a JSON object.","catalog.writeAccess":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and run again.","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"Run started; opening detail page...","catalog.invalidParams":"Invalid params","catalog.issue":"{path}: {message}","catalog.noParams":"No params declared.","catalog.required":"required","catalog.optional":"optional","catalog.default":"default","catalog.description":"description","catalog.path":"path","catalog.revision":"revision","catalog.nodeCount":"nodes"},$t={zh:wn,en:bn};function St(e){if(typeof e!="string")return null;let t=e.trim().toLowerCase();return t==="zh"||t.startsWith("zh-")?"zh":t==="en"||t.startsWith("en-")?"en":null}function hn(e=[]){for(let t of e){let o=St(t);if(o)return o}return"zh"}function Ue(e){return(t,o)=>{let s=$t[e][t]??$t.zh[t]??t;return o?s.replace(/\{(\w+)\}/g,(a,r)=>{let i=o[r];return i==null?`{${r}}`:String(i)}):s}}function Lt(e,t){return(e?St(e.getItem(nt)):null)??hn(t)}var ot="botmux.dashboard.theme";function yn(e){return e==="system"||e==="light"||e==="dark"?e:null}function Tt(e,t){return e==="system"?t?"dark":"light":e}function It(e){return yn(e?.getItem(ot))??"system"}var at=class{locale="zh";themeMode="system";resolvedTheme="light";listeners=new Set;translate=Ue(this.locale);mediaQuery=null;init(){let t=typeof window<"u"?window:void 0;this.locale=Lt(t?.localStorage,vn()),this.translate=Ue(this.locale),this.themeMode=It(t?.localStorage),this.mediaQuery=t?.matchMedia?.("(prefers-color-scheme: dark)")??null,this.mediaQuery?.addEventListener("change",()=>{this.applyTheme(),this.emit()}),this.applyTheme(),this.applyLocale()}t(t,o){return this.translate(t,o)}setLocale(t){this.locale!==t&&(this.locale=t,this.translate=Ue(t),window.localStorage.setItem(nt,t),this.applyLocale(),this.emit())}setThemeMode(t){this.themeMode!==t&&(this.themeMode=t,window.localStorage.setItem(ot,t),this.applyTheme(),this.emit())}on(t){return this.listeners.add(t),()=>this.listeners.delete(t)}emit(){for(let t of this.listeners)t()}applyTheme(){this.resolvedTheme=Tt(this.themeMode,!!this.mediaQuery?.matches),document.documentElement.dataset.theme=this.resolvedTheme,document.documentElement.dataset.themeMode=this.themeMode}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}};function vn(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var ge=new at;function n(e,t){return ge.t(e,t)}function l(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function Ae(e){if(!e)return"-";let t=Date.now()-e;return t<6e4?n("common.now"):t<36e5?Math.floor(t/6e4)+"m":t<864e5?Math.floor(t/36e5)+"h":Math.floor(t/864e5)+"d"}var st={chats:[],bots:[]};async function kn(){try{let e=await fetch("/api/groups");if(!e.ok)return;st=await e.json()}catch{}}function $n(e){return`status status-${l(e||"unknown")}`}function Sn(e){return`<li class="overview-list-row">
|
|
14
|
-
<div>
|
|
15
|
-
<
|
|
16
|
-
<
|
|
13
|
+
}`,"catalog.chatId":"Chat ID","catalog.larkAppId":"Lark app ID","catalog.chatBindingHint":"Required so humanGate cards and cancel routing know which Lark chat owns the run.","catalog.run":"Run","catalog.running":"Starting...","catalog.badParamsJson":"Params must be a JSON object.","catalog.writeAccess":"write access required: run `botmux dashboard` in the terminal to get a one-time URL, open it once to set the cookie, then come back and run again.","catalog.runHttp":"run HTTP {status}","catalog.runStarted":"Run started; opening detail page...","catalog.invalidParams":"Invalid params","catalog.issue":"{path}: {message}","catalog.noParams":"No params declared.","catalog.required":"required","catalog.optional":"optional","catalog.default":"default","catalog.description":"description","catalog.path":"path","catalog.revision":"revision","catalog.nodeCount":"nodes"},sn={zh:Io,en:Lo};function rn(e){if(typeof e!="string")return null;let t=e.trim().toLowerCase();return t==="zh"||t.startsWith("zh-")?"zh":t==="en"||t.startsWith("en-")?"en":null}function Eo(e=[]){for(let t of e){let n=rn(t);if(n)return n}return"zh"}function nt(e){return(t,n)=>{let s=sn[e][t]??sn.zh[t]??t;return n?s.replace(/\{(\w+)\}/g,(a,i)=>{let l=n[i];return l==null?`{${i}}`:String(l)}):s}}function ln(e,t){return(e?rn(e.getItem($t)):null)??Eo(t)}var St="botmux.dashboard.theme",dn="botmux.dashboard.sessions.view";function xo(e){return e==="system"||e==="light"||e==="dark"?e:null}function Mo(e){return e==="board"||e==="table"?e:null}function cn(e,t){return e==="system"?t?"dark":"light":e}function un(e){return xo(e?.getItem(St))??"dark"}function pn(e){return Mo(e?.getItem(dn))??"board"}var mn="botmux.dashboard.sessions.boardOrder",Fe=["needs-you","starting","working","idle"];function Ho(e){if(!Array.isArray(e)||e.length!==Fe.length)return null;let t=new Set(e);if(t.size!==e.length)return null;for(let n of Fe)if(!t.has(n))return null;return e.slice()}function fn(e){try{let t=e?.getItem(mn);return t?Ho(JSON.parse(t))??[...Fe]:[...Fe]}catch{return[...Fe]}}function Tt(e,t){try{e?.setItem(mn,JSON.stringify(t))}catch{}}function gn(e,t){try{e?.setItem(dn,t)}catch{}}var Co=["default","cyber","genshin","fallout","prts","bluearchive","zzz","dragonball","ikun"],It="botmux.dashboard.skin";function Ao(e){return typeof e=="string"&&Co.includes(e)?e:null}function bn(e){return Ao(e?.getItem(It))??"default"}var Do="\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF830123456789\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E$#%&@*+=<>/\\",hn=["186 100% 60%","56 97% 60%","330 100% 64%","150 80% 58%"],Et=[{key:"shake",dur:280},{key:"rgb",dur:340},{key:"tear",dur:400},{key:"invert",dur:220},{key:"slice",dur:320},{key:"blackout",dur:260}],wn=["ESTABLISHING NETLINK","BYPASSING ICE","DECRYPTING DATAFLOW","SYNCING BOTMUX TELEMETRY","ACCESS GRANTED"],yn="0123456789ABCDEF#<>*/=+\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C",Ro=3200,We=[],Be=0,ot=0;function Ht(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function xt(e,t){let n="";for(let s=0;s<e;s++)n+=t[Math.floor(Math.random()*t.length)];return n}function Oo(e){let t=document.createElement("div");t.className="cyber-rain";let n=Math.max(10,Math.min(26,Math.round(window.innerWidth/70)));for(let s=0;s<n;s++){let a=document.createElement("span");a.className="cyber-rain-col",a.textContent=xt(28+Math.floor(Math.random()*22),Do);let i=hn[Math.floor(Math.random()*hn.length)];a.style.cssText=`left:${(s+.5)/n*100}%;--rc:${i};--sz:${10+Math.floor(Math.random()*9)}px;--op:${(.25+Math.random()*.45).toFixed(2)};--dur:${(6+Math.random()*9).toFixed(1)}s;--delay:${(-Math.random()*12).toFixed(1)}s;`,t.appendChild(a)}e.appendChild(t)}function qo(){if(Ht())return;let e=document.body,t=()=>{let n=Et[Math.floor(Math.random()*Et.length)],s=`cp-fx-${n.key}`;e.classList.add(s),We.push(window.setTimeout(()=>e.classList.remove(s),n.dur)),We.push(window.setTimeout(t,2400+Math.random()*4200))};We.push(window.setTimeout(t,1800+Math.random()*2600))}function Bo(){We.forEach(e=>window.clearTimeout(e)),We=[];for(let e of Et)document.body.classList.remove(`cp-fx-${e.key}`)}function Po(){if(Ht()||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 t=e.querySelector(".cyber-loader-text"),n=e.querySelector(".cyber-loader-stream"),s=0,a=0,i=0;Be=window.setInterval(()=>{let l=wn[s];t&&(a<l.length?(a+=1,t.textContent=l.slice(0,a)+xt(l.length-a,yn),t.classList.remove("done")):i<16?(i+=1,t.textContent=l,t.classList.add("done")):(s=(s+1)%wn.length,a=0,i=0)),n&&(n.textContent=xt(26,yn))},50),ot=window.setTimeout(()=>{window.clearInterval(Be),Be=0,e.remove()},Ro)}function No(){Be&&(window.clearInterval(Be),Be=0),ot&&(window.clearTimeout(ot),ot=0),document.getElementById("cyber-boot")?.remove()}var Uo=320,vn=16,Ge=!0,qe=0,Lt=0,at=!1,st=[],Mt=[];function jo(){if(at)return;at=!0,Ge=!1,qe=0;let e=Ht(),t="";for(let s=0;s<vn;s++){let a=s%3===0?"186 100% 52%":s%3===1?"330 100% 58%":"56 97% 52%",i=(s%2===0?1:-1)*(8+s%5*7);t+=`<span class="cyber-breach-shard" style="top:${s/vn*100}%;height:${2+s%4*3}%;--shift:${i}px;--delay:${s%8*.09}s;--dur:${(.36+s%5*.12).toFixed(2)}s;--hue:${a}"></span>`}let n=document.createElement("div");n.id="cyber-breach",n.className="cyber-breach",n.setAttribute("aria-hidden","true"),n.innerHTML=`<span class="cyber-breach-flash"></span><span class="cyber-breach-grid"></span><div class="cyber-breach-shards">${t}</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(n),e||document.body.classList.add("cyber-breach-quake"),st.push(window.setTimeout(()=>document.body.classList.remove("cyber-breach-quake"),760)),st.push(window.setTimeout(()=>{n.remove(),at=!1},e?2600:4200))}function zo(){Ge=!0,qe=0;let e=document.documentElement,t=()=>e.scrollHeight-(window.innerHeight+window.scrollY)<=4,n=v=>{v<=0||!t()||(qe+=v,qe>Uo&&Ge&&jo())},s=v=>n(v.deltaY),a=v=>{Lt=v.touches[0]?.clientY??0},i=v=>{let y=v.touches[0]?.clientY??0,h=Lt-y;Lt=y,n(h)},l=()=>{t()||(qe=0,Ge=!0)},p=(v,y)=>{window.addEventListener(v,y,{passive:!0}),Mt.push([v,y])};p("wheel",s),p("touchstart",a),p("touchmove",i),p("scroll",l)}function _o(){for(let[e,t]of Mt)window.removeEventListener(e,t);Mt=[],st.forEach(e=>window.clearTimeout(e)),st=[],document.body.classList.remove("cyber-breach-quake"),document.getElementById("cyber-breach")?.remove(),at=!1,Ge=!0,qe=0}function kn(e,t=!1){if(!(typeof document>"u")){if(!e){document.getElementById("cyber-fx")?.remove(),document.getElementById("cyber-hud")?.remove(),document.getElementById("cyber-glitch")?.remove(),Bo(),No(),_o();return}if(!document.getElementById("cyber-fx")){let n=document.createElement("div");n.id="cyber-fx",n.className="cyber-fx",n.setAttribute("aria-hidden","true"),n.innerHTML='<div class="cyber-fx-grid"></div><div class="cyber-fx-scan"></div><span class="cyber-flicker"></span><span class="cyber-rollline"></span>',Oo(n),document.body.appendChild(n);let s=document.createElement("div");s.id="cyber-hud",s.className="cyber-hud",s.setAttribute("aria-hidden","true"),s.innerHTML='<span class="cyber-hud-corner tl"></span><span class="cyber-hud-corner tr"></span><span class="cyber-hud-corner bl"></span><span class="cyber-hud-corner br"></span><span class="cyber-hud-tag">NIGHT CITY // NETWATCH</span>',document.body.appendChild(s);let a=document.createElement("div");a.id="cyber-glitch",a.className="cyber-glitch",a.setAttribute("aria-hidden","true"),document.body.appendChild(a),qo(),zo()}t&&Po()}}var Fo={genshin:2e3,zzz:1900,dragonball:1900,ikun:1900},Wo='<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 Go(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 Wo;default:return""}}function Jo(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches}function $n(e){if(typeof document>"u"||Jo())return;let t=Fo[e];if(!t)return;document.getElementById("skin-intro")?.remove();let n=document.createElement("div");n.id="skin-intro",n.className=`skin-intro si-${e}`,n.setAttribute("aria-hidden","true"),n.style.setProperty("--si-dur",`${t}ms`),n.innerHTML=Go(e),document.body.appendChild(n),window.setTimeout(()=>n.remove(),t+80)}var At=class{locale="zh";themeMode="system";resolvedTheme="light";skin="default";listeners=new Set;translate=nt(this.locale);mediaQuery=null;init(){let t=typeof window<"u"?window:void 0;this.locale=ln(t?.localStorage,Vo()),this.translate=nt(this.locale),this.themeMode=un(t?.localStorage),this.skin=bn(t?.localStorage),this.mediaQuery=t?.matchMedia?.("(prefers-color-scheme: dark)")??null,this.mediaQuery?.addEventListener("change",()=>{this.applyTheme(),this.emit()}),this.applyTheme(),this.applySkin(),this.applyLocale()}t(t,n){return this.translate(t,n)}setLocale(t){this.locale!==t&&(this.locale=t,this.translate=nt(t),window.localStorage.setItem($t,t),this.applyLocale(),this.emit())}get theme(){return this.skin==="default"?this.themeMode:this.skin}setTheme(t){let n=t==="system"||t==="light"||t==="dark",s=n?"default":t,a=s!==this.skin;n&&this.themeMode!==t&&(this.themeMode=t,window.localStorage.setItem(St,this.themeMode)),a&&(this.skin=s,window.localStorage.setItem(It,this.skin)),this.applyTheme(),this.applySkin(a),this.emit()}on(t){return this.listeners.add(t),()=>this.listeners.delete(t)}emit(){for(let t of this.listeners)t()}applyTheme(){this.resolvedTheme=cn(this.themeMode,!!this.mediaQuery?.matches);let t=this.skin==="default"?this.resolvedTheme:Ko[this.skin];document.documentElement.dataset.theme=t,document.documentElement.dataset.themeMode=this.themeMode}applySkin(t=!1){document.documentElement.dataset.skin=this.skin,kn(this.skin==="cyber",t),t&&this.skin!=="cyber"&&this.skin!=="default"&&$n(this.skin)}applyLocale(){document.documentElement.lang=this.locale==="zh"?"zh-CN":"en"}},Ko={default:"light",cyber:"dark",genshin:"light",fallout:"dark",prts:"dark",bluearchive:"dark",zzz:"dark",dragonball:"light",ikun:"dark"};function Vo(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var me=new At;function o(e,t){return me.t(e,t)}function r(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function ue(e){if(!e)return"-";let t=Date.now()-e;return t<6e4?o("common.now"):t<36e5?Math.floor(t/6e4)+"m":t<864e5?Math.floor(t/36e5)+"h":Math.floor(t/864e5)+"d"}var Sn=[{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 de(e){let t=0,n=String(e??"");for(let i=0;i<n.length;i++)t=t*31+n.charCodeAt(i)>>>0;let{c1:s,c2:a}=Sn[t%Sn.length];return`--c1:${s};--c2:${a}`}var Tn=new Map,In=new Map,Ct=null;function Pe(){return Ct??=(async()=>{try{let e=await fetch("/api/groups");if(!e.ok)throw new Error(`HTTP ${e.status}`);let t=await e.json();for(let n of t.bots??[])n.larkAppId&&n.botName&&n.botName!==n.larkAppId&&Tn.set(n.larkAppId,String(n.botName));for(let n of t.chats??[])n.chatId&&n.name&&In.set(n.chatId,String(n.name))}catch{Ct=null}})(),Ct}function fe(e){let t=e.larkAppId?Tn.get(e.larkAppId):void 0;return t||(e.botName&&e.botName!==e.larkAppId?String(e.botName):String(e.botName??e.larkAppId??"-"))}function Ne(e){return e.chatId&&In.get(e.chatId)||null}function $e(e){let t=String(e??"");return t.replace(/^(?:@\S+\s*)+/,"").trim()||t}function Te(e){return e.status==="closed"?null:e.pendingRepo?o("sessions.board.signalRepo"):e.tuiPromptActive?o("sessions.board.signalPrompt"):e.status==="limited"?o("sessions.board.signalLimited"):null}var Ln={chats:[],bots:[]};async function Yo(){try{let e=await fetch("/api/groups");if(!e.ok)return;Ln=await e.json()}catch{}}var Dt=new Set(["working","analyzing","active","starting"]);function Qo(e){let t=new Map,n=a=>{let i=t.get(a);return i||(i={botName:a,larkAppId:a,cliId:"unknown",online:!1,sessions:[],active:[],busy:[],attention:[],lastActiveAt:0},t.set(a,i)),i};for(let a of Ln.bots??[]){let i=n(a.larkAppId??a.botName??"-");i.online=!0,a.botName&&(i.botName=a.botName)}let s=[...e].sort((a,i)=>+(a.status==="closed")-+(i.status==="closed"));for(let a of s){let i=a.larkAppId??a.botName??"-";if(a.status==="closed"&&!t.has(i))continue;let l=n(i);a.botName&&(l.botName===l.larkAppId||!l.botName)&&(l.botName=a.botName),l.sessions.push(a),a.cliId&&l.cliId==="unknown"&&(l.cliId=a.cliId),l.lastActiveAt=Math.max(l.lastActiveAt,Number(a.lastMessageAt??0)),a.status!=="closed"&&(l.active.push(a),Dt.has(a.status)&&l.busy.push(a),Te(a)&&l.attention.push(a))}return[...t.values()].sort((a,i)=>{let l=p=>p.attention.length?0:p.busy.length?1:p.online||p.active.length?2:3;return l(a)!==l(i)?l(a)-l(i):i.lastActiveAt-a.lastActiveAt})}function Xo(e){let t=!e.online&&e.active.length===0,n=e.attention.length>0,s=e.busy.length>0,a=n?"warn":s?"busy":t?"off":"ok",i;if(n){let p=e.attention[0];i=`<b>${r(($e(p.title)||p.sessionId).slice(0,60))}</b> \xB7 ${r(Te(p)??"")}`}else if(s){let p=[...e.busy].sort((v,y)=>Number(y.lastMessageAt??0)-Number(v.lastMessageAt??0))[0];i=`<b>${r(($e(p.title)||p.sessionId).slice(0,60))}</b>`}else t?i=r(o("overview.botOffline")):i=r(o("overview.botIdle"));let l=n?`<span class="tag tag-warn">${r(o("overview.botNeedsYou"))}</span>`:s?`<span class="tag tag-run">${r(o("overview.botBusy",{count:e.busy.length}))}</span>`:t?`<span class="tag tag-off">${r(o("overview.botOff"))}</span>`:`<span class="tag tag-ok">${r(o("overview.botReady"))}</span>`;return`<article class="mate${n?" mate-attn":""}${t?" mate-off":""}">
|
|
14
|
+
<div class="mate-top">
|
|
15
|
+
<span class="orb-avatar" style="${de(e.botName)}"><i class="orb-dot orb-dot-${a}"></i></span>
|
|
16
|
+
<div class="mate-id">
|
|
17
|
+
<b>${r(e.botName)}</b>
|
|
18
|
+
<span class="mate-role">${r(e.cliId)}</span>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="mate-task">${i}</div>
|
|
22
|
+
<div class="mate-foot">
|
|
23
|
+
${l}
|
|
24
|
+
<span>${e.lastActiveAt?r(o("overview.lastActive",{time:ue(e.lastActiveAt)})):r(o("common.never"))}</span>
|
|
25
|
+
</div>
|
|
26
|
+
</article>`}function Zo(e){let t=fe(e);return`<article class="qcard" data-id="${r(e.sessionId)}">
|
|
27
|
+
<span class="orb-avatar orb-avatar-sm" style="${de(t)}"></span>
|
|
28
|
+
<div class="qcard-tx">
|
|
29
|
+
<b>${r(t)} \xB7 ${r(($e(e.title)||e.sessionId).slice(0,56))}</b>
|
|
30
|
+
<span>${r(Te(e)??"")} \xB7 ${ue(e.lastMessageAt)}</span>
|
|
31
|
+
</div>
|
|
32
|
+
<a class="qcard-go" href="#/sessions">${r(o("strip.handle"))}</a>
|
|
33
|
+
</article>`}function ea(e){let t=fe(e);return`<li class="sess-row">
|
|
34
|
+
<span class="orb-avatar orb-avatar-sm" style="${de(t)}"></span>
|
|
35
|
+
<div class="sess-tx">
|
|
36
|
+
<b>${r(($e(e.title)||e.sessionId).slice(0,64))}</b>
|
|
37
|
+
<span>${r(t)} \xB7 ${r(Ne(e)??e.cliId??"unknown")} \xB7 ${ue(e.lastMessageAt)}</span>
|
|
17
38
|
</div>
|
|
18
|
-
<span class="
|
|
19
|
-
</li>`}function
|
|
39
|
+
<span class="status status-${r(e.status??"unknown")}">${r(e.status??"unknown")}</span>
|
|
40
|
+
</li>`}function ta(e){let t=e.nextRunAt?new Date(e.nextRunAt).toLocaleString():"-";return`<li class="overview-list-row">
|
|
20
41
|
<div>
|
|
21
|
-
<strong>${
|
|
22
|
-
<span>${
|
|
42
|
+
<strong>${r(e.name??e.id)}</strong>
|
|
43
|
+
<span>${r(fe(e))} \xB7 ${r(e.parsed?.display??"")}</span>
|
|
23
44
|
</div>
|
|
24
|
-
<span>${
|
|
25
|
-
</li>`}
|
|
45
|
+
<span>${r(t)}</span>
|
|
46
|
+
</li>`}function na(e,t,n){let s=e+t+n;if(s===0)return`<div class="donut-wrap"><div class="donut" style="background:conic-gradient(var(--border) 0 360deg)"></div>
|
|
47
|
+
<div class="donut-center"><b>0</b><span>${r(o("overview.openSessions"))}</span></div></div>`;let a=e/s*360,i=a+t/s*360;return`<div class="donut-wrap">
|
|
48
|
+
<div class="donut" style="background:conic-gradient(var(--accent) 0 ${a}deg, var(--warning) ${a}deg ${i}deg, var(--success) ${i}deg 360deg)"></div>
|
|
49
|
+
<div class="donut-center"><b>${s}</b><span>${r(o("overview.openSessions"))}</span></div>
|
|
50
|
+
</div>`}async function En(e){e.innerHTML=`<section class="page hero-page">
|
|
26
51
|
<div class="page-heading">
|
|
27
52
|
<div>
|
|
28
|
-
<p class="eyebrow">${
|
|
29
|
-
<h1>${
|
|
30
|
-
<p>${
|
|
53
|
+
<p class="eyebrow">${o("app.subtitle")}</p>
|
|
54
|
+
<h1>${o("overview.title")}</h1>
|
|
55
|
+
<p id="overview-sub">${o("overview.subtitle")}</p>
|
|
31
56
|
</div>
|
|
57
|
+
<div class="hero-pills" id="overview-pills"></div>
|
|
32
58
|
</div>
|
|
33
|
-
|
|
34
|
-
<div class="
|
|
59
|
+
|
|
60
|
+
<div class="sect-head">
|
|
61
|
+
<h2>${o("overview.team")}</h2><span>${o("overview.teamHint")}</span>
|
|
62
|
+
<a href="#/bot-defaults">${o("overview.viewAll")}</a>
|
|
63
|
+
</div>
|
|
64
|
+
<div class="team-grid" id="team-grid"></div>
|
|
65
|
+
|
|
66
|
+
<div class="sect-head" id="attention-head">
|
|
67
|
+
<h2>${o("overview.attention")}</h2><span>${o("overview.attentionHint")}</span>
|
|
68
|
+
</div>
|
|
69
|
+
<div class="qgrid" id="attention-list"></div>
|
|
70
|
+
|
|
71
|
+
<div class="overview-cols">
|
|
35
72
|
<section class="panel">
|
|
36
73
|
<header class="panel-header">
|
|
37
74
|
<div>
|
|
38
|
-
<h2>${
|
|
39
|
-
<p>${
|
|
75
|
+
<h2>${o("overview.activeSessions")}</h2>
|
|
76
|
+
<p>${o("overview.activeSessionsHint")}</p>
|
|
40
77
|
</div>
|
|
41
|
-
<a class="btn-link" href="#/sessions">${
|
|
78
|
+
<a class="btn-link" href="#/sessions">${o("overview.viewAll")}</a>
|
|
42
79
|
</header>
|
|
43
80
|
<ul class="overview-list" id="recent-sessions"></ul>
|
|
44
81
|
</section>
|
|
45
|
-
<
|
|
46
|
-
<
|
|
47
|
-
<
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
82
|
+
<div class="overview-side">
|
|
83
|
+
<section class="panel">
|
|
84
|
+
<header class="panel-header">
|
|
85
|
+
<div>
|
|
86
|
+
<h2>${o("overview.today")}</h2>
|
|
87
|
+
<p>${o("overview.todayHint")}</p>
|
|
88
|
+
</div>
|
|
89
|
+
</header>
|
|
90
|
+
<div class="donut-row" id="today-donut"></div>
|
|
91
|
+
</section>
|
|
92
|
+
<section class="panel">
|
|
93
|
+
<header class="panel-header">
|
|
94
|
+
<div>
|
|
95
|
+
<h2>${o("overview.nextSchedules")}</h2>
|
|
96
|
+
<p>${o("schedules.subtitle")}</p>
|
|
97
|
+
</div>
|
|
98
|
+
<a class="btn-link" href="#/schedules">${o("overview.viewAll")}</a>
|
|
99
|
+
</header>
|
|
100
|
+
<ul class="overview-list" id="next-schedules"></ul>
|
|
101
|
+
</section>
|
|
102
|
+
</div>
|
|
55
103
|
</div>
|
|
56
|
-
</section>`;let t=e.querySelector("#overview-
|
|
57
|
-
<span>${
|
|
58
|
-
<
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
104
|
+
</section>`;let t=e.querySelector("#overview-pills"),n=e.querySelector("#team-grid"),s=e.querySelector("#attention-list"),a=e.querySelector("#recent-sessions"),i=e.querySelector("#today-donut"),l=e.querySelector("#next-schedules");function p(){let v=[...G.sessions.values()],y=v.filter(f=>f.status!=="closed"),h=y.filter(f=>Te(f)).sort((f,w)=>Number(f.lastMessageAt??0)-Number(w.lastMessageAt??0)),k=y.filter(f=>Dt.has(f.status)&&!Te(f)),u=y.length-h.length-k.length,E=Qo(v),B=E.filter(f=>f.online||f.active.length>0).length;t.innerHTML=`
|
|
105
|
+
<span class="pill">${r(o("overview.workingSessions"))} <b>${k.length}</b></span>
|
|
106
|
+
<span class="pill${h.length?" pill-hot":""}">${r(o("overview.attention"))} <b>${h.length}</b></span>
|
|
107
|
+
<span class="pill">${r(o("overview.onlineBots"))} <b>${B}</b></span>`,n.innerHTML=E.length?E.map(Xo).join(""):`<div class="empty">${o("overview.noSessions")}</div>`,s.innerHTML=h.length?h.map(Zo).join(""):`<div class="qcard qcard-empty">${o("overview.noAttention")}</div>`;let $=y.filter(f=>Dt.has(f.status)||f.status==="idle").sort((f,w)=>Number(w.lastMessageAt??0)-Number(f.lastMessageAt??0)).slice(0,7);a.innerHTML=$.length?$.map(ea).join(""):`<li class="empty">${o("overview.noSessions")}</li>`,i.innerHTML=`${na(k.length,h.length,Math.max(0,u))}
|
|
108
|
+
<div class="donut-legend">
|
|
109
|
+
<span><i style="background:var(--accent)"></i>${r(o("overview.workingSessions"))} ${k.length}</span>
|
|
110
|
+
<span><i style="background:var(--warning)"></i>${r(o("overview.attention"))} ${h.length}</span>
|
|
111
|
+
<span><i style="background:var(--success)"></i>${r(o("sessions.board.idle"))} ${Math.max(0,u)}</span>
|
|
112
|
+
</div>`;let d=[...G.schedules.values()].filter(f=>f.nextRunAt).sort((f,w)=>Date.parse(f.nextRunAt)-Date.parse(w.nextRunAt)).slice(0,5);l.innerHTML=d.length?d.map(ta).join(""):`<li class="empty">${o("overview.noSchedules")}</li>`}G.on(p),p(),Yo().then(p),Pe().then(p)}function Ie(e,t){return`<th data-sort="${e}" data-label="${r(t)}">${r(t)}</th>`}var Hn=["claude-code","seed","codex","codex-app","cursor","gemini","opencode","mtr","hermes","mira","pi","copilot","aiden","coco","unknown"],xn=[{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"}];function oa(e){return String(e??"unknown").toLowerCase().replace(/[^a-z0-9_-]/g,"-")}function aa(e){let t=String(e??"").trim();return t?t.replace(/\\/g,"/").split("/").filter(Boolean).at(-1)??t:"-"}function Mn(e){if(!e.webPort)return null;let t=e.proxyPort??e.webPort,n=e.proxyPort?`/s/${encodeURIComponent(e.sessionId)}`:"";return`http://${location.hostname}:${t}${n}`}function sa(e){return e.status==="closed"?null:e.pendingRepo||e.tuiPromptActive||e.status==="limited"?"needs-you":e.status==="starting"?"starting":e.status==="working"||e.status==="analyzing"||e.status==="active"?"working":"idle"}function ia(){return`<details class="filter-cli">
|
|
113
|
+
<summary>${o("sessions.cli")} \xB7 <b id="cli-filter-count">${o("common.all")}</b></summary>
|
|
114
|
+
<div class="filter-cli-pop" role="group" aria-label="${o("sessions.cli")}">
|
|
115
|
+
${Hn.map(e=>`
|
|
116
|
+
<label class="filter-check">
|
|
117
|
+
<input type="checkbox" name="cli" value="${r(e)}" checked>
|
|
118
|
+
<span>${r(e)}</span>
|
|
119
|
+
</label>
|
|
120
|
+
`).join("")}
|
|
121
|
+
</div>
|
|
122
|
+
</details>`}function ra(){return`<section class="page">
|
|
69
123
|
<div class="page-heading">
|
|
70
124
|
<div>
|
|
71
|
-
<p class="eyebrow">${
|
|
72
|
-
<h1>${
|
|
73
|
-
<p>${
|
|
125
|
+
<p class="eyebrow">${o("nav.sessions")}</p>
|
|
126
|
+
<h1>${o("sessions.title")}</h1>
|
|
127
|
+
<p>${o("sessions.subtitle")}</p>
|
|
128
|
+
</div>
|
|
129
|
+
<div class="segmented sessions-view-toggle" role="group" aria-label="${o("sessions.viewMode")}">
|
|
130
|
+
<button type="button" data-view="board">${o("sessions.viewBoard")}</button>
|
|
131
|
+
<button type="button" data-view="table">${o("sessions.viewTable")}</button>
|
|
74
132
|
</div>
|
|
75
133
|
</div>
|
|
76
134
|
<form id="filters" class="filters sessions-filters">
|
|
77
|
-
<input type="search" name="q" placeholder="${
|
|
135
|
+
<input type="search" name="q" placeholder="${o("sessions.search")}" />
|
|
78
136
|
<select name="status">
|
|
79
|
-
<option value="">${
|
|
137
|
+
<option value="">${o("sessions.anyStatus")}</option>
|
|
80
138
|
<option>starting</option><option>working</option><option>idle</option>
|
|
81
139
|
<option>analyzing</option><option>active</option><option>closed</option>
|
|
82
140
|
</select>
|
|
83
141
|
<select name="adopt">
|
|
84
|
-
<option value="">${
|
|
85
|
-
<option value="yes">${
|
|
86
|
-
<option value="no">${
|
|
142
|
+
<option value="">${o("sessions.adoptAny")}</option>
|
|
143
|
+
<option value="yes">${o("sessions.adoptYes")}</option>
|
|
144
|
+
<option value="no">${o("sessions.adoptNo")}</option>
|
|
87
145
|
</select>
|
|
88
|
-
|
|
89
|
-
|
|
146
|
+
${ia()}
|
|
147
|
+
<label class="filter-toggle"><input type="checkbox" name="active" checked> <span>${o("sessions.activeOnly")}</span></label>
|
|
90
148
|
</form>
|
|
91
149
|
<div id="bulk-bar" class="bulk-bar" hidden>
|
|
92
150
|
<span id="bulk-count"></span>
|
|
93
|
-
<button type="button" id="bulk-close" class="contrast">${
|
|
94
|
-
<button type="button" id="bulk-clear">${
|
|
151
|
+
<button type="button" id="bulk-close" class="contrast">${o("sessions.closeSelected")}</button>
|
|
152
|
+
<button type="button" id="bulk-clear">${o("sessions.clearSelection")}</button>
|
|
95
153
|
</div>
|
|
96
154
|
<table id="sessions-table">
|
|
97
155
|
<thead><tr>
|
|
98
|
-
<th><input type="checkbox" id="select-all" title="${
|
|
99
|
-
${
|
|
100
|
-
${
|
|
101
|
-
${
|
|
102
|
-
${
|
|
103
|
-
${
|
|
104
|
-
${
|
|
105
|
-
${
|
|
106
|
-
${
|
|
107
|
-
<th>${
|
|
156
|
+
<th><input type="checkbox" id="select-all" title="${o("sessions.activeOnly")}"></th>
|
|
157
|
+
${Ie("botName",o("sessions.bot"))}
|
|
158
|
+
${Ie("cliId",o("sessions.cli"))}
|
|
159
|
+
${Ie("status",o("sessions.status"))}
|
|
160
|
+
${Ie("title",o("sessions.titleCol"))}
|
|
161
|
+
${Ie("workingDir",o("sessions.workingDir"))}
|
|
162
|
+
${Ie("spawnedAt",o("sessions.created"))}
|
|
163
|
+
${Ie("lastMessageAt",o("sessions.last"))}
|
|
164
|
+
${Ie("adopt",o("sessions.adopt"))}
|
|
165
|
+
<th>${o("sessions.actions")}</th>
|
|
108
166
|
</tr></thead>
|
|
109
167
|
<tbody></tbody>
|
|
110
168
|
</table>
|
|
169
|
+
<div id="sessions-board" class="sessions-board" hidden></div>
|
|
111
170
|
<dialog id="drawer"></dialog>
|
|
112
|
-
</section>`}function
|
|
113
|
-
<td><input type="checkbox" class="row-select" ${
|
|
114
|
-
<td>${
|
|
115
|
-
<td><span class="badge cli-${
|
|
116
|
-
<td><span class="status status-${
|
|
117
|
-
<td>${
|
|
118
|
-
<td title="${
|
|
119
|
-
<td>${
|
|
120
|
-
<td>${
|
|
121
|
-
<td>${
|
|
122
|
-
<td><button class="open" type="button">${
|
|
123
|
-
</tr>`}function
|
|
171
|
+
</section>`}function Cn(e){e.innerHTML=ra();let t=e.querySelector("#sessions-table tbody"),n=e.querySelector("#filters"),s=e.querySelector("#drawer"),a=e.querySelector("#select-all"),i=e.querySelector("#bulk-bar"),l=e.querySelector("#bulk-count"),p=e.querySelector("#bulk-close"),v=e.querySelector("#bulk-clear"),y=e.querySelector("#sessions-table"),h=e.querySelector("#sessions-board"),k=e.querySelectorAll("[data-view]"),u=new Set,E="lastMessageAt",B="desc",$=pn(window.localStorage),d=fn(window.localStorage),f=null,w="",T="",x=!1;function M(){return d.map(c=>xn.find(g=>g.id===c)).filter(c=>!!c)}function H(c,g){let S=d.indexOf(c),L=S+g;if(S<0||L<0||L>=d.length)return;let I=[...d];I.splice(S,1),I.splice(L,0,c),d=I,Tt(window.localStorage,d),Q()}function O(c,g){if(c===g)return;let S=d.indexOf(c),L=d.indexOf(g);if(S<0||L<0)return;let I=[...d];I.splice(S,1),I.splice(L,0,c),d=I,Tt(window.localStorage,d),Q()}function z(c){let g=c.status==="closed",S=u.has(c.sessionId)?"checked":"";return`<tr data-id="${r(c.sessionId)}">
|
|
172
|
+
<td><input type="checkbox" class="row-select" ${S} ${g?"disabled":""}></td>
|
|
173
|
+
<td>${r(fe(c))}</td>
|
|
174
|
+
<td><span class="badge cli-${oa(c.cliId)}">${r(c.cliId??"unknown")}</span></td>
|
|
175
|
+
<td><span class="status status-${r(c.status??"unknown")}">${r(c.status??"unknown")}</span></td>
|
|
176
|
+
<td title="${r(String(c.title??""))}">${r($e(c.title??"").slice(0,48))}</td>
|
|
177
|
+
<td title="${r(c.workingDir??"")}">${r((c.workingDir??"").slice(-34))}</td>
|
|
178
|
+
<td>${ue(c.spawnedAt)}</td>
|
|
179
|
+
<td>${ue(c.lastMessageAt)}</td>
|
|
180
|
+
<td>${c.adopt?'<span class="badge">adopt</span>':""}</td>
|
|
181
|
+
<td><button class="open" type="button">${o("sessions.details")}</button></td>
|
|
182
|
+
</tr>`}function j(c){return c.scope!=="chat"||!c.feishuChatLink?null:`<a class="btn-link" href="${r(c.feishuChatLink)}" target="_blank" rel="noopener">${o("sessions.openChat")}</a>`}function ee(c){return c.pendingRepo?o("sessions.board.signalRepo"):c.tuiPromptActive?o("sessions.board.signalPrompt"):c.status==="limited"?o("sessions.board.signalLimited"):""}function ae(c){let g=u.has(c.sessionId),S=$e(c.title)||c.sessionId,L=fe(c),I=Ne(c),P=Mn(c),q=ee(c);return`<article class="session-card${g?" selected":""}" data-id="${r(c.sessionId)}" aria-pressed="${g}">
|
|
183
|
+
<div class="session-card-top">
|
|
184
|
+
<span class="orb-avatar orb-avatar-sm" style="${de(L)}" aria-hidden="true"></span>
|
|
185
|
+
<div class="session-card-title">
|
|
186
|
+
<strong title="${r(String(c.title??S))}">${r(String(S).slice(0,72))}</strong>
|
|
187
|
+
<span>${r(L)} \xB7 ${r(I??c.cliId??"unknown")}</span>
|
|
188
|
+
</div>
|
|
189
|
+
<span class="status status-${r(c.status??"unknown")}">${r(c.status??"unknown")}</span>
|
|
190
|
+
</div>
|
|
191
|
+
<div class="session-card-meta">
|
|
192
|
+
<span title="${r(c.workingDir??"")}">${r(aa(c.workingDir))}</span>
|
|
193
|
+
${c.adopt?'<span class="badge">adopt</span>':""}
|
|
194
|
+
</div>
|
|
195
|
+
<div class="session-card-time">
|
|
196
|
+
<span>${r(o("sessions.last"))}: ${ue(c.lastMessageAt)}</span>
|
|
197
|
+
${q?`<span class="session-signal">${r(q)} \xB7 ${ue(c.lastMessageAt)}</span>`:""}
|
|
198
|
+
</div>
|
|
199
|
+
<div class="session-card-actions">
|
|
200
|
+
${j(c)??`<button type="button" data-action="locate">${o("sessions.locate")}</button>`}
|
|
201
|
+
<button type="button" data-action="details">${o("sessions.details")}</button>
|
|
202
|
+
${P?`<a class="btn-link primary" href="${r(P)}" target="_blank" rel="noopener">${o("sessions.openTerminal")}</a>`:""}
|
|
203
|
+
<button type="button" class="contrast" data-action="close">${o("sessions.close")}</button>
|
|
204
|
+
</div>
|
|
205
|
+
</article>`}function Z(c,g,S){let L=Number(c.lastMessageAt??0),I=Number(g.lastMessageAt??0);return L!==I?S==="needs-you"?L-I:I-L:String(c.title??c.sessionId).localeCompare(String(g.title??g.sessionId))}function J(c){let g=new Map(xn.map(I=>[I.id,[]]));for(let I of c){let P=sa(I);P&&g.get(P).push(I)}let S=M(),L=S.map((I,P)=>{let q=(g.get(I.id)??[]).sort((X,Y)=>Z(X,Y,I.id));return`<section class="session-board-column session-board-${I.id}" data-col="${I.id}">
|
|
206
|
+
<header draggable="true" title="${r(o("sessions.board.dragHint"))}">
|
|
207
|
+
<div>
|
|
208
|
+
<h2>${r(o(I.labelKey))}</h2>
|
|
209
|
+
<p>${r(o(I.hintKey))}</p>
|
|
210
|
+
</div>
|
|
211
|
+
<span class="session-board-head-right">
|
|
212
|
+
<span class="session-board-move">
|
|
213
|
+
<button type="button" data-move-col="${I.id}" data-dir="-1"
|
|
214
|
+
aria-label="${r(o("sessions.board.moveLeft"))}" ${P===0?"disabled":""}>\u2039</button>
|
|
215
|
+
<button type="button" data-move-col="${I.id}" data-dir="1"
|
|
216
|
+
aria-label="${r(o("sessions.board.moveRight"))}" ${P===S.length-1?"disabled":""}>\u203A</button>
|
|
217
|
+
</span>
|
|
218
|
+
<span class="session-board-count">${q.length}</span>
|
|
219
|
+
</span>
|
|
220
|
+
</header>
|
|
221
|
+
<div class="session-board-list">
|
|
222
|
+
${q.length?q.map(ae).join(""):`<div class="session-board-empty">${o("sessions.board.emptyColumn")}</div>`}
|
|
223
|
+
</div>
|
|
224
|
+
</section>`}).join("");L!==w&&(w=L,h.innerHTML=L,h.classList.toggle("board-enter",!x),x=!0)}function se(){let c=new FormData(n),g=(c.get("q")??"").toLowerCase(),S=c.getAll("cli"),L=S.length>0&&S.length<Hn.length,I=c.get("status"),P=c.get("adopt"),q=!!c.get("active"),X=[...G.sessions.values()].filter(Y=>!L||S.includes(Y.cliId??"unknown")).filter(Y=>!I||Y.status===I).filter(Y=>!P||P==="yes"==!!Y.adopt).filter(Y=>!q||Y.status!=="closed").filter(Y=>!g||JSON.stringify(Y).toLowerCase().includes(g));return X.sort(ye),X}function Me(c,g){return g==="spawnedAt"||g==="lastMessageAt"?Number(c[g]??0):g==="adopt"?!!c.adopt:String(c[g]??"").toLowerCase()}function ye(c,g){let S=Me(c,E),L=Me(g,E),I=0;return typeof S=="number"&&typeof L=="number"?I=S-L:typeof S=="boolean"&&typeof L=="boolean"?I=Number(S)-Number(L):I=String(S).localeCompare(String(L)),I===0&&(I=Number(c.lastMessageAt??0)-Number(g.lastMessageAt??0)),B==="asc"?I:-I}function ie(){y.querySelectorAll("th[data-sort]").forEach(c=>{let g=c.dataset.sort===E;c.classList.toggle("sorted",g),c.setAttribute("aria-sort",g?B==="asc"?"ascending":"descending":"none");let S=c.dataset.label??c.textContent?.trim()??"";c.textContent=g?`${S} ${B==="asc"?"\u25B2":"\u25BC"}`:S})}function re(c){i.hidden=u.size===0,l.textContent=o("sessions.selectedCount",{count:u.size});let g=c.filter(L=>L.status!=="closed");if(g.length===0){a.checked=!1,a.indeterminate=!1,a.disabled=!0;return}a.disabled=!1;let S=g.filter(L=>u.has(L.sessionId)).length;a.checked=S===g.length,a.indeterminate=S>0&&S<g.length}function te(){k.forEach(c=>{let g=c.dataset.view===$;c.classList.toggle("active",g),c.setAttribute("aria-pressed",String(g))})}function pe(){let c=n.querySelector("#cli-filter-count");if(!c)return;let g=[...n.querySelectorAll('input[name="cli"]')],S=g.filter(L=>L.checked).length;c.textContent=S===g.length?o("common.all"):`${S}/${g.length}`,c.classList.toggle("cli-filter-active",S!==g.length)}function Q(){let c=se();for(let L of[...u]){let I=G.sessions.get(L);(!I||I.status==="closed")&&u.delete(L)}let g=c.filter(L=>L.status!=="closed"),S=$==="board"?g:c;if(y.hidden=$!=="table",h.hidden=$!=="board",$==="table"){let L=c.length?c.map(z).join(""):`<tr><td colspan="10" class="empty">${o("sessions.empty")}</td></tr>`;L!==T&&(T=L,t.innerHTML=L)}else J(g);te(),ie(),pe(),re(S)}async function ve(c,g){g&&(g.disabled=!0,g.textContent=o("sessions.locating"));try{let S=await fetch(`/api/sessions/${encodeURIComponent(c.sessionId)}/locate`,{method:"POST"}),L=await S.json();if(L.ok){if(!g)return;let I=30;g.textContent=o("sessions.cooldown",{seconds:I});let P=setInterval(()=>{I-=1,I<=0?(clearInterval(P),g.disabled=!1,g.textContent=o("sessions.locate")):g.textContent=o("sessions.cooldown",{seconds:I})},1e3)}else alert(`Locate failed: ${L.error??S.status}`),g&&(g.disabled=!1,g.textContent=o("sessions.locate"))}catch(S){alert(`Locate error: ${S}`),g&&(g.disabled=!1,g.textContent=o("sessions.locate"))}}async function ke(c,g){if(!confirm(o("sessions.closeConfirm")))return!1;g&&(g.disabled=!0);try{let S=await fetch(`/api/sessions/${encodeURIComponent(c.sessionId)}/close`,{method:"POST"}),L=await S.json().catch(()=>({}));return!S.ok||L?.ok===!1?(S.status!==401&&alert(`Close failed: ${L?.error??S.status}`),!1):!0}catch(S){return alert(`Close error: ${S}`),!1}finally{g&&(g.disabled=!1)}}function V(c){let g=c.status==="closed",S=Mn(c);s.innerHTML=`<article>
|
|
124
225
|
<header>
|
|
125
|
-
<h3>${
|
|
126
|
-
<span class="status status-${
|
|
127
|
-
<p><code>${
|
|
226
|
+
<h3>${r($e(c.title)||c.sessionId)}</h3>
|
|
227
|
+
<span class="status status-${r(c.status??"unknown")}">${r(c.status??"unknown")}</span>
|
|
228
|
+
<p><code>${r(c.sessionId)}</code> <button data-copy="${r(c.sessionId)}">${o("sessions.copy")}</button></p>
|
|
128
229
|
</header>
|
|
129
|
-
<p><b>${
|
|
130
|
-
|
|
131
|
-
<p><b>
|
|
132
|
-
|
|
133
|
-
|
|
230
|
+
<p><b>${o("sessions.bot")}:</b> ${r(fe(c))} \xB7 <b>${o("sessions.cli")}:</b> ${r(c.cliId??"?")}</p>
|
|
231
|
+
${Ne(c)?`<p><b>${o("sessions.chat")}:</b> ${r(Ne(c))}</p>`:""}
|
|
232
|
+
<p><b>chatId:</b> <code>${r(c.chatId??"")}</code> <button data-copy="${r(c.chatId??"")}">${o("sessions.copy")}</button></p>
|
|
233
|
+
<p><b>rootMessageId:</b> <code>${r(c.rootMessageId??"")}</code> <button data-copy="${r(c.rootMessageId??"")}">${o("sessions.copy")}</button></p>
|
|
234
|
+
${c.threadId?`<p><b>threadId:</b> <code>${r(c.threadId)}</code></p>`:""}
|
|
235
|
+
<p><b>${o("sessions.workingDir")}:</b> ${r(c.workingDir??"-")}</p>
|
|
134
236
|
<div class="actions">
|
|
135
|
-
|
|
136
|
-
${
|
|
137
|
-
${
|
|
138
|
-
${
|
|
237
|
+
${j(c)??`<button id="locate-btn" type="button">${o("sessions.locate")}</button>`}
|
|
238
|
+
${S?`<a class="btn-link primary" href="${r(S)}" target="_blank" rel="noopener">${o("sessions.openTerminal")}</a>`:""}
|
|
239
|
+
${g?`<button id="resume-btn" type="button" class="primary">${o("sessions.resume")}</button>`:""}
|
|
240
|
+
${g?"":`<button id="close-btn" type="button" class="contrast">${o("sessions.close")}</button>`}
|
|
139
241
|
</div>
|
|
140
|
-
<form method="dialog"><button>${
|
|
141
|
-
</article>`,s.querySelectorAll("[data-copy]").forEach(
|
|
242
|
+
<form method="dialog"><button>${o("sessions.dismiss")}</button></form>
|
|
243
|
+
</article>`,s.querySelectorAll("[data-copy]").forEach(q=>{q.onclick=()=>{navigator.clipboard.writeText(q.dataset.copy??""),q.textContent=o("sessions.copied"),setTimeout(()=>{q.textContent=o("sessions.copy")},800)}});let L=s.querySelector("#locate-btn");L&&(L.onclick=()=>{ve(c,L)});let I=s.querySelector("#resume-btn");I&&(I.onclick=async()=>{I.disabled=!0;try{let q=await fetch(`/api/sessions/${encodeURIComponent(c.sessionId)}/resume`,{method:"POST"}),X=await q.json().catch(()=>({}));if(!q.ok||X.ok===!1){alert(`${o("sessions.resumeFailed")}: ${X?.error??q.status}`),I.disabled=!1;return}s.close()}catch(q){alert(`${o("sessions.resumeFailed")}: ${q}`),I.disabled=!1}});let P=s.querySelector("#close-btn");P&&(P.onclick=async()=>{await ke(c,P)&&s.close()}),s.showModal()}t.addEventListener("click",c=>{let g=c.target;if(g.classList.contains("row-select")){let P=g.closest("tr[data-id]");if(!P)return;g.checked?u.add(P.dataset.id):u.delete(P.dataset.id),re(se());return}let S=g.closest("td");if(S&&S.querySelector(".row-select"))return;let L=g.closest("tr[data-id]");if(!L)return;let I=G.sessions.get(L.dataset.id);I&&V(I)}),h.addEventListener("click",c=>{let g=c.target,S=g.closest("button[data-move-col]");if(S){H(S.dataset.moveCol,Number(S.dataset.dir));return}let L=g.closest(".session-card[data-id]");if(!L)return;let I=G.sessions.get(L.dataset.id);if(!I)return;let P=g.closest("button[data-action]");if(P){let q=P.dataset.action;q==="details"?V(I):q==="locate"?ve(I,P):q==="close"&&ke(I,P).then(X=>{X&&(u.delete(I.sessionId),Q())});return}g.closest("a, button, input, label")||(u.has(I.sessionId)?u.delete(I.sessionId):u.add(I.sessionId),L.classList.toggle("selected",u.has(I.sessionId)),L.setAttribute("aria-pressed",String(u.has(I.sessionId))),re(se().filter(q=>q.status!=="closed")))}),h.addEventListener("dragstart",c=>{let S=c.target.closest(".session-board-column > header[draggable]")?.closest(".session-board-column");S?.dataset.col&&(f=S.dataset.col,S.classList.add("dragging"),c.dataTransfer&&(c.dataTransfer.effectAllowed="move",c.dataTransfer.setData("text/plain",f)))}),h.addEventListener("dragover",c=>{if(!f)return;c.preventDefault(),c.dataTransfer&&(c.dataTransfer.dropEffect="move");let g=c.target.closest(".session-board-column");h.querySelectorAll(".drag-over").forEach(S=>S.classList.remove("drag-over")),g&&g.dataset.col!==f&&g.classList.add("drag-over")}),h.addEventListener("drop",c=>{if(!f)return;c.preventDefault();let g=c.target.closest(".session-board-column"),S=f;f=null,g?.dataset.col&&O(S,g.dataset.col)}),h.addEventListener("dragend",()=>{f=null,h.querySelectorAll(".drag-over, .dragging").forEach(c=>c.classList.remove("drag-over","dragging"))}),k.forEach(c=>{c.addEventListener("click",()=>{let g=c.dataset.view==="table"?"table":"board";g!==$&&($=g,gn(window.localStorage,$),Q())})}),a.addEventListener("change",()=>{let c=se().filter(g=>g.status!=="closed");for(let g of c)a.checked?u.add(g.sessionId):u.delete(g.sessionId);Q()}),v.addEventListener("click",()=>{u.clear(),Q()}),p.addEventListener("click",async()=>{let c=[...u];if(c.length===0||!confirm(o("sessions.closeBulkConfirm",{count:c.length})))return;p.disabled=!0,v.disabled=!0;let g=p.textContent,S=0,L=0,I=[...c];p.textContent=`0/${c.length}`;async function P(){for(;I.length;){let q=I.shift();try{let X=await fetch(`/api/sessions/${encodeURIComponent(q)}/close`,{method:"POST"}),Y=await X.json().catch(()=>({}));(!X.ok||Y?.ok===!1)&&(L+=1)}catch{L+=1}finally{S+=1,p.textContent=`${S}/${c.length}`}}}await Promise.all(Array.from({length:Math.min(6,c.length)},()=>P())),p.textContent=g,p.disabled=!1,v.disabled=!1,u.clear(),Q(),L>0&&alert(`Failed: ${L}/${c.length}`)}),y.querySelectorAll("th[data-sort]").forEach(c=>{c.addEventListener("click",()=>{let g=c.dataset.sort;E===g?B=B==="asc"?"desc":"asc":(E=g,B=g==="spawnedAt"||g==="lastMessageAt"?"desc":"asc"),Q()})}),n.addEventListener("input",Q),G.on(Q),Q(),Pe().then(Q)}function la(){return`<section class="page">
|
|
142
244
|
<div class="page-heading">
|
|
143
245
|
<div>
|
|
144
|
-
<p class="eyebrow">${
|
|
145
|
-
<h1>${
|
|
146
|
-
<p>${
|
|
246
|
+
<p class="eyebrow">${o("nav.schedules")}</p>
|
|
247
|
+
<h1>${o("schedules.title")}</h1>
|
|
248
|
+
<p>${o("schedules.subtitle")}</p>
|
|
147
249
|
</div>
|
|
148
250
|
</div>
|
|
149
251
|
<form id="sched-filters" class="filters">
|
|
150
|
-
<input type="search" name="q" placeholder="${
|
|
252
|
+
<input type="search" name="q" placeholder="${o("schedules.search")}" />
|
|
151
253
|
<select name="kind">
|
|
152
|
-
<option value="">${
|
|
254
|
+
<option value="">${o("schedules.anyKind")}</option>
|
|
153
255
|
<option>cron</option>
|
|
154
256
|
<option>interval</option>
|
|
155
257
|
<option>once</option>
|
|
156
258
|
</select>
|
|
157
|
-
<label><input type="checkbox" name="enabled"> ${
|
|
259
|
+
<label><input type="checkbox" name="enabled"> ${o("schedules.enabledOnly")}</label>
|
|
158
260
|
</form>
|
|
159
261
|
<table>
|
|
160
262
|
<thead><tr>
|
|
161
|
-
<th>${
|
|
162
|
-
<th>${
|
|
263
|
+
<th>${o("schedules.name")}</th><th>${o("schedules.bot")}</th><th>${o("schedules.schedule")}</th><th>${o("schedules.next")}</th><th>${o("schedules.last")}</th>
|
|
264
|
+
<th>${o("schedules.repeat")}</th><th>${o("schedules.enabled")}</th><th>${o("schedules.actions")}</th>
|
|
163
265
|
</tr></thead>
|
|
164
266
|
<tbody id="schedules-tbody"></tbody>
|
|
165
267
|
</table>
|
|
166
|
-
</section>`}function
|
|
167
|
-
<td>${
|
|
168
|
-
<td>${
|
|
169
|
-
<td><code>${
|
|
170
|
-
<td>${
|
|
171
|
-
<td>${
|
|
172
|
-
<td>${
|
|
173
|
-
<td>${
|
|
268
|
+
</section>`}function An(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function Dn(e){e.innerHTML=la();let t=e.querySelector("#schedules-tbody"),n=e.querySelector("#sched-filters");function s(){let i=new FormData(n),l=(i.get("q")??"").toLowerCase(),p=i.get("kind"),v=!!i.get("enabled");return[...G.schedules.values()].filter(y=>!p||y.parsed?.kind===p).filter(y=>!v||y.enabled).filter(y=>!l||JSON.stringify(y).toLowerCase().includes(l)).sort((y,h)=>{if(y.enabled!==h.enabled)return y.enabled?-1:1;let k=y.nextRunAt?Date.parse(y.nextRunAt):1/0,u=h.nextRunAt?Date.parse(h.nextRunAt):1/0;return k-u})}function a(){t.innerHTML=s().map(i=>`<tr data-id="${r(i.id)}">
|
|
269
|
+
<td>${r(i.name??i.id)}</td>
|
|
270
|
+
<td>${r(i.botName??i.larkAppId??"-")}</td>
|
|
271
|
+
<td><code>${r(i.parsed?.display??"?")}</code></td>
|
|
272
|
+
<td>${An(i.nextRunAt)}</td>
|
|
273
|
+
<td>${An(i.lastRunAt)} ${i.lastStatus==="error"?"\u26A0\uFE0F":""}</td>
|
|
274
|
+
<td>${i.repeat?`${i.repeat.completed}/${i.repeat.times??"\u221E"}`:"\u2014"}</td>
|
|
275
|
+
<td>${i.enabled?"\u2713":"\u2717"}</td>
|
|
174
276
|
<td class="actions-cell">
|
|
175
|
-
<button data-op="run" type="button">${
|
|
176
|
-
${
|
|
277
|
+
<button data-op="run" type="button">${o("schedules.runNow")}</button>
|
|
278
|
+
${i.enabled?`<button data-op="pause" type="button">${o("schedules.pause")}</button>`:`<button data-op="resume" type="button">${o("schedules.resume")}</button>`}
|
|
177
279
|
</td>
|
|
178
|
-
</tr>`).join("")||`<tr><td colspan="8" class="empty">${
|
|
280
|
+
</tr>`).join("")||`<tr><td colspan="8" class="empty">${o("schedules.empty")}</td></tr>`}t.addEventListener("click",async i=>{let l=i.target.closest("button[data-op]");if(!l)return;let p=l.closest("tr[data-id]");if(!p)return;let v=p.dataset.id,y=l.dataset.op;l.disabled=!0;let h=l.textContent;l.textContent="...";try{let k=await fetch(`/api/schedules/${encodeURIComponent(v)}/${y}`,{method:"POST"}),u=await k.json().catch(()=>({}));(!k.ok||u.ok===!1)&&alert(`Failed: ${k.status} ${u?.error??""}`.trim())}catch(k){alert("Network error: "+k)}finally{l.disabled=!1,l.textContent=h}}),n.addEventListener("input",a),G.on(a),a()}var oe={chats:[],bots:[]};function da(){return`<section class="page">
|
|
179
281
|
<div class="page-heading">
|
|
180
282
|
<div>
|
|
181
|
-
<p class="eyebrow">${
|
|
182
|
-
<h1>${
|
|
183
|
-
<p>${
|
|
283
|
+
<p class="eyebrow">${o("nav.groups")}</p>
|
|
284
|
+
<h1>${o("groups.title")}</h1>
|
|
285
|
+
<p>${o("groups.subtitle")}</p>
|
|
184
286
|
</div>
|
|
185
287
|
</div>
|
|
186
288
|
<form id="g-filters" class="filters">
|
|
187
|
-
<input type="search" name="q" placeholder="${
|
|
188
|
-
<label><input type="checkbox" name="missing"> ${
|
|
189
|
-
<button type="button" id="g-refresh">${
|
|
190
|
-
<button type="button" id="g-create" class="primary">${
|
|
289
|
+
<input type="search" name="q" placeholder="${o("groups.search")}" />
|
|
290
|
+
<label><input type="checkbox" name="missing"> ${o("groups.missingOnly")}</label>
|
|
291
|
+
<button type="button" id="g-refresh">${o("groups.refresh")}</button>
|
|
292
|
+
<button type="button" id="g-create" class="primary">${o("groups.create")}</button>
|
|
191
293
|
</form>
|
|
192
294
|
<table>
|
|
193
295
|
<thead id="g-head"></thead>
|
|
194
296
|
<tbody id="g-body"></tbody>
|
|
195
297
|
</table>
|
|
196
298
|
<dialog id="g-drawer"></dialog>
|
|
197
|
-
</section>`}async function
|
|
299
|
+
</section>`}async function Ue(){oe=await(await fetch("/api/groups")).json()}async function ca(){return(await fetch("/api/groups")).json()}function ua(e,t){if(t.size===0)return!0;let n=e?.memberBots??[];for(let s of t)if(!n.some(a=>a.larkAppId===s&&a.inChat))return!1;return!0}function Rn(e,t){return e.filter(n=>!t||!t.has(n.larkAppId)).map(n=>`
|
|
198
300
|
<label class="checkbox-row">
|
|
199
|
-
<input type="checkbox" name="bot" value="${
|
|
200
|
-
${
|
|
301
|
+
<input type="checkbox" name="bot" value="${r(n.larkAppId)}">
|
|
302
|
+
${r(n.botName??n.larkAppId)} <small>(${r(n.larkAppId)})</small>
|
|
201
303
|
</label>
|
|
202
|
-
`).join("")}async function
|
|
304
|
+
`).join("")}async function On(e){e.innerHTML=da();let t=e.querySelector("#g-head"),n=e.querySelector("#g-body"),s=e.querySelector("#g-filters"),a=e.querySelector("#g-refresh"),i=e.querySelector("#g-drawer");a.onclick=async()=>{a.disabled=!0;try{await Ue(),h()}finally{a.disabled=!1}};let l=e.querySelector("#g-create");l.onclick=()=>p(),await Ue();function p(){let u=oe.bots;if(u.length===0){alert(o("groups.noBotsOnline"));return}i.innerHTML=`
|
|
203
305
|
<article>
|
|
204
|
-
<header><h3>${
|
|
205
|
-
<p>${
|
|
306
|
+
<header><h3>${o("groups.createTitle")}</h3></header>
|
|
307
|
+
<p>${o("groups.createHelp")}</p>
|
|
206
308
|
<form id="g-createform">
|
|
207
309
|
<label class="form-row">
|
|
208
|
-
<span>${
|
|
209
|
-
<input type="text" name="name" placeholder="${
|
|
310
|
+
<span>${o("groups.name")}</span>
|
|
311
|
+
<input type="text" name="name" placeholder="${o("groups.namePlaceholder")}" maxlength="60">
|
|
210
312
|
</label>
|
|
211
313
|
<label class="form-row">
|
|
212
|
-
<span>${
|
|
314
|
+
<span>${o("groups.bindDir")}</span>
|
|
213
315
|
<input type="text" name="bindWorkingDir" placeholder="e.g. ~/projects/botmux">
|
|
214
|
-
<small>${
|
|
316
|
+
<small>${o("groups.bindDirHelp")}</small>
|
|
215
317
|
</label>
|
|
216
318
|
<fieldset>
|
|
217
|
-
<legend>${
|
|
218
|
-
${
|
|
319
|
+
<legend>${o("groups.botPicker")}</legend>
|
|
320
|
+
${Rn(u)}
|
|
219
321
|
</fieldset>
|
|
220
322
|
<div class="actions">
|
|
221
|
-
<button type="submit" class="primary">${
|
|
222
|
-
<button type="button" id="g-create-cancel">${
|
|
323
|
+
<button type="submit" class="primary">${o("groups.createSubmit")}</button>
|
|
324
|
+
<button type="button" id="g-create-cancel">${o("groups.cancel")}</button>
|
|
223
325
|
</div>
|
|
224
326
|
</form>
|
|
225
|
-
</article>`,
|
|
327
|
+
</article>`,i.showModal(),i.querySelector("#g-create-cancel").onclick=()=>i.close(),i.querySelector("#g-createform").onsubmit=async $=>{$.preventDefault();let d=new FormData($.target),f=(d.get("name")??"").trim(),w=(d.get("bindWorkingDir")??"").trim(),T=d.getAll("bot");if(T.length===0){alert("Pick at least one bot.");return}let x=$.target.querySelector("button[type=submit]");x&&(x.disabled=!0,x.textContent="Creating...");try{let M=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:f||void 0,larkAppIds:T,bindWorkingDir:w||void 0})}),H=await M.json();if(H.ok&&H.chatId){v(H);let O=Array.isArray(H.invalidBotIds)?H.invalidBotIds:[],z=T.filter(ee=>!O.includes(ee)),j=new Set(z);typeof H.creator=="string"&&H.creator&&j.add(H.creator),E(H.chatId,f||H.chatId,z,H.creator),h(),B(H.chatId,j).catch(()=>{})}else alert(`Failed: ${H.error??M.status}`),i.close()}catch(M){alert("Network error: "+M),i.close()}};function E($,d,f,w){let T=new Set(f);w&&T.add(w);let x=oe.bots.map(H=>({larkAppId:H.larkAppId,botName:H.botName,inChat:T.has(H.larkAppId),oncallChat:null})),M={chatId:$,name:d,ownerId:w??null,memberBots:x};oe.chats=[M,...oe.chats.filter(H=>H.chatId!==$)]}async function B($,d){let f=[600,1200,1200,1200,1200,1200];for(let w of f){await new Promise(M=>setTimeout(M,w));let T;try{T=await ca()}catch{continue}let x=(T.chats??[]).find(M=>M.chatId===$);if(x&&ua(x,d)){oe=T,h();return}}}}function v(u){let E=String(u.chatId),B=typeof u.shareLink=="string"&&u.shareLink?u.shareLink:`https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(E)}`,$=u.invalidBotIds??[],d=u.invalidUserIds??[],f=u.autoInvitedOpenId,w=!!u.autoInviteRejected,T=u.ownerTransferredTo,x=u.transferError,M=u.notifyMessageId,H=u.notifyError,O=Array.isArray(u.oncallBindings)?u.oncallBindings:[],z=O.filter(J=>J?.ok).length,j=O.filter(J=>!J?.ok),ee=O.length>0?j.length===0?`<p class="hint-ok">\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1A<code>${r(u.bindResolvedPath??"")}</code>\uFF08${z}/${O.length} bots\uFF09</p>`:`<p class="hint-warn">\u76EE\u5F55\u7ED1\u5B9A\u90E8\u5206\u5931\u8D25\uFF1A\u6210\u529F ${z}/${O.length}\u3002${j.map(J=>`<br><code>${r(J.larkAppId??"?")}</code>: ${r(J.error??"unknown")}`).join("")}</p>`:"",ae;if(f){let J=T?"<br><small>\u7FA4\u4E3B\u5DF2\u4ECE\u673A\u5668\u4EBA\u8F6C\u8BA9\u7ED9\u4F60\u3002</small>":x?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08${r(x)}\uFF09\uFF0C\u4F60\u73B0\u5728\u662F\u6210\u5458\u4F46\u7FA4\u4E3B\u4ECD\u662F\u673A\u5668\u4EBA\u3002</small>`:"",se=M?`<br><small>\u673A\u5668\u4EBA\u5DF2\u5728\u7FA4\u91CC @ \u4E86\u4F60\uFF08\u6D88\u606F id <code>${r(M)}</code>\uFF09\uFF0C\u770B\u98DE\u4E66\u901A\u77E5\u5C31\u80FD\u8FDB\u7FA4\u3002</small>`:H?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8 @ \u901A\u77E5\u5931\u8D25\uFF08${r(H)}\uFF09\uFF0C\u65B0\u7FA4\u53EF\u80FD\u4E0D\u4F1A\u4E3B\u52A8\u51FA\u73B0\u5728\u4F60\u4FA7\u8FB9\u680F\uFF0C\u5EFA\u8BAE\u4ECE\u4E0B\u9762\u6309\u94AE\u8DF3\u8FDB\u53BB\u3002</small>`:"";ae=`<p class="hint-ok">\u5DF2\u81EA\u52A8\u9080\u8BF7\u4F60\uFF08<code>${r(f)}</code>\uFF09\u4F5C\u4E3A\u6210\u5458\u3002${J}${se}</p>`}else w?ae='<p class="hint-warn">\u98DE\u4E66\u62D2\u7EDD\u4E86\u81EA\u52A8\u9080\u8BF7\uFF08\u4F60\u7684 open_id \u5728\u521B\u5EFA\u8005 bot \u7684 scope \u4E0B\u4E0D\u53EF\u7528\uFF09\u3002<strong>\u4F60\u76EE\u524D\u4E0D\u662F\u65B0\u7FA4\u6210\u5458</strong>\uFF0C\u9700\u8981\u8BA9\u7FA4\u91CC\u7684\u67D0\u4E2A\u673A\u5668\u4EBA\u624B\u52A8\u628A\u4F60\u52A0\u8FDB\u6765\u3002</p>':ae='<p class="hint-warn">\u6CA1\u5728 dashboard \u7F13\u5B58\u91CC\u627E\u5230 ownerOpenId\uFF0C<strong>\u6CA1\u6709\u81EA\u52A8\u9080\u8BF7\u4F60</strong>\u3002\u70B9\u5F00\u4E0B\u9762\u94FE\u63A5\u524D\uFF0C\u5148\u8BA9\u7FA4\u91CC\u4EFB\u4E00\u673A\u5668\u4EBA\u624B\u52A8\u628A\u4F60\u52A0\u8FDB\u53BB\u3002</p>';let Z=[$.length?`<li>\u65E0\u6548 bot id: <code>${$.map(r).join(", ")}</code></li>`:"",d.length?`<li>\u65E0\u6548\u7528\u6237 open_id: <code>${d.map(r).join(", ")}</code></li>`:""].filter(Boolean).join("");i.innerHTML=`
|
|
226
328
|
<article>
|
|
227
|
-
<header><h3>${
|
|
228
|
-
<p><b>chatId:</b> <code>${
|
|
229
|
-
<p><b>\u521B\u5EFA\u8005:</b> <code>${
|
|
230
|
-
${
|
|
231
|
-
${
|
|
232
|
-
${
|
|
329
|
+
<header><h3>${o("groups.successTitle")}</h3></header>
|
|
330
|
+
<p><b>chatId:</b> <code>${r(E)}</code> <button type="button" data-copy="${r(E)}">${o("sessions.copy")}</button></p>
|
|
331
|
+
<p><b>\u521B\u5EFA\u8005:</b> <code>${r(u.creator??"?")}</code></p>
|
|
332
|
+
${ae}
|
|
333
|
+
${ee}
|
|
334
|
+
${Z?`<ul>${Z}</ul>`:""}
|
|
233
335
|
<div class="actions">
|
|
234
|
-
<a class="btn-link primary" href="${
|
|
235
|
-
<button type="button" id="g-create-close">${
|
|
336
|
+
<a class="btn-link primary" href="${B}" target="_blank" rel="noopener">${o("groups.openGroup")}</a>
|
|
337
|
+
<button type="button" id="g-create-close">${o("sessions.dismiss")}</button>
|
|
236
338
|
</div>
|
|
237
|
-
</article>`,
|
|
238
|
-
<th>${
|
|
239
|
-
${
|
|
240
|
-
<th>${
|
|
241
|
-
</tr>`}function
|
|
339
|
+
</article>`,i.querySelectorAll("[data-copy]").forEach(J=>{J.onclick=()=>{navigator.clipboard.writeText(J.dataset.copy??""),J.textContent=o("sessions.copied"),setTimeout(()=>{J.textContent=o("sessions.copy")},800)}}),i.querySelector("#g-create-close").onclick=()=>i.close()}function y(){t.innerHTML=`<tr>
|
|
340
|
+
<th>${o("groups.chat")}</th>
|
|
341
|
+
${oe.bots.map(u=>`<th>${r(u.botName??u.larkAppId)}</th>`).join("")}
|
|
342
|
+
<th>${o("groups.actions")}</th>
|
|
343
|
+
</tr>`}function h(){y();let u=new FormData(s),E=(u.get("q")??"").toLowerCase(),B=!!u.get("missing"),$=oe.chats.filter(d=>!E||(d.name??"").toLowerCase().includes(E)||d.chatId.toLowerCase().includes(E)||(d.ownerId??"").toLowerCase().includes(E)).filter(d=>!B||d.memberBots.some(f=>!f.inChat));if($.length===0){n.innerHTML=`<tr><td colspan="${oe.bots.length+2}" class="empty">${o("groups.empty")}</td></tr>`;return}n.innerHTML=$.map(d=>`<tr data-chat="${r(d.chatId)}">
|
|
242
344
|
<td>
|
|
243
|
-
<strong>${
|
|
244
|
-
<small><code>${
|
|
345
|
+
<strong>${r(d.name??d.chatId)}</strong><br>
|
|
346
|
+
<small><code>${r(d.chatId)}</code></small>
|
|
245
347
|
</td>
|
|
246
|
-
${
|
|
348
|
+
${oe.bots.map(f=>{let w=d.memberBots.find(M=>M.larkAppId===f.larkAppId),T=w?w.error?"!":w.inChat?"\u2713":"\u2717":"?";return`<td class="${w?w.error?"cell-error":w.inChat?"cell-in":"cell-out":"cell-unknown"}" title="${r(w?.error??"")}">${T}</td>`}).join("")}
|
|
247
349
|
<td>
|
|
248
|
-
<button class="add-bots" type="button">${
|
|
249
|
-
<button class="manage-chat" type="button">${
|
|
350
|
+
<button class="add-bots" type="button">${o("groups.addBots")}</button>
|
|
351
|
+
<button class="manage-chat" type="button">${o("groups.manage")}</button>
|
|
250
352
|
</td>
|
|
251
|
-
</tr>`).join("")}
|
|
353
|
+
</tr>`).join("")}h(),n.addEventListener("click",async u=>{let E=u.target.closest("button.add-bots");if(!E)return;let $=E.closest("tr[data-chat]").dataset.chat,d=oe.chats.find(T=>T.chatId===$);if(!d)return;let f=new Set(d.memberBots.filter(T=>T.inChat).map(T=>T.larkAppId));if(!oe.bots.filter(T=>!f.has(T.larkAppId)).length){alert("All configured bots are already in this chat.");return}i.innerHTML=`
|
|
252
354
|
<article>
|
|
253
|
-
<header><h3>${
|
|
254
|
-
<p>${
|
|
355
|
+
<header><h3>${o("groups.addBots")} \xB7 ${r(d.name??d.chatId)}</h3></header>
|
|
356
|
+
<p>${o("groups.createHelp")}</p>
|
|
255
357
|
<form id="g-addform">
|
|
256
|
-
${
|
|
358
|
+
${Rn(oe.bots,f)}
|
|
257
359
|
<div class="actions">
|
|
258
|
-
<button type="submit" class="primary">${
|
|
259
|
-
<button type="button" id="g-cancel">${
|
|
360
|
+
<button type="submit" class="primary">${o("groups.addBots")}</button>
|
|
361
|
+
<button type="button" id="g-cancel">${o("groups.cancel")}</button>
|
|
260
362
|
</div>
|
|
261
363
|
</form>
|
|
262
|
-
</article>`,
|
|
263
|
-
`);alert(
|
|
364
|
+
</article>`,i.showModal(),i.querySelector("#g-cancel").onclick=()=>i.close(),i.querySelector("#g-addform").onsubmit=async T=>{T.preventDefault();let M=new FormData(T.target).getAll("bot");if(M.length===0){alert("Pick at least one bot.");return}try{let O=await(await fetch(`/api/groups/${encodeURIComponent($)}/add-bots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:M})})).json();if(O.error==="no_proxy_bot")alert("No bot is currently in this chat \u2014 add one manually in Feishu first, then retry.");else if(O.result){let z=O.result.map(j=>`${j.id}: ${j.ok?"OK":`failed (${j.error??"unknown"})`}`).join(`
|
|
365
|
+
`);alert(z),await Ue(),h()}else alert(`Unexpected response: ${JSON.stringify(O)}`)}catch(H){alert("Network error: "+H)}finally{i.close()}}}),n.addEventListener("click",async u=>{let E=u.target.closest("button.manage-chat");if(!E)return;let $=E.closest("tr[data-chat]").dataset.chat,d=oe.chats.find(f=>f.chatId===$);d&&k(d)});function k(u){let E=u.memberBots.filter($=>$.inChat),B=typeof u.ownerId=="string"?u.ownerId:"";i.innerHTML=`
|
|
264
366
|
<article>
|
|
265
|
-
<header><h3>${
|
|
266
|
-
<p><b>chatId:</b> <code>${
|
|
267
|
-
<p><b>${
|
|
367
|
+
<header><h3>${o("groups.manageTitle",{name:u.name??u.chatId})}</h3></header>
|
|
368
|
+
<p><b>chatId:</b> <code>${r(u.chatId)}</code></p>
|
|
369
|
+
<p><b>${o("groups.owner")}:</b> <code>${r(u.ownerId??o("common.unknown"))}</code></p>
|
|
268
370
|
|
|
269
371
|
<fieldset>
|
|
270
|
-
<legend>${
|
|
271
|
-
<p><small>${
|
|
272
|
-
${
|
|
273
|
-
<div class="oncall-row" data-bot="${
|
|
372
|
+
<legend>${o("groups.oncall")}</legend>
|
|
373
|
+
<p><small>${o("groups.oncallHelp")}</small></p>
|
|
374
|
+
${E.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':E.map($=>{let d=!!$.oncallChat,f=$.oncallChat?.workingDir??"";return`
|
|
375
|
+
<div class="oncall-row" data-bot="${r($.larkAppId)}">
|
|
274
376
|
<label class="checkbox-row">
|
|
275
|
-
<input type="checkbox" data-action="toggle" ${
|
|
276
|
-
<strong>${
|
|
277
|
-
<small>(${
|
|
377
|
+
<input type="checkbox" data-action="toggle" ${d?"checked":""}>
|
|
378
|
+
<strong>${r($.botName??$.larkAppId)}</strong>
|
|
379
|
+
<small>(${r($.larkAppId)})</small>
|
|
278
380
|
</label>
|
|
279
381
|
<div class="oncall-row-body">
|
|
280
382
|
<input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
|
|
281
|
-
value="${
|
|
282
|
-
<button type="button" data-action="save">${
|
|
383
|
+
value="${r(f)}" ${d?"":"disabled"}>
|
|
384
|
+
<button type="button" data-action="save">${o("groups.save")}</button>
|
|
283
385
|
<span class="oncall-status" data-status></span>
|
|
284
386
|
</div>
|
|
285
387
|
</div>
|
|
@@ -287,196 +389,221 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
287
389
|
</fieldset>
|
|
288
390
|
|
|
289
391
|
<fieldset>
|
|
290
|
-
<legend>${
|
|
291
|
-
${
|
|
392
|
+
<legend>${o("groups.leaveTitle")}</legend>
|
|
393
|
+
${E.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':E.map($=>`
|
|
292
394
|
<label class="checkbox-row">
|
|
293
|
-
<input type="checkbox" name="leave-bot" value="${
|
|
294
|
-
${
|
|
295
|
-
<small>${
|
|
395
|
+
<input type="checkbox" name="leave-bot" value="${r($.larkAppId)}">
|
|
396
|
+
${r($.botName??$.larkAppId)}
|
|
397
|
+
<small>${$.larkAppId===B?"\xB7 \u7FA4\u4E3B":""}</small>
|
|
296
398
|
</label>
|
|
297
399
|
`).join("")}
|
|
298
400
|
</fieldset>
|
|
299
401
|
|
|
300
402
|
<div class="actions">
|
|
301
|
-
<button id="g-leave-btn" type="button" ${
|
|
302
|
-
<button id="g-disband-btn" type="button" class="contrast" ${
|
|
403
|
+
<button id="g-leave-btn" type="button" ${E.length===0?"disabled":""}>${o("groups.leaveSelected")}</button>
|
|
404
|
+
<button id="g-disband-btn" type="button" class="contrast" ${E.length===0?"disabled":""}>${o("groups.disband")}</button>
|
|
303
405
|
</div>
|
|
304
|
-
<p class="hint-warn"><small>${
|
|
305
|
-
<form method="dialog"><button>${
|
|
306
|
-
</article>`,
|
|
307
|
-
`);alert(
|
|
308
|
-
\u5173\u95ED\u4E86 ${
|
|
309
|
-
\u5173\u95ED\u4E86 ${
|
|
310
|
-
${
|
|
406
|
+
<p class="hint-warn"><small>${o("groups.dangerHint")}</small></p>
|
|
407
|
+
<form method="dialog"><button>${o("sessions.dismiss")}</button></form>
|
|
408
|
+
</article>`,i.showModal(),i.querySelectorAll(".oncall-row").forEach($=>{let d=$.dataset.bot,f=$.querySelector("input[data-action=toggle]"),w=$.querySelector("input[data-input=workingDir]"),T=$.querySelector("button[data-action=save]"),x=$.querySelector("[data-status]");f.addEventListener("change",()=>{w.disabled=!f.checked,f.checked&&w.focus()}),T.addEventListener("click",async()=>{x.textContent="",x.className="oncall-status";let M=f.checked,H=w.value.trim();if(M&&!H){x.textContent=o("groups.needWorkingDir"),x.classList.add("hint-warn-inline");return}T.disabled=!0;try{let O=`/api/groups/${encodeURIComponent(u.chatId)}/oncall/${encodeURIComponent(d)}`,z=M?await fetch(O,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({workingDir:H})}):await fetch(O,{method:"DELETE"}),j=await z.json().catch(()=>({}));if(z.ok&&j.ok){x.textContent=M?`\u2713 \u5DF2\u7ED1\u5B9A \u2192 ${j.resolvedPath??H}`:"\u2713 \u5DF2\u89E3\u7ED1",x.classList.add("hint-ok");try{await Ue(),h()}catch{}}else x.textContent=`\u2717 ${j.error??z.status}`,x.classList.add("hint-warn-inline")}catch(O){x.textContent=`\u2717 ${O?.message??O}`,x.classList.add("hint-warn-inline")}finally{T.disabled=!1}})}),i.querySelector("#g-leave-btn").onclick=async()=>{let $=[...i.querySelectorAll("input[name=leave-bot]:checked")].map(d=>d.value);if($.length===0){alert("\u81F3\u5C11\u9009\u4E00\u4E2A\u673A\u5668\u4EBA");return}if(confirm(`\u786E\u5B9A\u8BA9 ${$.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 f=await(await fetch(`/api/groups/${encodeURIComponent(u.chatId)}/leave`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:$})})).json(),w=(f.result??[]).map(T=>{if(!T.ok)return`${T.larkAppId}: \u5931\u8D25 (${T.error??"unknown"})`;let x=T.closedSessions??[],M=x.filter(z=>!z.ok).length,H=x.length-M,O=x.length===0?"":M===0?`\uFF08\u5173\u95ED ${H} \u4E2A\u4F1A\u8BDD\uFF09`:`\uFF08\u5173\u95ED ${H} \u4E2A\uFF0C${M} \u4E2A\u5931\u8D25\uFF09`;return`${T.larkAppId}: OK${O}`}).join(`
|
|
409
|
+
`);alert(w||`Unexpected: ${JSON.stringify(f)}`),await Ue(),h()}catch(d){alert("Network error: "+d)}finally{i.close()}},i.querySelector("#g-disband-btn").onclick=async()=>{if(E.length===0||!confirm(`\u786E\u5B9A\u89E3\u6563\u7FA4\u804A\u300C${u.name??u.chatId}\u300D\uFF1F\u6B64\u64CD\u4F5C\u4E0D\u53EF\u6062\u590D\uFF0C\u672C\u7FA4\u6240\u6709\u673A\u5668\u4EBA\u4F1A\u8BDD\u4E5F\u4F1A\u4E00\u5E76\u5173\u95ED\u3002`))return;let $=[...E].sort((f,w)=>(w.larkAppId===B?1:0)-(f.larkAppId===B?1:0)),d=[];for(let f of $)try{let w=await fetch(`/api/groups/${encodeURIComponent(u.chatId)}/disband`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppId:f.larkAppId})}),T=await w.json();if(T.ok){let x=T.closedSessions??[],M=x.filter(z=>!z.ok).length,H=x.length-M,O=x.length===0?"":M===0?`
|
|
410
|
+
\u5173\u95ED\u4E86 ${H} \u4E2A\u4F1A\u8BDD\u3002`:`
|
|
411
|
+
\u5173\u95ED\u4E86 ${H} \u4E2A\u4F1A\u8BDD\uFF0C${M} \u4E2A\u4F1A\u8BDD\u5173\u95ED\u5931\u8D25\u3002`;alert(`\u5DF2\u89E3\u6563\uFF08\u7531 ${f.botName??f.larkAppId} \u6267\u884C\uFF09${O}`),await Ue(),h(),i.close();return}d.push(`${f.botName??f.larkAppId}: ${T.error??w.status}`)}catch(w){d.push(`${f.botName??f.larkAppId}: ${w}`)}alert(`\u6240\u6709\u5728\u7FA4\u673A\u5668\u4EBA\u5747\u65E0\u6CD5\u89E3\u6563\uFF1A
|
|
412
|
+
${d.join(`
|
|
311
413
|
`)}
|
|
312
414
|
|
|
313
|
-
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",
|
|
415
|
+
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",h)}var ge={bots:[]},ze=null,je=null;function qn(e){let t=null;for(let n of G.sessions.values())n.larkAppId!==e||!n.cliId||(!t||Number(n.lastMessageAt??0)>Number(t.lastMessageAt??0))&&(t=n);return t?.cliId??""}function pa(){return`<section class="page">
|
|
314
416
|
<div class="page-heading">
|
|
315
417
|
<div>
|
|
316
|
-
<p class="eyebrow">${
|
|
317
|
-
<h1>${
|
|
318
|
-
<p>${
|
|
418
|
+
<p class="eyebrow">${o("nav.botDefaults")}</p>
|
|
419
|
+
<h1>${o("botDefaults.title")}</h1>
|
|
420
|
+
<p>${o("botDefaults.subtitle")}</p>
|
|
319
421
|
</div>
|
|
320
422
|
</div>
|
|
321
|
-
<form id="bd-filters" class="filters">
|
|
322
|
-
<input type="search" name="q" placeholder="${
|
|
323
|
-
<button type="button" id="bd-refresh">${
|
|
423
|
+
<form id="bd-filters" class="filters sessions-filters">
|
|
424
|
+
<input type="search" name="q" placeholder="${o("botDefaults.search")}" />
|
|
425
|
+
<button type="button" id="bd-refresh">${o("botDefaults.refresh")}</button>
|
|
324
426
|
</form>
|
|
325
|
-
<div
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
<
|
|
332
|
-
<
|
|
333
|
-
<
|
|
427
|
+
<div class="bd-layout">
|
|
428
|
+
<aside id="bd-roster" class="bd-roster"></aside>
|
|
429
|
+
<div id="bd-list" class="bd-detail"></div>
|
|
430
|
+
</div>
|
|
431
|
+
</section>`}async function Bn(){try{let e=await fetch("/api/bots"),t=await e.json().catch(()=>({}));if(!e.ok){ze=t?.error?`HTTP ${e.status}: ${t.error}${t.path?` (${t.path})`:""}`:`HTTP ${e.status}`,ge={bots:[]};return}if(!t||!Array.isArray(t.bots)){ze="unexpected response shape (no `bots` array)",ge={bots:[]};return}ze=null,ge=t}catch(e){ze=e?.message??String(e),ge={bots:[]}}}function Pn(e){if(!e)return"\u2014";let t=new Date(e);return Number.isNaN(t.getTime())?"\u2014":t.toLocaleString()}async function Nn(e){e.innerHTML=pa();let t=e.querySelector("#bd-list"),n=e.querySelector("#bd-roster"),s=e.querySelector("#bd-filters"),a=e.querySelector("#bd-refresh");a.onclick=async()=>{a.disabled=!0;try{await Bn(),i()}finally{a.disabled=!1}},t.addEventListener("click",d=>{let f=d.target.closest(".toggle-tx small, small.bd-help");f&&(d.preventDefault(),f.classList.toggle("open"))}),await Bn();function i(){let f=(new FormData(s).get("q")??"").toLowerCase(),w=ge.bots.filter(x=>!f||(x.botName??"").toLowerCase().includes(f)||(x.larkAppId??"").toLowerCase().includes(f));if(ze){n.innerHTML="",t.innerHTML=`<p class="hint-warn">\u65E0\u6CD5\u52A0\u8F7D bot \u5217\u8868\uFF1A${r(ze)}<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(w.length===0){n.innerHTML="",t.innerHTML=`<p class="empty">${o("botDefaults.empty")}</p>`;return}(!je||!w.some(x=>x.larkAppId===je))&&(je=w[0].larkAppId),n.innerHTML=w.map(l).join(""),n.querySelectorAll(".bd-roster-item").forEach(x=>{x.onclick=()=>{je=x.dataset.appid,i()}});let T=w.find(x=>x.larkAppId===je);t.innerHTML=p(T),$()}function l(d){let f=d.botName??d.larkAppId,w=qn(d.larkAppId),T=d.defaultOncall?.enabled?'<span class="bd-roster-flag">oncall</span>':"";return`<div class="bd-roster-item${d.larkAppId===je?" on":""}" data-appid="${r(d.larkAppId)}" role="button" tabindex="0">
|
|
432
|
+
<span class="orb-avatar orb-avatar-sm" style="${de(f)}" aria-hidden="true"></span>
|
|
433
|
+
<div class="bd-roster-tx">
|
|
434
|
+
<b>${r(f)}</b>
|
|
435
|
+
<span>${r(w||d.larkAppId.slice(0,14))}</span>
|
|
436
|
+
</div>
|
|
437
|
+
${T}
|
|
438
|
+
</div>`}function p(d){if(d.error)return`<article class="bd-card bd-profile" data-appid="${r(d.larkAppId)}">
|
|
439
|
+
<header class="bd-profile-head">
|
|
440
|
+
<span class="orb-avatar" style="${de(d.botName??d.larkAppId)}" aria-hidden="true"></span>
|
|
441
|
+
<div class="bd-profile-id"><strong>${r(d.botName??d.larkAppId)}</strong>
|
|
442
|
+
<code>${r(d.larkAppId)}</code></div>
|
|
443
|
+
</header>
|
|
444
|
+
<p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${r(d.error)}</p>
|
|
445
|
+
</article>`;let f=d.defaultOncall??{enabled:!1,workingDir:"",since:0},w=!!f.enabled,T=d.botName??d.larkAppId,x=qn(d.larkAppId);return`<article class="bd-card bd-profile" data-appid="${r(d.larkAppId)}">
|
|
446
|
+
<header class="bd-profile-head">
|
|
447
|
+
<span class="orb-avatar" style="${de(T)}" aria-hidden="true"><i class="orb-dot orb-dot-ok"></i></span>
|
|
448
|
+
<div class="bd-profile-id">
|
|
449
|
+
<strong>${r(T)}</strong>
|
|
450
|
+
${x?`<span class="mate-role">${r(x)}</span>`:""}
|
|
451
|
+
<code>${r(d.larkAppId)}</code>
|
|
452
|
+
</div>
|
|
453
|
+
<div class="bd-profile-meta bd-meta">
|
|
454
|
+
<small class="bd-meta-ok">\u25CF ${o("botDefaults.metaOnline")}</small>
|
|
455
|
+
<small data-oncall-since>${o("botDefaults.lastEnabled")}: ${r(Pn(f.since??0))}</small>
|
|
456
|
+
<small>${o("botDefaults.autobound",{count:d.autoboundChatCount??0})}</small>
|
|
457
|
+
</div>
|
|
334
458
|
</header>
|
|
335
|
-
<div class="bd-body">
|
|
336
|
-
<section class="bd-
|
|
337
|
-
<
|
|
338
|
-
|
|
339
|
-
<
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
<label>
|
|
345
|
-
<span>${n("botDefaults.workingDir")}</span>
|
|
346
|
-
<input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
|
|
347
|
-
value="${l(g.workingDir??"")}" ${p?"":"disabled"}>
|
|
459
|
+
<div class="bd-body bd-grid">
|
|
460
|
+
<section class="bd-tile">
|
|
461
|
+
<section class="bd-section">
|
|
462
|
+
<h3 class="bd-section-title">${o("botDefaults.sectionOncall")}</h3>
|
|
463
|
+
<label class="toggle-row">
|
|
464
|
+
<input type="checkbox" data-action="toggle" ${w?"checked":""}>
|
|
465
|
+
<span class="switch" aria-hidden="true"></span>
|
|
466
|
+
<span class="toggle-tx"><strong>${o("botDefaults.defaultOncall")}</strong>
|
|
467
|
+
<small>${o("botDefaults.defaultOncallHelp")}\u3002${o("botDefaults.warning")}</small></span>
|
|
348
468
|
</label>
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
<
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
469
|
+
<div class="bd-row">
|
|
470
|
+
<label>
|
|
471
|
+
<span>${o("botDefaults.workingDir")}</span>
|
|
472
|
+
<input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
|
|
473
|
+
value="${r(f.workingDir??"")}" ${w?"":"disabled"}>
|
|
474
|
+
</label>
|
|
475
|
+
</div>
|
|
476
|
+
<div class="actions">
|
|
477
|
+
<button type="button" class="primary" data-action="save">${o("botDefaults.save")}</button>
|
|
478
|
+
<span class="oncall-status" data-status></span>
|
|
479
|
+
</div>
|
|
480
|
+
${B(d)}
|
|
481
|
+
</section>
|
|
360
482
|
</section>
|
|
361
|
-
|
|
362
|
-
${
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
<
|
|
368
|
-
<p class="bd-section-note">${n("botDefaults.roleHelp")}</p>
|
|
483
|
+
<section class="bd-tile">${v(d)}</section>
|
|
484
|
+
<section class="bd-tile">${k(d)}${h(d)}</section>
|
|
485
|
+
<section class="bd-tile">${E(d)}</section>
|
|
486
|
+
</div>
|
|
487
|
+
</article>`}function v(d){let f=typeof d.teamRole=="string";return`<section class="bd-section">
|
|
488
|
+
<h3 class="bd-section-title">${o("botDefaults.sectionRole")}</h3>
|
|
489
|
+
<p class="bd-section-note">${o("botDefaults.roleHelp")}</p>
|
|
369
490
|
<textarea data-input="teamRole" rows="6"
|
|
370
|
-
placeholder="${
|
|
371
|
-
style="width:100%;box-sizing:border-box;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px"${
|
|
491
|
+
placeholder="${r(o("botDefaults.rolePlaceholder"))}"
|
|
492
|
+
style="width:100%;box-sizing:border-box;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px"${f?"":" disabled"}>${f?r(d.teamRole):""}</textarea>
|
|
372
493
|
<div class="actions">
|
|
373
|
-
<button type="button" data-action="save-role"${
|
|
374
|
-
<button type="button" data-action="delete-role"${
|
|
494
|
+
<button type="button" class="primary" data-action="save-role"${f?"":" disabled"}>${o("botDefaults.roleSave")}</button>
|
|
495
|
+
<button type="button" data-action="delete-role"${f?"":" disabled"}>${o("botDefaults.roleDelete")}</button>
|
|
375
496
|
<span class="oncall-status" data-role-status></span>
|
|
376
497
|
</div>
|
|
377
|
-
</section>`}function
|
|
378
|
-
<h3 class="bd-section-title">${
|
|
498
|
+
</section>`}function y(d){return d==null?o("botDefaults.brandStateDefault"):d.trim()===""?o("botDefaults.brandStateOff"):o("botDefaults.brandStateCustom")}function h(d){let f=d.brandLabel??null;return`<section class="bd-section">
|
|
499
|
+
<h3 class="bd-section-title">${o("botDefaults.sectionBrand")}</h3>
|
|
379
500
|
<div class="bd-row bd-brand">
|
|
380
501
|
<label>
|
|
381
|
-
<span>${
|
|
502
|
+
<span>${o("botDefaults.brandLabel")}</span>
|
|
382
503
|
<input type="text" data-input="brandLabel"
|
|
383
|
-
placeholder="${
|
|
384
|
-
value="${
|
|
504
|
+
placeholder="${r(o("botDefaults.brandLabelPlaceholder"))}"
|
|
505
|
+
value="${r(f??"")}">
|
|
385
506
|
</label>
|
|
386
|
-
<small data-brand-state>${
|
|
387
|
-
<small>${
|
|
507
|
+
<small data-brand-state>${r(y(f))}</small>
|
|
508
|
+
<small class="bd-help">${o("botDefaults.brandLabelHelp")}</small>
|
|
388
509
|
<div class="actions">
|
|
389
|
-
<button type="button" data-action="save-brand">${
|
|
390
|
-
<button type="button" data-action="reset-brand">${
|
|
510
|
+
<button type="button" class="primary" data-action="save-brand">${o("botDefaults.brandSave")}</button>
|
|
511
|
+
<button type="button" data-action="reset-brand">${o("botDefaults.brandReset")}</button>
|
|
391
512
|
<span class="oncall-status" data-brand-status></span>
|
|
392
513
|
</div>
|
|
393
514
|
</div>
|
|
394
|
-
</section>`}function
|
|
395
|
-
<h3 class="bd-section-title">${
|
|
396
|
-
<label class="
|
|
397
|
-
<input type="checkbox" data-action="toggle-disable-streaming" ${
|
|
398
|
-
<
|
|
399
|
-
<
|
|
515
|
+
</section>`}function k(d){let f=d.disableStreamingCard===!0,w=d.writableTerminalLinkInCard===!0,T=d.privateCard===!0;return`<section class="bd-section">
|
|
516
|
+
<h3 class="bd-section-title">${o("botDefaults.sectionCard")}</h3>
|
|
517
|
+
<label class="toggle-row">
|
|
518
|
+
<input type="checkbox" data-action="toggle-disable-streaming" ${f?"checked":""}>
|
|
519
|
+
<span class="switch" aria-hidden="true"></span>
|
|
520
|
+
<span class="toggle-tx"><strong>${o("botDefaults.disableStreaming")}</strong>
|
|
521
|
+
<small>${o("botDefaults.disableStreamingHelp")}</small></span>
|
|
400
522
|
</label>
|
|
401
|
-
<label class="
|
|
402
|
-
<input type="checkbox" data-action="toggle-writable-link" ${
|
|
403
|
-
<
|
|
404
|
-
<
|
|
523
|
+
<label class="toggle-row">
|
|
524
|
+
<input type="checkbox" data-action="toggle-writable-link" ${w?"checked":""} ${f?"disabled":""}>
|
|
525
|
+
<span class="switch" aria-hidden="true"></span>
|
|
526
|
+
<span class="toggle-tx"><strong>${o("botDefaults.writableLink")}</strong>
|
|
527
|
+
<small>${o("botDefaults.writableLinkHelp")}</small></span>
|
|
405
528
|
</label>
|
|
406
|
-
<label class="
|
|
407
|
-
<input type="checkbox" data-action="toggle-private-card" ${
|
|
408
|
-
<
|
|
409
|
-
<
|
|
529
|
+
<label class="toggle-row">
|
|
530
|
+
<input type="checkbox" data-action="toggle-private-card" ${T?"checked":""}>
|
|
531
|
+
<span class="switch" aria-hidden="true"></span>
|
|
532
|
+
<span class="toggle-tx"><strong>${o("botDefaults.privateCard")}</strong>
|
|
533
|
+
<small>${o("botDefaults.privateCardHelp")}</small></span>
|
|
410
534
|
</label>
|
|
411
535
|
<div class="actions">
|
|
412
|
-
<small data-card-pref-moot class="hint-warn-inline" ${
|
|
536
|
+
<small data-card-pref-moot class="hint-warn-inline" ${f?"":"hidden"}>${o("botDefaults.writableLinkMoot")}</small>
|
|
413
537
|
<span class="oncall-status" data-card-pref-status></span>
|
|
414
538
|
</div>
|
|
415
|
-
</section>`}function
|
|
416
|
-
<h3 class="bd-section-title">${
|
|
417
|
-
<label class="
|
|
418
|
-
<input type="checkbox" data-action="toggle-restrict-grant" ${
|
|
419
|
-
<
|
|
420
|
-
<
|
|
539
|
+
</section>`}function u(d){return d==null?o("botDefaults.quotaStateOff"):o("botDefaults.quotaStateOn",{count:d})}function E(d){let f=d.restrictGrantCommands===!0,w=typeof d.messageQuotaDefaultLimit=="number"?d.messageQuotaDefaultLimit:null;return`<section class="bd-section">
|
|
540
|
+
<h3 class="bd-section-title">${o("botDefaults.sectionGrant")}</h3>
|
|
541
|
+
<label class="toggle-row">
|
|
542
|
+
<input type="checkbox" data-action="toggle-restrict-grant" ${f?"checked":""}>
|
|
543
|
+
<span class="switch" aria-hidden="true"></span>
|
|
544
|
+
<span class="toggle-tx"><strong>${o("botDefaults.restrictGrant")}</strong>
|
|
545
|
+
<small>${o("botDefaults.restrictGrantHelp")}</small></span>
|
|
421
546
|
</label>
|
|
422
547
|
<div class="bd-row bd-quota">
|
|
423
548
|
<label>
|
|
424
|
-
<span>${
|
|
549
|
+
<span>${o("botDefaults.quotaDefault")}</span>
|
|
425
550
|
<input type="number" min="1" step="1" data-input="quotaLimit"
|
|
426
|
-
placeholder="${
|
|
427
|
-
value="${
|
|
551
|
+
placeholder="${r(o("botDefaults.quotaPlaceholder"))}"
|
|
552
|
+
value="${w??""}">
|
|
428
553
|
</label>
|
|
429
|
-
<small data-quota-state>${
|
|
430
|
-
<small>${
|
|
554
|
+
<small data-quota-state>${r(u(w))}</small>
|
|
555
|
+
<small class="bd-help">${o("botDefaults.quotaHelp")}</small>
|
|
431
556
|
<div class="actions">
|
|
432
|
-
<button type="button" data-action="save-quota">${
|
|
433
|
-
<button type="button" data-action="off-quota">${
|
|
557
|
+
<button type="button" class="primary" data-action="save-quota">${o("botDefaults.quotaSave")}</button>
|
|
558
|
+
<button type="button" data-action="off-quota">${o("botDefaults.quotaOff")}</button>
|
|
434
559
|
<span class="oncall-status" data-grant-status></span>
|
|
435
560
|
</div>
|
|
436
561
|
</div>
|
|
437
|
-
</section>`}function
|
|
438
|
-
<h4 class="bd-subsection-title">${
|
|
439
|
-
<label class="
|
|
440
|
-
<input type="checkbox" data-action="toggle-auto-join" ${
|
|
441
|
-
<
|
|
442
|
-
<
|
|
562
|
+
</section>`}function B(d){let f=d.autoStartOnGroupJoin===!0,w=d.autoStartOnNewTopic===!0,T=typeof d.autoStartOnGroupJoinPrompt=="string"?d.autoStartOnGroupJoinPrompt:"";return`<div class="bd-subsection">
|
|
563
|
+
<h4 class="bd-subsection-title">${o("botDefaults.sectionAutoStart")}</h4>
|
|
564
|
+
<label class="toggle-row">
|
|
565
|
+
<input type="checkbox" data-action="toggle-auto-join" ${f?"checked":""}>
|
|
566
|
+
<span class="switch" aria-hidden="true"></span>
|
|
567
|
+
<span class="toggle-tx"><strong>${o("botDefaults.autoStartJoin")}</strong>
|
|
568
|
+
<small>${o("botDefaults.autoStartJoinHelp")}</small></span>
|
|
443
569
|
</label>
|
|
444
570
|
<div class="bd-row">
|
|
445
571
|
<label>
|
|
446
|
-
<span>${
|
|
572
|
+
<span>${o("botDefaults.autoStartJoinPrompt")}</span>
|
|
447
573
|
<textarea data-input="autoJoinPrompt" rows="3"
|
|
448
|
-
placeholder="${
|
|
574
|
+
placeholder="${r(o("botDefaults.autoStartJoinPromptPlaceholder"))}">${r(T)}</textarea>
|
|
449
575
|
</label>
|
|
450
576
|
<div class="actions">
|
|
451
|
-
<button type="button" data-action="save-auto-join-prompt">${
|
|
577
|
+
<button type="button" class="primary" data-action="save-auto-join-prompt">${o("botDefaults.autoStartJoinPromptSave")}</button>
|
|
452
578
|
</div>
|
|
453
579
|
</div>
|
|
454
|
-
<label class="
|
|
455
|
-
<input type="checkbox" data-action="toggle-auto-topic" ${
|
|
456
|
-
<
|
|
457
|
-
<
|
|
580
|
+
<label class="toggle-row">
|
|
581
|
+
<input type="checkbox" data-action="toggle-auto-topic" ${w?"checked":""}>
|
|
582
|
+
<span class="switch" aria-hidden="true"></span>
|
|
583
|
+
<span class="toggle-tx"><strong>${o("botDefaults.autoStartTopic")}</strong>
|
|
584
|
+
<small>${o("botDefaults.autoStartTopicHelp")}</small></span>
|
|
458
585
|
</label>
|
|
459
586
|
<div class="actions">
|
|
460
587
|
<span class="oncall-status" data-auto-start-status></span>
|
|
461
588
|
</div>
|
|
462
|
-
</div>`}function
|
|
589
|
+
</div>`}function $(){t.querySelectorAll(".bd-card").forEach(d=>{let f=d.dataset.appid,w=d.querySelector("input[data-action=toggle]"),T=d.querySelector("input[data-input=workingDir]"),x=d.querySelector("button[data-action=save]"),M=d.querySelector("[data-status]");if(!w||!T||!x||!M)return;w.addEventListener("change",()=>{T.disabled=!w.checked,w.checked&&T.focus()}),x.addEventListener("click",async()=>{M.textContent="",M.className="oncall-status";let K=w.checked,U=T.value.trim();if(K&&!U){M.textContent=o("botDefaults.required"),M.classList.add("hint-warn-inline");return}x.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(f)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:K,workingDir:U})}),_=await N.json().catch(()=>({}));if(N.ok&&_.ok){let b=_.resolvedPath?` \u2192 ${_.resolvedPath}`:"";M.textContent=K?`\u2713 \u5DF2\u5F00\u542F${b}\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",M.classList.add("hint-ok");let R=ge.bots.find(A=>A.larkAppId===f);R&&_.defaultOncall&&(R.defaultOncall=_.defaultOncall);let D=d.querySelector("[data-oncall-since]");D&&_.defaultOncall?.since!=null&&(D.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${Pn(_.defaultOncall.since)}`)}else M.textContent=`\u2717 ${_.error??N.status}`,M.classList.add("hint-warn-inline")}catch(N){M.textContent=`\u2717 ${N?.message??N}`,M.classList.add("hint-warn-inline")}finally{x.disabled=!1}});let H=d.querySelector("input[data-input=brandLabel]"),O=d.querySelector("button[data-action=save-brand]"),z=d.querySelector("button[data-action=reset-brand]"),j=d.querySelector("[data-brand-status]"),ee=d.querySelector("[data-brand-state]");async function ae(K,U){if(j){j.textContent="",j.className="oncall-status",U.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(f)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:K})}),_=await N.json().catch(()=>({}));if(N.ok&&_.ok){let b=_.brandLabel??null;j.textContent="\u2713",j.classList.add("hint-ok"),H&&(H.value=b??""),ee&&(ee.textContent=y(b));let R=ge.bots.find(D=>D.larkAppId===f);R&&(R.brandLabel=b)}else j.textContent=`\u2717 ${_.error??N.status}`,j.classList.add("hint-warn-inline")}catch(N){j.textContent=`\u2717 ${N?.message??N}`,j.classList.add("hint-warn-inline")}finally{U.disabled=!1}}}H&&O&&O.addEventListener("click",()=>ae(H.value,O)),z&&z.addEventListener("click",()=>ae(null,z));let Z=d.querySelector("input[data-action=toggle-disable-streaming]"),J=d.querySelector("input[data-action=toggle-writable-link]"),se=d.querySelector("input[data-action=toggle-private-card]"),Me=d.querySelector("[data-card-pref-status]"),ye=d.querySelector("[data-card-pref-moot]");async function ie(K,U,N=Me){if(N){N.textContent="",N.className="oncall-status",U.disabled=!0;try{let _=await fetch(`/api/bots/${encodeURIComponent(f)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(K)}),b=await _.json().catch(()=>({}));if(_.ok&&b.ok){N.textContent=`\u2713 ${o("botDefaults.cardPrefSaved")}`,N.classList.add("hint-ok");let R=ge.bots.find(D=>D.larkAppId===f);R&&(R.disableStreamingCard=b.disableStreamingCard,R.writableTerminalLinkInCard=b.writableTerminalLinkInCard,R.privateCard=b.privateCard,R.autoStartOnGroupJoin=b.autoStartOnGroupJoin,R.autoStartOnGroupJoinPrompt=b.autoStartOnGroupJoinPrompt,R.autoStartOnNewTopic=b.autoStartOnNewTopic)}else N.textContent=`\u2717 ${b.error??_.status}`,N.classList.add("hint-warn-inline")}catch(_){N.textContent=`\u2717 ${_?.message??_}`,N.classList.add("hint-warn-inline")}finally{U===J?U.disabled=!!Z?.checked:U.disabled=!1}}}Z&&Z.addEventListener("change",()=>{let K=Z.checked;J&&(J.disabled=K),ye&&(ye.hidden=!K),ie({disableStreamingCard:K},Z)}),J&&J.addEventListener("change",()=>{ie({writableTerminalLinkInCard:J.checked},J)}),se&&se.addEventListener("change",()=>{ie({privateCard:se.checked},se)});let re=d.querySelector("input[data-action=toggle-auto-join]"),te=d.querySelector("input[data-action=toggle-auto-topic]"),pe=d.querySelector("textarea[data-input=autoJoinPrompt]"),Q=d.querySelector("button[data-action=save-auto-join-prompt]"),ve=d.querySelector("[data-auto-start-status]");re&&re.addEventListener("change",()=>{ie({autoStartOnGroupJoin:re.checked},re,ve)}),te&&te.addEventListener("change",()=>{ie({autoStartOnNewTopic:te.checked},te,ve)}),pe&&Q&&Q.addEventListener("click",()=>{ie({autoStartOnGroupJoinPrompt:pe.value},Q,ve)});let ke=d.querySelector("textarea[data-input=teamRole]"),V=d.querySelector("button[data-action=save-role]"),c=d.querySelector("button[data-action=delete-role]"),g=d.querySelector("[data-role-status]");if(ke&&V&&c&&g){let N=function(b){let R=t.querySelector(`.bd-card[data-appid="${CSS.escape(f)}"]`);if(!R)return;let D=R.querySelector("textarea[data-input=teamRole]"),A=R.querySelector("button[data-action=save-role]"),ne=R.querySelector("button[data-action=delete-role]");D&&(D.value=b,D.disabled=!1),A&&(A.disabled=!1),ne&&(ne.disabled=!1)};var on=N;let K=`/api/team/local-bots/${encodeURIComponent(f)}/role`,U=ge.bots.find(b=>b.larkAppId===f);U&&typeof U.teamRole!="string"&&!U.teamRoleLoading&&(U.teamRoleLoading=!0,(async()=>{try{let b=await fetch(K),R=await b.json().catch(()=>({}));b.ok&&R.ok?(U.teamRole=R.role??"",N(U.teamRole)):(g.textContent=`\u2717 ${o("botDefaults.roleLoadErr")}: ${R.error??b.status}`,g.classList.add("hint-warn-inline"))}catch(b){g.textContent=`\u2717 ${o("botDefaults.roleLoadErr")}: ${b?.message??b}`,g.classList.add("hint-warn-inline")}finally{U.teamRoleLoading=!1}})());async function _(b,R,D){if(g&&!(!U||typeof U.teamRole!="string")){g.textContent="",g.className="oncall-status",V.disabled=!0,c.disabled=!0;try{let A=await fetch(K,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({role:b})}),ne=await A.json().catch(()=>({}));A.ok&&ne.ok?(U&&(U.teamRole=b.trim()),g.textContent=`\u2713 ${D?o("botDefaults.roleDeleted"):o("botDefaults.roleSaved")}`,g.classList.add("hint-ok")):(g.textContent=`\u2717 ${ne.error??A.status}`,g.classList.add("hint-warn-inline"))}catch(A){g.textContent=`\u2717 ${A?.message??A}`,g.classList.add("hint-warn-inline")}finally{V.disabled=!1,c.disabled=!1}}}V.addEventListener("click",()=>_(ke.value,V,!1)),c.addEventListener("click",()=>{ke.value="",_("",c,!0)})}let S=d.querySelector("input[data-action=toggle-restrict-grant]"),L=d.querySelector("input[data-input=quotaLimit]"),I=d.querySelector("button[data-action=save-quota]"),P=d.querySelector("button[data-action=off-quota]"),q=d.querySelector("[data-grant-status]"),X=d.querySelector("[data-quota-state]");async function Y(K,U){if(q){q.textContent="",q.className="oncall-status",U.disabled=!0;try{let N=await fetch(`/api/bots/${encodeURIComponent(f)}/grant-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(K)}),_=await N.json().catch(()=>({}));if(N.ok&&_.ok){q.textContent=`\u2713 ${o("botDefaults.cardPrefSaved")}`,q.classList.add("hint-ok");let b=typeof _.messageQuotaDefaultLimit=="number"?_.messageQuotaDefaultLimit:null,R=ge.bots.find(D=>D.larkAppId===f);R&&(R.restrictGrantCommands=_.restrictGrantCommands===!0,R.messageQuotaDefaultLimit=b),X&&(X.textContent=u(b)),L&&"messageQuotaDefaultLimit"in K&&(L.value=b==null?"":String(b))}else q.textContent=`\u2717 ${_.error??N.status}`,q.classList.add("hint-warn-inline")}catch(N){q.textContent=`\u2717 ${N?.message??N}`,q.classList.add("hint-warn-inline")}finally{U.disabled=!1}}}S&&S.addEventListener("change",()=>{Y({restrictGrantCommands:S.checked},S)}),L&&I&&I.addEventListener("click",()=>{let K=L.value.trim();if(K===""){Y({messageQuotaDefaultLimit:null},I);return}if(!/^[1-9]\d*$/.test(K)){q&&(q.textContent=`\u2717 ${o("botDefaults.quotaInvalid")}`,q.className="oncall-status hint-warn-inline");return}Y({messageQuotaDefaultLimit:Number(K)},I)}),L&&P&&P.addEventListener("click",()=>{L.value="",Y({messageQuotaDefaultLimit:null},P)})})}i(),s.addEventListener("input",i)}var Rt=4096,rt=[],be=null,he=null,ce="",_e=new Set;function ma(){return`<section class="page roles-page">
|
|
463
590
|
<div class="page-heading">
|
|
464
591
|
<div>
|
|
465
|
-
<p class="eyebrow">${
|
|
466
|
-
<h1>${
|
|
467
|
-
<p>${
|
|
592
|
+
<p class="eyebrow">${o("nav.roles")}</p>
|
|
593
|
+
<h1>${o("roles.title")}</h1>
|
|
594
|
+
<p>${o("roles.subtitle")}</p>
|
|
468
595
|
</div>
|
|
469
596
|
</div>
|
|
470
597
|
<div class="roles-layout">
|
|
471
598
|
<div class="roles-tree-panel">
|
|
472
599
|
<div class="roles-tree-header">
|
|
473
|
-
<input type="search" id="roles-search" placeholder="${
|
|
474
|
-
<button type="button" id="roles-refresh">${
|
|
600
|
+
<input type="search" id="roles-search" placeholder="${o("roles.search")}" />
|
|
601
|
+
<button type="button" id="roles-refresh">${o("roles.refresh")}</button>
|
|
475
602
|
</div>
|
|
476
603
|
<div id="roles-tree" class="roles-tree"></div>
|
|
477
604
|
</div>
|
|
478
605
|
<div class="roles-editor-panel">
|
|
479
|
-
<div id="roles-editor-empty" class="roles-editor-empty">${
|
|
606
|
+
<div id="roles-editor-empty" class="roles-editor-empty">${o("roles.selectHint")}</div>
|
|
480
607
|
<div id="roles-editor-form" class="roles-editor-form" style="display:none">
|
|
481
608
|
<div class="roles-editor-breadcrumb">
|
|
482
609
|
<span id="roles-editor-group-name"></span>
|
|
@@ -486,52 +613,52 @@ ${p.join(`
|
|
|
486
613
|
<div class="roles-editor-meta">
|
|
487
614
|
<span id="roles-editor-chat-id" class="roles-editor-meta-line"></span>
|
|
488
615
|
</div>
|
|
489
|
-
<textarea id="roles-editor-textarea" placeholder="${
|
|
616
|
+
<textarea id="roles-editor-textarea" placeholder="${o("roles.editorPlaceholder")}" rows="14"></textarea>
|
|
490
617
|
<div class="roles-editor-footer">
|
|
491
618
|
<span id="roles-editor-bytecount" class="roles-bytecount"></span>
|
|
492
619
|
<div class="roles-editor-actions">
|
|
493
|
-
<button type="button" id="roles-delete" class="danger">${
|
|
494
|
-
<button type="button" id="roles-save" class="primary">${
|
|
620
|
+
<button type="button" id="roles-delete" class="danger">${o("roles.delete")}</button>
|
|
621
|
+
<button type="button" id="roles-save" class="primary">${o("roles.save")}</button>
|
|
495
622
|
</div>
|
|
496
623
|
</div>
|
|
497
624
|
<div id="roles-preview" class="roles-preview"></div>
|
|
498
625
|
</div>
|
|
499
626
|
</div>
|
|
500
627
|
</div>
|
|
501
|
-
</section>`}async function
|
|
502
|
-
<div class="roles-bot-row ${
|
|
503
|
-
data-group-id="${
|
|
504
|
-
data-bot-id="${
|
|
628
|
+
</section>`}async function it(){rt=((await(await fetch("/api/groups")).json()).chats??[]).map(n=>({chatId:n.chatId,name:n.name??n.chatId,memberBots:(n.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 jn(e,t){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)).json()}async function fa(e,t,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({content:n})})).ok}async function ga(e,t){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{method:"DELETE"})).ok}function zn(e){return e.memberBots.filter(t=>t.inChat&&t.hasRole).length}function ba(e){return e.memberBots.filter(t=>t.inChat).length}function He(e=""){let t=document.getElementById("roles-tree");if(!t)return;let n=e.toLowerCase(),s=rt.filter(a=>{if(!n)return!0;let i=a.chatId.toLowerCase().includes(n)||(a.name??"").toLowerCase().includes(n),l=a.memberBots.some(p=>p.larkAppId.toLowerCase().includes(n)||(p.botName??"").toLowerCase().includes(n));return i||l});if(s.length===0){t.innerHTML=`<div class="roles-empty">${o("roles.noChats")}</div>`;return}t.innerHTML=s.map(a=>{let i=_e.has(a.chatId),l=a.memberBots.filter(k=>k.inChat),p=i?"\u25BE":"\u25B8",v=zn(a),y=ba(a),h=i?l.map(k=>`
|
|
629
|
+
<div class="roles-bot-row ${be===a.chatId&&he===k.larkAppId?"selected":""}"
|
|
630
|
+
data-group-id="${r(a.chatId)}"
|
|
631
|
+
data-bot-id="${r(k.larkAppId)}">
|
|
505
632
|
<span class="roles-bot-indent"></span>
|
|
506
|
-
<span class="
|
|
633
|
+
<span class="orb-avatar orb-avatar-sm" style="${de(k.botName)}" aria-hidden="true"></span>
|
|
507
634
|
<div class="roles-bot-info">
|
|
508
|
-
<div class="roles-bot-name">${
|
|
509
|
-
<div class="roles-bot-id">${
|
|
635
|
+
<div class="roles-bot-name">${r(k.botName)}</div>
|
|
636
|
+
<div class="roles-bot-id">${r(k.larkAppId)}</div>
|
|
510
637
|
</div>
|
|
511
|
-
<span class="roles-badge ${
|
|
512
|
-
${
|
|
638
|
+
<span class="roles-badge ${k.hasRole?"has-role":"no-role"}">
|
|
639
|
+
${k.hasRole?o("roles.configured"):o("roles.unconfigured")}
|
|
513
640
|
</span>
|
|
514
641
|
</div>`).join(""):"";return`
|
|
515
642
|
<div class="roles-group-section">
|
|
516
|
-
<div class="roles-group-row ${
|
|
517
|
-
data-group-id="${
|
|
518
|
-
<span class="roles-group-arrow">${
|
|
519
|
-
<span class="roles-group-icon"
|
|
643
|
+
<div class="roles-group-row ${i?"expanded":""} ${be===a.chatId&&!he?"selected":""}"
|
|
644
|
+
data-group-id="${r(a.chatId)}">
|
|
645
|
+
<span class="roles-group-arrow">${p}</span>
|
|
646
|
+
<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>
|
|
520
647
|
<div class="roles-group-info">
|
|
521
|
-
<div class="roles-group-name">${
|
|
648
|
+
<div class="roles-group-name">${r(a.name??a.chatId)}</div>
|
|
522
649
|
<div class="roles-group-meta">
|
|
523
|
-
${
|
|
650
|
+
${v}/${y} ${o("roles.botsWithRoles")}
|
|
524
651
|
</div>
|
|
525
652
|
</div>
|
|
526
653
|
<span class="roles-group-chevron"></span>
|
|
527
654
|
</div>
|
|
528
|
-
<div class="roles-bot-list">${
|
|
529
|
-
</div>`}).join(""),t.querySelectorAll(".roles-group-row").forEach(a=>{a.addEventListener("click",()=>{let
|
|
655
|
+
<div class="roles-bot-list">${h}</div>
|
|
656
|
+
</div>`}).join(""),t.querySelectorAll(".roles-group-row").forEach(a=>{a.addEventListener("click",()=>{let i=a.dataset.groupId;i&&(_e.has(i)?_e.delete(i):_e.add(i),He(document.getElementById("roles-search")?.value??""))})}),t.querySelectorAll(".roles-bot-row").forEach(a=>{a.addEventListener("click",i=>{i.stopPropagation();let l=a.dataset.groupId,p=a.dataset.botId;l&&p&&ha(l,p)})})}async function ha(e,t){be=e,he=t;let n=await jn(t,e),s=document.getElementById("roles-editor-empty"),a=document.getElementById("roles-editor-form"),i=document.getElementById("roles-editor-textarea"),l=document.getElementById("roles-editor-group-name"),p=document.getElementById("roles-editor-bot-name"),v=document.getElementById("roles-editor-chat-id");s&&(s.style.display="none"),a&&(a.style.display="");let y=rt.find(u=>u.chatId===e),h=y?.memberBots.find(u=>u.larkAppId===t);l&&(l.textContent=y?.name??e),p&&(p.textContent=h?.botName??t),v&&(v.textContent=`${e} \xB7 ${t}`),ce=n.content??"",i&&(i.value=ce,i.focus()),Ot(),qt(),He(document.getElementById("roles-search")?.value??"");let k=document.getElementById("roles-delete");k&&(k.style.display=n.hasRole?"":"none")}function Ot(){let e=document.getElementById("roles-editor-bytecount");if(!e)return;let t=new TextEncoder().encode(ce).length;e.textContent=`${t} / ${Rt} bytes`,e.className=`roles-bytecount ${t>3800?"warn":""} ${t>Rt?"over":""}`,wa(t)}function wa(e){let t=document.getElementById("roles-save");if(!t)return;let n=e??new TextEncoder().encode(ce).length;t.disabled=n>Rt||ce.trim().length===0}function qt(){let e=document.getElementById("roles-preview");e&&(ce.trim()?e.innerHTML=`<strong>${o("roles.preview")}</strong><pre>${r(ce)}</pre>`:e.innerHTML=`<small>${o("roles.previewEmpty")}</small>`)}function Un(){be=null,he=null,ce="";let e=document.getElementById("roles-editor-empty"),t=document.getElementById("roles-editor-form"),n=document.getElementById("roles-editor-textarea"),s=document.getElementById("roles-delete");e&&(e.style.display=""),t&&(t.style.display="none"),n&&(n.value=""),s&&(s.style.display="none")}async function _n(e){e.innerHTML=ma(),_e.clear(),Un(),await it();for(let t of rt)zn(t)>0&&_e.add(t.chatId);He(),document.getElementById("roles-search")?.addEventListener("input",t=>{He(t.target.value)}),document.getElementById("roles-refresh")?.addEventListener("click",async()=>{if(await it(),He(document.getElementById("roles-search")?.value??""),be&&he){let t=await jn(he,be),n=document.getElementById("roles-editor-textarea");n&&(n.value=t.content??""),ce=t.content??"",Ot(),qt();let s=document.getElementById("roles-delete");s&&(s.style.display=t.hasRole?"":"none")}}),document.getElementById("roles-save")?.addEventListener("click",async function(){if(!(!be||!he)){this.disabled=!0,this.textContent="...";try{if(await fa(he,be,ce)){await it(),He(document.getElementById("roles-search")?.value??"");let n=document.getElementById("roles-delete");n&&(n.style.display="");let s=document.createElement("span");s.className="roles-saved-flash",s.textContent=` ${o("roles.saved")}`,document.querySelector(".roles-editor-footer")?.appendChild(s),setTimeout(()=>s.remove(),2e3)}else{let n=document.createElement("span");n.className="roles-saved-flash roles-save-error",n.textContent=ce.trim().length===0?` ${o("roles.emptyError")}`:` ${o("roles.saveFailed")}`,document.querySelector(".roles-editor-footer")?.appendChild(n),setTimeout(()=>n.remove(),3e3)}}finally{this.disabled=!1,this.textContent=o("roles.save")}}}),document.getElementById("roles-delete")?.addEventListener("click",async function(){if(!(!be||!he)&&confirm(o("roles.confirmDelete"))){this.disabled=!0,this.textContent="...";try{await ga(he,be)&&(await it(),Un(),He(document.getElementById("roles-search")?.value??""))}finally{this.disabled=!1,this.textContent=o("roles.delete")}}}),document.getElementById("roles-editor-textarea")?.addEventListener("input",t=>{ce=t.target.value,Ot(),qt()})}async function ct(e){let t=await fetch(e);return{status:t.status,body:await t.json().catch(()=>({}))}}async function ut(e,t,n){let s=await fetch(t,{method:e,headers:{"content-type":"application/json"},body:n?JSON.stringify(n):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}var Ae=(e,t)=>ut("POST",e,t),ya=(e,t)=>ut("PUT",e,t),Bt=[],Fn=[],Wn="",lt="",Pt=new Map,dt=new Map,Je=new Set,Ke=new Set;function F(e){return document.getElementById(e)}function pt(){return[...Bt,...Fn]}function Ce(e){let t=Pt.get(e);return t||(t=new Set,Pt.set(e,t)),t}function va(e){return pt().find(t=>t.key===e)}function Gn(e){let t=(n,s,a)=>`<a href="${n}" style="padding:6px 14px;border-radius:8px;text-decoration:none;font-size:14px;font-weight:600;${a?"background:var(--accent);color:var(--on-accent)":"color:var(--muted);background:var(--surface-muted)"}">${s}</a>`;return`<div style="display:flex;gap:8px;margin-bottom:14px">${t("#/team","\u6211\u7684\u56E2\u961F",e==="home")}${t("#/team/manage","\u56E2\u961F\u7BA1\u7406",e==="manage")}</div>`}function ka(){return`<section class="page">
|
|
530
657
|
<div class="page-heading"><div>
|
|
531
658
|
<p class="eyebrow">\u56E2\u961F</p><h1>\u56E2\u961F\u534F\u4F5C\uFF08\u8DE8\u90E8\u7F72\uFF09</h1>
|
|
532
|
-
<p>\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</p>
|
|
659
|
+
<p class="tf-lede">\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</p>
|
|
533
660
|
</div></div>
|
|
534
|
-
${
|
|
661
|
+
${Gn("home")}
|
|
535
662
|
<div class="card" style="margin-bottom:16px">
|
|
536
663
|
<h2 style="margin-top:0">\u672C\u90E8\u7F72</h2>
|
|
537
664
|
<p>\u6211\u7684\u98DE\u4E66\u8EAB\u4EFD\uFF1A<b id="tf-owner">\u672A\u7ED1\u5B9A</b>
|
|
@@ -551,7 +678,7 @@ ${Ft("home")}
|
|
|
551
678
|
<div id="tf-teams">\u52A0\u8F7D\u4E2D\u2026</div>
|
|
552
679
|
</div>
|
|
553
680
|
<div id="tf-modal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);align-items:center;justify-content:center;z-index:50">
|
|
554
|
-
<div style="background:var(--
|
|
681
|
+
<div style="background:var(--surface);color:var(--fg);border:1px solid var(--border);border-radius:10px;padding:18px 20px;width:min(560px,92vw)">
|
|
555
682
|
<h2 id="tf-modal-title" style="margin-top:0">\u9ED8\u8BA4\u89D2\u8272</h2>
|
|
556
683
|
<p class="muted" style="font-size:13px">\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</p>
|
|
557
684
|
<textarea id="tf-modal-text" readonly style="width:100%;min-height:200px;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px;box-sizing:border-box"></textarea>
|
|
@@ -560,12 +687,12 @@ ${Ft("home")}
|
|
|
560
687
|
</div>
|
|
561
688
|
</div>
|
|
562
689
|
</div>
|
|
563
|
-
</section>`}function Un(e){let t=(j("tf-search").value||"").trim().toLowerCase();if(t&&!((e.name||"")+" "+(e.cliId||"")+" "+(e.capability||"")).toLowerCase().includes(t))return!1;let o=j("tf-cli").value;return!(o&&e.cliId!==o||j("tf-fcap").checked&&!e.capability||j("tf-frole").checked&&!e.hasTeamRole)}function _n(e,t){let o=[...e.deployments].sort((a,r)=>a.local===r.local?0:a.local?-1:1),s="";for(let a of o){let r=t.filter(c=>c.deployment.id===a.id);if(!r.length)continue;let i=a.id===_t,m=i?"\u672C\u90E8\u7F72":a.stale?"\u8FDC\u7AEF\xB7\u79BB\u7EBF\uFF1F":"\u8FDC\u7AEF",$=e.kind==="local"&&!i?` <button class="tf-rmmember ghost" data-team="${l(e.teamId)}" data-dep="${l(a.id)}" data-name="${l(a.name)}" style="font-size:12px">\u79FB\u9664</button>`:"",L=`${e.key}::${a.id}`,y=Re.has(L),v=r.filter(c=>Se(e.key).has(c.larkAppId)).length;if(s+=`<div class="tf-dep-h" data-dk="${l(L)}" style="cursor:pointer;margin:10px 0 2px"><b>${y?"\u25BE":"\u25B8"} ${l(a.name)}</b> <span class="muted" style="font-size:12px">\uFF08${m}\uFF09\xB7 ${r.length} \u4E2A${v?`\uFF0C\u5DF2\u9009 ${v}`:""}</span>${$}</div>`,!!y){s+='<table style="width:100%;border-collapse:collapse;font-size:14px"><tbody>';for(let c of r){let I=l(c.larkAppId),f=Se(e.key).has(c.larkAppId)?" checked":"",g=c.deployment.stale?"opacity:.55":"",p=i?`<input class="tf-cap" data-app="${I}" value="${l(c.capability||"")}" placeholder="\u80FD\u529B\u6807\u7B7E\u2026" style="width:92%;padding:3px 6px">`:c.capability?l(c.capability):'<span class="muted">\u2014</span>',S=c.hasTeamRole?i?`<button class="tf-role" data-app="${I}" data-name="${l(c.name)}">\u67E5\u770B</button>`:"\u6709\u89D2\u8272":'<span class="muted">\u2014</span>';s+=`<tr style="${g}"><td style="padding:4px 8px"><input type="checkbox" class="tf-pick" data-tk="${l(e.key)}" data-app="${I}"${f}></td><td style="padding:4px 8px">${l(c.name)}</td><td style="padding:4px 8px" class="muted">${l(c.cliId)}</td><td style="padding:4px 8px">${p}</td><td style="padding:4px 8px">${S}</td></tr>`}s+="</tbody></table>"}}return s||(s='<p class="muted" style="margin:8px 0 0">\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u673A\u5668\u4EBA\u3002</p>'),s+=`<div style="margin-top:12px;display:flex;gap:8px;flex-wrap:wrap;align-items:center"><input class="tf-gname" data-tk="${l(e.key)}" value="${l(We.get(e.key)||"")}" placeholder="\u7FA4\u540D\uFF08\u5982\uFF1A\u8DE8\u56E2\u961F\u6392\u969C\uFF09" style="min-width:200px"><button class="tf-grp primary" data-tk="${l(e.key)}">\u628A\u52FE\u9009\u7684\u673A\u5668\u4EBA\u62C9\u4E00\u4E2A\u7FA4</button><span class="muted" style="font-size:13px">\u52FE\u9009\u673A\u5668\u4EBA \u2192 \u62C9\u5230\u4E00\u4E2A\u98DE\u4E66\u7FA4\uFF08\u81EA\u52A8\u542B owner\uFF09</span><span class="tf-gout" data-tk="${l(e.key)}" style="font-size:13px;display:block;flex-basis:100%"></span></div>`,s}function be(){let e=j("tf-teams"),t=Qe();if(!t.length){e.innerHTML='<p class="muted">\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</p>',j("tf-count").textContent="";return}let o="",s=new Set,a=new Set;for(let i of t){let m=i.bots.filter(Un);m.forEach(v=>s.add(v.larkAppId)),i.bots.forEach(v=>a.add(v.larkAppId));let $=new Set(m.map(v=>v.larkAppId));[...Se(i.key)].forEach(v=>{$.has(v)||Se(i.key).delete(v)});let L=!De.has(i.key),y=i.kind==="remote"?i.ok?' <span class="ok" style="font-size:12px">\u5DF2\u8FDE\u63A5</span>':` <span class="err" style="font-size:12px">\u8FDE\u63A5\u5931\u8D25\uFF1A${l(i.error||"")}</span>`:' <span class="muted" style="font-size:12px">\u6211\u6258\u7BA1</span>';o+=`<div class="card" style="margin:0 0 12px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)"><div class="tf-team-h" data-tk="${l(i.key)}" style="cursor:pointer;display:flex;align-items:center;gap:8px;flex-wrap:wrap"><b style="font-size:15px">${L?"\u25B8":"\u25BE"} ${l(i.label)}</b>`+(i.sub?` <span class="muted" style="font-size:12px">${l(i.sub)}</span>`:"")+y+` <span class="muted" style="font-size:12px">\xB7 ${i.deployments.length} \u4E2A\u90E8\u7F72 \xB7 ${i.bots.length} \u4E2A\u673A\u5668\u4EBA</span></div>`,L||(o+=i.kind==="remote"&&!i.ok?'<p class="muted" style="margin:8px 0 0">\u65E0\u6CD5\u83B7\u53D6\u8BE5\u56E2\u961F\u82B1\u540D\u518C\u3002</p>':_n(i,m)),o+="</div>"}e.innerHTML=o;let r=t.length>1?`\uFF08\u8DE8 ${t.length} \u4E2A\u56E2\u961F\uFF0C\u53BB\u91CD\uFF09`:"";j("tf-count").textContent=`\xB7 ${s.size===a.size?`${a.size}`:`${s.size} / ${a.size}`} \u4E2A\u673A\u5668\u4EBA${r}`,Fn()}function Fn(){let e=j("tf-teams");e.querySelectorAll(".tf-team-h").forEach(t=>{t.onclick=()=>{let o=t.dataset.tk;De.has(o)?De.delete(o):De.add(o),be()}}),e.querySelectorAll(".tf-dep-h").forEach(t=>{t.onclick=()=>{let o=t.dataset.dk;Re.has(o)?Re.delete(o):Re.add(o),be()}}),e.querySelectorAll(".tf-pick").forEach(t=>{t.onchange=()=>{let o=Se(t.dataset.tk);t.checked?o.add(t.dataset.app):o.delete(t.dataset.app)}}),e.querySelectorAll(".tf-gname").forEach(t=>{t.oninput=()=>{We.set(t.dataset.tk,t.value)}}),e.querySelectorAll(".tf-cap").forEach(t=>{t.onchange=async()=>{let o=t.dataset.app,s=t.value;await Bn("/api/team/local-bots/"+encodeURIComponent(o)+"/capability",{capability:s}),Qe().forEach(a=>{let r=a.bots.find(i=>i.larkAppId===o);r&&(r.capability=s.trim()||null)})}}),e.querySelectorAll(".tf-role").forEach(t=>{t.onclick=()=>Wn(t.dataset.app,t.dataset.name||"")}),e.querySelectorAll(".tf-rmmember").forEach(t=>{t.onclick=async o=>{o.stopPropagation(),confirm(`\u628A\u300C${t.dataset.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`)&&(await Ge("DELETE",`/api/team/hosted/${encodeURIComponent(t.dataset.team)}/members/${encodeURIComponent(t.dataset.dep)}`),Oe())}}),e.querySelectorAll(".tf-grp").forEach(t=>{t.onclick=async()=>{let o=t.dataset.tk,s=Nn(o);if(!s)return;let a=[...Se(o)],r=e.querySelector(`.tf-gout[data-tk="${CSS.escape(o)}"]`);if(!a.length){r.innerHTML='<span class="err">\u8BF7\u5148\u52FE\u9009\u81F3\u5C11\u4E00\u4E2A\u673A\u5668\u4EBA</span>';return}let i=(e.querySelector(`.tf-gname[data-tk="${CSS.escape(o)}"]`)?.value||"").trim()||"\u534F\u4F5C\u7FA4";r.innerHTML='<span class="muted">\u5EFA\u7FA4\u4E2D\u2026</span>';let m=s.kind==="local"?await Le("/api/team/federated-group",{name:i,larkAppIds:a,teamId:s.teamId}):await Le("/api/team/remote-group",{hubUrl:s.hubUrl,teamId:s.teamId,name:i,larkAppIds:a});if(Jn(r,m.body,m.status),m.body?.ok){Se(o).clear(),We.delete(o);let $=r.innerHTML,L=()=>{let y=e.querySelector(`.tf-gout[data-tk="${CSS.escape(o)}"]`);y&&(y.innerHTML=$)};s.kind==="local"?Oe().then(L):(be(),L())}}})}function Jn(e,t,o){if(t?.ok&&t.chatId){let s=t.shareLink||"https://applink.feishu.cn/client/chat/open?openChatId="+encodeURIComponent(t.chatId),a=(t.invalidBotIds||[]).length?`<span class="err"> \xB7 \u672A\u52A0\u5165\u7684\u673A\u5668\u4EBA\uFF1A${l((t.invalidBotIds||[]).join(", "))}</span>`:"",r=(t.invalidOwnerUnionIds||[]).length?`<span class="err"> \xB7 ${(t.invalidOwnerUnionIds||[]).length} \u4E2A owner \u672A\u80FD\u62C9\u8FDB</span>`:"",i=t.missingOperatorIdentity?'<span class="err"> \xB7 \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</span>':"",m=(t.skippedNoOwner||[]).length?`<span class="err"> \xB7 ${(t.skippedNoOwner||[]).length} \u4E2A\u673A\u5668\u4EBA\u56E0\u8D1F\u8D23\u4EBA\u672A\u7ED1\u5B9A\u8EAB\u4EFD\u88AB\u8DF3\u8FC7\uFF08\u672A\u52A0\u5165\u7FA4\uFF09</span>`:"",$=t.delegatedTo?`\uFF08\u7531\u300C${l(t.delegatedTo)}\u300D\u5EFA\u7FA4\uFF09`:"";e.innerHTML=`<span class="ok">\u7FA4\u5DF2\u521B\u5EFA</span>${$} \xB7 <a href="${l(s)}" target="_blank">\u5728\u98DE\u4E66\u6253\u5F00</a>${a}${r}${i}${m}`}else{let s=t?.error||o,a=s==="no_local_online_bot"?"\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":s==="all_bots_skipped_no_owner"?"\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":s==="no_creator_available"?"\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":s==="delegation_timeout"?"\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":`\u5EFA\u7FA4\u5931\u8D25\uFF1A${s}`;e.innerHTML=`<span class="err">${l(String(a))}</span>`}}async function Wn(e,t){let o=await ze("/api/team/local-bots/"+encodeURIComponent(e)+"/role");j("tf-modal-title").textContent="\u9ED8\u8BA4\u89D2\u8272 \xB7 "+t,j("tf-modal-text").value=o.body?.role||"",j("tf-modal").dataset.app=e,j("tf-modal").style.display="flex"}function Jt(){let e=Array.from(new Set(Qe().flatMap(s=>s.bots.map(a=>a.cliId)).filter(Boolean))).sort(),t=j("tf-cli"),o=t.value;t.innerHTML='<option value="">\u5168\u90E8 CLI</option>'+e.map(s=>`<option value="${l(s)}">${l(s)}</option>`).join(""),t.value=o}async function Oe(){let t=(await ze("/api/team/hosted")).body;if(!t?.ok){dt=[],be();return}_t=t.deployment.deploymentId,Je=t.suggestedHubUrl||"",j("tf-owner").textContent=t.deployment.ownerName||(t.deployment.ownerUnionId?"\u5DF2\u7ED1\u5B9A":"\u672A\u7ED1\u5B9A"),dt=(t.teams||[]).map(o=>({kind:"local",key:`local:${o.teamId}`,teamId:o.teamId,label:o.isDefault?"\u6211\u6258\u7BA1\u7684\u56E2\u961F":o.name,sub:"",ok:!0,deployments:o.deployments||[],bots:o.bots||[]})),Jt(),be()}async function zn(){Ut=((await ze("/api/team/remote-roster")).body?.memberships||[]).map(o=>{let s=o.roster?.deployments||[],a=s.find(i=>i.local),r=a?.name?`${a.name} \u7684\u56E2\u961F`:o.teamName||o.teamId;return{kind:"remote",key:`${o.hubUrl}::${o.teamId}`,teamId:o.teamId,label:r,sub:o.hubUrl,ok:!!o.ok,error:o.error,hubUrl:o.hubUrl,deployments:s,bots:o.roster?.bots||[]}}),Jt(),be()}function Wt(e){e.innerHTML=jn(),ct.clear(),We.clear(),De.clear(),Re.clear(),["tf-search","tf-cli","tf-fcap","tf-frole"].forEach(t=>{let o=j(t);o.oninput=be,o.onchange=be}),j("tf-modal-cancel").onclick=()=>{j("tf-modal").style.display="none"},Qn(),Oe(),zn()}function Gn(){return`<section class="page">
|
|
690
|
+
</section>`}function $a(e){let t=(F("tf-search").value||"").trim().toLowerCase();if(t&&!((e.name||"")+" "+(e.cliId||"")+" "+(e.capability||"")).toLowerCase().includes(t))return!1;let n=F("tf-cli").value;return!(n&&e.cliId!==n||F("tf-fcap").checked&&!e.capability||F("tf-frole").checked&&!e.hasTeamRole)}function Sa(e,t){let n=[...e.deployments].sort((a,i)=>a.local===i.local?0:a.local?-1:1),s="";for(let a of n){let i=t.filter(u=>u.deployment.id===a.id);if(!i.length)continue;let l=a.id===Wn,p=l?"\u672C\u90E8\u7F72":a.stale?"\u8FDC\u7AEF\xB7\u79BB\u7EBF\uFF1F":"\u8FDC\u7AEF",v=e.kind==="local"&&!l?` <button class="tf-rmmember ghost" data-team="${r(e.teamId)}" data-dep="${r(a.id)}" data-name="${r(a.name)}" style="font-size:12px">\u79FB\u9664</button>`:"",y=`${e.key}::${a.id}`,h=Ke.has(y),k=i.filter(u=>Ce(e.key).has(u.larkAppId)).length;if(s+=`<div class="tf-dep-h" data-dk="${r(y)}" style="cursor:pointer;margin:10px 0 2px"><b>${h?"\u25BE":"\u25B8"} ${r(a.name)}</b> <span class="muted" style="font-size:12px">\uFF08${p}\uFF09\xB7 ${i.length} \u4E2A${k?`\uFF0C\u5DF2\u9009 ${k}`:""}</span>${v}</div>`,!!h){s+='<table style="width:100%;border-collapse:collapse;font-size:14px"><tbody>';for(let u of i){let E=r(u.larkAppId),B=Ce(e.key).has(u.larkAppId)?" checked":"",$=u.deployment.stale?"opacity:.55":"",d=l?`<input class="tf-cap" data-app="${E}" value="${r(u.capability||"")}" placeholder="\u80FD\u529B\u6807\u7B7E\u2026" style="width:92%;padding:3px 6px">`:u.capability?r(u.capability):'<span class="muted">\u2014</span>',f=u.hasTeamRole?l?`<button class="tf-role" data-app="${E}" data-name="${r(u.name)}">\u67E5\u770B</button>`:"\u6709\u89D2\u8272":'<span class="muted">\u2014</span>';s+=`<tr style="${$}"><td style="padding:4px 8px"><input type="checkbox" class="tf-pick" data-tk="${r(e.key)}" data-app="${E}"${B}></td><td style="padding:4px 8px">${r(u.name)}</td><td style="padding:4px 8px" class="muted">${r(u.cliId)}</td><td style="padding:4px 8px">${d}</td><td style="padding:4px 8px">${f}</td></tr>`}s+="</tbody></table>"}}return s||(s='<p class="muted" style="margin:8px 0 0">\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u673A\u5668\u4EBA\u3002</p>'),s+=`<div style="margin-top:12px;display:flex;gap:8px;flex-wrap:wrap;align-items:center"><input class="tf-gname" data-tk="${r(e.key)}" value="${r(dt.get(e.key)||"")}" placeholder="\u7FA4\u540D\uFF08\u5982\uFF1A\u8DE8\u56E2\u961F\u6392\u969C\uFF09" style="min-width:200px"><button class="tf-grp primary" data-tk="${r(e.key)}">\u628A\u52FE\u9009\u7684\u673A\u5668\u4EBA\u62C9\u4E00\u4E2A\u7FA4</button><span class="muted" style="font-size:13px">\u52FE\u9009\u673A\u5668\u4EBA \u2192 \u62C9\u5230\u4E00\u4E2A\u98DE\u4E66\u7FA4\uFF08\u81EA\u52A8\u542B owner\uFF09</span><span class="tf-gout" data-tk="${r(e.key)}" style="font-size:13px;display:block;flex-basis:100%"></span></div>`,s}function Le(){let e=F("tf-teams"),t=pt();if(!t.length){e.innerHTML='<p class="muted">\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</p>',F("tf-count").textContent="";return}let n="",s=new Set,a=new Set;for(let l of t){let p=l.bots.filter($a);p.forEach(k=>s.add(k.larkAppId)),l.bots.forEach(k=>a.add(k.larkAppId));let v=new Set(p.map(k=>k.larkAppId));[...Ce(l.key)].forEach(k=>{v.has(k)||Ce(l.key).delete(k)});let y=!Je.has(l.key),h=l.kind==="remote"?l.ok?' <span class="ok" style="font-size:12px">\u5DF2\u8FDE\u63A5</span>':` <span class="err" style="font-size:12px">\u8FDE\u63A5\u5931\u8D25\uFF1A${r(l.error||"")}</span>`:' <span class="muted" style="font-size:12px">\u6211\u6258\u7BA1</span>';n+=`<div class="card" style="margin:0 0 12px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)"><div class="tf-team-h" data-tk="${r(l.key)}" style="cursor:pointer;display:flex;align-items:center;gap:8px;flex-wrap:wrap"><b style="font-size:15px">${y?"\u25B8":"\u25BE"} ${r(l.label)}</b>`+(l.sub?` <span class="muted" style="font-size:12px">${r(l.sub)}</span>`:"")+h+` <span class="muted" style="font-size:12px">\xB7 ${l.deployments.length} \u4E2A\u90E8\u7F72 \xB7 ${l.bots.length} \u4E2A\u673A\u5668\u4EBA</span></div>`,y||(n+=l.kind==="remote"&&!l.ok?'<p class="muted" style="margin:8px 0 0">\u65E0\u6CD5\u83B7\u53D6\u8BE5\u56E2\u961F\u82B1\u540D\u518C\u3002</p>':Sa(l,p)),n+="</div>"}e.innerHTML=n;let i=t.length>1?`\uFF08\u8DE8 ${t.length} \u4E2A\u56E2\u961F\uFF0C\u53BB\u91CD\uFF09`:"";F("tf-count").textContent=`\xB7 ${s.size===a.size?`${a.size}`:`${s.size} / ${a.size}`} \u4E2A\u673A\u5668\u4EBA${i}`,Ta()}function Ta(){let e=F("tf-teams");e.querySelectorAll(".tf-team-h").forEach(t=>{t.onclick=()=>{let n=t.dataset.tk;Je.has(n)?Je.delete(n):Je.add(n),Le()}}),e.querySelectorAll(".tf-dep-h").forEach(t=>{t.onclick=()=>{let n=t.dataset.dk;Ke.has(n)?Ke.delete(n):Ke.add(n),Le()}}),e.querySelectorAll(".tf-pick").forEach(t=>{t.onchange=()=>{let n=Ce(t.dataset.tk);t.checked?n.add(t.dataset.app):n.delete(t.dataset.app)}}),e.querySelectorAll(".tf-gname").forEach(t=>{t.oninput=()=>{dt.set(t.dataset.tk,t.value)}}),e.querySelectorAll(".tf-cap").forEach(t=>{t.onchange=async()=>{let n=t.dataset.app,s=t.value;await ya("/api/team/local-bots/"+encodeURIComponent(n)+"/capability",{capability:s}),pt().forEach(a=>{let i=a.bots.find(l=>l.larkAppId===n);i&&(i.capability=s.trim()||null)})}}),e.querySelectorAll(".tf-role").forEach(t=>{t.onclick=()=>La(t.dataset.app,t.dataset.name||"")}),e.querySelectorAll(".tf-rmmember").forEach(t=>{t.onclick=async n=>{n.stopPropagation(),confirm(`\u628A\u300C${t.dataset.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`)&&(await ut("DELETE",`/api/team/hosted/${encodeURIComponent(t.dataset.team)}/members/${encodeURIComponent(t.dataset.dep)}`),Ve())}}),e.querySelectorAll(".tf-grp").forEach(t=>{t.onclick=async()=>{let n=t.dataset.tk,s=va(n);if(!s)return;let a=[...Ce(n)],i=e.querySelector(`.tf-gout[data-tk="${CSS.escape(n)}"]`);if(!a.length){i.innerHTML='<span class="err">\u8BF7\u5148\u52FE\u9009\u81F3\u5C11\u4E00\u4E2A\u673A\u5668\u4EBA</span>';return}let l=(e.querySelector(`.tf-gname[data-tk="${CSS.escape(n)}"]`)?.value||"").trim()||"\u534F\u4F5C\u7FA4";i.innerHTML='<span class="muted">\u5EFA\u7FA4\u4E2D\u2026</span>';let p=s.kind==="local"?await Ae("/api/team/federated-group",{name:l,larkAppIds:a,teamId:s.teamId}):await Ae("/api/team/remote-group",{hubUrl:s.hubUrl,teamId:s.teamId,name:l,larkAppIds:a});if(Ia(i,p.body,p.status),p.body?.ok){Ce(n).clear(),dt.delete(n);let v=i.innerHTML,y=()=>{let h=e.querySelector(`.tf-gout[data-tk="${CSS.escape(n)}"]`);h&&(h.innerHTML=v)};s.kind==="local"?Ve().then(y):(Le(),y())}}})}function Ia(e,t,n){if(t?.ok&&t.chatId){let s=t.shareLink||"https://applink.feishu.cn/client/chat/open?openChatId="+encodeURIComponent(t.chatId),a=(t.invalidBotIds||[]).length?`<span class="err"> \xB7 \u672A\u52A0\u5165\u7684\u673A\u5668\u4EBA\uFF1A${r((t.invalidBotIds||[]).join(", "))}</span>`:"",i=(t.invalidOwnerUnionIds||[]).length?`<span class="err"> \xB7 ${(t.invalidOwnerUnionIds||[]).length} \u4E2A owner \u672A\u80FD\u62C9\u8FDB</span>`:"",l=t.missingOperatorIdentity?'<span class="err"> \xB7 \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</span>':"",p=(t.skippedNoOwner||[]).length?`<span class="err"> \xB7 ${(t.skippedNoOwner||[]).length} \u4E2A\u673A\u5668\u4EBA\u56E0\u8D1F\u8D23\u4EBA\u672A\u7ED1\u5B9A\u8EAB\u4EFD\u88AB\u8DF3\u8FC7\uFF08\u672A\u52A0\u5165\u7FA4\uFF09</span>`:"",v=t.delegatedTo?`\uFF08\u7531\u300C${r(t.delegatedTo)}\u300D\u5EFA\u7FA4\uFF09`:"";e.innerHTML=`<span class="ok">\u7FA4\u5DF2\u521B\u5EFA</span>${v} \xB7 <a href="${r(s)}" target="_blank">\u5728\u98DE\u4E66\u6253\u5F00</a>${a}${i}${l}${p}`}else{let s=t?.error||n,a=s==="no_local_online_bot"?"\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":s==="all_bots_skipped_no_owner"?"\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":s==="no_creator_available"?"\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":s==="delegation_timeout"?"\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":`\u5EFA\u7FA4\u5931\u8D25\uFF1A${s}`;e.innerHTML=`<span class="err">${r(String(a))}</span>`}}async function La(e,t){let n=await ct("/api/team/local-bots/"+encodeURIComponent(e)+"/role");F("tf-modal-title").textContent="\u9ED8\u8BA4\u89D2\u8272 \xB7 "+t,F("tf-modal-text").value=n.body?.role||"",F("tf-modal").dataset.app=e,F("tf-modal").style.display="flex"}function Jn(){let e=Array.from(new Set(pt().flatMap(s=>s.bots.map(a=>a.cliId)).filter(Boolean))).sort(),t=F("tf-cli"),n=t.value;t.innerHTML='<option value="">\u5168\u90E8 CLI</option>'+e.map(s=>`<option value="${r(s)}">${r(s)}</option>`).join(""),t.value=n}async function Ve(){let t=(await ct("/api/team/hosted")).body;if(!t?.ok){Bt=[],Le();return}Wn=t.deployment.deploymentId,lt=t.suggestedHubUrl||"",F("tf-owner").textContent=t.deployment.ownerName||(t.deployment.ownerUnionId?"\u5DF2\u7ED1\u5B9A":"\u672A\u7ED1\u5B9A"),Bt=(t.teams||[]).map(n=>({kind:"local",key:`local:${n.teamId}`,teamId:n.teamId,label:n.isDefault?"\u6211\u6258\u7BA1\u7684\u56E2\u961F":n.name,sub:"",ok:!0,deployments:n.deployments||[],bots:n.bots||[]})),Jn(),Le()}async function Ea(){Fn=((await ct("/api/team/remote-roster")).body?.memberships||[]).map(n=>{let s=n.roster?.deployments||[],a=s.find(l=>l.local),i=a?.name?`${a.name} \u7684\u56E2\u961F`:n.teamName||n.teamId;return{kind:"remote",key:`${n.hubUrl}::${n.teamId}`,teamId:n.teamId,label:i,sub:n.hubUrl,ok:!!n.ok,error:n.error,hubUrl:n.hubUrl,deployments:s,bots:n.roster?.bots||[]}}),Jn(),Le()}function Kn(e){e.innerHTML=ka(),Pt.clear(),dt.clear(),Je.clear(),Ke.clear(),["tf-search","tf-cli","tf-fcap","tf-frole"].forEach(t=>{let n=F(t);n.oninput=Le,n.onchange=Le}),F("tf-modal-cancel").onclick=()=>{F("tf-modal").style.display="none"},Ma(),Ve(),Ea()}function xa(){return`<section class="page">
|
|
564
691
|
<div class="page-heading"><div>
|
|
565
692
|
<p class="eyebrow">\u56E2\u961F</p><h1>\u56E2\u961F\u7BA1\u7406</h1>
|
|
566
|
-
<p>\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</p>
|
|
693
|
+
<p class="tf-lede">\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</p>
|
|
567
694
|
</div></div>
|
|
568
|
-
${
|
|
695
|
+
${Gn("manage")}
|
|
569
696
|
<div class="card" style="margin-bottom:16px">
|
|
570
697
|
<h2 style="margin-top:0">\u6211\u6258\u7BA1\u7684\u56E2\u961F</h2>
|
|
571
698
|
<p style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:6px">
|
|
@@ -584,16 +711,16 @@ ${Ft("manage")}
|
|
|
584
711
|
</p>
|
|
585
712
|
<div id="tm-join-out" style="display:none;margin-top:6px"></div>
|
|
586
713
|
</div>
|
|
587
|
-
</section>`}async function
|
|
714
|
+
</section>`}async function Nt(){let t=(await ct("/api/team/hosted")).body,n=F("tm-list");lt=t?.suggestedHubUrl||lt;let s=t?.teams||[];if(!s.length){n.innerHTML='<p class="muted">\u8FD8\u6CA1\u6709\u56E2\u961F\u3002</p>';return}n.innerHTML=s.map(a=>{let i=(a.deployments||[]).filter(l=>!l.local).length;return`<div class="card" style="margin:0 0 8px;padding:10px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
588
715
|
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
589
|
-
<b>${
|
|
590
|
-
<span class="muted" style="font-size:12px">\xB7 ${(a.deployments||[]).length} \u4E2A\u90E8\u7F72${
|
|
716
|
+
<b>${r(a.name)}</b>${a.isDefault?' <span class="muted" style="font-size:12px">\u9ED8\u8BA4</span>':""}
|
|
717
|
+
<span class="muted" style="font-size:12px">\xB7 ${(a.deployments||[]).length} \u4E2A\u90E8\u7F72${i?`\uFF08\u542B ${i} \u8FDC\u7AEF\uFF09`:""} \xB7 ${(a.bots||[]).length} \u4E2A\u673A\u5668\u4EBA</span>
|
|
591
718
|
<span style="margin-left:auto;display:flex;gap:6px">
|
|
592
|
-
<button class="tm-invite ghost" data-team="${
|
|
593
|
-
${a.isDefault?"":`<button class="tm-del ghost" data-team="${
|
|
719
|
+
<button class="tm-invite ghost" data-team="${r(a.teamId)}" style="font-size:12px">\u751F\u6210\u9080\u8BF7\u7801</button>
|
|
720
|
+
${a.isDefault?"":`<button class="tm-del ghost" data-team="${r(a.teamId)}" data-name="${r(a.name)}" style="font-size:12px">\u5220\u9664</button>`}
|
|
594
721
|
</span>
|
|
595
722
|
</div>
|
|
596
|
-
<div class="tm-inv-out" data-team="${
|
|
723
|
+
<div class="tm-inv-out" data-team="${r(a.teamId)}" style="display:none;margin-top:6px;font-size:13px"></div></div>`}).join(""),n.querySelectorAll(".tm-invite").forEach(a=>{a.onclick=async()=>{let i=a.dataset.team,l=n.querySelector(`.tm-inv-out[data-team="${CSS.escape(i)}"]`);l.style.display="",l.innerHTML='<span class="muted">\u751F\u6210\u4E2D\u2026</span>';let p=await Ae("/api/team/local-invite",{teamId:i});p.body?.code?l.innerHTML=`\u628A\u4E0B\u9762\u4E24\u9879\u53D1\u7ED9<b>\u522B\u7684\u90E8\u7F72</b>\u7684\u4EBA\uFF0824 \u5C0F\u65F6\u5185\u3001\u5355\u6B21\u6709\u6548\uFF09\uFF1A<br>Hub \u5730\u5740\uFF1A<code>${r(lt)}</code><br>\u9080\u8BF7\u7801\uFF1A<code style="font-size:15px">${r(p.body.code)}</code>`:l.innerHTML='<span class="err">\u751F\u6210\u5931\u8D25\u3002</span>'}}),n.querySelectorAll(".tm-del").forEach(a=>{a.onclick=async()=>{confirm(`\u5220\u9664\u56E2\u961F\u300C${a.dataset.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`)&&(await ut("DELETE","/api/team/hosted/"+encodeURIComponent(a.dataset.team)),Nt())}})}function Vn(e){e.innerHTML=xa(),F("tm-create").onclick=async()=>{let t=F("tm-newname").value.trim(),n=e.querySelector(".tm-cout");if(!t){n.innerHTML='<span class="err">\u8BF7\u586B\u56E2\u961F\u540D\u79F0</span>';return}n.innerHTML='<span class="muted">\u521B\u5EFA\u4E2D\u2026</span>';let s=await Ae("/api/team/hosted",{name:t});s.body?.ok?(n.innerHTML='<span class="ok">\u5DF2\u521B\u5EFA</span>',F("tm-newname").value="",Nt()):n.innerHTML=`<span class="err">\u521B\u5EFA\u5931\u8D25\uFF1A${r(String(s.body?.error||s.status))}</span>`},F("tm-join").onclick=async()=>{let t=F("tm-hub").value.trim(),n=F("tm-code").value.trim(),s=F("tm-join-out");if(s.style.display="",!t||!n){s.innerHTML='<span class="err">\u8BF7\u586B Hub \u5730\u5740\u548C\u9080\u8BF7\u7801\u3002</span>';return}s.innerHTML='<span class="muted">\u52A0\u5165\u4E2D\u2026</span>';let a=await Ae("/api/team/join-remote",{hubUrl:t,inviteCode:n});if(a.body?.ok)s.innerHTML=`<span class="ok">\u5DF2\u52A0\u5165\u300C${r(a.body.teamName||"")}\u300D\uFF0C\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u67E5\u770B\u3002</span>`,F("tm-code").value="";else{let i=a.body?.error||a.status,l=i==="cannot_join_self"?"\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":i==="deployment_already_joined"?"\u4F60\u7684\u90E8\u7F72\u5DF2\u7ECF\u52A0\u5165\u8FC7\u8FD9\u4E2A\u56E2\u961F\u4E86":i==="hub_unreachable"?"\u8FDE\u4E0D\u4E0A\u5BF9\u65B9 Hub\uFF08\u68C0\u67E5\u5730\u5740/\u7F51\u7EDC\uFF09":i==="hub_timeout"?"\u5BF9\u65B9 Hub \u54CD\u5E94\u8D85\u65F6":`\u52A0\u5165\u5931\u8D25\uFF1A${i}`;s.innerHTML=`<span class="err">${r(String(l))}</span>`}},Nt()}function Ma(){F("tf-autobind").onclick=async()=>{let e=F("tf-bind-out");e.style.display="",e.innerHTML='<span class="muted">\u8BC6\u522B\u4E2D\u2026</span>';let n=(await Ae("/api/team/identity/auto-bind")).body;if(n?.ok&&n.owner){e.innerHTML=`<span class="ok">\u5DF2\u7ED1\u5B9A\uFF1A${r(n.owner.name||n.owner.unionId)}</span>`,Ve();return}if(n?.ok&&n.needChoice&&Array.isArray(n.candidates)){let s=n.candidates.map(a=>`<button class="tf-pickowner ghost" data-union="${r(a.unionId)}" style="margin:2px">${r(a.name||a.unionId)}</button>`).join(" ");e.innerHTML=`\u8BC6\u522B\u5230\u591A\u4E2A\u5019\u9009\uFF0C\u70B9\u4F60\u81EA\u5DF1\uFF1A<br>${s}`,e.querySelectorAll(".tf-pickowner").forEach(a=>{a.onclick=async()=>{e.innerHTML='<span class="muted">\u7ED1\u5B9A\u4E2D\u2026</span>';let l=(await Ae("/api/team/identity/auto-bind",{unionId:a.dataset.union})).body;l?.ok&&l.owner?(e.innerHTML=`<span class="ok">\u5DF2\u7ED1\u5B9A\uFF1A${r(l.owner.name||l.owner.unionId)}</span>`,Ve()):e.innerHTML=`<span class="err">\u7ED1\u5B9A\u5931\u8D25\uFF1A${r(String(l?.error||"unknown"))}</span>`}});return}if(n?.error==="no_candidates"){e.innerHTML='<span class="err">\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</span>';return}e.innerHTML=`<span class="err">\u7ED1\u5B9A\u5931\u8D25\uFF1A${r(String(n?.error||"unknown"))}</span>`}}async function Ut(e){let t=await fetch(e);return{status:t.status,body:await t.json().catch(()=>({}))}}async function zt(e,t,n){let s=await fetch(t,{method:e,headers:{"content-type":"application/json"},body:n?JSON.stringify(n):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}function W(e){return document.getElementById(e)}function De(e){return(W(e).value||"").trim()}var _t=[],Wt=[];function Ha(){return`<section class="page">
|
|
597
724
|
<div class="page-heading">
|
|
598
725
|
<div>
|
|
599
726
|
<p class="eyebrow">\u63A5\u5165\u70B9 \xB7 beta</p>
|
|
@@ -612,16 +739,39 @@ ${Ft("manage")}
|
|
|
612
739
|
<label class="cn-wf" style="display:none">\u5DE5\u4F5C\u6D41 ID</label><input class="cn-wf" id="cn-wf" style="display:none" placeholder="workflowId">
|
|
613
740
|
<label>\u6295\u9012\u5230\u54EA\u4E2A\u7FA4</label>
|
|
614
741
|
<select id="cn-mode">
|
|
615
|
-
<option value="dynamic">\u7531\u8BF7\u6C42\u6307\u5B9A\uFF08\u7FA4
|
|
742
|
+
<option value="dynamic">\u7531\u8BF7\u6C42\u6307\u5B9A\uFF08\u7FA4\u968F\u8BF7\u6C42\u4F20\u5165\uFF09</option>
|
|
616
743
|
<option value="fixed">\u56FA\u5B9A\u7FA4</option>
|
|
617
744
|
<option value="new-group">\u6BCF\u6B21\u65B0\u5EFA\u7FA4</option>
|
|
618
745
|
</select>
|
|
619
|
-
<label class="cn-fixed" style="display:none">\u7FA4
|
|
746
|
+
<label class="cn-fixed" style="display:none">\u6295\u9012\u5230\u7684\u7FA4</label>
|
|
747
|
+
<div class="cn-fixed" style="display:none">
|
|
748
|
+
<select id="cn-chat-sel" style="width:100%;box-sizing:border-box"></select>
|
|
749
|
+
<input id="cn-chat" placeholder="\u624B\u52A8\u586B\u7FA4 ID\uFF1Aoc_\u2026" style="display:none;width:100%;box-sizing:border-box;margin-top:6px">
|
|
750
|
+
<a href="#" id="cn-chat-manual" style="font-size:12px;display:inline-block;margin-top:4px">\u627E\u4E0D\u5230\u7FA4\uFF1F\u624B\u52A8\u586B ID \u2192</a>
|
|
751
|
+
</div>
|
|
620
752
|
<label class="cn-allow">\u5141\u8BB8\u7684\u7FA4<span class="muted" style="font-weight:400">\uFF08\u53EF\u9009\uFF09</span></label>
|
|
621
|
-
<
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
753
|
+
<div class="cn-allow">
|
|
754
|
+
<select id="cn-allow-sel" multiple size="4" style="width:100%;box-sizing:border-box"></select>
|
|
755
|
+
<div class="muted" style="font-size:12px;margin-top:4px">\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</div>
|
|
756
|
+
</div>
|
|
757
|
+
<div class="cn-dyn" style="display:none;grid-column:1 / -1">
|
|
758
|
+
<div class="muted" style="font-size:12px;line-height:1.7;background:var(--bg-soft,#f6f7f9);padding:8px 10px;border-radius:6px">
|
|
759
|
+
<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
|
|
760
|
+
</div>
|
|
761
|
+
</div>
|
|
762
|
+
<label class="cn-life" style="display:none">\u53BB\u91CD\u5B57\u6BB5<span class="muted" style="font-weight:400">\uFF08\u53EF\u9009\uFF09</span></label>
|
|
763
|
+
<div class="cn-life" style="display:none">
|
|
764
|
+
<input id="cn-dedup" placeholder="\u5982 alert.id\uFF08\u4ECE\u4E8B\u4EF6 body \u53D6\u503C\uFF09" style="width:100%;box-sizing:border-box">
|
|
765
|
+
<div class="muted" style="font-size:12px;margin-top:4px">\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</div>
|
|
766
|
+
</div>
|
|
767
|
+
<label style="align-self:start">\u5904\u7406\u6307\u4EE4<span class="muted" style="font-weight:400">\uFF08\u53EF\u9009\uFF09</span></label>
|
|
768
|
+
<textarea id="cn-instruction" rows="3" placeholder="\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" style="width:100%;box-sizing:border-box;font-family:inherit;font-size:13px"></textarea>
|
|
769
|
+
<label>\u6821\u9A8C\u65B9\u5F0F</label>
|
|
770
|
+
<select id="cn-verify">
|
|
771
|
+
<option value="token">\u4EE4\u724C\uFF08\u7B80\u5355\uFF1A\u5BC6\u94A5\u653E\u8FDB URL\uFF0C\u4E00\u6761 curl \u5C31\u80FD\u89E6\u53D1\uFF09</option>
|
|
772
|
+
<option value="hmac-sha256">HMAC \u7B7E\u540D\uFF08\u9AD8\u7EA7\uFF1A\u66F4\u5B89\u5168\uFF0C\u9700\u81EA\u884C\u5BF9\u8BF7\u6C42\u7B7E\u540D\uFF09</option>
|
|
773
|
+
</select>
|
|
774
|
+
<label>\u5BC6\u94A5 / \u4EE4\u724C</label><input id="cn-secret" placeholder="\u7559\u7A7A\u81EA\u52A8\u751F\u6210\uFF08\u53EA\u663E\u793A\u4E00\u6B21\uFF09">
|
|
625
775
|
</div>
|
|
626
776
|
<div style="margin-top:14px"><button id="cn-create" class="primary">\u521B\u5EFA</button>
|
|
627
777
|
<span class="muted" id="cn-create-out" style="margin-left:10px;font-size:13px"></span></div>
|
|
@@ -632,59 +782,97 @@ ${Ft("manage")}
|
|
|
632
782
|
<h2 style="margin-top:0">\u5DF2\u6709\u63A5\u5165\u70B9 <span class="muted" id="cn-count" style="font-size:13px"></span></h2>
|
|
633
783
|
<div id="cn-list">\u52A0\u8F7D\u4E2D\u2026</div>
|
|
634
784
|
</div>
|
|
635
|
-
</section>`}function
|
|
785
|
+
</section>`}function jt(){let e=W("cn-kind").value,t=W("cn-mode").value;document.querySelectorAll(".cn-wf").forEach(n=>{n.style.display=e==="workflow"?"":"none"}),document.querySelectorAll(".cn-fixed").forEach(n=>{n.style.display=t==="fixed"?"":"none"}),document.querySelectorAll(".cn-allow").forEach(n=>{n.style.display=t==="fixed"?"none":""}),document.querySelectorAll(".cn-dyn").forEach(n=>{n.style.display=t==="dynamic"?"":"none"}),document.querySelectorAll(".cn-life").forEach(n=>{n.style.display=t==="new-group"?"":"none"})}function Yn(e){return`${location.origin}/webhook/${encodeURIComponent(e)}`}function Ca(e){return e==="fixed"?"\u56FA\u5B9A\u7FA4":e==="new-group"?"\u6BCF\u6B21\u65B0\u5EFA\u7FA4":"\u8BF7\u6C42\u6307\u5B9A\u7FA4"}function Aa(e){return e==="workflow"?"\u5DE5\u4F5C\u6D41":"\u5355\u8F6E"}function Ft(e){return Wt.find(n=>n.chatId===e)?.name||e}function Da(e){return Wt.filter(t=>t.bots.includes(e))}function Qn(){let e=W("cn-bot").value,t=Da(e),n=p=>`<option value="${r(p.chatId)}">${r(p.name||p.chatId)}</option>`,s=W("cn-chat-sel"),a=s.value;s.innerHTML=t.length?t.map(n).join(""):'<option value="">\uFF08\u8BE5\u673A\u5668\u4EBA\u6682\u65E0\u53EF\u89C1\u7FA4\uFF0C\u70B9\u53F3\u4FA7\u624B\u52A8\u586B ID\uFF09</option>',a&&t.some(p=>p.chatId===a)&&(s.value=a);let i=W("cn-allow-sel"),l=new Set(Array.from(i.selectedOptions).map(p=>p.value));i.innerHTML=t.map(n).join(""),Array.from(i.options).forEach(p=>{l.has(p.value)&&(p.selected=!0)})}function Ra(e){let t=W("cn-list");if(W("cn-count").textContent=e.length?`\xB7 ${e.length} \u4E2A`:"",!e.length){t.innerHTML='<p class="muted">\u8FD8\u6CA1\u6709\u63A5\u5165\u70B9\u3002\u7528\u4E0A\u9762\u7684\u8868\u5355\u521B\u5EFA\u4E00\u4E2A\u3002</p>';return}t.innerHTML=e.map(n=>{let s=_t.find(v=>v.larkAppId===n.target.botId),a=Yn(n.id),i=(n.verify?.type??"token")==="token",l=i?"\u4EE4\u724C":"\u7B7E\u540D",p=n.target.mode==="fixed"&&n.target.chatId?` \xB7 \u6295\u9012\u300C${r(Ft(n.target.chatId))}\u300D`:"";return`<div class="card" style="margin:0 0 10px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
636
786
|
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
637
|
-
<b style="font-size:15px">${
|
|
638
|
-
<span class="${
|
|
639
|
-
<span class="muted" style="font-size:12px">\xB7 ${
|
|
787
|
+
<b style="font-size:15px">${r(n.name)}</b>
|
|
788
|
+
<span class="${n.enabled?"ok":"muted"}" style="font-size:12px">${n.enabled?"\u5DF2\u542F\u7528":"\u5DF2\u505C\u7528"}</span>
|
|
789
|
+
<span class="muted" style="font-size:12px">\xB7 ${r(s?.botName||n.target.botId)} \xB7 ${Aa(n.target.kind)} \xB7 ${Ca(n.target.mode)}${p} \xB7 ${l}</span>
|
|
640
790
|
<span style="margin-left:auto;display:flex;gap:6px">
|
|
641
|
-
<button class="cn-toggle ghost" data-id="${
|
|
642
|
-
<button class="cn-del ghost" data-id="${
|
|
791
|
+
<button class="cn-toggle ghost" data-id="${r(n.id)}" data-on="${n.enabled}" style="font-size:12px">${n.enabled?"\u505C\u7528":"\u542F\u7528"}</button>
|
|
792
|
+
<button class="cn-del ghost" data-id="${r(n.id)}" style="font-size:12px">\u5220\u9664</button>
|
|
643
793
|
</span>
|
|
644
794
|
</div>
|
|
645
795
|
<div style="margin-top:6px;font-size:13px;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
646
|
-
<span class="muted">Webhook URL\uFF1A</span><code style="font-size:12px;word-break:break-all">${
|
|
647
|
-
<button class="cn-copy ghost" data-url="${
|
|
648
|
-
</div
|
|
649
|
-
<
|
|
650
|
-
<p style="margin:
|
|
651
|
-
|
|
652
|
-
<p class="muted" style="font-size:12px;margin:6px 0 0">\
|
|
796
|
+
<span class="muted">Webhook URL\uFF1A</span><code style="font-size:12px;word-break:break-all">${r(a)}${i?"/<\u4EE4\u724C>":""}</code>
|
|
797
|
+
<button class="cn-copy ghost" data-url="${r(a)}" style="font-size:12px">\u590D\u5236</button>
|
|
798
|
+
</div>${i?'<div class="muted" style="font-size:12px;margin-top:4px">\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</div>':""}${n.target.mode==="dynamic"?'<div class="muted" style="font-size:12px;margin-top:4px">\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</div>':""}${n.promptEnvelope?.instruction?`<div class="muted" style="font-size:12px;margin-top:4px">\u5904\u7406\u6307\u4EE4\uFF1A${r(n.promptEnvelope.instruction)}</div>`:""}</div>`}).join(""),t.querySelectorAll(".cn-copy").forEach(n=>{n.onclick=()=>{navigator.clipboard?.writeText(n.dataset.url),n.textContent="\u5DF2\u590D\u5236",setTimeout(()=>n.textContent="\u590D\u5236",1200)}}),t.querySelectorAll(".cn-toggle").forEach(n=>{n.onclick=async()=>{await zt("PATCH","/api/connectors/"+encodeURIComponent(n.dataset.id),{enabled:n.dataset.on!=="true"}),mt()}}),t.querySelectorAll(".cn-del").forEach(n=>{n.onclick=async()=>{confirm("\u5220\u9664\u8FD9\u4E2A\u63A5\u5165\u70B9\uFF1F\u5B83\u7684 webhook URL \u4F1A\u7ACB\u5373\u5931\u6548\u3002")&&(await zt("DELETE","/api/connectors/"+encodeURIComponent(n.dataset.id)),mt())}})}async function mt(){let[e,t,n]=await Promise.all([Ut("/api/bots"),Ut("/api/connectors"),Ut("/api/groups")]);_t=(e.body?.bots||[]).map(i=>({larkAppId:i.larkAppId,botName:i.botName||i.larkAppId})),Wt=(n.body?.chats||[]).map(i=>({chatId:i.chatId,name:i.name||"",bots:(i.memberBots||[]).filter(l=>l.inChat).map(l=>l.larkAppId)}));let s=W("cn-bot"),a=s.value;s.innerHTML=_t.map(i=>`<option value="${r(i.larkAppId)}">${r(i.botName)}</option>`).join("")||'<option value="">\uFF08\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF09</option>',a&&(s.value=a),Qn(),Ra(t.body?.connectors||[])}function Xn(e){e.innerHTML=Ha(),W("cn-kind").onchange=jt,W("cn-mode").onchange=jt,W("cn-bot").onchange=Qn,W("cn-chat-manual").onclick=t=>{t.preventDefault();let n=W("cn-chat"),s=W("cn-chat-sel"),a=n.style.display==="none";n.style.display=a?"":"none",s.style.display=a?"none":"",W("cn-chat-manual").textContent=a?"\u4ECE\u7FA4\u5217\u8868\u9009\u62E9 \u2190":"\u627E\u4E0D\u5230\u7FA4\uFF1F\u624B\u52A8\u586B ID \u2192"},jt(),W("cn-create").onclick=async()=>{let t=W("cn-create-out"),n=De("cn-name"),s=W("cn-bot").value;if(!n){t.innerHTML='<span class="err">\u8BF7\u586B\u540D\u79F0</span>';return}if(!s){t.innerHTML='<span class="err">\u8BF7\u9009\u673A\u5668\u4EBA</span>';return}let a=W("cn-kind").value,i=W("cn-mode").value,l={name:n,enabled:!0,target:{kind:a,mode:i,botId:s},promptEnvelope:{sourceName:n}},p=De("cn-instruction");if(p&&(l.promptEnvelope.instruction=p),a==="workflow"){if(!De("cn-wf")){t.innerHTML='<span class="err">\u8BF7\u586B\u5DE5\u4F5C\u6D41 ID</span>';return}l.target.workflowId=De("cn-wf")}if(i==="fixed"){let k=W("cn-chat").style.display!=="none"?De("cn-chat"):W("cn-chat-sel").value;if(!k){t.innerHTML='<span class="err">\u8BF7\u9009\u62E9\uFF08\u6216\u624B\u52A8\u586B\uFF09\u6295\u9012\u7684\u7FA4</span>';return}l.target.chatId=k}else{let h=Array.from(W("cn-allow-sel").selectedOptions).map(k=>k.value).filter(Boolean);h.length&&(l.target.allowChats=h)}if(i==="new-group"){let h=De("cn-dedup");l.lifecycleExtractors=h?{dedupKey:h}:null}l.verify={type:W("cn-verify").value};let v=De("cn-secret");v&&(l.secret=v),t.innerHTML='<span class="muted">\u521B\u5EFA\u4E2D\u2026</span>';let y=await zt("POST","/api/connectors",l);if(y.status===201&&y.body?.ok){t.innerHTML="";let h=W("cn-created");h.style.display="";let k=y.body.webhookUrl||Yn(y.body.connector.id),u=y.body.secret,E=(y.body.connector?.verify?.type??"token")==="token",B=i==="dynamic",$=B?l.target.allowChats?.[0]||"<\u7FA4ID>":"",d=B?`${r(k)}?chatId=${r($)}`:r(k),f;E&&B?f=`<p class="muted" style="font-size:12px;margin:6px 0 0">\u52A8\u6001\u6A21\u5F0F\uFF1AURL \u5DF2\u542B\u4EE4\u724C\uFF0C\u8C03\u7528\u65F6\u518D\u5E26\u4E0A\u76EE\u6807\u7FA4 ID${$!=="<\u7FA4ID>"?`\uFF08${r(Ft(l.target.allowChats[0]))}\uFF09`:""}\uFF1A</p>
|
|
799
|
+
<pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${d}' -H 'content-type: application/json' -d '{}'</code></pre>
|
|
800
|
+
<p class="muted" style="font-size:12px;margin:6px 0 0">\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</p>`:E?f=`<p class="muted" style="font-size:12px;margin:6px 0 0">\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</p>
|
|
801
|
+
<pre style="margin:6px 0 0;font-size:12px;white-space:pre-wrap;word-break:break-all"><code>curl -X POST '${d}' -H 'content-type: application/json' -d '{}'</code></pre>
|
|
802
|
+
<p class="muted" style="font-size:12px;margin:6px 0 0">\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</p>`:f=`<p class="muted" style="font-size:12px;margin:6px 0 0">\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${B?"\uFF0C\u540C\u65F6\u6309\u4E0A\u9762\u65B9\u5F0F\u5E26\u76EE\u6807\u7FA4 ID":""}\u3002</p>`,h.innerHTML=`<div class="card" style="padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
803
|
+
<p class="ok" style="margin:0 0 6px">\u5DF2\u521B\u5EFA\u300C${r(n)}\u300D${i==="fixed"&&l.target.chatId?`<span class="muted" style="font-weight:400;font-size:13px"> \xB7 \u6295\u9012\u5230\u300C${r(Ft(l.target.chatId))}\u300D</span>`:""}</p>
|
|
804
|
+
<p style="margin:4px 0;font-size:13px"><span class="muted">Webhook URL\uFF1A</span><code style="word-break:break-all">${r(k)}</code></p>
|
|
805
|
+
${u?`<p style="margin:4px 0;font-size:13px"><span class="muted">${E?"\u8BBF\u95EE\u4EE4\u724C":"\u7B7E\u540D\u5BC6\u94A5"}\uFF08\u53EA\u663E\u793A\u8FD9\u4E00\u6B21\uFF0C\u8BF7\u4FDD\u5B58\uFF09\uFF1A</span><code>${r(u)}</code></p>`:""}
|
|
806
|
+
${f}</div>`,["cn-name","cn-wf","cn-chat","cn-dedup","cn-secret","cn-instruction"].forEach(w=>{W(w).value=""}),W("cn-allow-sel").selectedIndex=-1,mt()}else{let h=y.body?.error||y.status;t.innerHTML=`<span class="err">\u521B\u5EFA\u5931\u8D25\uFF1A${r(String(h))}</span>`}},mt()}var Ee=null,Ye=null,Gt=!0;function Oa(){return`<section class="page">
|
|
807
|
+
<div class="page-heading">
|
|
808
|
+
<div>
|
|
809
|
+
<p class="eyebrow">${o("nav.settings")}</p>
|
|
810
|
+
<h1>${o("settings.title")}</h1>
|
|
811
|
+
<p>${o("settings.subtitle")}</p>
|
|
812
|
+
</div>
|
|
813
|
+
</div>
|
|
814
|
+
<div id="settings-body"></div>
|
|
815
|
+
</section>`}function qa(){if(Ye)return`<p class="hint-warn">${o("settings.loadFailed")}: ${r(Ye)}</p>`;if(!Ee)return`<p class="empty">${o("settings.loading")}</p>`;let e=Gt?"":"disabled";return`<div class="settings-grid">
|
|
816
|
+
<article class="bd-card settings-card">
|
|
817
|
+
${Gt?"":`<p class="hint-warn">${o("settings.readOnlyVisitor")}</p>`}
|
|
818
|
+
<section class="bd-section">
|
|
819
|
+
<h3 class="bd-section-title">${o("settings.sectionAccess")}</h3>
|
|
820
|
+
<label class="toggle-row">
|
|
821
|
+
<input type="checkbox" data-setting="publicReadOnly" ${Ee.publicReadOnly?"checked":""} ${e}>
|
|
822
|
+
<span class="switch" aria-hidden="true"></span>
|
|
823
|
+
<span class="toggle-tx"><strong>${o("settings.publicReadOnly")}</strong>
|
|
824
|
+
<small>${o("settings.publicReadOnlyHelp")}</small></span>
|
|
825
|
+
</label>
|
|
826
|
+
</section>
|
|
827
|
+
<section class="bd-section">
|
|
828
|
+
<h3 class="bd-section-title">${o("settings.sectionCards")}</h3>
|
|
829
|
+
<label class="toggle-row">
|
|
830
|
+
<input type="checkbox" data-setting="openTerminalInFeishu" ${Ee.openTerminalInFeishu?"checked":""} ${e}>
|
|
831
|
+
<span class="switch" aria-hidden="true"></span>
|
|
832
|
+
<span class="toggle-tx"><strong>${o("settings.openTerminalInFeishu")}</strong>
|
|
833
|
+
<small>${o("settings.openTerminalInFeishuHelp")}</small></span>
|
|
834
|
+
</label>
|
|
835
|
+
</section>
|
|
836
|
+
<div class="actions settings-actions">
|
|
837
|
+
<span class="oncall-status" data-settings-status></span>
|
|
838
|
+
</div>
|
|
839
|
+
</article>
|
|
840
|
+
</div>`}async function Ba(){try{let e=await fetch("/api/settings"),t=await e.json().catch(()=>({}));if(!e.ok){Ee=null,Ye=t?.error??`HTTP ${e.status}`;return}Ee={publicReadOnly:t.settings?.publicReadOnly===!0,openTerminalInFeishu:t.settings?.openTerminalInFeishu===!0},Gt=t.authed===!0,Ye=null}catch(e){Ee=null,Ye=e?.message??String(e)}}async function Zn(e){e.innerHTML=Oa();let t=e.querySelector("#settings-body");function n(){t.innerHTML=qa(),i()}function s(){return t.querySelector("[data-settings-status]")}async function a(l,p){if(!Ee)return;let v=!p.checked;p.disabled=!0;let y=s();y&&(y.textContent=o("settings.saving"),y.className="oncall-status");try{let h=await fetch("/api/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(l)}),k=await h.json().catch(()=>({}));if(!h.ok||k.ok===!1)throw new Error(k?.error??`HTTP ${h.status}`);Ee={publicReadOnly:k.settings?.publicReadOnly===!0,openTerminalInFeishu:k.settings?.openTerminalInFeishu===!0},y&&(y.textContent=o("settings.saved"),y.classList.add("hint-ok"))}catch(h){p.checked=v,y&&(y.textContent=`${o("settings.saveFailed")}: ${h?.message??h}`,y.classList.add("hint-warn-inline"))}finally{p.disabled=!1}}function i(){t.querySelectorAll("input[data-setting]").forEach(l=>{l.addEventListener("change",()=>{let p=l.dataset.setting;a({[p]:l.checked},l)})})}n(),await Ba(),n()}function Pa(){let e=[["",o("workflow.filter.nonTerminal")],["all",o("workflow.filter.all")],["pending",xe("pending")],["running",xe("running")],["waiting",xe("waiting")],["succeeded",xe("succeeded")],["failed",xe("failed")],["cancelled",xe("cancelled")]];return`
|
|
653
841
|
<nav class="wf-subnav">
|
|
654
|
-
<a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${
|
|
655
|
-
<a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${
|
|
842
|
+
<a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${m(o("workflow.subnav.runs"))}</a>
|
|
843
|
+
<a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${m(o("workflow.subnav.catalog"))}</a>
|
|
656
844
|
</nav>
|
|
657
845
|
<form id="wf-filters" class="filters">
|
|
658
|
-
<input type="search" name="q" placeholder="${
|
|
846
|
+
<input type="search" name="q" placeholder="${m(o("workflow.searchPlaceholder"))}" />
|
|
659
847
|
<select name="status">
|
|
660
|
-
${e.map(([t,
|
|
848
|
+
${e.map(([t,n])=>`<option value="${m(t)}">${m(n)}</option>`).join("")}
|
|
661
849
|
</select>
|
|
662
850
|
<span id="wf-last-load" class="muted"></span>
|
|
663
851
|
</form>
|
|
664
852
|
<table>
|
|
665
853
|
<thead><tr>
|
|
666
|
-
<th>${
|
|
667
|
-
<th>${
|
|
668
|
-
<th>${
|
|
854
|
+
<th>${m(o("workflow.table.run"))}</th><th>${m(o("workflow.table.workflow"))}</th><th>${m(o("workflow.table.status"))}</th>
|
|
855
|
+
<th>${m(o("workflow.table.lastSeq"))}</th><th>${m(o("workflow.table.dangling"))}</th><th>${m(o("workflow.table.updated"))}</th>
|
|
856
|
+
<th>${m(o("workflow.table.chatApp"))}</th>
|
|
669
857
|
</tr></thead>
|
|
670
858
|
<tbody id="wf-tbody"></tbody>
|
|
671
859
|
</table>
|
|
672
|
-
`}var
|
|
673
|
-
<td><a href="#/workflows/${encodeURIComponent(
|
|
674
|
-
<td>${d
|
|
675
|
-
<td>${
|
|
676
|
-
<td>${
|
|
677
|
-
<td class="${
|
|
678
|
-
<td title="${
|
|
679
|
-
<td>${
|
|
680
|
-
</tr>`}).join("")}function
|
|
860
|
+
`}var Na=5e3,Ua=2e3,Qe=new Set(["succeeded","failed","cancelled"]);function m(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function ja(e){let t=new Date(e),s=Date.now()-e;return s<6e4?o("time.secondsAgo",{value:Math.max(1,Math.floor(s/1e3))}):s<36e5?o("time.minutesAgo",{value:Math.floor(s/6e4)}):s<864e5?o("time.hoursAgo",{value:Math.floor(s/36e5)}):t.toISOString().slice(0,19).replace("T"," ")}function Se(e){return`<span class="${Qe.has(e)?"wf-status terminal":"wf-status live"} wf-status-${m(e)}">${m(xe(e))}</span>`}function xe(e){let t=`workflow.status.${e}`,n=o(t);return n===t?e:n}function oo(e){let t=location.hash.match(/^#\/workflows\/([^?#]+)(?:\?([^#]*))?$/);if(t){let n=new URLSearchParams(t[2]??"");return _a(e,decodeURIComponent(t[1]),{focusAttemptId:n.get("attempt")??void 0})}return za(e)}function za(e){e.innerHTML=Pa();let t=e.querySelector("#wf-tbody"),n=e.querySelector("#wf-filters"),s=e.querySelector("#wf-last-load"),a=[],i=null,l=!1,p=null,v=!1;function y($){let f=(new FormData(n).get("q")??"").trim().toLowerCase();return f?$.filter(w=>w.runId.toLowerCase().includes(f)||w.workflowId.toLowerCase().includes(f)||(w.chatId??"").toLowerCase().includes(f)):$}function h(){let $=y(a);if($.length===0){t.innerHTML=`<tr><td colspan="7" class="empty">${p?m(o("workflow.list.failedLoad",{error:p})):a.length===0?m(o("workflow.list.noRuns")):m(o("workflow.list.noFilterMatch"))}</td></tr>`;return}t.innerHTML=$.map(d=>{let f=`${d.dEf}/${d.dAct}/${d.dWait}`,w=d.dEf+d.dAct+d.dWait>0?"wf-dangling has":"wf-dangling none",T=[];d.chatId&&T.push(m(d.chatId)),d.larkAppId&&T.push(`<span class="muted">${m(d.larkAppId)}</span>`);let x=T.length>0?T.join("<br/>"):"\u2014",M=Wa(d);return`<tr data-runid="${m(d.runId)}">
|
|
861
|
+
<td><a href="#/workflows/${encodeURIComponent(d.runId)}"><code>${m(d.runId)}</code></a></td>
|
|
862
|
+
<td>${m(d.workflowId)}</td>
|
|
863
|
+
<td>${Se(d.status)}${d.failedNodeId?` <span class="muted">(${m(d.failedNodeId)})</span>`:""}${M}</td>
|
|
864
|
+
<td>${d.lastSeq}</td>
|
|
865
|
+
<td class="${w}">${f}</td>
|
|
866
|
+
<td title="${m(new Date(d.updatedAt).toISOString())}">${ja(d.updatedAt)}</td>
|
|
867
|
+
<td>${x}</td>
|
|
868
|
+
</tr>`}).join("")}function k(){p?(s.textContent=o("workflow.list.error",{error:p}),s.classList.add("error")):(s.textContent=o("workflow.list.loaded",{count:a.length,time:new Date().toLocaleTimeString()}),s.classList.remove("error"))}async function u(){if(!(v||l)&&!document.hidden){l=!0;try{let $=n.elements.namedItem("status")?.value??"",d=new URLSearchParams;$==="all"?d.set("all","1"):$&&d.set("status",$);let f="/api/workflows/runs"+(d.toString()?`?${d}`:""),w=await fetch(f);w.ok?(a=(await w.json()).runs??[],p=null):(p=`HTTP ${w.status}`,a=[])}catch($){p=$?.message??String($),a=[]}finally{l=!1,v||(h(),k())}}}function E(){i!==null&&window.clearTimeout(i),i=window.setTimeout(async()=>{await u(),v||E()},Na)}function B(){document.hidden||u()}return n.addEventListener("input",()=>{h()}),n.addEventListener("change",$=>{$.target.getAttribute("name")==="status"&&u()}),document.addEventListener("visibilitychange",B),u().then(()=>{v||E()}),()=>{v=!0,i!==null&&window.clearTimeout(i),document.removeEventListener("visibilitychange",B)}}function _a(e,t,n={}){e.innerHTML=`
|
|
681
869
|
<div class="wf-detail-head">
|
|
682
|
-
<a class="btn-link" href="#/workflows">${
|
|
870
|
+
<a class="btn-link" href="#/workflows">${m(o("workflow.detail.back"))}</a>
|
|
683
871
|
<div>
|
|
684
|
-
<h2><code>${
|
|
685
|
-
<div id="wf-detail-subtitle" class="muted">${
|
|
872
|
+
<h2><code>${m(t)}</code></h2>
|
|
873
|
+
<div id="wf-detail-subtitle" class="muted">${m(o("workflow.detail.loading"))}</div>
|
|
686
874
|
</div>
|
|
687
|
-
<button id="wf-cancel-run" type="button" class="contrast" hidden>${
|
|
875
|
+
<button id="wf-cancel-run" type="button" class="contrast" hidden>${m(o("workflow.detail.cancel"))}</button>
|
|
688
876
|
<span id="wf-detail-refresh" class="muted"></span>
|
|
689
877
|
</div>
|
|
690
878
|
<section id="wf-detail-error" class="hint-warn" hidden></section>
|
|
@@ -693,20 +881,20 @@ ${Ft("manage")}
|
|
|
693
881
|
<section id="wf-dangling-panel"></section>
|
|
694
882
|
<section class="wf-panel">
|
|
695
883
|
<div class="wf-panel-title">
|
|
696
|
-
<h3>${
|
|
884
|
+
<h3>${m(o("workflow.detail.parallel"))}</h3>
|
|
697
885
|
<span id="wf-parallel-meta" class="muted"></span>
|
|
698
886
|
</div>
|
|
699
887
|
<div id="wf-parallel-view"></div>
|
|
700
888
|
</section>
|
|
701
889
|
<section class="wf-panel">
|
|
702
890
|
<div class="wf-panel-title">
|
|
703
|
-
<h3>${
|
|
891
|
+
<h3>${m(o("workflow.detail.nodes"))}</h3>
|
|
704
892
|
</div>
|
|
705
893
|
<div class="wf-table-scroll">
|
|
706
894
|
<table>
|
|
707
895
|
<thead><tr>
|
|
708
|
-
<th>${
|
|
709
|
-
<th>${
|
|
896
|
+
<th>${m(o("workflow.detail.node"))}</th><th>${m(o("workflow.detail.nodeStatus"))}</th><th>${m(o("workflow.detail.activity"))}</th><th>${m(o("workflow.detail.activityStatus"))}</th>
|
|
897
|
+
<th>${m(o("workflow.detail.attempts"))}</th><th>${m(o("workflow.detail.current"))}</th><th>${m(o("workflow.detail.detail"))}</th>
|
|
710
898
|
</tr></thead>
|
|
711
899
|
<tbody id="wf-node-tbody"></tbody>
|
|
712
900
|
</table>
|
|
@@ -714,265 +902,269 @@ ${Ft("manage")}
|
|
|
714
902
|
</section>
|
|
715
903
|
<section class="wf-panel">
|
|
716
904
|
<div class="wf-panel-title">
|
|
717
|
-
<h3>${
|
|
905
|
+
<h3>${m(o("workflow.detail.nodeIO"))}</h3>
|
|
718
906
|
</div>
|
|
719
907
|
<div id="wf-io-list" class="wf-io-list"></div>
|
|
720
908
|
</section>
|
|
721
909
|
<section class="wf-panel">
|
|
722
910
|
<div class="wf-panel-title">
|
|
723
|
-
<h3>${
|
|
724
|
-
<button id="wf-load-older" type="button" hidden>${
|
|
911
|
+
<h3>${m(o("workflow.detail.timeline"))}</h3>
|
|
912
|
+
<button id="wf-load-older" type="button" hidden>${m(o("workflow.detail.loadOlder"))}</button>
|
|
725
913
|
</div>
|
|
726
914
|
<div class="wf-table-scroll wf-timeline-scroll">
|
|
727
915
|
<table>
|
|
728
916
|
<thead><tr>
|
|
729
|
-
<th>${
|
|
917
|
+
<th>${m(o("workflow.detail.seq"))}</th><th>${m(o("workflow.detail.event"))}</th><th>${m(o("workflow.detail.actor"))}</th><th>${m(o("workflow.detail.node"))}</th><th>${m(o("workflow.detail.activity"))}</th><th>${m(o("workflow.detail.error"))}</th><th>${m(o("workflow.detail.time"))}</th>
|
|
730
918
|
</tr></thead>
|
|
731
919
|
<tbody id="wf-event-tbody"></tbody>
|
|
732
920
|
</table>
|
|
733
921
|
</div>
|
|
734
922
|
<div id="wf-event-meta" class="muted"></div>
|
|
735
923
|
</section>
|
|
736
|
-
`;let s=e.querySelector("#wf-detail-subtitle"),a=e.querySelector("#wf-detail-refresh"),
|
|
737
|
-
<span class="muted error">${
|
|
738
|
-
</div>`}function
|
|
924
|
+
`;let s=e.querySelector("#wf-detail-subtitle"),a=e.querySelector("#wf-detail-refresh"),i=e.querySelector("#wf-detail-error"),l=e.querySelector("#wf-cancel-status"),p=e.querySelector("#wf-summary"),v=e.querySelector("#wf-dangling-panel"),y=e.querySelector("#wf-parallel-view"),h=e.querySelector("#wf-parallel-meta"),k=e.querySelector("#wf-node-tbody"),u=e.querySelector("#wf-io-list"),E=e.querySelector(".wf-timeline-scroll"),B=e.querySelector("#wf-event-tbody"),$=e.querySelector("#wf-event-meta"),d=e.querySelector("#wf-cancel-run"),f=e.querySelector("#wf-load-older"),w=null,T=[],x=new Set,M=null,H=null,O=!1,z=0,j=null,ee=!1,ae=!1,Z=!1,J=new Set,se=new Map,Me=new Map,ye=new Map,ie=new Set,re=new Map,te=new Set,pe=new Map,Q=new Map,ve=0,ke=n.focusAttemptId;function V(b){if(!b){i.hidden=!0,i.textContent="";return}i.hidden=!1,i.textContent=b}function c(b){if(!b){l.hidden=!0,l.textContent="";return}l.hidden=!1,l.textContent=b}async function g(){let b=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/snapshot`);if(b.status===404)throw new Error(o("workflow.detail.unknownRun"));if(!b.ok)throw new Error(o("workflow.detail.snapshotHttp",{status:b.status}));w=await b.json()}async function S(b){let R=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/events?${b}`);if(R.status===404)throw new Error(o("workflow.detail.unknownRun"));if(!R.ok)throw new Error(o("workflow.detail.eventsHttp",{status:R.status}));return await R.json()}function L(b,R){let D=b.filter(A=>x.has(A.eventId)?!1:(x.add(A.eventId),!0));D.length!==0&&(T=R==="prepend"?[...D,...T]:[...T,...D],T.sort((A,ne)=>Xe(A.eventId)-Xe(ne.eventId)))}async function I(){await g();let b=await S(new URLSearchParams({tail:"100"}));T=[],x=new Set,L(b.events,"append"),M=b.oldestSeq,H=b.newestSeq,O=b.hasOlder,z=b.totalCount,U()}async function P(){if(!(ee||ae||document.hidden)){ae=!0;try{if(await g(),H!==null){let b=await S(new URLSearchParams({afterSeq:String(H),limit:"200"}));L(b.events,"append"),b.newestSeq!==null&&(H=b.newestSeq),M===null&&b.oldestSeq!==null&&(M=b.oldestSeq),z=b.totalCount}else{let b=await S(new URLSearchParams({tail:"1"}));L(b.events,"append"),M=b.oldestSeq,H=b.newestSeq,O=b.hasOlder,z=b.totalCount}V(null),U()}catch(b){V(b?.message??String(b))}finally{ae=!1}}}async function q(){if(!(M===null||!O)){f.disabled=!0;try{let b=await S(new URLSearchParams({beforeSeq:String(M),limit:"100"}));L(b.events,"prepend"),b.oldestSeq!==null&&(M=b.oldestSeq),O=b.hasOlder,z=b.totalCount,V(null),U()}catch(b){V(b?.message??String(b))}finally{f.disabled=!1}}}async function X(){if(!w||Qe.has(w.run.status)||Z)return;if(!w.chatBinding?.larkAppId){V(o("workflow.detail.cancelUnavailable",{runId:t}));return}let b=Ga(w),R=o("workflow.detail.cancelConfirm",{runId:t,...b});if(window.confirm(R)){Z=!0,d.disabled=!0;try{let D=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/cancel`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"cancelled via dashboard"})});if(D.status===401)throw new Error(o("workflow.detail.writeAccessCancel"));let A=await D.json().catch(()=>({}));if(!D.ok||!A.ok)throw new Error(A.hint??A.error??o("workflow.detail.cancelHttp",{status:D.status}));c(A.pending?o("workflow.detail.cancelPending"):null),V(null),await P()}catch(D){V(D?.message??String(D))}finally{Z=!1,d.disabled=!1,U()}}}async function Y(b,R){if(!te.has(b)){te.add(b),pe.delete(b),U();try{let D=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/attempts/${encodeURIComponent(R)}/${encodeURIComponent(b)}/resume`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});if(D.status===401)throw new Error(o("workflow.detail.writeAccessResume"));let A=await D.json().catch(()=>({}));if(!D.ok||!A.ok||!A.resumeId||!A.url)throw new Error(A.hint??A.message??A.error??o("workflow.detail.resumeStartFailed",{status:D.status}));re.set(b,{resumeId:A.resumeId,url:A.url})}catch(D){let A=D?.message??String(D);pe.set(b,A)}finally{te.delete(b),U()}}}async function on(b,R){if(!te.has(b)){te.add(b),pe.delete(b),U();try{let D=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/attempts/${encodeURIComponent(R)}/${encodeURIComponent(b)}/resume/end`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"ended_by_dashboard"})});if(D.status===401)throw new Error(o("workflow.detail.writeAccessResume"));let A=await D.json().catch(()=>({}));if(!D.ok||!A.ok)if(A.error==="resume_not_running")re.delete(b);else throw new Error(A.hint??A.message??A.error??o("workflow.detail.resumeEndFailed",{status:D.status}));else re.delete(b)}catch(D){let A=D?.message??String(D);pe.set(b,A)}finally{te.delete(b),U()}}}async function K(b,R){if(!ie.has(b)){ie.add(b),ye.delete(b),U();try{let D=Me.get(b)?.trim()||void 0,A=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/${R}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({comment:D})});if(A.status===401)throw new Error(o("workflow.detail.writeAccessApproval"));let ne=await A.json().catch(()=>({}));if(!A.ok||!ne.ok)throw new Error(ne.hint??ne.message??ne.error??o("workflow.detail.actionHttp",{action:R,status:A.status}));let vt=R==="approve"?o("workflow.detail.approved"):o("workflow.detail.rejected");ye.set(b,{kind:"ok",text:ne.alreadyTerminal?o("workflow.detail.alreadyTerminal",{label:vt}):ne.pending?o("workflow.detail.workflowContinue",{label:vt}):o("workflow.detail.workflowRefreshing",{label:vt})}),V(null),await P()}catch(D){let A=D?.message??String(D);ye.set(b,{kind:"error",text:A}),V(A)}finally{ie.delete(b),U()}}}function U(){if(!w)return;ve=E.scrollTop;let b=w.run;Qe.has(b.status)&&c(null),s.innerHTML=`${m(b.workflowId??"?")} \xB7 ${Se(b.status)} \xB7 lastSeq ${w.lastSeq}`,a.textContent=o("workflow.detail.refreshed",{time:new Date().toLocaleTimeString()}),d.hidden=Qe.has(b.status),d.disabled=Z||!w.chatBinding?.larkAppId,d.textContent=w.chatBinding?.larkAppId?o("workflow.detail.cancel"):o("workflow.detail.cliCancelOnly"),d.title=w.chatBinding?.larkAppId?o("workflow.detail.cancelTitle"):o("workflow.detail.cliCancelTitle",{runId:t}),Fa(p,w),Ja(v,w),Ka(y,h,w,T),es(k,w),ts(u,w,J,se,{comments:Me,statuses:ye,resolving:ie,onResolve:K},{sessions:re,pending:te,errors:pe,onStart:Y,onEnd:on},ke,Q)&&(ke=void 0),Es(B,T),E.scrollTop=ve,f.hidden=!O,$.textContent=o("workflow.detail.eventsLoaded",{loaded:T.length,total:z})}function N(){if(j!==null&&window.clearTimeout(j),w&&Qe.has(w.run.status)){j=null;return}j=window.setTimeout(async()=>{await P(),ee||N()},Ua)}function _(){document.hidden||P().then(()=>{!ee&&j===null&&N()})}return f.addEventListener("click",()=>{q()}),d.addEventListener("click",()=>{X()}),document.addEventListener("visibilitychange",_),I().then(()=>{V(null),ee||N()}).catch(b=>{V(b?.message??String(b)),s.textContent=o("workflow.detail.loadFailed")}),()=>{ee=!0,j!==null&&window.clearTimeout(j),document.removeEventListener("visibilitychange",_)}}function Fa(e,t){let n=t.run,s=[[o("workflow.summary.workflow"),m(n.workflowId??"?")],[o("workflow.summary.status"),Se(n.status)],[o("workflow.summary.lastSeq"),String(t.lastSeq)],[o("workflow.summary.updated"),m(new Date(t.updatedAt).toLocaleString())],[o("workflow.summary.revision"),m(bt(n.revisionId))],[o("workflow.summary.initiator"),m(n.initiator??"-")]];n.failedNodeId&&s.push([o("workflow.summary.failedNode"),m(n.failedNodeId)]),n.cancelOriginEventId&&s.push([o("workflow.summary.cancelOrigin"),m(n.cancelOriginEventId)]),t.chatBinding&&(s.push([o("workflow.summary.chat"),`<code>${m(t.chatBinding.chatId)}</code>`]),s.push([o("workflow.summary.app"),`<code>${m(t.chatBinding.larkAppId)}</code>`])),e.innerHTML=s.map(([a,i])=>`<div class="wf-summary-item"><span>${a}</span><strong>${i}</strong></div>`).join("")}function Wa(e){if(!e.errorCode)return"";let t=e.errorMessage?` \u2014 ${Cs(e.errorMessage,96)}`:"";return`<div class="wf-run-error">
|
|
925
|
+
<span class="muted error">${m(e.errorCode)}</span>${m(t)}
|
|
926
|
+
</div>`}function Ga(e){let t=e.dangling;return{total:new Set([...t.activities,...t.effectAttempted,...t.waits,...t.cancels]).size,effects:t.effectAttempted.length,activities:t.activities.length,waits:t.waits.length,cancels:t.cancels.length}}function Ja(e,t){let n=t.dangling,s=[[o("workflow.dangling.activities"),n.activities],[o("workflow.dangling.effects"),n.effectAttempted],[o("workflow.dangling.waits"),n.waits],[o("workflow.dangling.cancels"),n.cancels]],a=new Set(s.flatMap(([,i])=>i)).size;if(e.className=a>0?"wf-panel wf-dangling-panel has":"wf-panel wf-dangling-panel",a===0){e.innerHTML=`<div class="wf-panel-title"><h3>${m(o("workflow.detail.dangling"))}</h3></div><div class="muted">${m(o("workflow.detail.noDangling"))}</div>`;return}e.innerHTML=`<div class="wf-panel-title"><h3>${m(o("workflow.detail.dangling"))}</h3><span class="wf-dangling has">${a}</span></div>
|
|
739
927
|
<div class="wf-dangling-grid">
|
|
740
|
-
${s.map(([
|
|
741
|
-
</div>`}function
|
|
742
|
-
<span title="${
|
|
743
|
-
<span title="${
|
|
928
|
+
${s.map(([i,l])=>`<div><strong>${i}</strong>${l.length===0?`<div class="muted">${m(o("workflow.detail.none"))}</div>`:`<ul>${l.map(p=>`<li><code>${m(p)}</code></li>`).join("")}</ul>`}</div>`).join("")}
|
|
929
|
+
</div>`}function Ka(e,t,n,s){let a=Va(s,n);if(a.length===0){t.textContent="",e.innerHTML=`<div class="empty">${m(o("workflow.detail.noParallelData"))}</div>`;return}let i=Date.now(),l=Math.min(...a.map(u=>u.startedAt)),p=Math.max(...a.map(u=>u.endedAt??i),l+1e3),v=Math.max(1,p-l),y=Qa(a,i),h=a.filter(u=>!u.endedAt&&(u.status==="running"||u.status==="effectAttempting")).length;t.textContent=o("workflow.detail.parallelMeta",{count:a.length,max:y,running:h});let k=a.sort((u,E)=>u.startedAt-E.startedAt||u.activityId.localeCompare(E.activityId)).map(u=>Ya(u,l,v,i)).join("");e.innerHTML=`<div class="wf-parallel-axis">
|
|
930
|
+
<span title="${m(new Date(l).toISOString())}">${m(gt(l))}</span>
|
|
931
|
+
<span title="${m(new Date(p).toISOString())}">${m(gt(p))}</span>
|
|
744
932
|
</div>
|
|
745
|
-
<div class="wf-parallel-list">${
|
|
933
|
+
<div class="wf-parallel-list">${k}</div>`}function Va(e,t){let n=new Map,s=new Map(t.activities.map(a=>[a.activityId,a.ownerNodeId]));for(let a of[...e].sort((i,l)=>Xe(i.eventId)-Xe(l.eventId))){let i=Hs(a);if(!i)continue;let l=typeof i.activityId=="string"?i.activityId:void 0,p=typeof i.attemptId=="string"?i.attemptId:void 0;if(!l||!p)continue;let v=n.get(p);if(a.type==="attemptCreated"){let y=typeof i.attemptNumber=="number"?i.attemptNumber:void 0;v={nodeId:typeof i.nodeId=="string"?i.nodeId:s.get(l),activityId:l,attemptId:p,attemptNumber:y,status:"pending",startedAt:a.timestamp},n.set(p,v);continue}v||(v={nodeId:s.get(l),activityId:l,attemptId:p,status:"pending",startedAt:a.timestamp},n.set(p,v)),a.type==="activityRunning"?(v.status="running",v.runningAt=a.timestamp):a.type==="effectAttempted"?v.status="effectAttempting":a.type==="activityWaiting"||a.type==="waitCreated"?v.status="waiting":Xa(a.type)&&(v.status=Za(a.type),v.endedAt=a.timestamp,v.endType=a.type)}return[...n.values()]}function Ya(e,t,n,s){let a=e.endedAt??s,i=no((e.startedAt-t)/n*100,0,100),l=no((Math.max(a,e.startedAt+1)-e.startedAt)/n*100,.7,100-i),p=e.nodeId??e.activityId,v=e.attemptNumber!==void 0?`#${e.attemptNumber}`:bt(e.attemptId),y=[`${p} ${e.status}`,`${new Date(e.startedAt).toISOString()} \u2192 ${e.endedAt?new Date(e.endedAt).toISOString():o("workflow.detail.parallelNow")}`,e.endType?`end: ${e.endType}`:void 0].filter(Boolean).join(`
|
|
746
934
|
`);return`<div class="wf-parallel-row">
|
|
747
935
|
<div class="wf-parallel-label">
|
|
748
|
-
<code>${
|
|
749
|
-
<span class="muted">${
|
|
936
|
+
<code>${m(p)}</code>
|
|
937
|
+
<span class="muted">${m(e.activityId)} \xB7 ${m(v)}</span>
|
|
750
938
|
</div>
|
|
751
939
|
<div class="wf-parallel-track">
|
|
752
|
-
<div class="wf-parallel-bar wf-parallel-${
|
|
753
|
-
<span>${
|
|
940
|
+
<div class="wf-parallel-bar wf-parallel-${m(e.status)}" style="left:${i.toFixed(3)}%;width:${l.toFixed(3)}%;" title="${m(y)}">
|
|
941
|
+
<span>${m(xe(e.status))}</span>
|
|
754
942
|
</div>
|
|
755
943
|
</div>
|
|
756
|
-
</div>`}function
|
|
757
|
-
<td>${e?`<code>${
|
|
758
|
-
<td>${e?
|
|
759
|
-
<td>${t?`<code>${
|
|
760
|
-
<td>${t?
|
|
944
|
+
</div>`}function Qa(e,t){let n=[];for(let i of e)n.push({time:i.startedAt,delta:1}),n.push({time:i.endedAt??t,delta:-1});n.sort((i,l)=>i.time-l.time||l.delta-i.delta);let s=0,a=0;for(let i of n)s+=i.delta,a=Math.max(a,s);return a}function Xa(e){return e==="activitySucceeded"||e==="activityFailed"||e==="activityTimedOut"||e==="activityCanceled"}function Za(e){return e==="activitySucceeded"?"succeeded":e==="activityCanceled"?"cancelled":e==="activityTimedOut"?"timedOut":"failed"}function es(e,t){let n=new Map(t.activities.map(i=>[i.activityId,i])),s=new Set,a=[];for(let i of t.nodes){let l=(i.activityId?n.get(i.activityId):void 0)??t.activities.find(p=>p.ownerNodeId===i.nodeId);l&&s.add(l.activityId),a.push(eo(i,l))}for(let i of t.activities)s.has(i.activityId)||a.push(eo(void 0,i));e.innerHTML=a.length>0?a.join(""):`<tr><td colspan="7" class="empty">${m(o("workflow.detail.noNodes"))}</td></tr>`}function eo(e,t){let n=t?.attempts[t.attempts.length-1];return`<tr>
|
|
945
|
+
<td>${e?`<code>${m(e.nodeId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
946
|
+
<td>${e?Se(e.status):'<span class="muted">-</span>'}</td>
|
|
947
|
+
<td>${t?`<code>${m(t.activityId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
948
|
+
<td>${t?Se(t.status):'<span class="muted">-</span>'}</td>
|
|
761
949
|
<td>${t?.attempts.length??0}</td>
|
|
762
|
-
<td>${
|
|
763
|
-
<td>${
|
|
764
|
-
</tr>`}function
|
|
950
|
+
<td>${n?`<code>${m(n.attemptId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
951
|
+
<td>${n?Ls(n):`<span class="muted">${m(o("workflow.detail.idle"))}</span>`}</td>
|
|
952
|
+
</tr>`}function ts(e,t,n,s,a,i,l,p){vs(e,n,s),bs(e,a.comments);let v=!!(l&&t.attemptIO?.[l]?.terminal);v&&l&&n.add(Jt(l,o("workflow.detail.liveTerminal")));let y=ns(t),h=new Set;if(p){for(let u of y){h.add(u.key);let E=p.get(u.key);E||(E=os(u.key),p.set(u.key,E),e.appendChild(E.article)),as(E,u,n,a,i,l)}for(let[u,E]of Array.from(p))h.has(u)||(E.article.remove(),p.delete(u));if(y.length===0){if(!e.querySelector(".wf-io-empty-placeholder")){let u=document.createElement("div");u.className="empty wf-io-empty-placeholder",u.textContent=o("workflow.detail.noNodeIO"),e.appendChild(u)}}else e.querySelector(".wf-io-empty-placeholder")?.remove()}else{let u=[];for(let E of y)u.push(ds(E,n,a,i,l));e.innerHTML=u.length>0?u.join(""):`<div class="empty">${m(o("workflow.detail.noNodeIO"))}</div>`}$s(e,s);let k=ys(e,l);return ks(e,n),Ss(e,s),ws(e,a),mo(e,i),k&&v}function ns(e){let t=new Map(e.activities.map(a=>[a.activityId,a])),n=new Set,s=[];for(let a of e.nodes){let i=(a.activityId?t.get(a.activityId):void 0)??e.activities.find(l=>l.ownerNodeId===a.nodeId);if(!i){s.push({key:`node:${a.nodeId}`,node:a});continue}n.add(i.activityId),s.push({key:`activity:${i.activityId}`,node:a,activity:i,io:e.attemptIO?.[ft(i)?.attemptId??""]})}for(let a of e.activities)n.has(a.activityId)||s.push({key:`activity:${a.activityId}`,activity:a,io:e.attemptIO?.[ft(a)?.attemptId??""]});return s}function os(e){let t=document.createElement("article");t.className="wf-io-card",t.dataset.wfCardKey=e;let n=document.createElement("div");n.className="wf-io-card-head";let s=document.createElement("div");s.className="wf-io-terminal-slot";let a=document.createElement("div");return a.className="wf-io-grid",t.appendChild(n),t.appendChild(s),t.appendChild(a),{article:t,head:n,terminalSlot:s,grid:a,currentTerminalUrl:null}}function as(e,t,n,s,a,i){let l=ft(t.activity),p=t.node?.nodeId??t.activity?.ownerNodeId??t.activity?.activityId??"unknown",v=!!(l&&l.attemptId===i);e.article.classList.toggle("is-focused",v),l?e.article.dataset.wfAttemptCard=l.attemptId:delete e.article.dataset.wfAttemptCard;let y=po(l,s);e.head.innerHTML=`
|
|
765
953
|
<header>
|
|
766
954
|
<div>
|
|
767
|
-
<strong><code>${
|
|
768
|
-
<span class="muted">${t.activity?
|
|
955
|
+
<strong><code>${m(p)}</code></strong>
|
|
956
|
+
<span class="muted">${t.activity?m(t.activity.activityId):m(o("workflow.detail.notDispatched"))}</span>
|
|
769
957
|
</div>
|
|
770
|
-
<div>${t.node?
|
|
958
|
+
<div>${t.node?Se(t.node.status):""} ${t.activity?Se(t.activity.status):""}</div>
|
|
771
959
|
</header>
|
|
772
960
|
<div class="wf-io-meta">
|
|
773
|
-
${
|
|
961
|
+
${l?`${m(o("workflow.detail.attempt"))} <code>${m(l.attemptId)}</code>`:m(o("workflow.detail.noAttempt"))}
|
|
774
962
|
</div>
|
|
775
|
-
${
|
|
776
|
-
`;let
|
|
777
|
-
${
|
|
778
|
-
${
|
|
779
|
-
${
|
|
780
|
-
${
|
|
781
|
-
${t.io?.waitPrompt?
|
|
782
|
-
`}function
|
|
783
|
-
<summary>${
|
|
963
|
+
${y}
|
|
964
|
+
`;let h=ao(l,t.activity,t.io?.terminal,a),k=h?.url??null;if(k!==e.currentTerminalUrl)h===null?e.terminalSlot.innerHTML="":e.terminalSlot.innerHTML=so(t.key,l,t.activity,t.io?.terminal,h,n,a),e.currentTerminalUrl=k;else if(h!==null&&t.io?.terminal){let E=e.terminalSlot.querySelector("details.wf-terminal-block > summary");if(E){let B=io(h.kind);E.innerHTML=`${m(B)} ${uo(l,t.io.terminal)}`}l&&hs(e.terminalSlot,l,t.activity,t.io.terminal,h,a)}let u=l?.attemptId??t.activity?.activityId??t.node?.nodeId??"unknown";e.grid.innerHTML=`
|
|
965
|
+
${we(u,o("workflow.detail.authoredInput"),t.io?.input,n)}
|
|
966
|
+
${we(u,o("workflow.detail.resolvedInput"),t.io?.resolvedInput,n)}
|
|
967
|
+
${we(u,o("workflow.detail.output"),t.io?.output,n)}
|
|
968
|
+
${we(u,o("workflow.detail.executionLog"),t.io?.log,n)}
|
|
969
|
+
${t.io?.waitPrompt?we(u,o("workflow.detail.waitPrompt"),t.io.waitPrompt,n):""}
|
|
970
|
+
`}function ao(e,t,n,s){if(!n||n.error)return null;if(cs(e,n))return{kind:"live",url:ps(n)};if(!e||!t||!us(e,n))return null;let a=fs();if(!a)return null;let i=s?.sessions.get(e.attemptId);return i?{kind:"resume",url:i.url,resumeId:i.resumeId,downloadUrl:to(a,t.activityId,e.attemptId)}:{kind:"replay",url:ms(a,t.activityId,e.attemptId,!!n.hasPtyLog),downloadUrl:to(a,t.activityId,e.attemptId)}}function so(e,t,n,s,a,i,l){if(!s)return"";let p=io(a.kind),v=Jt(e,p),y=uo(t,s),h=ss(a.kind),k=a.kind==="replay"||a.kind==="resume"?`<a class="btn-link" href="${m(a.downloadUrl)}" download>${m(o("workflow.detail.downloadFullLog"))}</a>`:"",u=t?lo(t,n,s,a,l):"",E=t?co(t.attemptId,l):"";return`<details class="wf-io-block wf-terminal-block" data-io-key="${m(v)}"${i.has(v)?" open":""}>
|
|
971
|
+
<summary>${m(p)} ${y}</summary>
|
|
784
972
|
<div class="wf-terminal-actions">
|
|
785
|
-
<a class="btn-link" href="${
|
|
786
|
-
${
|
|
787
|
-
${
|
|
973
|
+
<a class="btn-link" href="${m(a.url)}" target="_blank" rel="noreferrer">${m(h)}</a>
|
|
974
|
+
${k}
|
|
975
|
+
${u}
|
|
788
976
|
</div>
|
|
789
|
-
${
|
|
790
|
-
<iframe class="wf-terminal-frame" src="${
|
|
791
|
-
</details>`}function
|
|
977
|
+
${E}
|
|
978
|
+
<iframe class="wf-terminal-frame" src="${m(a.url)}" title="${m(p)}" loading="lazy"></iframe>
|
|
979
|
+
</details>`}function io(e){return e==="live"?o("workflow.detail.liveTerminal"):e==="resume"?o("workflow.detail.terminalResume"):o("workflow.detail.terminalReplay")}function ss(e){return e==="live"?o("workflow.detail.openTerminalNewTab"):e==="resume"?o("workflow.detail.openResumeNewTab"):o("workflow.detail.openReplayNewTab")}var ro=new Set(["antigravity","codex-app","cursor","mira"]),is=new Set(["aiden","coco","claude-code","seed","codex","mtr","hermes","pi"]);function rs(e){return!!e&&(is.has(e)||ro.has(e))}function ls(e){return!!e&&ro.has(e)}function lo(e,t,n,s,a){if(!a||s.kind==="live"||!t)return"";let i=s.kind==="resume",l=a.pending.has(e.attemptId),p=`data-wf-resume-attempt="${m(e.attemptId)}" data-wf-resume-activity="${m(t.activityId)}"`;return i?`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="end" ${p}${l?" disabled":""}>${m(l?o("workflow.detail.resumeEnding"):o("workflow.detail.endResumeSession"))}</button>`:rs(n.cliId)?ls(n.cliId)&&!n.cliSessionId?`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${m(o("workflow.detail.resumeMissingCliSession"))}">${m(o("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="start" ${p}${l?" disabled":""}>${m(l?o("workflow.detail.resumeStarting"):o("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${m(o("workflow.detail.resumeUnsupportedCli",{cliId:n.cliId??"?"}))}">${m(o("workflow.detail.resumeSession"))}</button>`}function co(e,t){if(!t)return"";let n=t.errors.get(e);return n?`<div class="hint-warn wf-resume-status" data-wf-resume-status="${m(e)}">${m(n)}</div>`:""}function ds(e,t,n,s,a){let i=ft(e.activity),l=e.node?.nodeId??e.activity?.ownerNodeId??e.activity?.activityId??"unknown",p=i?.attemptId??e.activity?.activityId??e.node?.nodeId??"unknown",v=po(i,n),y=i?.attemptId===a?" is-focused":"",h=i?` data-wf-attempt-card="${m(i.attemptId)}"`:"",k=ao(i,e.activity,e.io?.terminal,s),u=k?so(p,i,e.activity,e.io?.terminal,k,t,s):"";return`<article class="wf-io-card${y}" data-wf-card-key="${m(e.key)}"${h}>
|
|
792
980
|
<div class="wf-io-card-head">
|
|
793
981
|
<header>
|
|
794
982
|
<div>
|
|
795
|
-
<strong><code>${
|
|
796
|
-
<span class="muted">${e.activity?
|
|
983
|
+
<strong><code>${m(l)}</code></strong>
|
|
984
|
+
<span class="muted">${e.activity?m(e.activity.activityId):m(o("workflow.detail.notDispatched"))}</span>
|
|
797
985
|
</div>
|
|
798
|
-
<div>${e.node?
|
|
986
|
+
<div>${e.node?Se(e.node.status):""} ${e.activity?Se(e.activity.status):""}</div>
|
|
799
987
|
</header>
|
|
800
988
|
<div class="wf-io-meta">
|
|
801
|
-
${
|
|
989
|
+
${i?`${m(o("workflow.detail.attempt"))} <code>${m(i.attemptId)}</code>`:m(o("workflow.detail.noAttempt"))}
|
|
802
990
|
</div>
|
|
803
|
-
${
|
|
991
|
+
${v}
|
|
804
992
|
</div>
|
|
805
|
-
<div class="wf-io-terminal-slot">${
|
|
993
|
+
<div class="wf-io-terminal-slot">${u}</div>
|
|
806
994
|
<div class="wf-io-grid">
|
|
807
|
-
${
|
|
808
|
-
${
|
|
809
|
-
${
|
|
810
|
-
${
|
|
811
|
-
${e.io?.waitPrompt?
|
|
995
|
+
${we(p,o("workflow.detail.authoredInput"),e.io?.input,t)}
|
|
996
|
+
${we(p,o("workflow.detail.resolvedInput"),e.io?.resolvedInput,t)}
|
|
997
|
+
${we(p,o("workflow.detail.output"),e.io?.output,t)}
|
|
998
|
+
${we(p,o("workflow.detail.executionLog"),e.io?.log,t)}
|
|
999
|
+
${e.io?.waitPrompt?we(p,o("workflow.detail.waitPrompt"),e.io.waitPrompt,t):""}
|
|
812
1000
|
</div>
|
|
813
|
-
</article>`}function
|
|
1001
|
+
</article>`}function ft(e){return e?.attempts[e.attempts.length-1]}function uo(e,t){let n=[];return t.error?n.push(o("workflow.detail.error")):n.push(t.status==="live"?o("workflow.detail.terminalLive"):o("workflow.detail.terminalClosedShort")),e?.status&&n.push(e.status),t.webPort>0&&n.push(`:${t.webPort}`),`<span class="muted">${m(n.join(" \xB7 "))}</span>`}function cs(e,t){return t.status==="live"&&t.webPort>0&&(e?.status==="pending"||e?.status==="running"||e?.status==="effectAttempting")}function us(e,t){return e.status==="succeeded"||e.status==="failed"||e.status==="cancelled"||e.status==="timedOut"?!!(t.sessionId||t.startedAt):!1}function ps(e){return`http://${window.location.hostname||"127.0.0.1"}:${e.webPort}`}function ms(e,t,n,s){let a=new URLSearchParams({runId:e,activityId:t,attemptId:n});return s&&a.set("hasPtyLog","1"),`/assets/terminal-replay.html?${a.toString()}`}function to(e,t,n){return`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(t)}/${encodeURIComponent(n)}/terminal-log/raw?download=1`}function fs(){let e=window.location.hash.match(/^#\/workflows\/([^/?#]+)/);if(!e)return null;try{return decodeURIComponent(e[1])}catch{return null}}function po(e,t){if(!gs(e))return"";let n=e.attemptId,s=t.comments.get(n)??"",a=t.resolving.has(n),i=t.statuses.get(n),l=i?.kind==="error"?"hint-warn":"hint-ok";return`<div class="wf-approval-box" data-wf-approval="${m(n)}">
|
|
814
1002
|
<label>
|
|
815
|
-
<span>${
|
|
816
|
-
<textarea class="wf-approval-comment" data-wf-approval-comment="${
|
|
1003
|
+
<span>${m(o("workflow.detail.approvalComment"))}</span>
|
|
1004
|
+
<textarea class="wf-approval-comment" data-wf-approval-comment="${m(n)}" rows="2" placeholder="${m(o("workflow.detail.optionalComment"))}"${a?" disabled":""}>${m(s)}</textarea>
|
|
817
1005
|
</label>
|
|
818
1006
|
<div class="wf-approval-actions">
|
|
819
|
-
<button type="button" class="primary" data-wf-approval-action="approve" data-wf-attempt-id="${
|
|
820
|
-
<button type="button" data-wf-approval-action="reject" data-wf-attempt-id="${
|
|
821
|
-
${a?`<span class="muted">${
|
|
1007
|
+
<button type="button" class="primary" data-wf-approval-action="approve" data-wf-attempt-id="${m(n)}"${a?" disabled":""}>${m(o("workflow.detail.approve"))}</button>
|
|
1008
|
+
<button type="button" data-wf-approval-action="reject" data-wf-attempt-id="${m(n)}"${a?" disabled":""}>${m(o("workflow.detail.reject"))}</button>
|
|
1009
|
+
${a?`<span class="muted">${m(o("workflow.detail.submitting"))}</span>`:""}
|
|
822
1010
|
</div>
|
|
823
|
-
${
|
|
824
|
-
</div>`}function
|
|
825
|
-
<summary>${
|
|
826
|
-
${
|
|
827
|
-
</details>`}function
|
|
828
|
-
<td>${
|
|
829
|
-
<td><code>${
|
|
830
|
-
<td>${
|
|
831
|
-
<td>${t.nodeId?`<code>${
|
|
832
|
-
<td>${t.activityId?`<code>${
|
|
833
|
-
<td>${t.errorCode?`<span class="muted error">${
|
|
834
|
-
<td title="${
|
|
835
|
-
</tr>`}function
|
|
1011
|
+
${i?`<div class="${l} wf-approval-status">${m(i.text)}</div>`:""}
|
|
1012
|
+
</div>`}function gs(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function bs(e,t){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(n=>{let s=n.dataset.wfApprovalComment;s&&t.set(s,n.value)})}function mo(e,t){e.querySelectorAll("button[data-wf-resume-action][data-wf-resume-attempt][data-wf-resume-activity]").forEach(n=>{n.dataset.wfResumeBound!=="1"&&(n.dataset.wfResumeBound="1",n.addEventListener("click",()=>{let s=n.dataset.wfResumeAttempt,a=n.dataset.wfResumeActivity,i=n.dataset.wfResumeAction;!s||!a||(i==="start"?t.onStart(s,a):i==="end"&&t.onEnd(s,a))}))})}function hs(e,t,n,s,a,i){let l=e.querySelector(".wf-terminal-actions");if(!l)return;let p=l.querySelector('button[data-wf-resume-button="1"]'),v=lo(t,n,s,a,i);p?p.outerHTML=v:v&&l.insertAdjacentHTML("beforeend",v);let y=e.querySelector("details.wf-terminal-block");if(y){let h=y.querySelector(".wf-resume-status"),k=co(t.attemptId,i);h?h.outerHTML=k:k&&l.insertAdjacentHTML("afterend",k)}mo(e,i)}function ws(e,t){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(n=>{let s=n.dataset.wfApprovalComment;s&&n.addEventListener("input",()=>{t.comments.set(s,n.value)})}),e.querySelectorAll("button[data-wf-approval-action][data-wf-attempt-id]").forEach(n=>{n.addEventListener("click",()=>{let s=n.dataset.wfAttemptId,a=n.dataset.wfApprovalAction;!s||a!=="approve"&&a!=="reject"||t.onResolve(s,a)})})}function we(e,t,n,s){let a=Jt(e,t);return`<details class="wf-io-block" data-io-key="${m(a)}"${s.has(a)?" open":""}>
|
|
1013
|
+
<summary>${m(t)} ${Ts(n)}</summary>
|
|
1014
|
+
${Is(n)}
|
|
1015
|
+
</details>`}function Jt(e,t){return`${e}:${t}`}function ys(e,t){if(!t)return!1;for(let n of e.querySelectorAll("[data-wf-attempt-card]"))if(n.dataset.wfAttemptCard===t)return n.scrollIntoView({block:"center"}),!0;return!1}function vs(e,t,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(s=>{let a=s.dataset.ioKey;if(!a)return;s.open?t.add(a):t.delete(a);let i=s.querySelector(".wf-io-pre");i&&n.set(a,i.scrollTop)})}function ks(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(n=>{n.dataset.ioToggleBound!=="1"&&(n.dataset.ioToggleBound="1",n.addEventListener("toggle",()=>{let s=n.dataset.ioKey;s&&(n.open?t.add(s):t.delete(s))}))})}function $s(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(n=>{let s=n.dataset.ioKey;if(!s)return;let a=t.get(s);if(a===void 0)return;let i=n.querySelector(".wf-io-pre");i&&(i.scrollTop=a)})}function Ss(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(n=>{let s=n.dataset.ioKey;if(!s)return;let a=n.querySelector(".wf-io-pre");a&&a.dataset.ioScrollBound!=="1"&&(a.dataset.ioScrollBound="1",a.addEventListener("scroll",()=>{t.set(s,a.scrollTop)}))})}function Ts(e){if(!e)return`<span class="muted">${m(o("workflow.detail.empty"))}</span>`;let t=[];return e.outputBytes!==void 0&&t.push(`${e.outputBytes}B`),e.truncated&&t.push(o("workflow.detail.truncated")),e.error&&t.push(o("workflow.detail.error")),e.outputHash&&t.push(bt(e.outputHash)),t.length?`<span class="muted">${m(t.join(" \xB7 "))}</span>`:""}function Is(e){if(!e)return`<div class="muted wf-io-empty">${m(o("workflow.detail.noData"))}</div>`;let t=e.value!==void 0?JSON.stringify(e.value,null,2):e.text??"",n=e.error?`<div class="muted error">${m(e.error)}</div>`:"";return t?`${n}<pre class="wf-io-pre">${m(t)}</pre>`:`${n}<div class="muted wf-io-empty">${m(o("workflow.detail.noPreview"))}</div>`}function Ls(e){let t=[];if(e.effectAttempted&&t.push(`${m(o("workflow.detail.effect"))} ${m(e.effectAttempted.provider)}`),e.wait){let n=e.wait.resolution?`${e.wait.resolution.kind}${e.wait.resolution.resolution?":"+e.wait.resolution.resolution:""}`:o("workflow.detail.open");t.push(`${m(o("workflow.detail.wait"))} ${m(e.wait.waitKind)} ${m(n)}`),e.wait.deadlineAt!==void 0&&t.push(`${m(o("workflow.detail.deadline"))} ${m(gt(e.wait.deadlineAt))}`)}if(e.error){let n=`${e.error.errorCode}${e.error.errorClass?` \xB7 ${e.error.errorClass}`:""}`;t.push(`<span class="muted error">${m(n)}</span>`),e.error.errorMessage&&t.push(`<span class="error wf-error-msg">${m(e.error.errorMessage)}</span>`)}return e.output&&t.push(`${m(o("workflow.detail.output"))} ${m(bt(e.output.outputHash))}`),e.runningMs!==void 0&&t.push(`${e.runningMs}ms`),t.length>0?t.join("<br/>"):'<span class="muted">-</span>'}function Es(e,t){e.innerHTML=t.length>0?t.map(xs).join(""):`<tr><td colspan="7" class="empty">${m(o("workflow.detail.noEvents"))}</td></tr>`}function xs(e){let t=Ms(e.payload);return`<tr>
|
|
1016
|
+
<td>${Xe(e.eventId)}</td>
|
|
1017
|
+
<td><code>${m(e.type)}</code></td>
|
|
1018
|
+
<td>${m(e.actor)}</td>
|
|
1019
|
+
<td>${t.nodeId?`<code>${m(t.nodeId)}</code>`:"-"}</td>
|
|
1020
|
+
<td>${t.activityId?`<code>${m(t.activityId)}</code>`:"-"}</td>
|
|
1021
|
+
<td>${t.errorCode?`<span class="muted error">${m(t.errorCode)}</span>`:"-"}</td>
|
|
1022
|
+
<td title="${m(new Date(e.timestamp).toISOString())}">${m(gt(e.timestamp))}</td>
|
|
1023
|
+
</tr>`}function Xe(e){let t=e.lastIndexOf("-");if(t<0)return 0;let n=Number(e.slice(t+1));return Number.isFinite(n)?n:0}function Ms(e){if(!e||typeof e!="object"||"ref"in e)return{};let t=e,n={};typeof t.nodeId=="string"&&(n.nodeId=t.nodeId),typeof t.activityId=="string"&&(n.activityId=t.activityId),typeof t.failedNodeId=="string"&&(n.nodeId=t.failedNodeId);let s=t.error;return s&&typeof s=="object"&&"errorCode"in s&&(n.errorCode=String(s.errorCode)),n}function Hs(e){return!e.payload||typeof e.payload!="object"||"ref"in e.payload?null:e.payload}function no(e,t,n){return Math.min(n,Math.max(t,e))}function bt(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function Cs(e,t){return e.length>t?e.slice(0,t-1)+"\u2026":e}function gt(e){return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}function C(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function fo(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function go(e){let t=location.hash.match(/^#\/(?:workflows\/catalog|workflows-catalog)\/([^/?#]+)$/);return t?Ds(e,decodeURIComponent(t[1])):As(e)}function As(e){e.innerHTML=`
|
|
836
1024
|
<nav class="wf-subnav">
|
|
837
|
-
<a href="#/workflows" data-i18n="workflow.subnav.runs">${
|
|
838
|
-
<a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${
|
|
1025
|
+
<a href="#/workflows" data-i18n="workflow.subnav.runs">${C(o("workflow.subnav.runs"))}</a>
|
|
1026
|
+
<a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${C(o("workflow.subnav.catalog"))}</a>
|
|
839
1027
|
</nav>
|
|
840
1028
|
<section class="catalog-head">
|
|
841
1029
|
<div>
|
|
842
|
-
<h2>${
|
|
843
|
-
<p class="muted">${
|
|
1030
|
+
<h2>${C(o("catalog.title"))}</h2>
|
|
1031
|
+
<p class="muted">${C(o("catalog.subtitle"))}</p>
|
|
844
1032
|
</div>
|
|
845
|
-
<button id="catalog-refresh" type="button">${
|
|
1033
|
+
<button id="catalog-refresh" type="button">${C(o("catalog.refresh"))}</button>
|
|
846
1034
|
</section>
|
|
847
1035
|
<form id="catalog-filters" class="filters">
|
|
848
|
-
<input type="search" name="q" placeholder="${
|
|
1036
|
+
<input type="search" name="q" placeholder="${C(o("catalog.searchPlaceholder"))}" />
|
|
849
1037
|
<span id="catalog-status" class="muted"></span>
|
|
850
1038
|
</form>
|
|
851
1039
|
<div class="wf-table-scroll">
|
|
852
1040
|
<table>
|
|
853
1041
|
<thead><tr>
|
|
854
|
-
<th>${
|
|
855
|
-
<th>${
|
|
856
|
-
<th>${
|
|
857
|
-
<th>${
|
|
858
|
-
<th>${
|
|
859
|
-
<th>${
|
|
1042
|
+
<th>${C(o("catalog.table.workflow"))}</th>
|
|
1043
|
+
<th>${C(o("catalog.table.version"))}</th>
|
|
1044
|
+
<th>${C(o("catalog.table.params"))}</th>
|
|
1045
|
+
<th>${C(o("catalog.table.nodes"))}</th>
|
|
1046
|
+
<th>${C(o("catalog.table.revision"))}</th>
|
|
1047
|
+
<th>${C(o("catalog.table.path"))}</th>
|
|
860
1048
|
</tr></thead>
|
|
861
1049
|
<tbody id="catalog-tbody"></tbody>
|
|
862
1050
|
</table>
|
|
863
1051
|
</div>
|
|
864
|
-
`;let t=e.querySelector("#catalog-tbody"),
|
|
1052
|
+
`;let t=e.querySelector("#catalog-tbody"),n=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),a=e.querySelector("#catalog-refresh"),i=[],l=null,p=!1;function v(){let k=(new FormData(s).get("q")??"").trim().toLowerCase();return k?i.filter(u=>u.workflowId.toLowerCase().includes(k)||u.path.toLowerCase().includes(k)):i}function y(){l?(n.textContent=o("catalog.loadFailed",{error:l}),n.classList.add("error")):(n.textContent=`${i.length}`,n.classList.remove("error"));let k=v();if(k.length===0){t.innerHTML=`<tr><td colspan="6" class="empty">${i.length===0?C(o("catalog.noDefinitions")):C(o("catalog.noFilterMatch"))}</td></tr>`;return}t.innerHTML=k.map(u=>`
|
|
865
1053
|
<tr>
|
|
866
|
-
<td><a href="#/workflows/catalog/${encodeURIComponent(
|
|
867
|
-
<td>${
|
|
868
|
-
<td>${
|
|
869
|
-
<td>${
|
|
870
|
-
<td><code>${
|
|
871
|
-
<td><code>${
|
|
1054
|
+
<td><a href="#/workflows/catalog/${encodeURIComponent(u.workflowId)}"><code>${C(u.workflowId)}</code></a></td>
|
|
1055
|
+
<td>${u.version}</td>
|
|
1056
|
+
<td>${C(o("catalog.paramSummary",{required:u.requiredParamCount,total:u.paramCount}))}</td>
|
|
1057
|
+
<td>${u.nodeCount}</td>
|
|
1058
|
+
<td><code>${C(fo(u.revisionId))}</code></td>
|
|
1059
|
+
<td><code>${C(u.path)}</code></td>
|
|
872
1060
|
</tr>
|
|
873
|
-
`).join("")}async function
|
|
1061
|
+
`).join("")}async function h(){a.disabled=!0,n.textContent=o("catalog.loading");try{let k=await fetch("/api/workflows/definitions");if(!k.ok)throw new Error(`HTTP ${k.status}`);i=(await k.json()).definitions??[],l=null}catch(k){l=k?.message??String(k),i=[]}finally{a.disabled=!1,p||y()}}return s.addEventListener("input",y),a.addEventListener("click",()=>{h()}),h(),()=>{p=!0}}function Ds(e,t){e.innerHTML=`
|
|
874
1062
|
<div class="catalog-detail-head">
|
|
875
|
-
<a class="btn-link" href="#/workflows/catalog">${
|
|
1063
|
+
<a class="btn-link" href="#/workflows/catalog">${C(o("catalog.back"))}</a>
|
|
876
1064
|
<div>
|
|
877
|
-
<h2><code>${
|
|
878
|
-
<div id="catalog-detail-subtitle" class="muted">${
|
|
1065
|
+
<h2><code>${C(t)}</code></h2>
|
|
1066
|
+
<div id="catalog-detail-subtitle" class="muted">${C(o("workflow.detail.loading"))}</div>
|
|
879
1067
|
</div>
|
|
880
1068
|
</div>
|
|
881
1069
|
<section id="catalog-error" class="hint-warn" hidden></section>
|
|
882
1070
|
<section id="catalog-run-status" class="hint-ok" hidden></section>
|
|
883
1071
|
<div id="catalog-detail-body"></div>
|
|
884
|
-
`;let
|
|
1072
|
+
`;let n=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),a=e.querySelector("#catalog-run-status"),i=e.querySelector("#catalog-detail-body"),l=null,p=!1,v=!1;function y(d){s.hidden=!d,s.textContent=d??""}function h(d){a.hidden=!d,a.textContent=d??""}function k(d){let f={};for(let[w,T]of Object.entries(d??{}))"default"in T&&(f[w]=T.default);return f}function u(){if(!l)return;let d=l.definition;n.textContent=`${o("catalog.revision")} ${fo(l.revisionId)} \xB7 ${l.path}`;let f=JSON.stringify(k(d.params),null,2);i.innerHTML=`
|
|
885
1073
|
<section class="wf-panel">
|
|
886
|
-
<div class="wf-panel-title"><h3>${
|
|
1074
|
+
<div class="wf-panel-title"><h3>${C(o("catalog.summary"))}</h3></div>
|
|
887
1075
|
<div class="wf-summary-grid">
|
|
888
|
-
<div class="wf-summary-item"><span>${
|
|
889
|
-
<div class="wf-summary-item"><span>${
|
|
890
|
-
<div class="wf-summary-item"><span>${
|
|
891
|
-
<div class="wf-summary-item"><span>${
|
|
1076
|
+
<div class="wf-summary-item"><span>${C(o("catalog.table.workflow"))}</span><strong><code>${C(d.workflowId)}</code></strong></div>
|
|
1077
|
+
<div class="wf-summary-item"><span>${C(o("catalog.table.version"))}</span><strong>${d.version}</strong></div>
|
|
1078
|
+
<div class="wf-summary-item"><span>${C(o("catalog.nodeCount"))}</span><strong>${Object.keys(d.nodes).length}</strong></div>
|
|
1079
|
+
<div class="wf-summary-item"><span>${C(o("catalog.path"))}</span><strong><code>${C(l.path)}</code></strong></div>
|
|
892
1080
|
</div>
|
|
893
1081
|
</section>
|
|
894
1082
|
|
|
895
1083
|
<section class="wf-panel">
|
|
896
|
-
<div class="wf-panel-title"><h3>${
|
|
1084
|
+
<div class="wf-panel-title"><h3>${C(o("catalog.runPanel"))}</h3></div>
|
|
897
1085
|
<form id="catalog-run-form" class="catalog-run-form">
|
|
898
1086
|
<label>
|
|
899
|
-
<span>${
|
|
900
|
-
<textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${
|
|
1087
|
+
<span>${C(o("catalog.paramsJson"))}</span>
|
|
1088
|
+
<textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${C(o("catalog.paramsPlaceholder"))}">${C(f)}</textarea>
|
|
901
1089
|
</label>
|
|
902
1090
|
<div class="catalog-chat-grid">
|
|
903
1091
|
<label>
|
|
904
|
-
<span>${
|
|
1092
|
+
<span>${C(o("catalog.chatId"))}</span>
|
|
905
1093
|
<input id="catalog-chat-id" type="text" autocomplete="off" />
|
|
906
1094
|
</label>
|
|
907
1095
|
<label>
|
|
908
|
-
<span>${
|
|
1096
|
+
<span>${C(o("catalog.larkAppId"))}</span>
|
|
909
1097
|
<input id="catalog-lark-app-id" type="text" autocomplete="off" />
|
|
910
1098
|
</label>
|
|
911
1099
|
</div>
|
|
912
|
-
<div class="muted">${
|
|
1100
|
+
<div class="muted">${C(o("catalog.chatBindingHint"))}</div>
|
|
913
1101
|
<div id="catalog-param-errors" class="catalog-param-errors" hidden></div>
|
|
914
|
-
<button id="catalog-run-btn" type="submit" class="primary">${
|
|
1102
|
+
<button id="catalog-run-btn" type="submit" class="primary">${C(o("catalog.run"))}</button>
|
|
915
1103
|
</form>
|
|
916
1104
|
</section>
|
|
917
1105
|
|
|
918
1106
|
<section class="wf-panel">
|
|
919
|
-
<div class="wf-panel-title"><h3>${
|
|
920
|
-
${
|
|
1107
|
+
<div class="wf-panel-title"><h3>${C(o("catalog.paramsSchema"))}</h3></div>
|
|
1108
|
+
${Rs(d.params)}
|
|
921
1109
|
</section>
|
|
922
1110
|
|
|
923
1111
|
<section class="wf-panel">
|
|
924
|
-
<div class="wf-panel-title"><h3>${
|
|
925
|
-
<pre class="wf-io-pre">${
|
|
1112
|
+
<div class="wf-panel-title"><h3>${C(o("catalog.definitionJson"))}</h3></div>
|
|
1113
|
+
<pre class="wf-io-pre">${C(JSON.stringify(d,null,2))}</pre>
|
|
926
1114
|
</section>
|
|
927
|
-
`,
|
|
1115
|
+
`,B()}async function E(){if(!l||v)return;let d=i.querySelector("#catalog-params"),f=i.querySelector("#catalog-chat-id"),w=i.querySelector("#catalog-lark-app-id"),T=i.querySelector("#catalog-run-btn"),x=i.querySelector("#catalog-param-errors"),M;try{if(M=JSON.parse(d.value||"{}"),!M||typeof M!="object"||Array.isArray(M))throw new Error(o("catalog.badParamsJson"))}catch(H){x.hidden=!1,x.innerHTML=`<div class="muted error">${C(H?.message??String(H))}</div>`;return}v=!0,T.disabled=!0,T.textContent=o("catalog.running"),x.hidden=!0,y(null),h(null);try{let H=await fetch(`/api/workflows/definitions/${encodeURIComponent(l.definition.workflowId)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({params:M,chatBinding:{chatId:f.value.trim(),larkAppId:w.value.trim()}})});if(H.status===401)throw new Error(o("catalog.writeAccess"));let O=await H.json().catch(()=>({}));if(!H.ok||!O.ok)throw O.issues?.length&&(x.hidden=!1,x.innerHTML=`<strong>${C(o("catalog.invalidParams"))}</strong><ul>${O.issues.map(z=>`<li>${C(o("catalog.issue",{path:z.path.length?z.path.join("."):"(root)",message:z.message}))}</li>`).join("")}</ul>`),new Error(O.hint??O.message??O.error??o("catalog.runHttp",{status:H.status}));h(o("catalog.runStarted")),O.runId&&(location.hash=`#/workflows/${encodeURIComponent(O.runId)}`)}catch(H){y(H?.message??String(H))}finally{v=!1,T.disabled=!1,T.textContent=o("catalog.run")}}function B(){i.querySelector("#catalog-run-form")?.addEventListener("submit",f=>{f.preventDefault(),E()})}async function $(){try{let d=await fetch(`/api/workflows/definitions/${encodeURIComponent(t)}`);if(d.status===404)throw new Error("unknown_workflow");if(!d.ok)throw new Error(`HTTP ${d.status}`);l=await d.json(),y(null),u()}catch(d){y(o("catalog.definitionLoadFailed",{error:d?.message??String(d)})),n.textContent=o("workflow.detail.loadFailed")}}return $().then(()=>{}),()=>{p=!0}}function Rs(e){let t=Object.entries(e??{});return t.length===0?`<div class="muted">${C(o("catalog.noParams"))}</div>`:`<div class="catalog-param-list">${t.map(([n,s])=>`
|
|
928
1116
|
<article class="catalog-param">
|
|
929
1117
|
<header>
|
|
930
|
-
<code>${
|
|
931
|
-
<span class="wf-status">${
|
|
932
|
-
<span class="muted">${
|
|
1118
|
+
<code>${C(n)}</code>
|
|
1119
|
+
<span class="wf-status">${C(s.required?o("catalog.required"):o("catalog.optional"))}</span>
|
|
1120
|
+
<span class="muted">${C(s.type)}${s.format?` \xB7 ${C(s.format)}`:""}</span>
|
|
933
1121
|
</header>
|
|
934
|
-
${s.description?`<div class="muted">${
|
|
935
|
-
${"default"in s?`<pre class="wf-io-pre">${
|
|
1122
|
+
${s.description?`<div class="muted">${C(o("catalog.description"))}: ${C(s.description)}</div>`:""}
|
|
1123
|
+
${"default"in s?`<pre class="wf-io-pre">${C(`${o("catalog.default")}: ${JSON.stringify(s.default,null,2)}`)}</pre>`:""}
|
|
936
1124
|
</article>
|
|
937
|
-
`).join("")}</div>`}var
|
|
938
|
-
<img class="qr-image" src="${e.qrDataUrl}" alt="${
|
|
939
|
-
${e.qrUrl?`<a class="onboarding-link" href="${
|
|
1125
|
+
`).join("")}</div>`}var Re=null,ht=null;function et(){ht!==null&&(window.clearInterval(ht),ht=null)}function Vt(){return Re||(Re=document.createElement("dialog"),Re.className="onboarding-dialog",document.body.appendChild(Re),Re.addEventListener("close",et),Re)}function Os(e){return e.status==="waiting_for_scan"?o("botOnboarding.waiting"):e.status==="verifying"?o("botOnboarding.verifying"):e.status==="configuring_permissions"?e.permissionStatusMsg?`${o("botOnboarding.configuringPermissions")} ${e.permissionStatusMsg}`:o("botOnboarding.configuringPermissions"):e.status==="waiting_for_platform_scan"?o("botOnboarding.platformScanHint"):e.status==="completed"?o("botOnboarding.completed"):e.status==="failed"?`${o("botOnboarding.failed")}: ${r(e.message??e.error??"unknown")}`:o("botOnboarding.starting")}function qs(e){if(e.status!=="completed"||!e.permission)return"";let t=e.permission;if(t.ok){let s=[o("botOnboarding.permissionOk",{count:t.scopeCount??0})];t.skippedScopeCount&&t.skippedScopeCount>0&&s.push(o("botOnboarding.permissionSkipped",{count:t.skippedScopeCount})),t.versionId&&s.push(o("botOnboarding.permissionVersion",{version:r(t.versionId)}));let a=`<p class="hint-ok">\u2705 ${s.join(" ")}</p>`;return t.scopeWarning&&(a+=`<p class="hint-warn">\u26A0\uFE0F ${r(t.scopeWarning)}</p>`),a}let n=(e.remainingSteps??[]).map(s=>`<li><a href="${r(s.url)}" target="_blank" rel="noopener">${r(s.title)}</a></li>`).join("");return`<p class="hint-warn">\u26A0\uFE0F ${o("botOnboarding.permissionManual")}${t.message?`\uFF08${r(t.message)}\uFF09`:""}</p>`+(n?`<ol class="onboarding-steps">${n}</ol>`:"")}function Ze(e){let t=Vt(),n=e.status==="waiting_for_scan"&&e.qrDataUrl?`<div class="qr-card">
|
|
1126
|
+
<img class="qr-image" src="${e.qrDataUrl}" alt="${o("botOnboarding.qrAlt")}">
|
|
1127
|
+
${e.qrUrl?`<a class="onboarding-link" href="${r(e.qrUrl)}" target="_blank" rel="noopener">${o("botOnboarding.openLink")}</a>`:""}
|
|
940
1128
|
</div>`:"",s=e.status==="waiting_for_platform_scan"&&e.platformQrDataUrl?`<div class="qr-card">
|
|
941
|
-
<img class="qr-image" src="${e.platformQrDataUrl}" alt="${
|
|
942
|
-
</div>`:"",a=e.appId?`<p><b>App ID:</b> <code>${
|
|
1129
|
+
<img class="qr-image" src="${e.platformQrDataUrl}" alt="${o("botOnboarding.platformQrAlt")}">
|
|
1130
|
+
</div>`:"",a=e.appId?`<p><b>App ID:</b> <code>${r(e.appId)}</code>`+(e.cliId?` \uFF5C <b>CLI:</b> <code>${r(e.cliId)}</code>`:"")+(e.workingDir?` \uFF5C <b>${o("botOnboarding.metaDir")}:</b> <code>${r(e.workingDir)}</code>`:"")+"</p>":"",i=e.status==="completed"?`<p class="hint-ok">${o("botOnboarding.restartHint")}</p>`:"";t.innerHTML=`<article>
|
|
943
1131
|
<header>
|
|
944
|
-
<h3>${
|
|
945
|
-
<p>${
|
|
1132
|
+
<h3>${o("botOnboarding.title")}</h3>
|
|
1133
|
+
<p>${o("botOnboarding.intro")}</p>
|
|
946
1134
|
</header>
|
|
947
|
-
<p class="onboarding-status status-${e.status}">${
|
|
948
|
-
${
|
|
1135
|
+
<p class="onboarding-status status-${e.status}">${Os(e)}</p>
|
|
1136
|
+
${n}
|
|
949
1137
|
${s}
|
|
950
1138
|
${a}
|
|
951
|
-
${
|
|
952
|
-
${
|
|
953
|
-
<form method="dialog"><button>${
|
|
954
|
-
</article>`}async function
|
|
1139
|
+
${qs(e)}
|
|
1140
|
+
${i}
|
|
1141
|
+
<form method="dialog"><button>${o("botOnboarding.close")}</button></form>
|
|
1142
|
+
</article>`}async function Bs(){try{let e=await fetch("/api/cli-options"),t=await e.json();if(e.ok&&Array.isArray(t?.options))return t.options}catch{}return[{id:"claude-code",label:"Claude"}]}function Kt(e,t){let n=Vt(),s=e.map(p=>`<option value="${r(p.id)}">${r(p.label)}\uFF08${r(p.id)}\uFF09</option>`).join(""),a=t?`<p class="form-error">${r(t)}</p>`:"";n.innerHTML=`<article>
|
|
955
1143
|
<header>
|
|
956
|
-
<h3>${
|
|
957
|
-
<p>${
|
|
1144
|
+
<h3>${o("botOnboarding.title")}</h3>
|
|
1145
|
+
<p>${o("botOnboarding.intro")}</p>
|
|
958
1146
|
</header>
|
|
959
1147
|
<form id="onboarding-form" class="onboarding-form">
|
|
960
1148
|
<label class="onboarding-field">
|
|
961
|
-
<span>${
|
|
1149
|
+
<span>${o("botOnboarding.cliLabel")}</span>
|
|
962
1150
|
<select id="ob-cli">${s}</select>
|
|
963
1151
|
</label>
|
|
964
1152
|
<label class="onboarding-field">
|
|
965
|
-
<span>${
|
|
966
|
-
<input id="ob-dir" type="text" value="~" placeholder="${
|
|
1153
|
+
<span>${o("botOnboarding.dirLabel")}</span>
|
|
1154
|
+
<input id="ob-dir" type="text" value="~" placeholder="${o("botOnboarding.dirPlaceholder")}" autocomplete="off" spellcheck="false">
|
|
967
1155
|
</label>
|
|
968
1156
|
<label class="onboarding-field">
|
|
969
|
-
<span>${
|
|
970
|
-
<input id="ob-model" type="text" placeholder="${
|
|
1157
|
+
<span>${o("botOnboarding.modelLabel")}</span>
|
|
1158
|
+
<input id="ob-model" type="text" placeholder="${o("botOnboarding.modelPlaceholder")}" autocomplete="off" spellcheck="false">
|
|
971
1159
|
</label>
|
|
972
1160
|
${a}
|
|
973
1161
|
<menu class="onboarding-actions">
|
|
974
|
-
<button type="button" id="ob-cancel">${
|
|
975
|
-
<button type="submit" class="primary">${
|
|
1162
|
+
<button type="button" id="ob-cancel">${o("botOnboarding.cancel")}</button>
|
|
1163
|
+
<button type="submit" class="primary">${o("botOnboarding.startScan")}</button>
|
|
976
1164
|
</menu>
|
|
977
1165
|
</form>
|
|
978
|
-
</article>`;let
|
|
1166
|
+
</article>`;let i=n.querySelector("#onboarding-form");n.querySelector("#ob-cancel")?.addEventListener("click",()=>n.close()),i?.addEventListener("submit",p=>{p.preventDefault();let v=n.querySelector("#ob-cli")?.value??"",y=n.querySelector("#ob-dir")?.value??"",h=n.querySelector("#ob-model")?.value??"";Ps({cliId:v,workingDir:y,model:h},e)})}async function Ps(e,t){et(),Ze({id:"",status:"starting"});try{let n=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 n.json();if(n.status===400){Kt(t,s?.message??s?.error??"invalid_input");return}if(!n.ok||!s?.job?.id)throw new Error(s?.error??`http_${n.status}`);Ze(s.job),ht=window.setInterval(()=>{Ns(s.job.id).catch(a=>{et(),Ze({id:s.job.id,status:"failed",message:a instanceof Error?a.message:String(a)})})},1200)}catch(n){Ze({id:"",status:"failed",message:n instanceof Error?n.message:String(n)})}}async function Ns(e){let t=await fetch(`/api/bot-onboarding/${encodeURIComponent(e)}`),n=await t.json();if(!t.ok||!n?.job)throw new Error(n?.error??`http_${t.status}`);Ze(n.job),(n.job.status==="completed"||n.job.status==="failed")&&et()}async function Us(){et();let e=Vt();Kt([{id:"claude-code",label:"Claude"}]),e.open||e.showModal();let t=await Bs();e.open&&e.querySelector("#onboarding-form")&&Kt(t)}function bo(){let e=document.getElementById("add-bot-btn");e&&(e.onclick=()=>{Us()})}var js={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"/>'},wo=[{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"}]}],ho=wo.flatMap(e=>e.options),Oe=!1;function Yt(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">${js[e]??""}</svg>`}function zs(e){return e.replace(/[&<>"]/g,t=>({"&":"&","<":"<",">":">",'"':"""})[t])}function yo(){let e=document.getElementById("theme-menu"),t=document.getElementById("theme-menu-btn"),n=document.getElementById("theme-menu-pop");if(!e||!t||!n)return;n.innerHTML=wo.map(a=>`<div class="tm-group" data-label-key="${a.labelKey}"></div>`+a.options.map(i=>`<button type="button" class="tm-item" role="option" data-value="${i.value}"><span class="tm-ic">${Yt(i.icon)}</span><span class="tm-label" data-label-key="${i.labelKey}"></span></button>`).join("")).join("");let s=a=>{Oe=a,n.hidden=!Oe,t.setAttribute("aria-expanded",String(Oe)),e.classList.toggle("open",Oe)};t.addEventListener("click",a=>{a.stopPropagation(),s(!Oe)}),n.addEventListener("click",a=>{let i=a.target.closest(".tm-item");i&&(me.setTheme(i.dataset.value??"system"),s(!1))}),document.addEventListener("click",a=>{Oe&&!e.contains(a.target)&&s(!1)}),document.addEventListener("keydown",a=>{a.key==="Escape"&&Oe&&s(!1)}),Qt()}function Qt(){let e=document.getElementById("theme-menu-btn");if(!e)return;let t=ho.find(n=>n.value===me.theme)??ho[0];e.innerHTML=`<span class="tm-ic">${Yt(t.icon)}</span><span class="tm-current">${zs(o(t.labelKey))}</span><span class="tm-chev">${Yt("chevron")}</span>`,document.querySelectorAll("#theme-menu-pop [data-label-key]").forEach(n=>{n.textContent=o(n.dataset.labelKey??"")}),document.querySelectorAll("#theme-menu-pop .tm-item").forEach(n=>{n.classList.toggle("active",n.dataset.value===me.theme)})}var le=document.getElementById("root"),wt=!0,$o=!1,So=["roles","bot-defaults","team","connectors"],Xt=!1;function _s(){if(Xt)return;Xt=!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 t=()=>{e.remove(),Xt=!1};e.querySelector("#auth-expired-dismiss")?.addEventListener("click",t),e.addEventListener("click",n=>{n.target===e&&t()})}var Zt;function Fs(){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",Zt&&window.clearTimeout(Zt),Zt=window.setTimeout(()=>{e.style.display="none"},4e3)}var Ws=window.fetch.bind(window);window.fetch=async function(...t){let n=await Ws(...t);if(n.status===401){let s=(t[1]?.method??"GET").toUpperCase();(s==="GET"||s==="HEAD")&&!$o?_s():Fs()}return n};var en="";function yt(){let e=document.getElementById("attention-strip");if(!e)return;let t=[...G.sessions.values()].map(a=>({s:a,reason:Te(a)})).filter(a=>!!a.reason).sort((a,i)=>Number(a.s.lastMessageAt??0)-Number(i.s.lastMessageAt??0));if(t.length===0){e.hidden=!0,e.innerHTML="",en="";return}let n=t[0],s=`
|
|
1167
|
+
<span class="attention-strip-ic" aria-hidden="true">!</span>
|
|
1168
|
+
<b>${r(o("strip.pending",{count:t.length}))}</b>
|
|
1169
|
+
<span class="attention-strip-longest">${r(o("strip.longest",{time:ue(n.s.lastMessageAt),bot:fe(n.s),reason:n.reason}))}</span>
|
|
1170
|
+
<a class="attention-strip-go" href="#/sessions">${r(o("strip.handle"))}</a>`;e.hidden=!1,s!==en&&(en=s,e.innerHTML=s)}G.on(yt);Pe().then(yt);async function Gs(){try{let e=await fetch("/api/settings");if(e.ok){let t=await e.json();wt=!!t.authed,$o=!!(t.settings&&t.settings.publicReadOnly)}}catch{}}function Js(){for(let t of So){let n=document.querySelector(`.sidebar-nav a[data-route="${t}"]`);n&&(n.style.display=wt?"":"none")}let e=document.getElementById("add-bot-btn");e&&(e.style.display=wt?"":"none")}function Ks(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 / \u63A5\u5165\u70B9\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 tt=null;function vo(e){for(let t of document.querySelectorAll(".sidebar-nav a")){let n=t.getAttribute("href")??"#/";t.classList.toggle("active",n===(e||"#/"))}}function tn(){tt&&(tt(),tt=null);let e=location.hash||"#/";if(!wt&&So.some(t=>e.startsWith("#/"+t))){Ks(le),vo(e);return}e.startsWith("#/workflows/catalog")||e.startsWith("#/workflows-catalog")?tt=go(le):e.startsWith("#/workflows")?tt=oo(le):e.startsWith("#/groups")?On(le):e.startsWith("#/settings")?Zn(le):e.startsWith("#/bot-defaults")?Nn(le):e.startsWith("#/connectors")?Xn(le):e.startsWith("#/team/manage")?Vn(le):e.startsWith("#/team")?Kn(le):e.startsWith("#/roles")?_n(le):e.startsWith("#/schedules")?Dn(le):e.startsWith("#/sessions")?Cn(le):En(le),vo(e)}var nn=document.getElementById("status");function To(){nn&&(nn.textContent=G.online?o("status.live"):o("status.disconnected"),nn.className="connection-status "+(G.online?"online":"offline"))}G.on(To);function ko(){document.querySelectorAll("[data-i18n]").forEach(e=>{e.textContent=o(e.dataset.i18n??"")}),document.querySelectorAll("[data-locale]").forEach(e=>{e.classList.toggle("active",e.dataset.locale===me.locale)}),Qt(),To()}function Vs(){document.querySelectorAll("[data-locale]").forEach(e=>{e.onclick=()=>me.setLocale(e.dataset.locale)}),yo()}(async()=>{me.init(),Vs(),bo(),me.on(()=>{ko(),yt(),tn()}),ko(),yt(),await Gs(),Js();try{await an()}catch(e){console.error("botmux dashboard bootstrap failed",e),G.setOnline(!1)}window.addEventListener("hashchange",tn),tn()})();})();
|