botmux 2.13.2 → 2.14.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 (58) hide show
  1. package/dist/core/command-handler.d.ts.map +1 -1
  2. package/dist/core/command-handler.js +10 -4
  3. package/dist/core/command-handler.js.map +1 -1
  4. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  5. package/dist/core/dashboard-ipc-server.js +65 -3
  6. package/dist/core/dashboard-ipc-server.js.map +1 -1
  7. package/dist/core/dashboard-rows.d.ts.map +1 -1
  8. package/dist/core/dashboard-rows.js +6 -1
  9. package/dist/core/dashboard-rows.js.map +1 -1
  10. package/dist/core/scheduler.d.ts +1 -0
  11. package/dist/core/scheduler.d.ts.map +1 -1
  12. package/dist/core/scheduler.js +1 -0
  13. package/dist/core/scheduler.js.map +1 -1
  14. package/dist/core/session-manager.d.ts.map +1 -1
  15. package/dist/core/session-manager.js +90 -52
  16. package/dist/core/session-manager.js.map +1 -1
  17. package/dist/core/types.d.ts +18 -2
  18. package/dist/core/types.d.ts.map +1 -1
  19. package/dist/core/types.js +14 -3
  20. package/dist/core/types.js.map +1 -1
  21. package/dist/core/worker-pool.d.ts.map +1 -1
  22. package/dist/core/worker-pool.js +22 -22
  23. package/dist/core/worker-pool.js.map +1 -1
  24. package/dist/daemon.d.ts.map +1 -1
  25. package/dist/daemon.js +131 -80
  26. package/dist/daemon.js.map +1 -1
  27. package/dist/dashboard/operator-selector.d.ts +17 -0
  28. package/dist/dashboard/operator-selector.d.ts.map +1 -0
  29. package/dist/dashboard/operator-selector.js +37 -0
  30. package/dist/dashboard/operator-selector.js.map +1 -0
  31. package/dist/dashboard/web/groups.d.ts.map +1 -1
  32. package/dist/dashboard/web/groups.js +61 -7
  33. package/dist/dashboard/web/groups.js.map +1 -1
  34. package/dist/dashboard-web/app.js +60 -53
  35. package/dist/dashboard-web/style.css +10 -1
  36. package/dist/dashboard.js +119 -34
  37. package/dist/dashboard.js.map +1 -1
  38. package/dist/im/lark/card-handler.js +8 -8
  39. package/dist/im/lark/card-handler.js.map +1 -1
  40. package/dist/im/lark/client.d.ts +20 -0
  41. package/dist/im/lark/client.d.ts.map +1 -1
  42. package/dist/im/lark/client.js +65 -8
  43. package/dist/im/lark/client.js.map +1 -1
  44. package/dist/im/lark/event-dispatcher.d.ts +39 -4
  45. package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
  46. package/dist/im/lark/event-dispatcher.js +84 -49
  47. package/dist/im/lark/event-dispatcher.js.map +1 -1
  48. package/dist/services/groups-store.d.ts +22 -0
  49. package/dist/services/groups-store.d.ts.map +1 -1
  50. package/dist/services/groups-store.js +39 -1
  51. package/dist/services/groups-store.js.map +1 -1
  52. package/dist/services/schedule-store.d.ts +1 -0
  53. package/dist/services/schedule-store.d.ts.map +1 -1
  54. package/dist/services/schedule-store.js +1 -0
  55. package/dist/services/schedule-store.js.map +1 -1
  56. package/dist/types.d.ts +12 -0
  57. package/dist/types.d.ts.map +1 -1
  58. package/package.json +1 -1
@@ -0,0 +1,17 @@
1
+ export interface SelectorSession {
2
+ ownerOpenId?: string;
3
+ larkAppId?: string;
4
+ status?: string;
5
+ lastMessageAt?: number;
6
+ }
7
+ export interface OperatorPick {
8
+ openId: string;
9
+ larkAppId: string;
10
+ }
11
+ /**
12
+ * Return the most-recent active session whose owner can be auto-invited
13
+ * (sessions whose larkAppId points at a daemon that's currently online).
14
+ * Closed sessions and sessions without ownerOpenId/larkAppId are skipped.
15
+ */
16
+ export declare function pickOperatorForCreate(sessions: Iterable<SelectorSession>, isOnline: (larkAppId: string) => boolean): OperatorPick | null;
17
+ //# sourceMappingURL=operator-selector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operator-selector.d.ts","sourceRoot":"","sources":["../../src/dashboard/operator-selector.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,eAAe;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,QAAQ,CAAC,eAAe,CAAC,EACnC,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,GACvC,YAAY,GAAG,IAAI,CAYrB"}
@@ -0,0 +1,37 @@
1
+ // src/dashboard/operator-selector.ts
2
+ //
3
+ // Helper for the "Create new group" flow: when the dashboard auto-invites the
4
+ // operator into the freshly-created chat, the operator's `open_id` and the
5
+ // creator bot must come from the SAME Lark app — Feishu open_ids are app-
6
+ // scoped, so using bot A as creator with bot B's open_id of the user lands the
7
+ // user in `invalid_user_id_list` and the chat ends up with only bots in it.
8
+ //
9
+ // This module isolates the selection logic so it's unit-testable independent
10
+ // of the rest of dashboard.ts (which is a pm2 entry script, awkward to test).
11
+ //
12
+ // Selection rule: from the aggregator's session cache, pick the most-recent
13
+ // non-closed session whose `larkAppId` corresponds to a currently-online
14
+ // daemon. Both the operator's `open_id` and the creator daemon are derived
15
+ // from that single session so the scope matches.
16
+ /**
17
+ * Return the most-recent active session whose owner can be auto-invited
18
+ * (sessions whose larkAppId points at a daemon that's currently online).
19
+ * Closed sessions and sessions without ownerOpenId/larkAppId are skipped.
20
+ */
21
+ export function pickOperatorForCreate(sessions, isOnline) {
22
+ let best = null;
23
+ for (const s of sessions) {
24
+ if (s.status === 'closed')
25
+ continue;
26
+ if (!s.ownerOpenId || !s.larkAppId)
27
+ continue;
28
+ if (!isOnline(s.larkAppId))
29
+ continue;
30
+ const ts = s.lastMessageAt ?? 0;
31
+ if (!best || ts > best.lastMessageAt) {
32
+ best = { openId: s.ownerOpenId, larkAppId: s.larkAppId, lastMessageAt: ts };
33
+ }
34
+ }
35
+ return best ? { openId: best.openId, larkAppId: best.larkAppId } : null;
36
+ }
37
+ //# sourceMappingURL=operator-selector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operator-selector.js","sourceRoot":"","sources":["../../src/dashboard/operator-selector.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,0EAA0E;AAC1E,+EAA+E;AAC/E,4EAA4E;AAC5E,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,EAAE;AACF,4EAA4E;AAC5E,yEAAyE;AACzE,2EAA2E;AAC3E,iDAAiD;AAcjD;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CACnC,QAAmC,EACnC,QAAwC;IAExC,IAAI,IAAI,GAAwE,IAAI,CAAC;IACrF,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ;YAAE,SAAS;QACpC,IAAI,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,SAAS;YAAE,SAAS;QAC7C,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;YAAE,SAAS;QACrC,MAAM,EAAE,GAAG,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,IAAI,EAAE,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;YACrC,IAAI,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC;QAC9E,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1E,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"groups.d.ts","sourceRoot":"","sources":["../../../src/dashboard/web/groups.ts"],"names":[],"mappings":"AA8BA,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,WAAW,iBAiMvD"}
1
+ {"version":3,"file":"groups.d.ts","sourceRoot":"","sources":["../../../src/dashboard/web/groups.ts"],"names":[],"mappings":"AA8BA,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,WAAW,iBAyPvD"}
@@ -97,24 +97,78 @@ export async function renderGroupsPage(root) {
97
97
  });
