botmux 2.44.0 → 2.46.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/README.en.md +1 -2
- package/README.md +1 -2
- package/dist/cli/bots-list-output.d.ts +8 -0
- package/dist/cli/bots-list-output.d.ts.map +1 -1
- package/dist/cli/bots-list-output.js +9 -0
- package/dist/cli/bots-list-output.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +6 -0
- package/dist/cli.js.map +1 -1
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +601 -50
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts +2 -0
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +170 -2
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/role-resolver.d.ts +17 -1
- package/dist/core/role-resolver.d.ts.map +1 -1
- package/dist/core/role-resolver.js +64 -10
- package/dist/core/role-resolver.js.map +1 -1
- package/dist/core/session-manager.d.ts +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +24 -13
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/trigger-session.d.ts +9 -0
- package/dist/core/trigger-session.d.ts.map +1 -0
- package/dist/core/trigger-session.js +158 -0
- package/dist/core/trigger-session.js.map +1 -0
- package/dist/core/worker-pool.d.ts +105 -0
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +284 -4
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +80 -45
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/connector-api.d.ts +3 -0
- package/dist/dashboard/connector-api.d.ts.map +1 -0
- package/dist/dashboard/connector-api.js +351 -0
- package/dist/dashboard/connector-api.js.map +1 -0
- package/dist/dashboard/federated-group-core.d.ts +54 -0
- package/dist/dashboard/federated-group-core.d.ts.map +1 -0
- package/dist/dashboard/federated-group-core.js +165 -0
- package/dist/dashboard/federated-group-core.js.map +1 -0
- package/dist/dashboard/federation-api.d.ts +42 -0
- package/dist/dashboard/federation-api.d.ts.map +1 -0
- package/dist/dashboard/federation-api.js +408 -0
- package/dist/dashboard/federation-api.js.map +1 -0
- package/dist/dashboard/federation-spoke-api.d.ts +76 -0
- package/dist/dashboard/federation-spoke-api.d.ts.map +1 -0
- package/dist/dashboard/federation-spoke-api.js +618 -0
- package/dist/dashboard/federation-spoke-api.js.map +1 -0
- package/dist/dashboard/team-group.d.ts +18 -0
- package/dist/dashboard/team-group.d.ts.map +1 -0
- package/dist/dashboard/team-group.js +7 -0
- package/dist/dashboard/team-group.js.map +1 -0
- package/dist/dashboard/trigger-api.d.ts +13 -0
- package/dist/dashboard/trigger-api.d.ts.map +1 -0
- package/dist/dashboard/trigger-api.js +77 -0
- package/dist/dashboard/trigger-api.js.map +1 -0
- package/dist/dashboard/web/app.js +8 -0
- package/dist/dashboard/web/app.js.map +1 -1
- package/dist/dashboard/web/connectors.d.ts +2 -0
- package/dist/dashboard/web/connectors.d.ts.map +1 -0
- package/dist/dashboard/web/connectors.js +187 -0
- package/dist/dashboard/web/connectors.js.map +1 -0
- package/dist/dashboard/web/team-federation.d.ts +3 -0
- package/dist/dashboard/web/team-federation.d.ts.map +1 -0
- package/dist/dashboard/web/team-federation.js +487 -0
- package/dist/dashboard/web/team-federation.js.map +1 -0
- package/dist/dashboard/webhook-routes.d.ts +19 -0
- package/dist/dashboard/webhook-routes.d.ts.map +1 -0
- package/dist/dashboard/webhook-routes.js +321 -0
- package/dist/dashboard/webhook-routes.js.map +1 -0
- package/dist/dashboard-web/app.js +509 -386
- package/dist/dashboard-web/index.html +2 -0
- package/dist/dashboard.js +152 -1
- package/dist/dashboard.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +85 -8
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +85 -8
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/card-builder.d.ts +82 -0
- package/dist/im/lark/card-builder.d.ts.map +1 -1
- package/dist/im/lark/card-builder.js +315 -0
- package/dist/im/lark/card-builder.js.map +1 -1
- package/dist/im/lark/card-handler.d.ts.map +1 -1
- package/dist/im/lark/card-handler.js +195 -1
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/client.d.ts +45 -0
- package/dist/im/lark/client.d.ts.map +1 -1
- package/dist/im/lark/client.js +169 -18
- package/dist/im/lark/client.js.map +1 -1
- package/dist/im/lark/message-parser.d.ts.map +1 -1
- package/dist/im/lark/message-parser.js +1 -0
- package/dist/im/lark/message-parser.js.map +1 -1
- package/dist/services/bot-owner-store.d.ts +28 -0
- package/dist/services/bot-owner-store.d.ts.map +1 -0
- package/dist/services/bot-owner-store.js +82 -0
- package/dist/services/bot-owner-store.js.map +1 -0
- package/dist/services/bot-profile-store.d.ts +16 -0
- package/dist/services/bot-profile-store.d.ts.map +1 -0
- package/dist/services/bot-profile-store.js +98 -0
- package/dist/services/bot-profile-store.js.map +1 -0
- package/dist/services/connector-store.d.ts +58 -0
- package/dist/services/connector-store.d.ts.map +1 -0
- package/dist/services/connector-store.js +79 -0
- package/dist/services/connector-store.js.map +1 -0
- package/dist/services/deployment-identity.d.ts +22 -0
- package/dist/services/deployment-identity.d.ts.map +1 -0
- package/dist/services/deployment-identity.js +67 -0
- package/dist/services/deployment-identity.js.map +1 -0
- package/dist/services/federation-membership-store.d.ts +23 -0
- package/dist/services/federation-membership-store.d.ts.map +1 -0
- package/dist/services/federation-membership-store.js +66 -0
- package/dist/services/federation-membership-store.js.map +1 -0
- package/dist/services/federation-roster.d.ts +54 -0
- package/dist/services/federation-roster.d.ts.map +1 -0
- package/dist/services/federation-roster.js +51 -0
- package/dist/services/federation-roster.js.map +1 -0
- package/dist/services/federation-store.d.ts +76 -0
- package/dist/services/federation-store.d.ts.map +1 -0
- package/dist/services/federation-store.js +133 -0
- package/dist/services/federation-store.js.map +1 -0
- package/dist/services/group-creator.d.ts +6 -0
- package/dist/services/group-creator.d.ts.map +1 -1
- package/dist/services/group-creator.js +10 -1
- package/dist/services/group-creator.js.map +1 -1
- package/dist/services/groups-store.d.ts +11 -0
- package/dist/services/groups-store.d.ts.map +1 -1
- package/dist/services/groups-store.js +42 -0
- package/dist/services/groups-store.js.map +1 -1
- package/dist/services/invite-store.d.ts +28 -0
- package/dist/services/invite-store.d.ts.map +1 -0
- package/dist/services/invite-store.js +85 -0
- package/dist/services/invite-store.js.map +1 -0
- package/dist/services/pairing-store.d.ts +47 -0
- package/dist/services/pairing-store.d.ts.map +1 -0
- package/dist/services/pairing-store.js +132 -0
- package/dist/services/pairing-store.js.map +1 -0
- package/dist/services/relay-picker.d.ts +22 -0
- package/dist/services/relay-picker.d.ts.map +1 -0
- package/dist/services/relay-picker.js +62 -0
- package/dist/services/relay-picker.js.map +1 -0
- package/dist/services/team-roster.d.ts +38 -0
- package/dist/services/team-roster.d.ts.map +1 -0
- package/dist/services/team-roster.js +82 -0
- package/dist/services/team-roster.js.map +1 -0
- package/dist/services/team-store.d.ts +54 -0
- package/dist/services/team-store.d.ts.map +1 -0
- package/dist/services/team-store.js +156 -0
- package/dist/services/team-store.js.map +1 -0
- package/dist/services/trigger-log-store.d.ts +46 -0
- package/dist/services/trigger-log-store.d.ts.map +1 -0
- package/dist/services/trigger-log-store.js +132 -0
- package/dist/services/trigger-log-store.js.map +1 -0
- package/dist/services/trigger-types.d.ts +57 -0
- package/dist/services/trigger-types.d.ts.map +1 -0
- package/dist/services/trigger-types.js +28 -0
- package/dist/services/trigger-types.js.map +1 -0
- package/dist/services/webhook-key.d.ts +16 -0
- package/dist/services/webhook-key.d.ts.map +1 -0
- package/dist/services/webhook-key.js +123 -0
- package/dist/services/webhook-key.js.map +1 -0
- package/dist/services/webhook-lifecycle-extractors.d.ts +15 -0
- package/dist/services/webhook-lifecycle-extractors.d.ts.map +1 -0
- package/dist/services/webhook-lifecycle-extractors.js +59 -0
- package/dist/services/webhook-lifecycle-extractors.js.map +1 -0
- package/dist/services/webhook-lifecycle-store.d.ts +45 -0
- package/dist/services/webhook-lifecycle-store.d.ts.map +1 -0
- package/dist/services/webhook-lifecycle-store.js +159 -0
- package/dist/services/webhook-lifecycle-store.js.map +1 -0
- package/dist/setup/verify-permissions.d.ts.map +1 -1
- package/dist/setup/verify-permissions.js +4 -0
- package/dist/setup/verify-permissions.js.map +1 -1
- package/dist/skills/definitions.d.ts.map +1 -1
- package/dist/skills/definitions.js +64 -10
- package/dist/skills/definitions.js.map +1 -1
- package/dist/types.d.ts +14 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/daemon-discovery.d.ts +11 -0
- package/dist/utils/daemon-discovery.d.ts.map +1 -0
- package/dist/utils/daemon-discovery.js +59 -0
- package/dist/utils/daemon-discovery.js.map +1 -0
- package/dist/workflows/events/payloads.d.ts +2 -2
- package/dist/workflows/events/schema.d.ts +8 -8
- package/dist/workflows/trigger-from-envelope.d.ts +13 -0
- package/dist/workflows/trigger-from-envelope.d.ts.map +1 -0
- package/dist/workflows/trigger-from-envelope.js +67 -0
- package/dist/workflows/trigger-from-envelope.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
"use strict";(()=>{var Me=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 r=this.sessions.get(o.sessionId);r&&this.sessions.set(o.sessionId,{...r,...o.patch})}else if(t==="session.exited"){let r=this.sessions.get(o.sessionId);r&&this.sessions.set(o.sessionId,{...r,status:"closed"})}else if(t==="schedule.created")this.schedules.set(o.schedule.id,o.schedule);else if(t==="schedule.updated"){let r=this.schedules.get(o.id);r&&this.schedules.set(o.id,{...r,...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()}},P=new Me;async function Je(){let[e,t]=await Promise.all([fetch("/api/sessions").then(a=>a.json()),fetch("/api/schedules").then(a=>a.json())]);P.upsertSessions(e.sessions??[]),P.upsertSchedules(t.schedules??[]);let o=new EventSource("/events"),r=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let a of r)o.addEventListener(a,s=>{try{let d=JSON.parse(s.data);P.applySse(a,d.body??d)}catch{}});o.onerror=()=>P.setOnline(!1),o.onopen=()=>P.setOnline(!0)}var Ae="botmux.dashboard.locale",qt={"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\uFF0C\u672C\u9879\u4E0D\u751F\u6548","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","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 We=class{sessions=new Map;schedules=new Map;online=!0;listeners=new Set;upsertSessions(t){for(let n of t)this.sessions.set(n.sessionId,n);this.emit()}upsertSchedules(t){for(let n of t)this.schedules.set(n.id,n);this.emit()}applySse(t,n){if(t==="session.spawned")this.sessions.set(n.session.sessionId,n.session);else if(t==="session.update"){let s=this.sessions.get(n.sessionId);s&&this.sessions.set(n.sessionId,{...s,...n.patch})}else if(t==="session.exited"){let s=this.sessions.get(n.sessionId);s&&this.sessions.set(n.sessionId,{...s,status:"closed"})}else if(t==="schedule.created")this.schedules.set(n.schedule.id,n.schedule);else if(t==="schedule.updated"){let s=this.schedules.get(n.id);s&&this.schedules.set(n.id,{...s,...n.patch})}else if(t==="schedule.deleted")this.schedules.delete(n.id);else return;this.emit()}setOnline(t){this.online!==t&&(this.online=t,this.emit())}on(t){return this.listeners.add(t),()=>this.listeners.delete(t)}emit(){for(let t of this.listeners)t()}},N=new We;async function pt(){let[e,t]=await Promise.all([fetch("/api/sessions").then(a=>a.json()),fetch("/api/schedules").then(a=>a.json())]);N.upsertSessions(e.sessions??[]),N.upsertSchedules(t.schedules??[]);let n=new EventSource("/events"),s=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let a of s)n.addEventListener(a,r=>{try{let i=JSON.parse(r.data);N.applySse(a,i.body??i)}catch{}});n.onerror=()=>N.setOnline(!1),n.onopen=()=>N.setOnline(!0)}var ze="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":"\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\uFF0C\u672C\u9879\u4E0D\u751F\u6548","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","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"},
|
|
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"},gn={"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","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"},ft={zh:wn,en:gn};function mt(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 n=mt(t);if(n)return n}return"zh"}function Me(e){return(t,n)=>{let s=ft[e][t]??ft.zh[t]??t;return n?s.replace(/\{(\w+)\}/g,(a,r)=>{let i=n[r];return i==null?`{${r}}`:String(i)}):s}}function wt(e,t){return(e?mt(e.getItem(ze)):null)??hn(t)}var Je="botmux.dashboard.theme";function bn(e){return e==="system"||e==="light"||e==="dark"?e:null}function gt(e,t){return e==="system"?t?"dark":"light":e}function ht(e){return bn(e?.getItem(Je))??"system"}var Ge=class{locale="zh";themeMode="system";resolvedTheme="light";listeners=new Set;translate=Me(this.locale);mediaQuery=null;init(){let t=typeof window<"u"?window:void 0;this.locale=wt(t?.localStorage,yn()),this.translate=Me(this.locale),this.themeMode=ht(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,n){return this.translate(t,n)}setLocale(t){this.locale!==t&&(this.locale=t,this.translate=Me(t),window.localStorage.setItem(ze,t),this.applyLocale(),this.emit())}setThemeMode(t){this.themeMode!==t&&(this.themeMode=t,window.localStorage.setItem(Je,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=gt(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 yn(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var ae=new Ge;function o(e,t){return ae.t(e,t)}function d(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function be(e){if(!e)return"-";let t=Date.now()-e;return t<6e4?o("common.now"):t<36e5?Math.floor(t/6e4)+"m":t<864e5?Math.floor(t/36e5)+"h":Math.floor(t/864e5)+"d"}var Ke={chats:[],bots:[]};async function vn(){try{let e=await fetch("/api/groups");if(!e.ok)return;Ke=await e.json()}catch{}}function kn(e){return`status status-${d(e||"unknown")}`}function $n(e){return`<li class="overview-list-row">
|
|
14
14
|
<div>
|
|
15
|
-
<strong>${
|
|
16
|
-
<span>${
|
|
15
|
+
<strong>${d(e.title??e.sessionId)}</strong>
|
|
16
|
+
<span>${d(e.botName??"")} \xB7 ${d(e.cliId??"unknown")}</span>
|
|
17
17
|
</div>
|
|
18
|
-
<span class="${
|
|
19
|
-
</li>`}function
|
|
18
|
+
<span class="${kn(e.status)}">${d(e.status??"unknown")}</span>
|
|
19
|
+
</li>`}function Sn(e){let t=e.nextRunAt?new Date(e.nextRunAt).toLocaleString():"-";return`<li class="overview-list-row">
|
|
20
20
|
<div>
|
|
21
|
-
<strong>${
|
|
22
|
-
<span>${
|
|
21
|
+
<strong>${d(e.name??e.id)}</strong>
|
|
22
|
+
<span>${d(e.botName??e.larkAppId??"")} \xB7 ${d(e.parsed?.display??"")}</span>
|
|
23
23
|
</div>
|
|
24
|
-
<span>${
|
|
25
|
-
</li>`}async function
|
|
24
|
+
<span>${d(t)}</span>
|
|
25
|
+
</li>`}async function bt(e){e.innerHTML=`<section class="page hero-page">
|
|
26
26
|
<div class="page-heading">
|
|
27
27
|
<div>
|
|
28
|
-
<p class="eyebrow">${
|
|
29
|
-
<h1>${
|
|
30
|
-
<p>${
|
|
28
|
+
<p class="eyebrow">${o("app.subtitle")}</p>
|
|
29
|
+
<h1>${o("overview.title")}</h1>
|
|
30
|
+
<p>${o("overview.subtitle")}</p>
|
|
31
31
|
</div>
|
|
32
32
|
</div>
|
|
33
33
|
<div class="metric-grid" id="overview-metrics"></div>
|
|
@@ -35,251 +35,251 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
35
35
|
<section class="panel">
|
|
36
36
|
<header class="panel-header">
|
|
37
37
|
<div>
|
|
38
|
-
<h2>${
|
|
39
|
-
<p>${
|
|
38
|
+
<h2>${o("overview.recentSessions")}</h2>
|
|
39
|
+
<p>${o("sessions.subtitle")}</p>
|
|
40
40
|
</div>
|
|
41
|
-
<a class="btn-link" href="#/sessions">${
|
|
41
|
+
<a class="btn-link" href="#/sessions">${o("nav.sessions")}</a>
|
|
42
42
|
</header>
|
|
43
43
|
<ul class="overview-list" id="recent-sessions"></ul>
|
|
44
44
|
</section>
|
|
45
45
|
<section class="panel">
|
|
46
46
|
<header class="panel-header">
|
|
47
47
|
<div>
|
|
48
|
-
<h2>${
|
|
49
|
-
<p>${
|
|
48
|
+
<h2>${o("overview.nextSchedules")}</h2>
|
|
49
|
+
<p>${o("schedules.subtitle")}</p>
|
|
50
50
|
</div>
|
|
51
|
-
<a class="btn-link" href="#/schedules">${
|
|
51
|
+
<a class="btn-link" href="#/schedules">${o("nav.schedules")}</a>
|
|
52
52
|
</header>
|
|
53
53
|
<ul class="overview-list" id="next-schedules"></ul>
|
|
54
54
|
</section>
|
|
55
55
|
</div>
|
|
56
|
-
</section>`;let t=e.querySelector("#overview-metrics"),
|
|
57
|
-
<span>${
|
|
58
|
-
<strong>${
|
|
59
|
-
<small>${
|
|
60
|
-
</article>`).join("");let l=
|
|
61
|
-
<span class="filter-check-label">${
|
|
62
|
-
${
|
|
56
|
+
</section>`;let t=e.querySelector("#overview-metrics"),n=e.querySelector("#recent-sessions"),s=e.querySelector("#next-schedules");function a(){let r=[...N.sessions.values()],i=[...N.schedules.values()],m=r.filter(L=>L.status!=="closed"),k=r.filter(L=>L.status==="working"||L.status==="analyzing"||L.status==="starting"),$=i.filter(L=>L.enabled),p=Ke.bots?.length||new Set(r.map(L=>L.larkAppId).filter(Boolean)).size,g=[{label:o("overview.openSessions"),value:m.length,meta:`${r.length} ${o("overview.total")}`},{label:o("overview.workingSessions"),value:k.length,meta:`${m.length} ${o("overview.active")}`},{label:o("overview.onlineBots"),value:p,meta:o("overview.daemonRegistry")},{label:o("overview.schedules"),value:i.length,meta:`${$.length} ${o("overview.enabledSchedules")}`},{label:o("overview.groups"),value:Ke.chats?.length??0,meta:o("overview.chatMatrix")}];t.innerHTML=g.map(L=>`<article class="metric-card">
|
|
57
|
+
<span>${d(L.label)}</span>
|
|
58
|
+
<strong>${L.value}</strong>
|
|
59
|
+
<small>${d(L.meta)}</small>
|
|
60
|
+
</article>`).join("");let l=r.sort((L,b)=>Number(b.lastMessageAt??0)-Number(L.lastMessageAt??0)).slice(0,6);n.innerHTML=l.length?l.map(L=>$n({...L,title:L.title??`${be(L.lastMessageAt)} \xB7 ${L.sessionId}`})).join(""):`<li class="empty">${o("overview.noSessions")}</li>`;let I=i.filter(L=>L.nextRunAt).sort((L,b)=>Date.parse(L.nextRunAt)-Date.parse(b.nextRunAt)).slice(0,6);s.innerHTML=I.length?I.map(Sn).join(""):`<li class="empty">${o("overview.noSchedules")}</li>`}N.on(a),a(),vn().then(a)}function se(e,t){return`<th data-sort="${e}" data-label="${d(t)}">${d(t)}</th>`}var yt=["claude-code","codex","codex-app","cursor","gemini","opencode","mtr","hermes","mira","aiden","coco","unknown"];function In(){return`<div class="filter-check-group" role="group" aria-label="${o("sessions.cli")}">
|
|
61
|
+
<span class="filter-check-label">${o("sessions.cli")}</span>
|
|
62
|
+
${yt.map(e=>`
|
|
63
63
|
<label class="filter-check">
|
|
64
|
-
<input type="checkbox" name="cli" value="${
|
|
65
|
-
<span>${
|
|
64
|
+
<input type="checkbox" name="cli" value="${d(e)}" checked>
|
|
65
|
+
<span>${d(e)}</span>
|
|
66
66
|
</label>
|
|
67
67
|
`).join("")}
|
|
68
|
-
</div>`}function
|
|
68
|
+
</div>`}function Tn(){return`<section class="page">
|
|
69
69
|
<div class="page-heading">
|
|
70
70
|
<div>
|
|
71
|
-
<p class="eyebrow">${
|
|
72
|
-
<h1>${
|
|
73
|
-
<p>${
|
|
71
|
+
<p class="eyebrow">${o("nav.sessions")}</p>
|
|
72
|
+
<h1>${o("sessions.title")}</h1>
|
|
73
|
+
<p>${o("sessions.subtitle")}</p>
|
|
74
74
|
</div>
|
|
75
75
|
</div>
|
|
76
76
|
<form id="filters" class="filters sessions-filters">
|
|
77
|
-
<input type="search" name="q" placeholder="${
|
|
77
|
+
<input type="search" name="q" placeholder="${o("sessions.search")}" />
|
|
78
78
|
<select name="status">
|
|
79
|
-
<option value="">${
|
|
79
|
+
<option value="">${o("sessions.anyStatus")}</option>
|
|
80
80
|
<option>starting</option><option>working</option><option>idle</option>
|
|
81
81
|
<option>analyzing</option><option>active</option><option>closed</option>
|
|
82
82
|
</select>
|
|
83
83
|
<select name="adopt">
|
|
84
|
-
<option value="">${
|
|
85
|
-
<option value="yes">${
|
|
86
|
-
<option value="no">${
|
|
84
|
+
<option value="">${o("sessions.adoptAny")}</option>
|
|
85
|
+
<option value="yes">${o("sessions.adoptYes")}</option>
|
|
86
|
+
<option value="no">${o("sessions.adoptNo")}</option>
|
|
87
87
|
</select>
|
|
88
|
-
<label class="filter-toggle"><input type="checkbox" name="active" checked> ${
|
|
89
|
-
${
|
|
88
|
+
<label class="filter-toggle"><input type="checkbox" name="active" checked> ${o("sessions.activeOnly")}</label>
|
|
89
|
+
${In()}
|
|
90
90
|
</form>
|
|
91
91
|
<div id="bulk-bar" class="bulk-bar" hidden>
|
|
92
92
|
<span id="bulk-count"></span>
|
|
93
|
-
<button type="button" id="bulk-close" class="contrast">${
|
|
94
|
-
<button type="button" id="bulk-clear">${
|
|
93
|
+
<button type="button" id="bulk-close" class="contrast">${o("sessions.closeSelected")}</button>
|
|
94
|
+
<button type="button" id="bulk-clear">${o("sessions.clearSelection")}</button>
|
|
95
95
|
</div>
|
|
96
96
|
<table id="sessions-table">
|
|
97
97
|
<thead><tr>
|
|
98
|
-
<th><input type="checkbox" id="select-all" title="${
|
|
99
|
-
${
|
|
100
|
-
${
|
|
101
|
-
${
|
|
102
|
-
${
|
|
103
|
-
${
|
|
104
|
-
${
|
|
105
|
-
${
|
|
106
|
-
${
|
|
107
|
-
<th>${
|
|
98
|
+
<th><input type="checkbox" id="select-all" title="${o("sessions.activeOnly")}"></th>
|
|
99
|
+
${se("botName",o("sessions.bot"))}
|
|
100
|
+
${se("cliId",o("sessions.cli"))}
|
|
101
|
+
${se("status",o("sessions.status"))}
|
|
102
|
+
${se("title",o("sessions.titleCol"))}
|
|
103
|
+
${se("workingDir",o("sessions.workingDir"))}
|
|
104
|
+
${se("spawnedAt",o("sessions.created"))}
|
|
105
|
+
${se("lastMessageAt",o("sessions.last"))}
|
|
106
|
+
${se("adopt",o("sessions.adopt"))}
|
|
107
|
+
<th>${o("sessions.actions")}</th>
|
|
108
108
|
</tr></thead>
|
|
109
109
|
<tbody></tbody>
|
|
110
110
|
</table>
|
|
111
111
|
<dialog id="drawer"></dialog>
|
|
112
|
-
</section>`}function
|
|
113
|
-
<td><input type="checkbox" class="row-select" ${h} ${
|
|
114
|
-
<td>${
|
|
115
|
-
<td><span class="badge cli-${
|
|
116
|
-
<td><span class="status status-${
|
|
117
|
-
<td>${
|
|
118
|
-
<td title="${
|
|
119
|
-
<td>${
|
|
120
|
-
<td>${
|
|
121
|
-
<td>${
|
|
122
|
-
<td><button class="open" type="button">${
|
|
123
|
-
</tr>`}function
|
|
112
|
+
</section>`}function vt(e){e.innerHTML=Tn();let t=e.querySelector("#sessions-table tbody"),n=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"),k=e.querySelector("#bulk-clear"),$=e.querySelector("#sessions-table"),p=new Set,g="lastMessageAt",l="desc";function I(u){let w=u.status==="closed",h=p.has(u.sessionId)?"checked":"";return`<tr data-id="${d(u.sessionId)}">
|
|
113
|
+
<td><input type="checkbox" class="row-select" ${h} ${w?"disabled":""}></td>
|
|
114
|
+
<td>${d(u.botName??"")}</td>
|
|
115
|
+
<td><span class="badge cli-${d(u.cliId??"unknown")}">${d(u.cliId??"unknown")}</span></td>
|
|
116
|
+
<td><span class="status status-${d(u.status??"unknown")}">${d(u.status??"unknown")}</span></td>
|
|
117
|
+
<td>${d((u.title??"").slice(0,48))}</td>
|
|
118
|
+
<td title="${d(u.workingDir??"")}">${d((u.workingDir??"").slice(-34))}</td>
|
|
119
|
+
<td>${be(u.spawnedAt)}</td>
|
|
120
|
+
<td>${be(u.lastMessageAt)}</td>
|
|
121
|
+
<td>${u.adopt?'<span class="badge">adopt</span>':""}</td>
|
|
122
|
+
<td><button class="open" type="button">${o("sessions.details")}</button></td>
|
|
123
|
+
</tr>`}function L(){let u=new FormData(n),w=(u.get("q")??"").toLowerCase(),h=u.getAll("cli"),E=h.length>0&&h.length<yt.length,M=u.get("status"),A=u.get("adopt"),P=!!u.get("active"),O=[...N.sessions.values()].filter(x=>!E||h.includes(x.cliId??"unknown")).filter(x=>!M||x.status===M).filter(x=>!A||A==="yes"==!!x.adopt).filter(x=>!P||x.status!=="closed").filter(x=>!w||JSON.stringify(x).toLowerCase().includes(w));return O.sort(f),O}function b(u,w){return w==="spawnedAt"||w==="lastMessageAt"?Number(u[w]??0):w==="adopt"?!!u.adopt:String(u[w]??"").toLowerCase()}function f(u,w){let h=b(u,g),E=b(w,g),M=0;return typeof h=="number"&&typeof E=="number"?M=h-E:typeof h=="boolean"&&typeof E=="boolean"?M=Number(h)-Number(E):M=String(h).localeCompare(String(E)),M===0&&(M=Number(u.lastMessageAt??0)-Number(w.lastMessageAt??0)),l==="asc"?M:-M}function T(){$.querySelectorAll("th[data-sort]").forEach(u=>{let w=u.dataset.sort===g;u.classList.toggle("sorted",w),u.setAttribute("aria-sort",w?l==="asc"?"ascending":"descending":"none");let h=u.dataset.label??u.textContent?.trim()??"";u.textContent=w?`${h} ${l==="asc"?"\u25B2":"\u25BC"}`:h})}function S(u){r.hidden=p.size===0,i.textContent=o("sessions.selectedCount",{count:p.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=>p.has(E.sessionId)).length;a.checked=h===w.length,a.indeterminate=h>0&&h<w.length}function y(){let u=L();for(let w of[...p]){let h=N.sessions.get(w);(!h||h.status==="closed")&&p.delete(w)}t.innerHTML=u.length?u.map(I).join(""):`<tr><td colspan="10" class="empty">${o("sessions.empty")}</td></tr>`,T(),S(u)}function H(u){let w=u.status==="closed";s.innerHTML=`<article>
|
|
124
124
|
<header>
|
|
125
|
-
<h3>${
|
|
126
|
-
<span class="status status-${
|
|
127
|
-
<p><code>${
|
|
125
|
+
<h3>${d(u.title??u.sessionId)}</h3>
|
|
126
|
+
<span class="status status-${d(u.status??"unknown")}">${d(u.status??"unknown")}</span>
|
|
127
|
+
<p><code>${d(u.sessionId)}</code> <button data-copy="${d(u.sessionId)}">${o("sessions.copy")}</button></p>
|
|
128
128
|
</header>
|
|
129
|
-
<p><b>${
|
|
130
|
-
<p><b>chatId:</b> <code>${
|
|
131
|
-
<p><b>rootMessageId:</b> <code>${
|
|
132
|
-
${
|
|
133
|
-
<p><b>${
|
|
129
|
+
<p><b>${o("sessions.bot")}:</b> ${d(u.botName??"-")} \xB7 <b>${o("sessions.cli")}:</b> ${d(u.cliId??"?")}</p>
|
|
130
|
+
<p><b>chatId:</b> <code>${d(u.chatId??"")}</code> <button data-copy="${d(u.chatId??"")}">${o("sessions.copy")}</button></p>
|
|
131
|
+
<p><b>rootMessageId:</b> <code>${d(u.rootMessageId??"")}</code> <button data-copy="${d(u.rootMessageId??"")}">${o("sessions.copy")}</button></p>
|
|
132
|
+
${u.threadId?`<p><b>threadId:</b> <code>${d(u.threadId)}</code></p>`:""}
|
|
133
|
+
<p><b>${o("sessions.workingDir")}:</b> ${d(u.workingDir??"-")}</p>
|
|
134
134
|
<div class="actions">
|
|
135
|
-
<button id="locate-btn" type="button">${
|
|
136
|
-
${
|
|
137
|
-
${
|
|
138
|
-
${
|
|
135
|
+
<button id="locate-btn" type="button">${o("sessions.locate")}</button>
|
|
136
|
+
${u.webPort?`<a class="btn-link primary" href="http://${d(location.hostname)}:${u.webPort}" target="_blank" rel="noopener">${o("sessions.openTerminal")}</a>`:""}
|
|
137
|
+
${w?`<button id="resume-btn" type="button" class="primary">${o("sessions.resume")}</button>`:""}
|
|
138
|
+
${w?"":`<button id="close-btn" type="button" class="contrast">${o("sessions.close")}</button>`}
|
|
139
139
|
</div>
|
|
140
|
-
<form method="dialog"><button>${
|
|
141
|
-
</article>`,
|
|
140
|
+
<form method="dialog"><button>${o("sessions.dismiss")}</button></form>
|
|
141
|
+
</article>`,s.querySelectorAll("[data-copy]").forEach(A=>{A.onclick=()=>{navigator.clipboard.writeText(A.dataset.copy??""),A.textContent=o("sessions.copied"),setTimeout(()=>{A.textContent=o("sessions.copy")},800)}});let h=s.querySelector("#locate-btn");h&&(h.onclick=async()=>{h.disabled=!0,h.textContent=o("sessions.locating");try{let A=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/locate`,{method:"POST"}),P=await A.json();if(P.ok){let O=30;h.textContent=o("sessions.cooldown",{seconds:O});let x=setInterval(()=>{O-=1,O<=0?(clearInterval(x),h.disabled=!1,h.textContent=o("sessions.locate")):h.textContent=o("sessions.cooldown",{seconds:O})},1e3)}else alert(`Locate failed: ${P.error??A.status}`),h.disabled=!1,h.textContent=o("sessions.locate")}catch(A){alert(`Locate error: ${A}`),h.disabled=!1,h.textContent=o("sessions.locate")}});let E=s.querySelector("#resume-btn");E&&(E.onclick=async()=>{E.disabled=!0;try{let A=await fetch(`/api/sessions/${encodeURIComponent(u.sessionId)}/resume`,{method:"POST"}),P=await A.json().catch(()=>({}));if(!A.ok||P.ok===!1){alert(`${o("sessions.resumeFailed")}: ${P?.error??A.status}`),E.disabled=!1;return}s.close()}catch(A){alert(`${o("sessions.resumeFailed")}: ${A}`),E.disabled=!1}});let M=s.querySelector("#close-btn");M&&(M.onclick=async()=>{if(confirm(o("sessions.closeConfirm"))){M.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 A=w.closest("tr[data-id]");if(!A)return;w.checked?p.add(A.dataset.id):p.delete(A.dataset.id),S(L());return}let h=w.closest("td");if(h&&h.querySelector(".row-select"))return;let E=w.closest("tr[data-id]");if(!E)return;let M=N.sessions.get(E.dataset.id);M&&H(M)}),a.addEventListener("change",()=>{let u=L().filter(w=>w.status!=="closed");for(let w of u)a.checked?p.add(w.sessionId):p.delete(w.sessionId);y()}),k.addEventListener("click",()=>{p.clear(),y()}),m.addEventListener("click",async()=>{let u=[...p];if(u.length===0||!confirm(o("sessions.closeBulkConfirm",{count:u.length})))return;m.disabled=!0,k.disabled=!0;let w=m.textContent,h=0,E=0,M=[...u];m.textContent=`0/${u.length}`;async function A(){for(;M.length;){let P=M.shift();try{let O=await fetch(`/api/sessions/${encodeURIComponent(P)}/close`,{method:"POST"}),x=await O.json().catch(()=>({}));(!O.ok||x?.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)},()=>A())),m.textContent=w,m.disabled=!1,k.disabled=!1,p.clear(),y(),E>0&&alert(`Failed: ${E}/${u.length}`)}),$.querySelectorAll("th[data-sort]").forEach(u=>{u.addEventListener("click",()=>{let w=u.dataset.sort;g===w?l=l==="asc"?"desc":"asc":(g=w,l=w==="spawnedAt"||w==="lastMessageAt"?"desc":"asc"),y()})}),n.addEventListener("input",y),N.on(y),y()}function Ln(){return`<section class="page">
|
|
142
142
|
<div class="page-heading">
|
|
143
143
|
<div>
|
|
144
|
-
<p class="eyebrow">${
|
|
145
|
-
<h1>${
|
|
146
|
-
<p>${
|
|
144
|
+
<p class="eyebrow">${o("nav.schedules")}</p>
|
|
145
|
+
<h1>${o("schedules.title")}</h1>
|
|
146
|
+
<p>${o("schedules.subtitle")}</p>
|
|
147
147
|
</div>
|
|
148
148
|
</div>
|
|
149
149
|
<form id="sched-filters" class="filters">
|
|
150
|
-
<input type="search" name="q" placeholder="${
|
|
150
|
+
<input type="search" name="q" placeholder="${o("schedules.search")}" />
|
|
151
151
|
<select name="kind">
|
|
152
|
-
<option value="">${
|
|
152
|
+
<option value="">${o("schedules.anyKind")}</option>
|
|
153
153
|
<option>cron</option>
|
|
154
154
|
<option>interval</option>
|
|
155
155
|
<option>once</option>
|
|
156
156
|
</select>
|
|
157
|
-
<label><input type="checkbox" name="enabled"> ${
|
|
157
|
+
<label><input type="checkbox" name="enabled"> ${o("schedules.enabledOnly")}</label>
|
|
158
158
|
</form>
|
|
159
159
|
<table>
|
|
160
160
|
<thead><tr>
|
|
161
|
-
<th>${
|
|
162
|
-
<th>${
|
|
161
|
+
<th>${o("schedules.name")}</th><th>${o("schedules.bot")}</th><th>${o("schedules.schedule")}</th><th>${o("schedules.next")}</th><th>${o("schedules.last")}</th>
|
|
162
|
+
<th>${o("schedules.repeat")}</th><th>${o("schedules.enabled")}</th><th>${o("schedules.actions")}</th>
|
|
163
163
|
</tr></thead>
|
|
164
164
|
<tbody id="schedules-tbody"></tbody>
|
|
165
165
|
</table>
|
|
166
|
-
</section>`}function
|
|
167
|
-
<td>${
|
|
168
|
-
<td>${
|
|
169
|
-
<td><code>${
|
|
170
|
-
<td>${
|
|
171
|
-
<td>${
|
|
172
|
-
<td>${
|
|
173
|
-
<td>${
|
|
166
|
+
</section>`}function kt(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function $t(e){e.innerHTML=Ln();let t=e.querySelector("#schedules-tbody"),n=e.querySelector("#sched-filters");function s(){let r=new FormData(n),i=(r.get("q")??"").toLowerCase(),m=r.get("kind"),k=!!r.get("enabled");return[...N.schedules.values()].filter($=>!m||$.parsed?.kind===m).filter($=>!k||$.enabled).filter($=>!i||JSON.stringify($).toLowerCase().includes(i)).sort(($,p)=>{if($.enabled!==p.enabled)return $.enabled?-1:1;let g=$.nextRunAt?Date.parse($.nextRunAt):1/0,l=p.nextRunAt?Date.parse(p.nextRunAt):1/0;return g-l})}function a(){t.innerHTML=s().map(r=>`<tr data-id="${d(r.id)}">
|
|
167
|
+
<td>${d(r.name??r.id)}</td>
|
|
168
|
+
<td>${d(r.botName??r.larkAppId??"-")}</td>
|
|
169
|
+
<td><code>${d(r.parsed?.display??"?")}</code></td>
|
|
170
|
+
<td>${kt(r.nextRunAt)}</td>
|
|
171
|
+
<td>${kt(r.lastRunAt)} ${r.lastStatus==="error"?"\u26A0\uFE0F":""}</td>
|
|
172
|
+
<td>${r.repeat?`${r.repeat.completed}/${r.repeat.times??"\u221E"}`:"\u2014"}</td>
|
|
173
|
+
<td>${r.enabled?"\u2713":"\u2717"}</td>
|
|
174
174
|
<td class="actions-cell">
|
|
175
|
-
<button data-op="run" type="button">${
|
|
176
|
-
${
|
|
175
|
+
<button data-op="run" type="button">${o("schedules.runNow")}</button>
|
|
176
|
+
${r.enabled?`<button data-op="pause" type="button">${o("schedules.pause")}</button>`:`<button data-op="resume" type="button">${o("schedules.resume")}</button>`}
|
|
177
177
|
</td>
|
|
178
|
-
</tr>`).join("")||`<tr><td colspan="8" class="empty">${
|
|
178
|
+
</tr>`).join("")||`<tr><td colspan="8" class="empty">${o("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 k=m.dataset.id,$=i.dataset.op;i.disabled=!0;let p=i.textContent;i.textContent="...";try{let g=await fetch(`/api/schedules/${encodeURIComponent(k)}/${$}`,{method:"POST"}),l=await g.json().catch(()=>({}));(!g.ok||l.ok===!1)&&alert(`Failed: ${g.status} ${l?.error??""}`.trim())}catch(g){alert("Network error: "+g)}finally{i.disabled=!1,i.textContent=p}}),n.addEventListener("input",a),N.on(a),a()}var W={chats:[],bots:[]};function En(){return`<section class="page">
|
|
179
179
|
<div class="page-heading">
|
|
180
180
|
<div>
|
|
181
|
-
<p class="eyebrow">${
|
|
182
|
-
<h1>${
|
|
183
|
-
<p>${
|
|
181
|
+
<p class="eyebrow">${o("nav.groups")}</p>
|
|
182
|
+
<h1>${o("groups.title")}</h1>
|
|
183
|
+
<p>${o("groups.subtitle")}</p>
|
|
184
184
|
</div>
|
|
185
185
|
</div>
|
|
186
186
|
<form id="g-filters" class="filters">
|
|
187
|
-
<input type="search" name="q" placeholder="${
|
|
188
|
-
<label><input type="checkbox" name="missing"> ${
|
|
189
|
-
<button type="button" id="g-refresh">${
|
|
190
|
-
<button type="button" id="g-create" class="primary">${
|
|
187
|
+
<input type="search" name="q" placeholder="${o("groups.search")}" />
|
|
188
|
+
<label><input type="checkbox" name="missing"> ${o("groups.missingOnly")}</label>
|
|
189
|
+
<button type="button" id="g-refresh">${o("groups.refresh")}</button>
|
|
190
|
+
<button type="button" id="g-create" class="primary">${o("groups.create")}</button>
|
|
191
191
|
</form>
|
|
192
192
|
<table>
|
|
193
193
|
<thead id="g-head"></thead>
|
|
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 fe(){W=await(await fetch("/api/groups")).json()}async function Mn(){return(await fetch("/api/groups")).json()}function Cn(e,t){if(t.size===0)return!0;let n=e?.memberBots??[];for(let s of t)if(!n.some(a=>a.larkAppId===s&&a.inChat))return!1;return!0}function St(e,t){return e.filter(n=>!t||!t.has(n.larkAppId)).map(n=>`
|
|
198
198
|
<label class="checkbox-row">
|
|
199
|
-
<input type="checkbox" name="bot" value="${
|
|
200
|
-
${
|
|
199
|
+
<input type="checkbox" name="bot" value="${d(n.larkAppId)}">
|
|
200
|
+
${d(n.botName??n.larkAppId)} <small>(${d(n.larkAppId)})</small>
|
|
201
201
|
</label>
|
|
202
|
-
`).join("")}async function
|
|
202
|
+
`).join("")}async function It(e){e.innerHTML=En();let t=e.querySelector("#g-head"),n=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 fe(),p()}finally{a.disabled=!1}};let i=e.querySelector("#g-create");i.onclick=()=>m(),await fe();function m(){let l=W.bots;if(l.length===0){alert(o("groups.noBotsOnline"));return}r.innerHTML=`
|
|
203
203
|
<article>
|
|
204
|
-
<header><h3>${
|
|
205
|
-
<p>${
|
|
204
|
+
<header><h3>${o("groups.createTitle")}</h3></header>
|
|
205
|
+
<p>${o("groups.createHelp")}</p>
|
|
206
206
|
<form id="g-createform">
|
|
207
207
|
<label class="form-row">
|
|
208
|
-
<span>${
|
|
209
|
-
<input type="text" name="name" placeholder="${
|
|
208
|
+
<span>${o("groups.name")}</span>
|
|
209
|
+
<input type="text" name="name" placeholder="${o("groups.namePlaceholder")}" maxlength="60">
|
|
210
210
|
</label>
|
|
211
211
|
<label class="form-row">
|
|
212
|
-
<span>${
|
|
212
|
+
<span>${o("groups.bindDir")}</span>
|
|
213
213
|
<input type="text" name="bindWorkingDir" placeholder="e.g. ~/projects/botmux">
|
|
214
|
-
<small>${
|
|
214
|
+
<small>${o("groups.bindDirHelp")}</small>
|
|
215
215
|
</label>
|
|
216
216
|
<fieldset>
|
|
217
|
-
<legend>${
|
|
218
|
-
${
|
|
217
|
+
<legend>${o("groups.botPicker")}</legend>
|
|
218
|
+
${St(l)}
|
|
219
219
|
</fieldset>
|
|
220
220
|
<div class="actions">
|
|
221
|
-
<button type="submit" class="primary">${
|
|
222
|
-
<button type="button" id="g-create-cancel">${
|
|
221
|
+
<button type="submit" class="primary">${o("groups.createSubmit")}</button>
|
|
222
|
+
<button type="button" id="g-create-cancel">${o("groups.cancel")}</button>
|
|
223
223
|
</div>
|
|
224
224
|
</form>
|
|
225
|
-
</article>`,
|
|
225
|
+
</article>`,r.showModal(),r.querySelector("#g-create-cancel").onclick=()=>r.close(),r.querySelector("#g-createform").onsubmit=async b=>{b.preventDefault();let f=new FormData(b.target),T=(f.get("name")??"").trim(),S=(f.get("bindWorkingDir")??"").trim(),y=f.getAll("bot");if(y.length===0){alert("Pick at least one bot.");return}let H=b.target.querySelector("button[type=submit]");H&&(H.disabled=!0,H.textContent="Creating...");try{let u=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:T||void 0,larkAppIds:y,bindWorkingDir:S||void 0})}),w=await u.json();if(w.ok&&w.chatId){k(w);let h=Array.isArray(w.invalidBotIds)?w.invalidBotIds:[],E=y.filter(A=>!h.includes(A)),M=new Set(E);typeof w.creator=="string"&&w.creator&&M.add(w.creator),I(w.chatId,T||w.chatId,E,w.creator),p(),L(w.chatId,M).catch(()=>{})}else alert(`Failed: ${w.error??u.status}`),r.close()}catch(u){alert("Network error: "+u),r.close()}};function I(b,f,T,S){let y=new Set(T);S&&y.add(S);let H=W.bots.map(w=>({larkAppId:w.larkAppId,botName:w.botName,inChat:y.has(w.larkAppId),oncallChat:null})),u={chatId:b,name:f,ownerId:S??null,memberBots:H};W.chats=[u,...W.chats.filter(w=>w.chatId!==b)]}async function L(b,f){let T=[600,1200,1200,1200,1200,1200];for(let S of T){await new Promise(u=>setTimeout(u,S));let y;try{y=await Mn()}catch{continue}let H=(y.chats??[]).find(u=>u.chatId===b);if(H&&Cn(H,f)){W=y,p();return}}}}function k(l){let I=String(l.chatId),L=`https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(I)}`,b=l.invalidBotIds??[],f=l.invalidUserIds??[],T=l.autoInvitedOpenId,S=!!l.autoInviteRejected,y=l.ownerTransferredTo,H=l.transferError,u=l.notifyMessageId,w=l.notifyError,h=Array.isArray(l.oncallBindings)?l.oncallBindings:[],E=h.filter(x=>x?.ok).length,M=h.filter(x=>!x?.ok),A=h.length>0?M.length===0?`<p class="hint-ok">\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1A<code>${d(l.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${M.map(x=>`<br><code>${d(x.larkAppId??"?")}</code>: ${d(x.error??"unknown")}`).join("")}</p>`:"",P;if(T){let x=y?"<br><small>\u7FA4\u4E3B\u5DF2\u4ECE\u673A\u5668\u4EBA\u8F6C\u8BA9\u7ED9\u4F60\u3002</small>":H?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08${d(H)}\uFF09\uFF0C\u4F60\u73B0\u5728\u662F\u6210\u5458\u4F46\u7FA4\u4E3B\u4ECD\u662F\u673A\u5668\u4EBA\u3002</small>`:"",q=u?`<br><small>\u673A\u5668\u4EBA\u5DF2\u5728\u7FA4\u91CC @ \u4E86\u4F60\uFF08\u6D88\u606F id <code>${d(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${d(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>`:"";P=`<p class="hint-ok">\u5DF2\u81EA\u52A8\u9080\u8BF7\u4F60\uFF08<code>${d(T)}</code>\uFF09\u4F5C\u4E3A\u6210\u5458\u3002${x}${q}</p>`}else S?P='<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>':P='<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 O=[b.length?`<li>\u65E0\u6548 bot id: <code>${b.map(d).join(", ")}</code></li>`:"",f.length?`<li>\u65E0\u6548\u7528\u6237 open_id: <code>${f.map(d).join(", ")}</code></li>`:""].filter(Boolean).join("");r.innerHTML=`
|
|
226
226
|
<article>
|
|
227
|
-
<header><h3>${
|
|
228
|
-
<p><b>chatId:</b> <code>${
|
|
229
|
-
<p><b>\u521B\u5EFA\u8005:</b> <code>${
|
|
230
|
-
${
|
|
231
|
-
${
|
|
227
|
+
<header><h3>${o("groups.successTitle")}</h3></header>
|
|
228
|
+
<p><b>chatId:</b> <code>${d(I)}</code> <button type="button" data-copy="${d(I)}">${o("sessions.copy")}</button></p>
|
|
229
|
+
<p><b>\u521B\u5EFA\u8005:</b> <code>${d(l.creator??"?")}</code></p>
|
|
230
|
+
${P}
|
|
231
|
+
${A}
|
|
232
232
|
${O?`<ul>${O}</ul>`:""}
|
|
233
233
|
<div class="actions">
|
|
234
|
-
<a class="btn-link primary" href="${
|
|
235
|
-
<button type="button" id="g-create-close">${
|
|
234
|
+
<a class="btn-link primary" href="${L}" target="_blank" rel="noopener">${o("groups.openGroup")}</a>
|
|
235
|
+
<button type="button" id="g-create-close">${o("sessions.dismiss")}</button>
|
|
236
236
|
</div>
|
|
237
|
-
</article>`,
|
|
238
|
-
<th>${
|
|
239
|
-
${
|
|
240
|
-
<th>${
|
|
241
|
-
</tr>`}function
|
|
237
|
+
</article>`,r.querySelectorAll("[data-copy]").forEach(x=>{x.onclick=()=>{navigator.clipboard.writeText(x.dataset.copy??""),x.textContent=o("sessions.copied"),setTimeout(()=>{x.textContent=o("sessions.copy")},800)}}),r.querySelector("#g-create-close").onclick=()=>r.close()}function $(){t.innerHTML=`<tr>
|
|
238
|
+
<th>${o("groups.chat")}</th>
|
|
239
|
+
${W.bots.map(l=>`<th>${d(l.botName??l.larkAppId)}</th>`).join("")}
|
|
240
|
+
<th>${o("groups.actions")}</th>
|
|
241
|
+
</tr>`}function p(){$();let l=new FormData(s),I=(l.get("q")??"").toLowerCase(),L=!!l.get("missing"),b=W.chats.filter(f=>!I||(f.name??"").toLowerCase().includes(I)||f.chatId.toLowerCase().includes(I)||(f.ownerId??"").toLowerCase().includes(I)).filter(f=>!L||f.memberBots.some(T=>!T.inChat));if(b.length===0){n.innerHTML=`<tr><td colspan="${W.bots.length+2}" class="empty">${o("groups.empty")}</td></tr>`;return}n.innerHTML=b.map(f=>`<tr data-chat="${d(f.chatId)}">
|
|
242
242
|
<td>
|
|
243
|
-
<strong>${
|
|
244
|
-
<small><code>${
|
|
243
|
+
<strong>${d(f.name??f.chatId)}</strong><br>
|
|
244
|
+
<small><code>${d(f.chatId)}</code></small>
|
|
245
245
|
</td>
|
|
246
|
-
${
|
|
246
|
+
${W.bots.map(T=>{let S=f.memberBots.find(u=>u.larkAppId===T.larkAppId),y=S?S.error?"!":S.inChat?"\u2713":"\u2717":"?";return`<td class="${S?S.error?"cell-error":S.inChat?"cell-in":"cell-out":"cell-unknown"}" title="${d(S?.error??"")}">${y}</td>`}).join("")}
|
|
247
247
|
<td>
|
|
248
|
-
<button class="add-bots" type="button">${
|
|
249
|
-
<button class="manage-chat" type="button">${
|
|
248
|
+
<button class="add-bots" type="button">${o("groups.addBots")}</button>
|
|
249
|
+
<button class="manage-chat" type="button">${o("groups.manage")}</button>
|
|
250
250
|
</td>
|
|
251
|
-
</tr>`).join("")}
|
|
251
|
+
</tr>`).join("")}p(),n.addEventListener("click",async l=>{let I=l.target.closest("button.add-bots");if(!I)return;let b=I.closest("tr[data-chat]").dataset.chat,f=W.chats.find(y=>y.chatId===b);if(!f)return;let T=new Set(f.memberBots.filter(y=>y.inChat).map(y=>y.larkAppId));if(!W.bots.filter(y=>!T.has(y.larkAppId)).length){alert("All configured bots are already in this chat.");return}r.innerHTML=`
|
|
252
252
|
<article>
|
|
253
|
-
<header><h3>${
|
|
254
|
-
<p>${
|
|
253
|
+
<header><h3>${o("groups.addBots")} \xB7 ${d(f.name??f.chatId)}</h3></header>
|
|
254
|
+
<p>${o("groups.createHelp")}</p>
|
|
255
255
|
<form id="g-addform">
|
|
256
|
-
${
|
|
256
|
+
${St(W.bots,T)}
|
|
257
257
|
<div class="actions">
|
|
258
|
-
<button type="submit" class="primary">${
|
|
259
|
-
<button type="button" id="g-cancel">${
|
|
258
|
+
<button type="submit" class="primary">${o("groups.addBots")}</button>
|
|
259
|
+
<button type="button" id="g-cancel">${o("groups.cancel")}</button>
|
|
260
260
|
</div>
|
|
261
261
|
</form>
|
|
262
|
-
</article>`,
|
|
263
|
-
`);alert(
|
|
262
|
+
</article>`,r.showModal(),r.querySelector("#g-cancel").onclick=()=>r.close(),r.querySelector("#g-addform").onsubmit=async y=>{y.preventDefault();let u=new FormData(y.target).getAll("bot");if(u.length===0){alert("Pick at least one bot.");return}try{let h=await(await fetch(`/api/groups/${encodeURIComponent(b)}/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(M=>`${M.id}: ${M.ok?"OK":`failed (${M.error??"unknown"})`}`).join(`
|
|
263
|
+
`);alert(E),await fe(),p()}else alert(`Unexpected response: ${JSON.stringify(h)}`)}catch(w){alert("Network error: "+w)}finally{r.close()}}}),n.addEventListener("click",async l=>{let I=l.target.closest("button.manage-chat");if(!I)return;let b=I.closest("tr[data-chat]").dataset.chat,f=W.chats.find(T=>T.chatId===b);f&&g(f)});function g(l){let I=l.memberBots.filter(b=>b.inChat),L=typeof l.ownerId=="string"?l.ownerId:"";r.innerHTML=`
|
|
264
264
|
<article>
|
|
265
|
-
<header><h3>${
|
|
266
|
-
<p><b>chatId:</b> <code>${
|
|
267
|
-
<p><b>${
|
|
265
|
+
<header><h3>${o("groups.manageTitle",{name:l.name??l.chatId})}</h3></header>
|
|
266
|
+
<p><b>chatId:</b> <code>${d(l.chatId)}</code></p>
|
|
267
|
+
<p><b>${o("groups.owner")}:</b> <code>${d(l.ownerId??o("common.unknown"))}</code></p>
|
|
268
268
|
|
|
269
269
|
<fieldset>
|
|
270
|
-
<legend>${
|
|
271
|
-
<p><small>${
|
|
272
|
-
${
|
|
273
|
-
<div class="oncall-row" data-bot="${
|
|
270
|
+
<legend>${o("groups.oncall")}</legend>
|
|
271
|
+
<p><small>${o("groups.oncallHelp")}</small></p>
|
|
272
|
+
${I.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':I.map(b=>{let f=!!b.oncallChat,T=b.oncallChat?.workingDir??"";return`
|
|
273
|
+
<div class="oncall-row" data-bot="${d(b.larkAppId)}">
|
|
274
274
|
<label class="checkbox-row">
|
|
275
|
-
<input type="checkbox" data-action="toggle" ${
|
|
276
|
-
<strong>${
|
|
277
|
-
<small>(${
|
|
275
|
+
<input type="checkbox" data-action="toggle" ${f?"checked":""}>
|
|
276
|
+
<strong>${d(b.botName??b.larkAppId)}</strong>
|
|
277
|
+
<small>(${d(b.larkAppId)})</small>
|
|
278
278
|
</label>
|
|
279
279
|
<div class="oncall-row-body">
|
|
280
280
|
<input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
|
|
281
|
-
value="${
|
|
282
|
-
<button type="button" data-action="save">${
|
|
281
|
+
value="${d(T)}" ${f?"":"disabled"}>
|
|
282
|
+
<button type="button" data-action="save">${o("groups.save")}</button>
|
|
283
283
|
<span class="oncall-status" data-status></span>
|
|
284
284
|
</div>
|
|
285
285
|
</div>
|
|
@@ -287,135 +287,135 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
287
287
|
</fieldset>
|
|
288
288
|
|
|
289
289
|
<fieldset>
|
|
290
|
-
<legend>${
|
|
291
|
-
${
|
|
290
|
+
<legend>${o("groups.leaveTitle")}</legend>
|
|
291
|
+
${I.length===0?'<p class="empty">\u6CA1\u6709\u673A\u5668\u4EBA\u5728\u7FA4\u91CC</p>':I.map(b=>`
|
|
292
292
|
<label class="checkbox-row">
|
|
293
|
-
<input type="checkbox" name="leave-bot" value="${
|
|
294
|
-
${
|
|
295
|
-
<small>${b.larkAppId===
|
|
293
|
+
<input type="checkbox" name="leave-bot" value="${d(b.larkAppId)}">
|
|
294
|
+
${d(b.botName??b.larkAppId)}
|
|
295
|
+
<small>${b.larkAppId===L?"\xB7 \u7FA4\u4E3B":""}</small>
|
|
296
296
|
</label>
|
|
297
297
|
`).join("")}
|
|
298
298
|
</fieldset>
|
|
299
299
|
|
|
300
300
|
<div class="actions">
|
|
301
|
-
<button id="g-leave-btn" type="button" ${
|
|
302
|
-
<button id="g-disband-btn" type="button" class="contrast" ${
|
|
301
|
+
<button id="g-leave-btn" type="button" ${I.length===0?"disabled":""}>${o("groups.leaveSelected")}</button>
|
|
302
|
+
<button id="g-disband-btn" type="button" class="contrast" ${I.length===0?"disabled":""}>${o("groups.disband")}</button>
|
|
303
303
|
</div>
|
|
304
|
-
<p class="hint-warn"><small>${
|
|
305
|
-
<form method="dialog"><button>${
|
|
306
|
-
</article>`,
|
|
307
|
-
`);alert(
|
|
308
|
-
\u5173\u95ED\u4E86 ${
|
|
309
|
-
\u5173\u95ED\u4E86 ${
|
|
310
|
-
${
|
|
304
|
+
<p class="hint-warn"><small>${o("groups.dangerHint")}</small></p>
|
|
305
|
+
<form method="dialog"><button>${o("sessions.dismiss")}</button></form>
|
|
306
|
+
</article>`,r.showModal(),r.querySelectorAll(".oncall-row").forEach(b=>{let f=b.dataset.bot,T=b.querySelector("input[data-action=toggle]"),S=b.querySelector("input[data-input=workingDir]"),y=b.querySelector("button[data-action=save]"),H=b.querySelector("[data-status]");T.addEventListener("change",()=>{S.disabled=!T.checked,T.checked&&S.focus()}),y.addEventListener("click",async()=>{H.textContent="",H.className="oncall-status";let u=T.checked,w=S.value.trim();if(u&&!w){H.textContent=o("groups.needWorkingDir"),H.classList.add("hint-warn-inline");return}y.disabled=!0;try{let h=`/api/groups/${encodeURIComponent(l.chatId)}/oncall/${encodeURIComponent(f)}`,E=u?await fetch(h,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({workingDir:w})}):await fetch(h,{method:"DELETE"}),M=await E.json().catch(()=>({}));if(E.ok&&M.ok){H.textContent=u?`\u2713 \u5DF2\u7ED1\u5B9A \u2192 ${M.resolvedPath??w}`:"\u2713 \u5DF2\u89E3\u7ED1",H.classList.add("hint-ok");try{await fe(),p()}catch{}}else H.textContent=`\u2717 ${M.error??E.status}`,H.classList.add("hint-warn-inline")}catch(h){H.textContent=`\u2717 ${h?.message??h}`,H.classList.add("hint-warn-inline")}finally{y.disabled=!1}})}),r.querySelector("#g-leave-btn").onclick=async()=>{let b=[...r.querySelectorAll("input[name=leave-bot]:checked")].map(f=>f.value);if(b.length===0){alert("\u81F3\u5C11\u9009\u4E00\u4E2A\u673A\u5668\u4EBA");return}if(confirm(`\u786E\u5B9A\u8BA9 ${b.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 T=await(await fetch(`/api/groups/${encodeURIComponent(l.chatId)}/leave`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:b})})).json(),S=(T.result??[]).map(y=>{if(!y.ok)return`${y.larkAppId}: \u5931\u8D25 (${y.error??"unknown"})`;let H=y.closedSessions??[],u=H.filter(E=>!E.ok).length,w=H.length-u,h=H.length===0?"":u===0?`\uFF08\u5173\u95ED ${w} \u4E2A\u4F1A\u8BDD\uFF09`:`\uFF08\u5173\u95ED ${w} \u4E2A\uFF0C${u} \u4E2A\u5931\u8D25\uFF09`;return`${y.larkAppId}: OK${h}`}).join(`
|
|
307
|
+
`);alert(S||`Unexpected: ${JSON.stringify(T)}`),await fe(),p()}catch(f){alert("Network error: "+f)}finally{r.close()}},r.querySelector("#g-disband-btn").onclick=async()=>{if(I.length===0||!confirm(`\u786E\u5B9A\u89E3\u6563\u7FA4\u804A\u300C${l.name??l.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 b=[...I].sort((T,S)=>(S.larkAppId===L?1:0)-(T.larkAppId===L?1:0)),f=[];for(let T of b)try{let S=await fetch(`/api/groups/${encodeURIComponent(l.chatId)}/disband`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppId:T.larkAppId})}),y=await S.json();if(y.ok){let H=y.closedSessions??[],u=H.filter(E=>!E.ok).length,w=H.length-u,h=H.length===0?"":u===0?`
|
|
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 ${T.botName??T.larkAppId} \u6267\u884C\uFF09${h}`),await fe(),p(),r.close();return}f.push(`${T.botName??T.larkAppId}: ${y.error??S.status}`)}catch(S){f.push(`${T.botName??T.larkAppId}: ${S}`)}alert(`\u6240\u6709\u5728\u7FA4\u673A\u5668\u4EBA\u5747\u65E0\u6CD5\u89E3\u6563\uFF1A
|
|
310
|
+
${f.join(`
|
|
311
311
|
`)}
|
|
312
312
|
|
|
313
|
-
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}
|
|
313
|
+
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}s.addEventListener("input",p)}var re={bots:[]},me=null;function Hn(){return`<section class="page">
|
|
314
314
|
<div class="page-heading">
|
|
315
315
|
<div>
|
|
316
|
-
<p class="eyebrow">${
|
|
317
|
-
<h1>${
|
|
318
|
-
<p>${
|
|
316
|
+
<p class="eyebrow">${o("nav.botDefaults")}</p>
|
|
317
|
+
<h1>${o("botDefaults.title")}</h1>
|
|
318
|
+
<p>${o("botDefaults.subtitle")}</p>
|
|
319
319
|
</div>
|
|
320
320
|
</div>
|
|
321
321
|
<form id="bd-filters" class="filters">
|
|
322
|
-
<input type="search" name="q" placeholder="${
|
|
323
|
-
<button type="button" id="bd-refresh">${
|
|
322
|
+
<input type="search" name="q" placeholder="${o("botDefaults.search")}" />
|
|
323
|
+
<button type="button" id="bd-refresh">${o("botDefaults.refresh")}</button>
|
|
324
324
|
</form>
|
|
325
325
|
<div id="bd-list"></div>
|
|
326
|
-
</section>`}async function
|
|
327
|
-
<header><strong>${
|
|
328
|
-
<small>${
|
|
329
|
-
<p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${
|
|
330
|
-
</article>`;let g=
|
|
326
|
+
</section>`}async function Tt(){try{let e=await fetch("/api/bots"),t=await e.json().catch(()=>({}));if(!e.ok){me=t?.error?`HTTP ${e.status}: ${t.error}${t.path?` (${t.path})`:""}`:`HTTP ${e.status}`,re={bots:[]};return}if(!t||!Array.isArray(t.bots)){me="unexpected response shape (no `bots` array)",re={bots:[]};return}me=null,re=t}catch(e){me=e?.message??String(e),re={bots:[]}}}function Lt(e){if(!e)return"\u2014";let t=new Date(e);return Number.isNaN(t.getTime())?"\u2014":t.toLocaleString()}async function Et(e){e.innerHTML=Hn();let t=e.querySelector("#bd-list"),n=e.querySelector("#bd-filters"),s=e.querySelector("#bd-refresh");s.onclick=async()=>{s.disabled=!0;try{await Tt(),a()}finally{s.disabled=!1}},await Tt();function a(){let g=(new FormData(n).get("q")??"").toLowerCase(),l=re.bots.filter(I=>!g||(I.botName??"").toLowerCase().includes(g)||(I.larkAppId??"").toLowerCase().includes(g));if(me){t.innerHTML=`<p class="hint-warn">\u65E0\u6CD5\u52A0\u8F7D bot \u5217\u8868\uFF1A${d(me)}<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(l.length===0){t.innerHTML=`<p class="empty">${o("botDefaults.empty")}</p>`;return}t.innerHTML=l.map(r).join(""),$()}function r(p){if(p.error)return`<article class="bd-card" data-appid="${d(p.larkAppId)}">
|
|
327
|
+
<header><strong>${d(p.botName??p.larkAppId)}</strong>
|
|
328
|
+
<small>${d(p.larkAppId)}</small></header>
|
|
329
|
+
<p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${d(p.error)}</p>
|
|
330
|
+
</article>`;let g=p.defaultOncall??{enabled:!1,workingDir:"",since:0},l=!!g.enabled;return`<article class="bd-card" data-appid="${d(p.larkAppId)}">
|
|
331
331
|
<header>
|
|
332
|
-
<strong>${
|
|
333
|
-
<small>${
|
|
332
|
+
<strong>${d(p.botName??p.larkAppId)}</strong>
|
|
333
|
+
<small>${d(p.larkAppId)}</small>
|
|
334
334
|
</header>
|
|
335
335
|
<div class="bd-body">
|
|
336
336
|
<section class="bd-section">
|
|
337
|
-
<h3 class="bd-section-title">${
|
|
337
|
+
<h3 class="bd-section-title">${o("botDefaults.sectionOncall")}</h3>
|
|
338
338
|
<label class="checkbox-row">
|
|
339
339
|
<input type="checkbox" data-action="toggle" ${l?"checked":""}>
|
|
340
|
-
<strong>${
|
|
341
|
-
<small>${
|
|
340
|
+
<strong>${o("botDefaults.defaultOncall")}</strong>
|
|
341
|
+
<small>${o("botDefaults.defaultOncallHelp")}</small>
|
|
342
342
|
</label>
|
|
343
343
|
<div class="bd-row">
|
|
344
344
|
<label>
|
|
345
|
-
<span>${
|
|
345
|
+
<span>${o("botDefaults.workingDir")}</span>
|
|
346
346
|
<input type="text" data-input="workingDir" placeholder="e.g. /root/iserver/botmux"
|
|
347
|
-
value="${
|
|
347
|
+
value="${d(g.workingDir??"")}" ${l?"":"disabled"}>
|
|
348
348
|
</label>
|
|
349
349
|
</div>
|
|
350
|
-
<p class="bd-section-note">${
|
|
350
|
+
<p class="bd-section-note">${o("botDefaults.warning")}</p>
|
|
351
351
|
<div class="bd-meta">
|
|
352
|
-
<small>${
|
|
353
|
-
<small>${
|
|
352
|
+
<small>${o("botDefaults.lastEnabled")}: ${d(Lt(g.since??0))}</small>
|
|
353
|
+
<small>${o("botDefaults.autobound",{count:p.autoboundChatCount??0})}</small>
|
|
354
354
|
</div>
|
|
355
355
|
<div class="actions">
|
|
356
|
-
<button type="button" data-action="save">${
|
|
356
|
+
<button type="button" data-action="save">${o("botDefaults.save")}</button>
|
|
357
357
|
<span class="oncall-status" data-status></span>
|
|
358
358
|
</div>
|
|
359
359
|
</section>
|
|
360
|
-
${
|
|
361
|
-
${
|
|
360
|
+
${m(p)}
|
|
361
|
+
${k(p)}
|
|
362
362
|
</div>
|
|
363
|
-
</article>`}function
|
|
364
|
-
<h3 class="bd-section-title">${
|
|
363
|
+
</article>`}function i(p){return p==null?o("botDefaults.brandStateDefault"):p.trim()===""?o("botDefaults.brandStateOff"):o("botDefaults.brandStateCustom")}function m(p){let g=p.brandLabel??null;return`<section class="bd-section">
|
|
364
|
+
<h3 class="bd-section-title">${o("botDefaults.sectionBrand")}</h3>
|
|
365
365
|
<div class="bd-row bd-brand">
|
|
366
366
|
<label>
|
|
367
|
-
<span>${
|
|
367
|
+
<span>${o("botDefaults.brandLabel")}</span>
|
|
368
368
|
<input type="text" data-input="brandLabel"
|
|
369
|
-
placeholder="${
|
|
370
|
-
value="${
|
|
369
|
+
placeholder="${d(o("botDefaults.brandLabelPlaceholder"))}"
|
|
370
|
+
value="${d(g??"")}">
|
|
371
371
|
</label>
|
|
372
|
-
<small data-brand-state>${
|
|
373
|
-
<small>${
|
|
372
|
+
<small data-brand-state>${d(i(g))}</small>
|
|
373
|
+
<small>${o("botDefaults.brandLabelHelp")}</small>
|
|
374
374
|
<div class="actions">
|
|
375
|
-
<button type="button" data-action="save-brand">${
|
|
376
|
-
<button type="button" data-action="reset-brand">${
|
|
375
|
+
<button type="button" data-action="save-brand">${o("botDefaults.brandSave")}</button>
|
|
376
|
+
<button type="button" data-action="reset-brand">${o("botDefaults.brandReset")}</button>
|
|
377
377
|
<span class="oncall-status" data-brand-status></span>
|
|
378
378
|
</div>
|
|
379
379
|
</div>
|
|
380
|
-
</section>`}function
|
|
381
|
-
<h3 class="bd-section-title">${
|
|
380
|
+
</section>`}function k(p){let g=p.disableStreamingCard===!0,l=p.writableTerminalLinkInCard===!0,I=p.privateCard===!0;return`<section class="bd-section">
|
|
381
|
+
<h3 class="bd-section-title">${o("botDefaults.sectionCard")}</h3>
|
|
382
382
|
<label class="checkbox-row">
|
|
383
383
|
<input type="checkbox" data-action="toggle-disable-streaming" ${g?"checked":""}>
|
|
384
|
-
<strong>${
|
|
385
|
-
<small>${
|
|
384
|
+
<strong>${o("botDefaults.disableStreaming")}</strong>
|
|
385
|
+
<small>${o("botDefaults.disableStreamingHelp")}</small>
|
|
386
386
|
</label>
|
|
387
387
|
<label class="checkbox-row">
|
|
388
388
|
<input type="checkbox" data-action="toggle-writable-link" ${l?"checked":""} ${g?"disabled":""}>
|
|
389
|
-
<strong>${
|
|
390
|
-
<small>${
|
|
389
|
+
<strong>${o("botDefaults.writableLink")}</strong>
|
|
390
|
+
<small>${o("botDefaults.writableLinkHelp")}</small>
|
|
391
391
|
</label>
|
|
392
392
|
<label class="checkbox-row">
|
|
393
|
-
<input type="checkbox" data-action="toggle-private-card" ${
|
|
394
|
-
<strong>${
|
|
395
|
-
<small>${
|
|
393
|
+
<input type="checkbox" data-action="toggle-private-card" ${I?"checked":""}>
|
|
394
|
+
<strong>${o("botDefaults.privateCard")}</strong>
|
|
395
|
+
<small>${o("botDefaults.privateCardHelp")}</small>
|
|
396
396
|
</label>
|
|
397
397
|
<div class="actions">
|
|
398
|
-
<small data-card-pref-moot class="hint-warn-inline" ${g?"":"hidden"}>${
|
|
398
|
+
<small data-card-pref-moot class="hint-warn-inline" ${g?"":"hidden"}>${o("botDefaults.writableLinkMoot")}</small>
|
|
399
399
|
<span class="oncall-status" data-card-pref-status></span>
|
|
400
400
|
</div>
|
|
401
|
-
</section>`}function
|
|
401
|
+
</section>`}function $(){t.querySelectorAll(".bd-card").forEach(p=>{let g=p.dataset.appid,l=p.querySelector("input[data-action=toggle]"),I=p.querySelector("input[data-input=workingDir]"),L=p.querySelector("button[data-action=save]"),b=p.querySelector("[data-status]");if(!l||!I||!L||!b)return;l.addEventListener("change",()=>{I.disabled=!l.checked,l.checked&&I.focus()}),L.addEventListener("click",async()=>{b.textContent="",b.className="oncall-status";let O=l.checked,x=I.value.trim();if(O&&!x){b.textContent=o("botDefaults.required"),b.classList.add("hint-warn-inline");return}L.disabled=!0;try{let q=await fetch(`/api/bots/${encodeURIComponent(g)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:O,workingDir:x})}),j=await q.json().catch(()=>({}));if(q.ok&&j.ok){let F=j.resolvedPath?` \u2192 ${j.resolvedPath}`:"";b.textContent=O?`\u2713 \u5DF2\u5F00\u542F${F}\uFF08\u672A\u7ED1\u5B9A\u7684\u7FA4\u4E0B\u6B21\u5F00\u8BDD\u9898\u81EA\u52A8 oncall\uFF09`:"\u2713 \u5DF2\u5173\u95ED\uFF08\u5DF2\u7ED1\u5B9A\u7684\u7FA4\u4E0D\u52A8\uFF09",b.classList.add("hint-ok");let z=re.bots.find(te=>te.larkAppId===g);z&&j.defaultOncall&&(z.defaultOncall=j.defaultOncall);let ee=p.querySelector(".bd-meta small:first-child");ee&&j.defaultOncall?.since!=null&&(ee.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${Lt(j.defaultOncall.since)}`)}else b.textContent=`\u2717 ${j.error??q.status}`,b.classList.add("hint-warn-inline")}catch(q){b.textContent=`\u2717 ${q?.message??q}`,b.classList.add("hint-warn-inline")}finally{L.disabled=!1}});let f=p.querySelector("input[data-input=brandLabel]"),T=p.querySelector("button[data-action=save-brand]"),S=p.querySelector("button[data-action=reset-brand]"),y=p.querySelector("[data-brand-status]"),H=p.querySelector("[data-brand-state]");async function u(O,x){if(y){y.textContent="",y.className="oncall-status",x.disabled=!0;try{let q=await fetch(`/api/bots/${encodeURIComponent(g)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:O})}),j=await q.json().catch(()=>({}));if(q.ok&&j.ok){let F=j.brandLabel??null;y.textContent="\u2713",y.classList.add("hint-ok"),f&&(f.value=F??""),H&&(H.textContent=i(F));let z=re.bots.find(ee=>ee.larkAppId===g);z&&(z.brandLabel=F)}else y.textContent=`\u2717 ${j.error??q.status}`,y.classList.add("hint-warn-inline")}catch(q){y.textContent=`\u2717 ${q?.message??q}`,y.classList.add("hint-warn-inline")}finally{x.disabled=!1}}}f&&T&&T.addEventListener("click",()=>u(f.value,T)),S&&S.addEventListener("click",()=>u(null,S));let w=p.querySelector("input[data-action=toggle-disable-streaming]"),h=p.querySelector("input[data-action=toggle-writable-link]"),E=p.querySelector("input[data-action=toggle-private-card]"),M=p.querySelector("[data-card-pref-status]"),A=p.querySelector("[data-card-pref-moot]");async function P(O,x){if(M){M.textContent="",M.className="oncall-status",x.disabled=!0;try{let q=await fetch(`/api/bots/${encodeURIComponent(g)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(O)}),j=await q.json().catch(()=>({}));if(q.ok&&j.ok){M.textContent=`\u2713 ${o("botDefaults.cardPrefSaved")}`,M.classList.add("hint-ok");let F=re.bots.find(z=>z.larkAppId===g);F&&(F.disableStreamingCard=j.disableStreamingCard,F.writableTerminalLinkInCard=j.writableTerminalLinkInCard,F.privateCard=j.privateCard)}else M.textContent=`\u2717 ${j.error??q.status}`,M.classList.add("hint-warn-inline")}catch(q){M.textContent=`\u2717 ${q?.message??q}`,M.classList.add("hint-warn-inline")}finally{x===h?x.disabled=!!w?.checked:x.disabled=!1}}}w&&w.addEventListener("change",()=>{let O=w.checked;h&&(h.disabled=O),A&&(A.hidden=!O),P({disableStreamingCard:O},w)}),h&&h.addEventListener("change",()=>{P({writableTerminalLinkInCard:h.checked},h)}),E&&E.addEventListener("change",()=>{P({privateCard:E.checked},E)})})}a(),n.addEventListener("input",a)}var Ve=4096,He=[],Q=null,X=null,J="",we=new Set;function xn(){return`<section class="page roles-page">
|
|
402
402
|
<div class="page-heading">
|
|
403
403
|
<div>
|
|
404
|
-
<p class="eyebrow">${
|
|
405
|
-
<h1>${
|
|
406
|
-
<p>${
|
|
404
|
+
<p class="eyebrow">${o("nav.roles")}</p>
|
|
405
|
+
<h1>${o("roles.title")}</h1>
|
|
406
|
+
<p>${o("roles.subtitle")}</p>
|
|
407
407
|
</div>
|
|
408
408
|
</div>
|
|
409
409
|
<div class="roles-layout">
|
|
410
410
|
<div class="roles-tree-panel">
|
|
411
411
|
<div class="roles-tree-header">
|
|
412
|
-
<input type="search" id="roles-search" placeholder="${
|
|
413
|
-
<button type="button" id="roles-refresh">${
|
|
412
|
+
<input type="search" id="roles-search" placeholder="${o("roles.search")}" />
|
|
413
|
+
<button type="button" id="roles-refresh">${o("roles.refresh")}</button>
|
|
414
414
|
</div>
|
|
415
415
|
<div id="roles-tree" class="roles-tree"></div>
|
|
416
416
|
</div>
|
|
417
417
|
<div class="roles-editor-panel">
|
|
418
|
-
<div id="roles-editor-empty" class="roles-editor-empty">${
|
|
418
|
+
<div id="roles-editor-empty" class="roles-editor-empty">${o("roles.selectHint")}</div>
|
|
419
419
|
<div id="roles-editor-form" class="roles-editor-form" style="display:none">
|
|
420
420
|
<div class="roles-editor-breadcrumb">
|
|
421
421
|
<span id="roles-editor-group-name"></span>
|
|
@@ -425,82 +425,205 @@ ${u.join(`
|
|
|
425
425
|
<div class="roles-editor-meta">
|
|
426
426
|
<span id="roles-editor-chat-id" class="roles-editor-meta-line"></span>
|
|
427
427
|
</div>
|
|
428
|
-
<textarea id="roles-editor-textarea" placeholder="${
|
|
428
|
+
<textarea id="roles-editor-textarea" placeholder="${o("roles.editorPlaceholder")}" rows="14"></textarea>
|
|
429
429
|
<div class="roles-editor-footer">
|
|
430
430
|
<span id="roles-editor-bytecount" class="roles-bytecount"></span>
|
|
431
431
|
<div class="roles-editor-actions">
|
|
432
|
-
<button type="button" id="roles-delete" class="danger">${
|
|
433
|
-
<button type="button" id="roles-save" class="primary">${
|
|
432
|
+
<button type="button" id="roles-delete" class="danger">${o("roles.delete")}</button>
|
|
433
|
+
<button type="button" id="roles-save" class="primary">${o("roles.save")}</button>
|
|
434
434
|
</div>
|
|
435
435
|
</div>
|
|
436
436
|
<div id="roles-preview" class="roles-preview"></div>
|
|
437
437
|
</div>
|
|
438
438
|
</div>
|
|
439
439
|
</div>
|
|
440
|
-
</section>`}async function
|
|
441
|
-
<div class="roles-bot-row ${
|
|
442
|
-
data-group-id="${
|
|
443
|
-
data-bot-id="${
|
|
440
|
+
</section>`}async function Ce(){He=((await(await fetch("/api/groups")).json()).chats??[]).map(n=>({chatId:n.chatId,name:n.name??n.chatId,memberBots:(n.memberBots??[]).map(s=>({larkAppId:s.larkAppId,botName:s.botName??s.larkAppId,inChat:s.inChat??!1,hasRole:s.hasRole??!1,oncallChat:s.oncallChat??null}))}))}async function Ct(e,t){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)).json()}async function An(e,t,n){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({content:n})})).ok}async function Rn(e,t){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{method:"DELETE"})).ok}function Ht(e){return e.memberBots.filter(t=>t.inChat&&t.hasRole).length}function Dn(e){return e.memberBots.filter(t=>t.inChat).length}function de(e=""){let t=document.getElementById("roles-tree");if(!t)return;let n=e.toLowerCase(),s=He.filter(a=>{if(!n)return!0;let r=a.chatId.toLowerCase().includes(n)||(a.name??"").toLowerCase().includes(n),i=a.memberBots.some(m=>m.larkAppId.toLowerCase().includes(n)||(m.botName??"").toLowerCase().includes(n));return r||i});if(s.length===0){t.innerHTML=`<div class="roles-empty">${o("roles.noChats")}</div>`;return}t.innerHTML=s.map(a=>{let r=we.has(a.chatId),i=a.memberBots.filter(g=>g.inChat),m=r?"\u25BE":"\u25B8",k=Ht(a),$=Dn(a),p=r?i.map(g=>`
|
|
441
|
+
<div class="roles-bot-row ${Q===a.chatId&&X===g.larkAppId?"selected":""}"
|
|
442
|
+
data-group-id="${d(a.chatId)}"
|
|
443
|
+
data-bot-id="${d(g.larkAppId)}">
|
|
444
444
|
<span class="roles-bot-indent"></span>
|
|
445
445
|
<span class="roles-bot-icon">\u{1F916}</span>
|
|
446
446
|
<div class="roles-bot-info">
|
|
447
|
-
<div class="roles-bot-name">${
|
|
448
|
-
<div class="roles-bot-id">${
|
|
447
|
+
<div class="roles-bot-name">${d(g.botName)}</div>
|
|
448
|
+
<div class="roles-bot-id">${d(g.larkAppId)}</div>
|
|
449
449
|
</div>
|
|
450
450
|
<span class="roles-badge ${g.hasRole?"has-role":"no-role"}">
|
|
451
|
-
${g.hasRole?
|
|
451
|
+
${g.hasRole?o("roles.configured"):o("roles.unconfigured")}
|
|
452
452
|
</span>
|
|
453
453
|
</div>`).join(""):"";return`
|
|
454
454
|
<div class="roles-group-section">
|
|
455
|
-
<div class="roles-group-row ${
|
|
456
|
-
data-group-id="${
|
|
457
|
-
<span class="roles-group-arrow">${
|
|
455
|
+
<div class="roles-group-row ${r?"expanded":""} ${Q===a.chatId&&!X?"selected":""}"
|
|
456
|
+
data-group-id="${d(a.chatId)}">
|
|
457
|
+
<span class="roles-group-arrow">${m}</span>
|
|
458
458
|
<span class="roles-group-icon">\u{1F4C1}</span>
|
|
459
459
|
<div class="roles-group-info">
|
|
460
|
-
<div class="roles-group-name">${
|
|
460
|
+
<div class="roles-group-name">${d(a.name??a.chatId)}</div>
|
|
461
461
|
<div class="roles-group-meta">
|
|
462
|
-
${
|
|
462
|
+
${k}/${$} ${o("roles.botsWithRoles")}
|
|
463
463
|
</div>
|
|
464
464
|
</div>
|
|
465
465
|
<span class="roles-group-chevron"></span>
|
|
466
466
|
</div>
|
|
467
|
-
<div class="roles-bot-list">${
|
|
468
|
-
</div>`}).join(""),t.querySelectorAll(".roles-group-row").forEach(a=>{a.addEventListener("click",()=>{let
|
|
467
|
+
<div class="roles-bot-list">${p}</div>
|
|
468
|
+
</div>`}).join(""),t.querySelectorAll(".roles-group-row").forEach(a=>{a.addEventListener("click",()=>{let r=a.dataset.groupId;r&&(we.has(r)?we.delete(r):we.add(r),de(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&&Bn(i,m)})})}async function Bn(e,t){Q=e,X=t;let n=await Ct(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"),k=document.getElementById("roles-editor-chat-id");s&&(s.style.display="none"),a&&(a.style.display="");let $=He.find(l=>l.chatId===e),p=$?.memberBots.find(l=>l.larkAppId===t);i&&(i.textContent=$?.name??e),m&&(m.textContent=p?.botName??t),k&&(k.textContent=`${e} \xB7 ${t}`),J=n.content??"",r&&(r.value=J,r.focus()),Ye(),Qe(),de(document.getElementById("roles-search")?.value??"");let g=document.getElementById("roles-delete");g&&(g.style.display=n.hasRole?"":"none")}function Ye(){let e=document.getElementById("roles-editor-bytecount");if(!e)return;let t=new TextEncoder().encode(J).length;e.textContent=`${t} / ${Ve} bytes`,e.className=`roles-bytecount ${t>3800?"warn":""} ${t>Ve?"over":""}`,On(t)}function On(e){let t=document.getElementById("roles-save");if(!t)return;let n=e??new TextEncoder().encode(J).length;t.disabled=n>Ve||J.trim().length===0}function Qe(){let e=document.getElementById("roles-preview");e&&(J.trim()?e.innerHTML=`<strong>${o("roles.preview")}</strong><pre>${d(J)}</pre>`:e.innerHTML=`<small>${o("roles.previewEmpty")}</small>`)}function Mt(){Q=null,X=null,J="";let e=document.getElementById("roles-editor-empty"),t=document.getElementById("roles-editor-form"),n=document.getElementById("roles-editor-textarea"),s=document.getElementById("roles-delete");e&&(e.style.display=""),t&&(t.style.display="none"),n&&(n.value=""),s&&(s.style.display="none")}async function xt(e){e.innerHTML=xn(),we.clear(),Mt(),await Ce();for(let t of He)Ht(t)>0&&we.add(t.chatId);de(),document.getElementById("roles-search")?.addEventListener("input",t=>{de(t.target.value)}),document.getElementById("roles-refresh")?.addEventListener("click",async()=>{if(await Ce(),de(document.getElementById("roles-search")?.value??""),Q&&X){let t=await Ct(X,Q),n=document.getElementById("roles-editor-textarea");n&&(n.value=t.content??""),J=t.content??"",Ye(),Qe();let s=document.getElementById("roles-delete");s&&(s.style.display=t.hasRole?"":"none")}}),document.getElementById("roles-save")?.addEventListener("click",async function(){if(!(!Q||!X)){this.disabled=!0,this.textContent="...";try{if(await An(X,Q,J)){await Ce(),de(document.getElementById("roles-search")?.value??"");let n=document.getElementById("roles-delete");n&&(n.style.display="");let s=document.createElement("span");s.className="roles-saved-flash",s.textContent=` ${o("roles.saved")}`,document.querySelector(".roles-editor-footer")?.appendChild(s),setTimeout(()=>s.remove(),2e3)}else{let n=document.createElement("span");n.className="roles-saved-flash roles-save-error",n.textContent=J.trim().length===0?` ${o("roles.emptyError")}`:` ${o("roles.saveFailed")}`,document.querySelector(".roles-editor-footer")?.appendChild(n),setTimeout(()=>n.remove(),3e3)}}finally{this.disabled=!1,this.textContent=o("roles.save")}}}),document.getElementById("roles-delete")?.addEventListener("click",async function(){if(!(!Q||!X)&&confirm(o("roles.confirmDelete"))){this.disabled=!0,this.textContent="...";try{await Rn(X,Q)&&(await Ce(),Mt(),de(document.getElementById("roles-search")?.value??""))}finally{this.disabled=!1,this.textContent=o("roles.delete")}}}),document.getElementById("roles-editor-textarea")?.addEventListener("input",t=>{J=t.target.value,Ye(),Qe()})}async function Re(e){let t=await fetch(e);return{status:t.status,body:await t.json().catch(()=>({}))}}async function De(e,t,n){let s=await fetch(t,{method:e,headers:{"content-type":"application/json"},body:n?JSON.stringify(n):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}var ue=(e,t)=>De("POST",e,t),At=(e,t)=>De("PUT",e,t),Xe=[],Rt=[],Dt="",xe="",Ze=new Map,Ae=new Map,ye=new Set,ve=new Set;function B(e){return document.getElementById(e)}function Be(){return[...Xe,...Rt]}function ce(e){let t=Ze.get(e);return t||(t=new Set,Ze.set(e,t)),t}function qn(e){return Be().find(t=>t.key===e)}function Bt(e){let t=(n,s,a)=>`<a href="${n}" 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 Pn(){return`<section class="page">
|
|
469
|
+
<div class="page-heading"><div>
|
|
470
|
+
<p class="eyebrow">\u56E2\u961F</p><h1>\u56E2\u961F\u534F\u4F5C\uFF08\u8DE8\u90E8\u7F72\uFF09</h1>
|
|
471
|
+
<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>
|
|
472
|
+
</div></div>
|
|
473
|
+
${Bt("home")}
|
|
474
|
+
<div class="card" style="margin-bottom:16px">
|
|
475
|
+
<h2 style="margin-top:0">\u672C\u90E8\u7F72</h2>
|
|
476
|
+
<p>\u6211\u7684\u98DE\u4E66\u8EAB\u4EFD\uFF1A<b id="tf-owner">\u672A\u7ED1\u5B9A</b>
|
|
477
|
+
<button id="tf-autobind" class="primary" style="margin-left:8px">\u7ED1\u5B9A</button>
|
|
478
|
+
<span class="muted" style="font-size:13px">\uFF08\u7528\u673A\u5668\u4EBA\u51ED\u8BC1\u81EA\u52A8\u8BC6\u522B\u4F60\uFF1B\u7ED1\u5B9A\u540E\u62C9\u7FA4\u4F1A\u628A\u4F60\u62C9\u8FDB\u7FA4\u3001\u673A\u5668\u4EBA\u4E5F\u5F52\u5230\u4F60\u540D\u4E0B\uFF09</span></p>
|
|
479
|
+
<div id="tf-bind-out" style="display:none;margin-top:6px"></div>
|
|
480
|
+
</div>
|
|
481
|
+
<div class="card">
|
|
482
|
+
<h2 style="margin-top:0">\u6211\u7684\u56E2\u961F <span class="muted" id="tf-count" style="font-size:13px"></span></h2>
|
|
483
|
+
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:8px;font-size:13px">
|
|
484
|
+
<input id="tf-search" placeholder="\u641C\u7D22 \u540D\u79F0/\u80FD\u529B/CLI\u2026" style="padding:5px 9px;min-width:180px">
|
|
485
|
+
<select id="tf-cli" style="padding:5px"><option value="">\u5168\u90E8 CLI</option></select>
|
|
486
|
+
<label><input type="checkbox" id="tf-fcap"> \u6709\u80FD\u529B\u6807\u7B7E</label>
|
|
487
|
+
<label><input type="checkbox" id="tf-frole"> \u6709\u56E2\u961F\u89D2\u8272</label>
|
|
488
|
+
</div>
|
|
489
|
+
<p class="muted" style="font-size:13px;margin:0 0 4px">\u6BCF\u4E2A\u56E2\u961F\u91CC\u52FE\u9009\u673A\u5668\u4EBA\u5373\u53EF\u5355\u72EC\u62C9\u7FA4\uFF08\u81EA\u52A8\u5E26\u4E0A\u5404\u81EA\u8D1F\u8D23\u4EBA\uFF09\u3002\u8981\u65B0\u5EFA\u56E2\u961F / \u751F\u6210\u9080\u8BF7\u7801 / \u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F\uFF0C\u53BB\u300C\u56E2\u961F\u7BA1\u7406\u300D\u3002</p>
|
|
490
|
+
<div id="tf-teams">\u52A0\u8F7D\u4E2D\u2026</div>
|
|
491
|
+
</div>
|
|
492
|
+
<div id="tf-modal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);align-items:center;justify-content:center;z-index:50">
|
|
493
|
+
<div style="background:var(--card,#fff);color:var(--text,#1f2329);border-radius:10px;padding:18px 20px;width:min(560px,92vw)">
|
|
494
|
+
<h2 id="tf-modal-title" style="margin-top:0">\u56E2\u961F\u89D2\u8272</h2>
|
|
495
|
+
<p class="muted" style="font-size:13px">\u56E2\u961F\u7EA7\u89D2\u8272\uFF08\u8BE5\u673A\u5668\u4EBA\u8DE8\u7FA4\u7684\u9ED8\u8BA4\u4EBA\u8BBE\uFF09\u3002\u7559\u7A7A\u4FDD\u5B58\u5373\u5220\u9664\u3002\u4EC5\u672C\u90E8\u7F72\u7684\u673A\u5668\u4EBA\u53EF\u7F16\u8F91\u3002</p>
|
|
496
|
+
<textarea id="tf-modal-text" style="width:100%;min-height:200px;font:13px/1.5 ui-monospace,Menlo,monospace;padding:10px;box-sizing:border-box"></textarea>
|
|
497
|
+
<div style="display:flex;justify-content:flex-end;gap:8px;margin-top:12px">
|
|
498
|
+
<button id="tf-modal-cancel">\u53D6\u6D88</button><button id="tf-modal-save" class="primary">\u4FDD\u5B58</button>
|
|
499
|
+
</div>
|
|
500
|
+
</div>
|
|
501
|
+
</div>
|
|
502
|
+
</section>`}function Nn(e){let t=(B("tf-search").value||"").trim().toLowerCase();if(t&&!((e.name||"")+" "+(e.cliId||"")+" "+(e.capability||"")).toLowerCase().includes(t))return!1;let n=B("tf-cli").value;return!(n&&e.cliId!==n||B("tf-fcap").checked&&!e.capability||B("tf-frole").checked&&!e.hasTeamRole)}function jn(e,t){let n=[...e.deployments].sort((a,r)=>a.local===r.local?0:a.local?-1:1),s="";for(let a of n){let r=t.filter(l=>l.deployment.id===a.id);if(!r.length)continue;let i=a.id===Dt,m=i?"\u672C\u90E8\u7F72":a.stale?"\u8FDC\u7AEF\xB7\u79BB\u7EBF\uFF1F":"\u8FDC\u7AEF",k=e.kind==="local"&&!i?` <button class="tf-rmmember ghost" data-team="${d(e.teamId)}" data-dep="${d(a.id)}" data-name="${d(a.name)}" style="font-size:12px">\u79FB\u9664</button>`:"",$=`${e.key}::${a.id}`,p=ve.has($),g=r.filter(l=>ce(e.key).has(l.larkAppId)).length;if(s+=`<div class="tf-dep-h" data-dk="${d($)}" style="cursor:pointer;margin:10px 0 2px"><b>${p?"\u25BE":"\u25B8"} ${d(a.name)}</b> <span class="muted" style="font-size:12px">\uFF08${m}\uFF09\xB7 ${r.length} \u4E2A${g?`\uFF0C\u5DF2\u9009 ${g}`:""}</span>${k}</div>`,!!p){s+='<table style="width:100%;border-collapse:collapse;font-size:14px"><tbody>';for(let l of r){let I=d(l.larkAppId),L=ce(e.key).has(l.larkAppId)?" checked":"",b=l.deployment.stale?"opacity:.55":"",f=i?`<input class="tf-cap" data-app="${I}" value="${d(l.capability||"")}" placeholder="\u80FD\u529B\u6807\u7B7E\u2026" style="width:92%;padding:3px 6px">`:l.capability?d(l.capability):'<span class="muted">\u2014</span>',T=i?`<button class="tf-role" data-app="${I}" data-name="${d(l.name)}">${l.hasTeamRole?"\u5DF2\u8BBE\xB7\u6539":"\u8BBE\u7F6E"}</button>`:l.hasTeamRole?"\u6709\u89D2\u8272":'<span class="muted">\u2014</span>';s+=`<tr style="${b}"><td style="padding:4px 8px"><input type="checkbox" class="tf-pick" data-tk="${d(e.key)}" data-app="${I}"${L}></td><td style="padding:4px 8px">${d(l.name)}</td><td style="padding:4px 8px" class="muted">${d(l.cliId)}</td><td style="padding:4px 8px">${f}</td><td style="padding:4px 8px">${T}</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="${d(e.key)}" value="${d(Ae.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="${d(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="${d(e.key)}" style="font-size:13px;display:block;flex-basis:100%"></span></div>`,s}function ie(){let e=B("tf-teams"),t=Be();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>',B("tf-count").textContent="";return}let n="",s=new Set,a=new Set;for(let i of t){let m=i.bots.filter(Nn);m.forEach(g=>s.add(g.larkAppId)),i.bots.forEach(g=>a.add(g.larkAppId));let k=new Set(m.map(g=>g.larkAppId));[...ce(i.key)].forEach(g=>{k.has(g)||ce(i.key).delete(g)});let $=!ye.has(i.key),p=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${d(i.error||"")}</span>`:' <span class="muted" style="font-size:12px">\u6211\u6258\u7BA1</span>';n+=`<div class="card" style="margin:0 0 12px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)"><div class="tf-team-h" data-tk="${d(i.key)}" style="cursor:pointer;display:flex;align-items:center;gap:8px;flex-wrap:wrap"><b style="font-size:15px">${$?"\u25B8":"\u25BE"} ${d(i.label)}</b>`+(i.sub?` <span class="muted" style="font-size:12px">${d(i.sub)}</span>`:"")+p+` <span class="muted" style="font-size:12px">\xB7 ${i.deployments.length} \u4E2A\u90E8\u7F72 \xB7 ${i.bots.length} \u4E2A\u673A\u5668\u4EBA</span></div>`,$||(n+=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>':jn(i,m)),n+="</div>"}e.innerHTML=n;let r=t.length>1?`\uFF08\u8DE8 ${t.length} \u4E2A\u56E2\u961F\uFF0C\u53BB\u91CD\uFF09`:"";B("tf-count").textContent=`\xB7 ${s.size===a.size?`${a.size}`:`${s.size} / ${a.size}`} \u4E2A\u673A\u5668\u4EBA${r}`,Un()}function Un(){let e=B("tf-teams");e.querySelectorAll(".tf-team-h").forEach(t=>{t.onclick=()=>{let n=t.dataset.tk;ye.has(n)?ye.delete(n):ye.add(n),ie()}}),e.querySelectorAll(".tf-dep-h").forEach(t=>{t.onclick=()=>{let n=t.dataset.dk;ve.has(n)?ve.delete(n):ve.add(n),ie()}}),e.querySelectorAll(".tf-pick").forEach(t=>{t.onchange=()=>{let n=ce(t.dataset.tk);t.checked?n.add(t.dataset.app):n.delete(t.dataset.app)}}),e.querySelectorAll(".tf-gname").forEach(t=>{t.oninput=()=>{Ae.set(t.dataset.tk,t.value)}}),e.querySelectorAll(".tf-cap").forEach(t=>{t.onchange=async()=>{let n=t.dataset.app,s=t.value;await At("/api/team/local-bots/"+encodeURIComponent(n)+"/capability",{capability:s}),Be().forEach(a=>{let r=a.bots.find(i=>i.larkAppId===n);r&&(r.capability=s.trim()||null)})}}),e.querySelectorAll(".tf-role").forEach(t=>{t.onclick=()=>_n(t.dataset.app,t.dataset.name||"")}),e.querySelectorAll(".tf-rmmember").forEach(t=>{t.onclick=async n=>{n.stopPropagation(),confirm(`\u628A\u300C${t.dataset.name}\u300D\u79FB\u51FA\u8FD9\u4E2A\u56E2\u961F\uFF1F\u5B83\u7684\u673A\u5668\u4EBA\u5C06\u4ECE\u672C\u56E2\u961F\u82B1\u540D\u518C\u6D88\u5931\uFF08\u4E0D\u5F71\u54CD\u5BF9\u65B9\u81EA\u5DF1\u7684\u90E8\u7F72\uFF09\u3002`)&&(await De("DELETE",`/api/team/hosted/${encodeURIComponent(t.dataset.team)}/members/${encodeURIComponent(t.dataset.dep)}`),ge())}}),e.querySelectorAll(".tf-grp").forEach(t=>{t.onclick=async()=>{let n=t.dataset.tk,s=qn(n);if(!s)return;let a=[...ce(n)],r=e.querySelector(`.tf-gout[data-tk="${CSS.escape(n)}"]`);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(n)}"]`)?.value||"").trim()||"\u534F\u4F5C\u7FA4";r.innerHTML='<span class="muted">\u5EFA\u7FA4\u4E2D\u2026</span>';let m=s.kind==="local"?await ue("/api/team/federated-group",{name:i,larkAppIds:a,teamId:s.teamId}):await ue("/api/team/remote-group",{hubUrl:s.hubUrl,teamId:s.teamId,name:i,larkAppIds:a});if(Fn(r,m.body,m.status),m.body?.ok){ce(n).clear(),Ae.delete(n);let k=r.innerHTML,$=()=>{let p=e.querySelector(`.tf-gout[data-tk="${CSS.escape(n)}"]`);p&&(p.innerHTML=k)};s.kind==="local"?ge().then($):(ie(),$())}}})}function Fn(e,t,n){if(t?.ok&&t.chatId){let s=t.shareLink||"https://applink.feishu.cn/client/chat/open?openChatId="+encodeURIComponent(t.chatId),a=(t.invalidBotIds||[]).length?`<span class="err"> \xB7 \u672A\u52A0\u5165\u7684\u673A\u5668\u4EBA\uFF1A${d((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>`:"",k=t.delegatedTo?`\uFF08\u7531\u300C${d(t.delegatedTo)}\u300D\u5EFA\u7FA4\uFF09`:"";e.innerHTML=`<span class="ok">\u7FA4\u5DF2\u521B\u5EFA</span>${k} \xB7 <a href="${d(s)}" target="_blank">\u5728\u98DE\u4E66\u6253\u5F00</a>${a}${r}${i}${m}`}else{let s=t?.error||n,a=s==="no_local_online_bot"?"\u8BF7\u81F3\u5C11\u52FE\u9009\u4E00\u4E2A\u4F60\u81EA\u5DF1\uFF08\u672C\u90E8\u7F72\uFF09\u7684\u5728\u7EBF\u673A\u5668\u4EBA\u2014\u2014\u7FA4\u8981\u7531\u5B83\u521B\u5EFA\u5E76\u628A\u4F60\uFF08\u53D1\u8D77\u4EBA\uFF09\u62C9\u8FDB\u7FA4\u3002":s==="all_bots_skipped_no_owner"?"\u6240\u9009\u673A\u5668\u4EBA\u7684\u8D1F\u8D23\u4EBA\u90FD\u6CA1\u7ED1\u5B9A\u8EAB\u4EFD\uFF0C\u65E0\u6CD5\u62C9\u7FA4\uFF08\u673A\u5668\u4EBA\u4E0D\u80FD\u8FDB\u4E00\u4E2A owner \u4E0D\u5728\u7684\u7FA4\uFF09\u3002\u8BF7\u8BA9\u5BF9\u5E94\u90E8\u7F72\u5148\u7ED1\u5B9A\u8EAB\u4EFD\u3002":s==="no_creator_available"?"\u6CA1\u6709\u53EF\u7528\u7684\u5EFA\u7FA4\u53D1\u8D77\u65B9\uFF08\u76F8\u5173\u90E8\u7F72\u90FD\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF0C\u6216\u4E0D\u53EF\u8FBE\uFF09":s==="delegation_timeout"?"\u59D4\u6258\u5BF9\u65B9\u90E8\u7F72\u5EFA\u7FA4\u8D85\u65F6\uFF08\u53EF\u80FD\u5DF2\u5EFA\uFF0C\u53BB\u98DE\u4E66\u786E\u8BA4\uFF0C\u52FF\u91CD\u590D\u70B9\uFF09":`\u5EFA\u7FA4\u5931\u8D25\uFF1A${s}`;e.innerHTML=`<span class="err">${d(String(a))}</span>`}}async function _n(e,t){let n=await Re("/api/team/local-bots/"+encodeURIComponent(e)+"/role");B("tf-modal-title").textContent="\u56E2\u961F\u89D2\u8272 \xB7 "+t,B("tf-modal-text").value=n.body?.role||"",B("tf-modal").dataset.app=e,B("tf-modal").style.display="flex"}function Ot(){let e=Array.from(new Set(Be().flatMap(s=>s.bots.map(a=>a.cliId)).filter(Boolean))).sort(),t=B("tf-cli"),n=t.value;t.innerHTML='<option value="">\u5168\u90E8 CLI</option>'+e.map(s=>`<option value="${d(s)}">${d(s)}</option>`).join(""),t.value=n}async function ge(){let t=(await Re("/api/team/hosted")).body;if(!t?.ok){Xe=[],ie();return}Dt=t.deployment.deploymentId,xe=t.suggestedHubUrl||"",B("tf-owner").textContent=t.deployment.ownerName||(t.deployment.ownerUnionId?"\u5DF2\u7ED1\u5B9A":"\u672A\u7ED1\u5B9A"),Xe=(t.teams||[]).map(n=>({kind:"local",key:`local:${n.teamId}`,teamId:n.teamId,label:n.isDefault?"\u6211\u6258\u7BA1\u7684\u56E2\u961F":n.name,sub:"",ok:!0,deployments:n.deployments||[],bots:n.bots||[]})),Ot(),ie()}async function Wn(){Rt=((await Re("/api/team/remote-roster")).body?.memberships||[]).map(n=>{let s=n.roster?.deployments||[],a=s.find(i=>i.local),r=a?.name?`${a.name} \u7684\u56E2\u961F`:n.teamName||n.teamId;return{kind:"remote",key:`${n.hubUrl}::${n.teamId}`,teamId:n.teamId,label:r,sub:n.hubUrl,ok:!!n.ok,error:n.error,hubUrl:n.hubUrl,deployments:s,bots:n.roster?.bots||[]}}),Ot(),ie()}function qt(e){e.innerHTML=Pn(),Ze.clear(),Ae.clear(),ye.clear(),ve.clear(),["tf-search","tf-cli","tf-fcap","tf-frole"].forEach(t=>{let n=B(t);n.oninput=ie,n.onchange=ie}),B("tf-modal-cancel").onclick=()=>{B("tf-modal").style.display="none"},B("tf-modal-save").onclick=async()=>{let t=B("tf-modal").dataset.app;await At("/api/team/local-bots/"+encodeURIComponent(t)+"/role",{role:B("tf-modal-text").value}),B("tf-modal").style.display="none",ge()},Jn(),ge(),Wn()}function zn(){return`<section class="page">
|
|
503
|
+
<div class="page-heading"><div>
|
|
504
|
+
<p class="eyebrow">\u56E2\u961F</p><h1>\u56E2\u961F\u7BA1\u7406</h1>
|
|
505
|
+
<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>
|
|
506
|
+
</div></div>
|
|
507
|
+
${Bt("manage")}
|
|
508
|
+
<div class="card" style="margin-bottom:16px">
|
|
509
|
+
<h2 style="margin-top:0">\u6211\u6258\u7BA1\u7684\u56E2\u961F</h2>
|
|
510
|
+
<p style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:6px">
|
|
511
|
+
<input id="tm-newname" placeholder="\u65B0\u56E2\u961F\u540D\u79F0" style="min-width:200px">
|
|
512
|
+
<button id="tm-create" class="primary">\u521B\u5EFA\u56E2\u961F</button>
|
|
513
|
+
<span class="muted tm-cout" style="font-size:13px"></span>
|
|
514
|
+
</p>
|
|
515
|
+
<div id="tm-list">\u52A0\u8F7D\u4E2D\u2026</div>
|
|
516
|
+
</div>
|
|
517
|
+
<div class="card">
|
|
518
|
+
<h2 style="margin-top:0">\u52A0\u5165\u522B\u4EBA\u7684\u56E2\u961F</h2>
|
|
519
|
+
<p style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">
|
|
520
|
+
<input id="tm-hub" placeholder="Hub \u5730\u5740\uFF0C\u5982 http://10.0.0.5:7891" style="flex:1;min-width:240px">
|
|
521
|
+
<input id="tm-code" placeholder="\u9080\u8BF7\u7801" style="min-width:160px">
|
|
522
|
+
<button id="tm-join" class="primary">\u52A0\u5165</button>
|
|
523
|
+
</p>
|
|
524
|
+
<div id="tm-join-out" style="display:none;margin-top:6px"></div>
|
|
525
|
+
</div>
|
|
526
|
+
</section>`}async function et(){let t=(await Re("/api/team/hosted")).body,n=B("tm-list");xe=t?.suggestedHubUrl||xe;let s=t?.teams||[];if(!s.length){n.innerHTML='<p class="muted">\u8FD8\u6CA1\u6709\u56E2\u961F\u3002</p>';return}n.innerHTML=s.map(a=>{let 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)">
|
|
527
|
+
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
528
|
+
<b>${d(a.name)}</b>${a.isDefault?' <span class="muted" style="font-size:12px">\u9ED8\u8BA4</span>':""}
|
|
529
|
+
<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>
|
|
530
|
+
<span style="margin-left:auto;display:flex;gap:6px">
|
|
531
|
+
<button class="tm-invite ghost" data-team="${d(a.teamId)}" style="font-size:12px">\u751F\u6210\u9080\u8BF7\u7801</button>
|
|
532
|
+
${a.isDefault?"":`<button class="tm-del ghost" data-team="${d(a.teamId)}" data-name="${d(a.name)}" style="font-size:12px">\u5220\u9664</button>`}
|
|
533
|
+
</span>
|
|
534
|
+
</div>
|
|
535
|
+
<div class="tm-inv-out" data-team="${d(a.teamId)}" style="display:none;margin-top:6px;font-size:13px"></div></div>`}).join(""),n.querySelectorAll(".tm-invite").forEach(a=>{a.onclick=async()=>{let r=a.dataset.team,i=n.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 ue("/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>${d(xe)}</code><br>\u9080\u8BF7\u7801\uFF1A<code style="font-size:15px">${d(m.body.code)}</code>`:i.innerHTML='<span class="err">\u751F\u6210\u5931\u8D25\u3002</span>'}}),n.querySelectorAll(".tm-del").forEach(a=>{a.onclick=async()=>{confirm(`\u5220\u9664\u56E2\u961F\u300C${a.dataset.name}\u300D\uFF1F\u5DF2\u52A0\u5165\u5B83\u7684\u90E8\u7F72\u4F1A\u88AB\u79FB\u9664\uFF08\u4E0D\u5F71\u54CD\u4ED6\u4EEC\u81EA\u5DF1\u7684\u90E8\u7F72\uFF09\u3002`)&&(await De("DELETE","/api/team/hosted/"+encodeURIComponent(a.dataset.team)),et())}})}function Pt(e){e.innerHTML=zn(),B("tm-create").onclick=async()=>{let t=B("tm-newname").value.trim(),n=e.querySelector(".tm-cout");if(!t){n.innerHTML='<span class="err">\u8BF7\u586B\u56E2\u961F\u540D\u79F0</span>';return}n.innerHTML='<span class="muted">\u521B\u5EFA\u4E2D\u2026</span>';let s=await ue("/api/team/hosted",{name:t});s.body?.ok?(n.innerHTML='<span class="ok">\u5DF2\u521B\u5EFA</span>',B("tm-newname").value="",et()):n.innerHTML=`<span class="err">\u521B\u5EFA\u5931\u8D25\uFF1A${d(String(s.body?.error||s.status))}</span>`},B("tm-join").onclick=async()=>{let t=B("tm-hub").value.trim(),n=B("tm-code").value.trim(),s=B("tm-join-out");if(s.style.display="",!t||!n){s.innerHTML='<span class="err">\u8BF7\u586B Hub \u5730\u5740\u548C\u9080\u8BF7\u7801\u3002</span>';return}s.innerHTML='<span class="muted">\u52A0\u5165\u4E2D\u2026</span>';let a=await ue("/api/team/join-remote",{hubUrl:t,inviteCode:n});if(a.body?.ok)s.innerHTML=`<span class="ok">\u5DF2\u52A0\u5165\u300C${d(a.body.teamName||"")}\u300D\uFF0C\u53BB\u300C\u6211\u7684\u56E2\u961F\u300D\u67E5\u770B\u3002</span>`,B("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">${d(String(i))}</span>`}},et()}function Jn(){B("tf-autobind").onclick=async()=>{let e=B("tf-bind-out");e.style.display="",e.innerHTML='<span class="muted">\u8BC6\u522B\u4E2D\u2026</span>';let n=(await ue("/api/team/identity/auto-bind")).body;if(n?.ok&&n.owner){e.innerHTML=`<span class="ok">\u5DF2\u7ED1\u5B9A\uFF1A${d(n.owner.name||n.owner.unionId)}</span>`,ge();return}if(n?.ok&&n.needChoice&&Array.isArray(n.candidates)){let s=n.candidates.map(a=>`<button class="tf-pickowner ghost" data-union="${d(a.unionId)}" style="margin:2px">${d(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 ue("/api/team/identity/auto-bind",{unionId:a.dataset.union})).body;i?.ok&&i.owner?(e.innerHTML=`<span class="ok">\u5DF2\u7ED1\u5B9A\uFF1A${d(i.owner.name||i.owner.unionId)}</span>`,ge()):e.innerHTML=`<span class="err">\u7ED1\u5B9A\u5931\u8D25\uFF1A${d(String(i?.error||"unknown"))}</span>`}});return}if(n?.error==="no_candidates"){e.innerHTML='<span class="err">\u6CA1\u8BC6\u522B\u5230\u8EAB\u4EFD\uFF1A\u8BF7\u786E\u8BA4\u673A\u5668\u4EBA\u914D\u7F6E\u4E86 allowedUsers\uFF08\u5141\u8BB8\u4F7F\u7528\u8005\uFF09\uFF0C\u4E14\u673A\u5668\u4EBA\u6709\u901A\u8BAF\u5F55\u6743\u9650\u3002</span>';return}e.innerHTML=`<span class="err">\u7ED1\u5B9A\u5931\u8D25\uFF1A${d(String(n?.error||"unknown"))}</span>`}}async function Nt(e){let t=await fetch(e);return{status:t.status,body:await t.json().catch(()=>({}))}}async function nt(e,t,n){let s=await fetch(t,{method:e,headers:{"content-type":"application/json"},body:n?JSON.stringify(n):void 0});return{status:s.status,body:await s.json().catch(()=>({}))}}function _(e){return document.getElementById(e)}function K(e){return(_(e).value||"").trim()}var ot=[];function Gn(){return`<section class="page">
|
|
536
|
+
<div class="page-heading">
|
|
537
|
+
<div>
|
|
538
|
+
<p class="eyebrow">\u63A5\u5165\u70B9 \xB7 beta</p>
|
|
539
|
+
<h1>\u63A5\u5165\u70B9\uFF08Webhook\uFF09<span class="muted" style="font-size:14px;font-weight:400">beta</span></h1>
|
|
540
|
+
<p>\u8BA9\u5916\u90E8\u7CFB\u7EDF\uFF08\u76D1\u63A7\u544A\u8B66\u3001CI\u3001\u5DE5\u5355\u2026\uFF09\u901A\u8FC7\u4E00\u4E2A webhook \u89E6\u53D1\u673A\u5668\u4EBA\u5728\u7FA4\u91CC\u8BF4\u8BDD\u6216\u8DD1\u5DE5\u4F5C\u6D41\u3002<span class="muted">\uFF08beta\uFF1A\u5C1A\u672A\u5145\u5206\u6D4B\u8BD5\uFF0C\u6B22\u8FCE\u53CD\u9988\uFF09</span></p>
|
|
541
|
+
</div>
|
|
542
|
+
</div>
|
|
543
|
+
|
|
544
|
+
<div class="card" style="margin-bottom:16px">
|
|
545
|
+
<h2 style="margin-top:0">\u65B0\u5EFA\u63A5\u5165\u70B9</h2>
|
|
546
|
+
<div class="cn-form" style="display:grid;grid-template-columns:140px 1fr;gap:10px 14px;align-items:center;max-width:680px">
|
|
547
|
+
<label>\u540D\u79F0</label><input id="cn-name" placeholder="\u5982\uFF1A\u7EBF\u4E0A\u544A\u8B66">
|
|
548
|
+
<label>\u89E6\u53D1\u7684\u673A\u5668\u4EBA</label><select id="cn-bot"></select>
|
|
549
|
+
<label>\u89E6\u53D1\u65B9\u5F0F</label>
|
|
550
|
+
<select id="cn-kind"><option value="turn">\u5355\u8F6E\u5BF9\u8BDD\uFF08\u8BA9\u673A\u5668\u4EBA\u56DE\u5E94\u4E00\u6B21\uFF09</option><option value="workflow">\u5DE5\u4F5C\u6D41</option></select>
|
|
551
|
+
<label class="cn-wf" style="display:none">\u5DE5\u4F5C\u6D41 ID</label><input class="cn-wf" id="cn-wf" style="display:none" placeholder="workflowId">
|
|
552
|
+
<label>\u6295\u9012\u5230\u54EA\u4E2A\u7FA4</label>
|
|
553
|
+
<select id="cn-mode">
|
|
554
|
+
<option value="dynamic">\u7531\u8BF7\u6C42\u6307\u5B9A\uFF08\u7FA4 ID \u968F\u8BF7\u6C42\u4F20\u5165\uFF09</option>
|
|
555
|
+
<option value="fixed">\u56FA\u5B9A\u7FA4</option>
|
|
556
|
+
<option value="new-group">\u6BCF\u6B21\u65B0\u5EFA\u7FA4</option>
|
|
557
|
+
</select>
|
|
558
|
+
<label class="cn-fixed" style="display:none">\u7FA4 ID</label><input class="cn-fixed" id="cn-chat" style="display:none" placeholder="oc_\u2026">
|
|
559
|
+
<label class="cn-allow">\u5141\u8BB8\u7684\u7FA4<span class="muted" style="font-weight:400">\uFF08\u53EF\u9009\uFF09</span></label>
|
|
560
|
+
<input class="cn-allow" id="cn-allow" placeholder="oc_xxx,oc_yyy\uFF08\u9017\u53F7\u5206\u9694\uFF0C\u7559\u7A7A=\u4E0D\u9650\uFF09">
|
|
561
|
+
<label class="cn-life" style="display:none">\u53BB\u91CD\u5B57\u6BB5</label><input class="cn-life" id="cn-dedup" style="display:none" placeholder="\u5982 payload.alert.id">
|
|
562
|
+
<label class="cn-life" style="display:none">\u72B6\u6001\u5B57\u6BB5</label><input class="cn-life" id="cn-status" style="display:none" placeholder="\u5982 payload.status">
|
|
563
|
+
<label>\u7B7E\u540D\u5BC6\u94A5</label><input id="cn-secret" placeholder="\u7559\u7A7A\u81EA\u52A8\u751F\u6210\uFF08\u53EA\u663E\u793A\u4E00\u6B21\uFF09">
|
|
564
|
+
</div>
|
|
565
|
+
<div style="margin-top:14px"><button id="cn-create" class="primary">\u521B\u5EFA</button>
|
|
566
|
+
<span class="muted" id="cn-create-out" style="margin-left:10px;font-size:13px"></span></div>
|
|
567
|
+
<div id="cn-created" style="display:none;margin-top:12px"></div>
|
|
568
|
+
</div>
|
|
569
|
+
|
|
570
|
+
<div class="card">
|
|
571
|
+
<h2 style="margin-top:0">\u5DF2\u6709\u63A5\u5165\u70B9 <span class="muted" id="cn-count" style="font-size:13px"></span></h2>
|
|
572
|
+
<div id="cn-list">\u52A0\u8F7D\u4E2D\u2026</div>
|
|
573
|
+
</div>
|
|
574
|
+
</section>`}function tt(){let e=_("cn-kind").value,t=_("cn-mode").value;document.querySelectorAll(".cn-wf").forEach(n=>{n.style.display=e==="workflow"?"":"none"}),document.querySelectorAll(".cn-fixed").forEach(n=>{n.style.display=t==="fixed"?"":"none"}),document.querySelectorAll(".cn-allow").forEach(n=>{n.style.display=t==="fixed"?"none":""}),document.querySelectorAll(".cn-life").forEach(n=>{n.style.display=t==="new-group"?"":"none"})}function jt(e){return`${location.origin}/webhook/${encodeURIComponent(e)}`}function Kn(e){return e==="fixed"?"\u56FA\u5B9A\u7FA4":e==="new-group"?"\u6BCF\u6B21\u65B0\u5EFA\u7FA4":"\u8BF7\u6C42\u6307\u5B9A\u7FA4"}function Vn(e){return e==="workflow"?"\u5DE5\u4F5C\u6D41":"\u5355\u8F6E"}function Yn(e){let t=_("cn-list");if(_("cn-count").textContent=e.length?`\xB7 ${e.length} \u4E2A`:"",!e.length){t.innerHTML='<p class="muted">\u8FD8\u6CA1\u6709\u63A5\u5165\u70B9\u3002\u7528\u4E0A\u9762\u7684\u8868\u5355\u521B\u5EFA\u4E00\u4E2A\u3002</p>';return}t.innerHTML=e.map(n=>{let s=ot.find(r=>r.larkAppId===n.target.botId),a=jt(n.id);return`<div class="card" style="margin:0 0 10px;padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
575
|
+
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
576
|
+
<b style="font-size:15px">${d(n.name)}</b>
|
|
577
|
+
<span class="${n.enabled?"ok":"muted"}" style="font-size:12px">${n.enabled?"\u5DF2\u542F\u7528":"\u5DF2\u505C\u7528"}</span>
|
|
578
|
+
<span class="muted" style="font-size:12px">\xB7 ${d(s?.botName||n.target.botId)} \xB7 ${Vn(n.target.kind)} \xB7 ${Kn(n.target.mode)}</span>
|
|
579
|
+
<span style="margin-left:auto;display:flex;gap:6px">
|
|
580
|
+
<button class="cn-toggle ghost" data-id="${d(n.id)}" data-on="${n.enabled}" style="font-size:12px">${n.enabled?"\u505C\u7528":"\u542F\u7528"}</button>
|
|
581
|
+
<button class="cn-del ghost" data-id="${d(n.id)}" style="font-size:12px">\u5220\u9664</button>
|
|
582
|
+
</span>
|
|
583
|
+
</div>
|
|
584
|
+
<div style="margin-top:6px;font-size:13px;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
585
|
+
<span class="muted">Webhook URL\uFF1A</span><code style="font-size:12px;word-break:break-all">${d(a)}</code>
|
|
586
|
+
<button class="cn-copy ghost" data-url="${d(a)}" style="font-size:12px">\u590D\u5236</button>
|
|
587
|
+
</div></div>`}).join(""),t.querySelectorAll(".cn-copy").forEach(n=>{n.onclick=()=>{navigator.clipboard?.writeText(n.dataset.url),n.textContent="\u5DF2\u590D\u5236",setTimeout(()=>n.textContent="\u590D\u5236",1200)}}),t.querySelectorAll(".cn-toggle").forEach(n=>{n.onclick=async()=>{await nt("PATCH","/api/connectors/"+encodeURIComponent(n.dataset.id),{enabled:n.dataset.on!=="true"}),Oe()}}),t.querySelectorAll(".cn-del").forEach(n=>{n.onclick=async()=>{confirm("\u5220\u9664\u8FD9\u4E2A\u63A5\u5165\u70B9\uFF1F\u5B83\u7684 webhook URL \u4F1A\u7ACB\u5373\u5931\u6548\u3002")&&(await nt("DELETE","/api/connectors/"+encodeURIComponent(n.dataset.id)),Oe())}})}async function Oe(){let[e,t]=await Promise.all([Nt("/api/bots"),Nt("/api/connectors")]);ot=(e.body?.bots||[]).map(a=>({larkAppId:a.larkAppId,botName:a.botName||a.larkAppId}));let n=_("cn-bot"),s=n.value;n.innerHTML=ot.map(a=>`<option value="${d(a.larkAppId)}">${d(a.botName)}</option>`).join("")||'<option value="">\uFF08\u6CA1\u6709\u5728\u7EBF\u673A\u5668\u4EBA\uFF09</option>',s&&(n.value=s),Yn(t.body?.connectors||[])}function Ut(e){e.innerHTML=Gn(),_("cn-kind").onchange=tt,_("cn-mode").onchange=tt,tt(),_("cn-create").onclick=async()=>{let t=_("cn-create-out"),n=K("cn-name"),s=_("cn-bot").value;if(!n){t.innerHTML='<span class="err">\u8BF7\u586B\u540D\u79F0</span>';return}if(!s){t.innerHTML='<span class="err">\u8BF7\u9009\u673A\u5668\u4EBA</span>';return}let a=_("cn-kind").value,r=_("cn-mode").value,i={name:n,enabled:!0,target:{kind:a,mode:r,botId:s},promptEnvelope:{sourceName:n}};if(a==="workflow"){if(!K("cn-wf")){t.innerHTML='<span class="err">\u8BF7\u586B\u5DE5\u4F5C\u6D41 ID</span>';return}i.target.workflowId=K("cn-wf")}if(r==="fixed"){if(!K("cn-chat")){t.innerHTML='<span class="err">\u56FA\u5B9A\u7FA4\u9700\u8981\u586B\u7FA4 ID</span>';return}i.target.chatId=K("cn-chat")}else{let $=K("cn-allow");$&&(i.target.allowChats=$.split(",").map(p=>p.trim()).filter(Boolean))}if(r==="new-group"){if(!K("cn-dedup")||!K("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:K("cn-dedup"),status:K("cn-status")}}let m=K("cn-secret");m&&(i.secret=m),t.innerHTML='<span class="muted">\u521B\u5EFA\u4E2D\u2026</span>';let k=await nt("POST","/api/connectors",i);if(k.status===201&&k.body?.ok){t.innerHTML="";let $=_("cn-created");$.style.display="";let p=k.body.webhookUrl||jt(k.body.connector.id),g=k.body.secret;$.innerHTML=`<div class="card" style="padding:12px 14px;background:var(--bg-soft,#f6f7f9)">
|
|
588
|
+
<p class="ok" style="margin:0 0 6px">\u5DF2\u521B\u5EFA\u300C${d(n)}\u300D</p>
|
|
589
|
+
<p style="margin:4px 0;font-size:13px"><span class="muted">Webhook URL\uFF1A</span><code style="word-break:break-all">${d(p)}</code></p>
|
|
590
|
+
${g?`<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>${d(g)}</code></p>`:""}
|
|
591
|
+
<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(l=>{_(l).value=""}),Oe()}else{let $=k.body?.error||k.status;t.innerHTML=`<span class="err">\u521B\u5EFA\u5931\u8D25\uFF1A${d(String($))}</span>`}},Oe()}function Qn(){let e=[["",o("workflow.filter.nonTerminal")],["all",o("workflow.filter.all")],["pending",le("pending")],["running",le("running")],["waiting",le("waiting")],["succeeded",le("succeeded")],["failed",le("failed")],["cancelled",le("cancelled")]];return`
|
|
469
592
|
<nav class="wf-subnav">
|
|
470
|
-
<a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${
|
|
471
|
-
<a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${
|
|
593
|
+
<a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${c(o("workflow.subnav.runs"))}</a>
|
|
594
|
+
<a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${c(o("workflow.subnav.catalog"))}</a>
|
|
472
595
|
</nav>
|
|
473
596
|
<form id="wf-filters" class="filters">
|
|
474
|
-
<input type="search" name="q" placeholder="${
|
|
597
|
+
<input type="search" name="q" placeholder="${c(o("workflow.searchPlaceholder"))}" />
|
|
475
598
|
<select name="status">
|
|
476
|
-
${e.map(([t,
|
|
599
|
+
${e.map(([t,n])=>`<option value="${c(t)}">${c(n)}</option>`).join("")}
|
|
477
600
|
</select>
|
|
478
601
|
<span id="wf-last-load" class="muted"></span>
|
|
479
602
|
</form>
|
|
480
603
|
<table>
|
|
481
604
|
<thead><tr>
|
|
482
|
-
<th>${
|
|
483
|
-
<th>${
|
|
484
|
-
<th>${
|
|
605
|
+
<th>${c(o("workflow.table.run"))}</th><th>${c(o("workflow.table.workflow"))}</th><th>${c(o("workflow.table.status"))}</th>
|
|
606
|
+
<th>${c(o("workflow.table.lastSeq"))}</th><th>${c(o("workflow.table.dangling"))}</th><th>${c(o("workflow.table.updated"))}</th>
|
|
607
|
+
<th>${c(o("workflow.table.chatApp"))}</th>
|
|
485
608
|
</tr></thead>
|
|
486
609
|
<tbody id="wf-tbody"></tbody>
|
|
487
610
|
</table>
|
|
488
|
-
`}var
|
|
489
|
-
<td><a href="#/workflows/${encodeURIComponent(
|
|
490
|
-
<td>${
|
|
491
|
-
<td>${
|
|
492
|
-
<td>${
|
|
493
|
-
<td class="${
|
|
494
|
-
<td title="${
|
|
495
|
-
<td>${
|
|
496
|
-
</tr>`}).join("")}function g(){
|
|
611
|
+
`}var Xn=5e3,Zn=2e3,ke=new Set(["succeeded","failed","cancelled"]);function c(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function eo(e){let t=new Date(e),s=Date.now()-e;return s<6e4?o("time.secondsAgo",{value:Math.max(1,Math.floor(s/1e3))}):s<36e5?o("time.minutesAgo",{value:Math.floor(s/6e4)}):s<864e5?o("time.hoursAgo",{value:Math.floor(s/36e5)}):t.toISOString().slice(0,19).replace("T"," ")}function ne(e){return`<span class="${ke.has(e)?"wf-status terminal":"wf-status live"} wf-status-${c(e)}">${c(le(e))}</span>`}function le(e){let t=`workflow.status.${e}`,n=o(t);return n===t?e:n}function zt(e){let t=location.hash.match(/^#\/workflows\/([^?#]+)(?:\?([^#]*))?$/);if(t){let n=new URLSearchParams(t[2]??"");return no(e,decodeURIComponent(t[1]),{focusAttemptId:n.get("attempt")??void 0})}return to(e)}function to(e){e.innerHTML=Qn();let t=e.querySelector("#wf-tbody"),n=e.querySelector("#wf-filters"),s=e.querySelector("#wf-last-load"),a=[],r=null,i=!1,m=null,k=!1;function $(b){let T=(new FormData(n).get("q")??"").trim().toLowerCase();return T?b.filter(S=>S.runId.toLowerCase().includes(T)||S.workflowId.toLowerCase().includes(T)||(S.chatId??"").toLowerCase().includes(T)):b}function p(){let b=$(a);if(b.length===0){t.innerHTML=`<tr><td colspan="7" class="empty">${m?c(o("workflow.list.failedLoad",{error:m})):a.length===0?c(o("workflow.list.noRuns")):c(o("workflow.list.noFilterMatch"))}</td></tr>`;return}t.innerHTML=b.map(f=>{let T=`${f.dEf}/${f.dAct}/${f.dWait}`,S=f.dEf+f.dAct+f.dWait>0?"wf-dangling has":"wf-dangling none",y=[];f.chatId&&y.push(c(f.chatId)),f.larkAppId&&y.push(`<span class="muted">${c(f.larkAppId)}</span>`);let H=y.length>0?y.join("<br/>"):"\u2014",u=ao(f);return`<tr data-runid="${c(f.runId)}">
|
|
612
|
+
<td><a href="#/workflows/${encodeURIComponent(f.runId)}"><code>${c(f.runId)}</code></a></td>
|
|
613
|
+
<td>${c(f.workflowId)}</td>
|
|
614
|
+
<td>${ne(f.status)}${f.failedNodeId?` <span class="muted">(${c(f.failedNodeId)})</span>`:""}${u}</td>
|
|
615
|
+
<td>${f.lastSeq}</td>
|
|
616
|
+
<td class="${S}">${T}</td>
|
|
617
|
+
<td title="${c(new Date(f.updatedAt).toISOString())}">${eo(f.updatedAt)}</td>
|
|
618
|
+
<td>${H}</td>
|
|
619
|
+
</tr>`}).join("")}function g(){m?(s.textContent=o("workflow.list.error",{error:m}),s.classList.add("error")):(s.textContent=o("workflow.list.loaded",{count:a.length,time:new Date().toLocaleTimeString()}),s.classList.remove("error"))}async function l(){if(!(k||i)&&!document.hidden){i=!0;try{let b=n.elements.namedItem("status")?.value??"",f=new URLSearchParams;b==="all"?f.set("all","1"):b&&f.set("status",b);let T="/api/workflows/runs"+(f.toString()?`?${f}`:""),S=await fetch(T);S.ok?(a=(await S.json()).runs??[],m=null):(m=`HTTP ${S.status}`,a=[])}catch(b){m=b?.message??String(b),a=[]}finally{i=!1,k||(p(),g())}}}function I(){r!==null&&window.clearTimeout(r),r=window.setTimeout(async()=>{await l(),k||I()},Xn)}function L(){document.hidden||l()}return n.addEventListener("input",()=>{p()}),n.addEventListener("change",b=>{b.target.getAttribute("name")==="status"&&l()}),document.addEventListener("visibilitychange",L),l().then(()=>{k||I()}),()=>{k=!0,r!==null&&window.clearTimeout(r),document.removeEventListener("visibilitychange",L)}}function no(e,t,n={}){e.innerHTML=`
|
|
497
620
|
<div class="wf-detail-head">
|
|
498
|
-
<a class="btn-link" href="#/workflows">${
|
|
621
|
+
<a class="btn-link" href="#/workflows">${c(o("workflow.detail.back"))}</a>
|
|
499
622
|
<div>
|
|
500
|
-
<h2><code>${
|
|
501
|
-
<div id="wf-detail-subtitle" class="muted">${
|
|
623
|
+
<h2><code>${c(t)}</code></h2>
|
|
624
|
+
<div id="wf-detail-subtitle" class="muted">${c(o("workflow.detail.loading"))}</div>
|
|
502
625
|
</div>
|
|
503
|
-
<button id="wf-cancel-run" type="button" class="contrast" hidden>${
|
|
626
|
+
<button id="wf-cancel-run" type="button" class="contrast" hidden>${c(o("workflow.detail.cancel"))}</button>
|
|
504
627
|
<span id="wf-detail-refresh" class="muted"></span>
|
|
505
628
|
</div>
|
|
506
629
|
<section id="wf-detail-error" class="hint-warn" hidden></section>
|
|
@@ -509,20 +632,20 @@ ${u.join(`
|
|
|
509
632
|
<section id="wf-dangling-panel"></section>
|
|
510
633
|
<section class="wf-panel">
|
|
511
634
|
<div class="wf-panel-title">
|
|
512
|
-
<h3>${
|
|
635
|
+
<h3>${c(o("workflow.detail.parallel"))}</h3>
|
|
513
636
|
<span id="wf-parallel-meta" class="muted"></span>
|
|
514
637
|
</div>
|
|
515
638
|
<div id="wf-parallel-view"></div>
|
|
516
639
|
</section>
|
|
517
640
|
<section class="wf-panel">
|
|
518
641
|
<div class="wf-panel-title">
|
|
519
|
-
<h3>${
|
|
642
|
+
<h3>${c(o("workflow.detail.nodes"))}</h3>
|
|
520
643
|
</div>
|
|
521
644
|
<div class="wf-table-scroll">
|
|
522
645
|
<table>
|
|
523
646
|
<thead><tr>
|
|
524
|
-
<th>${
|
|
525
|
-
<th>${
|
|
647
|
+
<th>${c(o("workflow.detail.node"))}</th><th>${c(o("workflow.detail.nodeStatus"))}</th><th>${c(o("workflow.detail.activity"))}</th><th>${c(o("workflow.detail.activityStatus"))}</th>
|
|
648
|
+
<th>${c(o("workflow.detail.attempts"))}</th><th>${c(o("workflow.detail.current"))}</th><th>${c(o("workflow.detail.detail"))}</th>
|
|
526
649
|
</tr></thead>
|
|
527
650
|
<tbody id="wf-node-tbody"></tbody>
|
|
528
651
|
</table>
|
|
@@ -530,237 +653,237 @@ ${u.join(`
|
|
|
530
653
|
</section>
|
|
531
654
|
<section class="wf-panel">
|
|
532
655
|
<div class="wf-panel-title">
|
|
533
|
-
<h3>${
|
|
656
|
+
<h3>${c(o("workflow.detail.nodeIO"))}</h3>
|
|
534
657
|
</div>
|
|
535
658
|
<div id="wf-io-list" class="wf-io-list"></div>
|
|
536
659
|
</section>
|
|
537
660
|
<section class="wf-panel">
|
|
538
661
|
<div class="wf-panel-title">
|
|
539
|
-
<h3>${
|
|
540
|
-
<button id="wf-load-older" type="button" hidden>${
|
|
662
|
+
<h3>${c(o("workflow.detail.timeline"))}</h3>
|
|
663
|
+
<button id="wf-load-older" type="button" hidden>${c(o("workflow.detail.loadOlder"))}</button>
|
|
541
664
|
</div>
|
|
542
665
|
<div class="wf-table-scroll wf-timeline-scroll">
|
|
543
666
|
<table>
|
|
544
667
|
<thead><tr>
|
|
545
|
-
<th>${
|
|
668
|
+
<th>${c(o("workflow.detail.seq"))}</th><th>${c(o("workflow.detail.event"))}</th><th>${c(o("workflow.detail.actor"))}</th><th>${c(o("workflow.detail.node"))}</th><th>${c(o("workflow.detail.activity"))}</th><th>${c(o("workflow.detail.error"))}</th><th>${c(o("workflow.detail.time"))}</th>
|
|
546
669
|
</tr></thead>
|
|
547
670
|
<tbody id="wf-event-tbody"></tbody>
|
|
548
671
|
</table>
|
|
549
672
|
</div>
|
|
550
673
|
<div id="wf-event-meta" class="muted"></div>
|
|
551
674
|
</section>
|
|
552
|
-
`;let
|
|
553
|
-
<span class="muted error">${
|
|
554
|
-
</div>`}function
|
|
675
|
+
`;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"),k=e.querySelector("#wf-dangling-panel"),$=e.querySelector("#wf-parallel-view"),p=e.querySelector("#wf-parallel-meta"),g=e.querySelector("#wf-node-tbody"),l=e.querySelector("#wf-io-list"),I=e.querySelector(".wf-timeline-scroll"),L=e.querySelector("#wf-event-tbody"),b=e.querySelector("#wf-event-meta"),f=e.querySelector("#wf-cancel-run"),T=e.querySelector("#wf-load-older"),S=null,y=[],H=new Set,u=null,w=null,h=!1,E=0,M=null,A=!1,P=!1,O=!1,x=new Set,q=new Map,j=new Map,F=new Map,z=new Set,ee=new Map,te=new Set,he=new Map,ln=new Map,it=0,lt=n.focusAttemptId;function G(v){if(!v){r.hidden=!0,r.textContent="";return}r.hidden=!1,r.textContent=v}function dt(v){if(!v){i.hidden=!0,i.textContent="";return}i.hidden=!1,i.textContent=v}async function ct(){let v=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/snapshot`);if(v.status===404)throw new Error(o("workflow.detail.unknownRun"));if(!v.ok)throw new Error(o("workflow.detail.snapshotHttp",{status:v.status}));S=await v.json()}async function Te(v){let U=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/events?${v}`);if(U.status===404)throw new Error(o("workflow.detail.unknownRun"));if(!U.ok)throw new Error(o("workflow.detail.eventsHttp",{status:U.status}));return await U.json()}function Le(v,U){let D=v.filter(R=>H.has(R.eventId)?!1:(H.add(R.eventId),!0));D.length!==0&&(y=U==="prepend"?[...D,...y]:[...y,...D],y.sort((R,oe)=>$e(R.eventId)-$e(oe.eventId)))}async function dn(){await ct();let v=await Te(new URLSearchParams({tail:"100"}));y=[],H=new Set,Le(v.events,"append"),u=v.oldestSeq,w=v.newestSeq,h=v.hasOlder,E=v.totalCount,Y()}async function Ee(){if(!(A||P||document.hidden)){P=!0;try{if(await ct(),w!==null){let v=await Te(new URLSearchParams({afterSeq:String(w),limit:"200"}));Le(v.events,"append"),v.newestSeq!==null&&(w=v.newestSeq),u===null&&v.oldestSeq!==null&&(u=v.oldestSeq),E=v.totalCount}else{let v=await Te(new URLSearchParams({tail:"1"}));Le(v.events,"append"),u=v.oldestSeq,w=v.newestSeq,h=v.hasOlder,E=v.totalCount}G(null),Y()}catch(v){G(v?.message??String(v))}finally{P=!1}}}async function cn(){if(!(u===null||!h)){T.disabled=!0;try{let v=await Te(new URLSearchParams({beforeSeq:String(u),limit:"100"}));Le(v.events,"prepend"),v.oldestSeq!==null&&(u=v.oldestSeq),h=v.hasOlder,E=v.totalCount,G(null),Y()}catch(v){G(v?.message??String(v))}finally{T.disabled=!1}}}async function un(){if(!S||ke.has(S.run.status)||O)return;if(!S.chatBinding?.larkAppId){G(o("workflow.detail.cancelUnavailable",{runId:t}));return}let v=so(S),U=o("workflow.detail.cancelConfirm",{runId:t,...v});if(window.confirm(U)){O=!0,f.disabled=!0;try{let D=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/cancel`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"cancelled via dashboard"})});if(D.status===401)throw new Error(o("workflow.detail.writeAccessCancel"));let R=await D.json().catch(()=>({}));if(!D.ok||!R.ok)throw new Error(R.hint??R.error??o("workflow.detail.cancelHttp",{status:D.status}));dt(R.pending?o("workflow.detail.cancelPending"):null),G(null),await Ee()}catch(D){G(D?.message??String(D))}finally{O=!1,f.disabled=!1,Y()}}}async function pn(v,U){if(!te.has(v)){te.add(v),he.delete(v),Y();try{let D=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/attempts/${encodeURIComponent(U)}/${encodeURIComponent(v)}/resume`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});if(D.status===401)throw new Error(o("workflow.detail.writeAccessResume"));let R=await D.json().catch(()=>({}));if(!D.ok||!R.ok||!R.resumeId||!R.url)throw new Error(R.hint??R.message??R.error??o("workflow.detail.resumeStartFailed",{status:D.status}));ee.set(v,{resumeId:R.resumeId,url:R.url})}catch(D){let R=D?.message??String(D);he.set(v,R)}finally{te.delete(v),Y()}}}async function fn(v,U){if(!te.has(v)){te.add(v),he.delete(v),Y();try{let D=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/attempts/${encodeURIComponent(U)}/${encodeURIComponent(v)}/resume/end`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"ended_by_dashboard"})});if(D.status===401)throw new Error(o("workflow.detail.writeAccessResume"));let R=await D.json().catch(()=>({}));if(!D.ok||!R.ok)if(R.error==="resume_not_running")ee.delete(v);else throw new Error(R.hint??R.message??R.error??o("workflow.detail.resumeEndFailed",{status:D.status}));else ee.delete(v)}catch(D){let R=D?.message??String(D);he.set(v,R)}finally{te.delete(v),Y()}}}async function mn(v,U){if(!z.has(v)){z.add(v),F.delete(v),Y();try{let D=j.get(v)?.trim()||void 0,R=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/${U}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({comment:D})});if(R.status===401)throw new Error(o("workflow.detail.writeAccessApproval"));let oe=await R.json().catch(()=>({}));if(!R.ok||!oe.ok)throw new Error(oe.hint??oe.message??oe.error??o("workflow.detail.actionHttp",{action:U,status:R.status}));let _e=U==="approve"?o("workflow.detail.approved"):o("workflow.detail.rejected");F.set(v,{kind:"ok",text:oe.alreadyTerminal?o("workflow.detail.alreadyTerminal",{label:_e}):oe.pending?o("workflow.detail.workflowContinue",{label:_e}):o("workflow.detail.workflowRefreshing",{label:_e})}),G(null),await Ee()}catch(D){let R=D?.message??String(D);F.set(v,{kind:"error",text:R}),G(R)}finally{z.delete(v),Y()}}}function Y(){if(!S)return;it=I.scrollTop;let v=S.run;ke.has(v.status)&&dt(null),s.innerHTML=`${c(v.workflowId??"?")} \xB7 ${ne(v.status)} \xB7 lastSeq ${S.lastSeq}`,a.textContent=o("workflow.detail.refreshed",{time:new Date().toLocaleTimeString()}),f.hidden=ke.has(v.status),f.disabled=O||!S.chatBinding?.larkAppId,f.textContent=S.chatBinding?.larkAppId?o("workflow.detail.cancel"):o("workflow.detail.cliCancelOnly"),f.title=S.chatBinding?.larkAppId?o("workflow.detail.cancelTitle"):o("workflow.detail.cliCancelTitle",{runId:t}),oo(m,S),ro(k,S),io($,p,S,y),mo(g,S),wo(l,S,x,q,{comments:j,statuses:F,resolving:z,onResolve:mn},{sessions:ee,pending:te,errors:he,onStart:pn,onEnd:fn},lt,ln)&&(lt=void 0),Uo(L,y),I.scrollTop=it,T.hidden=!h,b.textContent=o("workflow.detail.eventsLoaded",{loaded:y.length,total:E})}function Fe(){if(M!==null&&window.clearTimeout(M),S&&ke.has(S.run.status)){M=null;return}M=window.setTimeout(async()=>{await Ee(),A||Fe()},Zn)}function ut(){document.hidden||Ee().then(()=>{!A&&M===null&&Fe()})}return T.addEventListener("click",()=>{cn()}),f.addEventListener("click",()=>{un()}),document.addEventListener("visibilitychange",ut),dn().then(()=>{G(null),A||Fe()}).catch(v=>{G(v?.message??String(v)),s.textContent=o("workflow.detail.loadFailed")}),()=>{A=!0,M!==null&&window.clearTimeout(M),document.removeEventListener("visibilitychange",ut)}}function oo(e,t){let n=t.run,s=[[o("workflow.summary.workflow"),c(n.workflowId??"?")],[o("workflow.summary.status"),ne(n.status)],[o("workflow.summary.lastSeq"),String(t.lastSeq)],[o("workflow.summary.updated"),c(new Date(t.updatedAt).toLocaleString())],[o("workflow.summary.revision"),c(Ne(n.revisionId))],[o("workflow.summary.initiator"),c(n.initiator??"-")]];n.failedNodeId&&s.push([o("workflow.summary.failedNode"),c(n.failedNodeId)]),n.cancelOriginEventId&&s.push([o("workflow.summary.cancelOrigin"),c(n.cancelOriginEventId)]),t.chatBinding&&(s.push([o("workflow.summary.chat"),`<code>${c(t.chatBinding.chatId)}</code>`]),s.push([o("workflow.summary.app"),`<code>${c(t.chatBinding.larkAppId)}</code>`])),e.innerHTML=s.map(([a,r])=>`<div class="wf-summary-item"><span>${a}</span><strong>${r}</strong></div>`).join("")}function ao(e){if(!e.errorCode)return"";let t=e.errorMessage?` \u2014 ${zo(e.errorMessage,96)}`:"";return`<div class="wf-run-error">
|
|
676
|
+
<span class="muted error">${c(e.errorCode)}</span>${c(t)}
|
|
677
|
+
</div>`}function so(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 ro(e,t){let n=t.dangling,s=[[o("workflow.dangling.activities"),n.activities],[o("workflow.dangling.effects"),n.effectAttempted],[o("workflow.dangling.waits"),n.waits],[o("workflow.dangling.cancels"),n.cancels]],a=new Set(s.flatMap(([,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>${c(o("workflow.detail.dangling"))}</h3></div><div class="muted">${c(o("workflow.detail.noDangling"))}</div>`;return}e.innerHTML=`<div class="wf-panel-title"><h3>${c(o("workflow.detail.dangling"))}</h3><span class="wf-dangling has">${a}</span></div>
|
|
555
678
|
<div class="wf-dangling-grid">
|
|
556
|
-
${
|
|
557
|
-
</div>`}function
|
|
558
|
-
<span title="${
|
|
559
|
-
<span title="${
|
|
679
|
+
${s.map(([r,i])=>`<div><strong>${r}</strong>${i.length===0?`<div class="muted">${c(o("workflow.detail.none"))}</div>`:`<ul>${i.map(m=>`<li><code>${c(m)}</code></li>`).join("")}</ul>`}</div>`).join("")}
|
|
680
|
+
</div>`}function io(e,t,n,s){let a=lo(s,n);if(a.length===0){t.textContent="",e.innerHTML=`<div class="empty">${c(o("workflow.detail.noParallelData"))}</div>`;return}let r=Date.now(),i=Math.min(...a.map(l=>l.startedAt)),m=Math.max(...a.map(l=>l.endedAt??r),i+1e3),k=Math.max(1,m-i),$=uo(a,r),p=a.filter(l=>!l.endedAt&&(l.status==="running"||l.status==="effectAttempting")).length;t.textContent=o("workflow.detail.parallelMeta",{count:a.length,max:$,running:p});let g=a.sort((l,I)=>l.startedAt-I.startedAt||l.activityId.localeCompare(I.activityId)).map(l=>co(l,i,k,r)).join("");e.innerHTML=`<div class="wf-parallel-axis">
|
|
681
|
+
<span title="${c(new Date(i).toISOString())}">${c(Pe(i))}</span>
|
|
682
|
+
<span title="${c(new Date(m).toISOString())}">${c(Pe(m))}</span>
|
|
560
683
|
</div>
|
|
561
|
-
<div class="wf-parallel-list">${g}</div>`}function
|
|
684
|
+
<div class="wf-parallel-list">${g}</div>`}function lo(e,t){let n=new Map,s=new Map(t.activities.map(a=>[a.activityId,a.ownerNodeId]));for(let a of[...e].sort((r,i)=>$e(r.eventId)-$e(i.eventId))){let r=Wo(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 k=n.get(m);if(a.type==="attemptCreated"){let $=typeof r.attemptNumber=="number"?r.attemptNumber:void 0;k={nodeId:typeof r.nodeId=="string"?r.nodeId:s.get(i),activityId:i,attemptId:m,attemptNumber:$,status:"pending",startedAt:a.timestamp},n.set(m,k);continue}k||(k={nodeId:s.get(i),activityId:i,attemptId:m,status:"pending",startedAt:a.timestamp},n.set(m,k)),a.type==="activityRunning"?(k.status="running",k.runningAt=a.timestamp):a.type==="effectAttempted"?k.status="effectAttempting":a.type==="activityWaiting"||a.type==="waitCreated"?k.status="waiting":po(a.type)&&(k.status=fo(a.type),k.endedAt=a.timestamp,k.endType=a.type)}return[...n.values()]}function co(e,t,n,s){let a=e.endedAt??s,r=Wt((e.startedAt-t)/n*100,0,100),i=Wt((Math.max(a,e.startedAt+1)-e.startedAt)/n*100,.7,100-r),m=e.nodeId??e.activityId,k=e.attemptNumber!==void 0?`#${e.attemptNumber}`:Ne(e.attemptId),$=[`${m} ${e.status}`,`${new Date(e.startedAt).toISOString()} \u2192 ${e.endedAt?new Date(e.endedAt).toISOString():o("workflow.detail.parallelNow")}`,e.endType?`end: ${e.endType}`:void 0].filter(Boolean).join(`
|
|
562
685
|
`);return`<div class="wf-parallel-row">
|
|
563
686
|
<div class="wf-parallel-label">
|
|
564
|
-
<code>${
|
|
565
|
-
<span class="muted">${
|
|
687
|
+
<code>${c(m)}</code>
|
|
688
|
+
<span class="muted">${c(e.activityId)} \xB7 ${c(k)}</span>
|
|
566
689
|
</div>
|
|
567
690
|
<div class="wf-parallel-track">
|
|
568
|
-
<div class="wf-parallel-bar wf-parallel-${
|
|
569
|
-
<span>${
|
|
691
|
+
<div class="wf-parallel-bar wf-parallel-${c(e.status)}" style="left:${r.toFixed(3)}%;width:${i.toFixed(3)}%;" title="${c($)}">
|
|
692
|
+
<span>${c(le(e.status))}</span>
|
|
570
693
|
</div>
|
|
571
694
|
</div>
|
|
572
|
-
</div>`}function
|
|
573
|
-
<td>${e?`<code>${
|
|
574
|
-
<td>${e?
|
|
575
|
-
<td>${t?`<code>${
|
|
576
|
-
<td>${t?
|
|
695
|
+
</div>`}function uo(e,t){let n=[];for(let r of e)n.push({time:r.startedAt,delta:1}),n.push({time:r.endedAt??t,delta:-1});n.sort((r,i)=>r.time-i.time||i.delta-r.delta);let s=0,a=0;for(let r of n)s+=r.delta,a=Math.max(a,s);return a}function po(e){return e==="activitySucceeded"||e==="activityFailed"||e==="activityTimedOut"||e==="activityCanceled"}function fo(e){return e==="activitySucceeded"?"succeeded":e==="activityCanceled"?"cancelled":e==="activityTimedOut"?"timedOut":"failed"}function mo(e,t){let n=new Map(t.activities.map(r=>[r.activityId,r])),s=new Set,a=[];for(let r of t.nodes){let i=(r.activityId?n.get(r.activityId):void 0)??t.activities.find(m=>m.ownerNodeId===r.nodeId);i&&s.add(i.activityId),a.push(Ft(r,i))}for(let r of t.activities)s.has(r.activityId)||a.push(Ft(void 0,r));e.innerHTML=a.length>0?a.join(""):`<tr><td colspan="7" class="empty">${c(o("workflow.detail.noNodes"))}</td></tr>`}function Ft(e,t){let n=t?.attempts[t.attempts.length-1];return`<tr>
|
|
696
|
+
<td>${e?`<code>${c(e.nodeId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
697
|
+
<td>${e?ne(e.status):'<span class="muted">-</span>'}</td>
|
|
698
|
+
<td>${t?`<code>${c(t.activityId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
699
|
+
<td>${t?ne(t.status):'<span class="muted">-</span>'}</td>
|
|
577
700
|
<td>${t?.attempts.length??0}</td>
|
|
578
|
-
<td>${
|
|
579
|
-
<td>${
|
|
580
|
-
</tr>`}function
|
|
701
|
+
<td>${n?`<code>${c(n.attemptId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
702
|
+
<td>${n?jo(n):`<span class="muted">${c(o("workflow.detail.idle"))}</span>`}</td>
|
|
703
|
+
</tr>`}function wo(e,t,n,s,a,r,i,m){Do(e,n,s),Ho(e,a.comments);let k=!!(i&&t.attemptIO?.[i]?.terminal);k&&i&&n.add(at(i,o("workflow.detail.liveTerminal")));let $=go(t),p=new Set;if(m){for(let l of $){p.add(l.key);let I=m.get(l.key);I||(I=ho(l.key),m.set(l.key,I),e.appendChild(I.article)),bo(I,l,n,a,r,i)}for(let[l,I]of Array.from(m))p.has(l)||(I.article.remove(),m.delete(l));if($.length===0){if(!e.querySelector(".wf-io-empty-placeholder")){let l=document.createElement("div");l.className="empty wf-io-empty-placeholder",l.textContent=o("workflow.detail.noNodeIO"),e.appendChild(l)}}else e.querySelector(".wf-io-empty-placeholder")?.remove()}else{let l=[];for(let I of $)l.push(So(I,n,a,r,i));e.innerHTML=l.length>0?l.join(""):`<div class="empty">${c(o("workflow.detail.noNodeIO"))}</div>`}Oo(e,s);let g=Ro(e,i);return Bo(e,n),qo(e,s),Ao(e,a),en(e,r),g&&k}function go(e){let t=new Map(e.activities.map(a=>[a.activityId,a])),n=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}n.add(r.activityId),s.push({key:`activity:${r.activityId}`,node:a,activity:r,io:e.attemptIO?.[qe(r)?.attemptId??""]})}for(let a of e.activities)n.has(a.activityId)||s.push({key:`activity:${a.activityId}`,activity:a,io:e.attemptIO?.[qe(a)?.attemptId??""]});return s}function ho(e){let t=document.createElement("article");t.className="wf-io-card",t.dataset.wfCardKey=e;let n=document.createElement("div");n.className="wf-io-card-head";let s=document.createElement("div");s.className="wf-io-terminal-slot";let a=document.createElement("div");return a.className="wf-io-grid",t.appendChild(n),t.appendChild(s),t.appendChild(a),{article:t,head:n,terminalSlot:s,grid:a,currentTerminalUrl:null}}function bo(e,t,n,s,a,r){let i=qe(t.activity),m=t.node?.nodeId??t.activity?.ownerNodeId??t.activity?.activityId??"unknown",k=!!(i&&i.attemptId===r);e.article.classList.toggle("is-focused",k),i?e.article.dataset.wfAttemptCard=i.attemptId:delete e.article.dataset.wfAttemptCard;let $=Zt(i,s);e.head.innerHTML=`
|
|
581
704
|
<header>
|
|
582
705
|
<div>
|
|
583
|
-
<strong><code>${
|
|
584
|
-
<span class="muted">${t.activity?
|
|
706
|
+
<strong><code>${c(m)}</code></strong>
|
|
707
|
+
<span class="muted">${t.activity?c(t.activity.activityId):c(o("workflow.detail.notDispatched"))}</span>
|
|
585
708
|
</div>
|
|
586
|
-
<div>${t.node?
|
|
709
|
+
<div>${t.node?ne(t.node.status):""} ${t.activity?ne(t.activity.status):""}</div>
|
|
587
710
|
</header>
|
|
588
711
|
<div class="wf-io-meta">
|
|
589
|
-
${
|
|
712
|
+
${i?`${c(o("workflow.detail.attempt"))} <code>${c(i.attemptId)}</code>`:c(o("workflow.detail.noAttempt"))}
|
|
590
713
|
</div>
|
|
591
|
-
${
|
|
592
|
-
`;let
|
|
593
|
-
${
|
|
594
|
-
${
|
|
595
|
-
${
|
|
596
|
-
${
|
|
597
|
-
${t.io?.waitPrompt?
|
|
598
|
-
`}function
|
|
599
|
-
<summary>${
|
|
714
|
+
${$}
|
|
715
|
+
`;let p=Jt(i,t.activity,t.io?.terminal,a),g=p?.url??null;if(g!==e.currentTerminalUrl)p===null?e.terminalSlot.innerHTML="":e.terminalSlot.innerHTML=Gt(t.key,i,t.activity,t.io?.terminal,p,n,a),e.currentTerminalUrl=g;else if(p!==null&&t.io?.terminal){let I=e.terminalSlot.querySelector("details.wf-terminal-block > summary");if(I){let L=Kt(p.kind);I.innerHTML=`${c(L)} ${Xt(i,t.io.terminal)}`}i&&xo(e.terminalSlot,i,t.activity,t.io.terminal,p,a)}let l=i?.attemptId??t.activity?.activityId??t.node?.nodeId??"unknown";e.grid.innerHTML=`
|
|
716
|
+
${Z(l,o("workflow.detail.authoredInput"),t.io?.input,n)}
|
|
717
|
+
${Z(l,o("workflow.detail.resolvedInput"),t.io?.resolvedInput,n)}
|
|
718
|
+
${Z(l,o("workflow.detail.output"),t.io?.output,n)}
|
|
719
|
+
${Z(l,o("workflow.detail.executionLog"),t.io?.log,n)}
|
|
720
|
+
${t.io?.waitPrompt?Z(l,o("workflow.detail.waitPrompt"),t.io.waitPrompt,n):""}
|
|
721
|
+
`}function Jt(e,t,n,s){if(!n||n.error)return null;if(Io(e,n))return{kind:"live",url:Lo(n)};if(!e||!t||!To(e,n))return null;let a=Mo();if(!a)return null;let r=s?.sessions.get(e.attemptId);return r?{kind:"resume",url:r.url,resumeId:r.resumeId,downloadUrl:_t(a,t.activityId,e.attemptId)}:{kind:"replay",url:Eo(a,t.activityId,e.attemptId,!!n.hasPtyLog),downloadUrl:_t(a,t.activityId,e.attemptId)}}function Gt(e,t,n,s,a,r,i){if(!s)return"";let m=Kt(a.kind),k=at(e,m),$=Xt(t,s),p=yo(a.kind),g=a.kind==="replay"||a.kind==="resume"?`<a class="btn-link" href="${c(a.downloadUrl)}" download>${c(o("workflow.detail.downloadFullLog"))}</a>`:"",l=t?Yt(t,n,s,a,i):"",I=t?Qt(t.attemptId,i):"";return`<details class="wf-io-block wf-terminal-block" data-io-key="${c(k)}"${r.has(k)?" open":""}>
|
|
722
|
+
<summary>${c(m)} ${$}</summary>
|
|
600
723
|
<div class="wf-terminal-actions">
|
|
601
|
-
<a class="btn-link" href="${
|
|
724
|
+
<a class="btn-link" href="${c(a.url)}" target="_blank" rel="noreferrer">${c(p)}</a>
|
|
602
725
|
${g}
|
|
603
726
|
${l}
|
|
604
727
|
</div>
|
|
605
|
-
${
|
|
606
|
-
<iframe class="wf-terminal-frame" src="${
|
|
607
|
-
</details>`}function
|
|
728
|
+
${I}
|
|
729
|
+
<iframe class="wf-terminal-frame" src="${c(a.url)}" title="${c(m)}" loading="lazy"></iframe>
|
|
730
|
+
</details>`}function Kt(e){return e==="live"?o("workflow.detail.liveTerminal"):e==="resume"?o("workflow.detail.terminalResume"):o("workflow.detail.terminalReplay")}function yo(e){return e==="live"?o("workflow.detail.openTerminalNewTab"):e==="resume"?o("workflow.detail.openResumeNewTab"):o("workflow.detail.openReplayNewTab")}var Vt=new Set(["antigravity","codex-app","cursor","mira"]),vo=new Set(["aiden","coco","claude-code","codex","mtr","hermes"]);function ko(e){return!!e&&(vo.has(e)||Vt.has(e))}function $o(e){return!!e&&Vt.has(e)}function Yt(e,t,n,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="${c(e.attemptId)}" data-wf-resume-activity="${c(t.activityId)}"`;return r?`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="end" ${m}${i?" disabled":""}>${c(i?o("workflow.detail.resumeEnding"):o("workflow.detail.endResumeSession"))}</button>`:ko(n.cliId)?$o(n.cliId)&&!n.cliSessionId?`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${c(o("workflow.detail.resumeMissingCliSession"))}">${c(o("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="start" ${m}${i?" disabled":""}>${c(i?o("workflow.detail.resumeStarting"):o("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${c(o("workflow.detail.resumeUnsupportedCli",{cliId:n.cliId??"?"}))}">${c(o("workflow.detail.resumeSession"))}</button>`}function Qt(e,t){if(!t)return"";let n=t.errors.get(e);return n?`<div class="hint-warn wf-resume-status" data-wf-resume-status="${c(e)}">${c(n)}</div>`:""}function So(e,t,n,s,a){let r=qe(e.activity),i=e.node?.nodeId??e.activity?.ownerNodeId??e.activity?.activityId??"unknown",m=r?.attemptId??e.activity?.activityId??e.node?.nodeId??"unknown",k=Zt(r,n),$=r?.attemptId===a?" is-focused":"",p=r?` data-wf-attempt-card="${c(r.attemptId)}"`:"",g=Jt(r,e.activity,e.io?.terminal,s),l=g?Gt(m,r,e.activity,e.io?.terminal,g,t,s):"";return`<article class="wf-io-card${$}" data-wf-card-key="${c(e.key)}"${p}>
|
|
608
731
|
<div class="wf-io-card-head">
|
|
609
732
|
<header>
|
|
610
733
|
<div>
|
|
611
|
-
<strong><code>${i
|
|
612
|
-
<span class="muted">${e.activity?
|
|
734
|
+
<strong><code>${c(i)}</code></strong>
|
|
735
|
+
<span class="muted">${e.activity?c(e.activity.activityId):c(o("workflow.detail.notDispatched"))}</span>
|
|
613
736
|
</div>
|
|
614
|
-
<div>${e.node?
|
|
737
|
+
<div>${e.node?ne(e.node.status):""} ${e.activity?ne(e.activity.status):""}</div>
|
|
615
738
|
</header>
|
|
616
739
|
<div class="wf-io-meta">
|
|
617
|
-
${
|
|
740
|
+
${r?`${c(o("workflow.detail.attempt"))} <code>${c(r.attemptId)}</code>`:c(o("workflow.detail.noAttempt"))}
|
|
618
741
|
</div>
|
|
619
|
-
${
|
|
742
|
+
${k}
|
|
620
743
|
</div>
|
|
621
744
|
<div class="wf-io-terminal-slot">${l}</div>
|
|
622
745
|
<div class="wf-io-grid">
|
|
623
|
-
${
|
|
624
|
-
${
|
|
625
|
-
${
|
|
626
|
-
${
|
|
627
|
-
${e.io?.waitPrompt?
|
|
746
|
+
${Z(m,o("workflow.detail.authoredInput"),e.io?.input,t)}
|
|
747
|
+
${Z(m,o("workflow.detail.resolvedInput"),e.io?.resolvedInput,t)}
|
|
748
|
+
${Z(m,o("workflow.detail.output"),e.io?.output,t)}
|
|
749
|
+
${Z(m,o("workflow.detail.executionLog"),e.io?.log,t)}
|
|
750
|
+
${e.io?.waitPrompt?Z(m,o("workflow.detail.waitPrompt"),e.io.waitPrompt,t):""}
|
|
628
751
|
</div>
|
|
629
|
-
</article>`}function
|
|
752
|
+
</article>`}function qe(e){return e?.attempts[e.attempts.length-1]}function Xt(e,t){let n=[];return t.error?n.push(o("workflow.detail.error")):n.push(t.status==="live"?o("workflow.detail.terminalLive"):o("workflow.detail.terminalClosedShort")),e?.status&&n.push(e.status),t.webPort>0&&n.push(`:${t.webPort}`),`<span class="muted">${c(n.join(" \xB7 "))}</span>`}function Io(e,t){return t.status==="live"&&t.webPort>0&&(e?.status==="pending"||e?.status==="running"||e?.status==="effectAttempting")}function To(e,t){return e.status==="succeeded"||e.status==="failed"||e.status==="cancelled"||e.status==="timedOut"?!!(t.sessionId||t.startedAt):!1}function Lo(e){return`http://${window.location.hostname||"127.0.0.1"}:${e.webPort}`}function Eo(e,t,n,s){let a=new URLSearchParams({runId:e,activityId:t,attemptId:n});return s&&a.set("hasPtyLog","1"),`/assets/terminal-replay.html?${a.toString()}`}function _t(e,t,n){return`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(t)}/${encodeURIComponent(n)}/terminal-log/raw?download=1`}function Mo(){let e=window.location.hash.match(/^#\/workflows\/([^/?#]+)/);if(!e)return null;try{return decodeURIComponent(e[1])}catch{return null}}function Zt(e,t){if(!Co(e))return"";let n=e.attemptId,s=t.comments.get(n)??"",a=t.resolving.has(n),r=t.statuses.get(n),i=r?.kind==="error"?"hint-warn":"hint-ok";return`<div class="wf-approval-box" data-wf-approval="${c(n)}">
|
|
630
753
|
<label>
|
|
631
|
-
<span>${
|
|
632
|
-
<textarea class="wf-approval-comment" data-wf-approval-comment="${
|
|
754
|
+
<span>${c(o("workflow.detail.approvalComment"))}</span>
|
|
755
|
+
<textarea class="wf-approval-comment" data-wf-approval-comment="${c(n)}" rows="2" placeholder="${c(o("workflow.detail.optionalComment"))}"${a?" disabled":""}>${c(s)}</textarea>
|
|
633
756
|
</label>
|
|
634
757
|
<div class="wf-approval-actions">
|
|
635
|
-
<button type="button" class="primary" data-wf-approval-action="approve" data-wf-attempt-id="${
|
|
636
|
-
<button type="button" data-wf-approval-action="reject" data-wf-attempt-id="${
|
|
637
|
-
${a?`<span class="muted">${
|
|
758
|
+
<button type="button" class="primary" data-wf-approval-action="approve" data-wf-attempt-id="${c(n)}"${a?" disabled":""}>${c(o("workflow.detail.approve"))}</button>
|
|
759
|
+
<button type="button" data-wf-approval-action="reject" data-wf-attempt-id="${c(n)}"${a?" disabled":""}>${c(o("workflow.detail.reject"))}</button>
|
|
760
|
+
${a?`<span class="muted">${c(o("workflow.detail.submitting"))}</span>`:""}
|
|
638
761
|
</div>
|
|
639
|
-
${
|
|
640
|
-
</div>`}function
|
|
641
|
-
<summary>${
|
|
642
|
-
${
|
|
643
|
-
</details>`}function
|
|
644
|
-
<td>${
|
|
645
|
-
<td><code>${
|
|
646
|
-
<td>${
|
|
647
|
-
<td>${t.nodeId?`<code>${
|
|
648
|
-
<td>${t.activityId?`<code>${
|
|
649
|
-
<td>${t.errorCode?`<span class="muted error">${
|
|
650
|
-
<td title="${
|
|
651
|
-
</tr>`}function
|
|
762
|
+
${r?`<div class="${i} wf-approval-status">${c(r.text)}</div>`:""}
|
|
763
|
+
</div>`}function Co(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function Ho(e,t){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(n=>{let s=n.dataset.wfApprovalComment;s&&t.set(s,n.value)})}function en(e,t){e.querySelectorAll("button[data-wf-resume-action][data-wf-resume-attempt][data-wf-resume-activity]").forEach(n=>{n.dataset.wfResumeBound!=="1"&&(n.dataset.wfResumeBound="1",n.addEventListener("click",()=>{let s=n.dataset.wfResumeAttempt,a=n.dataset.wfResumeActivity,r=n.dataset.wfResumeAction;!s||!a||(r==="start"?t.onStart(s,a):r==="end"&&t.onEnd(s,a))}))})}function xo(e,t,n,s,a,r){let i=e.querySelector(".wf-terminal-actions");if(!i)return;let m=i.querySelector('button[data-wf-resume-button="1"]'),k=Yt(t,n,s,a,r);m?m.outerHTML=k:k&&i.insertAdjacentHTML("beforeend",k);let $=e.querySelector("details.wf-terminal-block");if($){let p=$.querySelector(".wf-resume-status"),g=Qt(t.attemptId,r);p?p.outerHTML=g:g&&i.insertAdjacentHTML("afterend",g)}en(e,r)}function Ao(e,t){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(n=>{let s=n.dataset.wfApprovalComment;s&&n.addEventListener("input",()=>{t.comments.set(s,n.value)})}),e.querySelectorAll("button[data-wf-approval-action][data-wf-attempt-id]").forEach(n=>{n.addEventListener("click",()=>{let s=n.dataset.wfAttemptId,a=n.dataset.wfApprovalAction;!s||a!=="approve"&&a!=="reject"||t.onResolve(s,a)})})}function Z(e,t,n,s){let a=at(e,t);return`<details class="wf-io-block" data-io-key="${c(a)}"${s.has(a)?" open":""}>
|
|
764
|
+
<summary>${c(t)} ${Po(n)}</summary>
|
|
765
|
+
${No(n)}
|
|
766
|
+
</details>`}function at(e,t){return`${e}:${t}`}function Ro(e,t){if(!t)return!1;for(let n of e.querySelectorAll("[data-wf-attempt-card]"))if(n.dataset.wfAttemptCard===t)return n.scrollIntoView({block:"center"}),!0;return!1}function Do(e,t,n){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(s=>{let a=s.dataset.ioKey;if(!a)return;s.open?t.add(a):t.delete(a);let r=s.querySelector(".wf-io-pre");r&&n.set(a,r.scrollTop)})}function Bo(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(n=>{n.dataset.ioToggleBound!=="1"&&(n.dataset.ioToggleBound="1",n.addEventListener("toggle",()=>{let s=n.dataset.ioKey;s&&(n.open?t.add(s):t.delete(s))}))})}function Oo(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(n=>{let s=n.dataset.ioKey;if(!s)return;let a=t.get(s);if(a===void 0)return;let r=n.querySelector(".wf-io-pre");r&&(r.scrollTop=a)})}function qo(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(n=>{let s=n.dataset.ioKey;if(!s)return;let a=n.querySelector(".wf-io-pre");a&&a.dataset.ioScrollBound!=="1"&&(a.dataset.ioScrollBound="1",a.addEventListener("scroll",()=>{t.set(s,a.scrollTop)}))})}function Po(e){if(!e)return`<span class="muted">${c(o("workflow.detail.empty"))}</span>`;let t=[];return e.outputBytes!==void 0&&t.push(`${e.outputBytes}B`),e.truncated&&t.push(o("workflow.detail.truncated")),e.error&&t.push(o("workflow.detail.error")),e.outputHash&&t.push(Ne(e.outputHash)),t.length?`<span class="muted">${c(t.join(" \xB7 "))}</span>`:""}function No(e){if(!e)return`<div class="muted wf-io-empty">${c(o("workflow.detail.noData"))}</div>`;let t=e.value!==void 0?JSON.stringify(e.value,null,2):e.text??"",n=e.error?`<div class="muted error">${c(e.error)}</div>`:"";return t?`${n}<pre class="wf-io-pre">${c(t)}</pre>`:`${n}<div class="muted wf-io-empty">${c(o("workflow.detail.noPreview"))}</div>`}function jo(e){let t=[];if(e.effectAttempted&&t.push(`${c(o("workflow.detail.effect"))} ${c(e.effectAttempted.provider)}`),e.wait){let n=e.wait.resolution?`${e.wait.resolution.kind}${e.wait.resolution.resolution?":"+e.wait.resolution.resolution:""}`:o("workflow.detail.open");t.push(`${c(o("workflow.detail.wait"))} ${c(e.wait.waitKind)} ${c(n)}`),e.wait.deadlineAt!==void 0&&t.push(`${c(o("workflow.detail.deadline"))} ${c(Pe(e.wait.deadlineAt))}`)}if(e.error){let n=`${e.error.errorCode}${e.error.errorClass?` \xB7 ${e.error.errorClass}`:""}`;t.push(`<span class="muted error">${c(n)}</span>`),e.error.errorMessage&&t.push(`<span class="error wf-error-msg">${c(e.error.errorMessage)}</span>`)}return e.output&&t.push(`${c(o("workflow.detail.output"))} ${c(Ne(e.output.outputHash))}`),e.runningMs!==void 0&&t.push(`${e.runningMs}ms`),t.length>0?t.join("<br/>"):'<span class="muted">-</span>'}function Uo(e,t){e.innerHTML=t.length>0?t.map(Fo).join(""):`<tr><td colspan="7" class="empty">${c(o("workflow.detail.noEvents"))}</td></tr>`}function Fo(e){let t=_o(e.payload);return`<tr>
|
|
767
|
+
<td>${$e(e.eventId)}</td>
|
|
768
|
+
<td><code>${c(e.type)}</code></td>
|
|
769
|
+
<td>${c(e.actor)}</td>
|
|
770
|
+
<td>${t.nodeId?`<code>${c(t.nodeId)}</code>`:"-"}</td>
|
|
771
|
+
<td>${t.activityId?`<code>${c(t.activityId)}</code>`:"-"}</td>
|
|
772
|
+
<td>${t.errorCode?`<span class="muted error">${c(t.errorCode)}</span>`:"-"}</td>
|
|
773
|
+
<td title="${c(new Date(e.timestamp).toISOString())}">${c(Pe(e.timestamp))}</td>
|
|
774
|
+
</tr>`}function $e(e){let t=e.lastIndexOf("-");if(t<0)return 0;let n=Number(e.slice(t+1));return Number.isFinite(n)?n:0}function _o(e){if(!e||typeof e!="object"||"ref"in e)return{};let t=e,n={};typeof t.nodeId=="string"&&(n.nodeId=t.nodeId),typeof t.activityId=="string"&&(n.activityId=t.activityId),typeof t.failedNodeId=="string"&&(n.nodeId=t.failedNodeId);let s=t.error;return s&&typeof s=="object"&&"errorCode"in s&&(n.errorCode=String(s.errorCode)),n}function Wo(e){return!e.payload||typeof e.payload!="object"||"ref"in e.payload?null:e.payload}function Wt(e,t,n){return Math.min(n,Math.max(t,e))}function Ne(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function zo(e,t){return e.length>t?e.slice(0,t-1)+"\u2026":e}function Pe(e){return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}function C(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function tn(e){return e?e.length>18?e.slice(0,10)+"..."+e.slice(-6):e:"-"}function nn(e){let t=location.hash.match(/^#\/(?:workflows\/catalog|workflows-catalog)\/([^/?#]+)$/);return t?Go(e,decodeURIComponent(t[1])):Jo(e)}function Jo(e){e.innerHTML=`
|
|
652
775
|
<nav class="wf-subnav">
|
|
653
|
-
<a href="#/workflows" data-i18n="workflow.subnav.runs">${
|
|
654
|
-
<a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${
|
|
776
|
+
<a href="#/workflows" data-i18n="workflow.subnav.runs">${C(o("workflow.subnav.runs"))}</a>
|
|
777
|
+
<a href="#/workflows/catalog" class="active" data-i18n="workflow.subnav.catalog">${C(o("workflow.subnav.catalog"))}</a>
|
|
655
778
|
</nav>
|
|
656
779
|
<section class="catalog-head">
|
|
657
780
|
<div>
|
|
658
|
-
<h2>${
|
|
659
|
-
<p class="muted">${
|
|
781
|
+
<h2>${C(o("catalog.title"))}</h2>
|
|
782
|
+
<p class="muted">${C(o("catalog.subtitle"))}</p>
|
|
660
783
|
</div>
|
|
661
|
-
<button id="catalog-refresh" type="button">${
|
|
784
|
+
<button id="catalog-refresh" type="button">${C(o("catalog.refresh"))}</button>
|
|
662
785
|
</section>
|
|
663
786
|
<form id="catalog-filters" class="filters">
|
|
664
|
-
<input type="search" name="q" placeholder="${
|
|
787
|
+
<input type="search" name="q" placeholder="${C(o("catalog.searchPlaceholder"))}" />
|
|
665
788
|
<span id="catalog-status" class="muted"></span>
|
|
666
789
|
</form>
|
|
667
790
|
<div class="wf-table-scroll">
|
|
668
791
|
<table>
|
|
669
792
|
<thead><tr>
|
|
670
|
-
<th>${
|
|
671
|
-
<th>${
|
|
672
|
-
<th>${
|
|
673
|
-
<th>${
|
|
674
|
-
<th>${
|
|
675
|
-
<th>${
|
|
793
|
+
<th>${C(o("catalog.table.workflow"))}</th>
|
|
794
|
+
<th>${C(o("catalog.table.version"))}</th>
|
|
795
|
+
<th>${C(o("catalog.table.params"))}</th>
|
|
796
|
+
<th>${C(o("catalog.table.nodes"))}</th>
|
|
797
|
+
<th>${C(o("catalog.table.revision"))}</th>
|
|
798
|
+
<th>${C(o("catalog.table.path"))}</th>
|
|
676
799
|
</tr></thead>
|
|
677
800
|
<tbody id="catalog-tbody"></tbody>
|
|
678
801
|
</table>
|
|
679
802
|
</div>
|
|
680
|
-
`;let t=e.querySelector("#catalog-tbody"),
|
|
803
|
+
`;let t=e.querySelector("#catalog-tbody"),n=e.querySelector("#catalog-status"),s=e.querySelector("#catalog-filters"),a=e.querySelector("#catalog-refresh"),r=[],i=null,m=!1;function k(){let g=(new FormData(s).get("q")??"").trim().toLowerCase();return g?r.filter(l=>l.workflowId.toLowerCase().includes(g)||l.path.toLowerCase().includes(g)):r}function $(){i?(n.textContent=o("catalog.loadFailed",{error:i}),n.classList.add("error")):(n.textContent=`${r.length}`,n.classList.remove("error"));let g=k();if(g.length===0){t.innerHTML=`<tr><td colspan="6" class="empty">${r.length===0?C(o("catalog.noDefinitions")):C(o("catalog.noFilterMatch"))}</td></tr>`;return}t.innerHTML=g.map(l=>`
|
|
681
804
|
<tr>
|
|
682
|
-
<td><a href="#/workflows/catalog/${encodeURIComponent(l.workflowId)}"><code>${
|
|
805
|
+
<td><a href="#/workflows/catalog/${encodeURIComponent(l.workflowId)}"><code>${C(l.workflowId)}</code></a></td>
|
|
683
806
|
<td>${l.version}</td>
|
|
684
|
-
<td>${
|
|
807
|
+
<td>${C(o("catalog.paramSummary",{required:l.requiredParamCount,total:l.paramCount}))}</td>
|
|
685
808
|
<td>${l.nodeCount}</td>
|
|
686
|
-
<td><code>${
|
|
687
|
-
<td><code>${
|
|
809
|
+
<td><code>${C(tn(l.revisionId))}</code></td>
|
|
810
|
+
<td><code>${C(l.path)}</code></td>
|
|
688
811
|
</tr>
|
|
689
|
-
`).join("")}async function
|
|
812
|
+
`).join("")}async function p(){a.disabled=!0,n.textContent=o("catalog.loading");try{let g=await fetch("/api/workflows/definitions");if(!g.ok)throw new Error(`HTTP ${g.status}`);r=(await g.json()).definitions??[],i=null}catch(g){i=g?.message??String(g),r=[]}finally{a.disabled=!1,m||$()}}return s.addEventListener("input",$),a.addEventListener("click",()=>{p()}),p(),()=>{m=!0}}function Go(e,t){e.innerHTML=`
|
|
690
813
|
<div class="catalog-detail-head">
|
|
691
|
-
<a class="btn-link" href="#/workflows/catalog">${
|
|
814
|
+
<a class="btn-link" href="#/workflows/catalog">${C(o("catalog.back"))}</a>
|
|
692
815
|
<div>
|
|
693
|
-
<h2><code>${
|
|
694
|
-
<div id="catalog-detail-subtitle" class="muted">${
|
|
816
|
+
<h2><code>${C(t)}</code></h2>
|
|
817
|
+
<div id="catalog-detail-subtitle" class="muted">${C(o("workflow.detail.loading"))}</div>
|
|
695
818
|
</div>
|
|
696
819
|
</div>
|
|
697
820
|
<section id="catalog-error" class="hint-warn" hidden></section>
|
|
698
821
|
<section id="catalog-run-status" class="hint-ok" hidden></section>
|
|
699
822
|
<div id="catalog-detail-body"></div>
|
|
700
|
-
`;let
|
|
823
|
+
`;let n=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,k=!1;function $(f){s.hidden=!f,s.textContent=f??""}function p(f){a.hidden=!f,a.textContent=f??""}function g(f){let T={};for(let[S,y]of Object.entries(f??{}))"default"in y&&(T[S]=y.default);return T}function l(){if(!i)return;let f=i.definition;n.textContent=`${o("catalog.revision")} ${tn(i.revisionId)} \xB7 ${i.path}`;let T=JSON.stringify(g(f.params),null,2);r.innerHTML=`
|
|
701
824
|
<section class="wf-panel">
|
|
702
|
-
<div class="wf-panel-title"><h3>${
|
|
825
|
+
<div class="wf-panel-title"><h3>${C(o("catalog.summary"))}</h3></div>
|
|
703
826
|
<div class="wf-summary-grid">
|
|
704
|
-
<div class="wf-summary-item"><span>${
|
|
705
|
-
<div class="wf-summary-item"><span>${
|
|
706
|
-
<div class="wf-summary-item"><span>${
|
|
707
|
-
<div class="wf-summary-item"><span>${
|
|
827
|
+
<div class="wf-summary-item"><span>${C(o("catalog.table.workflow"))}</span><strong><code>${C(f.workflowId)}</code></strong></div>
|
|
828
|
+
<div class="wf-summary-item"><span>${C(o("catalog.table.version"))}</span><strong>${f.version}</strong></div>
|
|
829
|
+
<div class="wf-summary-item"><span>${C(o("catalog.nodeCount"))}</span><strong>${Object.keys(f.nodes).length}</strong></div>
|
|
830
|
+
<div class="wf-summary-item"><span>${C(o("catalog.path"))}</span><strong><code>${C(i.path)}</code></strong></div>
|
|
708
831
|
</div>
|
|
709
832
|
</section>
|
|
710
833
|
|
|
711
834
|
<section class="wf-panel">
|
|
712
|
-
<div class="wf-panel-title"><h3>${
|
|
835
|
+
<div class="wf-panel-title"><h3>${C(o("catalog.runPanel"))}</h3></div>
|
|
713
836
|
<form id="catalog-run-form" class="catalog-run-form">
|
|
714
837
|
<label>
|
|
715
|
-
<span>${
|
|
716
|
-
<textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${
|
|
838
|
+
<span>${C(o("catalog.paramsJson"))}</span>
|
|
839
|
+
<textarea id="catalog-params" rows="8" spellcheck="false" placeholder="${C(o("catalog.paramsPlaceholder"))}">${C(T)}</textarea>
|
|
717
840
|
</label>
|
|
718
841
|
<div class="catalog-chat-grid">
|
|
719
842
|
<label>
|
|
720
|
-
<span>${
|
|
843
|
+
<span>${C(o("catalog.chatId"))}</span>
|
|
721
844
|
<input id="catalog-chat-id" type="text" autocomplete="off" />
|
|
722
845
|
</label>
|
|
723
846
|
<label>
|
|
724
|
-
<span>${
|
|
847
|
+
<span>${C(o("catalog.larkAppId"))}</span>
|
|
725
848
|
<input id="catalog-lark-app-id" type="text" autocomplete="off" />
|
|
726
849
|
</label>
|
|
727
850
|
</div>
|
|
728
|
-
<div class="muted">${
|
|
851
|
+
<div class="muted">${C(o("catalog.chatBindingHint"))}</div>
|
|
729
852
|
<div id="catalog-param-errors" class="catalog-param-errors" hidden></div>
|
|
730
|
-
<button id="catalog-run-btn" type="submit" class="primary">${
|
|
853
|
+
<button id="catalog-run-btn" type="submit" class="primary">${C(o("catalog.run"))}</button>
|
|
731
854
|
</form>
|
|
732
855
|
</section>
|
|
733
856
|
|
|
734
857
|
<section class="wf-panel">
|
|
735
|
-
<div class="wf-panel-title"><h3>${
|
|
736
|
-
${
|
|
858
|
+
<div class="wf-panel-title"><h3>${C(o("catalog.paramsSchema"))}</h3></div>
|
|
859
|
+
${Ko(f.params)}
|
|
737
860
|
</section>
|
|
738
861
|
|
|
739
862
|
<section class="wf-panel">
|
|
740
|
-
<div class="wf-panel-title"><h3>${
|
|
741
|
-
<pre class="wf-io-pre">${
|
|
863
|
+
<div class="wf-panel-title"><h3>${C(o("catalog.definitionJson"))}</h3></div>
|
|
864
|
+
<pre class="wf-io-pre">${C(JSON.stringify(f,null,2))}</pre>
|
|
742
865
|
</section>
|
|
743
|
-
`,
|
|
866
|
+
`,L()}async function I(){if(!i||k)return;let f=r.querySelector("#catalog-params"),T=r.querySelector("#catalog-chat-id"),S=r.querySelector("#catalog-lark-app-id"),y=r.querySelector("#catalog-run-btn"),H=r.querySelector("#catalog-param-errors"),u;try{if(u=JSON.parse(f.value||"{}"),!u||typeof u!="object"||Array.isArray(u))throw new Error(o("catalog.badParamsJson"))}catch(w){H.hidden=!1,H.innerHTML=`<div class="muted error">${C(w?.message??String(w))}</div>`;return}k=!0,y.disabled=!0,y.textContent=o("catalog.running"),H.hidden=!0,$(null),p(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:T.value.trim(),larkAppId:S.value.trim()}})});if(w.status===401)throw new Error(o("catalog.writeAccess"));let h=await w.json().catch(()=>({}));if(!w.ok||!h.ok)throw h.issues?.length&&(H.hidden=!1,H.innerHTML=`<strong>${C(o("catalog.invalidParams"))}</strong><ul>${h.issues.map(E=>`<li>${C(o("catalog.issue",{path:E.path.length?E.path.join("."):"(root)",message:E.message}))}</li>`).join("")}</ul>`),new Error(h.hint??h.message??h.error??o("catalog.runHttp",{status:w.status}));p(o("catalog.runStarted")),h.runId&&(location.hash=`#/workflows/${encodeURIComponent(h.runId)}`)}catch(w){$(w?.message??String(w))}finally{k=!1,y.disabled=!1,y.textContent=o("catalog.run")}}function L(){r.querySelector("#catalog-run-form")?.addEventListener("submit",T=>{T.preventDefault(),I()})}async function b(){try{let f=await fetch(`/api/workflows/definitions/${encodeURIComponent(t)}`);if(f.status===404)throw new Error("unknown_workflow");if(!f.ok)throw new Error(`HTTP ${f.status}`);i=await f.json(),$(null),l()}catch(f){$(o("catalog.definitionLoadFailed",{error:f?.message??String(f)})),n.textContent=o("workflow.detail.loadFailed")}}return b().then(()=>{}),()=>{m=!0}}function Ko(e){let t=Object.entries(e??{});return t.length===0?`<div class="muted">${C(o("catalog.noParams"))}</div>`:`<div class="catalog-param-list">${t.map(([n,s])=>`
|
|
744
867
|
<article class="catalog-param">
|
|
745
868
|
<header>
|
|
746
|
-
<code>${
|
|
747
|
-
<span class="wf-status">${
|
|
748
|
-
<span class="muted">${
|
|
869
|
+
<code>${C(n)}</code>
|
|
870
|
+
<span class="wf-status">${C(s.required?o("catalog.required"):o("catalog.optional"))}</span>
|
|
871
|
+
<span class="muted">${C(s.type)}${s.format?` \xB7 ${C(s.format)}`:""}</span>
|
|
749
872
|
</header>
|
|
750
|
-
${
|
|
751
|
-
${"default"in
|
|
873
|
+
${s.description?`<div class="muted">${C(o("catalog.description"))}: ${C(s.description)}</div>`:""}
|
|
874
|
+
${"default"in s?`<pre class="wf-io-pre">${C(`${o("catalog.default")}: ${JSON.stringify(s.default,null,2)}`)}</pre>`:""}
|
|
752
875
|
</article>
|
|
753
|
-
`).join("")}</div>`}var
|
|
754
|
-
<img class="qr-image" src="${e.qrDataUrl}" alt="${
|
|
755
|
-
${e.qrUrl?`<a class="onboarding-link" href="${e.qrUrl}" target="_blank" rel="noopener">${
|
|
756
|
-
</div>`:"",
|
|
876
|
+
`).join("")}</div>`}var pe=null,je=null;function Ue(){je!==null&&(window.clearInterval(je),je=null)}function on(){return pe||(pe=document.createElement("dialog"),pe.className="onboarding-dialog",document.body.appendChild(pe),pe.addEventListener("close",Ue),pe)}function Vo(e){return e.status==="waiting_for_scan"?o("botOnboarding.waiting"):e.status==="verifying"?o("botOnboarding.verifying"):e.status==="completed"?o("botOnboarding.completed"):e.status==="failed"?`${o("botOnboarding.failed")}: ${e.message??e.error??"unknown"}`:o("botOnboarding.starting")}function Se(e){let t=on(),n=e.qrDataUrl?`<div class="qr-card">
|
|
877
|
+
<img class="qr-image" src="${e.qrDataUrl}" alt="${o("botOnboarding.qrAlt")}">
|
|
878
|
+
${e.qrUrl?`<a class="onboarding-link" href="${e.qrUrl}" target="_blank" rel="noopener">${o("botOnboarding.openLink")}</a>`:""}
|
|
879
|
+
</div>`:"",s=e.appId?`<p><b>App ID:</b> <code>${e.appId}</code></p>`:"",a=e.status==="completed"?`<p class="hint-ok">${o("botOnboarding.restartHint")}</p>`:"";t.innerHTML=`<article>
|
|
757
880
|
<header>
|
|
758
|
-
<h3>${
|
|
759
|
-
<p>${
|
|
881
|
+
<h3>${o("botOnboarding.title")}</h3>
|
|
882
|
+
<p>${o("botOnboarding.intro")}</p>
|
|
760
883
|
</header>
|
|
761
|
-
<p class="onboarding-status status-${e.status}">${
|
|
762
|
-
${
|
|
763
|
-
${
|
|
884
|
+
<p class="onboarding-status status-${e.status}">${Vo(e)}</p>
|
|
885
|
+
${n}
|
|
886
|
+
${s}
|
|
764
887
|
${a}
|
|
765
|
-
<form method="dialog"><button>${
|
|
766
|
-
</article>`}async function
|
|
888
|
+
<form method="dialog"><button>${o("botOnboarding.close")}</button></form>
|
|
889
|
+
</article>`}async function Yo(e){let t=await fetch(`/api/bot-onboarding/${encodeURIComponent(e)}`),n=await t.json();if(!t.ok||!n?.job)throw new Error(n?.error??`http_${t.status}`);Se(n.job),(n.job.status==="completed"||n.job.status==="failed")&&Ue()}async function Qo(){Ue(),Se({id:"",status:"starting"});let e=on();e.open||e.showModal();try{let t=await fetch("/api/bot-onboarding/start",{method:"POST"}),n=await t.json();if(!t.ok||!n?.job?.id)throw new Error(n?.error??`http_${t.status}`);Se(n.job),je=window.setInterval(()=>{Yo(n.job.id).catch(s=>{Ue(),Se({id:n.job.id,status:"failed",message:s instanceof Error?s.message:String(s)})})},1200)}catch(t){Se({id:"",status:"failed",message:t instanceof Error?t.message:String(t)})}}function an(){let e=document.getElementById("add-bot-btn");e&&(e.onclick=()=>{Qo()})}var V=document.getElementById("root"),Ie=null;function st(){Ie&&(Ie(),Ie=null);let e=location.hash||"#/";e.startsWith("#/workflows/catalog")||e.startsWith("#/workflows-catalog")?Ie=nn(V):e.startsWith("#/workflows")?Ie=zt(V):e.startsWith("#/groups")?It(V):e.startsWith("#/bot-defaults")?Et(V):e.startsWith("#/connectors")?Ut(V):e.startsWith("#/team/manage")?Pt(V):e.startsWith("#/team")?qt(V):e.startsWith("#/roles")?xt(V):e.startsWith("#/schedules")?$t(V):e.startsWith("#/sessions")?vt(V):bt(V);for(let t of document.querySelectorAll(".sidebar-nav a")){let n=t.getAttribute("href")??"#/";t.classList.toggle("active",n===(e||"#/"))}}var rt=document.getElementById("status");function rn(){rt&&(rt.textContent=N.online?o("status.live"):o("status.disconnected"),rt.className="connection-status "+(N.online?"online":"offline"))}N.on(rn);function sn(){document.querySelectorAll("[data-i18n]").forEach(e=>{e.textContent=o(e.dataset.i18n??"")}),document.querySelectorAll("[data-locale]").forEach(e=>{e.classList.toggle("active",e.dataset.locale===ae.locale)}),document.querySelectorAll("[data-theme-mode]").forEach(e=>{e.classList.toggle("active",e.dataset.themeMode===ae.themeMode)}),rn()}function Xo(){document.querySelectorAll("[data-locale]").forEach(e=>{e.onclick=()=>ae.setLocale(e.dataset.locale)}),document.querySelectorAll("[data-theme-mode]").forEach(e=>{e.onclick=()=>ae.setThemeMode(e.dataset.themeMode)})}(async()=>{ae.init(),Xo(),an(),ae.on(()=>{sn(),st()}),sn();try{await pt()}catch(e){console.error("botmux dashboard bootstrap failed",e),N.setOnline(!1)}window.addEventListener("hashchange",st),st()})();})();
|