botmux 2.106.0 → 2.107.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.
Files changed (182) hide show
  1. package/dist/bot-registry.d.ts +25 -0
  2. package/dist/bot-registry.d.ts.map +1 -1
  3. package/dist/bot-registry.js +6 -0
  4. package/dist/bot-registry.js.map +1 -1
  5. package/dist/core/command-handler.d.ts.map +1 -1
  6. package/dist/core/command-handler.js +5 -0
  7. package/dist/core/command-handler.js.map +1 -1
  8. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  9. package/dist/core/dashboard-ipc-server.js +27 -1
  10. package/dist/core/dashboard-ipc-server.js.map +1 -1
  11. package/dist/core/dashboard-rows.d.ts +6 -0
  12. package/dist/core/dashboard-rows.d.ts.map +1 -1
  13. package/dist/core/dashboard-rows.js +25 -0
  14. package/dist/core/dashboard-rows.js.map +1 -1
  15. package/dist/core/pending-response.d.ts +1 -0
  16. package/dist/core/pending-response.d.ts.map +1 -1
  17. package/dist/core/pending-response.js +1 -0
  18. package/dist/core/pending-response.js.map +1 -1
  19. package/dist/core/resource-monitor/attribution.d.ts +70 -0
  20. package/dist/core/resource-monitor/attribution.d.ts.map +1 -0
  21. package/dist/core/resource-monitor/attribution.js +222 -0
  22. package/dist/core/resource-monitor/attribution.js.map +1 -0
  23. package/dist/core/resource-monitor/procfs.d.ts +22 -0
  24. package/dist/core/resource-monitor/procfs.d.ts.map +1 -0
  25. package/dist/core/resource-monitor/procfs.js +134 -0
  26. package/dist/core/resource-monitor/procfs.js.map +1 -0
  27. package/dist/core/resource-monitor/ring-buffer.d.ts +15 -0
  28. package/dist/core/resource-monitor/ring-buffer.d.ts.map +1 -0
  29. package/dist/core/resource-monitor/ring-buffer.js +61 -0
  30. package/dist/core/resource-monitor/ring-buffer.js.map +1 -0
  31. package/dist/core/resource-monitor/runtime.d.ts +31 -0
  32. package/dist/core/resource-monitor/runtime.d.ts.map +1 -0
  33. package/dist/core/resource-monitor/runtime.js +92 -0
  34. package/dist/core/resource-monitor/runtime.js.map +1 -0
  35. package/dist/core/resource-monitor/top-selector.d.ts +18 -0
  36. package/dist/core/resource-monitor/top-selector.d.ts.map +1 -0
  37. package/dist/core/resource-monitor/top-selector.js +57 -0
  38. package/dist/core/resource-monitor/top-selector.js.map +1 -0
  39. package/dist/core/resource-monitor/types.d.ts +181 -0
  40. package/dist/core/resource-monitor/types.d.ts.map +1 -0
  41. package/dist/core/resource-monitor/types.js +2 -0
  42. package/dist/core/resource-monitor/types.js.map +1 -0
  43. package/dist/core/session-manager.d.ts +3 -1
  44. package/dist/core/session-manager.d.ts.map +1 -1
  45. package/dist/core/session-manager.js +31 -1
  46. package/dist/core/session-manager.js.map +1 -1
  47. package/dist/core/types.d.ts +1 -0
  48. package/dist/core/types.d.ts.map +1 -1
  49. package/dist/core/types.js.map +1 -1
  50. package/dist/daemon.d.ts +1 -1
  51. package/dist/daemon.d.ts.map +1 -1
  52. package/dist/daemon.js +44 -22
  53. package/dist/daemon.js.map +1 -1
  54. package/dist/dashboard/bot-payload.d.ts +1 -0
  55. package/dist/dashboard/bot-payload.d.ts.map +1 -1
  56. package/dist/dashboard/bot-payload.js +1 -0
  57. package/dist/dashboard/bot-payload.js.map +1 -1
  58. package/dist/dashboard/resource-monitor-service.d.ts +56 -0
  59. package/dist/dashboard/resource-monitor-service.d.ts.map +1 -0
  60. package/dist/dashboard/resource-monitor-service.js +446 -0
  61. package/dist/dashboard/resource-monitor-service.js.map +1 -0
  62. package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
  63. package/dist/dashboard/web/bot-defaults.js +160 -1
  64. package/dist/dashboard/web/bot-defaults.js.map +1 -1
  65. package/dist/dashboard/web/dashboard-routes.d.ts.map +1 -1
  66. package/dist/dashboard/web/dashboard-routes.js +18 -0
  67. package/dist/dashboard/web/dashboard-routes.js.map +1 -1
  68. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  69. package/dist/dashboard/web/i18n.js +274 -2
  70. package/dist/dashboard/web/i18n.js.map +1 -1
  71. package/dist/dashboard/web/monitor-room-store.d.ts +20 -0
  72. package/dist/dashboard/web/monitor-room-store.d.ts.map +1 -0
  73. package/dist/dashboard/web/monitor-room-store.js +80 -0
  74. package/dist/dashboard/web/monitor-room-store.js.map +1 -0
  75. package/dist/dashboard/web/monitor-room.d.ts +31 -0
  76. package/dist/dashboard/web/monitor-room.d.ts.map +1 -0
  77. package/dist/dashboard/web/monitor-room.js +393 -0
  78. package/dist/dashboard/web/monitor-room.js.map +1 -0
  79. package/dist/dashboard/web/monitoring-page.d.ts +155 -0
  80. package/dist/dashboard/web/monitoring-page.d.ts.map +1 -0
  81. package/dist/dashboard/web/monitoring-page.js +189 -0
  82. package/dist/dashboard/web/monitoring-page.js.map +1 -0
  83. package/dist/dashboard/web/overview-page.d.ts.map +1 -1
  84. package/dist/dashboard/web/overview-page.js +108 -1
  85. package/dist/dashboard/web/overview-page.js.map +1 -1
  86. package/dist/dashboard/web/preferences.d.ts +3 -0
  87. package/dist/dashboard/web/preferences.d.ts.map +1 -1
  88. package/dist/dashboard/web/preferences.js +18 -0
  89. package/dist/dashboard/web/preferences.js.map +1 -1
  90. package/dist/dashboard/web/session-terminal.d.ts +7 -0
  91. package/dist/dashboard/web/session-terminal.d.ts.map +1 -0
  92. package/dist/dashboard/web/session-terminal.js +17 -0
  93. package/dist/dashboard/web/session-terminal.js.map +1 -0
  94. package/dist/dashboard/web/sessions-page.d.ts.map +1 -1
  95. package/dist/dashboard/web/sessions-page.js +2 -1
  96. package/dist/dashboard/web/sessions-page.js.map +1 -1
  97. package/dist/dashboard/web/sessions.d.ts +4 -0
  98. package/dist/dashboard/web/sessions.d.ts.map +1 -1
  99. package/dist/dashboard/web/sessions.js +98 -17
  100. package/dist/dashboard/web/sessions.js.map +1 -1
  101. package/dist/dashboard/web/skills-page.js +1 -1
  102. package/dist/dashboard/web/skills-page.js.map +1 -1
  103. package/dist/dashboard/web/substitute-targets.d.ts +30 -0
  104. package/dist/dashboard/web/substitute-targets.d.ts.map +1 -0
  105. package/dist/dashboard/web/substitute-targets.js +99 -0
  106. package/dist/dashboard/web/substitute-targets.js.map +1 -0
  107. package/dist/dashboard/web/ui.d.ts +1 -1
  108. package/dist/dashboard/web/ui.d.ts.map +1 -1
  109. package/dist/dashboard/web/ui.js +4 -1
  110. package/dist/dashboard/web/ui.js.map +1 -1
  111. package/dist/dashboard-web/app.js +3 -3
  112. package/dist/dashboard-web/chunks/bot-defaults-page-OCIHPGEU.js +438 -0
  113. package/dist/dashboard-web/chunks/chunk-3N2PPQVD.js +1 -0
  114. package/dist/dashboard-web/chunks/chunk-3UJYRR2Q.js +37 -0
  115. package/dist/dashboard-web/chunks/{chunk-VFCACTRF.js → chunk-PE6W3C2C.js} +1 -1
  116. package/dist/dashboard-web/chunks/chunk-QW54DWU3.js +325 -0
  117. package/dist/dashboard-web/chunks/{connectors-VDOAKUW3.js → connectors-IGETYWCP.js} +1 -1
  118. package/dist/dashboard-web/chunks/{groups-page-CX5AN4XG.js → groups-page-MYBS4ZYJ.js} +1 -1
  119. package/dist/dashboard-web/chunks/{insights-page-DOMRL4S6.js → insights-page-UPA32V2S.js} +1 -1
  120. package/dist/dashboard-web/chunks/monitor-room-RFX4HPS5.js +51 -0
  121. package/dist/dashboard-web/chunks/monitoring-page-7T3BESZ2.js +1 -0
  122. package/dist/dashboard-web/chunks/overview-page-LJSBCQW4.js +1 -0
  123. package/dist/dashboard-web/chunks/{roles-page-3FEAH6S4.js → roles-page-ESURTVQH.js} +1 -1
  124. package/dist/dashboard-web/chunks/{schedules-CTQEA7IE.js → schedules-LML2ISOT.js} +1 -1
  125. package/dist/dashboard-web/chunks/sessions-YB73XOTU.js +1 -0
  126. package/dist/dashboard-web/chunks/sessions-page-MCO5QR7Z.js +1 -0
  127. package/dist/dashboard-web/chunks/{settings-page-R23I3IZG.js → settings-page-OSDKNVS3.js} +1 -1
  128. package/dist/dashboard-web/chunks/skills-page-PXBZJ6P6.js +2 -0
  129. package/dist/dashboard-web/chunks/{team-federation-page-ZKL3YMGN.js → team-federation-page-TTPVHFPX.js} +1 -1
  130. package/dist/dashboard-web/chunks/{workflows-4BYQQBFP.js → workflows-FCPM4S4D.js} +1 -1
  131. package/dist/dashboard-web/index.html +2 -1
  132. package/dist/dashboard-web/style.css +818 -8
  133. package/dist/dashboard.js +37 -0
  134. package/dist/dashboard.js.map +1 -1
  135. package/dist/i18n/en.d.ts.map +1 -1
  136. package/dist/i18n/en.js +8 -0
  137. package/dist/i18n/en.js.map +1 -1
  138. package/dist/i18n/zh.d.ts.map +1 -1
  139. package/dist/i18n/zh.js +8 -0
  140. package/dist/i18n/zh.js.map +1 -1
  141. package/dist/im/lark/card-builder.d.ts.map +1 -1
  142. package/dist/im/lark/card-builder.js +18 -0
  143. package/dist/im/lark/card-builder.js.map +1 -1
  144. package/dist/im/lark/card-handler.d.ts.map +1 -1
  145. package/dist/im/lark/card-handler.js +12 -2
  146. package/dist/im/lark/card-handler.js.map +1 -1
  147. package/dist/im/lark/event-dispatcher.d.ts +3 -0
  148. package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
  149. package/dist/im/lark/event-dispatcher.js +59 -2
  150. package/dist/im/lark/event-dispatcher.js.map +1 -1
  151. package/dist/im/lark/message-parser.d.ts +35 -0
  152. package/dist/im/lark/message-parser.d.ts.map +1 -1
  153. package/dist/im/lark/message-parser.js +56 -0
  154. package/dist/im/lark/message-parser.js.map +1 -1
  155. package/dist/im/lark/substitute-command.d.ts +2 -0
  156. package/dist/im/lark/substitute-command.d.ts.map +1 -0
  157. package/dist/im/lark/substitute-command.js +51 -0
  158. package/dist/im/lark/substitute-command.js.map +1 -0
  159. package/dist/services/substitute-chat-toggle-store.d.ts +3 -0
  160. package/dist/services/substitute-chat-toggle-store.d.ts.map +1 -0
  161. package/dist/services/substitute-chat-toggle-store.js +58 -0
  162. package/dist/services/substitute-chat-toggle-store.js.map +1 -0
  163. package/dist/services/substitute-mode-normalize.d.ts +22 -0
  164. package/dist/services/substitute-mode-normalize.d.ts.map +1 -0
  165. package/dist/services/substitute-mode-normalize.js +56 -0
  166. package/dist/services/substitute-mode-normalize.js.map +1 -0
  167. package/dist/services/substitute-mode-store.d.ts +50 -0
  168. package/dist/services/substitute-mode-store.d.ts.map +1 -0
  169. package/dist/services/substitute-mode-store.js +115 -0
  170. package/dist/services/substitute-mode-store.js.map +1 -0
  171. package/dist/types.d.ts +14 -0
  172. package/dist/types.d.ts.map +1 -1
  173. package/dist/worker.js +20 -1
  174. package/dist/worker.js.map +1 -1
  175. package/package.json +1 -1
  176. package/dist/dashboard-web/chunks/bot-defaults-page-3OIY7N76.js +0 -409
  177. package/dist/dashboard-web/chunks/chunk-BNEXMNQD.js +0 -31
  178. package/dist/dashboard-web/chunks/chunk-DKKOGZCG.js +0 -317
  179. package/dist/dashboard-web/chunks/overview-page-AZBAXVZ7.js +0 -1
  180. package/dist/dashboard-web/chunks/sessions-LVZCXO2Z.js +0 -1
  181. package/dist/dashboard-web/chunks/sessions-page-NHBJDSBC.js +0 -1
  182. package/dist/dashboard-web/chunks/skills-page-VUG3EPWX.js +0 -2
