@zaofan/dsh-qqbot 1.10.46 → 1.10.48

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.
@@ -576,6 +576,106 @@ window.__ModuleLoader__.load({
576
576
  return h('div', null, body, h(HintBlock, { text: f.hint }))
577
577
  }
578
578
 
579
+ // ══ 扩展 UI(2026-10-26)════════════════════════════════════════════════
580
+ // 为什么要提到模块顶层:ExtCardPage 是给 QqbotHome 用的(顶层 tab 切换),
581
+ // 原来错写在 SettingsPage 内部 → QqbotHome 里 ReferenceError: ExtCardPage is not defined,
582
+ // 整页白屏(2026-10-26 主人实测)。
583
+ // 这里自包含实现,不依赖 SettingsPage 内部的 extUiText / injectExtUiCss。
584
+ var EXT_UI_CSS_ID = 'qqs-ext-css'
585
+ function extUiEnsureCss() {
586
+ try {
587
+ if (document.getElementById(EXT_UI_CSS_ID)) return
588
+ var s = document.createElement('style')
589
+ s.id = EXT_UI_CSS_ID
590
+ s.textContent = ''
591
+ + '.qqs-ext-cards{display:flex;gap:10px;overflow-x:auto;overflow-y:hidden;'
592
+ + '-webkit-overflow-scrolling:touch;scrollbar-width:none;'
593
+ + 'scroll-snap-type:x proximity;padding:2px 0 6px}'
594
+ + '.qqs-ext-cards::-webkit-scrollbar{display:none}'
595
+ + '.qqs-ext-card{flex:0 0 auto;scroll-snap-align:start;min-width:220px;max-width:320px}'
596
+ + '.qqs-top-tabs{scrollbar-width:none}'
597
+ + '.qqs-top-tabs::-webkit-scrollbar{display:none}'
598
+ + '.qqs-ext-page-card{display:block;min-width:260px}'
599
+ document.head.appendChild(s)
600
+ // 鼠标滚轮 → 横向滚动(2026-10-26 主人实测"不能横滑"):
601
+ // 容器 overflow-x:auto 在触摸屏上能滑,但**桌面上普通滚轮是纵向的**,
602
+ // 浏览器不会自动转成横滚,所以看着"溢出却不动"。这里做一次事件委托,
603
+ // .qqs-top-tabs / .qqs-ext-cards 上把纵向滚轮折算成 scrollLeft。
604
+ if (!window.__qqsExtWheelBound) {
605
+ window.__qqsExtWheelBound = true
606
+ document.addEventListener('wheel', function (e) {
607
+ var el = e.target
608
+ while (el && el !== document.body) {
609
+ // 用 id 判断(className 不一定被自定义 h() 落到 DOM 上)
610
+ var hit = el.id === 'qqs-top-tabs'
611
+ || (el.classList && (el.classList.contains('qqs-top-tabs') || el.classList.contains('qqs-ext-cards')))
612
+ if (hit) {
613
+ if (el.scrollWidth > el.clientWidth + 1 && Math.abs(e.deltaY) > Math.abs(e.deltaX)) {
614
+ el.scrollLeft += e.deltaY
615
+ e.preventDefault()
616
+ }
617
+ return
618
+ }
619
+ el = el.parentNode
620
+ }
621
+ }, { passive: false })
622
+ }
623
+ } catch (e) { /* ignore */ }
624
+ }
625
+ function extUiLoad(extId, f) {
626
+ return fetch('/api/qqbot-settings/ext-ui/file?f=' + encodeURIComponent(f) + '&id=' + encodeURIComponent(extId))
627
+ .then(function (r) { return r.json() })
628
+ .then(function (j) { return j && j.ok ? String(j.text || '') : '' })
629
+ .catch(function () { return '' })
630
+ }
631
+ /** 把一张扩展卡片用 Shadow DOM 挂进容器 */
632
+ function extUiMountCard(container, extId, cls) {
633
+ var host = document.createElement('div')
634
+ host.className = cls || 'qqs-ext-card'
635
+ var sr = host.attachShadow({ mode: 'open' })
636
+ container.appendChild(host)
637
+ Promise.all([extUiLoad(extId, 'card.html'), extUiLoad(extId, 'card.css'), extUiLoad(extId, 'card.js')])
638
+ .then(function (res) {
639
+ sr.innerHTML = '<style>' + (res[1] || '') + '</style>' + (res[0] || '')
640
+ if (!res[2]) return
641
+ var api = {
642
+ extId: extId,
643
+ api: function (p, opts) {
644
+ return fetch('/api/ext/' + encodeURIComponent(extId) + String(p || ''),
645
+ Object.assign({ headers: { 'Content-Type': 'application/json' } }, opts || {}))
646
+ .then(function (r) { return r.json() })
647
+ .catch(function () { return null })
648
+ },
649
+ toast: function (m) { try { window.alert(String(m)) } catch (e) { /* ignore */ } },
650
+ }
651
+ try {
652
+ new Function('qqbotExt', 'shadowRoot', res[2])(api, sr)
653
+ } catch (e) {
654
+ var d = document.createElement('div')
655
+ d.style.cssText = 'color:#c33;font-size:12px;padding:6px 0'
656
+ d.textContent = '卡片脚本出错: ' + (e && e.message ? e.message : e)
657
+ sr.appendChild(d)
658
+ }
659
+ })
660
+ return host
661
+ }
662
+ /** 扩展页签的整页视图:把它的卡片铺在内容区 */
663
+ function ExtCardPage(props) {
664
+ var extId = String((props && props.extId) || '')
665
+ var title = String((props && props.title) || extId)
666
+ useEffect(function () {
667
+ extUiEnsureCss()
668
+ var box = document.getElementById('qqs-ext-page')
669
+ if (!box || !extId) return
670
+ box.innerHTML = ''
671
+ extUiMountCard(box, extId, 'qqs-ext-page-card')
672
+ return function () { try { box.innerHTML = '' } catch (e) { /* ignore */ } }
673
+ }, [extId])
674
+ return h('div', { style: { maxWidth: 720 } },
675
+ h('h2', { style: { margin: '0 0 10px' } }, title),
676
+ h('div', { id: 'qqs-ext-page', style: { display: 'flex', flexWrap: 'wrap', gap: 12, alignItems: 'flex-start' } }))
677
+ }
678
+
579
679
  function SettingsPage(props) {
580
680
  var close = props && props.close
581
681
  // 多账号: 当前操作账号的 settings 命名空间(主=im-qqbot 不带参, 其它=实例 id)
@@ -711,6 +811,94 @@ window.__ModuleLoader__.load({
711
811
  q2 ? h('span', { onClick: function () { setQ2('') }, style: { fontSize: 12, color: T.text3, cursor: 'pointer' } }, '清空') : null,
712
812
  h('span', { style: { fontSize: 11, color: T.text3, whiteSpace: 'nowrap' } }, '程序算的相似度 · 本地即时')))
713
813
 
814
+ // ── 扩展 UI 卡片(2026-10-26)─────────────────────────────────────────
815
+ // 扩展在 {dataRoot}/.qqbot-extensions/ui/<id>/ 放 card.html / card.css / card.js,
816
+ // 这里拉过来用 **Shadow DOM** 挂到设置页底部。扫描与安全校验见 src/features/ext-ui.ts。
817
+ // 用 Shadow DOM 的两个理由:
818
+ // ① 扩展写的 CSS 不会污染这个 535KB 单文件里的任何样式(一条全局 button{} 就能改全站)
819
+ // ② 扩展脚本报错只白自己那张卡,不整页崩
820
+ var EXT_UI_LIST = '/api/qqbot-settings/ext-ui/list'
821
+ var EXT_UI_FILE = '/api/qqbot-settings/ext-ui/file?f='
822
+ function extUiText(extId, f) {
823
+ return fetch(EXT_UI_FILE + encodeURIComponent(f) + '&id=' + encodeURIComponent(extId))
824
+ .then(function (r) { return r.json() })
825
+ .then(function (j) { return j && j.ok ? String(j.text || '') : '' })
826
+ .catch(function () { return '' })
827
+ }
828
+ function extUiApi(extId) {
829
+ return {
830
+ extId: extId,
831
+ // 扩展自己的只读/只写接口走 /api/ext/<id>/…(由扩展自己注册,本插件不代管)
832
+ api: function (p, opts) {
833
+ return fetch('/api/ext/' + encodeURIComponent(extId) + String(p || ''),
834
+ Object.assign({ headers: { 'Content-Type': 'application/json' } }, opts || {}))
835
+ .then(function (r) { return r.json() })
836
+ .catch(function () { return null })
837
+ },
838
+ toast: function (m) { try { window.alert(String(m)) } catch (e) { /* ignore */ } },
839
+ }
840
+ }
841
+ function injectExtUiCss() {
842
+ if (document.getElementById('qqs-ext-css')) return
843
+ var s = document.createElement('style')
844
+ s.id = 'qqs-ext-css'
845
+ // 横向滑动:抄 .dk-tab 那套已在机器上跑熟的写法(overflow-x + 惯性 + 隐藏滚动条)。
846
+ // ★ flex:0 0 auto 是关键 —— 少了这句卡片会被 flex 压成一条缝,这是最常见的坑。
847
+ // scroll-snap 让"滑一下正好停在卡片边缘",不会卡在半张卡中间。
848
+ s.textContent = ''
849
+ + '.qqs-ext-cards{display:flex;gap:10px;overflow-x:auto;overflow-y:hidden;'
850
+ + '-webkit-overflow-scrolling:touch;scrollbar-width:none;'
851
+ + 'scroll-snap-type:x proximity;padding:2px 0 6px}'
852
+ + '.qqs-ext-cards::-webkit-scrollbar{display:none}'
853
+ + '.qqs-ext-card{flex:0 0 auto;scroll-snap-align:start;min-width:220px;max-width:320px}'
854
+ // 顶部页签条:内置四页 + 扩展页签,扩展多了横向滑动(2026-10-26)
855
+ + '.qqs-top-tabs{scrollbar-width:none}'
856
+ + '.qqs-top-tabs::-webkit-scrollbar{display:none}'
857
+ // 扩展整页视图:让卡片在页内能撑开(卡片自身宽度由 :host 决定)
858
+ + '.qqs-ext-page-card{display:block}'
859
+ document.head.appendChild(s)
860
+ }
861
+ function mountExtUiCards() {
862
+ injectExtUiCss()
863
+ var box = document.getElementById('qqs-ext-cards')
864
+ if (!box) return
865
+ fetch(EXT_UI_LIST).then(function (r) { return r.json() }).then(function (j) {
866
+ if (!j || !j.ok) return
867
+ var list = (j.items || []).filter(function (x) { return x.slot === 'settings' })
868
+ if (!list.length) { box.style.display = 'none'; return }
869
+ box.style.display = ''
870
+ // 幂等:卡片数量没变就不重挂(避免每次 setState 都把扩展的 DOM 冲掉)
871
+ var sig = list.map(function (x) { return x.extId }).join(',')
872
+ if (box.getAttribute('data-sig') === sig) return
873
+ box.setAttribute('data-sig', sig)
874
+ box.innerHTML = ''
875
+ list.forEach(function (it) {
876
+ var host = document.createElement('div')
877
+ host.className = 'qqs-ext-card'
878
+ var sr = host.attachShadow({ mode: 'open' })
879
+ box.appendChild(host)
880
+ Promise.all([
881
+ extUiText(it.extId, 'card.html'),
882
+ it.files && it.files.indexOf('card.css') >= 0 ? extUiText(it.extId, 'card.css') : Promise.resolve(''),
883
+ it.files && it.files.indexOf('card.js') >= 0 ? extUiText(it.extId, 'card.js') : Promise.resolve(''),
884
+ ]).then(function (res) {
885
+ sr.innerHTML = '<style>' + (res[1] || '') + '</style>' + (res[0] || '')
886
+ if (!res[2]) return
887
+ try {
888
+ // Function 而不是 eval:作用域干净,且把 qqbotExt 作为形参传进去
889
+ new Function('qqbotExt', 'shadowRoot', res[2])(extUiApi(it.extId), sr)
890
+ } catch (e) {
891
+ var d = document.createElement('div')
892
+ d.style.cssText = 'color:#c33;font-size:12px;padding:4px 0'
893
+ d.textContent = '卡片脚本出错: ' + (e && e.message ? e.message : e)
894
+ sr.appendChild(d)
895
+ }
896
+ })
897
+ })
898
+ }).catch(function () { /* 静默:扩展 UI 挂了不该影响设置页本体 */ })
899
+ }
900
+ setTimeout(function () { try { mountExtUiCards() } catch (e) { /* ignore */ } }, 0)
901
+
714
902
  return h('div', { style: { maxWidth: 720 } },
715
903
  h('h2', { style: { margin: '0 0 6px' } }, 'QQ 机器人设置'),
716
904
  h('p', { style: { fontSize: 12, color: T.text3, margin: '0 0 10px' } }, '改完点「保存」立刻生效(不用重启)。看不懂的项放着别动就行;想恢复"不限制"就把数字填 0、勾选取消、列表清空。只提交你改过的字段——没碰的项不会被动。'),
@@ -721,7 +909,9 @@ window.__ModuleLoader__.load({
721
909
  h(SButton, { variant: 'primary', onClick: doSave }, dirtyN ? ('保存(' + dirtyN + ' 项改动)') : '保存'),
722
910
  h(SButton, { variant: 'ghost', onClick: load }, '放弃修改(重新读取)'),
723
911
  msg ? h('span', { style: { fontSize: 13, color: T.text2 } }, msg) : null,
724
- close ? h(SButton, { variant: 'ghost', onClick: close }, '完成') : null))
912
+ close ? h(SButton, { variant: 'ghost', onClick: close }, '完成') : null),
913
+ // ★ 扩展卡片挂载点:横向可滑动,样式见文件末尾注入的 .qqs-ext-cards
914
+ h('div', { id: 'qqs-ext-cards', className: 'qqs-ext-cards' }))
725
915
  }
