From 87e44bd36e41db1cdda1a8228c48a1514c5ed336 Mon Sep 17 00:00:00 2001 From: oliver Date: Sat, 5 Sep 2026 17:44:17 +0800 Subject: [PATCH] Hide fully authorized contacts from the quick-grant list (4.9.1-ops.11). Recent contacts only show people who still need DM or group access actions. Co-authored-by: Cursor --- lib/client.js | 47 ++++++++++++---- lib/index.js | 4 +- package.json | 2 +- plugin-src/client/access-grant-settings.js | 64 +++++++++++++++++----- plugin-src/client/i18n.js | 4 +- 5 files changed, 92 insertions(+), 29 deletions(-) diff --git a/lib/client.js b/lib/client.js index 22b0f0e..2fe4620 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.10", + version: "4.9.1-ops.11", 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", @@ -876,7 +876,8 @@ var EN = Object.freeze({ "\u5DF2\u52A0\u5165\u672C\u7FA4\u6388\u6743\uFF0C\u8BB0\u5F97\u70B9\u4FDD\u5B58\u3002": "Added to this group. Remember to save.", "\u5DF2\u52A0\u5165\u79C1\u804A\u6388\u6743\uFF0C\u8BB0\u5F97\u70B9\u4FDD\u5B58\u3002": "Added to DM access. Remember to save.", "\u6682\u65E0\u8054\u7CFB\u4EBA\u3002\u6709\u4EBA\u79C1\u804A\u6216 @ \u673A\u5668\u4EBA\u540E\u4F1A\u51FA\u73B0\u5728\u6B64\u3002": "No contacts yet. They appear here after someone DMs or @mentions the bot.", - "\u4EC5\u8BB0\u5F55\u79C1\u804A\u673A\u5668\u4EBA\uFF0C\u6216\u5728\u7FA4\u91CC @ \u673A\u5668\u4EBA\u7684\u4EBA\u3002\u7535\u8BDD\u662F\u552F\u4E00\u6388\u6743\u952E\uFF0C\u53EF\u4E00\u952E\u52A0\u5165\u79C1\u804A/\u672C\u7FA4\u6388\u6743\u3002": "Only people who DM the bot or @mention it in a group are recorded. Phone is the sole auth key; use one-click to grant DM or group access.", + "\u5F53\u524D\u8054\u7CFB\u4EBA\u5747\u5DF2\u5177\u5907\u5BF9\u5E94\u6743\u9650\uFF0C\u65E0\u9700\u518D\u6388\u6743\u3002": "Everyone in contacts already has the matching access; nothing left to grant.", + "\u4EC5\u8BB0\u5F55\u79C1\u804A\u673A\u5668\u4EBA\uFF0C\u6216\u5728\u7FA4\u91CC @ \u673A\u5668\u4EBA\u7684\u4EBA\u3002\u5DF2\u6709\u5BF9\u5E94\u6743\u9650\u7684\u4EBA\u4F1A\u81EA\u52A8\u9690\u85CF\uFF1B\u7535\u8BDD\u662F\u552F\u4E00\u6388\u6743\u952E\uFF0C\u53EF\u4E00\u952E\u52A0\u5165\u79C1\u804A/\u672C\u7FA4\u6388\u6743\u3002": "Only people who DM the bot or @mention it in a group are recorded. People who already have the matching access are hidden. Phone is the sole auth key; use one-click to grant DM or group access.", "WhatsApp \u6309\u7535\u8BDD\u53F7\u7801\u6388\u6743\uFF1A\u5168\u5C40\u7BA1\u7406\u5458\u7BA1\u79C1\u804A\uFF1B\u7FA4\u7BA1\u7406\u5458\u53EA\u6279\u672C\u7FA4\u3002\u6210\u5458\u4E0D\u53EF\u8DE8\u7FA4\u3001\u6709\u7FA4\u6743\u4E5F\u4E0D\u81EA\u52A8\u83B7\u5F97\u79C1\u804A\u6743\u3002": "WhatsApp authorizes by phone number: global admins manage DMs; group admins approve only their group. Members do not cross groups, and group access does not grant DMs.", "\u4FDD\u5B58\u5206\u7EA7\u8BBF\u95EE\u8BBE\u7F6E": "Save graded access settings", "\u4FDD\u5B58\u8BBF\u95EE\u4E0E\u4F1A\u8BDD\u8BBE\u7F6E": "Save access and session settings", @@ -12614,6 +12615,17 @@ function groupDisplayName(groupJid, groups) { if (typeof title === "string" && title.trim()) return title.trim(); return "\u672A\u547D\u540D\u7FA4"; } +function contactNeedsGrantAction(contact, draft, knownGroupJids) { + const phone = contact?.phone || ""; + if (!phone) return true; + if ((draft.globalAdmins ?? []).includes(phone)) return false; + const alreadyDirect = (draft.directMembers ?? []).some((m) => m.phone === phone); + const pendingGroups = (contact.groupJids ?? []).filter((jid) => knownGroupJids.includes(jid)).filter((groupJid) => { + const group = draft.groups?.[groupJid] ?? { admins: [], members: [] }; + return !(group.admins ?? []).includes(phone) && !(group.members ?? []).some((m) => m.phone === phone); + }); + return !alreadyDirect || pendingGroups.length > 0; +} function digitsOnly(value) { return String(value ?? "").replace(/[^\d]/g, ""); } @@ -12885,6 +12897,10 @@ function AccessGrantSettingsPage({ channel: channel4, account, rpcCall, onSaved } return [...set].sort(); }, [draft.groups, draft.pending, contacts]); + const actionableContacts = React21.useMemo( + () => contacts.filter((contact) => contactNeedsGrantAction(contact, draft, knownGroupJids)), + [contacts, draft, knownGroupJids] + ); const resolvePending = async (pendingId, action) => { setFeedback(null); setSaving(true); @@ -13167,12 +13183,20 @@ function AccessGrantSettingsPage({ channel: channel4, account, rpcCall, onSaved h2( "p", { className: "dim-accessUsersEmpty" }, - "\u4EC5\u8BB0\u5F55\u79C1\u804A\u673A\u5668\u4EBA\uFF0C\u6216\u5728\u7FA4\u91CC @ \u673A\u5668\u4EBA\u7684\u4EBA\u3002\u7535\u8BDD\u662F\u552F\u4E00\u6388\u6743\u952E\uFF0C\u53EF\u4E00\u952E\u52A0\u5165\u79C1\u804A/\u672C\u7FA4\u6388\u6743\u3002" + "\u4EC5\u8BB0\u5F55\u79C1\u804A\u673A\u5668\u4EBA\uFF0C\u6216\u5728\u7FA4\u91CC @ \u673A\u5668\u4EBA\u7684\u4EBA\u3002\u5DF2\u6709\u5BF9\u5E94\u6743\u9650\u7684\u4EBA\u4F1A\u81EA\u52A8\u9690\u85CF\uFF1B\u7535\u8BDD\u662F\u552F\u4E00\u6388\u6743\u952E\uFF0C\u53EF\u4E00\u952E\u52A0\u5165\u79C1\u804A/\u672C\u7FA4\u6388\u6743\u3002" ), - contacts.length === 0 ? h2("div", { className: "dim-accessUsersEmpty" }, "\u6682\u65E0\u8054\u7CFB\u4EBA\u3002\u6709\u4EBA\u79C1\u804A\u6216 @ \u673A\u5668\u4EBA\u540E\u4F1A\u51FA\u73B0\u5728\u6B64\u3002") : h2("ul", { className: "dim-accessUserList" }, contacts.slice(0, 30).map((contact) => { + actionableContacts.length === 0 ? h2( + "div", + { className: "dim-accessUsersEmpty" }, + contacts.length === 0 ? "\u6682\u65E0\u8054\u7CFB\u4EBA\u3002\u6709\u4EBA\u79C1\u804A\u6216 @ \u673A\u5668\u4EBA\u540E\u4F1A\u51FA\u73B0\u5728\u6B64\u3002" : "\u5F53\u524D\u8054\u7CFB\u4EBA\u5747\u5DF2\u5177\u5907\u5BF9\u5E94\u6743\u9650\uFF0C\u65E0\u9700\u518D\u6388\u6743\u3002" + ) : h2("ul", { className: "dim-accessUserList" }, actionableContacts.slice(0, 30).map((contact) => { const phone = contact.phone || ""; - const alreadyDirect = phone && draft.directMembers.some((m) => m.phone === phone); - const groupTargets = (contact.groupJids ?? []).filter((jid) => knownGroupJids.includes(jid)); + const alreadyDirect = Boolean(phone) && ((draft.directMembers ?? []).some((m) => m.phone === phone) || (draft.globalAdmins ?? []).includes(phone)); + const groupTargets = (contact.groupJids ?? []).filter((jid) => knownGroupJids.includes(jid)).filter((groupJid) => { + if (!phone) return true; + const group = draft.groups[groupJid] ?? { admins: [], members: [] }; + return !(group.admins ?? []).includes(phone) && !(group.members ?? []).some((m) => m.phone === phone); + }); return h2( "li", { @@ -13186,11 +13210,11 @@ function AccessGrantSettingsPage({ channel: channel4, account, rpcCall, onSaved h2("span", null, (contact.scenes ?? []).join(" / ")), phone ? null : h2("span", null, "\u5F85\u8865\u7535\u8BDD") ), - phone ? h2("button", { + phone && !alreadyDirect ? h2("button", { type: "button", className: "dim-deliveryButton", "data-kind": "primary", - disabled: saving || alreadyDirect, + disabled: saving, onClick: () => { setDraft((current) => { if (current.directMembers.some((m) => m.phone === phone)) return current; @@ -13204,16 +13228,15 @@ function AccessGrantSettingsPage({ channel: channel4, account, rpcCall, onSaved }); setFeedback({ tone: "success", message: "\u5DF2\u52A0\u5165\u79C1\u804A\u6388\u6743\uFF0C\u8BB0\u5F97\u70B9\u4FDD\u5B58\u3002" }); } - }, alreadyDirect ? "\u5DF2\u5728\u79C1\u804A" : "\u52A0\u79C1\u804A") : null, + }, "\u52A0\u79C1\u804A") : null, ...groupTargets.map((groupJid) => { const group = draft.groups[groupJid] ?? { admins: [], members: [] }; const name2 = groupDisplayName(groupJid, draft.groups); - const already = group.admins.includes(phone) || group.members.some((m) => m.phone === phone); return h2("button", { key: `add-${groupJid}`, type: "button", className: "dim-deliveryButton", - disabled: saving || !phone || already, + disabled: saving || !phone, onClick: () => { setDraft((current) => { const existing = current.groups[groupJid] ?? { title: "", admins: [], members: [] }; @@ -13239,7 +13262,7 @@ function AccessGrantSettingsPage({ channel: channel4, account, rpcCall, onSaved message: ["\u5DF2\u52A0\u5165\u7FA4\u6388\u6743\uFF1A", name2, "\u3002\u8BB0\u5F97\u70B9\u4FDD\u5B58\u3002"].join("") }); } - }, [already ? "\u5DF2\u5728\u7FA4\uFF1A" : "\u52A0\u5165\u7FA4\uFF1A", name2].join("")); + }, ["\u52A0\u5165\u7FA4\uFF1A", name2].join("")); }) ); })) diff --git a/lib/index.js b/lib/index.js index e561458..dc3d45f 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.10",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.11",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(` @@ -378,7 +378,7 @@ ${w("\u5185\u5BB9\u8F83\u957F\uFF0C\u751F\u6210\u5B8C\u6210\u540E\u5C06\u5206\u6 `)+1;e(A&&(i=await this.#o(t,a.replyTo),e.push(i),A=!1),i),g={get messageId(){return i.messageId},rotate:async()=>{if(!A){A=!0;try{await this.#g(i,`${pG(r)} ${w("\u2935\uFE0F \u6700\u7EC8\u7ED3\u679C\u89C1\u4E0B\u65B9")}`),await this.#i(i)}catch(I){console.warn("[dsh-feishu] unable to finalize the superseded stream card:",I.message)}}},setContent:async I=>{let d=String(I??"")||"\u2026",B=await s();await this.#g(B,pG(d)),r=d}};await o.markdown(g);let c=OGe(r);for(let[I,d]of c.entries()){let B=I===0?await s():await this.#o(t,a.replyTo);I>0&&e.push(B),await this.#g(B,d),await this.#i(B)}return{messageId:e[0].messageId,providerMessageIds:e.map(I=>I.messageId)}}catch(r){for(let s of e)await this.#s(s.messageId);throw r}}async sendFile(t,o,{replyTo:a,signal:e}={}){return this.#I(t,o,{replyTo:a,signal:e,messageType:"file",presentation:"feishu-file"})}async sendImage(t,o,{replyTo:a,signal:e}={}){return this.#I(t,o,{replyTo:a,signal:e,messageType:"image",presentation:"feishu-image"})}async#I(t,o,{replyTo:a,signal:e,messageType:i,presentation:A}){if(e?.throwIfAborted(),typeof t!="string"||!t)throw new TypeError("chatId is required");if(!o||typeof o!="object"||typeof o.artifactId!="string"||!o.artifactId||typeof o.deliveryKey!="string"||!o.deliveryKey||typeof o.fileName!="string"||!o.fileName||!Buffer.isBuffer(o.bytes))throw new TypeError("A materialized result file is required");let r;try{r=await pZ(Q=>{Q.throwIfAborted();let y=i==="image"?this.#e.im.v1.image.create({data:{image_type:"message",image:o.bytes}}):this.#e.im.v1.file.create({data:{file_type:"stream",file_name:o.fileName,file:o.bytes}});return On(o,y),y},{signal:e,timeoutMs:this.#t,stage:"upload"})}catch(Q){throw e?.aborted?hG(e):eB("upload",Q)}e?.throwIfAborted();let s=i==="image"?r?.image_key??r?.data?.image_key:r?.file_key??r?.data?.file_key;if(typeof s!="string"||!s)throw eB("upload",void 0,r?.code);let g=wGe(o,t,i),c=JSON.stringify(i==="image"?{image_key:s}:{file_key:s}),I=a?{path:{message_id:a},data:{msg_type:i,content:c,uuid:g}}:{params:{receive_id_type:"chat_id"},data:{receive_id:t,msg_type:i,content:c,uuid:g}},d=()=>{let Q=a?this.#e.im.v1.message.reply(I):this.#e.im.v1.message.create(I);return On(o,Q),Q},B;try{B=await pZ(async Q=>{Q.throwIfAborted();let y;try{y=await d()}catch(m){if(uZ(m)!==230049)throw m;y={code:230049}}return Q.throwIfAborted(),Number(y?.code)===230049&&(y=await d(),Q.throwIfAborted()),y},{signal:e,timeoutMs:this.#r,stage:"message send"})}catch(Q){throw e?.aborted?hG(e):eB("message send",Q,void 0,{uncertain:!0})}if(Number.isFinite(Number(B?.code))&&Number(B.code)!==0)throw eB("message send",void 0,B.code,{uncertain:!0});let f=B?.data?.message_id;if(typeof f!="string"||!f)throw eB("message send",void 0,void 0,{uncertain:!0});return rr({deliveryId:o.deliveryKey,presentation:A,providerMessageIds:[f],artifacts:[{artifactId:o.artifactId,outcome:"sent"}]})}async#o(t,o){let a=pG(this.#A),i=Pl("Feishu card.create",await this.#e.cardkit.v1.card.create({data:{type:"card_json",data:JSON.stringify(bGe(a))}}))?.data?.card_id;if(!i)throw new Error("Feishu card.create returned no card_id");let A=await this.#a(t,i,o);return{cardId:i,messageId:A,content:a,sequence:0}}async#g(t,o){if(o===t.content)return;let a=await this.#e.cardkit.v1.cardElement.content({path:{card_id:t.cardId,element_id:hZ},data:{content:o,sequence:++t.sequence,uuid:`content_${t.cardId}_${t.sequence}`}});Pl("Feishu cardElement.content",a),t.content=o}async#i(t){let o=await this.#e.cardkit.v1.card.settings({path:{card_id:t.cardId},data:{settings:JSON.stringify({config:{streaming_mode:!1,summary:{content:DGe(t.content)||w("\u56DE\u7B54\u5B8C\u6210")}}}),sequence:++t.sequence,uuid:`settings_${t.cardId}_${t.sequence}`}});Pl("Feishu card.settings",o)}async#a(t,o,a){let e=JSON.stringify({type:"card",data:{card_id:o}}),i=a?await this.#e.im.v1.message.reply({path:{message_id:a},data:{msg_type:"interactive",content:e}}):await this.#e.im.v1.message.create({params:{receive_id_type:"chat_id"},data:{receive_id:t,msg_type:"interactive",content:e}});Pl("Feishu message send",i);let A=i?.data?.message_id;if(!A)throw new Error("Feishu message send returned no message_id");return A}async#s(t){try{let o=await this.#e.im.v1.message.delete({path:{message_id:t}});Pl("Feishu message delete",o)}catch(o){console.warn("[bridge] unable to recall a failed streaming card:",o.message)}}async addReaction(t,o){let e=Pl("Feishu reaction.create",await this.#e.im.v1.messageReaction.create({path:{message_id:t},data:{reaction_type:{emoji_type:o}}}))?.data?.reaction_id;if(!e)throw new Error("Feishu reaction.create returned no reaction_id");return e}async removeReaction(t,o){Pl("Feishu reaction.delete",await this.#e.im.v1.messageReaction.delete({path:{message_id:t,reaction_id:o}}))}};var BZ="/open-apis/application/v7/app_slash_commands",MGe=new Set(["99991640","99991672"]),$S=Object.freeze(["application:app_slash_command:read","application:app_slash_command:write"]),fZ="ai-agent_outlined",uG=Object.freeze([{command:"menu",icon:"skill_outlined",default:"\u6253\u5F00\u529F\u80FD\u83DC\u5355",en_us:"Open the feature menu"},{command:"new",icon:"ai-deepthink_outlined",default:"\u5F00\u542F\u5168\u65B0\u4F1A\u8BDD",en_us:"Start a fresh session"},{command:"help",icon:"promptword_outlined",default:"\u67E5\u770B\u5E2E\u52A9",en_us:"Show help"},{command:"status",icon:"ai-functions_outlined",default:"\u67E5\u770B\u673A\u5668\u4EBA\u72B6\u6001",en_us:"Show bot status"},{command:"compact",icon:"ai-block_outlined",default:"\u538B\u7F29\u5F53\u524D\u4F1A\u8BDD\u4E0A\u4E0B\u6587",en_us:"Compact the current session"},{command:"sessionlist",icon:"chat-ai_outlined",default:"\u5217\u51FA\u4F1A\u8BDD",en_us:"List sessions"},{command:"workspacelist",icon:"folder_outlined",default:"\u5217\u51FA\u5DE5\u4F5C\u533A",en_us:"List workspaces"},{command:"workspaces",icon:"folder_outlined",default:"\u5217\u51FA\u5DE5\u4F5C\u533A",en_us:"List workspaces"},{command:"wsl",icon:"folder_outlined",default:"\u5217\u51FA\u5DE5\u4F5C\u533A",en_us:"List workspaces"},{command:"ws",icon:"folder_outlined",default:"\u5207\u6362\u5DE5\u4F5C\u533A",en_us:"Switch workspace"},{command:"watch",icon:"flag_outlined",default:"\u5173\u6CE8\u4E00\u4E2A\u4F1A\u8BDD",en_us:"Watch a session"},{command:"unwatch",icon:"clear_outlined",default:"\u53D6\u6D88\u5173\u6CE8\u4F1A\u8BDD",en_us:"Unwatch a session"},{command:"watchlist",icon:"flag_outlined",default:"\u67E5\u770B\u5173\u6CE8\u5217\u8868",en_us:"List watched sessions"},{command:"archived",icon:"folder_outlined",default:"\u8BBE\u7F6E\u5F52\u6863\u4F1A\u8BDD\u663E\u9690\uFF08on/off\uFF09",en_us:"Show or hide archived sessions (on/off)"}]);function CG(n,t){let o=n==="lark"?"https://open.larksuite.com":"https://open.feishu.cn";return new URL(t,o)}function CZ(n,t){if(!n||typeof n!="object"||Array.isArray(n))throw new Error(`${t} returned a non-JSON response`);if(n.code!==0){let o=new Error(`${t} failed: ${n.msg||`code ${n.code}`}`);throw o.code=String(n.code),o.msg=n.msg,o}return n}function BG(n,t){let o=AbortSignal.timeout(t);return n?AbortSignal.any([n,o]):o}async function fG(n,t,o){try{return CZ(await n.request(t),o)}catch(a){let e=a?.response?.data;if(e&&typeof e=="object"&&!Array.isArray(e)&&Object.hasOwn(e,"code"))return CZ(e,o);throw a}}async function _Ge({appId:n,appSecret:t,domain:o,httpInstance:a,timeoutMs:e,signal:i}){if(!n||!t)throw new Error("Feishu slash registration requires app credentials");if(!a||typeof a.request!="function")throw new TypeError("Feishu slash registration requires an HTTP instance");let A=await fG(a,{method:"POST",url:CG(o,"/open-apis/auth/v3/tenant_access_token/internal").href,headers:{"content-type":"application/json; charset=utf-8"},data:{app_id:n,app_secret:t},signal:BG(i,e),timeout:e},"Feishu authentication");if(!A.tenant_access_token)throw new Error("Feishu authentication returned no tenant access token");return A.tenant_access_token}async function TGe({tenantAccessToken:n,domain:t,httpInstance:o,timeoutMs:a,signal:e}){let i=await fG(o,{method:"GET",url:CG(t,BZ).href,headers:{authorization:`Bearer ${n}`,"content-type":"application/json; charset=utf-8"},signal:BG(e,a),timeout:a},"Feishu slash command list");return Array.isArray(i.data?.items)?i.data.items:[]}async function NGe({tenantAccessToken:n,domain:t,httpInstance:o,timeoutMs:a,signal:e,command:i,description:A,icon:r=fZ}){let s={command:i};return A&&(A.default_value||A.i18n)?s.description=A:typeof A=="string"&&A.trim()&&(s.description={default_value:A.trim()}),r&&(s.description={...s.description??{},icon:{icon_key:r}}),(await fG(o,{method:"POST",url:CG(t,BZ).href,headers:{authorization:`Bearer ${n}`,"content-type":"application/json; charset=utf-8"},data:s,signal:BG(e,a),timeout:a},`Feishu slash command create (/${i})`)).data?.command_id??null}async function QZ({appId:n,appSecret:t,domain:o="feishu",httpInstance:a,timeoutMs:e=15e3,signal:i,manifest:A=uG}){let r=await _Ge({appId:n,appSecret:t,domain:o,httpInstance:a,timeoutMs:e,signal:i}),s=new Set((await TGe({tenantAccessToken:r,domain:o,httpInstance:a,timeoutMs:e,signal:i})).map(I=>I.command)),g=[],c=[];for(let I of A){let d=String(I.command??"").replace(/^\//,"");if(d&&!s.has(d))try{let B={default_value:I.default??I.en_us??d,i18n:{zh_cn:I.default??d,en_us:I.en_us??I.default??d}},f=await NGe({tenantAccessToken:r,domain:o,httpInstance:a,timeoutMs:e,signal:i,command:d,description:B,icon:I.icon??fZ});g.push({command:d,command_id:f})}catch(B){if(B?.code==="40000000"&&/already exists/i.test(B?.msg??"")){s.add(d);continue}if(MGe.has(B?.code)||/(?:lacks permission|access denied)/i.test(B?.msg??"")){c.push({command:d,error:B});break}c.push({command:d,error:B?.message??String(B)})}}return{created:g,existing:[...s].filter(I=>I!=null),failed:c}}var kGe=15e3,vGe="\u2705 \u4FEE\u590D\u5B8C\u6210\uFF1A\u5DF2\u5B9E\u6D4B\u6536\u5230 card.action.trigger\uFF0C\u83DC\u5355\u6309\u94AE\u73B0\u5728\u53EF\u7528\u3002",PGe="\u26A0\uFE0F \u4FEE\u590D\u9A8C\u8BC1\u8D85\u65F6\uFF1A\u672A\u6536\u5230\u6D4B\u8BD5\u5361\u6309\u94AE\u7684 card.action.trigger\uFF0C\u4E0D\u80FD\u786E\u8BA4\u6309\u94AE\u5DF2\u4FEE\u590D\u3002\u8BF7\u4E0D\u8981\u91CD\u590D\u6388\u6743\uFF1B\u5148\u68C0\u67E5\u98DE\u4E66\u5F00\u653E\u5E73\u53F0\u7684\u5361\u7247\u56DE\u8C03\u914D\u7F6E\uFF0C\u786E\u8BA4\u540E\u518D\u53D1\u9001 /repair\u3002",QG="\u26A0\uFE0F \u4FEE\u590D\u9A8C\u8BC1\u5931\u8D25\uFF1A\u65E0\u6CD5\u53D1\u9001\u4E13\u7528\u6D4B\u8BD5\u5361\uFF0C\u4E0D\u80FD\u786E\u8BA4 card.action.trigger \u5DF2\u6062\u590D\u3002\u8BF7\u4E0D\u8981\u91CD\u590D\u6388\u6743\uFF1B\u5148\u68C0\u67E5\u673A\u5668\u4EBA\u6D88\u606F\u6743\u9650\u548C\u8FDE\u63A5\u72B6\u6001\u3002",GGe="\u26A0\uFE0F \u4FEE\u590D\u9A8C\u8BC1\u4E2D\u65AD\uFF1ARuntime \u5DF2\u505C\u6B62\uFF0C\u672A\u5B8C\u6210 card.action.trigger \u5B9E\u6D4B\uFF0C\u4E0D\u80FD\u786E\u8BA4\u4FEE\u590D\u6210\u529F\u3002\u8BF7\u4E0D\u8981\u91CD\u590D\u6388\u6743\uFF1B\u5148\u7B49\u5F85\u673A\u5668\u4EBA\u6062\u590D\u8FDE\u63A5\u3002",FGe=new Set(["connected","connecting","reconnecting"]);function Un(n){return typeof n=="string"&&n.trim()?n.trim():null}function LGe(n){return Un(n?.operator?.open_id)??Un(n?.operator?.operator_id?.open_id)}function UGe(n,t){try{let o=n?.getConnectionStatus?.()?.state;return typeof o=="string"&&o?o:t}catch{return t}}function ph(n,t){let o=new Error(t);return o.code=n,o}function HGe(n,t){if(!n||typeof n.request!="function")return;let o=a=>({...a??{},timeout:a?.timeout??t});return{request:a=>n.request(o(a)),get:(a,e)=>n.get(a,o(e)),delete:(a,e)=>n.delete(a,o(e)),head:(a,e)=>n.head(a,o(e)),options:(a,e)=>n.options(a,o(e)),post:(a,e,i)=>n.post(a,e,o(i)),put:(a,e,i)=>n.put(a,e,o(i)),patch:(a,e,i)=>n.patch(a,e,o(i))}}function KGe({allowedSenderCount:n=1}={}){return{startedAt:null,ready:!1,feishuLongConnectionState:"idle",harnessReachable:!1,messagesReceived:0,messagesReplied:0,messagesRejected:0,reactionsAdded:0,reactionsRemoved:0,reactionErrors:0,streamResponses:0,streamUpdates:0,streamFallbacks:0,streamErrors:0,cardActionsReceived:0,cardActionProbesVerified:0,lastMessageAt:null,lastReplyAt:null,lastRejectedAt:null,lastCardActionAt:null,lastError:null,agentPreset:"standard",authorizationMode:"sender-open-id-allowlist",allowedSenderCount:n,slashCommandRegistration:"idle",slashCommandsRegistered:0,slashCommandsExisting:0,slashCommandsFailed:0,slashCommandsError:null}}var ew=class{#e;#A;#t;#r;#I;#o;#g;#i;#a;#s;#l;#c;#d;#n;#p;#E;#u;#C;#B=null;#f=null;#y=null;#w=null;#m=null;#Q=null;#D=new Map;#h;#k=!0;constructor({lark:t,botId:o,appId:a,appSecret:e,domain:i="feishu",botOpenId:A,groupResponseMode:r,ownerOpenId:s,ownerOpenIds:g,harness:c,state:I,contextEnhancement:d,accessPolicy:B,repair:f,replyTimeoutMs:Q=6e5,connectTimeoutMs:y=15e3,requestTimeoutMs:m=kGe,slashCommands:_=!0,wsAgent:T,logger:R=console}){if(!t)throw new Error("FeishuRuntime requires the Feishu SDK");if(!a||!e)throw new Error("FeishuRuntime requires app credentials");let L=Array.isArray(g)?g:[s],U=[...new Set(L.filter(F=>typeof F=="string"&&F))];if(U.length===0)throw new Error("FeishuRuntime requires at least one owner open_id");if(!c)throw new Error("FeishuRuntime requires a Harness client");if(!I)throw new Error("FeishuRuntime requires a state store");if(f!=null&&!Un(o))throw new TypeError("FeishuRuntime repair capability requires a botId");if(!Number.isFinite(m)||m<=0)throw new TypeError("FeishuRuntime requestTimeoutMs must be a positive number");this.#e=t,this.#A=Un(o),this.#t=a,this.#r=e,this.#I=i,this.#o=Un(A),this.#g=Bo(r),this.#i=U,this.#a=c,this.#s=I,this.#l=d,this.#c=B,this.#C=f??null,this.#d=Q,this.#n=y,this.#p=m,this.#k=!!_,this.#E=T,this.#u=R,this.#h=KGe({allowedSenderCount:U.length})}get status(){return structuredClone(this.#h)}setGroupResponseMode(t){this.#g=Bo(t),this.#f?.setGroupResponseMode(this.#g)}async start(){for(;;){for(;this.#m;)await this.#m;if(this.#w)return this.#w;let o=this.#y;if(o){let a=UGe(o,this.#h.feishuLongConnectionState);if(FGe.has(a))return this.status;await this.stop({preserveError:a==="failed"});continue}if(this.#B||this.#f||this.#Q){await this.stop({preserveError:this.#h.feishuLongConnectionState==="failed"});continue}break}let t;return t=this.#M().finally(()=>{this.#w===t&&(this.#w=null)}),this.#w=t,t}async#M(){let t=new AbortController;this.#Q=t;let{signal:o}=t,a=()=>o.reason??new DOMException("Feishu runtime stopped","AbortError"),e=()=>!o.aborted&&this.#Q===t,i=()=>{if(!e())throw a()};this.#h.startedAt=new Date().toISOString(),this.#h.feishuLongConnectionState="connecting",this.#h.lastError=null;try{await this.#a.ensureRunning({signal:o}),i(),this.#h.harnessReachable=!0;let A=this.#I==="lark"?this.#e.Domain.Lark:this.#e.Domain.Feishu,r={appId:this.#t,appSecret:this.#r,domain:A},s=HGe(this.#e.defaultHttpInstance,this.#p);s&&(r.httpInstance=s);let g=new this.#e.Client(r);this.#B=g;let c=new XS({client:g,initialText:w("\u5DF2\u8FDE\u63A5 DeepSeek Harness\uFF0C\u6B63\u5728\u601D\u8003\u2026")}),I=new WS({client:g,channel:c,harness:this.#a,state:this.#s,contextEnhancement:this.#l,accessPolicy:this.#c,status:this.#h,allowedSenderOpenIds:new Set(this.#i),botId:this.#A,appId:this.#t,botOpenId:this.#o,groupResponseMode:this.#g,repair:this.#C,replyTimeoutMs:this.#d,interactionCards:!["0","false","no","off"].includes(String(process.env.DSH_IM_INTERACTION_CARDS??"").trim().toLowerCase()),signal:o,logger:this.#u});this.#f=I;let d=new this.#e.EventDispatcher({}).register({"im.message.receive_v1":_=>{e()&&I.accept(_)},"im.message.reaction.created_v1":()=>{},"im.message.reaction.deleted_v1":()=>{},"card.action.trigger":_=>{e()&&(this.#h.cardActionsReceived+=1,this.#h.lastCardActionAt=new Date().toISOString(),this.#O(_)||I.onCardAction(_))}}),B,f,Q=new Promise((_,T)=>{let R=!1,L=()=>{f(a())},U=(z,J)=>{R||(R=!0,clearTimeout(F),o.removeEventListener("abort",L),z(J))},F=setTimeout(()=>{U(T,new Error(`Feishu WebSocket handshake timed out after ${this.#n}ms`))},this.#n);B=()=>{U(_)},f=z=>{U(T,z)},o.addEventListener("abort",L,{once:!0}),o.aborted&&L()});Q.catch(()=>{});let y=new this.#e.WSClient({...r,...this.#E?{agent:this.#E}:{},loggerLevel:this.#e.LoggerLevel.info,handshakeTimeoutMs:this.#n,onReady:()=>{e()&&(this.#h.feishuLongConnectionState="connected",this.#h.ready=!0,this.#h.lastError=null,B())},onError:_=>{e()&&(this.#h.feishuLongConnectionState="failed",this.#h.ready=!1,this.#h.lastError=_?.message??String(_),this.#u.error("[dsh-feishu] Feishu long connection failed:",this.#h.lastError),f(_))},onReconnecting:()=>{e()&&(this.#h.feishuLongConnectionState="reconnecting",this.#h.ready=!1)},onReconnected:()=>{e()&&(this.#h.feishuLongConnectionState="connected",this.#h.ready=!0,this.#h.lastError=null)}});this.#y=y;let m=Promise.resolve().then(()=>y.start({eventDispatcher:d})).catch(_=>{throw f(_),_});return await Promise.all([m,Q]),i(),this.#k&&s&&this.#T(s,e,o),this.status}catch(A){throw o.aborted||(this.#h.ready=!1,this.#h.feishuLongConnectionState="failed",this.#h.lastError=A?.message??String(A),await this.#P({preserveError:!0,abortController:t})),A}}async beginCardActionProbe({expectedOperatorOpenId:t,timeoutMs:o=9e4}={}){if(!this.#h.ready||!this.#B)throw ph("card_action_probe_unavailable","\u98DE\u4E66\u673A\u5668\u4EBA\u5C1A\u672A\u8FDE\u63A5");let a=Un(t);if(!a||a==="*")throw new TypeError("A precise Feishu operator open_id is required");if(!Number.isFinite(o)||o<=0||o>10*6e4)throw new TypeError("Card-action probe timeout must be between 1 and 600000ms");let e=RGe().replaceAll("-",""),i;try{i=await this.#B.im.v1.message.create({params:{receive_id_type:"open_id"},data:{receive_id:a,msg_type:"interactive",content:V5(e)}})}catch{throw this.#S(a,w(QG),"failure"),ph("card_action_probe_send_failed","\u65E0\u6CD5\u53D1\u9001\u98DE\u4E66\u5361\u7247\u56DE\u8C03\u6D4B\u8BD5")}if(i?.code&&i.code!==0)throw this.#S(a,w(QG),"failure"),ph("card_action_probe_send_failed","\u65E0\u6CD5\u53D1\u9001\u98DE\u4E66\u5361\u7247\u56DE\u8C03\u6D4B\u8BD5");let A=Un(i?.data?.message_id)??Un(i?.message_id);if(!A)throw this.#S(a,w(QG),"failure"),ph("card_action_probe_send_failed","\u98DE\u4E66\u672A\u8FD4\u56DE\u6D4B\u8BD5\u5361\u7247\u7684\u6D88\u606F ID");return new Promise((r,s)=>{let g=setTimeout(()=>{let c=this.#D.get(A);!c||c.nonce!==e||(this.#D.delete(A),this.#S(a,w(PGe),"timeout"),s(ph("card_action_probe_timeout","\u5728\u89C4\u5B9A\u65F6\u95F4\u5185\u672A\u6536\u5230\u98DE\u4E66\u5361\u7247\u6309\u94AE\u56DE\u8C03")))},o);g.unref?.(),this.#D.set(A,{messageId:A,nonce:e,expectedOperatorOpenId:a,timeout:g,resolve:r,reject:s})})}#O(t){let o=Un(t?.context?.open_message_id);if(!o)return!1;let a=this.#D.get(o);if(!a)return!1;let e=t?.action?.value,i=LGe(t);return e?.action!=="repair_verify"||e?.nonce!==a.nonce||i!==a.expectedOperatorOpenId?!1:(clearTimeout(a.timeout),this.#D.delete(o),this.#h.cardActionProbesVerified+=1,this.#S(i,w(vGe),"success").finally(()=>{a.resolve({verified:!0,messageId:o,operatorOpenId:i})}),!0)}#S(t,o,a){let e=this.#B;return e?Promise.resolve().then(async()=>{let i=await e.im.v1.message.create({params:{receive_id_type:"open_id"},data:{receive_id:t,msg_type:"text",content:JSON.stringify({text:o})}});if(i?.code&&i.code!==0)throw new Error("Feishu callback repair notice failed");return!0}).catch(()=>(this.#u.warn?.(`[dsh-feishu] unable to send the callback repair ${a} notice`),!1)):(this.#u.warn?.(`[dsh-feishu] unable to send the callback repair ${a} notice`),Promise.resolve(!1))}async sendConnectionTest(t){if(!this.#h.ready||!this.#B){let e=new Error("\u98DE\u4E66\u673A\u5668\u4EBA\u5C1A\u672A\u8FDE\u63A5");throw e.code="test-target-unavailable",e}if(typeof t!="string"||!t.trim())throw new TypeError("Feishu connection test text is required");let o=async(e,i,A)=>{let r=await this.#B.im.v1.message.create({params:{receive_id_type:e},data:{receive_id:i,msg_type:"text",content:JSON.stringify({text:A})}});if(r?.code&&r.code!==0)throw new Error(`Feishu connection test failed: ${r.msg||r.code}`)},a=this.#i.find(e=>e!=="*");return a?(await o("open_id",a,t),{sent:!0}):yc({state:this.#s,text:t,channelLabel:w("\u98DE\u4E66\u673A\u5668\u4EBA"),send:async(e,i)=>{let A=typeof e?.chatId=="string"?e.chatId.trim():"";if(!A)throw Qr(w("\u98DE\u4E66\u673A\u5668\u4EBA"));await o("chat_id",A,i)}})}async sendProactiveText(t,o,{signal:a}={}){if(!this.#h.ready||!this.#B){let r=new Error("\u98DE\u4E66\u673A\u5668\u4EBA\u5C1A\u672A\u8FDE\u63A5");throw r.code="bot-not-connected",r}let e=t?.kind==="user"?"open_id":t?.kind==="group"?"chat_id":null,i=t?.kind==="user"?Un(t?.route?.openId):t?.kind==="group"?Un(t?.route?.chatId):null;if(!e||!i){let r=new TypeError("Invalid Feishu proactive delivery target");throw r.code="invalid-target",r}a?.throwIfAborted();let A=await this.#B.im.v1.message.create({params:{receive_id_type:e},data:{receive_id:i,msg_type:"text",content:JSON.stringify({text:o})}});if(A?.code&&A.code!==0){let r=new Error(`Feishu proactive delivery failed: ${A.msg||A.code}`);throw r.code="target-rejected",r}return{sent:!0}}async#T(t,o,a){this.#h.slashCommandRegistration="registering",this.#h.slashCommandsError=null;try{let e=await QZ({appId:this.#t,appSecret:this.#r,domain:this.#I,httpInstance:t,signal:a,manifest:uG});if(!o())return;this.#h.slashCommandRegistration="done",this.#h.slashCommandsRegistered=e.created.length,this.#h.slashCommandsExisting=e.existing.length,this.#h.slashCommandsFailed=e.failed.length,this.#h.slashCommandsError=e.failed.length>0?e.failed.map(i=>`/${i.command}: ${i.error?.message??String(i.error)}`).join("; "):null,e.created.length>0&&this.#u.info?.(`[dsh-feishu] registered ${e.created.length} slash command(s)`),e.failed.length>0&&this.#u.warn?.(`[dsh-feishu] ${e.failed.length} slash command(s) failed to register: ${this.#h.slashCommandsError}`)}catch(e){if(!o())return;this.#h.slashCommandRegistration="failed",this.#h.slashCommandsError=e?.message??String(e),this.#u.warn?.(`[dsh-feishu] slash command registration skipped: ${this.#h.slashCommandsError}`)}}stop(t={}){if(this.#m)return this.#m;let o;return o=this.#N(t).finally(()=>{this.#m===o&&(this.#m=null)}),this.#m=o,o}async#N({preserveError:t=!1}={}){let o=this.#Q;this.#Q===o&&(this.#Q=null),o?.abort(new DOMException("Feishu runtime stopped","AbortError"));let a=this.#w;return a&&await a.catch(()=>{}),this.#P({preserveError:t,abortController:o})}async#P({preserveError:t=!1,abortController:o}={}){let a=t?this.#h.lastError:null;this.#Q===o&&(this.#Q=null),o?.abort(new DOMException("Feishu runtime stopped","AbortError"));for(let A of this.#D.values())clearTimeout(A.timeout),this.#S(A.expectedOperatorOpenId,w(GGe),"abort"),A.reject(ph("abort","\u98DE\u4E66\u8FD0\u884C\u65F6\u5DF2\u505C\u6B62"));this.#D.clear(),this.#h.ready=!1;let e=this.#y;this.#y=null,e?.close({force:!0});let i=this.#f;return this.#f=null,i&&await i.waitForIdle(),this.#B=null,this.#h.feishuLongConnectionState=t?"failed":"idle",this.#h.slashCommandRegistration="idle",this.#h.lastError=a,this.status}};var Aw=class extends yr{constructor(t){super({...t,rpcIdPrefix:"feishu",logPrefix:"dsh-feishu"})}};import{createHash as xGe}from"node:crypto";import{mkdir as YGe,readFile as jGe,rename as JGe,unlink as qGe,writeFile as zGe}from"node:fs/promises";import{dirname as VGe}from"node:path";var iw="DSH_FEISHU_APP_SECRET";function Ps(n){return typeof n=="string"&&n.trim()?n.trim():null}function yZ(n){let t=Ps(n);return t&&/^[A-Za-z0-9_-]{1,128}$/.test(t)?t:null}function mZ(n){return`bot_${xGe("sha256").update(n).digest("hex").slice(0,24)}`}function WGe(n){let t=Array.isArray(n.ownerOpenIds)?n.ownerOpenIds:[n.ownerOpenId];return[...new Set(t.map(Ps).filter(Boolean))]}function tw(n,{legacy:t=!1}={}){if(!n||typeof n!="object")return null;let o=Ps(n.appId),a=WGe(n);if(!o||a.length===0)return null;let e=yZ(n.id)??(t?mZ(o):null),i=Ps(n.secretRef)??(t?iw:null);if(!e||!i||!/^[A-Za-z_][A-Za-z0-9_]*$/.test(i))return null;let A=n.domain==="lark"?"lark":"feishu";return Object.freeze({id:e,appId:o,secretRef:i,ownerOpenIds:Object.freeze(a),domain:A,botName:Ps(n.botName),botOpenId:Ps(n.botOpenId),activated:n.activated??null,groupResponseMode:Bo(n.groupResponseMode),groupMessagePermissionGranted:n.groupMessagePermissionGranted===!0,deletionPending:n.deletionPending===!0,connectedAt:Ps(n.connectedAt),createdAt:Ps(n.createdAt)??Ps(n.connectedAt)})}function ZGe(n){if(!n||typeof n!="object")return null;if(n.version===2&&Array.isArray(n.bots)){let o=n.bots.map(A=>tw(A));if(o.some(A=>A===null))throw new Error("dsh-feishu config contains an invalid bot entry");let a=new Set,e=new Set,i=new Set;for(let A of o){if(a.has(A.id)||e.has(A.secretRef)||i.has(A.appId))throw new Error("dsh-feishu config contains duplicate bot identities");a.add(A.id),e.add(A.secretRef),i.add(A.appId)}return{value:Object.freeze({version:2,bots:Object.freeze(o)}),migrated:!1}}let t=tw(n,{legacy:!0});return t?{value:Object.freeze({version:2,bots:Object.freeze([t])}),migrated:!0}:null}var rw=class{#e;#A=Object.freeze({version:2,bots:Object.freeze([])});#t=Promise.resolve();constructor(t){this.#e=t}async load(){try{let t=JSON.parse(await jGe(this.#e,"utf8")),o=ZGe(t);if(!o)throw new Error("dsh-feishu config is incomplete or invalid");this.#A=o.value,o.migrated&&await this.#o(this.#A)}catch(t){if(t?.code!=="ENOENT")throw t;this.#A=Object.freeze({version:2,bots:Object.freeze([])})}return this}get(){let t=this.#A.bots[0];if(!t)return null;let o=structuredClone(t);return o.ownerOpenId=o.ownerOpenIds[0],o}list(){return structuredClone(this.#A.bots)}getBot(t){let o=this.#A.bots.find(a=>a.id===t);return o?structuredClone(o):null}async save(t){let o={...t};o.id||(o.id=mZ(Ps(o.appId)??"invalid")),o.secretRef||(o.secretRef=iw);let a=tw(o);if(!a)throw new Error("Refusing to persist incomplete dsh-feishu configuration");return await this.#r([a]),this.get()}async saveBot(t){let o=tw(t);if(!o)throw new Error("Refusing to persist incomplete dsh-feishu bot configuration");return this.#I(a=>{if(a.find(r=>r.secretRef===o.secretRef&&r.id!==o.id))throw new Error("Refusing to share a credential reference between Feishu bots");if(a.find(r=>r.appId===o.appId&&r.id!==o.id))throw new Error("Refusing to persist the same Feishu app twice");let A=a.findIndex(r=>r.id===o.id);return A===-1?a.push(o):a[A]=o,structuredClone(o)})}async removeBot(t){if(!yZ(t))throw new TypeError("Invalid Feishu bot id");return this.#I(o=>{let a=o.findIndex(i=>i.id===t);if(a===-1)return null;let[e]=o.splice(a,1);return structuredClone(e)})}async clear(){let t=this.#t.then(async()=>{try{await qGe(this.#e)}catch(o){if(o?.code!=="ENOENT")throw o}this.#A=Object.freeze({version:2,bots:Object.freeze([])})});this.#t=t.then(()=>{},()=>{}),await t}async#r(t){let o=Object.freeze({version:2,bots:Object.freeze([...t])}),a=this.#t.then(async()=>{await this.#o(o),this.#A=o});this.#t=a.then(()=>{},()=>{}),await a}async#I(t){let o,a=this.#t.then(async()=>{let e=[...this.#A.bots];o=t(e);let i=Object.freeze({version:2,bots:Object.freeze(e)});await this.#o(i),this.#A=i});return this.#t=a.then(()=>{},()=>{}),await a,o}async#o(t){await YGe(VGe(this.#e),{recursive:!0,mode:448});let o=`${this.#e}.tmp`;await zGe(o,`${JSON.stringify(t,null,2)} -`,{encoding:"utf8",mode:384}),await JGe(o,this.#e)}};import{randomUUID as MZ}from"node:crypto";var yG=new Set(["starting","qr_ready","polling","slow_down","domain_switched","saving"]),XGe=new Set(["polling","slow_down","domain_switched"]),Va=Object.freeze({IDLE:"idle",STARTING:"starting",QR_READY:"qr_ready",POLLING:"polling",SLOW_DOWN:"slow_down",DOMAIN_SWITCHED:"domain_switched",SAVING:"saving",SUCCEEDED:"succeeded",EXPIRED:"expired",CANCELLED:"cancelled",ERROR:"error"});function SZ(n){return["access_denied","expired_token","abort"].includes(n?.code)?n.code:"registration_failed"}function mG(n){let t=SZ(n);return{code:t,message:{access_denied:"Registration was denied.",abort:"Registration was cancelled.",expired_token:"The registration QR code expired."}[t]??"Unable to register the Feishu app."}}function $Ge(n){let t=Number(n);if(!Number.isFinite(t)||t<=0)throw new TypeError("registerApp onQRCodeReady returned an invalid expireIn");return t}function eFe(n){if(n!==void 0){if(n===null||typeof n!="object"||Array.isArray(n))throw new TypeError("registerApp returned invalid user_info");return{...n}}}var Yg=class{#e;#A;#t;#r;#I;#o=0;#g=null;#i;constructor({registerApp:t,onCredentials:o,now:a=Date.now,setTimeout:e=globalThis.setTimeout,clearTimeout:i=globalThis.clearTimeout}={}){if(typeof t!="function")throw new TypeError("RegistrationManager requires a registerApp function");if(typeof o!="function")throw new TypeError("RegistrationManager requires an onCredentials function");if(typeof a!="function"||typeof e!="function"||typeof i!="function")throw new TypeError("RegistrationManager clock dependencies must be functions");this.#e=t,this.#A=o,this.#t=a,this.#r=e,this.#I=i,this.#i=this.#s(null,Va.IDLE)}start(t={}){if(t===null||typeof t!="object"||Array.isArray(t))throw new TypeError("Registration options must be an object");this.#f();let o={id:++this.#o,controller:new AbortController,qrCodeUrl:null,expiresAt:null,pollIntervalSeconds:null,expiryTimer:null};this.#g=o,this.#i=this.#s(o,Va.STARTING);let a={...t,signal:o.controller.signal,onQRCodeReady:i=>this.#c(o,i),onStatusChange:i=>this.#d(o,i)};return Promise.resolve().then(()=>this.#e(a)).then(i=>this.#n(o,i),i=>this.#p(o,i)),this.status()}status(){this.#E();let t={...this.#i};t.error&&(t.error={...t.error});let o=this.#g;return o&&o.expiresAt!==null&&yG.has(t.state)&&(t.remainingSeconds=Math.max(0,Math.ceil((o.expiresAt-this.#t())/1e3))),t}cancel(){let t=this.#g;return t?(this.#C(t,Va.CANCELLED,{error:{code:"abort",message:"Registration was cancelled."}}),t.controller.abort(),this.status()):this.status()}#a(t){return this.#g===t}#s(t,o,a={}){let e={state:o,attempt:t?.id??this.#o,updatedAt:this.#t(),...a};return t?.qrCodeUrl&&yG.has(o)&&(e.qrCodeUrl=t.qrCodeUrl,e.expiresAt=t.expiresAt),t?.pollIntervalSeconds!==null&&yG.has(o)&&(e.pollIntervalSeconds=t.pollIntervalSeconds),e}#l(t,o,a={}){this.#a(t)&&(this.#i=this.#s(t,o,a))}#c(t,o){if(!this.#a(t))return;if(typeof o?.url!="string"||!o.url)throw new TypeError("registerApp onQRCodeReady returned an invalid URL");let a=$Ge(o.expireIn);t.qrCodeUrl=o.url,t.expiresAt=this.#t()+a*1e3,this.#B(t),t.expiryTimer=this.#r(()=>this.#u(t),a*1e3),t.expiryTimer?.unref?.(),this.#l(t,Va.QR_READY)}#d(t,o){!this.#a(t)||!XGe.has(o?.status)||(o.status===Va.SLOW_DOWN&&Number.isFinite(Number(o.interval))&&(t.pollIntervalSeconds=Number(o.interval)),this.#l(t,o.status))}async#n(t,o){if(!this.#a(t))return;let a=o?.client_id,e=o?.client_secret;if(typeof a!="string"||!a||typeof e!="string"||!e){this.#C(t,Va.ERROR,{error:{code:"invalid_credentials",message:"Feishu registration returned invalid credentials."}});return}let i;try{i=eFe(o.user_info)}catch{this.#C(t,Va.ERROR,{error:{code:"invalid_credentials",message:"Feishu registration returned invalid credentials."}});return}this.#B(t),t.qrCodeUrl=null,t.expiresAt=null,t.pollIntervalSeconds=null,this.#l(t,Va.SAVING);try{await this.#A({client_id:a,client_secret:e,user_info:i})}catch{this.#a(t)&&this.#C(t,Va.ERROR,{error:{code:"credentials_callback_failed",message:"Unable to store the Feishu credentials."}});return}this.#a(t)&&this.#C(t,Va.SUCCEEDED)}#p(t,o){if(!this.#a(t))return;let a=SZ(o);if(a==="expired_token"){this.#C(t,Va.EXPIRED,{error:mG(o)});return}if(a==="abort"){this.#C(t,Va.CANCELLED,{error:mG(o)});return}this.#C(t,Va.ERROR,{error:mG(o)})}#E(){let t=this.#g;t&&t.expiresAt!==null&&this.#t()>=t.expiresAt&&this.#u(t)}#u(t){this.#a(t)&&(this.#C(t,Va.EXPIRED,{error:{code:"expired_token",message:"The registration QR code expired."}}),t.controller.abort())}#C(t,o,a={}){this.#a(t)&&(this.#B(t),this.#i=this.#s(t,o,a),this.#g=null)}#B(t){t.expiryTimer!==null&&(this.#I(t.expiryTimer),t.expiryTimer=null)}#f(){let t=this.#g;t&&(this.#B(t),this.#g=null,t.controller.abort())}};var AFe="card.action.trigger",tFe="im:message:readonly",rFe="im:resource",tB="callback_repair";function iFe(n){return n==="lark"?"accounts.larksuite.com":"accounts.feishu.cn"}function aFe(n){return n==="lark"?"open.larksuite.com":"open.feishu.cn"}function SG(n,t,o="feishu",a="Feishu app update"){let e;try{e=new URL(n)}catch{throw new Error(`${a} returned an invalid verification URL`)}let i=o==="feishu"||o==="lark",A=e.searchParams.getAll("clientID"),r=e.searchParams.getAll("tp"),s=e.searchParams.getAll("addons"),g=String(t).includes("{{")||String(t).includes("}}")||[...e.searchParams.values()].some(c=>c.includes("{{")||c.includes("}}"));if(!i||e.protocol!=="https:"||e.hostname!==aFe(o)||e.port!==""||e.username!==""||e.password!==""||r.length!==1||r[0]!=="sdk"||A.length!==1||A[0]!==t||e.searchParams.has("createOnly")||s.length!==1||!s[0]?.trim()||g)throw new Error(`${a} returned an unsafe verification URL`);return e.toString()}function oFe(n,t,o="feishu"){return SG(n,t,o,"Feishu callback repair")}var aw=class{#e;#A;#t;constructor({registerApp:t,onCredentials:o,appId:a,domain:e="feishu"}={}){if(typeof t!="function")throw new TypeError("registerApp is required");if(typeof o!="function")throw new TypeError("onCredentials is required");if(typeof a!="string"||!a.trim())throw new TypeError("appId is required");if(e!=="feishu"&&e!=="lark")throw new TypeError("domain is invalid");this.#A=a.trim(),this.#t=e,this.#e=new Yg({registerApp:i=>t({...i,onQRCodeReady:A=>{oFe(A?.url,this.#A,this.#t),i.onQRCodeReady(A)}}),onCredentials:o})}start(){return this.#e.start({source:"deepseek-harness-card-action-repair",domain:iFe(this.#t),appId:this.#A,addons:{preset:!1,scopes:{tenant:[tFe,rFe,...$S]},callbacks:{items:[AFe]}}})}status(){return this.#e.status()}cancel(){return this.#e.cancel()}};var nFe="im:message.group_msg",nw="group_message_permission";function sFe(n){return n==="lark"?"accounts.larksuite.com":"accounts.feishu.cn"}function gFe(n,t,o="feishu"){return SG(n,t,o,"Feishu group message permission update")}var ow=class{#e;#A;#t;constructor({registerApp:t,onCredentials:o,appId:a,domain:e="feishu"}={}){if(typeof t!="function")throw new TypeError("registerApp is required");if(typeof o!="function")throw new TypeError("onCredentials is required");if(typeof a!="string"||!a.trim())throw new TypeError("appId is required");if(e!=="feishu"&&e!=="lark")throw new TypeError("domain is invalid");this.#A=a.trim(),this.#t=e,this.#e=new Yg({registerApp:i=>t({...i,onQRCodeReady:A=>{gFe(A?.url,this.#A,this.#t),i.onQRCodeReady(A)}}),onCredentials:o})}start(){return this.#e.start({source:"deepseek-harness-group-message-permission",domain:sFe(this.#t),appId:this.#A,addons:{preset:!1,scopes:{tenant:[nFe]}}})}status(){return this.#e.status()}cancel(){return this.#e.cancel()}};var wZ=Object.freeze(["im:message.p2p_msg:readonly","im:message.group_at_msg:readonly","im:message:readonly","im:message:send_as_bot","im:message.reactions:write_only","im:message:recall","im:resource","cardkit:card:write",...$S]);var wG=new Set(["starting","qr_ready","polling","slow_down","domain_switched"]),sw=new Set([...wG,"saving"]),DZ=new Set([tB,nw]),OZ="*",cFe=12e4,IFe=6e5;function _Z(){return{ready:!1,feishuLongConnectionState:"idle",harnessReachable:!1}}function rB(n){return n?n.status:_Z()}function iB(n){return n.ready===!0&&n.feishuLongConnectionState==="connected"&&n.harnessReachable===!0}function TZ(n){return n.length>12?`${n.slice(0,8)}\u2022\u2022\u2022\u2022${n.slice(-4)}`:"cli_\u2022\u2022\u2022\u2022"}function lFe(n){return{name:n.botName,appIdMasked:TZ(n.appId),activated:n.activated,domain:n.domain}}function dFe({connected:n,error:t,connection:o}){return n?"connected":t||o.feishuLongConnectionState==="failed"?"error":"disconnected"}function pFe(){return`bot_${MZ().replaceAll("-","")}`}function hFe(){return`reg_${MZ().replaceAll("-","")}`}function bZ(n){return`DSH_FEISHU_APP_SECRET_${n.slice(4).toUpperCase()}`}function gw(n){return JSON.stringify({id:n.id,appId:n.appId,secretRef:n.secretRef,ownerOpenIds:n.ownerOpenIds,domain:n.domain,botName:n.botName,botOpenId:n.botOpenId,activated:n.activated,groupResponseMode:Bo(n.groupResponseMode),groupMessagePermissionGranted:n.groupMessagePermissionGranted===!0,deletionPending:n.deletionPending===!0,connectedAt:n.connectedAt??null,createdAt:n.createdAt??null})}function cw(n){return typeof n=="string"&&n.trim()?n.trim():null}var aB=class{#e;#A;#t;#r;#I;#o;#g;#i;#a=new Map;#s=new Map;#l=new Map;#c=new Map;#d=new Map;#n=null;#p=Promise.resolve();#E=new Map;#u=1;#C;#B=!1;constructor({registerApp:t,verifyApp:o,credentials:a,configStore:e,createRuntime:i,deleteState:A=async()=>{},createBotId:r=pFe,createRegistrationId:s=hFe,callbackProbeTimeoutMs:g=cFe}){if(typeof t!="function")throw new Error("registerApp is required");if(typeof o!="function")throw new Error("verifyApp is required");if(!a)throw new Error("credentials service is required");if(!e||typeof e.list!="function")throw new Error("multi-bot config store is required");if(typeof i!="function")throw new Error("createRuntime is required");if(typeof A!="function")throw new Error("deleteState must be a function");if(!Number.isFinite(g)||g<=0||g>IFe)throw new TypeError("callbackProbeTimeoutMs must be between 1 and 600000ms");this.#e=t,this.#A=o,this.#t=a,this.#r=e,this.#I=i,this.#o=A,this.#g=r,this.#i=s,this.#C=g}async initialize(){if(this.#B)return this.status();let t=this.#r.list(),o=!1;return await Promise.allSettled(t.map(a=>this.#_(a.id,async()=>{let e=rB(this.#a.get(a.id));if(iB(e)||e.feishuLongConnectionState==="connecting"||e.feishuLongConnectionState==="reconnecting")return;if(o=!0,a.deletionPending){this.#s.set(a.id,{code:"deletion_pending",message:"\u673A\u5668\u4EBA\u6B63\u5728\u7B49\u5F85\u5B8C\u6210\u672C\u5730\u5220\u9664\uFF0C\u8BF7\u91CD\u8BD5\u79FB\u9664\u3002"});return}let i;try{i=await this.#t.resolve(a.secretRef)}catch{this.#s.set(a.id,{code:"missing_credentials",message:"\u65E0\u6CD5\u8BFB\u53D6\u673A\u5668\u4EBA\u51ED\u636E\uFF0C\u8BF7\u68C0\u67E5\u51ED\u636E\u5B58\u50A8\u3002"});return}if(!i?.value){this.#s.set(a.id,{code:"missing_credentials",message:"\u673A\u5668\u4EBA\u51ED\u636E\u7F3A\u5931\uFF0C\u8BF7\u5220\u9664\u540E\u91CD\u65B0\u626B\u7801\u63A5\u5165\u3002"});return}try{await this.#h(a,i.value),this.#s.delete(a.id)}catch{this.#s.set(a.id,{code:"connection_failed",message:"\u673A\u5668\u4EBA\u6682\u65F6\u65E0\u6CD5\u8FDE\u63A5\u98DE\u4E66\uFF0C\u8BF7\u91CD\u8BD5\u3002"})}}))),o&&this.#R(),this.status()}startRegistration(){this.#N();let t=this.#i();if(typeof t!="string"||!/^[A-Za-z0-9_-]{1,128}$/.test(t)||this.#l.has(t))throw new Error("Registration id generator returned an invalid or duplicate id");let o={id:t,manager:null,botId:null,createdNew:!1,cancelled:!1};return o.manager=new Yg({registerApp:this.#e,onCredentials:a=>this.#P(()=>this.#D(o,a))}),this.#l.set(t,o),this.#n=t,this.#G(),o.manager.start({source:"deepseek-harness",createOnly:!0,appPreset:{name:"{user} \u7684\u5317\u6C47\u661F\u6CB3 AI \u52A9\u624B",desc:"\u8FDE\u63A5\u98DE\u4E66\u4E0E DeepSeek Harness\uFF0C\u5728\u804A\u5929\u4E2D\u4F7F\u7528\u4F01\u4E1A AI \u52A9\u624B\u3002"},addons:{preset:!1,scopes:{tenant:[...wZ]},events:{items:{tenant:["im.message.receive_v1"]}},callbacks:{items:["card.action.trigger"]}}}),this.#R(),this.registrationStatus(t)}startCallbackRepair(t,{actorOpenId:o,chatId:a}={}){this.#N();let e=this.#T(t);if(e.deletionPending)throw new Error("Cannot repair a Feishu bot pending deletion");let i=this.#c.get(t),A=i?this.#l.get(i):null;if(A&&sw.has(A.manager.status().state)){if(A.operation!==tB)throw new Error("Another Feishu app update is already active for this bot");return this.registrationStatus(A.id)}this.#c.delete(t);let r=this.#i();if(typeof r!="string"||!/^[A-Za-z0-9_-]{1,128}$/.test(r)||this.#l.has(r))throw new Error("Registration id generator returned an invalid or duplicate id");let s={id:r,operation:tB,manager:null,botId:t,createdNew:!1,cancelled:!1,remoteCommitted:!1,processing:null,publicError:null,stage:"authorizing",target:structuredClone(e),targetFingerprint:gw(e),initiator:{actorOpenId:cw(o),chatId:cw(a)}};return s.manager=new aw({registerApp:this.#e,appId:e.appId,domain:e.domain,onCredentials:g=>{s.remoteCommitted=!0;let I=this.#m(s,g).finally(()=>{s.processing===I&&(s.processing=null)});return s.processing=I,I}}),this.#l.set(r,s),this.#c.set(t,r),this.#n=r,this.#G(),s.manager.start(),this.#R(),this.registrationStatus(r)}startGroupMessagePermission(t){this.#N();let o=this.#T(t);if(o.deletionPending)throw new Error("Cannot update permissions for a Feishu bot pending deletion");let a=this.#c.get(t),e=a?this.#l.get(a):null;if(e&&sw.has(e.manager.status().state)){if(e.operation!==nw)throw new Error("Another Feishu app update is already active for this bot");return this.registrationStatus(e.id)}this.#c.delete(t);let i=this.#i();if(typeof i!="string"||!/^[A-Za-z0-9_-]{1,128}$/.test(i)||this.#l.has(i))throw new Error("Registration id generator returned an invalid or duplicate id");let A={id:i,operation:nw,manager:null,botId:t,createdNew:!1,cancelled:!1,remoteCommitted:!1,processing:null,publicError:null,stage:"authorizing",target:structuredClone(o),targetFingerprint:gw(o),initiator:{actorOpenId:null,chatId:null}};return A.manager=new ow({registerApp:this.#e,appId:o.appId,domain:o.domain,onCredentials:r=>{A.remoteCommitted=!0;let g=this.#w(A,r).finally(()=>{A.processing===g&&(A.processing=null)});return A.processing=g,g}}),this.#l.set(i,A),this.#c.set(t,i),this.#n=i,this.#G(),A.manager.start(),this.#R(),this.registrationStatus(i)}hasRegistration(t){return this.#l.has(t)}registrationStatus(t){let o=this.#l.get(t);return o?this.#f({registration:o,selectedBotId:o.botId}):null}async cancelRegistration(t=this.#n){let o=this.#l.get(t);if(!o)return this.status();let a=o.manager.status().state;return DZ.has(o.operation)&&a==="saving"?this.registrationStatus(t):sw.has(a)?(o.cancelled=!0,o.manager.cancel(),await this.#P(async()=>{o.createdNew&&o.botId&&this.#d.get(o.botId)===o.id&&this.#r.getBot(o.botId)&&await this.#_(o.botId,()=>this.#O(o.botId))}),this.#R(),this.registrationStatus(t)??this.status()):this.registrationStatus(t)}status(t){return this.#f({registration:this.#l.get(this.#n)??null,selectedBotId:t})}async bindCredentials({appId:t,appSecret:o,domain:a="feishu"}={}){this.#N();let e=typeof t=="string"?t.trim():"",i=typeof o=="string"?o.trim():"",A=a==="lark"?"lark":"feishu";if(!e||!i)throw new TypeError("Feishu App ID and App Secret are required");return this.#P(async()=>{this.#N();let r=await this.#A({appId:e,appSecret:i,domain:A});this.#N();let s=this.#r.list().find(f=>f.appId===e),g=s?.id??this.#g();if(typeof g!="string"||!/^[A-Za-z0-9_-]{1,128}$/.test(g)||!s&&this.#r.getBot(g))throw new Error("Bot id generator returned an invalid or duplicate id");let c=s?.secretRef??bZ(g),I=await this.#t.resolve(c).catch(()=>{}),d={...s,id:g,appId:e,secretRef:c,ownerOpenIds:s?.ownerOpenIds?.length?s.ownerOpenIds:[OZ],domain:A,botName:r.name,botOpenId:r.openId,activated:r.activated,deletionPending:!1,connectedAt:new Date().toISOString(),createdAt:s?.createdAt??new Date().toISOString()};await this.#t.set(c,i);let B;try{B=await this.#r.saveBot(d)}catch(f){throw await this.#S(c,I),f}return await this.#_(g,async()=>{try{await this.#h(B,i),this.#s.delete(g)}catch{this.#s.set(g,{code:"connection_failed",message:"\u673A\u5668\u4EBA\u5DF2\u7ECF\u7ED1\u5B9A\uFF0C\u4F46\u957F\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u8BF7\u70B9\u51FB\u91CD\u8BD5\u3002"})}}),this.#R(),this.status(g)})}async reconnectBot(t){return this.#N(),this.#_(t,async()=>{let o=this.#T(t);if(o.deletionPending)return this.#s.set(t,{code:"deletion_pending",message:"\u673A\u5668\u4EBA\u6B63\u5728\u7B49\u5F85\u5B8C\u6210\u672C\u5730\u5220\u9664\uFF0C\u8BF7\u91CD\u8BD5\u79FB\u9664\u3002"}),this.status(t);if(iB(rB(this.#a.get(t))))return this.status(t);let a;try{a=await this.#t.resolve(o.secretRef)}catch{a=null}if(!a?.value)return this.#s.set(t,{code:"missing_credentials",message:"\u673A\u5668\u4EBA\u51ED\u636E\u7F3A\u5931\uFF0C\u8BF7\u5220\u9664\u540E\u91CD\u65B0\u626B\u7801\u63A5\u5165\u3002"}),this.#R(),this.status(t);try{await this.#h(o,a.value),this.#s.delete(t)}catch{this.#s.set(t,{code:"connection_failed",message:"\u673A\u5668\u4EBA\u6682\u65F6\u65E0\u6CD5\u8FDE\u63A5\u98DE\u4E66\uFF0C\u8BF7\u91CD\u8BD5\u3002"})}return this.#R(),this.status(t)})}async sendConnectionTest(t){return this.#N(),this.#_(t,async()=>{let o=this.#T(t),a=this.#a.get(t);if(!iB(rB(a))||typeof a.sendConnectionTest!="function"){let e=new Error("\u98DE\u4E66\u673A\u5668\u4EBA\u5C1A\u672A\u8FDE\u63A5");throw e.code="test-target-unavailable",e}return a.sendConnectionTest(Ki(`${o.botName}\uFF08${TZ(o.appId)}\uFF09`,"\u98DE\u4E66\u673A\u5668\u4EBA"))})}async sendProactiveText(t,o,a,e={}){return this.#N(),this.#_(t,async()=>{this.#T(t);let i=this.#a.get(t);if(!iB(rB(i))||typeof i.sendProactiveText!="function"){let A=new Error("\u98DE\u4E66\u673A\u5668\u4EBA\u5C1A\u672A\u8FDE\u63A5");throw A.code="bot-not-connected",A}return i.sendProactiveText(o,a,e)})}async disconnectBot(t){return this.#N(),this.#_(t,async()=>(this.#T(t),await this.#M(t),this.#s.delete(t),this.#R(),this.status(t)))}async updateGroupResponseMode(t,o){if(this.#N(),!jS(o))throw new TypeError("Invalid Feishu group response mode");return this.#P(()=>this.#_(t,async()=>{let a=this.#T(t);if(o==="all"&&a.groupMessagePermissionGranted!==!0){let i=new Error("Authorize im:message.group_msg before enabling all group messages");throw i.code="group_message_permission_required",i}let e=await this.#r.saveBot({...a,groupResponseMode:o});return this.#a.get(t)?.setGroupResponseMode?.(e.groupResponseMode),this.#R(),this.status(t)}))}async deleteBot(t){return this.#N(),this.#P(()=>this.#_(t,async()=>(this.#T(t),await this.#O(t),this.#R(),this.status())))}async reconnect(){let t=this.#r.list()[0];return t?this.reconnectBot(t.id):this.status()}async disconnect(){let t=this.#r.list()[0];return t?this.deleteBot(t.id):this.status()}async close(){if(this.#B)return;this.#B=!0;let t=[];for(let o of this.#l.values()){let a=o.manager.status().state;DZ.has(o.operation)&&a==="saving"?(o.manager.cancel(),o.processing&&t.push(o.processing)):sw.has(a)&&(o.cancelled=!0,o.manager.cancel())}await this.#p,await Promise.allSettled([...this.#E.values()]),await Promise.allSettled([...this.#a.keys()].map(o=>this.#M(o))),await Promise.allSettled(t),await this.#p,await Promise.allSettled([...this.#E.values()]),await Promise.allSettled([...this.#a.keys()].map(o=>this.#M(o)))}#f({registration:t,selectedBotId:o}={}){let a=this.#r.list().map(I=>{let d=rB(this.#a.get(I.id)),B=iB(d),f=this.#s.get(I.id)??null;return{botId:I.id,phase:dFe({connected:B,error:f,connection:d}),connected:B,configured:!0,groupResponseMode:Bo(I.groupResponseMode),groupMessagePermissionGranted:I.groupMessagePermissionGranted===!0,bot:lFe(I),connection:d,lastMessageError:ii(d.lastMessageError),error:f}}),e=t?this.#y(t):{state:"idle",attempt:0,updatedAt:Date.now()},i=wG.has(e.state),A=e.state==="saving",r=!!t&&(i||A),s=a.find(I=>I.botId===o)??(r?null:a[0]??null),g=a.some(I=>I.connected),c=s?.phase??"unconfigured";return i?c="registering":A?c="connecting":e.state==="error"&&!s&&(c="error"),{schemaVersion:2,revision:this.#u,phase:c,connected:s?.connected??!1,configured:a.length>0,bot:s?.bot??null,connection:s?.connection??_Z(),error:s?.error??e.error??null,registration:e,bots:a,totals:{configured:a.length,connected:a.filter(I=>I.connected).length},anyConnected:g}}#y(t){let o=t.manager.status();return{...o,attempt:t.id,...t.botId?{botId:t.botId}:{},...t.operation?{operation:t.operation}:{},...t.stage?{stage:t.stage}:{},...o.state==="error"&&t.publicError?{error:{...t.publicError}}:{}}}async#w(t,o){let a=o.client_id,e=o.client_secret,i=cw(o.user_info?.open_id),A=o.user_info?.tenant_brand,r=t.target;if(t.cancelled)throw this.#Q(t,"abort","Group message permission update was cancelled before local activation.");if(a!==r.appId)throw this.#Q(t,"repair_app_mismatch","Feishu returned credentials for a different app.");if(!i)throw this.#Q(t,"repair_owner_missing","Feishu returned no permission operator identity.");if(A!==void 0&&A!==r.domain)throw this.#Q(t,"repair_domain_mismatch","Feishu returned credentials for a different account domain.");if(!r.ownerOpenIds.includes(OZ)&&!r.ownerOpenIds.includes(i))throw this.#Q(t,"repair_owner_mismatch","The Feishu permission operator is not an owner of this configured bot.");t.stage="verifying_identity";let s;try{s=await this.#A({appId:a,appSecret:e,domain:r.domain})}catch(g){throw this.#Q(t,"repair_credentials_invalid","Feishu could not verify the updated app credentials.",g)}if(r.botOpenId&&s?.openId!==r.botOpenId)throw this.#Q(t,"repair_bot_mismatch","The updated Feishu app belongs to a different bot identity.");await this.#P(()=>this.#_(t.botId,async()=>{let g=this.#r.getBot(t.botId);if(!g||g.deletionPending||gw(g)!==t.targetFingerprint)throw this.#Q(t,"repair_target_changed","The Feishu bot changed while its permission update was in progress.");let c;try{c=await this.#t.resolve(g.secretRef)}catch(d){throw this.#Q(t,"credential_update_failed","Unable to read the current Feishu credential.",d)}if(c?.value!==e){t.stage="persisting_secret";try{await this.#t.set(g.secretRef,e)}catch(B){if((await this.#t.resolve(g.secretRef).catch(()=>null))?.value!==e)throw this.#Q(t,"credential_update_failed","Unable to store the updated Feishu credential.",B)}if((await this.#t.resolve(g.secretRef).catch(()=>null))?.value!==e)throw this.#Q(t,"credential_state_unknown","The updated Feishu credential could not be confirmed after writing.")}t.stage="enabling_all_messages";let I;try{I=await this.#r.saveBot({...g,groupMessagePermissionGranted:!0,groupResponseMode:"all"})}catch(d){throw this.#Q(t,"group_message_permission_save_failed","The permission was accepted, but all-message mode could not be saved.",d)}t.stage="restarting";try{await this.#h(I,e)}catch(d){throw this.#s.set(t.botId,{code:"connection_failed",message:"\u7FA4\u6D88\u606F\u6743\u9650\u5DF2\u5F00\u901A\uFF0C\u4F46\u673A\u5668\u4EBA\u957F\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u8BF7\u70B9\u51FB\u91CD\u8BD5\u3002"}),this.#R(),this.#Q(t,"group_message_permission_connection_failed","The permission was accepted, but the Feishu runtime could not restart.",d)}this.#s.delete(t.botId),t.stage="verified",t.publicError=null,this.#R()}))}async#m(t,o){let a=o.client_id,e=o.client_secret,i=cw(o.user_info?.open_id),A=o.user_info?.tenant_brand,r=t.target;if(t.cancelled)throw this.#Q(t,"abort","Callback repair was cancelled before local activation.");if(a!==r.appId)throw this.#Q(t,"repair_app_mismatch","Feishu returned credentials for a different app.");if(!i)throw this.#Q(t,"repair_owner_missing","Feishu returned no repair operator identity.");if(A!==void 0&&A!==r.domain)throw this.#Q(t,"repair_domain_mismatch","Feishu returned credentials for a different account domain.");t.stage="verifying_identity";let s;try{s=await this.#A({appId:a,appSecret:e,domain:r.domain})}catch(c){throw this.#Q(t,"repair_credentials_invalid","Feishu could not verify the repaired app credentials.",c)}if(r.botOpenId&&s?.openId!==r.botOpenId)throw this.#Q(t,"repair_bot_mismatch","The repaired Feishu app belongs to a different bot identity.");let g=await this.#P(()=>this.#_(t.botId,async()=>{let c=this.#r.getBot(t.botId);if(!c||c.deletionPending||gw(c)!==t.targetFingerprint)throw this.#Q(t,"repair_target_changed","The Feishu bot changed while its callback repair was in progress.");let I;try{I=await this.#t.resolve(c.secretRef)}catch(f){throw this.#Q(t,"credential_update_failed","Unable to read the current Feishu credential.",f)}if(I?.value!==e){t.stage="persisting_secret";try{await this.#t.set(c.secretRef,e)}catch(Q){if((await this.#t.resolve(c.secretRef).catch(()=>null))?.value!==e)throw this.#Q(t,"credential_update_failed","Unable to store the repaired Feishu credential.",Q)}if((await this.#t.resolve(c.secretRef).catch(()=>null))?.value!==e)throw this.#Q(t,"credential_state_unknown","The repaired Feishu credential could not be confirmed after writing.")}let B;t.stage="restarting";try{await this.#h(c,e),B=this.#a.get(t.botId)}catch(f){throw this.#s.set(t.botId,{code:"connection_failed",message:"\u673A\u5668\u4EBA\u56DE\u8C03\u4FEE\u590D\u5DF2\u4FDD\u5B58\uFF0C\u4F46\u957F\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u8BF7\u70B9\u51FB\u91CD\u8BD5\u3002"}),this.#R(),this.#Q(t,"repair_connection_failed","The repaired Feishu runtime could not be started.",f)}if(!B)throw this.#Q(t,"repair_connection_failed","The repaired Feishu runtime is unavailable.");return this.#s.delete(t.botId),this.#R(),B}));if(typeof g.beginCardActionProbe!="function")throw this.#Q(t,"card_action_probe_unavailable","The Feishu runtime cannot verify card callbacks.");t.stage="awaiting_callback";try{if((await g.beginCardActionProbe({expectedOperatorOpenId:t.initiator.actorOpenId??i,timeoutMs:this.#C,...t.initiator.chatId?{chatId:t.initiator.chatId}:{}}))?.verified!==!0){let I=new Error("Feishu runtime returned no callback proof");throw I.code="card_action_probe_failed",I}}catch(c){let I=c?.code==="card_action_probe_timeout"?"card_action_probe_timeout":c?.code==="card_action_probe_unavailable"?"card_action_probe_unavailable":c?.code==="card_action_probe_send_failed"?"card_action_probe_send_failed":"card_action_probe_failed";throw this.#Q(t,I,I==="card_action_probe_timeout"?"Timed out waiting for the Feishu callback verification button.":"The Feishu card callback probe failed.",c)}t.stage="verified",t.publicError=null,this.#R()}#Q(t,o,a,e){t.publicError={code:o,message:a};let i=new Error(a,e?{cause:e}:void 0);return i.code=o,i}async#D(t,o){if(t.cancelled)throw new Error("Registration was cancelled");let a=o.client_id,e=o.client_secret,i=o.user_info?.open_id,A=o.user_info?.tenant_brand==="lark"?"lark":"feishu";if(!i)throw new Error("Feishu registration returned no owner open_id");let r=await this.#A({appId:a,appSecret:e,domain:A});if(t.cancelled)throw new Error("Registration was cancelled");let s=this.#r.list().find(Q=>Q.appId===a),g=s?.id??this.#g();if(typeof g!="string"||!/^[A-Za-z0-9_-]{1,128}$/.test(g)||!s&&this.#r.getBot(g))throw new Error("Bot id generator returned an invalid or duplicate id");let c=s?.secretRef??bZ(g),I=this.#d.get(g),d=await this.#t.resolve(c).catch(()=>{});await this.#t.set(c,e);let B;try{B=await this.#r.saveBot({...s,id:g,appId:a,secretRef:c,ownerOpenIds:[...new Set([...s?.ownerOpenIds??[],i])],domain:A,botName:r.name,botOpenId:r.openId,activated:r.activated,deletionPending:!1,connectedAt:new Date().toISOString(),createdAt:s?.createdAt??new Date().toISOString()}),t.botId=g,t.createdNew=!s,this.#d.set(g,t.id)}catch(Q){try{await this.#S(c,d)}catch(y){throw new Error("Unable to restore the Feishu credential after a config failure.",{cause:y})}throw Q}if(t.cancelled)throw t.createdNew?await this.#_(g,()=>this.#O(g)):(await this.#r.saveBot(s),await this.#S(c,d),I?this.#d.set(g,I):this.#d.delete(g)),new Error("Registration was cancelled");let f=!1;try{if(await this.#_(g,()=>this.#h(B,e)),t.cancelled)throw t.createdNew?await this.#_(g,()=>this.#O(g)):(await this.#r.saveBot(s),await this.#S(c,d),I?this.#d.set(g,I):this.#d.delete(g),d?.value&&!s.deletionPending?await this.#_(g,()=>this.#h(s,d.value)):await this.#_(g,()=>this.#M(g))),f=!0,new Error("Registration was cancelled");this.#s.delete(g),this.#R()}catch(Q){if(t.cancelled)throw!f&&t.createdNew&&this.#r.getBot(g)?await this.#_(g,()=>this.#O(g)):!f&&s&&(await this.#r.saveBot(s),await this.#S(c,d),I?this.#d.set(g,I):this.#d.delete(g),!this.#B&&d?.value&&!s.deletionPending?await this.#_(g,()=>this.#h(s,d.value)):await this.#_(g,()=>this.#M(g))),this.#R(),Q;if(s&&d?.value)try{throw await this.#r.saveBot(s),await this.#S(c,d),I?this.#d.set(g,I):this.#d.delete(g),s.deletionPending?(await this.#_(g,()=>this.#M(g)),this.#s.set(g,{code:"deletion_pending",message:"\u673A\u5668\u4EBA\u6B63\u5728\u7B49\u5F85\u5B8C\u6210\u672C\u5730\u5220\u9664\uFF0C\u8BF7\u91CD\u8BD5\u79FB\u9664\u3002"})):(await this.#_(g,()=>this.#h(s,d.value)),this.#s.delete(g)),this.#R(),Q}catch(y){throw y===Q?Q:(this.#s.set(g,{code:"connection_failed",message:"\u673A\u5668\u4EBA\u8FDE\u63A5\u66F4\u65B0\u5931\u8D25\uFF0C\u4E14\u539F\u8FDE\u63A5\u65E0\u6CD5\u6062\u590D\uFF0C\u8BF7\u91CD\u8BD5\u3002"}),this.#R(),new Error("Unable to restore the previous Feishu bot connection.",{cause:y}))}throw this.#s.set(g,{code:"connection_failed",message:"\u673A\u5668\u4EBA\u5DF2\u7ECF\u521B\u5EFA\uFF0C\u4F46\u957F\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u8BF7\u70B9\u51FB\u91CD\u8BD5\u3002"}),this.#R(),Q}}async#h(t,o){await this.#M(t.id);let a=await this.#I({botId:t.id,config:t,appSecret:o,repair:this.#k(t.id)});this.#a.set(t.id,a);try{await a.start()}catch(e){throw this.#a.get(t.id)===a&&this.#a.delete(t.id),await a.stop({preserveError:!0}).catch(()=>{}),e}}#k(t){let o=a=>{let e=this.#l.get(a);return e?.operation===tB&&e.botId===t?e:null};return Object.freeze({start:({actorOpenId:a,chatId:e}={})=>this.startCallbackRepair(t,{actorOpenId:a,chatId:e}),status:({attemptId:a}={})=>o(a)?this.registrationStatus(a):null,cancel:async({attemptId:a}={})=>o(a)?this.cancelRegistration(a):this.status(t)})}async#M(t){let o=this.#a.get(t);this.#a.delete(t),o&&await o.stop()}async#O(t){let o=this.#r.getBot(t);if(o){o.deletionPending||(o=await this.#r.saveBot({...o,deletionPending:!0})),await this.#M(t);try{await this.#t.unset(o.secretRef)}catch(a){throw this.#s.set(t,{code:"credential_removal_failed",message:"\u65E0\u6CD5\u5220\u9664\u673A\u5668\u4EBA\u51ED\u636E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"}),new Error("Unable to remove the Feishu credential.",{cause:a})}try{await this.#o({botId:t,config:o})}catch(a){throw this.#s.set(t,{code:"state_cleanup_failed",message:"\u65E0\u6CD5\u5220\u9664\u673A\u5668\u4EBA\u7684\u672C\u5730\u4F1A\u8BDD\u6570\u636E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"}),new Error("Unable to remove the Feishu bot session state.",{cause:a})}await this.#r.removeBot(t),this.#s.delete(t),this.#d.delete(t)}}async#S(t,o){o?.value?await this.#t.set(t,o.value):await this.#t.unset(t)}#T(t){let o=this.#r.getBot(t);if(!o)throw new Error("Unknown Feishu bot");return o}#N(){if(this.#B)throw new Error("The Feishu controller is closed")}#P(t){let o=this.#p.then(t,t);return this.#p=o.then(()=>{},()=>{}),o}#_(t,o){let e=(this.#E.get(t)??Promise.resolve()).then(o,o),i=e.then(()=>{},()=>{});return this.#E.set(t,i),i.finally(()=>{this.#E.get(t)===i&&this.#E.delete(t)}),e}#G(){if(!(this.#l.size<=32))for(let[t,o]of this.#l){if(t===this.#n)continue;let a=o.manager.status().state;if(!wG.has(a)&&a!=="saving"&&this.#l.delete(t),this.#l.size<=32)break}}#R(){this.#u+=1}};var CFe=["open.feishu.cn","open.larksuite.com"];function BFe(n,t){if(t==="*")return!0;let o=t.startsWith(".")?t.slice(1):t;return o?n===o||n.endsWith(`.${o}`):!1}function fFe(n){for(let t of["no_proxy","NO_PROXY"]){let o=n?.[t];if(typeof o!="string"||!o.trim())continue;let a=o.split(",").map(e=>e.trim().toLowerCase()).filter(Boolean);if(CFe.some(e=>a.some(i=>BFe(e,i))))return!0}return!1}function QFe(n){if(!fFe(n))for(let t of["https_proxy","HTTPS_PROXY","http_proxy","HTTP_PROXY"]){let o=n?.[t];if(typeof o=="string"&&o.trim())return o.trim()}}function yFe(n,t=o=>new NZ.default(o)){let o=QFe(n);return o?t(o):void 0}function mFe(n){let t=Xc(n.dshHome??process.env.DSH_HOME??hh(EFe(),".dsh")),o=Xc(n.dataDir??hh(t,"integrations","dsh-feishu"));return{root:o,config:Xc(n.configPath??hh(o,"config.json")),legacyState:Xc(n.statePath??hh(o,"state.json")),bots:Xc(n.botsDir??hh(o,"bots")),workspaces:Xc(n.workspacesPath??hh(o,"workspaces.json"))}}async function DG(n,t={},o={}){if(!n?.credentials)throw new TypeError("dsh-feishu requires ctx.credentials");let a=ci(n,t),e=o.lark??iG,i=o.Controller??aB,A=o.ConfigStore??rw,r=o.StateStore??xS,s=o.HarnessClient??Aw,g=o.FeishuRuntime??ew,c=o.verifyFeishuApp??k5,I=Be=>c({...Be,httpInstance:e.defaultHttpInstance}),d=o.createConnectionSupervisor??aG,B=typeof n.logger=="function"?n.logger("dsh-feishu"):n.logger??console,f=()=>ji(n),Q=mFe(t),y=await new A(Q.config).load(),m=Xc(t.workspace??process.cwd()),_=o.WorkspaceStore??gi,T=o.workspaces??await new _(Q.workspaces,{defaultWorkspace:m}).load(),R=typeof y.list=="function",L=()=>R?y.list():[],U=L();R&&await T.reconcile(U.map(Be=>Be.id)),await Promise.all(U.map(Be=>T.ensure(Be.id,{defaultAgentPreset:t.agentPreset,initialAccessPolicy:pr("feishu",Be)})));let F=typeof y.removeBot=="function"?Ji(y,{workspaces:T,method:"removeBot",botIdFromRemoved:Be=>Be.id,saveMethod:"saveBot",botIdFromSave:Be=>Be?.id}):y,z=new Map,J=Be=>!Be.id||!Be.secretRef||Be.secretRef===iw?Q.legacyState:Xc(Q.bots,Be.id,"state.json"),K=async Be=>{let Re=Be.id??"__legacy__",Ne=z.get(Re);return Ne||(Ne=await new r(J(Be)).load(),z.set(Re,Ne)),Ne},G=async Be=>{let Re=L().find(Ne=>Ne.id===Be);if(!Re)throw new Error("Unknown Feishu bot");return K(Re)},V=Wi(n,o.commandExecutor),{controlExecutor:H,sessionMaintenanceExecutor:N,fileIngressExecutor:k}=Zi(n,{controlExecutor:o.controlExecutor,sessionMaintenanceExecutor:o.sessionMaintenanceExecutor,fileIngressExecutor:o.fileIngressExecutor}),q=new s({...a,workspace:m,autostart:!1,dshBin:t.dshBin??"dsh",...V?{commandExecutor:V}:{},...H?{controlExecutor:H}:{},...N?{sessionMaintenanceExecutor:N}:{},...k?{fileIngressExecutor:k}:{}}),X=o.proxyEnv??process.env,ie=yFe(X,o.createProxyAgent),De=new i({registerApp:Be=>e.registerApp(Be),verifyApp:I,credentials:n.credentials,configStore:F,createRuntime:async({botId:Be,config:Re,appSecret:Ne,repair:Je})=>{let ve=await K(Re),tA=Be??Re.id??Re.appId;await T.ensure(tA,{defaultAgentPreset:t.agentPreset,initialAccessPolicy:pr("feishu",Re)});let fe=qi(q,{botId:tA,workspaces:T,state:ve,agentPresetCatalog:f});return new g({lark:e,botId:tA,repair:Je,appId:Re.appId,appSecret:Ne,domain:Re.domain,botOpenId:Re.botOpenId,groupResponseMode:Re.groupResponseMode,ownerOpenIds:Re.ownerOpenIds??[Re.ownerOpenId],harness:fe.harness,state:fe.state,contextEnhancement:{botId:tA,getSettings:()=>T.contextEnhancementFor(tA)},accessPolicy:Xi(T,tA,{channel:"feishu",config:Re}),groupSessionScope:{getScope:()=>T.groupSessionScopeFor(tA)},replyTimeoutMs:t.replyTimeoutMs??6e5,slashCommands:t.slashCommands!==!1,...ie?{wsAgent:ie}:{},logger:{error:(...Ie)=>B.error?.(`[${Be??Re.id}]`,...Ie),warn:(...Ie)=>B.warn?.(`[${Be??Re.id}]`,...Ie),info:(...Ie)=>B.info?.(`[${Be??Re.id}]`,...Ie),debug:(...Ie)=>B.debug?.(`[${Be??Re.id}]`,...Ie)}})},deleteState:async({botId:Be,config:Re})=>{z.delete(Be);try{await uFe(J(Re))}catch(Ne){if(Ne?.code!=="ENOENT")throw Ne}}}),oe=zi(De,{workspaces:T,stateFor:G,agentPresetCatalog:f}),Se=d({controller:oe,harness:q,logger:B,retryDelaysMs:t.retryDelaysMs,healthyIntervalMs:t.healthyIntervalMs}).start();return{controller:oe,deliveryAdapter:Vi({channel:"feishu",workspaces:T,coreController:De,stateFor:G}),ready:Se.ready,async close(){await Se.close(),await oe.close(),q.stopManagedProcess(),ie?.destroy?.()}}}import KFe from"qrcode";var uh=ze(RG(),1);var LFe=ze(RG(),1);var UFe=Object.freeze({$locale:"en",IM\u673A\u5668\u4EBA:"IM bots",IM\u673A\u5668\u4EBA\u8BBE\u7F6E:"IM bot settings",\u66F4\u591A\u673A\u5668\u4EBA\u8BBE\u7F6E:"More bot settings",\u673A\u5668\u4EBA\u8BBE\u7F6E:"Bot settings",\u673A\u5668\u4EBA\u8BBE\u7F6E\u9875\u7B7E:"Bot settings tabs",\u6295\u9012\u8BBE\u7F6E:"Delivery settings",\u8BBF\u95EE\u8BBE\u7F6E:"Access settings","\u8BF7\u63D0\u4EA4\u6709\u6548\u7684\u7FA4\u540D\u540C\u6B65\u8BF7\u6C42\u3002":"Submit a valid group-name sync request.","\u540C\u6B65\u7FA4\u540D\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002":"Could not sync the group name. Try again later.","\u672A\u80FD\u4ECE WhatsApp \u8BFB\u53D6\u7FA4\u540D\uFF0C\u8BF7\u786E\u8BA4\u673A\u5668\u4EBA\u5728\u7EBF\u4E14\u4ECD\u5728\u8BE5\u7FA4\u3002":"Could not read the group name from WhatsApp. Confirm the bot is online and still in the group.","\u5DF2\u540C\u6B65\u7FA4\u540D\uFF1A":"Synced group name: ",\u540C\u6B65\u7FA4\u540D:"Sync group name",\u672A\u547D\u540D\u7FA4:"Unnamed group","\u6682\u65E0\u6635\u79F0\uFF08\u79C1\u804A/@ \u540E\u4F1A\u81EA\u52A8\u8865\u9F50\uFF09":"No nickname yet (filled after DM or @mention)","\u7FA4\u804A \xB7 ":"Group \xB7 ","\u3002\u8BB0\u5F97\u70B9\u4FDD\u5B58\u3002":". Remember to save.","\u5DF2\u52A0\u5165\u7FA4\u6388\u6743\uFF1A":"Added group access for: ","\u52A0\u5165\u7FA4\uFF1A":"Add to group: ","\u5DF2\u5728\u7FA4\uFF1A":"Already in group: ",\u586B\u5199\u4FBF\u4E8E\u8BC6\u522B\u7684\u7FA4\u540D\u79F0:"Enter a readable group name",\u7FA4\u540D\u79F0:"Group name",\u672A\u77E5\u7FA4:"Unknown group","\u65E0\u6CD5\u8BFB\u53D6\u8BBF\u95EE\u6388\u6743\uFF0C\u8BF7\u8FD4\u56DE\u5237\u65B0\u540E\u91CD\u8BD5\u3002":"Could not load the access grant. Go back, refresh, and try again.","\u6B63\u5728\u8BFB\u53D6\u5206\u7EA7\u8BBF\u95EE\u8BBE\u7F6E\u2026":"Loading graded access settings\u2026",\u52A0\u672C\u7FA4:"Add to group",\u5DF2\u5728\u672C\u7FA4:"Already in group",\u52A0\u79C1\u804A:"Add to DMs",\u5DF2\u5728\u79C1\u804A:"Already in DMs","\u5DF2\u52A0\u5165\u672C\u7FA4\u6388\u6743\uFF0C\u8BB0\u5F97\u70B9\u4FDD\u5B58\u3002":"Added to this group. Remember to save.","\u5DF2\u52A0\u5165\u79C1\u804A\u6388\u6743\uFF0C\u8BB0\u5F97\u70B9\u4FDD\u5B58\u3002":"Added to DM access. Remember to save.","\u6682\u65E0\u8054\u7CFB\u4EBA\u3002\u6709\u4EBA\u79C1\u804A\u6216 @ \u673A\u5668\u4EBA\u540E\u4F1A\u51FA\u73B0\u5728\u6B64\u3002":"No contacts yet. They appear here after someone DMs or @mentions the bot.","\u4EC5\u8BB0\u5F55\u79C1\u804A\u673A\u5668\u4EBA\uFF0C\u6216\u5728\u7FA4\u91CC @ \u673A\u5668\u4EBA\u7684\u4EBA\u3002\u7535\u8BDD\u662F\u552F\u4E00\u6388\u6743\u952E\uFF0C\u53EF\u4E00\u952E\u52A0\u5165\u79C1\u804A/\u672C\u7FA4\u6388\u6743\u3002":"Only people who DM the bot or @mention it in a group are recorded. Phone is the sole auth key; use one-click to grant DM or group access.","WhatsApp \u6309\u7535\u8BDD\u53F7\u7801\u6388\u6743\uFF1A\u5168\u5C40\u7BA1\u7406\u5458\u7BA1\u79C1\u804A\uFF1B\u7FA4\u7BA1\u7406\u5458\u53EA\u6279\u672C\u7FA4\u3002\u6210\u5458\u4E0D\u53EF\u8DE8\u7FA4\u3001\u6709\u7FA4\u6743\u4E5F\u4E0D\u81EA\u52A8\u83B7\u5F97\u79C1\u804A\u6743\u3002":"WhatsApp authorizes by phone number: global admins manage DMs; group admins approve only their group. Members do not cross groups, and group access does not grant DMs.",\u4FDD\u5B58\u5206\u7EA7\u8BBF\u95EE\u8BBE\u7F6E:"Save graded access settings",\u4FDD\u5B58\u8BBF\u95EE\u4E0E\u4F1A\u8BDD\u8BBE\u7F6E:"Save access and session settings",\u5168\u5C40\u7BA1\u7406\u5458:"Global admins","\u5206\u7EA7\u8BBF\u95EE\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002":"Graded access settings saved.","\u5BA1\u6279\u5931\u8D25\u3002":"Approval failed.","\u5C1A\u65E0\u5DF2\u77E5\u7FA4\u3002\u53EF\u5728\u4E0B\u65B9\u7C98\u8D34\u7FA4 JID\uFF08\u2026@g.us\uFF09\uFF0C\u6216\u7B49\u7FA4\u5185\u6709\u4EBA @ \u673A\u5668\u4EBA\u540E\u81EA\u52A8\u51FA\u73B0\u3002":"No known groups yet. Paste a group JID (\u2026@g.us) below, or wait until someone @mentions the bot in a group.","\u5DF2\u6279\u51C6\u7533\u8BF7\u3002":"Request approved.","\u5DF2\u62D2\u7EDD\u7533\u8BF7\u3002":"Request denied.","\u5F53\u524D\u6E20\u9053\u4ECD\u4F7F\u7528\u65E7\u7248\u8BBF\u95EE\u8BBE\u7F6E\u3002":"This channel still uses the legacy access settings.",\u5F85\u5BA1\u6279:"Pending approval",\u5F85\u8865\u7535\u8BDD:"Phone pending",\u6279\u51C6:"Approve",\u62D2\u7EDD:"Deny","\u6309\u53D1\u8A00\u4EBA\u62C6\u5206\uFF08\u63A8\u8350\uFF09":"Split by speaker (recommended)","\u6574\u7FA4\u5171\u4EAB\u4E00\u4E2A Session":"Share one session for the whole group",\u65B0\u589E\u7BA1\u7406\u5458:"Add admin",\u6682\u65E0\u5F85\u6279\u7533\u8BF7:"No pending requests","\u6682\u65E0\u8054\u7CFB\u4EBA\u3002\u79C1\u804A\u6216\u7FA4\u5185\u89E6\u53D1\u540E\u4F1A\u51FA\u73B0\u5728\u6B64\uFF0C\u4FBF\u4E8E\u8865\u9F50\u7535\u8BDD\u4E0E\u6635\u79F0\u3002":"No contacts yet. People who DM or trigger the bot in a group appear here so you can fill in phones and names.","\u6700\u8FD1\u8054\u7CFB\u4EBA\uFF08\u81EA\u52A8\u6C89\u6DC0\uFF09":"Recent contacts (auto-collected)","\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u5DF2\u4FDD\u5B58\u7684\u8BBF\u95EE\u6388\u6743\u3002":"The service did not return the saved access grant.",\u672A\u547D\u540D:"Unnamed","\u672A\u914D\u7F6E\u65F6\uFF0C\u672C\u7FA4\u7533\u8BF7\u56DE\u843D\u7ED9\u5168\u5C40\u7BA1\u7406\u5458\u5BA1\u6279\uFF08\u4ECD\u53EA\u6388\u4E88\u672C\u7FA4\u6743\uFF09\u3002":"When unset, this group's requests fall back to global admins (still grants only this group).",\u672C\u7FA4\u6388\u6743\u6210\u5458:"Group members",\u672C\u7FA4\u7BA1\u7406\u5458:"Group admins",\u67E5\u770B\u7FA4\u4F1A\u8BDD\u7B56\u7565\u8BF4\u660E:"View group session policy details",\u6DFB\u52A0\u7FA4:"Add group","\u6DFB\u52A0\u7FA4 JID":"Add group JID",\u7535\u8BDD:"Phone",\u79C1\u804A\u6388\u6743\u7528\u6237:"DM members","\u7ED1\u5B9A\u8D26\u53F7\u81EA\u52A8\u4E3A\u5168\u5C40\u7BA1\u7406\u5458\uFF0C\u81F3\u5C11\u4FDD\u7559\u4E00\u4F4D\u3002":"The linked account is a global admin automatically. Keep at least one.","\u7ED1\u5B9A\u8D26\u53F7\uFF08\u5168\u5C40\u7BA1\u7406\u5458\uFF09":"Linked account (global admin)","\u7F3A\u5C11\u53EF\u7528\u4E8E\u5BA1\u6279\u7684\u5168\u5C40\u7BA1\u7406\u5458\u7535\u8BDD\u3002":"No global admin phone is available for approval.","\u7FA4 JID \u683C\u5F0F\u65E0\u6548\u3002":"Invalid group JID.",\u7FA4\u4F1A\u8BDD\u7B56\u7565:"Group session policy","\u7FA4\u5185 Session \u7ED1\u5B9A":"In-group session binding",\u7FA4\u5907\u6CE8\u540D:"Group display name",\u7FA4\u6388\u6743:"Group grants","\u8BBF\u95EE\u4E0E\u7FA4\u4F1A\u8BDD\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002":"Access and group session settings saved.","\u8BBF\u95EE\u6388\u6743\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002":"Could not save the access grant. Try again later.","\u8BBF\u95EE\u6388\u6743\u6682\u4E0D\u53EF\u7528\u3002":"Access grant settings are currently unavailable.","\u8FD0\u7EF4\u9ED8\u8BA4\u6309\u53D1\u8A00\u4EBA\u62C6\u5206 Session\uFF0C\u907F\u514D\u540C\u7FA4\u591A\u4EBA\u4E92\u76F8\u6253\u65AD\uFF1B\u53EF\u9009\u6539\u56DE\u6574\u7FA4\u5171\u4EAB Session\u3002":"Ops defaults to one session per speaker so group members do not interrupt each other. You can switch back to one shared group session.","\uFF08\u7535\u8BDD\u672A\u89E3\u6790\uFF0C\u8BF7\u5148\u5728\u8054\u7CFB\u4EBA\u4E2D\u786E\u8BA4\uFF09":"(Phone unresolved \u2014 confirm it in contacts first)",\u67E5\u770B\u8BBF\u95EE\u6743\u9650\u8BF4\u660E:"View access permission details",\u5141\u8BB8\u6240\u6709\u7528\u6237:"Allow all users",\u4EC5\u767D\u540D\u5355\u7528\u6237:"Allowlisted users only",\u9ED8\u8BA4\u547D\u4EE4\u6743\u9650:"Default command permission",\u547D\u4EE4\u6743\u9650:"Command permission",\u53EF\u4EE5\u6267\u884C\u547D\u4EE4:"Can run commands",\u4E0D\u53EF\u4EE5\u6267\u884C\u547D\u4EE4:"Cannot run commands",\u767D\u540D\u5355\u7528\u6237:"Allowlisted users",\u67E5\u770B\u767D\u540D\u5355\u8BF4\u660E:"View allowlist details",\u547D\u4EE4\u6743\u9650\u4F8B\u5916:"Command permission exceptions","\u5F53\u524D\u6CA1\u6709\u767D\u540D\u5355\u7528\u6237\uFF0C\u4FDD\u5B58\u540E\u666E\u901A\u7528\u6237\u5C06\u65E0\u6CD5\u4F7F\u7528\u673A\u5668\u4EBA\u3002":"There are currently no allowlisted users. After saving, regular users will not be able to use the bot.",\u65B0\u589E\u7528\u6237:"Add user",\u5C1A\u672A\u6DFB\u52A0\u7528\u6237:"No users added",\u5F53\u524D\u6E20\u9053\u4E0D\u652F\u6301\u7FA4\u804A:"Group chat is not supported by this channel","\u539F\u6240\u6709\u8005\u6216\u626B\u7801\u63A5\u5165\u8005\u59CB\u7EC8\u53EF\u4EE5\u8BBF\u95EE\u5E76\u6267\u884C\u547D\u4EE4\uFF1B\u4EE5\u4E0B\u8BBE\u7F6E\u4EC5\u7EA6\u675F\u5176\u4ED6\u7528\u6237\u3002":"The original owner or QR-code operator can always access the bot and run commands; the settings below apply only to other users.","\u6B64\u533A\u57DF\u65E0\u9700\u914D\u7F6E\uFF0C\u4FDD\u5B58\u79C1\u804A\u8BBE\u7F6E\u65F6\u4F1A\u4FDD\u7559\u73B0\u6709\u7FA4\u804A\u7B56\u7565\u3002":"No setup is needed here. Saving direct-message settings keeps the existing group policy.","\u8BBF\u95EE\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002":"Access settings saved.","\u8BBF\u95EE\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002":"Access settings are currently unavailable.","\u8BBF\u95EE\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002":"Could not save access settings. Try again later.","\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u5DF2\u4FDD\u5B58\u7684\u8BBF\u95EE\u7B56\u7565\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5\u3002":"The service did not return the saved access policy. Refresh and try again.","\u8BBF\u95EE\u7B56\u7565\u5C1A\u672A\u5C31\u7EEA\uFF0C\u8BF7\u8FD4\u56DE\u673A\u5668\u4EBA\u5217\u8868\u5237\u65B0\u540E\u91CD\u8BD5\u3002":"The access policy is not ready. Return to the bot list, refresh, and try again.","\u5F53\u524D\u6E20\u9053\u6682\u4E0D\u652F\u6301\u8BBF\u95EE\u8BBE\u7F6E\u3002":"Access settings are not supported by this channel yet.","\u7528\u6237\u6807\u8BC6\u65E0\u6548\u3002":"The user ID is invalid.","\u7528\u6237\u6807\u8BC6\u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u3002":"The user ID must be a string.","\u7528\u6237\u6807\u8BC6\u4E0D\u80FD\u4E3A\u7A7A\u3001\u5305\u542B\u63A7\u5236\u5B57\u7B26\u6216\u8D85\u8FC7 256 \u4E2A\u5B57\u7B26\u3002":"The user ID cannot be empty, contain control characters, or exceed 256 characters.","\u7528\u6237\u6761\u76EE\u5FC5\u987B\u5305\u542B\u7528\u6237\u6807\u8BC6\u548C\u547D\u4EE4\u6743\u9650\u3002":"Each user entry must include a user ID and command permission.","\u547D\u4EE4\u6743\u9650\u5FC5\u987B\u662F\u5E03\u5C14\u503C\u3002":"Command permission must be a boolean.","\u8BBF\u95EE\u6A21\u5F0F\u53EA\u80FD\u662F open \u6216 allowlist\u3002":"Access mode must be open or allowlist.","\u5F00\u653E\u6A21\u5F0F\u8BBE\u7F6E\u5FC5\u987B\u5B8C\u6574\u3002":"Open-mode settings must be complete.","\u5F00\u653E\u6A21\u5F0F\u9ED8\u8BA4\u547D\u4EE4\u6743\u9650\u5FC5\u987B\u662F\u5E03\u5C14\u503C\u3002":"The open-mode default command permission must be a boolean.","\u5F00\u653E\u6A21\u5F0F\u547D\u4EE4\u6743\u9650\u8986\u76D6\u7528\u6237\u5FC5\u987B\u662F\u6570\u7EC4\u3002":"Open-mode command permission overrides must be an array.","\u5F00\u653E\u6A21\u5F0F\u547D\u4EE4\u6743\u9650\u8986\u76D6\u7528\u6237\u4E0D\u80FD\u5305\u542B\u91CD\u590D\u7684\u7528\u6237\u6807\u8BC6\u3002":"Open-mode command permission overrides cannot contain duplicate user IDs.","\u767D\u540D\u5355\u6A21\u5F0F\u8BBE\u7F6E\u5FC5\u987B\u5B8C\u6574\u3002":"Allowlist-mode settings must be complete.","\u767D\u540D\u5355\u6A21\u5F0F\u7528\u6237\u5FC5\u987B\u662F\u6570\u7EC4\u3002":"Allowlist-mode users must be an array.","\u767D\u540D\u5355\u6A21\u5F0F\u7528\u6237\u4E0D\u80FD\u5305\u542B\u91CD\u590D\u7684\u7528\u6237\u6807\u8BC6\u3002":"Allowlist-mode users cannot contain duplicate user IDs.","\u8BBF\u95EE\u573A\u666F\u8BBE\u7F6E\u5FC5\u987B\u540C\u65F6\u5305\u542B\u6A21\u5F0F\u3001\u5F00\u653E\u6A21\u5F0F\u8BBE\u7F6E\u548C\u767D\u540D\u5355\u6A21\u5F0F\u8BBE\u7F6E\u3002":"Each access context must include its mode, open-mode settings, and allowlist-mode settings.","\u8BF7\u540C\u65F6\u63D0\u4EA4\u5B8C\u6574\u7684\u79C1\u804A\u548C\u7FA4\u804A\u8BBF\u95EE\u8BBE\u7F6E\u3002":"Submit complete direct-message and group access settings together.","\u586B\u5199\u5FAE\u4FE1\u7528\u6237 ID":"Enter a WeChat user ID","\u98DE\u4E66 Open ID":"Feishu Open ID","\u7FA4\u6210\u5458 Open ID":"Group member Open ID","\u9489\u9489\u7528\u6237 ID":"DingTalk user ID","\u586B\u5199 senderStaffId \u6216 senderId":"Enter senderStaffId or senderId","\u7FA4\u6210\u5458\u7528\u6237 ID":"Group member user ID","\u4F01\u4E1A\u5FAE\u4FE1\u7528\u6237 ID":"WeCom user ID","\u586B\u5199 userid":"Enter userid","\u586B\u5199 member_openid":"Enter member_openid","QQ User Open ID":"QQ User Open ID","\u7FA4\u6210\u5458 User ID":"Group member User ID","\u586B\u5199\u6570\u5B57 User ID":"Enter a numeric user ID","WhatsApp \u7535\u8BDD\u53F7\u7801\u6216 JID":"WhatsApp phone number or JID","\u7FA4\u6210\u5458\u7535\u8BDD\u53F7\u7801\u6216 JID":"Group member phone number or JID","8613800000000 \u6216\u5B8C\u6574 JID":"8613800000000 or a full JID","IM \u6E20\u9053":"IM channels","\u8BA9 DeepSeek Harness \u89E6\u624B\u53EF\u53CA":"Connecting DeepSeek Harness",\u5F53\u524D\u7248\u672C:"Current version","DSH-IM \u66F4\u65B0":"DSH-IM update",\u68C0\u67E5\u66F4\u65B0:"Check for updates",\u91CD\u65B0\u68C0\u67E5:"Check again",\u5237\u65B0\u72B6\u6001:"Refresh status",\u624B\u5DE5\u66F4\u65B0:"Manual update",\u624B\u5DE5\u66F4\u65B0\u547D\u4EE4:"Manual update command",\u590D\u5236\u547D\u4EE4:"Copy command","\u590D\u5236\u4E2D\u2026":"Copying\u2026",\u5DF2\u590D\u5236:"Copied","\u547D\u4EE4\u5DF2\u590D\u5236\u3002":"Command copied.","\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u9009\u4E2D\u547D\u4EE4\u540E\u6309 Ctrl+C \u6216 \u2318C \u590D\u5236\u3002":"Copy failed. Select the command and press Ctrl+C or \u2318C to copy it.","\u81EA\u52A8\u66F4\u65B0\u5931\u8D25\u53EF\u4EE5\u4F7F\u7528\u547D\u4EE4\u66F4\u65B0\uFF1A":"If the automatic update fails, update with this command:","\u5C1A\u672A\u786E\u8BA4\u76EE\u6807\u7248\u672C\uFF0C\u6B64\u547D\u4EE4\u5B89\u88C5\u6267\u884C\u65F6 npm \u7684 latest \u7248\u672C\u3002":"No target version has been confirmed. This command installs the npm latest version available when you run it.","\u8BF7\u5728\u5F53\u524D Desktop \u7684\u5185\u7F6E\u7EC8\u7AEF\u6267\u884C\uFF0C\u5B8C\u6210\u540E\u624B\u52A8\u91CD\u542F\u3002":"Run this in the current Desktop\u2019s built-in terminal, then restart manually.","\u8BF7\u5728\u8FD0\u884C\u5F53\u524D Harness \u7684\u540C\u4E00\u73AF\u5883\u6267\u884C\uFF0C\u4FDD\u6301 DSH_HOME \u4E00\u81F4\uFF0C\u5B8C\u6210\u540E\u624B\u52A8\u91CD\u542F\u3002":"Run this in the same environment as the current Harness, with the same DSH_HOME, then restart manually.","\u8BF7\u7B49\u5F85\u5F53\u524D\u64CD\u4F5C\u7ED3\u675F\uFF0C\u786E\u8BA4\u6CA1\u6709\u5B89\u88C5\u8FDB\u7A0B\u8FD0\u884C\u540E\u518D\u6267\u884C\u547D\u4EE4\u3002":"Wait for the current operation to finish and confirm no installer is running before using this command.","\u6E90\u7801\u6216\u94FE\u63A5\u5B89\u88C5\u8BF7\u6309\u539F\u5B89\u88C5\u65B9\u5F0F\u66F4\u65B0\uFF0C\u4E0D\u63D0\u4F9B\u8986\u76D6\u6E90\u7801\u7684 npm \u547D\u4EE4\u3002":"Update source or linked installations using their original method. No npm command is provided to overwrite the source.","\u65E0\u6CD5\u5B89\u5168\u751F\u6210\u5F53\u524D profile \u7684\u547D\u4EE4\uFF0C\u8BF7\u5728\u7EC8\u7AEF\u4E2D\u624B\u52A8\u786E\u8BA4 profile \u540E\u66F4\u65B0\u3002":"A safe command cannot be generated for this profile. Confirm the profile in your terminal before updating manually.",\u66F4\u65B0\u81F3:"Update to",\u5B89\u88C5\u66F4\u65B0:"Install update","\u6B63\u5728\u66F4\u65B0\u2026":"Updating\u2026",\u5F85\u624B\u52A8\u91CD\u542F:"Restart needed",\u8FD0\u884C\u7248\u672C:"Running version",\u5DF2\u5B89\u88C5\u7248\u672C:"Installed version","\u76EE\u6807 profile":"Target profile",\u76EE\u6807\u7248\u672C:"Target version",\u65E0\u6CD5\u786E\u8BA4:"Unknown",\u53D1\u73B0\u65B0\u7248\u672C:"Update available",\u5DF2\u662F\u6700\u65B0\u7248\u672C:"Up to date",\u5F53\u524D\u7248\u672C\u65E0\u9700\u66F4\u65B0:"No newer version available","\u5DF2\u83B7\u53D6 npm \u6700\u65B0\u7248\u672C":"Latest npm version retrieved","\u68C0\u67E5 npm \u6700\u65B0\u7248\u672C\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u5B89\u88C5\u3002":"Check the latest npm version. Nothing is installed automatically.","\u6B63\u5728\u4ECE npm \u68C0\u67E5\u6700\u65B0\u7248\u672C\u2026":"Checking npm for the latest version\u2026","\u6B63\u5728\u5B89\u88C5\uFF0C\u8BF7\u7A0D\u5019\u2026":"Installing, please wait\u2026","\u6B63\u5728\u6821\u9A8C\u5B89\u88C5\u7ED3\u679C\u2026":"Verifying the installation\u2026","\u5DF2\u5B89\u88C5\uFF0C\u5F85\u624B\u52A8\u91CD\u542F":"Installed \u2014 manual restart needed",\u66F4\u65B0\u5DF2\u751F\u6548:"Updated version is active",\u66F4\u65B0\u5931\u8D25:"Update failed",\u66F4\u65B0\u8BF7\u6C42\u5931\u8D25:"Update request failed","\u4EC5\u66F4\u65B0 DSH-IM\u3002\u5B89\u88C5\u5B8C\u6210\u540E\u9700\u624B\u52A8\u91CD\u542F\u540E\u53F0\uFF1B\u672C\u529F\u80FD\u4E0D\u4F1A\u81EA\u52A8\u91CD\u542F\u6216\u4E3B\u52A8\u5237\u65B0\u9875\u9762\u3002":"Only DSH-IM will be updated. Restart the backend manually after installation. This feature does not automatically restart it or initiate a page refresh.","\u5F53\u524D\u662F\u6E90\u7801\u6216\u94FE\u63A5\u5B89\u88C5\uFF0C\u53EA\u80FD\u68C0\u67E5\u7248\u672C\uFF1B\u8BF7\u624B\u52A8\u66F4\u65B0\u6E90\u7801\uFF0C\u6216\u8FC1\u79FB\u5230 npm \u5B89\u88C5\u3002":"This is a source or linked installation. You can check versions, but must update the source manually or migrate to an npm installation.","\u65E0\u6CD5\u786E\u8BA4\u5F53\u524D profile\uFF0C\u8BF7\u5728\u5BF9\u5E94\u7684 Harness \u73AF\u5883\u4E2D\u624B\u52A8\u66F4\u65B0\u3002":"The current profile could not be identified. Update manually in the corresponding Harness environment.","\u5F53\u524D\u8FD0\u884C\u73AF\u5883\u4E0D\u652F\u6301\u6309\u94AE\u5B89\u88C5\uFF0C\u8BF7\u624B\u52A8\u66F4\u65B0\u63D2\u4EF6\u3002":"This runtime cannot install through this button. Update the plugin manually.","\u5F53\u524D npm \u6E90\u914D\u7F6E\u4E0E\u5B98\u65B9\u6E90\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u5148\u68C0\u67E5 registry \u914D\u7F6E\u3002":"The npm registry configuration differs from the official registry. Check your registry settings first.","\u5F53\u524D Host \u7684 Node.js \u7248\u672C\u4E0D\u6EE1\u8DB3\u65B0\u7248\u8981\u6C42\uFF0C\u8BF7\u5148\u66F4\u65B0\u8FD0\u884C\u73AF\u5883\u3002":"The Host Node.js version does not meet the new version\u2019s requirements. Update the runtime first.","\u65B0\u7248\u672C\u5DF2\u5B89\u88C5\uFF0C\u8BF7\u5728\u65B9\u4FBF\u65F6\u624B\u52A8\u91CD\u542F\u5F53\u524D Harness \u6216 Desktop\u3002":"The new version is installed. Manually restart this Harness or Desktop when convenient.","\u4E0A\u6B21\u5B89\u88C5\u7ED3\u679C\u65E0\u6CD5\u786E\u8BA4\uFF0C\u8BF7\u5148\u68C0\u67E5\u6B64 profile \u7684\u63D2\u4EF6\u5B89\u88C5\u72B6\u6001\u3002":"The previous installation result is uncertain. Check this profile\u2019s plugin installation first.","\u65E0\u6CD5\u8BBF\u95EE npm \u6216\u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u91CD\u65B0\u68C0\u67E5\u3002":"npm is unreachable or the request timed out. Check again later.","npm \u8FD4\u56DE\u7684\u7248\u672C\u4FE1\u606F\u65E0\u6548\uFF0C\u6682\u65F6\u65E0\u6CD5\u66F4\u65B0\u3002":"npm returned invalid release information. Updating is unavailable.","\u7248\u672C\u786E\u8BA4\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5\u540E\u518D\u5B89\u88C5\u3002":"The version confirmation expired. Check again before installing.","\u63D2\u4EF6\u5B89\u88C5\u72B6\u6001\u5DF2\u53D1\u751F\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5\u3002":"The plugin installation changed. Check again.","\u6B64 profile \u6B63\u5728\u66F4\u65B0\uFF0C\u8BF7\u7A0D\u540E\u67E5\u770B\u72B6\u6001\u3002":"This profile is already updating. Check its status shortly.","\u5B89\u88C5\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u5F53\u524D\u5B89\u88C5\u72B6\u6001\u540E\u91CD\u8BD5\u3002":"Installation failed. Check the current installation before retrying.","\u5B89\u88C5\u7ED3\u679C\u6821\u9A8C\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u68C0\u67E5\u63D2\u4EF6\u7248\u672C\u3002":"Installation verification failed. Check the plugin version manually.","\u65E0\u6CD5\u5B89\u5168\u4FDD\u5B58\u66F4\u65B0\u72B6\u6001\uFF0C\u8BF7\u5148\u68C0\u67E5\u5F53\u524D\u5B89\u88C5\u7ED3\u679C\u3002":"Update state could not be saved safely. Check the current installation result before retrying.","\u4E0A\u6B21\u66F4\u65B0\u5DF2\u4E2D\u65AD\uFF0C\u8BF7\u68C0\u67E5\u5B89\u88C5\u72B6\u6001\u540E\u91CD\u8BD5\u3002":"The previous update was interrupted. Check the installation before retrying.","\u66F4\u65B0\u670D\u52A1\u5DF2\u5173\u95ED\uFF0C\u8BF7\u624B\u52A8\u91CD\u65B0\u6253\u5F00\u8BBE\u7F6E\u9875\u3002":"The update service has closed. Reopen settings manually.","\u66F4\u65B0\u8BF7\u6C42\u65E0\u6548\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5\u7248\u672C\u3002":"The update request is invalid. Check the version again.","\u5F53\u524D\u63D2\u4EF6\u5B89\u88C5\u4E0D\u5B8C\u6574\u6216\u4E0E profile \u4E0D\u7B26\uFF0C\u8BF7\u624B\u52A8\u68C0\u67E5\u5B89\u88C5\u914D\u7F6E\u3002":"The plugin installation is incomplete or does not match this profile. Check the installation configuration manually.","\u65E0\u6CD5\u786E\u8BA4\u5F53\u524D npm \u6E90\u914D\u7F6E\uFF0C\u6682\u65F6\u4E0D\u80FD\u5B89\u88C5\u66F4\u65B0\u3002":"The npm registry configuration could not be verified. Installation is unavailable.","\u5B89\u88C5\u8D85\u65F6\uFF0C\u8BF7\u5148\u786E\u8BA4\u5F53\u524D\u5B89\u88C5\u72B6\u6001\uFF0C\u518D\u51B3\u5B9A\u662F\u5426\u91CD\u8BD5\u3002":"Installation timed out. Check the current installation before retrying.","\u66F4\u65B0\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002":"The update request failed. Try again.","\u66F4\u65B0\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94\u3002":"The update service returned an unrecognized response.","\u5F53\u524D Host \u4E0D\u652F\u6301\u66F4\u65B0\u63A5\u53E3\uFF0C\u8BF7\u5148\u624B\u52A8\u66F4\u65B0\u63D2\u4EF6\u5E76\u91CD\u542F\u3002":"This Host does not support the update API. Update the plugin manually and restart first.","\u5173\u95ED\u7A97\u53E3\u4E0D\u4F1A\u53D6\u6D88\u5B89\u88C5\u3002\u8BF7\u52FF\u540C\u65F6\u5728\u5176\u4ED6\u7A97\u53E3\u7BA1\u7406\u6B64 profile \u7684\u63D2\u4EF6\u3002":"Closing this window does not cancel installation. Do not manage this profile\u2019s plugins in another window at the same time.","\u9875\u9762\u7248\u672C\u4E0E\u8FD0\u884C\u7248\u672C\u4E0D\u540C\uFF0C\u8BF7\u624B\u52A8\u5237\u65B0\u9875\u9762\uFF1B\u82E5\u4ECD\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u624B\u52A8\u91CD\u542F Harness \u6216 Desktop\u3002":"The page and running versions differ. Refresh the page manually; if they still differ, manually restart Harness or Desktop.","\u8BF7\u5728\u673A\u5668\u4EBA\u7A7A\u95F2\u65F6\u5B89\u88C5\uFF1B\u5B89\u88C5\u4F1A\u4FEE\u6539\u5F53\u524D profile \u7684\u4F9D\u8D56\uFF0C\u5B8C\u6210\u540E\u9700\u624B\u52A8\u91CD\u542F\u3002":"Install while bots are idle. This changes the current profile\u2019s dependencies and requires a manual restart afterward.","AI Office":"AI Office","\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09":"(Experimental)","AI Office \u8BBE\u7F6E":"AI Office settings","AI Office \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5":"AI Office settings are missing an RPC connection","\u6B63\u5728\u8BFB\u53D6 AI Office Connector\u2026":"Loading AI Office Connector\u2026","\u672C\u673A\u4E3B\u52A8\u8FDE\u63A5\u516C\u7F51 Office\uFF1BHarness \u4E0D\u5F00\u653E\u7AEF\u53E3\u3002\u534F\u8BAE Hook \u56FA\u5B9A\u4E3A ":"This machine connects outward to the public Office; Harness exposes no port. Protocol hooks: ",\u5C1A\u672A\u914D\u7F6E:"Not configured","\u5DF2\u8FDE\u63A5 Office":"Connected to Office",\u5DF2\u914D\u7F6E:"Configured",\u7B49\u5F85\u91CD\u8FDE:"Waiting to reconnect",\u51ED\u636E\u7F3A\u5931:"Credential missing",\u6700\u8FD1\u5FC3\u8DF3:"Last heartbeat",\u6700\u8FD1\u4E8B\u4EF6:"Last event",\u91CD\u8FDE\u6B21\u6570:"Reconnects","\u8FD0\u884C Job":"Running Jobs","\u5B8C\u6210 Job":"Completed Jobs",\u5C1A\u65E0:"None yet",\u8BBE\u5907\u8FDE\u63A5:"Device connection","Token \u53EA\u5199\u5165\u672C\u673A\u51ED\u636E\u5B58\u50A8":"Token is written only to the local credential store","\u7C98\u8D34 Office \u4E00\u6B21\u6027\u51ED\u636E":"Paste the one-time Office credential","\u5DF2\u5B89\u5168\u4FDD\u5B58\uFF1B\u7559\u7A7A\u4FDD\u6301\u4E0D\u53D8":"Stored securely; leave blank to keep it",\u6700\u5927\u5E76\u53D1:"Max concurrency","Heartbeat \u79D2\u6570":"Heartbeat seconds","Workspace \u6620\u5C04":"Workspace mappings","\u6BCF\u884C alias=/\u672C\u673A/\u7EDD\u5BF9\u8DEF\u5F84\uFF1BOffice \u53EA\u80FD\u770B\u5230 alias\u3002":"One alias=/local/absolute/path per line; Office sees only aliases.","Instruction Preset \u6620\u5C04":"Instruction preset mappings","\u6BCF\u884C alias=\u6307\u4EE4\uFF1B\u65B0\u589E preset \u4E0D\u9700\u8981\u6539 Office \u4EE3\u7801\u3002":"One alias=instruction per line; new presets require no Office code change.",\u4FDD\u5B58\u5E76\u8FDE\u63A5:"Save and connect",\u6D4B\u8BD5\u8FDE\u63A5:"Test connection","\u6D4B\u8BD5\u4E2D\u2026":"Testing\u2026",\u91CD\u65B0\u8FDE\u63A5:"Reconnect",\u79FB\u9664\u8FDE\u63A5:"Remove connection","\u8FDE\u63A5\u6D4B\u8BD5\u901A\u8FC7\u3002":"Connection test passed.","\u914D\u7F6E\u5DF2\u4FDD\u5B58\u3002":"Configuration saved.","\u534F\u8BAE Hook \u9884\u89C8":"Protocol hook preview","\u7531 Base URL \u81EA\u52A8\u6D3E\u751F\uFF0C\u4E0D\u5355\u72EC\u586B\u5199":"Derived from Base URL; no separate input","Base URL \u65E0\u6548":"Invalid Base URL","Office Hook \u5C1A\u672A\u90E8\u7F72\u65F6\uFF0C\u914D\u7F6E\u4F1A\u5B89\u5168\u4FDD\u5B58\u5E76\u81EA\u52A8\u91CD\u8BD5\uFF1B\u51FA\u73B0 HTTP 404 \u4EE3\u8868\u534F\u8BAE\u7AEF\u70B9\u5F85\u4E0A\u7EBF\uFF0C\u4E0D\u4EE3\u8868 Harness \u6545\u969C\u3002":"Configuration is saved and retried while Office hooks are unavailable; HTTP 404 means the protocol endpoint is pending, not a Harness failure.","Workspace \u6620\u5C04\u6BCF\u884C\u5FC5\u987B\u4F7F\u7528 alias=value":"Each workspace mapping must use alias=value","Instruction Preset \u6620\u5C04\u6BCF\u884C\u5FC5\u987B\u4F7F\u7528 alias=value":"Each instruction preset mapping must use alias=value","action-items=\u8F6C\u6362\u4E3A\u8D1F\u8D23\u4EBA\u3001\u622A\u6B62\u548C\u9A8C\u6536\u660E\u786E\u7684\u5DE5\u5355":"action-items=Turn this into accountable tasks with deadlines and acceptance criteria","AI Office \u62D2\u7EDD\u4E86 Device Token\u3002":"AI Office rejected the Device Token.","AI Office Connector Hook \u5C1A\u672A\u5C31\u7EEA\u3002":"AI Office Connector hooks are not available yet.","AI Office Connector \u534F\u8BAE\u7248\u672C\u4E0D\u517C\u5BB9\u3002":"The AI Office Connector protocol is incompatible.","\u672C\u673A\u6682\u65F6\u65E0\u6CD5\u8BBF\u95EE AI Office\u3002":"AI Office cannot currently be reached from this machine.","AI Office \u8FDE\u63A5\u5DF2\u4E2D\u65AD\u3002":"The AI Office connection was interrupted.","\u5E2E\u52A9\u4E0E\u53CD\u9988 \xB7 \u524D\u5F80 GitHub":"Help & feedback \xB7 Open GitHub","\u8BF7\u6539\u7528 localhost \u91CD\u65B0\u6253\u5F00":"Reopen with localhost","\u9875\u9762\u4F1A\u5728\u5F53\u524D\u7AEF\u53E3\u91CD\u65B0\u6253\u5F00\uFF0C\u673A\u5668\u4EBA\u914D\u7F6E\u4E0D\u4F1A\u6539\u53D8\u3002":"The page will reopen on the current port. Your bot configuration will not change.","\u4F7F\u7528 localhost \u91CD\u65B0\u6253\u5F00":"Reopen with localhost","\u5F53\u524D\u5730\u5740\u4E0E\u6D4F\u89C8\u5668\u7684\u672C\u673A\u8BF7\u6C42\u6821\u9A8C\u4E0D\u517C\u5BB9\u3002\u8BF7\u4F7F\u7528\u4E0A\u65B9\u6309\u94AE\u6539\u7528 localhost \u91CD\u65B0\u6253\u5F00\u3002":"This address is incompatible with the browser\u2019s local-request checks. Use the button above to reopen with localhost.",\u5FAE\u4FE1:"WeChat",\u98DE\u4E66:"Feishu",\u9489\u9489:"DingTalk",\u4F01\u4E1A\u5FAE\u4FE1:"WeCom",\u5FAE\u4FE1\u673A\u5668\u4EBA:"WeChat bot",\u98DE\u4E66\u673A\u5668\u4EBA:"Feishu bot",\u9489\u9489\u673A\u5668\u4EBA:"DingTalk bot",\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA:"WeCom bot",QQ\u673A\u5668\u4EBA:"QQ bot",WhatsApp\u673A\u5668\u4EBA:"WhatsApp bot",WhatsApp\u8D26\u53F7:"WhatsApp account",\u5FAE\u4FE1\u8BBE\u7F6E:"WeChat settings",\u98DE\u4E66\u673A\u5668\u4EBA\u8BBE\u7F6E:"Feishu bot settings",\u7FA4\u804A\u54CD\u5E94\u65B9\u5F0F:"Group response mode","\u4EC5\u5728 @\u673A\u5668\u4EBA\u65F6\u54CD\u5E94\uFF08\u63A8\u8350\uFF09":"Only respond when @mentioned (recommended)",\u54CD\u5E94\u6240\u6709\u7FA4\u6D88\u606F:"Respond to all group messages","\u54CD\u5E94\u6240\u6709\u7FA4\u6D88\u606F\uFF08\u9700\u98DE\u4E66\u654F\u611F\u6743\u9650\uFF09":"Respond to all group messages (requires a sensitive Feishu scope)",\u91CD\u65B0\u6388\u6743:"Reauthorize",\u53BB\u6388\u6743:"Authorize",\u91CD\u65B0\u6388\u6743\u7FA4\u6D88\u606F\u6743\u9650:"Reauthorize group-message permission",\u6388\u6743\u7FA4\u6D88\u606F\u6743\u9650:"Authorize group-message permission","\u6B63\u5728\u51C6\u5907\u6388\u6743\u2026":"Preparing authorization\u2026","\u6B63\u5728\u51C6\u5907\u2026":"Preparing\u2026","\u79C1\u804A\u59CB\u7EC8\u54CD\u5E94\uFF1B\u7FA4\u804A\u4EC5\u5904\u7406\u660E\u786E @\u5F53\u524D\u673A\u5668\u4EBA\u7684\u6D88\u606F\u3002\u7FA4\u6D88\u606F\u6743\u9650\u5DF2\u5F00\u901A\uFF0C\u518D\u6B21\u5207\u6362\u65E0\u9700\u6388\u6743\u3002":"Direct messages always work; group chats require an explicit @mention of this bot. The group-message permission is already granted, so switching again needs no authorization.","\u79C1\u804A\u59CB\u7EC8\u54CD\u5E94\uFF1B\u7FA4\u804A\u4EC5\u5904\u7406\u660E\u786E @\u5F53\u524D\u673A\u5668\u4EBA\u7684\u6D88\u606F\u3002\u9009\u62E9\u5168\u90E8\u6D88\u606F\u540E\u4F1A\u6253\u5F00\u98DE\u4E66\u5B98\u65B9\u6388\u6743\u6D41\u7A0B\u3002":"Direct messages always work; group chats require an explicit @mention of this bot. Selecting all messages opens the official Feishu authorization flow.","\u5DF2\u5F00\u901A\u201C\u83B7\u53D6\u7FA4\u7EC4\u4E2D\u6240\u6709\u6D88\u606F\u201D\u6743\u9650\uFF08im:message.group_msg\uFF09\uFF1B\u673A\u5668\u4EBA\u4F1A\u5904\u7406\u7FA4\u804A\u4E2D\u7684\u6240\u6709\u53EF\u89C1\u6D88\u606F\u3002":"The \u201CRead all messages in associated group chat\u201D scope (im:message.group_msg) is granted; the bot processes every visible group message.","\u5C1A\u672A\u786E\u8BA4\u201C\u83B7\u53D6\u7FA4\u7EC4\u4E2D\u6240\u6709\u6D88\u606F\u201D\u6743\u9650\uFF0C\u8BF7\u5B8C\u6210\u98DE\u4E66\u6388\u6743\u3002":"The \u201CRead all messages in associated group chat\u201D scope has not been confirmed. Complete Feishu authorization.","\u79C1\u804A\u59CB\u7EC8\u54CD\u5E94\uFF1B\u7FA4\u804A\u4EC5\u5904\u7406\u660E\u786E @\u5F53\u524D\u673A\u5668\u4EBA\u7684\u6D88\u606F\u3002":"Direct messages always work; group chats require an explicit @mention of this bot.","\u9700\u5728\u98DE\u4E66\u4E3A\u8BE5\u673A\u5668\u4EBA\u5F00\u901A\u201C\u83B7\u53D6\u7FA4\u7EC4\u4E2D\u6240\u6709\u6D88\u606F\u201D\u6743\u9650\uFF08im:message.group_msg\uFF09\uFF1B\u5F00\u901A\u540E\uFF0C\u673A\u5668\u4EBA\u4F1A\u5904\u7406\u7FA4\u804A\u4E2D\u7684\u6240\u6709\u53EF\u89C1\u6D88\u606F\u3002":"Grant this bot the \u201CRead all messages in associated group chat\u201D Feishu scope (im:message.group_msg); once granted, it will process every visible group message.","\u7FA4\u804A\u54CD\u5E94\u65B9\u5F0F\u4FEE\u6539\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002":"Could not update the group response mode. Try again.","\u7FA4\u6D88\u606F\u6743\u9650\u6388\u6743\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002":"Could not authorize group-message permission. Try again.",\u9489\u9489\u8BBE\u7F6E:"DingTalk settings",\u4F01\u4E1A\u5FAE\u4FE1\u8BBE\u7F6E:"WeCom settings",\u626B\u7801\u63A5\u5165\u673A\u5668\u4EBA:"Scan QR code",\u6B63\u5728\u63A5\u5165:"Connecting",\u624B\u52A8\u63A5\u5165:"Manual setup",\u6536\u8D77\u51ED\u636E:"Hide credentials",\u6536\u8D77\u63A5\u5165:"Hide setup",\u63A5\u5165\u673A\u5668\u4EBA:"Connect bot",\u5F00\u59CB\u63A5\u5165:"Start setup",\u5728\u7EBF:"online",\u8FD0\u884C\u6B63\u5E38:"Connected",\u6B63\u5728\u8FDE\u63A5:"Connecting","\u6B63\u5728\u8FDE\u63A5\u2026":"Connecting\u2026",\u8FDE\u63A5\u672A\u5C31\u7EEA:"Not connected",\u8FDE\u63A5\u4E2D:"Connecting",\u8FDE\u63A5\u4E2D\u65AD:"Disconnected",\u9700\u8981\u5904\u7406:"Needs attention",\u72B6\u6001\u672A\u77E5:"Unknown status",\u79BB\u7EBF:"Offline",\u5DF2\u65AD\u5F00:"Disconnected",\u6D88\u606F\u901A\u9053:"Message channel",\u67E5\u770B\u6D88\u606F\u901A\u9053\u8BF4\u660E:"View message channel details",\u6700\u8FD1\u68C0\u67E5:"Last checked",\u6700\u8FD1\u4E00\u6761\u6D88\u606F\u5904\u7406\u5931\u8D25:"Latest message failed",\u9519\u8BEF\u7801:"Code",\u53C2\u8003\u53F7:"Reference",\u5F53\u524D\u5DE5\u4F5C\u533A:"Current workspace",\u9009\u62E9\u76EE\u5F55:"Choose folder",\u9009\u62E9\u673A\u5668\u4EBA\u5DE5\u4F5C\u533A\u76EE\u5F55:"Select bot workspace folder",\u5F53\u524D\u76EE\u5F55:"Current folder",\u4E3B\u76EE\u5F55:"Home",\u76F4\u63A5\u8F93\u5165\u8DEF\u5F84:"Enter a path directly","\u652F\u6301 Windows \u76D8\u7B26\u3001UNC \u4E0E POSIX \u7EDD\u5BF9\u8DEF\u5F84\u3002":"Supports Windows drives, UNC paths, and POSIX absolute paths.","\u8F93\u5165 Host \u4E0A\u7684\u5B8C\u6574\u7EDD\u5BF9\u8DEF\u5F84":"Enter a full absolute path on the Host",\u524D\u5F80:"Go","\u8BFB\u53D6\u4E2D\u2026":"Loading\u2026","\u6B63\u5728\u51C6\u5907\u76EE\u5F55\u9009\u62E9\u5668\u2026":"Preparing folder picker\u2026","\u6B63\u5728\u8BFB\u53D6\u76EE\u5F55\u2026":"Loading folders\u2026","\u8FD9\u4E2A\u76EE\u5F55\u4E2D\u6CA1\u6709\u5B50\u6587\u4EF6\u5939\u3002":"This folder has no subfolders.","\u6B64\u76EE\u5F55\u7684\u5B50\u6587\u4EF6\u5939\u8FC7\u591A\uFF0C\u4EC5\u663E\u793A\u524D\u4E00\u90E8\u5206\u3002":"This folder has too many subfolders; only the first group is shown.","\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF0C\u8BF7\u91CD\u8BD5\u3002":"Could not load the folder. Try again.",\u91CD\u8BD5:"Retry",\u663E\u793A\u9690\u85CF\u6587\u4EF6\u5939:"Show hidden folders","\u5207\u6362\u540E\u4F1A\u6E05\u9664\u8FD9\u4E2A\u673A\u5668\u4EBA\u7684\u65E7\u4F1A\u8BDD\u6620\u5C04\u3002":"Switching clears this bot\u2019s previous session mappings.","\u5207\u6362\u4E2D\u2026":"Switching\u2026",\u9009\u62E9\u6B64\u76EE\u5F55:"Select this folder",\u5DE5\u4F5C\u533A\u7EDD\u5BF9\u8DEF\u5F84:"Absolute workspace path","/\u7EDD\u5BF9\u8DEF\u5F84/\u5230/\u5DE5\u4F5C\u533A":"/absolute/path/to/workspace",\u4FEE\u6539:"Change",\u4FDD\u5B58:"Save",\u4E0A\u4E0B\u6587\u589E\u5F3A:"Context enhancement",\u672A\u5F00\u542F:"Not enabled",\u4EC5\u7FA4\u804A:"Groups only",\u4EC5\u79C1\u804A:"Direct only",\u7FA4\u804A\u548C\u79C1\u804A:"Groups and direct",\u5173\u95ED\u5F39\u7A97:"Close dialog",\u67E5\u770B\u4E0A\u4E0B\u6587\u589E\u5F3A\u8BF4\u660E:"View context enhancement details",\u4E0A\u4E0B\u6587\u589E\u5F3A\u8303\u56F4:"Context enhancement scope",\u542F\u7528\u8303\u56F4:"Enable in",\u542F\u7528:"Enabled","\uFF08\u5F53\u524D\u6E20\u9053\u4E0D\u652F\u6301\u7FA4\u804A\uFF09":"(This channel does not support group chats)",\u6765\u6E90\u5B57\u6BB5:"Source fields",\u67E5\u770B\u6765\u6E90\u5B57\u6BB5\u8BF4\u660E:"View source field details",\u67E5\u770B\u7FA4\u804A\u6765\u6E90\u5B57\u6BB5\u8BF4\u660E:"View group source field details",\u67E5\u770B\u79C1\u804A\u6765\u6E90\u5B57\u6BB5\u8BF4\u660E:"View direct source field details",\u6E20\u9053:"Channel",\u4F1A\u8BDD\u7C7B\u578B:"Conversation type",\u53D1\u9001\u8005\u6807\u8BC6:"Sender ID",\u53D1\u9001\u8005\u6635\u79F0:"Sender name",\u67E5\u770B\u53D1\u9001\u8005\u6635\u79F0\u5B57\u6BB5\u8BF4\u660E:"View sender name field details",\u67E5\u770B\u7FA4\u804A\u53D1\u9001\u8005\u6635\u79F0\u5B57\u6BB5\u8BF4\u660E:"View group sender name field details",\u67E5\u770B\u79C1\u804A\u53D1\u9001\u8005\u6635\u79F0\u5B57\u6BB5\u8BF4\u660E:"View direct sender name field details","\u8BE5\u5B57\u6BB5\u4E0D\u662F\u6BCF\u4E2A\u6E20\u9053\u90FD\u80FD\u63D0\u4F9B\u3002\u5F53\u524D\u6D88\u606F\u6CA1\u6709\u53D1\u9001\u8005\u6635\u79F0\u65F6\uFF0C\u5373\u4F7F\u5DF2\u9009\u62E9\u8BE5\u5B57\u6BB5\uFF0C \u4E2D\u4E5F\u4F1A\u7701\u7565 senderName\u3002":"This field is not available on every channel. If the current message has no sender name, omits senderName even when the field is selected.",\u4F1A\u8BDD\u6807\u9898:"Conversation title",\u67E5\u770B\u7FA4\u804A\u4F1A\u8BDD\u6807\u9898\u5B57\u6BB5\u8BF4\u660E:"View group conversation title field details",\u67E5\u770B\u79C1\u804A\u4F1A\u8BDD\u6807\u9898\u5B57\u6BB5\u8BF4\u660E:"View direct conversation title field details","\u8BE5\u5B57\u6BB5\u4E0D\u662F\u6BCF\u4E2A\u6E20\u9053\u90FD\u80FD\u63D0\u4F9B\u3002\u9489\u9489\u7FA4\u804A\u4F1A\u5E26\u4E0A\u7FA4\u540D\u3002\u5F53\u524D\u6D88\u606F\u6CA1\u6709\u4F1A\u8BDD\u6807\u9898\u65F6\uFF0C\u5373\u4F7F\u5DF2\u9009\u62E9\u8BE5\u5B57\u6BB5\uFF0C \u4E2D\u4E5F\u4F1A\u7701\u7565 conversationTitle\u3002":"This field is not available on every channel. DingTalk group chats include the group name. If the current message has no conversation title, omits conversationTitle even when the field is selected.",\u4F1A\u8BDD\u6807\u8BC6:"Chat ID",\u67E5\u770B\u7FA4\u804A\u4F1A\u8BDD\u6807\u8BC6\u5B57\u6BB5\u8BF4\u660E:"View group chat ID field details",\u67E5\u770B\u79C1\u804A\u4F1A\u8BDD\u6807\u8BC6\u5B57\u6BB5\u8BF4\u660E:"View direct chat ID field details","\u8BE5\u5B57\u6BB5\u4E0D\u662F\u6BCF\u4E2A\u6E20\u9053\u90FD\u80FD\u63D0\u4F9B\u3002\u4F1A\u8BDD\u6807\u8BC6\u7528\u4E8E\u533A\u5206\u4E0D\u540C\u7684\u7FA4\u7EC4\u6216\u79C1\u804A\uFF0C\u98DE\u4E66\u7FA4\u804A\u4F1A\u5E26\u4E0A\u7FA4 ID\u3002\u5F53\u524D\u6D88\u606F\u6CA1\u6709\u4F1A\u8BDD\u6807\u8BC6\u65F6\uFF0C\u5373\u4F7F\u5DF2\u9009\u62E9\u8BE5\u5B57\u6BB5\uFF0C \u4E2D\u4E5F\u4F1A\u7701\u7565 chatId\u3002":"This field is not available on every channel. The chat ID distinguishes different groups or direct chats, and Feishu group chats include the group ID. If the current message has no chat ID, omits chatId even when the field is selected.",\u8BDD\u9898\u6807\u8BC6:"Topic ID",\u67E5\u770B\u7FA4\u804A\u8BDD\u9898\u6807\u8BC6\u5B57\u6BB5\u8BF4\u660E:"View group topic ID field details",\u67E5\u770B\u79C1\u804A\u8BDD\u9898\u6807\u8BC6\u5B57\u6BB5\u8BF4\u660E:"View direct topic ID field details","\u8BE5\u5B57\u6BB5\u4E0D\u662F\u6BCF\u4E2A\u6E20\u9053\u90FD\u80FD\u63D0\u4F9B\u3002\u98DE\u4E66\u8BDD\u9898\u7FA4\u7684\u6D88\u606F\u4F1A\u5E26\u4E0A\u8BDD\u9898 ID\uFF0C\u7528\u4E8E\u533A\u5206\u540C\u4E00\u7FA4\u7EC4\u5185\u7684\u4E0D\u540C\u8BDD\u9898\uFF1B\u5F53\u524D\u6D88\u606F\u4E0D\u5728\u8BDD\u9898\u4E2D\u65F6\uFF0C\u5373\u4F7F\u5DF2\u9009\u62E9\u8BE5\u5B57\u6BB5\uFF0C \u4E2D\u4E5F\u4F1A\u7701\u7565 threadId\u3002":"This field is not available on every channel. Messages in a Feishu topic chat carry the topic ID, which distinguishes different topics inside the same group. If the current message is not inside a topic, omits threadId even when the field is selected.",\u673A\u5668\u4EBA\u6807\u8BC6:"Bot ID",\u589E\u5F3A\u63D0\u793A\u8BCD:"Guidance",\u67E5\u770B\u589E\u5F3A\u63D0\u793A\u8BCD\u4F7F\u7528\u8BF4\u660E:"View guidance instructions",\u67E5\u770B\u7FA4\u804A\u589E\u5F3A\u63D0\u793A\u8BCD\u4F7F\u7528\u8BF4\u660E:"View group guidance instructions",\u67E5\u770B\u79C1\u804A\u589E\u5F3A\u63D0\u793A\u8BCD\u4F7F\u7528\u8BF4\u660E:"View direct guidance instructions",\u4F7F\u7528\u8BF4\u660E:"How to use","\u7528\u4E8E\u544A\u8BC9\u6A21\u578B\u5982\u4F55\u4F7F\u7528 \u4E2D\u5DF2\u9009\u62E9\u7684\u6765\u6E90\u5B57\u6BB5\u3002\u53EA\u586B\u5199\u6B63\u6587\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u6DFB\u52A0 \u6210\u5BF9\u6807\u7B7E\u3002":"Tell the model how to use the selected fields in . Enter only the body; the plugin adds paired tags.",\u751F\u6548\u89C4\u5219:"Behavior",\u9690\u79C1\u63D0\u793A:"Privacy",\u4F7F\u7528\u793A\u4F8B:"Example","\u4EC5\u4F9D\u636E\u5F53\u524D\u6D88\u606F\u7684 \u4E2D\u5B9E\u9645\u63D0\u4F9B\u7684\u5B57\u6BB5\u7406\u89E3\u6765\u6E90\uFF1B\u6CA1\u6709\u63D0\u4F9B\u7684\u5B57\u6BB5\u4E0D\u8981\u731C\u6D4B\u6216\u8865\u5168\u3002\nconversationType\u662F\u7FA4\u804A\u65F6\u56DE\u590D\u4E25\u8083\u4E00\u70B9\uFF0CconversationType\u662F\u79C1\u804A\u65F6\u56DE\u590D\u4E00\u5B9A\u8981\u5E7D\u9ED8\u641E\u7B11\uFF0C\u50CF\u5468\u661F\u9A70\u7684\u7535\u5F71\u4E00\u6837\u641E\u7B11":`Understand the source only from fields actually present in for the current message; do not guess or fill in missing fields. +`,{encoding:"utf8",mode:384}),await JGe(o,this.#e)}};import{randomUUID as MZ}from"node:crypto";var yG=new Set(["starting","qr_ready","polling","slow_down","domain_switched","saving"]),XGe=new Set(["polling","slow_down","domain_switched"]),Va=Object.freeze({IDLE:"idle",STARTING:"starting",QR_READY:"qr_ready",POLLING:"polling",SLOW_DOWN:"slow_down",DOMAIN_SWITCHED:"domain_switched",SAVING:"saving",SUCCEEDED:"succeeded",EXPIRED:"expired",CANCELLED:"cancelled",ERROR:"error"});function SZ(n){return["access_denied","expired_token","abort"].includes(n?.code)?n.code:"registration_failed"}function mG(n){let t=SZ(n);return{code:t,message:{access_denied:"Registration was denied.",abort:"Registration was cancelled.",expired_token:"The registration QR code expired."}[t]??"Unable to register the Feishu app."}}function $Ge(n){let t=Number(n);if(!Number.isFinite(t)||t<=0)throw new TypeError("registerApp onQRCodeReady returned an invalid expireIn");return t}function eFe(n){if(n!==void 0){if(n===null||typeof n!="object"||Array.isArray(n))throw new TypeError("registerApp returned invalid user_info");return{...n}}}var Yg=class{#e;#A;#t;#r;#I;#o=0;#g=null;#i;constructor({registerApp:t,onCredentials:o,now:a=Date.now,setTimeout:e=globalThis.setTimeout,clearTimeout:i=globalThis.clearTimeout}={}){if(typeof t!="function")throw new TypeError("RegistrationManager requires a registerApp function");if(typeof o!="function")throw new TypeError("RegistrationManager requires an onCredentials function");if(typeof a!="function"||typeof e!="function"||typeof i!="function")throw new TypeError("RegistrationManager clock dependencies must be functions");this.#e=t,this.#A=o,this.#t=a,this.#r=e,this.#I=i,this.#i=this.#s(null,Va.IDLE)}start(t={}){if(t===null||typeof t!="object"||Array.isArray(t))throw new TypeError("Registration options must be an object");this.#f();let o={id:++this.#o,controller:new AbortController,qrCodeUrl:null,expiresAt:null,pollIntervalSeconds:null,expiryTimer:null};this.#g=o,this.#i=this.#s(o,Va.STARTING);let a={...t,signal:o.controller.signal,onQRCodeReady:i=>this.#c(o,i),onStatusChange:i=>this.#d(o,i)};return Promise.resolve().then(()=>this.#e(a)).then(i=>this.#n(o,i),i=>this.#p(o,i)),this.status()}status(){this.#E();let t={...this.#i};t.error&&(t.error={...t.error});let o=this.#g;return o&&o.expiresAt!==null&&yG.has(t.state)&&(t.remainingSeconds=Math.max(0,Math.ceil((o.expiresAt-this.#t())/1e3))),t}cancel(){let t=this.#g;return t?(this.#C(t,Va.CANCELLED,{error:{code:"abort",message:"Registration was cancelled."}}),t.controller.abort(),this.status()):this.status()}#a(t){return this.#g===t}#s(t,o,a={}){let e={state:o,attempt:t?.id??this.#o,updatedAt:this.#t(),...a};return t?.qrCodeUrl&&yG.has(o)&&(e.qrCodeUrl=t.qrCodeUrl,e.expiresAt=t.expiresAt),t?.pollIntervalSeconds!==null&&yG.has(o)&&(e.pollIntervalSeconds=t.pollIntervalSeconds),e}#l(t,o,a={}){this.#a(t)&&(this.#i=this.#s(t,o,a))}#c(t,o){if(!this.#a(t))return;if(typeof o?.url!="string"||!o.url)throw new TypeError("registerApp onQRCodeReady returned an invalid URL");let a=$Ge(o.expireIn);t.qrCodeUrl=o.url,t.expiresAt=this.#t()+a*1e3,this.#B(t),t.expiryTimer=this.#r(()=>this.#u(t),a*1e3),t.expiryTimer?.unref?.(),this.#l(t,Va.QR_READY)}#d(t,o){!this.#a(t)||!XGe.has(o?.status)||(o.status===Va.SLOW_DOWN&&Number.isFinite(Number(o.interval))&&(t.pollIntervalSeconds=Number(o.interval)),this.#l(t,o.status))}async#n(t,o){if(!this.#a(t))return;let a=o?.client_id,e=o?.client_secret;if(typeof a!="string"||!a||typeof e!="string"||!e){this.#C(t,Va.ERROR,{error:{code:"invalid_credentials",message:"Feishu registration returned invalid credentials."}});return}let i;try{i=eFe(o.user_info)}catch{this.#C(t,Va.ERROR,{error:{code:"invalid_credentials",message:"Feishu registration returned invalid credentials."}});return}this.#B(t),t.qrCodeUrl=null,t.expiresAt=null,t.pollIntervalSeconds=null,this.#l(t,Va.SAVING);try{await this.#A({client_id:a,client_secret:e,user_info:i})}catch{this.#a(t)&&this.#C(t,Va.ERROR,{error:{code:"credentials_callback_failed",message:"Unable to store the Feishu credentials."}});return}this.#a(t)&&this.#C(t,Va.SUCCEEDED)}#p(t,o){if(!this.#a(t))return;let a=SZ(o);if(a==="expired_token"){this.#C(t,Va.EXPIRED,{error:mG(o)});return}if(a==="abort"){this.#C(t,Va.CANCELLED,{error:mG(o)});return}this.#C(t,Va.ERROR,{error:mG(o)})}#E(){let t=this.#g;t&&t.expiresAt!==null&&this.#t()>=t.expiresAt&&this.#u(t)}#u(t){this.#a(t)&&(this.#C(t,Va.EXPIRED,{error:{code:"expired_token",message:"The registration QR code expired."}}),t.controller.abort())}#C(t,o,a={}){this.#a(t)&&(this.#B(t),this.#i=this.#s(t,o,a),this.#g=null)}#B(t){t.expiryTimer!==null&&(this.#I(t.expiryTimer),t.expiryTimer=null)}#f(){let t=this.#g;t&&(this.#B(t),this.#g=null,t.controller.abort())}};var AFe="card.action.trigger",tFe="im:message:readonly",rFe="im:resource",tB="callback_repair";function iFe(n){return n==="lark"?"accounts.larksuite.com":"accounts.feishu.cn"}function aFe(n){return n==="lark"?"open.larksuite.com":"open.feishu.cn"}function SG(n,t,o="feishu",a="Feishu app update"){let e;try{e=new URL(n)}catch{throw new Error(`${a} returned an invalid verification URL`)}let i=o==="feishu"||o==="lark",A=e.searchParams.getAll("clientID"),r=e.searchParams.getAll("tp"),s=e.searchParams.getAll("addons"),g=String(t).includes("{{")||String(t).includes("}}")||[...e.searchParams.values()].some(c=>c.includes("{{")||c.includes("}}"));if(!i||e.protocol!=="https:"||e.hostname!==aFe(o)||e.port!==""||e.username!==""||e.password!==""||r.length!==1||r[0]!=="sdk"||A.length!==1||A[0]!==t||e.searchParams.has("createOnly")||s.length!==1||!s[0]?.trim()||g)throw new Error(`${a} returned an unsafe verification URL`);return e.toString()}function oFe(n,t,o="feishu"){return SG(n,t,o,"Feishu callback repair")}var aw=class{#e;#A;#t;constructor({registerApp:t,onCredentials:o,appId:a,domain:e="feishu"}={}){if(typeof t!="function")throw new TypeError("registerApp is required");if(typeof o!="function")throw new TypeError("onCredentials is required");if(typeof a!="string"||!a.trim())throw new TypeError("appId is required");if(e!=="feishu"&&e!=="lark")throw new TypeError("domain is invalid");this.#A=a.trim(),this.#t=e,this.#e=new Yg({registerApp:i=>t({...i,onQRCodeReady:A=>{oFe(A?.url,this.#A,this.#t),i.onQRCodeReady(A)}}),onCredentials:o})}start(){return this.#e.start({source:"deepseek-harness-card-action-repair",domain:iFe(this.#t),appId:this.#A,addons:{preset:!1,scopes:{tenant:[tFe,rFe,...$S]},callbacks:{items:[AFe]}}})}status(){return this.#e.status()}cancel(){return this.#e.cancel()}};var nFe="im:message.group_msg",nw="group_message_permission";function sFe(n){return n==="lark"?"accounts.larksuite.com":"accounts.feishu.cn"}function gFe(n,t,o="feishu"){return SG(n,t,o,"Feishu group message permission update")}var ow=class{#e;#A;#t;constructor({registerApp:t,onCredentials:o,appId:a,domain:e="feishu"}={}){if(typeof t!="function")throw new TypeError("registerApp is required");if(typeof o!="function")throw new TypeError("onCredentials is required");if(typeof a!="string"||!a.trim())throw new TypeError("appId is required");if(e!=="feishu"&&e!=="lark")throw new TypeError("domain is invalid");this.#A=a.trim(),this.#t=e,this.#e=new Yg({registerApp:i=>t({...i,onQRCodeReady:A=>{gFe(A?.url,this.#A,this.#t),i.onQRCodeReady(A)}}),onCredentials:o})}start(){return this.#e.start({source:"deepseek-harness-group-message-permission",domain:sFe(this.#t),appId:this.#A,addons:{preset:!1,scopes:{tenant:[nFe]}}})}status(){return this.#e.status()}cancel(){return this.#e.cancel()}};var wZ=Object.freeze(["im:message.p2p_msg:readonly","im:message.group_at_msg:readonly","im:message:readonly","im:message:send_as_bot","im:message.reactions:write_only","im:message:recall","im:resource","cardkit:card:write",...$S]);var wG=new Set(["starting","qr_ready","polling","slow_down","domain_switched"]),sw=new Set([...wG,"saving"]),DZ=new Set([tB,nw]),OZ="*",cFe=12e4,IFe=6e5;function _Z(){return{ready:!1,feishuLongConnectionState:"idle",harnessReachable:!1}}function rB(n){return n?n.status:_Z()}function iB(n){return n.ready===!0&&n.feishuLongConnectionState==="connected"&&n.harnessReachable===!0}function TZ(n){return n.length>12?`${n.slice(0,8)}\u2022\u2022\u2022\u2022${n.slice(-4)}`:"cli_\u2022\u2022\u2022\u2022"}function lFe(n){return{name:n.botName,appIdMasked:TZ(n.appId),activated:n.activated,domain:n.domain}}function dFe({connected:n,error:t,connection:o}){return n?"connected":t||o.feishuLongConnectionState==="failed"?"error":"disconnected"}function pFe(){return`bot_${MZ().replaceAll("-","")}`}function hFe(){return`reg_${MZ().replaceAll("-","")}`}function bZ(n){return`DSH_FEISHU_APP_SECRET_${n.slice(4).toUpperCase()}`}function gw(n){return JSON.stringify({id:n.id,appId:n.appId,secretRef:n.secretRef,ownerOpenIds:n.ownerOpenIds,domain:n.domain,botName:n.botName,botOpenId:n.botOpenId,activated:n.activated,groupResponseMode:Bo(n.groupResponseMode),groupMessagePermissionGranted:n.groupMessagePermissionGranted===!0,deletionPending:n.deletionPending===!0,connectedAt:n.connectedAt??null,createdAt:n.createdAt??null})}function cw(n){return typeof n=="string"&&n.trim()?n.trim():null}var aB=class{#e;#A;#t;#r;#I;#o;#g;#i;#a=new Map;#s=new Map;#l=new Map;#c=new Map;#d=new Map;#n=null;#p=Promise.resolve();#E=new Map;#u=1;#C;#B=!1;constructor({registerApp:t,verifyApp:o,credentials:a,configStore:e,createRuntime:i,deleteState:A=async()=>{},createBotId:r=pFe,createRegistrationId:s=hFe,callbackProbeTimeoutMs:g=cFe}){if(typeof t!="function")throw new Error("registerApp is required");if(typeof o!="function")throw new Error("verifyApp is required");if(!a)throw new Error("credentials service is required");if(!e||typeof e.list!="function")throw new Error("multi-bot config store is required");if(typeof i!="function")throw new Error("createRuntime is required");if(typeof A!="function")throw new Error("deleteState must be a function");if(!Number.isFinite(g)||g<=0||g>IFe)throw new TypeError("callbackProbeTimeoutMs must be between 1 and 600000ms");this.#e=t,this.#A=o,this.#t=a,this.#r=e,this.#I=i,this.#o=A,this.#g=r,this.#i=s,this.#C=g}async initialize(){if(this.#B)return this.status();let t=this.#r.list(),o=!1;return await Promise.allSettled(t.map(a=>this.#_(a.id,async()=>{let e=rB(this.#a.get(a.id));if(iB(e)||e.feishuLongConnectionState==="connecting"||e.feishuLongConnectionState==="reconnecting")return;if(o=!0,a.deletionPending){this.#s.set(a.id,{code:"deletion_pending",message:"\u673A\u5668\u4EBA\u6B63\u5728\u7B49\u5F85\u5B8C\u6210\u672C\u5730\u5220\u9664\uFF0C\u8BF7\u91CD\u8BD5\u79FB\u9664\u3002"});return}let i;try{i=await this.#t.resolve(a.secretRef)}catch{this.#s.set(a.id,{code:"missing_credentials",message:"\u65E0\u6CD5\u8BFB\u53D6\u673A\u5668\u4EBA\u51ED\u636E\uFF0C\u8BF7\u68C0\u67E5\u51ED\u636E\u5B58\u50A8\u3002"});return}if(!i?.value){this.#s.set(a.id,{code:"missing_credentials",message:"\u673A\u5668\u4EBA\u51ED\u636E\u7F3A\u5931\uFF0C\u8BF7\u5220\u9664\u540E\u91CD\u65B0\u626B\u7801\u63A5\u5165\u3002"});return}try{await this.#h(a,i.value),this.#s.delete(a.id)}catch{this.#s.set(a.id,{code:"connection_failed",message:"\u673A\u5668\u4EBA\u6682\u65F6\u65E0\u6CD5\u8FDE\u63A5\u98DE\u4E66\uFF0C\u8BF7\u91CD\u8BD5\u3002"})}}))),o&&this.#R(),this.status()}startRegistration(){this.#N();let t=this.#i();if(typeof t!="string"||!/^[A-Za-z0-9_-]{1,128}$/.test(t)||this.#l.has(t))throw new Error("Registration id generator returned an invalid or duplicate id");let o={id:t,manager:null,botId:null,createdNew:!1,cancelled:!1};return o.manager=new Yg({registerApp:this.#e,onCredentials:a=>this.#P(()=>this.#D(o,a))}),this.#l.set(t,o),this.#n=t,this.#G(),o.manager.start({source:"deepseek-harness",createOnly:!0,appPreset:{name:"{user} \u7684\u5317\u6C47\u661F\u6CB3 AI \u52A9\u624B",desc:"\u8FDE\u63A5\u98DE\u4E66\u4E0E DeepSeek Harness\uFF0C\u5728\u804A\u5929\u4E2D\u4F7F\u7528\u4F01\u4E1A AI \u52A9\u624B\u3002"},addons:{preset:!1,scopes:{tenant:[...wZ]},events:{items:{tenant:["im.message.receive_v1"]}},callbacks:{items:["card.action.trigger"]}}}),this.#R(),this.registrationStatus(t)}startCallbackRepair(t,{actorOpenId:o,chatId:a}={}){this.#N();let e=this.#T(t);if(e.deletionPending)throw new Error("Cannot repair a Feishu bot pending deletion");let i=this.#c.get(t),A=i?this.#l.get(i):null;if(A&&sw.has(A.manager.status().state)){if(A.operation!==tB)throw new Error("Another Feishu app update is already active for this bot");return this.registrationStatus(A.id)}this.#c.delete(t);let r=this.#i();if(typeof r!="string"||!/^[A-Za-z0-9_-]{1,128}$/.test(r)||this.#l.has(r))throw new Error("Registration id generator returned an invalid or duplicate id");let s={id:r,operation:tB,manager:null,botId:t,createdNew:!1,cancelled:!1,remoteCommitted:!1,processing:null,publicError:null,stage:"authorizing",target:structuredClone(e),targetFingerprint:gw(e),initiator:{actorOpenId:cw(o),chatId:cw(a)}};return s.manager=new aw({registerApp:this.#e,appId:e.appId,domain:e.domain,onCredentials:g=>{s.remoteCommitted=!0;let I=this.#m(s,g).finally(()=>{s.processing===I&&(s.processing=null)});return s.processing=I,I}}),this.#l.set(r,s),this.#c.set(t,r),this.#n=r,this.#G(),s.manager.start(),this.#R(),this.registrationStatus(r)}startGroupMessagePermission(t){this.#N();let o=this.#T(t);if(o.deletionPending)throw new Error("Cannot update permissions for a Feishu bot pending deletion");let a=this.#c.get(t),e=a?this.#l.get(a):null;if(e&&sw.has(e.manager.status().state)){if(e.operation!==nw)throw new Error("Another Feishu app update is already active for this bot");return this.registrationStatus(e.id)}this.#c.delete(t);let i=this.#i();if(typeof i!="string"||!/^[A-Za-z0-9_-]{1,128}$/.test(i)||this.#l.has(i))throw new Error("Registration id generator returned an invalid or duplicate id");let A={id:i,operation:nw,manager:null,botId:t,createdNew:!1,cancelled:!1,remoteCommitted:!1,processing:null,publicError:null,stage:"authorizing",target:structuredClone(o),targetFingerprint:gw(o),initiator:{actorOpenId:null,chatId:null}};return A.manager=new ow({registerApp:this.#e,appId:o.appId,domain:o.domain,onCredentials:r=>{A.remoteCommitted=!0;let g=this.#w(A,r).finally(()=>{A.processing===g&&(A.processing=null)});return A.processing=g,g}}),this.#l.set(i,A),this.#c.set(t,i),this.#n=i,this.#G(),A.manager.start(),this.#R(),this.registrationStatus(i)}hasRegistration(t){return this.#l.has(t)}registrationStatus(t){let o=this.#l.get(t);return o?this.#f({registration:o,selectedBotId:o.botId}):null}async cancelRegistration(t=this.#n){let o=this.#l.get(t);if(!o)return this.status();let a=o.manager.status().state;return DZ.has(o.operation)&&a==="saving"?this.registrationStatus(t):sw.has(a)?(o.cancelled=!0,o.manager.cancel(),await this.#P(async()=>{o.createdNew&&o.botId&&this.#d.get(o.botId)===o.id&&this.#r.getBot(o.botId)&&await this.#_(o.botId,()=>this.#O(o.botId))}),this.#R(),this.registrationStatus(t)??this.status()):this.registrationStatus(t)}status(t){return this.#f({registration:this.#l.get(this.#n)??null,selectedBotId:t})}async bindCredentials({appId:t,appSecret:o,domain:a="feishu"}={}){this.#N();let e=typeof t=="string"?t.trim():"",i=typeof o=="string"?o.trim():"",A=a==="lark"?"lark":"feishu";if(!e||!i)throw new TypeError("Feishu App ID and App Secret are required");return this.#P(async()=>{this.#N();let r=await this.#A({appId:e,appSecret:i,domain:A});this.#N();let s=this.#r.list().find(f=>f.appId===e),g=s?.id??this.#g();if(typeof g!="string"||!/^[A-Za-z0-9_-]{1,128}$/.test(g)||!s&&this.#r.getBot(g))throw new Error("Bot id generator returned an invalid or duplicate id");let c=s?.secretRef??bZ(g),I=await this.#t.resolve(c).catch(()=>{}),d={...s,id:g,appId:e,secretRef:c,ownerOpenIds:s?.ownerOpenIds?.length?s.ownerOpenIds:[OZ],domain:A,botName:r.name,botOpenId:r.openId,activated:r.activated,deletionPending:!1,connectedAt:new Date().toISOString(),createdAt:s?.createdAt??new Date().toISOString()};await this.#t.set(c,i);let B;try{B=await this.#r.saveBot(d)}catch(f){throw await this.#S(c,I),f}return await this.#_(g,async()=>{try{await this.#h(B,i),this.#s.delete(g)}catch{this.#s.set(g,{code:"connection_failed",message:"\u673A\u5668\u4EBA\u5DF2\u7ECF\u7ED1\u5B9A\uFF0C\u4F46\u957F\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u8BF7\u70B9\u51FB\u91CD\u8BD5\u3002"})}}),this.#R(),this.status(g)})}async reconnectBot(t){return this.#N(),this.#_(t,async()=>{let o=this.#T(t);if(o.deletionPending)return this.#s.set(t,{code:"deletion_pending",message:"\u673A\u5668\u4EBA\u6B63\u5728\u7B49\u5F85\u5B8C\u6210\u672C\u5730\u5220\u9664\uFF0C\u8BF7\u91CD\u8BD5\u79FB\u9664\u3002"}),this.status(t);if(iB(rB(this.#a.get(t))))return this.status(t);let a;try{a=await this.#t.resolve(o.secretRef)}catch{a=null}if(!a?.value)return this.#s.set(t,{code:"missing_credentials",message:"\u673A\u5668\u4EBA\u51ED\u636E\u7F3A\u5931\uFF0C\u8BF7\u5220\u9664\u540E\u91CD\u65B0\u626B\u7801\u63A5\u5165\u3002"}),this.#R(),this.status(t);try{await this.#h(o,a.value),this.#s.delete(t)}catch{this.#s.set(t,{code:"connection_failed",message:"\u673A\u5668\u4EBA\u6682\u65F6\u65E0\u6CD5\u8FDE\u63A5\u98DE\u4E66\uFF0C\u8BF7\u91CD\u8BD5\u3002"})}return this.#R(),this.status(t)})}async sendConnectionTest(t){return this.#N(),this.#_(t,async()=>{let o=this.#T(t),a=this.#a.get(t);if(!iB(rB(a))||typeof a.sendConnectionTest!="function"){let e=new Error("\u98DE\u4E66\u673A\u5668\u4EBA\u5C1A\u672A\u8FDE\u63A5");throw e.code="test-target-unavailable",e}return a.sendConnectionTest(Ki(`${o.botName}\uFF08${TZ(o.appId)}\uFF09`,"\u98DE\u4E66\u673A\u5668\u4EBA"))})}async sendProactiveText(t,o,a,e={}){return this.#N(),this.#_(t,async()=>{this.#T(t);let i=this.#a.get(t);if(!iB(rB(i))||typeof i.sendProactiveText!="function"){let A=new Error("\u98DE\u4E66\u673A\u5668\u4EBA\u5C1A\u672A\u8FDE\u63A5");throw A.code="bot-not-connected",A}return i.sendProactiveText(o,a,e)})}async disconnectBot(t){return this.#N(),this.#_(t,async()=>(this.#T(t),await this.#M(t),this.#s.delete(t),this.#R(),this.status(t)))}async updateGroupResponseMode(t,o){if(this.#N(),!jS(o))throw new TypeError("Invalid Feishu group response mode");return this.#P(()=>this.#_(t,async()=>{let a=this.#T(t);if(o==="all"&&a.groupMessagePermissionGranted!==!0){let i=new Error("Authorize im:message.group_msg before enabling all group messages");throw i.code="group_message_permission_required",i}let e=await this.#r.saveBot({...a,groupResponseMode:o});return this.#a.get(t)?.setGroupResponseMode?.(e.groupResponseMode),this.#R(),this.status(t)}))}async deleteBot(t){return this.#N(),this.#P(()=>this.#_(t,async()=>(this.#T(t),await this.#O(t),this.#R(),this.status())))}async reconnect(){let t=this.#r.list()[0];return t?this.reconnectBot(t.id):this.status()}async disconnect(){let t=this.#r.list()[0];return t?this.deleteBot(t.id):this.status()}async close(){if(this.#B)return;this.#B=!0;let t=[];for(let o of this.#l.values()){let a=o.manager.status().state;DZ.has(o.operation)&&a==="saving"?(o.manager.cancel(),o.processing&&t.push(o.processing)):sw.has(a)&&(o.cancelled=!0,o.manager.cancel())}await this.#p,await Promise.allSettled([...this.#E.values()]),await Promise.allSettled([...this.#a.keys()].map(o=>this.#M(o))),await Promise.allSettled(t),await this.#p,await Promise.allSettled([...this.#E.values()]),await Promise.allSettled([...this.#a.keys()].map(o=>this.#M(o)))}#f({registration:t,selectedBotId:o}={}){let a=this.#r.list().map(I=>{let d=rB(this.#a.get(I.id)),B=iB(d),f=this.#s.get(I.id)??null;return{botId:I.id,phase:dFe({connected:B,error:f,connection:d}),connected:B,configured:!0,groupResponseMode:Bo(I.groupResponseMode),groupMessagePermissionGranted:I.groupMessagePermissionGranted===!0,bot:lFe(I),connection:d,lastMessageError:ii(d.lastMessageError),error:f}}),e=t?this.#y(t):{state:"idle",attempt:0,updatedAt:Date.now()},i=wG.has(e.state),A=e.state==="saving",r=!!t&&(i||A),s=a.find(I=>I.botId===o)??(r?null:a[0]??null),g=a.some(I=>I.connected),c=s?.phase??"unconfigured";return i?c="registering":A?c="connecting":e.state==="error"&&!s&&(c="error"),{schemaVersion:2,revision:this.#u,phase:c,connected:s?.connected??!1,configured:a.length>0,bot:s?.bot??null,connection:s?.connection??_Z(),error:s?.error??e.error??null,registration:e,bots:a,totals:{configured:a.length,connected:a.filter(I=>I.connected).length},anyConnected:g}}#y(t){let o=t.manager.status();return{...o,attempt:t.id,...t.botId?{botId:t.botId}:{},...t.operation?{operation:t.operation}:{},...t.stage?{stage:t.stage}:{},...o.state==="error"&&t.publicError?{error:{...t.publicError}}:{}}}async#w(t,o){let a=o.client_id,e=o.client_secret,i=cw(o.user_info?.open_id),A=o.user_info?.tenant_brand,r=t.target;if(t.cancelled)throw this.#Q(t,"abort","Group message permission update was cancelled before local activation.");if(a!==r.appId)throw this.#Q(t,"repair_app_mismatch","Feishu returned credentials for a different app.");if(!i)throw this.#Q(t,"repair_owner_missing","Feishu returned no permission operator identity.");if(A!==void 0&&A!==r.domain)throw this.#Q(t,"repair_domain_mismatch","Feishu returned credentials for a different account domain.");if(!r.ownerOpenIds.includes(OZ)&&!r.ownerOpenIds.includes(i))throw this.#Q(t,"repair_owner_mismatch","The Feishu permission operator is not an owner of this configured bot.");t.stage="verifying_identity";let s;try{s=await this.#A({appId:a,appSecret:e,domain:r.domain})}catch(g){throw this.#Q(t,"repair_credentials_invalid","Feishu could not verify the updated app credentials.",g)}if(r.botOpenId&&s?.openId!==r.botOpenId)throw this.#Q(t,"repair_bot_mismatch","The updated Feishu app belongs to a different bot identity.");await this.#P(()=>this.#_(t.botId,async()=>{let g=this.#r.getBot(t.botId);if(!g||g.deletionPending||gw(g)!==t.targetFingerprint)throw this.#Q(t,"repair_target_changed","The Feishu bot changed while its permission update was in progress.");let c;try{c=await this.#t.resolve(g.secretRef)}catch(d){throw this.#Q(t,"credential_update_failed","Unable to read the current Feishu credential.",d)}if(c?.value!==e){t.stage="persisting_secret";try{await this.#t.set(g.secretRef,e)}catch(B){if((await this.#t.resolve(g.secretRef).catch(()=>null))?.value!==e)throw this.#Q(t,"credential_update_failed","Unable to store the updated Feishu credential.",B)}if((await this.#t.resolve(g.secretRef).catch(()=>null))?.value!==e)throw this.#Q(t,"credential_state_unknown","The updated Feishu credential could not be confirmed after writing.")}t.stage="enabling_all_messages";let I;try{I=await this.#r.saveBot({...g,groupMessagePermissionGranted:!0,groupResponseMode:"all"})}catch(d){throw this.#Q(t,"group_message_permission_save_failed","The permission was accepted, but all-message mode could not be saved.",d)}t.stage="restarting";try{await this.#h(I,e)}catch(d){throw this.#s.set(t.botId,{code:"connection_failed",message:"\u7FA4\u6D88\u606F\u6743\u9650\u5DF2\u5F00\u901A\uFF0C\u4F46\u673A\u5668\u4EBA\u957F\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u8BF7\u70B9\u51FB\u91CD\u8BD5\u3002"}),this.#R(),this.#Q(t,"group_message_permission_connection_failed","The permission was accepted, but the Feishu runtime could not restart.",d)}this.#s.delete(t.botId),t.stage="verified",t.publicError=null,this.#R()}))}async#m(t,o){let a=o.client_id,e=o.client_secret,i=cw(o.user_info?.open_id),A=o.user_info?.tenant_brand,r=t.target;if(t.cancelled)throw this.#Q(t,"abort","Callback repair was cancelled before local activation.");if(a!==r.appId)throw this.#Q(t,"repair_app_mismatch","Feishu returned credentials for a different app.");if(!i)throw this.#Q(t,"repair_owner_missing","Feishu returned no repair operator identity.");if(A!==void 0&&A!==r.domain)throw this.#Q(t,"repair_domain_mismatch","Feishu returned credentials for a different account domain.");t.stage="verifying_identity";let s;try{s=await this.#A({appId:a,appSecret:e,domain:r.domain})}catch(c){throw this.#Q(t,"repair_credentials_invalid","Feishu could not verify the repaired app credentials.",c)}if(r.botOpenId&&s?.openId!==r.botOpenId)throw this.#Q(t,"repair_bot_mismatch","The repaired Feishu app belongs to a different bot identity.");let g=await this.#P(()=>this.#_(t.botId,async()=>{let c=this.#r.getBot(t.botId);if(!c||c.deletionPending||gw(c)!==t.targetFingerprint)throw this.#Q(t,"repair_target_changed","The Feishu bot changed while its callback repair was in progress.");let I;try{I=await this.#t.resolve(c.secretRef)}catch(f){throw this.#Q(t,"credential_update_failed","Unable to read the current Feishu credential.",f)}if(I?.value!==e){t.stage="persisting_secret";try{await this.#t.set(c.secretRef,e)}catch(Q){if((await this.#t.resolve(c.secretRef).catch(()=>null))?.value!==e)throw this.#Q(t,"credential_update_failed","Unable to store the repaired Feishu credential.",Q)}if((await this.#t.resolve(c.secretRef).catch(()=>null))?.value!==e)throw this.#Q(t,"credential_state_unknown","The repaired Feishu credential could not be confirmed after writing.")}let B;t.stage="restarting";try{await this.#h(c,e),B=this.#a.get(t.botId)}catch(f){throw this.#s.set(t.botId,{code:"connection_failed",message:"\u673A\u5668\u4EBA\u56DE\u8C03\u4FEE\u590D\u5DF2\u4FDD\u5B58\uFF0C\u4F46\u957F\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u8BF7\u70B9\u51FB\u91CD\u8BD5\u3002"}),this.#R(),this.#Q(t,"repair_connection_failed","The repaired Feishu runtime could not be started.",f)}if(!B)throw this.#Q(t,"repair_connection_failed","The repaired Feishu runtime is unavailable.");return this.#s.delete(t.botId),this.#R(),B}));if(typeof g.beginCardActionProbe!="function")throw this.#Q(t,"card_action_probe_unavailable","The Feishu runtime cannot verify card callbacks.");t.stage="awaiting_callback";try{if((await g.beginCardActionProbe({expectedOperatorOpenId:t.initiator.actorOpenId??i,timeoutMs:this.#C,...t.initiator.chatId?{chatId:t.initiator.chatId}:{}}))?.verified!==!0){let I=new Error("Feishu runtime returned no callback proof");throw I.code="card_action_probe_failed",I}}catch(c){let I=c?.code==="card_action_probe_timeout"?"card_action_probe_timeout":c?.code==="card_action_probe_unavailable"?"card_action_probe_unavailable":c?.code==="card_action_probe_send_failed"?"card_action_probe_send_failed":"card_action_probe_failed";throw this.#Q(t,I,I==="card_action_probe_timeout"?"Timed out waiting for the Feishu callback verification button.":"The Feishu card callback probe failed.",c)}t.stage="verified",t.publicError=null,this.#R()}#Q(t,o,a,e){t.publicError={code:o,message:a};let i=new Error(a,e?{cause:e}:void 0);return i.code=o,i}async#D(t,o){if(t.cancelled)throw new Error("Registration was cancelled");let a=o.client_id,e=o.client_secret,i=o.user_info?.open_id,A=o.user_info?.tenant_brand==="lark"?"lark":"feishu";if(!i)throw new Error("Feishu registration returned no owner open_id");let r=await this.#A({appId:a,appSecret:e,domain:A});if(t.cancelled)throw new Error("Registration was cancelled");let s=this.#r.list().find(Q=>Q.appId===a),g=s?.id??this.#g();if(typeof g!="string"||!/^[A-Za-z0-9_-]{1,128}$/.test(g)||!s&&this.#r.getBot(g))throw new Error("Bot id generator returned an invalid or duplicate id");let c=s?.secretRef??bZ(g),I=this.#d.get(g),d=await this.#t.resolve(c).catch(()=>{});await this.#t.set(c,e);let B;try{B=await this.#r.saveBot({...s,id:g,appId:a,secretRef:c,ownerOpenIds:[...new Set([...s?.ownerOpenIds??[],i])],domain:A,botName:r.name,botOpenId:r.openId,activated:r.activated,deletionPending:!1,connectedAt:new Date().toISOString(),createdAt:s?.createdAt??new Date().toISOString()}),t.botId=g,t.createdNew=!s,this.#d.set(g,t.id)}catch(Q){try{await this.#S(c,d)}catch(y){throw new Error("Unable to restore the Feishu credential after a config failure.",{cause:y})}throw Q}if(t.cancelled)throw t.createdNew?await this.#_(g,()=>this.#O(g)):(await this.#r.saveBot(s),await this.#S(c,d),I?this.#d.set(g,I):this.#d.delete(g)),new Error("Registration was cancelled");let f=!1;try{if(await this.#_(g,()=>this.#h(B,e)),t.cancelled)throw t.createdNew?await this.#_(g,()=>this.#O(g)):(await this.#r.saveBot(s),await this.#S(c,d),I?this.#d.set(g,I):this.#d.delete(g),d?.value&&!s.deletionPending?await this.#_(g,()=>this.#h(s,d.value)):await this.#_(g,()=>this.#M(g))),f=!0,new Error("Registration was cancelled");this.#s.delete(g),this.#R()}catch(Q){if(t.cancelled)throw!f&&t.createdNew&&this.#r.getBot(g)?await this.#_(g,()=>this.#O(g)):!f&&s&&(await this.#r.saveBot(s),await this.#S(c,d),I?this.#d.set(g,I):this.#d.delete(g),!this.#B&&d?.value&&!s.deletionPending?await this.#_(g,()=>this.#h(s,d.value)):await this.#_(g,()=>this.#M(g))),this.#R(),Q;if(s&&d?.value)try{throw await this.#r.saveBot(s),await this.#S(c,d),I?this.#d.set(g,I):this.#d.delete(g),s.deletionPending?(await this.#_(g,()=>this.#M(g)),this.#s.set(g,{code:"deletion_pending",message:"\u673A\u5668\u4EBA\u6B63\u5728\u7B49\u5F85\u5B8C\u6210\u672C\u5730\u5220\u9664\uFF0C\u8BF7\u91CD\u8BD5\u79FB\u9664\u3002"})):(await this.#_(g,()=>this.#h(s,d.value)),this.#s.delete(g)),this.#R(),Q}catch(y){throw y===Q?Q:(this.#s.set(g,{code:"connection_failed",message:"\u673A\u5668\u4EBA\u8FDE\u63A5\u66F4\u65B0\u5931\u8D25\uFF0C\u4E14\u539F\u8FDE\u63A5\u65E0\u6CD5\u6062\u590D\uFF0C\u8BF7\u91CD\u8BD5\u3002"}),this.#R(),new Error("Unable to restore the previous Feishu bot connection.",{cause:y}))}throw this.#s.set(g,{code:"connection_failed",message:"\u673A\u5668\u4EBA\u5DF2\u7ECF\u521B\u5EFA\uFF0C\u4F46\u957F\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u8BF7\u70B9\u51FB\u91CD\u8BD5\u3002"}),this.#R(),Q}}async#h(t,o){await this.#M(t.id);let a=await this.#I({botId:t.id,config:t,appSecret:o,repair:this.#k(t.id)});this.#a.set(t.id,a);try{await a.start()}catch(e){throw this.#a.get(t.id)===a&&this.#a.delete(t.id),await a.stop({preserveError:!0}).catch(()=>{}),e}}#k(t){let o=a=>{let e=this.#l.get(a);return e?.operation===tB&&e.botId===t?e:null};return Object.freeze({start:({actorOpenId:a,chatId:e}={})=>this.startCallbackRepair(t,{actorOpenId:a,chatId:e}),status:({attemptId:a}={})=>o(a)?this.registrationStatus(a):null,cancel:async({attemptId:a}={})=>o(a)?this.cancelRegistration(a):this.status(t)})}async#M(t){let o=this.#a.get(t);this.#a.delete(t),o&&await o.stop()}async#O(t){let o=this.#r.getBot(t);if(o){o.deletionPending||(o=await this.#r.saveBot({...o,deletionPending:!0})),await this.#M(t);try{await this.#t.unset(o.secretRef)}catch(a){throw this.#s.set(t,{code:"credential_removal_failed",message:"\u65E0\u6CD5\u5220\u9664\u673A\u5668\u4EBA\u51ED\u636E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"}),new Error("Unable to remove the Feishu credential.",{cause:a})}try{await this.#o({botId:t,config:o})}catch(a){throw this.#s.set(t,{code:"state_cleanup_failed",message:"\u65E0\u6CD5\u5220\u9664\u673A\u5668\u4EBA\u7684\u672C\u5730\u4F1A\u8BDD\u6570\u636E\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002"}),new Error("Unable to remove the Feishu bot session state.",{cause:a})}await this.#r.removeBot(t),this.#s.delete(t),this.#d.delete(t)}}async#S(t,o){o?.value?await this.#t.set(t,o.value):await this.#t.unset(t)}#T(t){let o=this.#r.getBot(t);if(!o)throw new Error("Unknown Feishu bot");return o}#N(){if(this.#B)throw new Error("The Feishu controller is closed")}#P(t){let o=this.#p.then(t,t);return this.#p=o.then(()=>{},()=>{}),o}#_(t,o){let e=(this.#E.get(t)??Promise.resolve()).then(o,o),i=e.then(()=>{},()=>{});return this.#E.set(t,i),i.finally(()=>{this.#E.get(t)===i&&this.#E.delete(t)}),e}#G(){if(!(this.#l.size<=32))for(let[t,o]of this.#l){if(t===this.#n)continue;let a=o.manager.status().state;if(!wG.has(a)&&a!=="saving"&&this.#l.delete(t),this.#l.size<=32)break}}#R(){this.#u+=1}};var CFe=["open.feishu.cn","open.larksuite.com"];function BFe(n,t){if(t==="*")return!0;let o=t.startsWith(".")?t.slice(1):t;return o?n===o||n.endsWith(`.${o}`):!1}function fFe(n){for(let t of["no_proxy","NO_PROXY"]){let o=n?.[t];if(typeof o!="string"||!o.trim())continue;let a=o.split(",").map(e=>e.trim().toLowerCase()).filter(Boolean);if(CFe.some(e=>a.some(i=>BFe(e,i))))return!0}return!1}function QFe(n){if(!fFe(n))for(let t of["https_proxy","HTTPS_PROXY","http_proxy","HTTP_PROXY"]){let o=n?.[t];if(typeof o=="string"&&o.trim())return o.trim()}}function yFe(n,t=o=>new NZ.default(o)){let o=QFe(n);return o?t(o):void 0}function mFe(n){let t=Xc(n.dshHome??process.env.DSH_HOME??hh(EFe(),".dsh")),o=Xc(n.dataDir??hh(t,"integrations","dsh-feishu"));return{root:o,config:Xc(n.configPath??hh(o,"config.json")),legacyState:Xc(n.statePath??hh(o,"state.json")),bots:Xc(n.botsDir??hh(o,"bots")),workspaces:Xc(n.workspacesPath??hh(o,"workspaces.json"))}}async function DG(n,t={},o={}){if(!n?.credentials)throw new TypeError("dsh-feishu requires ctx.credentials");let a=ci(n,t),e=o.lark??iG,i=o.Controller??aB,A=o.ConfigStore??rw,r=o.StateStore??xS,s=o.HarnessClient??Aw,g=o.FeishuRuntime??ew,c=o.verifyFeishuApp??k5,I=Be=>c({...Be,httpInstance:e.defaultHttpInstance}),d=o.createConnectionSupervisor??aG,B=typeof n.logger=="function"?n.logger("dsh-feishu"):n.logger??console,f=()=>ji(n),Q=mFe(t),y=await new A(Q.config).load(),m=Xc(t.workspace??process.cwd()),_=o.WorkspaceStore??gi,T=o.workspaces??await new _(Q.workspaces,{defaultWorkspace:m}).load(),R=typeof y.list=="function",L=()=>R?y.list():[],U=L();R&&await T.reconcile(U.map(Be=>Be.id)),await Promise.all(U.map(Be=>T.ensure(Be.id,{defaultAgentPreset:t.agentPreset,initialAccessPolicy:pr("feishu",Be)})));let F=typeof y.removeBot=="function"?Ji(y,{workspaces:T,method:"removeBot",botIdFromRemoved:Be=>Be.id,saveMethod:"saveBot",botIdFromSave:Be=>Be?.id}):y,z=new Map,J=Be=>!Be.id||!Be.secretRef||Be.secretRef===iw?Q.legacyState:Xc(Q.bots,Be.id,"state.json"),K=async Be=>{let Re=Be.id??"__legacy__",Ne=z.get(Re);return Ne||(Ne=await new r(J(Be)).load(),z.set(Re,Ne)),Ne},G=async Be=>{let Re=L().find(Ne=>Ne.id===Be);if(!Re)throw new Error("Unknown Feishu bot");return K(Re)},V=Wi(n,o.commandExecutor),{controlExecutor:H,sessionMaintenanceExecutor:N,fileIngressExecutor:k}=Zi(n,{controlExecutor:o.controlExecutor,sessionMaintenanceExecutor:o.sessionMaintenanceExecutor,fileIngressExecutor:o.fileIngressExecutor}),q=new s({...a,workspace:m,autostart:!1,dshBin:t.dshBin??"dsh",...V?{commandExecutor:V}:{},...H?{controlExecutor:H}:{},...N?{sessionMaintenanceExecutor:N}:{},...k?{fileIngressExecutor:k}:{}}),X=o.proxyEnv??process.env,ie=yFe(X,o.createProxyAgent),De=new i({registerApp:Be=>e.registerApp(Be),verifyApp:I,credentials:n.credentials,configStore:F,createRuntime:async({botId:Be,config:Re,appSecret:Ne,repair:Je})=>{let ve=await K(Re),tA=Be??Re.id??Re.appId;await T.ensure(tA,{defaultAgentPreset:t.agentPreset,initialAccessPolicy:pr("feishu",Re)});let fe=qi(q,{botId:tA,workspaces:T,state:ve,agentPresetCatalog:f});return new g({lark:e,botId:tA,repair:Je,appId:Re.appId,appSecret:Ne,domain:Re.domain,botOpenId:Re.botOpenId,groupResponseMode:Re.groupResponseMode,ownerOpenIds:Re.ownerOpenIds??[Re.ownerOpenId],harness:fe.harness,state:fe.state,contextEnhancement:{botId:tA,getSettings:()=>T.contextEnhancementFor(tA)},accessPolicy:Xi(T,tA,{channel:"feishu",config:Re}),groupSessionScope:{getScope:()=>T.groupSessionScopeFor(tA)},replyTimeoutMs:t.replyTimeoutMs??6e5,slashCommands:t.slashCommands!==!1,...ie?{wsAgent:ie}:{},logger:{error:(...Ie)=>B.error?.(`[${Be??Re.id}]`,...Ie),warn:(...Ie)=>B.warn?.(`[${Be??Re.id}]`,...Ie),info:(...Ie)=>B.info?.(`[${Be??Re.id}]`,...Ie),debug:(...Ie)=>B.debug?.(`[${Be??Re.id}]`,...Ie)}})},deleteState:async({botId:Be,config:Re})=>{z.delete(Be);try{await uFe(J(Re))}catch(Ne){if(Ne?.code!=="ENOENT")throw Ne}}}),oe=zi(De,{workspaces:T,stateFor:G,agentPresetCatalog:f}),Se=d({controller:oe,harness:q,logger:B,retryDelaysMs:t.retryDelaysMs,healthyIntervalMs:t.healthyIntervalMs}).start();return{controller:oe,deliveryAdapter:Vi({channel:"feishu",workspaces:T,coreController:De,stateFor:G}),ready:Se.ready,async close(){await Se.close(),await oe.close(),q.stopManagedProcess(),ie?.destroy?.()}}}import KFe from"qrcode";var uh=ze(RG(),1);var LFe=ze(RG(),1);var UFe=Object.freeze({$locale:"en",IM\u673A\u5668\u4EBA:"IM bots",IM\u673A\u5668\u4EBA\u8BBE\u7F6E:"IM bot settings",\u66F4\u591A\u673A\u5668\u4EBA\u8BBE\u7F6E:"More bot settings",\u673A\u5668\u4EBA\u8BBE\u7F6E:"Bot settings",\u673A\u5668\u4EBA\u8BBE\u7F6E\u9875\u7B7E:"Bot settings tabs",\u6295\u9012\u8BBE\u7F6E:"Delivery settings",\u8BBF\u95EE\u8BBE\u7F6E:"Access settings","\u8BF7\u63D0\u4EA4\u6709\u6548\u7684\u7FA4\u540D\u540C\u6B65\u8BF7\u6C42\u3002":"Submit a valid group-name sync request.","\u540C\u6B65\u7FA4\u540D\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002":"Could not sync the group name. Try again later.","\u672A\u80FD\u4ECE WhatsApp \u8BFB\u53D6\u7FA4\u540D\uFF0C\u8BF7\u786E\u8BA4\u673A\u5668\u4EBA\u5728\u7EBF\u4E14\u4ECD\u5728\u8BE5\u7FA4\u3002":"Could not read the group name from WhatsApp. Confirm the bot is online and still in the group.","\u5DF2\u540C\u6B65\u7FA4\u540D\uFF1A":"Synced group name: ",\u540C\u6B65\u7FA4\u540D:"Sync group name",\u672A\u547D\u540D\u7FA4:"Unnamed group","\u6682\u65E0\u6635\u79F0\uFF08\u79C1\u804A/@ \u540E\u4F1A\u81EA\u52A8\u8865\u9F50\uFF09":"No nickname yet (filled after DM or @mention)","\u7FA4\u804A \xB7 ":"Group \xB7 ","\u3002\u8BB0\u5F97\u70B9\u4FDD\u5B58\u3002":". Remember to save.","\u5DF2\u52A0\u5165\u7FA4\u6388\u6743\uFF1A":"Added group access for: ","\u52A0\u5165\u7FA4\uFF1A":"Add to group: ","\u5DF2\u5728\u7FA4\uFF1A":"Already in group: ",\u586B\u5199\u4FBF\u4E8E\u8BC6\u522B\u7684\u7FA4\u540D\u79F0:"Enter a readable group name",\u7FA4\u540D\u79F0:"Group name",\u672A\u77E5\u7FA4:"Unknown group","\u65E0\u6CD5\u8BFB\u53D6\u8BBF\u95EE\u6388\u6743\uFF0C\u8BF7\u8FD4\u56DE\u5237\u65B0\u540E\u91CD\u8BD5\u3002":"Could not load the access grant. Go back, refresh, and try again.","\u6B63\u5728\u8BFB\u53D6\u5206\u7EA7\u8BBF\u95EE\u8BBE\u7F6E\u2026":"Loading graded access settings\u2026",\u52A0\u672C\u7FA4:"Add to group",\u5DF2\u5728\u672C\u7FA4:"Already in group",\u52A0\u79C1\u804A:"Add to DMs",\u5DF2\u5728\u79C1\u804A:"Already in DMs","\u5DF2\u52A0\u5165\u672C\u7FA4\u6388\u6743\uFF0C\u8BB0\u5F97\u70B9\u4FDD\u5B58\u3002":"Added to this group. Remember to save.","\u5DF2\u52A0\u5165\u79C1\u804A\u6388\u6743\uFF0C\u8BB0\u5F97\u70B9\u4FDD\u5B58\u3002":"Added to DM access. Remember to save.","\u6682\u65E0\u8054\u7CFB\u4EBA\u3002\u6709\u4EBA\u79C1\u804A\u6216 @ \u673A\u5668\u4EBA\u540E\u4F1A\u51FA\u73B0\u5728\u6B64\u3002":"No contacts yet. They appear here after someone DMs or @mentions the bot.","\u5F53\u524D\u8054\u7CFB\u4EBA\u5747\u5DF2\u5177\u5907\u5BF9\u5E94\u6743\u9650\uFF0C\u65E0\u9700\u518D\u6388\u6743\u3002":"Everyone in contacts already has the matching access; nothing left to grant.","\u4EC5\u8BB0\u5F55\u79C1\u804A\u673A\u5668\u4EBA\uFF0C\u6216\u5728\u7FA4\u91CC @ \u673A\u5668\u4EBA\u7684\u4EBA\u3002\u5DF2\u6709\u5BF9\u5E94\u6743\u9650\u7684\u4EBA\u4F1A\u81EA\u52A8\u9690\u85CF\uFF1B\u7535\u8BDD\u662F\u552F\u4E00\u6388\u6743\u952E\uFF0C\u53EF\u4E00\u952E\u52A0\u5165\u79C1\u804A/\u672C\u7FA4\u6388\u6743\u3002":"Only people who DM the bot or @mention it in a group are recorded. People who already have the matching access are hidden. Phone is the sole auth key; use one-click to grant DM or group access.","WhatsApp \u6309\u7535\u8BDD\u53F7\u7801\u6388\u6743\uFF1A\u5168\u5C40\u7BA1\u7406\u5458\u7BA1\u79C1\u804A\uFF1B\u7FA4\u7BA1\u7406\u5458\u53EA\u6279\u672C\u7FA4\u3002\u6210\u5458\u4E0D\u53EF\u8DE8\u7FA4\u3001\u6709\u7FA4\u6743\u4E5F\u4E0D\u81EA\u52A8\u83B7\u5F97\u79C1\u804A\u6743\u3002":"WhatsApp authorizes by phone number: global admins manage DMs; group admins approve only their group. Members do not cross groups, and group access does not grant DMs.",\u4FDD\u5B58\u5206\u7EA7\u8BBF\u95EE\u8BBE\u7F6E:"Save graded access settings",\u4FDD\u5B58\u8BBF\u95EE\u4E0E\u4F1A\u8BDD\u8BBE\u7F6E:"Save access and session settings",\u5168\u5C40\u7BA1\u7406\u5458:"Global admins","\u5206\u7EA7\u8BBF\u95EE\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002":"Graded access settings saved.","\u5BA1\u6279\u5931\u8D25\u3002":"Approval failed.","\u5C1A\u65E0\u5DF2\u77E5\u7FA4\u3002\u53EF\u5728\u4E0B\u65B9\u7C98\u8D34\u7FA4 JID\uFF08\u2026@g.us\uFF09\uFF0C\u6216\u7B49\u7FA4\u5185\u6709\u4EBA @ \u673A\u5668\u4EBA\u540E\u81EA\u52A8\u51FA\u73B0\u3002":"No known groups yet. Paste a group JID (\u2026@g.us) below, or wait until someone @mentions the bot in a group.","\u5DF2\u6279\u51C6\u7533\u8BF7\u3002":"Request approved.","\u5DF2\u62D2\u7EDD\u7533\u8BF7\u3002":"Request denied.","\u5F53\u524D\u6E20\u9053\u4ECD\u4F7F\u7528\u65E7\u7248\u8BBF\u95EE\u8BBE\u7F6E\u3002":"This channel still uses the legacy access settings.",\u5F85\u5BA1\u6279:"Pending approval",\u5F85\u8865\u7535\u8BDD:"Phone pending",\u6279\u51C6:"Approve",\u62D2\u7EDD:"Deny","\u6309\u53D1\u8A00\u4EBA\u62C6\u5206\uFF08\u63A8\u8350\uFF09":"Split by speaker (recommended)","\u6574\u7FA4\u5171\u4EAB\u4E00\u4E2A Session":"Share one session for the whole group",\u65B0\u589E\u7BA1\u7406\u5458:"Add admin",\u6682\u65E0\u5F85\u6279\u7533\u8BF7:"No pending requests","\u6682\u65E0\u8054\u7CFB\u4EBA\u3002\u79C1\u804A\u6216\u7FA4\u5185\u89E6\u53D1\u540E\u4F1A\u51FA\u73B0\u5728\u6B64\uFF0C\u4FBF\u4E8E\u8865\u9F50\u7535\u8BDD\u4E0E\u6635\u79F0\u3002":"No contacts yet. People who DM or trigger the bot in a group appear here so you can fill in phones and names.","\u6700\u8FD1\u8054\u7CFB\u4EBA\uFF08\u81EA\u52A8\u6C89\u6DC0\uFF09":"Recent contacts (auto-collected)","\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u5DF2\u4FDD\u5B58\u7684\u8BBF\u95EE\u6388\u6743\u3002":"The service did not return the saved access grant.",\u672A\u547D\u540D:"Unnamed","\u672A\u914D\u7F6E\u65F6\uFF0C\u672C\u7FA4\u7533\u8BF7\u56DE\u843D\u7ED9\u5168\u5C40\u7BA1\u7406\u5458\u5BA1\u6279\uFF08\u4ECD\u53EA\u6388\u4E88\u672C\u7FA4\u6743\uFF09\u3002":"When unset, this group's requests fall back to global admins (still grants only this group).",\u672C\u7FA4\u6388\u6743\u6210\u5458:"Group members",\u672C\u7FA4\u7BA1\u7406\u5458:"Group admins",\u67E5\u770B\u7FA4\u4F1A\u8BDD\u7B56\u7565\u8BF4\u660E:"View group session policy details",\u6DFB\u52A0\u7FA4:"Add group","\u6DFB\u52A0\u7FA4 JID":"Add group JID",\u7535\u8BDD:"Phone",\u79C1\u804A\u6388\u6743\u7528\u6237:"DM members","\u7ED1\u5B9A\u8D26\u53F7\u81EA\u52A8\u4E3A\u5168\u5C40\u7BA1\u7406\u5458\uFF0C\u81F3\u5C11\u4FDD\u7559\u4E00\u4F4D\u3002":"The linked account is a global admin automatically. Keep at least one.","\u7ED1\u5B9A\u8D26\u53F7\uFF08\u5168\u5C40\u7BA1\u7406\u5458\uFF09":"Linked account (global admin)","\u7F3A\u5C11\u53EF\u7528\u4E8E\u5BA1\u6279\u7684\u5168\u5C40\u7BA1\u7406\u5458\u7535\u8BDD\u3002":"No global admin phone is available for approval.","\u7FA4 JID \u683C\u5F0F\u65E0\u6548\u3002":"Invalid group JID.",\u7FA4\u4F1A\u8BDD\u7B56\u7565:"Group session policy","\u7FA4\u5185 Session \u7ED1\u5B9A":"In-group session binding",\u7FA4\u5907\u6CE8\u540D:"Group display name",\u7FA4\u6388\u6743:"Group grants","\u8BBF\u95EE\u4E0E\u7FA4\u4F1A\u8BDD\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002":"Access and group session settings saved.","\u8BBF\u95EE\u6388\u6743\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002":"Could not save the access grant. Try again later.","\u8BBF\u95EE\u6388\u6743\u6682\u4E0D\u53EF\u7528\u3002":"Access grant settings are currently unavailable.","\u8FD0\u7EF4\u9ED8\u8BA4\u6309\u53D1\u8A00\u4EBA\u62C6\u5206 Session\uFF0C\u907F\u514D\u540C\u7FA4\u591A\u4EBA\u4E92\u76F8\u6253\u65AD\uFF1B\u53EF\u9009\u6539\u56DE\u6574\u7FA4\u5171\u4EAB Session\u3002":"Ops defaults to one session per speaker so group members do not interrupt each other. You can switch back to one shared group session.","\uFF08\u7535\u8BDD\u672A\u89E3\u6790\uFF0C\u8BF7\u5148\u5728\u8054\u7CFB\u4EBA\u4E2D\u786E\u8BA4\uFF09":"(Phone unresolved \u2014 confirm it in contacts first)",\u67E5\u770B\u8BBF\u95EE\u6743\u9650\u8BF4\u660E:"View access permission details",\u5141\u8BB8\u6240\u6709\u7528\u6237:"Allow all users",\u4EC5\u767D\u540D\u5355\u7528\u6237:"Allowlisted users only",\u9ED8\u8BA4\u547D\u4EE4\u6743\u9650:"Default command permission",\u547D\u4EE4\u6743\u9650:"Command permission",\u53EF\u4EE5\u6267\u884C\u547D\u4EE4:"Can run commands",\u4E0D\u53EF\u4EE5\u6267\u884C\u547D\u4EE4:"Cannot run commands",\u767D\u540D\u5355\u7528\u6237:"Allowlisted users",\u67E5\u770B\u767D\u540D\u5355\u8BF4\u660E:"View allowlist details",\u547D\u4EE4\u6743\u9650\u4F8B\u5916:"Command permission exceptions","\u5F53\u524D\u6CA1\u6709\u767D\u540D\u5355\u7528\u6237\uFF0C\u4FDD\u5B58\u540E\u666E\u901A\u7528\u6237\u5C06\u65E0\u6CD5\u4F7F\u7528\u673A\u5668\u4EBA\u3002":"There are currently no allowlisted users. After saving, regular users will not be able to use the bot.",\u65B0\u589E\u7528\u6237:"Add user",\u5C1A\u672A\u6DFB\u52A0\u7528\u6237:"No users added",\u5F53\u524D\u6E20\u9053\u4E0D\u652F\u6301\u7FA4\u804A:"Group chat is not supported by this channel","\u539F\u6240\u6709\u8005\u6216\u626B\u7801\u63A5\u5165\u8005\u59CB\u7EC8\u53EF\u4EE5\u8BBF\u95EE\u5E76\u6267\u884C\u547D\u4EE4\uFF1B\u4EE5\u4E0B\u8BBE\u7F6E\u4EC5\u7EA6\u675F\u5176\u4ED6\u7528\u6237\u3002":"The original owner or QR-code operator can always access the bot and run commands; the settings below apply only to other users.","\u6B64\u533A\u57DF\u65E0\u9700\u914D\u7F6E\uFF0C\u4FDD\u5B58\u79C1\u804A\u8BBE\u7F6E\u65F6\u4F1A\u4FDD\u7559\u73B0\u6709\u7FA4\u804A\u7B56\u7565\u3002":"No setup is needed here. Saving direct-message settings keeps the existing group policy.","\u8BBF\u95EE\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002":"Access settings saved.","\u8BBF\u95EE\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002":"Access settings are currently unavailable.","\u8BBF\u95EE\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002":"Could not save access settings. Try again later.","\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u5DF2\u4FDD\u5B58\u7684\u8BBF\u95EE\u7B56\u7565\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5\u3002":"The service did not return the saved access policy. Refresh and try again.","\u8BBF\u95EE\u7B56\u7565\u5C1A\u672A\u5C31\u7EEA\uFF0C\u8BF7\u8FD4\u56DE\u673A\u5668\u4EBA\u5217\u8868\u5237\u65B0\u540E\u91CD\u8BD5\u3002":"The access policy is not ready. Return to the bot list, refresh, and try again.","\u5F53\u524D\u6E20\u9053\u6682\u4E0D\u652F\u6301\u8BBF\u95EE\u8BBE\u7F6E\u3002":"Access settings are not supported by this channel yet.","\u7528\u6237\u6807\u8BC6\u65E0\u6548\u3002":"The user ID is invalid.","\u7528\u6237\u6807\u8BC6\u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u3002":"The user ID must be a string.","\u7528\u6237\u6807\u8BC6\u4E0D\u80FD\u4E3A\u7A7A\u3001\u5305\u542B\u63A7\u5236\u5B57\u7B26\u6216\u8D85\u8FC7 256 \u4E2A\u5B57\u7B26\u3002":"The user ID cannot be empty, contain control characters, or exceed 256 characters.","\u7528\u6237\u6761\u76EE\u5FC5\u987B\u5305\u542B\u7528\u6237\u6807\u8BC6\u548C\u547D\u4EE4\u6743\u9650\u3002":"Each user entry must include a user ID and command permission.","\u547D\u4EE4\u6743\u9650\u5FC5\u987B\u662F\u5E03\u5C14\u503C\u3002":"Command permission must be a boolean.","\u8BBF\u95EE\u6A21\u5F0F\u53EA\u80FD\u662F open \u6216 allowlist\u3002":"Access mode must be open or allowlist.","\u5F00\u653E\u6A21\u5F0F\u8BBE\u7F6E\u5FC5\u987B\u5B8C\u6574\u3002":"Open-mode settings must be complete.","\u5F00\u653E\u6A21\u5F0F\u9ED8\u8BA4\u547D\u4EE4\u6743\u9650\u5FC5\u987B\u662F\u5E03\u5C14\u503C\u3002":"The open-mode default command permission must be a boolean.","\u5F00\u653E\u6A21\u5F0F\u547D\u4EE4\u6743\u9650\u8986\u76D6\u7528\u6237\u5FC5\u987B\u662F\u6570\u7EC4\u3002":"Open-mode command permission overrides must be an array.","\u5F00\u653E\u6A21\u5F0F\u547D\u4EE4\u6743\u9650\u8986\u76D6\u7528\u6237\u4E0D\u80FD\u5305\u542B\u91CD\u590D\u7684\u7528\u6237\u6807\u8BC6\u3002":"Open-mode command permission overrides cannot contain duplicate user IDs.","\u767D\u540D\u5355\u6A21\u5F0F\u8BBE\u7F6E\u5FC5\u987B\u5B8C\u6574\u3002":"Allowlist-mode settings must be complete.","\u767D\u540D\u5355\u6A21\u5F0F\u7528\u6237\u5FC5\u987B\u662F\u6570\u7EC4\u3002":"Allowlist-mode users must be an array.","\u767D\u540D\u5355\u6A21\u5F0F\u7528\u6237\u4E0D\u80FD\u5305\u542B\u91CD\u590D\u7684\u7528\u6237\u6807\u8BC6\u3002":"Allowlist-mode users cannot contain duplicate user IDs.","\u8BBF\u95EE\u573A\u666F\u8BBE\u7F6E\u5FC5\u987B\u540C\u65F6\u5305\u542B\u6A21\u5F0F\u3001\u5F00\u653E\u6A21\u5F0F\u8BBE\u7F6E\u548C\u767D\u540D\u5355\u6A21\u5F0F\u8BBE\u7F6E\u3002":"Each access context must include its mode, open-mode settings, and allowlist-mode settings.","\u8BF7\u540C\u65F6\u63D0\u4EA4\u5B8C\u6574\u7684\u79C1\u804A\u548C\u7FA4\u804A\u8BBF\u95EE\u8BBE\u7F6E\u3002":"Submit complete direct-message and group access settings together.","\u586B\u5199\u5FAE\u4FE1\u7528\u6237 ID":"Enter a WeChat user ID","\u98DE\u4E66 Open ID":"Feishu Open ID","\u7FA4\u6210\u5458 Open ID":"Group member Open ID","\u9489\u9489\u7528\u6237 ID":"DingTalk user ID","\u586B\u5199 senderStaffId \u6216 senderId":"Enter senderStaffId or senderId","\u7FA4\u6210\u5458\u7528\u6237 ID":"Group member user ID","\u4F01\u4E1A\u5FAE\u4FE1\u7528\u6237 ID":"WeCom user ID","\u586B\u5199 userid":"Enter userid","\u586B\u5199 member_openid":"Enter member_openid","QQ User Open ID":"QQ User Open ID","\u7FA4\u6210\u5458 User ID":"Group member User ID","\u586B\u5199\u6570\u5B57 User ID":"Enter a numeric user ID","WhatsApp \u7535\u8BDD\u53F7\u7801\u6216 JID":"WhatsApp phone number or JID","\u7FA4\u6210\u5458\u7535\u8BDD\u53F7\u7801\u6216 JID":"Group member phone number or JID","8613800000000 \u6216\u5B8C\u6574 JID":"8613800000000 or a full JID","IM \u6E20\u9053":"IM channels","\u8BA9 DeepSeek Harness \u89E6\u624B\u53EF\u53CA":"Connecting DeepSeek Harness",\u5F53\u524D\u7248\u672C:"Current version","DSH-IM \u66F4\u65B0":"DSH-IM update",\u68C0\u67E5\u66F4\u65B0:"Check for updates",\u91CD\u65B0\u68C0\u67E5:"Check again",\u5237\u65B0\u72B6\u6001:"Refresh status",\u624B\u5DE5\u66F4\u65B0:"Manual update",\u624B\u5DE5\u66F4\u65B0\u547D\u4EE4:"Manual update command",\u590D\u5236\u547D\u4EE4:"Copy command","\u590D\u5236\u4E2D\u2026":"Copying\u2026",\u5DF2\u590D\u5236:"Copied","\u547D\u4EE4\u5DF2\u590D\u5236\u3002":"Command copied.","\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u9009\u4E2D\u547D\u4EE4\u540E\u6309 Ctrl+C \u6216 \u2318C \u590D\u5236\u3002":"Copy failed. Select the command and press Ctrl+C or \u2318C to copy it.","\u81EA\u52A8\u66F4\u65B0\u5931\u8D25\u53EF\u4EE5\u4F7F\u7528\u547D\u4EE4\u66F4\u65B0\uFF1A":"If the automatic update fails, update with this command:","\u5C1A\u672A\u786E\u8BA4\u76EE\u6807\u7248\u672C\uFF0C\u6B64\u547D\u4EE4\u5B89\u88C5\u6267\u884C\u65F6 npm \u7684 latest \u7248\u672C\u3002":"No target version has been confirmed. This command installs the npm latest version available when you run it.","\u8BF7\u5728\u5F53\u524D Desktop \u7684\u5185\u7F6E\u7EC8\u7AEF\u6267\u884C\uFF0C\u5B8C\u6210\u540E\u624B\u52A8\u91CD\u542F\u3002":"Run this in the current Desktop\u2019s built-in terminal, then restart manually.","\u8BF7\u5728\u8FD0\u884C\u5F53\u524D Harness \u7684\u540C\u4E00\u73AF\u5883\u6267\u884C\uFF0C\u4FDD\u6301 DSH_HOME \u4E00\u81F4\uFF0C\u5B8C\u6210\u540E\u624B\u52A8\u91CD\u542F\u3002":"Run this in the same environment as the current Harness, with the same DSH_HOME, then restart manually.","\u8BF7\u7B49\u5F85\u5F53\u524D\u64CD\u4F5C\u7ED3\u675F\uFF0C\u786E\u8BA4\u6CA1\u6709\u5B89\u88C5\u8FDB\u7A0B\u8FD0\u884C\u540E\u518D\u6267\u884C\u547D\u4EE4\u3002":"Wait for the current operation to finish and confirm no installer is running before using this command.","\u6E90\u7801\u6216\u94FE\u63A5\u5B89\u88C5\u8BF7\u6309\u539F\u5B89\u88C5\u65B9\u5F0F\u66F4\u65B0\uFF0C\u4E0D\u63D0\u4F9B\u8986\u76D6\u6E90\u7801\u7684 npm \u547D\u4EE4\u3002":"Update source or linked installations using their original method. No npm command is provided to overwrite the source.","\u65E0\u6CD5\u5B89\u5168\u751F\u6210\u5F53\u524D profile \u7684\u547D\u4EE4\uFF0C\u8BF7\u5728\u7EC8\u7AEF\u4E2D\u624B\u52A8\u786E\u8BA4 profile \u540E\u66F4\u65B0\u3002":"A safe command cannot be generated for this profile. Confirm the profile in your terminal before updating manually.",\u66F4\u65B0\u81F3:"Update to",\u5B89\u88C5\u66F4\u65B0:"Install update","\u6B63\u5728\u66F4\u65B0\u2026":"Updating\u2026",\u5F85\u624B\u52A8\u91CD\u542F:"Restart needed",\u8FD0\u884C\u7248\u672C:"Running version",\u5DF2\u5B89\u88C5\u7248\u672C:"Installed version","\u76EE\u6807 profile":"Target profile",\u76EE\u6807\u7248\u672C:"Target version",\u65E0\u6CD5\u786E\u8BA4:"Unknown",\u53D1\u73B0\u65B0\u7248\u672C:"Update available",\u5DF2\u662F\u6700\u65B0\u7248\u672C:"Up to date",\u5F53\u524D\u7248\u672C\u65E0\u9700\u66F4\u65B0:"No newer version available","\u5DF2\u83B7\u53D6 npm \u6700\u65B0\u7248\u672C":"Latest npm version retrieved","\u68C0\u67E5 npm \u6700\u65B0\u7248\u672C\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u5B89\u88C5\u3002":"Check the latest npm version. Nothing is installed automatically.","\u6B63\u5728\u4ECE npm \u68C0\u67E5\u6700\u65B0\u7248\u672C\u2026":"Checking npm for the latest version\u2026","\u6B63\u5728\u5B89\u88C5\uFF0C\u8BF7\u7A0D\u5019\u2026":"Installing, please wait\u2026","\u6B63\u5728\u6821\u9A8C\u5B89\u88C5\u7ED3\u679C\u2026":"Verifying the installation\u2026","\u5DF2\u5B89\u88C5\uFF0C\u5F85\u624B\u52A8\u91CD\u542F":"Installed \u2014 manual restart needed",\u66F4\u65B0\u5DF2\u751F\u6548:"Updated version is active",\u66F4\u65B0\u5931\u8D25:"Update failed",\u66F4\u65B0\u8BF7\u6C42\u5931\u8D25:"Update request failed","\u4EC5\u66F4\u65B0 DSH-IM\u3002\u5B89\u88C5\u5B8C\u6210\u540E\u9700\u624B\u52A8\u91CD\u542F\u540E\u53F0\uFF1B\u672C\u529F\u80FD\u4E0D\u4F1A\u81EA\u52A8\u91CD\u542F\u6216\u4E3B\u52A8\u5237\u65B0\u9875\u9762\u3002":"Only DSH-IM will be updated. Restart the backend manually after installation. This feature does not automatically restart it or initiate a page refresh.","\u5F53\u524D\u662F\u6E90\u7801\u6216\u94FE\u63A5\u5B89\u88C5\uFF0C\u53EA\u80FD\u68C0\u67E5\u7248\u672C\uFF1B\u8BF7\u624B\u52A8\u66F4\u65B0\u6E90\u7801\uFF0C\u6216\u8FC1\u79FB\u5230 npm \u5B89\u88C5\u3002":"This is a source or linked installation. You can check versions, but must update the source manually or migrate to an npm installation.","\u65E0\u6CD5\u786E\u8BA4\u5F53\u524D profile\uFF0C\u8BF7\u5728\u5BF9\u5E94\u7684 Harness \u73AF\u5883\u4E2D\u624B\u52A8\u66F4\u65B0\u3002":"The current profile could not be identified. Update manually in the corresponding Harness environment.","\u5F53\u524D\u8FD0\u884C\u73AF\u5883\u4E0D\u652F\u6301\u6309\u94AE\u5B89\u88C5\uFF0C\u8BF7\u624B\u52A8\u66F4\u65B0\u63D2\u4EF6\u3002":"This runtime cannot install through this button. Update the plugin manually.","\u5F53\u524D npm \u6E90\u914D\u7F6E\u4E0E\u5B98\u65B9\u6E90\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u5148\u68C0\u67E5 registry \u914D\u7F6E\u3002":"The npm registry configuration differs from the official registry. Check your registry settings first.","\u5F53\u524D Host \u7684 Node.js \u7248\u672C\u4E0D\u6EE1\u8DB3\u65B0\u7248\u8981\u6C42\uFF0C\u8BF7\u5148\u66F4\u65B0\u8FD0\u884C\u73AF\u5883\u3002":"The Host Node.js version does not meet the new version\u2019s requirements. Update the runtime first.","\u65B0\u7248\u672C\u5DF2\u5B89\u88C5\uFF0C\u8BF7\u5728\u65B9\u4FBF\u65F6\u624B\u52A8\u91CD\u542F\u5F53\u524D Harness \u6216 Desktop\u3002":"The new version is installed. Manually restart this Harness or Desktop when convenient.","\u4E0A\u6B21\u5B89\u88C5\u7ED3\u679C\u65E0\u6CD5\u786E\u8BA4\uFF0C\u8BF7\u5148\u68C0\u67E5\u6B64 profile \u7684\u63D2\u4EF6\u5B89\u88C5\u72B6\u6001\u3002":"The previous installation result is uncertain. Check this profile\u2019s plugin installation first.","\u65E0\u6CD5\u8BBF\u95EE npm \u6216\u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u91CD\u65B0\u68C0\u67E5\u3002":"npm is unreachable or the request timed out. Check again later.","npm \u8FD4\u56DE\u7684\u7248\u672C\u4FE1\u606F\u65E0\u6548\uFF0C\u6682\u65F6\u65E0\u6CD5\u66F4\u65B0\u3002":"npm returned invalid release information. Updating is unavailable.","\u7248\u672C\u786E\u8BA4\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5\u540E\u518D\u5B89\u88C5\u3002":"The version confirmation expired. Check again before installing.","\u63D2\u4EF6\u5B89\u88C5\u72B6\u6001\u5DF2\u53D1\u751F\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5\u3002":"The plugin installation changed. Check again.","\u6B64 profile \u6B63\u5728\u66F4\u65B0\uFF0C\u8BF7\u7A0D\u540E\u67E5\u770B\u72B6\u6001\u3002":"This profile is already updating. Check its status shortly.","\u5B89\u88C5\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u5F53\u524D\u5B89\u88C5\u72B6\u6001\u540E\u91CD\u8BD5\u3002":"Installation failed. Check the current installation before retrying.","\u5B89\u88C5\u7ED3\u679C\u6821\u9A8C\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u68C0\u67E5\u63D2\u4EF6\u7248\u672C\u3002":"Installation verification failed. Check the plugin version manually.","\u65E0\u6CD5\u5B89\u5168\u4FDD\u5B58\u66F4\u65B0\u72B6\u6001\uFF0C\u8BF7\u5148\u68C0\u67E5\u5F53\u524D\u5B89\u88C5\u7ED3\u679C\u3002":"Update state could not be saved safely. Check the current installation result before retrying.","\u4E0A\u6B21\u66F4\u65B0\u5DF2\u4E2D\u65AD\uFF0C\u8BF7\u68C0\u67E5\u5B89\u88C5\u72B6\u6001\u540E\u91CD\u8BD5\u3002":"The previous update was interrupted. Check the installation before retrying.","\u66F4\u65B0\u670D\u52A1\u5DF2\u5173\u95ED\uFF0C\u8BF7\u624B\u52A8\u91CD\u65B0\u6253\u5F00\u8BBE\u7F6E\u9875\u3002":"The update service has closed. Reopen settings manually.","\u66F4\u65B0\u8BF7\u6C42\u65E0\u6548\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5\u7248\u672C\u3002":"The update request is invalid. Check the version again.","\u5F53\u524D\u63D2\u4EF6\u5B89\u88C5\u4E0D\u5B8C\u6574\u6216\u4E0E profile \u4E0D\u7B26\uFF0C\u8BF7\u624B\u52A8\u68C0\u67E5\u5B89\u88C5\u914D\u7F6E\u3002":"The plugin installation is incomplete or does not match this profile. Check the installation configuration manually.","\u65E0\u6CD5\u786E\u8BA4\u5F53\u524D npm \u6E90\u914D\u7F6E\uFF0C\u6682\u65F6\u4E0D\u80FD\u5B89\u88C5\u66F4\u65B0\u3002":"The npm registry configuration could not be verified. Installation is unavailable.","\u5B89\u88C5\u8D85\u65F6\uFF0C\u8BF7\u5148\u786E\u8BA4\u5F53\u524D\u5B89\u88C5\u72B6\u6001\uFF0C\u518D\u51B3\u5B9A\u662F\u5426\u91CD\u8BD5\u3002":"Installation timed out. Check the current installation before retrying.","\u66F4\u65B0\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002":"The update request failed. Try again.","\u66F4\u65B0\u670D\u52A1\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u54CD\u5E94\u3002":"The update service returned an unrecognized response.","\u5F53\u524D Host \u4E0D\u652F\u6301\u66F4\u65B0\u63A5\u53E3\uFF0C\u8BF7\u5148\u624B\u52A8\u66F4\u65B0\u63D2\u4EF6\u5E76\u91CD\u542F\u3002":"This Host does not support the update API. Update the plugin manually and restart first.","\u5173\u95ED\u7A97\u53E3\u4E0D\u4F1A\u53D6\u6D88\u5B89\u88C5\u3002\u8BF7\u52FF\u540C\u65F6\u5728\u5176\u4ED6\u7A97\u53E3\u7BA1\u7406\u6B64 profile \u7684\u63D2\u4EF6\u3002":"Closing this window does not cancel installation. Do not manage this profile\u2019s plugins in another window at the same time.","\u9875\u9762\u7248\u672C\u4E0E\u8FD0\u884C\u7248\u672C\u4E0D\u540C\uFF0C\u8BF7\u624B\u52A8\u5237\u65B0\u9875\u9762\uFF1B\u82E5\u4ECD\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u624B\u52A8\u91CD\u542F Harness \u6216 Desktop\u3002":"The page and running versions differ. Refresh the page manually; if they still differ, manually restart Harness or Desktop.","\u8BF7\u5728\u673A\u5668\u4EBA\u7A7A\u95F2\u65F6\u5B89\u88C5\uFF1B\u5B89\u88C5\u4F1A\u4FEE\u6539\u5F53\u524D profile \u7684\u4F9D\u8D56\uFF0C\u5B8C\u6210\u540E\u9700\u624B\u52A8\u91CD\u542F\u3002":"Install while bots are idle. This changes the current profile\u2019s dependencies and requires a manual restart afterward.","AI Office":"AI Office","\uFF08\u5B9E\u9A8C\u529F\u80FD\uFF09":"(Experimental)","AI Office \u8BBE\u7F6E":"AI Office settings","AI Office \u8BBE\u7F6E\u9875\u7F3A\u5C11 RPC \u8FDE\u63A5":"AI Office settings are missing an RPC connection","\u6B63\u5728\u8BFB\u53D6 AI Office Connector\u2026":"Loading AI Office Connector\u2026","\u672C\u673A\u4E3B\u52A8\u8FDE\u63A5\u516C\u7F51 Office\uFF1BHarness \u4E0D\u5F00\u653E\u7AEF\u53E3\u3002\u534F\u8BAE Hook \u56FA\u5B9A\u4E3A ":"This machine connects outward to the public Office; Harness exposes no port. Protocol hooks: ",\u5C1A\u672A\u914D\u7F6E:"Not configured","\u5DF2\u8FDE\u63A5 Office":"Connected to Office",\u5DF2\u914D\u7F6E:"Configured",\u7B49\u5F85\u91CD\u8FDE:"Waiting to reconnect",\u51ED\u636E\u7F3A\u5931:"Credential missing",\u6700\u8FD1\u5FC3\u8DF3:"Last heartbeat",\u6700\u8FD1\u4E8B\u4EF6:"Last event",\u91CD\u8FDE\u6B21\u6570:"Reconnects","\u8FD0\u884C Job":"Running Jobs","\u5B8C\u6210 Job":"Completed Jobs",\u5C1A\u65E0:"None yet",\u8BBE\u5907\u8FDE\u63A5:"Device connection","Token \u53EA\u5199\u5165\u672C\u673A\u51ED\u636E\u5B58\u50A8":"Token is written only to the local credential store","\u7C98\u8D34 Office \u4E00\u6B21\u6027\u51ED\u636E":"Paste the one-time Office credential","\u5DF2\u5B89\u5168\u4FDD\u5B58\uFF1B\u7559\u7A7A\u4FDD\u6301\u4E0D\u53D8":"Stored securely; leave blank to keep it",\u6700\u5927\u5E76\u53D1:"Max concurrency","Heartbeat \u79D2\u6570":"Heartbeat seconds","Workspace \u6620\u5C04":"Workspace mappings","\u6BCF\u884C alias=/\u672C\u673A/\u7EDD\u5BF9\u8DEF\u5F84\uFF1BOffice \u53EA\u80FD\u770B\u5230 alias\u3002":"One alias=/local/absolute/path per line; Office sees only aliases.","Instruction Preset \u6620\u5C04":"Instruction preset mappings","\u6BCF\u884C alias=\u6307\u4EE4\uFF1B\u65B0\u589E preset \u4E0D\u9700\u8981\u6539 Office \u4EE3\u7801\u3002":"One alias=instruction per line; new presets require no Office code change.",\u4FDD\u5B58\u5E76\u8FDE\u63A5:"Save and connect",\u6D4B\u8BD5\u8FDE\u63A5:"Test connection","\u6D4B\u8BD5\u4E2D\u2026":"Testing\u2026",\u91CD\u65B0\u8FDE\u63A5:"Reconnect",\u79FB\u9664\u8FDE\u63A5:"Remove connection","\u8FDE\u63A5\u6D4B\u8BD5\u901A\u8FC7\u3002":"Connection test passed.","\u914D\u7F6E\u5DF2\u4FDD\u5B58\u3002":"Configuration saved.","\u534F\u8BAE Hook \u9884\u89C8":"Protocol hook preview","\u7531 Base URL \u81EA\u52A8\u6D3E\u751F\uFF0C\u4E0D\u5355\u72EC\u586B\u5199":"Derived from Base URL; no separate input","Base URL \u65E0\u6548":"Invalid Base URL","Office Hook \u5C1A\u672A\u90E8\u7F72\u65F6\uFF0C\u914D\u7F6E\u4F1A\u5B89\u5168\u4FDD\u5B58\u5E76\u81EA\u52A8\u91CD\u8BD5\uFF1B\u51FA\u73B0 HTTP 404 \u4EE3\u8868\u534F\u8BAE\u7AEF\u70B9\u5F85\u4E0A\u7EBF\uFF0C\u4E0D\u4EE3\u8868 Harness \u6545\u969C\u3002":"Configuration is saved and retried while Office hooks are unavailable; HTTP 404 means the protocol endpoint is pending, not a Harness failure.","Workspace \u6620\u5C04\u6BCF\u884C\u5FC5\u987B\u4F7F\u7528 alias=value":"Each workspace mapping must use alias=value","Instruction Preset \u6620\u5C04\u6BCF\u884C\u5FC5\u987B\u4F7F\u7528 alias=value":"Each instruction preset mapping must use alias=value","action-items=\u8F6C\u6362\u4E3A\u8D1F\u8D23\u4EBA\u3001\u622A\u6B62\u548C\u9A8C\u6536\u660E\u786E\u7684\u5DE5\u5355":"action-items=Turn this into accountable tasks with deadlines and acceptance criteria","AI Office \u62D2\u7EDD\u4E86 Device Token\u3002":"AI Office rejected the Device Token.","AI Office Connector Hook \u5C1A\u672A\u5C31\u7EEA\u3002":"AI Office Connector hooks are not available yet.","AI Office Connector \u534F\u8BAE\u7248\u672C\u4E0D\u517C\u5BB9\u3002":"The AI Office Connector protocol is incompatible.","\u672C\u673A\u6682\u65F6\u65E0\u6CD5\u8BBF\u95EE AI Office\u3002":"AI Office cannot currently be reached from this machine.","AI Office \u8FDE\u63A5\u5DF2\u4E2D\u65AD\u3002":"The AI Office connection was interrupted.","\u5E2E\u52A9\u4E0E\u53CD\u9988 \xB7 \u524D\u5F80 GitHub":"Help & feedback \xB7 Open GitHub","\u8BF7\u6539\u7528 localhost \u91CD\u65B0\u6253\u5F00":"Reopen with localhost","\u9875\u9762\u4F1A\u5728\u5F53\u524D\u7AEF\u53E3\u91CD\u65B0\u6253\u5F00\uFF0C\u673A\u5668\u4EBA\u914D\u7F6E\u4E0D\u4F1A\u6539\u53D8\u3002":"The page will reopen on the current port. Your bot configuration will not change.","\u4F7F\u7528 localhost \u91CD\u65B0\u6253\u5F00":"Reopen with localhost","\u5F53\u524D\u5730\u5740\u4E0E\u6D4F\u89C8\u5668\u7684\u672C\u673A\u8BF7\u6C42\u6821\u9A8C\u4E0D\u517C\u5BB9\u3002\u8BF7\u4F7F\u7528\u4E0A\u65B9\u6309\u94AE\u6539\u7528 localhost \u91CD\u65B0\u6253\u5F00\u3002":"This address is incompatible with the browser\u2019s local-request checks. Use the button above to reopen with localhost.",\u5FAE\u4FE1:"WeChat",\u98DE\u4E66:"Feishu",\u9489\u9489:"DingTalk",\u4F01\u4E1A\u5FAE\u4FE1:"WeCom",\u5FAE\u4FE1\u673A\u5668\u4EBA:"WeChat bot",\u98DE\u4E66\u673A\u5668\u4EBA:"Feishu bot",\u9489\u9489\u673A\u5668\u4EBA:"DingTalk bot",\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA:"WeCom bot",QQ\u673A\u5668\u4EBA:"QQ bot",WhatsApp\u673A\u5668\u4EBA:"WhatsApp bot",WhatsApp\u8D26\u53F7:"WhatsApp account",\u5FAE\u4FE1\u8BBE\u7F6E:"WeChat settings",\u98DE\u4E66\u673A\u5668\u4EBA\u8BBE\u7F6E:"Feishu bot settings",\u7FA4\u804A\u54CD\u5E94\u65B9\u5F0F:"Group response mode","\u4EC5\u5728 @\u673A\u5668\u4EBA\u65F6\u54CD\u5E94\uFF08\u63A8\u8350\uFF09":"Only respond when @mentioned (recommended)",\u54CD\u5E94\u6240\u6709\u7FA4\u6D88\u606F:"Respond to all group messages","\u54CD\u5E94\u6240\u6709\u7FA4\u6D88\u606F\uFF08\u9700\u98DE\u4E66\u654F\u611F\u6743\u9650\uFF09":"Respond to all group messages (requires a sensitive Feishu scope)",\u91CD\u65B0\u6388\u6743:"Reauthorize",\u53BB\u6388\u6743:"Authorize",\u91CD\u65B0\u6388\u6743\u7FA4\u6D88\u606F\u6743\u9650:"Reauthorize group-message permission",\u6388\u6743\u7FA4\u6D88\u606F\u6743\u9650:"Authorize group-message permission","\u6B63\u5728\u51C6\u5907\u6388\u6743\u2026":"Preparing authorization\u2026","\u6B63\u5728\u51C6\u5907\u2026":"Preparing\u2026","\u79C1\u804A\u59CB\u7EC8\u54CD\u5E94\uFF1B\u7FA4\u804A\u4EC5\u5904\u7406\u660E\u786E @\u5F53\u524D\u673A\u5668\u4EBA\u7684\u6D88\u606F\u3002\u7FA4\u6D88\u606F\u6743\u9650\u5DF2\u5F00\u901A\uFF0C\u518D\u6B21\u5207\u6362\u65E0\u9700\u6388\u6743\u3002":"Direct messages always work; group chats require an explicit @mention of this bot. The group-message permission is already granted, so switching again needs no authorization.","\u79C1\u804A\u59CB\u7EC8\u54CD\u5E94\uFF1B\u7FA4\u804A\u4EC5\u5904\u7406\u660E\u786E @\u5F53\u524D\u673A\u5668\u4EBA\u7684\u6D88\u606F\u3002\u9009\u62E9\u5168\u90E8\u6D88\u606F\u540E\u4F1A\u6253\u5F00\u98DE\u4E66\u5B98\u65B9\u6388\u6743\u6D41\u7A0B\u3002":"Direct messages always work; group chats require an explicit @mention of this bot. Selecting all messages opens the official Feishu authorization flow.","\u5DF2\u5F00\u901A\u201C\u83B7\u53D6\u7FA4\u7EC4\u4E2D\u6240\u6709\u6D88\u606F\u201D\u6743\u9650\uFF08im:message.group_msg\uFF09\uFF1B\u673A\u5668\u4EBA\u4F1A\u5904\u7406\u7FA4\u804A\u4E2D\u7684\u6240\u6709\u53EF\u89C1\u6D88\u606F\u3002":"The \u201CRead all messages in associated group chat\u201D scope (im:message.group_msg) is granted; the bot processes every visible group message.","\u5C1A\u672A\u786E\u8BA4\u201C\u83B7\u53D6\u7FA4\u7EC4\u4E2D\u6240\u6709\u6D88\u606F\u201D\u6743\u9650\uFF0C\u8BF7\u5B8C\u6210\u98DE\u4E66\u6388\u6743\u3002":"The \u201CRead all messages in associated group chat\u201D scope has not been confirmed. Complete Feishu authorization.","\u79C1\u804A\u59CB\u7EC8\u54CD\u5E94\uFF1B\u7FA4\u804A\u4EC5\u5904\u7406\u660E\u786E @\u5F53\u524D\u673A\u5668\u4EBA\u7684\u6D88\u606F\u3002":"Direct messages always work; group chats require an explicit @mention of this bot.","\u9700\u5728\u98DE\u4E66\u4E3A\u8BE5\u673A\u5668\u4EBA\u5F00\u901A\u201C\u83B7\u53D6\u7FA4\u7EC4\u4E2D\u6240\u6709\u6D88\u606F\u201D\u6743\u9650\uFF08im:message.group_msg\uFF09\uFF1B\u5F00\u901A\u540E\uFF0C\u673A\u5668\u4EBA\u4F1A\u5904\u7406\u7FA4\u804A\u4E2D\u7684\u6240\u6709\u53EF\u89C1\u6D88\u606F\u3002":"Grant this bot the \u201CRead all messages in associated group chat\u201D Feishu scope (im:message.group_msg); once granted, it will process every visible group message.","\u7FA4\u804A\u54CD\u5E94\u65B9\u5F0F\u4FEE\u6539\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002":"Could not update the group response mode. Try again.","\u7FA4\u6D88\u606F\u6743\u9650\u6388\u6743\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002":"Could not authorize group-message permission. Try again.",\u9489\u9489\u8BBE\u7F6E:"DingTalk settings",\u4F01\u4E1A\u5FAE\u4FE1\u8BBE\u7F6E:"WeCom settings",\u626B\u7801\u63A5\u5165\u673A\u5668\u4EBA:"Scan QR code",\u6B63\u5728\u63A5\u5165:"Connecting",\u624B\u52A8\u63A5\u5165:"Manual setup",\u6536\u8D77\u51ED\u636E:"Hide credentials",\u6536\u8D77\u63A5\u5165:"Hide setup",\u63A5\u5165\u673A\u5668\u4EBA:"Connect bot",\u5F00\u59CB\u63A5\u5165:"Start setup",\u5728\u7EBF:"online",\u8FD0\u884C\u6B63\u5E38:"Connected",\u6B63\u5728\u8FDE\u63A5:"Connecting","\u6B63\u5728\u8FDE\u63A5\u2026":"Connecting\u2026",\u8FDE\u63A5\u672A\u5C31\u7EEA:"Not connected",\u8FDE\u63A5\u4E2D:"Connecting",\u8FDE\u63A5\u4E2D\u65AD:"Disconnected",\u9700\u8981\u5904\u7406:"Needs attention",\u72B6\u6001\u672A\u77E5:"Unknown status",\u79BB\u7EBF:"Offline",\u5DF2\u65AD\u5F00:"Disconnected",\u6D88\u606F\u901A\u9053:"Message channel",\u67E5\u770B\u6D88\u606F\u901A\u9053\u8BF4\u660E:"View message channel details",\u6700\u8FD1\u68C0\u67E5:"Last checked",\u6700\u8FD1\u4E00\u6761\u6D88\u606F\u5904\u7406\u5931\u8D25:"Latest message failed",\u9519\u8BEF\u7801:"Code",\u53C2\u8003\u53F7:"Reference",\u5F53\u524D\u5DE5\u4F5C\u533A:"Current workspace",\u9009\u62E9\u76EE\u5F55:"Choose folder",\u9009\u62E9\u673A\u5668\u4EBA\u5DE5\u4F5C\u533A\u76EE\u5F55:"Select bot workspace folder",\u5F53\u524D\u76EE\u5F55:"Current folder",\u4E3B\u76EE\u5F55:"Home",\u76F4\u63A5\u8F93\u5165\u8DEF\u5F84:"Enter a path directly","\u652F\u6301 Windows \u76D8\u7B26\u3001UNC \u4E0E POSIX \u7EDD\u5BF9\u8DEF\u5F84\u3002":"Supports Windows drives, UNC paths, and POSIX absolute paths.","\u8F93\u5165 Host \u4E0A\u7684\u5B8C\u6574\u7EDD\u5BF9\u8DEF\u5F84":"Enter a full absolute path on the Host",\u524D\u5F80:"Go","\u8BFB\u53D6\u4E2D\u2026":"Loading\u2026","\u6B63\u5728\u51C6\u5907\u76EE\u5F55\u9009\u62E9\u5668\u2026":"Preparing folder picker\u2026","\u6B63\u5728\u8BFB\u53D6\u76EE\u5F55\u2026":"Loading folders\u2026","\u8FD9\u4E2A\u76EE\u5F55\u4E2D\u6CA1\u6709\u5B50\u6587\u4EF6\u5939\u3002":"This folder has no subfolders.","\u6B64\u76EE\u5F55\u7684\u5B50\u6587\u4EF6\u5939\u8FC7\u591A\uFF0C\u4EC5\u663E\u793A\u524D\u4E00\u90E8\u5206\u3002":"This folder has too many subfolders; only the first group is shown.","\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF0C\u8BF7\u91CD\u8BD5\u3002":"Could not load the folder. Try again.",\u91CD\u8BD5:"Retry",\u663E\u793A\u9690\u85CF\u6587\u4EF6\u5939:"Show hidden folders","\u5207\u6362\u540E\u4F1A\u6E05\u9664\u8FD9\u4E2A\u673A\u5668\u4EBA\u7684\u65E7\u4F1A\u8BDD\u6620\u5C04\u3002":"Switching clears this bot\u2019s previous session mappings.","\u5207\u6362\u4E2D\u2026":"Switching\u2026",\u9009\u62E9\u6B64\u76EE\u5F55:"Select this folder",\u5DE5\u4F5C\u533A\u7EDD\u5BF9\u8DEF\u5F84:"Absolute workspace path","/\u7EDD\u5BF9\u8DEF\u5F84/\u5230/\u5DE5\u4F5C\u533A":"/absolute/path/to/workspace",\u4FEE\u6539:"Change",\u4FDD\u5B58:"Save",\u4E0A\u4E0B\u6587\u589E\u5F3A:"Context enhancement",\u672A\u5F00\u542F:"Not enabled",\u4EC5\u7FA4\u804A:"Groups only",\u4EC5\u79C1\u804A:"Direct only",\u7FA4\u804A\u548C\u79C1\u804A:"Groups and direct",\u5173\u95ED\u5F39\u7A97:"Close dialog",\u67E5\u770B\u4E0A\u4E0B\u6587\u589E\u5F3A\u8BF4\u660E:"View context enhancement details",\u4E0A\u4E0B\u6587\u589E\u5F3A\u8303\u56F4:"Context enhancement scope",\u542F\u7528\u8303\u56F4:"Enable in",\u542F\u7528:"Enabled","\uFF08\u5F53\u524D\u6E20\u9053\u4E0D\u652F\u6301\u7FA4\u804A\uFF09":"(This channel does not support group chats)",\u6765\u6E90\u5B57\u6BB5:"Source fields",\u67E5\u770B\u6765\u6E90\u5B57\u6BB5\u8BF4\u660E:"View source field details",\u67E5\u770B\u7FA4\u804A\u6765\u6E90\u5B57\u6BB5\u8BF4\u660E:"View group source field details",\u67E5\u770B\u79C1\u804A\u6765\u6E90\u5B57\u6BB5\u8BF4\u660E:"View direct source field details",\u6E20\u9053:"Channel",\u4F1A\u8BDD\u7C7B\u578B:"Conversation type",\u53D1\u9001\u8005\u6807\u8BC6:"Sender ID",\u53D1\u9001\u8005\u6635\u79F0:"Sender name",\u67E5\u770B\u53D1\u9001\u8005\u6635\u79F0\u5B57\u6BB5\u8BF4\u660E:"View sender name field details",\u67E5\u770B\u7FA4\u804A\u53D1\u9001\u8005\u6635\u79F0\u5B57\u6BB5\u8BF4\u660E:"View group sender name field details",\u67E5\u770B\u79C1\u804A\u53D1\u9001\u8005\u6635\u79F0\u5B57\u6BB5\u8BF4\u660E:"View direct sender name field details","\u8BE5\u5B57\u6BB5\u4E0D\u662F\u6BCF\u4E2A\u6E20\u9053\u90FD\u80FD\u63D0\u4F9B\u3002\u5F53\u524D\u6D88\u606F\u6CA1\u6709\u53D1\u9001\u8005\u6635\u79F0\u65F6\uFF0C\u5373\u4F7F\u5DF2\u9009\u62E9\u8BE5\u5B57\u6BB5\uFF0C \u4E2D\u4E5F\u4F1A\u7701\u7565 senderName\u3002":"This field is not available on every channel. If the current message has no sender name, omits senderName even when the field is selected.",\u4F1A\u8BDD\u6807\u9898:"Conversation title",\u67E5\u770B\u7FA4\u804A\u4F1A\u8BDD\u6807\u9898\u5B57\u6BB5\u8BF4\u660E:"View group conversation title field details",\u67E5\u770B\u79C1\u804A\u4F1A\u8BDD\u6807\u9898\u5B57\u6BB5\u8BF4\u660E:"View direct conversation title field details","\u8BE5\u5B57\u6BB5\u4E0D\u662F\u6BCF\u4E2A\u6E20\u9053\u90FD\u80FD\u63D0\u4F9B\u3002\u9489\u9489\u7FA4\u804A\u4F1A\u5E26\u4E0A\u7FA4\u540D\u3002\u5F53\u524D\u6D88\u606F\u6CA1\u6709\u4F1A\u8BDD\u6807\u9898\u65F6\uFF0C\u5373\u4F7F\u5DF2\u9009\u62E9\u8BE5\u5B57\u6BB5\uFF0C \u4E2D\u4E5F\u4F1A\u7701\u7565 conversationTitle\u3002":"This field is not available on every channel. DingTalk group chats include the group name. If the current message has no conversation title, omits conversationTitle even when the field is selected.",\u4F1A\u8BDD\u6807\u8BC6:"Chat ID",\u67E5\u770B\u7FA4\u804A\u4F1A\u8BDD\u6807\u8BC6\u5B57\u6BB5\u8BF4\u660E:"View group chat ID field details",\u67E5\u770B\u79C1\u804A\u4F1A\u8BDD\u6807\u8BC6\u5B57\u6BB5\u8BF4\u660E:"View direct chat ID field details","\u8BE5\u5B57\u6BB5\u4E0D\u662F\u6BCF\u4E2A\u6E20\u9053\u90FD\u80FD\u63D0\u4F9B\u3002\u4F1A\u8BDD\u6807\u8BC6\u7528\u4E8E\u533A\u5206\u4E0D\u540C\u7684\u7FA4\u7EC4\u6216\u79C1\u804A\uFF0C\u98DE\u4E66\u7FA4\u804A\u4F1A\u5E26\u4E0A\u7FA4 ID\u3002\u5F53\u524D\u6D88\u606F\u6CA1\u6709\u4F1A\u8BDD\u6807\u8BC6\u65F6\uFF0C\u5373\u4F7F\u5DF2\u9009\u62E9\u8BE5\u5B57\u6BB5\uFF0C \u4E2D\u4E5F\u4F1A\u7701\u7565 chatId\u3002":"This field is not available on every channel. The chat ID distinguishes different groups or direct chats, and Feishu group chats include the group ID. If the current message has no chat ID, omits chatId even when the field is selected.",\u8BDD\u9898\u6807\u8BC6:"Topic ID",\u67E5\u770B\u7FA4\u804A\u8BDD\u9898\u6807\u8BC6\u5B57\u6BB5\u8BF4\u660E:"View group topic ID field details",\u67E5\u770B\u79C1\u804A\u8BDD\u9898\u6807\u8BC6\u5B57\u6BB5\u8BF4\u660E:"View direct topic ID field details","\u8BE5\u5B57\u6BB5\u4E0D\u662F\u6BCF\u4E2A\u6E20\u9053\u90FD\u80FD\u63D0\u4F9B\u3002\u98DE\u4E66\u8BDD\u9898\u7FA4\u7684\u6D88\u606F\u4F1A\u5E26\u4E0A\u8BDD\u9898 ID\uFF0C\u7528\u4E8E\u533A\u5206\u540C\u4E00\u7FA4\u7EC4\u5185\u7684\u4E0D\u540C\u8BDD\u9898\uFF1B\u5F53\u524D\u6D88\u606F\u4E0D\u5728\u8BDD\u9898\u4E2D\u65F6\uFF0C\u5373\u4F7F\u5DF2\u9009\u62E9\u8BE5\u5B57\u6BB5\uFF0C \u4E2D\u4E5F\u4F1A\u7701\u7565 threadId\u3002":"This field is not available on every channel. Messages in a Feishu topic chat carry the topic ID, which distinguishes different topics inside the same group. If the current message is not inside a topic, omits threadId even when the field is selected.",\u673A\u5668\u4EBA\u6807\u8BC6:"Bot ID",\u589E\u5F3A\u63D0\u793A\u8BCD:"Guidance",\u67E5\u770B\u589E\u5F3A\u63D0\u793A\u8BCD\u4F7F\u7528\u8BF4\u660E:"View guidance instructions",\u67E5\u770B\u7FA4\u804A\u589E\u5F3A\u63D0\u793A\u8BCD\u4F7F\u7528\u8BF4\u660E:"View group guidance instructions",\u67E5\u770B\u79C1\u804A\u589E\u5F3A\u63D0\u793A\u8BCD\u4F7F\u7528\u8BF4\u660E:"View direct guidance instructions",\u4F7F\u7528\u8BF4\u660E:"How to use","\u7528\u4E8E\u544A\u8BC9\u6A21\u578B\u5982\u4F55\u4F7F\u7528 \u4E2D\u5DF2\u9009\u62E9\u7684\u6765\u6E90\u5B57\u6BB5\u3002\u53EA\u586B\u5199\u6B63\u6587\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u6DFB\u52A0 \u6210\u5BF9\u6807\u7B7E\u3002":"Tell the model how to use the selected fields in . Enter only the body; the plugin adds paired tags.",\u751F\u6548\u89C4\u5219:"Behavior",\u9690\u79C1\u63D0\u793A:"Privacy",\u4F7F\u7528\u793A\u4F8B:"Example","\u4EC5\u4F9D\u636E\u5F53\u524D\u6D88\u606F\u7684 \u4E2D\u5B9E\u9645\u63D0\u4F9B\u7684\u5B57\u6BB5\u7406\u89E3\u6765\u6E90\uFF1B\u6CA1\u6709\u63D0\u4F9B\u7684\u5B57\u6BB5\u4E0D\u8981\u731C\u6D4B\u6216\u8865\u5168\u3002\nconversationType\u662F\u7FA4\u804A\u65F6\u56DE\u590D\u4E25\u8083\u4E00\u70B9\uFF0CconversationType\u662F\u79C1\u804A\u65F6\u56DE\u590D\u4E00\u5B9A\u8981\u5E7D\u9ED8\u641E\u7B11\uFF0C\u50CF\u5468\u661F\u9A70\u7684\u7535\u5F71\u4E00\u6837\u641E\u7B11":`Understand the source only from fields actually present in for the current message; do not guess or fill in missing fields. When conversationType is group, reply more seriously. When conversationType is direct, make the reply humorous and funny.`,"\u4EC5\u4F9D\u636E\u5F53\u524D\u6D88\u606F\u7684 \u4E2D\u5B9E\u9645\u63D0\u4F9B\u7684\u5B57\u6BB5\u7406\u89E3\u6765\u6E90\uFF1B\u6CA1\u6709\u63D0\u4F9B\u7684\u5B57\u6BB5\u4E0D\u8981\u731C\u6D4B\u6216\u8865\u5168\u3002\n\u5F53\u524D\u6D88\u606F\u6765\u81EA\u7FA4\u804A\uFF0C\u8BF7\u4F7F\u7528\u4E25\u8083\u3001\u514B\u5236\u3001\u7B80\u6D01\u7684\u8868\u8FBE\u65B9\u5F0F\u3002":`Understand the source only from fields actually present in for the current message; do not guess or fill in missing fields. This message is from a group chat. Use a serious, restrained, and concise style.`,"\u4EC5\u4F9D\u636E\u5F53\u524D\u6D88\u606F\u7684 \u4E2D\u5B9E\u9645\u63D0\u4F9B\u7684\u5B57\u6BB5\u7406\u89E3\u6765\u6E90\uFF1B\u6CA1\u6709\u63D0\u4F9B\u7684\u5B57\u6BB5\u4E0D\u8981\u731C\u6D4B\u6216\u8865\u5168\u3002\n\u5F53\u524D\u6D88\u606F\u6765\u81EA\u79C1\u804A\uFF0C\u53EF\u4EE5\u4F7F\u7528\u66F4\u8F7B\u677E\u3001\u5E7D\u9ED8\u3001\u8BE6\u7EC6\u7684\u8868\u8FBE\u65B9\u5F0F\u3002":`Understand the source only from fields actually present in for the current message; do not guess or fill in missing fields. This message is from a direct chat. You may use a lighter, more humorous, and detailed style.`,\u586B\u5165\u793A\u4F8B:"Use example",\u6E05\u7A7A:"Clear","\u9009\u62E9\u5728\u54EA\u4E9B\u4F1A\u8BDD\u4E2D\u542F\u7528\u3001\u63D0\u4F9B\u54EA\u4E9B\u6765\u6E90\u5B57\u6BB5\uFF0C\u4EE5\u53CA\u5982\u4F55\u4F7F\u7528\u8FD9\u4E9B\u4FE1\u606F\u3002\u4EC5\u4F7F\u7528\u5DF2\u6709\u6D88\u606F\u5143\u6570\u636E\uFF0C\u4E0D\u67E5\u8BE2\u5E73\u53F0 API\u3002":"Choose which conversations to enhance, which source fields to include, and how to use them. Only existing message metadata is used; no platform APIs are queried.","\u589E\u5F3A\u63D0\u793A\u8BCD\u4E2D\u8BF7\u4F7F\u7528\u5B57\u6BB5\u540D\uFF08\u5982 senderId\u3001conversationType\uFF09\u5F15\u7528\u8FD9\u4E9B\u4FE1\u606F\u3002\u53EA\u53D1\u9001\u52FE\u9009\u4E14\u5F53\u524D\u6D88\u606F\u4E2D\u53EF\u7528\u7684\u5B57\u6BB5\uFF0C\u4E0D\u4F1A\u989D\u5916\u67E5\u8BE2\u6216\u8865\u5168\u3002":"Reference these values by field name (such as senderId or conversationType) in the guidance. Only selected fields available in the current message are sent; no extra lookups are made.","\u589E\u5F3A\u63D0\u793A\u8BCD\u4E2D\u8BF7\u4F7F\u7528\u5B57\u6BB5\u540D\uFF08\u5982 senderId\u3001conversationType\uFF09\u5F15\u7528\u8FD9\u4E9B\u4FE1\u606F\u3002\u53EA\u53D1\u9001\u5F53\u524D\u4F1A\u8BDD\u4E2D\u52FE\u9009\u4E14\u53EF\u7528\u7684\u5B57\u6BB5\uFF0C\u4E0D\u4F1A\u989D\u5916\u67E5\u8BE2\u6216\u8865\u5168\u3002":"Reference these values by field name (such as senderId or conversationType) in the guidance. Only fields selected and available in the current conversation are sent; no extra lookups are made.","\u7528\u4E8E\u544A\u8BC9\u6A21\u578B\u5982\u4F55\u4F7F\u7528\u5F53\u524D\u7FA4\u804A\u6D88\u606F\u7684 \u6765\u6E90\u5B57\u6BB5\u3002\u53EA\u586B\u5199\u6B63\u6587\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u6DFB\u52A0 \u6210\u5BF9\u6807\u7B7E\u3002":"Tell the model how to use fields for the current group message. Enter only the body; the plugin adds paired tags.","\u7528\u4E8E\u544A\u8BC9\u6A21\u578B\u5982\u4F55\u4F7F\u7528\u5F53\u524D\u79C1\u804A\u6D88\u606F\u7684 \u6765\u6E90\u5B57\u6BB5\u3002\u53EA\u586B\u5199\u6B63\u6587\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u6DFB\u52A0 \u6210\u5BF9\u6807\u7B7E\u3002":"Tell the model how to use fields for the current direct message. Enter only the body; the plugin adds paired tags.","\u4EC5\u5728\u7FA4\u804A\u5F00\u5173\u5F00\u542F\u65F6\u4F7F\u7528\u3002\u6E05\u7A7A\u5E76\u4FDD\u5B58\u540E\u4E0D\u518D\u9644\u52A0\u7FA4\u804A\u589E\u5F3A\u63D0\u793A\u8BCD\uFF1B\u6240\u9009\u6765\u6E90\u5B57\u6BB5\u4ECD\u6309\u5F53\u524D\u573A\u666F\u8BBE\u7F6E\u53D1\u9001\u3002":"Used only when group enhancement is enabled. Clear and save to omit group guidance; selected source fields still follow the group settings.","\u4EC5\u5728\u79C1\u804A\u5F00\u5173\u5F00\u542F\u65F6\u4F7F\u7528\u3002\u6E05\u7A7A\u5E76\u4FDD\u5B58\u540E\u4E0D\u518D\u9644\u52A0\u79C1\u804A\u589E\u5F3A\u63D0\u793A\u8BCD\uFF1B\u6240\u9009\u6765\u6E90\u5B57\u6BB5\u4ECD\u6309\u5F53\u524D\u573A\u666F\u8BBE\u7F6E\u53D1\u9001\u3002":"Used only when direct enhancement is enabled. Clear and save to omit direct guidance; selected source fields still follow the direct settings.","\u53EA\u9700\u586B\u5199\u6B63\u6587\uFF0C\u63D2\u4EF6\u81EA\u52A8\u6DFB\u52A0 \u6210\u5BF9\u6807\u7B7E\u3002\u6E05\u7A7A\u5E76\u4FDD\u5B58\u540E\uFF0C\u4E0D\u518D\u9644\u52A0\u589E\u5F3A\u63D0\u793A\u8BCD\uFF0C\u5DF2\u9009\u6765\u6E90\u5B57\u6BB5\u4ECD\u6309\u5F00\u5173\u8BBE\u7F6E\u53D1\u9001\u3002":"Enter only the body; the plugin adds paired tags. Clear and save to omit guidance. Selected source fields still follow the conversation switches.","\u53D1\u9001\u8005\u6807\u8BC6\u53EF\u80FD\u5305\u542B\u5E73\u53F0\u7528\u6237 ID \u6216\u7535\u8BDD\u53F7\u7801\u5F62\u5F0F\u7684\u6807\u8BC6\u3002\u5173\u95ED\u5F00\u5173\u4E0D\u4F1A\u5220\u9664\u5DF2\u7ECF\u5199\u5165\u4F1A\u8BDD\u5386\u53F2\u7684\u4FE1\u606F\u3002":"Sender IDs may contain platform user IDs or phone-number-like identifiers. Turning this off does not remove information already saved in conversation history.","\u4E0A\u4E0B\u6587\u589E\u5F3A\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002":"Could not save context enhancement. Try again.","\u8BF7\u63D0\u4EA4\u5B8C\u6574\u7684\u4E0A\u4E0B\u6587\u589E\u5F3A\u8BBE\u7F6E\u3002":"Submit the complete context enhancement settings.","\u7FA4\u804A\u548C\u79C1\u804A\u5F00\u5173\u5FC5\u987B\u662F\u5E03\u5C14\u503C\u3002":"Group and direct switches must be booleans.","\u6765\u6E90\u5B57\u6BB5\u53EA\u80FD\u9009\u62E9\u5DF2\u5B9A\u4E49\u7684\u516B\u4E2A\u5B57\u6BB5\u3002":"Source fields must be chosen from the eight defined fields.","\u4FDD\u5B58\u4E2D\u2026":"Saving\u2026",\u672A\u8BBE\u7F6E:"Not set","\u5DE5\u4F5C\u533A\u4FEE\u6539\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002":"Could not update the workspace. Try again.","\u8BF7\u8F93\u5165\u5DE5\u4F5C\u533A\u7EDD\u5BF9\u8DEF\u5F84\u3002":"Enter an absolute workspace path.","\u5DE5\u4F5C\u533A\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84\u3002":"The workspace must be an absolute path.","\u5DE5\u4F5C\u533A\u8DEF\u5F84\u4E0D\u5B58\u5728\u3002":"The workspace path does not exist.","\u5DE5\u4F5C\u533A\u8DEF\u5F84\u5FC5\u987B\u6307\u5411\u4E00\u4E2A\u76EE\u5F55\u3002":"The workspace path must point to a directory.","\u627E\u4E0D\u5230\u8981\u4FEE\u6539\u7684\u673A\u5668\u4EBA\u3002":"The bot could not be found.","Agent Preset":"Agent Preset","\u67E5\u770B Agent Preset \u8BF4\u660E":"View Agent Preset help","\u8DDF\u968F Host \u9ED8\u8BA4":"Follow the Host default","\uFF08\u5DF2\u4E0D\u53EF\u7528\uFF09":" (unavailable)","\u53EA\u5F71\u54CD\u65B0\u5EFA\u4F1A\u8BDD\uFF1B\u82E5\u5F53\u524D\u804A\u5929\u5DF2\u6709\u4F1A\u8BDD\uFF0C\u5148\u53D1\u9001 /new\uFF0C\u518D\u53D1\u9001\u666E\u901A\u6D88\u606F\u751F\u6548\u3002":"This affects only new sessions. If the current chat already has a session, send /new, then send a regular message to apply it.","\u5F53\u524D Agent Preset \u5DF2\u4E0D\u53EF\u7528\uFF0C\u8BF7\u9009\u62E9\u5176\u4ED6 Preset \u6216\u8DDF\u968F Host \u9ED8\u8BA4\u3002":"The current Agent Preset is unavailable. Choose another preset or follow the Host default.","Agent Preset \u4FEE\u6539\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002":"Could not update the Agent Preset. Try again.","\u8BF7\u9009\u62E9 Agent Preset\u3002":"Choose an Agent Preset.","Agent Preset \u65E0\u6548\u3002":"The Agent Preset is invalid.","Agent Preset \u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u7528\u3002":"The Agent Preset does not exist or is unavailable.",\u5C1A\u672A\u68C0\u67E5:"Not checked yet",\u521A\u521A:"Just now",\u68C0\u67E5\u8FDE\u63A5:"Check connection","\u68C0\u67E5\u4E2D\u2026":"Checking\u2026","\u8FDE\u63A5\u68C0\u67E5\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002":"Connection check failed. Try again later.","\u673A\u5668\u4EBA\u5DF2\u4FDD\u5B58\uFF0C\u4F46\u8FDE\u63A5\u672A\u5C31\u7EEA":"The bot was saved, but the connection is not ready",\u67E5\u770B\u5DF2\u4FDD\u5B58\u7684\u673A\u5668\u4EBA:"View saved bot","\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230\u5BF9\u5E94\u673A\u5668\u4EBA\u4F1A\u8BDD\u4E2D\u786E\u8BA4\u3002":"Test message sent. Check the matching bot conversation.","\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\u3002\u673A\u5668\u4EBA\u5C1A\u672A\u6536\u5230\u53EF\u7528\u4E8E\u6D4B\u8BD5\u7684\u79C1\u804A\u6D88\u606F\u3002":"Connection check completed. The bot has not received a direct message it can use for testing.","\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002":"Connection check completed, but the test message could not be sent.","\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230\u98DE\u4E66\u4F1A\u8BDD\u4E2D\u786E\u8BA4\u3002":"Test message sent. Check the Feishu conversation.","\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\uFF0C\u8BF7\u5230 WhatsApp \u81EA\u804A\u4F1A\u8BDD\u4E2D\u786E\u8BA4\u3002":"Test message sent. Check the WhatsApp self-chat.","\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u5F53\u524D\u6CA1\u6709\u53EF\u7528\u7684 WhatsApp \u81EA\u804A\u76EE\u6807\u3002":"Connection check completed, but no WhatsApp self-chat target is available.","\u9489\u9489\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\u3002":"DingTalk connection check completed and the test message was sent.","\u9489\u9489\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002":"DingTalk connection check completed, but the test message could not be sent.","\u5FAE\u4FE1\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\u3002":"WeChat connection check completed and the test message was sent.","\u5FAE\u4FE1\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002":"WeChat connection check completed, but the test message could not be sent.","\u4F01\u4E1A\u5FAE\u4FE1\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u6D4B\u8BD5\u6D88\u606F\u5DF2\u53D1\u9001\u3002":"WeCom connection check completed and the test message was sent.","\u4F01\u4E1A\u5FAE\u4FE1\u8FDE\u63A5\u68C0\u67E5\u5B8C\u6210\uFF0C\u4F46\u6D4B\u8BD5\u6D88\u606F\u53D1\u9001\u5931\u8D25\u3002":"WeCom connection check completed, but the test message could not be sent.",\u91CD\u8BD5\u8FDE\u63A5:"Reconnect","\u91CD\u8BD5\u4E2D\u2026":"Retrying\u2026",\u79FB\u9664\u63A5\u5165:"Remove connection",\u786E\u8BA4\u79FB\u9664\u63A5\u5165:"Remove connection",\u786E\u8BA4\u79FB\u9664:"Remove","\u6B63\u5728\u79FB\u9664\u2026":"Removing\u2026",\u4FDD\u7559\u673A\u5668\u4EBA:"Keep bot",\u4FDD\u7559\u8D26\u53F7:"Keep account",\u53D6\u6D88:"Cancel",\u5173\u95ED:"Close",\u7ACB\u5373\u91CD\u8BD5:"Retry now",\u91CD\u65B0\u8BFB\u53D6:"Reload",\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801:"Generate a new QR code",\u91CD\u65B0\u751F\u6210\u4E8C\u7EF4\u7801\u540E\u7EE7\u7EED:"Generate a new QR code",\u5237\u65B0\u4E8C\u7EF4\u7801:"Refresh QR code","\u5237\u65B0\u4E2D\u2026":"Refreshing\u2026",\u6362\u4E00\u4E2A\u4E8C\u7EF4\u7801:"Get another QR code",\u7EE7\u7EED\u8FDE\u63A5:"Continue connecting",\u7ED1\u5B9A\u5E76\u8FDE\u63A5:"Connect","\u6B63\u5728\u7ED1\u5B9A\u2026":"Connecting\u2026",\u9A8C\u8BC1\u5E76\u8FDE\u63A5:"Verify and connect","\u6B63\u5728\u9A8C\u8BC1\u5E76\u8FDE\u63A5\u2026":"Verifying and connecting\u2026","\u6B63\u5728\u9A8C\u8BC1\u2026":"Verifying\u2026","\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5":"The operation failed. Try again later.",\u8BF7\u7A0D\u540E\u91CD\u8BD5:"Try again later.",\u5F53\u524D\u4E8C\u7EF4\u7801\u6709\u6548\u65F6\u95F4:"QR code expires in",\u4E8C\u7EF4\u7801\u6709\u6548\u65F6\u95F4:"QR code expires in",\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F:"QR code expired",\u4E8C\u7EF4\u7801\u5DF2\u5931\u6548:"QR code expired","\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F\n\u8BF7\u91CD\u65B0\u751F\u6210":`QR code expired diff --git a/package.json b/package.json index c908f19..9ef7e48 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dsh-im-ops", - "version": "4.9.1-ops.10", + "version": "4.9.1-ops.11", "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/access-grant-settings.js b/plugin-src/client/access-grant-settings.js index 496c8ae..71dd5fa 100644 --- a/plugin-src/client/access-grant-settings.js +++ b/plugin-src/client/access-grant-settings.js @@ -92,6 +92,30 @@ function groupDisplayName(groupJid, groups) { return '未命名群'; } +/** + * Keep contacts that still need a grant action (DM and/or a known group). + * Fully authorized people are hidden from the quick-grant list. + * @param {{ phone?: string, groupJids?: string[] }} contact + * @param {object} draft + * @param {string[]} knownGroupJids + */ +function contactNeedsGrantAction(contact, draft, knownGroupJids) { + const phone = contact?.phone || ''; + if (!phone) return true; + if ((draft.globalAdmins ?? []).includes(phone)) return false; + + const alreadyDirect = (draft.directMembers ?? []).some((m) => m.phone === phone); + const pendingGroups = (contact.groupJids ?? []) + .filter((jid) => knownGroupJids.includes(jid)) + .filter((groupJid) => { + const group = draft.groups?.[groupJid] ?? { admins: [], members: [] }; + return !(group.admins ?? []).includes(phone) + && !(group.members ?? []).some((m) => m.phone === phone); + }); + + return !alreadyDirect || pendingGroups.length > 0; +} + function digitsOnly(value) { return String(value ?? '').replace(/[^\d]/g, ''); } @@ -355,6 +379,10 @@ export function AccessGrantSettingsPage({ channel, account, rpcCall, onSaved }) } return [...set].sort(); }, [draft.groups, draft.pending, contacts]); + const actionableContacts = React.useMemo( + () => contacts.filter((contact) => contactNeedsGrantAction(contact, draft, knownGroupJids)), + [contacts, draft, knownGroupJids], + ); const resolvePending = async (pendingId, action) => { setFeedback(null); @@ -617,13 +645,25 @@ export function AccessGrantSettingsPage({ channel, account, rpcCall, onSaved }) h('fieldset', { className: 'dim-accessScene', disabled: saving }, h('legend', null, '最近联系人(自动沉淀)'), h('p', { className: 'dim-accessUsersEmpty' }, - '仅记录私聊机器人,或在群里 @ 机器人的人。电话是唯一授权键,可一键加入私聊/本群授权。'), - contacts.length === 0 - ? h('div', { className: 'dim-accessUsersEmpty' }, '暂无联系人。有人私聊或 @ 机器人后会出现在此。') - : h('ul', { className: 'dim-accessUserList' }, contacts.slice(0, 30).map((contact) => { + '仅记录私聊机器人,或在群里 @ 机器人的人。已有对应权限的人会自动隐藏;电话是唯一授权键,可一键加入私聊/本群授权。'), + actionableContacts.length === 0 + ? h('div', { className: 'dim-accessUsersEmpty' }, + contacts.length === 0 + ? '暂无联系人。有人私聊或 @ 机器人后会出现在此。' + : '当前联系人均已具备对应权限,无需再授权。') + : h('ul', { className: 'dim-accessUserList' }, actionableContacts.slice(0, 30).map((contact) => { const phone = contact.phone || ''; - const alreadyDirect = phone && draft.directMembers.some((m) => m.phone === phone); - const groupTargets = (contact.groupJids ?? []).filter((jid) => knownGroupJids.includes(jid)); + const alreadyDirect = Boolean(phone) + && ((draft.directMembers ?? []).some((m) => m.phone === phone) + || (draft.globalAdmins ?? []).includes(phone)); + const groupTargets = (contact.groupJids ?? []) + .filter((jid) => knownGroupJids.includes(jid)) + .filter((groupJid) => { + if (!phone) return true; + const group = draft.groups[groupJid] ?? { admins: [], members: [] }; + return !(group.admins ?? []).includes(phone) + && !(group.members ?? []).some((m) => m.phone === phone); + }); return h('li', { key: `${contact.phone ?? ''}-${(contact.lids ?? []).join(',')}`, className: 'dim-accessUserRow', @@ -632,11 +672,11 @@ export function AccessGrantSettingsPage({ channel, account, rpcCall, onSaved }) h('strong', null, contactLabel(contact)), h('span', null, (contact.scenes ?? []).join(' / ')), phone ? null : h('span', null, '待补电话')), - phone ? h('button', { + phone && !alreadyDirect ? h('button', { type: 'button', className: 'dim-deliveryButton', 'data-kind': 'primary', - disabled: saving || alreadyDirect, + disabled: saving, onClick: () => { setDraft((current) => { if (current.directMembers.some((m) => m.phone === phone)) return current; @@ -650,17 +690,15 @@ export function AccessGrantSettingsPage({ channel, account, rpcCall, onSaved }) }); setFeedback({ tone: 'success', message: '已加入私聊授权,记得点保存。' }); }, - }, alreadyDirect ? '已在私聊' : '加私聊') : null, + }, '加私聊') : null, ...groupTargets.map((groupJid) => { const group = draft.groups[groupJid] ?? { admins: [], members: [] }; const name = groupDisplayName(groupJid, draft.groups); - const already = group.admins.includes(phone) - || group.members.some((m) => m.phone === phone); return h('button', { key: `add-${groupJid}`, type: 'button', className: 'dim-deliveryButton', - disabled: saving || !phone || already, + disabled: saving || !phone, onClick: () => { setDraft((current) => { const existing = current.groups[groupJid] ?? { title: '', admins: [], members: [] }; @@ -687,7 +725,7 @@ export function AccessGrantSettingsPage({ channel, account, rpcCall, onSaved }) message: ['已加入群授权:', name, '。记得点保存。'].join(''), }); }, - }, [already ? '已在群:' : '加入群:', name].join('')); + }, ['加入群:', name].join('')); })); }))), h('fieldset', { className: 'dim-accessScene', disabled: saving }, diff --git a/plugin-src/client/i18n.js b/plugin-src/client/i18n.js index 80522a2..dfd3182 100644 --- a/plugin-src/client/i18n.js +++ b/plugin-src/client/i18n.js @@ -52,7 +52,9 @@ const EN = Object.freeze({ "暂无联系人。有人私聊或 @ 机器人后会出现在此。": "No contacts yet. They appear here after someone DMs or @mentions the bot.", - "仅记录私聊机器人,或在群里 @ 机器人的人。电话是唯一授权键,可一键加入私聊/本群授权。": "Only people who DM the bot or @mention it in a group are recorded. Phone is the sole auth key; use one-click to grant DM or group access.", + "当前联系人均已具备对应权限,无需再授权。": "Everyone in contacts already has the matching access; nothing left to grant.", + + "仅记录私聊机器人,或在群里 @ 机器人的人。已有对应权限的人会自动隐藏;电话是唯一授权键,可一键加入私聊/本群授权。": "Only people who DM the bot or @mention it in a group are recorded. People who already have the matching access are hidden. Phone is the sole auth key; use one-click to grant DM or group access.", "WhatsApp 按电话号码授权:全局管理员管私聊;群管理员只批本群。成员不可跨群、有群权也不自动获得私聊权。": "WhatsApp authorizes by phone number: global admins manage DMs; group admins approve only their group. Members do not cross groups, and group access does not grant DMs.", "保存分级访问设置": "Save graded access settings",