@@ -0,0 +1,17 @@
1
+ function currentLocation() {
2
+ return typeof window === 'undefined' ? null : window.location;
3
+ }
4
+ export function sessionTerminalHref(s, loc = currentLocation()) {
5
+ if (!s?.webPort || !loc)
6
+ return null;
7
+ // On the central HTTPS machine domain, terminals must go through the same
8
+ // origin `/s/<session>` reverse proxy. Exposing a raw port would produce a
9
+ // dead link because the platform only proxies 443.
10
+ if (loc.protocol === 'https:') {
11
+ return s.proxyPort ? `${loc.origin}/s/${encodeURIComponent(s.sessionId)}` : null;
12
+ }
13
+ const port = s.proxyPort ?? s.webPort;
14
+ const suffix = s.proxyPort ? `/s/${encodeURIComponent(s.sessionId)}` : '';
15
+ return `http://${loc.hostname}:${port}${suffix}`;
16
+ }
17
+ //# sourceMappingURL=session-terminal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-terminal.js","sourceRoot":"","sources":["../../../src/dashboard/web/session-terminal.ts"],"names":[],"mappings":"AAMA,SAAS,eAAe;IACtB,OAAO,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,CAAM,EAAE,MAAsC,eAAe,EAAE;IACjG,IAAI,CAAC,CAAC,EAAE,OAAO,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACrC,0EAA0E;IAC1E,2EAA2E;IAC3E,mDAAmD;IACnD,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,MAAM,kBAAkB,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACnF,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,OAAO,CAAC;IACtC,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,kBAAkB,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1E,OAAO,UAAU,GAAG,CAAC,QAAQ,IAAI,IAAI,GAAG,MAAM,EAAE,CAAC;AACnD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"sessions-page.d.ts","sourceRoot":"","sources":["../../../src/dashboard/web/sessions-page.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAsHrE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,GAAG,YAAY,CAElE"}
1
+ {"version":3,"file":"sessions-page.d.ts","sourceRoot":"","sources":["../../../src/dashboard/web/sessions-page.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAoIrE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,GAAG,YAAY,CAElE"}
@@ -4,6 +4,7 @@ import { IDLE_CLEANUP_HOUR_OPTIONS } from '../session-cleanup.js';
4
4
  import { mountReactPage } from './react-mount.js';
5
5
  import { renderCliFilterGroup, SESSION_STATUS_OPTIONS, sessionStatusText, wireSessionsPage } from './sessions.js';
6
6
  import { useT } from './react-hooks.js';
7
+ import { readStoredSessionsShowUnknownChats } from './preferences.js';
7
8
  function SortHeader(props) {
8
9
  return _jsx("th", { "data-sort": props.sort, "data-label": props.label, children: props.label });
9
10
  }
@@ -20,7 +21,7 @@ function SessionsPage() {
20
21
  return undefined;
21
22
  return wireSessionsPage(hostRef.current);
22
23
  }, []);
