botmux 2.54.0 → 2.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/backend/zellij-observe-backend.d.ts +15 -0
- package/dist/adapters/backend/zellij-observe-backend.d.ts.map +1 -1
- package/dist/adapters/backend/zellij-observe-backend.js +37 -0
- package/dist/adapters/backend/zellij-observe-backend.js.map +1 -1
- package/dist/adapters/cli/claude-code.d.ts +3 -3
- package/dist/adapters/cli/claude-code.js.map +1 -1
- package/dist/adapters/cli/codex.d.ts.map +1 -1
- package/dist/adapters/cli/codex.js +44 -28
- package/dist/adapters/cli/codex.js.map +1 -1
- package/dist/adapters/cli/seed.d.ts +1 -1
- package/dist/adapters/cli/seed.js +2 -2
- package/dist/adapters/cli/seed.js.map +1 -1
- package/dist/adapters/cli/types.d.ts +5 -1
- package/dist/adapters/cli/types.d.ts.map +1 -1
- package/dist/bot-registry.d.ts +8 -0
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +31 -5
- package/dist/bot-registry.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +250 -101
- package/dist/cli.js.map +1 -1
- package/dist/core/dispatch.d.ts +23 -0
- package/dist/core/dispatch.d.ts.map +1 -1
- package/dist/core/dispatch.js +17 -0
- package/dist/core/dispatch.js.map +1 -1
- package/dist/core/pending-response.d.ts +0 -6
- package/dist/core/pending-response.d.ts.map +1 -1
- package/dist/core/pending-response.js +0 -5
- package/dist/core/pending-response.js.map +1 -1
- package/dist/core/session-discovery.d.ts.map +1 -1
- package/dist/core/session-discovery.js +5 -0
- package/dist/core/session-discovery.js.map +1 -1
- package/dist/core/worker-pool.d.ts +26 -0
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +68 -1
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/dashboard/bot-onboarding.d.ts +46 -3
- package/dist/dashboard/bot-onboarding.d.ts.map +1 -1
- package/dist/dashboard/bot-onboarding.js +86 -7
- package/dist/dashboard/bot-onboarding.js.map +1 -1
- package/dist/dashboard/federated-group-core.js +8 -4
- package/dist/dashboard/federated-group-core.js.map +1 -1
- package/dist/dashboard/federation-api.d.ts.map +1 -1
- package/dist/dashboard/federation-api.js +22 -2
- package/dist/dashboard/federation-api.js.map +1 -1
- package/dist/dashboard/web/bot-onboarding.d.ts.map +1 -1
- package/dist/dashboard/web/bot-onboarding.js +139 -20
- package/dist/dashboard/web/bot-onboarding.js.map +1 -1
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +36 -6
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard-web/app.js +171 -143
- package/dist/dashboard-web/style.css +58 -0
- package/dist/dashboard.js +37 -1
- package/dist/dashboard.js.map +1 -1
- package/dist/global-config.d.ts +5 -0
- package/dist/global-config.d.ts.map +1 -1
- package/dist/global-config.js +17 -0
- package/dist/global-config.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +4 -0
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +4 -0
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/card-builder.d.ts +1 -1
- package/dist/im/lark/card-builder.js +1 -1
- package/dist/im/lark/card-handler.d.ts.map +1 -1
- package/dist/im/lark/card-handler.js +59 -10
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/client.d.ts +3 -1
- package/dist/im/lark/client.d.ts.map +1 -1
- package/dist/im/lark/client.js +7 -2
- package/dist/im/lark/client.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +8 -6
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/services/codex-paths.d.ts +7 -0
- package/dist/services/codex-paths.d.ts.map +1 -0
- package/dist/services/codex-paths.js +19 -0
- package/dist/services/codex-paths.js.map +1 -0
- package/dist/services/codex-transcript.d.ts.map +1 -1
- package/dist/services/codex-transcript.js +5 -4
- package/dist/services/codex-transcript.js.map +1 -1
- package/dist/services/voice/audio.d.ts +32 -0
- package/dist/services/voice/audio.d.ts.map +1 -0
- package/dist/services/voice/audio.js +114 -0
- package/dist/services/voice/audio.js.map +1 -0
- package/dist/services/voice/index.d.ts +32 -0
- package/dist/services/voice/index.d.ts.map +1 -0
- package/dist/services/voice/index.js +98 -0
- package/dist/services/voice/index.js.map +1 -0
- package/dist/services/voice/openai.d.ts +24 -0
- package/dist/services/voice/openai.d.ts.map +1 -0
- package/dist/services/voice/openai.js +47 -0
- package/dist/services/voice/openai.js.map +1 -0
- package/dist/services/voice/sami.d.ts +22 -0
- package/dist/services/voice/sami.d.ts.map +1 -0
- package/dist/services/voice/sami.js +128 -0
- package/dist/services/voice/sami.js.map +1 -0
- package/dist/services/voice/types.d.ts +32 -0
- package/dist/services/voice/types.d.ts.map +1 -0
- package/dist/services/voice/types.js +2 -0
- package/dist/services/voice/types.js.map +1 -0
- package/dist/setup/bot-config-editor.d.ts +9 -0
- package/dist/setup/bot-config-editor.d.ts.map +1 -1
- package/dist/setup/bot-config-editor.js +26 -0
- package/dist/setup/bot-config-editor.js.map +1 -1
- package/dist/setup/verify-permissions.js +3 -3
- package/dist/setup/verify-permissions.js.map +1 -1
- package/dist/skills/definitions.d.ts.map +1 -1
- package/dist/skills/definitions.js +0 -1
- package/dist/skills/definitions.js.map +1 -1
- package/dist/worker.js +33 -2
- package/dist/worker.js.map +1 -1
- package/dist/workflows/events/schema.d.ts +140 -140
- package/package.json +1 -1
|
@@ -1,28 +1,28 @@
|
|
|
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()}},W=new tt;async function yt(){let[e,t]=await Promise.all([fetch("/api/sessions").then(a=>a.json()),fetch("/api/schedules").then(a=>a.json())]);W.upsertSessions(e.sessions??[]),W.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);W.applySse(a,i.body??i)}catch{}});o.onerror=()=>W.setOnline(!1),o.onopen=()=>W.setOnline(!0)}var nt="botmux.dashboard.locale",gn={"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":"\u626B\u7801\u6DFB\u52A0\u673A\u5668\u4EBA","botOnboarding.intro":"\u7528\u98DE\u4E66 App \u626B\u7801\u521B\u5EFA PersonalAgent \u5E94\u7528\uFF0C\u6210\u529F\u540E\u4F1A\u5199\u5165\u672C\u673A bots.json\u3002","botOnboarding.starting":"\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801...","botOnboarding.waiting":"\u8BF7\u7528\u98DE\u4E66 App \u626B\u7801\u786E\u8BA4\u3002","botOnboarding.verifying":"\u626B\u7801\u6210\u529F\uFF0C\u6B63\u5728\u6821\u9A8C\u51ED\u8BC1...","botOnboarding.completed":"\u673A\u5668\u4EBA\u5DF2\u6DFB\u52A0\u3002","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
|
|
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
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
|
|
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"},wn={"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":"Scan to Add Bot","botOnboarding.intro":"Scan with the Feishu app to create a PersonalAgent app. The dashboard writes it to local bots.json after success.","botOnboarding.starting":"Generating QR code...","botOnboarding.waiting":"Scan with the Feishu app to continue.","botOnboarding.verifying":"Scan accepted. Verifying credentials...","botOnboarding.completed":"Bot added.","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.:
|
|
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
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}?
|
|
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"}
|
|
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
14
|
<div>
|
|
15
15
|
<strong>${l(e.title??e.sessionId)}</strong>
|
|
16
16
|
<span>${l(e.botName??"")} \xB7 ${l(e.cliId??"unknown")}</span>
|
|
17
17
|
</div>
|
|
18
|
-
<span class="${
|
|
19
|
-
</li>`}function
|
|
18
|
+
<span class="${$n(e.status)}">${l(e.status??"unknown")}</span>
|
|
19
|
+
</li>`}function Ln(e){let t=e.nextRunAt?new Date(e.nextRunAt).toLocaleString():"-";return`<li class="overview-list-row">
|
|
20
20
|
<div>
|
|
21
21
|
<strong>${l(e.name??e.id)}</strong>
|
|
22
22
|
<span>${l(e.botName??e.larkAppId??"")} \xB7 ${l(e.parsed?.display??"")}</span>
|
|
23
23
|
</div>
|
|
24
24
|
<span>${l(t)}</span>
|
|
25
|
-
</li>`}async function
|
|
25
|
+
</li>`}async function Et(e){e.innerHTML=`<section class="page hero-page">
|
|
26
26
|
<div class="page-heading">
|
|
27
27
|
<div>
|
|
28
28
|
<p class="eyebrow">${n("app.subtitle")}</p>
|
|
@@ -53,19 +53,19 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
53
53
|
<ul class="overview-list" id="next-schedules"></ul>
|
|
54
54
|
</section>
|
|
55
55
|
</div>
|
|
56
|
-
</section>`;let t=e.querySelector("#overview-metrics"),o=e.querySelector("#recent-sessions"),s=e.querySelector("#next-schedules");function a(){let r=[...
|
|
56
|
+
</section>`;let t=e.querySelector("#overview-metrics"),o=e.querySelector("#recent-sessions"),s=e.querySelector("#next-schedules");function a(){let r=[...z.sessions.values()],i=[...z.schedules.values()],m=r.filter(f=>f.status!=="closed"),$=r.filter(f=>f.status==="working"||f.status==="analyzing"||f.status==="starting"),L=i.filter(f=>f.enabled),y=st.bots?.length||new Set(r.map(f=>f.larkAppId).filter(Boolean)).size,v=[{label:n("overview.openSessions"),value:m.length,meta:`${r.length} ${n("overview.total")}`},{label:n("overview.workingSessions"),value:$.length,meta:`${m.length} ${n("overview.active")}`},{label:n("overview.onlineBots"),value:y,meta:n("overview.daemonRegistry")},{label:n("overview.schedules"),value:i.length,meta:`${L.length} ${n("overview.enabledSchedules")}`},{label:n("overview.groups"),value:st.chats?.length??0,meta:n("overview.chatMatrix")}];t.innerHTML=v.map(f=>`<article class="metric-card">
|
|
57
57
|
<span>${l(f.label)}</span>
|
|
58
58
|
<strong>${f.value}</strong>
|
|
59
59
|
<small>${l(f.meta)}</small>
|
|
60
|
-
</article>`).join("");let c=r.sort((f,g)=>Number(g.lastMessageAt??0)-Number(f.lastMessageAt??0)).slice(0,6);o.innerHTML=c.length?c.map(f
|
|
60
|
+
</article>`).join("");let c=r.sort((f,g)=>Number(g.lastMessageAt??0)-Number(f.lastMessageAt??0)).slice(0,6);o.innerHTML=c.length?c.map(f=>Sn({...f,title:f.title??`${Ae(f.lastMessageAt)} \xB7 ${f.sessionId}`})).join(""):`<li class="empty">${n("overview.noSessions")}</li>`;let I=i.filter(f=>f.nextRunAt).sort((f,g)=>Date.parse(f.nextRunAt)-Date.parse(g.nextRunAt)).slice(0,6);s.innerHTML=I.length?I.map(Ln).join(""):`<li class="empty">${n("overview.noSchedules")}</li>`}z.on(a),a(),kn().then(a)}function we(e,t){return`<th data-sort="${e}" data-label="${l(t)}">${l(t)}</th>`}var Mt=["claude-code","seed","codex","codex-app","cursor","gemini","opencode","mtr","hermes","mira","aiden","coco","unknown"];function Tn(){return`<div class="filter-check-group" role="group" aria-label="${n("sessions.cli")}">
|
|
61
61
|
<span class="filter-check-label">${n("sessions.cli")}</span>
|
|
62
|
-
${
|
|
62
|
+
${Mt.map(e=>`
|
|
63
63
|
<label class="filter-check">
|
|
64
64
|
<input type="checkbox" name="cli" value="${l(e)}" checked>
|
|
65
65
|
<span>${l(e)}</span>
|
|
66
66
|
</label>
|
|
67
67
|
`).join("")}
|
|
68
|
-
</div>`}function
|
|
68
|
+
</div>`}function In(){return`<section class="page">
|
|
69
69
|
<div class="page-heading">
|
|
70
70
|
<div>
|
|
71
71
|
<p class="eyebrow">${n("nav.sessions")}</p>
|
|
@@ -109,8 +109,8 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
109
109
|
<tbody></tbody>
|
|
110
110
|
</table>
|
|
111
111
|
<dialog id="drawer"></dialog>
|
|
112
|
-
</section>`}function
|
|
113
|
-
<td><input type="checkbox" class="row-select" ${
|
|
112
|
+
</section>`}function xt(e){e.innerHTML=In();let t=e.querySelector("#sessions-table tbody"),o=e.querySelector("#filters"),s=e.querySelector("#drawer"),a=e.querySelector("#select-all"),r=e.querySelector("#bulk-bar"),i=e.querySelector("#bulk-count"),m=e.querySelector("#bulk-close"),$=e.querySelector("#bulk-clear"),L=e.querySelector("#sessions-table"),y=new Set,v="lastMessageAt",c="desc";function I(u){let w=u.status==="closed",h=y.has(u.sessionId)?"checked":"";return`<tr data-id="${l(u.sessionId)}">
|
|
113
|
+
<td><input type="checkbox" class="row-select" ${h} ${w?"disabled":""}></td>
|
|
114
114
|
<td>${l(u.botName??"")}</td>
|
|
115
115
|
<td><span class="badge cli-${l(u.cliId??"unknown")}">${l(u.cliId??"unknown")}</span></td>
|
|
116
116
|
<td><span class="status status-${l(u.status??"unknown")}">${l(u.status??"unknown")}</span></td>
|
|
@@ -120,7 +120,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
120
120
|
<td>${Ae(u.lastMessageAt)}</td>
|
|
121
121
|
<td>${u.adopt?'<span class="badge">adopt</span>':""}</td>
|
|
122
122
|
<td><button class="open" type="button">${n("sessions.details")}</button></td>
|
|
123
|
-
</tr>`}function f(){let u=new FormData(o),w=(u.get("q")??"").toLowerCase(),
|
|
123
|
+
</tr>`}function f(){let u=new FormData(o),w=(u.get("q")??"").toLowerCase(),h=u.getAll("cli"),E=h.length>0&&h.length<Mt.length,C=u.get("status"),H=u.get("adopt"),U=!!u.get("active"),J=[...z.sessions.values()].filter(P=>!E||h.includes(P.cliId??"unknown")).filter(P=>!C||P.status===C).filter(P=>!H||H==="yes"==!!P.adopt).filter(P=>!U||P.status!=="closed").filter(P=>!w||JSON.stringify(P).toLowerCase().includes(w));return J.sort(p),J}function g(u,w){return w==="spawnedAt"||w==="lastMessageAt"?Number(u[w]??0):w==="adopt"?!!u.adopt:String(u[w]??"").toLowerCase()}function p(u,w){let h=g(u,v),E=g(w,v),C=0;return typeof h=="number"&&typeof E=="number"?C=h-E:typeof h=="boolean"&&typeof E=="boolean"?C=Number(h)-Number(E):C=String(h).localeCompare(String(E)),C===0&&(C=Number(u.lastMessageAt??0)-Number(w.lastMessageAt??0)),c==="asc"?C:-C}function S(){L.querySelectorAll("th[data-sort]").forEach(u=>{let w=u.dataset.sort===v;u.classList.toggle("sorted",w),u.setAttribute("aria-sort",w?c==="asc"?"ascending":"descending":"none");let h=u.dataset.label??u.textContent?.trim()??"";u.textContent=w?`${h} ${c==="asc"?"\u25B2":"\u25BC"}`:h})}function T(u){r.hidden=y.size===0,i.textContent=n("sessions.selectedCount",{count:y.size});let w=u.filter(E=>E.status!=="closed");if(w.length===0){a.checked=!1,a.indeterminate=!1,a.disabled=!0;return}a.disabled=!1;let h=w.filter(E=>y.has(E.sessionId)).length;a.checked=h===w.length,a.indeterminate=h>0&&h<w.length}function k(){let u=f();for(let w of[...y]){let h=z.sessions.get(w);(!h||h.status==="closed")&&y.delete(w)}t.innerHTML=u.length?u.map(I).join(""):`<tr><td colspan="10" class="empty">${n("sessions.empty")}</td></tr>`,S(),T(u)}function M(u){let w=u.status==="closed";s.innerHTML=`<article>
|
|
124
124
|
<header>
|
|
125
125
|
<h3>${l(u.title??u.sessionId)}</h3>
|
|
126
126
|
<span class="status status-${l(u.status??"unknown")}">${l(u.status??"unknown")}</span>
|
|
@@ -138,7 +138,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
138
138
|
${w?"":`<button id="close-btn" type="button" class="contrast">${n("sessions.close")}</button>`}
|
|
139
139
|
</div>
|
|
140
140
|
<form method="dialog"><button>${n("sessions.dismiss")}</button></form>
|
|
141
|
-
</article>`,s.querySelectorAll("[data-copy]").forEach(
|
|
141
|
+
</article>`,s.querySelectorAll("[data-copy]").forEach(H=>{H.onclick=()=>{navigator.clipboard.writeText(H.dataset.copy??""),H.textContent=n("sessions.copied"),setTimeout(()=>{H.textContent=n("sessions.copy")},800)}});let h=s.querySelector("#locate-btn");h&&(h.onclick=async()=>{h.disabled=!0,h.textContent=n("sessions.locating");try{let H=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/locate`,{method:"POST"}),U=await H.json();if(U.ok){let J=30;h.textContent=n("sessions.cooldown",{seconds:J});let P=setInterval(()=>{J-=1,J<=0?(clearInterval(P),h.disabled=!1,h.textContent=n("sessions.locate")):h.textContent=n("sessions.cooldown",{seconds:J})},1e3)}else alert(`Locate failed: ${U.error??H.status}`),h.disabled=!1,h.textContent=n("sessions.locate")}catch(H){alert(`Locate error: ${H}`),h.disabled=!1,h.textContent=n("sessions.locate")}});let E=s.querySelector("#resume-btn");E&&(E.onclick=async()=>{E.disabled=!0;try{let H=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/resume`,{method:"POST"}),U=await H.json().catch(()=>({}));if(!H.ok||U.ok===!1){alert(`${n("sessions.resumeFailed")}: ${U?.error??H.status}`),E.disabled=!1;return}s.close()}catch(H){alert(`${n("sessions.resumeFailed")}: ${H}`),E.disabled=!1}});let C=s.querySelector("#close-btn");C&&(C.onclick=async()=>{if(confirm(n("sessions.closeConfirm"))){C.disabled=!0;try{await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/close`,{method:"POST"})}finally{s.close()}}}),s.showModal()}t.addEventListener("click",u=>{let w=u.target;if(w.classList.contains("row-select")){let H=w.closest("tr[data-id]");if(!H)return;w.checked?y.add(H.dataset.id):y.delete(H.dataset.id),T(f());return}let h=w.closest("td");if(h&&h.querySelector(".row-select"))return;let E=w.closest("tr[data-id]");if(!E)return;let C=z.sessions.get(E.dataset.id);C&&M(C)}),a.addEventListener("change",()=>{let u=f().filter(w=>w.status!=="closed");for(let w of u)a.checked?y.add(w.sessionId):y.delete(w.sessionId);k()}),$.addEventListener("click",()=>{y.clear(),k()}),m.addEventListener("click",async()=>{let u=[...y];if(u.length===0||!confirm(n("sessions.closeBulkConfirm",{count:u.length})))return;m.disabled=!0,$.disabled=!0;let w=m.textContent,h=0,E=0,C=[...u];m.textContent=`0/${u.length}`;async function H(){for(;C.length;){let U=C.shift();try{let J=await fetch(`/api/sessions/${encodeURIComponent(U)}/close`,{method:"POST"}),P=await J.json().catch(()=>({}));(!J.ok||P?.ok===!1)&&(E+=1)}catch{E+=1}finally{h+=1,m.textContent=`${h}/${u.length}`}}}await Promise.all(Array.from({length:Math.min(6,u.length)},()=>H())),m.textContent=w,m.disabled=!1,$.disabled=!1,y.clear(),k(),E>0&&alert(`Failed: ${E}/${u.length}`)}),L.querySelectorAll("th[data-sort]").forEach(u=>{u.addEventListener("click",()=>{let w=u.dataset.sort;v===w?c=c==="asc"?"desc":"asc":(v=w,c=w==="spawnedAt"||w==="lastMessageAt"?"desc":"asc"),k()})}),o.addEventListener("input",k),z.on(k),k()}function En(){return`<section class="page">
|
|
142
142
|
<div class="page-heading">
|
|
143
143
|
<div>
|
|
144
144
|
<p class="eyebrow">${n("nav.schedules")}</p>
|
|
@@ -163,19 +163,19 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
163
163
|
</tr></thead>
|
|
164
164
|
<tbody id="schedules-tbody"></tbody>
|
|
165
165
|
</table>
|
|
166
|
-
</section>`}function
|
|
166
|
+
</section>`}function Ct(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function Ht(e){e.innerHTML=En();let t=e.querySelector("#schedules-tbody"),o=e.querySelector("#sched-filters");function s(){let r=new FormData(o),i=(r.get("q")??"").toLowerCase(),m=r.get("kind"),$=!!r.get("enabled");return[...z.schedules.values()].filter(L=>!m||L.parsed?.kind===m).filter(L=>!$||L.enabled).filter(L=>!i||JSON.stringify(L).toLowerCase().includes(i)).sort((L,y)=>{if(L.enabled!==y.enabled)return L.enabled?-1:1;let v=L.nextRunAt?Date.parse(L.nextRunAt):1/0,c=y.nextRunAt?Date.parse(y.nextRunAt):1/0;return v-c})}function a(){t.innerHTML=s().map(r=>`<tr data-id="${l(r.id)}">
|
|
167
167
|
<td>${l(r.name??r.id)}</td>
|
|
168
168
|
<td>${l(r.botName??r.larkAppId??"-")}</td>
|
|
169
169
|
<td><code>${l(r.parsed?.display??"?")}</code></td>
|
|
170
|
-
<td>${
|
|
171
|
-
<td>${
|
|
170
|
+
<td>${Ct(r.nextRunAt)}</td>
|
|
171
|
+
<td>${Ct(r.lastRunAt)} ${r.lastStatus==="error"?"\u26A0\uFE0F":""}</td>
|
|
172
172
|
<td>${r.repeat?`${r.repeat.completed}/${r.repeat.times??"\u221E"}`:"\u2014"}</td>
|
|
173
173
|
<td>${r.enabled?"\u2713":"\u2717"}</td>
|
|
174
174
|
<td class="actions-cell">
|
|
175
175
|
<button data-op="run" type="button">${n("schedules.runNow")}</button>
|
|
176
176
|
${r.enabled?`<button data-op="pause" type="button">${n("schedules.pause")}</button>`:`<button data-op="resume" type="button">${n("schedules.resume")}</button>`}
|
|
177
177
|
</td>
|
|
178
|
-
</tr>`).join("")||`<tr><td colspan="8" class="empty">${n("schedules.empty")}</td></tr>`}t.addEventListener("click",async r=>{let i=r.target.closest("button[data-op]");if(!i)return;let m=i.closest("tr[data-id]");if(!m)return;let $=m.dataset.id,
|
|
178
|
+
</tr>`).join("")||`<tr><td colspan="8" class="empty">${n("schedules.empty")}</td></tr>`}t.addEventListener("click",async r=>{let i=r.target.closest("button[data-op]");if(!i)return;let m=i.closest("tr[data-id]");if(!m)return;let $=m.dataset.id,L=i.dataset.op;i.disabled=!0;let y=i.textContent;i.textContent="...";try{let v=await fetch(`/api/schedules/${encodeURIComponent($)}/${L}`,{method:"POST"}),c=await v.json().catch(()=>({}));(!v.ok||c.ok===!1)&&alert(`Failed: ${v.status} ${c?.error??""}`.trim())}catch(v){alert("Network error: "+v)}finally{i.disabled=!1,i.textContent=y}}),o.addEventListener("input",a),z.on(a),a()}var K={chats:[],bots:[]};function Mn(){return`<section class="page">
|
|
179
179
|
<div class="page-heading">
|
|
180
180
|
<div>
|
|
181
181
|
<p class="eyebrow">${n("nav.groups")}</p>
|
|
@@ -194,12 +194,12 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
194
194
|
<tbody id="g-body"></tbody>
|
|
195
195
|
</table>
|
|
196
196
|
<dialog id="g-drawer"></dialog>
|
|
197
|
-
</section>`}async function
|
|
197
|
+
</section>`}async function Me(){K=await(await fetch("/api/groups")).json()}async function xn(){return(await fetch("/api/groups")).json()}function Cn(e,t){if(t.size===0)return!0;let o=e?.memberBots??[];for(let s of t)if(!o.some(a=>a.larkAppId===s&&a.inChat))return!1;return!0}function At(e,t){return e.filter(o=>!t||!t.has(o.larkAppId)).map(o=>`
|
|
198
198
|
<label class="checkbox-row">
|
|
199
199
|
<input type="checkbox" name="bot" value="${l(o.larkAppId)}">
|
|
200
200
|
${l(o.botName??o.larkAppId)} <small>(${l(o.larkAppId)})</small>
|
|
201
201
|
</label>
|
|
202
|
-
`).join("")}async function
|
|
202
|
+
`).join("")}async function Dt(e){e.innerHTML=Mn();let t=e.querySelector("#g-head"),o=e.querySelector("#g-body"),s=e.querySelector("#g-filters"),a=e.querySelector("#g-refresh"),r=e.querySelector("#g-drawer");a.onclick=async()=>{a.disabled=!0;try{await Me(),y()}finally{a.disabled=!1}};let i=e.querySelector("#g-create");i.onclick=()=>m(),await Me();function m(){let c=K.bots;if(c.length===0){alert(n("groups.noBotsOnline"));return}r.innerHTML=`
|
|
203
203
|
<article>
|
|
204
204
|
<header><h3>${n("groups.createTitle")}</h3></header>
|
|
205
205
|
<p>${n("groups.createHelp")}</p>
|
|
@@ -215,52 +215,52 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
215
215
|
</label>
|
|
216
216
|
<fieldset>
|
|
217
217
|
<legend>${n("groups.botPicker")}</legend>
|
|
218
|
-
${
|
|
218
|
+
${At(c)}
|
|
219
219
|
</fieldset>
|
|
220
220
|
<div class="actions">
|
|
221
221
|
<button type="submit" class="primary">${n("groups.createSubmit")}</button>
|
|
222
222
|
<button type="button" id="g-create-cancel">${n("groups.cancel")}</button>
|
|
223
223
|
</div>
|
|
224
224
|
</form>
|
|
225
|
-
</article>`,r.showModal(),r.querySelector("#g-create-cancel").onclick=()=>r.close(),r.querySelector("#g-createform").onsubmit=async g=>{g.preventDefault();let p=new FormData(g.target),S=(p.get("name")??"").trim(),
|
|
225
|
+
</article>`,r.showModal(),r.querySelector("#g-create-cancel").onclick=()=>r.close(),r.querySelector("#g-createform").onsubmit=async g=>{g.preventDefault();let p=new FormData(g.target),S=(p.get("name")??"").trim(),T=(p.get("bindWorkingDir")??"").trim(),k=p.getAll("bot");if(k.length===0){alert("Pick at least one bot.");return}let M=g.target.querySelector("button[type=submit]");M&&(M.disabled=!0,M.textContent="Creating...");try{let u=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:S||void 0,larkAppIds:k,bindWorkingDir:T||void 0})}),w=await u.json();if(w.ok&&w.chatId){$(w);let h=Array.isArray(w.invalidBotIds)?w.invalidBotIds:[],E=k.filter(H=>!h.includes(H)),C=new Set(E);typeof w.creator=="string"&&w.creator&&C.add(w.creator),I(w.chatId,S||w.chatId,E,w.creator),y(),f(w.chatId,C).catch(()=>{})}else alert(`Failed: ${w.error??u.status}`),r.close()}catch(u){alert("Network error: "+u),r.close()}};function I(g,p,S,T){let k=new Set(S);T&&k.add(T);let M=K.bots.map(w=>({larkAppId:w.larkAppId,botName:w.botName,inChat:k.has(w.larkAppId),oncallChat:null})),u={chatId:g,name:p,ownerId:T??null,memberBots:M};K.chats=[u,...K.chats.filter(w=>w.chatId!==g)]}async function f(g,p){let S=[600,1200,1200,1200,1200,1200];for(let T of S){await new Promise(u=>setTimeout(u,T));let k;try{k=await xn()}catch{continue}let M=(k.chats??[]).find(u=>u.chatId===g);if(M&&Cn(M,p)){K=k,y();return}}}}function $(c){let I=String(c.chatId),f=`https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(I)}`,g=c.invalidBotIds??[],p=c.invalidUserIds??[],S=c.autoInvitedOpenId,T=!!c.autoInviteRejected,k=c.ownerTransferredTo,M=c.transferError,u=c.notifyMessageId,w=c.notifyError,h=Array.isArray(c.oncallBindings)?c.oncallBindings:[],E=h.filter(P=>P?.ok).length,C=h.filter(P=>!P?.ok),H=h.length>0?C.length===0?`<p class="hint-ok">\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1A<code>${l(c.bindResolvedPath??"")}</code>\uFF08${E}/${h.length} bots\uFF09</p>`:`<p class="hint-warn">\u76EE\u5F55\u7ED1\u5B9A\u90E8\u5206\u5931\u8D25\uFF1A\u6210\u529F ${E}/${h.length}\u3002${C.map(P=>`<br><code>${l(P.larkAppId??"?")}</code>: ${l(P.error??"unknown")}`).join("")}</p>`:"",U;if(S){let P=k?"<br><small>\u7FA4\u4E3B\u5DF2\u4ECE\u673A\u5668\u4EBA\u8F6C\u8BA9\u7ED9\u4F60\u3002</small>":M?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08${l(M)}\uFF09\uFF0C\u4F60\u73B0\u5728\u662F\u6210\u5458\u4F46\u7FA4\u4E3B\u4ECD\u662F\u673A\u5668\u4EBA\u3002</small>`:"",Ie=u?`<br><small>\u673A\u5668\u4EBA\u5DF2\u5728\u7FA4\u91CC @ \u4E86\u4F60\uFF08\u6D88\u606F id <code>${l(u)}</code>\uFF09\uFF0C\u770B\u98DE\u4E66\u901A\u77E5\u5C31\u80FD\u8FDB\u7FA4\u3002</small>`:w?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8 @ \u901A\u77E5\u5931\u8D25\uFF08${l(w)}\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>`:"";U=`<p class="hint-ok">\u5DF2\u81EA\u52A8\u9080\u8BF7\u4F60\uFF08<code>${l(S)}</code>\uFF09\u4F5C\u4E3A\u6210\u5458\u3002${P}${Ie}</p>`}else T?U='<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>':U='<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 J=[g.length?`<li>\u65E0\u6548 bot id: <code>${g.map(l).join(", ")}</code></li>`:"",p.length?`<li>\u65E0\u6548\u7528\u6237 open_id: <code>${p.map(l).join(", ")}</code></li>`:""].filter(Boolean).join("");r.innerHTML=`
|
|
226
226
|
<article>
|
|
227
227
|
<header><h3>${n("groups.successTitle")}</h3></header>
|
|
228
228
|
<p><b>chatId:</b> <code>${l(I)}</code> <button type="button" data-copy="${l(I)}">${n("sessions.copy")}</button></p>
|
|
229
229
|
<p><b>\u521B\u5EFA\u8005:</b> <code>${l(c.creator??"?")}</code></p>
|
|
230
230
|
${U}
|
|
231
|
-
${
|
|
231
|
+
${H}
|
|
232
232
|
${J?`<ul>${J}</ul>`:""}
|
|
233
233
|
<div class="actions">
|
|
234
234
|
<a class="btn-link primary" href="${f}" target="_blank" rel="noopener">${n("groups.openGroup")}</a>
|
|
235
235
|
<button type="button" id="g-create-close">${n("sessions.dismiss")}</button>
|
|
236
236
|
</div>
|
|
237
|
-
</article>`,r.querySelectorAll("[data-copy]").forEach(P=>{P.onclick=()=>{navigator.clipboard.writeText(P.dataset.copy??""),P.textContent=n("sessions.copied"),setTimeout(()=>{P.textContent=n("sessions.copy")},800)}}),r.querySelector("#g-create-close").onclick=()=>r.close()}function
|
|
237
|
+
</article>`,r.querySelectorAll("[data-copy]").forEach(P=>{P.onclick=()=>{navigator.clipboard.writeText(P.dataset.copy??""),P.textContent=n("sessions.copied"),setTimeout(()=>{P.textContent=n("sessions.copy")},800)}}),r.querySelector("#g-create-close").onclick=()=>r.close()}function L(){t.innerHTML=`<tr>
|
|
238
238
|
<th>${n("groups.chat")}</th>
|
|
239
|
-
${
|
|
239
|
+
${K.bots.map(c=>`<th>${l(c.botName??c.larkAppId)}</th>`).join("")}
|
|
240
240
|
<th>${n("groups.actions")}</th>
|
|
241
|
-
</tr>`}function
|
|
241
|
+
</tr>`}function y(){L();let c=new FormData(s),I=(c.get("q")??"").toLowerCase(),f=!!c.get("missing"),g=K.chats.filter(p=>!I||(p.name??"").toLowerCase().includes(I)||p.chatId.toLowerCase().includes(I)||(p.ownerId??"").toLowerCase().includes(I)).filter(p=>!f||p.memberBots.some(S=>!S.inChat));if(g.length===0){o.innerHTML=`<tr><td colspan="${K.bots.length+2}" class="empty">${n("groups.empty")}</td></tr>`;return}o.innerHTML=g.map(p=>`<tr data-chat="${l(p.chatId)}">
|
|
242
242
|
<td>
|
|
243
243
|
<strong>${l(p.name??p.chatId)}</strong><br>
|
|
244
244
|
<small><code>${l(p.chatId)}</code></small>
|
|
245
245
|
</td>
|
|
246
|
-
${
|
|
246
|
+
${K.bots.map(S=>{let T=p.memberBots.find(u=>u.larkAppId===S.larkAppId),k=T?T.error?"!":T.inChat?"\u2713":"\u2717":"?";return`<td class="${T?T.error?"cell-error":T.inChat?"cell-in":"cell-out":"cell-unknown"}" title="${l(T?.error??"")}">${k}</td>`}).join("")}
|
|
247
247
|
<td>
|
|
248
248
|
<button class="add-bots" type="button">${n("groups.addBots")}</button>
|
|
249
249
|
<button class="manage-chat" type="button">${n("groups.manage")}</button>
|
|
250
250
|
</td>
|
|
251
|
-
</tr>`).join("")}
|
|
251
|
+
</tr>`).join("")}y(),o.addEventListener("click",async c=>{let I=c.target.closest("button.add-bots");if(!I)return;let g=I.closest("tr[data-chat]").dataset.chat,p=K.chats.find(k=>k.chatId===g);if(!p)return;let S=new Set(p.memberBots.filter(k=>k.inChat).map(k=>k.larkAppId));if(!K.bots.filter(k=>!S.has(k.larkAppId)).length){alert("All configured bots are already in this chat.");return}r.innerHTML=`
|
|
252
252
|
<article>
|
|
253
253
|
<header><h3>${n("groups.addBots")} \xB7 ${l(p.name??p.chatId)}</h3></header>
|
|
254
254
|
<p>${n("groups.createHelp")}</p>
|
|
255
255
|
<form id="g-addform">
|
|
256
|
-
${
|
|
256
|
+
${At(K.bots,S)}
|
|
257
257
|
<div class="actions">
|
|
258
258
|
<button type="submit" class="primary">${n("groups.addBots")}</button>
|
|
259
259
|
<button type="button" id="g-cancel">${n("groups.cancel")}</button>
|
|
260
260
|
</div>
|
|
261
261
|
</form>
|
|
262
|
-
</article>`,r.showModal(),r.querySelector("#g-cancel").onclick=()=>r.close(),r.querySelector("#g-addform").onsubmit=async
|
|
263
|
-
`);alert(E),await
|
|
262
|
+
</article>`,r.showModal(),r.querySelector("#g-cancel").onclick=()=>r.close(),r.querySelector("#g-addform").onsubmit=async k=>{k.preventDefault();let u=new FormData(k.target).getAll("bot");if(u.length===0){alert("Pick at least one bot.");return}try{let h=await(await fetch(`/api/groups/${encodeURIComponent(g)}/add-bots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:u})})).json();if(h.error==="no_proxy_bot")alert("No bot is currently in this chat \u2014 add one manually in Feishu first, then retry.");else if(h.result){let E=h.result.map(C=>`${C.id}: ${C.ok?"OK":`failed (${C.error??"unknown"})`}`).join(`
|
|
263
|
+
`);alert(E),await Me(),y()}else alert(`Unexpected response: ${JSON.stringify(h)}`)}catch(w){alert("Network error: "+w)}finally{r.close()}}}),o.addEventListener("click",async c=>{let I=c.target.closest("button.manage-chat");if(!I)return;let g=I.closest("tr[data-chat]").dataset.chat,p=K.chats.find(S=>S.chatId===g);p&&v(p)});function v(c){let I=c.memberBots.filter(g=>g.inChat),f=typeof c.ownerId=="string"?c.ownerId:"";r.innerHTML=`
|
|
264
264
|
<article>
|
|
265
265
|
<header><h3>${n("groups.manageTitle",{name:c.name??c.chatId})}</h3></header>
|
|
266
266
|
<p><b>chatId:</b> <code>${l(c.chatId)}</code></p>
|
|
@@ -303,14 +303,14 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
303
303
|
</div>
|
|
304
304
|
<p class="hint-warn"><small>${n("groups.dangerHint")}</small></p>
|
|
305
305
|
<form method="dialog"><button>${n("sessions.dismiss")}</button></form>
|
|
306
|
-
</article>`,r.showModal(),r.querySelectorAll(".oncall-row").forEach(g=>{let p=g.dataset.bot,S=g.querySelector("input[data-action=toggle]"),
|
|
307
|
-
`);alert(
|
|
306
|
+
</article>`,r.showModal(),r.querySelectorAll(".oncall-row").forEach(g=>{let p=g.dataset.bot,S=g.querySelector("input[data-action=toggle]"),T=g.querySelector("input[data-input=workingDir]"),k=g.querySelector("button[data-action=save]"),M=g.querySelector("[data-status]");S.addEventListener("change",()=>{T.disabled=!S.checked,S.checked&&T.focus()}),k.addEventListener("click",async()=>{M.textContent="",M.className="oncall-status";let u=S.checked,w=T.value.trim();if(u&&!w){M.textContent=n("groups.needWorkingDir"),M.classList.add("hint-warn-inline");return}k.disabled=!0;try{let h=`/api/groups/${encodeURIComponent(c.chatId)}/oncall/${encodeURIComponent(p)}`,E=u?await fetch(h,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({workingDir:w})}):await fetch(h,{method:"DELETE"}),C=await E.json().catch(()=>({}));if(E.ok&&C.ok){M.textContent=u?`\u2713 \u5DF2\u7ED1\u5B9A \u2192 ${C.resolvedPath??w}`:"\u2713 \u5DF2\u89E3\u7ED1",M.classList.add("hint-ok");try{await Me(),y()}catch{}}else M.textContent=`\u2717 ${C.error??E.status}`,M.classList.add("hint-warn-inline")}catch(h){M.textContent=`\u2717 ${h?.message??h}`,M.classList.add("hint-warn-inline")}finally{k.disabled=!1}})}),r.querySelector("#g-leave-btn").onclick=async()=>{let g=[...r.querySelectorAll("input[name=leave-bot]:checked")].map(p=>p.value);if(g.length===0){alert("\u81F3\u5C11\u9009\u4E00\u4E2A\u673A\u5668\u4EBA");return}if(confirm(`\u786E\u5B9A\u8BA9 ${g.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 S=await(await fetch(`/api/groups/${encodeURIComponent(c.chatId)}/leave`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:g})})).json(),T=(S.result??[]).map(k=>{if(!k.ok)return`${k.larkAppId}: \u5931\u8D25 (${k.error??"unknown"})`;let M=k.closedSessions??[],u=M.filter(E=>!E.ok).length,w=M.length-u,h=M.length===0?"":u===0?`\uFF08\u5173\u95ED ${w} \u4E2A\u4F1A\u8BDD\uFF09`:`\uFF08\u5173\u95ED ${w} \u4E2A\uFF0C${u} \u4E2A\u5931\u8D25\uFF09`;return`${k.larkAppId}: OK${h}`}).join(`
|
|
307
|
+
`);alert(T||`Unexpected: ${JSON.stringify(S)}`),await Me(),y()}catch(p){alert("Network error: "+p)}finally{r.close()}},r.querySelector("#g-disband-btn").onclick=async()=>{if(I.length===0||!confirm(`\u786E\u5B9A\u89E3\u6563\u7FA4\u804A\u300C${c.name??c.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 g=[...I].sort((S,T)=>(T.larkAppId===f?1:0)-(S.larkAppId===f?1:0)),p=[];for(let S of g)try{let T=await fetch(`/api/groups/${encodeURIComponent(c.chatId)}/disband`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppId:S.larkAppId})}),k=await T.json();if(k.ok){let M=k.closedSessions??[],u=M.filter(E=>!E.ok).length,w=M.length-u,h=M.length===0?"":u===0?`
|
|
308
308
|
\u5173\u95ED\u4E86 ${w} \u4E2A\u4F1A\u8BDD\u3002`:`
|
|
309
|
-
\u5173\u95ED\u4E86 ${w} \u4E2A\u4F1A\u8BDD\uFF0C${u} \u4E2A\u4F1A\u8BDD\u5173\u95ED\u5931\u8D25\u3002`;alert(`\u5DF2\u89E3\u6563\uFF08\u7531 ${S.botName??S.larkAppId} \u6267\u884C\uFF09${
|
|
309
|
+
\u5173\u95ED\u4E86 ${w} \u4E2A\u4F1A\u8BDD\uFF0C${u} \u4E2A\u4F1A\u8BDD\u5173\u95ED\u5931\u8D25\u3002`;alert(`\u5DF2\u89E3\u6563\uFF08\u7531 ${S.botName??S.larkAppId} \u6267\u884C\uFF09${h}`),await Me(),y(),r.close();return}p.push(`${S.botName??S.larkAppId}: ${k.error??T.status}`)}catch(T){p.push(`${S.botName??S.larkAppId}: ${T}`)}alert(`\u6240\u6709\u5728\u7FA4\u673A\u5668\u4EBA\u5747\u65E0\u6CD5\u89E3\u6563\uFF1A
|
|
310
310
|
${p.join(`
|
|
311
311
|
`)}
|
|
312
312
|
|
|
313
|
-
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",
|
|
313
|
+
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",y)}var ee={bots:[]},xe=null;function Hn(){return`<section class="page">
|
|
314
314
|
<div class="page-heading">
|
|
315
315
|
<div>
|
|
316
316
|
<p class="eyebrow">${n("nav.botDefaults")}</p>
|
|
@@ -323,7 +323,7 @@ ${p.join(`
|
|
|
323
323
|
<button type="button" id="bd-refresh">${n("botDefaults.refresh")}</button>
|
|
324
324
|
</form>
|
|
325
325
|
<div id="bd-list"></div>
|
|
326
|
-
</section>`}async function
|
|
326
|
+
</section>`}async function Rt(){try{let e=await fetch("/api/bots"),t=await e.json().catch(()=>({}));if(!e.ok){xe=t?.error?`HTTP ${e.status}: ${t.error}${t.path?` (${t.path})`:""}`:`HTTP ${e.status}`,ee={bots:[]};return}if(!t||!Array.isArray(t.bots)){xe="unexpected response shape (no `bots` array)",ee={bots:[]};return}xe=null,ee=t}catch(e){xe=e?.message??String(e),ee={bots:[]}}}function Ot(e){if(!e)return"\u2014";let t=new Date(e);return Number.isNaN(t.getTime())?"\u2014":t.toLocaleString()}async function qt(e){e.innerHTML=Hn();let t=e.querySelector("#bd-list"),o=e.querySelector("#bd-filters"),s=e.querySelector("#bd-refresh");s.onclick=async()=>{s.disabled=!0;try{await Rt(),a()}finally{s.disabled=!1}},await Rt();function a(){let g=(new FormData(o).get("q")??"").toLowerCase(),p=ee.bots.filter(S=>!g||(S.botName??"").toLowerCase().includes(g)||(S.larkAppId??"").toLowerCase().includes(g));if(xe){t.innerHTML=`<p class="hint-warn">\u65E0\u6CD5\u52A0\u8F7D bot \u5217\u8868\uFF1A${l(xe)}<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(p.length===0){t.innerHTML=`<p class="empty">${n("botDefaults.empty")}</p>`;return}t.innerHTML=p.map(r).join(""),I()}function r(f){if(f.error)return`<article class="bd-card" data-appid="${l(f.larkAppId)}">
|
|
327
327
|
<header><strong>${l(f.botName??f.larkAppId)}</strong>
|
|
328
328
|
<small>${l(f.larkAppId)}</small></header>
|
|
329
329
|
<p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${l(f.error)}</p>
|
|
@@ -349,7 +349,7 @@ ${p.join(`
|
|
|
349
349
|
</div>
|
|
350
350
|
<p class="bd-section-note">${n("botDefaults.warning")}</p>
|
|
351
351
|
<div class="bd-meta">
|
|
352
|
-
<small>${n("botDefaults.lastEnabled")}: ${l(
|
|
352
|
+
<small>${n("botDefaults.lastEnabled")}: ${l(Ot(g.since??0))}</small>
|
|
353
353
|
<small>${n("botDefaults.autobound",{count:f.autoboundChatCount??0})}</small>
|
|
354
354
|
</div>
|
|
355
355
|
<div class="actions">
|
|
@@ -360,8 +360,8 @@ ${p.join(`
|
|
|
360
360
|
</section>
|
|
361
361
|
${i(f)}
|
|
362
362
|
${$(f)}
|
|
363
|
-
${
|
|
364
|
-
${
|
|
363
|
+
${L(f)}
|
|
364
|
+
${v(f)}
|
|
365
365
|
</div>
|
|
366
366
|
</article>`}function i(f){let g=typeof f.teamRole=="string";return`<section class="bd-section">
|
|
367
367
|
<h3 class="bd-section-title">${n("botDefaults.sectionRole")}</h3>
|
|
@@ -391,7 +391,7 @@ ${p.join(`
|
|
|
391
391
|
<span class="oncall-status" data-brand-status></span>
|
|
392
392
|
</div>
|
|
393
393
|
</div>
|
|
394
|
-
</section>`}function
|
|
394
|
+
</section>`}function L(f){let g=f.disableStreamingCard===!0,p=f.writableTerminalLinkInCard===!0,S=f.privateCard===!0;return`<section class="bd-section">
|
|
395
395
|
<h3 class="bd-section-title">${n("botDefaults.sectionCard")}</h3>
|
|
396
396
|
<label class="checkbox-row">
|
|
397
397
|
<input type="checkbox" data-action="toggle-disable-streaming" ${g?"checked":""}>
|
|
@@ -412,7 +412,7 @@ ${p.join(`
|
|
|
412
412
|
<small data-card-pref-moot class="hint-warn-inline" ${g?"":"hidden"}>${n("botDefaults.writableLinkMoot")}</small>
|
|
413
413
|
<span class="oncall-status" data-card-pref-status></span>
|
|
414
414
|
</div>
|
|
415
|
-
</section>`}function
|
|
415
|
+
</section>`}function y(f){return f==null?n("botDefaults.quotaStateOff"):n("botDefaults.quotaStateOn",{count:f})}function v(f){let g=f.restrictGrantCommands===!0,p=typeof f.messageQuotaDefaultLimit=="number"?f.messageQuotaDefaultLimit:null;return`<section class="bd-section">
|
|
416
416
|
<h3 class="bd-section-title">${n("botDefaults.sectionGrant")}</h3>
|
|
417
417
|
<label class="checkbox-row">
|
|
418
418
|
<input type="checkbox" data-action="toggle-restrict-grant" ${g?"checked":""}>
|
|
@@ -426,7 +426,7 @@ ${p.join(`
|
|
|
426
426
|
placeholder="${l(n("botDefaults.quotaPlaceholder"))}"
|
|
427
427
|
value="${p??""}">
|
|
428
428
|
</label>
|
|
429
|
-
<small data-quota-state>${l(
|
|
429
|
+
<small data-quota-state>${l(y(p))}</small>
|
|
430
430
|
<small>${n("botDefaults.quotaHelp")}</small>
|
|
431
431
|
<div class="actions">
|
|
432
432
|
<button type="button" data-action="save-quota">${n("botDefaults.quotaSave")}</button>
|
|
@@ -459,7 +459,7 @@ ${p.join(`
|
|
|
459
459
|
<div class="actions">
|
|
460
460
|
<span class="oncall-status" data-auto-start-status></span>
|
|
461
461
|
</div>
|
|
462
|
-
</div>`}function I(){t.querySelectorAll(".bd-card").forEach(f=>{let g=f.dataset.appid,p=f.querySelector("input[data-action=toggle]"),S=f.querySelector("input[data-input=workingDir]"),
|
|
462
|
+
</div>`}function I(){t.querySelectorAll(".bd-card").forEach(f=>{let g=f.dataset.appid,p=f.querySelector("input[data-action=toggle]"),S=f.querySelector("input[data-input=workingDir]"),T=f.querySelector("button[data-action=save]"),k=f.querySelector("[data-status]");if(!p||!S||!T||!k)return;p.addEventListener("change",()=>{S.disabled=!p.checked,p.checked&&S.focus()}),T.addEventListener("click",async()=>{k.textContent="",k.className="oncall-status";let W=p.checked,_=S.value.trim();if(W&&!_){k.textContent=n("botDefaults.required"),k.classList.add("hint-warn-inline");return}T.disabled=!0;try{let q=await fetch(`/api/bots/${encodeURIComponent(g)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:W,workingDir:_})}),A=await q.json().catch(()=>({}));if(q.ok&&A.ok){let R=A.resolvedPath?` \u2192 ${A.resolvedPath}`:"";k.textContent=W?`\u2713 \u5DF2\u5F00\u542F${R}\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",k.classList.add("hint-ok");let B=ee.bots.find(N=>N.larkAppId===g);B&&A.defaultOncall&&(B.defaultOncall=A.defaultOncall);let b=f.querySelector(".bd-meta small:first-child");b&&A.defaultOncall?.since!=null&&(b.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${Ot(A.defaultOncall.since)}`)}else k.textContent=`\u2717 ${A.error??q.status}`,k.classList.add("hint-warn-inline")}catch(q){k.textContent=`\u2717 ${q?.message??q}`,k.classList.add("hint-warn-inline")}finally{T.disabled=!1}});let M=f.querySelector("input[data-input=brandLabel]"),u=f.querySelector("button[data-action=save-brand]"),w=f.querySelector("button[data-action=reset-brand]"),h=f.querySelector("[data-brand-status]"),E=f.querySelector("[data-brand-state]");async function C(W,_){if(h){h.textContent="",h.className="oncall-status",_.disabled=!0;try{let q=await fetch(`/api/bots/${encodeURIComponent(g)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:W})}),A=await q.json().catch(()=>({}));if(q.ok&&A.ok){let R=A.brandLabel??null;h.textContent="\u2713",h.classList.add("hint-ok"),M&&(M.value=R??""),E&&(E.textContent=m(R));let B=ee.bots.find(b=>b.larkAppId===g);B&&(B.brandLabel=R)}else h.textContent=`\u2717 ${A.error??q.status}`,h.classList.add("hint-warn-inline")}catch(q){h.textContent=`\u2717 ${q?.message??q}`,h.classList.add("hint-warn-inline")}finally{_.disabled=!1}}}M&&u&&u.addEventListener("click",()=>C(M.value,u)),w&&w.addEventListener("click",()=>C(null,w));let H=f.querySelector("input[data-action=toggle-disable-streaming]"),U=f.querySelector("input[data-action=toggle-writable-link]"),J=f.querySelector("input[data-action=toggle-private-card]"),P=f.querySelector("[data-card-pref-status]"),Ie=f.querySelector("[data-card-pref-moot]");async function ae(W,_,q=P){if(q){q.textContent="",q.className="oncall-status",_.disabled=!0;try{let A=await fetch(`/api/bots/${encodeURIComponent(g)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(W)}),R=await A.json().catch(()=>({}));if(A.ok&&R.ok){q.textContent=`\u2713 ${n("botDefaults.cardPrefSaved")}`,q.classList.add("hint-ok");let B=ee.bots.find(b=>b.larkAppId===g);B&&(B.disableStreamingCard=R.disableStreamingCard,B.writableTerminalLinkInCard=R.writableTerminalLinkInCard,B.privateCard=R.privateCard,B.autoStartOnGroupJoin=R.autoStartOnGroupJoin,B.autoStartOnGroupJoinPrompt=R.autoStartOnGroupJoinPrompt,B.autoStartOnNewTopic=R.autoStartOnNewTopic)}else q.textContent=`\u2717 ${R.error??A.status}`,q.classList.add("hint-warn-inline")}catch(A){q.textContent=`\u2717 ${A?.message??A}`,q.classList.add("hint-warn-inline")}finally{_===U?_.disabled=!!H?.checked:_.disabled=!1}}}H&&H.addEventListener("change",()=>{let W=H.checked;U&&(U.disabled=W),Ie&&(Ie.hidden=!W),ae({disableStreamingCard:W},H)}),U&&U.addEventListener("change",()=>{ae({writableTerminalLinkInCard:U.checked},U)}),J&&J.addEventListener("change",()=>{ae({privateCard:J.checked},J)});let se=f.querySelector("input[data-action=toggle-auto-join]"),re=f.querySelector("input[data-action=toggle-auto-topic]"),ye=f.querySelector("textarea[data-input=autoJoinPrompt]"),Y=f.querySelector("button[data-action=save-auto-join-prompt]"),ie=f.querySelector("[data-auto-start-status]");se&&se.addEventListener("change",()=>{ae({autoStartOnGroupJoin:se.checked},se,ie)}),re&&re.addEventListener("change",()=>{ae({autoStartOnNewTopic:re.checked},re,ie)}),ye&&Y&&Y.addEventListener("click",()=>{ae({autoStartOnGroupJoinPrompt:ye.value},Y,ie)});let He=f.querySelector("textarea[data-input=teamRole]"),ue=f.querySelector("button[data-action=save-role]"),pe=f.querySelector("button[data-action=delete-role]"),F=f.querySelector("[data-role-status]");if(He&&ue&&pe&&F){let q=function(R){let B=t.querySelector(`.bd-card[data-appid="${CSS.escape(g)}"]`);if(!B)return;let b=B.querySelector("textarea[data-input=teamRole]"),N=B.querySelector("button[data-action=save-role]"),D=B.querySelector("button[data-action=delete-role]");b&&(b.value=R,b.disabled=!1),N&&(N.disabled=!1),D&&(D.disabled=!1)};var vt=q;let W=`/api/team/local-bots/${encodeURIComponent(g)}/role`,_=ee.bots.find(R=>R.larkAppId===g);_&&typeof _.teamRole!="string"&&!_.teamRoleLoading&&(_.teamRoleLoading=!0,(async()=>{try{let R=await fetch(W),B=await R.json().catch(()=>({}));R.ok&&B.ok?(_.teamRole=B.role??"",q(_.teamRole)):(F.textContent=`\u2717 ${n("botDefaults.roleLoadErr")}: ${B.error??R.status}`,F.classList.add("hint-warn-inline"))}catch(R){F.textContent=`\u2717 ${n("botDefaults.roleLoadErr")}: ${R?.message??R}`,F.classList.add("hint-warn-inline")}finally{_.teamRoleLoading=!1}})());async function A(R,B,b){if(F&&!(!_||typeof _.teamRole!="string")){F.textContent="",F.className="oncall-status",ue.disabled=!0,pe.disabled=!0;try{let N=await fetch(W,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({role:R})}),D=await N.json().catch(()=>({}));N.ok&&D.ok?(_&&(_.teamRole=R.trim()),F.textContent=`\u2713 ${b?n("botDefaults.roleDeleted"):n("botDefaults.roleSaved")}`,F.classList.add("hint-ok")):(F.textContent=`\u2717 ${D.error??N.status}`,F.classList.add("hint-warn-inline"))}catch(N){F.textContent=`\u2717 ${N?.message??N}`,F.classList.add("hint-warn-inline")}finally{ue.disabled=!1,pe.disabled=!1}}}ue.addEventListener("click",()=>A(He.value,ue,!1)),pe.addEventListener("click",()=>{He.value="",A("",pe,!0)})}let ve=f.querySelector("input[data-action=toggle-restrict-grant]"),le=f.querySelector("input[data-input=quotaLimit]"),de=f.querySelector("button[data-action=save-quota]"),fe=f.querySelector("button[data-action=off-quota]"),Q=f.querySelector("[data-grant-status]"),ke=f.querySelector("[data-quota-state]");async function Ee(W,_){if(Q){Q.textContent="",Q.className="oncall-status",_.disabled=!0;try{let q=await fetch(`/api/bots/${encodeURIComponent(g)}/grant-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(W)}),A=await q.json().catch(()=>({}));if(q.ok&&A.ok){Q.textContent=`\u2713 ${n("botDefaults.cardPrefSaved")}`,Q.classList.add("hint-ok");let R=typeof A.messageQuotaDefaultLimit=="number"?A.messageQuotaDefaultLimit:null,B=ee.bots.find(b=>b.larkAppId===g);B&&(B.restrictGrantCommands=A.restrictGrantCommands===!0,B.messageQuotaDefaultLimit=R),ke&&(ke.textContent=y(R)),le&&"messageQuotaDefaultLimit"in W&&(le.value=R==null?"":String(R))}else Q.textContent=`\u2717 ${A.error??q.status}`,Q.classList.add("hint-warn-inline")}catch(q){Q.textContent=`\u2717 ${q?.message??q}`,Q.classList.add("hint-warn-inline")}finally{_.disabled=!1}}}ve&&ve.addEventListener("change",()=>{Ee({restrictGrantCommands:ve.checked},ve)}),le&&de&&de.addEventListener("click",()=>{let W=le.value.trim();if(W===""){Ee({messageQuotaDefaultLimit:null},de);return}if(!/^[1-9]\d*$/.test(W)){Q&&(Q.textContent=`\u2717 ${n("botDefaults.quotaInvalid")}`,Q.className="oncall-status hint-warn-inline");return}Ee({messageQuotaDefaultLimit:Number(W)},de)}),le&&fe&&fe.addEventListener("click",()=>{le.value="",Ee({messageQuotaDefaultLimit:null},fe)})})}a(),o.addEventListener("input",a)}var rt=4096,Fe=[],te=null,ne=null,V="",Ce=new Set;function An(){return`<section class="page roles-page">
|
|
463
463
|
<div class="page-heading">
|
|
464
464
|
<div>
|
|
465
465
|
<p class="eyebrow">${n("nav.roles")}</p>
|
|
@@ -498,18 +498,18 @@ ${p.join(`
|
|
|
498
498
|
</div>
|
|
499
499
|
</div>
|
|
500
500
|
</div>
|
|
501
|
-
</section>`}async function
|
|
502
|
-
<div class="roles-bot-row ${te===a.chatId&&ne===
|
|
501
|
+
</section>`}async function _e(){Fe=((await(await fetch("/api/groups")).json()).chats??[]).map(o=>({chatId:o.chatId,name:o.name??o.chatId,memberBots:(o.memberBots??[]).map(s=>({larkAppId:s.larkAppId,botName:s.botName??s.larkAppId,inChat:s.inChat??!1,hasRole:s.hasRole??!1,oncallChat:s.oncallChat??null}))}))}async function Bt(e,t){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)).json()}async function Dn(e,t,o){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({content:o})})).ok}async function Rn(e,t){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{method:"DELETE"})).ok}function Nt(e){return e.memberBots.filter(t=>t.inChat&&t.hasRole).length}function On(e){return e.memberBots.filter(t=>t.inChat).length}function $e(e=""){let t=document.getElementById("roles-tree");if(!t)return;let o=e.toLowerCase(),s=Fe.filter(a=>{if(!o)return!0;let r=a.chatId.toLowerCase().includes(o)||(a.name??"").toLowerCase().includes(o),i=a.memberBots.some(m=>m.larkAppId.toLowerCase().includes(o)||(m.botName??"").toLowerCase().includes(o));return r||i});if(s.length===0){t.innerHTML=`<div class="roles-empty">${n("roles.noChats")}</div>`;return}t.innerHTML=s.map(a=>{let r=Ce.has(a.chatId),i=a.memberBots.filter(v=>v.inChat),m=r?"\u25BE":"\u25B8",$=Nt(a),L=On(a),y=r?i.map(v=>`
|
|
502
|
+
<div class="roles-bot-row ${te===a.chatId&&ne===v.larkAppId?"selected":""}"
|
|
503
503
|
data-group-id="${l(a.chatId)}"
|
|
504
|
-
data-bot-id="${l(
|
|
504
|
+
data-bot-id="${l(v.larkAppId)}">
|
|
505
505
|
<span class="roles-bot-indent"></span>
|
|
506
506
|
<span class="roles-bot-icon">\u{1F916}</span>
|
|
507
507
|
<div class="roles-bot-info">
|
|
508
|
-
<div class="roles-bot-name">${l(
|
|
509
|
-
<div class="roles-bot-id">${l(
|
|
508
|
+
<div class="roles-bot-name">${l(v.botName)}</div>
|
|
509
|
+
<div class="roles-bot-id">${l(v.larkAppId)}</div>
|
|
510
510
|
</div>
|
|
511
|
-
<span class="roles-badge ${
|
|
512
|
-
${
|
|
511
|
+
<span class="roles-badge ${v.hasRole?"has-role":"no-role"}">
|
|
512
|
+
${v.hasRole?n("roles.configured"):n("roles.unconfigured")}
|
|
513
513
|
</span>
|
|
514
514
|
</div>`).join(""):"";return`
|
|
515
515
|
<div class="roles-group-section">
|
|
@@ -520,18 +520,18 @@ ${p.join(`
|
|
|
520
520
|
<div class="roles-group-info">
|
|
521
521
|
<div class="roles-group-name">${l(a.name??a.chatId)}</div>
|
|
522
522
|
<div class="roles-group-meta">
|
|
523
|
-
${$}/${
|
|
523
|
+
${$}/${L} ${n("roles.botsWithRoles")}
|
|
524
524
|
</div>
|
|
525
525
|
</div>
|
|
526
526
|
<span class="roles-group-chevron"></span>
|
|
527
527
|
</div>
|
|
528
|
-
<div class="roles-bot-list">${
|
|
529
|
-
</div>`}).join(""),t.querySelectorAll(".roles-group-row").forEach(a=>{a.addEventListener("click",()=>{let r=a.dataset.groupId;r&&(
|
|
528
|
+
<div class="roles-bot-list">${y}</div>
|
|
529
|
+
</div>`}).join(""),t.querySelectorAll(".roles-group-row").forEach(a=>{a.addEventListener("click",()=>{let r=a.dataset.groupId;r&&(Ce.has(r)?Ce.delete(r):Ce.add(r),$e(document.getElementById("roles-search")?.value??""))})}),t.querySelectorAll(".roles-bot-row").forEach(a=>{a.addEventListener("click",r=>{r.stopPropagation();let i=a.dataset.groupId,m=a.dataset.botId;i&&m&&qn(i,m)})})}async function qn(e,t){te=e,ne=t;let o=await Bt(t,e),s=document.getElementById("roles-editor-empty"),a=document.getElementById("roles-editor-form"),r=document.getElementById("roles-editor-textarea"),i=document.getElementById("roles-editor-group-name"),m=document.getElementById("roles-editor-bot-name"),$=document.getElementById("roles-editor-chat-id");s&&(s.style.display="none"),a&&(a.style.display="");let L=Fe.find(c=>c.chatId===e),y=L?.memberBots.find(c=>c.larkAppId===t);i&&(i.textContent=L?.name??e),m&&(m.textContent=y?.botName??t),$&&($.textContent=`${e} \xB7 ${t}`),V=o.content??"",r&&(r.value=V,r.focus()),it(),lt(),$e(document.getElementById("roles-search")?.value??"");let v=document.getElementById("roles-delete");v&&(v.style.display=o.hasRole?"":"none")}function it(){let e=document.getElementById("roles-editor-bytecount");if(!e)return;let t=new TextEncoder().encode(V).length;e.textContent=`${t} / ${rt} bytes`,e.className=`roles-bytecount ${t>3800?"warn":""} ${t>rt?"over":""}`,Pn(t)}function Pn(e){let t=document.getElementById("roles-save");if(!t)return;let o=e??new TextEncoder().encode(V).length;t.disabled=o>rt||V.trim().length===0}function lt(){let e=document.getElementById("roles-preview");e&&(V.trim()?e.innerHTML=`<strong>${n("roles.preview")}</strong><pre>${l(V)}</pre>`:e.innerHTML=`<small>${n("roles.previewEmpty")}</small>`)}function Pt(){te=null,ne=null,V="";let e=document.getElementById("roles-editor-empty"),t=document.getElementById("roles-editor-form"),o=document.getElementById("roles-editor-textarea"),s=document.getElementById("roles-delete");e&&(e.style.display=""),t&&(t.style.display="none"),o&&(o.value=""),s&&(s.style.display="none")}async function jt(e){e.innerHTML=An(),Ce.clear(),Pt(),await _e();for(let t of Fe)Nt(t)>0&&Ce.add(t.chatId);$e(),document.getElementById("roles-search")?.addEventListener("input",t=>{$e(t.target.value)}),document.getElementById("roles-refresh")?.addEventListener("click",async()=>{if(await _e(),$e(document.getElementById("roles-search")?.value??""),te&&ne){let t=await Bt(ne,te),o=document.getElementById("roles-editor-textarea");o&&(o.value=t.content??""),V=t.content??"",it(),lt();let s=document.getElementById("roles-delete");s&&(s.style.display=t.hasRole?"":"none")}}),document.getElementById("roles-save")?.addEventListener("click",async function(){if(!(!te||!ne)){this.disabled=!0,this.textContent="...";try{if(await Dn(ne,te,V)){await _e(),$e(document.getElementById("roles-search")?.value??"");let o=document.getElementById("roles-delete");o&&(o.style.display="");let s=document.createElement("span");s.className="roles-saved-flash",s.textContent=` ${n("roles.saved")}`,document.querySelector(".roles-editor-footer")?.appendChild(s),setTimeout(()=>s.remove(),2e3)}else{let o=document.createElement("span");o.className="roles-saved-flash roles-save-error",o.textContent=V.trim().length===0?` ${n("roles.emptyError")}`:` ${n("roles.saveFailed")}`,document.querySelector(".roles-editor-footer")?.appendChild(o),setTimeout(()=>o.remove(),3e3)}}finally{this.disabled=!1,this.textContent=n("roles.save")}}}),document.getElementById("roles-delete")?.addEventListener("click",async function(){if(!(!te||!ne)&&confirm(n("roles.confirmDelete"))){this.disabled=!0,this.textContent="...";try{await Rn(ne,te)&&(await _e(),Pt(),$e(document.getElementById("roles-search")?.value??""))}finally{this.disabled=!1,this.textContent=n("roles.delete")}}}),document.getElementById("roles-editor-textarea")?.addEventListener("input",t=>{V=t.target.value,it(),lt()})}async function ze(e){let t=await fetch(e);return{status:t.status,body:await t.json().catch(()=>({}))}}async function Ge(e,t,o){let s=await fetch(t,{method:e,headers:{"content-type":"application/json"},body:o?JSON.stringify(o):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}var Le=(e,t)=>Ge("POST",e,t),Bn=(e,t)=>Ge("PUT",e,t),dt=[],Ut=[],_t="",Je="",ct=new Map,We=new Map,De=new Set,Re=new Set;function j(e){return document.getElementById(e)}function Qe(){return[...dt,...Ut]}function Se(e){let t=ct.get(e);return t||(t=new Set,ct.set(e,t)),t}function Nn(e){return Qe().find(t=>t.key===e)}function Ft(e){let t=(o,s,a)=>`<a href="${o}" style="padding:6px 14px;border-radius:8px;text-decoration:none;font-size:14px;${a?"background:var(--accent,#3370ff);color:#fff":"color:var(--text,#1f2329)"}">${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 jn(){return`<section class="page">
|
|
530
530
|
<div class="page-heading"><div>
|
|
531
531
|
<p class="eyebrow">\u56E2\u961F</p><h1>\u56E2\u961F\u534F\u4F5C\uFF08\u8DE8\u90E8\u7F72\uFF09</h1>
|
|
532
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>
|
|
533
533
|
</div></div>
|
|
534
|
-
${
|
|
534
|
+
${Ft("home")}
|
|
535
535
|
<div class="card" style="margin-bottom:16px">
|
|
536
536
|
<h2 style="margin-top:0">\u672C\u90E8\u7F72</h2>
|
|
537
537
|
<p>\u6211\u7684\u98DE\u4E66\u8EAB\u4EFD\uFF1A<b id="tf-owner">\u672A\u7ED1\u5B9A</b>
|
|
@@ -560,12 +560,12 @@ ${Ut("home")}
|
|
|
560
560
|
</div>
|
|
561
561
|
</div>
|
|
562
562
|
</div>
|
|
563
|
-
</section>`}function jn(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 Un(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===jt,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>`:"",T=`${e.key}::${a.id}`,k=Re.has(T),y=r.filter(c=>Se(e.key).has(c.larkAppId)).length;if(s+=`<div class="tf-dep-h" data-dk="${l(T)}" style="cursor:pointer;margin:10px 0 2px"><b>${k?"\u25BE":"\u25B8"} ${l(a.name)}</b> <span class="muted" style="font-size:12px">\uFF08${m}\uFF09\xB7 ${r.length} \u4E2A${y?`\uFF0C\u5DF2\u9009 ${y}`:""}</span>${$}</div>`,!!k){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(Je.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 he(){let e=j("tf-teams"),t=Ge();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(jn);m.forEach(y=>s.add(y.larkAppId)),i.bots.forEach(y=>a.add(y.larkAppId));let $=new Set(m.map(y=>y.larkAppId));[...Se(i.key)].forEach(y=>{$.has(y)||Se(i.key).delete(y)});let T=!De.has(i.key),k=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">${T?"\u25B8":"\u25BE"} ${l(i.label)}</b>`+(i.sub?` <span class="muted" style="font-size:12px">${l(i.sub)}</span>`:"")+k+` <span class="muted" style="font-size:12px">\xB7 ${i.deployments.length} \u4E2A\u90E8\u7F72 \xB7 ${i.bots.length} \u4E2A\u673A\u5668\u4EBA</span></div>`,T||(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>':Un(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),he()}}),e.querySelectorAll(".tf-dep-h").forEach(t=>{t.onclick=()=>{let o=t.dataset.dk;Re.has(o)?Re.delete(o):Re.add(o),he()}}),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=()=>{Je.set(t.dataset.tk,t.value)}}),e.querySelectorAll(".tf-cap").forEach(t=>{t.onchange=async()=>{let o=t.dataset.app,s=t.value;await Pn("/api/team/local-bots/"+encodeURIComponent(o)+"/capability",{capability:s}),Ge().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=()=>Jn(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 We("DELETE",`/api/team/hosted/${encodeURIComponent(t.dataset.team)}/members/${encodeURIComponent(t.dataset.dep)}`),qe())}}),e.querySelectorAll(".tf-grp").forEach(t=>{t.onclick=async()=>{let o=t.dataset.tk,s=Bn(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 Te("/api/team/federated-group",{name:i,larkAppIds:a,teamId:s.teamId}):await Te("/api/team/remote-group",{hubUrl:s.hubUrl,teamId:s.teamId,name:i,larkAppIds:a});if(_n(r,m.body,m.status),m.body?.ok){Se(o).clear(),Je.delete(o);let $=r.innerHTML,T=()=>{let k=e.querySelector(`.tf-gout[data-tk="${CSS.escape(o)}"]`);k&&(k.innerHTML=$)};s.kind==="local"?qe().then(T):(he(),T())}}})}function _n(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 Jn(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 Ft(){let e=Array.from(new Set(Ge().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 qe(){let t=(await ze("/api/team/hosted")).body;if(!t?.ok){dt=[],he();return}jt=t.deployment.deploymentId,_e=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||[]})),Ft(),he()}async function zn(){Nt=((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||[]}}),Ft(),he()}function _t(e){e.innerHTML=Nn(),ct.clear(),Je.clear(),De.clear(),Re.clear(),["tf-search","tf-cli","tf-fcap","tf-frole"].forEach(t=>{let o=j(t);o.oninput=he,o.onchange=he}),j("tf-modal-cancel").onclick=()=>{j("tf-modal").style.display="none"},Gn(),qe(),zn()}function Wn(){return`<section class="page">
|
|
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">
|
|
564
564
|
<div class="page-heading"><div>
|
|
565
565
|
<p class="eyebrow">\u56E2\u961F</p><h1>\u56E2\u961F\u7BA1\u7406</h1>
|
|
566
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>
|
|
567
567
|
</div></div>
|
|
568
|
-
${
|
|
568
|
+
${Ft("manage")}
|
|
569
569
|
<div class="card" style="margin-bottom:16px">
|
|
570
570
|
<h2 style="margin-top:0">\u6211\u6258\u7BA1\u7684\u56E2\u961F</h2>
|
|
571
571
|
<p style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:6px">
|
|
@@ -584,7 +584,7 @@ ${Ut("manage")}
|
|
|
584
584
|
</p>
|
|
585
585
|
<div id="tm-join-out" style="display:none;margin-top:6px"></div>
|
|
586
586
|
</div>
|
|
587
|
-
</section>`}async function ut(){let t=(await ze("/api/team/hosted")).body,o=j("tm-list");
|
|
587
|
+
</section>`}async function ut(){let t=(await ze("/api/team/hosted")).body,o=j("tm-list");Je=t?.suggestedHubUrl||Je;let s=t?.teams||[];if(!s.length){o.innerHTML='<p class="muted">\u8FD8\u6CA1\u6709\u56E2\u961F\u3002</p>';return}o.innerHTML=s.map(a=>{let r=(a.deployments||[]).filter(i=>!i.local).length;return`<div class="card" style="margin:0 0 8px;padding:10px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
588
588
|
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
589
589
|
<b>${l(a.name)}</b>${a.isDefault?' <span class="muted" style="font-size:12px">\u9ED8\u8BA4</span>':""}
|
|
590
590
|
<span class="muted" style="font-size:12px">\xB7 ${(a.deployments||[]).length} \u4E2A\u90E8\u7F72${r?`\uFF08\u542B ${r} \u8FDC\u7AEF\uFF09`:""} \xB7 ${(a.bots||[]).length} \u4E2A\u673A\u5668\u4EBA</span>
|
|
@@ -593,7 +593,7 @@ ${Ut("manage")}
|
|
|
593
593
|
${a.isDefault?"":`<button class="tm-del ghost" data-team="${l(a.teamId)}" data-name="${l(a.name)}" style="font-size:12px">\u5220\u9664</button>`}
|
|
594
594
|
</span>
|
|
595
595
|
</div>
|
|
596
|
-
<div class="tm-inv-out" data-team="${l(a.teamId)}" style="display:none;margin-top:6px;font-size:13px"></div></div>`}).join(""),o.querySelectorAll(".tm-invite").forEach(a=>{a.onclick=async()=>{let r=a.dataset.team,i=o.querySelector(`.tm-inv-out[data-team="${CSS.escape(r)}"]`);i.style.display="",i.innerHTML='<span class="muted">\u751F\u6210\u4E2D\u2026</span>';let m=await
|
|
596
|
+
<div class="tm-inv-out" data-team="${l(a.teamId)}" style="display:none;margin-top:6px;font-size:13px"></div></div>`}).join(""),o.querySelectorAll(".tm-invite").forEach(a=>{a.onclick=async()=>{let r=a.dataset.team,i=o.querySelector(`.tm-inv-out[data-team="${CSS.escape(r)}"]`);i.style.display="",i.innerHTML='<span class="muted">\u751F\u6210\u4E2D\u2026</span>';let m=await Le("/api/team/local-invite",{teamId:r});m.body?.code?i.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>${l(Je)}</code><br>\u9080\u8BF7\u7801\uFF1A<code style="font-size:15px">${l(m.body.code)}</code>`:i.innerHTML='<span class="err">\u751F\u6210\u5931\u8D25\u3002</span>'}}),o.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 Ge("DELETE","/api/team/hosted/"+encodeURIComponent(a.dataset.team)),ut())}})}function zt(e){e.innerHTML=Gn(),j("tm-create").onclick=async()=>{let t=j("tm-newname").value.trim(),o=e.querySelector(".tm-cout");if(!t){o.innerHTML='<span class="err">\u8BF7\u586B\u56E2\u961F\u540D\u79F0</span>';return}o.innerHTML='<span class="muted">\u521B\u5EFA\u4E2D\u2026</span>';let s=await Le("/api/team/hosted",{name:t});s.body?.ok?(o.innerHTML='<span class="ok">\u5DF2\u521B\u5EFA</span>',j("tm-newname").value="",ut()):o.innerHTML=`<span class="err">\u521B\u5EFA\u5931\u8D25\uFF1A${l(String(s.body?.error||s.status))}</span>`},j("tm-join").onclick=async()=>{let t=j("tm-hub").value.trim(),o=j("tm-code").value.trim(),s=j("tm-join-out");if(s.style.display="",!t||!o){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 Le("/api/team/join-remote",{hubUrl:t,inviteCode:o});if(a.body?.ok)s.innerHTML=`<span class="ok">\u5DF2\u52A0\u5165\u300C${l(a.body.teamName||"")}\u300D\uFF0C\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u67E5\u770B\u3002</span>`,j("tm-code").value="";else{let r=a.body?.error||a.status,i=r==="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":r==="deployment_already_joined"?"\u4F60\u7684\u90E8\u7F72\u5DF2\u7ECF\u52A0\u5165\u8FC7\u8FD9\u4E2A\u56E2\u961F\u4E86":r==="hub_unreachable"?"\u8FDE\u4E0D\u4E0A\u5BF9\u65B9 Hub\uFF08\u68C0\u67E5\u5730\u5740/\u7F51\u7EDC\uFF09":r==="hub_timeout"?"\u5BF9\u65B9 Hub \u54CD\u5E94\u8D85\u65F6":`\u52A0\u5165\u5931\u8D25\uFF1A${r}`;s.innerHTML=`<span class="err">${l(String(i))}</span>`}},ut()}function Qn(){j("tf-autobind").onclick=async()=>{let e=j("tf-bind-out");e.style.display="",e.innerHTML='<span class="muted">\u8BC6\u522B\u4E2D\u2026</span>';let o=(await Le("/api/team/identity/auto-bind")).body;if(o?.ok&&o.owner){e.innerHTML=`<span class="ok">\u5DF2\u7ED1\u5B9A\uFF1A${l(o.owner.name||o.owner.unionId)}</span>`,Oe();return}if(o?.ok&&o.needChoice&&Array.isArray(o.candidates)){let s=o.candidates.map(a=>`<button class="tf-pickowner ghost" data-union="${l(a.unionId)}" style="margin:2px">${l(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 i=(await Le("/api/team/identity/auto-bind",{unionId:a.dataset.union})).body;i?.ok&&i.owner?(e.innerHTML=`<span class="ok">\u5DF2\u7ED1\u5B9A\uFF1A${l(i.owner.name||i.owner.unionId)}</span>`,Oe()):e.innerHTML=`<span class="err">\u7ED1\u5B9A\u5931\u8D25\uFF1A${l(String(i?.error||"unknown"))}</span>`}});return}if(o?.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${l(String(o?.error||"unknown"))}</span>`}}async function Gt(e){let t=await fetch(e);return{status:t.status,body:await t.json().catch(()=>({}))}}async function ft(e,t,o){let s=await fetch(t,{method:e,headers:{"content-type":"application/json"},body:o?JSON.stringify(o):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}function G(e){return document.getElementById(e)}function X(e){return(G(e).value||"").trim()}var mt=[];function Kn(){return`<section class="page">
|
|
597
597
|
<div class="page-heading">
|
|
598
598
|
<div>
|
|
599
599
|
<p class="eyebrow">\u63A5\u5165\u70B9 \xB7 beta</p>
|
|
@@ -632,11 +632,11 @@ ${Ut("manage")}
|
|
|
632
632
|
<h2 style="margin-top:0">\u5DF2\u6709\u63A5\u5165\u70B9 <span class="muted" id="cn-count" style="font-size:13px"></span></h2>
|
|
633
633
|
<div id="cn-list">\u52A0\u8F7D\u4E2D\u2026</div>
|
|
634
634
|
</div>
|
|
635
|
-
</section>`}function pt(){let e=G("cn-kind").value,t=G("cn-mode").value;document.querySelectorAll(".cn-wf").forEach(o=>{o.style.display=e==="workflow"?"":"none"}),document.querySelectorAll(".cn-fixed").forEach(o=>{o.style.display=t==="fixed"?"":"none"}),document.querySelectorAll(".cn-allow").forEach(o=>{o.style.display=t==="fixed"?"none":""}),document.querySelectorAll(".cn-life").forEach(o=>{o.style.display=t==="new-group"?"":"none"})}function
|
|
635
|
+
</section>`}function pt(){let e=G("cn-kind").value,t=G("cn-mode").value;document.querySelectorAll(".cn-wf").forEach(o=>{o.style.display=e==="workflow"?"":"none"}),document.querySelectorAll(".cn-fixed").forEach(o=>{o.style.display=t==="fixed"?"":"none"}),document.querySelectorAll(".cn-allow").forEach(o=>{o.style.display=t==="fixed"?"none":""}),document.querySelectorAll(".cn-life").forEach(o=>{o.style.display=t==="new-group"?"":"none"})}function Qt(e){return`${location.origin}/webhook/${encodeURIComponent(e)}`}function Vn(e){return e==="fixed"?"\u56FA\u5B9A\u7FA4":e==="new-group"?"\u6BCF\u6B21\u65B0\u5EFA\u7FA4":"\u8BF7\u6C42\u6307\u5B9A\u7FA4"}function Yn(e){return e==="workflow"?"\u5DE5\u4F5C\u6D41":"\u5355\u8F6E"}function Xn(e){let t=G("cn-list");if(G("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(o=>{let s=mt.find(r=>r.larkAppId===o.target.botId),a=Qt(o.id);return`<div class="card" style="margin:0 0 10px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
636
636
|
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
637
637
|
<b style="font-size:15px">${l(o.name)}</b>
|
|
638
638
|
<span class="${o.enabled?"ok":"muted"}" style="font-size:12px">${o.enabled?"\u5DF2\u542F\u7528":"\u5DF2\u505C\u7528"}</span>
|
|
639
|
-
<span class="muted" style="font-size:12px">\xB7 ${l(s?.botName||o.target.botId)} \xB7 ${
|
|
639
|
+
<span class="muted" style="font-size:12px">\xB7 ${l(s?.botName||o.target.botId)} \xB7 ${Yn(o.target.kind)} \xB7 ${Vn(o.target.mode)}</span>
|
|
640
640
|
<span style="margin-left:auto;display:flex;gap:6px">
|
|
641
641
|
<button class="cn-toggle ghost" data-id="${l(o.id)}" data-on="${o.enabled}" style="font-size:12px">${o.enabled?"\u505C\u7528":"\u542F\u7528"}</button>
|
|
642
642
|
<button class="cn-del ghost" data-id="${l(o.id)}" style="font-size:12px">\u5220\u9664</button>
|
|
@@ -645,11 +645,11 @@ ${Ut("manage")}
|
|
|
645
645
|
<div style="margin-top:6px;font-size:13px;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
646
646
|
<span class="muted">Webhook URL\uFF1A</span><code style="font-size:12px;word-break:break-all">${l(a)}</code>
|
|
647
647
|
<button class="cn-copy ghost" data-url="${l(a)}" style="font-size:12px">\u590D\u5236</button>
|
|
648
|
-
</div></div>`}).join(""),t.querySelectorAll(".cn-copy").forEach(o=>{o.onclick=()=>{navigator.clipboard?.writeText(o.dataset.url),o.textContent="\u5DF2\u590D\u5236",setTimeout(()=>o.textContent="\u590D\u5236",1200)}}),t.querySelectorAll(".cn-toggle").forEach(o=>{o.onclick=async()=>{await ft("PATCH","/api/connectors/"+encodeURIComponent(o.dataset.id),{enabled:o.dataset.on!=="true"}),Ke()}}),t.querySelectorAll(".cn-del").forEach(o=>{o.onclick=async()=>{confirm("\u5220\u9664\u8FD9\u4E2A\u63A5\u5165\u70B9\uFF1F\u5B83\u7684 webhook URL \u4F1A\u7ACB\u5373\u5931\u6548\u3002")&&(await ft("DELETE","/api/connectors/"+encodeURIComponent(o.dataset.id)),Ke())}})}async function Ke(){let[e,t]=await Promise.all([
|
|
648
|
+
</div></div>`}).join(""),t.querySelectorAll(".cn-copy").forEach(o=>{o.onclick=()=>{navigator.clipboard?.writeText(o.dataset.url),o.textContent="\u5DF2\u590D\u5236",setTimeout(()=>o.textContent="\u590D\u5236",1200)}}),t.querySelectorAll(".cn-toggle").forEach(o=>{o.onclick=async()=>{await ft("PATCH","/api/connectors/"+encodeURIComponent(o.dataset.id),{enabled:o.dataset.on!=="true"}),Ke()}}),t.querySelectorAll(".cn-del").forEach(o=>{o.onclick=async()=>{confirm("\u5220\u9664\u8FD9\u4E2A\u63A5\u5165\u70B9\uFF1F\u5B83\u7684 webhook URL \u4F1A\u7ACB\u5373\u5931\u6548\u3002")&&(await ft("DELETE","/api/connectors/"+encodeURIComponent(o.dataset.id)),Ke())}})}async function Ke(){let[e,t]=await Promise.all([Gt("/api/bots"),Gt("/api/connectors")]);mt=(e.body?.bots||[]).map(a=>({larkAppId:a.larkAppId,botName:a.botName||a.larkAppId}));let o=G("cn-bot"),s=o.value;o.innerHTML=mt.map(a=>`<option value="${l(a.larkAppId)}">${l(a.botName)}</option>`).join("")||'<option value="">\uFF08\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF09</option>',s&&(o.value=s),Xn(t.body?.connectors||[])}function Kt(e){e.innerHTML=Kn(),G("cn-kind").onchange=pt,G("cn-mode").onchange=pt,pt(),G("cn-create").onclick=async()=>{let t=G("cn-create-out"),o=X("cn-name"),s=G("cn-bot").value;if(!o){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=G("cn-kind").value,r=G("cn-mode").value,i={name:o,enabled:!0,target:{kind:a,mode:r,botId:s},promptEnvelope:{sourceName:o}};if(a==="workflow"){if(!X("cn-wf")){t.innerHTML='<span class="err">\u8BF7\u586B\u5DE5\u4F5C\u6D41 ID</span>';return}i.target.workflowId=X("cn-wf")}if(r==="fixed"){if(!X("cn-chat")){t.innerHTML='<span class="err">\u56FA\u5B9A\u7FA4\u9700\u8981\u586B\u7FA4 ID</span>';return}i.target.chatId=X("cn-chat")}else{let L=X("cn-allow");L&&(i.target.allowChats=L.split(",").map(y=>y.trim()).filter(Boolean))}if(r==="new-group"){if(!X("cn-dedup")||!X("cn-status")){t.innerHTML='<span class="err">\u300C\u6BCF\u6B21\u65B0\u5EFA\u7FA4\u300D\u9700\u8981\u586B\u53BB\u91CD\u5B57\u6BB5\u548C\u72B6\u6001\u5B57\u6BB5</span>';return}i.lifecycleExtractors={dedupKey:X("cn-dedup"),status:X("cn-status")}}let m=X("cn-secret");m&&(i.secret=m),t.innerHTML='<span class="muted">\u521B\u5EFA\u4E2D\u2026</span>';let $=await ft("POST","/api/connectors",i);if($.status===201&&$.body?.ok){t.innerHTML="";let L=G("cn-created");L.style.display="";let y=$.body.webhookUrl||Qt($.body.connector.id),v=$.body.secret;L.innerHTML=`<div class="card" style="padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
649
649
|
<p class="ok" style="margin:0 0 6px">\u5DF2\u521B\u5EFA\u300C${l(o)}\u300D</p>
|
|
650
|
-
<p style="margin:4px 0;font-size:13px"><span class="muted">Webhook URL\uFF1A</span><code style="word-break:break-all">${l(
|
|
651
|
-
${
|
|
652
|
-
<p class="muted" style="font-size:12px;margin:6px 0 0">\u5916\u90E8\u7CFB\u7EDF\u7528\u6B64 URL + \u5BC6\u94A5\uFF08HMAC-SHA256 \u7B7E\u540D\uFF09\u8C03\u7528\u5373\u53EF\u89E6\u53D1\u3002</p></div>`,["cn-name","cn-wf","cn-chat","cn-allow","cn-dedup","cn-status","cn-secret"].forEach(c=>{G(c).value=""}),Ke()}else{let
|
|
650
|
+
<p style="margin:4px 0;font-size:13px"><span class="muted">Webhook URL\uFF1A</span><code style="word-break:break-all">${l(y)}</code></p>
|
|
651
|
+
${v?`<p style="margin:4px 0;font-size:13px"><span class="muted">\u7B7E\u540D\u5BC6\u94A5\uFF08\u53EA\u663E\u793A\u8FD9\u4E00\u6B21\uFF0C\u8BF7\u4FDD\u5B58\uFF09\uFF1A</span><code>${l(v)}</code></p>`:""}
|
|
652
|
+
<p class="muted" style="font-size:12px;margin:6px 0 0">\u5916\u90E8\u7CFB\u7EDF\u7528\u6B64 URL + \u5BC6\u94A5\uFF08HMAC-SHA256 \u7B7E\u540D\uFF09\u8C03\u7528\u5373\u53EF\u89E6\u53D1\u3002</p></div>`,["cn-name","cn-wf","cn-chat","cn-allow","cn-dedup","cn-status","cn-secret"].forEach(c=>{G(c).value=""}),Ke()}else{let L=$.body?.error||$.status;t.innerHTML=`<span class="err">\u521B\u5EFA\u5931\u8D25\uFF1A${l(String(L))}</span>`}},Ke()}function Zn(){let e=[["",n("workflow.filter.nonTerminal")],["all",n("workflow.filter.all")],["pending",he("pending")],["running",he("running")],["waiting",he("waiting")],["succeeded",he("succeeded")],["failed",he("failed")],["cancelled",he("cancelled")]];return`
|
|
653
653
|
<nav class="wf-subnav">
|
|
654
654
|
<a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${d(n("workflow.subnav.runs"))}</a>
|
|
655
655
|
<a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${d(n("workflow.subnav.catalog"))}</a>
|
|
@@ -669,15 +669,15 @@ ${Ut("manage")}
|
|
|
669
669
|
</tr></thead>
|
|
670
670
|
<tbody id="wf-tbody"></tbody>
|
|
671
671
|
</table>
|
|
672
|
-
`}var
|
|
672
|
+
`}var eo=5e3,to=2e3,qe=new Set(["succeeded","failed","cancelled"]);function d(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function no(e){let t=new Date(e),s=Date.now()-e;return s<6e4?n("time.secondsAgo",{value:Math.max(1,Math.floor(s/1e3))}):s<36e5?n("time.minutesAgo",{value:Math.floor(s/6e4)}):s<864e5?n("time.hoursAgo",{value:Math.floor(s/36e5)}):t.toISOString().slice(0,19).replace("T"," ")}function ce(e){return`<span class="${qe.has(e)?"wf-status terminal":"wf-status live"} wf-status-${d(e)}">${d(he(e))}</span>`}function he(e){let t=`workflow.status.${e}`,o=n(t);return o===t?e:o}function Zt(e){let t=location.hash.match(/^#\/workflows\/([^?#]+)(?:\?([^#]*))?$/);if(t){let o=new URLSearchParams(t[2]??"");return ao(e,decodeURIComponent(t[1]),{focusAttemptId:o.get("attempt")??void 0})}return oo(e)}function oo(e){e.innerHTML=Zn();let t=e.querySelector("#wf-tbody"),o=e.querySelector("#wf-filters"),s=e.querySelector("#wf-last-load"),a=[],r=null,i=!1,m=null,$=!1;function L(g){let S=(new FormData(o).get("q")??"").trim().toLowerCase();return S?g.filter(T=>T.runId.toLowerCase().includes(S)||T.workflowId.toLowerCase().includes(S)||(T.chatId??"").toLowerCase().includes(S)):g}function y(){let g=L(a);if(g.length===0){t.innerHTML=`<tr><td colspan="7" class="empty">${m?d(n("workflow.list.failedLoad",{error:m})):a.length===0?d(n("workflow.list.noRuns")):d(n("workflow.list.noFilterMatch"))}</td></tr>`;return}t.innerHTML=g.map(p=>{let S=`${p.dEf}/${p.dAct}/${p.dWait}`,T=p.dEf+p.dAct+p.dWait>0?"wf-dangling has":"wf-dangling none",k=[];p.chatId&&k.push(d(p.chatId)),p.larkAppId&&k.push(`<span class="muted">${d(p.larkAppId)}</span>`);let M=k.length>0?k.join("<br/>"):"\u2014",u=ro(p);return`<tr data-runid="${d(p.runId)}">
|
|
673
673
|
<td><a href="#/workflows/${encodeURIComponent(p.runId)}"><code>${d(p.runId)}</code></a></td>
|
|
674
674
|
<td>${d(p.workflowId)}</td>
|
|
675
675
|
<td>${ce(p.status)}${p.failedNodeId?` <span class="muted">(${d(p.failedNodeId)})</span>`:""}${u}</td>
|
|
676
676
|
<td>${p.lastSeq}</td>
|
|
677
|
-
<td class="${
|
|
678
|
-
<td title="${d(new Date(p.updatedAt).toISOString())}">${
|
|
679
|
-
<td>${
|
|
680
|
-
</tr>`}).join("")}function
|
|
677
|
+
<td class="${T}">${S}</td>
|
|
678
|
+
<td title="${d(new Date(p.updatedAt).toISOString())}">${no(p.updatedAt)}</td>
|
|
679
|
+
<td>${M}</td>
|
|
680
|
+
</tr>`}).join("")}function v(){m?(s.textContent=n("workflow.list.error",{error:m}),s.classList.add("error")):(s.textContent=n("workflow.list.loaded",{count:a.length,time:new Date().toLocaleTimeString()}),s.classList.remove("error"))}async function c(){if(!($||i)&&!document.hidden){i=!0;try{let g=o.elements.namedItem("status")?.value??"",p=new URLSearchParams;g==="all"?p.set("all","1"):g&&p.set("status",g);let S="/api/workflows/runs"+(p.toString()?`?${p}`:""),T=await fetch(S);T.ok?(a=(await T.json()).runs??[],m=null):(m=`HTTP ${T.status}`,a=[])}catch(g){m=g?.message??String(g),a=[]}finally{i=!1,$||(y(),v())}}}function I(){r!==null&&window.clearTimeout(r),r=window.setTimeout(async()=>{await c(),$||I()},eo)}function f(){document.hidden||c()}return o.addEventListener("input",()=>{y()}),o.addEventListener("change",g=>{g.target.getAttribute("name")==="status"&&c()}),document.addEventListener("visibilitychange",f),c().then(()=>{$||I()}),()=>{$=!0,r!==null&&window.clearTimeout(r),document.removeEventListener("visibilitychange",f)}}function ao(e,t,o={}){e.innerHTML=`
|
|
681
681
|
<div class="wf-detail-head">
|
|
682
682
|
<a class="btn-link" href="#/workflows">${d(n("workflow.detail.back"))}</a>
|
|
683
683
|
<div>
|
|
@@ -733,35 +733,35 @@ ${Ut("manage")}
|
|
|
733
733
|
</div>
|
|
734
734
|
<div id="wf-event-meta" class="muted"></div>
|
|
735
735
|
</section>
|
|
736
|
-
`;let s=e.querySelector("#wf-detail-subtitle"),a=e.querySelector("#wf-detail-refresh"),r=e.querySelector("#wf-detail-error"),i=e.querySelector("#wf-cancel-status"),m=e.querySelector("#wf-summary"),$=e.querySelector("#wf-dangling-panel"),
|
|
736
|
+
`;let s=e.querySelector("#wf-detail-subtitle"),a=e.querySelector("#wf-detail-refresh"),r=e.querySelector("#wf-detail-error"),i=e.querySelector("#wf-cancel-status"),m=e.querySelector("#wf-summary"),$=e.querySelector("#wf-dangling-panel"),L=e.querySelector("#wf-parallel-view"),y=e.querySelector("#wf-parallel-meta"),v=e.querySelector("#wf-node-tbody"),c=e.querySelector("#wf-io-list"),I=e.querySelector(".wf-timeline-scroll"),f=e.querySelector("#wf-event-tbody"),g=e.querySelector("#wf-event-meta"),p=e.querySelector("#wf-cancel-run"),S=e.querySelector("#wf-load-older"),T=null,k=[],M=new Set,u=null,w=null,h=!1,E=0,C=null,H=!1,U=!1,J=!1,P=new Set,Ie=new Map,ae=new Map,se=new Map,re=new Set,ye=new Map,Y=new Set,ie=new Map,He=new Map,ue=0,pe=o.focusAttemptId;function F(b){if(!b){r.hidden=!0,r.textContent="";return}r.hidden=!1,r.textContent=b}function ve(b){if(!b){i.hidden=!0,i.textContent="";return}i.hidden=!1,i.textContent=b}async function le(){let b=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/snapshot`);if(b.status===404)throw new Error(n("workflow.detail.unknownRun"));if(!b.ok)throw new Error(n("workflow.detail.snapshotHttp",{status:b.status}));T=await b.json()}async function de(b){let N=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/events?${b}`);if(N.status===404)throw new Error(n("workflow.detail.unknownRun"));if(!N.ok)throw new Error(n("workflow.detail.eventsHttp",{status:N.status}));return await N.json()}function fe(b,N){let D=b.filter(O=>M.has(O.eventId)?!1:(M.add(O.eventId),!0));D.length!==0&&(k=N==="prepend"?[...D,...k]:[...k,...D],k.sort((O,me)=>Pe(O.eventId)-Pe(me.eventId)))}async function Q(){await le();let b=await de(new URLSearchParams({tail:"100"}));k=[],M=new Set,fe(b.events,"append"),u=b.oldestSeq,w=b.newestSeq,h=b.hasOlder,E=b.totalCount,A()}async function ke(){if(!(H||U||document.hidden)){U=!0;try{if(await le(),w!==null){let b=await de(new URLSearchParams({afterSeq:String(w),limit:"200"}));fe(b.events,"append"),b.newestSeq!==null&&(w=b.newestSeq),u===null&&b.oldestSeq!==null&&(u=b.oldestSeq),E=b.totalCount}else{let b=await de(new URLSearchParams({tail:"1"}));fe(b.events,"append"),u=b.oldestSeq,w=b.newestSeq,h=b.hasOlder,E=b.totalCount}F(null),A()}catch(b){F(b?.message??String(b))}finally{U=!1}}}async function Ee(){if(!(u===null||!h)){S.disabled=!0;try{let b=await de(new URLSearchParams({beforeSeq:String(u),limit:"100"}));fe(b.events,"prepend"),b.oldestSeq!==null&&(u=b.oldestSeq),h=b.hasOlder,E=b.totalCount,F(null),A()}catch(b){F(b?.message??String(b))}finally{S.disabled=!1}}}async function vt(){if(!T||qe.has(T.run.status)||J)return;if(!T.chatBinding?.larkAppId){F(n("workflow.detail.cancelUnavailable",{runId:t}));return}let b=io(T),N=n("workflow.detail.cancelConfirm",{runId:t,...b});if(window.confirm(N)){J=!0,p.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(n("workflow.detail.writeAccessCancel"));let O=await D.json().catch(()=>({}));if(!D.ok||!O.ok)throw new Error(O.hint??O.error??n("workflow.detail.cancelHttp",{status:D.status}));ve(O.pending?n("workflow.detail.cancelPending"):null),F(null),await ke()}catch(D){F(D?.message??String(D))}finally{J=!1,p.disabled=!1,A()}}}async function W(b,N){if(!Y.has(b)){Y.add(b),ie.delete(b),A();try{let D=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/attempts/${encodeURIComponent(N)}/${encodeURIComponent(b)}/resume`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});if(D.status===401)throw new Error(n("workflow.detail.writeAccessResume"));let O=await D.json().catch(()=>({}));if(!D.ok||!O.ok||!O.resumeId||!O.url)throw new Error(O.hint??O.message??O.error??n("workflow.detail.resumeStartFailed",{status:D.status}));ye.set(b,{resumeId:O.resumeId,url:O.url})}catch(D){let O=D?.message??String(D);ie.set(b,O)}finally{Y.delete(b),A()}}}async function _(b,N){if(!Y.has(b)){Y.add(b),ie.delete(b),A();try{let D=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/attempts/${encodeURIComponent(N)}/${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(n("workflow.detail.writeAccessResume"));let O=await D.json().catch(()=>({}));if(!D.ok||!O.ok)if(O.error==="resume_not_running")ye.delete(b);else throw new Error(O.hint??O.message??O.error??n("workflow.detail.resumeEndFailed",{status:D.status}));else ye.delete(b)}catch(D){let O=D?.message??String(D);ie.set(b,O)}finally{Y.delete(b),A()}}}async function q(b,N){if(!re.has(b)){re.add(b),se.delete(b),A();try{let D=ae.get(b)?.trim()||void 0,O=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/${N}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({comment:D})});if(O.status===401)throw new Error(n("workflow.detail.writeAccessApproval"));let me=await O.json().catch(()=>({}));if(!O.ok||!me.ok)throw new Error(me.hint??me.message??me.error??n("workflow.detail.actionHttp",{action:N,status:O.status}));let et=N==="approve"?n("workflow.detail.approved"):n("workflow.detail.rejected");se.set(b,{kind:"ok",text:me.alreadyTerminal?n("workflow.detail.alreadyTerminal",{label:et}):me.pending?n("workflow.detail.workflowContinue",{label:et}):n("workflow.detail.workflowRefreshing",{label:et})}),F(null),await ke()}catch(D){let O=D?.message??String(D);se.set(b,{kind:"error",text:O}),F(O)}finally{re.delete(b),A()}}}function A(){if(!T)return;ue=I.scrollTop;let b=T.run;qe.has(b.status)&&ve(null),s.innerHTML=`${d(b.workflowId??"?")} \xB7 ${ce(b.status)} \xB7 lastSeq ${T.lastSeq}`,a.textContent=n("workflow.detail.refreshed",{time:new Date().toLocaleTimeString()}),p.hidden=qe.has(b.status),p.disabled=J||!T.chatBinding?.larkAppId,p.textContent=T.chatBinding?.larkAppId?n("workflow.detail.cancel"):n("workflow.detail.cliCancelOnly"),p.title=T.chatBinding?.larkAppId?n("workflow.detail.cancelTitle"):n("workflow.detail.cliCancelTitle",{runId:t}),so(m,T),lo($,T),co(L,y,T,k),wo(v,T),bo(c,T,P,Ie,{comments:ae,statuses:se,resolving:re,onResolve:q},{sessions:ye,pending:Y,errors:ie,onStart:W,onEnd:_},pe,He)&&(pe=void 0),Fo(f,k),I.scrollTop=ue,S.hidden=!h,g.textContent=n("workflow.detail.eventsLoaded",{loaded:k.length,total:E})}function R(){if(C!==null&&window.clearTimeout(C),T&&qe.has(T.run.status)){C=null;return}C=window.setTimeout(async()=>{await ke(),H||R()},to)}function B(){document.hidden||ke().then(()=>{!H&&C===null&&R()})}return S.addEventListener("click",()=>{Ee()}),p.addEventListener("click",()=>{vt()}),document.addEventListener("visibilitychange",B),Q().then(()=>{F(null),H||R()}).catch(b=>{F(b?.message??String(b)),s.textContent=n("workflow.detail.loadFailed")}),()=>{H=!0,C!==null&&window.clearTimeout(C),document.removeEventListener("visibilitychange",B)}}function so(e,t){let o=t.run,s=[[n("workflow.summary.workflow"),d(o.workflowId??"?")],[n("workflow.summary.status"),ce(o.status)],[n("workflow.summary.lastSeq"),String(t.lastSeq)],[n("workflow.summary.updated"),d(new Date(t.updatedAt).toLocaleString())],[n("workflow.summary.revision"),d(Xe(o.revisionId))],[n("workflow.summary.initiator"),d(o.initiator??"-")]];o.failedNodeId&&s.push([n("workflow.summary.failedNode"),d(o.failedNodeId)]),o.cancelOriginEventId&&s.push([n("workflow.summary.cancelOrigin"),d(o.cancelOriginEventId)]),t.chatBinding&&(s.push([n("workflow.summary.chat"),`<code>${d(t.chatBinding.chatId)}</code>`]),s.push([n("workflow.summary.app"),`<code>${d(t.chatBinding.larkAppId)}</code>`])),e.innerHTML=s.map(([a,r])=>`<div class="wf-summary-item"><span>${a}</span><strong>${r}</strong></div>`).join("")}function ro(e){if(!e.errorCode)return"";let t=e.errorMessage?` \u2014 ${Go(e.errorMessage,96)}`:"";return`<div class="wf-run-error">
|
|
737
737
|
<span class="muted error">${d(e.errorCode)}</span>${d(t)}
|
|
738
|
-
</div>`}function
|
|
738
|
+
</div>`}function io(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 lo(e,t){let o=t.dangling,s=[[n("workflow.dangling.activities"),o.activities],[n("workflow.dangling.effects"),o.effectAttempted],[n("workflow.dangling.waits"),o.waits],[n("workflow.dangling.cancels"),o.cancels]],a=new Set(s.flatMap(([,r])=>r)).size;if(e.className=a>0?"wf-panel wf-dangling-panel has":"wf-panel wf-dangling-panel",a===0){e.innerHTML=`<div class="wf-panel-title"><h3>${d(n("workflow.detail.dangling"))}</h3></div><div class="muted">${d(n("workflow.detail.noDangling"))}</div>`;return}e.innerHTML=`<div class="wf-panel-title"><h3>${d(n("workflow.detail.dangling"))}</h3><span class="wf-dangling has">${a}</span></div>
|
|
739
739
|
<div class="wf-dangling-grid">
|
|
740
740
|
${s.map(([r,i])=>`<div><strong>${r}</strong>${i.length===0?`<div class="muted">${d(n("workflow.detail.none"))}</div>`:`<ul>${i.map(m=>`<li><code>${d(m)}</code></li>`).join("")}</ul>`}</div>`).join("")}
|
|
741
|
-
</div>`}function
|
|
742
|
-
<span title="${d(new Date(i).toISOString())}">${d(
|
|
743
|
-
<span title="${d(new Date(m).toISOString())}">${d(
|
|
741
|
+
</div>`}function co(e,t,o,s){let a=uo(s,o);if(a.length===0){t.textContent="",e.innerHTML=`<div class="empty">${d(n("workflow.detail.noParallelData"))}</div>`;return}let r=Date.now(),i=Math.min(...a.map(c=>c.startedAt)),m=Math.max(...a.map(c=>c.endedAt??r),i+1e3),$=Math.max(1,m-i),L=fo(a,r),y=a.filter(c=>!c.endedAt&&(c.status==="running"||c.status==="effectAttempting")).length;t.textContent=n("workflow.detail.parallelMeta",{count:a.length,max:L,running:y});let v=a.sort((c,I)=>c.startedAt-I.startedAt||c.activityId.localeCompare(I.activityId)).map(c=>po(c,i,$,r)).join("");e.innerHTML=`<div class="wf-parallel-axis">
|
|
742
|
+
<span title="${d(new Date(i).toISOString())}">${d(Ye(i))}</span>
|
|
743
|
+
<span title="${d(new Date(m).toISOString())}">${d(Ye(m))}</span>
|
|
744
744
|
</div>
|
|
745
|
-
<div class="wf-parallel-list">${
|
|
745
|
+
<div class="wf-parallel-list">${v}</div>`}function uo(e,t){let o=new Map,s=new Map(t.activities.map(a=>[a.activityId,a.ownerNodeId]));for(let a of[...e].sort((r,i)=>Pe(r.eventId)-Pe(i.eventId))){let r=zo(a);if(!r)continue;let i=typeof r.activityId=="string"?r.activityId:void 0,m=typeof r.attemptId=="string"?r.attemptId:void 0;if(!i||!m)continue;let $=o.get(m);if(a.type==="attemptCreated"){let L=typeof r.attemptNumber=="number"?r.attemptNumber:void 0;$={nodeId:typeof r.nodeId=="string"?r.nodeId:s.get(i),activityId:i,attemptId:m,attemptNumber:L,status:"pending",startedAt:a.timestamp},o.set(m,$);continue}$||($={nodeId:s.get(i),activityId:i,attemptId:m,status:"pending",startedAt:a.timestamp},o.set(m,$)),a.type==="activityRunning"?($.status="running",$.runningAt=a.timestamp):a.type==="effectAttempted"?$.status="effectAttempting":a.type==="activityWaiting"||a.type==="waitCreated"?$.status="waiting":mo(a.type)&&($.status=go(a.type),$.endedAt=a.timestamp,$.endType=a.type)}return[...o.values()]}function po(e,t,o,s){let a=e.endedAt??s,r=Xt((e.startedAt-t)/o*100,0,100),i=Xt((Math.max(a,e.startedAt+1)-e.startedAt)/o*100,.7,100-r),m=e.nodeId??e.activityId,$=e.attemptNumber!==void 0?`#${e.attemptNumber}`:Xe(e.attemptId),L=[`${m} ${e.status}`,`${new Date(e.startedAt).toISOString()} \u2192 ${e.endedAt?new Date(e.endedAt).toISOString():n("workflow.detail.parallelNow")}`,e.endType?`end: ${e.endType}`:void 0].filter(Boolean).join(`
|
|
746
746
|
`);return`<div class="wf-parallel-row">
|
|
747
747
|
<div class="wf-parallel-label">
|
|
748
748
|
<code>${d(m)}</code>
|
|
749
749
|
<span class="muted">${d(e.activityId)} \xB7 ${d($)}</span>
|
|
750
750
|
</div>
|
|
751
751
|
<div class="wf-parallel-track">
|
|
752
|
-
<div class="wf-parallel-bar wf-parallel-${d(e.status)}" style="left:${r.toFixed(3)}%;width:${i.toFixed(3)}%;" title="${d(
|
|
753
|
-
<span>${d(
|
|
752
|
+
<div class="wf-parallel-bar wf-parallel-${d(e.status)}" style="left:${r.toFixed(3)}%;width:${i.toFixed(3)}%;" title="${d(L)}">
|
|
753
|
+
<span>${d(he(e.status))}</span>
|
|
754
754
|
</div>
|
|
755
755
|
</div>
|
|
756
|
-
</div>`}function
|
|
756
|
+
</div>`}function fo(e,t){let o=[];for(let r of e)o.push({time:r.startedAt,delta:1}),o.push({time:r.endedAt??t,delta:-1});o.sort((r,i)=>r.time-i.time||i.delta-r.delta);let s=0,a=0;for(let r of o)s+=r.delta,a=Math.max(a,s);return a}function mo(e){return e==="activitySucceeded"||e==="activityFailed"||e==="activityTimedOut"||e==="activityCanceled"}function go(e){return e==="activitySucceeded"?"succeeded":e==="activityCanceled"?"cancelled":e==="activityTimedOut"?"timedOut":"failed"}function wo(e,t){let o=new Map(t.activities.map(r=>[r.activityId,r])),s=new Set,a=[];for(let r of t.nodes){let i=(r.activityId?o.get(r.activityId):void 0)??t.activities.find(m=>m.ownerNodeId===r.nodeId);i&&s.add(i.activityId),a.push(Vt(r,i))}for(let r of t.activities)s.has(r.activityId)||a.push(Vt(void 0,r));e.innerHTML=a.length>0?a.join(""):`<tr><td colspan="7" class="empty">${d(n("workflow.detail.noNodes"))}</td></tr>`}function Vt(e,t){let o=t?.attempts[t.attempts.length-1];return`<tr>
|
|
757
757
|
<td>${e?`<code>${d(e.nodeId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
758
758
|
<td>${e?ce(e.status):'<span class="muted">-</span>'}</td>
|
|
759
759
|
<td>${t?`<code>${d(t.activityId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
760
760
|
<td>${t?ce(t.status):'<span class="muted">-</span>'}</td>
|
|
761
761
|
<td>${t?.attempts.length??0}</td>
|
|
762
762
|
<td>${o?`<code>${d(o.attemptId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
763
|
-
<td>${o?
|
|
764
|
-
</tr>`}function
|
|
763
|
+
<td>${o?_o(o):`<span class="muted">${d(n("workflow.detail.idle"))}</span>`}</td>
|
|
764
|
+
</tr>`}function bo(e,t,o,s,a,r,i,m){qo(e,o,s),Ao(e,a.comments);let $=!!(i&&t.attemptIO?.[i]?.terminal);$&&i&&o.add(gt(i,n("workflow.detail.liveTerminal")));let L=ho(t),y=new Set;if(m){for(let c of L){y.add(c.key);let I=m.get(c.key);I||(I=yo(c.key),m.set(c.key,I),e.appendChild(I.article)),vo(I,c,o,a,r,i)}for(let[c,I]of Array.from(m))y.has(c)||(I.article.remove(),m.delete(c));if(L.length===0){if(!e.querySelector(".wf-io-empty-placeholder")){let c=document.createElement("div");c.className="empty wf-io-empty-placeholder",c.textContent=n("workflow.detail.noNodeIO"),e.appendChild(c)}}else e.querySelector(".wf-io-empty-placeholder")?.remove()}else{let c=[];for(let I of L)c.push(To(I,o,a,r,i));e.innerHTML=c.length>0?c.join(""):`<div class="empty">${d(n("workflow.detail.noNodeIO"))}</div>`}Bo(e,s);let v=Oo(e,i);return Po(e,o),No(e,s),Ro(e,a),dn(e,r),v&&$}function ho(e){let t=new Map(e.activities.map(a=>[a.activityId,a])),o=new Set,s=[];for(let a of e.nodes){let r=(a.activityId?t.get(a.activityId):void 0)??e.activities.find(i=>i.ownerNodeId===a.nodeId);if(!r){s.push({key:`node:${a.nodeId}`,node:a});continue}o.add(r.activityId),s.push({key:`activity:${r.activityId}`,node:a,activity:r,io:e.attemptIO?.[Ve(r)?.attemptId??""]})}for(let a of e.activities)o.has(a.activityId)||s.push({key:`activity:${a.activityId}`,activity:a,io:e.attemptIO?.[Ve(a)?.attemptId??""]});return s}function yo(e){let t=document.createElement("article");t.className="wf-io-card",t.dataset.wfCardKey=e;let o=document.createElement("div");o.className="wf-io-card-head";let s=document.createElement("div");s.className="wf-io-terminal-slot";let a=document.createElement("div");return a.className="wf-io-grid",t.appendChild(o),t.appendChild(s),t.appendChild(a),{article:t,head:o,terminalSlot:s,grid:a,currentTerminalUrl:null}}function vo(e,t,o,s,a,r){let i=Ve(t.activity),m=t.node?.nodeId??t.activity?.ownerNodeId??t.activity?.activityId??"unknown",$=!!(i&&i.attemptId===r);e.article.classList.toggle("is-focused",$),i?e.article.dataset.wfAttemptCard=i.attemptId:delete e.article.dataset.wfAttemptCard;let L=ln(i,s);e.head.innerHTML=`
|
|
765
765
|
<header>
|
|
766
766
|
<div>
|
|
767
767
|
<strong><code>${d(m)}</code></strong>
|
|
@@ -772,23 +772,23 @@ ${Ut("manage")}
|
|
|
772
772
|
<div class="wf-io-meta">
|
|
773
773
|
${i?`${d(n("workflow.detail.attempt"))} <code>${d(i.attemptId)}</code>`:d(n("workflow.detail.noAttempt"))}
|
|
774
774
|
</div>
|
|
775
|
-
${
|
|
776
|
-
`;let
|
|
775
|
+
${L}
|
|
776
|
+
`;let y=en(i,t.activity,t.io?.terminal,a),v=y?.url??null;if(v!==e.currentTerminalUrl)y===null?e.terminalSlot.innerHTML="":e.terminalSlot.innerHTML=tn(t.key,i,t.activity,t.io?.terminal,y,o,a),e.currentTerminalUrl=v;else if(y!==null&&t.io?.terminal){let I=e.terminalSlot.querySelector("details.wf-terminal-block > summary");if(I){let f=nn(y.kind);I.innerHTML=`${d(f)} ${rn(i,t.io.terminal)}`}i&&Do(e.terminalSlot,i,t.activity,t.io.terminal,y,a)}let c=i?.attemptId??t.activity?.activityId??t.node?.nodeId??"unknown";e.grid.innerHTML=`
|
|
777
777
|
${oe(c,n("workflow.detail.authoredInput"),t.io?.input,o)}
|
|
778
778
|
${oe(c,n("workflow.detail.resolvedInput"),t.io?.resolvedInput,o)}
|
|
779
779
|
${oe(c,n("workflow.detail.output"),t.io?.output,o)}
|
|
780
780
|
${oe(c,n("workflow.detail.executionLog"),t.io?.log,o)}
|
|
781
781
|
${t.io?.waitPrompt?oe(c,n("workflow.detail.waitPrompt"),t.io.waitPrompt,o):""}
|
|
782
|
-
`}function
|
|
783
|
-
<summary>${d(m)} ${
|
|
782
|
+
`}function en(e,t,o,s){if(!o||o.error)return null;if(Io(e,o))return{kind:"live",url:Mo(o)};if(!e||!t||!Eo(e,o))return null;let a=Co();if(!a)return null;let r=s?.sessions.get(e.attemptId);return r?{kind:"resume",url:r.url,resumeId:r.resumeId,downloadUrl:Yt(a,t.activityId,e.attemptId)}:{kind:"replay",url:xo(a,t.activityId,e.attemptId,!!o.hasPtyLog),downloadUrl:Yt(a,t.activityId,e.attemptId)}}function tn(e,t,o,s,a,r,i){if(!s)return"";let m=nn(a.kind),$=gt(e,m),L=rn(t,s),y=ko(a.kind),v=a.kind==="replay"||a.kind==="resume"?`<a class="btn-link" href="${d(a.downloadUrl)}" download>${d(n("workflow.detail.downloadFullLog"))}</a>`:"",c=t?an(t,o,s,a,i):"",I=t?sn(t.attemptId,i):"";return`<details class="wf-io-block wf-terminal-block" data-io-key="${d($)}"${r.has($)?" open":""}>
|
|
783
|
+
<summary>${d(m)} ${L}</summary>
|
|
784
784
|
<div class="wf-terminal-actions">
|
|
785
|
-
<a class="btn-link" href="${d(a.url)}" target="_blank" rel="noreferrer">${d(
|
|
786
|
-
${
|
|
785
|
+
<a class="btn-link" href="${d(a.url)}" target="_blank" rel="noreferrer">${d(y)}</a>
|
|
786
|
+
${v}
|
|
787
787
|
${c}
|
|
788
788
|
</div>
|
|
789
789
|
${I}
|
|
790
790
|
<iframe class="wf-terminal-frame" src="${d(a.url)}" title="${d(m)}" loading="lazy"></iframe>
|
|
791
|
-
</details>`}function
|
|
791
|
+
</details>`}function nn(e){return e==="live"?n("workflow.detail.liveTerminal"):e==="resume"?n("workflow.detail.terminalResume"):n("workflow.detail.terminalReplay")}function ko(e){return e==="live"?n("workflow.detail.openTerminalNewTab"):e==="resume"?n("workflow.detail.openResumeNewTab"):n("workflow.detail.openReplayNewTab")}var on=new Set(["antigravity","codex-app","cursor","mira"]),$o=new Set(["aiden","coco","claude-code","seed","codex","mtr","hermes"]);function So(e){return!!e&&($o.has(e)||on.has(e))}function Lo(e){return!!e&&on.has(e)}function an(e,t,o,s,a){if(!a||s.kind==="live"||!t)return"";let r=s.kind==="resume",i=a.pending.has(e.attemptId),m=`data-wf-resume-attempt="${d(e.attemptId)}" data-wf-resume-activity="${d(t.activityId)}"`;return r?`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="end" ${m}${i?" disabled":""}>${d(i?n("workflow.detail.resumeEnding"):n("workflow.detail.endResumeSession"))}</button>`:So(o.cliId)?Lo(o.cliId)&&!o.cliSessionId?`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${d(n("workflow.detail.resumeMissingCliSession"))}">${d(n("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="start" ${m}${i?" disabled":""}>${d(i?n("workflow.detail.resumeStarting"):n("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${d(n("workflow.detail.resumeUnsupportedCli",{cliId:o.cliId??"?"}))}">${d(n("workflow.detail.resumeSession"))}</button>`}function sn(e,t){if(!t)return"";let o=t.errors.get(e);return o?`<div class="hint-warn wf-resume-status" data-wf-resume-status="${d(e)}">${d(o)}</div>`:""}function To(e,t,o,s,a){let r=Ve(e.activity),i=e.node?.nodeId??e.activity?.ownerNodeId??e.activity?.activityId??"unknown",m=r?.attemptId??e.activity?.activityId??e.node?.nodeId??"unknown",$=ln(r,o),L=r?.attemptId===a?" is-focused":"",y=r?` data-wf-attempt-card="${d(r.attemptId)}"`:"",v=en(r,e.activity,e.io?.terminal,s),c=v?tn(m,r,e.activity,e.io?.terminal,v,t,s):"";return`<article class="wf-io-card${L}" data-wf-card-key="${d(e.key)}"${y}>
|
|
792
792
|
<div class="wf-io-card-head">
|
|
793
793
|
<header>
|
|
794
794
|
<div>
|
|
@@ -810,7 +810,7 @@ ${Ut("manage")}
|
|
|
810
810
|
${oe(m,n("workflow.detail.executionLog"),e.io?.log,t)}
|
|
811
811
|
${e.io?.waitPrompt?oe(m,n("workflow.detail.waitPrompt"),e.io.waitPrompt,t):""}
|
|
812
812
|
</div>
|
|
813
|
-
</article>`}function
|
|
813
|
+
</article>`}function Ve(e){return e?.attempts[e.attempts.length-1]}function rn(e,t){let o=[];return t.error?o.push(n("workflow.detail.error")):o.push(t.status==="live"?n("workflow.detail.terminalLive"):n("workflow.detail.terminalClosedShort")),e?.status&&o.push(e.status),t.webPort>0&&o.push(`:${t.webPort}`),`<span class="muted">${d(o.join(" \xB7 "))}</span>`}function Io(e,t){return t.status==="live"&&t.webPort>0&&(e?.status==="pending"||e?.status==="running"||e?.status==="effectAttempting")}function Eo(e,t){return e.status==="succeeded"||e.status==="failed"||e.status==="cancelled"||e.status==="timedOut"?!!(t.sessionId||t.startedAt):!1}function Mo(e){return`http://${window.location.hostname||"127.0.0.1"}:${e.webPort}`}function xo(e,t,o,s){let a=new URLSearchParams({runId:e,activityId:t,attemptId:o});return s&&a.set("hasPtyLog","1"),`/assets/terminal-replay.html?${a.toString()}`}function Yt(e,t,o){return`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(t)}/${encodeURIComponent(o)}/terminal-log/raw?download=1`}function Co(){let e=window.location.hash.match(/^#\/workflows\/([^/?#]+)/);if(!e)return null;try{return decodeURIComponent(e[1])}catch{return null}}function ln(e,t){if(!Ho(e))return"";let o=e.attemptId,s=t.comments.get(o)??"",a=t.resolving.has(o),r=t.statuses.get(o),i=r?.kind==="error"?"hint-warn":"hint-ok";return`<div class="wf-approval-box" data-wf-approval="${d(o)}">
|
|
814
814
|
<label>
|
|
815
815
|
<span>${d(n("workflow.detail.approvalComment"))}</span>
|
|
816
816
|
<textarea class="wf-approval-comment" data-wf-approval-comment="${d(o)}" rows="2" placeholder="${d(n("workflow.detail.optionalComment"))}"${a?" disabled":""}>${d(s)}</textarea>
|
|
@@ -821,130 +821,158 @@ ${Ut("manage")}
|
|
|
821
821
|
${a?`<span class="muted">${d(n("workflow.detail.submitting"))}</span>`:""}
|
|
822
822
|
</div>
|
|
823
823
|
${r?`<div class="${i} wf-approval-status">${d(r.text)}</div>`:""}
|
|
824
|
-
</div>`}function Ho(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function
|
|
825
|
-
<summary>${d(t)} ${
|
|
826
|
-
${
|
|
827
|
-
</details>`}function gt(e,t){return`${e}:${t}`}function
|
|
824
|
+
</div>`}function Ho(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function Ao(e,t){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(o=>{let s=o.dataset.wfApprovalComment;s&&t.set(s,o.value)})}function dn(e,t){e.querySelectorAll("button[data-wf-resume-action][data-wf-resume-attempt][data-wf-resume-activity]").forEach(o=>{o.dataset.wfResumeBound!=="1"&&(o.dataset.wfResumeBound="1",o.addEventListener("click",()=>{let s=o.dataset.wfResumeAttempt,a=o.dataset.wfResumeActivity,r=o.dataset.wfResumeAction;!s||!a||(r==="start"?t.onStart(s,a):r==="end"&&t.onEnd(s,a))}))})}function Do(e,t,o,s,a,r){let i=e.querySelector(".wf-terminal-actions");if(!i)return;let m=i.querySelector('button[data-wf-resume-button="1"]'),$=an(t,o,s,a,r);m?m.outerHTML=$:$&&i.insertAdjacentHTML("beforeend",$);let L=e.querySelector("details.wf-terminal-block");if(L){let y=L.querySelector(".wf-resume-status"),v=sn(t.attemptId,r);y?y.outerHTML=v:v&&i.insertAdjacentHTML("afterend",v)}dn(e,r)}function Ro(e,t){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(o=>{let s=o.dataset.wfApprovalComment;s&&o.addEventListener("input",()=>{t.comments.set(s,o.value)})}),e.querySelectorAll("button[data-wf-approval-action][data-wf-attempt-id]").forEach(o=>{o.addEventListener("click",()=>{let s=o.dataset.wfAttemptId,a=o.dataset.wfApprovalAction;!s||a!=="approve"&&a!=="reject"||t.onResolve(s,a)})})}function oe(e,t,o,s){let a=gt(e,t);return`<details class="wf-io-block" data-io-key="${d(a)}"${s.has(a)?" open":""}>
|
|
825
|
+
<summary>${d(t)} ${jo(o)}</summary>
|
|
826
|
+
${Uo(o)}
|
|
827
|
+
</details>`}function gt(e,t){return`${e}:${t}`}function Oo(e,t){if(!t)return!1;for(let o of e.querySelectorAll("[data-wf-attempt-card]"))if(o.dataset.wfAttemptCard===t)return o.scrollIntoView({block:"center"}),!0;return!1}function qo(e,t,o){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 r=s.querySelector(".wf-io-pre");r&&o.set(a,r.scrollTop)})}function Po(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(o=>{o.dataset.ioToggleBound!=="1"&&(o.dataset.ioToggleBound="1",o.addEventListener("toggle",()=>{let s=o.dataset.ioKey;s&&(o.open?t.add(s):t.delete(s))}))})}function Bo(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(o=>{let s=o.dataset.ioKey;if(!s)return;let a=t.get(s);if(a===void 0)return;let r=o.querySelector(".wf-io-pre");r&&(r.scrollTop=a)})}function No(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(o=>{let s=o.dataset.ioKey;if(!s)return;let a=o.querySelector(".wf-io-pre");a&&a.dataset.ioScrollBound!=="1"&&(a.dataset.ioScrollBound="1",a.addEventListener("scroll",()=>{t.set(s,a.scrollTop)}))})}function jo(e){if(!e)return`<span class="muted">${d(n("workflow.detail.empty"))}</span>`;let t=[];return e.outputBytes!==void 0&&t.push(`${e.outputBytes}B`),e.truncated&&t.push(n("workflow.detail.truncated")),e.error&&t.push(n("workflow.detail.error")),e.outputHash&&t.push(Xe(e.outputHash)),t.length?`<span class="muted">${d(t.join(" \xB7 "))}</span>`:""}function Uo(e){if(!e)return`<div class="muted wf-io-empty">${d(n("workflow.detail.noData"))}</div>`;let t=e.value!==void 0?JSON.stringify(e.value,null,2):e.text??"",o=e.error?`<div class="muted error">${d(e.error)}</div>`:"";return t?`${o}<pre class="wf-io-pre">${d(t)}</pre>`:`${o}<div class="muted wf-io-empty">${d(n("workflow.detail.noPreview"))}</div>`}function _o(e){let t=[];if(e.effectAttempted&&t.push(`${d(n("workflow.detail.effect"))} ${d(e.effectAttempted.provider)}`),e.wait){let o=e.wait.resolution?`${e.wait.resolution.kind}${e.wait.resolution.resolution?":"+e.wait.resolution.resolution:""}`:n("workflow.detail.open");t.push(`${d(n("workflow.detail.wait"))} ${d(e.wait.waitKind)} ${d(o)}`),e.wait.deadlineAt!==void 0&&t.push(`${d(n("workflow.detail.deadline"))} ${d(Ye(e.wait.deadlineAt))}`)}if(e.error){let o=`${e.error.errorCode}${e.error.errorClass?` \xB7 ${e.error.errorClass}`:""}`;t.push(`<span class="muted error">${d(o)}</span>`),e.error.errorMessage&&t.push(`<span class="error wf-error-msg">${d(e.error.errorMessage)}</span>`)}return e.output&&t.push(`${d(n("workflow.detail.output"))} ${d(Xe(e.output.outputHash))}`),e.runningMs!==void 0&&t.push(`${e.runningMs}ms`),t.length>0?t.join("<br/>"):'<span class="muted">-</span>'}function Fo(e,t){e.innerHTML=t.length>0?t.map(Jo).join(""):`<tr><td colspan="7" class="empty">${d(n("workflow.detail.noEvents"))}</td></tr>`}function Jo(e){let t=Wo(e.payload);return`<tr>
|
|
828
828
|
<td>${Pe(e.eventId)}</td>
|
|
829
829
|
<td><code>${d(e.type)}</code></td>
|
|
830
830
|
<td>${d(e.actor)}</td>
|
|
831
831
|
<td>${t.nodeId?`<code>${d(t.nodeId)}</code>`:"-"}</td>
|
|
832
832
|
<td>${t.activityId?`<code>${d(t.activityId)}</code>`:"-"}</td>
|
|
833
833
|
<td>${t.errorCode?`<span class="muted error">${d(t.errorCode)}</span>`:"-"}</td>
|
|
834
|
-
<td title="${d(new Date(e.timestamp).toISOString())}">${d(
|
|
835
|
-
</tr>`}function Pe(e){let t=e.lastIndexOf("-");if(t<0)return 0;let o=Number(e.slice(t+1));return Number.isFinite(o)?o:0}function
|
|
834
|
+
<td title="${d(new Date(e.timestamp).toISOString())}">${d(Ye(e.timestamp))}</td>
|
|
835
|
+
</tr>`}function Pe(e){let t=e.lastIndexOf("-");if(t<0)return 0;let o=Number(e.slice(t+1));return Number.isFinite(o)?o:0}function Wo(e){if(!e||typeof e!="object"||"ref"in e)return{};let t=e,o={};typeof t.nodeId=="string"&&(o.nodeId=t.nodeId),typeof t.activityId=="string"&&(o.activityId=t.activityId),typeof t.failedNodeId=="string"&&(o.nodeId=t.failedNodeId);let s=t.error;return s&&typeof s=="object"&&"errorCode"in s&&(o.errorCode=String(s.errorCode)),o}function zo(e){return!e.payload||typeof e.payload!="object"||"ref"in e.payload?null:e.payload}function Xt(e,t,o){return Math.min(o,Math.max(t,e))}function Xe(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function Go(e,t){return e.length>t?e.slice(0,t-1)+"\u2026":e}function Ye(e){return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}function x(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function cn(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function un(e){let t=location.hash.match(/^#\/(?:workflows\/catalog|workflows-catalog)\/([^/?#]+)$/);return t?Ko(e,decodeURIComponent(t[1])):Qo(e)}function Qo(e){e.innerHTML=`
|
|
836
836
|
<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">${
|
|
837
|
+
<a href="#/workflows" data-i18n="workflow.subnav.runs">${x(n("workflow.subnav.runs"))}</a>
|
|
838
|
+
<a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${x(n("workflow.subnav.catalog"))}</a>
|
|
839
839
|
</nav>
|
|
840
840
|
<section class="catalog-head">
|
|
841
841
|
<div>
|
|
842
|
-
<h2>${
|
|
843
|
-
<p class="muted">${
|
|
842
|
+
<h2>${x(n("catalog.title"))}</h2>
|
|
843
|
+
<p class="muted">${x(n("catalog.subtitle"))}</p>
|
|
844
844
|
</div>
|
|
845
|
-
<button id="catalog-refresh" type="button">${
|
|
845
|
+
<button id="catalog-refresh" type="button">${x(n("catalog.refresh"))}</button>
|
|
846
846
|
</section>
|
|
847
847
|
<form id="catalog-filters" class="filters">
|
|
848
|
-
<input type="search" name="q" placeholder="${
|
|
848
|
+
<input type="search" name="q" placeholder="${x(n("catalog.searchPlaceholder"))}" />
|
|
849
849
|
<span id="catalog-status" class="muted"></span>
|
|
850
850
|
</form>
|
|
851
851
|
<div class="wf-table-scroll">
|
|
852
852
|
<table>
|
|
853
853
|
<thead><tr>
|
|
854
|
-
<th>${
|
|
855
|
-
<th>${
|
|
856
|
-
<th>${
|
|
857
|
-
<th>${
|
|
858
|
-
<th>${
|
|
859
|
-
<th>${
|
|
854
|
+
<th>${x(n("catalog.table.workflow"))}</th>
|
|
855
|
+
<th>${x(n("catalog.table.version"))}</th>
|
|
856
|
+
<th>${x(n("catalog.table.params"))}</th>
|
|
857
|
+
<th>${x(n("catalog.table.nodes"))}</th>
|
|
858
|
+
<th>${x(n("catalog.table.revision"))}</th>
|
|
859
|
+
<th>${x(n("catalog.table.path"))}</th>
|
|
860
860
|
</tr></thead>
|
|
861
861
|
<tbody id="catalog-tbody"></tbody>
|
|
862
862
|
</table>
|
|
863
863
|
</div>
|
|
864
|
-
`;let t=e.querySelector("#catalog-tbody"),o=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),a=e.querySelector("#catalog-refresh"),r=[],i=null,m=!1;function $(){let
|
|
864
|
+
`;let t=e.querySelector("#catalog-tbody"),o=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),a=e.querySelector("#catalog-refresh"),r=[],i=null,m=!1;function $(){let v=(new FormData(s).get("q")??"").trim().toLowerCase();return v?r.filter(c=>c.workflowId.toLowerCase().includes(v)||c.path.toLowerCase().includes(v)):r}function L(){i?(o.textContent=n("catalog.loadFailed",{error:i}),o.classList.add("error")):(o.textContent=`${r.length}`,o.classList.remove("error"));let v=$();if(v.length===0){t.innerHTML=`<tr><td colspan="6" class="empty">${r.length===0?x(n("catalog.noDefinitions")):x(n("catalog.noFilterMatch"))}</td></tr>`;return}t.innerHTML=v.map(c=>`
|
|
865
865
|
<tr>
|
|
866
|
-
<td><a href="#/workflows/catalog/${encodeURIComponent(c.workflowId)}"><code>${
|
|
866
|
+
<td><a href="#/workflows/catalog/${encodeURIComponent(c.workflowId)}"><code>${x(c.workflowId)}</code></a></td>
|
|
867
867
|
<td>${c.version}</td>
|
|
868
|
-
<td>${
|
|
868
|
+
<td>${x(n("catalog.paramSummary",{required:c.requiredParamCount,total:c.paramCount}))}</td>
|
|
869
869
|
<td>${c.nodeCount}</td>
|
|
870
|
-
<td><code>${
|
|
871
|
-
<td><code>${
|
|
870
|
+
<td><code>${x(cn(c.revisionId))}</code></td>
|
|
871
|
+
<td><code>${x(c.path)}</code></td>
|
|
872
872
|
</tr>
|
|
873
|
-
`).join("")}async function
|
|
873
|
+
`).join("")}async function y(){a.disabled=!0,o.textContent=n("catalog.loading");try{let v=await fetch("/api/workflows/definitions");if(!v.ok)throw new Error(`HTTP ${v.status}`);r=(await v.json()).definitions??[],i=null}catch(v){i=v?.message??String(v),r=[]}finally{a.disabled=!1,m||L()}}return s.addEventListener("input",L),a.addEventListener("click",()=>{y()}),y(),()=>{m=!0}}function Ko(e,t){e.innerHTML=`
|
|
874
874
|
<div class="catalog-detail-head">
|
|
875
|
-
<a class="btn-link" href="#/workflows/catalog">${
|
|
875
|
+
<a class="btn-link" href="#/workflows/catalog">${x(n("catalog.back"))}</a>
|
|
876
876
|
<div>
|
|
877
|
-
<h2><code>${
|
|
878
|
-
<div id="catalog-detail-subtitle" class="muted">${
|
|
877
|
+
<h2><code>${x(t)}</code></h2>
|
|
878
|
+
<div id="catalog-detail-subtitle" class="muted">${x(n("workflow.detail.loading"))}</div>
|
|
879
879
|
</div>
|
|
880
880
|
</div>
|
|
881
881
|
<section id="catalog-error" class="hint-warn" hidden></section>
|
|
882
882
|
<section id="catalog-run-status" class="hint-ok" hidden></section>
|
|
883
883
|
<div id="catalog-detail-body"></div>
|
|
884
|
-
`;let o=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),a=e.querySelector("#catalog-run-status"),r=e.querySelector("#catalog-detail-body"),i=null,m=!1,$=!1;function
|
|
884
|
+
`;let o=e.querySelector("#catalog-detail-subtitle"),s=e.querySelector("#catalog-error"),a=e.querySelector("#catalog-run-status"),r=e.querySelector("#catalog-detail-body"),i=null,m=!1,$=!1;function L(p){s.hidden=!p,s.textContent=p??""}function y(p){a.hidden=!p,a.textContent=p??""}function v(p){let S={};for(let[T,k]of Object.entries(p??{}))"default"in k&&(S[T]=k.default);return S}function c(){if(!i)return;let p=i.definition;o.textContent=`${n("catalog.revision")} ${cn(i.revisionId)} \xB7 ${i.path}`;let S=JSON.stringify(v(p.params),null,2);r.innerHTML=`
|
|
885
885
|
<section class="wf-panel">
|
|
886
|
-
<div class="wf-panel-title"><h3>${
|
|
886
|
+
<div class="wf-panel-title"><h3>${x(n("catalog.summary"))}</h3></div>
|
|
887
887
|
<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>${
|
|
888
|
+
<div class="wf-summary-item"><span>${x(n("catalog.table.workflow"))}</span><strong><code>${x(p.workflowId)}</code></strong></div>
|
|
889
|
+
<div class="wf-summary-item"><span>${x(n("catalog.table.version"))}</span><strong>${p.version}</strong></div>
|
|
890
|
+
<div class="wf-summary-item"><span>${x(n("catalog.nodeCount"))}</span><strong>${Object.keys(p.nodes).length}</strong></div>
|
|
891
|
+
<div class="wf-summary-item"><span>${x(n("catalog.path"))}</span><strong><code>${x(i.path)}</code></strong></div>
|
|
892
892
|
</div>
|
|
893
893
|
</section>
|
|
894
894
|
|
|
895
895
|
<section class="wf-panel">
|
|
896
|
-
<div class="wf-panel-title"><h3>${
|
|
896
|
+
<div class="wf-panel-title"><h3>${x(n("catalog.runPanel"))}</h3></div>
|
|
897
897
|
<form id="catalog-run-form" class="catalog-run-form">
|
|
898
898
|
<label>
|
|
899
|
-
<span>${
|
|
900
|
-
<textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${
|
|
899
|
+
<span>${x(n("catalog.paramsJson"))}</span>
|
|
900
|
+
<textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${x(n("catalog.paramsPlaceholder"))}">${x(S)}</textarea>
|
|
901
901
|
</label>
|
|
902
902
|
<div class="catalog-chat-grid">
|
|
903
903
|
<label>
|
|
904
|
-
<span>${
|
|
904
|
+
<span>${x(n("catalog.chatId"))}</span>
|
|
905
905
|
<input id="catalog-chat-id" type="text" autocomplete="off" />
|
|
906
906
|
</label>
|
|
907
907
|
<label>
|
|
908
|
-
<span>${
|
|
908
|
+
<span>${x(n("catalog.larkAppId"))}</span>
|
|
909
909
|
<input id="catalog-lark-app-id" type="text" autocomplete="off" />
|
|
910
910
|
</label>
|
|
911
911
|
</div>
|
|
912
|
-
<div class="muted">${
|
|
912
|
+
<div class="muted">${x(n("catalog.chatBindingHint"))}</div>
|
|
913
913
|
<div id="catalog-param-errors" class="catalog-param-errors" hidden></div>
|
|
914
|
-
<button id="catalog-run-btn" type="submit" class="primary">${
|
|
914
|
+
<button id="catalog-run-btn" type="submit" class="primary">${x(n("catalog.run"))}</button>
|
|
915
915
|
</form>
|
|
916
916
|
</section>
|
|
917
917
|
|
|
918
918
|
<section class="wf-panel">
|
|
919
|
-
<div class="wf-panel-title"><h3>${
|
|
920
|
-
${
|
|
919
|
+
<div class="wf-panel-title"><h3>${x(n("catalog.paramsSchema"))}</h3></div>
|
|
920
|
+
${Vo(p.params)}
|
|
921
921
|
</section>
|
|
922
922
|
|
|
923
923
|
<section class="wf-panel">
|
|
924
|
-
<div class="wf-panel-title"><h3>${
|
|
925
|
-
<pre class="wf-io-pre">${
|
|
924
|
+
<div class="wf-panel-title"><h3>${x(n("catalog.definitionJson"))}</h3></div>
|
|
925
|
+
<pre class="wf-io-pre">${x(JSON.stringify(p,null,2))}</pre>
|
|
926
926
|
</section>
|
|
927
|
-
`,f()}async function I(){if(!i||$)return;let p=r.querySelector("#catalog-params"),S=r.querySelector("#catalog-chat-id"),
|
|
927
|
+
`,f()}async function I(){if(!i||$)return;let p=r.querySelector("#catalog-params"),S=r.querySelector("#catalog-chat-id"),T=r.querySelector("#catalog-lark-app-id"),k=r.querySelector("#catalog-run-btn"),M=r.querySelector("#catalog-param-errors"),u;try{if(u=JSON.parse(p.value||"{}"),!u||typeof u!="object"||Array.isArray(u))throw new Error(n("catalog.badParamsJson"))}catch(w){M.hidden=!1,M.innerHTML=`<div class="muted error">${x(w?.message??String(w))}</div>`;return}$=!0,k.disabled=!0,k.textContent=n("catalog.running"),M.hidden=!0,L(null),y(null);try{let w=await fetch(`/api/workflows/definitions/${encodeURIComponent(i.definition.workflowId)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({params:u,chatBinding:{chatId:S.value.trim(),larkAppId:T.value.trim()}})});if(w.status===401)throw new Error(n("catalog.writeAccess"));let h=await w.json().catch(()=>({}));if(!w.ok||!h.ok)throw h.issues?.length&&(M.hidden=!1,M.innerHTML=`<strong>${x(n("catalog.invalidParams"))}</strong><ul>${h.issues.map(E=>`<li>${x(n("catalog.issue",{path:E.path.length?E.path.join("."):"(root)",message:E.message}))}</li>`).join("")}</ul>`),new Error(h.hint??h.message??h.error??n("catalog.runHttp",{status:w.status}));y(n("catalog.runStarted")),h.runId&&(location.hash=`#/workflows/${encodeURIComponent(h.runId)}`)}catch(w){L(w?.message??String(w))}finally{$=!1,k.disabled=!1,k.textContent=n("catalog.run")}}function f(){r.querySelector("#catalog-run-form")?.addEventListener("submit",S=>{S.preventDefault(),I()})}async function g(){try{let p=await fetch(`/api/workflows/definitions/${encodeURIComponent(t)}`);if(p.status===404)throw new Error("unknown_workflow");if(!p.ok)throw new Error(`HTTP ${p.status}`);i=await p.json(),L(null),c()}catch(p){L(n("catalog.definitionLoadFailed",{error:p?.message??String(p)})),o.textContent=n("workflow.detail.loadFailed")}}return g().then(()=>{}),()=>{m=!0}}function Vo(e){let t=Object.entries(e??{});return t.length===0?`<div class="muted">${x(n("catalog.noParams"))}</div>`:`<div class="catalog-param-list">${t.map(([o,s])=>`
|
|
928
928
|
<article class="catalog-param">
|
|
929
929
|
<header>
|
|
930
|
-
<code>${
|
|
931
|
-
<span class="wf-status">${
|
|
932
|
-
<span class="muted">${
|
|
930
|
+
<code>${x(o)}</code>
|
|
931
|
+
<span class="wf-status">${x(s.required?n("catalog.required"):n("catalog.optional"))}</span>
|
|
932
|
+
<span class="muted">${x(s.type)}${s.format?` \xB7 ${x(s.format)}`:""}</span>
|
|
933
933
|
</header>
|
|
934
|
-
${s.description?`<div class="muted">${
|
|
935
|
-
${"default"in s?`<pre class="wf-io-pre">${
|
|
934
|
+
${s.description?`<div class="muted">${x(n("catalog.description"))}: ${x(s.description)}</div>`:""}
|
|
935
|
+
${"default"in s?`<pre class="wf-io-pre">${x(`${n("catalog.default")}: ${JSON.stringify(s.default,null,2)}`)}</pre>`:""}
|
|
936
936
|
</article>
|
|
937
|
-
`).join("")}</div>`}var
|
|
937
|
+
`).join("")}</div>`}var Te=null,Ze=null;function Ne(){Ze!==null&&(window.clearInterval(Ze),Ze=null)}function bt(){return Te||(Te=document.createElement("dialog"),Te.className="onboarding-dialog",document.body.appendChild(Te),Te.addEventListener("close",Ne),Te)}function Yo(e){return e.status==="waiting_for_scan"?n("botOnboarding.waiting"):e.status==="verifying"?n("botOnboarding.verifying"):e.status==="configuring_permissions"?e.permissionStatusMsg?`${n("botOnboarding.configuringPermissions")} ${e.permissionStatusMsg}`:n("botOnboarding.configuringPermissions"):e.status==="waiting_for_platform_scan"?n("botOnboarding.platformScanHint"):e.status==="completed"?n("botOnboarding.completed"):e.status==="failed"?`${n("botOnboarding.failed")}: ${l(e.message??e.error??"unknown")}`:n("botOnboarding.starting")}function Xo(e){if(e.status!=="completed"||!e.permission)return"";let t=e.permission;if(t.ok){let s=[n("botOnboarding.permissionOk",{count:t.scopeCount??0})];t.skippedScopeCount&&t.skippedScopeCount>0&&s.push(n("botOnboarding.permissionSkipped",{count:t.skippedScopeCount})),t.versionId&&s.push(n("botOnboarding.permissionVersion",{version:l(t.versionId)}));let a=`<p class="hint-ok">\u2705 ${s.join(" ")}</p>`;return t.scopeWarning&&(a+=`<p class="hint-warn">\u26A0\uFE0F ${l(t.scopeWarning)}</p>`),a}let o=(e.remainingSteps??[]).map(s=>`<li><a href="${l(s.url)}" target="_blank" rel="noopener">${l(s.title)}</a></li>`).join("");return`<p class="hint-warn">\u26A0\uFE0F ${n("botOnboarding.permissionManual")}${t.message?`\uFF08${l(t.message)}\uFF09`:""}</p>`+(o?`<ol class="onboarding-steps">${o}</ol>`:"")}function Be(e){let t=bt(),o=e.status==="waiting_for_scan"&&e.qrDataUrl?`<div class="qr-card">
|
|
938
938
|
<img class="qr-image" src="${e.qrDataUrl}" alt="${n("botOnboarding.qrAlt")}">
|
|
939
|
-
${e.qrUrl?`<a class="onboarding-link" href="${e.qrUrl}" target="_blank" rel="noopener">${n("botOnboarding.openLink")}</a>`:""}
|
|
940
|
-
</div>`:"",s=e.
|
|
939
|
+
${e.qrUrl?`<a class="onboarding-link" href="${l(e.qrUrl)}" target="_blank" rel="noopener">${n("botOnboarding.openLink")}</a>`:""}
|
|
940
|
+
</div>`:"",s=e.status==="waiting_for_platform_scan"&&e.platformQrDataUrl?`<div class="qr-card">
|
|
941
|
+
<img class="qr-image" src="${e.platformQrDataUrl}" alt="${n("botOnboarding.platformQrAlt")}">
|
|
942
|
+
</div>`:"",a=e.appId?`<p><b>App ID:</b> <code>${l(e.appId)}</code>`+(e.cliId?` \uFF5C <b>CLI:</b> <code>${l(e.cliId)}</code>`:"")+(e.workingDir?` \uFF5C <b>${n("botOnboarding.metaDir")}:</b> <code>${l(e.workingDir)}</code>`:"")+"</p>":"",r=e.status==="completed"?`<p class="hint-ok">${n("botOnboarding.restartHint")}</p>`:"";t.innerHTML=`<article>
|
|
941
943
|
<header>
|
|
942
944
|
<h3>${n("botOnboarding.title")}</h3>
|
|
943
945
|
<p>${n("botOnboarding.intro")}</p>
|
|
944
946
|
</header>
|
|
945
|
-
<p class="onboarding-status status-${e.status}">${
|
|
947
|
+
<p class="onboarding-status status-${e.status}">${Yo(e)}</p>
|
|
946
948
|
${o}
|
|
947
949
|
${s}
|
|
948
950
|
${a}
|
|
951
|
+
${Xo(e)}
|
|
952
|
+
${r}
|
|
949
953
|
<form method="dialog"><button>${n("botOnboarding.close")}</button></form>
|
|
950
|
-
</article>`}async function
|
|
954
|
+
</article>`}async function Zo(){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 wt(e,t){let o=bt(),s=e.map(m=>`<option value="${l(m.id)}">${l(m.label)}\uFF08${l(m.id)}\uFF09</option>`).join(""),a=t?`<p class="form-error">${l(t)}</p>`:"";o.innerHTML=`<article>
|
|
955
|
+
<header>
|
|
956
|
+
<h3>${n("botOnboarding.title")}</h3>
|
|
957
|
+
<p>${n("botOnboarding.intro")}</p>
|
|
958
|
+
</header>
|
|
959
|
+
<form id="onboarding-form" class="onboarding-form">
|
|
960
|
+
<label class="onboarding-field">
|
|
961
|
+
<span>${n("botOnboarding.cliLabel")}</span>
|
|
962
|
+
<select id="ob-cli">${s}</select>
|
|
963
|
+
</label>
|
|
964
|
+
<label class="onboarding-field">
|
|
965
|
+
<span>${n("botOnboarding.dirLabel")}</span>
|
|
966
|
+
<input id="ob-dir" type="text" value="~" placeholder="${n("botOnboarding.dirPlaceholder")}" autocomplete="off" spellcheck="false">
|
|
967
|
+
</label>
|
|
968
|
+
<label class="onboarding-field">
|
|
969
|
+
<span>${n("botOnboarding.modelLabel")}</span>
|
|
970
|
+
<input id="ob-model" type="text" placeholder="${n("botOnboarding.modelPlaceholder")}" autocomplete="off" spellcheck="false">
|
|
971
|
+
</label>
|
|
972
|
+
${a}
|
|
973
|
+
<menu class="onboarding-actions">
|
|
974
|
+
<button type="button" id="ob-cancel">${n("botOnboarding.cancel")}</button>
|
|
975
|
+
<button type="submit" class="primary">${n("botOnboarding.startScan")}</button>
|
|
976
|
+
</menu>
|
|
977
|
+
</form>
|
|
978
|
+
</article>`;let r=o.querySelector("#onboarding-form");o.querySelector("#ob-cancel")?.addEventListener("click",()=>o.close()),r?.addEventListener("submit",m=>{m.preventDefault();let $=o.querySelector("#ob-cli")?.value??"",L=o.querySelector("#ob-dir")?.value??"",y=o.querySelector("#ob-model")?.value??"";ea({cliId:$,workingDir:L,model:y},e)})}async function ea(e,t){Ne(),Be({id:"",status:"starting"});try{let o=await fetch("/api/bot-onboarding/start",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({cliId:e.cliId,workingDir:e.workingDir.trim(),model:e.model.trim()||void 0})}),s=await o.json();if(o.status===400){wt(t,s?.message??s?.error??"invalid_input");return}if(!o.ok||!s?.job?.id)throw new Error(s?.error??`http_${o.status}`);Be(s.job),Ze=window.setInterval(()=>{ta(s.job.id).catch(a=>{Ne(),Be({id:s.job.id,status:"failed",message:a instanceof Error?a.message:String(a)})})},1200)}catch(o){Be({id:"",status:"failed",message:o instanceof Error?o.message:String(o)})}}async function ta(e){let t=await fetch(`/api/bot-onboarding/${encodeURIComponent(e)}`),o=await t.json();if(!t.ok||!o?.job)throw new Error(o?.error??`http_${t.status}`);Be(o.job),(o.job.status==="completed"||o.job.status==="failed")&&Ne()}async function na(){Ne();let e=bt();wt([{id:"claude-code",label:"Claude"}]),e.open||e.showModal();let t=await Zo();e.open&&e.querySelector("#onboarding-form")&&wt(t)}function pn(){let e=document.getElementById("add-bot-btn");e&&(e.onclick=()=>{na()})}var Z=document.getElementById("root"),fn=!1;function oa(){if(fn)return;fn=!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(--card,#fff);color:var(--text,#1f2329);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">\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\u3002<br>\u6700\u597D\u5173\u95ED\u5F53\u524D\u9875\u3002</p><button onclick="window.close()" style="padding:8px 22px;background:var(--accent,#3370ff);color:#fff;border:none;border-radius:8px;cursor:pointer;font-size:14px">\u5173\u95ED\u6B64\u9875</button></div>',document.body.appendChild(e)}var aa=window.fetch.bind(window);window.fetch=async function(...t){let o=await aa(...t);return o.status===401&&oa(),o};var je=null;function ht(){je&&(je(),je=null);let e=location.hash||"#/";e.startsWith("#/workflows/catalog")||e.startsWith("#/workflows-catalog")?je=un(Z):e.startsWith("#/workflows")?je=Zt(Z):e.startsWith("#/groups")?Dt(Z):e.startsWith("#/bot-defaults")?qt(Z):e.startsWith("#/connectors")?Kt(Z):e.startsWith("#/team/manage")?zt(Z):e.startsWith("#/team")?Wt(Z):e.startsWith("#/roles")?jt(Z):e.startsWith("#/schedules")?Ht(Z):e.startsWith("#/sessions")?xt(Z):Et(Z);for(let t of document.querySelectorAll(".sidebar-nav a")){let o=t.getAttribute("href")??"#/";t.classList.toggle("active",o===(e||"#/"))}}var yt=document.getElementById("status");function gn(){yt&&(yt.textContent=z.online?n("status.live"):n("status.disconnected"),yt.className="connection-status "+(z.online?"online":"offline"))}z.on(gn);function mn(){document.querySelectorAll("[data-i18n]").forEach(e=>{e.textContent=n(e.dataset.i18n??"")}),document.querySelectorAll("[data-locale]").forEach(e=>{e.classList.toggle("active",e.dataset.locale===ge.locale)}),document.querySelectorAll("[data-theme-mode]").forEach(e=>{e.classList.toggle("active",e.dataset.themeMode===ge.themeMode)}),gn()}function sa(){document.querySelectorAll("[data-locale]").forEach(e=>{e.onclick=()=>ge.setLocale(e.dataset.locale)}),document.querySelectorAll("[data-theme-mode]").forEach(e=>{e.onclick=()=>ge.setThemeMode(e.dataset.themeMode)})}(async()=>{ge.init(),sa(),pn(),ge.on(()=>{mn(),ht()}),mn();try{await kt()}catch(e){console.error("botmux dashboard bootstrap failed",e),z.setOnline(!1)}window.addEventListener("hashchange",ht),ht()})();})();
|