diff --git a/lib/client.js b/lib/client.js index 5d0ed53..932755b 100644 --- a/lib/client.js +++ b/lib/client.js @@ -571,7 +571,7 @@ var React24 = __toESM(require("react"), 1); // package.json var package_default = { name: "dsh-im-ops", - version: "4.9.1-ops.12", + version: "4.9.1-ops.13", description: "Ops fork of dsh-im (all channels kept). Based on @xmanrui/dsh-im@4.9.1 \u2014 access/session policies owned here.", keywords: [ "deepseek-harness", @@ -14282,14 +14282,13 @@ var CSS11 = String.raw` .dim-githubArrow { font-size: 13px; line-height: 1; } .dim-githubTooltip { position: absolute; top: calc(100% + 8px); right: 0; z-index: 20; width: max-content; max-width: min(220px, 80vw); padding: 6px 9px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 8px 24px rgb(31 35 41 / 14%); font-size: 11px; line-height: 16px; font-weight: 500; white-space: nowrap; opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; } .dim-githubAction:hover .dim-githubTooltip, .dim-githubAction:focus-within .dim-githubTooltip { opacity: 1; visibility: visible; transform: translateY(0); } -.dim-layout { display: grid; grid-template-columns: 174px 1px minmax(0, 1fr); gap: 24px; align-items: start; } -.dim-rail { max-height: 520px; display: grid; align-content: start; gap: 8px; overflow-y: auto; padding: 0 4px 1px 1px; scrollbar-width: thin; scrollbar-color: var(--dsw-alias-border-l2, #dfe1e5) transparent; } -.dim-rail::-webkit-scrollbar { width: 4px; } -.dim-rail::-webkit-scrollbar-thumb { border-radius: 99px; background: var(--dsw-alias-border-l2, #dfe1e5); } -.dim-channel { width: 100%; min-height: 48px; display: grid; grid-template-columns: 30px minmax(0, 1fr); align-items: center; gap: 10px; padding: 8px 12px; border: 1px solid var(--dsw-alias-border-l2, #eef0f3); border-radius: 14px; color: inherit; background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 2px 8px rgb(31 35 41 / 3%); font: inherit; text-align: left; cursor: pointer; transition: border-color .16s ease, background .16s ease, box-shadow .16s ease; } -.dim-channel:hover { border-color: color-mix(in srgb, var(--dim-blue) 25%, var(--dsw-alias-border-l2, #eef0f3)); background: color-mix(in srgb, var(--dim-blue) 2%, var(--dsw-alias-bg-layer-3, #fff)); box-shadow: 0 5px 16px rgb(31 35 41 / 5%); } -.dim-channel[aria-selected="true"] { border-color: color-mix(in srgb, var(--dim-blue) 43%, var(--dsw-alias-border-l2, #dfe1e5)); color: var(--dim-blue); background: color-mix(in srgb, var(--dim-blue) 12%, var(--dsw-alias-bg-layer-3, #fff)); box-shadow: 0 3px 12px rgb(51 112 255 / 7%); } -.dim-channel:focus-visible { outline: none; border-color: color-mix(in srgb, var(--dim-blue) 72%, var(--dsw-alias-border-l2, #dfe1e5)); box-shadow: 0 0 0 1px color-mix(in srgb, var(--dim-blue) 24%, transparent) inset, 0 3px 12px rgb(51 112 255 / 7%); } +.dim-layout { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; align-items: start; } +.dim-channelPicker { min-width: 0; display: flex; align-items: center; gap: 10px; } +.dim-channelPickerLabel { flex: none; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 18px; font-weight: 560; white-space: nowrap; } +.dim-channelPickerControl { min-width: 0; flex: 1 1 auto; display: grid; grid-template-columns: 30px minmax(0, 1fr); align-items: center; gap: 10px; max-width: 420px; padding: 4px 10px 4px 6px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 10px; background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 1px 2px rgb(31 35 41 / 4%); } +.dim-channelPickerSelect { min-width: 0; width: 100%; height: 34px; padding: 0 4px 0 0; border: 0; border-radius: 6px; color: var(--dsw-alias-label-primary, #1f2329); background: transparent; font: inherit; font-size: 14px; font-weight: 650; cursor: pointer; } +.dim-channelPickerSelect:focus { outline: none; } +.dim-channelPickerControl:focus-within { border-color: color-mix(in srgb, var(--dim-blue) 55%, var(--dsw-alias-border-l2, #dfe1e5)); box-shadow: 0 0 0 3px color-mix(in srgb, var(--dim-blue) 16%, transparent); } .dim-logo { width: 30px; height: 30px; display: grid; place-items: center; border-radius: 9px; box-shadow: 0 1px 3px rgb(31 35 41 / 7%); } .dim-logo svg { display: block; width: 20px; height: 20px; } .dim-logoWeixin { color: white; background: #07c160; } @@ -14312,10 +14311,6 @@ var CSS11 = String.raw` .dim-logoSlack svg { width: 21px; height: 21px; } .dim-logoWhatsapp { color: white; background: #25d366; } .dim-logoWhatsapp svg { width: 21px; height: 21px; } -.dim-channelCopy { min-width: 0; display: grid; } -.dim-channelCopy strong { overflow: hidden; color: inherit; font-size: 14px; line-height: 20px; font-weight: 680; text-overflow: ellipsis; white-space: nowrap; } -.dim-channelNote { overflow: hidden; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 10px; line-height: 13px; font-weight: 500; text-overflow: ellipsis; white-space: nowrap; } -.dim-divider { width: 1px; min-height: 520px; background: var(--dsw-alias-border-l1, #eef0f3); } .dim-panel { min-width: 0; container-type: inline-size; } .dim-loopbackRecovery { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin: 0 0 14px; padding: 14px 16px; border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary, #d97706) 30%, var(--dsw-alias-border-l2, #dfe1e5)); border-radius: 12px; color: var(--dsw-alias-label-primary, #1f2329); background: color-mix(in srgb, var(--dsw-alias-state-warn-primary, #d97706) 8%, var(--dsw-alias-bg-layer-1, #fff)); } .dim-loopbackRecoveryCopy { min-width: 0; } @@ -14746,11 +14741,7 @@ var CSS11 = String.raw` } @media (max-width: 840px) { .dim-title { align-items: flex-start; } - .dim-layout { grid-template-columns: minmax(0, 1fr); gap: 18px; } - .dim-rail { grid-template-columns: repeat(2, minmax(0, 1fr)); } - .dim-divider { display: none; } - .dim-rail { max-height: none; overflow: visible; padding-right: 1px; } - .dim-channel { min-height: 48px; } + .dim-channelPickerControl { max-width: none; } } @media (max-width: 560px) { .dim-title { flex-direction: column; gap: 10px; } @@ -14763,7 +14754,8 @@ var CSS11 = String.raw` .dim-updateBody { padding: 16px 18px; } .dim-updateFooter { padding: 12px 18px; } .dim-githubTooltip { right: auto; left: 0; } - .dim-rail { grid-template-columns: minmax(0, 1fr); } + .dim-channelPicker { align-items: stretch; flex-direction: column; gap: 6px; } + .dim-channelPickerControl { max-width: none; } .dim-loopbackRecovery { align-items: stretch; flex-direction: column; gap: 12px; } .dim-loopbackRecoveryAction { width: 100%; } .dim-deliverySectionHeading { align-items: stretch; flex-direction: column; } @@ -15439,6 +15431,7 @@ function IMSettingsTab({ const [runningVersion, setRunningVersion] = React24.useState(IM_PLUGIN_VERSION); const [deliverySettings, setDeliverySettings] = React24.useState(null); const githubTooltipId = React24.useId(); + const channelSelectId = React24.useId(); const active = CHANNELS.find((channel4) => channel4.id === selected) ?? CHANNELS[0]; const reportLoopbackRecovery = React24.useCallback((recovery) => { setLoopbackRecovery((current) => current?.url === recovery.url ? current : recovery); @@ -15537,40 +15530,37 @@ function IMSettingsTab({ "div", { className: "dim-layout" }, h2( - "nav", - { className: "dim-rail", role: "tablist", "aria-label": "IM \u6E20\u9053" }, - CHANNELS.map((channel4) => h2( - "button", - { - key: channel4.id, - type: "button", - role: "tab", - id: `dim-tab-${channel4.id}`, - className: "dim-channel", - "aria-selected": channel4.id === active.id, - "aria-controls": `dim-panel-${channel4.id}`, - onClick: () => { - setSelected(channel4.id); + "div", + { className: "dim-channelPicker" }, + h2("label", { + className: "dim-channelPickerLabel", + htmlFor: channelSelectId + }, "IM \u6E20\u9053"), + h2( + "div", + { className: "dim-channelPickerControl" }, + h2(ChannelLogo, { channel: active.id }), + h2("select", { + id: channelSelectId, + className: "dim-channelPickerSelect", + value: active.id, + "aria-label": "IM \u6E20\u9053", + onChange: (event) => { + setSelected(event.target.value); setDeliverySettings(null); } - }, - h2(ChannelLogo, { channel: channel4.id }), - h2( - "span", - { className: "dim-channelCopy" }, - h2("strong", null, channel4.label), - channel4.note ? h2("small", { className: "dim-channelNote" }, channel4.note) : null - ) - )) + }, CHANNELS.map((channel4) => h2("option", { + key: channel4.id, + value: channel4.id + }, channel4.label, channel4.note || null))) + ) ), - h2("div", { className: "dim-divider", "aria-hidden": "true" }), h2( "main", { className: "dim-panel", - role: "tabpanel", id: `dim-panel-${active.id}`, - "aria-labelledby": `dim-tab-${active.id}` + "aria-label": active.label }, loopbackRecovery ? h2(LoopbackRecoveryNotice, { recovery: loopbackRecovery, diff --git a/lib/index.js b/lib/index.js index c292385..4524bd1 100644 --- a/lib/index.js +++ b/lib/index.js @@ -169,7 +169,7 @@ ${n}`:n)}function P_(n,t,o){return{cardParamMap:{flowStatus:t,msgContent:gu(n,o) ${sEe(I.text,s)}`);g=wc([i,...c,A.join(` `)].join(` -`)),s=Math.floor(s/2)}while(s>0&&(g.message.length>3e3||g.messages.length>3));return g}function cEe(n){let t=n?.code??n?.failure?.code;return t==="session-not-found"?w("\u5F53\u524D\u804A\u5929\u7ED1\u5B9A\u7684\u4F1A\u8BDD\u5DF2\u4E0D\u5B58\u5728\uFF0C\u8BF7\u91CD\u65B0\u7ED1\u5B9A\u4F1A\u8BDD\u3002"):t===Mi||t==="workspace-bot-not-found"||t==="session-binding-changed"?w("\u4F1A\u8BDD\u3001\u5DE5\u4F5C\u533A\u6216\u673A\u5668\u4EBA\u72B6\u6001\u5DF2\u53D1\u751F\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C /history\u3002"):t==="harness-api-not-found"?w("\u5F53\u524D Harness \u6682\u4E0D\u652F\u6301\u8BFB\u53D6\u4F1A\u8BDD\u5386\u53F2\u3002"):n?.name==="AbortError"?w("\u5386\u53F2\u8BFB\u53D6\u5DF2\u53D6\u6D88\u3002"):n?.name==="TimeoutError"||t==="harness-timeout"?w("\u8BFB\u53D6\u5386\u53F2\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"):w("\u6682\u65F6\u65E0\u6CD5\u8BFB\u53D6\u4F1A\u8BDD\u5386\u53F2\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002")}function Yi(n){return typeof n=="string"&&s1.test(n.trim())}async function so(n,t,o,a,{signal:e,isDirect:i=!1,hasImages:A=!1,hasFiles:r=!1}={}){if(!Yi(n))return null;let s=s1.exec(n.trim())[1].trim();if(s&&(!/^\d+$/u.test(s)||/^0+$/u.test(s)))return wc(w(rEe));let g=s?Math.min(Number(s),iEe):3;if(!i)return wc(w("\u8BF7\u5728\u4E0E\u673A\u5668\u4EBA\u7684\u79C1\u804A\u4E2D\u4F7F\u7528 /history\u3002"));if(A||r)return wc(w("/history \u4EC5\u652F\u6301\u6587\u5B57\u547D\u4EE4\uFF0C\u8BF7\u79FB\u9664\u56FE\u7247\u6216\u6587\u4EF6\u540E\u91CD\u8BD5\u3002"));let c=o?.sessionFor?.(a);if(typeof c!="string"||!c)return wc(w("\u5F53\u524D\u804A\u5929\u5C1A\u672A\u7ED1\u5B9A\u4F1A\u8BDD\uFF0C\u8BF7\u5148\u53D1\u9001\u6D88\u606F\u6216\u4F7F\u7528 /session \u7ED1\u5B9A\u4F1A\u8BDD\u3002"));try{let I=t?.workspaceSession?.(c);if(typeof I?.readHistory!="function")return wc(w("\u5F53\u524D Harness \u6682\u4E0D\u652F\u6301\u8BFB\u53D6\u4F1A\u8BDD\u5386\u53F2\u3002"));let d=AbortSignal.timeout(n1),B=e?AbortSignal.any([e,d]):d,f=Date.now()+n1,Q=new Map,y,m,_=[],T=!1;for(let R=0;R=f)throw new DOMException("History read timed out","TimeoutError");let L=await I.readHistory({maxMessages:aEe,...y===void 0?{}:{beforeSeq:y},timeoutMs:Math.max(1,f-Date.now()),signal:B});if(B.throwIfAborted(),Date.now()>=f)throw new DOMException("History read timed out","TimeoutError");if(o.sessionFor(a)!==c){let z=new Error("Session binding changed during history read");throw z.code="session-binding-changed",z}if(!L||!Array.isArray(L.events)||typeof L.hasMore!="boolean")throw new TypeError("Invalid history page");let U=y??1/0;for(let z of L.events){let J=z?.event;if(!J||!Number.isSafeInteger(J.seq)||J.seq<0||typeof J.type!="string"||!J.type)throw new TypeError("Invalid history event");if(m!==void 0&&J.seq>m)continue;let K=Q.get(J.seq);if(K){if(!tEe(K,J))throw new TypeError("Conflicting history events")}else{if(y!==void 0&&J.seq>=y)throw new TypeError("Invalid history cursor");Q.set(J.seq,J)}U=Math.min(U,J.seq)}let F=[...Q.values()].sort((z,J)=>z.seq-J.seq);if(m??=F.at(-1)?.seq,T=L.hasMore,T&&(!Number.isFinite(U)||U===y))throw new TypeError("History cursor did not advance");if(_=nEe(F).slice(-g),_.length>=g||!T)break;y=U}return _.length===0?wc(T?w("\u672C\u6B21\u6709\u9650\u8BFB\u53D6\u4E2D\u672A\u627E\u5230\u53EF\u9884\u89C8\u7684\u5386\u53F2\u6D88\u606F\u3002"):w("\u5F53\u524D\u4F1A\u8BDD\u6682\u65E0\u53EF\u9884\u89C8\u7684\u5386\u53F2\u6D88\u606F\u3002")):gEe(c,_,g,T)}catch(I){return wc(cEe(I))}}var WQ={name:"dsh-im-ops",version:"4.9.1-ops.12",description:"Ops fork of dsh-im (all channels kept). Based on @xmanrui/dsh-im@4.9.1 \u2014 access/session policies owned here.",keywords:["deepseek-harness","dsh","dsh-plugin","ai-agent","im","instant-messaging","chatbot","feishu","lark","wechat","wecom","dingtalk","qq","slack","telegram","discord","whatsapp","ai-office","ops","fork"],author:"xmanrui (https://github.com/xmanrui)",contributors:[{name:"C3H3-AI",url:"https://github.com/C3H3-AI"},{name:"divingleee",url:"https://github.com/divingleee"},{name:"Chan-0312",url:"https://github.com/Chan-0312"}],license:"MIT",type:"module",repository:{type:"git",url:"git+https://github.com/hansjone/dsh-im-ops.git"},homepage:"https://github.com/hansjone/dsh-im-ops#readme",bugs:{url:"https://github.com/hansjone/dsh-im-ops/issues"},bin:{"dsh-im":"bin/dsh-im.mjs"},main:"./lib/index.js",exports:{".":"./lib/index.js","./client":"./lib/client.js","./package.json":"./package.json"},files:["assets","bin","cordis.patch.yml","lib","plugin-src","scripts","src","PROACTIVE_DELIVERY.md","PROACTIVE_DELIVERY.en.md","LICENSE","README.md","README.en.md","THIRD_PARTY_NOTICES.md"],dsh:{bundle:{patch:"./cordis.patch.yml"},client:{inject:["@deepseek-ai/dsh-client-connection","@deepseek-ai/dsh-client-runtime","@deepseek-ai/dsh-client-ui-settings","@deepseek-ai/dsh-client-ui-slots","@deepseek-ai/dsh-client-locale"],platform:"web"}},scripts:{build:"node plugin-src/client/build.mjs && node plugin-src/host/build.mjs",test:"node --test test/*.test.mjs test/channels/*/*.test.mjs",check:"npm run build && npm test && node scripts/verify-package.mjs"},engines:{node:">=22.19"},dependencies:{"@tencent-connect/qqbot-connector":"1.2.0","@tencent-connect/qqbot-nodejs":"1.0.4","@wecom/aibot-node-sdk":"1.0.7","dingtalk-stream":"2.1.4",qrcode:"1.5.4",undici:"7.29.0"},devDependencies:{"@deepseek-ai/cordis":"4.0.1","@larksuiteoapi/node-sdk":"1.73.0","@whiskeysockets/baileys":"7.0.0-rc14",esbuild:"0.25.9","https-proxy-agent":"5.0.1",react:"18.3.1","react-dom":"18.3.1","react-test-renderer":"18.3.1",semver:"7.8.5"},directories:{doc:"docs",lib:"lib",test:"test"}};var lEe=/^\/(?:stop|steer|version)(?=$|\s)/iu,dEe=/^\/stop(?=$|\s)/iu,pEe=/^\/version(?=$|\s)/iu,hEe="\u7528\u6CD5\uFF1A/stop\uFF08\u4E0D\u5E26\u53C2\u6570\uFF09",EEe="\u7528\u6CD5\uFF1A/version\uFF08\u4E0D\u5E26\u53C2\u6570\uFF09",uEe="\u7528\u6CD5\uFF1A/steer <\u8865\u5145\u6307\u4EE4>",CEe="\u63A7\u5236\u547D\u4EE4\u4EC5\u652F\u6301\u7EAF\u6587\u5B57\uFF0C\u8BF7\u79FB\u9664\u56FE\u7247\u540E\u91CD\u8BD5\u3002";function Po(n,t={}){return{message:n,...t}}function c1(n){return n?{signal:n}:{}}function I1(n,t,o){if(typeof t?.sessionFor!="function")return null;let a=t.sessionFor(o);if(typeof a!="string"||!a)return null;if(typeof n?.workspaceSession!="function")throw new TypeError("Harness does not support workspace sessions");let e=n.workspaceSession(a);if(!e||typeof e!="object")throw new TypeError("Harness returned an invalid workspace session");return e}function pa(n){return typeof n=="string"&&lEe.test(n.trim())}async function va(n,t,o,a,{signal:e,hasImages:i=!1,pendingInteraction:A=!1,control:r}={}){if(!pa(n))return null;let s=n.trim(),g=dEe.test(s),c=pEe.test(s);if(i)return Po(w(CEe));if(c)return/^\/version$/iu.test(s)?Po(`dsh-im v${WQ.version}`):Po(w(EEe));if(g){if(!/^\/stop$/iu.test(s))return Po(w(hEe));let Q=I1(t,o,a);if(!Q)return Po(w("\u5F53\u524D\u804A\u5929\u6CA1\u6709\u6B63\u5728\u8FD0\u884C\u7684\u4EFB\u52A1\u3002"));if(typeof Q.stopActiveTurn!="function")throw new TypeError("Harness session does not support stopping active turns");return await Q.stopActiveTurn(r,c1(e))?Po(w("\u5DF2\u8BF7\u6C42\u505C\u6B62\u5F53\u524D\u4EFB\u52A1\u3002"),{stopped:!0}):Po(w("\u5F53\u524D\u804A\u5929\u6CA1\u6709\u6B63\u5728\u8FD0\u884C\u7684\u4EFB\u52A1\u3002"))}let d=/^\/steer(?:\s+([\s\S]*))?$/iu.exec(s)?.[1]?.trim()??"";if(!d)return Po(w(uEe));if(A)return Po([w("\u5F53\u524D\u4EFB\u52A1\u6B63\u5728\u7B49\u5F85\u4F60\u7684\u56DE\u7B54\u6216\u5BA1\u6279\u3002"),"",w("\u8BF7\u5148\u5904\u7406\u5F53\u524D\u8BF7\u6C42\uFF0C\u6216\u8005\u53D1\u9001 /stop \u505C\u6B62\u4EFB\u52A1\u3002")].join(` +`)),s=Math.floor(s/2)}while(s>0&&(g.message.length>3e3||g.messages.length>3));return g}function cEe(n){let t=n?.code??n?.failure?.code;return t==="session-not-found"?w("\u5F53\u524D\u804A\u5929\u7ED1\u5B9A\u7684\u4F1A\u8BDD\u5DF2\u4E0D\u5B58\u5728\uFF0C\u8BF7\u91CD\u65B0\u7ED1\u5B9A\u4F1A\u8BDD\u3002"):t===Mi||t==="workspace-bot-not-found"||t==="session-binding-changed"?w("\u4F1A\u8BDD\u3001\u5DE5\u4F5C\u533A\u6216\u673A\u5668\u4EBA\u72B6\u6001\u5DF2\u53D1\u751F\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C /history\u3002"):t==="harness-api-not-found"?w("\u5F53\u524D Harness \u6682\u4E0D\u652F\u6301\u8BFB\u53D6\u4F1A\u8BDD\u5386\u53F2\u3002"):n?.name==="AbortError"?w("\u5386\u53F2\u8BFB\u53D6\u5DF2\u53D6\u6D88\u3002"):n?.name==="TimeoutError"||t==="harness-timeout"?w("\u8BFB\u53D6\u5386\u53F2\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"):w("\u6682\u65F6\u65E0\u6CD5\u8BFB\u53D6\u4F1A\u8BDD\u5386\u53F2\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002")}function Yi(n){return typeof n=="string"&&s1.test(n.trim())}async function so(n,t,o,a,{signal:e,isDirect:i=!1,hasImages:A=!1,hasFiles:r=!1}={}){if(!Yi(n))return null;let s=s1.exec(n.trim())[1].trim();if(s&&(!/^\d+$/u.test(s)||/^0+$/u.test(s)))return wc(w(rEe));let g=s?Math.min(Number(s),iEe):3;if(!i)return wc(w("\u8BF7\u5728\u4E0E\u673A\u5668\u4EBA\u7684\u79C1\u804A\u4E2D\u4F7F\u7528 /history\u3002"));if(A||r)return wc(w("/history \u4EC5\u652F\u6301\u6587\u5B57\u547D\u4EE4\uFF0C\u8BF7\u79FB\u9664\u56FE\u7247\u6216\u6587\u4EF6\u540E\u91CD\u8BD5\u3002"));let c=o?.sessionFor?.(a);if(typeof c!="string"||!c)return wc(w("\u5F53\u524D\u804A\u5929\u5C1A\u672A\u7ED1\u5B9A\u4F1A\u8BDD\uFF0C\u8BF7\u5148\u53D1\u9001\u6D88\u606F\u6216\u4F7F\u7528 /session \u7ED1\u5B9A\u4F1A\u8BDD\u3002"));try{let I=t?.workspaceSession?.(c);if(typeof I?.readHistory!="function")return wc(w("\u5F53\u524D Harness \u6682\u4E0D\u652F\u6301\u8BFB\u53D6\u4F1A\u8BDD\u5386\u53F2\u3002"));let d=AbortSignal.timeout(n1),B=e?AbortSignal.any([e,d]):d,f=Date.now()+n1,Q=new Map,y,m,_=[],T=!1;for(let R=0;R=f)throw new DOMException("History read timed out","TimeoutError");let L=await I.readHistory({maxMessages:aEe,...y===void 0?{}:{beforeSeq:y},timeoutMs:Math.max(1,f-Date.now()),signal:B});if(B.throwIfAborted(),Date.now()>=f)throw new DOMException("History read timed out","TimeoutError");if(o.sessionFor(a)!==c){let z=new Error("Session binding changed during history read");throw z.code="session-binding-changed",z}if(!L||!Array.isArray(L.events)||typeof L.hasMore!="boolean")throw new TypeError("Invalid history page");let U=y??1/0;for(let z of L.events){let J=z?.event;if(!J||!Number.isSafeInteger(J.seq)||J.seq<0||typeof J.type!="string"||!J.type)throw new TypeError("Invalid history event");if(m!==void 0&&J.seq>m)continue;let K=Q.get(J.seq);if(K){if(!tEe(K,J))throw new TypeError("Conflicting history events")}else{if(y!==void 0&&J.seq>=y)throw new TypeError("Invalid history cursor");Q.set(J.seq,J)}U=Math.min(U,J.seq)}let F=[...Q.values()].sort((z,J)=>z.seq-J.seq);if(m??=F.at(-1)?.seq,T=L.hasMore,T&&(!Number.isFinite(U)||U===y))throw new TypeError("History cursor did not advance");if(_=nEe(F).slice(-g),_.length>=g||!T)break;y=U}return _.length===0?wc(T?w("\u672C\u6B21\u6709\u9650\u8BFB\u53D6\u4E2D\u672A\u627E\u5230\u53EF\u9884\u89C8\u7684\u5386\u53F2\u6D88\u606F\u3002"):w("\u5F53\u524D\u4F1A\u8BDD\u6682\u65E0\u53EF\u9884\u89C8\u7684\u5386\u53F2\u6D88\u606F\u3002")):gEe(c,_,g,T)}catch(I){return wc(cEe(I))}}var WQ={name:"dsh-im-ops",version:"4.9.1-ops.13",description:"Ops fork of dsh-im (all channels kept). Based on @xmanrui/dsh-im@4.9.1 \u2014 access/session policies owned here.",keywords:["deepseek-harness","dsh","dsh-plugin","ai-agent","im","instant-messaging","chatbot","feishu","lark","wechat","wecom","dingtalk","qq","slack","telegram","discord","whatsapp","ai-office","ops","fork"],author:"xmanrui (https://github.com/xmanrui)",contributors:[{name:"C3H3-AI",url:"https://github.com/C3H3-AI"},{name:"divingleee",url:"https://github.com/divingleee"},{name:"Chan-0312",url:"https://github.com/Chan-0312"}],license:"MIT",type:"module",repository:{type:"git",url:"git+https://github.com/hansjone/dsh-im-ops.git"},homepage:"https://github.com/hansjone/dsh-im-ops#readme",bugs:{url:"https://github.com/hansjone/dsh-im-ops/issues"},bin:{"dsh-im":"bin/dsh-im.mjs"},main:"./lib/index.js",exports:{".":"./lib/index.js","./client":"./lib/client.js","./package.json":"./package.json"},files:["assets","bin","cordis.patch.yml","lib","plugin-src","scripts","src","PROACTIVE_DELIVERY.md","PROACTIVE_DELIVERY.en.md","LICENSE","README.md","README.en.md","THIRD_PARTY_NOTICES.md"],dsh:{bundle:{patch:"./cordis.patch.yml"},client:{inject:["@deepseek-ai/dsh-client-connection","@deepseek-ai/dsh-client-runtime","@deepseek-ai/dsh-client-ui-settings","@deepseek-ai/dsh-client-ui-slots","@deepseek-ai/dsh-client-locale"],platform:"web"}},scripts:{build:"node plugin-src/client/build.mjs && node plugin-src/host/build.mjs",test:"node --test test/*.test.mjs test/channels/*/*.test.mjs",check:"npm run build && npm test && node scripts/verify-package.mjs"},engines:{node:">=22.19"},dependencies:{"@tencent-connect/qqbot-connector":"1.2.0","@tencent-connect/qqbot-nodejs":"1.0.4","@wecom/aibot-node-sdk":"1.0.7","dingtalk-stream":"2.1.4",qrcode:"1.5.4",undici:"7.29.0"},devDependencies:{"@deepseek-ai/cordis":"4.0.1","@larksuiteoapi/node-sdk":"1.73.0","@whiskeysockets/baileys":"7.0.0-rc14",esbuild:"0.25.9","https-proxy-agent":"5.0.1",react:"18.3.1","react-dom":"18.3.1","react-test-renderer":"18.3.1",semver:"7.8.5"},directories:{doc:"docs",lib:"lib",test:"test"}};var lEe=/^\/(?:stop|steer|version)(?=$|\s)/iu,dEe=/^\/stop(?=$|\s)/iu,pEe=/^\/version(?=$|\s)/iu,hEe="\u7528\u6CD5\uFF1A/stop\uFF08\u4E0D\u5E26\u53C2\u6570\uFF09",EEe="\u7528\u6CD5\uFF1A/version\uFF08\u4E0D\u5E26\u53C2\u6570\uFF09",uEe="\u7528\u6CD5\uFF1A/steer <\u8865\u5145\u6307\u4EE4>",CEe="\u63A7\u5236\u547D\u4EE4\u4EC5\u652F\u6301\u7EAF\u6587\u5B57\uFF0C\u8BF7\u79FB\u9664\u56FE\u7247\u540E\u91CD\u8BD5\u3002";function Po(n,t={}){return{message:n,...t}}function c1(n){return n?{signal:n}:{}}function I1(n,t,o){if(typeof t?.sessionFor!="function")return null;let a=t.sessionFor(o);if(typeof a!="string"||!a)return null;if(typeof n?.workspaceSession!="function")throw new TypeError("Harness does not support workspace sessions");let e=n.workspaceSession(a);if(!e||typeof e!="object")throw new TypeError("Harness returned an invalid workspace session");return e}function pa(n){return typeof n=="string"&&lEe.test(n.trim())}async function va(n,t,o,a,{signal:e,hasImages:i=!1,pendingInteraction:A=!1,control:r}={}){if(!pa(n))return null;let s=n.trim(),g=dEe.test(s),c=pEe.test(s);if(i)return Po(w(CEe));if(c)return/^\/version$/iu.test(s)?Po(`dsh-im v${WQ.version}`):Po(w(EEe));if(g){if(!/^\/stop$/iu.test(s))return Po(w(hEe));let Q=I1(t,o,a);if(!Q)return Po(w("\u5F53\u524D\u804A\u5929\u6CA1\u6709\u6B63\u5728\u8FD0\u884C\u7684\u4EFB\u52A1\u3002"));if(typeof Q.stopActiveTurn!="function")throw new TypeError("Harness session does not support stopping active turns");return await Q.stopActiveTurn(r,c1(e))?Po(w("\u5DF2\u8BF7\u6C42\u505C\u6B62\u5F53\u524D\u4EFB\u52A1\u3002"),{stopped:!0}):Po(w("\u5F53\u524D\u804A\u5929\u6CA1\u6709\u6B63\u5728\u8FD0\u884C\u7684\u4EFB\u52A1\u3002"))}let d=/^\/steer(?:\s+([\s\S]*))?$/iu.exec(s)?.[1]?.trim()??"";if(!d)return Po(w(uEe));if(A)return Po([w("\u5F53\u524D\u4EFB\u52A1\u6B63\u5728\u7B49\u5F85\u4F60\u7684\u56DE\u7B54\u6216\u5BA1\u6279\u3002"),"",w("\u8BF7\u5148\u5904\u7406\u5F53\u524D\u8BF7\u6C42\uFF0C\u6216\u8005\u53D1\u9001 /stop \u505C\u6B62\u4EFB\u52A1\u3002")].join(` `));let B=I1(t,o,a);if(!B)return Po(w("\u5F53\u524D\u804A\u5929\u6CA1\u6709\u7ED1\u5B9A\u4F1A\u8BDD\uFF0C\u65E0\u6CD5\u8865\u5145\u6307\u4EE4\u3002\u8BF7\u5148\u7ED1\u5B9A\u4F1A\u8BDD\u3002"));if(typeof B.steerActiveTurn!="function")throw new TypeError("Harness session does not support steering active turns");let f=await B.steerActiveTurn(d,r,c1(e));return Po(f?w("\u5DF2\u63D0\u4EA4\u8865\u5145\u6307\u4EE4\uFF0CAgent \u4F1A\u5728\u4E0B\u4E00\u6B65\u8BFB\u53D6\u3002"):w("\u4EFB\u52A1\u5DF2\u7ED3\u675F\uFF0C\u6CA1\u6709\u6B63\u5728\u8FD0\u884C\u7684\u4EFB\u52A1\uFF0C\u65E0\u6CD5\u8865\u5145\u6307\u4EE4\u3002\u8BF7\u76F4\u63A5\u53D1\u9001\u6D88\u606F\u5F00\u59CB\u65B0\u4EFB\u52A1\u3002"))}var BEe=/^\/model(?=$|\s)/i,f1=/^\/models(?=$|\s)/i,Q1=/^\/reasoning(?=$|\s)/i,y1=/^\/reasonings(?=$|\s)/i,m1=/^\/reasoninglist(?=$|\s)/i,l1="\u7528\u6CD5\uFF1A/model <\u5E8F\u53F7\u6216 provider/model> [\u63A8\u7406\u7B49\u7EA7ID]",fEe="\u7528\u6CD5\uFF1A/models\uFF08\u4E0D\u5E26\u53C2\u6570\uFF09",QEe="\u7528\u6CD5\uFF1A/reasoning [\u5E8F\u53F7\u3001\u7B49\u7EA7ID\u6216 --default]",yEe="\u7528\u6CD5\uFF1A/reasoninglist \u6216 /reasonings\uFF08\u4E0D\u5E26\u53C2\u6570\uFF09",S1="session-binding-changed",w1="model-selection-mismatch",mEe=/[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]+/gu;function Ct(n){return{handled:!0,message:n,messages:Cg(n)}}function oi(n){return typeof n!="string"?"":n.replace(mEe," ").replace(/\s+/gu," ").trim()}function SEe(n){return n?{signal:n}:{}}function wEe(n){if(n===void 0)return;if(!n||typeof n!="object"||!Array.isArray(n.efforts)||n.efforts.length===0)throw new TypeError("Harness returned invalid model reasoning metadata");let t=n.efforts.map(o=>{if(!o||typeof o!="object"||typeof o.id!="string"||!o.id||typeof o.name!="string"||!o.name||o.description!==void 0&&typeof o.description!="string")throw new TypeError("Harness returned an invalid reasoning effort");return{id:o.id,name:o.name,...o.description===void 0?{}:{description:o.description}}});if(n.defaultEffort!==void 0&&(typeof n.defaultEffort!="string"||!n.defaultEffort))throw new TypeError("Harness returned an invalid default reasoning effort");return{efforts:t,...n.defaultEffort===void 0?{}:{defaultEffort:n.defaultEffort}}}function D1(n,{requireCurrent:t=!1}={}){if(!n||typeof n!="object"||!Array.isArray(n.groups)||!Array.isArray(n.failures))throw new TypeError("Harness returned an invalid model catalog");let o=n.groups.map(i=>{if(!i||typeof i!="object"||typeof i.id!="string"||!i.id||typeof i.name!="string"||!i.name||!Array.isArray(i.models))throw new TypeError("Harness returned an invalid model provider group");return{id:i.id,name:i.name,models:i.models.map(A=>{if(!A||typeof A!="object"||typeof A.id!="string"||!A.id||typeof A.name!="string"||!A.name||A.description!==void 0&&typeof A.description!="string")throw new TypeError("Harness returned an invalid model");return{id:A.id,name:A.name,...A.description===void 0?{}:{description:A.description},...A.reasoning===void 0?{}:{reasoning:wEe(A.reasoning)}}})}}),a=n.failures.map(i=>{if(!i||typeof i!="object"||typeof i.id!="string"||!i.id||typeof i.name!="string"||!i.name)throw new TypeError("Harness returned an invalid model provider failure");return{id:i.id,name:i.name}}),e=null;if(n.current!==void 0){if(!n.current||typeof n.current!="object"||typeof n.current.provider!="string"||!n.current.provider||typeof n.current.model!="string"||!n.current.model||n.current.reasoningEffort!==void 0&&(typeof n.current.reasoningEffort!="string"||!n.current.reasoningEffort))throw new TypeError("Harness returned an invalid current model");e={provider:n.current.provider,model:n.current.model,...n.current.reasoningEffort===void 0?{}:{reasoningEffort:n.current.reasoningEffort}}}else if(t)throw new TypeError("Harness returned no current model");return{groups:o,failures:a,current:e}}function Bg(n,t){return`${n}/${t}`}function O1(n,t){return n?.provider===t?.provider&&n?.model===t?.model}function DEe(n,t){return O1(n,t)&&n?.reasoningEffort===t?.reasoningEffort}function OEe(n,t){return O1(n,t)&&(t.reasoningEffort===void 0||n?.reasoningEffort===t.reasoningEffort)}function tT(n){if(!n?.provider||!n?.model)return"";let t=Bg(n.provider,n.model);return n.reasoningEffort===void 0?t:`${t} \xB7 reasoningEffort=${oi(n.reasoningEffort)}`}function d1(n,t,o){let a=new Error(`Harness ${o} did not confirm the selected model`);return a.code=w1,a.expected=n,a.actual=t,a.source=o,a}function b1(){let n=new Error("Conversation binding changed during model selection");return n.code=S1,n}function p1(n,t,o){if((typeof n?.sessionFor=="function"?n.sessionFor(t):null)!==o)throw b1()}function bEe(n,t){for(let o of n.groups)for(let a of o.models)if(Bg(o.id,a.id)===t)return{provider:o.id,model:a.id};return null}function MEe(n,t){let o=0;for(let a of n.groups)for(let e of a.models)if(o+=1,o===t)return{provider:a.id,model:e.id};return null}function h1(n){if(!/^\d+$/u.test(n))return null;let t=Number(n);return{index:Number.isSafeInteger(t)&&t>0?t:null}}function ZQ(n,t){return t?n.groups.find(({id:a})=>a===t.provider)?.models.find(({id:a})=>a===t.model)??null:null}function _Ee(n,t){return n?.reasoning?.efforts?.[t-1]??null}function rT(n,t){return n?.reasoning?.efforts?.find(({id:o})=>o===t)??null}function XQ(n,t){return n?.reasoningEffort??t?.reasoning?.defaultEffort}function Iu(n,t){if(t===void 0)return w("Default\uFF08\u7531\u6A21\u578B\u6216 Provider \u51B3\u5B9A\uFF09");let o=rT(n,t);if(!o)return oi(t);let a=oi(o.name),e=oi(o.id);return a===e?e:`${a} (${e})`}function M1(n){let t=ZQ(n,n.current);return Iu(t,XQ(n.current,t))}function TEe(n,t,o){return n===t&&n===o?w("\uFF08\u5F53\u524D\u3001\u9ED8\u8BA4\uFF09"):n===t?w("\uFF08\u5F53\u524D\uFF09"):n===o?w("\uFF08\u9ED8\u8BA4\uFF09"):""}function E1(n){return[w("\u6A21\u578B\u5E8F\u53F7\u65E0\u6548\uFF1A{input}",{input:oi(n)}),"",w("\u8BF7\u53D1\u9001 /models \u67E5\u770B\u5E76\u8F93\u5165\u6709\u6548\u7684\u6B63\u6574\u6570\u5E8F\u53F7\u3002")].join(` `)}function u1(n){return[w("\u63A8\u7406\u7B49\u7EA7\u5E8F\u53F7\u65E0\u6548\uFF1A{input}",{input:oi(n)}),"",w("\u8BF7\u53D1\u9001 /reasoninglist \u67E5\u770B\u5E76\u8F93\u5165\u6709\u6548\u7684\u6B63\u6574\u6570\u5E8F\u53F7\u3002")].join(` `)}function $_(n,t,o){let a=[w("\u6A21\u578B\u4E0D\u652F\u6301\u63A8\u7406\u7B49\u7EA7\uFF1A{effort}",{effort:oi(t)}),"",oi(tT(n))],e=o?.reasoning?.efforts?.map(({id:i})=>oi(i))??[];return e.length>0?a.push(w("\u53EF\u7528\u63A8\u7406\u7B49\u7EA7\uFF1A{efforts}",{efforts:e.join(", ")})):a.push(w("\u8BE5\u6A21\u578B\u4E0D\u63D0\u4F9B\u53EF\u5207\u6362\u7684\u63A8\u7406\u7B49\u7EA7\u3002")),a.join(` diff --git a/package.json b/package.json index 0e6633d..6ae0eff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dsh-im-ops", - "version": "4.9.1-ops.12", + "version": "4.9.1-ops.13", "description": "Ops fork of dsh-im (all channels kept). Based on @xmanrui/dsh-im@4.9.1 — access/session policies owned here.", "keywords": [ "deepseek-harness", diff --git a/plugin-src/client/index.js b/plugin-src/client/index.js index 03d0138..c5c7c67 100644 --- a/plugin-src/client/index.js +++ b/plugin-src/client/index.js @@ -182,6 +182,7 @@ export function IMSettingsTab({ const [runningVersion, setRunningVersion] = React.useState(IM_PLUGIN_VERSION); const [deliverySettings, setDeliverySettings] = React.useState(null); const githubTooltipId = React.useId(); + const channelSelectId = React.useId(); const active = CHANNELS.find((channel) => channel.id === selected) ?? CHANNELS[0]; const reportLoopbackRecovery = React.useCallback((recovery) => { setLoopbackRecovery((current) => current?.url === recovery.url ? current : recovery); @@ -256,31 +257,30 @@ export function IMSettingsTab({ }, '帮助与反馈 · 前往 GitHub'))), ), h('div', { className: 'dim-layout' }, - h('nav', { className: 'dim-rail', role: 'tablist', 'aria-label': 'IM 渠道' }, - CHANNELS.map((channel) => h('button', { - key: channel.id, - type: 'button', - role: 'tab', - id: `dim-tab-${channel.id}`, - className: 'dim-channel', - 'aria-selected': channel.id === active.id, - 'aria-controls': `dim-panel-${channel.id}`, - onClick: () => { - setSelected(channel.id); - setDeliverySettings(null); - }, - }, - h(ChannelLogo, { channel: channel.id }), - h('span', { className: 'dim-channelCopy' }, - h('strong', null, channel.label), - channel.note ? h('small', { className: 'dim-channelNote' }, channel.note) : null, - )))), - h('div', { className: 'dim-divider', 'aria-hidden': 'true' }), + h('div', { className: 'dim-channelPicker' }, + h('label', { + className: 'dim-channelPickerLabel', + htmlFor: channelSelectId, + }, 'IM 渠道'), + h('div', { className: 'dim-channelPickerControl' }, + h(ChannelLogo, { channel: active.id }), + h('select', { + id: channelSelectId, + className: 'dim-channelPickerSelect', + value: active.id, + 'aria-label': 'IM 渠道', + onChange: (event) => { + setSelected(event.target.value); + setDeliverySettings(null); + }, + }, CHANNELS.map((channel) => h('option', { + key: channel.id, + value: channel.id, + }, channel.label, channel.note || null))))), h('main', { className: 'dim-panel', - role: 'tabpanel', id: `dim-panel-${active.id}`, - 'aria-labelledby': `dim-tab-${active.id}`, + 'aria-label': active.label, }, loopbackRecovery ? h(LoopbackRecoveryNotice, { diff --git a/plugin-src/client/styles.js b/plugin-src/client/styles.js index 368e8a9..abd1a9d 100644 --- a/plugin-src/client/styles.js +++ b/plugin-src/client/styles.js @@ -61,14 +61,13 @@ const CSS = String.raw` .dim-githubArrow { font-size: 13px; line-height: 1; } .dim-githubTooltip { position: absolute; top: calc(100% + 8px); right: 0; z-index: 20; width: max-content; max-width: min(220px, 80vw); padding: 6px 9px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 7px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 8px 24px rgb(31 35 41 / 14%); font-size: 11px; line-height: 16px; font-weight: 500; white-space: nowrap; opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; } .dim-githubAction:hover .dim-githubTooltip, .dim-githubAction:focus-within .dim-githubTooltip { opacity: 1; visibility: visible; transform: translateY(0); } -.dim-layout { display: grid; grid-template-columns: 174px 1px minmax(0, 1fr); gap: 24px; align-items: start; } -.dim-rail { max-height: 520px; display: grid; align-content: start; gap: 8px; overflow-y: auto; padding: 0 4px 1px 1px; scrollbar-width: thin; scrollbar-color: var(--dsw-alias-border-l2, #dfe1e5) transparent; } -.dim-rail::-webkit-scrollbar { width: 4px; } -.dim-rail::-webkit-scrollbar-thumb { border-radius: 99px; background: var(--dsw-alias-border-l2, #dfe1e5); } -.dim-channel { width: 100%; min-height: 48px; display: grid; grid-template-columns: 30px minmax(0, 1fr); align-items: center; gap: 10px; padding: 8px 12px; border: 1px solid var(--dsw-alias-border-l2, #eef0f3); border-radius: 14px; color: inherit; background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 2px 8px rgb(31 35 41 / 3%); font: inherit; text-align: left; cursor: pointer; transition: border-color .16s ease, background .16s ease, box-shadow .16s ease; } -.dim-channel:hover { border-color: color-mix(in srgb, var(--dim-blue) 25%, var(--dsw-alias-border-l2, #eef0f3)); background: color-mix(in srgb, var(--dim-blue) 2%, var(--dsw-alias-bg-layer-3, #fff)); box-shadow: 0 5px 16px rgb(31 35 41 / 5%); } -.dim-channel[aria-selected="true"] { border-color: color-mix(in srgb, var(--dim-blue) 43%, var(--dsw-alias-border-l2, #dfe1e5)); color: var(--dim-blue); background: color-mix(in srgb, var(--dim-blue) 12%, var(--dsw-alias-bg-layer-3, #fff)); box-shadow: 0 3px 12px rgb(51 112 255 / 7%); } -.dim-channel:focus-visible { outline: none; border-color: color-mix(in srgb, var(--dim-blue) 72%, var(--dsw-alias-border-l2, #dfe1e5)); box-shadow: 0 0 0 1px color-mix(in srgb, var(--dim-blue) 24%, transparent) inset, 0 3px 12px rgb(51 112 255 / 7%); } +.dim-layout { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; align-items: start; } +.dim-channelPicker { min-width: 0; display: flex; align-items: center; gap: 10px; } +.dim-channelPickerLabel { flex: none; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; line-height: 18px; font-weight: 560; white-space: nowrap; } +.dim-channelPickerControl { min-width: 0; flex: 1 1 auto; display: grid; grid-template-columns: 30px minmax(0, 1fr); align-items: center; gap: 10px; max-width: 420px; padding: 4px 10px 4px 6px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 10px; background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 1px 2px rgb(31 35 41 / 4%); } +.dim-channelPickerSelect { min-width: 0; width: 100%; height: 34px; padding: 0 4px 0 0; border: 0; border-radius: 6px; color: var(--dsw-alias-label-primary, #1f2329); background: transparent; font: inherit; font-size: 14px; font-weight: 650; cursor: pointer; } +.dim-channelPickerSelect:focus { outline: none; } +.dim-channelPickerControl:focus-within { border-color: color-mix(in srgb, var(--dim-blue) 55%, var(--dsw-alias-border-l2, #dfe1e5)); box-shadow: 0 0 0 3px color-mix(in srgb, var(--dim-blue) 16%, transparent); } .dim-logo { width: 30px; height: 30px; display: grid; place-items: center; border-radius: 9px; box-shadow: 0 1px 3px rgb(31 35 41 / 7%); } .dim-logo svg { display: block; width: 20px; height: 20px; } .dim-logoWeixin { color: white; background: #07c160; } @@ -91,10 +90,6 @@ const CSS = String.raw` .dim-logoSlack svg { width: 21px; height: 21px; } .dim-logoWhatsapp { color: white; background: #25d366; } .dim-logoWhatsapp svg { width: 21px; height: 21px; } -.dim-channelCopy { min-width: 0; display: grid; } -.dim-channelCopy strong { overflow: hidden; color: inherit; font-size: 14px; line-height: 20px; font-weight: 680; text-overflow: ellipsis; white-space: nowrap; } -.dim-channelNote { overflow: hidden; color: var(--dsw-alias-label-tertiary, #8f959e); font-size: 10px; line-height: 13px; font-weight: 500; text-overflow: ellipsis; white-space: nowrap; } -.dim-divider { width: 1px; min-height: 520px; background: var(--dsw-alias-border-l1, #eef0f3); } .dim-panel { min-width: 0; container-type: inline-size; } .dim-loopbackRecovery { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin: 0 0 14px; padding: 14px 16px; border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary, #d97706) 30%, var(--dsw-alias-border-l2, #dfe1e5)); border-radius: 12px; color: var(--dsw-alias-label-primary, #1f2329); background: color-mix(in srgb, var(--dsw-alias-state-warn-primary, #d97706) 8%, var(--dsw-alias-bg-layer-1, #fff)); } .dim-loopbackRecoveryCopy { min-width: 0; } @@ -525,11 +520,7 @@ const CSS = String.raw` } @media (max-width: 840px) { .dim-title { align-items: flex-start; } - .dim-layout { grid-template-columns: minmax(0, 1fr); gap: 18px; } - .dim-rail { grid-template-columns: repeat(2, minmax(0, 1fr)); } - .dim-divider { display: none; } - .dim-rail { max-height: none; overflow: visible; padding-right: 1px; } - .dim-channel { min-height: 48px; } + .dim-channelPickerControl { max-width: none; } } @media (max-width: 560px) { .dim-title { flex-direction: column; gap: 10px; } @@ -542,7 +533,8 @@ const CSS = String.raw` .dim-updateBody { padding: 16px 18px; } .dim-updateFooter { padding: 12px 18px; } .dim-githubTooltip { right: auto; left: 0; } - .dim-rail { grid-template-columns: minmax(0, 1fr); } + .dim-channelPicker { align-items: stretch; flex-direction: column; gap: 6px; } + .dim-channelPickerControl { max-width: none; } .dim-loopbackRecovery { align-items: stretch; flex-direction: column; gap: 12px; } .dim-loopbackRecoveryAction { width: 100%; } .dim-deliverySectionHeading { align-items: stretch; flex-direction: column; } diff --git a/test/client-ui.test.mjs b/test/client-ui.test.mjs index b882267..16636f2 100644 --- a/test/client-ui.test.mjs +++ b/test/client-ui.test.mjs @@ -147,6 +147,8 @@ test('IM settings renders nine IM channels plus the AI Office connector', async assert.match(styles, /\.dim-githubTooltip \{[^}]*top: calc\(100% \+ 8px\);[^}]*transform: translateY\(-3px\);/); assert.match(styles, /\.dim-githubAction:hover \.dim-githubTooltip, \.dim-githubAction:focus-within \.dim-githubTooltip \{[^}]*opacity: 1;[^}]*visibility: visible;/); assert.doesNotMatch(markup, /\d+ 个渠道|dim-channelCount/); + assert.match(markup, /dim-channelPickerSelect/); + assert.match(markup, /aria-label="IM 渠道"/); assert.match(markup, />微信飞书钉钉TelegramDiscordWhatsAppAI Office<\/strong>(实验功能)<\/small>/); + assert.match(markup, />AI Office(实验功能)]*value="weixin"[^>]*selected=""/); + assert.doesNotMatch(markup, /role="tab"|role="tablist"|role="tabpanel"/); assert.doesNotMatch(markup, /role="switch"|type="checkbox"/); assert.doesNotMatch(markup, /dim-chevron|扫码绑定<\/small>|扫码接入<\/small>/); assert.doesNotMatch(markup, />INSTANT MESSAGING<|>Channel<|>微信设置 { assert.match(styles, /--dim-blue: var\(--dsw-alias-state-business-primary, #3370ff\)/); assert.match( styles, - /\.dim-channel\[aria-selected="true"\][^}]*var\(--dsw-alias-bg-layer-3/, + /\.dim-channelPickerControl:focus-within[^}]*var\(--dim-blue\)/, ); assert.match( styles, @@ -450,8 +454,8 @@ test('all channel settings states use the DingTalk page treatment', async () => assert.match(styles, /\.dim-panel \.dim-confirm \{[^}]*padding: 18px 24px;[^}]*border-top: 1px solid/); }); -test('bot cards reuse the same channel brand logos as the channel rail', () => { - const railMarkup = renderToStaticMarkup(React.createElement(IMSettingsTab, { +test('bot cards reuse the same channel brand logos as the channel picker', () => { + const pickerMarkup = renderToStaticMarkup(React.createElement(IMSettingsTab, { feishuRpcCall: async () => ({ ok: true, value: {} }), weixinRpcCall: async () => ({ ok: true, value: {} }), dingtalkRpcCall: async () => ({ ok: true, value: {} }), @@ -472,9 +476,8 @@ test('bot cards reuse the same channel brand logos as the channel rail', () => { onCancelRemove() {}, })); - assert.match(railMarkup, /data-im-channel-logo="weixin"/); - assert.match(railMarkup, /data-im-channel-logo="feishu"/); - assert.match(railMarkup, /data-im-channel-logo="wecom"/); + assert.match(pickerMarkup, /dim-channelPickerSelect/); + assert.match(pickerMarkup, /data-im-channel-logo="weixin"/); assert.match(accountMarkup, /class="dxw-card dim-botCard"/); assert.match(accountMarkup, /class="dxw-avatar dim-botAvatar"[^]*data-im-channel-logo="weixin"/); assert.match(accountMarkup, /class="dxw-health dim-botHealth"/); @@ -813,7 +816,7 @@ test('client registers one top-level bilingual IM settings section with a direct assert.match(markup, /Help & feedback · Open GitHub/); assert.match(markup, />WeChat<|>Feishu<|>DingTalk<|>WeComQQ<[^]*>Slack<[^]*>Telegram<[^]*>Discord<[^]*>WhatsAppAI Office<\/strong>\(Experimental\)<\/small>/); + assert.match(markup, />AI Office\(Experimental\)