@shgroup/dsh-serenity-hooks 1.26.17 → 1.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dsh.plugin.json +1 -1
- package/lib/ccc.d.ts +42 -0
- package/lib/client.js +416 -1
- package/lib/index.js +387 -815
- package/lib/rolldown-runtime-D7D4PA-g.js +13 -0
- package/lib/skiff-core-BewZSbVH.js +424 -0
- package/lib/skiff-core.d.ts +3 -1
- package/lib/skiff-role-Dw7UKCUm.js +126 -0
- package/lib/weixin-api-b8HLmcPE.js +211 -0
- package/lib/weixin-api.d.ts +119 -0
- package/lib/weixin-bridge.d.ts +56 -0
- package/lib/weixin-route-CHCWBvLZ.js +473 -0
- package/lib/weixin-route.d.ts +61 -0
- package/package.json +1 -1
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-serenity-hooks",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.27.0",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"description": "宁静号 ACC harness(Native Cordis 插件):真实 DSH 工具 cc_fs/session/acc_msm/eap/neat/cce/handyman/session_rebuild/skiff_admin + 拦截缝机械约束(safe-mode/路径守卫)+ 高级设定面板(双端口网关/账号管理)+ Skiff 认知子集角色(实验性)。适配 DSH 公开版(0.1.0-rc,deepseek-ai/deepseek-harness)。",
|
|
6
6
|
"engines": {
|
package/lib/ccc.d.ts
CHANGED
|
@@ -63,6 +63,14 @@ export interface SerenityConfig {
|
|
|
63
63
|
* 未配置或 enabled=false → 机制完全不启动(零资源占用,零影响现有功能)。
|
|
64
64
|
*/
|
|
65
65
|
autotrajectory?: AutoTrajectorySettings;
|
|
66
|
+
/**
|
|
67
|
+
* 微信桥(F4c-3,v1.27.0 实验性):**CCC 级**配置——dsh 一个进程含多个 CCC,
|
|
68
|
+
* 每个 CCC 独立对接微信桥(S142 用户拍板:ACC 不绑定 role,配置归 CCC,手工)。
|
|
69
|
+
* 结构/路由/开关在此文件(git 管可重建);**bot_token 凭据在 CCC localstore**
|
|
70
|
+
* (weixin.accounts.<accountId>.token/.baseUrl/.userId——扫码后自动写入,安全纪律)。
|
|
71
|
+
* 未配置或 enabled=false → 该 CCC 桥完全不启动(零资源占用)。
|
|
72
|
+
*/
|
|
73
|
+
weixin?: WeixinSettings;
|
|
66
74
|
}
|
|
67
75
|
/**
|
|
68
76
|
* 自主轨迹配置(CCC 定义;S142 用户拍板 v0.5):
|
|
@@ -95,6 +103,40 @@ export interface AutoTrajectorySettings {
|
|
|
95
103
|
end?: number;
|
|
96
104
|
};
|
|
97
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* 微信桥配置(CCC 级;S142 用户拍板):
|
|
108
|
+
* - 结构/路由/开关在 .opencode/serenity.json(git 管可重建)
|
|
109
|
+
* - **bot_token 凭据在 CCC localstore**(weixin.accounts.<accountId>.token/.baseUrl/.userId)——
|
|
110
|
+
* 扫码登录后插件自动写入(面板只显示"已绑定"),永不进 git 明文面
|
|
111
|
+
* - 路由 user → role:exact 匹配优先,通配 `*` 兜底;role 必须是该 CCC skiff.roles 之一
|
|
112
|
+
* - 多账号:accounts[] 每项 { accountId, name?, enabled }(本地唯一键,如 wechat-1)
|
|
113
|
+
*/
|
|
114
|
+
export interface WeixinSettings {
|
|
115
|
+
/** 总开关(缺省 false——默认关,未开零资源占用) */
|
|
116
|
+
enabled?: boolean;
|
|
117
|
+
/** bot_type(iLink 取码参数;实证 3 可用,留配置项应对未来语义变化) */
|
|
118
|
+
botType?: string;
|
|
119
|
+
/** 账号表(本地键 accountId;凭据在 localstore) */
|
|
120
|
+
accounts?: WeixinAccountConfig[];
|
|
121
|
+
/** 消息路由:微信用户 → 该 CCC 的 skiff role(不绑定具体 role——用户自选) */
|
|
122
|
+
routes?: WeixinRouteConfig[];
|
|
123
|
+
}
|
|
124
|
+
/** 微信桥账号配置(serenity.json 内;凭据部分在 localstore) */
|
|
125
|
+
export interface WeixinAccountConfig {
|
|
126
|
+
/** 本地唯一键(如 wechat-1;localstore 凭据键 weixin.accounts.<accountId>.*) */
|
|
127
|
+
accountId: string;
|
|
128
|
+
/** 展示名(可选;如"家庭招财") */
|
|
129
|
+
name?: string;
|
|
130
|
+
/** 该账号轮询开关(缺省 true) */
|
|
131
|
+
enabled?: boolean;
|
|
132
|
+
}
|
|
133
|
+
/** 微信桥路由配置:微信用户 → CCC 的 skiff role */
|
|
134
|
+
export interface WeixinRouteConfig {
|
|
135
|
+
/** 微信用户标识(from_user_id,形如 userA@im.wechat);`*` = 通配兜底 */
|
|
136
|
+
user: string;
|
|
137
|
+
/** 目标 skiff role 名(必须 ∈ 该 CCC skiff.roles;ACC 不绑定——用户自选) */
|
|
138
|
+
role: string;
|
|
139
|
+
}
|
|
98
140
|
/**
|
|
99
141
|
* Skiff 角色配置(CCC 定义:全知全能轨迹的一个子集):
|
|
100
142
|
* 能力面 = tools(非 MSM 工具白名单)+ msms(MSM 白名单)双白名单,白名单外全隐藏;
|
package/lib/client.js
CHANGED
|
@@ -4098,8 +4098,416 @@ Instruction-following style:
|
|
|
4098
4098
|
});
|
|
4099
4099
|
}
|
|
4100
4100
|
//#endregion
|
|
4101
|
+
//#region src/client/WeixinBridgeEditor.tsx
|
|
4102
|
+
/**
|
|
4103
|
+
* WeixinBridgeEditor.tsx — 「微信桥」配置区块(F4c-3,v1.27.0 实验性)
|
|
4104
|
+
*
|
|
4105
|
+
* **CCC 级配置**(S142 用户拍板:dsh 一个进程含多个 CCC,每个 CCC 独立对接微信桥):
|
|
4106
|
+
* - 顶部 **CCC 选择器**(数据源 /serenity/cccs——discoverCccs 复用)——显式选择配置目标,
|
|
4107
|
+
* 不隐式依赖"当前活跃会话"(WebUI 顶层全局,微信桥是配置写入必须显式)
|
|
4108
|
+
* - 选中 CCC 后:总开关 / 账号列表(扫码绑定)/ 路由表(user → role)
|
|
4109
|
+
* - 扫码绑定:POST login-start → qrcode-generator 生成二维码 SVG(复用 v1.24.6 TOTP 同款机制)
|
|
4110
|
+
* → 轮询 /serenity/weixin/login → confirmed 自动写凭据 + 账号元信息
|
|
4111
|
+
*
|
|
4112
|
+
* 全部端点带显式 ccc 参数 + x-serenity-ui 头(服务端校验)。
|
|
4113
|
+
*/
|
|
4114
|
+
/** 生成二维码 SVG(内容 = iLink qrcode_img_content URL——用户微信扫它打开 liteapp 确认页) */
|
|
4115
|
+
function qrSvgFor(content) {
|
|
4116
|
+
const qr = qrcode(0, "M");
|
|
4117
|
+
qr.addData(content);
|
|
4118
|
+
qr.make();
|
|
4119
|
+
return qr.createSvgTag({
|
|
4120
|
+
cellSize: 4,
|
|
4121
|
+
margin: 2,
|
|
4122
|
+
scalable: true
|
|
4123
|
+
});
|
|
4124
|
+
}
|
|
4125
|
+
/** 当前工作区 CCC(默认选择器初值:settings 面板无 workspace 参数——服务端 /serenity/weixin 显式 ccc;
|
|
4126
|
+
* 选择器默认选第一个;用户手选) */
|
|
4127
|
+
function WeixinBridgeEditor() {
|
|
4128
|
+
const [cccs, setCccs] = (0, react.useState)([]);
|
|
4129
|
+
const [selectedRoot, setSelectedRoot] = (0, react.useState)("");
|
|
4130
|
+
const [status, setStatus] = (0, react.useState)(null);
|
|
4131
|
+
const [loadError, setLoadError] = (0, react.useState)(null);
|
|
4132
|
+
const [loginPhase, setLoginPhase] = (0, react.useState)("idle");
|
|
4133
|
+
const [loginQrSvg, setLoginQrSvg] = (0, react.useState)("");
|
|
4134
|
+
const [loginKey, setLoginKey] = (0, react.useState)("");
|
|
4135
|
+
const [loginError, setLoginError] = (0, react.useState)(null);
|
|
4136
|
+
const [loginNotice, setLoginNotice] = (0, react.useState)(null);
|
|
4137
|
+
const [routesDraft, setRoutesDraft] = (0, react.useState)("");
|
|
4138
|
+
(0, react.useEffect)(() => {
|
|
4139
|
+
let alive = true;
|
|
4140
|
+
(async () => {
|
|
4141
|
+
try {
|
|
4142
|
+
const res = await fetch("/serenity/cccs", { headers: { accept: "application/json" } });
|
|
4143
|
+
if (!res.ok) return;
|
|
4144
|
+
const body = await res.json();
|
|
4145
|
+
if (!alive || !Array.isArray(body.cccs)) return;
|
|
4146
|
+
setCccs(body.cccs);
|
|
4147
|
+
if (body.cccs.length > 0) setSelectedRoot((prev) => prev || body.cccs[0].root);
|
|
4148
|
+
} catch {}
|
|
4149
|
+
})();
|
|
4150
|
+
return () => {
|
|
4151
|
+
alive = false;
|
|
4152
|
+
};
|
|
4153
|
+
}, []);
|
|
4154
|
+
(0, react.useEffect)(() => {
|
|
4155
|
+
if (!selectedRoot) return;
|
|
4156
|
+
let alive = true;
|
|
4157
|
+
setStatus(null);
|
|
4158
|
+
setLoadError(null);
|
|
4159
|
+
setLoginPhase("idle");
|
|
4160
|
+
(async () => {
|
|
4161
|
+
try {
|
|
4162
|
+
const res = await fetch(`/serenity/weixin?ccc=${encodeURIComponent(selectedRoot)}`, { headers: { accept: "application/json" } });
|
|
4163
|
+
if (!res.ok) {
|
|
4164
|
+
const body = await res.json().catch(() => null);
|
|
4165
|
+
if (alive) setLoadError(body?.error ?? `HTTP ${res.status}`);
|
|
4166
|
+
return;
|
|
4167
|
+
}
|
|
4168
|
+
const body = await res.json();
|
|
4169
|
+
if (!alive) return;
|
|
4170
|
+
setStatus(body);
|
|
4171
|
+
setRoutesDraft(JSON.stringify(body.routes ?? [], null, 2));
|
|
4172
|
+
} catch {}
|
|
4173
|
+
})();
|
|
4174
|
+
return () => {
|
|
4175
|
+
alive = false;
|
|
4176
|
+
};
|
|
4177
|
+
}, [selectedRoot]);
|
|
4178
|
+
(0, react.useEffect)(() => {
|
|
4179
|
+
if (loginPhase !== "waiting" || !loginKey) return;
|
|
4180
|
+
let alive = true;
|
|
4181
|
+
let timer;
|
|
4182
|
+
const poll = async () => {
|
|
4183
|
+
try {
|
|
4184
|
+
const res = await fetch(`/serenity/weixin/login?key=${encodeURIComponent(loginKey)}`, { headers: { accept: "application/json" } });
|
|
4185
|
+
if (!alive) return;
|
|
4186
|
+
if (!res.ok) {
|
|
4187
|
+
const body = await res.json().catch(() => null);
|
|
4188
|
+
setLoginPhase("error");
|
|
4189
|
+
setLoginError(body?.error ?? `HTTP ${res.status}`);
|
|
4190
|
+
return;
|
|
4191
|
+
}
|
|
4192
|
+
const body = await res.json();
|
|
4193
|
+
if (body.status === "confirmed") {
|
|
4194
|
+
setLoginPhase("confirmed");
|
|
4195
|
+
setLoginNotice(`账号 ${body.accountId} 已绑定 ✓(token 已写入 CCC localstore)`);
|
|
4196
|
+
if (selectedRoot) {
|
|
4197
|
+
const sbody = await (await fetch(`/serenity/weixin?ccc=${encodeURIComponent(selectedRoot)}`, { headers: { accept: "application/json" } })).json().catch(() => null);
|
|
4198
|
+
if (alive && sbody) setStatus(sbody);
|
|
4199
|
+
}
|
|
4200
|
+
return;
|
|
4201
|
+
}
|
|
4202
|
+
if (body.status === "expired" || body.status === "error") {
|
|
4203
|
+
setLoginPhase("error");
|
|
4204
|
+
setLoginError(body.error ?? "二维码已过期,请重新获取");
|
|
4205
|
+
return;
|
|
4206
|
+
}
|
|
4207
|
+
timer = setTimeout(() => void poll(), 1e3);
|
|
4208
|
+
} catch {
|
|
4209
|
+
if (alive) timer = setTimeout(() => void poll(), 1e3);
|
|
4210
|
+
}
|
|
4211
|
+
};
|
|
4212
|
+
poll();
|
|
4213
|
+
return () => {
|
|
4214
|
+
alive = false;
|
|
4215
|
+
if (timer) clearTimeout(timer);
|
|
4216
|
+
};
|
|
4217
|
+
}, [
|
|
4218
|
+
loginPhase,
|
|
4219
|
+
loginKey,
|
|
4220
|
+
selectedRoot
|
|
4221
|
+
]);
|
|
4222
|
+
const startLogin = async () => {
|
|
4223
|
+
if (!selectedRoot || loginPhase === "waiting") return;
|
|
4224
|
+
setLoginPhase("waiting");
|
|
4225
|
+
setLoginError(null);
|
|
4226
|
+
setLoginNotice(null);
|
|
4227
|
+
try {
|
|
4228
|
+
const res = await fetch("/serenity/weixin", {
|
|
4229
|
+
method: "POST",
|
|
4230
|
+
headers: {
|
|
4231
|
+
"content-type": "application/json",
|
|
4232
|
+
"x-serenity-ui": "1"
|
|
4233
|
+
},
|
|
4234
|
+
body: JSON.stringify({
|
|
4235
|
+
action: "login-start",
|
|
4236
|
+
ccc: selectedRoot
|
|
4237
|
+
})
|
|
4238
|
+
});
|
|
4239
|
+
const body = await res.json();
|
|
4240
|
+
if (!res.ok || !body.qrcode_img_content || !body.loginKey) {
|
|
4241
|
+
setLoginPhase("error");
|
|
4242
|
+
setLoginError(body.error ?? `HTTP ${res.status}`);
|
|
4243
|
+
return;
|
|
4244
|
+
}
|
|
4245
|
+
setLoginQrSvg(qrSvgFor(body.qrcode_img_content));
|
|
4246
|
+
setLoginKey(body.loginKey);
|
|
4247
|
+
} catch (err) {
|
|
4248
|
+
setLoginPhase("error");
|
|
4249
|
+
setLoginError(err instanceof Error ? err.message : String(err));
|
|
4250
|
+
}
|
|
4251
|
+
};
|
|
4252
|
+
const removeAccount = async (accountId) => {
|
|
4253
|
+
if (!selectedRoot) return;
|
|
4254
|
+
try {
|
|
4255
|
+
if (!(await fetch("/serenity/weixin", {
|
|
4256
|
+
method: "POST",
|
|
4257
|
+
headers: {
|
|
4258
|
+
"content-type": "application/json",
|
|
4259
|
+
"x-serenity-ui": "1"
|
|
4260
|
+
},
|
|
4261
|
+
body: JSON.stringify({
|
|
4262
|
+
action: "remove-account",
|
|
4263
|
+
ccc: selectedRoot,
|
|
4264
|
+
accountId
|
|
4265
|
+
})
|
|
4266
|
+
})).ok) return;
|
|
4267
|
+
const sbody = await (await fetch(`/serenity/weixin?ccc=${encodeURIComponent(selectedRoot)}`, { headers: { accept: "application/json" } })).json().catch(() => null);
|
|
4268
|
+
if (sbody) setStatus(sbody);
|
|
4269
|
+
} catch {}
|
|
4270
|
+
};
|
|
4271
|
+
const saveRoutes = async () => {
|
|
4272
|
+
if (!selectedRoot) return;
|
|
4273
|
+
let routes;
|
|
4274
|
+
try {
|
|
4275
|
+
routes = JSON.parse(routesDraft);
|
|
4276
|
+
if (!Array.isArray(routes) || routes.some((r) => typeof r?.user !== "string" || typeof r?.role !== "string")) throw new Error("bad");
|
|
4277
|
+
} catch {
|
|
4278
|
+
setLoadError("路由表 JSON 格式错误(期望 [{user, role}, ...])");
|
|
4279
|
+
return;
|
|
4280
|
+
}
|
|
4281
|
+
try {
|
|
4282
|
+
const res = await fetch("/serenity/weixin", {
|
|
4283
|
+
method: "POST",
|
|
4284
|
+
headers: {
|
|
4285
|
+
"content-type": "application/json",
|
|
4286
|
+
"x-serenity-ui": "1"
|
|
4287
|
+
},
|
|
4288
|
+
body: JSON.stringify({
|
|
4289
|
+
action: "save-routes",
|
|
4290
|
+
ccc: selectedRoot,
|
|
4291
|
+
routes
|
|
4292
|
+
})
|
|
4293
|
+
});
|
|
4294
|
+
const body = await res.json().catch(() => null);
|
|
4295
|
+
if (!res.ok) {
|
|
4296
|
+
setLoadError(body?.error ?? `HTTP ${res.status}`);
|
|
4297
|
+
return;
|
|
4298
|
+
}
|
|
4299
|
+
setLoadError(null);
|
|
4300
|
+
const sbody = await (await fetch(`/serenity/weixin?ccc=${encodeURIComponent(selectedRoot)}`, { headers: { accept: "application/json" } })).json().catch(() => null);
|
|
4301
|
+
if (sbody) setStatus(sbody);
|
|
4302
|
+
} catch {}
|
|
4303
|
+
};
|
|
4304
|
+
const toggleEnabled = async (on) => {
|
|
4305
|
+
if (!selectedRoot) return;
|
|
4306
|
+
try {
|
|
4307
|
+
const res = await fetch("/serenity/weixin", {
|
|
4308
|
+
method: "POST",
|
|
4309
|
+
headers: {
|
|
4310
|
+
"content-type": "application/json",
|
|
4311
|
+
"x-serenity-ui": "1"
|
|
4312
|
+
},
|
|
4313
|
+
body: JSON.stringify({
|
|
4314
|
+
action: "set-enabled",
|
|
4315
|
+
ccc: selectedRoot,
|
|
4316
|
+
enabled: on
|
|
4317
|
+
})
|
|
4318
|
+
});
|
|
4319
|
+
const body = await res.json().catch(() => null);
|
|
4320
|
+
if (!res.ok) {
|
|
4321
|
+
setLoadError(body?.error ?? `HTTP ${res.status}`);
|
|
4322
|
+
return;
|
|
4323
|
+
}
|
|
4324
|
+
setLoadError(null);
|
|
4325
|
+
const sbody = await (await fetch(`/serenity/weixin?ccc=${encodeURIComponent(selectedRoot)}`, { headers: { accept: "application/json" } })).json().catch(() => null);
|
|
4326
|
+
if (sbody) setStatus(sbody);
|
|
4327
|
+
} catch {}
|
|
4328
|
+
};
|
|
4329
|
+
const bridgeStateText = (accountId) => {
|
|
4330
|
+
const b = status?.bridge.find((x) => x.accountId === accountId);
|
|
4331
|
+
if (!b) return "未运行";
|
|
4332
|
+
if (b.lastError) return `错误: ${b.lastError}`;
|
|
4333
|
+
if (b.lastPollAt > 0) return `轮询中(${new Date(b.lastPollAt).toLocaleTimeString()})`;
|
|
4334
|
+
return "启动中";
|
|
4335
|
+
};
|
|
4336
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
|
|
4337
|
+
className: "ss-rows",
|
|
4338
|
+
children: [
|
|
4339
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4340
|
+
className: "ss-rowCard",
|
|
4341
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4342
|
+
className: "ss-rowText",
|
|
4343
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4344
|
+
className: "ss-rowName",
|
|
4345
|
+
children: "目标 CCC"
|
|
4346
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4347
|
+
className: "ss-rowDesc",
|
|
4348
|
+
children: "选择要配置微信桥的认知容器(显式,非当前活跃会话)"
|
|
4349
|
+
})]
|
|
4350
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4351
|
+
className: "ss-rowControl",
|
|
4352
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
4353
|
+
className: "ss-select",
|
|
4354
|
+
value: selectedRoot,
|
|
4355
|
+
onChange: (e) => setSelectedRoot(e.target.value),
|
|
4356
|
+
children: [cccs.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
4357
|
+
value: "",
|
|
4358
|
+
children: "加载中…"
|
|
4359
|
+
}), cccs.map((c) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
4360
|
+
value: c.root,
|
|
4361
|
+
children: c.name
|
|
4362
|
+
}, c.root))]
|
|
4363
|
+
})
|
|
4364
|
+
})]
|
|
4365
|
+
}) }),
|
|
4366
|
+
loadError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4367
|
+
className: "ss-rowCard",
|
|
4368
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4369
|
+
className: "ss-rowText",
|
|
4370
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4371
|
+
className: "ss-rowName",
|
|
4372
|
+
children: "提示"
|
|
4373
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4374
|
+
className: "ss-rowDesc",
|
|
4375
|
+
children: loadError
|
|
4376
|
+
})]
|
|
4377
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "ss-rowControl" })]
|
|
4378
|
+
}) }),
|
|
4379
|
+
status && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
4380
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4381
|
+
className: "ss-rowCard",
|
|
4382
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4383
|
+
className: "ss-rowText",
|
|
4384
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4385
|
+
className: "ss-rowName",
|
|
4386
|
+
children: "总开关"
|
|
4387
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4388
|
+
className: "ss-rowDesc",
|
|
4389
|
+
children: "启用后该 CCC 的微信桥开始轮询(需先扫码绑定至少一个账号)"
|
|
4390
|
+
})]
|
|
4391
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4392
|
+
className: "ss-rowControl",
|
|
4393
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
4394
|
+
className: "ss-switch",
|
|
4395
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4396
|
+
type: "checkbox",
|
|
4397
|
+
checked: status.enabled,
|
|
4398
|
+
onChange: (e) => void toggleEnabled(e.target.checked)
|
|
4399
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "ss-switchTrack" })]
|
|
4400
|
+
})
|
|
4401
|
+
})]
|
|
4402
|
+
}) }),
|
|
4403
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4404
|
+
className: "ss-rowCard",
|
|
4405
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4406
|
+
className: "ss-rowText",
|
|
4407
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4408
|
+
className: "ss-rowName",
|
|
4409
|
+
children: "账号"
|
|
4410
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4411
|
+
className: "ss-rowDesc",
|
|
4412
|
+
children: status.accounts.length === 0 ? "未绑定任何微信账号——点击右侧「扫码绑定」" : status.accounts.map((a) => `${a.accountId}${a.name ? ` · ${a.name}` : ""}${a.bound ? " · 已绑定" : " · 未绑定凭据"}(${bridgeStateText(a.accountId)})`).join(";")
|
|
4413
|
+
})]
|
|
4414
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4415
|
+
className: "ss-rowControl",
|
|
4416
|
+
children: status.accounts.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4417
|
+
type: "button",
|
|
4418
|
+
className: "ss-removeBtn",
|
|
4419
|
+
onClick: () => void removeAccount(status.accounts[0].accountId),
|
|
4420
|
+
children: "移除首个"
|
|
4421
|
+
})
|
|
4422
|
+
})]
|
|
4423
|
+
}) }),
|
|
4424
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4425
|
+
className: "ss-rowCard",
|
|
4426
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4427
|
+
className: "ss-rowText",
|
|
4428
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4429
|
+
className: "ss-rowName",
|
|
4430
|
+
children: "扫码绑定微信"
|
|
4431
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4432
|
+
className: "ss-rowDesc",
|
|
4433
|
+
children: [
|
|
4434
|
+
loginPhase === "idle" && "用手机微信「扫一扫」扫描二维码并确认,即绑定该 CCC 的微信桥账号",
|
|
4435
|
+
loginPhase === "waiting" && "二维码已生成(5 分钟内有效)——微信扫一扫 → 手机上确认绑定",
|
|
4436
|
+
loginPhase === "confirmed" && (loginNotice ?? "绑定成功"),
|
|
4437
|
+
loginPhase === "error" && (loginError ?? "绑定失败"),
|
|
4438
|
+
loginPhase === "expired" && "二维码已过期,请重新获取"
|
|
4439
|
+
]
|
|
4440
|
+
})]
|
|
4441
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4442
|
+
className: "ss-rowControl",
|
|
4443
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4444
|
+
type: "button",
|
|
4445
|
+
className: "ss-loginBtn",
|
|
4446
|
+
disabled: loginPhase === "waiting" || !status.enabled === false,
|
|
4447
|
+
onClick: () => void startLogin(),
|
|
4448
|
+
children: loginPhase === "waiting" ? "等待扫码…" : "扫码绑定"
|
|
4449
|
+
})
|
|
4450
|
+
})]
|
|
4451
|
+
}) }),
|
|
4452
|
+
loginPhase === "waiting" && loginQrSvg !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4453
|
+
className: "ss-rowCard ss-qrRow",
|
|
4454
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4455
|
+
className: "ss-qrSvg",
|
|
4456
|
+
dangerouslySetInnerHTML: { __html: loginQrSvg }
|
|
4457
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4458
|
+
className: "ss-rowText",
|
|
4459
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4460
|
+
className: "ss-rowDesc",
|
|
4461
|
+
children: "1. 打开手机微信 → 扫一扫 2. 扫描此二维码 3. 在手机上确认绑定"
|
|
4462
|
+
})
|
|
4463
|
+
})]
|
|
4464
|
+
}) }),
|
|
4465
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4466
|
+
className: "ss-rowCard",
|
|
4467
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4468
|
+
className: "ss-rowText",
|
|
4469
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4470
|
+
className: "ss-rowName",
|
|
4471
|
+
children: "路由表"
|
|
4472
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4473
|
+
className: "ss-rowDesc",
|
|
4474
|
+
children: "微信用户 → 该 CCC 的 skiff 角色(`*` = 通配兜底;role 必须已定义)"
|
|
4475
|
+
})]
|
|
4476
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4477
|
+
className: "ss-rowControl",
|
|
4478
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4479
|
+
type: "button",
|
|
4480
|
+
className: "ss-loginBtn",
|
|
4481
|
+
onClick: () => void saveRoutes(),
|
|
4482
|
+
children: "保存路由"
|
|
4483
|
+
})
|
|
4484
|
+
})]
|
|
4485
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
4486
|
+
className: "ss-routesEditor",
|
|
4487
|
+
rows: 5,
|
|
4488
|
+
value: routesDraft,
|
|
4489
|
+
onChange: (e) => setRoutesDraft(e.target.value)
|
|
4490
|
+
})] })
|
|
4491
|
+
] }),
|
|
4492
|
+
!status && !loadError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4493
|
+
className: "ss-rowCard",
|
|
4494
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4495
|
+
className: "ss-rowText",
|
|
4496
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4497
|
+
className: "ss-rowName",
|
|
4498
|
+
children: "加载中…"
|
|
4499
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4500
|
+
className: "ss-rowDesc",
|
|
4501
|
+
children: "读取所选 CCC 的微信桥配置"
|
|
4502
|
+
})]
|
|
4503
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "ss-rowControl" })]
|
|
4504
|
+
}) })
|
|
4505
|
+
]
|
|
4506
|
+
});
|
|
4507
|
+
}
|
|
4508
|
+
//#endregion
|
|
4101
4509
|
//#region \0sp-css:/home/yh/home/home-serenity/AI_LAB/dsh-serenity-plugin/hooks/dsh-serenity-hooks/src/client/SettingsSection
|
|
4102
|
-
const css = "/* SettingsSection — dsh 原生设置面板 serenity-hooks 简单配置页\n v1.21.1 看齐 dsh 自身:官方 settings 设计语言——\n section > title + intro + group(groupTitle) + rowCard 行卡;\n 全部 --dsw-alias-* token(与 ui-settings-models 同词汇表)。 */\n\n/* 页面容器(官方 .section:flex column gap 12) */\n.ss-section {\n display: flex;\n flex-direction: column;\n gap: 14px;\n max-width: 720px;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 页面标题(官方 .title:16px/24 500) */\n.ss-title {\n margin: 0;\n font-size: 16px;\n line-height: 24px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 页面说明(官方 .intro:14px/22 tertiary) */\n.ss-intro {\n margin: 0;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 分组(多级标题:分组标题 + 行卡列表) */\n.ss-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n/* 分组标题(二级:12px/18 500 secondary——官方 fieldLabel 风格) */\n.ss-groupTitle {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* 行卡列表(官方 .rows:无 marker,gap 8) */\n.ss-rows {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n/* 行卡(官方 .rowCard:border-l2 r12 padding 12/14) */\n.ss-rowCard {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n padding: 12px 14px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n}\n\n/* 行卡文本(标题 + 说明 左列) */\n.ss-rowText {\n display: flex;\n flex-direction: column;\n gap: 3px;\n min-width: 0;\n flex: 1;\n}\n\n/* 行卡标题(官方 .rowName:14px/22 500) */\n.ss-rowName {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 行卡说明(12px/18 tertiary) */\n.ss-rowDesc {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 行卡控件(右置) */\n.ss-rowControl {\n flex: none;\n display: flex;\n align-items: center;\n}\n\n/* 开关(官方 token 的自绘 toggle:track 22px,thumb 16px) */\n.ss-switch {\n position: relative;\n flex: none;\n width: 40px;\n height: 22px;\n cursor: pointer;\n}\n\n.ss-switch input {\n position: absolute;\n opacity: 0;\n width: 100%;\n height: 100%;\n margin: 0;\n cursor: pointer;\n}\n\n.ss-switchTrack {\n position: absolute;\n inset: 0;\n border-radius: 11px;\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.3));\n transition: background var(--ds-transition-duration-fast, 0.15s) var(--ds-ease-in-out, ease);\n}\n\n.ss-switchTrack::after {\n content: '';\n position: absolute;\n top: 3px;\n left: 3px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--dsw-alias-label-primary, #eee);\n transition: transform var(--ds-transition-duration-fast, 0.15s) var(--ds-ease-in-out, ease);\n}\n\n.ss-switch input:checked + .ss-switchTrack {\n background: var(--dsw-alias-state-success-primary, #22c55e);\n}\n\n.ss-switch input:checked + .ss-switchTrack::after {\n transform: translateX(18px);\n}\n\n.ss-switch input:disabled + .ss-switchTrack {\n opacity: 0.4;\n cursor: default;\n}\n\n/* 阈值行(滑块 + 值) */\n.ss-threshold {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.ss-threshold input[type='range'] {\n width: 160px;\n}\n\n/* Skiff 调试端口输入(number;关闭时跟随 disabled 半透明) */\n.ss-portInput {\n width: 96px;\n padding: 6px 8px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-fill-l1, rgba(128, 128, 128, 0.08));\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n font-variant-numeric: tabular-nums;\n text-align: right;\n}\n\n.ss-portInput:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n.ss-value {\n min-width: 40px;\n font-variant-numeric: tabular-nums;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n text-align: right;\n}\n\n/* 自主轨迹「立即唤起」按钮(v1.26.14 调试语义;官方 button 语言:primary 弱化) */\n.ss-wakeBtn {\n flex: none;\n padding: 5px 12px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.12));\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n cursor: pointer;\n transition: opacity var(--ds-transition-duration-fast, 0.15s) ease;\n}\n\n.ss-wakeBtn:hover:not(:disabled) {\n border-color: var(--dsw-alias-state-success-primary, #22c55e);\n color: var(--dsw-alias-state-success-primary, #22c55e);\n}\n\n.ss-wakeBtn:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n/* 底部帮助行 */\n.ss-hint {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 降级提示 */\n.ss-degrade {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-warn-label);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n";
|
|
4510
|
+
const css = "/* SettingsSection — dsh 原生设置面板 serenity-hooks 简单配置页\n v1.21.1 看齐 dsh 自身:官方 settings 设计语言——\n section > title + intro + group(groupTitle) + rowCard 行卡;\n 全部 --dsw-alias-* token(与 ui-settings-models 同词汇表)。 */\n\n/* 页面容器(官方 .section:flex column gap 12) */\n.ss-section {\n display: flex;\n flex-direction: column;\n gap: 14px;\n max-width: 720px;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 页面标题(官方 .title:16px/24 500) */\n.ss-title {\n margin: 0;\n font-size: 16px;\n line-height: 24px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 页面说明(官方 .intro:14px/22 tertiary) */\n.ss-intro {\n margin: 0;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 分组(多级标题:分组标题 + 行卡列表) */\n.ss-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n/* 分组标题(二级:12px/18 500 secondary——官方 fieldLabel 风格) */\n.ss-groupTitle {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* 行卡列表(官方 .rows:无 marker,gap 8) */\n.ss-rows {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n/* 行卡(官方 .rowCard:border-l2 r12 padding 12/14) */\n.ss-rowCard {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n padding: 12px 14px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n}\n\n/* 行卡文本(标题 + 说明 左列) */\n.ss-rowText {\n display: flex;\n flex-direction: column;\n gap: 3px;\n min-width: 0;\n flex: 1;\n}\n\n/* 行卡标题(官方 .rowName:14px/22 500) */\n.ss-rowName {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n/* 行卡说明(12px/18 tertiary) */\n.ss-rowDesc {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 行卡控件(右置) */\n.ss-rowControl {\n flex: none;\n display: flex;\n align-items: center;\n}\n\n/* 开关(官方 token 的自绘 toggle:track 22px,thumb 16px) */\n.ss-switch {\n position: relative;\n flex: none;\n width: 40px;\n height: 22px;\n cursor: pointer;\n}\n\n.ss-switch input {\n position: absolute;\n opacity: 0;\n width: 100%;\n height: 100%;\n margin: 0;\n cursor: pointer;\n}\n\n.ss-switchTrack {\n position: absolute;\n inset: 0;\n border-radius: 11px;\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.3));\n transition: background var(--ds-transition-duration-fast, 0.15s) var(--ds-ease-in-out, ease);\n}\n\n.ss-switchTrack::after {\n content: '';\n position: absolute;\n top: 3px;\n left: 3px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--dsw-alias-label-primary, #eee);\n transition: transform var(--ds-transition-duration-fast, 0.15s) var(--ds-ease-in-out, ease);\n}\n\n.ss-switch input:checked + .ss-switchTrack {\n background: var(--dsw-alias-state-success-primary, #22c55e);\n}\n\n.ss-switch input:checked + .ss-switchTrack::after {\n transform: translateX(18px);\n}\n\n.ss-switch input:disabled + .ss-switchTrack {\n opacity: 0.4;\n cursor: default;\n}\n\n/* 阈值行(滑块 + 值) */\n.ss-threshold {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.ss-threshold input[type='range'] {\n width: 160px;\n}\n\n/* Skiff 调试端口输入(number;关闭时跟随 disabled 半透明) */\n.ss-portInput {\n width: 96px;\n padding: 6px 8px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-fill-l1, rgba(128, 128, 128, 0.08));\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n font-variant-numeric: tabular-nums;\n text-align: right;\n}\n\n.ss-portInput:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n.ss-value {\n min-width: 40px;\n font-variant-numeric: tabular-nums;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n text-align: right;\n}\n\n/* 自主轨迹「立即唤起」按钮(v1.26.14 调试语义;官方 button 语言:primary 弱化) */\n.ss-wakeBtn {\n flex: none;\n padding: 5px 12px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.12));\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n cursor: pointer;\n transition: opacity var(--ds-transition-duration-fast, 0.15s) ease;\n}\n\n.ss-wakeBtn:hover:not(:disabled) {\n border-color: var(--dsw-alias-state-success-primary, #22c55e);\n color: var(--dsw-alias-state-success-primary, #22c55e);\n}\n\n.ss-wakeBtn:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n/* 底部帮助行 */\n.ss-hint {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 降级提示 */\n.ss-degrade {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-warn-label);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* ── 微信桥(F4c-3,v1.27.0 实验性)── */\n\n/* CCC 选择器(下拉) */\n.ss-select {\n max-width: 280px;\n padding: 6px 8px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-fill-l1, rgba(128, 128, 128, 0.08));\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n/* 扫码绑定按钮(复用 wakeBtn 语言) */\n.ss-loginBtn {\n flex: none;\n padding: 5px 12px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.12));\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n cursor: pointer;\n transition: opacity var(--ds-transition-duration-fast, 0.15s) ease;\n}\n\n.ss-loginBtn:hover:not(:disabled) {\n border-color: var(--dsw-alias-state-success-primary, #22c55e);\n color: var(--dsw-alias-state-success-primary, #22c55e);\n}\n\n.ss-loginBtn:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n/* 移除账号按钮(危险语义:红边框) */\n.ss-removeBtn {\n flex: none;\n padding: 5px 12px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.12));\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n cursor: pointer;\n transition: opacity var(--ds-transition-duration-fast, 0.15s) ease;\n}\n\n.ss-removeBtn:hover:not(:disabled) {\n border-color: var(--dsw-alias-state-error-primary, #ef4444);\n color: var(--dsw-alias-state-error-primary, #ef4444);\n}\n\n/* 二维码展示行 */\n.ss-qrRow {\n align-items: flex-start;\n}\n\n.ss-qrSvg {\n flex: none;\n width: 160px;\n height: 160px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: #fff; /* 二维码需要白底才能被微信扫出 */\n padding: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.ss-qrSvg svg {\n width: 100%;\n height: 100%;\n}\n\n/* 路由表 JSON 编辑框 */\n.ss-routesEditor {\n width: 100%;\n box-sizing: border-box;\n margin-top: 6px;\n padding: 8px 10px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-fill-l1, rgba(128, 128, 128, 0.08));\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n font-family: var(--ds-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);\n resize: vertical;\n}\n";
|
|
4103
4511
|
if (typeof document !== "undefined" && document.querySelector("style[data-sp-css=\"SettingsSection\"]") === null) {
|
|
4104
4512
|
const tag = document.createElement("style");
|
|
4105
4513
|
tag.setAttribute("data-sp-css", "SettingsSection");
|
|
@@ -4346,6 +4754,13 @@ Instruction-following style:
|
|
|
4346
4754
|
className: "ss-groupTitle",
|
|
4347
4755
|
children: "自主轨迹"
|
|
4348
4756
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AutoTrajectoryStatusBlock, {})]
|
|
4757
|
+
}),
|
|
4758
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4759
|
+
className: "ss-group",
|
|
4760
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
4761
|
+
className: "ss-groupTitle",
|
|
4762
|
+
children: "微信桥"
|
|
4763
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WeixinBridgeEditor, {})]
|
|
4349
4764
|
})
|
|
4350
4765
|
]
|
|
4351
4766
|
});
|