From af7e6a22963a9c4ecd464e34b3824f6c5133b3b0 Mon Sep 17 00:00:00 2001 From: xmanrui <841206367@qq.com> Date: Sat, 15 Aug 2026 06:09:19 +0800 Subject: [PATCH] Add DingTalk to unified IM plugin --- README.md | 34 +- THIRD_PARTY_NOTICES.md | 4 +- bin/dsh-im.mjs | 8 +- docs/images/imbot.png | Bin 131576 -> 42848 bytes lib/client.js | 2223 ++++++++++++++++++++++++++--------- lib/index.js | 3 + package-lock.json | 28 + package.json | 1 + plugin-src/client/index.js | 31 +- plugin-src/client/styles.js | 9 +- plugin-src/host/index.mjs | 3 + scripts/verify-package.mjs | 13 +- test/client-ui.test.mjs | 7 +- test/host.test.mjs | 23 +- 14 files changed, 1809 insertions(+), 578 deletions(-) diff --git a/README.md b/README.md index de6690c..8172e61 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## 中文 -通过扫码把 IM 机器人接入 DeepSeek Harness。一个插件、一个设置入口,统一管理飞书和微信机器人。 +通过扫码把 IM 机器人接入 DeepSeek Harness。一个插件、一个设置入口,统一管理飞书、微信和钉钉机器人。 > GitHub 简介:通过扫码把IM机器人接入DeepSeek Harness(支持飞书、微信、钉钉等)。 @@ -13,9 +13,10 @@ ## 当前内置渠道 - 飞书:扫码创建并绑定机器人,使用长连接收发消息; -- 微信:扫码绑定微信机器人,使用腾讯 iLink 长轮询收发消息。 +- 微信:扫码绑定微信机器人,使用腾讯 iLink 长轮询收发消息; +- 钉钉:扫码创建并授权机器人,使用钉钉 Stream 长连接收发消息。 -钉钉等其他 IM 平台可继续按同一渠道适配器结构接入;当前可操作界面仅展示已实现的飞书和微信。 +其他 IM 平台可继续按同一渠道适配器结构接入。 ## 安装 @@ -23,14 +24,16 @@ npx -y github:xmanrui/dsh-im install ``` -重启 `dsh web`,然后打开「设置 → 插件 → IM机器人」。安装器会用 `dsh-im` 替换 profile 中直接安装的 `dsh-feishu` 和 `dsh-weixin`,但不删除任何渠道数据;原有飞书凭据和微信扫码绑定会继续使用。 +重启 `dsh web`,然后打开「设置 → 插件 → IM机器人」。安装器会用 `dsh-im` 替换 profile 中直接安装的 `dsh-feishu`、`dsh-weixin` 和 `dsh-dingtalk`,但不删除任何渠道数据;原有渠道凭据和扫码绑定会继续使用。 + +钉钉接入时,用钉钉 App 扫描页面二维码,再在钉钉授权页点击「一键创建新机器人」。钉钉当前可能在该官方授权页显示 OpenClaw 品牌;扫码后的机器人连接、凭据和消息均由 DeepSeek Harness 管理。由于扫码结果不包含扫码人的 staff ID,首次私聊后还需要在本机页面批准该使用者,未批准消息不会进入 Harness。 ## 设计 - Harness 中只注册一个「IM机器人」设置页; -- 左侧使用飞书和微信 Logo 切换渠道,不使用启用/停用开关; -- 两个渠道保持独立的 RPC、凭据、连接监督和会话映射; -- 浏览器只获得二维码和脱敏状态,不获得 App Secret 或 `bot_token`。 +- 左侧使用渠道 Logo 切换微信、飞书和钉钉,不使用启用/停用开关; +- 三个渠道保持独立的 RPC、凭据、连接监督和会话映射; +- 浏览器只获得二维码和脱敏状态,不获得 App Secret、`bot_token`、钉钉 `client_secret` 或原始 staff ID。 ## 本地开发 @@ -40,13 +43,13 @@ npm run check node bin/dsh-im.mjs install --source . ``` -`npm run check` 运行单元测试、构建 Host/Client 产物,并验证发布包不包含凭据或独立飞书/微信设置页注册。 +`npm run check` 运行单元测试、构建 Host/Client 产物,并验证发布包不包含凭据或独立渠道设置页注册。 --- ## English -Connect IM bots to DeepSeek Harness by scanning a QR code. One plugin and one settings entry provide unified management for Feishu and WeChat bots. +Connect IM bots to DeepSeek Harness by scanning a QR code. One plugin and one settings entry provide unified management for Feishu, WeChat, and DingTalk bots. > GitHub description: Connect IM bots to DeepSeek Harness by scanning a QR code (supports Feishu, WeChat, DingTalk, and more). @@ -58,8 +61,9 @@ Connect IM bots to DeepSeek Harness by scanning a QR code. One plugin and one se - Feishu: create and bind a bot by scanning a QR code, then send and receive messages over a persistent connection. - WeChat: bind a WeChat bot by scanning a QR code, then send and receive messages through Tencent iLink long polling. +- DingTalk: create and authorize a bot by scanning a QR code, then send and receive messages through DingTalk Stream. -Other IM platforms such as DingTalk can be added through the same channel-adapter structure. The current interface only exposes the implemented Feishu and WeChat channels. +Other IM platforms can be added through the same channel-adapter structure. ## Installation @@ -67,14 +71,16 @@ Other IM platforms such as DingTalk can be added through the same channel-adapte npx -y github:xmanrui/dsh-im install ``` -Restart `dsh web`, then open **Settings → Plugins → IM Bot**. The installer replaces directly installed `dsh-feishu` and `dsh-weixin` entries in the profile with `dsh-im` without deleting channel data. Existing Feishu credentials and WeChat QR bindings continue to work. +Restart `dsh web`, then open **Settings → Plugins → IM Bot**. The installer replaces directly installed `dsh-feishu`, `dsh-weixin`, and `dsh-dingtalk` entries in the profile with `dsh-im` without deleting channel data. + +For DingTalk, scan the QR code with the DingTalk app and choose **Create a new bot** on the authorization page. That DingTalk-hosted page may currently display OpenClaw branding; the resulting connection, credentials, and messages are managed by DeepSeek Harness. Because the scan result does not identify the scanning user, send the bot a direct message and approve that sender locally before the message can enter Harness. ## Design - Registers a single **IM Bot** settings page in Harness. -- Uses Feishu and WeChat logos for channel navigation without enable/disable switches. +- Uses channel logos for WeChat, Feishu, and DingTalk navigation without enable/disable switches. - Keeps RPC endpoints, credentials, connection supervision, and session mappings isolated by channel. -- Sends only QR codes and redacted status data to the browser, never App Secrets or `bot_token` values. +- Sends only QR codes and redacted status data to the browser, never App Secrets, `bot_token`, DingTalk `client_secret`, or raw staff IDs. ## Local development @@ -84,4 +90,4 @@ npm run check node bin/dsh-im.mjs install --source . ``` -`npm run check` runs unit tests, builds the Host and Client artifacts, and verifies that the published package contains neither credentials nor standalone Feishu or WeChat settings-page registrations. +`npm run check` runs unit tests, builds the Host and Client artifacts, and verifies that the published package contains neither credentials nor standalone channel settings-page registrations. diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index a1175af..60dd601 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -1,7 +1,7 @@ # Third-party notices -This package composes [`@xmanrui/dsh-feishu`](https://github.com/xmanrui/dsh-feishu) at commit `aad650feabadd511241aa58b236d64273d5e397f` and [`@xmanrui/dsh-weixin`](https://github.com/xmanrui/dsh-weixin) at commit `76d076771b2c84fb4c5598c2344d486695eda080`, both under the MIT License. +This package composes [`@xmanrui/dsh-feishu`](https://github.com/xmanrui/dsh-feishu) at commit `aad650feabadd511241aa58b236d64273d5e397f`, [`@xmanrui/dsh-weixin`](https://github.com/xmanrui/dsh-weixin) at commit `76d076771b2c84fb4c5598c2344d486695eda080`, and [`@xmanrui/dsh-dingtalk`](https://github.com/xmanrui/dsh-dingtalk) at commit `67f7211b8011f0623b47ce9e01004bbab8e6614f`, all under the MIT License. The channel client components are adapted from those projects and preserve their security model: secrets remain in the DeepSeek Harness Host credential provider and never enter the browser-facing RPC response. -The WeChat mark uses path data published by Simple Icons under the CC0 1.0 Universal license. The Feishu mark is an original inline vector used for channel identification. Product names and logos remain trademarks of their respective owners. +The WeChat mark uses path data published by Simple Icons under the CC0 1.0 Universal license. The Feishu and DingTalk marks are inline vectors used for channel identification. Product names and logos remain trademarks of their respective owners. diff --git a/bin/dsh-im.mjs b/bin/dsh-im.mjs index cde924a..f2b46fd 100755 --- a/bin/dsh-im.mjs +++ b/bin/dsh-im.mjs @@ -7,7 +7,11 @@ import { spawnSync } from 'node:child_process'; const PACKAGE_NAME = '@xmanrui/dsh-im'; const DEFAULT_SOURCE = 'github:xmanrui/dsh-im'; -const LEGACY_PACKAGES = ['@xmanrui/dsh-feishu', '@xmanrui/dsh-weixin']; +const LEGACY_PACKAGES = [ + '@xmanrui/dsh-feishu', + '@xmanrui/dsh-weixin', + '@xmanrui/dsh-dingtalk', +]; function usage() { console.log(`Usage: @@ -80,7 +84,7 @@ try { } console.log('\nIM 机器人插件已安装。请重启 dsh web,然后打开「设置 → 插件 → IM机器人」。'); if (legacy.size > 0) { - console.log('已用 dsh-im 替换独立飞书/微信插件;原有凭据和扫码绑定保持不变。'); + console.log('已用 dsh-im 替换独立飞书/微信/钉钉插件;原有凭据和扫码绑定保持不变。'); } } else if (command === 'uninstall') { if (args.length > 0) throw new Error(`无法识别的参数:${args.join(' ')}`); diff --git a/docs/images/imbot.png b/docs/images/imbot.png index cbdd48b003c804df30060876e467993072486ac3..cf9bfac7d0dc4fcd238fc28c8998bf807960cce6 100644 GIT binary patch literal 42848 zcmeFZ2UL^WwlEsIfT$?Fs)#^niiBPiHy~jrKnf)^5fPFQklsPJV4*4`pg=$fA%qZ6 zA@rgkARsjXqzgzd(vkk-Irr?d?-}R5_wF74c;k)t-pUyH)|zv!x#p_hTyw7V?SI|> z1~?1WH`E6lIs^b5I`{$h`vJEA$B!O6e(dP+Th( z=i}z(6%>&W6BH5`=HQtOu>S$Tb@FigF~E^SmjH*k4jth-wEqbp{7cMZzr_7B965COK;9E453umFfWwE5 z96oa7#EFx~PaZvf_Q~>pqI>=p5nY zyN*EKz3ku^pFzqT^?dw(Q9}9F9|bj6^p*+_mgrJoim|_w)`P#YZncUb_BnQAu|Mw%-RhbwGHS>j)P> z2e5YakjbB1|4rnWq6tUDy*G#HaeB*_?!63pMq5_2dig^BbEB*NjdF2`Qh~#BQ3>Dg zalHTk5?Bs+?B>lEz`wTFA?ypj!ep5N2u!^sKKTm6*3HRpS%B`XTwMfV51 zMlO?FyAc+mIcI=-h4kG7or`KIATnAFNocpPHTQ{x$^Df=DVNOM%&sKJX{R} zOx@0DcP?p}4RsFjDlWaf1t_UeD8^E+XFGr2VEH7zUbJ@bH4v2)t<`vF&Jrvan z&W1CdOdAUN_C?~hJ!1U$~SIf4&%A&*<#5ass72U-)q5%=>vxdY6h6#P6lqJcz8G?Dz}*=8VW&R<^By z(nQ+qb(MxbTS*!~lgx_Pl^AtERFc`|J!~cOA8Mw8(xoOnmaffUxG&18+xeD{PJj<1RANPYNxcvgn7o4)*WTXa1f;axUW1D7PqMpSPxe1TWZFp33_LB`G8Yzr z?cw+V_U9p-bzL;+YlOy4mp+BQWPgYbYH`W~D~+e1bl>86;# zYCT6ef80Dm)v~{2bssQOHmo+#lJIyr5SL|JUp9I9!@^t$*7#f0A5A8`$9SfGEz+h> zOb+Qcy>G0z@?kEJhpf*%L_(?2H0u*W^|ceX_I^C?I@@b%wvLyovxol?`^S|_2i^I< zHxzkB@j6aVC7M~4(WW61duWG+-`Ng{VgtGN0l2-9q@g;U{?L;DDMW~>x(`4bbM)|~ zoV$`4Z!Ep_w@G#6^?XbUMb8cv1H8pWjr~3N%v$J=bS9UrsW~qpyU`KxI5y(Q7xs+L znwiZHOL?S_|ETjJmv&>BQzeW~r!yz7&{ryAJmxu+UZ?`|^ zY>0h0V+Y{672UOM>78jkyXKbtRZg&})!b~Oy(|*!ZsCRbSV2|ub;tL}R|bmLu4$>< zBrj9@Tw6`Zoa$NhEL2almDO#q5~jv`23+}jUA-zs)T?yD^yizY@@xG>|Ml2g%x!zO zjA<4l8Z^|uNP~jJHJRWj{9^H*XGYsCv9_i@m{MK7UrtDkmVMRa|J*MRu<axA_Vy_)S>Kqu)kFiKM_ypx(4O#logqTJ*zC*uerXYTAF*KFH;5`TYR$>^N6 z7(&ucn4QC4&UiB@E!R1#!oby=8Q<3q+!QJz=n(iE-3@jHQ)AUvr;#KW@OpFr_&S)3 zij`J=pEMJEQtw~e_r(3;bb2VaF4jMK#Q7$4< zi%PpmWEv-oz#@IxnWse|6uT#OEiJApX!yFJH}!ft7z7b5Y3oMQEY_uN_>YzGFL9lf zLc@5WI-Dshx+*2xEam!yaijvM8p|Qcm+j-(tRd6Si6XR?)|5pNGBJZl7#++_;*r){ zLAQlm@7A!(JYCBWsdzuvMGg;!8&_xLt4Q5!4Rhk-?uWs0D%mP>^CH#I0_&Aoqr>R# zwbf|dZsK;on>)-)5(*n>%DN8CP4hW78RaqCK2l}6TH4;dt)(9>(?11cR3vPr1gu15 zPU~s4lPs49`o6d~=fA1jRHk8}%$ul8Z<%P@NHV(;&@8{ED06O<2o>7t1IuGoXJx&Q zP)ar-OlO;>p#WR@C%8$3J4s|O@CnTOd`-QbyeYckitA)Qr|6SJhu~~$x|Z#&U_o=g zu;Fr=<@EGwst9#@T}3dJ>S^#BgT`+?AcKj>KlWflt0XJQqQ+vpZ7nq&>rG~DYIGL< zgq8T3^A=8mW74pjUk7fv6qCdGRav!zng&{y`Wpqi#qEr?%VcaYl&^=IwG%_Cv(WT} z1iszOvo2M>Gh-*!cRE?Eez}aa*@vfs$+vYu1ogscs3~q0o|3p{J^b6vUQ`eMhy1ip zRkW2&C@c!?jvG^uB&gQShXW%uP=jiqE95d*y_rDsKEOaecUu4zpp=VquHWoi%;{y( z;f`8h(jTzV%#7kmA^(-hHoR!DeIPa)r8`qI5#Gi4eU7f1ks|T*>2rDGBzFwIDX8{Kxn40phykvxH{4C!ePez1#@*fxv8BFBeHu?rA)JCpoX%e*R1i;?;MPlLoN%i`5Chc9i@qVKYXZkaIW^QCGS z>fY1!nf9n;ifUHDbG;Sgfe)VnhrY9hUyD5gUL+61ejpt307hKOW`Fo!PU>feqq3>L zhb7CrdjS`h=;#0Xq41+I}M8xcmW;@|G1xrX1@W_sojApB&-(} z)>YVSRATNmh%}1}g2Y}O*p+r%4l1p-ECQf^lwV7?gS{ntXIii*_NuJHND|KnJPLcC zFS*0RI@+Fma2(OL-HYsWFzc3e9;$C82iX`2 zp`{EPDbt4Xsl^=uH`jJ;0}o zPOxl`nMua#k%c8wCOJK=doCYm2`1U3GqLUAfha~^cAF}Z!9X>Frd+xFLMFddsn3UH zTbV`8mRPe0K#QX6{uE!=NGp$|e)*EA5514sW)dP8>d?$$7VTr~#Q0N9m15NzKgg@j zdEU4@CpV7I$b9w+0XSIz5trJac~^Qb%1%2aY4$VcTTsH*da~^h*>7Nu1Wf@pdD{cA zE=>0j56e~o7mZuwR(7ui!fjO;wd^cDF4|DFR!-g$k7^(ZFCJ&{tH;nCDa!fS90-iy zIvaA&J+U#c=b{_U(%MD_17gwC5HW*v&&T}=2I>2N3)dfU2IeRM`#Wh`1trN8L;K23 zQ+(2fM^u`QsVF(ScRFFFa<@*MI|a|3wUjV)Zu>^l@ziRxQXdZmoSCe#_A*0K%Vj zC2HeMBU^>g_VUL0*_>}=(^14aezSBKk2Dl$k|K(TpJJ{iJ_K~npcaT(J>Q0`vk|7l zm(!(PVi~fM43D58z6;7XG9?6Ru7}}C5_o2lb2i{6)>rpO^!JtFkJ;14@fLA2r8{6& zDG53gT{t6QTj(ftizy-OR4em|?GdL;4#-ueoni{6A1B=2RM(}x$ zKbnH4_N3gW1MX++!p1k^0ODgETd2^&r=qc)%-zh}fY?}rY4l#FaDa}H@%qaPK`*$L zrgr6Y`fmLP923&>_3j{6Fqn+-a?O|Oq``$8)a)xN6pCL6SpO~4i@$S>#8`Jwpl~Ye zY8V_(mN%4`zOQxAwZQ`Am{zN6Wr|_x5(NBWrysWSIGlcBH!XD^(A+jJ1Laha9%vX(sj^0=rOi%cck4cls&Y^6E<)`9@1|(yTZgBmlWbw1W}kW(-MU`f~Mt{2@Q;4{*xx2R@RSf+C0xVBTqy1uK=+2+ZI>c2)8 zw-n+H@9l_u_Z_x-dgdj2fPk-m4!VDhaEiIe&~V~Wc`~Ln!IvY8nat!iQ25YzVl2$9 z-Jh`@uRg4@CBt0JHUD4<5NhsEg?|)j{S;_C%C(=VO z>&BW;A+3e!wcgWBNy*VtR3nF#qDh^KDGE;4YZB@u4L}RGR_vi`42#s; zqP?CE*vIwgn3J#Qn2-pqXtnaY7#}HlBF39c zOf7=mwFI5Jg;^Quoe{Otka^aMSe;2&!~TGiDr=I#V0QO$$x?f&&eP25o6tm@RWTh# zS93>0k(f?+1X)r*O{zgod8G}zR@^8uZ>53ih{E)nra17Oq{1Om6^;s?HRB6197fIv z&+tnAmW40)b0MBzO1FnqW`zu{2hrC5SSGIHS8hRE$+`WXT(KUo+I8iHCkxRnj6vCX zy;bj!mU^G-q!Z&x_6LJ63GejjX>xJL<=rzKvyDCa*TN8Y@OKl=8L?dgCKRnX3Lw(K z9#LJtjUVlcvw-~^>(ujqLNR{Ym$ND_FGYLZlSP#tw61eVo3tjGyIdtpWiL;>jT`VO zt4ODH#XL3UL2u@p;601Dd$ff@Sevrmef?`robwSX;UJRuZ8ov2WMR_dWGwS78xi zy)$K_q^Stjmud%U9`ZhY%>#yZHDVh}0^Xcp$o-IWQOfasK*)Lx^YtbQrrgefdi%n{ ze!59#gDq^%k9S?nmf1}T0?Cx+4S(i4UN~lZ8tH4KaQ0L2{K%NEcFAfgo}-Z2>V{!1 z@9L%&cxHn~1%nGRrrhn57Opo(IdtO4Vfz68*P$pgr0QC}tJkhAnJ8gl!xmT#{g1^9tTG_SE}3`6}H`p{NRxiFtL{Tapaw0W$44 z%{br>N@JrDrnc>JrNHHG9VsK*GUS4z{xmf9rJ;Voicf=v!x_*-AS-^=d;D<+;Oj^s z+1H@3`1BSJZ=#lNPI_$`j$qoU-0F_(7Os9Z5Bv8BE);sx$_o=V|o6|jiRyoqx*p6U^;7o zn8b1wf7Y6No?PP*(HvMbzTCVK82j6?uOoRlV7)qdRl4F5IF4!M8Mh=n+muh!ZHD=DF%!s(1!DlDmQy5=;o7BWgSABr-kgPM%bw0k47 zD@t!V20XKqC+ma82^@708~CVxN^!RGdht}#)Y6aD6;Pi|u8fH$2;#-cq-&t!X-nyp{UC&0!o4+mhjWj99OOg=;$a1btPm zlo|4-I%fU>S+!J@f}s}@?Q}1s01oU9e&GX?Je*aTH>HseW;T=kI-+X9~tB*#~m!{#rAH_&({}$$+8Q*x}uU+yh&c$0rt`jho4dA&H_1316 z%lwa)DYqN894hIRhx}xRo~$1GRuCZ6&i5*Dy~@;BG+z85Aw1RrEL}+y_jGg=3J~J6 z7O-j`dN=_(-P~DT?tTAWpHB#}-0Fc_@d1lwYad%4Y!fN?_gTnkZXDUDy=7=s<&7G! zGX8P)IIr7k;4z1rHwF3+7*z1O-3mCoXj#cQ#Sy{#Lr=J!jSIP;^C&3mSx$>fC_u{# z02nL3)xRqPWtqj2!Gdkh<49OcA{M3j+fu^Bu$2BaNYR$Z8u9s9pLq9hV^vwXT*Fv{ zU8&LI+T~%%<@`3^ogrnF`QfSl=?@~YPTQemjC$<%V3W@v_JdT-zVIiMrA917fN^K2P&xIdp7J(QAKbNtB$qfCpS zG2KIdu=9j+dV-rSgCvT9n!QN;%5OSx#zJ=Kan4%VoolnnIf5<=WV0^4?r1EKrR-{H z1iC1S^K7v8)SN5^F(S%#3X{x{`I0i*xVNN}Oe)Yb-Cq(61)*Idz9xO?$xk!L-aJcy z$nRQp4da}Q4C(H$C;I?Jg=oIgI%}lin6C=IQ=09Y04)W4NK1EgF4c@RqradrKj0Nv zPcslIIMd?aEWBKKyfYTF8c-%-V`I&FlBQ21nUSpm@PpFQQk6@1L`Hm2zoA4+VQH$u zo3Ar?y0)>jvGF`A>0Lh$r*5D0XrJ1MB)r9T+I}n%p7qwZJ53Tb-&Hw5viHR13^YBU z13^xv>Qq%E4yq78$=G`zvyGU45}AcL-LyP9Viu7#G2PougR+x8sUX6H9TI1q(+agH zo#mRN3{)4j)P&}_Ny9LTIw{3LYZRT4larc{gmV@WzylX~lXml9T zja;g)LL1DSciVCOEpTP zgBk%nTqV&5tyKPIq^ofxi*mWs=FFRaolF0l(#v3*xKGX!MrdA_^wM1ZSbtm0)t*oLHVKA#%B!f9Lz$kubc<7(Dq$U{oiI`R|3^r z|6mq|y-7Tng@%{QJlBZN0G{64=hMwfh)qTL`s?0KD080;q;n5GYnhd!3x>s}>lMWr zUXJ4~=OgQe53&cwqxq!bA$I=T3W}8qGh1kL|YgUNduQI~YY?@pyJ(Gw5~_MUNqAfzpWGrviIT$A^JQj{zY@jZW_EZ{@`Jfil3ufE zK7MhmbTsHYE9qb#4SjW}sn6$xZUM{L&Z^cVyz5jpVu$43sGJOOt2M?n1*M+O{?8qy z^7t@)m8_=Q&F<&t8UG2sreI0HDlZxmuYb%PvkR6hI~Zl5pHzE>A#Qu)`v9&)+D{7n zKBtr5_B4GTFi<@zjQx>Sybti$2RsX?e$MKBY*}Bmg$>?!*+F9rB`gX3;Leq}23kHg;p01hYBkN$0IhaOz;)z01}Yf^U7oCN?4%W2EO zq^8iu^+zvGg-Y)OB>Vma(|mwAIo%aCq^<+M3^?R6$*-Wc_eTEc>B%m!LJEE#5I=w9 z0{Xw(6kWqh8NJ>-Y3cI)T!^8MB?FwdW$7P{aD8W%&TJ~}1HwWf z0)P{PdeY3dtCpNPAe}J7V>Z9fowRI`}%5Z znf29%gOT?#Xj0iFDooY!KY9p8(AUgPKR4%mzW@usbN~Qw<}!J}?y$v6*n+|%*&7v9 z-8YE;JWc+RI;tmdurip&noTGTE50p>BBkAo4lUs5hJoe#&ju|X&D%>#RkV{Sk(#^` z;j?V(>87TbRLAo|nSEXE^@D_|?~_!OdfUe84CWsn&i#e$LG*oYmugXq7vn@Z-e16c z$s=PCYj2h!rP`$ZKnNSqRH*no+BRPEd*2}u!|W@);pV24qr3Hb3x0|po7zG)7p6|! zL?_+nw=)ivWv5Y!!pp`uQrTG2(U_Zl<5b~?xtoOc0%__?`+CG0V%;BWe zM+xq?ajSeY)qR$sV>-L%S<>jBAj2H*_CRytr`( zrXVdCY*(n9R1_B!1L}X8oZX^hz6HBh(w9eygW)mLj`J(<$tay}T&lct z>g(JeyHBnq#0&NNamqjK(~z?ZX9rixysm5Ppy|82Hz3BNg0rT&;zi!ILB?QBMUnd7 z0Q`!7@1K)X+MGM?19?f{L-`!=)K+34e5-t(KX`DBjdn@XeeEkmFT0G1PeWS zUl-&4#aO1NFc_RyY-^fsR)}e7Iv>$gJC(fZK+!Rs7SvP6=TdbGi&;_P0!H1P6D_Lm z`_^B*>P~reeOO}N${cmCW;AL6XcCU`$cIQnlj1xgf`x3%9yBdcHw}&i`SttGwP}^s zLqOqV4cl(JGH#?QqL3^NzE*=D1k;Ol6<*6H?!BaAHf*1PiJ4+$Tm$=nQL4l~pwG>_ z=s^hyR*5=Gha#z$XW%fXiE)-WGUYn^wiVL_1N1d7TAeAa7ZTAcRbk3#CQ`0kNk&6^ z7y*fgBgjx6pJms-6|!Kgo!H{{O8u$OmJ!Mqv^v8@)|c;(<&&bff*~t0_tux!WVgNw z4L5b49;yuR#RHk?CtxJ9sj&;J)jx=R0HeIVHVw;}pum8JE^Ztiu{!2z@)U75TXUQ6 ztXaFSti1X8?_|N8_^^tegX;VHPi#4H20&~{94NkZo}Wc<*Qhs3Cs_np9LAIQ+g5hV zBnG!^I4L2Ta^EENr{_$Rlpz>sq>7c1IgX?lo`pyj$yMJBmsT?@W;N&U;-fBHUGSE{ z20rhgs+GO?g99nsEL{i$Q>C}-Q5_u9%NEN4?fN6*UebV1Pg%^F2~ zu~C43^MhDp0|ld2(KI+B){((cX2gThMWS0LCXi!C3kHo9;w&dNt9>u13yP$7%BV*O z5;8_wK9-tAG~4C{^=M}~4vuqJ`J2;Cf$p_9&za5ONiqGL!Y-w4t6&2|3Qh>s8-Ba^ z3E8N6awSd8b8F~5v8aILE!agNQQNba-ecg?NOGfW#pGS%wQ87kErV`L1o8k|jT}`= z8}s}O@6`shM3hlnXAq;T{@4~sL#t(kM?GtpT98D~3f*xqeUE|&c};7Y5v3%7SXB=r zofN|$MdoVZyIgxC;{v4cG%bM7r`u~lU;(_0q^qN zz=h{csXR(awY8Slaq71p8!kUt`nr2dY-S&@^HLMBo`%=igR*p%|CY2^@efVaHa^i= zJrtX`B1>1VuOfL11v)QKFAr-+a%k?HYIbeI_+CA5%SpQ}tSXl}e>I>7&M4TH2|8%EZJsIao7uh2L1$)d%#v)#LCF`Z2~Wwd2!m*OAh^&-#;3 z3l7Ot2klm!o0MBMYFhVN82i3dOqF|wUyyD{b&pa>155jpY*3wK7_6AaPEa-V!s=6q zGb>hWq}&c_Ut0mMil`xx|ypqVzhI-JOip`&787ATKQ`+u()>w5nUecpH-#; z&@AisB<_A|rB2%d1*D+MI>zhMkNQiYL#+X6_d(zab8tiox@XxJq@d!fG!)<hr-FQ1pNK$#$>fM&(;B1%=X z%*l_Hi&o5}iLxq-4I%m^Q-Tn>pG6l1F%-0+RyiyWT35aM>a7IN@JIYKwX36DVaBYubf+B2ikWJs!h|JYFdE-0%_7!=&WWvnrElsIr+XX5*?YUleT1A! zD2xR(qZ&@P84b%tsIFLV=9#XP@681+ieBp*8o(+sT)(1=it#QOlsdQEIQt8lYHKDc z670$q5lE6Y^6cxh@K+uTpTClyGeb-#duChPJeZj(*{w!YimWTX z_cusH_sQ4U7@2nQCQ=Y|7y|__$~T3@4Y9~D&y=01h7cilsLj==m^vT0`CMhN?h_Jw zUk)KtV^cY3W9@5<>pPzF>R6fY9Vr{MxU1!jE}V`6=Sae_tN(3D9& zQ`30F&IVtRFsY?^CwI-YacID{8MT~~M>ztc>!!k1?%*F(b^EupB)aHGO*0ux5XPr4 z8`_=g;6$li(Qp^U04GmNZ>in+v1dFtgWft3*TtlL1@qinN0RlEQ~ej}fbq5|jup!n zrf>XZaQuqi!ThOh%XbB?yX|`J13E4-gF-CqwH244y)B*d-h;O{(t#e9YuUf8HlOZ7 z7o)r@F^NiY3&2`UK?3jHmDq!=Tk!HzN>_Src?-Rx#He*uS|ZBtvd7a{mxS7cVF5pF zW{5m?M$_>}q8WPyu!hV5ZgTeLvO@c8Vk4X$*}SFDDx&Fr@BjvDQ0xB zxpCD=H>J&x63SL=`shTIz@-(Trv-6DZ*A5DT__tOHNyU`MTGI;!VYQT2h|PCS#)xMW;&!u9wLCkHgl6F;Bb1n(~`kxVgc zbo$mGdQK)<+_;2b;EvX(QDGoTl^QI?fuUU4{BltHB|X3En)*Iqa7P=WopBdbd~rFL z51VU?YJqzaPIe7K$!fW-Sb?XRKYrJM$k(@yBIjkNOlVSb9^_-fxs$?CwND92*YC|f zb8RprdtU%dy8OMrPv!(I9GtJ>*#}I$mj0#OALza+`+%d7VqOW|T3oP~3mKH_cdSmY z?iGKFjQpFPf0hpb01=+pcV&$z_@=*pl-bQM*Z}4nue(<%D=Ys5OM>h@hjQvT%>&U- z4BT`H6^?>eO<*ZGngNbi`a@*DK0t5lIDccVhjbMDuBe`{iZSvABPL}X6eHZkwq5>- zZU?PS!Lo)=6I7jgBlMi~@ncf0DVH;uaqh-)0Xtl2A1QOYq{qg++xqpF?|xrQuuO&u zU3h6xr{_<-lxdoqd;K(Bg)Ol1)ECYxZ$EVF5>%m?BTz1)e#-YaD8yrOR(x5;8et2$ z#UprN%}}nGNQH+K$2(6kLo?vNxEd8=$v9mw7=Z>!%_ZC^%?nB^PhN6tjg~|ryuQuI z`nSqx7Q}?oe-`NcA~!gmR0hf_ z+$dLF-mx2IsQw^D8Onthn_}Rd{@JAO!lkHs^@gg912eV76wGT-1uU%6(txSm)vx_i z%tz1pOO-OB`X2Niji?98v>5VSD%~4~6Ky}wT+2$vTuYpRM~2>YdY-1&dM!nQtq!bc zfzHi};e&0e73RAG6U^foVX1x|lut$@Egnm1YN|N@NaT3Ht*7yzjGx=vsc4+1Z8x02 zz~ITMC5AN+6~3+@j_jd96L&9HEc3xa2@5NBq-rnsV2d@pI=m4()3$qHy@MQhCR^q< zgHpIYes9p@ipZ^~STZ$(wvAyfH)K@PKGzQ=^N87L64#rCpO zT~tc{r&9l6QKJuWsnk#~_Xv1-^ekl{3Zs;$x%#u9^xss>UrXOkfjVcMy%FrNuu>LJ zK*dvGP!e2Z*gX?RD=1vi1QLgX?bZ%urfiTywez zU0*cf@ILhl-HFAKR-7dR*~EBwD_aJg!leS=Peit5oX$neF4zJhbe6XYdR@pyiP2RqAjj(fpW1TtL?t zG&wow;VXWh4Hiuv_FEOwNTKZp^i-$}c|M~GZsh8ldr0-da*jposz{5rt;gX9Rszzp zdEp;^iDp6qnm%$6rwt~4c=@txq50d1{D&vs{KEX3aLPtMGT*I;6ZjHi;?`Zpj|b+w z3re|P3RcLqqb3{5zDnf9(+r`8^%)lM$l4|4&JMbfKy1)8d3yGsDM2Q}oeH&akifTG zF26_uL&~+Qa^mftS1(I%$uDSL+!6mw*dmm6`?RV>^!As-q@rE#+FhWC2LD`JXZ+U_+ zU(~0N=0|S-!1(`z_V;c7B42Bcpoq|6`M;K|;ZN*2JbWo_qdE3u=*i^+6LL_=;?u>L zAt&z-#s3gb^B=j2Uk^Tz`;#d4AKB(7{+p~@GLzldcrEn?to;r40bsWJw9VvMg{SEu z?|)7&;?$W`t3l;=-{O96je1~&x&-3jVk}J^KK{i1@AfBoxu*f4R*N^R|4oPeAAyd1 zl!4N6GvjL%?R`OKpb&!k*$38%x>W{{s)raSZ@2(11FYh$yyDVKqfi?i(qD1_(U&_+ zX@okP=H!nrDW&Rdp7(1TrMDtSbgw4BKJw&OK8|+0Y!CGo`C?^!e9wy{nGk7HA!Lj> zVi!VIfAEpF??o8wJ8m4TAYgNZ%op`W$s34x+@J{2#+kc9k}dmnZA@>YYDCWR<-D5$ zr<$J2cz-+L?7!TMI3`qc(U%MMfe*kQjoSw2T1}b3(xp7>A2@cW3)0U0CVC5S;q8xu zyO1~gPM9ITSIh-m^)7VQkNaeb!-A2vP6rpY!pC3M#EhQ<7gT+LdwiTaUH{n7MbFVe z-zep*@G0zoJGYbcy`Y!;+G`yfz;A3csdqMNOIix1r;Wr#%PT^8t0+Uo?4w6GnK8cZkI^KLcB-bk;01PZ|IR);f0Z@o{u%(r-(yUBWix#{s9~g7l1`^ z2#DCuRUM6rIWR{9w1VC<^uVW$^V1Lf^t%_g8rkcqFr?_c{te#8DV6hWjVdpcoEY7#$iYK!ZC6vgb zMk8HH-fs?NSInO#I-wQ_E#P+q8bvVKxz*1T(!efV^*mw9CX?yi+oXOkZ|0+3bEJkk zYg$uNiJ~f1oTlsl{lmcHn{Y;%rd*y(dBT`Mbg7gk1Druou0%t~X#;K_{yB=}ZBEg! zPfK;(q*w1tS-%pxb132=;8d)uarJ_Ypro_G~$3jp?A;WsRBBrZAJP&?jz-5w3QMv~A~Z+Jx%g;fgnu z#Sf&hE7)oHJN)+XPeE#dMt>3V2ISd#t2R}^_tF$YqB-6DUPa&Yytvt=!;5@307W9x zyKW!(cxx+l=sz#W0}i#WS6j2Z0+PJtWPUGX$qXR~Qq25p{jO4}1+ZFFaS=Y1Pw)Iq z-+tT9Y2PFSsOocjVPSPO$-aR?)2D^y7_rSGy4{zqYFj&GQP;JLDs9PmvBqX0aCdel zsRlZf6Y2RF7ULL>?|~<<7CRrPE+@z%KYKsuwpDjz;0XUh zV8(WdMg0SVYM-Zto$Y~!>Ak~N%$UR+mJj}iYL%CKk}LQ4Dc^e;opEkyR}$eWjIG^b z$88ON+E9Ha)x;Fc{cTdZ6=o6!Gpr~D%dDmPduHhnnv-c;5tS4tIozaye!i+|E91-C zo%h%LFxUF<*LxI$-eb2t`!HJ#jZm6>Zb!-c`75t|DV;1SlgFL|3)487L4t(9NXeMy zX29VhpJ7?$F7$f9>6!)KL`ABISzk2Kzw4dXbY0^EmM^0!^HQ?K#IAmu<)-O-3hC>N zASV&0PYm!iKaWJve|phbtd%k~xc7y0{xP|tE%CTHIsBa0pk1MRmkb&t7kEp>(>ITa zko0sOgDO&NN*c~6x@z(61hl&D=7>oSMs~ZpVdUg6f^@elwNXGfbB1)+KvKekgaOb{ zlm8Lg`%Pa)_B3?TD2G1gX{N#>rSEO+Y!Dq0A?=hYRkU?Cz1t^oTr@Sh&$w~5usL}a zi{j%;+7oTGjM1DD$XD=Ht!QJW!AKH0C(>hY9RmoDCaX(O(+jCuIAglyQ;K8YqNkWT%j+WMK@wap4 zO$^bFnb7!gk}b28h)Gd{QFSxL^>may>kOop>mMW;ceZ-8jhAiB8s&SfascI(Pp`A9 ztmH6Ts$VNj8=P_cB7q;yZr{NVSWOR0m3cF&s1Dis3w`4V0(-I8YmiFaihlSRyicBJK){0&DSvY!-=_NVeMq=qZEceM zFZ#ouH96#HI|lN$8fqaQJduHOoUZ`choiqa{uf`#;FfB_-?8{Sb6^>~{2%9GCJuaN z`vBv$z2lb8Lp#NCb>E%Q=?cvin-1Lva4w5A2JQn?s-5B&i<&j<_KNv@zPPMhOG$m` znOON`j=VdFr46;B`S?JYlQ6mw*aQE4tEg|HDaOuVIe+#zrg-(*Y%+IVS215xi7f`_ z#Ed2e3wbu5Ag2(XHvVvu1!2s)6WEi|RZ!tMp;N0s2KNk{(s})pIcTGRe&iDa>)f}V zZ$seZeUc_bYYy~<5v5sq1L-hV4DWJeTtfX)ISrC$p;*p_HdARfV$!+_iFMKAU|%TD z_o*h8vrq0$nliJOOsh<-P?oL!TOvL8ypqcZGd8*tbnwQtvJ_&=ZyWXU*9ZCO# z!oQU3&!xtaFlQ^6xS4|^_1E9T=d0D}dqk0&AR`lO%SRf1c-`BBI@?)0_dUtzj&}n` zcjkk+r|LADvjR(?1sB=bo;uO?WTSIa^?==^! za}>O2Ux!RDWoBpp2rSA=+1lcK`)8LPXg(7k`T?g9fJ67TSN9Ya9LM8-Fn{iysyLaw zLNzna2@EwmzjGUeElV&%%1iZc-lDXc!1_8@tD;heE6r#3PA=_r`BcN^C{4<=j}deS zyKprt7Ea$TDPoXsDk!O~e8A_yPu~e!bZotNsLttOvlxA2bDJMl8=D&Q;*3>=AJl$C z5#faCd{ps*<*NL%sfEzD$*Xm)cHBXeq`Z#xa>mk5JPZ|_CiZ;u*@W_9tH<{qm6+7x zDecJI6x@}Rl%&T{V}YQuW#KA`lA?$q2hW9N=Wq8~0*vXz9hly@_^bI7SPE%Iu`u?2 zxj{CWM_wyB69e;Ky)sdn|A<*z7LnpQDbZUs?7THV0b|CDD$V2GMyF0I^wylIs6Oc7Ec=skfR=kW-m9@494Cx2<{E(pC)E?<>QpX%_fEh@AIwtu!`tS@}}^}!22mZ$+DWB zmIfyN3XSlJxAOHhHUJyI;jg}wwd$kRe>dViEIAkzDoDp{DkQJmeDs(k)=m4$7B~4*{mw_N zpVMi!Y{GX3tRh?$WD<>UI-Rq-rNh6s^eM5utzM^s?VO>#?B%NkX@+9|8Nrdm3`e>0 z*bCJB+Rp9+OmRj5ARZ8mpqAryb&z|#0@U2q$k=N5ms|r5@>Fe$iOQo$oE#18L3h*7 zr0@u+-Bh`JaEj*pW}>^q>h-1AAHs&gr*<5+Kjc#3L<iq9nBFNuo^wr<7ka)H*cP@G?>D3 zik=2El@67n+ZT?!2CJo*q76vCu&|l?ttd@6xzFn@!hjDv>QWE)i5H$vTzygr2@#^0gzMc~Xv~v<~q;3o0N? zcUt-qJ4(~~YHlfoy8_+f8|1H}0_?%-TnWM)Rz;lX%l5athl=rJ%a)}l!kMI6ta_LK ztp}x87)Dui6J5``esJK5@~6fcjeII-`yQMw>|i*^tTR_ zOJ23QF9@)@L}zrHsnpawu-Qkp27Baw6z#2|4D4J`VBB-w)1r8CU`Gk$iqcExF4&>x z0)MlxAec2S^raa%?f25TCSU}(_;U}SdB@)#-fzaFWzFd6*@sY>JAr5|%DAlMu<4yx z!px=*F^eiC;6$$OMI^RH=GOESN`+BaEBXUAG1u7h#Xg+`11M* zSW@(PVn&Rn3Srf5z4$kW`t_iHF6}bmo?SiSgpt z8NJWhs(Safo`Io?+&8@59YORv+O=wEgwvB#M&~Ax`}IAo=mxDR7164PG%7pl7(-!|J^5KN;PT4{s;A#t)XGqzLU&nl>+#(G1K#hOZN{?6`nwm; zo0!(T>&JbhN>aL>pKY(uk%00ru=&9KBqkQ`rt08aJ?C95t7SJ+Up-rmGF1Wpk z@+A{Z;Gg#p8s7zCwEUB#wI~#;= z(Yv&1s(Bf}A!W4?){s6>t)`dlsuN&5+WCSOADGu&SZ!G!0HP-wvZys6HaY8s;m9nj zkngHV56%Ly5i@zbRf-*QeVozdM`t7MJx5%d*6ETJQeCPf@Ox$2OpyhU z3_Q{xXdGCqe*|K`JdQ5*!{(9+cJ?vI!7au%-06B$OFmWfYu3n8IZo{UNbC5l7QQVAv~p^t9I#$%b-L z@^6fUA91J^CE?zzw%A>zG3MsDktzskHO8_0!=T7hIz0Or!FA+*k6X;^UteRkA3Pqa zuY^#pG%JHN&p8Zl?r=?AXr34LEtA`2dh<)(cH6Rm_&2W*_i{DO@6>dl#|Ld6!*33v zbHyQy+YTFd4Alk_@BZ(z$3WV$$EP?^^YF$3u@4irEU$hBORDZq(aV?Kp?Q8Oj$x7vQE7@FmueZlcxOT9DktU z%0LM#xO!prBVr&IbnPQm zl5yV>U69)_UBT8CXtETpae}JgH6SEkkf}9dn3hRsh`)~-xKvII-e{1@Pbs?qHCL#9 zwqf^~oNw}+kTC?u2Bs#UdZv0jy-EwbMH*c_0+R>Q^mfdJF3GlkF1DDh&Rh^qM{1dJ zb}6usb;i^}2&4QSp@u6yhFj^?4Qqj*82Pm|?lrN& zy&$*8DqBz?qw3<~j&bh`h*gW=YzAcm$;;xq8bk5>8gMS>mmJ|3!T8+Fh!lkc7HsRm z)eRVtNyBr~y&e(MX?UYwKPrH|!|^F?Pi6L?iW=QS770-HCxGPQyRIe3 zr_s^Hfw{K)?s!G_IYL`{{8fGyb{)=Xl#J!=M;F*0eL}EdQl(UR8M3)UCO2m? zAyZcQ@VH9^R8OyT1J}JgAT+Qx|LVsc2B{)|`xNxnlskq+<%i)py$!srjG_8+PUe{B z6*rTw`g&3OeOB{q2yR0NrtQa**(tv6ZBI>&IOL$CwaivH$%%ujhJZ$-N)d}apg52R z*eU^bJCDA=UQ^mR?=)M+2cPK-#O~pb-U@x2xw{;T@ON zIf1WJ0TTB|7UO#J?C%sNS=GOj{>}XBqyB6S-YNO25XDOepF=;DgJ%$(J6hl;G1$~>q-vsm3N%_S}xun*enotl;LV`B2L>eVqAd-l@p{B zSt1*LgCFDXb}cSqH;rNaBgTOR6$MyveGpsFB7q=AvyTHlznv4qRc%>eVh4QIaL|wG z>rxVB_59_^1!;{O)5wDk9xAlf_czZ;+CMc_4O>tya`|*;M*WIiRfOtu8;o1b<^nVl zjZMq+e5BqC@HVZeK45;s!~7h%@{+4f?%R?_y(+6Yxh3uO?Vn=ixF9=bjk{;Gl_qFh z&~6EnoT;4WG3+1VU=#=)XJ%X|09r)vcnj~9xHRse#A|9)fv*rcEbD^G73~}Fxm9%? zRd!ZYKI#GAk(B4plr#1*^>mX@rCy@<6g>KthqlP*N%7O%8^i3P)^1aFyMaiB*di1#@FFnHH|j1=M{TLe{G5hNY$X zLwY)7AV%fsfDjohKNetR(Ws-Qi`Pdi+=>R5ro*bks6dw9U{dUUnrJo$&GlUCxhNqs zHu}n9GqZ>m_64F!kpT|3qdL6_8xWvd1;PDw!ui7sQX1`sYNwL|OZXD|gO8ffy0^61 zD-;xEMBvdtuS{?bj|oDd(?l?rfozbu;FprzAkv(k6RIK?Pd)+fP&}|&h%6n!$er5H zVjLJ6MU(FHis)T#NwM&VU!)A?EYY-mGk$H>SO#Xeoc^l-J!#pnuP&k&w8T5v3%1CW z?KgcoHJKn#8xVU;x;1+}uzEV(a1tx2ktE>0qU`(dCqTwzh?y*L(1*E%)l)v;XN-pg z#NUnIy4f<)ROmoyZC`^ewHas3_M|rZtRt`Ei!Y!;77OHvA@hZVx|v1s6X7P6DR1sY(xpKIdKa0|*3sRTQvH00C3hCXfv~6gka}wGirj$Z~qGWWOm^%DN-fSIWu1_g%f>Fc|J(Wyw4RRf`*mZC$CruX4ZSX5 zYW}RxW=NsGH{RqO&cQ*os8Ec1DqEpcoVOnZGmLLw^<#}|hGhvuxNa9`882&}9-k5~ zQgg)4^WjhV&yt*3^5e?&W*{HaH+#d^nV%uVwzl)Zad?Zq02{E2wMSvSpd zAwOj8itgbQ_-4^o-$}OC8q=Qu+jy4m^(R34ig9bmzh>1~vmH&_gXPsMc9ZZ3e&gY8 zym>c6F0X$ehuIw$<=Hj%r4euD!=mnJ0T+5`WOY3 z9b2E#RMiU@k9om%KgE8(N{dR9xF7 zSe}@Q;%PT0aI1ySCk0#a+n-0T{{&#cY{#E0?2QacyS*Hf{(b&TtN28E^6jh_C7POJ z!bg|Zf&C7sd2jvXM#R99QU+P(JP?)YN7PeP0iPdIhMk+}s;y)daNt5=b?3ZXfy|m(O#sSwDKstObenGUfhn0-S-)jF!RvNU=xf3_A(1lcX9Ruob}DGdhUCJLp0AdKSvO8k zmvFP2%C`eCJ656>!*L@Fvf7Yp>zMb9zlejR_XtY@>#bcoHYPe$(oN38ONWRJX zH*sugk3qJa!DM}G8l__A*rrA>!Mw}?YAUs=o66s2R@F(Ujg~@=rMhUKN>}pG!H9aW zVONFBX6t6NRoVP>Ge;Rq;Fsi1r~^OG-VN2!11iff8clhq;xWljn5!$Ps$vrX`2ct=#iw=*p2gJmoWQZ-E1&Kx1!v*( zDgAK^&cG3^2Ha9vamj*E+opykSP`h2d~4`xvt2~mjfCl`O^(J1erV?wq+g$uOj4Ou z>M5!r`)b_6F)|y_IOrtI104S*#ZIirvst47Z%<*T5_L?jc-MWz=jLE}J^v<`MDe+6{@UBv+e_rzmXv;H zrrFzB_{TmXH9l5&lBL`BCToM}dh=Sm)!4*`0KV&L*PZ&4RVkAO2#fA``0630LSSjP z=CPWhxQX67T@64^XaqFEOix<$(Wt8ypQ7w3ofIcVl$~mXB&(0EbtUP`o#4GB@%?)T z96((%;EaPO6aXz)P8FgmRND16~BA5Mx{u~vcJFoCjr1-HDMMZ9_5WF39R9nbU)G3`JOH-v#tTV6>Kex zWuSSpp~IB{ae3v8(QsuxVWhOj)xJ=L0Nq>pE6vFPD{e$6PE}7U^VXP>R~KD-aafSX zeccA00*3`fSzw9MqQi&k!JJ8TKe%)rvfIV)Z9z#p>L+VLTEOoZpUB8I zf#vk-##tT+|Hz-r0`pvtxvTU%lKul9u|w2QBKB@LSM7gvPa3g!v|~8lXQ3-Zj_l;v z^EUv!jLwCrE;p+PLvUGw`fKNl{Dwbz`EB*f<8VfCdi5SkCl5JwqSwWXcoMKK6KVDF zHvq3J(7Tp0iXl>tEDcPzn}BmtW*x+;nQUQx4T?SO(#^imb3ri)d`Yw;-JLV=xn0fx z{&ift8?^tq#Y(bIViHZ@#OI#?L>9K;_NNTz8gL-gHQUPSEi(~}4GS^=;xs-O+f;d) zn@zWP$Za@w6v(JSWc2NP%AUlgRp_`!#Pn{)vBHKA(>n$l@HK%Vv|D-(s5Ywr!*;(< zMawGOjTeN@Z8dJ!xQZ=2eBz`VGtJy|qPllX_XRBXj1iH{w9i#^bEo)wLF)l8+?NF! zY*Yi}y;I2xrI`gCVOSv6ahB2oT_83x)GK!#9LmEv=sC#@{{&GaoiF}qS<(IWZ3;Eq?oR_m!v zTOA)HGqs!T z^425`6S$^mr2#Du9Td=-=9S&~lx8r0YJYuTo-r7w&Enn6b&GF4QM4AgO7eC0H8!AN zhw3jJLM=x5VNXS&F+~YQGi;a*#pyzyp8zMu+kOIUK;2x(!75h3Dd_f|-E$cSGX9C9Mc8+#dcSG_ymQ%@ zn7m$HzV&S80g2MDsNo4FAffYVzFlc*#nvZ=Uzisvo>@t%OUFidj8dh>KHT%}+wK@~ zEGsF;$;#)&k=UcD3M|!xLi1>nWA7#lLS0=-*p)7cd#e9#lYg8ZP8Fxyo;w zV7UR#uA_IM+%>FBVg&_nJ5dXplSs6Cd3h4r#(0IQR;ymws^vGGNBb?TY)s$_jwWQ5 zBWP^m%|gM z5MlbEaCsYfsqN)l%(mhg%;LJni3e|sP{ZekT2V<~(8@Ly*=m-Nk*Z2(E7JFzYf-Gp z!lYTWNfhYI#ZO#AeZiBFtneP6(qk%x;CgJJ6-4l4kC17VQ?G1ed4JTmN-G-fXlQMY zjbXo7+PkCj=d{j7l^kp;O`eqlcOukz07`dBuIl}QbD ztt|c6RjH5kdv6CjnyCf`SDVplb5FIUA?f-Toajuu=AsIVLVwjG*nNY2mCF2R@{_<4 z(Jy|9Z*R_Q9(`Uz@U@tWg?XKFEmg2H;Eb|#;uz1pbM&iW`m{O>>QzZ0=}Ma=k95 zq677hN-$pMG^LgmYQqY(uwW=M&tQMO9bTMyjw;1omWbd%4i8%D^cQlm$d15fp}xRS z#;{LBZaNv|Re+xBE~4Uea+sY_?mF^A6|iPVf%!xl*X=^tGDk<)i`2bnPayZ=DJR&h z#D`HtpilksP!H5x|G3l0BX5IN|KQ10Ls^o+@Mfy2vI6&M#;D*DWEnzG7$Lo`dEsDU z**2ct)DMM!ZykP_{<{wU!9P_w*o_U0 z>Na^_;$&LhVq&w!c8irr1h7X#zXCoPu6IVyZ4jwfP_A-Fi^aPx89Ebp&6hZpY!1_o zS&B0sjFBCt+U)wM+;j{hJLfi?@K*St4h5M1Di`eeB`MkKy!!HL^5-S`PGB$h%=*L= zurC}x6bF*+>@A!G@24I;YCwV_^aEcCku8}DX<`b`yrn8k5Z6W9K)s77Qo54io{&54 z=9Vp`BPZ3&hdb^q=RP@Io;!{eyVpz&oQu(vWC>Au(R#>u0_eHgBZKqikxlM-?O2Jc+nr6e5nT1ff-6G^Zxtzqi z0%9w1A9UueqRQ>e-k)1~_JFTZf7>zK<3x9%{ZD{8O(u|~vGStBOGf#Jtl8NF40&93 zIbvEaGH7H@>D#`SZ`Q=w?4yCqml_T9-!wMdf|VC_eg&CFzPi;EELwHs+i4V(fANcJ$mVQ;St)AR2CH+~kcPvRO=fqC^SBK&@_54o$o1K=_-=~>+d#z(fr>n)~ z!aZUD#F>BQ=>J~l|8~kb_<6XHaohcrP+JT0i|+c4(=(ygM*yDqA3QVM7?muYQZC?E zALk=JtOWdTrIm{d-IIvbYiQK^aUyBtn)6GREYa=~^GIDy-)wg&uv4d(HlW?Oqe#0@ z|I~wfb&&(Jsz!T=shC-#sOwGH_Byf(or$oe3?vnDo=$W*N2XZEp;I|8f~2-v=~XH5 zQ})P;A7)@~A@SMA*kY>Zo5{u=A@S&3r0np>L)i!Od7MT$giG37q2F(HH@iIU*s*nP ztoA)F#FHqo4@w7P@ZO&Rs~>i7f8XYxPJhPOYuEoAbUhFX`0j8xC3wNznA!OLW+ip0Npru9!Q;OB$-wdjvoUD_L-WRT!ky$&uF79Ye zz%zS1^GCnbM7Qlg?!nxP>QCLj6Ac~l@>sEjm;mQ zL6r#}S6aSr2kUV%NLkm*4PA^k%myOWG(1&TN$@=sW$3HpMiRUNYQh=pkd^ zvPnx^g7Ex~D#(SXY}OH5XDcvx^9EN!;erws)>9m<{3Ay_JaQ$o2E>e2>QWp?>eT~P z9p_6TPso1cUAr@5nV3&Rrr0OoJx#{bAO%=|3tU~8L8$91?XRI`7E&;wIfJ)YHMRG{ zIVWoshWo1%*hReborR2@zm9jm*VKQQ{)1Q^XU`WdE!B~%T{?v(3}7D|lQ7I}w`cv* zvI|NDHapvRAthY_edrb;m%g3rV0y$#@mPNTjT{H%kEnC{-JA3%DF~_>q6Q_a)I~bE z)*CgNhS#9g?OGZ%hL@TTS!@PisRvj#X)i%y3elRz$dvR594TS0JcBFvcagj!hzfJ6 z?(Y7{Zc)j|>3*1FV;6-#fr^BH`%`A~wmnkCDqwnNHa#HXm~_0@kvY}X`jngGAyq7o z9=RYsR;(m`u;)Zth5d!9s3eOPUA(0g7`{$dgpUJZ5grfbNAaSSvGGB@n(p?C_Yll6 zGODwT{MsW>{Gf!xjfss-$;O4%QQHl!%B~p;B7@L?A-3QS59G;FZk1Lk^IfTkQZ>9HcTKc|BdQOXxXnbgsHRre+$vcY&oJD~c^d?;Wi z%DR@B+F+?)Zf#utW4`B6Xa%-7vskhs-fenjSxoLHfU$HvLz*xGjRMlhgr%JEVWUgIufgfWh|m4NjC&&}uNx|dT`*LiXltcYWlA_mYp zGpE+U4SVtSY^AWRm`JsOs0)JPAiG3~vaLu(fq_U%eZ4X;79341F!F@fgCL`4N`@L? z@mDt_?7i zUDk%9O(BFf=gf)4l;@+MGihrTb$f_~NLNP^p(jd`Xq<+u;BWz6h^8Zze;gc`RU}vs zbbIHibP;O63R5^ad3SyJ6q?L@ugQFOi$%B7#;vAql!-_Ux~XtkT+jh8_Ti<_56Tj{ zfd*z%owcs-;H3%Mf__9`uKGgt`9;~2aj^)nwk}ERbkPXHQc|LxZpf)GlXxM&)VzO< zf{TIV=VJx$EpXt(FK|2KTFS?qQanCv4P&AkvI&fg>4{Ff(m146HYIr(e{9kVW)?S* zRQG9#@e|+&qI0UIWa)r}mfGj^B=_OuhWFq^+xj!;Mao=KFJhe?xBF#8lw)}{c?n&X zZejMx4;ty7-;u>#IuBSEZ?EU_$6Hdj%GKmU|WN2~b&+H6Mf z^cMh9I?te$rA#{I;#dYmHWwU7;maeMu_gB^%$gS9_C56pur^VaR=ii}Zb)R`?{(3Q zzcki{tSh$X&Cm%5Mna|au=veUzV6czDW*S!PO&7*ZbevvCg@cq?nU(~8*h~ZP4h^4 z`PVp3houhM)3ot%3zk<%-uvj#H_v^NMVOar<=XeA%nqfMm(fi4{p7vX4m{Iec5?_U zzK~-vducU-ExtXUq^oYW>~QJ2BSEjJz_}$#L^z!98$z60Vv|SWWi8pYBKInamDuKL zUoo({_XFEoz^>nh&;LX7{`2ZTaeKbo6!+aW>J3RJs#)^*n;_Y&~NW1e|I?0n@4r3ovy?m9b>q<+@DRzP{7t3S@Jj(1; z+SGYeG~=0xCbBLhcxNt&PSp>bn@gVQDIbAQvc@vvVsp>Mh=ecdr(gI00PH9D9w7Q2 zN6U_S8;qYW`f*VTR+T)EmxxCn;Ze^Dc_^c5Rn!33r@5Wri(|805Uz3LWlZ%mY!13Y)$?#V_ze%cap~6-BY+Mv(rqr+$lADe>Gj zRI0e{roM1Tw|D3EkYS`LUGRmz>tSCTGxv4jZ*Zqwn1Es!P{Ul3CuXxa%obsXQuoCV z`HQ#u!A66f)q`k-nu=poyJiX9z)b>4jNox7QYlxrXTN!4^u~ zcG609q~kQn+)FRaC#}=481lB^cpqMy`MAqPg?VgD=Yruhu?F)w`(f$`E?sYLQ@1@@ z_!XhMv(Raf`zgn!z6txSVZ+YQzhy zG6DD*Y(7#yUFmRC;DxRai2sYM(d{#vkmxXW`I>H77wHv3Yg~Lb8rW^mPLir*->(+{ z(hj(|svodY;Hbq)GUA=bu*_tM(q)UyLA+&f-mZu-YBg{LZ}VVSMx_O0JXl;NOOnbp zuvp~%^0cHJpD~*h)-w43%Z?~zbn9xlMdf7jYzi#5Lj1RagJSe2wmW-XptkgJL;a{2 z(LI$5Nm{M|3F1_7h_O+QlH$H58^d$JZ5q{;n zRn8^*Xm>fS^8^oNCAWEr1-`8xpoHX^&#^YZ|0&l>;>Z@I&n zMMxUSm?~V|=BW$2;KzpF3(~h9(krbvE#dU}ie6*;UZX>|Vgscr0&|?7^6ZI)cc|fr(zghT?P2^@t zO(Ra03So(bL6KAwino&>Mdv2Zffb3y9$_GQ4wrkJI|>$0ubb}8EZ?p3ptm@{gd%cy zW$RHxwc67Sn{0Q_Qk>GD#TYz6b;T+juOjcb7O0=?YNwT2(2r1-uPlq@GPE~$9g?m3 z2|!5~$F>bd=dl^$eVp{VNM^>>KTxc#&D`9wG~`w!D1@Vn_z%-)WL!9$F-b*daIBC{a4UKIC6Drm4taa&Q(h=+W^BYa^kMlli18z zF9r0O0Yi!>mY=g92c3fXH)GOqr31H*s_ck9AaKQ|b%~cE;;%A~^@afBZ1A$=<0rp9 zw;f`_`IwjpX4AfW-)@YQVz_*mj$(B*jvBDKKz4){TC*rcUJQHaCW{QSSub!vmCw5% z&%&~cM*f0xGzNQacIwNmK0A3Za8Al{Q&33ICRd*rDvblDN|blrzs6$PL^N3XyN(Sw zR{^Aimp(n)#oco=y!OBNz3JMh5%dCMcsJ?pm3a&sdEdfkyB3fwrDLJvj{OY8@*7)) z>+Qva;=p)whY&I$Z=wG=v>)aqV8o9WmZkTr6)(9W+kzFo*vAZWNZQ4TMZpn#7gdJ4 z`g;i8$8}XsmS#)nfFcKdsE%5sL{jVjiGq(s|Q2nX3_{uTmxfoqH$M&oi}gRT5bR$CdK(( zy46uBRs9uC^^+MzJok6M{Q6{BKM8ZirxY9Lojfww$OGwpYP2m()=XJGA{feZg&a3I z!}j*#f5jjI>~O-LfEow}Prf^#;=Ug9_XVs`#0pEo2OudS-p%`A{Jk8&ye_uN?e7aj zJl8t_V7C~LY+l*J6aIcXTLpv1|5G7cly*7;@C`Pfw>_q%mY&?b8N0Ysy8}?cQXl%t zJQ@AQNfd>Db*CMX1O5kQ;_uP#p#XqP@&IoO8V%#lVZ^@_xOjbF1V%p85qHkXNkNkF zcA|LCTmB{#!_F`;QH0;(OGRE*PVviOHdABMY>0G|=jqG>%WiTVY--O0e`V^8u;UUm zPqAzQl(c7Tb4S`Ct5wulL(f-UR4_1MRkU5;BvPbsfNnMzmB;i-GE{#ma0GQ*y4{yO z&fmFT%Q7oz<&GPxMgag8okRcThfwM_}=iqHzh&Uv-vb5NH{!6h7Ygn;G$tW4vo7)>r7}bPfIhR+_&7DrX%S z$HLl+8{^HLtu{p1u8jHLR$tZNs=*qNrY>E+lnKuLRB+8hxf18K92cyVGs^$enMrh{ zI6#{U?0Ysf_{}F79P-}wrd~IPJs><17IcvF9MBOXx|9`vKnGWLjIDJXOd?@ZZVrKs z@me6)Oh(8LSrww;Y4JKn(70B>go5{RTLNP>byd)03xV#iG^->+2n1NYS89_&$`N%;Fm=b3bs)70Yz`?ge{KeltK$HD> zuRWdSXtDP)W0wbF!+9itMJ6aQaani6EStMFf*OxL0luzy^zCo7?rm)7w?7V1jq*=1 z-~PUC!}0GoOgxiBM;5xfatOZ;+DCi^izGoL%9rD;`B|yoez~3x|M7y1TWmXVD>pvacMx9Rb=?2`4*r*PhraLh$LWqg zD&Xw=&T!Z_x*U;?&{wUljA$7bZB3_~_3reSRQj>Y&r1LIL>1ZFxcMO&$O zZj;z--?Dy_LQmjE&pIW_ z;=okdnHGy$jMducs~S)Dx3nb`I$t*ULeUZl;^TUyTj2muS@Heg_=GYQ*j{+N5#fPrR8N&iv>uF0T&#C;)0~7eX4l!y42|Hup0H~ zbo=1krVlAED9TY)bOr5^OL&b(jEAH7qv3eic>>KP#2F`vo@?^7xtlFsVhj9|Ng_c@ z7I>p`-gXoQ!-kb**Ro@H91cAh0P8i0H8s6rW%p~7NpuN;DMI!P7~!u~f_%+KY8yIV zO!6G-^n^9?rwPCwG%dc#O0uFYsl>+Dw4pYYUA>}V?@Rhqf!rz>Tv?O&pUY&wHVM`mHgeV4WFXWD@` zr}`Jy-~~Y1s}R&#qqzHJtWab88_?49BL(5s!Tz9lR6neA0poqR2{Y4*L63rulA?*+ zr48pX0wF&0)z6wp3wv*DK@Fjl%)Ut3_S;!VOx~1o%rG|9bf0Qm)}*?LhgB(=tHv*IMz)^5dR_igRdZD#mE zktnVqw~{sf-B$0buX_}oaFlfAUNA0I3uX|Ew4vJ zqI=N(8@ngLJbyr7{c@1Mpo+4vSS(osQ1XC9e188`<_Y;;13BVFM{=Iw9V$L901r>W=IZY6@!c79vx}Q~$UUYQLAZl`$K8 zLpT1%laf)XD#&o-N8kwb%?6{IREzTk?}+~Kc#uJk<=p|8 z6EK+|TZJ)|z2!m(ysZ`tqk`9Y;|M+ren;}NOVin9WiANzCn{~&rBp2GY-=Qx;yewg z)h*q!+=SK??&V|jBhd;UyJ&oTbFh$kTmQbdgG2O+DgxM`inKu)m8Fay^k?d?cy@Kd zug$J2Ct4^9B=wp&L_Q_7nBEtXm_EMU%C4XE=4OT0^gZM2MBCQwe$VK(Cp}~x7MQnm zUWa^DSy}JWw3qR6G2`q&QXG%_piRaD}@QSW9N_M@lu9DV|j4laAF zXvUJ10-`4_7%VOV8y2Z=@`l7X|%j*HBvWl#uWR7Q7Eau6?6%7X+n9rjeX=|%)&9bdKR$Ply_>-?ta`pHbkd8)OJ za{T@Gq=x)L^-o&RROQG#C1w0=q@6L`$&rJs1TzD%u-cd{qw=!$8!1D|Qi+$eu=N(*Ks|kzR?%!eh|9#}!$+)K z&CjdnU&}56O$lC1IKiYF;{=Po;=pn4b?~vsf!?IKH)#VG!-SNolL+7=BnzGw=PwyY zxVr~4KDMFQcIFpK%=xqvT>UGm&A}=!J`anuY?RN&Ug|!^Wl*2{D4B{RL z-;6^yt8X7W|6>MVA36!%Elzi{bYEPNztPtfcGWe)Z#MmsLwx62NYAc}$fnsqO($VP z{k|ZLiY4)AYA zN0w%K9`HVsf&*GE#kcY)#yB226AvTx%AuW@0aSC#AqiuvU9&15M%BTnwC+~J&gwm7 z77Qv$!vY5^^UAC5HbH6|xp1gWAG_?!XbRcgHM)F+~IiI)Gg` zj=H%;E{`XMyLed9uFGB-e9C_&RR~ybsfBV1nx1-fNv6|vzijx;w$q`%spZq&Vv>qr zNn8`%FhO_vCqVa?tllX`^~bAmIpYRgsd_qRBbqU3TsF@|Sm@f#7nG3OUu^qt$T;bH ziCd^*le5_)FuA1qddNzo|6GfQSOsHVM#R9>w}&EPtR`ep6p^4hE|(5B$Xj+`7FMH- zzwNH6xm~y*6Fo^O6hjI`$TH8Gh-pJyp=&7tGU>|)YCz6 zNLAvmd-9gSWoNXgWE9JH285=FCLvdD43CA;^A_feiG-G}v?fV(+#Fv_bU-8}>5X4H zi=|<@76yaHncRpA!enjS#6-+Zbq9AipZ+yawDVv70?~gt5Z;MeA32cqFXlb}H%mbK zo40r85{~`OulxO`CRs&ZlW%nS7V@u(M!(=i>K9(lpO3Q(@j@|sm2dEd&jUAnrfq9}iX`#;V7HiQg2qF-?OsMRb%T5& zuVxH()kT4xFiX*YDKj(NR+7LyXHK&Mu40e1-WM~J&5qQUx}P>r?wX>ZAs$Kr3k~VE zKg>60BGs&whOzaau0jd0@qOUHM?ulzoRRd0v(rDWJX=${N^;fdpEC8HpQU>)A$w7n zNnlK_Jx`c4=t517v+Ro00a7LZYF<4_)f1-^7x5NTx_PdN9C@sPLt@<0SYRn|ZKYJQ z%F?(WtyyL8qHT7hWuo6&Dt$J!S{bpb*KLAr#8`Y}Widz*#X&VyRdRdk)8;1I@yK=e zEmLu=)edaSKDeD!{?j6L z<432aYQRWRV6;8Sv116T+NyM}EE<$k0#SsSLk)9z z_;uCidRiqRgz67%6~ZOKmy0$bHR+!Cf!e8rbX%7#M=L`I@x&N^%L@JU^RAwF^TFBT zuDJnYEQatQRq%#d@P0WRjbk(D0x9hq>M8!Tr-gC7j5br`hR^2vy2R@Neh; zCjtn6d4j*tWBQ*!$NuHH{$}C-|KNV9n7`0H3jJl}?+gF`gZq7b{CVzA*6E)&`8P{` z`^71wKV<y z;;hH~3@Xv)HMNri?oK}Twh6#FZ)Yb8&@GCNdb~rpK}r7NuE1mc9Vd4xo~cO0$Hm1! zZ`ue0FuQ(p;J@Mn{ATrUiryx;WT_J5Nt2LyZqMEquhe^mTg8~gOw&-#zQM5zDK zzW*6gvx9p>9;TXlu||VE;U!B{^84>E!8PAk{(k!3@gw~H9RFeNKT*^W^fxHf z@feg`XccDfAOnpdO6U}xr}MRP7uIj4T_Jj(qs*l#DyHQ^4De#vx!y8GYSxD@`QOyo zJ@IRe{3V0yudn)lX3X)|$Nu}J-@f)`A|H}ceeC?WV%ZsDPxpthk-Wan2d5tFHgVi+ zx-Qc!%0A@M^n@quE8626vrPO^F+Gs*0u%?2gwZ9#A^CUIZJ?&@IS5W8&=(iOkVE!| zDwjn($wnTQaSGPQMBJ7Ta*IXcyMDgO29e*3r@EG@z9J2 z4xxAr$A{6inBqE*=$vsb4ZM0T$_<9+H>#B!exfrNIWEYrZprsL@8Ylb z@u!BbG`PnKx~#2xD8GrmiL(0G!B3Y@S$B;&*FLXkEo7y~z|(a~2ein*^wba(n`>Vm z7@_Z}Se;2y^`>3Wy=;#bK!G{WDQd_oM=LWpR2#;OE1{4H##(}+(6GoEUj>DIorD^> z)^qRGlvshkre!wsw!#BjxX~yBN@2JyiV$PM+%|rWYwR#R|C@ z6159bg0b%u(DR`m6ZdUNV2xwcNG~JSj`*!}T%dmtRN0bxdHDL?Shw-{!X0(7#Z`d+ z`l?5!28wZd*XkKLv*im{4*T!D_qM53Us6E(*w<^hx%Yv!29}pgj^?6pGzxKX9pJ~4 zGYxzjrwq+4okp>c>aWJ0G@dwSChzCo=1|-tv339&1&jTrTyMXz4qP7eA;fA5z9dN0YB~$M_TiH1dTNMvrSR=^Vgq zeD-)LJau>%W3sL`W?w#0`MCYb3!!`4c;@uOn=`$^ac`gRZO`~1qez3lev;@mq*~2; z0TB3DoyTh1d&%t6@dTL zt-SYgR=Lh~H#aV&YRCJGj|Y`qF$wzepHr)(KLgfJ`e~?c9ev~ftfwp5%z;%${ddMz z$I8(SQZHY61j>JWtT8CeJ}uf~Dgw+|YllHE28ODO)2oJ=GTC0ZGbu*G9}e%2Zs=Q% zXnfgc9ObZUja4m=g(cO2P1mnA!N+5mtXjV_8j$lzzvW8zKre>4%r+Am^aTbR!sr9Z z(AFcupAG{`Nisu6c~H#(6MJ9WtD8{<9-%Tl4u=fs(EUA~1ct;V~q9^(7 z20xbT$j87<@9g?O5(^7uJqA@mqfqxd)GAU{PbFt>CEIkR+C$Z5NdaJS{gqMa9g7z~ zqGHtdit(fbL>)kpy94813V*ol?(2%?U6ks~dC{g2dw^{H@p)YBI-d~@L(Ch0ES#M0 zQ;azUw74+_4=OJNKFF&?Z=FY`LHh@Kz)stU4TUL|w7ya$- zvwskk{iWq%Df#aV;|BtYvUx^Lbqt3?48sd2Zl72OQh04u@tw#gb!A0o``8$+ z?X}~5x>#v0D@U%!sRIY3eof1YwG{p2x;b-xV}t3&%a1ns=I5-`b4z1mXe#+EqbzvK zyY9{ARG?gGj%e7NR$D8Be7VV)K)%prrQ3Creq??OJZv^Yf;radWbnK|TkndqPZw)5 zGi2XwF;7(jPKQs~)boaiku@T(*>#I%P9IMX52MWDDHqqQUiN;)lRSf9hQ#Pwt4g*_ z^E#$GTZV^m?Vq`PJDvq*Ubs6sy|KYyVWz~EOL}Ybr6wMBi(_Lr6gKf@kKnnJRlGp2 z9BpM;`BtZFbsoP4HG6Jk=r?uzuC5;%?JYg*!Lo|K9`vLY_$` literal 131576 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
*%4R`iL$AMAWEcVYdm7g$?tDD*98c^>>lM?9vI# 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 name }); module.exports = __toCommonJS(index_exports); -var React3 = __toESM(require("react"), 1); +var React4 = __toESM(require("react"), 1); + +// node_modules/@xmanrui/dsh-dingtalk/plugin-src/client/api.js +var DINGTALK_RPC_CHANNEL = "/dingtalk"; +var DINGTALK_ENDPOINTS = Object.freeze({ + status: "connection.status", + beginProvisioning: "provision.begin", + pollProvisioning: "provision.poll", + cancelProvisioning: "provision.cancel", + reconnectBot: "bot.reconnect", + deleteBot: "bot.delete", + approveSender: "bot.sender.approve", + revokeSender: "bot.sender.revoke" +}); +var ACCOUNT_STATES = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]); +var SNAPSHOT_STATES = /* @__PURE__ */ new Set(["disconnected", "offline", "provisioning", "connected", "degraded"]); +var PROVISION_STATES = /* @__PURE__ */ new Set([ + "starting", + "pending", + "scanned", + "authorizing", + "creating", + "connecting", + "connected", + "expired", + "failed", + "cancelled" +]); +var HEALTH_STATES = /* @__PURE__ */ new Set(["healthy", "checking", "degraded", "offline"]); +var FORBIDDEN_ERROR_FIELDS = /(client[_-]?secret|secret[_-]?ref|device[_-]?code|app[_-]?secret|access[_-]?token|token)/i; +var QR_DATA_URL = /^data:image\/(?:png|webp);base64,[a-z\d+/]+={0,2}$/i; +var MAX_QR_SOURCE_LENGTH = 2 * 1024 * 1024; +function isRecord(value) { + return value !== null && typeof value === "object" && !Array.isArray(value); +} +function optionalString(value, maxLength = 240) { + if (typeof value !== "string") return void 0; + const trimmed = value.trim(); + return trimmed ? trimmed.slice(0, maxLength) : void 0; +} +function opaqueId(value) { + const id = optionalString(value, 128); + return id && /^[a-z\d_-]+$/i.test(id) ? id : void 0; +} +function timestamp(value) { + if (typeof value === "number" && Number.isFinite(value)) return value; + if (typeof value === "string" && value.trim()) { + const parsed = Date.parse(value); + return Number.isNaN(parsed) ? void 0 : parsed; + } + return void 0; +} +function nonNegativeInteger(value) { + const number = Number(value); + return Number.isSafeInteger(number) && number >= 0 ? number : 0; +} +function clamp(value, min, max, fallback) { + const number = Number(value); + return Number.isFinite(number) ? Math.min(max, Math.max(min, number)) : fallback; +} +function safeErrorCode(value, fallback) { + const code = optionalString(value, 80); + return code && /^[a-z][a-z\d_.:-]*$/i.test(code) && !FORBIDDEN_ERROR_FIELDS.test(code) ? code : fallback; +} +function sanitizeMessage(value, fallback) { + const message = optionalString(value, 480) ?? fallback; + if (FORBIDDEN_ERROR_FIELDS.test(message)) return fallback; + return message.replace(/([=:]\s*)[^\s,;,。]+/g, "$1\u2022\u2022\u2022\u2022\u2022\u2022").slice(0, 240); +} +function normalizeError(value, fallbackCode, fallbackMessage) { + if (!isRecord(value)) return void 0; + return { + code: safeErrorCode(value.code, fallbackCode), + message: sanitizeMessage(value.message, fallbackMessage) + }; +} +function unwrapRpcResult(result) { + if (!isRecord(result) || typeof result.ok !== "boolean") { + throw new Error("\u9489\u9489\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94"); + } + if (!result.ok) { + const error = new Error(sanitizeMessage(result.error?.message, "\u9489\u9489\u64CD\u4F5C\u5931\u8D25")); + error.code = safeErrorCode(result.error?.code, "DINGTALK_RPC_ERROR"); + throw error; + } + return result.value; +} +function safeQrSource(value) { + if (typeof value !== "string" || value.length > MAX_QR_SOURCE_LENGTH) return void 0; + return QR_DATA_URL.test(value) ? value : void 0; +} +function normalizeProvisioning(value, now = Date.now()) { + const source = isRecord(value?.provisioning) ? value.provisioning : value; + if (!isRecord(source)) throw new Error("\u9489\u9489\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u626B\u7801\u7ED1\u5B9A\u8FDB\u5EA6"); + const attemptId = opaqueId(source.attemptId); + if (!attemptId) throw new Error("\u9489\u9489\u626B\u7801\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u7ED1\u5B9A\u4EFB\u52A1"); + const reportedStatus = optionalString(source.status, 32) ?? optionalString(source.state, 32); + const status = PROVISION_STATES.has(reportedStatus) ? reportedStatus : "failed"; + const expiresAt = timestamp(source.expiresAt) ?? now + clamp(source.expiresIn, 1, 2 * 60 * 60, 10 * 60) * 1e3; + const result = { + attemptId, + status, + expiresAt, + pollIntervalMs: clamp(source.pollIntervalMs, 1e3, 1e4, 3e3) + }; + const qrCodeDataUrl = safeQrSource(source.qrCodeDataUrl); + if (qrCodeDataUrl) result.qrCodeDataUrl = qrCodeDataUrl; + if (opaqueId(source.botId)) result.botId = opaqueId(source.botId); + if (source.alreadyConnected === true) result.alreadyConnected = true; + const error = normalizeError( + source.error, + "DINGTALK_PROVISION_FAILED", + "\u9489\u9489\u673A\u5668\u4EBA\u6CA1\u6709\u63A5\u5165\u5B8C\u6210" + ); + if (error) result.error = error; + return result; +} +function normalizeConversationType(value) { + if (value === "group" || value === "2") return "group"; + return "direct"; +} +function normalizePendingSender(value) { + if (!isRecord(value)) return void 0; + const requestId = opaqueId(value.requestId); + if (!requestId) return void 0; + return { + requestId, + displayName: optionalString(value.displayName, 80) ?? "\u5F85\u6279\u51C6\u4F7F\u7528\u8005", + senderIdMasked: optionalString(value.senderIdMasked, 120) ?? "\u8EAB\u4EFD\u5DF2\u9690\u85CF", + conversationType: normalizeConversationType(value.conversationType), + requestedAt: timestamp(value.requestedAt) + }; +} +function normalizeApprovedSender(value) { + if (!isRecord(value)) return void 0; + const senderKey = opaqueId(value.senderKey); + if (!senderKey) return void 0; + return { + senderKey, + displayName: optionalString(value.displayName, 80) ?? "\u5DF2\u6279\u51C6\u4F7F\u7528\u8005", + senderIdMasked: optionalString(value.senderIdMasked, 120) ?? "\u8EAB\u4EFD\u5DF2\u9690\u85CF", + approvedAt: timestamp(value.approvedAt) + }; +} +function uniqueBy(items, key) { + const seen = /* @__PURE__ */ new Set(); + return items.filter((item) => { + if (!item || seen.has(item[key])) return false; + seen.add(item[key]); + return true; + }); +} +function normalizeSenders(value) { + const source = isRecord(value) ? value : {}; + return { + pending: uniqueBy( + (Array.isArray(source.pending) ? source.pending : []).map(normalizePendingSender), + "requestId" + ), + approved: uniqueBy( + (Array.isArray(source.approved) ? source.approved : []).map(normalizeApprovedSender), + "senderKey" + ) + }; +} +function normalizeBot(value) { + if (!isRecord(value)) return void 0; + const botId = opaqueId(value.botId); + if (!botId) return void 0; + const bot = isRecord(value.bot) ? value.bot : {}; + const connected = value.connected === true; + const reportedState = ACCOUNT_STATES.has(value.state) ? value.state : "offline"; + const state = connected ? "connected" : reportedState === "connected" ? "connecting" : reportedState; + const health = isRecord(value.health) ? value.health : {}; + const stats = isRecord(value.stats) ? value.stats : {}; + const senderSource = value.senders ?? value.senderPolicy ?? value.access; + return { + botId, + state, + connected, + configured: value.configured !== false, + bot: { + name: optionalString(bot.name, 100) ?? "\u9489\u9489\u673A\u5668\u4EBA", + clientIdMasked: optionalString(bot.clientIdMasked, 140) ?? "\u5DF2\u5B89\u5168\u4FDD\u5B58" + }, + health: { + status: HEALTH_STATES.has(health.status) ? health.status : connected ? "healthy" : "offline", + summary: optionalString(health.summary, 200) ?? (connected ? "\u9489\u9489 Stream \u957F\u8FDE\u63A5\u8FD0\u884C\u6B63\u5E38" : "\u9489\u9489\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA"), + lastCheckedAt: timestamp(health.lastCheckedAt), + lastConnectedAt: timestamp(health.lastConnectedAt) + }, + stats: { + messagesReceived: nonNegativeInteger(stats.messagesReceived), + messagesReplied: nonNegativeInteger(stats.messagesReplied) + }, + senders: normalizeSenders(senderSource), + error: normalizeError(value.error, "DINGTALK_ACCOUNT_ERROR", "\u9489\u9489\u8FDE\u63A5\u5C1A\u672A\u5C31\u7EEA") ?? null + }; +} +function normalizeSnapshot(value) { + const source = isRecord(value?.snapshot) ? value.snapshot : value; + if (!isRecord(source) || !Array.isArray(source.bots)) { + throw new Error("\u9489\u9489\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u673A\u5668\u4EBA\u5217\u8868"); + } + const seen = /* @__PURE__ */ new Set(); + const bots = source.bots.map(normalizeBot).filter((bot) => { + if (!bot || seen.has(bot.botId)) return false; + seen.add(bot.botId); + return true; + }); + return { + schemaVersion: Number.isSafeInteger(source.schemaVersion) ? source.schemaVersion : 1, + revision: nonNegativeInteger(source.revision), + state: SNAPSHOT_STATES.has(source.state) ? source.state : "offline", + bots, + totals: { + configured: bots.length, + connected: bots.filter((bot) => bot.connected).length, + pendingApproval: bots.reduce((total, bot) => total + bot.senders.pending.length, 0) + }, + provisioning: source.provisioning ? normalizeProvisioning(source.provisioning) : null + }; +} +function presentError(error) { + return { + code: safeErrorCode(error?.code, "DINGTALK_ERROR"), + message: sanitizeMessage(error?.message, "\u9489\u9489\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5") + }; +} +function formatRemaining(milliseconds) { + const seconds = Math.max(0, Math.ceil(Number(milliseconds) / 1e3) || 0); + return `${String(Math.floor(seconds / 60)).padStart(2, "0")}:${String(seconds % 60).padStart(2, "0")}`; +} + +// node_modules/@xmanrui/dsh-dingtalk/plugin-src/client/index.js +var React = __toESM(require("react"), 1); + +// node_modules/@xmanrui/dsh-dingtalk/plugin-src/client/styles.js +var DINGTALK_STYLE_ID = "xmanrui-dsh-dingtalk-settings"; +var CSS = String.raw` +.ddt-page { + --ddt-accent: #1677ff; + --ddt-accent-deep: #0958d9; + --ddt-accent-wash: #eaf3ff; + --ddt-success: var(--dsw-alias-state-success-primary, #20a162); + --ddt-warning: var(--dsw-alias-state-warning-primary, #d97706); + --ddt-error: var(--dsw-alias-state-error-primary, #d54941); + width: 100%; + max-width: 880px; + display: flex; + flex-direction: column; + gap: 18px; + padding: 2px 0 28px; + color: var(--dsw-alias-label-primary, #1f2329); + box-sizing: border-box; +} +.ddt-page *, .ddt-page *::before, .ddt-page *::after { box-sizing: border-box; } +.ddt-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; } +.ddt-headingCopy { min-width: 0; } +.ddt-heading h2, .ddt-heading p, .ddt-card h3, .ddt-card h4, .ddt-card p { margin: 0; } +.ddt-eyebrow { margin-bottom: 3px; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 12px; font-weight: 650; letter-spacing: .08em; text-transform: uppercase; } +.ddt-heading h2 { font-size: 20px; line-height: 28px; font-weight: 680; } +.ddt-heading p { margin-top: 5px; color: var(--dsw-alias-label-secondary, #646a73); font-size: 13px; line-height: 20px; white-space: nowrap; } +.ddt-tools, .ddt-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; } +.ddt-tools { justify-content: flex-end; } +.ddt-badge { min-height: 30px; display: inline-flex; align-items: center; gap: 7px; padding: 0 11px; border-radius: 999px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-fill-secondary, #f2f3f5); font-size: 12px; white-space: nowrap; } +.ddt-badge[data-tone="attention"] { color: #ad6800; background: #fff7e6; } +.ddt-dot { width: 8px; height: 8px; flex: none; border-radius: 50%; background: #aeb3bb; } +.ddt-dot[data-tone="success"] { background: var(--ddt-success); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ddt-success) 14%, transparent); } +.ddt-dot[data-tone="warning"] { background: var(--ddt-warning); } +.ddt-dot[data-tone="error"] { background: var(--ddt-error); } +.ddt-button { min-height: 34px; display: inline-flex; align-items: center; justify-content: center; gap: 7px; padding: 0 13px; border: 1px solid var(--dsw-alias-line-border, #dfe1e5); border-radius: 8px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-body, #fff); font: inherit; font-size: 13px; font-weight: 560; text-decoration: none; cursor: pointer; transition: border-color .15s ease, background .15s ease, transform .15s ease; } +.ddt-button:hover:not(:disabled) { border-color: #aeb3bb; background: var(--dsw-alias-fill-tertiary, #f7f8fa); } +.ddt-button:active:not(:disabled) { transform: translateY(1px); } +.ddt-button:focus-visible { outline: 2px solid color-mix(in srgb, var(--ddt-accent) 70%, white); outline-offset: 2px; } +.ddt-button:disabled { cursor: not-allowed; opacity: .55; } +.ddt-button[data-kind="primary"] { color: #fff; border-color: var(--ddt-accent); background: var(--ddt-accent); } +.ddt-button[data-kind="primary"]:hover:not(:disabled) { border-color: var(--ddt-accent-deep); background: var(--ddt-accent-deep); } +.ddt-button[data-kind="danger"] { color: var(--ddt-error); } +.ddt-button[data-kind="quiet"] { min-height: 30px; padding: 0 10px; border-color: transparent; background: transparent; } +.ddt-card { overflow: hidden; border: 1px solid var(--dsw-alias-line-border, #e5e6eb); border-radius: 14px; background: var(--dsw-alias-bg-body, #fff); box-shadow: 0 1px 2px rgb(31 35 41 / 3%); } +.ddt-cardBody { padding: 24px; } +.ddt-empty { min-height: 230px; display: grid; grid-template-columns: minmax(0, 1fr) 180px; align-items: center; gap: 30px; } +.ddt-empty h3 { margin: 8px 0; font-size: 18px; } +.ddt-empty p { max-width: 560px; color: var(--dsw-alias-label-secondary, #646a73); line-height: 1.65; } +.ddt-empty .ddt-actions { margin-top: 20px; } +.ddt-brandMark { width: 110px; height: 110px; display: grid; place-items: center; justify-self: center; border-radius: 28px; color: #fff; background: linear-gradient(145deg, #2997ff, var(--ddt-accent)); box-shadow: 0 18px 45px rgb(22 119 255 / 23%); } +.ddt-brandMark svg { filter: drop-shadow(0 3px 8px rgb(0 35 96 / 16%)); } +.ddt-qrLayout { display: grid; grid-template-columns: 300px minmax(0, 1fr); gap: 34px; align-items: center; } +.ddt-qrColumn { display: flex; flex-direction: column; align-items: center; gap: 12px; } +.ddt-qrFrame { position: relative; width: 270px; aspect-ratio: 1; display: grid; place-items: center; overflow: hidden; padding: 10px; border: 1px solid var(--dsw-alias-line-border, #e5e6eb); border-radius: 16px; background: #fff; } +.ddt-qrFrame::before { content: ''; position: absolute; inset: 6px; border: 1px solid rgb(22 119 255 / 10%); border-radius: 11px; pointer-events: none; } +.ddt-qrFrame img { display: block; width: 100%; height: 100%; object-fit: contain; } +.ddt-qrFallback { padding: 24px; color: #646a73; text-align: center; } +.ddt-expired { position: absolute; inset: 0; display: grid; place-items: center; padding: 30px; color: #fff; text-align: center; font-weight: 650; white-space: pre-line; background: rgb(31 35 41 / 76%); backdrop-filter: blur(3px); } +.ddt-countdown { width: 270px; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; } +.ddt-countdownTop { display: flex; justify-content: space-between; margin-bottom: 6px; } +.ddt-countdown strong { color: var(--dsw-alias-label-primary, #1f2329); font-variant-numeric: tabular-nums; } +.ddt-progress { height: 4px; overflow: hidden; border-radius: 99px; background: #eef0f3; } +.ddt-progress span { display: block; width: var(--ddt-progress); height: 100%; background: var(--ddt-accent); transition: width .2s linear; } +.ddt-stateLabel { display: inline-flex; align-items: center; gap: 8px; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; font-weight: 600; } +.ddt-qrCopy h3 { margin: 9px 0 8px; font-size: 18px; } +.ddt-qrCopy > p { color: var(--dsw-alias-label-secondary, #646a73); line-height: 1.65; } +.ddt-steps { margin: 18px 0 16px; padding: 0; list-style: none; counter-reset: ddt-step; } +.ddt-steps li { position: relative; min-height: 28px; padding: 3px 0 3px 36px; color: var(--dsw-alias-label-secondary, #646a73); font-size: 13px; line-height: 22px; counter-increment: ddt-step; } +.ddt-steps li::before { content: counter(ddt-step); position: absolute; left: 0; top: 1px; width: 26px; height: 26px; display: grid; place-items: center; border-radius: 8px; color: var(--ddt-accent-deep); background: var(--ddt-accent-wash); font-size: 12px; font-weight: 700; } +.ddt-brandNotice { margin: 0 0 18px; padding: 10px 12px; border-left: 3px solid #91caff; border-radius: 0 8px 8px 0; color: var(--dsw-alias-label-secondary, #646a73); background: #f5f9ff; font-size: 12px; line-height: 1.55; } +.ddt-loading { padding: 38px; color: var(--dsw-alias-label-secondary, #646a73); text-align: center; } +.ddt-loading h3 { margin: 0 0 7px; color: var(--dsw-alias-label-primary, #1f2329); font-size: 17px; } +.ddt-loading p { line-height: 1.6; } +.ddt-spinner { width: 24px; height: 24px; margin: 0 auto 13px; border: 3px solid #e6e8eb; border-top-color: var(--ddt-accent); border-radius: 50%; animation: ddt-spin .8s linear infinite; } +.ddt-statusNotice, .ddt-inlineError { display: flex; align-items: flex-start; gap: 10px; padding: 13px 15px; border: 1px solid color-mix(in srgb, var(--ddt-error) 28%, transparent); border-radius: 10px; color: var(--ddt-error); background: color-mix(in srgb, var(--ddt-error) 7%, transparent); font-size: 13px; } +.ddt-inlineError { flex-direction: column; padding: 22px; } +.ddt-inlineError h3 { font-size: 17px; } +.ddt-inlineError p { line-height: 1.55; } +.ddt-errorCode { font: 11px ui-monospace, SFMono-Regular, monospace; opacity: .8; } +.ddt-listHeading { display: flex; align-items: center; justify-content: space-between; margin: 2px 0 9px; } +.ddt-listHeading h3 { margin: 0; font-size: 14px; } +.ddt-listHeading span { color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 12px; } +.ddt-list { display: grid; gap: 12px; margin: 0; padding: 0; list-style: none; } +.ddt-accountTop { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; } +.ddt-accountIdentity { min-width: 0; display: flex; align-items: center; gap: 12px; } +.ddt-avatar { width: 42px; height: 42px; display: grid; place-items: center; flex: none; border-radius: 12px; color: #fff; background: linear-gradient(145deg, #2997ff, var(--ddt-accent)); } +.ddt-accountIdentity h3 { overflow: hidden; font-size: 15px; text-overflow: ellipsis; white-space: nowrap; } +.ddt-accountIdentity p { margin-top: 4px; color: var(--dsw-alias-label-secondary, #646a73); font: 12px ui-monospace, SFMono-Regular, monospace; } +.ddt-health { display: inline-flex; align-items: center; gap: 7px; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; white-space: nowrap; } +.ddt-metrics { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin: 20px 0; } +.ddt-metric { padding: 12px 14px; border-radius: 9px; background: var(--dsw-alias-fill-tertiary, #f7f8fa); } +.ddt-metric dt { color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; } +.ddt-metric dd { overflow: hidden; margin: 5px 0 0; font-size: 13px; text-overflow: ellipsis; white-space: nowrap; } +.ddt-access { margin-top: 18px; padding: 15px 16px; border: 1px solid var(--dsw-alias-line-divider, #eef0f3); border-radius: 11px; background: color-mix(in srgb, var(--ddt-accent-wash) 35%, var(--dsw-alias-bg-body, #fff)); } +.ddt-accessHeader { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; } +.ddt-accessHeader h4 { font-size: 13px; } +.ddt-accessHeader p { margin-top: 4px; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; line-height: 1.5; } +.ddt-accessCount { flex: none; padding: 3px 8px; border-radius: 99px; color: var(--dsw-alias-label-secondary, #646a73); background: var(--dsw-alias-fill-secondary, #f2f3f5); font-size: 11px; } +.ddt-accessCount[data-pending="true"] { color: #ad6800; background: #fff1d6; } +.ddt-senderList { display: grid; gap: 8px; margin: 12px 0 0; padding: 0; list-style: none; } +.ddt-sender { min-height: 42px; display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 10px; border-radius: 8px; background: var(--dsw-alias-bg-body, #fff); } +.ddt-senderIdentity { min-width: 0; } +.ddt-senderIdentity strong { display: block; overflow: hidden; font-size: 12px; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; } +.ddt-senderIdentity span { display: block; overflow: hidden; margin-top: 3px; color: var(--dsw-alias-label-tertiary, #8f959e); font: 10px ui-monospace, SFMono-Regular, monospace; text-overflow: ellipsis; white-space: nowrap; } +.ddt-approvedLabel { margin-top: 13px; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; font-weight: 600; } +.ddt-noSenders { margin-top: 11px !important; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 11px; } +.ddt-accountFooter { display: flex; align-items: center; justify-content: space-between; gap: 15px; padding-top: 16px; border-top: 1px solid var(--dsw-alias-line-divider, #eef0f3); } +.ddt-summary { color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; } +.ddt-confirm { padding: 18px 24px; border-top: 1px solid color-mix(in srgb, var(--ddt-error) 25%, transparent); background: color-mix(in srgb, var(--ddt-error) 5%, transparent); } +.ddt-confirm strong { display: block; margin-bottom: 6px; font-size: 14px; } +.ddt-confirm p { color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 1.55; } +.ddt-confirm .ddt-actions { margin-top: 13px; } +.ddt-visuallyHidden { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; } +@keyframes ddt-spin { to { transform: rotate(360deg); } } +@media (max-width: 720px) { + .ddt-heading, .ddt-accountTop, .ddt-accountFooter { flex-direction: column; align-items: stretch; } + .ddt-heading p { white-space: normal; } + .ddt-tools { justify-content: flex-start; } + .ddt-empty { grid-template-columns: minmax(0, 1fr); } + .ddt-brandMark { display: none; } + .ddt-qrLayout { grid-template-columns: minmax(0, 1fr); justify-items: center; } + .ddt-qrCopy { width: 100%; } + .ddt-metrics { grid-template-columns: minmax(0, 1fr); } + .ddt-cardBody { padding: 20px; } + .ddt-sender { align-items: flex-start; } +} +@media (prefers-reduced-motion: reduce) { + .ddt-page *, .ddt-page *::before, .ddt-page *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; } +} +`; +function installDingtalkStyles() { + if (typeof document === "undefined") return () => { + }; + const existing = document.querySelector(`style[data-plugin-css="${DINGTALK_STYLE_ID}"]`); + if (existing) return () => { + }; + const style = document.createElement("style"); + style.dataset.plugin = "@xmanrui/dsh-dingtalk"; + style.dataset.pluginCss = DINGTALK_STYLE_ID; + style.textContent = CSS; + document.head.appendChild(style); + return () => style.remove(); +} + +// node_modules/@xmanrui/dsh-dingtalk/plugin-src/client/index.js +var h = React.createElement; +var ACTIVE_PROVISION_STATES = /* @__PURE__ */ new Set(["pending", "scanned", "authorizing", "creating", "connecting"]); +function DingtalkIcon({ size = 28 }) { + return h("svg", { + width: size, + height: size, + viewBox: "0 0 48 48", + fill: "none", + xmlns: "http://www.w3.org/2000/svg", + "aria-hidden": "true", + focusable: "false" + }, h("path", { + fill: "currentColor", + d: "M37.05 22.783c-6.758-5.216-14.378-12.128-22.73-19.538-.655-.585-1.242-.354-1.536.42-1.88 4.973-.058 9.386 2.889 11.932s7.368 4.912 10.058 6.155c.105.049.013.203-.093.163-4.953-2.182-8.397-3.765-13.07-7.368-.497-.388-1.01-.242-1.07.521-.384 4.748 2.657 8.483 6.058 9.745 2.1.781 4.398 1.212 6.53 1.474.109.015.084.178-.027.178-2.747.01-6.058-.654-8.935-1.751-.606-.233-.818.25-.722.633.491 2.008 2.974 5.076 6.926 5.73a12 12 0 0 0 2.228.115c.164 0 .208.089.154.217q-2.685 4.6-2.803 4.797c-.091.152-.036.275.156.275h3.543c.164 0 .264.106.18.246l-4.958 8.196c-.191.328.035.565.395.301s15.212-11.133 15.636-11.448c.195-.142.148-.327-.124-.327h-3.18c-.206 0-.252-.14-.111-.28.14-.141 3.602-3.594 4.837-4.888 1.283-1.35 1.938-3.825-.231-5.498" + })); +} +var Button = React.forwardRef(function Button2({ children, kind = "secondary", className = "", ...props }, ref) { + return h("button", { + ...props, + ref, + type: "button", + className: `ddt-button ${className}`.trim(), + "data-kind": kind + }, children); +}); +function Heading({ totals, adding, busy, onAdd, addButtonRef }) { + return h( + "div", + { className: "ddt-heading" }, + h( + "div", + { className: "ddt-headingCopy" }, + h("div", { className: "ddt-eyebrow" }, "Channel"), + h("h2", null, "\u9489\u9489\u673A\u5668\u4EBA"), + h("p", null, "\u901A\u8FC7\u626B\u7801\u628A\u9489\u9489\u673A\u5668\u4EBA\u63A5\u5165 DeepSeek Harness") + ), + h( + "div", + { className: "ddt-tools" }, + totals.configured > 0 ? h( + "div", + { className: "ddt-badge" }, + h("span", { + className: "ddt-dot", + "data-tone": totals.connected > 0 ? "success" : "warning" + }), + h("span", null, `${totals.connected} / ${totals.configured} \u5728\u7EBF`) + ) : null, + totals.pendingApproval > 0 ? h( + "div", + { className: "ddt-badge", "data-tone": "attention" }, + `${totals.pendingApproval} \u4E2A\u5F85\u6279\u51C6` + ) : null, + h("div", { + className: "ddt-badge", + title: "\u5E94\u7528\u5BC6\u94A5\u53EA\u5199\u5165 Harness Host \u51ED\u636E\u670D\u52A1\uFF0C\u4E0D\u4F1A\u53D1\u9001\u5230\u6D4F\u89C8\u5668" + }, "\u51ED\u636E\u4EC5\u4FDD\u5B58\u5728\u672C\u673A"), + h(Button, { + kind: "primary", + onClick: onAdd, + disabled: adding || busy, + ref: addButtonRef + }, adding ? "\u6B63\u5728\u63A5\u5165" : "\u626B\u7801\u63A5\u5165\u9489\u9489") + ) + ); +} +function LoadingView() { + return h( + "div", + { className: "ddt-card ddt-loading", "aria-busy": "true" }, + h("div", { className: "ddt-spinner" }), + h("span", null, "\u6B63\u5728\u8BFB\u53D6\u9489\u9489\u8FDE\u63A5\u72B6\u6001\u2026") + ); +} +function EmptyView({ busy, onStart }) { + return h( + "div", + { className: "ddt-card" }, + h( + "div", + { className: "ddt-cardBody ddt-empty" }, + h( + "div", + null, + h( + "div", + { className: "ddt-stateLabel" }, + h("span", { className: "ddt-dot" }), + h("span", null, "\u5C1A\u672A\u63A5\u5165\u9489\u9489\u673A\u5668\u4EBA") + ), + h("h3", null, "\u626B\u4E00\u6B21\u7801\uFF0C\u81EA\u52A8\u521B\u5EFA\u5E76\u8FDE\u63A5\u673A\u5668\u4EBA"), + h("p", null, "\u6388\u6743\u7531\u9489\u9489\u5B98\u65B9\u9875\u9762\u5B8C\u6210\u3002\u521B\u5EFA\u6210\u529F\u540E\uFF0C\u5E94\u7528\u51ED\u636E\u4F1A\u76F4\u63A5\u5199\u5165 Harness Host\uFF0C\u672C\u9875\u9762\u53EA\u63A5\u6536\u8131\u654F\u7684\u8FDE\u63A5\u72B6\u6001\u3002"), + h( + "div", + { className: "ddt-actions" }, + h( + Button, + { kind: "primary", onClick: onStart, disabled: busy }, + busy ? "\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801\u2026" : "\u751F\u6210\u9489\u9489\u4E8C\u7EF4\u7801" + ) + ) + ), + h( + "div", + { className: "ddt-brandMark", "aria-hidden": "true" }, + h(DingtalkIcon, { size: 68 }) + ) + ) + ); +} +function QrPanel({ provision, now, busy, onRefresh, onCancel }) { + const [imageFailed, setImageFailed] = React.useState(false); + const source = safeQrSource(provision.qrCodeDataUrl); + const remaining = Math.max(0, provision.expiresAt - now); + const expired = remaining === 0 || provision.status === "expired"; + const duration = Math.max(1, provision.durationMs ?? 10 * 6e4); + const progress = Math.round(Math.min(1, remaining / duration) * 100); + React.useEffect(() => setImageFailed(false), [source]); + return h( + "div", + { className: "ddt-card" }, + h( + "div", + { className: "ddt-cardBody ddt-qrLayout" }, + h( + "div", + { className: "ddt-qrColumn" }, + h( + "div", + { className: "ddt-qrFrame" }, + source && !imageFailed ? h("img", { + src: source, + alt: "\u7528\u4E8E\u628A\u9489\u9489\u673A\u5668\u4EBA\u63A5\u5165 DeepSeek Harness \u7684\u4E00\u6B21\u6027\u4E8C\u7EF4\u7801", + onError: () => setImageFailed(true) + }) : h("div", { className: "ddt-qrFallback" }, "\u4E8C\u7EF4\u7801\u56FE\u7247\u672A\u5C31\u7EEA\uFF0C\u8BF7\u91CD\u65B0\u751F\u6210\u3002"), + expired ? h("div", { className: "ddt-expired" }, "\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F\n\u8BF7\u91CD\u65B0\u751F\u6210") : null + ), + h( + "div", + { className: "ddt-countdown" }, + h( + "div", + { className: "ddt-countdownTop" }, + h("span", null, "\u4E8C\u7EF4\u7801\u6709\u6548\u65F6\u95F4"), + h("strong", null, formatRemaining(remaining)) + ), + h( + "div", + { className: "ddt-progress", "aria-hidden": "true" }, + h("span", { style: { "--ddt-progress": `${progress}%` } }) + ) + ) + ), + h( + "div", + { className: "ddt-qrCopy" }, + h( + "div", + { className: "ddt-stateLabel" }, + h("span", { className: "ddt-dot", "data-tone": expired ? "error" : "warning" }), + h("span", null, expired ? "\u4E8C\u7EF4\u7801\u5DF2\u5931\u6548" : "\u7B49\u5F85\u9489\u9489\u626B\u7801\u6388\u6743") + ), + h("h3", null, expired ? "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801\u540E\u7EE7\u7EED" : "\u4F7F\u7528\u9489\u9489 App \u5B8C\u6210\u673A\u5668\u4EBA\u6388\u6743"), + h("p", null, "\u626B\u7801\u540E\u4E0D\u9700\u8981\u624B\u5DE5\u590D\u5236\u5E94\u7528\u6807\u8BC6\u6216\u5BC6\u94A5\uFF0C\u6388\u6743\u7ED3\u679C\u4F1A\u5B89\u5168\u8FD4\u56DE\u5230\u672C\u673A Host\u3002"), + h( + "ol", + { className: "ddt-steps" }, + h("li", null, "\u6253\u5F00\u9489\u9489 App\uFF0C\u626B\u63CF\u5DE6\u4FA7\u4E8C\u7EF4\u7801"), + h("li", null, "\u5728\u6388\u6743\u9875\u70B9\u51FB\u201C\u4E00\u952E\u521B\u5EFA\u65B0\u673A\u5668\u4EBA\u201D"), + h("li", null, "\u4FDD\u6301\u672C\u9875\u6253\u5F00\uFF0C\u7B49\u5F85\u673A\u5668\u4EBA\u81EA\u52A8\u8FDE\u63A5") + ), + h( + "div", + { className: "ddt-brandNotice" }, + "\u9489\u9489\u5B98\u65B9\u6388\u6743\u9875\u76EE\u524D\u53EF\u80FD\u663E\u793A OpenClaw \u54C1\u724C\uFF0C\u8FD9\u662F\u5B98\u65B9\u8FDE\u63A5\u5668\u6388\u6743\u9875\u9762\uFF0C\u4E0D\u5F71\u54CD\u673A\u5668\u4EBA\u63A5\u5165 DeepSeek Harness\u3002" + ), + h( + "div", + { className: "ddt-actions" }, + expired ? h(Button, { kind: "primary", onClick: onRefresh, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801") : null, + !expired ? h(Button, { onClick: onRefresh, disabled: busy }, "\u6362\u4E00\u4E2A\u4E8C\u7EF4\u7801") : null, + h(Button, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88") + ) + ) + ) + ); +} +function ProgressPanel({ status, busy, onCancel }) { + const connecting = status === "connecting"; + const creating = status === "creating"; + return h( + "div", + { className: "ddt-card ddt-loading", "aria-busy": "true" }, + h("div", { className: "ddt-spinner" }), + h("h3", null, connecting ? "\u673A\u5668\u4EBA\u5DF2\u521B\u5EFA\uFF0C\u6B63\u5728\u5EFA\u7ACB\u6D88\u606F\u8FDE\u63A5" : creating ? "\u6388\u6743\u5DF2\u786E\u8BA4\uFF0C\u6B63\u5728\u521B\u5EFA\u9489\u9489\u673A\u5668\u4EBA" : "\u6B63\u5728\u786E\u8BA4\u9489\u9489\u6388\u6743"), + h("p", null, connecting ? "\u6B63\u5728\u68C0\u67E5\u9489\u9489 Stream \u957F\u8FDE\u63A5\uFF0C\u6210\u529F\u540E\u4F1A\u81EA\u52A8\u663E\u793A\u4E3A\u5728\u7EBF\u3002" : "\u8BF7\u52FF\u5173\u95ED\u672C\u9875\uFF0C\u9489\u9489\u5B8C\u6210\u6388\u6743\u540E\u5C06\u81EA\u52A8\u7EE7\u7EED\u3002"), + h( + "div", + { className: "ddt-actions", style: { justifyContent: "center", marginTop: 14 } }, + h(Button, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88\u63A5\u5165") + ) + ); +} +function ProvisionError({ provision, busy, onRetry, onClose }) { + const error = provision.error ?? { + code: "DINGTALK_PROVISION_FAILED", + message: "\u9489\u9489\u673A\u5668\u4EBA\u6CA1\u6709\u63A5\u5165\u5B8C\u6210" + }; + return h( + "div", + { className: "ddt-card" }, + h( + "div", + { className: "ddt-inlineError", role: "alert" }, + h("h3", null, provision.status === "expired" ? "\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F" : "\u9489\u9489\u673A\u5668\u4EBA\u6CA1\u6709\u63A5\u5165\u5B8C\u6210"), + h("p", null, error.message), + h("span", { className: "ddt-errorCode" }, error.code), + h( + "div", + { className: "ddt-actions" }, + h(Button, { kind: "primary", onClick: onRetry, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"), + h(Button, { onClick: onClose, disabled: busy }, "\u5173\u95ED") + ) + ) + ); +} +function checkedTime(value) { + if (!value) return "\u5C1A\u672A\u68C0\u67E5"; + try { + return new Intl.DateTimeFormat("zh-CN", { + hour: "2-digit", + minute: "2-digit", + second: "2-digit" + }).format(new Date(value)); + } catch { + return "\u521A\u521A"; + } +} +function SenderAccess({ account, busy, onApprove, onRevoke }) { + const pending = account.senders.pending; + const approved = account.senders.approved; + return h( + "section", + { className: "ddt-access", "aria-label": `${account.bot.name}\u4F7F\u7528\u8005\u6743\u9650` }, + h( + "div", + { className: "ddt-accessHeader" }, + h( + "div", + null, + h("h4", null, "\u5141\u8BB8\u4F7F\u7528\u673A\u5668\u4EBA\u7684\u9489\u9489\u8D26\u53F7"), + h("p", null, "\u65B0\u4F7F\u7528\u8005\u9996\u6B21\u53D1\u6D88\u606F\u540E\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\uFF0C\u987B\u5728\u672C\u673A\u660E\u786E\u6279\u51C6\u3002") + ), + h("span", { + className: "ddt-accessCount", + "data-pending": pending.length > 0 ? "true" : void 0 + }, pending.length > 0 ? `${pending.length} \u4E2A\u5F85\u6279\u51C6` : `${approved.length} \u4E2A\u5DF2\u6279\u51C6`) + ), + pending.length > 0 ? h("ul", { className: "ddt-senderList" }, pending.map((sender) => h( + "li", + { + className: "ddt-sender", + key: sender.requestId + }, + h( + "div", + { className: "ddt-senderIdentity" }, + h("strong", null, sender.displayName), + h("span", null, `${sender.senderIdMasked} \xB7 ${sender.conversationType === "group" ? "\u7FA4\u804A" : "\u5355\u804A"}`) + ), + h(Button, { + kind: "primary", + onClick: () => onApprove(sender), + disabled: Boolean(busy) + }, busy === `approve:${sender.requestId}` ? "\u6279\u51C6\u4E2D\u2026" : "\u6279\u51C6\u4F7F\u7528") + ))) : null, + approved.length > 0 ? h( + React.Fragment, + null, + h("div", { className: "ddt-approvedLabel" }, "\u5DF2\u6279\u51C6"), + h("ul", { className: "ddt-senderList" }, approved.map((sender) => h( + "li", + { + className: "ddt-sender", + key: sender.senderKey + }, + h( + "div", + { className: "ddt-senderIdentity" }, + h("strong", null, sender.displayName), + h("span", null, sender.senderIdMasked) + ), + h(Button, { + kind: "quiet", + onClick: () => onRevoke(sender), + disabled: Boolean(busy) + }, busy === `revoke:${sender.senderKey}` ? "\u64A4\u9500\u4E2D\u2026" : "\u64A4\u9500") + ))) + ) : null, + pending.length === 0 && approved.length === 0 ? h("p", { className: "ddt-noSenders" }, "\u5C1A\u65E0\u4F7F\u7528\u8BF7\u6C42\u3002\u673A\u5668\u4EBA\u6536\u5230\u7B2C\u4E00\u6761\u6D88\u606F\u540E\uFF0C\u53EF\u5728\u6B64\u6279\u51C6\u53D1\u9001\u8005\u3002") : null + ); +} +function RemoveConfirmation({ account, busy, onConfirm, onCancel }) { + const cancelRef = React.useRef(null); + React.useEffect(() => cancelRef.current?.focus(), []); + return h( + "div", + { + className: "ddt-confirm", + role: "alertdialog", + "aria-label": `\u79FB\u9664${account.bot.name}`, + onKeyDown: (event) => { + if (event.key === "Escape" && !busy) onCancel(); + } + }, + h("strong", null, `\u4ECE DeepSeek Harness \u79FB\u9664\u201C${account.bot.name}\u201D\uFF1F`), + h("p", null, "\u8FD9\u4F1A\u505C\u6B62\u6D88\u606F\u8FDE\u63A5\uFF0C\u5E76\u5220\u9664\u672C\u673A\u4FDD\u5B58\u7684\u5E94\u7528\u51ED\u636E\u3001\u673A\u5668\u4EBA\u914D\u7F6E\u3001\u4F1A\u8BDD\u6620\u5C04\u53CA\u4F7F\u7528\u8005\u6279\u51C6\u8BB0\u5F55\u3002\u9489\u9489\u5F00\u653E\u5E73\u53F0\u4E2D\u7684\u673A\u5668\u4EBA\u4E0D\u4F1A\u88AB\u81EA\u52A8\u5220\u9664\u3002"), + h( + "div", + { className: "ddt-actions" }, + h(Button, { ref: cancelRef, onClick: onCancel, disabled: busy }, "\u4FDD\u7559\u673A\u5668\u4EBA"), + h( + Button, + { kind: "danger", onClick: onConfirm, disabled: busy }, + busy ? "\u6B63\u5728\u79FB\u9664\u2026" : "\u786E\u8BA4\u79FB\u9664\u63A5\u5165" + ) + ) + ); +} +function AccountCard({ + account, + busy, + removing, + onReconnect, + onRequestRemove, + onConfirmRemove, + onCancelRemove, + onApprove, + onRevoke +}) { + const state = busy === "reconnect" ? "connecting" : account.state; + const tone = account.connected ? "success" : state === "error" ? "error" : "warning"; + const stateLabel = account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA"; + return h( + "article", + { className: "ddt-card", tabIndex: -1, "data-bot-id": account.botId }, + h( + "div", + { className: "ddt-cardBody" }, + h( + "div", + { className: "ddt-accountTop" }, + h( + "div", + { className: "ddt-accountIdentity" }, + h("div", { className: "ddt-avatar", "aria-hidden": "true" }, h(DingtalkIcon, { size: 29 })), + h( + "div", + null, + h("h3", { title: account.bot.name }, account.bot.name), + h("p", { title: account.bot.clientIdMasked }, account.bot.clientIdMasked) + ) + ), + h( + "div", + { className: "ddt-health" }, + h("span", { className: "ddt-dot", "data-tone": tone }), + h("span", null, stateLabel) + ) + ), + h( + "dl", + { className: "ddt-metrics" }, + h( + "div", + { className: "ddt-metric" }, + h("dt", null, "\u6D88\u606F\u901A\u9053"), + h("dd", null, account.connected ? "Stream \u957F\u8FDE\u63A5" : "\u79BB\u7EBF") + ), + h( + "div", + { className: "ddt-metric" }, + h("dt", null, "\u6536\u5230 / \u56DE\u590D"), + h("dd", null, `${account.stats.messagesReceived} / ${account.stats.messagesReplied}`) + ), + h( + "div", + { className: "ddt-metric" }, + h("dt", null, "\u6700\u8FD1\u68C0\u67E5"), + h("dd", null, checkedTime(account.health.lastCheckedAt)) + ) + ), + h(SenderAccess, { account, busy, onApprove, onRevoke }), + h( + "div", + { className: "ddt-accountFooter" }, + h("div", { className: "ddt-summary" }, account.error?.message ?? account.health.summary), + h( + "div", + { className: "ddt-actions" }, + h( + Button, + { onClick: onReconnect, disabled: Boolean(busy) }, + busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5" + ), + h( + Button, + { kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, + "\u79FB\u9664\u63A5\u5165" + ) + ) + ) + ), + removing ? h(RemoveConfirmation, { + account, + busy: busy === "delete", + onConfirm: onConfirmRemove, + onCancel: onCancelRemove + }) : null + ); +} +function AccountList(props) { + return h( + "section", + null, + h( + "div", + { className: "ddt-listHeading" }, + h("h3", null, "\u5DF2\u63A5\u5165\u7684\u9489\u9489\u673A\u5668\u4EBA"), + h("span", null, `${props.bots.length} \u4E2A`) + ), + h("ul", { className: "ddt-list" }, props.bots.map((account) => h( + "li", + { key: account.botId }, + h(AccountCard, { + account, + busy: props.busyByBot[account.botId], + removing: props.removeTarget === account.botId, + onReconnect: () => props.onReconnect(account), + onRequestRemove: () => props.onRequestRemove(account), + onConfirmRemove: () => props.onConfirmRemove(account), + onCancelRemove: props.onCancelRemove, + onApprove: (sender) => props.onApprove(account, sender), + onRevoke: (sender) => props.onRevoke(account, sender) + }) + ))) + ); +} +var EMPTY_TOTALS = Object.freeze({ configured: 0, connected: 0, pendingApproval: 0 }); +function DingtalkSettingsTab({ rpcCall }) { + const [model, setModel] = React.useState({ + phase: "loading", + bots: [], + totals: EMPTY_TOTALS, + revision: 0, + error: null + }); + const [provision, setProvision] = React.useState(null); + const [busy, setBusy] = React.useState(false); + const [busyByBot, setBusyByBot] = React.useState({}); + const [removeTarget, setRemoveTarget] = React.useState(null); + const [notice, setNotice] = React.useState(""); + const [now, setNow] = React.useState(() => Date.now()); + const addButtonRef = React.useRef(null); + React.useEffect(() => installDingtalkStyles(), []); + const announce = React.useCallback((message) => { + setNotice(""); + if (message) window.requestAnimationFrame(() => setNotice(message)); + }, []); + const invoke = React.useCallback(async (endpoint, payload = {}, signal) => { + if (typeof rpcCall !== "function") throw new TypeError("\u9489\u9489\u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5"); + return unwrapRpcResult(await rpcCall(endpoint, payload, signal)); + }, [rpcCall]); + const loadStatus = React.useCallback(async ({ signal, silent = false } = {}) => { + if (!silent) setModel((current) => ({ ...current, phase: "loading", error: null })); + try { + const snapshot = normalizeSnapshot(await invoke(DINGTALK_ENDPOINTS.status, {}, signal)); + setModel({ + phase: "ready", + bots: snapshot.bots, + totals: snapshot.totals, + revision: snapshot.revision, + error: null + }); + if (snapshot.provisioning) { + setProvision((current) => !current || current.attemptId === snapshot.provisioning.attemptId ? { + ...current, + ...snapshot.provisioning, + durationMs: current?.durationMs ?? Math.max(1, snapshot.provisioning.expiresAt - Date.now()) + } : current); + } + return snapshot; + } catch (error) { + if (error?.name === "AbortError") return void 0; + setModel((current) => ({ + ...current, + phase: silent && current.phase === "ready" ? "ready" : "error", + error: presentError(error) + })); + return void 0; + } + }, [invoke]); + React.useEffect(() => { + const controller = new AbortController(); + void loadStatus({ signal: controller.signal }); + return () => controller.abort(); + }, [loadStatus]); + React.useEffect(() => { + if (model.phase !== "ready") return void 0; + const controller = new AbortController(); + let running = false; + const timer = window.setInterval(async () => { + if (running) return; + running = true; + await loadStatus({ signal: controller.signal, silent: true }); + running = false; + }, 15e3); + return () => { + controller.abort(); + window.clearInterval(timer); + }; + }, [loadStatus, model.phase]); + React.useEffect(() => { + if (!provision || !ACTIVE_PROVISION_STATES.has(provision.status)) return void 0; + const timer = window.setInterval(() => setNow(Date.now()), 1e3); + return () => window.clearInterval(timer); + }, [provision?.attemptId, provision?.status]); + const startProvisioning = React.useCallback(async ({ replace = false } = {}) => { + setBusy(true); + try { + if (replace && provision?.attemptId) { + await invoke(DINGTALK_ENDPOINTS.cancelProvisioning, { + attemptId: provision.attemptId + }); + } + setProvision({ status: "starting" }); + const started = normalizeProvisioning(await invoke( + DINGTALK_ENDPOINTS.beginProvisioning, + { locale: "zh-CN" } + )); + if (!started.qrCodeDataUrl) { + throw new Error("\u9489\u9489\u626B\u7801\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u5B89\u5168\u7684\u4E8C\u7EF4\u7801"); + } + setNow(Date.now()); + setProvision({ + ...started, + durationMs: Math.max(1, started.expiresAt - Date.now()) + }); + announce("\u9489\u9489\u4E8C\u7EF4\u7801\u5DF2\u751F\u6210\uFF0C\u8BF7\u4F7F\u7528\u9489\u9489 App \u626B\u63CF\u3002"); + } catch (error) { + setProvision({ + attemptId: provision?.attemptId, + status: "failed", + error: presentError(error) + }); + } finally { + setBusy(false); + } + }, [announce, invoke, provision?.attemptId]); + const cancelProvisioning = React.useCallback(async () => { + setBusy(true); + try { + if (provision?.attemptId && !["failed", "expired", "cancelled"].includes(provision.status)) { + await invoke(DINGTALK_ENDPOINTS.cancelProvisioning, { attemptId: provision.attemptId }); + } + setProvision(null); + announce("\u5DF2\u53D6\u6D88\u9489\u9489\u673A\u5668\u4EBA\u63A5\u5165\u3002"); + window.requestAnimationFrame(() => addButtonRef.current?.focus()); + } catch (error) { + setProvision((current) => ({ ...current, status: "failed", error: presentError(error) })); + } finally { + setBusy(false); + } + }, [announce, invoke, provision?.attemptId, provision?.status]); + React.useEffect(() => { + const attemptId = provision?.attemptId; + if (!attemptId || !ACTIVE_PROVISION_STATES.has(provision.status)) return void 0; + const controller = new AbortController(); + let timer; + const poll = async () => { + try { + const result = normalizeProvisioning(await invoke( + DINGTALK_ENDPOINTS.pollProvisioning, + { attemptId }, + controller.signal + )); + if (result.status === "connected") { + const snapshot = await loadStatus({ signal: controller.signal, silent: true }); + const account = result.botId ? snapshot?.bots.find((bot) => bot.botId === result.botId) : snapshot?.bots.find((bot) => bot.connected); + if (!account?.connected) { + setProvision((current) => current?.attemptId === attemptId ? { ...current, ...result, status: "connecting" } : current); + timer = window.setTimeout(poll, result.pollIntervalMs); + return; + } + setProvision(null); + announce(result.alreadyConnected ? "\u8FD9\u4E2A\u9489\u9489\u673A\u5668\u4EBA\u5DF2\u7ECF\u63A5\u5165\u5E76\u4FDD\u6301\u5728\u7EBF\u3002" : "\u9489\u9489\u673A\u5668\u4EBA\u5DF2\u63A5\u5165\uFF0C\u53EF\u4EE5\u5F00\u59CB\u53D1\u9001\u6D88\u606F\u3002"); + return; + } + setProvision((current) => current?.attemptId === attemptId ? { ...current, ...result, durationMs: current.durationMs } : current); + if (ACTIVE_PROVISION_STATES.has(result.status)) { + timer = window.setTimeout(poll, result.pollIntervalMs); + } + } catch (error) { + if (error?.name === "AbortError") return; + setProvision((current) => current?.attemptId === attemptId ? { ...current, status: "failed", error: presentError(error) } : current); + } + }; + timer = window.setTimeout(poll, provision.pollIntervalMs ?? 3e3); + return () => { + controller.abort(); + window.clearTimeout(timer); + }; + }, [announce, invoke, loadStatus, provision?.attemptId, provision?.pollIntervalMs, provision?.status]); + const setBotBusy = React.useCallback((botId, operation) => { + setBusyByBot((current) => { + const next = { ...current }; + if (operation) next[botId] = operation; + else delete next[botId]; + return next; + }); + }, []); + const runBotAction = React.useCallback(async ({ account, operation, endpoint, payload, success }) => { + setBotBusy(account.botId, operation); + try { + await invoke(endpoint, payload); + const snapshot = await loadStatus({ silent: true }); + announce(typeof success === "function" ? success(snapshot) : success); + return snapshot; + } catch (error) { + announce(`\u64CD\u4F5C\u5931\u8D25\uFF1A${presentError(error).message}`); + return void 0; + } finally { + setBotBusy(account.botId, null); + } + }, [announce, invoke, loadStatus, setBotBusy]); + const reconnect = React.useCallback((account) => runBotAction({ + account, + operation: "reconnect", + endpoint: DINGTALK_ENDPOINTS.reconnectBot, + payload: { botId: account.botId }, + success: (snapshot) => snapshot?.bots.find((bot) => bot.botId === account.botId)?.connected ? "\u9489\u9489\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\u3002" : "\u9489\u9489\u4ECD\u672A\u8FDE\u63A5\uFF0C\u63D2\u4EF6\u4F1A\u7EE7\u7EED\u81EA\u52A8\u91CD\u8BD5\u3002" + }), [runBotAction]); + const remove = React.useCallback(async (account) => { + const snapshot = await runBotAction({ + account, + operation: "delete", + endpoint: DINGTALK_ENDPOINTS.deleteBot, + payload: { botId: account.botId, confirm: true }, + success: "\u9489\u9489\u673A\u5668\u4EBA\u53CA\u672C\u673A\u51ED\u636E\u5DF2\u79FB\u9664\u3002" + }); + if (snapshot) setRemoveTarget(null); + }, [runBotAction]); + const approve = React.useCallback((account, sender) => runBotAction({ + account, + operation: `approve:${sender.requestId}`, + endpoint: DINGTALK_ENDPOINTS.approveSender, + payload: { botId: account.botId, requestId: sender.requestId, confirm: true }, + success: `\u5DF2\u6279\u51C6 ${sender.displayName} \u4F7F\u7528\u8FD9\u4E2A\u673A\u5668\u4EBA\u3002` + }), [runBotAction]); + const revoke = React.useCallback((account, sender) => runBotAction({ + account, + operation: `revoke:${sender.senderKey}`, + endpoint: DINGTALK_ENDPOINTS.revokeSender, + payload: { botId: account.botId, senderKey: sender.senderKey, confirm: true }, + success: `\u5DF2\u64A4\u9500 ${sender.displayName} \u7684\u4F7F\u7528\u6743\u9650\u3002` + }), [runBotAction]); + let provisionView = null; + if (provision?.status === "starting") { + provisionView = h( + "div", + { className: "ddt-card ddt-loading", "aria-busy": "true" }, + h("div", { className: "ddt-spinner" }), + h("span", null, "\u6B63\u5728\u7533\u8BF7\u9489\u9489\u6388\u6743\u4E8C\u7EF4\u7801\u2026") + ); + } else if (provision?.status === "pending") { + provisionView = h(QrPanel, { + provision, + now, + busy, + onRefresh: () => void startProvisioning({ replace: true }), + onCancel: () => void cancelProvisioning() + }); + } else if (["scanned", "authorizing", "creating", "connecting"].includes(provision?.status)) { + provisionView = h(ProgressPanel, { + status: provision.status, + busy, + onCancel: () => void cancelProvisioning() + }); + } else if (provision && ["failed", "expired", "cancelled"].includes(provision.status)) { + provisionView = h(ProvisionError, { + provision, + busy, + onRetry: () => void startProvisioning({ replace: Boolean(provision.attemptId) }), + onClose: () => void cancelProvisioning() + }); + } + return h( + "section", + { className: "ddt-page", "aria-label": "\u9489\u9489\u8BBE\u7F6E" }, + h(Heading, { + totals: model.totals, + adding: Boolean(provision), + busy, + onAdd: () => void startProvisioning(), + addButtonRef + }), + h("div", { className: "ddt-visuallyHidden", role: "status", "aria-live": "polite" }, notice), + model.error && model.phase === "ready" ? h("div", { className: "ddt-statusNotice", role: "alert" }, `\u72B6\u6001\u5237\u65B0\u5931\u8D25\uFF1A${model.error.message}`) : null, + model.phase === "loading" ? h(LoadingView) : model.phase === "error" ? h( + "div", + { className: "ddt-card" }, + h( + "div", + { className: "ddt-inlineError", role: "alert" }, + h("h3", null, "\u65E0\u6CD5\u8BFB\u53D6\u9489\u9489\u673A\u5668\u4EBA\u72B6\u6001"), + h("p", null, model.error?.message ?? "\u8BF7\u7A0D\u540E\u91CD\u8BD5"), + h(Button, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6") + ) + ) : h( + React.Fragment, + null, + provisionView, + model.bots.length === 0 && !provision ? h(EmptyView, { busy, onStart: () => void startProvisioning() }) : null, + model.bots.length > 0 ? h(AccountList, { + bots: model.bots, + busyByBot, + removeTarget, + onReconnect: (account) => void reconnect(account), + onRequestRemove: (account) => setRemoveTarget(account.botId), + onConfirmRemove: (account) => void remove(account), + onCancelRemove: () => setRemoveTarget(null), + onApprove: (account, sender) => void approve(account, sender), + onRevoke: (account, sender) => void revoke(account, sender) + }) : null + ) + ); +} // plugin-src/client/channels/feishu/index.js -var React = __toESM(require("react"), 1); +var React2 = __toESM(require("react"), 1); // plugin-src/client/channels/feishu/api.js var FEISHU_RPC_CHANNEL = "/feishu"; @@ -76,10 +1194,10 @@ var POLL_STATES = /* @__PURE__ */ new Set([ "expired", "failed" ]); -function isRecord(value) { +function isRecord2(value) { return value !== null && typeof value === "object" && !Array.isArray(value); } -function optionalString(value) { +function optionalString2(value) { return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0; } function optionalTimestamp(value) { @@ -90,67 +1208,67 @@ function optionalTimestamp(value) { } return void 0; } -function clamp(value, min, max, fallback) { +function clamp2(value, min, max, fallback) { return typeof value === "number" && Number.isFinite(value) ? Math.min(max, Math.max(min, value)) : fallback; } -function unwrapRpcResult(result) { - if (!isRecord(result) || typeof result.ok !== "boolean") { +function unwrapRpcResult2(result) { + if (!isRecord2(result) || typeof result.ok !== "boolean") { throw new Error("\u98DE\u4E66\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94"); } if (!result.ok) { - const message = optionalString(result.error?.message) ?? "\u98DE\u4E66\u670D\u52A1\u8BF7\u6C42\u5931\u8D25"; + const message = optionalString2(result.error?.message) ?? "\u98DE\u4E66\u670D\u52A1\u8BF7\u6C42\u5931\u8D25"; const error = new Error(message); - error.code = optionalString(result.error?.code) ?? "FEISHU_RPC_ERROR"; + error.code = optionalString2(result.error?.code) ?? "FEISHU_RPC_ERROR"; throw error; } return result.value; } -function normalizeProvisioning(value, now = Date.now()) { - const source = isRecord(value?.provisioning) ? value.provisioning : value; - if (!isRecord(source)) throw new Error("\u98DE\u4E66\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u4E8C\u7EF4\u7801\u4FE1\u606F"); - const attemptId = optionalString(source.attemptId) ?? optionalString(source.provisioningId); - const verificationUrl = optionalString(source.verificationUrl); - const qrCodeDataUrl = optionalString(source.qrCodeDataUrl); +function normalizeProvisioning2(value, now = Date.now()) { + const source = isRecord2(value?.provisioning) ? value.provisioning : value; + if (!isRecord2(source)) throw new Error("\u98DE\u4E66\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u4E8C\u7EF4\u7801\u4FE1\u606F"); + const attemptId = optionalString2(source.attemptId) ?? optionalString2(source.provisioningId); + const verificationUrl = optionalString2(source.verificationUrl); + const qrCodeDataUrl = optionalString2(source.qrCodeDataUrl); if (!attemptId || !verificationUrl && !qrCodeDataUrl) { throw new Error("\u98DE\u4E66\u670D\u52A1\u8FD4\u56DE\u7684\u4E8C\u7EF4\u7801\u4FE1\u606F\u4E0D\u5B8C\u6574"); } const explicitExpiry = optionalTimestamp(source.expiresAt); - const expireIn = clamp(source.expireIn, 1, 60 * 60, 5 * 60); + const expireIn = clamp2(source.expireIn, 1, 60 * 60, 5 * 60); return { attemptId, verificationUrl, qrCodeDataUrl, expiresAt: explicitExpiry ?? now + expireIn * 1e3, - pollIntervalMs: clamp(source.pollIntervalMs, 800, 1e4, 1800) + pollIntervalMs: clamp2(source.pollIntervalMs, 800, 1e4, 1800) }; } -function normalizeBot(value) { - const source = isRecord(value) ? value : {}; +function normalizeBot2(value) { + const source = isRecord2(value) ? value : {}; return { - name: optionalString(source.name) ?? "\u98DE\u4E66\u673A\u5668\u4EBA", - avatarUrl: optionalString(source.avatarUrl), - appIdMasked: optionalString(source.appIdMasked), - tenantName: optionalString(source.tenantName), + name: optionalString2(source.name) ?? "\u98DE\u4E66\u673A\u5668\u4EBA", + avatarUrl: optionalString2(source.avatarUrl), + appIdMasked: optionalString2(source.appIdMasked), + tenantName: optionalString2(source.tenantName), domain: source.domain === "lark" ? "lark" : "feishu", activated: typeof source.activated === "boolean" || typeof source.activated === "number" ? source.activated : void 0 }; } function normalizeHealth(value, connected = false) { - const source = isRecord(value) ? value : {}; + const source = isRecord2(value) ? value : {}; const fallbackStatus = connected ? "healthy" : "offline"; const status = ["healthy", "degraded", "offline", "checking"].includes(source.status) ? source.status : fallbackStatus; return { status, - summary: optionalString(source.summary) ?? (connected ? "\u957F\u8FDE\u63A5\u8FD0\u884C\u6B63\u5E38" : "\u673A\u5668\u4EBA\u5C1A\u672A\u8FDE\u63A5"), + summary: optionalString2(source.summary) ?? (connected ? "\u957F\u8FDE\u63A5\u8FD0\u884C\u6B63\u5E38" : "\u673A\u5668\u4EBA\u5C1A\u672A\u8FDE\u63A5"), lastCheckedAt: optionalTimestamp(source.lastCheckedAt), lastConnectedAt: optionalTimestamp(source.lastConnectedAt) }; } -function normalizeError(value) { - if (!isRecord(value)) return void 0; - const message = optionalString(value.message); +function normalizeError2(value) { + if (!isRecord2(value)) return void 0; + const message = optionalString2(value.message); if (!message) return void 0; - return { message, code: optionalString(value.code) }; + return { message, code: optionalString2(value.code) }; } function authoritativeState(value, connected) { if (connected) return "connected"; @@ -162,8 +1280,8 @@ function authoritativeState(value, connected) { return "offline"; } function normalizeBotConnection(value, fallbackBotId) { - if (!isRecord(value)) throw new Error("\u98DE\u4E66\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6548\u7684\u673A\u5668\u4EBA\u72B6\u6001"); - const botId = optionalString(value.botId) ?? optionalString(fallbackBotId); + if (!isRecord2(value)) throw new Error("\u98DE\u4E66\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6548\u7684\u673A\u5668\u4EBA\u72B6\u6001"); + const botId = optionalString2(value.botId) ?? optionalString2(fallbackBotId); if (!botId) throw new Error("\u98DE\u4E66\u670D\u52A1\u8FD4\u56DE\u7684\u673A\u5668\u4EBA\u7F3A\u5C11 botId"); const connected = value.connected === true; return { @@ -171,17 +1289,17 @@ function normalizeBotConnection(value, fallbackBotId) { state: authoritativeState(value.state, connected), connected, configured: value.configured !== false, - bot: normalizeBot(value.bot), + bot: normalizeBot2(value.bot), health: normalizeHealth(value.health, connected), - error: normalizeError(value.error) + error: normalizeError2(value.error) }; } function normalizeBotsSnapshot(value) { - if (!isRecord(value)) throw new Error("\u98DE\u4E66\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u8FDE\u63A5\u72B6\u6001"); + if (!isRecord2(value)) throw new Error("\u98DE\u4E66\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u8FDE\u63A5\u72B6\u6001"); let sourceBots = Array.isArray(value.bots) ? value.bots : []; if (sourceBots.length === 0 && value.configured === true) { sourceBots = [{ - botId: optionalString(value.botId) ?? "legacy-default", + botId: optionalString2(value.botId) ?? "legacy-default", state: value.state, connected: value.connected, configured: true, @@ -210,49 +1328,49 @@ function normalizeBotsSnapshot(value) { // Derive counts from the authoritative list so stale summary fields never // make the UI claim that an unavailable bot is online. totals: { configured, connected }, - provisioning: value.provisioning ? normalizeProvisioning(value.provisioning) : void 0, - error: normalizeError(value.error) + provisioning: value.provisioning ? normalizeProvisioning2(value.provisioning) : void 0, + error: normalizeError2(value.error) }; } function normalizeConnectionSnapshot(value) { - if (!isRecord(value)) throw new Error("\u98DE\u4E66\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u8FDE\u63A5\u72B6\u6001"); + if (!isRecord2(value)) throw new Error("\u98DE\u4E66\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u8FDE\u63A5\u72B6\u6001"); const connected = value.connected === true; const reportedState = CONNECTION_STATES.has(value.state) ? value.state : "disconnected"; const state = connected ? "connected" : reportedState === "connected" ? "connecting" : reportedState; const snapshot = { state, configured: value.configured === true, - bot: normalizeBot(value.bot), + bot: normalizeBot2(value.bot), health: normalizeHealth(value.health, connected), provisioning: void 0, - errorMessage: optionalString(value.error?.message) ?? optionalString(value.message) + errorMessage: optionalString2(value.error?.message) ?? optionalString2(value.message) }; - if (value.provisioning) snapshot.provisioning = normalizeProvisioning(value.provisioning); + if (value.provisioning) snapshot.provisioning = normalizeProvisioning2(value.provisioning); return snapshot; } function normalizePollResult(value) { - if (!isRecord(value)) throw new Error("\u98DE\u4E66\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u521B\u5EFA\u8FDB\u5EA6"); + if (!isRecord2(value)) throw new Error("\u98DE\u4E66\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u521B\u5EFA\u8FDB\u5EA6"); const status = POLL_STATES.has(value.status) ? value.status : POLL_STATES.has(value.state) ? value.state : void 0; if (!status) throw new Error("\u98DE\u4E66\u670D\u52A1\u8FD4\u56DE\u4E86\u672A\u77E5\u7684\u521B\u5EFA\u72B6\u6001"); const normalized = { status, - botId: optionalString(value.botId), - message: optionalString(value.error?.message) ?? optionalString(value.message), + botId: optionalString2(value.botId), + message: optionalString2(value.error?.message) ?? optionalString2(value.message), connection: void 0, provisioning: void 0 }; - if (value.provisioning) normalized.provisioning = normalizeProvisioning(value.provisioning); - if (status === "connected" && isRecord(value.connection)) { + if (value.provisioning) normalized.provisioning = normalizeProvisioning2(value.provisioning); + if (status === "connected" && isRecord2(value.connection)) { normalized.connection = value.connection.botId ? normalizeBotConnection(value.connection) : normalizeConnectionSnapshot(value.connection); } return normalized; } -function presentError(error) { - const raw = optionalString(error?.message) ?? "\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5"; +function presentError2(error) { + const raw = optionalString2(error?.message) ?? "\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5"; const message = raw.replace(/(client[_-]?secret|app[_-]?secret|secret|token)\s*[:=]\s*[^\s,;]+/gi, "$1=\u2022\u2022\u2022\u2022\u2022\u2022").slice(0, 240); - return { message, code: optionalString(error?.code) }; + return { message, code: optionalString2(error?.code) }; } -function formatRemaining(milliseconds) { +function formatRemaining2(milliseconds) { const totalSeconds = Math.max(0, Math.ceil(milliseconds / 1e3)); const minutes = Math.floor(totalSeconds / 60); const seconds = totalSeconds % 60; @@ -261,7 +1379,7 @@ function formatRemaining(milliseconds) { // plugin-src/client/channels/feishu/styles.js var FEISHU_STYLE_ID = "beihuixinghe-dsh-feishu-settings"; -var CSS = String.raw` +var CSS2 = String.raw` .bxf-page { --bxf-accent: var(--dsw-alias-state-business-primary, #3370ff); --bxf-success: var(--dsw-alias-state-success-primary, #20a162); @@ -778,7 +1896,7 @@ function installFeishuStyles() { const style = document.createElement("style"); style.dataset.plugin = "@xmanrui/dsh-feishu"; style.dataset.pluginCss = FEISHU_STYLE_ID; - style.textContent = CSS; + style.textContent = CSS2; document.head.appendChild(style); return () => { style.remove(); @@ -786,9 +1904,9 @@ function installFeishuStyles() { } // plugin-src/client/channels/feishu/index.js -var h = React.createElement; +var h2 = React2.createElement; function SvgIcon({ children, size = 18, className, viewBox = "0 0 24 24" }) { - return h("svg", { + return h2("svg", { width: size, height: size, viewBox, @@ -800,16 +1918,16 @@ function SvgIcon({ children, size = 18, className, viewBox = "0 0 24 24" }) { }, children); } function ShieldIcon({ size = 18 }) { - return h( + return h2( SvgIcon, { size }, - h("path", { + h2("path", { d: "M12 3 5.5 5.8v5.1c0 4.25 2.72 7.87 6.5 9.1 3.78-1.23 6.5-4.85 6.5-9.1V5.8L12 3Z", stroke: "currentColor", strokeWidth: "1.7", strokeLinejoin: "round" }), - h("path", { + h2("path", { d: "m9.3 11.8 1.7 1.7 3.8-4", stroke: "currentColor", strokeWidth: "1.7", @@ -819,10 +1937,10 @@ function ShieldIcon({ size = 18 }) { ); } function RobotIcon({ size = 26 }) { - return h( + return h2( SvgIcon, { size }, - h("rect", { + h2("rect", { x: "5", y: "7.5", width: "14", @@ -831,7 +1949,7 @@ function RobotIcon({ size = 26 }) { stroke: "currentColor", strokeWidth: "1.7" }), - h("path", { + h2("path", { d: "M12 4.5v3M8.7 12h.01M15.3 12h.01M9.2 15.3c1.67 1.08 3.93 1.08 5.6 0M3.5 11.5v3M20.5 11.5v3", stroke: "currentColor", strokeWidth: "1.7", @@ -840,23 +1958,23 @@ function RobotIcon({ size = 26 }) { ); } function SparkIcon({ size = 18 }) { - return h( + return h2( SvgIcon, { size }, - h("path", { + h2("path", { d: "M12 2.8c.75 3.67 2.7 5.62 6.4 6.4-3.7.77-5.65 2.72-6.4 6.4-.75-3.68-2.7-5.63-6.4-6.4 3.7-.78 5.65-2.73 6.4-6.4Z", stroke: "currentColor", strokeWidth: "1.55", strokeLinejoin: "round" }), - h("path", { + h2("path", { d: "M5.2 15.8c.35 1.7 1.28 2.63 3 3-1.72.36-2.65 1.29-3 3-.36-1.71-1.29-2.64-3-3 1.71-.37 2.64-1.3 3-3ZM18.7 2.7c.22 1.06.79 1.63 1.85 1.85-1.06.22-1.63.79-1.85 1.85-.22-1.06-.79-1.63-1.85-1.85 1.06-.22 1.63-.79 1.85-1.85Z", fill: "currentColor" }) ); } function PlusIcon({ size = 17 }) { - return h(SvgIcon, { size }, h("path", { + return h2(SvgIcon, { size }, h2("path", { d: "M12 5v14M5 12h14", stroke: "currentColor", strokeWidth: "1.8", @@ -864,7 +1982,7 @@ function PlusIcon({ size = 17 }) { })); } function RefreshIcon({ size = 16 }) { - return h(SvgIcon, { size }, h("path", { + return h2(SvgIcon, { size }, h2("path", { d: "M19 7.5V4m0 0h-3.5M19 4l-2.1 2.1A7 7 0 1 0 19 13", stroke: "currentColor", strokeWidth: "1.8", @@ -873,7 +1991,7 @@ function RefreshIcon({ size = 16 }) { })); } function ExternalIcon({ size = 15 }) { - return h(SvgIcon, { size }, h("path", { + return h2(SvgIcon, { size }, h2("path", { d: "M13 5h6v6M19 5l-8.5 8.5M18 13.5V18a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h4.5", stroke: "currentColor", strokeWidth: "1.7", @@ -882,16 +2000,16 @@ function ExternalIcon({ size = 15 }) { })); } function AlertIcon({ size = 22 }) { - return h( + return h2( SvgIcon, { size }, - h("path", { + h2("path", { d: "M12 3.4 21 19H3L12 3.4Z", stroke: "currentColor", strokeWidth: "1.7", strokeLinejoin: "round" }), - h("path", { + h2("path", { d: "M12 9v4.4M12 16.6v.01", stroke: "currentColor", strokeWidth: "1.9", @@ -900,48 +2018,48 @@ function AlertIcon({ size = 22 }) { ); } function QrIcon({ size = 58 }) { - return h(SvgIcon, { size }, h("path", { + return h2(SvgIcon, { size }, h2("path", { d: "M4 4h6v6H4V4Zm10 0h6v6h-6V4ZM4 14h6v6H4v-6Zm10 0h2v2h-2v-2Zm4 0h2v4h-2v-4Zm-4 4h4v2h-4v-2Z", fill: "currentColor" })); } -var Button = React.forwardRef(function Button2({ children, kind = "secondary", size, icon, className = "", ...props }, ref) { - return h("button", { +var Button3 = React2.forwardRef(function Button4({ children, kind = "secondary", size, icon, className = "", ...props }, ref) { + return h2("button", { ...props, ref, type: "button", className: `bxf-button ${className}`.trim(), "data-kind": kind, "data-size": size - }, icon, h("span", null, children)); + }, icon, h2("span", null, children)); }); function BrandMark({ compact = false }) { - return h( + return h2( "div", { className: compact ? "bxf-avatar" : "bxf-brandMark" }, - h(RobotIcon, { size: compact ? 25 : 34 }) + h2(RobotIcon, { size: compact ? 25 : 34 }) ); } -function Heading({ totals, onAdd, adding, busy, addButtonRef }) { +function Heading2({ totals, onAdd, adding, busy, addButtonRef }) { const hasBots = totals.configured > 0; - return h( + return h2( "div", { className: "bxf-heading" }, - h( + h2( "div", { className: "bxf-headingTools" }, - hasBots ? h("div", { + hasBots ? h2("div", { className: "bxf-totalBadge", "aria-label": `\u5DF2\u63A5\u5165 ${totals.configured} \u4E2A\u673A\u5668\u4EBA\uFF0C\u5176\u4E2D ${totals.connected} \u4E2A\u5728\u7EBF` - }, h("strong", null, totals.connected), h("span", null, `/ ${totals.configured} \u5728\u7EBF`)) : null, - h("div", { + }, h2("strong", null, totals.connected), h2("span", null, `/ ${totals.configured} \u5728\u7EBF`)) : null, + h2("div", { className: "bxf-localBadge", title: "\u6BCF\u4E2A\u5E94\u7528\u7684\u51ED\u636E\u5747\u7531 Host \u72EC\u7ACB\u4FDD\u5B58\uFF0C\u4E0D\u4F1A\u53D1\u9001\u5230\u6D4F\u89C8\u5668" - }, h(ShieldIcon, { size: 14 }), h("span", null, "\u51ED\u636E\u4EC5\u4FDD\u5B58\u5728\u672C\u673A")), - h(Button, { + }, h2(ShieldIcon, { size: 14 }), h2("span", null, "\u51ED\u636E\u4EC5\u4FDD\u5B58\u5728\u672C\u673A")), + h2(Button3, { kind: "primary", size: "small", - icon: h(PlusIcon), + icon: h2(PlusIcon), onClick: onAdd, disabled: adding || busy, ref: addButtonRef, @@ -950,58 +2068,58 @@ function Heading({ totals, onAdd, adding, busy, addButtonRef }) { ) ); } -function LoadingView() { - return h("div", { +function LoadingView2() { + return h2("div", { className: "bxf-card", "aria-busy": "true", "aria-label": "\u6B63\u5728\u8BFB\u53D6\u98DE\u4E66\u673A\u5668\u4EBA\u5217\u8868" - }, h( + }, h2( "div", { className: "bxf-skeleton" }, - h("div", { className: "bxf-skeletonLine" }), - h("div", { className: "bxf-skeletonLine" }), - h("div", { className: "bxf-skeletonLine" }), - h("div", { className: "bxf-skeletonLine" }), - h("div", { className: "bxf-skeletonBox" }) + h2("div", { className: "bxf-skeletonLine" }), + h2("div", { className: "bxf-skeletonLine" }), + h2("div", { className: "bxf-skeletonLine" }), + h2("div", { className: "bxf-skeletonLine" }), + h2("div", { className: "bxf-skeletonBox" }) )); } -function EmptyView({ onStart, busy }) { - return h( +function EmptyView2({ onStart, busy }) { + return h2( "div", { className: "bxf-card" }, - h( + h2( "div", { className: "bxf-cardBody bxf-intro" }, - h( + h2( "div", { className: "bxf-introCopy" }, - h( + h2( "div", { className: "bxf-stateLabel" }, - h("span", { className: "bxf-dot" }), - h("span", null, "\u5C1A\u672A\u63A5\u5165\u673A\u5668\u4EBA") + h2("span", { className: "bxf-dot" }), + h2("span", null, "\u5C1A\u672A\u63A5\u5165\u673A\u5668\u4EBA") ), - h("h3", null, "\u626B\u7801\uFF0C\u521B\u5EFA\u7B2C\u4E00\u4E2A\u98DE\u4E66\u5165\u53E3"), - h("p", null, "\u65E0\u9700\u624B\u52A8\u586B\u5199 App ID\u3002\u4EE5\u540E\u8FD8\u53EF\u4EE5\u7EE7\u7EED\u6DFB\u52A0\u673A\u5668\u4EBA\uFF0C\u5206\u522B\u670D\u52A1\u4E0D\u540C\u56E2\u961F\u6216\u98DE\u4E66\u79DF\u6237\u3002"), - h( + h2("h3", null, "\u626B\u7801\uFF0C\u521B\u5EFA\u7B2C\u4E00\u4E2A\u98DE\u4E66\u5165\u53E3"), + h2("p", null, "\u65E0\u9700\u624B\u52A8\u586B\u5199 App ID\u3002\u4EE5\u540E\u8FD8\u53EF\u4EE5\u7EE7\u7EED\u6DFB\u52A0\u673A\u5668\u4EBA\uFF0C\u5206\u522B\u670D\u52A1\u4E0D\u540C\u56E2\u961F\u6216\u98DE\u4E66\u79DF\u6237\u3002"), + h2( "div", { className: "bxf-actions" }, - h(Button, { + h2(Button3, { kind: "primary", - icon: h(SparkIcon), + icon: h2(SparkIcon), onClick: onStart, disabled: busy, "aria-busy": busy ? "true" : void 0 }, busy ? "\u6B63\u5728\u521B\u5EFA\u2026" : "\u4E00\u952E\u521B\u5EFA\u98DE\u4E66\u673A\u5668\u4EBA") ), - h( + h2( "div", { className: "bxf-note" }, - h(ShieldIcon, { size: 16 }), - h("span", null, "\u6BCF\u4E2A App Secret \u90FD\u53EA\u5199\u5165 Host \u51ED\u636E\u5B58\u50A8\uFF0C\u6D4F\u89C8\u5668\u4E0D\u4F1A\u6536\u5230 Secret\u3002") + h2(ShieldIcon, { size: 16 }), + h2("span", null, "\u6BCF\u4E2A App Secret \u90FD\u53EA\u5199\u5165 Host \u51ED\u636E\u5B58\u50A8\uFF0C\u6D4F\u89C8\u5668\u4E0D\u4F1A\u6536\u5230 Secret\u3002") ) ), - h("div", { className: "bxf-markStage", "aria-hidden": "true" }, h(BrandMark)) + h2("div", { className: "bxf-markStage", "aria-hidden": "true" }, h2(BrandMark)) ) ); } @@ -1014,99 +2132,99 @@ function safeVerificationHref(value) { return void 0; } } -function safeQrSource(value) { +function safeQrSource2(value) { if (!value) return void 0; return /^data:image\/(?:png|webp|svg\+xml)(?:;charset=[^;,]+)?;base64,/i.test(value) ? value : void 0; } function QrPane({ provision, now, onRefresh, onCancel, busy }) { - const [imageFailed, setImageFailed] = React.useState(false); - const qrSource = safeQrSource(provision.qrCodeDataUrl); + const [imageFailed, setImageFailed] = React2.useState(false); + const qrSource = safeQrSource2(provision.qrCodeDataUrl); const href = safeVerificationHref(provision.verificationUrl); const remaining = Math.max(0, provision.expiresAt - now); const expired = provision.expired === true || remaining === 0; const progress = Math.min(1, remaining / Math.max(1, provision.durationMs ?? remaining)); - React.useEffect(() => setImageFailed(false), [qrSource]); - return h( + React2.useEffect(() => setImageFailed(false), [qrSource]); + return h2( "div", { className: "bxf-card bxf-provisionCard" }, - h( + h2( "div", { className: "bxf-cardBody bxf-qrLayout" }, - h( + h2( "div", { className: "bxf-qrColumn" }, - h( + h2( "div", { className: "bxf-qrFrame" }, - qrSource && !imageFailed ? h("img", { + qrSource && !imageFailed ? h2("img", { src: qrSource, alt: "\u7528\u4E8E\u65B0\u589E DeepSeek Harness \u98DE\u4E66\u673A\u5668\u4EBA\u7684\u4E00\u6B21\u6027\u6388\u6743\u4E8C\u7EF4\u7801", onError: () => setImageFailed(true) - }) : h( + }) : h2( "div", { className: "bxf-qrFallback" }, - h("div", null, h(QrIcon), h("span", null, "\u4E8C\u7EF4\u7801\u672A\u5C31\u7EEA\uFF0C\u8BF7\u6253\u5F00\u6388\u6743\u94FE\u63A5")) + h2("div", null, h2(QrIcon), h2("span", null, "\u4E8C\u7EF4\u7801\u672A\u5C31\u7EEA\uFF0C\u8BF7\u6253\u5F00\u6388\u6743\u94FE\u63A5")) ), - expired ? h( + expired ? h2( "div", { className: "bxf-expiredOverlay", role: "status" }, - h("div", null, "\u4E8C\u7EF4\u7801\u5DF2\u5931\u6548", h("br"), "\u8BF7\u5237\u65B0\u540E\u91CD\u65B0\u626B\u7801") + h2("div", null, "\u4E8C\u7EF4\u7801\u5DF2\u5931\u6548", h2("br"), "\u8BF7\u5237\u65B0\u540E\u91CD\u65B0\u626B\u7801") ) : null ), - h( + h2( "div", { className: "bxf-countdown", - "aria-label": expired ? "\u4E8C\u7EF4\u7801\u5DF2\u5931\u6548" : `\u4E8C\u7EF4\u7801\u5269\u4F59 ${formatRemaining(remaining)}` + "aria-label": expired ? "\u4E8C\u7EF4\u7801\u5DF2\u5931\u6548" : `\u4E8C\u7EF4\u7801\u5269\u4F59 ${formatRemaining2(remaining)}` }, - h( + h2( "div", { className: "bxf-countdownTop", "aria-hidden": "true" }, - h("span", null, expired ? "\u7B49\u5F85\u5237\u65B0" : "\u4E8C\u7EF4\u7801\u6709\u6548\u65F6\u95F4"), - h("strong", null, formatRemaining(remaining)) + h2("span", null, expired ? "\u7B49\u5F85\u5237\u65B0" : "\u4E8C\u7EF4\u7801\u6709\u6548\u65F6\u95F4"), + h2("strong", null, formatRemaining2(remaining)) ), - h( + h2( "div", { className: "bxf-progress", "aria-hidden": "true" }, - h("span", { style: { "--bxf-progress": `${Math.round(progress * 100)}%` } }) + h2("span", { style: { "--bxf-progress": `${Math.round(progress * 100)}%` } }) ) ) ), - h( + h2( "div", { className: "bxf-qrCopy" }, - h( + h2( "div", { className: "bxf-stateLabel" }, - h("span", { className: "bxf-dot", "data-tone": "warning" }), - h("span", null, "\u6B63\u5728\u6DFB\u52A0\u65B0\u673A\u5668\u4EBA") + h2("span", { className: "bxf-dot", "data-tone": "warning" }), + h2("span", null, "\u6B63\u5728\u6DFB\u52A0\u65B0\u673A\u5668\u4EBA") ), - h("h3", null, expired ? "\u5237\u65B0\u4E8C\u7EF4\u7801\u540E\u7EE7\u7EED" : "\u4F7F\u7528\u98DE\u4E66\u626B\u7801\u521B\u5EFA\u673A\u5668\u4EBA"), - h("p", null, "\u626B\u7801\u53EA\u4F1A\u65B0\u589E\u4E00\u4E2A\u673A\u5668\u4EBA\uFF0C\u5DF2\u63A5\u5165\u7684\u673A\u5668\u4EBA\u4F1A\u7EE7\u7EED\u6B63\u5E38\u6536\u53D1\u6D88\u606F\u3002"), - h( + h2("h3", null, expired ? "\u5237\u65B0\u4E8C\u7EF4\u7801\u540E\u7EE7\u7EED" : "\u4F7F\u7528\u98DE\u4E66\u626B\u7801\u521B\u5EFA\u673A\u5668\u4EBA"), + h2("p", null, "\u626B\u7801\u53EA\u4F1A\u65B0\u589E\u4E00\u4E2A\u673A\u5668\u4EBA\uFF0C\u5DF2\u63A5\u5165\u7684\u673A\u5668\u4EBA\u4F1A\u7EE7\u7EED\u6B63\u5E38\u6536\u53D1\u6D88\u606F\u3002"), + h2( "ol", { className: "bxf-steps" }, - h("li", null, "\u6253\u5F00\u98DE\u4E66\u79FB\u52A8\u7AEF\uFF0C\u4F7F\u7528\u626B\u4E00\u626B\u8BFB\u53D6\u4E8C\u7EF4\u7801"), - h("li", null, "\u6838\u5BF9\u5E94\u7528\u540D\u79F0\u4E0E\u6743\u9650\u8303\u56F4\uFF0C\u5E76\u786E\u8BA4\u521B\u5EFA"), - h("li", null, "\u4FDD\u6301\u672C\u9875\u6253\u5F00\uFF0C\u7B49\u5F85\u65B0\u673A\u5668\u4EBA\u7684\u957F\u8FDE\u63A5\u5C31\u7EEA") + h2("li", null, "\u6253\u5F00\u98DE\u4E66\u79FB\u52A8\u7AEF\uFF0C\u4F7F\u7528\u626B\u4E00\u626B\u8BFB\u53D6\u4E8C\u7EF4\u7801"), + h2("li", null, "\u6838\u5BF9\u5E94\u7528\u540D\u79F0\u4E0E\u6743\u9650\u8303\u56F4\uFF0C\u5E76\u786E\u8BA4\u521B\u5EFA"), + h2("li", null, "\u4FDD\u6301\u672C\u9875\u6253\u5F00\uFF0C\u7B49\u5F85\u65B0\u673A\u5668\u4EBA\u7684\u957F\u8FDE\u63A5\u5C31\u7EEA") ), - h( + h2( "div", { className: "bxf-actions" }, - expired ? h(Button, { + expired ? h2(Button3, { kind: "primary", - icon: h(RefreshIcon), + icon: h2(RefreshIcon), onClick: onRefresh, disabled: busy - }, busy ? "\u5237\u65B0\u4E2D\u2026" : "\u5237\u65B0\u4E8C\u7EF4\u7801") : href ? h("a", { + }, busy ? "\u5237\u65B0\u4E2D\u2026" : "\u5237\u65B0\u4E8C\u7EF4\u7801") : href ? h2("a", { className: "bxf-button bxf-link", "data-kind": "secondary", href, target: "_blank", rel: "noopener noreferrer" - }, h(ExternalIcon), h("span", null, "\u5728\u98DE\u4E66\u4E2D\u6253\u5F00")) : null, - !expired ? h(Button, { icon: h(RefreshIcon), onClick: onRefresh, disabled: busy }, "\u6362\u4E00\u4E2A\u4E8C\u7EF4\u7801") : null, - h(Button, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88\u6DFB\u52A0") + }, h2(ExternalIcon), h2("span", null, "\u5728\u98DE\u4E66\u4E2D\u6253\u5F00")) : null, + !expired ? h2(Button3, { icon: h2(RefreshIcon), onClick: onRefresh, disabled: busy }, "\u6362\u4E00\u4E2A\u4E8C\u7EF4\u7801") : null, + h2(Button3, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88\u6DFB\u52A0") ) ) ) @@ -1114,58 +2232,58 @@ function QrPane({ provision, now, onRefresh, onCancel, busy }) { } function ProvisionProgress({ phase, onCancel, busy }) { const connecting = phase === "connecting"; - return h( + return h2( "div", { className: "bxf-card bxf-provisionCard", "aria-busy": "true" }, - h( + h2( "div", { className: "bxf-connecting bxf-connectingCompact" }, - h( + h2( "div", { className: "bxf-connectingCopy" }, - h( + h2( "div", { className: "bxf-orbit" }, - h( + h2( "div", { className: "bxf-orbitCore" }, - connecting ? h(RobotIcon, { size: 24 }) : h(SparkIcon, { size: 24 }) + connecting ? h2(RobotIcon, { size: 24 }) : h2(SparkIcon, { size: 24 }) ) ), - h("h3", null, connecting ? "\u5DF2\u786E\u8BA4\uFF0C\u6B63\u5728\u8FDE\u63A5\u65B0\u673A\u5668\u4EBA" : "\u6B63\u5728\u51C6\u5907\u6388\u6743\u4E8C\u7EF4\u7801"), - h("p", null, connecting ? "\u6B63\u5728\u5B89\u5168\u4FDD\u5B58\u51ED\u636E\u5E76\u68C0\u67E5\u65B0\u673A\u5668\u4EBA\u7684\u6D88\u606F\u901A\u9053\uFF0C\u5176\u4ED6\u673A\u5668\u4EBA\u4E0D\u4F1A\u4E2D\u65AD\u3002" : "\u6B63\u5728\u5411\u98DE\u4E66\u7533\u8BF7\u4E00\u6B21\u6027\u6388\u6743\u4E8C\u7EF4\u7801\uFF0C\u8BF7\u7A0D\u5019\u3002"), - connecting ? h( + h2("h3", null, connecting ? "\u5DF2\u786E\u8BA4\uFF0C\u6B63\u5728\u8FDE\u63A5\u65B0\u673A\u5668\u4EBA" : "\u6B63\u5728\u51C6\u5907\u6388\u6743\u4E8C\u7EF4\u7801"), + h2("p", null, connecting ? "\u6B63\u5728\u5B89\u5168\u4FDD\u5B58\u51ED\u636E\u5E76\u68C0\u67E5\u65B0\u673A\u5668\u4EBA\u7684\u6D88\u606F\u901A\u9053\uFF0C\u5176\u4ED6\u673A\u5668\u4EBA\u4E0D\u4F1A\u4E2D\u65AD\u3002" : "\u6B63\u5728\u5411\u98DE\u4E66\u7533\u8BF7\u4E00\u6B21\u6027\u6388\u6743\u4E8C\u7EF4\u7801\uFF0C\u8BF7\u7A0D\u5019\u3002"), + connecting ? h2( "div", { className: "bxf-actions", style: { justifyContent: "center" } }, - h(Button, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88\u6DFB\u52A0") + h2(Button3, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88\u6DFB\u52A0") ) : null ) ) ); } -function ProvisionError({ error, onRetry, onCancel, busy }) { - return h( +function ProvisionError2({ error, onRetry, onCancel, busy }) { + return h2( "div", { className: "bxf-card bxf-provisionCard" }, - h( + h2( "div", { className: "bxf-inlineError", role: "alert" }, - h("div", { className: "bxf-errorIcon" }, h(AlertIcon)), - h( + h2("div", { className: "bxf-errorIcon" }, h2(AlertIcon)), + h2( "div", null, - h("h3", null, "\u65B0\u673A\u5668\u4EBA\u6CA1\u6709\u6DFB\u52A0\u5B8C\u6210"), - h("p", null, error.message), - error.code ? h("span", { className: "bxf-errorCode" }, error.code) : null, - h( + h2("h3", null, "\u65B0\u673A\u5668\u4EBA\u6CA1\u6709\u6DFB\u52A0\u5B8C\u6210"), + h2("p", null, error.message), + error.code ? h2("span", { className: "bxf-errorCode" }, error.code) : null, + h2( "div", { className: "bxf-actions" }, - h( - Button, - { kind: "primary", icon: h(RefreshIcon), onClick: onRetry, disabled: busy }, + h2( + Button3, + { kind: "primary", icon: h2(RefreshIcon), onClick: onRetry, disabled: busy }, busy ? "\u91CD\u8BD5\u4E2D\u2026" : "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801" ), - h(Button, { onClick: onCancel, disabled: busy }, "\u5173\u95ED") + h2(Button3, { onClick: onCancel, disabled: busy }, "\u5173\u95ED") ) ) ) @@ -1177,25 +2295,25 @@ var HEALTH_LABELS = { offline: "\u8FDE\u63A5\u4E2D\u65AD", error: "\u9700\u8981\u5904\u7406" }; -function formatCheckedTime(timestamp2) { - if (!timestamp2) return "\u5C1A\u672A\u68C0\u67E5"; +function formatCheckedTime(timestamp3) { + if (!timestamp3) return "\u5C1A\u672A\u68C0\u67E5"; try { return new Intl.DateTimeFormat("zh-CN", { hour: "2-digit", minute: "2-digit", second: "2-digit" - }).format(new Date(timestamp2)); + }).format(new Date(timestamp3)); } catch { return "\u521A\u521A"; } } -function RemoveConfirmation({ bot, busy, onConfirm, onCancel }) { - const cancelRef = React.useRef(null); +function RemoveConfirmation2({ bot, busy, onConfirm, onCancel }) { + const cancelRef = React2.useRef(null); const idPart = bot.botId.replace(/[^a-zA-Z0-9_-]/g, "-"); const titleId = `bxf-remove-title-${idPart}`; const descriptionId = `bxf-remove-description-${idPart}`; - React.useEffect(() => cancelRef.current?.focus(), []); - return h( + React2.useEffect(() => cancelRef.current?.focus(), []); + return h2( "div", { className: "bxf-confirm", @@ -1209,18 +2327,18 @@ function RemoveConfirmation({ bot, busy, onConfirm, onCancel }) { } } }, - h("h4", { id: titleId }, `\u4ECE DeepSeek Harness \u79FB\u9664\u201C${bot.bot.name}\u201D\uFF1F`), - h( + h2("h4", { id: titleId }, `\u4ECE DeepSeek Harness \u79FB\u9664\u201C${bot.bot.name}\u201D\uFF1F`), + h2( "p", { id: descriptionId }, "\u6B64\u64CD\u4F5C\u4F1A\u505C\u6B62\u8FD9\u4E2A\u673A\u5668\u4EBA\u7684\u8FDE\u63A5\uFF0C\u5E76\u5220\u9664\u4FDD\u5B58\u5728\u672C\u673A\u7684\u63A5\u5165\u914D\u7F6E\u548C\u51ED\u636E\u3002\u98DE\u4E66\u5F00\u653E\u5E73\u53F0\u4E2D\u7684\u5E94\u7528\u4E0D\u4F1A\u88AB\u81EA\u52A8\u5220\u9664\uFF0C\u5176\u4ED6\u673A\u5668\u4EBA\u4E5F\u4E0D\u53D7\u5F71\u54CD\u3002" ), - h( + h2( "div", { className: "bxf-actions" }, - h(Button, { ref: cancelRef, onClick: onCancel, disabled: busy }, "\u4FDD\u7559\u673A\u5668\u4EBA"), - h( - Button, + h2(Button3, { ref: cancelRef, onClick: onCancel, disabled: busy }, "\u4FDD\u7559\u673A\u5668\u4EBA"), + h2( + Button3, { kind: "danger", onClick: onConfirm, disabled: busy }, busy ? "\u6B63\u5728\u79FB\u9664\u2026" : "\u786E\u8BA4\u79FB\u9664\u63A5\u5165" ) @@ -1245,7 +2363,7 @@ function BotCard({ const summary = actionError?.message ?? connection.error?.message ?? health.summary; const titleId = `bxf-bot-${connection.botId.replace(/[^a-zA-Z0-9_-]/g, "-")}`; const domainLabel = bot.domain === "lark" ? "Lark" : "\u98DE\u4E66"; - return h( + return h2( "article", { className: "bxf-card bxf-botCard", @@ -1254,74 +2372,74 @@ function BotCard({ tabIndex: -1, ref: cardRef }, - h( + h2( "div", { className: "bxf-cardBody" }, - h( + h2( "div", { className: "bxf-connectedTop" }, - h( + h2( "div", { className: "bxf-botIdentity" }, - bot.avatarUrl ? h("div", { className: "bxf-avatar" }, h("img", { src: bot.avatarUrl, alt: "" })) : h(BrandMark, { compact: true }), - h( + bot.avatarUrl ? h2("div", { className: "bxf-avatar" }, h2("img", { src: bot.avatarUrl, alt: "" })) : h2(BrandMark, { compact: true }), + h2( "div", { className: "bxf-botName" }, - h("h3", { id: titleId, title: bot.name }, bot.name), - h("p", null, bot.tenantName ? `${bot.tenantName} \xB7 ${domainLabel}\u673A\u5668\u4EBA` : `${domainLabel}\u673A\u5668\u4EBA`) + h2("h3", { id: titleId, title: bot.name }, bot.name), + h2("p", null, bot.tenantName ? `${bot.tenantName} \xB7 ${domainLabel}\u673A\u5668\u4EBA` : `${domainLabel}\u673A\u5668\u4EBA`) ) ), - h( + h2( "div", { className: "bxf-healthPill", "data-health": stateForDisplay }, - h("span", { className: "bxf-dot", "data-tone": tone }), - h("span", null, HEALTH_LABELS[stateForDisplay] ?? "\u72B6\u6001\u672A\u77E5") + h2("span", { className: "bxf-dot", "data-tone": tone }), + h2("span", null, HEALTH_LABELS[stateForDisplay] ?? "\u72B6\u6001\u672A\u77E5") ) ), - h( + h2( "dl", { className: "bxf-statusGrid" }, - h( + h2( "div", { className: "bxf-metric" }, - h("dt", null, "\u6D88\u606F\u901A\u9053"), - h("dd", null, connected ? "\u957F\u8FDE\u63A5" : stateForDisplay === "connecting" ? "\u8FDE\u63A5\u4E2D" : "\u5DF2\u65AD\u5F00") + h2("dt", null, "\u6D88\u606F\u901A\u9053"), + h2("dd", null, connected ? "\u957F\u8FDE\u63A5" : stateForDisplay === "connecting" ? "\u8FDE\u63A5\u4E2D" : "\u5DF2\u65AD\u5F00") ), - h( + h2( "div", { className: "bxf-metric" }, - h("dt", null, "\u5E94\u7528\u6807\u8BC6"), - h("dd", { title: bot.appIdMasked }, bot.appIdMasked ?? "\u5DF2\u5B89\u5168\u4FDD\u5B58") + h2("dt", null, "\u5E94\u7528\u6807\u8BC6"), + h2("dd", { title: bot.appIdMasked }, bot.appIdMasked ?? "\u5DF2\u5B89\u5168\u4FDD\u5B58") ), - h( + h2( "div", { className: "bxf-metric" }, - h("dt", null, "\u6700\u8FD1\u68C0\u67E5"), - h("dd", null, formatCheckedTime(health.lastCheckedAt)) + h2("dt", null, "\u6700\u8FD1\u68C0\u67E5"), + h2("dd", null, formatCheckedTime(health.lastCheckedAt)) ) ), - h("div", { className: "bxf-divider" }), - h( + h2("div", { className: "bxf-divider" }), + h2( "div", { className: "bxf-connectedFooter" }, - h( + h2( "div", { className: "bxf-healthSummary", "data-error": actionError || connection.error ? "true" : void 0 }, - h("strong", null, "\u8FDE\u63A5\u72B6\u6001\uFF1A"), - h("span", null, summary) + h2("strong", null, "\u8FDE\u63A5\u72B6\u6001\uFF1A"), + h2("span", null, summary) ), - h( + h2( "div", { className: "bxf-actions bxf-botActions" }, - h(Button, { + h2(Button3, { size: "small", - icon: h(RefreshIcon), + icon: h2(RefreshIcon), onClick: onReconnect, disabled: Boolean(busy), "aria-busy": busy === "reconnect" ? "true" : void 0, "aria-label": `${connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"}${bot.name}` }, busy === "reconnect" ? connected ? "\u68C0\u67E5\u4E2D\u2026" : "\u6B63\u5728\u8FDE\u63A5\u2026" : connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5"), - h(Button, { + h2(Button3, { size: "small", kind: "danger", onClick: onRequestRemove, @@ -1332,7 +2450,7 @@ function BotCard({ ) ) ), - removing ? h(RemoveConfirmation, { + removing ? h2(RemoveConfirmation2, { bot: connection, busy: busy === "delete", onConfirm: onConfirmRemove, @@ -1341,22 +2459,22 @@ function BotCard({ ); } function BotList(props) { - return h( + return h2( "section", { className: "bxf-listSection", "aria-labelledby": "bxf-bot-list-title" }, - h( + h2( "div", { className: "bxf-listHeading" }, - h("h3", { id: "bxf-bot-list-title" }, "\u5DF2\u63A5\u5165\u7684\u673A\u5668\u4EBA"), - h("span", null, `${props.bots.length} \u4E2A`) + h2("h3", { id: "bxf-bot-list-title" }, "\u5DF2\u63A5\u5165\u7684\u673A\u5668\u4EBA"), + h2("span", null, `${props.bots.length} \u4E2A`) ), - h( + h2( "ul", { className: "bxf-botList", role: "list" }, - props.bots.map((bot) => h( + props.bots.map((bot) => h2( "li", { key: bot.botId }, - h(BotCard, { + h2(BotCard, { connection: bot, busy: props.busyByBot[bot.botId], actionError: props.errorsByBot[bot.botId], @@ -1373,25 +2491,25 @@ function BotList(props) { ); } function PageError({ error, onRetry, busy }) { - return h( + return h2( "div", { className: "bxf-card" }, - h( + h2( "div", { className: "bxf-error", role: "alert" }, - h("div", { className: "bxf-errorIcon" }, h(AlertIcon)), - h( + h2("div", { className: "bxf-errorIcon" }, h2(AlertIcon)), + h2( "div", null, - h("h3", null, "\u65E0\u6CD5\u8BFB\u53D6\u98DE\u4E66\u673A\u5668\u4EBA"), - h("p", null, error.message), - error.code ? h("span", { className: "bxf-errorCode" }, error.code) : null, - h( + h2("h3", null, "\u65E0\u6CD5\u8BFB\u53D6\u98DE\u4E66\u673A\u5668\u4EBA"), + h2("p", null, error.message), + error.code ? h2("span", { className: "bxf-errorCode" }, error.code) : null, + h2( "div", { className: "bxf-actions" }, - h( - Button, - { kind: "primary", icon: h(RefreshIcon), onClick: onRetry, disabled: busy }, + h2( + Button3, + { kind: "primary", icon: h2(RefreshIcon), onClick: onRetry, disabled: busy }, busy ? "\u91CD\u8BD5\u4E2D\u2026" : "\u91CD\u65B0\u8BFB\u53D6" ) ) @@ -1399,37 +2517,37 @@ function PageError({ error, onRetry, busy }) { ) ); } -var EMPTY_TOTALS = Object.freeze({ configured: 0, connected: 0 }); +var EMPTY_TOTALS2 = Object.freeze({ configured: 0, connected: 0 }); function FeishuSettingsTab({ rpcCall }) { - const [model, setModel] = React.useState({ + const [model, setModel] = React2.useState({ phase: "loading", revision: 0, bots: [], - totals: EMPTY_TOTALS, + totals: EMPTY_TOTALS2, provisioning: null, pageError: null, statusError: null }); - const [pageBusy, setPageBusy] = React.useState(false); - const [provisionBusy, setProvisionBusy] = React.useState(false); - const [busyByBot, setBusyByBot] = React.useState({}); - const [errorsByBot, setErrorsByBot] = React.useState({}); - const [removeTargetId, setRemoveTargetId] = React.useState(null); - const [announcement, setAnnouncement] = React.useState(""); - const [now, setNow] = React.useState(() => Date.now()); - const [focusBotId, setFocusBotId] = React.useState(null); - const cardRefs = React.useRef(/* @__PURE__ */ new Map()); - const removeButtonRefs = React.useRef(/* @__PURE__ */ new Map()); - const addButtonRef = React.useRef(null); - const announce = React.useCallback((message) => { + const [pageBusy, setPageBusy] = React2.useState(false); + const [provisionBusy, setProvisionBusy] = React2.useState(false); + const [busyByBot, setBusyByBot] = React2.useState({}); + const [errorsByBot, setErrorsByBot] = React2.useState({}); + const [removeTargetId, setRemoveTargetId] = React2.useState(null); + const [announcement, setAnnouncement] = React2.useState(""); + const [now, setNow] = React2.useState(() => Date.now()); + const [focusBotId, setFocusBotId] = React2.useState(null); + const cardRefs = React2.useRef(/* @__PURE__ */ new Map()); + const removeButtonRefs = React2.useRef(/* @__PURE__ */ new Map()); + const addButtonRef = React2.useRef(null); + const announce = React2.useCallback((message) => { setAnnouncement(""); if (!message) return; window.requestAnimationFrame(() => setAnnouncement(message)); }, []); - const invoke = React.useCallback(async (endpoint, payload = {}, signal) => { - return unwrapRpcResult(await rpcCall(endpoint, payload, signal)); + const invoke = React2.useCallback(async (endpoint, payload = {}, signal) => { + return unwrapRpcResult2(await rpcCall(endpoint, payload, signal)); }, [rpcCall]); - const mergeSnapshot = React.useCallback((snapshot, { restoreProvisioning = true } = {}) => { + const mergeSnapshot = React2.useCallback((snapshot, { restoreProvisioning = true } = {}) => { setModel((current) => { if (snapshot.revision > 0 && current.revision > snapshot.revision) return current; let provisioning = current.provisioning; @@ -1453,7 +2571,7 @@ function FeishuSettingsTab({ rpcCall }) { }; }); }, []); - const loadStatus = React.useCallback(async ({ signal, silent = false, restoreProvisioning = true } = {}) => { + const loadStatus = React2.useCallback(async ({ signal, silent = false, restoreProvisioning = true } = {}) => { if (!silent) setPageBusy(true); try { const snapshot = normalizeBotsSnapshot(await invoke(FEISHU_ENDPOINTS.status, {}, signal)); @@ -1461,19 +2579,19 @@ function FeishuSettingsTab({ rpcCall }) { return snapshot; } catch (error) { if (error?.name === "AbortError") return void 0; - const presented = presentError(error); + const presented = presentError2(error); setModel((current) => current.phase === "loading" || !silent ? { ...current, phase: "error", pageError: presented } : { ...current, statusError: presented }); return void 0; } finally { if (!silent) setPageBusy(false); } }, [invoke, mergeSnapshot]); - React.useEffect(() => { + React2.useEffect(() => { const controller = new AbortController(); void loadStatus({ signal: controller.signal }); return () => controller.abort(); }, [loadStatus]); - React.useEffect(() => { + React2.useEffect(() => { if (model.phase !== "ready") return void 0; const controller = new AbortController(); let inFlight = false; @@ -1488,7 +2606,7 @@ function FeishuSettingsTab({ rpcCall }) { window.clearInterval(timer); }; }, [loadStatus, model.phase]); - React.useEffect(() => { + React2.useEffect(() => { if (!focusBotId) return; const node = cardRefs.current.get(focusBotId); if (!node) return; @@ -1496,7 +2614,7 @@ function FeishuSettingsTab({ rpcCall }) { node.focus({ preventScroll: true }); setFocusBotId(null); }, [focusBotId, model.bots]); - const startProvisioning = React.useCallback(async ({ replace = false } = {}) => { + const startProvisioning = React2.useCallback(async ({ replace = false } = {}) => { setProvisionBusy(true); announce(""); const previousAttemptId = model.provisioning?.attemptId; @@ -1509,18 +2627,18 @@ function FeishuSettingsTab({ rpcCall }) { if (replace && previousAttemptId) { await invoke(FEISHU_ENDPOINTS.cancelProvisioning, { attemptId: previousAttemptId }); } - const provision2 = normalizeProvisioning(await invoke( + const provision2 = normalizeProvisioning2(await invoke( FEISHU_ENDPOINTS.beginProvisioning, { locale: "zh-CN" } )); - const timestamp2 = Date.now(); - setNow(timestamp2); + const timestamp3 = Date.now(); + setNow(timestamp3); setModel((current) => ({ ...current, provisioning: { phase: "qr", ...provision2, - durationMs: Math.max(1, provision2.expiresAt - timestamp2), + durationMs: Math.max(1, provision2.expiresAt - timestamp3), expired: false } })); @@ -1528,13 +2646,13 @@ function FeishuSettingsTab({ rpcCall }) { } catch (error) { setModel((current) => ({ ...current, - provisioning: { phase: "error", error: presentError(error) } + provisioning: { phase: "error", error: presentError2(error) } })); } finally { setProvisionBusy(false); } }, [announce, invoke, model.provisioning?.attemptId]); - const cancelProvisioning = React.useCallback(async () => { + const cancelProvisioning = React2.useCallback(async () => { const attemptId = model.provisioning?.attemptId; setProvisionBusy(true); try { @@ -1546,19 +2664,19 @@ function FeishuSettingsTab({ rpcCall }) { } catch (error) { setModel((current) => ({ ...current, - provisioning: { phase: "error", attemptId, error: presentError(error) } + provisioning: { phase: "error", attemptId, error: presentError2(error) } })); } finally { setProvisionBusy(false); } }, [announce, invoke, loadStatus, model.provisioning?.attemptId]); - React.useEffect(() => { + React2.useEffect(() => { const provision2 = model.provisioning; if (!provision2 || provision2.phase !== "qr" || provision2.expired) return void 0; const tick = () => { - const timestamp2 = Date.now(); - setNow(timestamp2); - if (timestamp2 >= provision2.expiresAt) { + const timestamp3 = Date.now(); + setNow(timestamp3); + if (timestamp3 >= provision2.expiresAt) { setModel((current) => current.provisioning?.attemptId === provision2.attemptId ? { ...current, provisioning: { ...current.provisioning, expired: true } } : current); } }; @@ -1566,7 +2684,7 @@ function FeishuSettingsTab({ rpcCall }) { const timer = window.setInterval(tick, 1e3); return () => window.clearInterval(timer); }, [model.provisioning]); - React.useEffect(() => { + React2.useEffect(() => { const provision2 = model.provisioning; if (!provision2 || !["qr", "connecting"].includes(provision2.phase) || !provision2.attemptId || provision2.expired) return void 0; const controller = new AbortController(); @@ -1620,7 +2738,7 @@ function FeishuSettingsTab({ rpcCall }) { provisioning: { phase: "error", attemptId: provision2.attemptId, - error: presentError(error) + error: presentError2(error) } } : current); } @@ -1630,7 +2748,7 @@ function FeishuSettingsTab({ rpcCall }) { window.clearTimeout(timer); }; }, [announce, invoke, loadStatus, model.provisioning]); - const setBotBusy = React.useCallback((botId, value) => { + const setBotBusy = React2.useCallback((botId, value) => { setBusyByBot((current) => { const next = { ...current }; if (value) next[botId] = value; @@ -1638,15 +2756,15 @@ function FeishuSettingsTab({ rpcCall }) { return next; }); }, []); - const setBotError = React.useCallback((botId, error) => { + const setBotError = React2.useCallback((botId, error) => { setErrorsByBot((current) => { const next = { ...current }; - if (error) next[botId] = presentError(error); + if (error) next[botId] = presentError2(error); else delete next[botId]; return next; }); }, []); - const reconnectOneBot = React.useCallback(async (connection) => { + const reconnectOneBot = React2.useCallback(async (connection) => { const { botId, bot } = connection; setBotBusy(botId, "reconnect"); setBotError(botId, null); @@ -1669,15 +2787,15 @@ function FeishuSettingsTab({ rpcCall }) { setBotBusy(botId, null); } }, [announce, invoke, mergeSnapshot, setBotBusy, setBotError]); - const requestRemove = React.useCallback((connection) => { + const requestRemove = React2.useCallback((connection) => { setRemoveTargetId(connection.botId); }, []); - const cancelRemove = React.useCallback(() => { + const cancelRemove = React2.useCallback(() => { const botId = removeTargetId; setRemoveTargetId(null); window.requestAnimationFrame(() => removeButtonRefs.current.get(botId)?.focus()); }, [removeTargetId]); - const confirmRemove = React.useCallback(async (connection) => { + const confirmRemove = React2.useCallback(async (connection) => { const { botId, bot } = connection; setBotBusy(botId, "delete"); setBotError(botId, null); @@ -1708,9 +2826,9 @@ function FeishuSettingsTab({ rpcCall }) { const provision = model.provisioning; let provisionContent = null; if (provision?.phase === "creating") { - provisionContent = h(ProvisionProgress, { phase: "creating", busy: provisionBusy }); + provisionContent = h2(ProvisionProgress, { phase: "creating", busy: provisionBusy }); } else if (provision?.phase === "qr") { - provisionContent = h(QrPane, { + provisionContent = h2(QrPane, { provision, now, onRefresh: () => void startProvisioning({ replace: true }), @@ -1718,60 +2836,60 @@ function FeishuSettingsTab({ rpcCall }) { busy: provisionBusy || model.phase !== "ready" }); } else if (provision?.phase === "connecting") { - provisionContent = h(ProvisionProgress, { + provisionContent = h2(ProvisionProgress, { phase: "connecting", onCancel: () => void cancelProvisioning(), busy: provisionBusy }); } else if (provision?.phase === "error") { - provisionContent = h(ProvisionError, { + provisionContent = h2(ProvisionError2, { error: provision.error, onRetry: () => void startProvisioning({ replace: Boolean(provision.attemptId) }), onCancel: () => void cancelProvisioning(), busy: provisionBusy }); } - const setCardRef = React.useCallback((botId, node) => { + const setCardRef = React2.useCallback((botId, node) => { if (node) cardRefs.current.set(botId, node); else cardRefs.current.delete(botId); }, []); - const setRemoveButtonRef = React.useCallback((botId, node) => { + const setRemoveButtonRef = React2.useCallback((botId, node) => { if (node) removeButtonRefs.current.set(botId, node); else removeButtonRefs.current.delete(botId); }, []); - return h( + return h2( "section", { className: "bxf-page", "aria-label": "\u98DE\u4E66\u673A\u5668\u4EBA\u8BBE\u7F6E" }, - h(Heading, { + h2(Heading2, { totals: model.totals, onAdd: () => void startProvisioning(), adding: Boolean(provision), busy: provisionBusy, addButtonRef }), - h("div", { + h2("div", { className: "bxf-visuallyHidden", role: "status", "aria-live": "polite", "aria-atomic": "true" }, announcement), - model.statusError ? h( + model.statusError ? h2( "div", { className: "bxf-statusNotice", role: "status" }, - h(AlertIcon, { size: 16 }), - h("span", null, `\u72B6\u6001\u81EA\u52A8\u5237\u65B0\u5931\u8D25\uFF1A${model.statusError.message}`), - h(Button, { size: "small", onClick: () => void loadStatus({ silent: true }), disabled: pageBusy }, "\u7ACB\u5373\u91CD\u8BD5") + h2(AlertIcon, { size: 16 }), + h2("span", null, `\u72B6\u6001\u81EA\u52A8\u5237\u65B0\u5931\u8D25\uFF1A${model.statusError.message}`), + h2(Button3, { size: "small", onClick: () => void loadStatus({ silent: true }), disabled: pageBusy }, "\u7ACB\u5373\u91CD\u8BD5") ) : null, - model.phase === "loading" ? h(LoadingView) : model.phase === "error" ? h(PageError, { + model.phase === "loading" ? h2(LoadingView2) : model.phase === "error" ? h2(PageError, { error: model.pageError ?? { message: "\u65E0\u6CD5\u8BFB\u53D6\u8FDE\u63A5\u72B6\u6001" }, onRetry: () => void loadStatus(), busy: pageBusy - }) : h( - React.Fragment, + }) : h2( + React2.Fragment, null, provisionContent, - model.bots.length === 0 && !provision ? h(EmptyView, { onStart: () => void startProvisioning(), busy: provisionBusy }) : null, - model.bots.length > 0 ? h(BotList, { + model.bots.length === 0 && !provision ? h2(EmptyView2, { onStart: () => void startProvisioning(), busy: provisionBusy }) : null, + model.bots.length > 0 ? h2(BotList, { bots: model.bots, busyByBot, errorsByBot, @@ -1788,7 +2906,7 @@ function FeishuSettingsTab({ rpcCall }) { } // plugin-src/client/channels/weixin/index.js -var React2 = __toESM(require("react"), 1); +var React3 = __toESM(require("react"), 1); // plugin-src/client/channels/weixin/api.js var WEIXIN_RPC_CHANNEL = "/weixin"; @@ -1801,8 +2919,8 @@ var WEIXIN_ENDPOINTS = Object.freeze({ reconnectBot: "bot.reconnect", deleteBot: "bot.delete" }); -var ACCOUNT_STATES = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]); -var PROVISION_STATES = /* @__PURE__ */ new Set([ +var ACCOUNT_STATES2 = /* @__PURE__ */ new Set(["connected", "connecting", "offline", "error"]); +var PROVISION_STATES2 = /* @__PURE__ */ new Set([ "starting", "pending", "scanned", @@ -1813,17 +2931,17 @@ var PROVISION_STATES = /* @__PURE__ */ new Set([ "failed", "cancelled" ]); -function isRecord2(value) { +function isRecord3(value) { return value !== null && typeof value === "object" && !Array.isArray(value); } function string(value, fallback = "") { return typeof value === "string" && value.trim() ? value.trim() : fallback; } -function timestamp(value) { +function timestamp2(value) { return typeof value === "number" && Number.isFinite(value) ? value : null; } -function unwrapRpcResult2(result) { - if (!isRecord2(result) || typeof result.ok !== "boolean") { +function unwrapRpcResult3(result) { + if (!isRecord3(result) || typeof result.ok !== "boolean") { throw new Error("\u5FAE\u4FE1\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94"); } if (!result.ok) { @@ -1833,7 +2951,7 @@ function unwrapRpcResult2(result) { } return result.value; } -function safeQrSource2(value) { +function safeQrSource3(value) { return typeof value === "string" && /^data:image\/(?:png|webp|svg\+xml)(?:;charset=[^;,]+)?;base64,/i.test(value) ? value : void 0; } function safeVerificationUrl(value) { @@ -1846,25 +2964,25 @@ function safeVerificationUrl(value) { return void 0; } } -function normalizeProvisioning2(value) { - if (!isRecord2(value) || !string(value.attemptId)) { +function normalizeProvisioning3(value) { + if (!isRecord3(value) || !string(value.attemptId)) { throw new Error("\u5FAE\u4FE1\u626B\u7801\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u7ED1\u5B9A\u4EFB\u52A1"); } - const status = PROVISION_STATES.has(value.status) ? value.status : "failed"; + const status = PROVISION_STATES2.has(value.status) ? value.status : "failed"; const result = { attemptId: string(value.attemptId), status, - expiresAt: timestamp(value.expiresAt) ?? Date.now(), + expiresAt: timestamp2(value.expiresAt) ?? Date.now(), pollIntervalMs: Math.min(5e3, Math.max(500, Number(value.pollIntervalMs) || 1e3)), verificationRequired: value.verificationRequired === true || status === "needs_verification" }; const verificationUrl = safeVerificationUrl(value.verificationUrl); - const qrCodeDataUrl = safeQrSource2(value.qrCodeDataUrl); + const qrCodeDataUrl = safeQrSource3(value.qrCodeDataUrl); if (verificationUrl) result.verificationUrl = verificationUrl; if (qrCodeDataUrl) result.qrCodeDataUrl = qrCodeDataUrl; if (string(value.botId)) result.botId = string(value.botId); if (value.alreadyConnected === true) result.alreadyConnected = true; - if (isRecord2(value.error)) { + if (isRecord3(value.error)) { result.error = { code: string(value.error.code, "WEIXIN_PROVISION_FAILED"), message: string(value.error.message, "\u5FAE\u4FE1\u7ED1\u5B9A\u6CA1\u6709\u5B8C\u6210") @@ -1872,9 +2990,9 @@ function normalizeProvisioning2(value) { } return result; } -function normalizeBot2(value) { - if (!isRecord2(value) || !string(value.botId) || !isRecord2(value.bot)) return null; - const state = ACCOUNT_STATES.has(value.state) ? value.state : "error"; +function normalizeBot3(value) { + if (!isRecord3(value) || !string(value.botId) || !isRecord3(value.bot)) return null; + const state = ACCOUNT_STATES2.has(value.state) ? value.state : "error"; const connected = value.connected === true; return { botId: string(value.botId), @@ -1888,23 +3006,23 @@ function normalizeBot2(value) { health: { status: string(value.health?.status, connected ? "healthy" : "offline"), summary: string(value.health?.summary, connected ? "\u5FAE\u4FE1\u8FDE\u63A5\u6B63\u5E38" : "\u5FAE\u4FE1\u8FDE\u63A5\u672A\u5C31\u7EEA"), - lastCheckedAt: timestamp(value.health?.lastCheckedAt) + lastCheckedAt: timestamp2(value.health?.lastCheckedAt) }, stats: { messagesReceived: Math.max(0, Number(value.stats?.messagesReceived) || 0), messagesReplied: Math.max(0, Number(value.stats?.messagesReplied) || 0) }, - error: isRecord2(value.error) ? { + error: isRecord3(value.error) ? { code: string(value.error.code, "WEIXIN_ACCOUNT_ERROR"), message: string(value.error.message, "\u5FAE\u4FE1\u8FDE\u63A5\u672A\u5C31\u7EEA") } : null }; } -function normalizeSnapshot(value) { - if (!isRecord2(value) || !Array.isArray(value.bots)) { +function normalizeSnapshot2(value) { + if (!isRecord3(value) || !Array.isArray(value.bots)) { throw new Error("\u5FAE\u4FE1\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u7684\u8D26\u53F7\u5217\u8868"); } - const bots = value.bots.map(normalizeBot2).filter(Boolean); + const bots = value.bots.map(normalizeBot3).filter(Boolean); return { schemaVersion: Number(value.schemaVersion) || 1, revision: Number(value.revision) || 0, @@ -1914,23 +3032,23 @@ function normalizeSnapshot(value) { configured: bots.length, connected: bots.filter((bot) => bot.connected).length }, - provisioning: value.provisioning ? normalizeProvisioning2(value.provisioning) : null + provisioning: value.provisioning ? normalizeProvisioning3(value.provisioning) : null }; } -function presentError2(error) { +function presentError3(error) { return { code: string(error?.code, "WEIXIN_ERROR"), message: string(error?.message, "\u5FAE\u4FE1\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5") }; } -function formatRemaining2(milliseconds) { +function formatRemaining3(milliseconds) { const seconds = Math.max(0, Math.ceil(milliseconds / 1e3)); return `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, "0")}`; } // plugin-src/client/channels/weixin/styles.js var WEIXIN_STYLE_ID = "xmanrui-dsh-weixin-settings"; -var CSS2 = String.raw` +var CSS3 = String.raw` .dxw-page { --dxw-accent: #07c160; --dxw-accent-dark: #05994c; @@ -2045,15 +3163,15 @@ function installWeixinStyles() { const style = document.createElement("style"); style.dataset.plugin = "@xmanrui/dsh-weixin"; style.dataset.pluginCss = WEIXIN_STYLE_ID; - style.textContent = CSS2; + style.textContent = CSS3; document.head.appendChild(style); return () => style.remove(); } // plugin-src/client/channels/weixin/index.js -var h2 = React2.createElement; +var h3 = React3.createElement; function WeixinIcon({ size = 26 }) { - return h2( + return h3( "svg", { width: size, @@ -2063,25 +3181,25 @@ function WeixinIcon({ size = 26 }) { xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true" }, - h2("path", { + h3("path", { d: "M9.7 4.2c-4.15 0-7.5 2.72-7.5 6.08 0 1.91 1.08 3.61 2.78 4.72l-.7 2.35 2.75-1.37c.84.25 1.73.38 2.67.38 4.14 0 7.5-2.72 7.5-6.08S13.84 4.2 9.7 4.2Z", fill: "currentColor", opacity: ".96" }), - h2("path", { + h3("path", { d: "M14.4 8.2c4.08 0 7.4 2.66 7.4 5.95 0 1.78-.97 3.38-2.5 4.47l.58 2-2.36-1.18c-.97.43-2.03.65-3.12.65-4.09 0-7.4-2.66-7.4-5.94 0-3.29 3.31-5.95 7.4-5.95Z", fill: "currentColor", stroke: "white", strokeWidth: ".8" }), - h2("circle", { cx: "7.25", cy: "9.5", r: "1", fill: "white" }), - h2("circle", { cx: "11.55", cy: "9.5", r: "1", fill: "white" }), - h2("circle", { cx: "12.1", cy: "13.2", r: ".9", fill: "white" }), - h2("circle", { cx: "16.3", cy: "13.2", r: ".9", fill: "white" }) + h3("circle", { cx: "7.25", cy: "9.5", r: "1", fill: "white" }), + h3("circle", { cx: "11.55", cy: "9.5", r: "1", fill: "white" }), + h3("circle", { cx: "12.1", cy: "13.2", r: ".9", fill: "white" }), + h3("circle", { cx: "16.3", cy: "13.2", r: ".9", fill: "white" }) ); } -var Button3 = React2.forwardRef(function Button4({ children, kind = "secondary", className = "", ...props }, ref) { - return h2("button", { +var Button5 = React3.forwardRef(function Button6({ children, kind = "secondary", className = "", ...props }, ref) { + return h3("button", { ...props, ref, type: "button", @@ -2089,25 +3207,25 @@ var Button3 = React2.forwardRef(function Button4({ children, kind = "secondary", "data-kind": kind }, children); }); -function Heading2({ totals, adding, busy, onAdd, addButtonRef }) { - return h2( +function Heading3({ totals, adding, busy, onAdd, addButtonRef }) { + return h3( "div", { className: "dxw-heading" }, - h2( + h3( "div", { className: "dxw-tools" }, - totals.configured > 0 ? h2( + totals.configured > 0 ? h3( "div", { className: "dxw-badge" }, - h2("span", { className: "dxw-dot", "data-tone": totals.connected > 0 ? "success" : "warning" }), - h2("span", null, `${totals.connected} / ${totals.configured} \u5728\u7EBF`) + h3("span", { className: "dxw-dot", "data-tone": totals.connected > 0 ? "success" : "warning" }), + h3("span", null, `${totals.connected} / ${totals.configured} \u5728\u7EBF`) ) : null, - h2( + h3( "div", { className: "dxw-badge", title: "bot_token \u4EC5\u4FDD\u5B58\u5728 Harness Host \u51ED\u636E\u670D\u52A1\u4E2D" }, - h2("span", null, "\u51ED\u636E\u4EC5\u4FDD\u5B58\u5728\u672C\u673A") + h3("span", null, "\u51ED\u636E\u4EC5\u4FDD\u5B58\u5728\u672C\u673A") ), - h2(Button3, { + h3(Button5, { kind: "primary", onClick: onAdd, disabled: adding || busy, @@ -2116,128 +3234,128 @@ function Heading2({ totals, adding, busy, onAdd, addButtonRef }) { ) ); } -function LoadingView2() { - return h2( +function LoadingView3() { + return h3( "div", { className: "dxw-card dxw-loading", "aria-busy": "true" }, - h2("div", { className: "dxw-spinner" }), - h2("span", null, "\u6B63\u5728\u8BFB\u53D6\u5FAE\u4FE1\u8FDE\u63A5\u72B6\u6001\u2026") + h3("div", { className: "dxw-spinner" }), + h3("span", null, "\u6B63\u5728\u8BFB\u53D6\u5FAE\u4FE1\u8FDE\u63A5\u72B6\u6001\u2026") ); } -function EmptyView2({ onStart, busy }) { - return h2( +function EmptyView3({ onStart, busy }) { + return h3( "div", { className: "dxw-card" }, - h2( + h3( "div", { className: "dxw-cardBody dxw-empty" }, - h2( + h3( "div", null, - h2( + h3( "div", { className: "dxw-stateLabel" }, - h2("span", { className: "dxw-dot" }), - h2("span", null, "\u5C1A\u672A\u7ED1\u5B9A\u5FAE\u4FE1") + h3("span", { className: "dxw-dot" }), + h3("span", null, "\u5C1A\u672A\u7ED1\u5B9A\u5FAE\u4FE1") ), - h2("h3", null, "\u626B\u4E00\u6B21\u7801\uFF0C\u5C31\u80FD\u5728\u5FAE\u4FE1\u91CC\u4F7F\u7528 Harness"), - h2("p", null, "\u4E8C\u7EF4\u7801\u7531\u817E\u8BAF\u5FAE\u4FE1 iLink \u670D\u52A1\u7B7E\u53D1\u3002\u7528\u624B\u673A\u5FAE\u4FE1\u626B\u63CF\u5E76\u786E\u8BA4\u540E\uFF0C\u8D26\u53F7\u51ED\u636E\u4F1A\u76F4\u63A5\u5199\u5165 Harness Host\uFF0C\u6D4F\u89C8\u5668\u4E0D\u4F1A\u6536\u5230 bot_token\u3002"), - h2( + h3("h3", null, "\u626B\u4E00\u6B21\u7801\uFF0C\u5C31\u80FD\u5728\u5FAE\u4FE1\u91CC\u4F7F\u7528 Harness"), + h3("p", null, "\u4E8C\u7EF4\u7801\u7531\u817E\u8BAF\u5FAE\u4FE1 iLink \u670D\u52A1\u7B7E\u53D1\u3002\u7528\u624B\u673A\u5FAE\u4FE1\u626B\u63CF\u5E76\u786E\u8BA4\u540E\uFF0C\u8D26\u53F7\u51ED\u636E\u4F1A\u76F4\u63A5\u5199\u5165 Harness Host\uFF0C\u6D4F\u89C8\u5668\u4E0D\u4F1A\u6536\u5230 bot_token\u3002"), + h3( "div", { className: "dxw-actions" }, - h2( - Button3, + h3( + Button5, { kind: "primary", onClick: onStart, disabled: busy }, busy ? "\u6B63\u5728\u751F\u6210\u4E8C\u7EF4\u7801\u2026" : "\u751F\u6210\u5FAE\u4FE1\u4E8C\u7EF4\u7801" ) ) ), - h2("div", { className: "dxw-logo", "aria-hidden": "true" }, h2(WeixinIcon, { size: 64 })) + h3("div", { className: "dxw-logo", "aria-hidden": "true" }, h3(WeixinIcon, { size: 64 })) ) ); } -function QrPanel({ provision, now, busy, onRefresh, onCancel }) { - const [imageFailed, setImageFailed] = React2.useState(false); - const source = safeQrSource2(provision.qrCodeDataUrl); +function QrPanel2({ provision, now, busy, onRefresh, onCancel }) { + const [imageFailed, setImageFailed] = React3.useState(false); + const source = safeQrSource3(provision.qrCodeDataUrl); const href = safeVerificationUrl(provision.verificationUrl); const remaining = Math.max(0, provision.expiresAt - now); const expired = remaining === 0 || provision.status === "expired"; const duration = Math.max(1, provision.durationMs ?? 5 * 6e4); const progress = Math.round(Math.min(1, remaining / duration) * 100); - React2.useEffect(() => setImageFailed(false), [source]); - return h2( + React3.useEffect(() => setImageFailed(false), [source]); + return h3( "div", { className: "dxw-card" }, - h2( + h3( "div", { className: "dxw-cardBody dxw-qrLayout" }, - h2( + h3( "div", { className: "dxw-qrColumn" }, - h2( + h3( "div", { className: "dxw-qrFrame" }, - source && !imageFailed ? h2("img", { + source && !imageFailed ? h3("img", { src: source, alt: "\u7528\u4E8E\u628A\u5FAE\u4FE1\u673A\u5668\u4EBA\u7ED1\u5B9A\u5230 DeepSeek Harness \u7684\u4E00\u6B21\u6027\u4E8C\u7EF4\u7801", onError: () => setImageFailed(true) - }) : h2("div", { className: "dxw-qrFallback" }, "\u4E8C\u7EF4\u7801\u56FE\u7247\u672A\u5C31\u7EEA\uFF0C\u8BF7\u4F7F\u7528\u5907\u7528\u94FE\u63A5\u3002"), - expired ? h2("div", { className: "dxw-expired" }, "\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F\n\u8BF7\u91CD\u65B0\u751F\u6210") : null + }) : h3("div", { className: "dxw-qrFallback" }, "\u4E8C\u7EF4\u7801\u56FE\u7247\u672A\u5C31\u7EEA\uFF0C\u8BF7\u4F7F\u7528\u5907\u7528\u94FE\u63A5\u3002"), + expired ? h3("div", { className: "dxw-expired" }, "\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F\n\u8BF7\u91CD\u65B0\u751F\u6210") : null ), - h2( + h3( "div", { className: "dxw-countdown" }, - h2("div", null, h2("span", null, "\u4E8C\u7EF4\u7801\u6709\u6548\u65F6\u95F4"), h2("strong", null, formatRemaining2(remaining))), - h2( + h3("div", null, h3("span", null, "\u4E8C\u7EF4\u7801\u6709\u6548\u65F6\u95F4"), h3("strong", null, formatRemaining3(remaining))), + h3( "div", { className: "dxw-progress", "aria-hidden": "true" }, - h2("span", { style: { "--dxw-progress": `${progress}%` } }) + h3("span", { style: { "--dxw-progress": `${progress}%` } }) ) ) ), - h2( + h3( "div", { className: "dxw-qrCopy" }, - h2( + h3( "div", { className: "dxw-stateLabel" }, - h2("span", { className: "dxw-dot", "data-tone": provision.status === "scanned" ? "success" : "warning" }), - h2("span", null, provision.status === "scanned" ? "\u5DF2\u626B\u7801\uFF0C\u8BF7\u5728\u624B\u673A\u4E0A\u786E\u8BA4" : "\u7B49\u5F85\u5FAE\u4FE1\u626B\u7801") + h3("span", { className: "dxw-dot", "data-tone": provision.status === "scanned" ? "success" : "warning" }), + h3("span", null, provision.status === "scanned" ? "\u5DF2\u626B\u7801\uFF0C\u8BF7\u5728\u624B\u673A\u4E0A\u786E\u8BA4" : "\u7B49\u5F85\u5FAE\u4FE1\u626B\u7801") ), - h2("h3", null, expired ? "\u4E8C\u7EF4\u7801\u5DF2\u5931\u6548" : "\u4F7F\u7528\u624B\u673A\u5FAE\u4FE1\u626B\u63CF\u4E8C\u7EF4\u7801"), - h2("p", null, "\u8BF7\u5728\u624B\u673A\u4E0A\u6838\u5BF9\u5E76\u786E\u8BA4\u6388\u6743\u3002\u90E8\u5206\u8D26\u53F7\u4F1A\u989D\u5916\u663E\u793A\u4E00\u4E2A\u914D\u5BF9\u6570\u5B57\uFF0C\u9875\u9762\u4F1A\u5728\u9700\u8981\u65F6\u63D0\u793A\u8F93\u5165\u3002"), - h2( + h3("h3", null, expired ? "\u4E8C\u7EF4\u7801\u5DF2\u5931\u6548" : "\u4F7F\u7528\u624B\u673A\u5FAE\u4FE1\u626B\u63CF\u4E8C\u7EF4\u7801"), + h3("p", null, "\u8BF7\u5728\u624B\u673A\u4E0A\u6838\u5BF9\u5E76\u786E\u8BA4\u6388\u6743\u3002\u90E8\u5206\u8D26\u53F7\u4F1A\u989D\u5916\u663E\u793A\u4E00\u4E2A\u914D\u5BF9\u6570\u5B57\uFF0C\u9875\u9762\u4F1A\u5728\u9700\u8981\u65F6\u63D0\u793A\u8F93\u5165\u3002"), + h3( "ol", { className: "dxw-steps" }, - h2("li", null, "\u6253\u5F00\u624B\u673A\u5FAE\u4FE1\u5E76\u626B\u63CF\u5DE6\u4FA7\u4E8C\u7EF4\u7801"), - h2("li", null, "\u5728\u5FAE\u4FE1\u4E2D\u786E\u8BA4\u8FDE\u63A5\u8BE5\u673A\u5668\u4EBA"), - h2("li", null, "\u4FDD\u6301\u672C\u9875\u6253\u5F00\uFF0C\u7B49\u5F85\u6D88\u606F\u957F\u8F6E\u8BE2\u53D8\u4E3A\u5728\u7EBF") + h3("li", null, "\u6253\u5F00\u624B\u673A\u5FAE\u4FE1\u5E76\u626B\u63CF\u5DE6\u4FA7\u4E8C\u7EF4\u7801"), + h3("li", null, "\u5728\u5FAE\u4FE1\u4E2D\u786E\u8BA4\u8FDE\u63A5\u8BE5\u673A\u5668\u4EBA"), + h3("li", null, "\u4FDD\u6301\u672C\u9875\u6253\u5F00\uFF0C\u7B49\u5F85\u6D88\u606F\u957F\u8F6E\u8BE2\u53D8\u4E3A\u5728\u7EBF") ), - h2( + h3( "div", { className: "dxw-actions" }, - expired ? h2(Button3, { kind: "primary", onClick: onRefresh, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801") : null, - href ? h2("a", { + expired ? h3(Button5, { kind: "primary", onClick: onRefresh, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801") : null, + href ? h3("a", { className: "dxw-button", href, target: "_blank", rel: "noopener noreferrer" }, "\u6253\u5F00\u5907\u7528\u94FE\u63A5") : null, - !expired ? h2(Button3, { onClick: onRefresh, disabled: busy }, "\u6362\u4E00\u4E2A\u4E8C\u7EF4\u7801") : null, - h2(Button3, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88") + !expired ? h3(Button5, { onClick: onRefresh, disabled: busy }, "\u6362\u4E00\u4E2A\u4E8C\u7EF4\u7801") : null, + h3(Button5, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88") ) ) ) ); } function VerificationPanel({ provision, busy, onSubmit, onCancel }) { - const [code, setCode] = React2.useState(""); + const [code, setCode] = React3.useState(""); const valid = /^\d{4,8}$/.test(code); - React2.useEffect(() => setCode(""), [provision.attemptId]); - return h2( + React3.useEffect(() => setCode(""), [provision.attemptId]); + return h3( "div", { className: "dxw-card" }, - h2( + h3( "form", { className: "dxw-verify", @@ -2246,18 +3364,18 @@ function VerificationPanel({ provision, busy, onSubmit, onCancel }) { if (valid && !busy) onSubmit(code); } }, - h2( + h3( "div", { className: "dxw-stateLabel" }, - h2("span", { className: "dxw-dot", "data-tone": "warning" }), - h2("span", null, "\u9700\u8981\u914D\u5BF9\u7801") + h3("span", { className: "dxw-dot", "data-tone": "warning" }), + h3("span", null, "\u9700\u8981\u914D\u5BF9\u7801") ), - h2("h3", null, "\u8F93\u5165\u624B\u673A\u5FAE\u4FE1\u663E\u793A\u7684\u6570\u5B57"), - h2("p", null, "\u8FD9\u662F\u5FAE\u4FE1\u9644\u52A0\u7684\u5B89\u5168\u786E\u8BA4\u6B65\u9AA4\u3002\u914D\u5BF9\u7801\u53EA\u7528\u4E8E\u672C\u6B21\u626B\u7801\u8F6E\u8BE2\uFF0C\u4E0D\u4F1A\u5199\u5165\u914D\u7F6E\u6216\u65E5\u5FD7\u3002"), - h2( + h3("h3", null, "\u8F93\u5165\u624B\u673A\u5FAE\u4FE1\u663E\u793A\u7684\u6570\u5B57"), + h3("p", null, "\u8FD9\u662F\u5FAE\u4FE1\u9644\u52A0\u7684\u5B89\u5168\u786E\u8BA4\u6B65\u9AA4\u3002\u914D\u5BF9\u7801\u53EA\u7528\u4E8E\u672C\u6B21\u626B\u7801\u8F6E\u8BE2\uFF0C\u4E0D\u4F1A\u5199\u5165\u914D\u7F6E\u6216\u65E5\u5FD7\u3002"), + h3( "div", { className: "dxw-codeRow" }, - h2("input", { + h3("input", { className: "dxw-input", value: code, inputMode: "numeric", @@ -2267,137 +3385,137 @@ function VerificationPanel({ provision, busy, onSubmit, onCancel }) { onChange: (event) => setCode(event.target.value.replace(/\D/g, "").slice(0, 8)), autoFocus: true }), - h2("button", { + h3("button", { type: "submit", className: "dxw-button", "data-kind": "primary", disabled: !valid || busy }, busy ? "\u6B63\u5728\u9A8C\u8BC1\u2026" : "\u7EE7\u7EED\u8FDE\u63A5") ), - h2(Button3, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88\u7ED1\u5B9A") + h3(Button5, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88\u7ED1\u5B9A") ) ); } -function ProgressPanel({ scanned, onCancel, busy }) { - return h2( +function ProgressPanel2({ scanned, onCancel, busy }) { + return h3( "div", { className: "dxw-card dxw-loading", "aria-busy": "true" }, - h2("div", { className: "dxw-spinner" }), - h2("h3", null, scanned ? "\u5FAE\u4FE1\u5DF2\u786E\u8BA4\uFF0C\u6B63\u5728\u542F\u52A8\u6D88\u606F\u8FDE\u63A5" : "\u6B63\u5728\u51C6\u5907\u5FAE\u4FE1\u4E8C\u7EF4\u7801"), - h2("p", null, scanned ? "\u6B63\u5728\u4FDD\u5B58\u51ED\u636E\u5E76\u9A8C\u8BC1 Harness \u4E0E\u5FAE\u4FE1\u957F\u8F6E\u8BE2\u3002" : "\u6B63\u5728\u8054\u7CFB\u817E\u8BAF\u5FAE\u4FE1 iLink \u670D\u52A1\u3002"), - onCancel ? h2( + h3("div", { className: "dxw-spinner" }), + h3("h3", null, scanned ? "\u5FAE\u4FE1\u5DF2\u786E\u8BA4\uFF0C\u6B63\u5728\u542F\u52A8\u6D88\u606F\u8FDE\u63A5" : "\u6B63\u5728\u51C6\u5907\u5FAE\u4FE1\u4E8C\u7EF4\u7801"), + h3("p", null, scanned ? "\u6B63\u5728\u4FDD\u5B58\u51ED\u636E\u5E76\u9A8C\u8BC1 Harness \u4E0E\u5FAE\u4FE1\u957F\u8F6E\u8BE2\u3002" : "\u6B63\u5728\u8054\u7CFB\u817E\u8BAF\u5FAE\u4FE1 iLink \u670D\u52A1\u3002"), + onCancel ? h3( "div", { className: "dxw-actions", style: { justifyContent: "center", marginTop: 14 } }, - h2(Button3, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88") + h3(Button5, { onClick: onCancel, disabled: busy }, "\u53D6\u6D88") ) : null ); } -function ProvisionError2({ provision, busy, onRetry, onClose }) { +function ProvisionError3({ provision, busy, onRetry, onClose }) { const error = provision.error ?? { code: "WEIXIN_PROVISION_FAILED", message: "\u5FAE\u4FE1\u7ED1\u5B9A\u6CA1\u6709\u5B8C\u6210" }; - return h2( + return h3( "div", { className: "dxw-card" }, - h2( + h3( "div", { className: "dxw-error", role: "alert" }, - h2("h3", null, provision.status === "expired" ? "\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F" : "\u5FAE\u4FE1\u6CA1\u6709\u7ED1\u5B9A\u5B8C\u6210"), - h2("p", null, error.message), - h2("span", { className: "dxw-errorCode" }, error.code), - h2( + h3("h3", null, provision.status === "expired" ? "\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F" : "\u5FAE\u4FE1\u6CA1\u6709\u7ED1\u5B9A\u5B8C\u6210"), + h3("p", null, error.message), + h3("span", { className: "dxw-errorCode" }, error.code), + h3( "div", { className: "dxw-actions" }, - h2(Button3, { kind: "primary", onClick: onRetry, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"), - h2(Button3, { onClick: onClose, disabled: busy }, "\u5173\u95ED") + h3(Button5, { kind: "primary", onClick: onRetry, disabled: busy }, "\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801"), + h3(Button5, { onClick: onClose, disabled: busy }, "\u5173\u95ED") ) ) ); } -function checkedTime(timestamp2) { - if (!timestamp2) return "\u5C1A\u672A\u68C0\u67E5"; +function checkedTime2(timestamp3) { + if (!timestamp3) return "\u5C1A\u672A\u68C0\u67E5"; try { return new Intl.DateTimeFormat("zh-CN", { hour: "2-digit", minute: "2-digit", second: "2-digit" - }).format(new Date(timestamp2)); + }).format(new Date(timestamp3)); } catch { return "\u521A\u521A"; } } -function AccountCard({ account, busy, removing, onReconnect, onRequestRemove, onConfirmRemove, onCancelRemove }) { +function AccountCard2({ account, busy, removing, onReconnect, onRequestRemove, onConfirmRemove, onCancelRemove }) { const state = busy === "reconnect" ? "connecting" : account.state; const tone = account.connected ? "success" : state === "error" ? "error" : "warning"; - return h2( + return h3( "article", { className: "dxw-card", tabIndex: -1, "data-bot-id": account.botId }, - h2( + h3( "div", { className: "dxw-cardBody" }, - h2( + h3( "div", { className: "dxw-accountTop" }, - h2( + h3( "div", { className: "dxw-accountIdentity" }, - h2("div", { className: "dxw-avatar", "aria-hidden": "true" }, h2(WeixinIcon, { size: 27 })), - h2("div", null, h2("h3", null, account.bot.name), h2("p", null, account.bot.accountIdMasked)) + h3("div", { className: "dxw-avatar", "aria-hidden": "true" }, h3(WeixinIcon, { size: 27 })), + h3("div", null, h3("h3", null, account.bot.name), h3("p", null, account.bot.accountIdMasked)) ), - h2( + h3( "div", { className: "dxw-health" }, - h2("span", { className: "dxw-dot", "data-tone": tone }), - h2("span", null, account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA") + h3("span", { className: "dxw-dot", "data-tone": tone }), + h3("span", null, account.connected ? "\u8FD0\u884C\u6B63\u5E38" : state === "connecting" ? "\u6B63\u5728\u8FDE\u63A5" : "\u8FDE\u63A5\u672A\u5C31\u7EEA") ) ), - h2( + h3( "dl", { className: "dxw-metrics" }, - h2( + h3( "div", { className: "dxw-metric" }, - h2("dt", null, "\u6D88\u606F\u901A\u9053"), - h2("dd", null, account.connected ? "iLink \u957F\u8F6E\u8BE2" : "\u79BB\u7EBF") + h3("dt", null, "\u6D88\u606F\u901A\u9053"), + h3("dd", null, account.connected ? "iLink \u957F\u8F6E\u8BE2" : "\u79BB\u7EBF") ), - h2( + h3( "div", { className: "dxw-metric" }, - h2("dt", null, "\u6536\u5230 / \u56DE\u590D"), - h2("dd", null, `${account.stats.messagesReceived} / ${account.stats.messagesReplied}`) + h3("dt", null, "\u6536\u5230 / \u56DE\u590D"), + h3("dd", null, `${account.stats.messagesReceived} / ${account.stats.messagesReplied}`) ), - h2( + h3( "div", { className: "dxw-metric" }, - h2("dt", null, "\u6700\u8FD1\u68C0\u67E5"), - h2("dd", null, checkedTime(account.health.lastCheckedAt)) + h3("dt", null, "\u6700\u8FD1\u68C0\u67E5"), + h3("dd", null, checkedTime2(account.health.lastCheckedAt)) ) ), - h2( + h3( "div", { className: "dxw-accountFooter" }, - h2("div", { className: "dxw-summary" }, account.error?.message ?? account.health.summary), - h2( + h3("div", { className: "dxw-summary" }, account.error?.message ?? account.health.summary), + h3( "div", { className: "dxw-actions" }, - h2( - Button3, + h3( + Button5, { onClick: onReconnect, disabled: Boolean(busy) }, busy === "reconnect" ? "\u68C0\u67E5\u4E2D\u2026" : account.connected ? "\u68C0\u67E5\u8FDE\u63A5" : "\u91CD\u8BD5\u8FDE\u63A5" ), - h2(Button3, { kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165") + h3(Button5, { kind: "danger", onClick: onRequestRemove, disabled: Boolean(busy) }, "\u79FB\u9664\u63A5\u5165") ) ) ), - removing ? h2( + removing ? h3( "div", { className: "dxw-confirm", role: "alertdialog" }, - h2("strong", null, "\u4ECE\u6B64 Harness \u79FB\u9664\u8FD9\u4E2A\u5FAE\u4FE1\u8D26\u53F7\uFF1F"), - h2("p", null, "\u8FD9\u4F1A\u505C\u6B62\u6D88\u606F\u8FDE\u63A5\uFF0C\u5E76\u5220\u9664\u672C\u673A\u4FDD\u5B58\u7684 bot_token\u3001\u8D26\u53F7\u914D\u7F6E\u548C\u4F1A\u8BDD\u6620\u5C04\u3002\u5176\u4ED6\u5FAE\u4FE1\u8D26\u53F7\u4E0D\u53D7\u5F71\u54CD\u3002"), - h2( + h3("strong", null, "\u4ECE\u6B64 Harness \u79FB\u9664\u8FD9\u4E2A\u5FAE\u4FE1\u8D26\u53F7\uFF1F"), + h3("p", null, "\u8FD9\u4F1A\u505C\u6B62\u6D88\u606F\u8FDE\u63A5\uFF0C\u5E76\u5220\u9664\u672C\u673A\u4FDD\u5B58\u7684 bot_token\u3001\u8D26\u53F7\u914D\u7F6E\u548C\u4F1A\u8BDD\u6620\u5C04\u3002\u5176\u4ED6\u5FAE\u4FE1\u8D26\u53F7\u4E0D\u53D7\u5F71\u54CD\u3002"), + h3( "div", { className: "dxw-actions" }, - h2(Button3, { onClick: onCancelRemove, disabled: busy === "delete" }, "\u4FDD\u7559\u8D26\u53F7"), - h2( - Button3, + h3(Button5, { onClick: onCancelRemove, disabled: busy === "delete" }, "\u4FDD\u7559\u8D26\u53F7"), + h3( + Button5, { kind: "danger", onClick: onConfirmRemove, disabled: busy === "delete" }, busy === "delete" ? "\u6B63\u5728\u79FB\u9664\u2026" : "\u786E\u8BA4\u79FB\u9664" ) @@ -2405,15 +3523,15 @@ function AccountCard({ account, busy, removing, onReconnect, onRequestRemove, on ) : null ); } -function AccountList(props) { - return h2( +function AccountList2(props) { + return h3( "section", null, - h2("div", { className: "dxw-listHeading" }, h2("h3", null, "\u5DF2\u63A5\u5165\u7684\u5FAE\u4FE1\u8D26\u53F7"), h2("span", null, `${props.bots.length} \u4E2A`)), - h2("ul", { className: "dxw-list" }, props.bots.map((account) => h2( + h3("div", { className: "dxw-listHeading" }, h3("h3", null, "\u5DF2\u63A5\u5165\u7684\u5FAE\u4FE1\u8D26\u53F7"), h3("span", null, `${props.bots.length} \u4E2A`)), + h3("ul", { className: "dxw-list" }, props.bots.map((account) => h3( "li", { key: account.botId }, - h2(AccountCard, { + h3(AccountCard2, { account, busy: props.busyByBot[account.botId], removing: props.removeTarget === account.botId, @@ -2425,33 +3543,33 @@ function AccountList(props) { ))) ); } -var EMPTY_TOTALS2 = Object.freeze({ configured: 0, connected: 0 }); +var EMPTY_TOTALS3 = Object.freeze({ configured: 0, connected: 0 }); function WeixinSettingsTab({ rpcCall }) { - const [model, setModel] = React2.useState({ + const [model, setModel] = React3.useState({ phase: "loading", bots: [], - totals: EMPTY_TOTALS2, + totals: EMPTY_TOTALS3, revision: 0, error: null }); - const [provision, setProvision] = React2.useState(null); - const [busy, setBusy] = React2.useState(false); - const [busyByBot, setBusyByBot] = React2.useState({}); - const [removeTarget, setRemoveTarget] = React2.useState(null); - const [notice, setNotice] = React2.useState(""); - const [now, setNow] = React2.useState(() => Date.now()); - const addButtonRef = React2.useRef(null); - const announce = React2.useCallback((value) => { + const [provision, setProvision] = React3.useState(null); + const [busy, setBusy] = React3.useState(false); + const [busyByBot, setBusyByBot] = React3.useState({}); + const [removeTarget, setRemoveTarget] = React3.useState(null); + const [notice, setNotice] = React3.useState(""); + const [now, setNow] = React3.useState(() => Date.now()); + const addButtonRef = React3.useRef(null); + const announce = React3.useCallback((value) => { setNotice(""); if (value) window.requestAnimationFrame(() => setNotice(value)); }, []); - const invoke = React2.useCallback(async (endpoint, payload = {}, signal) => { - return unwrapRpcResult2(await rpcCall(endpoint, payload, signal)); + const invoke = React3.useCallback(async (endpoint, payload = {}, signal) => { + return unwrapRpcResult3(await rpcCall(endpoint, payload, signal)); }, [rpcCall]); - const loadStatus = React2.useCallback(async ({ signal, silent = false } = {}) => { + const loadStatus = React3.useCallback(async ({ signal, silent = false } = {}) => { if (!silent) setModel((current) => ({ ...current, phase: "loading", error: null })); try { - const snapshot = normalizeSnapshot(await invoke(WEIXIN_ENDPOINTS.status, {}, signal)); + const snapshot = normalizeSnapshot2(await invoke(WEIXIN_ENDPOINTS.status, {}, signal)); setModel({ phase: "ready", bots: snapshot.bots, @@ -2468,17 +3586,17 @@ function WeixinSettingsTab({ rpcCall }) { setModel((current) => ({ ...current, phase: silent && current.phase === "ready" ? "ready" : "error", - error: presentError2(error) + error: presentError3(error) })); return void 0; } }, [invoke]); - React2.useEffect(() => { + React3.useEffect(() => { const controller = new AbortController(); void loadStatus({ signal: controller.signal }); return () => controller.abort(); }, [loadStatus]); - React2.useEffect(() => { + React3.useEffect(() => { if (model.phase !== "ready") return void 0; const controller = new AbortController(); let running = false; @@ -2493,33 +3611,33 @@ function WeixinSettingsTab({ rpcCall }) { window.clearInterval(timer); }; }, [loadStatus, model.phase]); - React2.useEffect(() => { + React3.useEffect(() => { if (!provision || !["pending", "scanned"].includes(provision.status)) return void 0; const timer = window.setInterval(() => setNow(Date.now()), 1e3); return () => window.clearInterval(timer); }, [provision?.attemptId, provision?.status]); - const startProvisioning = React2.useCallback(async ({ replace = false } = {}) => { + const startProvisioning = React3.useCallback(async ({ replace = false } = {}) => { setBusy(true); try { if (replace && provision?.attemptId) { await invoke(WEIXIN_ENDPOINTS.cancelProvisioning, { attemptId: provision.attemptId }); } setProvision({ status: "starting" }); - const started = normalizeProvisioning2(await invoke(WEIXIN_ENDPOINTS.beginProvisioning, { locale: "zh-CN" })); + const started = normalizeProvisioning3(await invoke(WEIXIN_ENDPOINTS.beginProvisioning, { locale: "zh-CN" })); setNow(Date.now()); setProvision({ ...started, durationMs: Math.max(1, started.expiresAt - Date.now()) }); announce("\u5FAE\u4FE1\u4E8C\u7EF4\u7801\u5DF2\u751F\u6210\uFF0C\u8BF7\u4F7F\u7528\u624B\u673A\u5FAE\u4FE1\u626B\u63CF\u3002"); } catch (error) { setProvision({ status: "failed", - error: presentError2(error), + error: presentError3(error), ...provision?.attemptId ? { attemptId: provision.attemptId } : {} }); } finally { setBusy(false); } }, [announce, invoke, provision?.attemptId]); - const cancelProvisioning = React2.useCallback(async () => { + const cancelProvisioning = React3.useCallback(async () => { setBusy(true); try { if (provision?.attemptId && !["failed", "expired", "cancelled"].includes(provision.status)) { @@ -2529,35 +3647,35 @@ function WeixinSettingsTab({ rpcCall }) { announce("\u5DF2\u53D6\u6D88\u5FAE\u4FE1\u7ED1\u5B9A\u3002"); window.requestAnimationFrame(() => addButtonRef.current?.focus()); } catch (error) { - setProvision((current) => ({ ...current, status: "failed", error: presentError2(error) })); + setProvision((current) => ({ ...current, status: "failed", error: presentError3(error) })); } finally { setBusy(false); } }, [announce, invoke, provision?.attemptId, provision?.status]); - const submitVerification = React2.useCallback(async (verifyCode) => { + const submitVerification = React3.useCallback(async (verifyCode) => { if (!provision?.attemptId) return; setBusy(true); try { - const next = normalizeProvisioning2(await invoke(WEIXIN_ENDPOINTS.submitVerification, { + const next = normalizeProvisioning3(await invoke(WEIXIN_ENDPOINTS.submitVerification, { attemptId: provision.attemptId, verifyCode })); setProvision((current) => ({ ...current, ...next })); announce("\u914D\u5BF9\u7801\u5DF2\u63D0\u4EA4\uFF0C\u6B63\u5728\u7B49\u5F85\u5FAE\u4FE1\u786E\u8BA4\u3002"); } catch (error) { - setProvision((current) => ({ ...current, status: "failed", error: presentError2(error) })); + setProvision((current) => ({ ...current, status: "failed", error: presentError3(error) })); } finally { setBusy(false); } }, [announce, invoke, provision?.attemptId]); - React2.useEffect(() => { + React3.useEffect(() => { const attemptId = provision?.attemptId; if (!attemptId || !["pending", "scanned", "connecting"].includes(provision.status)) return void 0; const controller = new AbortController(); let timer; const poll = async () => { try { - const result = normalizeProvisioning2(await invoke( + const result = normalizeProvisioning3(await invoke( WEIXIN_ENDPOINTS.pollProvisioning, { attemptId }, controller.signal @@ -2580,7 +3698,7 @@ function WeixinSettingsTab({ rpcCall }) { } } catch (error) { if (error?.name === "AbortError") return; - setProvision((current) => current?.attemptId === attemptId ? { ...current, status: "failed", error: presentError2(error) } : current); + setProvision((current) => current?.attemptId === attemptId ? { ...current, status: "failed", error: presentError3(error) } : current); } }; timer = window.setTimeout(poll, provision.pollIntervalMs ?? 1e3); @@ -2589,7 +3707,7 @@ function WeixinSettingsTab({ rpcCall }) { window.clearTimeout(timer); }; }, [announce, invoke, loadStatus, provision?.attemptId, provision?.status, provision?.pollIntervalMs]); - const setBotBusy = React2.useCallback((botId, value) => { + const setBotBusy = React3.useCallback((botId, value) => { setBusyByBot((current) => { const next = { ...current }; if (value) next[botId] = value; @@ -2597,23 +3715,23 @@ function WeixinSettingsTab({ rpcCall }) { return next; }); }, []); - const reconnect = React2.useCallback(async (account) => { + const reconnect = React3.useCallback(async (account) => { setBotBusy(account.botId, "reconnect"); try { - const snapshot = normalizeSnapshot(await invoke(WEIXIN_ENDPOINTS.reconnectBot, { botId: account.botId })); + const snapshot = normalizeSnapshot2(await invoke(WEIXIN_ENDPOINTS.reconnectBot, { botId: account.botId })); setModel((current) => ({ ...current, bots: snapshot.bots, totals: snapshot.totals, revision: snapshot.revision })); const refreshed = snapshot.bots.find((bot) => bot.botId === account.botId); announce(refreshed?.connected ? "\u5FAE\u4FE1\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\u3002" : "\u5FAE\u4FE1\u4ECD\u672A\u8FDE\u63A5\uFF0C\u63D2\u4EF6\u4F1A\u7EE7\u7EED\u81EA\u52A8\u91CD\u8BD5\u3002"); } catch (error) { - announce(`\u8FDE\u63A5\u68C0\u67E5\u5931\u8D25\uFF1A${presentError2(error).message}`); + announce(`\u8FDE\u63A5\u68C0\u67E5\u5931\u8D25\uFF1A${presentError3(error).message}`); } finally { setBotBusy(account.botId, null); } }, [announce, invoke, setBotBusy]); - const remove = React2.useCallback(async (account) => { + const remove = React3.useCallback(async (account) => { setBotBusy(account.botId, "delete"); try { - const snapshot = normalizeSnapshot(await invoke(WEIXIN_ENDPOINTS.deleteBot, { + const snapshot = normalizeSnapshot2(await invoke(WEIXIN_ENDPOINTS.deleteBot, { botId: account.botId, confirm: true })); @@ -2621,16 +3739,16 @@ function WeixinSettingsTab({ rpcCall }) { setRemoveTarget(null); announce("\u5FAE\u4FE1\u8D26\u53F7\u53CA\u672C\u673A\u51ED\u636E\u5DF2\u79FB\u9664\u3002"); } catch (error) { - announce(`\u79FB\u9664\u5931\u8D25\uFF1A${presentError2(error).message}`); + announce(`\u79FB\u9664\u5931\u8D25\uFF1A${presentError3(error).message}`); } finally { setBotBusy(account.botId, null); } }, [announce, invoke, setBotBusy]); let provisionView = null; if (provision?.status === "starting") { - provisionView = h2(ProgressPanel, { busy }); + provisionView = h3(ProgressPanel2, { busy }); } else if (["pending", "scanned"].includes(provision?.status)) { - provisionView = h2(QrPanel, { + provisionView = h3(QrPanel2, { provision, now, busy, @@ -2638,54 +3756,54 @@ function WeixinSettingsTab({ rpcCall }) { onCancel: () => void cancelProvisioning() }); } else if (provision?.status === "needs_verification") { - provisionView = h2(VerificationPanel, { + provisionView = h3(VerificationPanel, { provision, busy, onSubmit: (code) => void submitVerification(code), onCancel: () => void cancelProvisioning() }); } else if (provision?.status === "connecting") { - provisionView = h2(ProgressPanel, { + provisionView = h3(ProgressPanel2, { scanned: true, busy, onCancel: () => void cancelProvisioning() }); } else if (provision && ["failed", "expired", "cancelled"].includes(provision.status)) { - provisionView = h2(ProvisionError2, { + provisionView = h3(ProvisionError3, { provision, busy, onRetry: () => void startProvisioning({ replace: Boolean(provision.attemptId) }), onClose: () => void cancelProvisioning() }); } - return h2( + return h3( "section", { className: "dxw-page", "aria-label": "\u5FAE\u4FE1\u8BBE\u7F6E" }, - h2(Heading2, { + h3(Heading3, { totals: model.totals, adding: Boolean(provision), busy, onAdd: () => void startProvisioning(), addButtonRef }), - h2("div", { className: "dxw-visuallyHidden", role: "status", "aria-live": "polite" }, notice), - model.error && model.phase === "ready" ? h2("div", { className: "dxw-statusNotice" }, `\u72B6\u6001\u5237\u65B0\u5931\u8D25\uFF1A${model.error.message}`) : null, - model.phase === "loading" ? h2(LoadingView2) : model.phase === "error" ? h2( + h3("div", { className: "dxw-visuallyHidden", role: "status", "aria-live": "polite" }, notice), + model.error && model.phase === "ready" ? h3("div", { className: "dxw-statusNotice" }, `\u72B6\u6001\u5237\u65B0\u5931\u8D25\uFF1A${model.error.message}`) : null, + model.phase === "loading" ? h3(LoadingView3) : model.phase === "error" ? h3( "div", { className: "dxw-card" }, - h2( + h3( "div", { className: "dxw-error" }, - h2("h3", null, "\u65E0\u6CD5\u8BFB\u53D6\u5FAE\u4FE1\u72B6\u6001"), - h2("p", null, model.error?.message ?? "\u8BF7\u7A0D\u540E\u91CD\u8BD5"), - h2(Button3, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6") + h3("h3", null, "\u65E0\u6CD5\u8BFB\u53D6\u5FAE\u4FE1\u72B6\u6001"), + h3("p", null, model.error?.message ?? "\u8BF7\u7A0D\u540E\u91CD\u8BD5"), + h3(Button5, { onClick: () => void loadStatus() }, "\u91CD\u65B0\u8BFB\u53D6") ) - ) : h2( - React2.Fragment, + ) : h3( + React3.Fragment, null, provisionView, - model.bots.length === 0 && !provision ? h2(EmptyView2, { onStart: () => void startProvisioning(), busy }) : null, - model.bots.length > 0 ? h2(AccountList, { + model.bots.length === 0 && !provision ? h3(EmptyView3, { onStart: () => void startProvisioning(), busy }) : null, + model.bots.length > 0 ? h3(AccountList2, { bots: model.bots, busyByBot, removeTarget, @@ -2700,7 +3818,7 @@ function WeixinSettingsTab({ rpcCall }) { // plugin-src/client/styles.js var IM_STYLE_ID = "xmanrui-dsh-im-settings"; -var CSS3 = String.raw` +var CSS4 = String.raw` .dim-page { --dim-blue: #3370ff; --dim-blue-soft: color-mix(in srgb, var(--dim-blue) 9%, transparent); @@ -2728,13 +3846,16 @@ var CSS3 = String.raw` .dim-logoWeixin svg { width: 19px; height: 19px; } .dim-logoFeishu { background: white; border: 1px solid var(--dsw-alias-line-border, #e5e6eb); } .dim-logoFeishu svg { width: 22px; height: 22px; } +.dim-logoDingtalk { color: white; background: #1677ff; } +.dim-logoDingtalk svg { width: 24px; height: 24px; } .dim-channelCopy { min-width: 0; display: block; } .dim-channelCopy strong { overflow: hidden; color: inherit; font-size: 14px; line-height: 20px; font-weight: 680; text-overflow: ellipsis; white-space: nowrap; } .dim-divider { width: 1px; min-height: 520px; background: var(--dsw-alias-line-divider, #eef0f3); } .dim-panel { min-width: 0; } -.dim-panel .bxf-page, .dim-panel .dxw-page { width: 100%; max-width: none; padding: 0 0 24px; } -.dim-panel .bxf-heading, .dim-panel .dxw-heading { justify-content: flex-end; } -.dim-panel .bxf-headingTools, .dim-panel .dxw-tools { width: 100%; justify-content: flex-end; } +.dim-panel .bxf-page, .dim-panel .dxw-page, .dim-panel .ddt-page { width: 100%; max-width: none; padding: 0 0 24px; } +.dim-panel .bxf-heading, .dim-panel .dxw-heading, .dim-panel .ddt-heading { justify-content: flex-end; } +.dim-panel .bxf-headingTools, .dim-panel .dxw-tools, .dim-panel .ddt-tools { width: 100%; justify-content: flex-end; } +.dim-panel .ddt-headingCopy { display: none; } @media (max-width: 840px) { .dim-title { align-items: flex-start; } .dim-layout { grid-template-columns: minmax(0, 1fr); gap: 18px; } @@ -2761,27 +3882,28 @@ function installImStyles() { const style = document.createElement("style"); style.dataset.plugin = "@xmanrui/dsh-im"; style.dataset.pluginCss = IM_STYLE_ID; - style.textContent = CSS3; + style.textContent = CSS4; document.head.appendChild(style); return () => style.remove(); } // plugin-src/client/index.js -var h3 = React3.createElement; +var h4 = React4.createElement; var name = "im-settings"; var inject = ["slots", "connection"]; var CHANNELS = Object.freeze([ { id: "weixin", label: "\u5FAE\u4FE1" }, - { id: "feishu", label: "\u98DE\u4E66" } + { id: "feishu", label: "\u98DE\u4E66" }, + { id: "dingtalk", label: "\u9489\u9489" } ]); function WeixinLogo() { - return h3( + return h4( "span", { className: "dim-logo dim-logoWeixin", "aria-hidden": "true" }, - h3( + h4( "svg", { viewBox: "0 0 24 24", focusable: "false" }, - h3("path", { + h4("path", { fill: "currentColor", d: "M8.691 2.188C3.891 2.188 0 5.476 0 9.53c0 2.212 1.17 4.203 3.002 5.55a.59.59 0 0 1 .213.665l-.39 1.48c-.019.07-.048.141-.048.213 0 .163.13.295.29.295a.326.326 0 0 0 .167-.054l1.903-1.114a.864.864 0 0 1 .717-.098 10.16 10.16 0 0 0 2.837.403c.276 0 .543-.027.811-.05-.857-2.578.157-4.972 1.932-6.446 1.703-1.415 3.882-1.98 5.853-1.838-.576-3.583-4.196-6.348-8.596-6.348zM5.785 5.991c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 0 1-1.162 1.178A1.17 1.17 0 0 1 4.623 7.17c0-.651.52-1.18 1.162-1.18zm5.813 0c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 0 1-1.162 1.178 1.17 1.17 0 0 1-1.162-1.178c0-.651.52-1.18 1.162-1.18zm5.34 2.867c-1.797-.052-3.746.512-5.28 1.786-1.72 1.428-2.687 3.72-1.78 6.22.942 2.453 3.666 4.229 6.884 4.229.826 0 1.622-.12 2.361-.336a.722.722 0 0 1 .598.082l1.584.926a.272.272 0 0 0 .14.047c.134 0 .24-.111.24-.247 0-.06-.023-.12-.038-.177l-.327-1.233a.582.582 0 0 1-.023-.156.49.49 0 0 1 .201-.398C23.024 18.48 24 16.82 24 14.98c0-3.21-2.931-5.837-6.656-6.088V8.89c-.135-.01-.27-.027-.407-.03zm-2.53 3.274c.535 0 .969.44.969.982a.976.976 0 0 1-.969.983.976.976 0 0 1-.969-.983c0-.542.434-.982.97-.982zm4.844 0c.535 0 .969.44.969.982a.976.976 0 0 1-.969.983.976.976 0 0 1-.969-.983c0-.542.434-.982.969-.982z" }) @@ -2789,40 +3911,56 @@ function WeixinLogo() { ); } function FeishuLogo() { - return h3( + return h4( "span", { className: "dim-logo dim-logoFeishu", "aria-hidden": "true" }, - h3( + h4( "svg", { viewBox: "0 0 24 24", focusable: "false" }, - h3("path", { fill: "#00D6B9", d: "M7.2 4.5h7.6c1.2 0 2.1.55 2.7 1.58 1.05 1.8 1.55 3.45 1.58 4.95-2.04-.62-4.2-.15-6.22 1.45C11.3 9.7 9.42 7.04 7.2 4.5Z" }), - h3("path", { fill: "#1456B8", d: "M10.8 13.55c3.3-2.93 5.72-4.24 9.47-2.52-1.2 1.45-2.27 4.18-3.86 5.43-1.67 1.31-3.9.5-5.61-.64v-2.27Z" }), - h3("path", { fill: "#3370FF", d: "M4.4 8.35c3.47 3.61 7.25 6.1 10.33 5.7 1.06-.14 2.2-.72 3.4-1.72-1.04 2.65-2.6 4.8-5.06 6-2.46 1.2-5.56.52-7.42-.72A2.76 2.76 0 0 1 4.4 15.3V8.35Z" }) + h4("path", { fill: "#00D6B9", d: "M7.2 4.5h7.6c1.2 0 2.1.55 2.7 1.58 1.05 1.8 1.55 3.45 1.58 4.95-2.04-.62-4.2-.15-6.22 1.45C11.3 9.7 9.42 7.04 7.2 4.5Z" }), + h4("path", { fill: "#1456B8", d: "M10.8 13.55c3.3-2.93 5.72-4.24 9.47-2.52-1.2 1.45-2.27 4.18-3.86 5.43-1.67 1.31-3.9.5-5.61-.64v-2.27Z" }), + h4("path", { fill: "#3370FF", d: "M4.4 8.35c3.47 3.61 7.25 6.1 10.33 5.7 1.06-.14 2.2-.72 3.4-1.72-1.04 2.65-2.6 4.8-5.06 6-2.46 1.2-5.56.52-7.42-.72A2.76 2.76 0 0 1 4.4 15.3V8.35Z" }) + ) + ); +} +function DingtalkLogo() { + return h4( + "span", + { className: "dim-logo dim-logoDingtalk", "aria-hidden": "true" }, + h4( + "svg", + { viewBox: "0 0 48 48", focusable: "false" }, + h4("path", { + fill: "currentColor", + d: "M37.05 22.783c-6.758-5.216-14.378-12.128-22.73-19.538-.655-.585-1.242-.354-1.536.42-1.88 4.973-.058 9.386 2.889 11.932s7.368 4.912 10.058 6.155c.105.049.013.203-.093.163-4.953-2.182-8.397-3.765-13.07-7.368-.497-.388-1.01-.242-1.07.521-.384 4.748 2.657 8.483 6.058 9.745 2.1.781 4.398 1.212 6.53 1.474.109.015.084.178-.027.178-2.747.01-6.058-.654-8.935-1.751-.606-.233-.818.25-.722.633.491 2.008 2.974 5.076 6.926 5.73a12 12 0 0 0 2.228.115c.164 0 .208.089.154.217q-2.685 4.6-2.803 4.797c-.091.152-.036.275.156.275h3.543c.164 0 .264.106.18.246l-4.958 8.196c-.191.328.035.565.395.301s15.212-11.133 15.636-11.448c.195-.142.148-.327-.124-.327h-3.18c-.206 0-.252-.14-.111-.28.14-.141 3.602-3.594 4.837-4.888 1.283-1.35 1.938-3.825-.231-5.498" + }) ) ); } function ChannelLogo({ channel }) { - return channel === "weixin" ? h3(WeixinLogo) : h3(FeishuLogo); + if (channel === "weixin") return h4(WeixinLogo); + if (channel === "feishu") return h4(FeishuLogo); + return h4(DingtalkLogo); } -function IMSettingsTab({ feishuRpcCall, weixinRpcCall }) { - const [selected, setSelected] = React3.useState("weixin"); +function IMSettingsTab({ dingtalkRpcCall, feishuRpcCall, weixinRpcCall }) { + const [selected, setSelected] = React4.useState("weixin"); const active = CHANNELS.find((channel) => channel.id === selected) ?? CHANNELS[0]; - return h3( + return h4( "section", { className: "dim-page", "aria-label": "IM\u673A\u5668\u4EBA\u8BBE\u7F6E" }, - h3( + h4( "header", { className: "dim-title" }, - h3("p", null, "\u901A\u8FC7\u626B\u7801\u628A\u673A\u5668\u4EBA\u63A5\u5165 DeepSeek Harness"), - h3("div", { className: "dim-channelCount" }, "2 \u4E2A\u6E20\u9053") + h4("p", null, "\u901A\u8FC7\u626B\u7801\u628A\u673A\u5668\u4EBA\u63A5\u5165 DeepSeek Harness"), + h4("div", { className: "dim-channelCount" }, `${CHANNELS.length} \u4E2A\u6E20\u9053`) ), - h3( + h4( "div", { className: "dim-layout" }, - h3( + h4( "nav", { className: "dim-rail", role: "tablist", "aria-label": "IM \u6E20\u9053" }, - CHANNELS.map((channel) => h3( + CHANNELS.map((channel) => h4( "button", { key: channel.id, @@ -2834,21 +3972,21 @@ function IMSettingsTab({ feishuRpcCall, weixinRpcCall }) { "aria-controls": `dim-panel-${channel.id}`, onClick: () => setSelected(channel.id) }, - h3(ChannelLogo, { channel: channel.id }), - h3( + h4(ChannelLogo, { channel: channel.id }), + h4( "span", { className: "dim-channelCopy" }, - h3("strong", null, channel.label) + h4("strong", null, channel.label) ) )) ), - h3("div", { className: "dim-divider", "aria-hidden": "true" }), - h3("main", { + h4("div", { className: "dim-divider", "aria-hidden": "true" }), + h4("main", { className: "dim-panel", role: "tabpanel", id: `dim-panel-${active.id}`, "aria-labelledby": `dim-tab-${active.id}` - }, active.id === "weixin" ? h3(WeixinSettingsTab, { rpcCall: weixinRpcCall }) : h3(FeishuSettingsTab, { rpcCall: feishuRpcCall })) + }, active.id === "weixin" ? h4(WeixinSettingsTab, { rpcCall: weixinRpcCall }) : active.id === "feishu" ? h4(FeishuSettingsTab, { rpcCall: feishuRpcCall }) : h4(DingtalkSettingsTab, { rpcCall: dingtalkRpcCall })) ) ); } @@ -2861,12 +3999,13 @@ function apply(ctx) { }, "im-settings: install combined channel styles"); const feishuRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(FEISHU_RPC_CHANNEL, endpoint, payload, signal); const weixinRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(WEIXIN_RPC_CHANNEL, endpoint, payload, signal); + const dingtalkRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(DINGTALK_RPC_CHANNEL, endpoint, payload, signal); ctx.slots.inject("settings.plugins.tab", () => ctx.slots.register({ name: "settings.plugins.tab", id: "im", order: 20, label: "IM\u673A\u5668\u4EBA", - inject: () => ({ feishuRpcCall, weixinRpcCall }) + inject: () => ({ dingtalkRpcCall, feishuRpcCall, weixinRpcCall }) }, IMSettingsTab)); } diff --git a/lib/index.js b/lib/index.js index 0235b86..449864e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,4 +1,5 @@ // plugin-src/host/index.mjs +import { apply as applyDingtalk } from "@xmanrui/dsh-dingtalk"; import { apply as applyFeishu } from "@xmanrui/dsh-feishu"; import { apply as applyWeixin } from "@xmanrui/dsh-weixin"; var name = "dsh-im-host"; @@ -6,12 +7,14 @@ var inject = ["connection", "credentials", "webServer"]; function createImHostPlugin(internals = {}) { const startFeishu = internals.applyFeishu ?? applyFeishu; const startWeixin = internals.applyWeixin ?? applyWeixin; + const startDingtalk = internals.applyDingtalk ?? applyDingtalk; return Object.freeze({ name, inject, async apply(ctx, config = {}) { await startFeishu(ctx, config.feishu ?? {}); await startWeixin(ctx, config.weixin ?? {}); + await startDingtalk(ctx, config.dingtalk ?? {}); } }); } diff --git a/package-lock.json b/package-lock.json index 26b34b8..27eb739 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "license": "MIT", "dependencies": { + "@xmanrui/dsh-dingtalk": "https://github.com/xmanrui/dsh-dingtalk/archive/67f7211b8011f0623b47ce9e01004bbab8e6614f.tar.gz", "@xmanrui/dsh-feishu": "https://github.com/xmanrui/dsh-feishu/archive/aad650feabadd511241aa58b236d64273d5e397f.tar.gz", "@xmanrui/dsh-weixin": "https://github.com/xmanrui/dsh-weixin/archive/76d076771b2c84fb4c5598c2344d486695eda080.tar.gz" }, @@ -547,6 +548,22 @@ "undici-types": "~8.3.0" } }, + "node_modules/@xmanrui/dsh-dingtalk": { + "version": "0.1.0", + "resolved": "https://github.com/xmanrui/dsh-dingtalk/archive/67f7211b8011f0623b47ce9e01004bbab8e6614f.tar.gz", + "integrity": "sha512-aOA3vvEL7mKt/NIlMRVJTWB+V5E+J3gWgqE0Q19in8KTrEwYqUk1TYe08B/OdikEghwaQnNfri2bqqpgsCzCqg==", + "license": "MIT", + "dependencies": { + "dingtalk-stream": "2.1.4", + "qrcode": "1.5.4" + }, + "bin": { + "dsh-dingtalk": "bin/dsh-dingtalk.mjs" + }, + "engines": { + "node": ">=22.19" + } + }, "node_modules/@xmanrui/dsh-feishu": { "version": "0.1.0", "resolved": "https://github.com/xmanrui/dsh-feishu/archive/aad650feabadd511241aa58b236d64273d5e397f.tar.gz", @@ -753,6 +770,17 @@ "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", "license": "MIT" }, + "node_modules/dingtalk-stream": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/dingtalk-stream/-/dingtalk-stream-2.1.4.tgz", + "integrity": "sha512-rgQbXLGWfASuB9onFcqXTnRSj4ZotimhBOnzrB4kS19AaU9lshXiuofs1GAYcKh5uzPWCAuEs3tMtiadTQWP4A==", + "license": "MIT", + "dependencies": { + "axios": "^1.4.0", + "debug": "^4.3.4", + "ws": "^8.13.0" + } + }, "node_modules/dotenv": { "version": "17.4.2", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", diff --git a/package.json b/package.json index c4bea39..284bb5c 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "node": ">=22.19" }, "dependencies": { + "@xmanrui/dsh-dingtalk": "https://github.com/xmanrui/dsh-dingtalk/archive/67f7211b8011f0623b47ce9e01004bbab8e6614f.tar.gz", "@xmanrui/dsh-feishu": "https://github.com/xmanrui/dsh-feishu/archive/aad650feabadd511241aa58b236d64273d5e397f.tar.gz", "@xmanrui/dsh-weixin": "https://github.com/xmanrui/dsh-weixin/archive/76d076771b2c84fb4c5598c2344d486695eda080.tar.gz" }, diff --git a/plugin-src/client/index.js b/plugin-src/client/index.js index 6d0b7c0..7e455ed 100644 --- a/plugin-src/client/index.js +++ b/plugin-src/client/index.js @@ -1,5 +1,7 @@ import * as React from 'react'; +import { DINGTALK_RPC_CHANNEL } from '@xmanrui/dsh-dingtalk/client-api'; +import { DingtalkSettingsTab } from '@xmanrui/dsh-dingtalk/client-source'; import { FeishuSettingsTab } from './channels/feishu/index.js'; import { FEISHU_RPC_CHANNEL } from './channels/feishu/api.js'; import { installFeishuStyles } from './channels/feishu/styles.js'; @@ -16,6 +18,7 @@ export const inject = ['slots', 'connection']; const CHANNELS = Object.freeze([ { id: 'weixin', label: '微信' }, { id: 'feishu', label: '飞书' }, + { id: 'dingtalk', label: '钉钉' }, ]); function WeixinLogo() { @@ -37,17 +40,29 @@ function FeishuLogo() { )); } -function ChannelLogo({ channel }) { - return channel === 'weixin' ? h(WeixinLogo) : h(FeishuLogo); +function DingtalkLogo() { + return h('span', { className: 'dim-logo dim-logoDingtalk', 'aria-hidden': 'true' }, + h('svg', { viewBox: '0 0 48 48', focusable: 'false' }, + h('path', { + fill: 'currentColor', + d: 'M37.05 22.783c-6.758-5.216-14.378-12.128-22.73-19.538-.655-.585-1.242-.354-1.536.42-1.88 4.973-.058 9.386 2.889 11.932s7.368 4.912 10.058 6.155c.105.049.013.203-.093.163-4.953-2.182-8.397-3.765-13.07-7.368-.497-.388-1.01-.242-1.07.521-.384 4.748 2.657 8.483 6.058 9.745 2.1.781 4.398 1.212 6.53 1.474.109.015.084.178-.027.178-2.747.01-6.058-.654-8.935-1.751-.606-.233-.818.25-.722.633.491 2.008 2.974 5.076 6.926 5.73a12 12 0 0 0 2.228.115c.164 0 .208.089.154.217q-2.685 4.6-2.803 4.797c-.091.152-.036.275.156.275h3.543c.164 0 .264.106.18.246l-4.958 8.196c-.191.328.035.565.395.301s15.212-11.133 15.636-11.448c.195-.142.148-.327-.124-.327h-3.18c-.206 0-.252-.14-.111-.28.14-.141 3.602-3.594 4.837-4.888 1.283-1.35 1.938-3.825-.231-5.498', + }), + )); } -export function IMSettingsTab({ feishuRpcCall, weixinRpcCall }) { +function ChannelLogo({ channel }) { + if (channel === 'weixin') return h(WeixinLogo); + if (channel === 'feishu') return h(FeishuLogo); + return h(DingtalkLogo); +} + +export function IMSettingsTab({ dingtalkRpcCall, feishuRpcCall, weixinRpcCall }) { const [selected, setSelected] = React.useState('weixin'); const active = CHANNELS.find((channel) => channel.id === selected) ?? CHANNELS[0]; return h('section', { className: 'dim-page', 'aria-label': 'IM机器人设置' }, h('header', { className: 'dim-title' }, h('p', null, '通过扫码把机器人接入 DeepSeek Harness'), - h('div', { className: 'dim-channelCount' }, '2 个渠道'), + h('div', { className: 'dim-channelCount' }, `${CHANNELS.length} 个渠道`), ), h('div', { className: 'dim-layout' }, h('nav', { className: 'dim-rail', role: 'tablist', 'aria-label': 'IM 渠道' }, @@ -73,7 +88,9 @@ export function IMSettingsTab({ feishuRpcCall, weixinRpcCall }) { 'aria-labelledby': `dim-tab-${active.id}`, }, active.id === 'weixin' ? h(WeixinSettingsTab, { rpcCall: weixinRpcCall }) - : h(FeishuSettingsTab, { rpcCall: feishuRpcCall })), + : active.id === 'feishu' + ? h(FeishuSettingsTab, { rpcCall: feishuRpcCall }) + : h(DingtalkSettingsTab, { rpcCall: dingtalkRpcCall })), ), ); } @@ -90,12 +107,14 @@ export function apply(ctx) { ctx.connection.rpc.call(FEISHU_RPC_CHANNEL, endpoint, payload, signal); const weixinRpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(WEIXIN_RPC_CHANNEL, endpoint, payload, signal); + const dingtalkRpcCall = (endpoint, payload, signal) => + ctx.connection.rpc.call(DINGTALK_RPC_CHANNEL, endpoint, payload, signal); ctx.slots.inject('settings.plugins.tab', () => ctx.slots.register({ name: 'settings.plugins.tab', id: 'im', order: 20, label: 'IM机器人', - inject: () => ({ feishuRpcCall, weixinRpcCall }), + inject: () => ({ dingtalkRpcCall, feishuRpcCall, weixinRpcCall }), }, IMSettingsTab)); } diff --git a/plugin-src/client/styles.js b/plugin-src/client/styles.js index e359370..72d6cab 100644 --- a/plugin-src/client/styles.js +++ b/plugin-src/client/styles.js @@ -28,13 +28,16 @@ const CSS = String.raw` .dim-logoWeixin svg { width: 19px; height: 19px; } .dim-logoFeishu { background: white; border: 1px solid var(--dsw-alias-line-border, #e5e6eb); } .dim-logoFeishu svg { width: 22px; height: 22px; } +.dim-logoDingtalk { color: white; background: #1677ff; } +.dim-logoDingtalk svg { width: 24px; height: 24px; } .dim-channelCopy { min-width: 0; display: block; } .dim-channelCopy strong { overflow: hidden; color: inherit; font-size: 14px; line-height: 20px; font-weight: 680; text-overflow: ellipsis; white-space: nowrap; } .dim-divider { width: 1px; min-height: 520px; background: var(--dsw-alias-line-divider, #eef0f3); } .dim-panel { min-width: 0; } -.dim-panel .bxf-page, .dim-panel .dxw-page { width: 100%; max-width: none; padding: 0 0 24px; } -.dim-panel .bxf-heading, .dim-panel .dxw-heading { justify-content: flex-end; } -.dim-panel .bxf-headingTools, .dim-panel .dxw-tools { width: 100%; justify-content: flex-end; } +.dim-panel .bxf-page, .dim-panel .dxw-page, .dim-panel .ddt-page { width: 100%; max-width: none; padding: 0 0 24px; } +.dim-panel .bxf-heading, .dim-panel .dxw-heading, .dim-panel .ddt-heading { justify-content: flex-end; } +.dim-panel .bxf-headingTools, .dim-panel .dxw-tools, .dim-panel .ddt-tools { width: 100%; justify-content: flex-end; } +.dim-panel .ddt-headingCopy { display: none; } @media (max-width: 840px) { .dim-title { align-items: flex-start; } .dim-layout { grid-template-columns: minmax(0, 1fr); gap: 18px; } diff --git a/plugin-src/host/index.mjs b/plugin-src/host/index.mjs index b2184a4..e23f2da 100644 --- a/plugin-src/host/index.mjs +++ b/plugin-src/host/index.mjs @@ -1,3 +1,4 @@ +import { apply as applyDingtalk } from '@xmanrui/dsh-dingtalk'; import { apply as applyFeishu } from '@xmanrui/dsh-feishu'; import { apply as applyWeixin } from '@xmanrui/dsh-weixin'; @@ -7,12 +8,14 @@ export const inject = ['connection', 'credentials', 'webServer']; export function createImHostPlugin(internals = {}) { const startFeishu = internals.applyFeishu ?? applyFeishu; const startWeixin = internals.applyWeixin ?? applyWeixin; + const startDingtalk = internals.applyDingtalk ?? applyDingtalk; return Object.freeze({ name, inject, async apply(ctx, config = {}) { await startFeishu(ctx, config.feishu ?? {}); await startWeixin(ctx, config.weixin ?? {}); + await startDingtalk(ctx, config.dingtalk ?? {}); }, }); } diff --git a/scripts/verify-package.mjs b/scripts/verify-package.mjs index a790164..0bfe433 100644 --- a/scripts/verify-package.mjs +++ b/scripts/verify-package.mjs @@ -33,15 +33,18 @@ if ((client.match(/ctx\.slots\.inject\("settings\.plugins\.tab"/g) ?? []).length if (/role:\s*["']switch|type:\s*["']checkbox/.test(client)) { throw new Error('client bundle contains a channel enable switch'); } -if (!host.includes('@xmanrui/dsh-feishu') || !host.includes('@xmanrui/dsh-weixin')) { - throw new Error('host bundle does not compose both channel providers'); +if (!host.includes('@xmanrui/dsh-feishu') + || !host.includes('@xmanrui/dsh-weixin') + || !host.includes('@xmanrui/dsh-dingtalk')) { + throw new Error('host bundle does not compose all three channel providers'); } -if (!patch.includes("name: '@xmanrui/dsh-im'") || /dsh-(?:feishu|weixin)/.test(patch)) { +if (!patch.includes("name: '@xmanrui/dsh-im'") || /dsh-(?:feishu|weixin|dingtalk)/.test(patch)) { throw new Error('bundle patch must activate only dsh-im'); } -for (const name of ['@xmanrui/dsh-feishu', '@xmanrui/dsh-weixin']) { +for (const name of ['@xmanrui/dsh-feishu', '@xmanrui/dsh-weixin', '@xmanrui/dsh-dingtalk']) { const spec = manifest.dependencies?.[name]; - if (typeof spec !== 'string' || !spec.startsWith('https://github.com/')) { + if (typeof spec !== 'string' + || !/^https:\/\/github\.com\/[^/]+\/[^/]+\/archive\/[0-9a-f]{40}\.tar\.gz$/.test(spec)) { throw new Error(`${name} must use a pinned public HTTPS archive`); } } diff --git a/test/client-ui.test.mjs b/test/client-ui.test.mjs index 0742338..2559a71 100644 --- a/test/client-ui.test.mjs +++ b/test/client-ui.test.mjs @@ -6,19 +6,22 @@ import { renderToStaticMarkup } from 'react-dom/server'; import { IMSettingsTab } from '../plugin-src/client/index.js'; -test('IM settings renders two logo channel tabs without enable switches', () => { +test('IM settings renders three compact logo channel tabs without enable switches', () => { const markup = renderToStaticMarkup(React.createElement(IMSettingsTab, { feishuRpcCall: async () => ({ ok: true, value: {} }), weixinRpcCall: async () => ({ ok: true, value: {} }), + dingtalkRpcCall: async () => ({ ok: true, value: {} }), })); assert.match(markup, /IM机器人/); assert.match(markup, /通过扫码把机器人接入 DeepSeek Harness/); assert.match(markup, />微信飞书钉钉|扫码接入<\/small>/); diff --git a/test/host.test.mjs b/test/host.test.mjs index b74b2d0..3d02de4 100644 --- a/test/host.test.mjs +++ b/test/host.test.mjs @@ -3,14 +3,19 @@ import test from 'node:test'; import { createImHostPlugin, inject, name } from '../plugin-src/host/index.mjs'; -test('Host composes Feishu and Weixin inside one plugin context', async () => { +test('Host composes Feishu, Weixin, and DingTalk inside one plugin context', async () => { const calls = []; const plugin = createImHostPlugin({ applyFeishu: async (ctx, config) => calls.push(['feishu', ctx, config]), applyWeixin: async (ctx, config) => calls.push(['weixin', ctx, config]), + applyDingtalk: async (ctx, config) => calls.push(['dingtalk', ctx, config]), }); const ctx = { marker: 'shared-context' }; - const config = { feishu: { domain: 'feishu' }, weixin: { timeout: 30 } }; + const config = { + feishu: { domain: 'feishu' }, + weixin: { timeout: 30 }, + dingtalk: { replyTimeoutMs: 60_000 }, + }; await plugin.apply(ctx, config); @@ -19,6 +24,7 @@ test('Host composes Feishu and Weixin inside one plugin context', async () => { assert.deepEqual(calls, [ ['feishu', ctx, config.feishu], ['weixin', ctx, config.weixin], + ['dingtalk', ctx, config.dingtalk], ]); }); @@ -27,8 +33,21 @@ test('Host does not start Weixin when Feishu activation fails', async () => { const plugin = createImHostPlugin({ applyFeishu: async () => { throw new Error('feishu unavailable'); }, applyWeixin: async () => { weixinStarted = true; }, + applyDingtalk: async () => { throw new Error('DingTalk must not start'); }, }); await assert.rejects(() => plugin.apply({}, {}), /feishu unavailable/); assert.equal(weixinStarted, false); }); + +test('Host does not start DingTalk when Weixin activation fails', async () => { + let dingtalkStarted = false; + const plugin = createImHostPlugin({ + applyFeishu: async () => {}, + applyWeixin: async () => { throw new Error('weixin unavailable'); }, + applyDingtalk: async () => { dingtalkStarted = true; }, + }); + + await assert.rejects(() => plugin.apply({}, {}), /weixin unavailable/); + assert.equal(dingtalkStarted, false); +});