23
- return (_jsxs("section", { className: "page", ref: hostRef, children: [_jsxs("div", { className: "page-heading", children: [_jsxs("div", { children: [_jsx("p", { className: "eyebrow", children: tr('nav.sessions') }), _jsx("h1", { children: tr('sessions.title') }), _jsx("p", { children: tr('sessions.subtitle') })] }), _jsxs("div", { className: "sessions-view-controls", children: [_jsx("span", { id: "kanban-team-stats", className: "kanban-team-stats", hidden: true }), _jsx("select", { id: "kanban-team", className: "kanban-team-select", "aria-label": tr('sessions.kanban.groupTeam'), hidden: true }), _jsxs("div", { className: "segmented kanban-groupby", id: "kanban-groupby", role: "group", "aria-label": tr('sessions.kanban.groupBy'), hidden: true, children: [_jsx("button", { type: "button", "data-groupby": "flow", children: tr('sessions.kanban.groupFlow') }), _jsx("button", { type: "button", "data-groupby": "team", children: tr('sessions.kanban.groupTeam') }), _jsx("button", { type: "button", "data-groupby": "bot", children: tr('sessions.kanban.groupBot') })] }), _jsxs("div", { className: "segmented sessions-view-toggle", role: "group", "aria-label": tr('sessions.viewMode'), children: [_jsx("button", { type: "button", "data-view": "kanban", children: tr('sessions.viewKanban') }), _jsx("button", { type: "button", "data-view": "board", children: tr('sessions.viewBoard') }), _jsx("button", { type: "button", "data-view": "table", children: tr('sessions.viewTable') })] })] })] }), _jsxs("form", { id: "filters", className: "filters sessions-filters", children: [_jsx("input", { type: "search", name: "q", placeholder: tr('sessions.search') }), _jsxs("select", { name: "status", children: [_jsx("option", { value: "", children: tr('sessions.anyStatus') }), SESSION_STATUS_OPTIONS.map(status => (_jsx("option", { value: status, children: sessionStatusText(status) }, status)))] }), _jsxs("select", { name: "adopt", children: [_jsx("option", { value: "", children: tr('sessions.adoptAny') }), _jsx("option", { value: "yes", children: tr('sessions.adoptYes') }), _jsx("option", { value: "no", children: tr('sessions.adoptNo') })] }), _jsx("span", { style: { display: 'contents' }, dangerouslySetInnerHTML: { __html: renderCliFilterGroup() } }), _jsxs("label", { className: "filter-toggle", children: [_jsx("input", { type: "checkbox", name: "active", defaultChecked: true }), " ", _jsx("span", { children: tr('sessions.activeOnly') })] })] }), _jsxs("div", { id: "idle-cleanup-bar", className: "idle-cleanup-bar", children: [_jsxs("div", { className: "idle-cleanup-summary", children: [_jsx("span", { className: "idle-cleanup-dot", "aria-hidden": "true" }), _jsx("span", { id: "idle-cleanup-count", className: "idle-cleanup-count" })] }), _jsxs("div", { className: "idle-cleanup-controls", children: [_jsx("span", { className: "idle-cleanup-label", children: tr('sessions.idleCleanupOlderThan') }), _jsx("div", { id: "idle-cleanup-threshold", className: "idle-cleanup-thresholds", role: "group", "aria-label": tr('sessions.idleCleanupThreshold'), children: IDLE_CLEANUP_HOUR_OPTIONS.map(hours => (_jsx("button", { type: "button", "data-hours": hours, "aria-pressed": hours === 24 ? 'true' : 'false', children: hours === 168 ? '7d' : `${hours}H` }, hours))) }), _jsx("button", { type: "button", id: "idle-cleanup-run", className: "contrast idle-cleanup-run", children: tr('sessions.idleCleanupRun') })] }), _jsx("span", { id: "idle-cleanup-status", className: "idle-cleanup-status", "aria-live": "polite" })] }), _jsxs("div", { id: "bulk-bar", className: "bulk-bar", hidden: true, children: [_jsx("span", { id: "bulk-count" }), _jsx("button", { type: "button", id: "bulk-lock", children: tr('sessions.lockSelected') }), _jsx("button", { type: "button", id: "bulk-unlock", children: tr('sessions.unlockSelected') }), _jsx("button", { type: "button", id: "bulk-close", className: "contrast", children: tr('sessions.closeSelected') }), _jsx("button", { type: "button", id: "bulk-clear", children: tr('sessions.clearSelection') })] }), _jsxs("table", { id: "sessions-table", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: _jsx("input", { type: "checkbox", id: "select-all", title: tr('sessions.activeOnly') }) }), _jsx(SortHeader, { sort: "botName", label: tr('sessions.bot') }), _jsx(SortHeader, { sort: "cliId", label: tr('sessions.cli') }), _jsx(SortHeader, { sort: "status", label: tr('sessions.status') }), _jsx(SortHeader, { sort: "tokenIn", label: tr('sessions.tokenIn') }), _jsx(SortHeader, { sort: "tokenOut", label: tr('sessions.tokenOut') }), _jsx(SortHeader, { sort: "title", label: tr('sessions.titleCol') }), _jsx(SortHeader, { sort: "workingDir", label: tr('sessions.workingDir') }), _jsx(SortHeader, { sort: "spawnedAt", label: tr('sessions.created') }), _jsx(SortHeader, { sort: "lastMessageAt", label: tr('sessions.last') }), _jsx(SortHeader, { sort: "adopt", label: tr('sessions.adopt') }), _jsx("th", { children: tr('sessions.actions') })] }) }), _jsx("tbody", {})] }), _jsx("div", { id: "sessions-board", className: "sessions-board", hidden: true }), _jsx("div", { id: "sessions-kanban", className: "sessions-kanban", hidden: true }), _jsx("dialog", { id: "drawer" }), _jsx("dialog", { id: "term-modal", className: "term-modal" }), _jsx("dialog", { id: "history-modal", className: "history-modal" })] }));
24
+ return (_jsxs("section", { className: "page", ref: hostRef, children: [_jsxs("div", { className: "page-heading", children: [_jsxs("div", { children: [_jsx("p", { className: "eyebrow", children: tr('nav.sessions') }), _jsx("h1", { children: tr('sessions.title') }), _jsx("p", { children: tr('sessions.subtitle') })] }), _jsxs("div", { className: "sessions-view-controls", children: [_jsx("span", { id: "kanban-team-stats", className: "kanban-team-stats", hidden: true }), _jsx("select", { id: "kanban-team", className: "kanban-team-select", "aria-label": tr('sessions.kanban.groupTeam'), hidden: true }), _jsxs("div", { className: "segmented kanban-groupby", id: "kanban-groupby", role: "group", "aria-label": tr('sessions.kanban.groupBy'), hidden: true, children: [_jsx("button", { type: "button", "data-groupby": "flow", children: tr('sessions.kanban.groupFlow') }), _jsx("button", { type: "button", "data-groupby": "team", children: tr('sessions.kanban.groupTeam') }), _jsx("button", { type: "button", "data-groupby": "bot", children: tr('sessions.kanban.groupBot') })] }), _jsxs("div", { className: "segmented sessions-view-toggle", role: "group", "aria-label": tr('sessions.viewMode'), children: [_jsx("button", { type: "button", "data-view": "kanban", children: tr('sessions.viewKanban') }), _jsx("button", { type: "button", "data-view": "board", children: tr('sessions.viewBoard') }), _jsx("button", { type: "button", "data-view": "table", children: tr('sessions.viewTable') })] }), _jsx("button", { type: "button", id: "monitor-room-open", className: "monitor-room-open", children: tr('sessions.monitorRoom') })] })] }), _jsxs("form", { id: "filters", className: "filters sessions-filters", children: [_jsx("input", { type: "search", name: "q", placeholder: tr('sessions.search') }), _jsxs("select", { name: "status", children: [_jsx("option", { value: "", children: tr('sessions.anyStatus') }), SESSION_STATUS_OPTIONS.map(status => (_jsx("option", { value: status, children: sessionStatusText(status) }, status)))] }), _jsxs("select", { name: "adopt", children: [_jsx("option", { value: "", children: tr('sessions.adoptAny') }), _jsx("option", { value: "yes", children: tr('sessions.adoptYes') }), _jsx("option", { value: "no", children: tr('sessions.adoptNo') })] }), _jsx("select", { name: "chat", "aria-label": tr('sessions.location'), children: _jsx("option", { value: "", children: tr('sessions.chatAny') }) }), _jsx("span", { style: { display: 'contents' }, dangerouslySetInnerHTML: { __html: renderCliFilterGroup() } }), _jsxs("label", { className: "filter-toggle", children: [_jsx("input", { type: "checkbox", name: "showUnknownChats", defaultChecked: readStoredSessionsShowUnknownChats(typeof window === 'undefined' ? undefined : window.localStorage) }), " ", _jsx("span", { children: tr('sessions.showUnknownChats') })] }), _jsxs("label", { className: "filter-toggle", children: [_jsx("input", { type: "checkbox", name: "active", defaultChecked: true }), " ", _jsx("span", { children: tr('sessions.activeOnly') })] })] }), _jsxs("div", { id: "idle-cleanup-bar", className: "idle-cleanup-bar", children: [_jsxs("div", { className: "idle-cleanup-summary", children: [_jsx("span", { className: "idle-cleanup-dot", "aria-hidden": "true" }), _jsx("span", { id: "idle-cleanup-count", className: "idle-cleanup-count" })] }), _jsxs("div", { className: "idle-cleanup-controls", children: [_jsx("span", { className: "idle-cleanup-label", children: tr('sessions.idleCleanupOlderThan') }), _jsx("div", { id: "idle-cleanup-threshold", className: "idle-cleanup-thresholds", role: "group", "aria-label": tr('sessions.idleCleanupThreshold'), children: IDLE_CLEANUP_HOUR_OPTIONS.map(hours => (_jsx("button", { type: "button", "data-hours": hours, "aria-pressed": hours === 24 ? 'true' : 'false', children: hours === 168 ? '7d' : `${hours}H` }, hours))) }), _jsx("button", { type: "button", id: "idle-cleanup-run", className: "contrast idle-cleanup-run", children: tr('sessions.idleCleanupRun') })] }), _jsx("span", { id: "idle-cleanup-status", className: "idle-cleanup-status", "aria-live": "polite" })] }), _jsxs("div", { id: "bulk-bar", className: "bulk-bar", hidden: true, children: [_jsx("span", { id: "bulk-count" }), _jsx("button", { type: "button", id: "bulk-monitor-room", children: tr('sessions.addToMonitorRoom') }), _jsx("button", { type: "button", id: "bulk-lock", children: tr('sessions.lockSelected') }), _jsx("button", { type: "button", id: "bulk-unlock", children: tr('sessions.unlockSelected') }), _jsx("button", { type: "button", id: "bulk-close", className: "contrast", children: tr('sessions.closeSelected') }), _jsx("button", { type: "button", id: "bulk-clear", children: tr('sessions.clearSelection') })] }), _jsxs("table", { id: "sessions-table", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: _jsx("input", { type: "checkbox", id: "select-all", title: tr('sessions.activeOnly') }) }), _jsx(SortHeader, { sort: "botName", label: tr('sessions.bot') }), _jsx(SortHeader, { sort: "cliId", label: tr('sessions.cli') }), _jsx(SortHeader, { sort: "status", label: tr('sessions.status') }), _jsx(SortHeader, { sort: "chat", label: tr('sessions.location') }), _jsx(SortHeader, { sort: "tokenIn", label: tr('sessions.tokenIn') }), _jsx(SortHeader, { sort: "tokenOut", label: tr('sessions.tokenOut') }), _jsx(SortHeader, { sort: "title", label: tr('sessions.titleCol') }), _jsx(SortHeader, { sort: "workingDir", label: tr('sessions.workingDir') }), _jsx(SortHeader, { sort: "spawnedAt", label: tr('sessions.created') }), _jsx(SortHeader, { sort: "lastMessageAt", label: tr('sessions.last') }), _jsx(SortHeader, { sort: "adopt", label: tr('sessions.adopt') }), _jsx("th", { children: tr('sessions.actions') })] }) }), _jsx("tbody", {})] }), _jsx("div", { id: "sessions-board", className: "sessions-board", hidden: true }), _jsx("div", { id: "sessions-kanban", className: "sessions-kanban", hidden: true }), _jsx("dialog", { id: "drawer" }), _jsx("dialog", { id: "term-modal", className: "term-modal" }), _jsx("dialog", { id: "history-modal", className: "history-modal" })] }));
24
25
  }
