mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-08 23:13:17 +08:00
Add configurable group session scope (default user_in_chat).
Ops bots now isolate per-speaker Harness sessions in groups, with a settings/RPC toggle to restore shared chat sessions when needed. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
d10a941fc8
commit
7f1b9bd480
30 changed files with 798 additions and 282 deletions
|
|
@ -571,7 +571,7 @@ var React23 = __toESM(require("react"), 1);
|
|||
// package.json
|
||||
var package_default = {
|
||||
name: "dsh-im-ops",
|
||||
version: "4.9.1-ops.0",
|
||||
version: "4.9.1-ops.1",
|
||||
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",
|
||||
|
|
@ -11797,7 +11797,29 @@ var React21 = __toESM(require("react"), 1);
|
|||
|
||||
// plugin-src/client/access-policy-settings.js
|
||||
var React20 = __toESM(require("react"), 1);
|
||||
|
||||
// src/channels/shared/session-scope.mjs
|
||||
var GROUP_SESSION_SCOPES = Object.freeze(["chat", "user_in_chat"]);
|
||||
var DEFAULT_GROUP_SESSION_SCOPE = "user_in_chat";
|
||||
function normalizeGroupSessionScope(value) {
|
||||
const scope = String(value ?? "").trim().toLowerCase();
|
||||
if (scope === "chat" || scope === "shared" || scope === "shared_chat") return "chat";
|
||||
if (scope === "user_in_chat" || scope === "user" || scope === "per_user" || scope === "member") {
|
||||
return "user_in_chat";
|
||||
}
|
||||
return DEFAULT_GROUP_SESSION_SCOPE;
|
||||
}
|
||||
function validateGroupSessionScope(value) {
|
||||
const scope = String(value ?? "").trim().toLowerCase();
|
||||
if (scope === "chat" || scope === "user_in_chat") return scope;
|
||||
const error = new TypeError(`Invalid group session scope: ${String(value)}`);
|
||||
error.code = "invalid-group-session-scope";
|
||||
throw error;
|
||||
}
|
||||
|
||||
// plugin-src/client/access-policy-settings.js
|
||||
var ACCESS_POLICY_ENDPOINT = "bot.access-policy.set";
|
||||
var GROUP_SESSION_SCOPE_ENDPOINT = "bot.group-session-scope.set";
|
||||
var ACCESS_CHANNEL_DEFINITIONS = Object.freeze({
|
||||
weixin: Object.freeze({
|
||||
directUserLabel: "\u5FAE\u4FE1\u7528\u6237 ID",
|
||||
|
|
@ -12092,15 +12114,18 @@ function AccessPolicySettingsPage({ channel: channel4, account, rpcCall, onSaved
|
|||
const definition = ACCESS_CHANNEL_DEFINITIONS[channel4];
|
||||
const initialPolicy = normalizeAccessPolicy(account?.accessPolicy);
|
||||
const initialKey = JSON.stringify(initialPolicy);
|
||||
const initialScope = normalizeGroupSessionScope(account?.groupSessionScope);
|
||||
const [draft, setDraft] = React20.useState(() => clonePolicy(
|
||||
initialPolicy ?? DEFAULT_ACCESS_POLICY
|
||||
));
|
||||
const [groupSessionScope, setGroupSessionScope] = React20.useState(initialScope);
|
||||
const [saving, setSaving] = React20.useState(false);
|
||||
const [feedback, setFeedback] = React20.useState(null);
|
||||
React20.useEffect(() => {
|
||||
const next = normalizeAccessPolicy(account?.accessPolicy);
|
||||
setDraft(clonePolicy(next ?? DEFAULT_ACCESS_POLICY));
|
||||
}, [account?.botId, initialKey]);
|
||||
setGroupSessionScope(normalizeGroupSessionScope(account?.groupSessionScope));
|
||||
}, [account?.botId, initialKey, account?.groupSessionScope]);
|
||||
React20.useEffect(() => {
|
||||
setFeedback(null);
|
||||
}, [account?.botId]);
|
||||
|
|
@ -12117,16 +12142,25 @@ function AccessPolicySettingsPage({ channel: channel4, account, rpcCall, onSaved
|
|||
setSaving(true);
|
||||
try {
|
||||
const policy = validateAccessPolicy(draft);
|
||||
const scope = validateGroupSessionScope(groupSessionScope);
|
||||
if (typeof rpcCall !== "function") throw new Error("\u8BBF\u95EE\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002");
|
||||
const value = unwrapRpcResult10(await rpcCall(ACCESS_POLICY_ENDPOINT, {
|
||||
botId: account.botId,
|
||||
policy
|
||||
}));
|
||||
const scopeValue = unwrapRpcResult10(await rpcCall(GROUP_SESSION_SCOPE_ENDPOINT, {
|
||||
botId: account.botId,
|
||||
groupSessionScope: scope
|
||||
}));
|
||||
const saved = policyFromSnapshot(value, account.botId);
|
||||
if (!saved) throw new Error("\u670D\u52A1\u6CA1\u6709\u8FD4\u56DE\u5DF2\u4FDD\u5B58\u7684\u8BBF\u95EE\u7B56\u7565\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5\u3002");
|
||||
const savedScope = normalizeGroupSessionScope(
|
||||
scopeValue?.snapshot?.bots?.find?.((bot) => bot?.botId === account.botId)?.groupSessionScope ?? scopeValue?.bots?.find?.((bot) => bot?.botId === account.botId)?.groupSessionScope ?? scope
|
||||
);
|
||||
setDraft(clonePolicy(saved));
|
||||
onSaved?.(saved);
|
||||
setFeedback({ tone: "success", message: "\u8BBF\u95EE\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002" });
|
||||
setGroupSessionScope(savedScope);
|
||||
onSaved?.({ ...saved, groupSessionScope: savedScope });
|
||||
setFeedback({ tone: "success", message: "\u8BBF\u95EE\u4E0E\u7FA4\u4F1A\u8BDD\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002" });
|
||||
} catch (error) {
|
||||
setFeedback({
|
||||
tone: "error",
|
||||
|
|
@ -12172,6 +12206,59 @@ function AccessPolicySettingsPage({ channel: channel4, account, rpcCall, onSaved
|
|||
setFeedback(null);
|
||||
}
|
||||
}),
|
||||
definition.groupSupported === false ? null : h2(
|
||||
"fieldset",
|
||||
{
|
||||
className: "dim-accessScene",
|
||||
disabled: saving,
|
||||
"data-scene": "group-session",
|
||||
"aria-label": localizeText("\u7FA4\u4F1A\u8BDD\u7B56\u7565")
|
||||
},
|
||||
h2(
|
||||
"legend",
|
||||
null,
|
||||
h2(
|
||||
"span",
|
||||
{ className: "dim-accessLegendContent" },
|
||||
h2("span", null, "\u7FA4\u4F1A\u8BDD\u7B56\u7565"),
|
||||
h2(
|
||||
"span",
|
||||
{ className: "dim-channelHelp dim-accessLegendHelp" },
|
||||
h2("button", {
|
||||
type: "button",
|
||||
className: "dim-channelHelpButton",
|
||||
"aria-label": localizeText("\u67E5\u770B\u7FA4\u4F1A\u8BDD\u7B56\u7565\u8BF4\u660E")
|
||||
}, h2("span", { "aria-hidden": true }, "?")),
|
||||
h2("span", {
|
||||
className: "dim-channelTooltip dim-accessHelpTooltip",
|
||||
role: "tooltip"
|
||||
}, "\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")
|
||||
)
|
||||
)
|
||||
),
|
||||
h2(
|
||||
"div",
|
||||
{ className: "dim-accessControls" },
|
||||
h2(
|
||||
"label",
|
||||
{ className: "dim-accessField" },
|
||||
h2("span", null, "\u7FA4\u5185 Session \u7ED1\u5B9A"),
|
||||
h2(
|
||||
"select",
|
||||
{
|
||||
value: groupSessionScope || DEFAULT_GROUP_SESSION_SCOPE,
|
||||
"aria-label": localizeText("\u7FA4\u5185 Session \u7ED1\u5B9A"),
|
||||
onChange: (event) => {
|
||||
setGroupSessionScope(event.target.value);
|
||||
setFeedback(null);
|
||||
}
|
||||
},
|
||||
h2("option", { value: "user_in_chat" }, "\u6309\u53D1\u8A00\u4EBA\u62C6\u5206\uFF08\u63A8\u8350\uFF09"),
|
||||
h2("option", { value: "chat" }, "\u6574\u7FA4\u5171\u4EAB\u4E00\u4E2A Session")
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
feedback ? h2("p", {
|
||||
className: "dim-accessFeedback",
|
||||
"data-tone": feedback.tone,
|
||||
|
|
@ -12186,7 +12273,7 @@ function AccessPolicySettingsPage({ channel: channel4, account, rpcCall, onSaved
|
|||
className: "dim-deliveryButton",
|
||||
"data-kind": "primary",
|
||||
disabled: saving || !initialPolicy
|
||||
}, saving ? "\u6B63\u5728\u4FDD\u5B58\u2026" : "\u4FDD\u5B58\u8BBF\u95EE\u8BBE\u7F6E")
|
||||
}, saving ? "\u6B63\u5728\u4FDD\u5B58\u2026" : "\u4FDD\u5B58\u8BBF\u95EE\u4E0E\u4F1A\u8BDD\u8BBE\u7F6E")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
|||
524
lib/index.js
524
lib/index.js
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue