botmux 2.43.0 → 2.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bot-registry.d.ts +11 -0
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +1 -0
- package/dist/bot-registry.js.map +1 -1
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +38 -2
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +5 -2
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/worker-pool.d.ts +22 -0
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +54 -2
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults.js +13 -0
- package/dist/dashboard/web/bot-defaults.js.map +1 -1
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +4 -0
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard-web/app.js +80 -75
- package/dist/dashboard.js +1 -0
- package/dist/dashboard.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +7 -1
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +7 -1
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/card-builder.d.ts +25 -2
- package/dist/im/lark/card-builder.d.ts.map +1 -1
- package/dist/im/lark/card-builder.js +141 -43
- 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 +20 -4
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/client.d.ts +20 -0
- package/dist/im/lark/client.d.ts.map +1 -1
- package/dist/im/lark/client.js +88 -30
- package/dist/im/lark/client.js.map +1 -1
- package/dist/services/card-prefs-store.d.ts +2 -1
- package/dist/services/card-prefs-store.d.ts.map +1 -1
- package/dist/services/card-prefs-store.js +13 -4
- package/dist/services/card-prefs-store.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,16 +1,16 @@
|
|
|
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()}},q=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())]);q.upsertSessions(e.sessions??[]),q.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);q.applySse(a,d.body??d)}catch{}});o.onerror=()=>q.setOnline(!1),o.onopen=()=>q.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.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 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
|
|
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"},Pt={"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.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.:
|
|
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"},Pt={"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"},Ge={zh:qt,en:Pt};function ze(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 Nt(e=[]){for(let t of e){let o=ze(t);if(o)return o}return"zh"}function ve(e){return(t,o)=>{let r=Ge[e][t]??Ge.zh[t]??t;return o?r.replace(/\{(\w+)\}/g,(a,s)=>{let d=o[s];return d==null?`{${s}}`:String(d)}):r}}function Ke(e,t){return(e?ze(e.getItem(Ae)):null)??Nt(t)}var He="botmux.dashboard.theme";function jt(e){return e==="system"||e==="light"||e==="dark"?e:null}function Ve(e,t){return e==="system"?t?"dark":"light":e}function Ye(e){return jt(e?.getItem(He))??"system"}var Re=class{locale="zh";themeMode="system";resolvedTheme="light";listeners=new Set;translate=ve(this.locale);mediaQuery=null;init(){let t=typeof window<"u"?window:void 0;this.locale=Ke(t?.localStorage,Ut()),this.translate=ve(this.locale),this.themeMode=Ye(t?.localStorage),this.mediaQuery=t?.matchMedia?.("(prefers-color-scheme: dark)")??null,this.mediaQuery?.addEventListener("change",()=>{this.applyTheme(),this.emit()}),this.applyTheme(),this.applyLocale()}t(t,o){return this.translate(t,o)}setLocale(t){this.locale!==t&&(this.locale=t,this.translate=ve(t),window.localStorage.setItem(Ae,t),this.applyLocale(),this.emit())}setThemeMode(t){this.themeMode!==t&&(this.themeMode=t,window.localStorage.setItem(He,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=Ve(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 Ut(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var
|
|
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"},Ge={zh:qt,en:Pt};function ze(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 Nt(e=[]){for(let t of e){let o=ze(t);if(o)return o}return"zh"}function ve(e){return(t,o)=>{let r=Ge[e][t]??Ge.zh[t]??t;return o?r.replace(/\{(\w+)\}/g,(a,s)=>{let d=o[s];return d==null?`{${s}}`:String(d)}):r}}function Ke(e,t){return(e?ze(e.getItem(Ae)):null)??Nt(t)}var He="botmux.dashboard.theme";function jt(e){return e==="system"||e==="light"||e==="dark"?e:null}function Ve(e,t){return e==="system"?t?"dark":"light":e}function Ye(e){return jt(e?.getItem(He))??"system"}var Re=class{locale="zh";themeMode="system";resolvedTheme="light";listeners=new Set;translate=ve(this.locale);mediaQuery=null;init(){let t=typeof window<"u"?window:void 0;this.locale=Ke(t?.localStorage,Ut()),this.translate=ve(this.locale),this.themeMode=Ye(t?.localStorage),this.mediaQuery=t?.matchMedia?.("(prefers-color-scheme: dark)")??null,this.mediaQuery?.addEventListener("change",()=>{this.applyTheme(),this.emit()}),this.applyTheme(),this.applyLocale()}t(t,o){return this.translate(t,o)}setLocale(t){this.locale!==t&&(this.locale=t,this.translate=ve(t),window.localStorage.setItem(Ae,t),this.applyLocale(),this.emit())}setThemeMode(t){this.themeMode!==t&&(this.themeMode=t,window.localStorage.setItem(He,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=Ve(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 Ut(){return typeof navigator>"u"?[]:navigator.languages?.length?navigator.languages:[navigator.language].filter(Boolean)}var ee=new Re;function n(e,t){return ee.t(e,t)}function m(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function ue(e){if(!e)return"-";let t=Date.now()-e;return t<6e4?n("common.now"):t<36e5?Math.floor(t/6e4)+"m":t<864e5?Math.floor(t/36e5)+"h":Math.floor(t/864e5)+"d"}var De={chats:[],bots:[]};async function Ft(){try{let e=await fetch("/api/groups");if(!e.ok)return;De=await e.json()}catch{}}function Wt(e){return`status status-${m(e||"unknown")}`}function _t(e){return`<li class="overview-list-row">
|
|
14
14
|
<div>
|
|
15
15
|
<strong>${m(e.title??e.sessionId)}</strong>
|
|
16
16
|
<span>${m(e.botName??"")} \xB7 ${m(e.cliId??"unknown")}</span>
|
|
@@ -53,11 +53,11 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
53
53
|
<ul class="overview-list" id="next-schedules"></ul>
|
|
54
54
|
</section>
|
|
55
55
|
</div>
|
|
56
|
-
</section>`;let t=e.querySelector("#overview-metrics"),o=e.querySelector("#recent-sessions"),r=e.querySelector("#next-schedules");function a(){let s=[...
|
|
56
|
+
</section>`;let t=e.querySelector("#overview-metrics"),o=e.querySelector("#recent-sessions"),r=e.querySelector("#next-schedules");function a(){let s=[...P.sessions.values()],d=[...P.schedules.values()],w=s.filter(E=>E.status!=="closed"),I=s.filter(E=>E.status==="working"||E.status==="analyzing"||E.status==="starting"),T=d.filter(E=>E.enabled),f=De.bots?.length||new Set(s.map(E=>E.larkAppId).filter(Boolean)).size,g=[{label:n("overview.openSessions"),value:w.length,meta:`${s.length} ${n("overview.total")}`},{label:n("overview.workingSessions"),value:I.length,meta:`${w.length} ${n("overview.active")}`},{label:n("overview.onlineBots"),value:f,meta:n("overview.daemonRegistry")},{label:n("overview.schedules"),value:d.length,meta:`${T.length} ${n("overview.enabledSchedules")}`},{label:n("overview.groups"),value:De.chats?.length??0,meta:n("overview.chatMatrix")}];t.innerHTML=g.map(E=>`<article class="metric-card">
|
|
57
57
|
<span>${m(E.label)}</span>
|
|
58
58
|
<strong>${E.value}</strong>
|
|
59
59
|
<small>${m(E.meta)}</small>
|
|
60
|
-
</article>`).join("");let l=s.sort((E,b)=>Number(b.lastMessageAt??0)-Number(E.lastMessageAt??0)).slice(0,6);o.innerHTML=l.length?l.map(E=>_t({...E,title:E.title??`${ue(E.lastMessageAt)} \xB7 ${E.sessionId}`})).join(""):`<li class="empty">${n("overview.noSessions")}</li>`;let S=d.filter(E=>E.nextRunAt).sort((E,b)=>Date.parse(E.nextRunAt)-Date.parse(b.nextRunAt)).slice(0,6);r.innerHTML=S.length?S.map(Jt).join(""):`<li class="empty">${n("overview.noSchedules")}</li>`}
|
|
60
|
+
</article>`).join("");let l=s.sort((E,b)=>Number(b.lastMessageAt??0)-Number(E.lastMessageAt??0)).slice(0,6);o.innerHTML=l.length?l.map(E=>_t({...E,title:E.title??`${ue(E.lastMessageAt)} \xB7 ${E.sessionId}`})).join(""):`<li class="empty">${n("overview.noSessions")}</li>`;let S=d.filter(E=>E.nextRunAt).sort((E,b)=>Date.parse(E.nextRunAt)-Date.parse(b.nextRunAt)).slice(0,6);r.innerHTML=S.length?S.map(Jt).join(""):`<li class="empty">${n("overview.noSchedules")}</li>`}P.on(a),a(),Ft().then(a)}function te(e,t){return`<th data-sort="${e}" data-label="${m(t)}">${m(t)}</th>`}var Xe=["claude-code","codex","codex-app","cursor","gemini","opencode","mtr","hermes","mira","aiden","coco","unknown"];function Gt(){return`<div class="filter-check-group" role="group" aria-label="${n("sessions.cli")}">
|
|
61
61
|
<span class="filter-check-label">${n("sessions.cli")}</span>
|
|
62
62
|
${Xe.map(e=>`
|
|
63
63
|
<label class="filter-check">
|
|
@@ -96,20 +96,20 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
96
96
|
<table id="sessions-table">
|
|
97
97
|
<thead><tr>
|
|
98
98
|
<th><input type="checkbox" id="select-all" title="${n("sessions.activeOnly")}"></th>
|
|
99
|
-
${
|
|
100
|
-
${
|
|
101
|
-
${
|
|
102
|
-
${
|
|
103
|
-
${
|
|
104
|
-
${
|
|
105
|
-
${
|
|
106
|
-
${
|
|
99
|
+
${te("botName",n("sessions.bot"))}
|
|
100
|
+
${te("cliId",n("sessions.cli"))}
|
|
101
|
+
${te("status",n("sessions.status"))}
|
|
102
|
+
${te("title",n("sessions.titleCol"))}
|
|
103
|
+
${te("workingDir",n("sessions.workingDir"))}
|
|
104
|
+
${te("spawnedAt",n("sessions.created"))}
|
|
105
|
+
${te("lastMessageAt",n("sessions.last"))}
|
|
106
|
+
${te("adopt",n("sessions.adopt"))}
|
|
107
107
|
<th>${n("sessions.actions")}</th>
|
|
108
108
|
</tr></thead>
|
|
109
109
|
<tbody></tbody>
|
|
110
110
|
</table>
|
|
111
111
|
<dialog id="drawer"></dialog>
|
|
112
|
-
</section>`}function Ze(e){e.innerHTML=zt();let t=e.querySelector("#sessions-table tbody"),o=e.querySelector("#filters"),r=e.querySelector("#drawer"),a=e.querySelector("#select-all"),s=e.querySelector("#bulk-bar"),d=e.querySelector("#bulk-count"),w=e.querySelector("#bulk-close"),I=e.querySelector("#bulk-clear"),
|
|
112
|
+
</section>`}function Ze(e){e.innerHTML=zt();let t=e.querySelector("#sessions-table tbody"),o=e.querySelector("#filters"),r=e.querySelector("#drawer"),a=e.querySelector("#select-all"),s=e.querySelector("#bulk-bar"),d=e.querySelector("#bulk-count"),w=e.querySelector("#bulk-close"),I=e.querySelector("#bulk-clear"),T=e.querySelector("#sessions-table"),f=new Set,g="lastMessageAt",l="desc";function S(c){let p=c.status==="closed",h=f.has(c.sessionId)?"checked":"";return`<tr data-id="${m(c.sessionId)}">
|
|
113
113
|
<td><input type="checkbox" class="row-select" ${h} ${p?"disabled":""}></td>
|
|
114
114
|
<td>${m(c.botName??"")}</td>
|
|
115
115
|
<td><span class="badge cli-${m(c.cliId??"unknown")}">${m(c.cliId??"unknown")}</span></td>
|
|
@@ -120,7 +120,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
120
120
|
<td>${ue(c.lastMessageAt)}</td>
|
|
121
121
|
<td>${c.adopt?'<span class="badge">adopt</span>':""}</td>
|
|
122
122
|
<td><button class="open" type="button">${n("sessions.details")}</button></td>
|
|
123
|
-
</tr>`}function E(){let c=new FormData(o),p=(c.get("q")??"").toLowerCase(),h=c.getAll("cli"),
|
|
123
|
+
</tr>`}function E(){let c=new FormData(o),p=(c.get("q")??"").toLowerCase(),h=c.getAll("cli"),L=h.length>0&&h.length<Xe.length,C=c.get("status"),R=c.get("adopt"),q=!!c.get("active"),O=[...P.sessions.values()].filter(H=>!L||h.includes(H.cliId??"unknown")).filter(H=>!C||H.status===C).filter(H=>!R||R==="yes"==!!H.adopt).filter(H=>!q||H.status!=="closed").filter(H=>!p||JSON.stringify(H).toLowerCase().includes(p));return O.sort(u),O}function b(c,p){return p==="spawnedAt"||p==="lastMessageAt"?Number(c[p]??0):p==="adopt"?!!c.adopt:String(c[p]??"").toLowerCase()}function u(c,p){let h=b(c,g),L=b(p,g),C=0;return typeof h=="number"&&typeof L=="number"?C=h-L:typeof h=="boolean"&&typeof L=="boolean"?C=Number(h)-Number(L):C=String(h).localeCompare(String(L)),C===0&&(C=Number(c.lastMessageAt??0)-Number(p.lastMessageAt??0)),l==="asc"?C:-C}function $(){T.querySelectorAll("th[data-sort]").forEach(c=>{let p=c.dataset.sort===g;c.classList.toggle("sorted",p),c.setAttribute("aria-sort",p?l==="asc"?"ascending":"descending":"none");let h=c.dataset.label??c.textContent?.trim()??"";c.textContent=p?`${h} ${l==="asc"?"\u25B2":"\u25BC"}`:h})}function k(c){s.hidden=f.size===0,d.textContent=n("sessions.selectedCount",{count:f.size});let p=c.filter(L=>L.status!=="closed");if(p.length===0){a.checked=!1,a.indeterminate=!1,a.disabled=!0;return}a.disabled=!1;let h=p.filter(L=>f.has(L.sessionId)).length;a.checked=h===p.length,a.indeterminate=h>0&&h<p.length}function v(){let c=E();for(let p of[...f]){let h=P.sessions.get(p);(!h||h.status==="closed")&&f.delete(p)}t.innerHTML=c.length?c.map(S).join(""):`<tr><td colspan="10" class="empty">${n("sessions.empty")}</td></tr>`,$(),k(c)}function A(c){let p=c.status==="closed";r.innerHTML=`<article>
|
|
124
124
|
<header>
|
|
125
125
|
<h3>${m(c.title??c.sessionId)}</h3>
|
|
126
126
|
<span class="status status-${m(c.status??"unknown")}">${m(c.status??"unknown")}</span>
|
|
@@ -138,7 +138,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
138
138
|
${p?"":`<button id="close-btn" type="button" class="contrast">${n("sessions.close")}</button>`}
|
|
139
139
|
</div>
|
|
140
140
|
<form method="dialog"><button>${n("sessions.dismiss")}</button></form>
|
|
141
|
-
</article>`,r.querySelectorAll("[data-copy]").forEach(R=>{R.onclick=()=>{navigator.clipboard.writeText(R.dataset.copy??""),R.textContent=n("sessions.copied"),setTimeout(()=>{R.textContent=n("sessions.copy")},800)}});let h=r.querySelector("#locate-btn");h&&(h.onclick=async()=>{h.disabled=!0,h.textContent=n("sessions.locating");try{let R=await fetch(`/api/sessions/${encodeURIComponent(c.sessionId)}/locate`,{method:"POST"}),
|
|
141
|
+
</article>`,r.querySelectorAll("[data-copy]").forEach(R=>{R.onclick=()=>{navigator.clipboard.writeText(R.dataset.copy??""),R.textContent=n("sessions.copied"),setTimeout(()=>{R.textContent=n("sessions.copy")},800)}});let h=r.querySelector("#locate-btn");h&&(h.onclick=async()=>{h.disabled=!0,h.textContent=n("sessions.locating");try{let R=await fetch(`/api/sessions/${encodeURIComponent(c.sessionId)}/locate`,{method:"POST"}),q=await R.json();if(q.ok){let O=30;h.textContent=n("sessions.cooldown",{seconds:O});let H=setInterval(()=>{O-=1,O<=0?(clearInterval(H),h.disabled=!1,h.textContent=n("sessions.locate")):h.textContent=n("sessions.cooldown",{seconds:O})},1e3)}else alert(`Locate failed: ${q.error??R.status}`),h.disabled=!1,h.textContent=n("sessions.locate")}catch(R){alert(`Locate error: ${R}`),h.disabled=!1,h.textContent=n("sessions.locate")}});let L=r.querySelector("#resume-btn");L&&(L.onclick=async()=>{L.disabled=!0;try{let R=await fetch(`/api/sessions/${encodeURIComponent(c.sessionId)}/resume`,{method:"POST"}),q=await R.json().catch(()=>({}));if(!R.ok||q.ok===!1){alert(`${n("sessions.resumeFailed")}: ${q?.error??R.status}`),L.disabled=!1;return}r.close()}catch(R){alert(`${n("sessions.resumeFailed")}: ${R}`),L.disabled=!1}});let C=r.querySelector("#close-btn");C&&(C.onclick=async()=>{if(confirm(n("sessions.closeConfirm"))){C.disabled=!0;try{await fetch(`/api/sessions/${encodeURIComponent(c.sessionId)}/close`,{method:"POST"})}finally{r.close()}}}),r.showModal()}t.addEventListener("click",c=>{let p=c.target;if(p.classList.contains("row-select")){let R=p.closest("tr[data-id]");if(!R)return;p.checked?f.add(R.dataset.id):f.delete(R.dataset.id),k(E());return}let h=p.closest("td");if(h&&h.querySelector(".row-select"))return;let L=p.closest("tr[data-id]");if(!L)return;let C=P.sessions.get(L.dataset.id);C&&A(C)}),a.addEventListener("change",()=>{let c=E().filter(p=>p.status!=="closed");for(let p of c)a.checked?f.add(p.sessionId):f.delete(p.sessionId);v()}),I.addEventListener("click",()=>{f.clear(),v()}),w.addEventListener("click",async()=>{let c=[...f];if(c.length===0||!confirm(n("sessions.closeBulkConfirm",{count:c.length})))return;w.disabled=!0,I.disabled=!0;let p=w.textContent,h=0,L=0,C=[...c];w.textContent=`0/${c.length}`;async function R(){for(;C.length;){let q=C.shift();try{let O=await fetch(`/api/sessions/${encodeURIComponent(q)}/close`,{method:"POST"}),H=await O.json().catch(()=>({}));(!O.ok||H?.ok===!1)&&(L+=1)}catch{L+=1}finally{h+=1,w.textContent=`${h}/${c.length}`}}}await Promise.all(Array.from({length:Math.min(6,c.length)},()=>R())),w.textContent=p,w.disabled=!1,I.disabled=!1,f.clear(),v(),L>0&&alert(`Failed: ${L}/${c.length}`)}),T.querySelectorAll("th[data-sort]").forEach(c=>{c.addEventListener("click",()=>{let p=c.dataset.sort;g===p?l=l==="asc"?"desc":"asc":(g=p,l=p==="spawnedAt"||p==="lastMessageAt"?"desc":"asc"),v()})}),o.addEventListener("input",v),P.on(v),v()}function Kt(){return`<section class="page">
|
|
142
142
|
<div class="page-heading">
|
|
143
143
|
<div>
|
|
144
144
|
<p class="eyebrow">${n("nav.schedules")}</p>
|
|
@@ -163,7 +163,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
163
163
|
</tr></thead>
|
|
164
164
|
<tbody id="schedules-tbody"></tbody>
|
|
165
165
|
</table>
|
|
166
|
-
</section>`}function et(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function tt(e){e.innerHTML=Kt();let t=e.querySelector("#schedules-tbody"),o=e.querySelector("#sched-filters");function r(){let s=new FormData(o),d=(s.get("q")??"").toLowerCase(),w=s.get("kind"),I=!!s.get("enabled");return[...
|
|
166
|
+
</section>`}function et(e){if(!e)return"\u2014";try{return new Date(e).toLocaleString()}catch{return e}}function tt(e){e.innerHTML=Kt();let t=e.querySelector("#schedules-tbody"),o=e.querySelector("#sched-filters");function r(){let s=new FormData(o),d=(s.get("q")??"").toLowerCase(),w=s.get("kind"),I=!!s.get("enabled");return[...P.schedules.values()].filter(T=>!w||T.parsed?.kind===w).filter(T=>!I||T.enabled).filter(T=>!d||JSON.stringify(T).toLowerCase().includes(d)).sort((T,f)=>{if(T.enabled!==f.enabled)return T.enabled?-1:1;let g=T.nextRunAt?Date.parse(T.nextRunAt):1/0,l=f.nextRunAt?Date.parse(f.nextRunAt):1/0;return g-l})}function a(){t.innerHTML=r().map(s=>`<tr data-id="${m(s.id)}">
|
|
167
167
|
<td>${m(s.name??s.id)}</td>
|
|
168
168
|
<td>${m(s.botName??s.larkAppId??"-")}</td>
|
|
169
169
|
<td><code>${m(s.parsed?.display??"?")}</code></td>
|
|
@@ -175,7 +175,7 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
175
175
|
<button data-op="run" type="button">${n("schedules.runNow")}</button>
|
|
176
176
|
${s.enabled?`<button data-op="pause" type="button">${n("schedules.pause")}</button>`:`<button data-op="resume" type="button">${n("schedules.resume")}</button>`}
|
|
177
177
|
</td>
|
|
178
|
-
</tr>`).join("")||`<tr><td colspan="8" class="empty">${n("schedules.empty")}</td></tr>`}t.addEventListener("click",async s=>{let d=s.target.closest("button[data-op]");if(!d)return;let w=d.closest("tr[data-id]");if(!w)return;let I=w.dataset.id,
|
|
178
|
+
</tr>`).join("")||`<tr><td colspan="8" class="empty">${n("schedules.empty")}</td></tr>`}t.addEventListener("click",async s=>{let d=s.target.closest("button[data-op]");if(!d)return;let w=d.closest("tr[data-id]");if(!w)return;let I=w.dataset.id,T=d.dataset.op;d.disabled=!0;let f=d.textContent;d.textContent="...";try{let g=await fetch(`/api/schedules/${encodeURIComponent(I)}/${T}`,{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{d.disabled=!1,d.textContent=f}}),o.addEventListener("input",a),P.on(a),a()}var F={chats:[],bots:[]};function Vt(){return`<section class="page">
|
|
179
179
|
<div class="page-heading">
|
|
180
180
|
<div>
|
|
181
181
|
<p class="eyebrow">${n("nav.groups")}</p>
|
|
@@ -194,12 +194,12 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
194
194
|
<tbody id="g-body"></tbody>
|
|
195
195
|
</table>
|
|
196
196
|
<dialog id="g-drawer"></dialog>
|
|
197
|
-
</section>`}async function ie(){
|
|
197
|
+
</section>`}async function ie(){F=await(await fetch("/api/groups")).json()}async function Yt(){return(await fetch("/api/groups")).json()}function Qt(e,t){if(t.size===0)return!0;let o=e?.memberBots??[];for(let r of t)if(!o.some(a=>a.larkAppId===r&&a.inChat))return!1;return!0}function nt(e,t){return e.filter(o=>!t||!t.has(o.larkAppId)).map(o=>`
|
|
198
198
|
<label class="checkbox-row">
|
|
199
199
|
<input type="checkbox" name="bot" value="${m(o.larkAppId)}">
|
|
200
200
|
${m(o.botName??o.larkAppId)} <small>(${m(o.larkAppId)})</small>
|
|
201
201
|
</label>
|
|
202
|
-
`).join("")}async function ot(e){e.innerHTML=Vt();let t=e.querySelector("#g-head"),o=e.querySelector("#g-body"),r=e.querySelector("#g-filters"),a=e.querySelector("#g-refresh"),s=e.querySelector("#g-drawer");a.onclick=async()=>{a.disabled=!0;try{await ie(),f()}finally{a.disabled=!1}};let d=e.querySelector("#g-create");d.onclick=()=>w(),await ie();function w(){let l=
|
|
202
|
+
`).join("")}async function ot(e){e.innerHTML=Vt();let t=e.querySelector("#g-head"),o=e.querySelector("#g-body"),r=e.querySelector("#g-filters"),a=e.querySelector("#g-refresh"),s=e.querySelector("#g-drawer");a.onclick=async()=>{a.disabled=!0;try{await ie(),f()}finally{a.disabled=!1}};let d=e.querySelector("#g-create");d.onclick=()=>w(),await ie();function w(){let l=F.bots;if(l.length===0){alert(n("groups.noBotsOnline"));return}s.innerHTML=`
|
|
203
203
|
<article>
|
|
204
204
|
<header><h3>${n("groups.createTitle")}</h3></header>
|
|
205
205
|
<p>${n("groups.createHelp")}</p>
|
|
@@ -222,45 +222,45 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
222
222
|
<button type="button" id="g-create-cancel">${n("groups.cancel")}</button>
|
|
223
223
|
</div>
|
|
224
224
|
</form>
|
|
225
|
-
</article>`,s.showModal(),s.querySelector("#g-create-cancel").onclick=()=>s.close(),s.querySelector("#g-createform").onsubmit=async b=>{b.preventDefault();let u=new FormData(b.target),$=(u.get("name")??"").trim(),k=(u.get("bindWorkingDir")??"").trim(),v=u.getAll("bot");if(v.length===0){alert("Pick at least one bot.");return}let A=b.target.querySelector("button[type=submit]");A&&(A.disabled=!0,A.textContent="Creating...");try{let c=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:$||void 0,larkAppIds:v,bindWorkingDir:k||void 0})}),p=await c.json();if(p.ok&&p.chatId){I(p);let h=Array.isArray(p.invalidBotIds)?p.invalidBotIds:[],
|
|
225
|
+
</article>`,s.showModal(),s.querySelector("#g-create-cancel").onclick=()=>s.close(),s.querySelector("#g-createform").onsubmit=async b=>{b.preventDefault();let u=new FormData(b.target),$=(u.get("name")??"").trim(),k=(u.get("bindWorkingDir")??"").trim(),v=u.getAll("bot");if(v.length===0){alert("Pick at least one bot.");return}let A=b.target.querySelector("button[type=submit]");A&&(A.disabled=!0,A.textContent="Creating...");try{let c=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:$||void 0,larkAppIds:v,bindWorkingDir:k||void 0})}),p=await c.json();if(p.ok&&p.chatId){I(p);let h=Array.isArray(p.invalidBotIds)?p.invalidBotIds:[],L=v.filter(R=>!h.includes(R)),C=new Set(L);typeof p.creator=="string"&&p.creator&&C.add(p.creator),S(p.chatId,$||p.chatId,L,p.creator),f(),E(p.chatId,C).catch(()=>{})}else alert(`Failed: ${p.error??c.status}`),s.close()}catch(c){alert("Network error: "+c),s.close()}};function S(b,u,$,k){let v=new Set($);k&&v.add(k);let A=F.bots.map(p=>({larkAppId:p.larkAppId,botName:p.botName,inChat:v.has(p.larkAppId),oncallChat:null})),c={chatId:b,name:u,ownerId:k??null,memberBots:A};F.chats=[c,...F.chats.filter(p=>p.chatId!==b)]}async function E(b,u){let $=[600,1200,1200,1200,1200,1200];for(let k of $){await new Promise(c=>setTimeout(c,k));let v;try{v=await Yt()}catch{continue}let A=(v.chats??[]).find(c=>c.chatId===b);if(A&&Qt(A,u)){F=v,f();return}}}}function I(l){let S=String(l.chatId),E=`https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(S)}`,b=l.invalidBotIds??[],u=l.invalidUserIds??[],$=l.autoInvitedOpenId,k=!!l.autoInviteRejected,v=l.ownerTransferredTo,A=l.transferError,c=l.notifyMessageId,p=l.notifyError,h=Array.isArray(l.oncallBindings)?l.oncallBindings:[],L=h.filter(H=>H?.ok).length,C=h.filter(H=>!H?.ok),R=h.length>0?C.length===0?`<p class="hint-ok">\u5DF2\u7ED1\u5B9A\u76EE\u5F55\uFF1A<code>${m(l.bindResolvedPath??"")}</code>\uFF08${L}/${h.length} bots\uFF09</p>`:`<p class="hint-warn">\u76EE\u5F55\u7ED1\u5B9A\u90E8\u5206\u5931\u8D25\uFF1A\u6210\u529F ${L}/${h.length}\u3002${C.map(H=>`<br><code>${m(H.larkAppId??"?")}</code>: ${m(H.error??"unknown")}`).join("")}</p>`:"",q;if($){let H=v?"<br><small>\u7FA4\u4E3B\u5DF2\u4ECE\u673A\u5668\u4EBA\u8F6C\u8BA9\u7ED9\u4F60\u3002</small>":A?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08${m(A)}\uFF09\uFF0C\u4F60\u73B0\u5728\u662F\u6210\u5458\u4F46\u7FA4\u4E3B\u4ECD\u662F\u673A\u5668\u4EBA\u3002</small>`:"",B=c?`<br><small>\u673A\u5668\u4EBA\u5DF2\u5728\u7FA4\u91CC @ \u4E86\u4F60\uFF08\u6D88\u606F id <code>${m(c)}</code>\uFF09\uFF0C\u770B\u98DE\u4E66\u901A\u77E5\u5C31\u80FD\u8FDB\u7FA4\u3002</small>`:p?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8 @ \u901A\u77E5\u5931\u8D25\uFF08${m(p)}\uFF09\uFF0C\u65B0\u7FA4\u53EF\u80FD\u4E0D\u4F1A\u4E3B\u52A8\u51FA\u73B0\u5728\u4F60\u4FA7\u8FB9\u680F\uFF0C\u5EFA\u8BAE\u4ECE\u4E0B\u9762\u6309\u94AE\u8DF3\u8FDB\u53BB\u3002</small>`:"";q=`<p class="hint-ok">\u5DF2\u81EA\u52A8\u9080\u8BF7\u4F60\uFF08<code>${m($)}</code>\uFF09\u4F5C\u4E3A\u6210\u5458\u3002${H}${B}</p>`}else k?q='<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>':q='<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(m).join(", ")}</code></li>`:"",u.length?`<li>\u65E0\u6548\u7528\u6237 open_id: <code>${u.map(m).join(", ")}</code></li>`:""].filter(Boolean).join("");s.innerHTML=`
|
|
226
226
|
<article>
|
|
227
227
|
<header><h3>${n("groups.successTitle")}</h3></header>
|
|
228
228
|
<p><b>chatId:</b> <code>${m(S)}</code> <button type="button" data-copy="${m(S)}">${n("sessions.copy")}</button></p>
|
|
229
229
|
<p><b>\u521B\u5EFA\u8005:</b> <code>${m(l.creator??"?")}</code></p>
|
|
230
|
-
${
|
|
230
|
+
${q}
|
|
231
231
|
${R}
|
|
232
|
-
${
|
|
232
|
+
${O?`<ul>${O}</ul>`:""}
|
|
233
233
|
<div class="actions">
|
|
234
234
|
<a class="btn-link primary" href="${E}" target="_blank" rel="noopener">${n("groups.openGroup")}</a>
|
|
235
235
|
<button type="button" id="g-create-close">${n("sessions.dismiss")}</button>
|
|
236
236
|
</div>
|
|
237
|
-
</article>`,s.querySelectorAll("[data-copy]").forEach(
|
|
237
|
+
</article>`,s.querySelectorAll("[data-copy]").forEach(H=>{H.onclick=()=>{navigator.clipboard.writeText(H.dataset.copy??""),H.textContent=n("sessions.copied"),setTimeout(()=>{H.textContent=n("sessions.copy")},800)}}),s.querySelector("#g-create-close").onclick=()=>s.close()}function T(){t.innerHTML=`<tr>
|
|
238
238
|
<th>${n("groups.chat")}</th>
|
|
239
|
-
${
|
|
239
|
+
${F.bots.map(l=>`<th>${m(l.botName??l.larkAppId)}</th>`).join("")}
|
|
240
240
|
<th>${n("groups.actions")}</th>
|
|
241
|
-
</tr>`}function f(){
|
|
241
|
+
</tr>`}function f(){T();let l=new FormData(r),S=(l.get("q")??"").toLowerCase(),E=!!l.get("missing"),b=F.chats.filter(u=>!S||(u.name??"").toLowerCase().includes(S)||u.chatId.toLowerCase().includes(S)||(u.ownerId??"").toLowerCase().includes(S)).filter(u=>!E||u.memberBots.some($=>!$.inChat));if(b.length===0){o.innerHTML=`<tr><td colspan="${F.bots.length+2}" class="empty">${n("groups.empty")}</td></tr>`;return}o.innerHTML=b.map(u=>`<tr data-chat="${m(u.chatId)}">
|
|
242
242
|
<td>
|
|
243
243
|
<strong>${m(u.name??u.chatId)}</strong><br>
|
|
244
244
|
<small><code>${m(u.chatId)}</code></small>
|
|
245
245
|
</td>
|
|
246
|
-
${
|
|
246
|
+
${F.bots.map($=>{let k=u.memberBots.find(c=>c.larkAppId===$.larkAppId),v=k?k.error?"!":k.inChat?"\u2713":"\u2717":"?";return`<td class="${k?k.error?"cell-error":k.inChat?"cell-in":"cell-out":"cell-unknown"}" title="${m(k?.error??"")}">${v}</td>`}).join("")}
|
|
247
247
|
<td>
|
|
248
248
|
<button class="add-bots" type="button">${n("groups.addBots")}</button>
|
|
249
249
|
<button class="manage-chat" type="button">${n("groups.manage")}</button>
|
|
250
250
|
</td>
|
|
251
|
-
</tr>`).join("")}f(),o.addEventListener("click",async l=>{let S=l.target.closest("button.add-bots");if(!S)return;let b=S.closest("tr[data-chat]").dataset.chat,u=
|
|
251
|
+
</tr>`).join("")}f(),o.addEventListener("click",async l=>{let S=l.target.closest("button.add-bots");if(!S)return;let b=S.closest("tr[data-chat]").dataset.chat,u=F.chats.find(v=>v.chatId===b);if(!u)return;let $=new Set(u.memberBots.filter(v=>v.inChat).map(v=>v.larkAppId));if(!F.bots.filter(v=>!$.has(v.larkAppId)).length){alert("All configured bots are already in this chat.");return}s.innerHTML=`
|
|
252
252
|
<article>
|
|
253
253
|
<header><h3>${n("groups.addBots")} \xB7 ${m(u.name??u.chatId)}</h3></header>
|
|
254
254
|
<p>${n("groups.createHelp")}</p>
|
|
255
255
|
<form id="g-addform">
|
|
256
|
-
${nt(
|
|
256
|
+
${nt(F.bots,$)}
|
|
257
257
|
<div class="actions">
|
|
258
258
|
<button type="submit" class="primary">${n("groups.addBots")}</button>
|
|
259
259
|
<button type="button" id="g-cancel">${n("groups.cancel")}</button>
|
|
260
260
|
</div>
|
|
261
261
|
</form>
|
|
262
|
-
</article>`,s.showModal(),s.querySelector("#g-cancel").onclick=()=>s.close(),s.querySelector("#g-addform").onsubmit=async v=>{v.preventDefault();let c=new FormData(v.target).getAll("bot");if(c.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:c})})).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
|
|
263
|
-
`);alert(
|
|
262
|
+
</article>`,s.showModal(),s.querySelector("#g-cancel").onclick=()=>s.close(),s.querySelector("#g-addform").onsubmit=async v=>{v.preventDefault();let c=new FormData(v.target).getAll("bot");if(c.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:c})})).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 L=h.result.map(C=>`${C.id}: ${C.ok?"OK":`failed (${C.error??"unknown"})`}`).join(`
|
|
263
|
+
`);alert(L),await ie(),f()}else alert(`Unexpected response: ${JSON.stringify(h)}`)}catch(p){alert("Network error: "+p)}finally{s.close()}}}),o.addEventListener("click",async l=>{let S=l.target.closest("button.manage-chat");if(!S)return;let b=S.closest("tr[data-chat]").dataset.chat,u=F.chats.find($=>$.chatId===b);u&&g(u)});function g(l){let S=l.memberBots.filter(b=>b.inChat),E=typeof l.ownerId=="string"?l.ownerId:"";s.innerHTML=`
|
|
264
264
|
<article>
|
|
265
265
|
<header><h3>${n("groups.manageTitle",{name:l.name??l.chatId})}</h3></header>
|
|
266
266
|
<p><b>chatId:</b> <code>${m(l.chatId)}</code></p>
|
|
@@ -303,14 +303,14 @@ effects={effects}, activities={activities}, waits={waits}, cancels={cancels}`,"w
|
|
|
303
303
|
</div>
|
|
304
304
|
<p class="hint-warn"><small>${n("groups.dangerHint")}</small></p>
|
|
305
305
|
<form method="dialog"><button>${n("sessions.dismiss")}</button></form>
|
|
306
|
-
</article>`,s.showModal(),s.querySelectorAll(".oncall-row").forEach(b=>{let u=b.dataset.bot,$=b.querySelector("input[data-action=toggle]"),k=b.querySelector("input[data-input=workingDir]"),v=b.querySelector("button[data-action=save]"),A=b.querySelector("[data-status]");$.addEventListener("change",()=>{k.disabled=!$.checked,$.checked&&k.focus()}),v.addEventListener("click",async()=>{A.textContent="",A.className="oncall-status";let c=$.checked,p=k.value.trim();if(c&&!p){A.textContent=n("groups.needWorkingDir"),A.classList.add("hint-warn-inline");return}v.disabled=!0;try{let h=`/api/groups/${encodeURIComponent(l.chatId)}/oncall/${encodeURIComponent(u)}`,
|
|
307
|
-
`);alert(k||`Unexpected: ${JSON.stringify($)}`),await ie(),f()}catch(u){alert("Network error: "+u)}finally{s.close()}},s.querySelector("#g-disband-btn").onclick=async()=>{if(S.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=[...S].sort(($,k)=>(k.larkAppId===E?1:0)-($.larkAppId===E?1:0)),u=[];for(let $ of b)try{let k=await fetch(`/api/groups/${encodeURIComponent(l.chatId)}/disband`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppId:$.larkAppId})}),v=await k.json();if(v.ok){let A=v.closedSessions??[],c=A.filter(
|
|
306
|
+
</article>`,s.showModal(),s.querySelectorAll(".oncall-row").forEach(b=>{let u=b.dataset.bot,$=b.querySelector("input[data-action=toggle]"),k=b.querySelector("input[data-input=workingDir]"),v=b.querySelector("button[data-action=save]"),A=b.querySelector("[data-status]");$.addEventListener("change",()=>{k.disabled=!$.checked,$.checked&&k.focus()}),v.addEventListener("click",async()=>{A.textContent="",A.className="oncall-status";let c=$.checked,p=k.value.trim();if(c&&!p){A.textContent=n("groups.needWorkingDir"),A.classList.add("hint-warn-inline");return}v.disabled=!0;try{let h=`/api/groups/${encodeURIComponent(l.chatId)}/oncall/${encodeURIComponent(u)}`,L=c?await fetch(h,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({workingDir:p})}):await fetch(h,{method:"DELETE"}),C=await L.json().catch(()=>({}));if(L.ok&&C.ok){A.textContent=c?`\u2713 \u5DF2\u7ED1\u5B9A \u2192 ${C.resolvedPath??p}`:"\u2713 \u5DF2\u89E3\u7ED1",A.classList.add("hint-ok");try{await ie(),f()}catch{}}else A.textContent=`\u2717 ${C.error??L.status}`,A.classList.add("hint-warn-inline")}catch(h){A.textContent=`\u2717 ${h?.message??h}`,A.classList.add("hint-warn-inline")}finally{v.disabled=!1}})}),s.querySelector("#g-leave-btn").onclick=async()=>{let b=[...s.querySelectorAll("input[name=leave-bot]:checked")].map(u=>u.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 $=await(await fetch(`/api/groups/${encodeURIComponent(l.chatId)}/leave`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:b})})).json(),k=($.result??[]).map(v=>{if(!v.ok)return`${v.larkAppId}: \u5931\u8D25 (${v.error??"unknown"})`;let A=v.closedSessions??[],c=A.filter(L=>!L.ok).length,p=A.length-c,h=A.length===0?"":c===0?`\uFF08\u5173\u95ED ${p} \u4E2A\u4F1A\u8BDD\uFF09`:`\uFF08\u5173\u95ED ${p} \u4E2A\uFF0C${c} \u4E2A\u5931\u8D25\uFF09`;return`${v.larkAppId}: OK${h}`}).join(`
|
|
307
|
+
`);alert(k||`Unexpected: ${JSON.stringify($)}`),await ie(),f()}catch(u){alert("Network error: "+u)}finally{s.close()}},s.querySelector("#g-disband-btn").onclick=async()=>{if(S.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=[...S].sort(($,k)=>(k.larkAppId===E?1:0)-($.larkAppId===E?1:0)),u=[];for(let $ of b)try{let k=await fetch(`/api/groups/${encodeURIComponent(l.chatId)}/disband`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppId:$.larkAppId})}),v=await k.json();if(v.ok){let A=v.closedSessions??[],c=A.filter(L=>!L.ok).length,p=A.length-c,h=A.length===0?"":c===0?`
|
|
308
308
|
\u5173\u95ED\u4E86 ${p} \u4E2A\u4F1A\u8BDD\u3002`:`
|
|
309
309
|
\u5173\u95ED\u4E86 ${p} \u4E2A\u4F1A\u8BDD\uFF0C${c} \u4E2A\u4F1A\u8BDD\u5173\u95ED\u5931\u8D25\u3002`;alert(`\u5DF2\u89E3\u6563\uFF08\u7531 ${$.botName??$.larkAppId} \u6267\u884C\uFF09${h}`),await ie(),f(),s.close();return}u.push(`${$.botName??$.larkAppId}: ${v.error??k.status}`)}catch(k){u.push(`${$.botName??$.larkAppId}: ${k}`)}alert(`\u6240\u6709\u5728\u7FA4\u673A\u5668\u4EBA\u5747\u65E0\u6CD5\u89E3\u6563\uFF1A
|
|
310
310
|
${u.join(`
|
|
311
311
|
`)}
|
|
312
312
|
|
|
313
|
-
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}r.addEventListener("input",f)}var
|
|
313
|
+
\u5EFA\u8BAE\u6539\u7528\u300C\u9000\u51FA\u7FA4\u804A\u300D\u3002`)}}r.addEventListener("input",f)}var ne={bots:[]},le=null;function Xt(){return`<section class="page">
|
|
314
314
|
<div class="page-heading">
|
|
315
315
|
<div>
|
|
316
316
|
<p class="eyebrow">${n("nav.botDefaults")}</p>
|
|
@@ -323,7 +323,7 @@ ${u.join(`
|
|
|
323
323
|
<button type="button" id="bd-refresh">${n("botDefaults.refresh")}</button>
|
|
324
324
|
</form>
|
|
325
325
|
<div id="bd-list"></div>
|
|
326
|
-
</section>`}async function at(){try{let e=await fetch("/api/bots"),t=await e.json().catch(()=>({}));if(!e.ok){le=t?.error?`HTTP ${e.status}: ${t.error}${t.path?` (${t.path})`:""}`:`HTTP ${e.status}`,
|
|
326
|
+
</section>`}async function at(){try{let e=await fetch("/api/bots"),t=await e.json().catch(()=>({}));if(!e.ok){le=t?.error?`HTTP ${e.status}: ${t.error}${t.path?` (${t.path})`:""}`:`HTTP ${e.status}`,ne={bots:[]};return}if(!t||!Array.isArray(t.bots)){le="unexpected response shape (no `bots` array)",ne={bots:[]};return}le=null,ne=t}catch(e){le=e?.message??String(e),ne={bots:[]}}}function st(e){if(!e)return"\u2014";let t=new Date(e);return Number.isNaN(t.getTime())?"\u2014":t.toLocaleString()}async function rt(e){e.innerHTML=Xt();let t=e.querySelector("#bd-list"),o=e.querySelector("#bd-filters"),r=e.querySelector("#bd-refresh");r.onclick=async()=>{r.disabled=!0;try{await at(),a()}finally{r.disabled=!1}},await at();function a(){let g=(new FormData(o).get("q")??"").toLowerCase(),l=ne.bots.filter(S=>!g||(S.botName??"").toLowerCase().includes(g)||(S.larkAppId??"").toLowerCase().includes(g));if(le){t.innerHTML=`<p class="hint-warn">\u65E0\u6CD5\u52A0\u8F7D bot \u5217\u8868\uFF1A${m(le)}<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">${n("botDefaults.empty")}</p>`;return}t.innerHTML=l.map(s).join(""),T()}function s(f){if(f.error)return`<article class="bd-card" data-appid="${m(f.larkAppId)}">
|
|
327
327
|
<header><strong>${m(f.botName??f.larkAppId)}</strong>
|
|
328
328
|
<small>${m(f.larkAppId)}</small></header>
|
|
329
329
|
<p class="hint-warn-inline">\u67E5\u8BE2\u5931\u8D25\uFF1A${m(f.error)}</p>
|
|
@@ -377,7 +377,7 @@ ${u.join(`
|
|
|
377
377
|
<span class="oncall-status" data-brand-status></span>
|
|
378
378
|
</div>
|
|
379
379
|
</div>
|
|
380
|
-
</section>`}function I(f){let g=f.disableStreamingCard===!0,l=f.writableTerminalLinkInCard===!0;return`<section class="bd-section">
|
|
380
|
+
</section>`}function I(f){let g=f.disableStreamingCard===!0,l=f.writableTerminalLinkInCard===!0,S=f.privateCard===!0;return`<section class="bd-section">
|
|
381
381
|
<h3 class="bd-section-title">${n("botDefaults.sectionCard")}</h3>
|
|
382
382
|
<label class="checkbox-row">
|
|
383
383
|
<input type="checkbox" data-action="toggle-disable-streaming" ${g?"checked":""}>
|
|
@@ -389,11 +389,16 @@ ${u.join(`
|
|
|
389
389
|
<strong>${n("botDefaults.writableLink")}</strong>
|
|
390
390
|
<small>${n("botDefaults.writableLinkHelp")}</small>
|
|
391
391
|
</label>
|
|
392
|
+
<label class="checkbox-row">
|
|
393
|
+
<input type="checkbox" data-action="toggle-private-card" ${S?"checked":""}>
|
|
394
|
+
<strong>${n("botDefaults.privateCard")}</strong>
|
|
395
|
+
<small>${n("botDefaults.privateCardHelp")}</small>
|
|
396
|
+
</label>
|
|
392
397
|
<div class="actions">
|
|
393
398
|
<small data-card-pref-moot class="hint-warn-inline" ${g?"":"hidden"}>${n("botDefaults.writableLinkMoot")}</small>
|
|
394
399
|
<span class="oncall-status" data-card-pref-status></span>
|
|
395
400
|
</div>
|
|
396
|
-
</section>`}function
|
|
401
|
+
</section>`}function T(){t.querySelectorAll(".bd-card").forEach(f=>{let g=f.dataset.appid,l=f.querySelector("input[data-action=toggle]"),S=f.querySelector("input[data-input=workingDir]"),E=f.querySelector("button[data-action=save]"),b=f.querySelector("[data-status]");if(!l||!S||!E||!b)return;l.addEventListener("change",()=>{S.disabled=!l.checked,l.checked&&S.focus()}),E.addEventListener("click",async()=>{b.textContent="",b.className="oncall-status";let O=l.checked,H=S.value.trim();if(O&&!H){b.textContent=n("botDefaults.required"),b.classList.add("hint-warn-inline");return}E.disabled=!0;try{let B=await fetch(`/api/bots/${encodeURIComponent(g)}/default-oncall`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({enabled:O,workingDir:H})}),N=await B.json().catch(()=>({}));if(B.ok&&N.ok){let U=N.resolvedPath?` \u2192 ${N.resolvedPath}`:"";b.textContent=O?`\u2713 \u5DF2\u5F00\u542F${U}\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 W=ne.bots.find(Q=>Q.larkAppId===g);W&&N.defaultOncall&&(W.defaultOncall=N.defaultOncall);let Y=f.querySelector(".bd-meta small:first-child");Y&&N.defaultOncall?.since!=null&&(Y.textContent=`\u4E0A\u6B21\u542F\u7528\u65F6\u95F4\uFF1A${st(N.defaultOncall.since)}`)}else b.textContent=`\u2717 ${N.error??B.status}`,b.classList.add("hint-warn-inline")}catch(B){b.textContent=`\u2717 ${B?.message??B}`,b.classList.add("hint-warn-inline")}finally{E.disabled=!1}});let u=f.querySelector("input[data-input=brandLabel]"),$=f.querySelector("button[data-action=save-brand]"),k=f.querySelector("button[data-action=reset-brand]"),v=f.querySelector("[data-brand-status]"),A=f.querySelector("[data-brand-state]");async function c(O,H){if(v){v.textContent="",v.className="oncall-status",H.disabled=!0;try{let B=await fetch(`/api/bots/${encodeURIComponent(g)}/brand-label`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({brandLabel:O})}),N=await B.json().catch(()=>({}));if(B.ok&&N.ok){let U=N.brandLabel??null;v.textContent="\u2713",v.classList.add("hint-ok"),u&&(u.value=U??""),A&&(A.textContent=d(U));let W=ne.bots.find(Y=>Y.larkAppId===g);W&&(W.brandLabel=U)}else v.textContent=`\u2717 ${N.error??B.status}`,v.classList.add("hint-warn-inline")}catch(B){v.textContent=`\u2717 ${B?.message??B}`,v.classList.add("hint-warn-inline")}finally{H.disabled=!1}}}u&&$&&$.addEventListener("click",()=>c(u.value,$)),k&&k.addEventListener("click",()=>c(null,k));let p=f.querySelector("input[data-action=toggle-disable-streaming]"),h=f.querySelector("input[data-action=toggle-writable-link]"),L=f.querySelector("input[data-action=toggle-private-card]"),C=f.querySelector("[data-card-pref-status]"),R=f.querySelector("[data-card-pref-moot]");async function q(O,H){if(C){C.textContent="",C.className="oncall-status",H.disabled=!0;try{let B=await fetch(`/api/bots/${encodeURIComponent(g)}/card-prefs`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(O)}),N=await B.json().catch(()=>({}));if(B.ok&&N.ok){C.textContent=`\u2713 ${n("botDefaults.cardPrefSaved")}`,C.classList.add("hint-ok");let U=ne.bots.find(W=>W.larkAppId===g);U&&(U.disableStreamingCard=N.disableStreamingCard,U.writableTerminalLinkInCard=N.writableTerminalLinkInCard,U.privateCard=N.privateCard)}else C.textContent=`\u2717 ${N.error??B.status}`,C.classList.add("hint-warn-inline")}catch(B){C.textContent=`\u2717 ${B?.message??B}`,C.classList.add("hint-warn-inline")}finally{H===h?H.disabled=!!p?.checked:H.disabled=!1}}}p&&p.addEventListener("change",()=>{let O=p.checked;h&&(h.disabled=O),R&&(R.hidden=!O),q({disableStreamingCard:O},p)}),h&&h.addEventListener("change",()=>{q({writableTerminalLinkInCard:h.checked},h)}),L&&L.addEventListener("change",()=>{q({privateCard:L.checked},L)})})}a(),o.addEventListener("input",a)}var xe=4096,ke=[],z=null,K=null,_="",de=new Set;function Zt(){return`<section class="page roles-page">
|
|
397
402
|
<div class="page-heading">
|
|
398
403
|
<div>
|
|
399
404
|
<p class="eyebrow">${n("nav.roles")}</p>
|
|
@@ -432,8 +437,8 @@ ${u.join(`
|
|
|
432
437
|
</div>
|
|
433
438
|
</div>
|
|
434
439
|
</div>
|
|
435
|
-
</section>`}async function ye(){ke=((await(await fetch("/api/groups")).json()).chats??[]).map(o=>({chatId:o.chatId,name:o.name??o.chatId,memberBots:(o.memberBots??[]).map(r=>({larkAppId:r.larkAppId,botName:r.botName??r.larkAppId,inChat:r.inChat??!1,hasRole:r.hasRole??!1,oncallChat:r.oncallChat??null}))}))}async function lt(e,t){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)).json()}async function en(e,t,o){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({content:o})})).ok}async function tn(e,t){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{method:"DELETE"})).ok}function dt(e){return e.memberBots.filter(t=>t.inChat&&t.hasRole).length}function nn(e){return e.memberBots.filter(t=>t.inChat).length}function
|
|
436
|
-
<div class="roles-bot-row ${
|
|
440
|
+
</section>`}async function ye(){ke=((await(await fetch("/api/groups")).json()).chats??[]).map(o=>({chatId:o.chatId,name:o.name??o.chatId,memberBots:(o.memberBots??[]).map(r=>({larkAppId:r.larkAppId,botName:r.botName??r.larkAppId,inChat:r.inChat??!1,hasRole:r.hasRole??!1,oncallChat:r.oncallChat??null}))}))}async function lt(e,t){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`)).json()}async function en(e,t,o){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({content:o})})).ok}async function tn(e,t){return(await fetch(`/api/roles/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,{method:"DELETE"})).ok}function dt(e){return e.memberBots.filter(t=>t.inChat&&t.hasRole).length}function nn(e){return e.memberBots.filter(t=>t.inChat).length}function se(e=""){let t=document.getElementById("roles-tree");if(!t)return;let o=e.toLowerCase(),r=ke.filter(a=>{if(!o)return!0;let s=a.chatId.toLowerCase().includes(o)||(a.name??"").toLowerCase().includes(o),d=a.memberBots.some(w=>w.larkAppId.toLowerCase().includes(o)||(w.botName??"").toLowerCase().includes(o));return s||d});if(r.length===0){t.innerHTML=`<div class="roles-empty">${n("roles.noChats")}</div>`;return}t.innerHTML=r.map(a=>{let s=de.has(a.chatId),d=a.memberBots.filter(g=>g.inChat),w=s?"\u25BE":"\u25B8",I=dt(a),T=nn(a),f=s?d.map(g=>`
|
|
441
|
+
<div class="roles-bot-row ${z===a.chatId&&K===g.larkAppId?"selected":""}"
|
|
437
442
|
data-group-id="${m(a.chatId)}"
|
|
438
443
|
data-bot-id="${m(g.larkAppId)}">
|
|
439
444
|
<span class="roles-bot-indent"></span>
|
|
@@ -447,20 +452,20 @@ ${u.join(`
|
|
|
447
452
|
</span>
|
|
448
453
|
</div>`).join(""):"";return`
|
|
449
454
|
<div class="roles-group-section">
|
|
450
|
-
<div class="roles-group-row ${s?"expanded":""} ${
|
|
455
|
+
<div class="roles-group-row ${s?"expanded":""} ${z===a.chatId&&!K?"selected":""}"
|
|
451
456
|
data-group-id="${m(a.chatId)}">
|
|
452
457
|
<span class="roles-group-arrow">${w}</span>
|
|
453
458
|
<span class="roles-group-icon">\u{1F4C1}</span>
|
|
454
459
|
<div class="roles-group-info">
|
|
455
460
|
<div class="roles-group-name">${m(a.name??a.chatId)}</div>
|
|
456
461
|
<div class="roles-group-meta">
|
|
457
|
-
${I}/${
|
|
462
|
+
${I}/${T} ${n("roles.botsWithRoles")}
|
|
458
463
|
</div>
|
|
459
464
|
</div>
|
|
460
465
|
<span class="roles-group-chevron"></span>
|
|
461
466
|
</div>
|
|
462
467
|
<div class="roles-bot-list">${f}</div>
|
|
463
|
-
</div>`}).join(""),t.querySelectorAll(".roles-group-row").forEach(a=>{a.addEventListener("click",()=>{let s=a.dataset.groupId;s&&(de.has(s)?de.delete(s):de.add(s),
|
|
468
|
+
</div>`}).join(""),t.querySelectorAll(".roles-group-row").forEach(a=>{a.addEventListener("click",()=>{let s=a.dataset.groupId;s&&(de.has(s)?de.delete(s):de.add(s),se(document.getElementById("roles-search")?.value??""))})}),t.querySelectorAll(".roles-bot-row").forEach(a=>{a.addEventListener("click",s=>{s.stopPropagation();let d=a.dataset.groupId,w=a.dataset.botId;d&&w&&on(d,w)})})}async function on(e,t){z=e,K=t;let o=await lt(t,e),r=document.getElementById("roles-editor-empty"),a=document.getElementById("roles-editor-form"),s=document.getElementById("roles-editor-textarea"),d=document.getElementById("roles-editor-group-name"),w=document.getElementById("roles-editor-bot-name"),I=document.getElementById("roles-editor-chat-id");r&&(r.style.display="none"),a&&(a.style.display="");let T=ke.find(l=>l.chatId===e),f=T?.memberBots.find(l=>l.larkAppId===t);d&&(d.textContent=T?.name??e),w&&(w.textContent=f?.botName??t),I&&(I.textContent=`${e} \xB7 ${t}`),_=o.content??"",s&&(s.value=_,s.focus()),Oe(),Be(),se(document.getElementById("roles-search")?.value??"");let g=document.getElementById("roles-delete");g&&(g.style.display=o.hasRole?"":"none")}function Oe(){let e=document.getElementById("roles-editor-bytecount");if(!e)return;let t=new TextEncoder().encode(_).length;e.textContent=`${t} / ${xe} bytes`,e.className=`roles-bytecount ${t>3800?"warn":""} ${t>xe?"over":""}`,an(t)}function an(e){let t=document.getElementById("roles-save");if(!t)return;let o=e??new TextEncoder().encode(_).length;t.disabled=o>xe||_.trim().length===0}function Be(){let e=document.getElementById("roles-preview");e&&(_.trim()?e.innerHTML=`<strong>${n("roles.preview")}</strong><pre>${m(_)}</pre>`:e.innerHTML=`<small>${n("roles.previewEmpty")}</small>`)}function it(){z=null,K=null,_="";let e=document.getElementById("roles-editor-empty"),t=document.getElementById("roles-editor-form"),o=document.getElementById("roles-editor-textarea"),r=document.getElementById("roles-delete");e&&(e.style.display=""),t&&(t.style.display="none"),o&&(o.value=""),r&&(r.style.display="none")}async function ct(e){e.innerHTML=Zt(),de.clear(),it(),await ye();for(let t of ke)dt(t)>0&&de.add(t.chatId);se(),document.getElementById("roles-search")?.addEventListener("input",t=>{se(t.target.value)}),document.getElementById("roles-refresh")?.addEventListener("click",async()=>{if(await ye(),se(document.getElementById("roles-search")?.value??""),z&&K){let t=await lt(K,z),o=document.getElementById("roles-editor-textarea");o&&(o.value=t.content??""),_=t.content??"",Oe(),Be();let r=document.getElementById("roles-delete");r&&(r.style.display=t.hasRole?"":"none")}}),document.getElementById("roles-save")?.addEventListener("click",async function(){if(!(!z||!K)){this.disabled=!0,this.textContent="...";try{if(await en(K,z,_)){await ye(),se(document.getElementById("roles-search")?.value??"");let o=document.getElementById("roles-delete");o&&(o.style.display="");let r=document.createElement("span");r.className="roles-saved-flash",r.textContent=` ${n("roles.saved")}`,document.querySelector(".roles-editor-footer")?.appendChild(r),setTimeout(()=>r.remove(),2e3)}else{let o=document.createElement("span");o.className="roles-saved-flash roles-save-error",o.textContent=_.trim().length===0?` ${n("roles.emptyError")}`:` ${n("roles.saveFailed")}`,document.querySelector(".roles-editor-footer")?.appendChild(o),setTimeout(()=>o.remove(),3e3)}}finally{this.disabled=!1,this.textContent=n("roles.save")}}}),document.getElementById("roles-delete")?.addEventListener("click",async function(){if(!(!z||!K)&&confirm(n("roles.confirmDelete"))){this.disabled=!0,this.textContent="...";try{await tn(K,z)&&(await ye(),it(),se(document.getElementById("roles-search")?.value??""))}finally{this.disabled=!1,this.textContent=n("roles.delete")}}}),document.getElementById("roles-editor-textarea")?.addEventListener("input",t=>{_=t.target.value,Oe(),Be()})}function sn(){let e=[["",n("workflow.filter.nonTerminal")],["all",n("workflow.filter.all")],["pending",oe("pending")],["running",oe("running")],["waiting",oe("waiting")],["succeeded",oe("succeeded")],["failed",oe("failed")],["cancelled",oe("cancelled")]];return`
|
|
464
469
|
<nav class="wf-subnav">
|
|
465
470
|
<a href="#/workflows" class="active" data-i18n="workflow.subnav.runs">${i(n("workflow.subnav.runs"))}</a>
|
|
466
471
|
<a href="#/workflows/catalog" data-i18n="workflow.subnav.catalog">${i(n("workflow.subnav.catalog"))}</a>
|
|
@@ -480,10 +485,10 @@ ${u.join(`
|
|
|
480
485
|
</tr></thead>
|
|
481
486
|
<tbody id="wf-tbody"></tbody>
|
|
482
487
|
</table>
|
|
483
|
-
`}var rn=5e3,ln=2e3,fe=new Set(["succeeded","failed","cancelled"]);function i(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function dn(e){let t=new Date(e),r=Date.now()-e;return r<6e4?n("time.secondsAgo",{value:Math.max(1,Math.floor(r/1e3))}):r<36e5?n("time.minutesAgo",{value:Math.floor(r/6e4)}):r<864e5?n("time.hoursAgo",{value:Math.floor(r/36e5)}):t.toISOString().slice(0,19).replace("T"," ")}function
|
|
488
|
+
`}var rn=5e3,ln=2e3,fe=new Set(["succeeded","failed","cancelled"]);function i(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}function dn(e){let t=new Date(e),r=Date.now()-e;return r<6e4?n("time.secondsAgo",{value:Math.max(1,Math.floor(r/1e3))}):r<36e5?n("time.minutesAgo",{value:Math.floor(r/6e4)}):r<864e5?n("time.hoursAgo",{value:Math.floor(r/36e5)}):t.toISOString().slice(0,19).replace("T"," ")}function X(e){return`<span class="${fe.has(e)?"wf-status terminal":"wf-status live"} wf-status-${i(e)}">${i(oe(e))}</span>`}function oe(e){let t=`workflow.status.${e}`,o=n(t);return o===t?e:o}function mt(e){let t=location.hash.match(/^#\/workflows\/([^?#]+)(?:\?([^#]*))?$/);if(t){let o=new URLSearchParams(t[2]??"");return un(e,decodeURIComponent(t[1]),{focusAttemptId:o.get("attempt")??void 0})}return cn(e)}function cn(e){e.innerHTML=sn();let t=e.querySelector("#wf-tbody"),o=e.querySelector("#wf-filters"),r=e.querySelector("#wf-last-load"),a=[],s=null,d=!1,w=null,I=!1;function T(b){let $=(new FormData(o).get("q")??"").trim().toLowerCase();return $?b.filter(k=>k.runId.toLowerCase().includes($)||k.workflowId.toLowerCase().includes($)||(k.chatId??"").toLowerCase().includes($)):b}function f(){let b=T(a);if(b.length===0){t.innerHTML=`<tr><td colspan="7" class="empty">${w?i(n("workflow.list.failedLoad",{error:w})):a.length===0?i(n("workflow.list.noRuns")):i(n("workflow.list.noFilterMatch"))}</td></tr>`;return}t.innerHTML=b.map(u=>{let $=`${u.dEf}/${u.dAct}/${u.dWait}`,k=u.dEf+u.dAct+u.dWait>0?"wf-dangling has":"wf-dangling none",v=[];u.chatId&&v.push(i(u.chatId)),u.larkAppId&&v.push(`<span class="muted">${i(u.larkAppId)}</span>`);let A=v.length>0?v.join("<br/>"):"\u2014",c=pn(u);return`<tr data-runid="${i(u.runId)}">
|
|
484
489
|
<td><a href="#/workflows/${encodeURIComponent(u.runId)}"><code>${i(u.runId)}</code></a></td>
|
|
485
490
|
<td>${i(u.workflowId)}</td>
|
|
486
|
-
<td>${
|
|
491
|
+
<td>${X(u.status)}${u.failedNodeId?` <span class="muted">(${i(u.failedNodeId)})</span>`:""}${c}</td>
|
|
487
492
|
<td>${u.lastSeq}</td>
|
|
488
493
|
<td class="${k}">${$}</td>
|
|
489
494
|
<td title="${i(new Date(u.updatedAt).toISOString())}">${dn(u.updatedAt)}</td>
|
|
@@ -544,54 +549,54 @@ ${u.join(`
|
|
|
544
549
|
</div>
|
|
545
550
|
<div id="wf-event-meta" class="muted"></div>
|
|
546
551
|
</section>
|
|
547
|
-
`;let r=e.querySelector("#wf-detail-subtitle"),a=e.querySelector("#wf-detail-refresh"),s=e.querySelector("#wf-detail-error"),d=e.querySelector("#wf-cancel-status"),w=e.querySelector("#wf-summary"),I=e.querySelector("#wf-dangling-panel"),
|
|
552
|
+
`;let r=e.querySelector("#wf-detail-subtitle"),a=e.querySelector("#wf-detail-refresh"),s=e.querySelector("#wf-detail-error"),d=e.querySelector("#wf-cancel-status"),w=e.querySelector("#wf-summary"),I=e.querySelector("#wf-dangling-panel"),T=e.querySelector("#wf-parallel-view"),f=e.querySelector("#wf-parallel-meta"),g=e.querySelector("#wf-node-tbody"),l=e.querySelector("#wf-io-list"),S=e.querySelector(".wf-timeline-scroll"),E=e.querySelector("#wf-event-tbody"),b=e.querySelector("#wf-event-meta"),u=e.querySelector("#wf-cancel-run"),$=e.querySelector("#wf-load-older"),k=null,v=[],A=new Set,c=null,p=null,h=!1,L=0,C=null,R=!1,q=!1,O=!1,H=new Set,B=new Map,N=new Map,U=new Map,W=new Set,Y=new Map,Q=new Set,ce=new Map,At=new Map,je=0,Ue=o.focusAttemptId;function J(y){if(!y){s.hidden=!0,s.textContent="";return}s.hidden=!1,s.textContent=y}function Fe(y){if(!y){d.hidden=!0,d.textContent="";return}d.hidden=!1,d.textContent=y}async function We(){let y=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/snapshot`);if(y.status===404)throw new Error(n("workflow.detail.unknownRun"));if(!y.ok)throw new Error(n("workflow.detail.snapshotHttp",{status:y.status}));k=await y.json()}async function ge(y){let j=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/events?${y}`);if(j.status===404)throw new Error(n("workflow.detail.unknownRun"));if(!j.ok)throw new Error(n("workflow.detail.eventsHttp",{status:j.status}));return await j.json()}function he(y,j){let x=y.filter(D=>A.has(D.eventId)?!1:(A.add(D.eventId),!0));x.length!==0&&(v=j==="prepend"?[...x,...v]:[...v,...x],v.sort((D,Z)=>pe(D.eventId)-pe(Z.eventId)))}async function Ht(){await We();let y=await ge(new URLSearchParams({tail:"100"}));v=[],A=new Set,he(y.events,"append"),c=y.oldestSeq,p=y.newestSeq,h=y.hasOlder,L=y.totalCount,G()}async function be(){if(!(R||q||document.hidden)){q=!0;try{if(await We(),p!==null){let y=await ge(new URLSearchParams({afterSeq:String(p),limit:"200"}));he(y.events,"append"),y.newestSeq!==null&&(p=y.newestSeq),c===null&&y.oldestSeq!==null&&(c=y.oldestSeq),L=y.totalCount}else{let y=await ge(new URLSearchParams({tail:"1"}));he(y.events,"append"),c=y.oldestSeq,p=y.newestSeq,h=y.hasOlder,L=y.totalCount}J(null),G()}catch(y){J(y?.message??String(y))}finally{q=!1}}}async function Rt(){if(!(c===null||!h)){$.disabled=!0;try{let y=await ge(new URLSearchParams({beforeSeq:String(c),limit:"100"}));he(y.events,"prepend"),y.oldestSeq!==null&&(c=y.oldestSeq),h=y.hasOlder,L=y.totalCount,J(null),G()}catch(y){J(y?.message??String(y))}finally{$.disabled=!1}}}async function Dt(){if(!k||fe.has(k.run.status)||O)return;if(!k.chatBinding?.larkAppId){J(n("workflow.detail.cancelUnavailable",{runId:t}));return}let y=mn(k),j=n("workflow.detail.cancelConfirm",{runId:t,...y});if(window.confirm(j)){O=!0,u.disabled=!0;try{let x=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/cancel`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"cancelled via dashboard"})});if(x.status===401)throw new Error(n("workflow.detail.writeAccessCancel"));let D=await x.json().catch(()=>({}));if(!x.ok||!D.ok)throw new Error(D.hint??D.error??n("workflow.detail.cancelHttp",{status:x.status}));Fe(D.pending?n("workflow.detail.cancelPending"):null),J(null),await be()}catch(x){J(x?.message??String(x))}finally{O=!1,u.disabled=!1,G()}}}async function xt(y,j){if(!Q.has(y)){Q.add(y),ce.delete(y),G();try{let x=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/attempts/${encodeURIComponent(j)}/${encodeURIComponent(y)}/resume`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});if(x.status===401)throw new Error(n("workflow.detail.writeAccessResume"));let D=await x.json().catch(()=>({}));if(!x.ok||!D.ok||!D.resumeId||!D.url)throw new Error(D.hint??D.message??D.error??n("workflow.detail.resumeStartFailed",{status:x.status}));Y.set(y,{resumeId:D.resumeId,url:D.url})}catch(x){let D=x?.message??String(x);ce.set(y,D)}finally{Q.delete(y),G()}}}async function Ot(y,j){if(!Q.has(y)){Q.add(y),ce.delete(y),G();try{let x=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/attempts/${encodeURIComponent(j)}/${encodeURIComponent(y)}/resume/end`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"ended_by_dashboard"})});if(x.status===401)throw new Error(n("workflow.detail.writeAccessResume"));let D=await x.json().catch(()=>({}));if(!x.ok||!D.ok)if(D.error==="resume_not_running")Y.delete(y);else throw new Error(D.hint??D.message??D.error??n("workflow.detail.resumeEndFailed",{status:x.status}));else Y.delete(y)}catch(x){let D=x?.message??String(x);ce.set(y,D)}finally{Q.delete(y),G()}}}async function Bt(y,j){if(!W.has(y)){W.add(y),U.delete(y),G();try{let x=N.get(y)?.trim()||void 0,D=await fetch(`/api/workflows/runs/${encodeURIComponent(t)}/${j}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({comment:x})});if(D.status===401)throw new Error(n("workflow.detail.writeAccessApproval"));let Z=await D.json().catch(()=>({}));if(!D.ok||!Z.ok)throw new Error(Z.hint??Z.message??Z.error??n("workflow.detail.actionHttp",{action:j,status:D.status}));let Ce=j==="approve"?n("workflow.detail.approved"):n("workflow.detail.rejected");U.set(y,{kind:"ok",text:Z.alreadyTerminal?n("workflow.detail.alreadyTerminal",{label:Ce}):Z.pending?n("workflow.detail.workflowContinue",{label:Ce}):n("workflow.detail.workflowRefreshing",{label:Ce})}),J(null),await be()}catch(x){let D=x?.message??String(x);U.set(y,{kind:"error",text:D}),J(D)}finally{W.delete(y),G()}}}function G(){if(!k)return;je=S.scrollTop;let y=k.run;fe.has(y.status)&&Fe(null),r.innerHTML=`${i(y.workflowId??"?")} \xB7 ${X(y.status)} \xB7 lastSeq ${k.lastSeq}`,a.textContent=n("workflow.detail.refreshed",{time:new Date().toLocaleTimeString()}),u.hidden=fe.has(y.status),u.disabled=O||!k.chatBinding?.larkAppId,u.textContent=k.chatBinding?.larkAppId?n("workflow.detail.cancel"):n("workflow.detail.cliCancelOnly"),u.title=k.chatBinding?.larkAppId?n("workflow.detail.cancelTitle"):n("workflow.detail.cliCancelTitle",{runId:t}),fn(w,k),wn(I,k),gn(T,f,k,v),$n(g,k),Sn(l,k,H,B,{comments:N,statuses:U,resolving:W,onResolve:Bt},{sessions:Y,pending:Q,errors:ce,onStart:xt,onEnd:Ot},Ue,At)&&(Ue=void 0),Vn(E,v),S.scrollTop=je,$.hidden=!h,b.textContent=n("workflow.detail.eventsLoaded",{loaded:v.length,total:L})}function Ee(){if(C!==null&&window.clearTimeout(C),k&&fe.has(k.run.status)){C=null;return}C=window.setTimeout(async()=>{await be(),R||Ee()},ln)}function _e(){document.hidden||be().then(()=>{!R&&C===null&&Ee()})}return $.addEventListener("click",()=>{Rt()}),u.addEventListener("click",()=>{Dt()}),document.addEventListener("visibilitychange",_e),Ht().then(()=>{J(null),R||Ee()}).catch(y=>{J(y?.message??String(y)),r.textContent=n("workflow.detail.loadFailed")}),()=>{R=!0,C!==null&&window.clearTimeout(C),document.removeEventListener("visibilitychange",_e)}}function fn(e,t){let o=t.run,r=[[n("workflow.summary.workflow"),i(o.workflowId??"?")],[n("workflow.summary.status"),X(o.status)],[n("workflow.summary.lastSeq"),String(t.lastSeq)],[n("workflow.summary.updated"),i(new Date(t.updatedAt).toLocaleString())],[n("workflow.summary.revision"),i(Ie(o.revisionId))],[n("workflow.summary.initiator"),i(o.initiator??"-")]];o.failedNodeId&&r.push([n("workflow.summary.failedNode"),i(o.failedNodeId)]),o.cancelOriginEventId&&r.push([n("workflow.summary.cancelOrigin"),i(o.cancelOriginEventId)]),t.chatBinding&&(r.push([n("workflow.summary.chat"),`<code>${i(t.chatBinding.chatId)}</code>`]),r.push([n("workflow.summary.app"),`<code>${i(t.chatBinding.larkAppId)}</code>`])),e.innerHTML=r.map(([a,s])=>`<div class="wf-summary-item"><span>${a}</span><strong>${s}</strong></div>`).join("")}function pn(e){if(!e.errorCode)return"";let t=e.errorMessage?` \u2014 ${Zn(e.errorMessage,96)}`:"";return`<div class="wf-run-error">
|
|
548
553
|
<span class="muted error">${i(e.errorCode)}</span>${i(t)}
|
|
549
554
|
</div>`}function mn(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 wn(e,t){let o=t.dangling,r=[[n("workflow.dangling.activities"),o.activities],[n("workflow.dangling.effects"),o.effectAttempted],[n("workflow.dangling.waits"),o.waits],[n("workflow.dangling.cancels"),o.cancels]],a=new Set(r.flatMap(([,s])=>s)).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>${i(n("workflow.detail.dangling"))}</h3></div><div class="muted">${i(n("workflow.detail.noDangling"))}</div>`;return}e.innerHTML=`<div class="wf-panel-title"><h3>${i(n("workflow.detail.dangling"))}</h3><span class="wf-dangling has">${a}</span></div>
|
|
550
555
|
<div class="wf-dangling-grid">
|
|
551
556
|
${r.map(([s,d])=>`<div><strong>${s}</strong>${d.length===0?`<div class="muted">${i(n("workflow.detail.none"))}</div>`:`<ul>${d.map(w=>`<li><code>${i(w)}</code></li>`).join("")}</ul>`}</div>`).join("")}
|
|
552
|
-
</div>`}function gn(e,t,o,r){let a=hn(r,o);if(a.length===0){t.textContent="",e.innerHTML=`<div class="empty">${i(n("workflow.detail.noParallelData"))}</div>`;return}let s=Date.now(),d=Math.min(...a.map(l=>l.startedAt)),w=Math.max(...a.map(l=>l.endedAt??s),d+1e3),I=Math.max(1,w-d),
|
|
557
|
+
</div>`}function gn(e,t,o,r){let a=hn(r,o);if(a.length===0){t.textContent="",e.innerHTML=`<div class="empty">${i(n("workflow.detail.noParallelData"))}</div>`;return}let s=Date.now(),d=Math.min(...a.map(l=>l.startedAt)),w=Math.max(...a.map(l=>l.endedAt??s),d+1e3),I=Math.max(1,w-d),T=vn(a,s),f=a.filter(l=>!l.endedAt&&(l.status==="running"||l.status==="effectAttempting")).length;t.textContent=n("workflow.detail.parallelMeta",{count:a.length,max:T,running:f});let g=a.sort((l,S)=>l.startedAt-S.startedAt||l.activityId.localeCompare(S.activityId)).map(l=>bn(l,d,I,s)).join("");e.innerHTML=`<div class="wf-parallel-axis">
|
|
553
558
|
<span title="${i(new Date(d).toISOString())}">${i(Se(d))}</span>
|
|
554
559
|
<span title="${i(new Date(w).toISOString())}">${i(Se(w))}</span>
|
|
555
560
|
</div>
|
|
556
|
-
<div class="wf-parallel-list">${g}</div>`}function hn(e,t){let o=new Map,r=new Map(t.activities.map(a=>[a.activityId,a.ownerNodeId]));for(let a of[...e].sort((s,d)=>pe(s.eventId)-pe(d.eventId))){let s=Xn(a);if(!s)continue;let d=typeof s.activityId=="string"?s.activityId:void 0,w=typeof s.attemptId=="string"?s.attemptId:void 0;if(!d||!w)continue;let I=o.get(w);if(a.type==="attemptCreated"){let
|
|
561
|
+
<div class="wf-parallel-list">${g}</div>`}function hn(e,t){let o=new Map,r=new Map(t.activities.map(a=>[a.activityId,a.ownerNodeId]));for(let a of[...e].sort((s,d)=>pe(s.eventId)-pe(d.eventId))){let s=Xn(a);if(!s)continue;let d=typeof s.activityId=="string"?s.activityId:void 0,w=typeof s.attemptId=="string"?s.attemptId:void 0;if(!d||!w)continue;let I=o.get(w);if(a.type==="attemptCreated"){let T=typeof s.attemptNumber=="number"?s.attemptNumber:void 0;I={nodeId:typeof s.nodeId=="string"?s.nodeId:r.get(d),activityId:d,attemptId:w,attemptNumber:T,status:"pending",startedAt:a.timestamp},o.set(w,I);continue}I||(I={nodeId:r.get(d),activityId:d,attemptId:w,status:"pending",startedAt:a.timestamp},o.set(w,I)),a.type==="activityRunning"?(I.status="running",I.runningAt=a.timestamp):a.type==="effectAttempted"?I.status="effectAttempting":a.type==="activityWaiting"||a.type==="waitCreated"?I.status="waiting":yn(a.type)&&(I.status=kn(a.type),I.endedAt=a.timestamp,I.endType=a.type)}return[...o.values()]}function bn(e,t,o,r){let a=e.endedAt??r,s=pt((e.startedAt-t)/o*100,0,100),d=pt((Math.max(a,e.startedAt+1)-e.startedAt)/o*100,.7,100-s),w=e.nodeId??e.activityId,I=e.attemptNumber!==void 0?`#${e.attemptNumber}`:Ie(e.attemptId),T=[`${w} ${e.status}`,`${new Date(e.startedAt).toISOString()} \u2192 ${e.endedAt?new Date(e.endedAt).toISOString():n("workflow.detail.parallelNow")}`,e.endType?`end: ${e.endType}`:void 0].filter(Boolean).join(`
|
|
557
562
|
`);return`<div class="wf-parallel-row">
|
|
558
563
|
<div class="wf-parallel-label">
|
|
559
564
|
<code>${i(w)}</code>
|
|
560
565
|
<span class="muted">${i(e.activityId)} \xB7 ${i(I)}</span>
|
|
561
566
|
</div>
|
|
562
567
|
<div class="wf-parallel-track">
|
|
563
|
-
<div class="wf-parallel-bar wf-parallel-${i(e.status)}" style="left:${s.toFixed(3)}%;width:${d.toFixed(3)}%;" title="${i(
|
|
564
|
-
<span>${i(
|
|
568
|
+
<div class="wf-parallel-bar wf-parallel-${i(e.status)}" style="left:${s.toFixed(3)}%;width:${d.toFixed(3)}%;" title="${i(T)}">
|
|
569
|
+
<span>${i(oe(e.status))}</span>
|
|
565
570
|
</div>
|
|
566
571
|
</div>
|
|
567
572
|
</div>`}function vn(e,t){let o=[];for(let s of e)o.push({time:s.startedAt,delta:1}),o.push({time:s.endedAt??t,delta:-1});o.sort((s,d)=>s.time-d.time||d.delta-s.delta);let r=0,a=0;for(let s of o)r+=s.delta,a=Math.max(a,r);return a}function yn(e){return e==="activitySucceeded"||e==="activityFailed"||e==="activityTimedOut"||e==="activityCanceled"}function kn(e){return e==="activitySucceeded"?"succeeded":e==="activityCanceled"?"cancelled":e==="activityTimedOut"?"timedOut":"failed"}function $n(e,t){let o=new Map(t.activities.map(s=>[s.activityId,s])),r=new Set,a=[];for(let s of t.nodes){let d=(s.activityId?o.get(s.activityId):void 0)??t.activities.find(w=>w.ownerNodeId===s.nodeId);d&&r.add(d.activityId),a.push(ut(s,d))}for(let s of t.activities)r.has(s.activityId)||a.push(ut(void 0,s));e.innerHTML=a.length>0?a.join(""):`<tr><td colspan="7" class="empty">${i(n("workflow.detail.noNodes"))}</td></tr>`}function ut(e,t){let o=t?.attempts[t.attempts.length-1];return`<tr>
|
|
568
573
|
<td>${e?`<code>${i(e.nodeId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
569
|
-
<td>${e?
|
|
574
|
+
<td>${e?X(e.status):'<span class="muted">-</span>'}</td>
|
|
570
575
|
<td>${t?`<code>${i(t.activityId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
571
|
-
<td>${t?
|
|
576
|
+
<td>${t?X(t.status):'<span class="muted">-</span>'}</td>
|
|
572
577
|
<td>${t?.attempts.length??0}</td>
|
|
573
578
|
<td>${o?`<code>${i(o.attemptId)}</code>`:'<span class="muted">-</span>'}</td>
|
|
574
579
|
<td>${o?Kn(o):`<span class="muted">${i(n("workflow.detail.idle"))}</span>`}</td>
|
|
575
|
-
</tr>`}function Sn(e,t,o,r,a,s,d,w){Fn(e,o,r),Pn(e,a.comments);let I=!!(d&&t.attemptIO?.[d]?.terminal);I&&d&&o.add(qe(d,n("workflow.detail.liveTerminal")));let
|
|
580
|
+
</tr>`}function Sn(e,t,o,r,a,s,d,w){Fn(e,o,r),Pn(e,a.comments);let I=!!(d&&t.attemptIO?.[d]?.terminal);I&&d&&o.add(qe(d,n("workflow.detail.liveTerminal")));let T=In(t),f=new Set;if(w){for(let l of T){f.add(l.key);let S=w.get(l.key);S||(S=Tn(l.key),w.set(l.key,S),e.appendChild(S.article)),Ln(S,l,o,a,s,d)}for(let[l,S]of Array.from(w))f.has(l)||(S.article.remove(),w.delete(l));if(T.length===0){if(!e.querySelector(".wf-io-empty-placeholder")){let l=document.createElement("div");l.className="empty wf-io-empty-placeholder",l.textContent=n("workflow.detail.noNodeIO"),e.appendChild(l)}}else e.querySelector(".wf-io-empty-placeholder")?.remove()}else{let l=[];for(let S of T)l.push(Hn(S,o,a,s,d));e.innerHTML=l.length>0?l.join(""):`<div class="empty">${i(n("workflow.detail.noNodeIO"))}</div>`}_n(e,r);let g=Un(e,d);return Wn(e,o),Jn(e,r),jn(e,a),St(e,s),g&&I}function In(e){let t=new Map(e.activities.map(a=>[a.activityId,a])),o=new Set,r=[];for(let a of e.nodes){let s=(a.activityId?t.get(a.activityId):void 0)??e.activities.find(d=>d.ownerNodeId===a.nodeId);if(!s){r.push({key:`node:${a.nodeId}`,node:a});continue}o.add(s.activityId),r.push({key:`activity:${s.activityId}`,node:a,activity:s,io:e.attemptIO?.[$e(s)?.attemptId??""]})}for(let a of e.activities)o.has(a.activityId)||r.push({key:`activity:${a.activityId}`,activity:a,io:e.attemptIO?.[$e(a)?.attemptId??""]});return r}function Tn(e){let t=document.createElement("article");t.className="wf-io-card",t.dataset.wfCardKey=e;let o=document.createElement("div");o.className="wf-io-card-head";let r=document.createElement("div");r.className="wf-io-terminal-slot";let a=document.createElement("div");return a.className="wf-io-grid",t.appendChild(o),t.appendChild(r),t.appendChild(a),{article:t,head:o,terminalSlot:r,grid:a,currentTerminalUrl:null}}function Ln(e,t,o,r,a,s){let d=$e(t.activity),w=t.node?.nodeId??t.activity?.ownerNodeId??t.activity?.activityId??"unknown",I=!!(d&&d.attemptId===s);e.article.classList.toggle("is-focused",I),d?e.article.dataset.wfAttemptCard=d.attemptId:delete e.article.dataset.wfAttemptCard;let T=$t(d,r);e.head.innerHTML=`
|
|
576
581
|
<header>
|
|
577
582
|
<div>
|
|
578
583
|
<strong><code>${i(w)}</code></strong>
|
|
579
584
|
<span class="muted">${t.activity?i(t.activity.activityId):i(n("workflow.detail.notDispatched"))}</span>
|
|
580
585
|
</div>
|
|
581
|
-
<div>${t.node?
|
|
586
|
+
<div>${t.node?X(t.node.status):""} ${t.activity?X(t.activity.status):""}</div>
|
|
582
587
|
</header>
|
|
583
588
|
<div class="wf-io-meta">
|
|
584
589
|
${d?`${i(n("workflow.detail.attempt"))} <code>${i(d.attemptId)}</code>`:i(n("workflow.detail.noAttempt"))}
|
|
585
590
|
</div>
|
|
586
|
-
${
|
|
591
|
+
${T}
|
|
587
592
|
`;let f=wt(d,t.activity,t.io?.terminal,a),g=f?.url??null;if(g!==e.currentTerminalUrl)f===null?e.terminalSlot.innerHTML="":e.terminalSlot.innerHTML=gt(t.key,d,t.activity,t.io?.terminal,f,o,a),e.currentTerminalUrl=g;else if(f!==null&&t.io?.terminal){let S=e.terminalSlot.querySelector("details.wf-terminal-block > summary");if(S){let E=ht(f.kind);S.innerHTML=`${i(E)} ${kt(d,t.io.terminal)}`}d&&Nn(e.terminalSlot,d,t.activity,t.io.terminal,f,a)}let l=d?.attemptId??t.activity?.activityId??t.node?.nodeId??"unknown";e.grid.innerHTML=`
|
|
588
|
-
${
|
|
589
|
-
${
|
|
590
|
-
${
|
|
591
|
-
${
|
|
592
|
-
${t.io?.waitPrompt?
|
|
593
|
-
`}function wt(e,t,o,r){if(!o||o.error)return null;if(Rn(e,o))return{kind:"live",url:xn(o)};if(!e||!t||!Dn(e,o))return null;let a=Bn();if(!a)return null;let s=r?.sessions.get(e.attemptId);return s?{kind:"resume",url:s.url,resumeId:s.resumeId,downloadUrl:ft(a,t.activityId,e.attemptId)}:{kind:"replay",url:On(a,t.activityId,e.attemptId,!!o.hasPtyLog),downloadUrl:ft(a,t.activityId,e.attemptId)}}function gt(e,t,o,r,a,s,d){if(!r)return"";let w=ht(a.kind),I=qe(e,w),
|
|
594
|
-
<summary>${i(w)} ${
|
|
593
|
+
${V(l,n("workflow.detail.authoredInput"),t.io?.input,o)}
|
|
594
|
+
${V(l,n("workflow.detail.resolvedInput"),t.io?.resolvedInput,o)}
|
|
595
|
+
${V(l,n("workflow.detail.output"),t.io?.output,o)}
|
|
596
|
+
${V(l,n("workflow.detail.executionLog"),t.io?.log,o)}
|
|
597
|
+
${t.io?.waitPrompt?V(l,n("workflow.detail.waitPrompt"),t.io.waitPrompt,o):""}
|
|
598
|
+
`}function wt(e,t,o,r){if(!o||o.error)return null;if(Rn(e,o))return{kind:"live",url:xn(o)};if(!e||!t||!Dn(e,o))return null;let a=Bn();if(!a)return null;let s=r?.sessions.get(e.attemptId);return s?{kind:"resume",url:s.url,resumeId:s.resumeId,downloadUrl:ft(a,t.activityId,e.attemptId)}:{kind:"replay",url:On(a,t.activityId,e.attemptId,!!o.hasPtyLog),downloadUrl:ft(a,t.activityId,e.attemptId)}}function gt(e,t,o,r,a,s,d){if(!r)return"";let w=ht(a.kind),I=qe(e,w),T=kt(t,r),f=En(a.kind),g=a.kind==="replay"||a.kind==="resume"?`<a class="btn-link" href="${i(a.downloadUrl)}" download>${i(n("workflow.detail.downloadFullLog"))}</a>`:"",l=t?vt(t,o,r,a,d):"",S=t?yt(t.attemptId,d):"";return`<details class="wf-io-block wf-terminal-block" data-io-key="${i(I)}"${s.has(I)?" open":""}>
|
|
599
|
+
<summary>${i(w)} ${T}</summary>
|
|
595
600
|
<div class="wf-terminal-actions">
|
|
596
601
|
<a class="btn-link" href="${i(a.url)}" target="_blank" rel="noreferrer">${i(f)}</a>
|
|
597
602
|
${g}
|
|
@@ -599,14 +604,14 @@ ${u.join(`
|
|
|
599
604
|
</div>
|
|
600
605
|
${S}
|
|
601
606
|
<iframe class="wf-terminal-frame" src="${i(a.url)}" title="${i(w)}" loading="lazy"></iframe>
|
|
602
|
-
</details>`}function ht(e){return e==="live"?n("workflow.detail.liveTerminal"):e==="resume"?n("workflow.detail.terminalResume"):n("workflow.detail.terminalReplay")}function En(e){return e==="live"?n("workflow.detail.openTerminalNewTab"):e==="resume"?n("workflow.detail.openResumeNewTab"):n("workflow.detail.openReplayNewTab")}var bt=new Set(["antigravity","codex-app","cursor","mira"]),Cn=new Set(["aiden","coco","claude-code","codex","mtr","hermes"]);function Mn(e){return!!e&&(Cn.has(e)||bt.has(e))}function An(e){return!!e&&bt.has(e)}function vt(e,t,o,r,a){if(!a||r.kind==="live"||!t)return"";let s=r.kind==="resume",d=a.pending.has(e.attemptId),w=`data-wf-resume-attempt="${i(e.attemptId)}" data-wf-resume-activity="${i(t.activityId)}"`;return s?`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="end" ${w}${d?" disabled":""}>${i(d?n("workflow.detail.resumeEnding"):n("workflow.detail.endResumeSession"))}</button>`:Mn(o.cliId)?An(o.cliId)&&!o.cliSessionId?`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${i(n("workflow.detail.resumeMissingCliSession"))}">${i(n("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="start" ${w}${d?" disabled":""}>${i(d?n("workflow.detail.resumeStarting"):n("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${i(n("workflow.detail.resumeUnsupportedCli",{cliId:o.cliId??"?"}))}">${i(n("workflow.detail.resumeSession"))}</button>`}function yt(e,t){if(!t)return"";let o=t.errors.get(e);return o?`<div class="hint-warn wf-resume-status" data-wf-resume-status="${i(e)}">${i(o)}</div>`:""}function Hn(e,t,o,r,a){let s=$e(e.activity),d=e.node?.nodeId??e.activity?.ownerNodeId??e.activity?.activityId??"unknown",w=s?.attemptId??e.activity?.activityId??e.node?.nodeId??"unknown",I=$t(s,o),
|
|
607
|
+
</details>`}function ht(e){return e==="live"?n("workflow.detail.liveTerminal"):e==="resume"?n("workflow.detail.terminalResume"):n("workflow.detail.terminalReplay")}function En(e){return e==="live"?n("workflow.detail.openTerminalNewTab"):e==="resume"?n("workflow.detail.openResumeNewTab"):n("workflow.detail.openReplayNewTab")}var bt=new Set(["antigravity","codex-app","cursor","mira"]),Cn=new Set(["aiden","coco","claude-code","codex","mtr","hermes"]);function Mn(e){return!!e&&(Cn.has(e)||bt.has(e))}function An(e){return!!e&&bt.has(e)}function vt(e,t,o,r,a){if(!a||r.kind==="live"||!t)return"";let s=r.kind==="resume",d=a.pending.has(e.attemptId),w=`data-wf-resume-attempt="${i(e.attemptId)}" data-wf-resume-activity="${i(t.activityId)}"`;return s?`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="end" ${w}${d?" disabled":""}>${i(d?n("workflow.detail.resumeEnding"):n("workflow.detail.endResumeSession"))}</button>`:Mn(o.cliId)?An(o.cliId)&&!o.cliSessionId?`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${i(n("workflow.detail.resumeMissingCliSession"))}">${i(n("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="start" ${w}${d?" disabled":""}>${i(d?n("workflow.detail.resumeStarting"):n("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${i(n("workflow.detail.resumeUnsupportedCli",{cliId:o.cliId??"?"}))}">${i(n("workflow.detail.resumeSession"))}</button>`}function yt(e,t){if(!t)return"";let o=t.errors.get(e);return o?`<div class="hint-warn wf-resume-status" data-wf-resume-status="${i(e)}">${i(o)}</div>`:""}function Hn(e,t,o,r,a){let s=$e(e.activity),d=e.node?.nodeId??e.activity?.ownerNodeId??e.activity?.activityId??"unknown",w=s?.attemptId??e.activity?.activityId??e.node?.nodeId??"unknown",I=$t(s,o),T=s?.attemptId===a?" is-focused":"",f=s?` data-wf-attempt-card="${i(s.attemptId)}"`:"",g=wt(s,e.activity,e.io?.terminal,r),l=g?gt(w,s,e.activity,e.io?.terminal,g,t,r):"";return`<article class="wf-io-card${T}" data-wf-card-key="${i(e.key)}"${f}>
|
|
603
608
|
<div class="wf-io-card-head">
|
|
604
609
|
<header>
|
|
605
610
|
<div>
|
|
606
611
|
<strong><code>${i(d)}</code></strong>
|
|
607
612
|
<span class="muted">${e.activity?i(e.activity.activityId):i(n("workflow.detail.notDispatched"))}</span>
|
|
608
613
|
</div>
|
|
609
|
-
<div>${e.node?
|
|
614
|
+
<div>${e.node?X(e.node.status):""} ${e.activity?X(e.activity.status):""}</div>
|
|
610
615
|
</header>
|
|
611
616
|
<div class="wf-io-meta">
|
|
612
617
|
${s?`${i(n("workflow.detail.attempt"))} <code>${i(s.attemptId)}</code>`:i(n("workflow.detail.noAttempt"))}
|
|
@@ -615,11 +620,11 @@ ${u.join(`
|
|
|
615
620
|
</div>
|
|
616
621
|
<div class="wf-io-terminal-slot">${l}</div>
|
|
617
622
|
<div class="wf-io-grid">
|
|
618
|
-
${
|
|
619
|
-
${
|
|
620
|
-
${
|
|
621
|
-
${
|
|
622
|
-
${e.io?.waitPrompt?
|
|
623
|
+
${V(w,n("workflow.detail.authoredInput"),e.io?.input,t)}
|
|
624
|
+
${V(w,n("workflow.detail.resolvedInput"),e.io?.resolvedInput,t)}
|
|
625
|
+
${V(w,n("workflow.detail.output"),e.io?.output,t)}
|
|
626
|
+
${V(w,n("workflow.detail.executionLog"),e.io?.log,t)}
|
|
627
|
+
${e.io?.waitPrompt?V(w,n("workflow.detail.waitPrompt"),e.io.waitPrompt,t):""}
|
|
623
628
|
</div>
|
|
624
629
|
</article>`}function $e(e){return e?.attempts[e.attempts.length-1]}function kt(e,t){let o=[];return t.error?o.push(n("workflow.detail.error")):o.push(t.status==="live"?n("workflow.detail.terminalLive"):n("workflow.detail.terminalClosedShort")),e?.status&&o.push(e.status),t.webPort>0&&o.push(`:${t.webPort}`),`<span class="muted">${i(o.join(" \xB7 "))}</span>`}function Rn(e,t){return t.status==="live"&&t.webPort>0&&(e?.status==="pending"||e?.status==="running"||e?.status==="effectAttempting")}function Dn(e,t){return e.status==="succeeded"||e.status==="failed"||e.status==="cancelled"||e.status==="timedOut"?!!(t.sessionId||t.startedAt):!1}function xn(e){return`http://${window.location.hostname||"127.0.0.1"}:${e.webPort}`}function On(e,t,o,r){let a=new URLSearchParams({runId:e,activityId:t,attemptId:o});return r&&a.set("hasPtyLog","1"),`/assets/terminal-replay.html?${a.toString()}`}function ft(e,t,o){return`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(t)}/${encodeURIComponent(o)}/terminal-log/raw?download=1`}function Bn(){let e=window.location.hash.match(/^#\/workflows\/([^/?#]+)/);if(!e)return null;try{return decodeURIComponent(e[1])}catch{return null}}function $t(e,t){if(!qn(e))return"";let o=e.attemptId,r=t.comments.get(o)??"",a=t.resolving.has(o),s=t.statuses.get(o),d=s?.kind==="error"?"hint-warn":"hint-ok";return`<div class="wf-approval-box" data-wf-approval="${i(o)}">
|
|
625
630
|
<label>
|
|
@@ -632,7 +637,7 @@ ${u.join(`
|
|
|
632
637
|
${a?`<span class="muted">${i(n("workflow.detail.submitting"))}</span>`:""}
|
|
633
638
|
</div>
|
|
634
639
|
${s?`<div class="${d} wf-approval-status">${i(s.text)}</div>`:""}
|
|
635
|
-
</div>`}function qn(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function Pn(e,t){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(o=>{let r=o.dataset.wfApprovalComment;r&&t.set(r,o.value)})}function St(e,t){e.querySelectorAll("button[data-wf-resume-action][data-wf-resume-attempt][data-wf-resume-activity]").forEach(o=>{o.dataset.wfResumeBound!=="1"&&(o.dataset.wfResumeBound="1",o.addEventListener("click",()=>{let r=o.dataset.wfResumeAttempt,a=o.dataset.wfResumeActivity,s=o.dataset.wfResumeAction;!r||!a||(s==="start"?t.onStart(r,a):s==="end"&&t.onEnd(r,a))}))})}function Nn(e,t,o,r,a,s){let d=e.querySelector(".wf-terminal-actions");if(!d)return;let w=d.querySelector('button[data-wf-resume-button="1"]'),I=vt(t,o,r,a,s);w?w.outerHTML=I:I&&d.insertAdjacentHTML("beforeend",I);let
|
|
640
|
+
</div>`}function qn(e){return!!e&&e.status==="waiting"&&e.wait?.waitKind==="human-gate"&&!e.wait.resolution}function Pn(e,t){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(o=>{let r=o.dataset.wfApprovalComment;r&&t.set(r,o.value)})}function St(e,t){e.querySelectorAll("button[data-wf-resume-action][data-wf-resume-attempt][data-wf-resume-activity]").forEach(o=>{o.dataset.wfResumeBound!=="1"&&(o.dataset.wfResumeBound="1",o.addEventListener("click",()=>{let r=o.dataset.wfResumeAttempt,a=o.dataset.wfResumeActivity,s=o.dataset.wfResumeAction;!r||!a||(s==="start"?t.onStart(r,a):s==="end"&&t.onEnd(r,a))}))})}function Nn(e,t,o,r,a,s){let d=e.querySelector(".wf-terminal-actions");if(!d)return;let w=d.querySelector('button[data-wf-resume-button="1"]'),I=vt(t,o,r,a,s);w?w.outerHTML=I:I&&d.insertAdjacentHTML("beforeend",I);let T=e.querySelector("details.wf-terminal-block");if(T){let f=T.querySelector(".wf-resume-status"),g=yt(t.attemptId,s);f?f.outerHTML=g:g&&d.insertAdjacentHTML("afterend",g)}St(e,s)}function jn(e,t){e.querySelectorAll("textarea[data-wf-approval-comment]").forEach(o=>{let r=o.dataset.wfApprovalComment;r&&o.addEventListener("input",()=>{t.comments.set(r,o.value)})}),e.querySelectorAll("button[data-wf-approval-action][data-wf-attempt-id]").forEach(o=>{o.addEventListener("click",()=>{let r=o.dataset.wfAttemptId,a=o.dataset.wfApprovalAction;!r||a!=="approve"&&a!=="reject"||t.onResolve(r,a)})})}function V(e,t,o,r){let a=qe(e,t);return`<details class="wf-io-block" data-io-key="${i(a)}"${r.has(a)?" open":""}>
|
|
636
641
|
<summary>${i(t)} ${Gn(o)}</summary>
|
|
637
642
|
${zn(o)}
|
|
638
643
|
</details>`}function qe(e,t){return`${e}:${t}`}function Un(e,t){if(!t)return!1;for(let o of e.querySelectorAll("[data-wf-attempt-card]"))if(o.dataset.wfAttemptCard===t)return o.scrollIntoView({block:"center"}),!0;return!1}function Fn(e,t,o){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(r=>{let a=r.dataset.ioKey;if(!a)return;r.open?t.add(a):t.delete(a);let s=r.querySelector(".wf-io-pre");s&&o.set(a,s.scrollTop)})}function Wn(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(o=>{o.dataset.ioToggleBound!=="1"&&(o.dataset.ioToggleBound="1",o.addEventListener("toggle",()=>{let r=o.dataset.ioKey;r&&(o.open?t.add(r):t.delete(r))}))})}function _n(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(o=>{let r=o.dataset.ioKey;if(!r)return;let a=t.get(r);if(a===void 0)return;let s=o.querySelector(".wf-io-pre");s&&(s.scrollTop=a)})}function Jn(e,t){e.querySelectorAll("details.wf-io-block[data-io-key]").forEach(o=>{let r=o.dataset.ioKey;if(!r)return;let a=o.querySelector(".wf-io-pre");a&&a.dataset.ioScrollBound!=="1"&&(a.dataset.ioScrollBound="1",a.addEventListener("scroll",()=>{t.set(r,a.scrollTop)}))})}function Gn(e){if(!e)return`<span class="muted">${i(n("workflow.detail.empty"))}</span>`;let t=[];return e.outputBytes!==void 0&&t.push(`${e.outputBytes}B`),e.truncated&&t.push(n("workflow.detail.truncated")),e.error&&t.push(n("workflow.detail.error")),e.outputHash&&t.push(Ie(e.outputHash)),t.length?`<span class="muted">${i(t.join(" \xB7 "))}</span>`:""}function zn(e){if(!e)return`<div class="muted wf-io-empty">${i(n("workflow.detail.noData"))}</div>`;let t=e.value!==void 0?JSON.stringify(e.value,null,2):e.text??"",o=e.error?`<div class="muted error">${i(e.error)}</div>`:"";return t?`${o}<pre class="wf-io-pre">${i(t)}</pre>`:`${o}<div class="muted wf-io-empty">${i(n("workflow.detail.noPreview"))}</div>`}function Kn(e){let t=[];if(e.effectAttempted&&t.push(`${i(n("workflow.detail.effect"))} ${i(e.effectAttempted.provider)}`),e.wait){let o=e.wait.resolution?`${e.wait.resolution.kind}${e.wait.resolution.resolution?":"+e.wait.resolution.resolution:""}`:n("workflow.detail.open");t.push(`${i(n("workflow.detail.wait"))} ${i(e.wait.waitKind)} ${i(o)}`),e.wait.deadlineAt!==void 0&&t.push(`${i(n("workflow.detail.deadline"))} ${i(Se(e.wait.deadlineAt))}`)}if(e.error){let o=`${e.error.errorCode}${e.error.errorClass?` \xB7 ${e.error.errorClass}`:""}`;t.push(`<span class="muted error">${i(o)}</span>`),e.error.errorMessage&&t.push(`<span class="error wf-error-msg">${i(e.error.errorMessage)}</span>`)}return e.output&&t.push(`${i(n("workflow.detail.output"))} ${i(Ie(e.output.outputHash))}`),e.runningMs!==void 0&&t.push(`${e.runningMs}ms`),t.length>0?t.join("<br/>"):'<span class="muted">-</span>'}function Vn(e,t){e.innerHTML=t.length>0?t.map(Yn).join(""):`<tr><td colspan="7" class="empty">${i(n("workflow.detail.noEvents"))}</td></tr>`}function Yn(e){let t=Qn(e.payload);return`<tr>
|
|
@@ -672,7 +677,7 @@ ${u.join(`
|
|
|
672
677
|
<tbody id="catalog-tbody"></tbody>
|
|
673
678
|
</table>
|
|
674
679
|
</div>
|
|
675
|
-
`;let t=e.querySelector("#catalog-tbody"),o=e.querySelector("#catalog-status"),r=e.querySelector("#catalog-filters"),a=e.querySelector("#catalog-refresh"),s=[],d=null,w=!1;function I(){let g=(new FormData(r).get("q")??"").trim().toLowerCase();return g?s.filter(l=>l.workflowId.toLowerCase().includes(g)||l.path.toLowerCase().includes(g)):s}function
|
|
680
|
+
`;let t=e.querySelector("#catalog-tbody"),o=e.querySelector("#catalog-status"),r=e.querySelector("#catalog-filters"),a=e.querySelector("#catalog-refresh"),s=[],d=null,w=!1;function I(){let g=(new FormData(r).get("q")??"").trim().toLowerCase();return g?s.filter(l=>l.workflowId.toLowerCase().includes(g)||l.path.toLowerCase().includes(g)):s}function T(){d?(o.textContent=n("catalog.loadFailed",{error:d}),o.classList.add("error")):(o.textContent=`${s.length}`,o.classList.remove("error"));let g=I();if(g.length===0){t.innerHTML=`<tr><td colspan="6" class="empty">${s.length===0?M(n("catalog.noDefinitions")):M(n("catalog.noFilterMatch"))}</td></tr>`;return}t.innerHTML=g.map(l=>`
|
|
676
681
|
<tr>
|
|
677
682
|
<td><a href="#/workflows/catalog/${encodeURIComponent(l.workflowId)}"><code>${M(l.workflowId)}</code></a></td>
|
|
678
683
|
<td>${l.version}</td>
|
|
@@ -681,7 +686,7 @@ ${u.join(`
|
|
|
681
686
|
<td><code>${M(It(l.revisionId))}</code></td>
|
|
682
687
|
<td><code>${M(l.path)}</code></td>
|
|
683
688
|
</tr>
|
|
684
|
-
`).join("")}async function f(){a.disabled=!0,o.textContent=n("catalog.loading");try{let g=await fetch("/api/workflows/definitions");if(!g.ok)throw new Error(`HTTP ${g.status}`);s=(await g.json()).definitions??[],d=null}catch(g){d=g?.message??String(g),s=[]}finally{a.disabled=!1,w||
|
|
689
|
+
`).join("")}async function f(){a.disabled=!0,o.textContent=n("catalog.loading");try{let g=await fetch("/api/workflows/definitions");if(!g.ok)throw new Error(`HTTP ${g.status}`);s=(await g.json()).definitions??[],d=null}catch(g){d=g?.message??String(g),s=[]}finally{a.disabled=!1,w||T()}}return r.addEventListener("input",T),a.addEventListener("click",()=>{f()}),f(),()=>{w=!0}}function to(e,t){e.innerHTML=`
|
|
685
690
|
<div class="catalog-detail-head">
|
|
686
691
|
<a class="btn-link" href="#/workflows/catalog">${M(n("catalog.back"))}</a>
|
|
687
692
|
<div>
|
|
@@ -692,7 +697,7 @@ ${u.join(`
|
|
|
692
697
|
<section id="catalog-error" class="hint-warn" hidden></section>
|
|
693
698
|
<section id="catalog-run-status" class="hint-ok" hidden></section>
|
|
694
699
|
<div id="catalog-detail-body"></div>
|
|
695
|
-
`;let o=e.querySelector("#catalog-detail-subtitle"),r=e.querySelector("#catalog-error"),a=e.querySelector("#catalog-run-status"),s=e.querySelector("#catalog-detail-body"),d=null,w=!1,I=!1;function
|
|
700
|
+
`;let o=e.querySelector("#catalog-detail-subtitle"),r=e.querySelector("#catalog-error"),a=e.querySelector("#catalog-run-status"),s=e.querySelector("#catalog-detail-body"),d=null,w=!1,I=!1;function T(u){r.hidden=!u,r.textContent=u??""}function f(u){a.hidden=!u,a.textContent=u??""}function g(u){let $={};for(let[k,v]of Object.entries(u??{}))"default"in v&&($[k]=v.default);return $}function l(){if(!d)return;let u=d.definition;o.textContent=`${n("catalog.revision")} ${It(d.revisionId)} \xB7 ${d.path}`;let $=JSON.stringify(g(u.params),null,2);s.innerHTML=`
|
|
696
701
|
<section class="wf-panel">
|
|
697
702
|
<div class="wf-panel-title"><h3>${M(n("catalog.summary"))}</h3></div>
|
|
698
703
|
<div class="wf-summary-grid">
|
|
@@ -735,7 +740,7 @@ ${u.join(`
|
|
|
735
740
|
<div class="wf-panel-title"><h3>${M(n("catalog.definitionJson"))}</h3></div>
|
|
736
741
|
<pre class="wf-io-pre">${M(JSON.stringify(u,null,2))}</pre>
|
|
737
742
|
</section>
|
|
738
|
-
`,E()}async function S(){if(!d||I)return;let u=s.querySelector("#catalog-params"),$=s.querySelector("#catalog-chat-id"),k=s.querySelector("#catalog-lark-app-id"),v=s.querySelector("#catalog-run-btn"),A=s.querySelector("#catalog-param-errors"),c;try{if(c=JSON.parse(u.value||"{}"),!c||typeof c!="object"||Array.isArray(c))throw new Error(n("catalog.badParamsJson"))}catch(p){A.hidden=!1,A.innerHTML=`<div class="muted error">${M(p?.message??String(p))}</div>`;return}I=!0,v.disabled=!0,v.textContent=n("catalog.running"),A.hidden=!0,
|
|
743
|
+
`,E()}async function S(){if(!d||I)return;let u=s.querySelector("#catalog-params"),$=s.querySelector("#catalog-chat-id"),k=s.querySelector("#catalog-lark-app-id"),v=s.querySelector("#catalog-run-btn"),A=s.querySelector("#catalog-param-errors"),c;try{if(c=JSON.parse(u.value||"{}"),!c||typeof c!="object"||Array.isArray(c))throw new Error(n("catalog.badParamsJson"))}catch(p){A.hidden=!1,A.innerHTML=`<div class="muted error">${M(p?.message??String(p))}</div>`;return}I=!0,v.disabled=!0,v.textContent=n("catalog.running"),A.hidden=!0,T(null),f(null);try{let p=await fetch(`/api/workflows/definitions/${encodeURIComponent(d.definition.workflowId)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({params:c,chatBinding:{chatId:$.value.trim(),larkAppId:k.value.trim()}})});if(p.status===401)throw new Error(n("catalog.writeAccess"));let h=await p.json().catch(()=>({}));if(!p.ok||!h.ok)throw h.issues?.length&&(A.hidden=!1,A.innerHTML=`<strong>${M(n("catalog.invalidParams"))}</strong><ul>${h.issues.map(L=>`<li>${M(n("catalog.issue",{path:L.path.length?L.path.join("."):"(root)",message:L.message}))}</li>`).join("")}</ul>`),new Error(h.hint??h.message??h.error??n("catalog.runHttp",{status:p.status}));f(n("catalog.runStarted")),h.runId&&(location.hash=`#/workflows/${encodeURIComponent(h.runId)}`)}catch(p){T(p?.message??String(p))}finally{I=!1,v.disabled=!1,v.textContent=n("catalog.run")}}function E(){s.querySelector("#catalog-run-form")?.addEventListener("submit",$=>{$.preventDefault(),S()})}async function b(){try{let u=await fetch(`/api/workflows/definitions/${encodeURIComponent(t)}`);if(u.status===404)throw new Error("unknown_workflow");if(!u.ok)throw new Error(`HTTP ${u.status}`);d=await u.json(),T(null),l()}catch(u){T(n("catalog.definitionLoadFailed",{error:u?.message??String(u)})),o.textContent=n("workflow.detail.loadFailed")}}return b().then(()=>{}),()=>{w=!0}}function no(e){let t=Object.entries(e??{});return t.length===0?`<div class="muted">${M(n("catalog.noParams"))}</div>`:`<div class="catalog-param-list">${t.map(([o,r])=>`
|
|
739
744
|
<article class="catalog-param">
|
|
740
745
|
<header>
|
|
741
746
|
<code>${M(o)}</code>
|
|
@@ -745,7 +750,7 @@ ${u.join(`
|
|
|
745
750
|
${r.description?`<div class="muted">${M(n("catalog.description"))}: ${M(r.description)}</div>`:""}
|
|
746
751
|
${"default"in r?`<pre class="wf-io-pre">${M(`${n("catalog.default")}: ${JSON.stringify(r.default,null,2)}`)}</pre>`:""}
|
|
747
752
|
</article>
|
|
748
|
-
`).join("")}</div>`}var
|
|
753
|
+
`).join("")}</div>`}var re=null,Te=null;function Le(){Te!==null&&(window.clearInterval(Te),Te=null)}function Lt(){return re||(re=document.createElement("dialog"),re.className="onboarding-dialog",document.body.appendChild(re),re.addEventListener("close",Le),re)}function oo(e){return e.status==="waiting_for_scan"?n("botOnboarding.waiting"):e.status==="verifying"?n("botOnboarding.verifying"):e.status==="completed"?n("botOnboarding.completed"):e.status==="failed"?`${n("botOnboarding.failed")}: ${e.message??e.error??"unknown"}`:n("botOnboarding.starting")}function me(e){let t=Lt(),o=e.qrDataUrl?`<div class="qr-card">
|
|
749
754
|
<img class="qr-image" src="${e.qrDataUrl}" alt="${n("botOnboarding.qrAlt")}">
|
|
750
755
|
${e.qrUrl?`<a class="onboarding-link" href="${e.qrUrl}" target="_blank" rel="noopener">${n("botOnboarding.openLink")}</a>`:""}
|
|
751
756
|
</div>`:"",r=e.appId?`<p><b>App ID:</b> <code>${e.appId}</code></p>`:"",a=e.status==="completed"?`<p class="hint-ok">${n("botOnboarding.restartHint")}</p>`:"";t.innerHTML=`<article>
|
|
@@ -758,4 +763,4 @@ ${u.join(`
|
|
|
758
763
|
${r}
|
|
759
764
|
${a}
|
|
760
765
|
<form method="dialog"><button>${n("botOnboarding.close")}</button></form>
|
|
761
|
-
</article>`}async function ao(e){let t=await fetch(`/api/bot-onboarding/${encodeURIComponent(e)}`),o=await t.json();if(!t.ok||!o?.job)throw new Error(o?.error??`http_${t.status}`);me(o.job),(o.job.status==="completed"||o.job.status==="failed")&&Le()}async function so(){Le(),me({id:"",status:"starting"});let e=Lt();e.open||e.showModal();try{let t=await fetch("/api/bot-onboarding/start",{method:"POST"}),o=await t.json();if(!t.ok||!o?.job?.id)throw new Error(o?.error??`http_${t.status}`);me(o.job),Te=window.setInterval(()=>{ao(o.job.id).catch(r=>{Le(),me({id:o.job.id,status:"failed",message:r instanceof Error?r.message:String(r)})})},1200)}catch(t){me({id:"",status:"failed",message:t instanceof Error?t.message:String(t)})}}function Et(){let e=document.getElementById("add-bot-btn");e&&(e.onclick=()=>{so()})}var
|
|
766
|
+
</article>`}async function ao(e){let t=await fetch(`/api/bot-onboarding/${encodeURIComponent(e)}`),o=await t.json();if(!t.ok||!o?.job)throw new Error(o?.error??`http_${t.status}`);me(o.job),(o.job.status==="completed"||o.job.status==="failed")&&Le()}async function so(){Le(),me({id:"",status:"starting"});let e=Lt();e.open||e.showModal();try{let t=await fetch("/api/bot-onboarding/start",{method:"POST"}),o=await t.json();if(!t.ok||!o?.job?.id)throw new Error(o?.error??`http_${t.status}`);me(o.job),Te=window.setInterval(()=>{ao(o.job.id).catch(r=>{Le(),me({id:o.job.id,status:"failed",message:r instanceof Error?r.message:String(r)})})},1200)}catch(t){me({id:"",status:"failed",message:t instanceof Error?t.message:String(t)})}}function Et(){let e=document.getElementById("add-bot-btn");e&&(e.onclick=()=>{so()})}var ae=document.getElementById("root"),we=null;function Pe(){we&&(we(),we=null);let e=location.hash||"#/";e.startsWith("#/workflows/catalog")||e.startsWith("#/workflows-catalog")?we=Tt(ae):e.startsWith("#/workflows")?we=mt(ae):e.startsWith("#/groups")?ot(ae):e.startsWith("#/bot-defaults")?rt(ae):e.startsWith("#/roles")?ct(ae):e.startsWith("#/schedules")?tt(ae):e.startsWith("#/sessions")?Ze(ae):Qe(ae);for(let t of document.querySelectorAll(".sidebar-nav a")){let o=t.getAttribute("href")??"#/";t.classList.toggle("active",o===(e||"#/"))}}var Ne=document.getElementById("status");function Mt(){Ne&&(Ne.textContent=P.online?n("status.live"):n("status.disconnected"),Ne.className="connection-status "+(P.online?"online":"offline"))}P.on(Mt);function Ct(){document.querySelectorAll("[data-i18n]").forEach(e=>{e.textContent=n(e.dataset.i18n??"")}),document.querySelectorAll("[data-locale]").forEach(e=>{e.classList.toggle("active",e.dataset.locale===ee.locale)}),document.querySelectorAll("[data-theme-mode]").forEach(e=>{e.classList.toggle("active",e.dataset.themeMode===ee.themeMode)}),Mt()}function ro(){document.querySelectorAll("[data-locale]").forEach(e=>{e.onclick=()=>ee.setLocale(e.dataset.locale)}),document.querySelectorAll("[data-theme-mode]").forEach(e=>{e.onclick=()=>ee.setThemeMode(e.dataset.themeMode)})}(async()=>{ee.init(),ro(),Et(),ee.on(()=>{Ct(),Pe()}),Ct();try{await Je()}catch(e){console.error("botmux dashboard bootstrap failed",e),P.setOnline(!1)}window.addEventListener("hashchange",Pe),Pe()})();})();
|