98
98
  const respBody = await r.json();
99
99
  if (respBody.ok && respBody.chatId) {
100
- const invalid = respBody.invalidBotIds ?? [];
101
- const tail = invalid.length ? `\n\nInvalid bot ids: ${invalid.join(', ')}` : '';
102
- alert(`Group created.\nchatId: ${respBody.chatId}\ncreator: ${respBody.creator ?? '?'}${tail}`);
103
- await loadGroups();
104
- rerender();
100
+ renderCreateSuccess(respBody);
101
+ // Refresh matrix in the background so the new chat eventually shows
102
+ // up won't block the success drawer.
103
+ void loadGroups().then(rerender).catch(() => { });
105
104
  }
106
105
  else {
107
106
  alert(`Failed: ${respBody.error ?? r.status}`);
107
+ drawer.close();
108
108
  }
109
109
  }
110
110
  catch (e) {
111
111
  alert('Network error: ' + e);
112
- }
113
- finally {
114
112
  drawer.close();
115
113
  }
116
114
  };
117
115
  }
116
+ function renderCreateSuccess(resp) {
117
+ const chatId = String(resp.chatId);
118
+ const appLink = `https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(chatId)}`;
119
+ const invalidBots = (resp.invalidBotIds ?? []);
120
+ const invalidUsers = (resp.invalidUserIds ?? []);
121
+ const auto = resp.autoInvitedOpenId;
122
+ const rejected = !!resp.autoInviteRejected;
123
+ const ownerTo = resp.ownerTransferredTo;
124
+ const transferErr = resp.transferError;
125
+ const notifyMsgId = resp.notifyMessageId;
126
+ const notifyErr = resp.notifyError;
127
+ let inviteNote;
128
+ if (auto) {
129
+ const transferLine = ownerTo
130
+ ? `<br><small>群主已从机器人转让给你。</small>`
131
+ : transferErr
132
+ ? `<br><small class="hint-warn-inline">⚠ 自动转让群主失败(${escapeHtml(transferErr)}),你现在是成员但群主仍是机器人。</small>`
133
+ : '';
134
+ const notifyLine = notifyMsgId
135
+ ? `<br><small>机器人已在群里 @ 了你(消息 id <code>${escapeHtml(notifyMsgId)}</code>),看飞书通知就能进群。</small>`
136
+ : notifyErr
137
+ ? `<br><small class="hint-warn-inline">⚠ 自动 @ 通知失败(${escapeHtml(notifyErr)}),新群可能不会主动出现在你侧边栏,建议从下面按钮跳进去。</small>`
138
+ : '';
139
+ inviteNote = `<p class="hint-ok">已自动邀请你(<code>${escapeHtml(auto)}</code>)作为成员。${transferLine}${notifyLine}</p>`;
140
+ }
141
+ else if (rejected) {
142
+ inviteNote = `<p class="hint-warn">飞书拒绝了自动邀请(你的 open_id 在创建者 bot 的 scope 下不可用)。<strong>你目前不是新群成员</strong>,需要让群里的某个机器人手动把你加进来。</p>`;
143
+ }
144
+ else {
145
+ inviteNote = `<p class="hint-warn">没在 dashboard 缓存里找到 ownerOpenId,<strong>没有自动邀请你</strong>。点开下面链接前,先让群里任一机器人手动把你加进去。</p>`;
146
+ }
147
+ const invalidNote = [
148
+ invalidBots.length ? `<li>无效 bot id: <code>${invalidBots.map(escapeHtml).join(', ')}</code></li>` : '',
149
+ invalidUsers.length ? `<li>无效用户 open_id: <code>${invalidUsers.map(escapeHtml).join(', ')}</code></li>` : '',
150
+ ].filter(Boolean).join('');
151
+ drawer.innerHTML = `
152
+ <article>
153
+ <header><h3>群创建成功</h3></header>
154
+ <p><b>chatId:</b> <code>${escapeHtml(chatId)}</code> <button type="button" data-copy="${escapeHtml(chatId)}">copy</button></p>
155
+ <p><b>创建者:</b> <code>${escapeHtml(resp.creator ?? '?')}</code></p>
156
+ ${inviteNote}
157
+ ${invalidNote ? `<ul>${invalidNote}</ul>` : ''}
158
+ <div class="actions">
159
+ <a class="btn-link primary" href="${appLink}" target="_blank" rel="noopener">↗ 打开新群</a>
160
+ <button type="button" id="g-create-close">关闭</button>
161
+ </div>
162
+ </article>`;
163
+ drawer.querySelectorAll('[data-copy]').forEach(b => {
164
+ b.onclick = () => {
165
+ navigator.clipboard.writeText(b.dataset.copy ?? '');
166
+ b.textContent = 'copied';
167
+ setTimeout(() => { b.textContent = 'copy'; }, 800);
168
+ };
169
+ });
170
+ drawer.querySelector('#g-create-close').onclick = () => drawer.close();
171
+ }
118
172
  function renderHead() {
119
173
  head.innerHTML = `<tr>
120
174
  <th>chat</th>
@@ -1 +1 @@
1
- {"version":3,"file":"groups.js","sourceRoot":"","sources":["../../../src/dashboard/web/groups.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"groups.js","sourceRoot":"","sources":["../../../src/dashboard/web/groups.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- "use strict";(()=>{var v=class{sessions=new Map;schedules=new Map;online=!0;listeners=new Set;upsertSessions(t){for(let i of t)this.sessions.set(i.sessionId,i);this.emit()}upsertSchedules(t){for(let i of t)this.schedules.set(i.id,i);this.emit()}applySse(t,i){if(t==="session.spawned")this.sessions.set(i.session.sessionId,i.session);else if(t==="session.update"){let u=this.sessions.get(i.sessionId);u&&this.sessions.set(i.sessionId,{...u,...i.patch})}else if(t==="session.exited"){let u=this.sessions.get(i.sessionId);u&&this.sessions.set(i.sessionId,{...u,status:"closed"})}else if(t==="schedule.created")this.schedules.set(i.schedule.id,i.schedule);else if(t==="schedule.updated"){let u=this.schedules.get(i.id);u&&this.schedules.set(i.id,{...u,...i.patch})}else if(t==="schedule.deleted")this.schedules.delete(i.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()}},m=new v;async function A(){let[n,t]=await Promise.all([fetch("/api/sessions").then(f=>f.json()),fetch("/api/schedules").then(f=>f.json())]);m.upsertSessions(n.sessions??[]),m.upsertSchedules(t.schedules??[]);let i=new EventSource("/events"),u=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let f of u)i.addEventListener(f,s=>{try{let h=JSON.parse(s.data);m.applySse(f,h.body??h)}catch{}});i.onerror=()=>m.setOnline(!1),i.onopen=()=>m.setOnline(!0)}var _=`
1
+ "use strict";(()=>{var A=class{sessions=new Map;schedules=new Map;online=!0;listeners=new Set;upsertSessions(t){for(let r of t)this.sessions.set(r.sessionId,r);this.emit()}upsertSchedules(t){for(let r of t)this.schedules.set(r.id,r);this.emit()}applySse(t,r){if(t==="session.spawned")this.sessions.set(r.session.sessionId,r.session);else if(t==="session.update"){let u=this.sessions.get(r.sessionId);u&&this.sessions.set(r.sessionId,{...u,...r.patch})}else if(t==="session.exited"){let u=this.sessions.get(r.sessionId);u&&this.sessions.set(r.sessionId,{...u,status:"closed"})}else if(t==="schedule.created")this.schedules.set(r.schedule.id,r.schedule);else if(t==="schedule.updated"){let u=this.schedules.get(r.id);u&&this.schedules.set(r.id,{...u,...r.patch})}else if(t==="schedule.deleted")this.schedules.delete(r.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()}},b=new A;async function N(){let[o,t]=await Promise.all([fetch("/api/sessions").then(g=>g.json()),fetch("/api/schedules").then(g=>g.json())]);b.upsertSessions(o.sessions??[]),b.upsertSchedules(t.schedules??[]);let r=new EventSource("/events"),u=["session.spawned","session.update","session.exited","schedule.created","schedule.updated","schedule.deleted","schedule.fired","heartbeat"];for(let g of u)r.addEventListener(g,n=>{try{let f=JSON.parse(n.data);b.applySse(g,f.body??f)}catch{}});r.onerror=()=>b.setOnline(!1),r.onopen=()=>b.setOnline(!0)}var G=`
2
2
  <form id="filters" class="filters">
3
3
  <input type="search" name="q" placeholder="search workingDir / title / ids" />
4
4
  <select name="cli" multiple size="4">
@@ -30,34 +30,34 @@
30
30
  <tbody></tbody>
31
31
  </table>
32
32
  <dialog id="drawer"></dialog>
33
- `;function q(n){if(!n)return"-";let t=Date.now()-n;return t<6e4?"now":t<36e5?Math.floor(t/6e4)+"m":t<864e5?Math.floor(t/36e5)+"h":Math.floor(t/864e5)+"d"}function p(n){return n.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}var j="\u{1FA9E}",L="\u{1F4CD}",G="\u{1F5A5}\uFE0F";function N(n){n.innerHTML=_;let t=n.querySelector("#sessions-table tbody"),i=n.querySelector("#filters"),u=n.querySelector("#drawer");function f(e){return`<tr data-id="${p(e.sessionId)}">
34
- <td>${p(e.botName??"")}</td>
35
- <td><span class="badge cli-${p(e.cliId??"unknown")}">${p(e.cliId??"unknown")}</span></td>
36
- <td><span class="status status-${p(e.status)}">${p(e.status)}</span></td>
37
- <td>${p((e.title??"").slice(0,40))}</td>
38
- <td title="${p(e.workingDir??"")}">${p((e.workingDir??"").slice(-30))}</td>
39
- <td>${q(e.spawnedAt)}</td>
40
- <td>${q(e.lastMessageAt)}</td>
41
- <td>${e.adopt?j:""}</td>
33
+ `;function R(o){if(!o)return"-";let t=Date.now()-o;return t<6e4?"now":t<36e5?Math.floor(t/6e4)+"m":t<864e5?Math.floor(t/36e5)+"h":Math.floor(t/864e5)+"d"}function h(o){return o.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}var J="\u{1FA9E}",M="\u{1F4CD}",z="\u{1F5A5}\uFE0F";function D(o){o.innerHTML=G;let t=o.querySelector("#sessions-table tbody"),r=o.querySelector("#filters"),u=o.querySelector("#drawer");function g(e){return`<tr data-id="${h(e.sessionId)}">
34
+ <td>${h(e.botName??"")}</td>
35
+ <td><span class="badge cli-${h(e.cliId??"unknown")}">${h(e.cliId??"unknown")}</span></td>
36
+ <td><span class="status status-${h(e.status)}">${h(e.status)}</span></td>
37
+ <td>${h((e.title??"").slice(0,40))}</td>
38
+ <td title="${h(e.workingDir??"")}">${h((e.workingDir??"").slice(-30))}</td>
39
+ <td>${R(e.spawnedAt)}</td>
40
+ <td>${R(e.lastMessageAt)}</td>
41
+ <td>${e.adopt?J:""}</td>
42
42
  <td><button class="open">\u22EF</button></td>
43
- </tr>`}function s(){let e=new FormData(i),l=(e.get("q")??"").toLowerCase(),a=e.getAll("cli"),r=e.get("status"),d=e.get("adopt"),g=!!e.get("active");return[...m.sessions.values()].filter(o=>!a.length||a.includes(o.cliId??"unknown")).filter(o=>!r||o.status===r).filter(o=>!d||d==="yes"==!!o.adopt).filter(o=>!g||o.status!=="closed").filter(o=>!l||JSON.stringify(o).toLowerCase().includes(l)).sort((o,b)=>(b.lastMessageAt??0)-(o.lastMessageAt??0))}function h(){t.innerHTML=s().map(f).join("")}function w(e){let l=e.status==="closed";u.innerHTML=`
43
+ </tr>`}function n(){let e=new FormData(r),p=(e.get("q")??"").toLowerCase(),i=e.getAll("cli"),s=e.get("status"),a=e.get("adopt"),$=!!e.get("active");return[...b.sessions.values()].filter(l=>!i.length||i.includes(l.cliId??"unknown")).filter(l=>!s||l.status===s).filter(l=>!a||a==="yes"==!!l.adopt).filter(l=>!$||l.status!=="closed").filter(l=>!p||JSON.stringify(l).toLowerCase().includes(p)).sort((l,c)=>(c.lastMessageAt??0)-(l.lastMessageAt??0))}function f(){t.innerHTML=n().map(g).join("")}function w(e){let p=e.status==="closed";u.innerHTML=`
44
44
  <article>
45
45
  <header>
46
- <h3>${p(e.title??e.sessionId)}</h3>
47
- <code>${p(e.sessionId)}</code> <button data-copy="${p(e.sessionId)}">copy</button>
46
+ <h3>${h(e.title??e.sessionId)}</h3>
47
+ <code>${h(e.sessionId)}</code> <button data-copy="${h(e.sessionId)}">copy</button>
48
48
  </header>
49
- <p><b>bot:</b> ${p(e.botName??"-")} \xB7 <b>cli:</b> ${p(e.cliId??"?")} \xB7 <b>status:</b> ${p(e.status)}</p>
50
- <p><b>chatId:</b> <code>${p(e.chatId)}</code> <button data-copy="${p(e.chatId)}">copy</button></p>
51
- <p><b>rootMessageId:</b> <code>${p(e.rootMessageId??"")}</code> <button data-copy="${p(e.rootMessageId??"")}">copy</button></p>
52
- ${e.threadId?`<p><b>threadId:</b> <code>${p(e.threadId)}</code></p>`:""}
53
- <p><b>workingDir:</b> ${p(e.workingDir??"-")}</p>
49
+ <p><b>bot:</b> ${h(e.botName??"-")} \xB7 <b>cli:</b> ${h(e.cliId??"?")} \xB7 <b>status:</b> ${h(e.status)}</p>
50
+ <p><b>chatId:</b> <code>${h(e.chatId)}</code> <button data-copy="${h(e.chatId)}">copy</button></p>
51
+ <p><b>rootMessageId:</b> <code>${h(e.rootMessageId??"")}</code> <button data-copy="${h(e.rootMessageId??"")}">copy</button></p>
52
+ ${e.threadId?`<p><b>threadId:</b> <code>${h(e.threadId)}</code></p>`:""}
53
+ <p><b>workingDir:</b> ${h(e.workingDir??"-")}</p>
54
54
  <div class="actions">
55
- <button id="locate-btn" type="button">${L} \u5B9A\u4F4D\u5230\u98DE\u4E66\u8BDD\u9898</button>
56
- ${e.webPort?`<a class="btn-link" href="http://${p(location.hostname)}:${e.webPort}" target="_blank">${G} \u6253\u5F00 xterm</a>`:""}
57
- ${l?"":'<button id="close-btn" type="button" class="contrast">\u5173\u95ED\u4F1A\u8BDD</button>'}
55
+ <button id="locate-btn" type="button">${M} \u5B9A\u4F4D\u5230\u98DE\u4E66\u8BDD\u9898</button>
56
+ ${e.webPort?`<a class="btn-link" href="http://${h(location.hostname)}:${e.webPort}" target="_blank">${z} \u6253\u5F00 xterm</a>`:""}
57
+ ${p?"":'<button id="close-btn" type="button" class="contrast">\u5173\u95ED\u4F1A\u8BDD</button>'}
58
58
  </div>
59
59
  <form method="dialog"><button>\u5173\u95ED</button></form>
60
- </article>`,u.querySelectorAll("[data-copy]").forEach(d=>{d.onclick=()=>{navigator.clipboard.writeText(d.dataset.copy??""),d.textContent="copied",setTimeout(()=>{d.textContent="copy"},800)}});let a=u.querySelector("#locate-btn");a&&(a.onclick=async()=>{a.disabled=!0,a.textContent=`${L} \u53D1\u9001\u4E2D...`;try{let d=await fetch(`/api/sessions/${encodeURIComponent(e.sessionId)}/locate`,{method:"POST"}),g=await d.json();if(g.ok){let o=30;a.textContent=`${L} (\u51B7\u5374 ${o}s)`;let b=setInterval(()=>{o-=1,o<=0?(clearInterval(b),a.disabled=!1,a.textContent=`${L} \u5B9A\u4F4D\u5230\u98DE\u4E66\u8BDD\u9898`):a.textContent=`${L} (\u51B7\u5374 ${o}s)`},1e3)}else{let o=g.error??d.status;alert("Locate failed: "+o),a.disabled=!1,a.textContent=`${L} \u5B9A\u4F4D\u5230\u98DE\u4E66\u8BDD\u9898`}}catch(d){alert("Locate error: "+d),a.disabled=!1,a.textContent=`${L} \u5B9A\u4F4D\u5230\u98DE\u4E66\u8BDD\u9898`}});let r=u.querySelector("#close-btn");r&&(r.onclick=async()=>{if(confirm("\u5173\u95ED\u8FD9\u4E2A\u4F1A\u8BDD?")){r.disabled=!0;try{await fetch(`/api/sessions/${encodeURIComponent(e.sessionId)}/close`,{method:"POST"})}finally{u.close()}}}),u.showModal()}t.addEventListener("click",e=>{let l=e.target.closest("tr[data-id]");if(!l)return;let a=l.dataset.id,r=m.sessions.get(a);r&&w(r)}),i.addEventListener("input",h),m.on(h),h()}var J=`
60
+ </article>`,u.querySelectorAll("[data-copy]").forEach(a=>{a.onclick=()=>{navigator.clipboard.writeText(a.dataset.copy??""),a.textContent="copied",setTimeout(()=>{a.textContent="copy"},800)}});let i=u.querySelector("#locate-btn");i&&(i.onclick=async()=>{i.disabled=!0,i.textContent=`${M} \u53D1\u9001\u4E2D...`;try{let a=await fetch(`/api/sessions/${encodeURIComponent(e.sessionId)}/locate`,{method:"POST"}),$=await a.json();if($.ok){let l=30;i.textContent=`${M} (\u51B7\u5374 ${l}s)`;let c=setInterval(()=>{l-=1,l<=0?(clearInterval(c),i.disabled=!1,i.textContent=`${M} \u5B9A\u4F4D\u5230\u98DE\u4E66\u8BDD\u9898`):i.textContent=`${M} (\u51B7\u5374 ${l}s)`},1e3)}else{let l=$.error??a.status;alert("Locate failed: "+l),i.disabled=!1,i.textContent=`${M} \u5B9A\u4F4D\u5230\u98DE\u4E66\u8BDD\u9898`}}catch(a){alert("Locate error: "+a),i.disabled=!1,i.textContent=`${M} \u5B9A\u4F4D\u5230\u98DE\u4E66\u8BDD\u9898`}});let s=u.querySelector("#close-btn");s&&(s.onclick=async()=>{if(confirm("\u5173\u95ED\u8FD9\u4E2A\u4F1A\u8BDD?")){s.disabled=!0;try{await fetch(`/api/sessions/${encodeURIComponent(e.sessionId)}/close`,{method:"POST"})}finally{u.close()}}}),u.showModal()}t.addEventListener("click",e=>{let p=e.target.closest("tr[data-id]");if(!p)return;let i=p.dataset.id,s=b.sessions.get(i);s&&w(s)}),r.addEventListener("input",f),b.on(f),f()}var W=`
61
61
  <form id="sched-filters" class="filters">
62
62
  <input type="search" name="q" placeholder="search name / prompt / workingDir" />
63
63
  <select name="kind">
@@ -75,19 +75,19 @@
75
75
  </tr></thead>
76
76
  <tbody id="schedules-tbody"></tbody>
77
77
  </table>
78
- `;function E(n){return n.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}function B(n){if(!n)return"\u2014";try{return new Date(n).toLocaleString()}catch{return n}}function D(n){n.innerHTML=J;let t=n.querySelector("#schedules-tbody"),i=n.querySelector("#sched-filters");function u(){let s=new FormData(i),h=(s.get("q")??"").toLowerCase(),w=s.get("kind"),e=!!s.get("enabled");return[...m.schedules.values()].filter(l=>!w||l.parsed?.kind===w).filter(l=>!e||l.enabled).filter(l=>!h||JSON.stringify(l).toLowerCase().includes(h)).sort((l,a)=>{if(l.enabled!==a.enabled)return l.enabled?-1:1;let r=l.nextRunAt?Date.parse(l.nextRunAt):1/0,d=a.nextRunAt?Date.parse(a.nextRunAt):1/0;return r-d})}function f(){t.innerHTML=u().map(s=>`<tr data-id="${E(s.id)}">
79
- <td>${E(s.name??s.id)}</td>
80
- <td>${E(s.botName??s.larkAppId??"-")}</td>
81
- <td><code>${E(s.parsed?.display??"?")}</code></td>
82
- <td>${B(s.nextRunAt)}</td>
83
- <td>${B(s.lastRunAt)} ${s.lastStatus==="error"?"\u26A0\uFE0F":""}</td>
84
- <td>${s.repeat?`${s.repeat.completed}/${s.repeat.times??"\u221E"}`:"\u2014"}</td>
85
- <td>${s.enabled?"\u2713":"\u2717"}</td>
78
+ `;function C(o){return o.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}function O(o){if(!o)return"\u2014";try{return new Date(o).toLocaleString()}catch{return o}}function P(o){o.innerHTML=W;let t=o.querySelector("#schedules-tbody"),r=o.querySelector("#sched-filters");function u(){let n=new FormData(r),f=(n.get("q")??"").toLowerCase(),w=n.get("kind"),e=!!n.get("enabled");return[...b.schedules.values()].filter(p=>!w||p.parsed?.kind===w).filter(p=>!e||p.enabled).filter(p=>!f||JSON.stringify(p).toLowerCase().includes(f)).sort((p,i)=>{if(p.enabled!==i.enabled)return p.enabled?-1:1;let s=p.nextRunAt?Date.parse(p.nextRunAt):1/0,a=i.nextRunAt?Date.parse(i.nextRunAt):1/0;return s-a})}function g(){t.innerHTML=u().map(n=>`<tr data-id="${C(n.id)}">
79
+ <td>${C(n.name??n.id)}</td>
80
+ <td>${C(n.botName??n.larkAppId??"-")}</td>
81
+ <td><code>${C(n.parsed?.display??"?")}</code></td>
82
+ <td>${O(n.nextRunAt)}</td>
83
+ <td>${O(n.lastRunAt)} ${n.lastStatus==="error"?"\u26A0\uFE0F":""}</td>
84
+ <td>${n.repeat?`${n.repeat.completed}/${n.repeat.times??"\u221E"}`:"\u2014"}</td>
85
+ <td>${n.enabled?"\u2713":"\u2717"}</td>
86
86
  <td class="actions-cell">
87
87
  <button data-op="run" type="button">Run now</button>
88
- ${s.enabled?'<button data-op="pause" type="button">Pause</button>':'<button data-op="resume" type="button">Resume</button>'}
88
+ ${n.enabled?'<button data-op="pause" type="button">Pause</button>':'<button data-op="resume" type="button">Resume</button>'}
89
89
  </td>
90
- </tr>`).join("")||'<tr><td colspan="8" class="empty">No schedules.</td></tr>'}t.addEventListener("click",async s=>{let h=s.target.closest("button[data-op]");if(!h)return;let w=h.closest("tr[data-id]");if(!w)return;let e=w.dataset.id,l=h.dataset.op;h.disabled=!0;let a=h.textContent;h.textContent="...";try{let r=await fetch(`/api/schedules/${encodeURIComponent(e)}/${l}`,{method:"POST"}),d=await r.json().catch(()=>({}));(!r.ok||d.ok===!1)&&alert(`Failed: ${r.status} ${d?.error??""}`.trim())}catch(r){alert("Network error: "+r)}finally{h.disabled=!1,h.textContent=a}}),i.addEventListener("input",f),m.on(f),f()}var I={chats:[],bots:[]},U=`
90
+ </tr>`).join("")||'<tr><td colspan="8" class="empty">No schedules.</td></tr>'}t.addEventListener("click",async n=>{let f=n.target.closest("button[data-op]");if(!f)return;let w=f.closest("tr[data-id]");if(!w)return;let e=w.dataset.id,p=f.dataset.op;f.disabled=!0;let i=f.textContent;f.textContent="...";try{let s=await fetch(`/api/schedules/${encodeURIComponent(e)}/${p}`,{method:"POST"}),a=await s.json().catch(()=>({}));(!s.ok||a.ok===!1)&&alert(`Failed: ${s.status} ${a?.error??""}`.trim())}catch(s){alert("Network error: "+s)}finally{f.disabled=!1,f.textContent=i}}),r.addEventListener("input",g),b.on(g),g()}var T={chats:[],bots:[]},K=`
91
91
  <form id="g-filters" class="filters">
92
92
  <input type="search" name="q" placeholder="search chat name / id / owner" />
93
93
  <label><input type="checkbox" name="missing"> missing-bot only</label>
@@ -99,7 +99,7 @@
99
99
  <tbody id="g-body"></tbody>
100
100
  </table>
101
101
  <dialog id="g-drawer"></dialog>
102
- `;function y(n){return n.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}async function H(){I=await(await fetch("/api/groups")).json()}async function P(n){n.innerHTML=U;let t=n.querySelector("#g-head"),i=n.querySelector("#g-body"),u=n.querySelector("#g-filters"),f=n.querySelector("#g-refresh"),s=n.querySelector("#g-drawer");f.onclick=async()=>{f.disabled=!0;try{await H(),l()}finally{f.disabled=!1}};let h=n.querySelector("#g-create");h.onclick=()=>w(),await H();function w(){let a=I.bots;if(a.length===0){alert("No bots online. Restart the daemon first.");return}s.innerHTML=`
102
+ `;function m(o){return o.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}async function x(){T=await(await fetch("/api/groups")).json()}async function j(o){o.innerHTML=K;let t=o.querySelector("#g-head"),r=o.querySelector("#g-body"),u=o.querySelector("#g-filters"),g=o.querySelector("#g-refresh"),n=o.querySelector("#g-drawer");g.onclick=async()=>{g.disabled=!0;try{await x(),i()}finally{g.disabled=!1}};let f=o.querySelector("#g-create");f.onclick=()=>w(),await x();function w(){let s=T.bots;if(s.length===0){alert("No bots online. Restart the daemon first.");return}n.innerHTML=`
103
103
  <article>
104
104
  <header><h3>Create new group</h3></header>
105
105
  <p>Pick bots to invite. The dashboard auto-selects an online daemon as the chat creator/owner; the rest are added as members in the same call.</p>
@@ -110,10 +110,10 @@
110
110
  </label>
111
111
  <fieldset>
112
112
  <legend>Bots</legend>
113
- ${a.map(r=>`
113
+ ${s.map(a=>`
114
114
  <label class="checkbox-row">
115
- <input type="checkbox" name="bot" value="${y(r.larkAppId)}">
116
- ${y(r.botName??r.larkAppId)} <small>(${y(r.larkAppId)})</small>
115
+ <input type="checkbox" name="bot" value="${m(a.larkAppId)}">
116
+ ${m(a.botName??a.larkAppId)} <small>(${m(a.larkAppId)})</small>
117
117
  </label>
118
118
  `).join("")}
119
119
  </fieldset>
@@ -122,30 +122,37 @@
122
122
  <button type="button" id="g-create-cancel">Cancel</button>
123
123
  </div>
124
124
  </form>
125
- </article>`,s.showModal(),s.querySelector("#g-create-cancel").onclick=()=>s.close(),s.querySelector("#g-createform").onsubmit=async r=>{r.preventDefault();let d=new FormData(r.target),g=(d.get("name")??"").trim(),o=d.getAll("bot");if(o.length===0){alert("Pick at least one bot.");return}let b=r.target.querySelector("button[type=submit]");b&&(b.disabled=!0,b.textContent="Creating...");try{let c=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:g||void 0,larkAppIds:o})}),$=await c.json();if($.ok&&$.chatId){let M=$.invalidBotIds??[],k=M.length?`
126
-
127
- Invalid bot ids: ${M.join(", ")}`:"";alert(`Group created.
128
- chatId: ${$.chatId}
129
- creator: ${$.creator??"?"}${k}`),await H(),l()}else alert(`Failed: ${$.error??c.status}`)}catch(c){alert("Network error: "+c)}finally{s.close()}}}function e(){t.innerHTML=`<tr>
125
+ </article>`,n.showModal(),n.querySelector("#g-create-cancel").onclick=()=>n.close(),n.querySelector("#g-createform").onsubmit=async a=>{a.preventDefault();let $=new FormData(a.target),l=($.get("name")??"").trim(),c=$.getAll("bot");if(c.length===0){alert("Pick at least one bot.");return}let y=a.target.querySelector("button[type=submit]");y&&(y.disabled=!0,y.textContent="Creating...");try{let d=await fetch("/api/groups/create",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:l||void 0,larkAppIds:c})}),I=await d.json();I.ok&&I.chatId?(e(I),x().then(i).catch(()=>{})):(alert(`Failed: ${I.error??d.status}`),n.close())}catch(d){alert("Network error: "+d),n.close()}}}function e(s){let a=String(s.chatId),$=`https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(a)}`,l=s.invalidBotIds??[],c=s.invalidUserIds??[],y=s.autoInvitedOpenId,d=!!s.autoInviteRejected,I=s.ownerTransferredTo,v=s.transferError,L=s.notifyMessageId,k=s.notifyError,E;if(y){let H=I?"<br><small>\u7FA4\u4E3B\u5DF2\u4ECE\u673A\u5668\u4EBA\u8F6C\u8BA9\u7ED9\u4F60\u3002</small>":v?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8\u8F6C\u8BA9\u7FA4\u4E3B\u5931\u8D25\uFF08${m(v)}\uFF09\uFF0C\u4F60\u73B0\u5728\u662F\u6210\u5458\u4F46\u7FA4\u4E3B\u4ECD\u662F\u673A\u5668\u4EBA\u3002</small>`:"",U=L?`<br><small>\u673A\u5668\u4EBA\u5DF2\u5728\u7FA4\u91CC @ \u4E86\u4F60\uFF08\u6D88\u606F id <code>${m(L)}</code>\uFF09\uFF0C\u770B\u98DE\u4E66\u901A\u77E5\u5C31\u80FD\u8FDB\u7FA4\u3002</small>`:k?`<br><small class="hint-warn-inline">\u26A0 \u81EA\u52A8 @ \u901A\u77E5\u5931\u8D25\uFF08${m(k)}\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>`:"";E=`<p class="hint-ok">\u5DF2\u81EA\u52A8\u9080\u8BF7\u4F60\uFF08<code>${m(y)}</code>\uFF09\u4F5C\u4E3A\u6210\u5458\u3002${H}${U}</p>`}else d?E='<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>':E='<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 S=[l.length?`<li>\u65E0\u6548 bot id: <code>${l.map(m).join(", ")}</code></li>`:"",c.length?`<li>\u65E0\u6548\u7528\u6237 open_id: <code>${c.map(m).join(", ")}</code></li>`:""].filter(Boolean).join("");n.innerHTML=`
126
+ <article>
127
+ <header><h3>\u7FA4\u521B\u5EFA\u6210\u529F</h3></header>
128
+ <p><b>chatId:</b> <code>${m(a)}</code> <button type="button" data-copy="${m(a)}">copy</button></p>
129
+ <p><b>\u521B\u5EFA\u8005:</b> <code>${m(s.creator??"?")}</code></p>
130
+ ${E}
131
+ ${S?`<ul>${S}</ul>`:""}
132
+ <div class="actions">
133
+ <a class="btn-link primary" href="${$}" target="_blank" rel="noopener">\u2197 \u6253\u5F00\u65B0\u7FA4</a>
134
+ <button type="button" id="g-create-close">\u5173\u95ED</button>
135
+ </div>
136
+ </article>`,n.querySelectorAll("[data-copy]").forEach(H=>{H.onclick=()=>{navigator.clipboard.writeText(H.dataset.copy??""),H.textContent="copied",setTimeout(()=>{H.textContent="copy"},800)}}),n.querySelector("#g-create-close").onclick=()=>n.close()}function p(){t.innerHTML=`<tr>
130
137
  <th>chat</th>
131
- ${I.bots.map(a=>`<th>${y(a.botName??a.larkAppId)}</th>`).join("")}
138
+ ${T.bots.map(s=>`<th>${m(s.botName??s.larkAppId)}</th>`).join("")}
132
139
  <th>actions</th>
133
- </tr>`}function l(){e();let a=new FormData(u),r=(a.get("q")??"").toLowerCase(),d=!!a.get("missing"),g=I.chats.filter(o=>!r||(o.name??"").toLowerCase().includes(r)||o.chatId.toLowerCase().includes(r)||(o.ownerId??"").toLowerCase().includes(r)).filter(o=>!d||o.memberBots.some(b=>!b.inChat));if(g.length===0){i.innerHTML=`<tr><td colspan="${I.bots.length+2}" class="empty">No chats match the filter.</td></tr>`;return}i.innerHTML=g.map(o=>`<tr data-chat="${y(o.chatId)}">
140
+ </tr>`}function i(){p();let s=new FormData(u),a=(s.get("q")??"").toLowerCase(),$=!!s.get("missing"),l=T.chats.filter(c=>!a||(c.name??"").toLowerCase().includes(a)||c.chatId.toLowerCase().includes(a)||(c.ownerId??"").toLowerCase().includes(a)).filter(c=>!$||c.memberBots.some(y=>!y.inChat));if(l.length===0){r.innerHTML=`<tr><td colspan="${T.bots.length+2}" class="empty">No chats match the filter.</td></tr>`;return}r.innerHTML=l.map(c=>`<tr data-chat="${m(c.chatId)}">
134
141
  <td>
135
- <strong>${y(o.name??o.chatId)}</strong><br>
136
- <small><code>${y(o.chatId)}</code></small>
142
+ <strong>${m(c.name??c.chatId)}</strong><br>
143
+ <small><code>${m(c.chatId)}</code></small>
137
144
  </td>
138
- ${I.bots.map(b=>{let c=o.memberBots.find(k=>k.larkAppId===b.larkAppId),$=c?c.error?"!":c.inChat?"\u2713":"\u2717":"?";return`<td class="${c?c.error?"cell-error":c.inChat?"cell-in":"cell-out":"cell-unknown"}" title="${y(c?.error??"")}">${$}</td>`}).join("")}
145
+ ${T.bots.map(y=>{let d=c.memberBots.find(L=>L.larkAppId===y.larkAppId),I=d?d.error?"!":d.inChat?"\u2713":"\u2717":"?";return`<td class="${d?d.error?"cell-error":d.inChat?"cell-in":"cell-out":"cell-unknown"}" title="${m(d?.error??"")}">${I}</td>`}).join("")}
139
146
  <td><button class="add-bots" type="button">Add bots</button></td>
140
- </tr>`).join("")}l(),i.addEventListener("click",async a=>{let r=a.target.closest("button.add-bots");if(!r)return;let g=r.closest("tr[data-chat]").dataset.chat,o=I.chats.find(c=>c.chatId===g);if(!o)return;let b=o.memberBots.filter(c=>!c.inChat);if(!b.length){alert("All configured bots are already in this chat.");return}s.innerHTML=`
147
+ </tr>`).join("")}i(),r.addEventListener("click",async s=>{let a=s.target.closest("button.add-bots");if(!a)return;let l=a.closest("tr[data-chat]").dataset.chat,c=T.chats.find(d=>d.chatId===l);if(!c)return;let y=c.memberBots.filter(d=>!d.inChat);if(!y.length){alert("All configured bots are already in this chat.");return}n.innerHTML=`
141
148
  <article>
142
- <header><h3>Add bots to ${y(o.name??o.chatId)}</h3></header>
149
+ <header><h3>Add bots to ${m(c.name??c.chatId)}</h3></header>
143
150
  <p>Select bots to add. The dashboard will pick a bot that's already in the chat as the proxy.</p>
144
151
  <form id="g-addform">
145
- ${b.map(c=>`
152
+ ${y.map(d=>`
146
153
  <label class="checkbox-row">
147
- <input type="checkbox" name="bot" value="${y(c.larkAppId)}">
148
- ${y(c.botName??c.larkAppId)} <small>(${y(c.larkAppId)})</small>
154
+ <input type="checkbox" name="bot" value="${m(d.larkAppId)}">
155
+ ${m(d.botName??d.larkAppId)} <small>(${m(d.larkAppId)})</small>
149
156
  </label>
150
157
  `).join("")}
151
158
  <div class="actions">
@@ -153,5 +160,5 @@ creator: ${$.creator??"?"}${k}`),await H(),l()}else alert(`Failed: ${$.error??c.
153
160
  <button type="button" id="g-cancel">Cancel</button>
154
161
  </div>
155
162
  </form>
156
- </article>`,s.showModal(),s.querySelector("#g-cancel").onclick=()=>s.close(),s.querySelector("#g-addform").onsubmit=async c=>{c.preventDefault();let M=new FormData(c.target).getAll("bot");if(M.length===0){alert("Pick at least one bot.");return}try{let T=await(await fetch(`/api/groups/${encodeURIComponent(g)}/add-bots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:M})})).json();if(T.error==="no_proxy_bot")alert("No bot is currently in this chat \u2014 add one manually in Feishu first, then retry.");else if(T.result){let F=T.result.map(S=>`${S.id}: ${S.ok?"OK":`failed (${S.error??"unknown"})`}`).join(`
157
- `);alert(F),await H(),l()}else alert(`Unexpected response: ${JSON.stringify(T)}`)}catch(k){alert("Network error: "+k)}finally{s.close()}}}),u.addEventListener("input",l)}var C=document.getElementById("root");function R(){let n=location.hash||"#/";n.startsWith("#/groups")?P(C):n.startsWith("#/schedules")?D(C):N(C);for(let t of document.querySelectorAll("header nav a"))t.classList.toggle("active",t.getAttribute("href")===(n||"#/")||n==="#/"&&t.dataset.route==="sessions")}var x=document.getElementById("status");function O(){x&&(x.textContent=m.online?"\u25CF live":"\u25CF disconnected",x.className="status "+(m.online?"online":"offline"))}m.on(O);O();(async()=>{try{await A()}catch(n){console.error("botmux dashboard bootstrap failed",n),m.setOnline(!1)}window.addEventListener("hashchange",R),R()})();})();
163
+ </article>`,n.showModal(),n.querySelector("#g-cancel").onclick=()=>n.close(),n.querySelector("#g-addform").onsubmit=async d=>{d.preventDefault();let v=new FormData(d.target).getAll("bot");if(v.length===0){alert("Pick at least one bot.");return}try{let k=await(await fetch(`/api/groups/${encodeURIComponent(l)}/add-bots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({larkAppIds:v})})).json();if(k.error==="no_proxy_bot")alert("No bot is currently in this chat \u2014 add one manually in Feishu first, then retry.");else if(k.result){let E=k.result.map(S=>`${S.id}: ${S.ok?"OK":`failed (${S.error??"unknown"})`}`).join(`
164
+ `);alert(E),await x(),i()}else alert(`Unexpected response: ${JSON.stringify(k)}`)}catch(L){alert("Network error: "+L)}finally{n.close()}}}),u.addEventListener("input",i)}var q=document.getElementById("root");function _(){let o=location.hash||"#/";o.startsWith("#/groups")?j(q):o.startsWith("#/schedules")?P(q):D(q);for(let t of document.querySelectorAll("header nav a"))t.classList.toggle("active",t.getAttribute("href")===(o||"#/")||o==="#/"&&t.dataset.route==="sessions")}var B=document.getElementById("status");function F(){B&&(B.textContent=b.online?"\u25CF live":"\u25CF disconnected",B.className="status "+(b.online?"online":"offline"))}b.on(F);F();(async()=>{try{await N()}catch(o){console.error("botmux dashboard bootstrap failed",o),b.setOnline(!1)}window.addEventListener("hashchange",_),_()})();})();
@@ -21,7 +21,12 @@ table { border-collapse: collapse; width: 100%; font-variant-numeric: tabular-nu
21
21
  th, td { padding: 0.4rem 0.6rem; text-align: left; border-bottom: 1px solid var(--border); white-space: nowrap; }
22
22
  th { background: var(--header-bg); font-weight: 600; }
23
23
  tr[data-id]:hover { background: #f6f8fa; cursor: pointer; }
24
- button { padding: 0.25rem 0.6rem; border: 1px solid var(--border); background: white; border-radius: 4px; cursor: pointer; }
24
+ button { padding: 0.25rem 0.6rem; border: 1px solid var(--border); background: white; border-radius: 4px; cursor: pointer;
25
+ /* iOS Safari renders default <button> with -webkit-appearance: button which
26
+ can hide our text under a system gradient on small screens. Reset to
27
+ normalize so "Create" / "Cancel" / etc. render reliably across mobile. */
28
+ color: var(--fg); font-family: inherit; font-size: inherit; line-height: 1.2;
29
+ -webkit-appearance: none; appearance: none; }
25
30
  button:disabled { opacity: 0.5; cursor: default; }
26
31
  button.contrast { background: #cf222e; color: white; border-color: #cf222e; }
27
32
  .btn-link { display: inline-block; padding: 0.25rem 0.6rem; border: 1px solid var(--border); border-radius: 4px; text-decoration: none; color: var(--fg); }
@@ -55,3 +60,7 @@ dialog#g-drawer { border: none; border-radius: 8px; padding: 0; max-width: 600px
55
60
  dialog#g-drawer article { padding: 1rem 1.5rem; }
56
61
  dialog#g-drawer fieldset { margin: 0.5rem 0; padding: 0.4rem 0.8rem; border: 1px solid var(--border); border-radius: 4px; }
57
62
  dialog#g-drawer fieldset legend { padding: 0 0.3rem; color: var(--muted); font-size: 12px; }
63
+ .hint-ok { background: #ddf4e4; border-left: 3px solid #1a7f37; padding: 0.4rem 0.6rem; border-radius: 3px; margin: 0.5rem 0; font-size: 13px; }
64
+ .hint-warn { background: #fff8c5; border-left: 3px solid #bf8700; padding: 0.4rem 0.6rem; border-radius: 3px; margin: 0.5rem 0; font-size: 13px; }
65
+ .btn-link.primary { background: #1f6feb; color: white; border-color: #1f6feb; font-weight: 600; }
66
+ .hint-warn-inline { color: #9a6700; }