726
916
 
727
917
  // ── ⑥ QQ 群管理(单开大卡片; P3+ 设计系统版: 横排 Tab + 状态条 + 表格 + 空状态 + 预留接口位) ──
@@ -1539,6 +1729,21 @@ window.__ModuleLoader__.load({
1539
1729
  })
1540
1730
  return function () { alive = false }
1541
1731
  }, [accts, acctId])
1732
+ // ── 扩展 UI 页签(2026-10-26):slot=settings 的扩展挂到顶部 tab 右边 ──
1733
+ // 数据来自 /api/qqbot-settings/ext-ui/list(profile 级目录,全 profile 一份)。
1734
+ var [extTabs, setExtTabs] = useState([])
1735
+ useEffect(function () {
1736
+ var alive = true
1737
+ fetch('/api/qqbot-settings/ext-ui/list')
1738
+ .then(function (r) { return r.json() })
1739
+ .then(function (j) {
1740
+ if (!alive || !j || !j.ok) return
1741
+ var list = (j.items || []).filter(function (x) { return x.slot === 'settings' })
1742
+ setExtTabs(list)
1743
+ })
1744
+ .catch(function () { /* 扩展列表拉不到不影响设置页 */ })
1745
+ return function () { alive = false }
1746
+ }, [])
1542
1747
  if (!tab) return h('div', null, '…')