25
26
  export function renderSessionsPage(root) {
26
27
  return mountReactPage(root, _jsx(SessionsPage, {}));
@@ -1 +1 @@
1
- {"version":3,"file":"sessions-page.js","sourceRoot":"","sources":["../../../src/dashboard/web/sessions-page.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sessions-page.js","sourceRoot":"","sources":["../../../src/dashboard/web/sessions-page.tsx"],"names":[],"mappings":"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"}
@@ -1,5 +1,9 @@
1
+ import { sessionTerminalHref } from './session-terminal.js';
1
2
  export declare const SESSION_STATUS_OPTIONS: string[];
2
3
  export declare function sessionStatusText(status: unknown): string;
4
+ export declare function sessionLocationText(s: any): string;
5
+ export declare function isUnknownChatSession(s: any, resolveTitle?: (session: any) => string | null): boolean;
6
+ export declare const terminalHref: typeof sessionTerminalHref;
3
7
  export declare function renderCliFilterGroup(): string;
4
8
  export declare function restartConfirmMessage(s: any): string;
5
9
  export declare function canRestartSession(s: any): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../../src/dashboard/web/sessions.ts"],"names":[],"mappings":"AA2GA,eAAO,MAAM,sBAAsB,UASlC,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAKzD;AAmHD,wBAAgB,oBAAoB,IAAI,MAAM,CAY7C;AAED,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,GAAG,GAAG,MAAM,CAYpD;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,GAAG,GAAG,OAAO,CAEjD;AA4JD,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAQ5D;AAkGD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,IAAI,CAGhE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,IAAI,CA27D9D"}
1
+ {"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../../src/dashboard/web/sessions.ts"],"names":[],"mappings":"AA2CA,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAoE5D,eAAO,MAAM,sBAAsB,UASlC,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAKzD;AAkBD,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,GAAG,GAAG,MAAM,CAMlD;AAED,wBAAgB,oBAAoB,CAClC,CAAC,EAAE,GAAG,EACN,YAAY,GAAE,CAAC,OAAO,EAAE,GAAG,KAAK,MAAM,GAAG,IAAuB,GAC/D,OAAO,CAGT;AAYD,eAAO,MAAM,YAAY,4BAAsB,CAAC;AAyFhD,wBAAgB,oBAAoB,IAAI,MAAM,CAY7C;AAED,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,GAAG,GAAG,MAAM,CAYpD;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,GAAG,GAAG,OAAO,CAEjD;AAsKD,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAQ5D;AAkGD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,IAAI,CAGhE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,IAAI,CAy/D9D"}
@@ -1,10 +1,12 @@
1
1
  // Sessions page: filter bar, status board/table, detail drawer with locate/resume/close.
2
- import { KANBAN_TEAM_STORAGE_KEY, normalizeSessionsViewMode, readStoredBoardOrder, readStoredKanbanGroupBy, readStoredSessionsViewMode, writeStoredBoardOrder, writeStoredKanbanGroupBy, writeStoredSessionsViewMode, } from './preferences.js';
2
+ import { KANBAN_TEAM_STORAGE_KEY, normalizeSessionsViewMode, readStoredBoardOrder, readStoredKanbanGroupBy, readStoredSessionsShowUnknownChats, readStoredSessionsViewMode, writeStoredBoardOrder, writeStoredKanbanGroupBy, writeStoredSessionsShowUnknownChats, writeStoredSessionsViewMode, } from './preferences.js';
3
3
  import { computeDropPosition, deriveKanbanColumn, effectiveKanbanPosition, } from './kanban-model.js';
4
4
  import { store } from './store.js';
5
5
  import { botDisplayName, botAvatarHtml, chatAvatarHtml, chatDisplayTitle, attentionWaitSince, escapeHtml, loadNameMaps, relTime, stripMentionPrefix, t, ui, } from './ui.js';
6
6
  import { IDLE_CLEANUP_HOUR_OPTIONS, parseIdleCleanupHours, selectIdleCleanupCandidates, } from '../session-cleanup.js';
7
7
  import { CLI_OPTIONS } from '../../setup/bot-config-editor.js';
8
+ import { addMonitorRoomSessionIds, monitorRoomUrl } from './monitor-room-store.js';
9
+ import { sessionTerminalHref } from './session-terminal.js';
8
10
  function th(sort, label) {
9
11
  return `<th data-sort="${sort}" data-label="${escapeHtml(label)}">${escapeHtml(label)}</th>`;
10
12
  }
@@ -86,20 +88,31 @@ function repoBasename(workingDir) {
86
88
  const parts = value.replace(/\\/g, '/').split('/').filter(Boolean);
87
89
  return parts.at(-1) ?? value;
88
90
  }
89
- function terminalHref(s) {
90
- if (!s.webPort)
91
- return null;
92
- // 经中心化平台访问时(本页是 HTTPS 机器子域 m-<id>.<host>):终端走**同源 /s/<session>**——
93
- // 平台在 443 反代该路径 本机 dashboard → 本地终端。不能带 :port(平台只在 443 反代,:8801 打不通)。
94
- // 需要本地终端反代口(proxyPort)已起;没起则平台侧无法反代,返回 null 不给死链。
95
- if (location.protocol === 'https:') {
96
- return s.proxyPort ? `${location.origin}/s/${encodeURIComponent(s.sessionId)}` : null;
97
- }
98
- // 本地直连:http://host:port[/s/...]
99
- const port = s.proxyPort ?? s.webPort;
100
- const suffix = s.proxyPort ? `/s/${encodeURIComponent(s.sessionId)}` : '';
101
- return `http://${location.hostname}:${port}${suffix}`;
91
+ function sessionChatKindLabel(s) {
92
+ return s?.chatType === 'p2p' ? t('sessions.directChat') : t('sessions.groupChat');
93
+ }
94
+ export function sessionLocationText(s) {
95
+ const chatId = String(s?.chatId ?? '').trim();
96
+ const name = chatDisplayTitle(s);
97
+ if (name)
98
+ return `${sessionChatKindLabel(s)} · ${name}`;
99
+ if (chatId)
100
+ return `${sessionChatKindLabel(s)} · ${chatId}`;
101
+ return t('sessions.chatUnknown');
102
+ }
103
+ export function isUnknownChatSession(s, resolveTitle = chatDisplayTitle) {
104
+ const chatId = String(s?.chatId ?? '').trim();
105
+ return !!chatId && !resolveTitle(s);
106
+ }
107
+ function sessionLocationTitle(s) {
108
+ const label = sessionLocationText(s);
109
+ const chatId = String(s?.chatId ?? '').trim();
110
+ return chatId && !label.includes(chatId) ? `${label} · ${chatId}` : label;
102
111
  }
112
+ function sessionSearchText(s) {
113
+ return `${JSON.stringify(s)} ${sessionLocationText(s)} ${sessionLocationTitle(s)}`.toLowerCase();
114
+ }
115
+ export const terminalHref = sessionTerminalHref;
103
116
  // Cohesive icon set for the session-card action bar — stroke-based (CSS sets
104
117
  // stroke:currentColor), 16px viewBox to match the sidebar nav glyphs. Icons
105
118
  // instead of text labels keep the row a fixed width across locales: the EN
@@ -225,6 +238,7 @@ export function canRestartSession(s) {
225
238
  return s.status !== 'closed' && !s.adopt && !s.pendingRepo;
226
239
  }
227
240
  function pageHtml() {
241
+ const showUnknownChatsChecked = readStoredSessionsShowUnknownChats(typeof window === 'undefined' ? undefined : window.localStorage) ? ' checked' : '';
228
242
  return `<section class="page">
229
243
  <div class="page-heading">
230
244
  <div>
@@ -245,6 +259,7 @@ function pageHtml() {
245
259
  <button type="button" data-view="board">${t('sessions.viewBoard')}</button>
246
260
  <button type="button" data-view="table">${t('sessions.viewTable')}</button>
247
261
  </div>
262
+ <button type="button" id="monitor-room-open" class="monitor-room-open">${t('sessions.monitorRoom')}</button>
248
263
  </div>
249
264
  </div>
250
265
  <form id="filters" class="filters sessions-filters">
@@ -258,7 +273,11 @@ function pageHtml() {
258
273
  <option value="yes">${t('sessions.adoptYes')}</option>
259
274
  <option value="no">${t('sessions.adoptNo')}</option>
260
275
  </select>
276
+ <select name="chat" aria-label="${t('sessions.location')}">
277
+ <option value="">${t('sessions.chatAny')}</option>
278
+ </select>
261
279
  ${renderCliFilterGroup()}
280
+ <label class="filter-toggle"><input type="checkbox" name="showUnknownChats"${showUnknownChatsChecked}> <span>${t('sessions.showUnknownChats')}</span></label>
262
281
  <label class="filter-toggle"><input type="checkbox" name="active" checked> <span>${t('sessions.activeOnly')}</span></label>
263
282
  </form>
264
283
  <div id="idle-cleanup-bar" class="idle-cleanup-bar">
@@ -277,6 +296,7 @@ function pageHtml() {
277
296
  </div>
278
297
  <div id="bulk-bar" class="bulk-bar" hidden>
279
298
  <span id="bulk-count"></span>
299
+ <button type="button" id="bulk-monitor-room">${t('sessions.addToMonitorRoom')}</button>
280
300
  <button type="button" id="bulk-lock">${t('sessions.lockSelected')}</button>
281
301
  <button type="button" id="bulk-unlock">${t('sessions.unlockSelected')}</button>
282
302
  <button type="button" id="bulk-close" class="contrast">${t('sessions.closeSelected')}</button>
@@ -288,6 +308,7 @@ function pageHtml() {
288
308
  ${th('botName', t('sessions.bot'))}
289
309
  ${th('cliId', t('sessions.cli'))}
290
310
  ${th('status', t('sessions.status'))}
311
+ ${th('chat', t('sessions.location'))}
291
312
  ${th('tokenIn', t('sessions.tokenIn'))}
292
313
  ${th('tokenOut', t('sessions.tokenOut'))}
293
314
  ${th('title', t('sessions.titleCol'))}
@@ -510,10 +531,13 @@ export function renderSessionsPage(root) {
510
531
  export function wireSessionsPage(root) {
511
532
  const tbody = root.querySelector('#sessions-table tbody');
512
533
  const filtersForm = root.querySelector('#filters');
534
+ const chatSelect = root.querySelector('select[name="chat"]');
535
+ const showUnknownChatsInput = root.querySelector('input[name="showUnknownChats"]');
513
536
  const drawer = root.querySelector('#drawer');
514
537
  const selectAllBox = root.querySelector('#select-all');
515
538
  const bulkBar = root.querySelector('#bulk-bar');
516
539
  const bulkCountSpan = root.querySelector('#bulk-count');
540
+ const bulkMonitorRoomBtn = root.querySelector('#bulk-monitor-room');
517
541
  const bulkLockBtn = root.querySelector('#bulk-lock');
518
542
  const bulkUnlockBtn = root.querySelector('#bulk-unlock');
519
543
  const bulkCloseBtn = root.querySelector('#bulk-close');
@@ -532,6 +556,7 @@ export function wireSessionsPage(root) {
532
556
  const teamSelect = root.querySelector('#kanban-team');
533
557
  const teamStats = root.querySelector('#kanban-team-stats');
534
558
  const viewButtons = root.querySelectorAll('.sessions-view-toggle [data-view]');
559
+ const monitorRoomOpenBtn = root.querySelector('#monitor-room-open');
535
560
  // 「创建会话」按钮 + 弹窗已提到全局顶栏,由 wireCreateSessionButton() 一次性接线(见 app.ts)。
536
561
  const selected = new Set();
537
562
  let sortKey = 'lastMessageAt';
@@ -545,6 +570,7 @@ export function wireSessionsPage(root) {
545
570
  let lastBoardHtml = '';
546
571
  let lastTableHtml = '';
547
572
  let lastKanbanHtml = '';
573
+ let lastChatFilterHtml = '';
548
574
  let boardAnimated = false;
549
575
  // 看板交互态:拖拽中的卡片 id / 标题就地编辑中 —— 两者期间都跳过看板重绘,
550
576
  // 否则 SSE 触发的 innerHTML 重建会把拖拽源/输入框拍没。
@@ -579,6 +605,9 @@ export function wireSessionsPage(root) {
579
605
  })();
580
606
  let idleCleanupBusy = false;
581
607
  let idleCleanupHours = 24;
608
+ if (showUnknownChatsInput) {
609
+ showUnknownChatsInput.checked = readStoredSessionsShowUnknownChats(window.localStorage);
610
+ }
582
611
  function selectedIdleCleanupHours() {
583
612
  return idleCleanupHours;
584
613
  }
@@ -849,11 +878,13 @@ export function wireSessionsPage(root) {
849
878
  function rowHtml(s) {
850
879
  const closed = s.status === 'closed';
851
880
  const checked = selected.has(s.sessionId) ? 'checked' : '';
881
+ const location = sessionLocationText(s);
852
882
  return `<tr data-id="${escapeHtml(s.sessionId)}">
853
883
  <td><input type="checkbox" class="row-select" ${checked} ${closed ? 'disabled' : ''}></td>
854
884
  <td>${escapeHtml(botDisplayName(s))}</td>
855
885
  <td><span class="badge cli-${cssToken(s.cliId)}">${escapeHtml(s.cliId ?? 'unknown')}</span></td>
856
886
  <td>${statusBadgeHtml(s.status)}${lockChipHtml(s)}</td>
887
+ <td class="session-location-cell" title="${escapeHtml(sessionLocationTitle(s))}">${escapeHtml(location)}</td>
857
888
  <td class="token-cell">${formatTokenCount(s.tokenUsage?.in)}</td>
858
889
  <td class="token-cell">${formatTokenCount(s.tokenUsage?.out)}</td>
859
890
  <td title="${escapeHtml(String(s.title ?? ''))}">${escapeHtml(stripMentionPrefix(s.title ?? '').slice(0, 48))}</td>
@@ -1497,16 +1528,20 @@ export function wireSessionsPage(root) {
1497
1528
  const cliFilterActive = cli.length > 0 && cli.length < CLI_FILTER_OPTIONS.length;
1498
1529
  const status = f.get('status');
1499
1530
  const adopt = f.get('adopt');
1531
+ const chat = f.get('chat');
1500
1532
  const active = !!f.get('active');
1533
+ const showUnknownChats = !!f.get('showUnknownChats');
1501
1534
  // 看板视图的「已完成」列收纳已关闭会话——「仅活跃」开关不再把它们整体
1502
1535
  // 滤掉,否则该列永远是空的。
1503
1536
  const keepClosed = viewMode === 'kanban';
1504
1537
  const rows = [...store.sessions.values()]
1505
1538
  .filter(s => !cliFilterActive || cli.includes(s.cliId ?? 'unknown'))
1539
+ .filter(s => showUnknownChats || !isUnknownChatSession(s))
1506
1540
  .filter(s => !status || s.status === status)
1507
1541
  .filter(s => !adopt || (adopt === 'yes') === !!s.adopt)
1542
+ .filter(s => !chat || String(s.chatId ?? '') === chat)
1508
1543
  .filter(s => !active || keepClosed || s.status !== 'closed')
1509
- .filter(s => !q || JSON.stringify(s).toLowerCase().includes(q));
1544
+ .filter(s => !q || sessionSearchText(s).includes(q));
1510
1545
  rows.sort(compareRows);
1511
1546
  return rows;
1512
1547
  }
@@ -1519,6 +1554,8 @@ export function wireSessionsPage(root) {
1519
1554
  return tokenCount(s.tokenUsage?.out) ?? -1;
1520
1555
  if (key === 'adopt')
1521
1556
  return !!s.adopt;
1557
+ if (key === 'chat')
1558
+ return sessionLocationText(s).toLowerCase();
1522
1559
  return String(s[key] ?? '').toLowerCase();
1523
1560
  }
1524
1561
  function compareRows(a, b) {
@@ -1550,6 +1587,7 @@ export function wireSessionsPage(root) {
1550
1587
  const selectedRows = [...selected]
1551
1588
  .map(id => store.sessions.get(id))
1552
1589
  .filter((r) => !!r && r.status !== 'closed');
1590
+ bulkMonitorRoomBtn.disabled = selectedRows.length === 0;
1553
1591
  bulkLockBtn.disabled = !selectedRows.some(r => !r.locked);
1554
1592
  bulkUnlockBtn.disabled = !selectedRows.some(r => !!r.locked);
1555
1593
  const selectable = rows.filter(r => r.status !== 'closed');
@@ -1599,7 +1637,31 @@ export function wireSessionsPage(root) {
1599
1637
  countEl.textContent = checked === boxes.length ? t('common.all') : `${checked}/${boxes.length}`;
1600
1638
  countEl.classList.toggle('cli-filter-active', checked !== boxes.length);
1601
1639
  }
1640
+ function syncChatFilterOptions() {
1641
+ const prev = chatSelect.value;
1642
+ const showUnknownChats = !!filtersForm.querySelector('input[name="showUnknownChats"]')?.checked;
1643
+ const options = new Map();
1644
+ for (const row of store.sessions.values()) {
1645
+ const chatId = String(row.chatId ?? '').trim();
1646
+ if (!chatId)
1647
+ continue;
1648
+ if (!showUnknownChats && isUnknownChatSession(row))
1649
+ continue;
1650
+ const label = sessionLocationText(row);
1651
+ const existing = options.get(chatId);
1652
+ if (!existing || label < existing)
1653
+ options.set(chatId, label);
1654
+ }
1655
+ const rows = [...options.entries()].sort((a, b) => a[1].localeCompare(b[1]));
1656
+ const html = `<option value="">${escapeHtml(t('sessions.chatAny'))}</option>${rows.map(([chatId, label]) => `<option value="${escapeHtml(chatId)}">${escapeHtml(label)}</option>`).join('')}`;
1657
+ if (html !== lastChatFilterHtml) {
1658
+ chatSelect.innerHTML = html;
1659
+ lastChatFilterHtml = html;
1660
+ }
1661
+ chatSelect.value = prev && options.has(prev) ? prev : '';
1662
+ }
1602
1663
  function rerender() {
1664
+ syncChatFilterOptions();
1603
1665
  const rows = filtered();
1604
1666
  for (const sid of [...selected]) {
1605
1667
  const s = store.sessions.get(sid);
@@ -1614,7 +1676,7 @@ export function wireSessionsPage(root) {
1614
1676
  if (viewMode === 'table') {
1615
1677
  const tableHtml = rows.length
1616
1678
  ? rows.map(rowHtml).join('')
1617
- : `<tr><td colspan="12" class="empty">${t('sessions.empty')}</td></tr>`;
1679
+ : `<tr><td colspan="13" class="empty">${t('sessions.empty')}</td></tr>`;
1618
1680
  if (tableHtml !== lastTableHtml) {
1619
1681
  lastTableHtml = tableHtml;
1620
1682
  tbody.innerHTML = tableHtml;
@@ -1853,7 +1915,7 @@ export function wireSessionsPage(root) {
1853
1915
  <p><code>${escapeHtml(s.sessionId)}</code> <button data-copy="${escapeHtml(s.sessionId)}">${t('sessions.copy')}</button></p>
1854
1916
  </header>
1855
1917
  <p><b>${t('sessions.bot')}:</b> ${escapeHtml(botDisplayName(s))} · <b>${t('sessions.cli')}:</b> ${escapeHtml(s.cliId ?? '?')}</p>
1856
- ${chatDisplayTitle(s) ? `<p><b>${t('sessions.chat')}:</b> ${escapeHtml(chatDisplayTitle(s))}</p>` : ''}
1918
+ <p><b>${t('sessions.location')}:</b> ${escapeHtml(sessionLocationText(s))}</p>
1857
1919
  <p><b>chatId:</b> <code>${escapeHtml(s.chatId ?? '')}</code> <button data-copy="${escapeHtml(s.chatId ?? '')}">${t('sessions.copy')}</button></p>
1858
1920
  <p><b>rootMessageId:</b> <code>${escapeHtml(s.rootMessageId ?? '')}</code> <button data-copy="${escapeHtml(s.rootMessageId ?? '')}">${t('sessions.copy')}</button></p>
1859
1921
  ${s.threadId ? `<p><b>threadId:</b> <code>${escapeHtml(s.threadId)}</code></p>` : ''}
@@ -2161,6 +2223,9 @@ export function wireSessionsPage(root) {
2161
2223
  rerender();
2162
2224
  });
2163
2225
  });
2226
+ monitorRoomOpenBtn.addEventListener('click', () => {
2227
+ window.location.href = monitorRoomUrl();
2228
+ });
2164
2229
  groupByBox.querySelectorAll('[data-groupby]').forEach(btn => {
2165
2230
  btn.addEventListener('click', () => {
2166
2231
  const raw = btn.dataset.groupby;
@@ -2403,6 +2468,15 @@ export function wireSessionsPage(root) {
2403
2468
  selected.clear();
2404
2469
  rerender();
2405
2470
  });
2471
+ bulkMonitorRoomBtn.addEventListener('click', () => {
2472
+ const ids = [...selected].filter(id => !!store.sessions.get(id));
2473
+ const result = addMonitorRoomSessionIds(ids);
2474
+ const original = bulkMonitorRoomBtn.textContent;
2475
+ bulkMonitorRoomBtn.textContent = t('sessions.monitorRoomAdded', { added: result.added, total: result.total });
2476
+ window.setTimeout(() => {
2477
+ bulkMonitorRoomBtn.textContent = original;
2478
+ }, 1800);
2479
+ });
2406
2480
  bulkCloseBtn.addEventListener('click', async () => {
2407
2481
  const ids = [...selected];
2408
2482
  if (ids.length === 0)
@@ -2568,6 +2642,13 @@ export function wireSessionsPage(root) {
2568
2642
  });
2569
2643
  });
2570
2644
  filtersForm.addEventListener('input', rerender);
2645
+ filtersForm.addEventListener('change', event => {
2646
+ const target = event.target;
2647
+ if (target?.name === 'showUnknownChats') {
2648
+ writeStoredSessionsShowUnknownChats(window.localStorage, target.checked);
2649
+ rerender();
2650
+ }
2651
+ });
2571
2652
  const unsubscribeStore = store.on(rerender);
2572
2653
  // 团队看板 30s 软刷新(拉对方部署的会话快照与共享编排);页面切走后
2573
2654
  // kanban 脱离 DOM,定时器自清。