1543
1748
  function choose(t) { setTab(t); try { localStorage.setItem(TAB_KEY, t) } catch (e) {} }
1544
1749
  function chooseAcct(id) { setAcctId(id); try { localStorage.setItem(ACCT_KEY, id) } catch (e) {} }
@@ -1553,6 +1758,16 @@ window.__ModuleLoader__.load({
1553
1758
  var sub = tab === 'gallery' ? h(GalleryPage, { key: subKey, close: props && props.close, acct: acctx })
1554
1759
  : tab === 'timers' ? h(TimersPage, { key: subKey, close: props && props.close, acct: acctx })
1555
1760
  : tab === 'accounts' ? h(AccountsPage, { close: props && props.close })
1761
+ : String(tab).indexOf('ext:') === 0
1762
+ ? h(ExtCardPage, {
1763
+ key: String(tab).slice(4),
1764
+ extId: String(tab).slice(4),
1765
+ title: (function () {
1766
+ var hit = null
1767
+ extTabs.forEach(function (x) { if (x.extId === String(tab).slice(4)) hit = x })
1768
+ return hit ? hit.title : String(tab).slice(4)
1769
+ })(),
1770
+ })
1556
1771
  : h(SettingsPage, { key: subKey, close: props && props.close, acct: acctx })
1557
1772
  var acctLine = (accts && accts.length > 1) || (accts && accts.length === 1)
1558
1773
  return h('div', { style: { width: '100%' } },
@@ -1568,16 +1783,26 @@ window.__ModuleLoader__.load({
1568
1783
  ac ? h('span', { style: { fontSize: 12, color: '#6d28d9', whiteSpace: 'nowrap' } }, ac.dataDir ? '数据目录: ' + ac.dataDir : '') : null,
1569
1784
  h('span', { style: { flex: 1 } }),
1570
1785
  h('span', { style: { fontSize: 12, color: '#8a97ad' } }, '设置/图库/定时 都跟随上面选的机器人')),
1571
- h('div', { style: { position: 'sticky', top: 0, zIndex: 30, background: 'transparent', padding: '10px 4px 12px', display: 'flex', gap: 10, flexWrap: 'nowrap', alignItems: 'stretch', marginBottom: 12 } },
1572
- [['settings', '设置', '#ff5d5d'], ['gallery', '表情包图库', '#ffd97a'], ['timers', '定时任务', '#5b9dff'], ['accounts', '账号与预设', '#b197fc']].map(function (t) {
1786
+ // ★ 2026-10-26 修「页签条不能横滑」:原来把 `position:sticky` 和 `overflow-x:auto`
1787
+ // 放在**同一个元素**上 —— sticky 会创建新的格式化上下文,导致滚动容器的
1788
+ // scrollWidth 计算异常(看着溢出、实际判定为没溢出),于是滚不动。
1789
+ // 拆成两层:外层只管 sticky + 裁剪,内层只管横向滚动。
1790
+ h('div', { style: { position: 'sticky', top: 0, zIndex: 30, background: 'transparent', overflow: 'hidden', marginBottom: 12 } },
1791
+ h('div', { id: 'qqs-top-tabs', className: 'qqs-top-tabs', style: { display: 'flex', gap: 10, flexWrap: 'nowrap', alignItems: 'stretch', padding: '10px 4px 12px', overflowX: 'auto', overflowY: 'hidden', WebkitOverflowScrolling: 'touch', scrollbarWidth: 'none', width: '100%', boxSizing: 'border-box' } },
1792
+ // 内置四页 + 扩展页签(2026-10-26):扩展 tab 用青蓝色区分,放在最右边。
1793
+ // 容器从「四个 flex:1 平分」改成「按钮 flex:0 0 auto + 容器横向可滑」——
1794
+ // 否则扩展一多,按钮会被压成一条缝(这跟 .dk-tab 那套是同一个道理)。
1795
+ [['settings', '设置', '#ff5d5d'], ['gallery', '表情包图库', '#ffd97a'], ['timers', '定时任务', '#5b9dff'], ['accounts', '账号与预设', '#b197fc']]
1796
+ .concat(extTabs.map(function (x) { return ['ext:' + x.extId, x.title, '#38bdf8'] }))
1797
+ .map(function (t) {
1573
1798
  var on = tab === t[0]
1574
1799
  var n = t[0] === 'gallery' ? badges.untagged : t[0] === 'timers' ? badges.timers : 0
1575
1800
  var col = t[2]
1576
1801
  return h('button', { key: t[0], onClick: function () { choose(t[0]) },
1577
1802
  style: {
1578
- flex: 1, minWidth: 0, cursor: 'pointer', font: 'inherit',
1803
+ flex: '0 0 auto', minWidth: 104, cursor: 'pointer', font: 'inherit',
1579
1804
  color: 'var(--qqs-text,#171a21)', fontSize: 14, textAlign: 'center',
1580
- whiteSpace: 'nowrap', padding: '9px 8px', borderRadius: 14,
1805
+ whiteSpace: 'nowrap', padding: '9px 14px', borderRadius: 14,
1581
1806
  border: '1px solid ' + (on ? col : col + 'a6'),
1582
1807
  background: 'linear-gradient(165deg,' + col + (on ? '66' : '40') + ',' + col + (on ? '1f' : '14') + ')',
1583
1808
  boxShadow: on
@@ -1588,7 +1813,7 @@ window.__ModuleLoader__.load({
1588
1813
  transition: 'all .15s', outline: 'none',
1589
1814
  } },
1590
1815
  t[1], badge(n))
1591
- })),
1816
+ }))),
1592
1817
  sub)
1593
1818
  }
1594
1819
 
@@ -3370,10 +3595,14 @@ var QQS_THEME_CSS = [
3370
3595
  intervalMin: state.gaInterval,
3371
3596
  minCount: state.gaMinCount,
3372
3597
  wakeLlm: state.gaPollWake,
3373
- hubNotify: state.gaHubNotify,
3374
- notifyGroup: state.gaNotifyGroup,
3375
- wakeGroup: state.gaWakeGroup,
3376
3598
  },
3599
+ // ★ 2026-10-26 修(主人报「叉掉注入群管会话还是会注入」):
3600
+ // hubNotify / notifyInGroup / wakeGroup 是 groupAdmin 的**顶层**字段
3601
+ // (见 config.ts 的 groupAdmin schema),原来错写进 pollJoinRequests 子对象里,
3602
+ // 后端读顶层永远读不到 → UI 上取消勾选完全无效。
3603
+ hubNotify: state.gaHubNotify,
3604
+ notifyInGroup: state.gaNotifyGroup,
3605
+ wakeGroup: state.gaWakeGroup,
3377
3606
  // 🔨 自动撤回(2026-10-20 主人定): 命中关键词/附件类型 → 立刻撤; mode 决定是否进 AI
3378
3607
  autoRecall: {
3379
3608
  enabled: state.arOn === true,
@@ -0,0 +1,44 @@
1
+ /** 允许的挂载点 */
2
+ export declare const EXT_UI_SLOTS: readonly ["settings", "dock"];
3
+ export type ExtUiSlot = (typeof EXT_UI_SLOTS)[number];
4
+ /** 允许被面板读取的文件名(写死,不接受任意路径) */
5
+ export declare const EXT_UI_FILES: readonly ["card.html", "card.css", "card.js"];
6
+ export type ExtUiFile = (typeof EXT_UI_FILES)[number];
7
+ export interface ExtUiInfo {
8
+ /** 扩展 id(= 目录名) */
9
+ extId: string;
10
+ /** 目录绝对路径 */
11
+ dir: string;
12
+ /** 来源:profile = profile 级;data = 数据根;pack = 扩展包内 */
13
+ from: 'profile' | 'data' | 'pack';
14
+ /** 扩展包目录名(from=pack 时有) */
15
+ pack?: string;
16
+ slot: ExtUiSlot;
17
+ title: string;
18
+ order: number;
19
+ /** 实际存在哪些文件 */
20
+ files: ExtUiFile[];
21
+ }
22
+ /**
23
+ * 列出所有扩展 UI 卡片。任何异常都安全跳过,绝不抛。
24
+ *
25
+ * @param dataRoot 插件数据根(每个机器人实例一份)→ 只收 slot=dock
26
+ * @param profileRoot DSH profile 根(全 profile 一份)→ 只收 slot=settings
27
+ */
28
+ export declare function listExtUi(dataRoot: string, profileRoot?: string): ExtUiInfo[];
29
+ export interface ExtUiFileResult {
30
+ ok: boolean;
31
+ path?: string;
32
+ text?: string;
33
+ reason?: string;
34
+ }
35
+ /**
36
+ * 读一个扩展 UI 文件。
37
+ *
38
+ * 三重防护:
39
+ * ① extId 白名单正则 + 必须是 listExtUi 里真实存在的
40
+ * ② fileName 只允许 card.html / card.css / card.js
41
+ * ③ 拼完 resolve 再校验仍在所属目录内(防 `..` 穿越)
42
+ */
43
+ export declare function readExtUiFile(dataRoot: string, profileRoot: string | undefined, extId: string, fileName: string): ExtUiFileResult;
44
+ //# sourceMappingURL=ext-ui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ext-ui.d.ts","sourceRoot":"","sources":["../../src/features/ext-ui.ts"],"names":[],"mappings":"AAgCA,aAAa;AACb,eAAO,MAAM,YAAY,+BAAgC,CAAC;AAC1D,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtD,8BAA8B;AAC9B,eAAO,MAAM,YAAY,+CAAgD,CAAC;AAC1E,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAKtD,MAAM,WAAW,SAAS;IACxB,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,oDAAoD;IACpD,IAAI,EAAE,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;IAClC,2BAA2B;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,eAAe;IACf,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AAyED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,CA0C7E;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf,eAAe,CAkBjB"}
@@ -0,0 +1,185 @@
1
+ /**
2
+ * ext-ui.ts — 扩展 UI 卡片(2026-10-26 主人定)
3
+ *
4
+ * 背景:面板(设置页 + 悬浮台)全塞在 `client/qqbot-settings.js` 一个 535KB 手写 bundle 里,
5
+ * 扩展想加自己的界面只能「按字符串锚点往文件里塞代码」—— 社区作者 wuwo1979 就是这么干的
6
+ * (见 dsh-qqbot-muu 的 add-ext-ui.mjs / add-memory-panel.mjs)。
7
+ * 版本一换锚点就失效,而且只对写补丁的那台机器有效。
8
+ *
9
+ * ── ★ 两个源,各管一种 slot,不许混(2026-10-26 主人纠正)──────────────
10
+ *
11
+ * slot: settings = DSH 设置页里那页 → **profile 级**(全 profile 一份)
12
+ * {PROFILE_ROOT}/.qqbot-extensions/ui/<extId>/
13
+ * 理由:设置页是全局界面,不属于任何工作区。放数据根会「几个工作区就有几份」。
14
+ *
15
+ * slot: dock = 悬浮球/悬浮台 → **数据根**(每个机器人实例一份)
16
+ * {dataRoot}/.qqbot-extensions/ui/<extId>/
17
+ * 理由:悬浮球本来就是「按工作区判断」的,一个实例一个。
18
+ *
19
+ * 扩展包内 ui/ 跟着包走:包在数据根下 → 视为实例级(只收 dock)。
20
+ *
21
+ * ⚠️ `ui/` **不是第七个扩展点**:另外六个 kind 都是 `.mjs` 模块、扫完要 `import()`;
22
+ * `ui/` 是静态资源,只登记路径,绝不 import(否则会试图 import 一个 .html 直接报错)。
23
+ *
24
+ * 元信息写在 card.html 顶部注释里(前 2KB 内):
25
+ *
26
+ * <!-- qqbot-ui: { "slot": "settings", "title": "本地代答", "order": 10 } -->
27
+ */
28
+ import { readdirSync, statSync, existsSync, readFileSync } from 'node:fs';
29
+ import { join, resolve, sep } from 'node:path';
30
+ import { EXT_PACKS_SUBDIR } from './ext-packs.js';
31
+ /** 允许的挂载点 */
32
+ export const EXT_UI_SLOTS = ['settings', 'dock'];
33
+ /** 允许被面板读取的文件名(写死,不接受任意路径) */
34
+ export const EXT_UI_FILES = ['card.html', 'card.css', 'card.js'];
35
+ /** 扩展 id 白名单(防路径穿越) */
36
+ const EXT_ID_RE = /^[A-Za-z0-9_-]{1,64}$/;
37
+ /** 解析 card.html 顶部的 `<!-- qqbot-ui: {...} -->` */
38
+ function parseMeta(html) {
39
+ try {
40
+ const head = html.slice(0, 2048); // 只看前 2KB
41
+ const m = head.match(/<!--\s*qqbot-ui:\s*(\{[\s\S]*?\})\s*-->/);
42
+ if (!m)
43
+ return {};
44
+ const j = JSON.parse(m[1] ?? '{}');
45
+ return j && typeof j === 'object' ? j : {};
46
+ }
47
+ catch {
48
+ return {};
49
+ }
50
+ }
51
+ /**
52
+ * 扫一个 `ui/` 目录。
53
+ *
54
+ * @param allowSlots 只收这些 slot —— profile 源只收 settings,数据根源只收 dock,防止两边重复
55
+ */
56
+ function scanOneUiRoot(uiRoot, from, pack, allowSlots, out) {
57
+ let names = [];
58
+ try {
59
+ if (!existsSync(uiRoot))
60
+ return;
61
+ names = readdirSync(uiRoot);
62
+ }
63
+ catch {
64
+ return;
65
+ }
66
+ for (const extId of names) {
67
+ if (!EXT_ID_RE.test(extId))
68
+ continue; // 名字不合法 → 跳过(防穿越)
69
+ const dir = join(uiRoot, extId);
70
+ try {
71
+ if (!statSync(dir).isDirectory())
72
+ continue;
73
+ }
74
+ catch {
75
+ continue;
76
+ }
77
+ const htmlPath = join(dir, 'card.html');
78
+ if (!existsSync(htmlPath))
79
+ continue; // 必须有 card.html
80
+ let html = '';
81
+ try {
82
+ html = readFileSync(htmlPath, 'utf8');
83
+ }
84
+ catch {
85
+ continue;
86
+ }
87
+ const meta = parseMeta(html);
88
+ const slotRaw = String(meta.slot ?? 'settings').trim();
89
+ const slot = EXT_UI_SLOTS.includes(slotRaw)
90
+ ? slotRaw
91
+ : 'settings';
92
+ if (!allowSlots.includes(slot))
93
+ continue; // 放错源 → 静默跳过(不报错,免得用户困惑)
94
+ const orderNum = Number(meta.order);
95
+ const files = EXT_UI_FILES.filter((f) => existsSync(join(dir, f)));
96
+ out.push({
97
+ extId,
98
+ dir,
99
+ from,
100
+ ...(pack ? { pack } : {}),
101
+ slot,
102
+ title: String(meta.title ?? '').trim() || extId,
103
+ order: Number.isFinite(orderNum) ? orderNum : 100,
104
+ files,
105
+ });
106
+ }
107
+ }
108
+ /**
109
+ * 列出所有扩展 UI 卡片。任何异常都安全跳过,绝不抛。
110
+ *
111
+ * @param dataRoot 插件数据根(每个机器人实例一份)→ 只收 slot=dock
112
+ * @param profileRoot DSH profile 根(全 profile 一份)→ 只收 slot=settings
113
+ */
114
+ export function listExtUi(dataRoot, profileRoot) {
115
+ const out = [];
116
+ const seen = new Set();
117
+ const push = (info) => {
118
+ if (seen.has(info.extId))
119
+ return; // 同名先到先得
120
+ seen.add(info.extId);
121
+ out.push(info);
122
+ };
123
+ // ① profile 级:只收 slot=settings
124
+ if (profileRoot) {
125
+ const found = [];
126
+ scanOneUiRoot(join(profileRoot, '.qqbot-extensions', 'ui'), 'profile', undefined, ['settings'], found);
127
+ found.forEach(push);
128
+ }
129
+ // ② 数据根:只收 slot=dock
130
+ {
131
+ const found = [];
132
+ scanOneUiRoot(join(dataRoot, '.qqbot-extensions', 'ui'), 'data', undefined, ['dock'], found);
133
+ found.forEach(push);
134
+ }
135
+ // ③ 扩展包内:跟着包走,包在数据根下 ⇒ 实例级 ⇒ 只收 dock
136
+ const packsRoot = join(dataRoot, EXT_PACKS_SUBDIR);
137
+ let packs = [];
138
+ try {
139
+ if (existsSync(packsRoot))
140
+ packs = readdirSync(packsRoot);
141
+ }
142
+ catch {
143
+ packs = [];
144
+ }
145
+ for (const pack of packs) {
146
+ const uiRoot = join(packsRoot, pack, 'ui');
147
+ if (!existsSync(uiRoot))
148
+ continue;
149
+ const found = [];
150
+ scanOneUiRoot(uiRoot, 'pack', pack, ['dock'], found);
151
+ found.forEach(push);
152
+ }
153
+ out.sort((a, b) => a.order - b.order || a.extId.localeCompare(b.extId));
154
+ return out;
155
+ }
156
+ /**
157
+ * 读一个扩展 UI 文件。
158
+ *
159
+ * 三重防护:
160
+ * ① extId 白名单正则 + 必须是 listExtUi 里真实存在的
161
+ * ② fileName 只允许 card.html / card.css / card.js
162
+ * ③ 拼完 resolve 再校验仍在所属目录内(防 `..` 穿越)
163
+ */
164
+ export function readExtUiFile(dataRoot, profileRoot, extId, fileName) {
165
+ if (!EXT_ID_RE.test(String(extId ?? '')))
166
+ return { ok: false, reason: 'extId 不合法' };
167
+ if (!EXT_UI_FILES.includes(fileName)) {
168
+ return { ok: false, reason: '只允许 card.html / card.css / card.js' };
169
+ }
170
+ const hit = listExtUi(dataRoot, profileRoot).find((x) => x.extId === extId);
171
+ if (!hit)
172
+ return { ok: false, reason: '没有这个扩展 UI(没扫到 card.html,或 slot 放错了源)' };
173
+ const target = resolve(hit.dir, fileName);
174
+ if (!target.startsWith(resolve(hit.dir) + sep))
175
+ return { ok: false, reason: '路径越界' };
176
+ try {
177
+ if (!existsSync(target))
178
+ return { ok: false, reason: '文件不存在' };
179
+ return { ok: true, path: target, text: readFileSync(target, 'utf8') };
180
+ }
181
+ catch (e) {
182
+ return { ok: false, reason: e instanceof Error ? e.message : String(e) };
183
+ }
184
+ }
185
+ //# sourceMappingURL=ext-ui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ext-ui.js","sourceRoot":"","sources":["../../src/features/ext-ui.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,6 @@ import type { QQBotSender } from '../transport/outbound-buffer.js';
2
2
  import type { ImQQBotConfig } from '../config.js';
3
3
  import type { Logger } from '../types.js';
4
4
  import type { SessionManager } from '../session/index.js';
5
- /** 官方 GROUP_JOIN_REQUEST 事件体(与本项目用到的字段) */
6
5
  export interface GroupJoinRequestEvent {
7
6
  group_openid?: string;
8
7
  join_request_id?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"group-join-request.d.ts","sourceRoot":"","sources":["../../src/features/group-join-request.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAM1D,2CAA2C;AAC3C,MAAM,WAAW,qBAAqB;IACpC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,KAAK,CAAC;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC;IACzH,aAAa,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,gCAAgC;AAChC,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qBAAqB;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB;IAChB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAuDD,4DAA4D;AAC5D,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,EAAE,EAAE,kBAAkB,GACrB,IAAI,CAUN;AAED,iDAAiD;AACjD,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,GAAG,CAAC,EAAE,MAAM,GACX,kBAAkB,EAAE,CAItB;AAED;;;;;;;;GAQG;AACH,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE,OAAO,EACb,IAAI,EAAE;IACJ,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,cAAc,CAAC;CACzB,GACA,OAAO,CAAC,OAAO,CAAC,CAgMlB"}
1
+ {"version":3,"file":"group-join-request.d.ts","sourceRoot":"","sources":["../../src/features/group-join-request.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAyB1D,MAAM,WAAW,qBAAqB;IACpC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,KAAK,CAAC;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC;IACzH,aAAa,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,gCAAgC;AAChC,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qBAAqB;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB;IAChB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAuDD,4DAA4D;AAC5D,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,EAAE,EAAE,kBAAkB,GACrB,IAAI,CAUN;AAED,iDAAiD;AACjD,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,GAAG,CAAC,EAAE,MAAM,GACX,kBAAkB,EAAE,CAItB;AAED;;;;;;;;GAQG;AACH,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE,OAAO,EACb,IAAI,EAAE;IACJ,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,cAAc,CAAC;CACzB,GACA,OAAO,CAAC,OAAO,CAAC,CAgMlB"}