@shgroup/dsh-serenity-hooks 1.69.0 → 1.69.2
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/README.md +7 -4
- package/dsh.plugin.json +1 -1
- package/lib/{ccc-roots-RMzGU-CJ.js → ccc-roots-RzasspMr.js} +1 -1
- package/lib/ccc.d.ts +0 -63
- package/lib/client.js +4 -338
- package/lib/index.d.ts +0 -28
- package/lib/index.js +42 -1239
- package/lib/{message-source-Catc7q1z.js → message-source-DWWECjGB.js} +1 -1
- package/lib/ports.d.ts +3 -5
- package/lib/{settings-section-B1YzjFz6.js → settings-section-0TPYWug9.js} +3 -29
- package/lib/settings-section.d.ts +0 -22
- package/lib/{skiff-role-Boc4SKct.js → skiff-role-cwxAt0gE.js} +29 -16
- package/lib/skiff-role.d.ts +18 -3
- package/lib/weixin-route-D_DvgPqy.js +558 -0
- package/package.json +1 -1
- package/lib/acp-auth.d.ts +0 -273
- package/lib/acp-face.d.ts +0 -244
- package/lib/localstore-ops-ylQoPz1Q.js +0 -282
- package/lib/weixin-route-BoSC-uPp.js +0 -281
package/README.md
CHANGED
|
@@ -275,7 +275,8 @@ my-workspace/ ← 工作区根目录(放一个 .serenity
|
|
|
275
275
|
|
|
276
276
|
### 6.4 对外接入(官方 ACP)
|
|
277
277
|
|
|
278
|
-
|
|
278
|
+
**本插件不提供 ACP 面** —— 既不提供当年那种自造 HTTP 面,也不提供跑在 `dsh web` 进程内的
|
|
279
|
+
那一版(后者已在 v1.69.1 整面删除)。要程序化或远程使用,用宿主自带的官方 ACP server:
|
|
279
280
|
|
|
280
281
|
| 步 | 做什么 |
|
|
281
282
|
|---|---|
|
|
@@ -283,8 +284,10 @@ my-workspace/ ← 工作区根目录(放一个 .serenity
|
|
|
283
284
|
| 2 | 用任一 ACP 客户端连它(编辑器内直接起子进程;手机/远程经桥 + 隧道) |
|
|
284
285
|
| 3 | **认证放在接入层**(隧道 / 反代 / Cloudflare Access)——官方 server 自身不做认证 |
|
|
285
286
|
|
|
286
|
-
>
|
|
287
|
-
>
|
|
287
|
+
> **为什么不自造**:原 3100 面是一个**没有客户端生态**的私有外壳,而官方件已发布并随宿主同版本演进。
|
|
288
|
+
> **为什么连进程内那版也删掉**:`dsh-acp` 没有 `session/load`,且 `session/resume` 不回放历史
|
|
289
|
+
> ⇒ 客户端每次连上只能新建会话、看不到既有对话。对一个以「长期认知轨迹」为核心的系统,
|
|
290
|
+
> 那是结构性障碍,不是体验问题。⇒ 详见 CHANGELOG 的 v1.69.1。
|
|
288
291
|
|
|
289
292
|
### 6.5 认知轨迹与定时唤醒(cognitive trajectory)
|
|
290
293
|
|
|
@@ -345,7 +348,7 @@ my-workspace/ ← 工作区根目录(放一个 .serenity
|
|
|
345
348
|
|
|
346
349
|
| 层 | 位置 | 放什么 |
|
|
347
350
|
|---|---|---|
|
|
348
|
-
| DSH 原生设置 | DSH 的 settings.yaml(即设置面板那几项) | 开关与阈值:网关总开关、重建阈值、子角色开关与调试端口、**CRO 总闸(`croEnabled
|
|
351
|
+
| DSH 原生设置 | DSH 的 settings.yaml(即设置面板那几项) | 开关与阈值:网关总开关、重建阈值、子角色开关与调试端口、**CRO 总闸(`croEnabled`,默认为开)**、**图工具总闸(默认关)** |
|
|
349
352
|
| 插件全局文件 | `~/.dsh/serenity-hooks.json`(权限 0600) | 网关账号(scrypt + TOTP)、监听地址与端口、工作区白名单、cookie 安全开关 |
|
|
350
353
|
| 工作区配置 | `.opencode/serenity.json` | 助手模型白名单、日志阈值、安全模式黑名单、子角色、**认知轨迹级 skill 供给(`cognitiveTrajectory.skills`)**、微信(账号/路由/开关) |
|
|
351
354
|
| 工作区凭据 | `localstore.json` | 密钥与本地偏好;微信机器人 token 也在这一层 |
|
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-serenity-hooks",
|
|
3
|
-
"version": "1.69.
|
|
3
|
+
"version": "1.69.2",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"description": "宁静号 ACC harness(Native Cordis 插件):给 DSH 装一个「AI 工作区」——14 个工具(container_fs/cognitive_trajectory/dashboard/container_git/msm/praxis/ontology/serenity-skill-creator/cheap-worker/localstore/container_admin;另三个 im-bridge/acc-diag/diagram 按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 认知轨迹日志与原地重建 + 网页登录入口/微信桥/子角色/官方 ACP 面/认知轨迹唤醒注册表。适配 DSH 0.1.7-rc.1 / 0.2.0-rc.1 / 0.2.1-rc.1(三档,deepseek-ai/deepseek-harness)。",
|
|
6
6
|
"engines": {
|
|
@@ -227,7 +227,7 @@ async function listCccs(ctx, opts = {}) {
|
|
|
227
227
|
if (typeof defaultRoot === "string" && defaultRoot !== "" && !c.roots.includes(defaultRoot)) c.roots.unshift(defaultRoot);
|
|
228
228
|
let rolesOf = null;
|
|
229
229
|
if (opts.withRoles === true) {
|
|
230
|
-
const { readSkiffRoles } = await import("./skiff-role-
|
|
230
|
+
const { readSkiffRoles } = await import("./skiff-role-cwxAt0gE.js").then((n) => n.d);
|
|
231
231
|
rolesOf = (root) => [...readSkiffRoles(root).keys()];
|
|
232
232
|
}
|
|
233
233
|
return c.roots.map((root) => ({
|
package/lib/ccc.d.ts
CHANGED
|
@@ -131,16 +131,6 @@ interface SerenityConfig {
|
|
|
131
131
|
* 未配置或 enabled=false → 该 CCC 桥完全不启动(零资源占用)。
|
|
132
132
|
*/
|
|
133
133
|
weixin?: WeixinSettings;
|
|
134
|
-
/**
|
|
135
|
-
* IM 通道选择(v1.59.0,owner 2026-10-17 令):
|
|
136
|
-
* 「将微信桥升级为 IM 桥,每个 CCC 可以选择微信实现或 ACP 实现,微信实现保留不变向前兼容,
|
|
137
|
-
* ACP 实现就可以暴露端口并绑定 skiff,并且要随即生成认证用的 token」。
|
|
138
|
-
*
|
|
139
|
-
* 🔴 **缺省 = weixin**(未配置的 CCC 行为与今天**逐字相同**)⇒ 向前兼容由**缺省值**保证,
|
|
140
|
-
* 不靠代码分支。选 `acp` 时该 CCC 的入站改走 ACP 面(面 E,端口 3200);
|
|
141
|
-
* 其 `weixin.*` 段**保留**(向前兼容),但**不再驱动入站**;出站 `im-bridge` 不受影响。
|
|
142
|
-
*/
|
|
143
|
-
im?: ImSettings;
|
|
144
134
|
/**
|
|
145
135
|
* 专属工具声明(v1.33,S142 §32.11):**ACC 注册但默认对所有 CCC 隐藏**的工具,
|
|
146
136
|
* 只有在自己这里声明的 CCC 可见(例:`["acc-diag"]` = ACC 负责人的运行态诊断)。
|
|
@@ -214,59 +204,6 @@ export interface WeixinSettings {
|
|
|
214
204
|
*/
|
|
215
205
|
fallbackOnNoSend?: boolean;
|
|
216
206
|
}
|
|
217
|
-
/**
|
|
218
|
-
* IM 通道选择(CCC 级;v1.59.0,owner 2026-10-17 令)。
|
|
219
|
-
*
|
|
220
|
-
* 归属判据(D23「改它要不要发版」):**选哪个通道、绑哪个角色 = CCC 的数据** ⇒ 归此处;
|
|
221
|
-
* **怎么校验 token、怎么把 ACP 会话套上角色 = 机制** ⇒ 归 ACC 源码。
|
|
222
|
-
*/
|
|
223
|
-
export interface ImSettings {
|
|
224
|
-
/**
|
|
225
|
-
* 入站通道选择。`"weixin"`(**缺省**,=现状)| `"acp"`。
|
|
226
|
-
*
|
|
227
|
-
* 🔴 **缺省值即向前兼容**:不写这一项(或整个 `im` 段不存在)的 CCC,行为与升级前逐字相同。
|
|
228
|
-
* ⚠️ **只影响入站**(谁来驱动本 CCC 的 agent);**出站**(`im-bridge` 工具发送)不受本项影响。
|
|
229
|
-
*/
|
|
230
|
-
channel?: 'weixin' | 'acp';
|
|
231
|
-
/** ACP 通道参数(仅 `channel: "acp"` 时有意义) */
|
|
232
|
-
acp?: ImAcpSettings;
|
|
233
|
-
}
|
|
234
|
-
/** ACP 通道参数(CCC 级) */
|
|
235
|
-
export interface ImAcpSettings {
|
|
236
|
-
/**
|
|
237
|
-
* 该 CCC 的 ACP 面开关(**与 `channel: "acp"` 是「与」关系**:两者都真才算启用)。
|
|
238
|
-
* 缺省 false。
|
|
239
|
-
*/
|
|
240
|
-
enabled?: boolean;
|
|
241
|
-
/**
|
|
242
|
-
* **账户声明 —— 必填**(v1.59.1,owner 2026-10-17 令「token 生成和 skiff 绑定都做配置上」)。
|
|
243
|
-
*
|
|
244
|
-
* 🔴 **声明式,照 `weixin.accounts[]` 的形态**:结构(账户与角色)放本文件,
|
|
245
|
-
* 凭据(token)由 `accountId` 派生键 `IM_ACP_TOKEN_<ACCOUNT_ID>` 落 localstore。
|
|
246
|
-
*
|
|
247
|
-
* 判据(关键):**配置是真相源,localstore 只是它的派生凭据**。
|
|
248
|
-
* 声明了账户却还没有 token ⇒ **下次判定前当场生成**(不依赖启动那一次)。
|
|
249
|
-
* 撤销账户 ⇒ 该账户的 token **不再被接受**(即使 localstore 里还留着,也只是死键)。
|
|
250
|
-
*
|
|
251
|
-
* ⚠️ **没有简写退回**:不写本项 ⇒ **一个账户都没有 ⇒ 谁都认证不了**。
|
|
252
|
-
* 刻意如此 —— 多一条永不生效的简写分支,只会把"配置写错了"伪装成"用了简写"。
|
|
253
|
-
*/
|
|
254
|
-
accounts?: ImAcpAccount[];
|
|
255
|
-
}
|
|
256
|
-
/** ACP 账户声明(一台客户端一条;形状对齐 `weixin.accounts[]`) */
|
|
257
|
-
export interface ImAcpAccount {
|
|
258
|
-
/**
|
|
259
|
-
* 本地唯一键(如 `agmente-phone`;凭据键 `IM_ACP_TOKEN_<ACCOUNT_ID>`)。
|
|
260
|
-
* ⚠️ 归一为 **UPPER_SNAKE**(`agmente-phone` → `AGMENTE_PHONE`),与微信桥同规则。
|
|
261
|
-
*/
|
|
262
|
-
accountId: string;
|
|
263
|
-
/** 该账户绑定的 skiff 角色名(**必须 ∈ `skiff.roles`**;缺省 = 拒绝该账户) */
|
|
264
|
-
role?: string;
|
|
265
|
-
/** 该账户开关(缺省 true)——撤一台设备用它,不必删条目 */
|
|
266
|
-
enabled?: boolean;
|
|
267
|
-
/** 展示名(可选,仅用于诊断面) */
|
|
268
|
-
name?: string;
|
|
269
|
-
}
|
|
270
207
|
/** 微信桥账号配置(serenity.json 内;凭据部分在 localstore) */
|
|
271
208
|
export interface WeixinAccountConfig {
|
|
272
209
|
/** 本地唯一键(如 wechat-1;localstore 凭据键 weixin.accounts.<accountId>.*) */
|
package/lib/client.js
CHANGED
|
@@ -3593,321 +3593,6 @@ window.__ModuleLoader__.load({
|
|
|
3593
3593
|
});
|
|
3594
3594
|
}
|
|
3595
3595
|
//#endregion
|
|
3596
|
-
//#region src/client/AcpAccountsEditor.tsx
|
|
3597
|
-
/**
|
|
3598
|
-
* AcpAccountsEditor.tsx — 「ACP 账户台账」配置区块(v1.59.1,owner 2026-10-17 令)
|
|
3599
|
-
*
|
|
3600
|
-
* ## 为什么要有它
|
|
3601
|
-
* owner 原话:「**面板里只放个开关不放具体的条目吗?**」
|
|
3602
|
-
* 面 E 那个总开关只管"端口开不开",而**谁能连进来**在 CCC 的 `im.acp.accounts[]` 里。
|
|
3603
|
-
* 没有本区块时,加一台设备=找人改 JSON + 找 token —— 两件都不该由 owner 操心。
|
|
3604
|
-
*
|
|
3605
|
-
* ## 形状(照 `WeixinBridgeEditor`,不发明新范式)
|
|
3606
|
-
* - 顶部 **CCC 选择器**(数据源 `/serenity/cccs`)—— ACP 账户是 **CCC 级**数据,
|
|
3607
|
-
* 必须显式选目标,不靠"当前活跃会话"(面板是全局的,猜错就是改到别人家)
|
|
3608
|
-
* - 选中后:该 CCC 的通道状态 + 账户表(可用性 / 角色 / token 指纹)
|
|
3609
|
-
* - 每条可:改(角色/开关)/删 /**轮换 token**(唯一会让在用客户端断线的那一下)
|
|
3610
|
-
* - 新增:填 accountId + 角色 + 名字 ⇒ **保存即生成 token**,当场显示一次供抄走
|
|
3611
|
-
*
|
|
3612
|
-
* ## 🔴 两条安全纪律(写在这里,因为 UI 最容易违反)
|
|
3613
|
-
* ① **token 明文只在"刚生成"与"刚轮换"两处出现** —— 其余一律只显示指纹
|
|
3614
|
-
* (服务端 `acpChannelStatus` 本来就不回明文;这里的 state 也只是短暂持有)
|
|
3615
|
-
* ② **删账户会同时删掉它的 token**(服务端做),所以删除是不可逆的:UI 必须二次确认
|
|
3616
|
-
*/
|
|
3617
|
-
const emptyDraft = () => ({
|
|
3618
|
-
accountId: "",
|
|
3619
|
-
role: "",
|
|
3620
|
-
name: ""
|
|
3621
|
-
});
|
|
3622
|
-
function AcpAccountsEditor() {
|
|
3623
|
-
const [cccs, setCccs] = (0, react.useState)([]);
|
|
3624
|
-
const [selectedRoot, setSelectedRoot] = (0, react.useState)("");
|
|
3625
|
-
const [status, setStatus] = (0, react.useState)(null);
|
|
3626
|
-
const [loadError, setLoadError] = (0, react.useState)(null);
|
|
3627
|
-
const [draft, setDraft] = (0, react.useState)(emptyDraft());
|
|
3628
|
-
const [busy, setBusy] = (0, react.useState)(false);
|
|
3629
|
-
const [error, setError] = (0, react.useState)(null);
|
|
3630
|
-
/** 刚生成 / 刚轮换出来的明文 token(**只在这两种时机出现**;刷新即消失) */
|
|
3631
|
-
const [freshToken, setFreshToken] = (0, react.useState)(null);
|
|
3632
|
-
/** 待确认删除的 accountId(二次确认;删会连带删 token,不可逆) */
|
|
3633
|
-
const [confirmRemove, setConfirmRemove] = (0, react.useState)(null);
|
|
3634
|
-
(0, react.useEffect)(() => {
|
|
3635
|
-
let alive = true;
|
|
3636
|
-
(async () => {
|
|
3637
|
-
try {
|
|
3638
|
-
const res = await fetch("/serenity/cccs", { headers: { accept: "application/json" } });
|
|
3639
|
-
if (!res.ok) return;
|
|
3640
|
-
const body = await res.json();
|
|
3641
|
-
if (!alive || !Array.isArray(body.cccs)) return;
|
|
3642
|
-
setCccs(body.cccs);
|
|
3643
|
-
if (body.cccs.length > 0) setSelectedRoot((prev) => prev || body.cccs[0].root);
|
|
3644
|
-
} catch {}
|
|
3645
|
-
})();
|
|
3646
|
-
return () => {
|
|
3647
|
-
alive = false;
|
|
3648
|
-
};
|
|
3649
|
-
}, []);
|
|
3650
|
-
/** 读一次该 CCC 的 ACP 台账(供初次加载与每次写操作后刷新) */
|
|
3651
|
-
const reload = async (root) => {
|
|
3652
|
-
setLoadError(null);
|
|
3653
|
-
try {
|
|
3654
|
-
const res = await fetch(`/serenity/acp?ccc=${encodeURIComponent(root)}`, { headers: {
|
|
3655
|
-
accept: "application/json",
|
|
3656
|
-
"x-serenity-ui": "1"
|
|
3657
|
-
} });
|
|
3658
|
-
if (!res.ok) {
|
|
3659
|
-
const body = await res.json().catch(() => null);
|
|
3660
|
-
setLoadError(body?.error ?? `HTTP ${res.status}`);
|
|
3661
|
-
return;
|
|
3662
|
-
}
|
|
3663
|
-
setStatus(await res.json());
|
|
3664
|
-
} catch {}
|
|
3665
|
-
};
|
|
3666
|
-
(0, react.useEffect)(() => {
|
|
3667
|
-
if (!selectedRoot) return;
|
|
3668
|
-
let alive = true;
|
|
3669
|
-
setStatus(null);
|
|
3670
|
-
(async () => {
|
|
3671
|
-
if (alive) await reload(selectedRoot);
|
|
3672
|
-
})();
|
|
3673
|
-
return () => {
|
|
3674
|
-
alive = false;
|
|
3675
|
-
};
|
|
3676
|
-
}, [selectedRoot]);
|
|
3677
|
-
/** 发一条写动作(三个 action 共用一条通道) */
|
|
3678
|
-
const post = async (payload) => {
|
|
3679
|
-
setBusy(true);
|
|
3680
|
-
setError(null);
|
|
3681
|
-
try {
|
|
3682
|
-
const res = await fetch("/serenity/acp", {
|
|
3683
|
-
method: "POST",
|
|
3684
|
-
headers: {
|
|
3685
|
-
"content-type": "application/json",
|
|
3686
|
-
"x-serenity-ui": "1"
|
|
3687
|
-
},
|
|
3688
|
-
body: JSON.stringify({
|
|
3689
|
-
ccc: selectedRoot,
|
|
3690
|
-
...payload
|
|
3691
|
-
})
|
|
3692
|
-
});
|
|
3693
|
-
const body = await res.json().catch(() => null);
|
|
3694
|
-
if (!res.ok) {
|
|
3695
|
-
setError(typeof body?.error === "string" ? body.error : `HTTP ${res.status}`);
|
|
3696
|
-
return null;
|
|
3697
|
-
}
|
|
3698
|
-
await reload(selectedRoot);
|
|
3699
|
-
return body;
|
|
3700
|
-
} catch (err) {
|
|
3701
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
3702
|
-
return null;
|
|
3703
|
-
} finally {
|
|
3704
|
-
setBusy(false);
|
|
3705
|
-
}
|
|
3706
|
-
};
|
|
3707
|
-
const addAccount = async () => {
|
|
3708
|
-
const accountId = draft.accountId.trim();
|
|
3709
|
-
if (accountId === "") {
|
|
3710
|
-
setError("账户 ID 必填(它同时是 token 的键名,如 agmente-phone)");
|
|
3711
|
-
return;
|
|
3712
|
-
}
|
|
3713
|
-
if (draft.role.trim() === "") {
|
|
3714
|
-
setError("角色必填(必须是本 CCC 已有的 skiff 角色)");
|
|
3715
|
-
return;
|
|
3716
|
-
}
|
|
3717
|
-
const body = await post({
|
|
3718
|
-
action: "upsert",
|
|
3719
|
-
account: {
|
|
3720
|
-
accountId,
|
|
3721
|
-
role: draft.role.trim(),
|
|
3722
|
-
name: draft.name.trim() || void 0
|
|
3723
|
-
}
|
|
3724
|
-
});
|
|
3725
|
-
if (body) {
|
|
3726
|
-
if (typeof body.token === "string" && body.token !== "") setFreshToken({
|
|
3727
|
-
accountId,
|
|
3728
|
-
token: body.token
|
|
3729
|
-
});
|
|
3730
|
-
setDraft(emptyDraft());
|
|
3731
|
-
}
|
|
3732
|
-
};
|
|
3733
|
-
const rotate = async (accountId) => {
|
|
3734
|
-
const body = await post({
|
|
3735
|
-
action: "rotate",
|
|
3736
|
-
accountId
|
|
3737
|
-
});
|
|
3738
|
-
if (body && typeof body.token === "string") setFreshToken({
|
|
3739
|
-
accountId,
|
|
3740
|
-
token: body.token
|
|
3741
|
-
});
|
|
3742
|
-
};
|
|
3743
|
-
const remove = async (accountId) => {
|
|
3744
|
-
await post({
|
|
3745
|
-
action: "remove",
|
|
3746
|
-
accountId
|
|
3747
|
-
});
|
|
3748
|
-
setConfirmRemove(null);
|
|
3749
|
-
};
|
|
3750
|
-
/** 该 CCC 已有的角色(新增账户时作为候选;避免手打出静默失败的角色名) */
|
|
3751
|
-
const rolesForSelected = cccs.find((c) => c.root === selectedRoot)?.roles ?? [];
|
|
3752
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3753
|
-
className: "ss-detailStack",
|
|
3754
|
-
children: [
|
|
3755
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3756
|
-
className: "ss-detailIntro",
|
|
3757
|
-
children: "ACP 账户台账(每台客户端一条:一枚 token ↔ 一个角色)\n· 连接归属哪个 CCC 由 token 决定(服务端权威),不看客户端填什么\n· 加一台设备 = 这里加一条 ⇒ token 随即生成,保存后当场显示一次,抄进客户端即可\n· 客户端地址:ws://<本机IP>:3200 + Authorization: Bearer <token>(或用 ?token=<token>);working directory 可以只填目录名 —— ACC 会按 token 归属自动归到该 CCC 根\n· 「轮换」会让在用的那台立刻断线 ⇒ 只在怀疑泄露时按;「删除」连带删 token,不可逆"
|
|
3758
|
-
}),
|
|
3759
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3760
|
-
className: "ss-switchRow",
|
|
3761
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3762
|
-
className: "ss-fieldLabel",
|
|
3763
|
-
children: "目标 CCC"
|
|
3764
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
3765
|
-
className: "ss-select",
|
|
3766
|
-
value: selectedRoot,
|
|
3767
|
-
onChange: (e) => setSelectedRoot(e.target.value),
|
|
3768
|
-
children: [cccs.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3769
|
-
value: "",
|
|
3770
|
-
children: "(未发现 CCC)"
|
|
3771
|
-
}), cccs.map((c) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3772
|
-
value: c.root,
|
|
3773
|
-
children: c.name
|
|
3774
|
-
}, c.root))]
|
|
3775
|
-
})]
|
|
3776
|
-
}),
|
|
3777
|
-
loadError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3778
|
-
className: "ss-error",
|
|
3779
|
-
children: `读取失败:${loadError}`
|
|
3780
|
-
}),
|
|
3781
|
-
status && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3782
|
-
className: "ss-detailIntro",
|
|
3783
|
-
children: `通道:${status.channel}${status.channel === "acp" ? "" : "(未选 ACP ⇒ 账户不生效)"} / 面开关:${status.enabled ? "开" : "关"}\n可用账户:${status.accounts.filter((a) => a.usable).length} / ${status.accounts.length}
|
|
3784
|
-
每个可用账户在客户端里只看到自己那一条对话(第一次发消息时建立,之后一直用它)。`
|
|
3785
|
-
}),
|
|
3786
|
-
status && status.accounts.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3787
|
-
className: "ss-tableWrap",
|
|
3788
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("table", {
|
|
3789
|
-
className: "ss-table",
|
|
3790
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
|
|
3791
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: "账户" }),
|
|
3792
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: "角色" }),
|
|
3793
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: "状态" }),
|
|
3794
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: "对话" }),
|
|
3795
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: "token" }),
|
|
3796
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {})
|
|
3797
|
-
] }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tbody", { children: status.accounts.map((a) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
|
|
3798
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("td", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", { children: a.accountId }), a.name ? ` · ${a.name}` : ""] }),
|
|
3799
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: a.role ?? "—" }),
|
|
3800
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: a.usable ? "✅ 可用" : `⚠️ ${a.blockedBy ?? "不可用"}` }),
|
|
3801
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
|
|
3802
|
-
title: a.mainSession ?? void 0,
|
|
3803
|
-
children: a.mainSession ? `…${a.mainSession.slice(-8)}` : "(还没建,客户端发第一条消息时建立)"
|
|
3804
|
-
}),
|
|
3805
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: a.hasToken ? `…${a.tokenFingerprint ?? ""}` : "(无)" }),
|
|
3806
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("td", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3807
|
-
type: "button",
|
|
3808
|
-
disabled: busy,
|
|
3809
|
-
onClick: () => void rotate(a.accountId),
|
|
3810
|
-
children: "轮换"
|
|
3811
|
-
}), confirmRemove === a.accountId ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3812
|
-
type: "button",
|
|
3813
|
-
disabled: busy,
|
|
3814
|
-
onClick: () => void remove(a.accountId),
|
|
3815
|
-
children: "确认删除"
|
|
3816
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3817
|
-
type: "button",
|
|
3818
|
-
onClick: () => setConfirmRemove(null),
|
|
3819
|
-
children: "取消"
|
|
3820
|
-
})] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3821
|
-
type: "button",
|
|
3822
|
-
disabled: busy,
|
|
3823
|
-
onClick: () => setConfirmRemove(a.accountId),
|
|
3824
|
-
children: "删除"
|
|
3825
|
-
})] })
|
|
3826
|
-
] }, a.accountId)) })]
|
|
3827
|
-
})
|
|
3828
|
-
}),
|
|
3829
|
-
status && status.accounts.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3830
|
-
className: "ss-detailIntro",
|
|
3831
|
-
children: "该 CCC 还没有声明任何 ACP 账户 ⇒ 客户端一律连不上(fail-closed)。在下面加一条。"
|
|
3832
|
-
}),
|
|
3833
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3834
|
-
className: "ss-switchRow ss-switchRowWrap",
|
|
3835
|
-
children: [
|
|
3836
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3837
|
-
className: "ss-fieldLabel",
|
|
3838
|
-
children: "新增账户"
|
|
3839
|
-
}),
|
|
3840
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3841
|
-
className: "ss-textInput",
|
|
3842
|
-
placeholder: "账户 ID(如 agmente-phone)",
|
|
3843
|
-
value: draft.accountId,
|
|
3844
|
-
onChange: (e) => setDraft({
|
|
3845
|
-
...draft,
|
|
3846
|
-
accountId: e.target.value
|
|
3847
|
-
})
|
|
3848
|
-
}),
|
|
3849
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3850
|
-
className: "ss-textInput",
|
|
3851
|
-
placeholder: "角色(必须是本 CCC 已有的)",
|
|
3852
|
-
value: draft.role,
|
|
3853
|
-
onChange: (e) => setDraft({
|
|
3854
|
-
...draft,
|
|
3855
|
-
role: e.target.value
|
|
3856
|
-
}),
|
|
3857
|
-
list: `acp-roles-${selectedRoot}`
|
|
3858
|
-
}),
|
|
3859
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("datalist", {
|
|
3860
|
-
id: `acp-roles-${selectedRoot}`,
|
|
3861
|
-
children: rolesForSelected.map((r) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", { value: r }, r))
|
|
3862
|
-
}),
|
|
3863
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3864
|
-
className: "ss-textInput",
|
|
3865
|
-
placeholder: "显示名(可选)",
|
|
3866
|
-
value: draft.name,
|
|
3867
|
-
onChange: (e) => setDraft({
|
|
3868
|
-
...draft,
|
|
3869
|
-
name: e.target.value
|
|
3870
|
-
})
|
|
3871
|
-
}),
|
|
3872
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3873
|
-
type: "button",
|
|
3874
|
-
className: "ss-wakeBtn",
|
|
3875
|
-
disabled: busy || !selectedRoot,
|
|
3876
|
-
onClick: () => void addAccount(),
|
|
3877
|
-
children: "保存并生成 token"
|
|
3878
|
-
})
|
|
3879
|
-
]
|
|
3880
|
-
}),
|
|
3881
|
-
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3882
|
-
className: "ss-error",
|
|
3883
|
-
children: `⚠️ ${error}`
|
|
3884
|
-
}),
|
|
3885
|
-
freshToken && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3886
|
-
className: "ss-detailStack",
|
|
3887
|
-
children: [
|
|
3888
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3889
|
-
className: "ss-detailIntro",
|
|
3890
|
-
children: `🔑 ${freshToken.accountId} 的 token(只显示这一次,复制进客户端)\n记得随客户端配置一起保存。`
|
|
3891
|
-
}),
|
|
3892
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
3893
|
-
className: "ss-tokenBox",
|
|
3894
|
-
children: freshToken.token
|
|
3895
|
-
}),
|
|
3896
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3897
|
-
className: "ss-switchRow",
|
|
3898
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3899
|
-
type: "button",
|
|
3900
|
-
className: "ss-wakeBtn",
|
|
3901
|
-
onClick: () => setFreshToken(null),
|
|
3902
|
-
children: "我已抄走,隐藏"
|
|
3903
|
-
})
|
|
3904
|
-
})
|
|
3905
|
-
]
|
|
3906
|
-
})
|
|
3907
|
-
]
|
|
3908
|
-
});
|
|
3909
|
-
}
|
|
3910
|
-
//#endregion
|
|
3911
3596
|
//#region \0sp-css:src/client/PersonaEditor
|
|
3912
3597
|
const css$3 = "/* PersonaEditor.css — 彩蛋模式区块(v1.23.1,官方 settings 设计语言:rowCard 内分组)\n * token 合规(v1.27.14 修复):全部使用 design-platform.css 官方 --dsw-alias-* 词汇;\n * 弃用自造名(text-primary/accent/border/state-success 等)——未定义时深色 fallback\n * 在浅色主题下显示为黑框黑字(用户反馈白色主题通性问题)。 */\n\n.pe-wrap {\n display: flex;\n flex-direction: column;\n gap: 10px;\n width: 100%;\n padding: 2px 0 6px;\n}\n\n.pe-row {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.pe-label {\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n user-select: none;\n}\n\n.pe-input,\n.pe-textarea {\n width: 100%;\n box-sizing: border-box;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n font-size: 13px;\n padding: 8px 10px;\n outline: none;\n}\n\n.pe-input:focus,\n.pe-textarea:focus {\n border-color: var(--dsw-alias-button-ghost-active-border);\n}\n\n.pe-textarea {\n resize: vertical;\n min-height: 72px; /* v1.27.5 紧凑化:默认 4 行(原 120px 过高),可拖拽扩大 */\n line-height: 1.5;\n font-family: var(--ds-font-family-code);\n font-size: 12px;\n}\n\n.pe-actions {\n display: flex;\n gap: 8px;\n align-items: center;\n flex-wrap: wrap;\n}\n\n.pe-btn {\n border-radius: 6px;\n padding: 5px 12px;\n font-size: 12px;\n cursor: pointer;\n border: 1px solid var(--dsw-alias-border-l2);\n background: transparent;\n color: var(--dsw-alias-label-primary);\n transition: opacity 0.15s;\n}\n\n.pe-btn:hover:not(:disabled) {\n opacity: 0.85;\n}\n\n.pe-btn:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n.pe-btnGhost {\n border-color: var(--dsw-alias-border-l2);\n}\n\n.pe-btnPrimary {\n background: var(--dsw-alias-button-primary-fill);\n border-color: transparent;\n color: var(--dsw-alias-label-primary-foreground);\n}\n\n.pe-hint {\n font-size: 12px;\n margin: 0;\n}\n\n.pe-hintOk {\n color: var(--dsw-alias-state-success-primary);\n}\n\n.pe-hintErr {\n color: var(--dsw-alias-state-error-primary);\n}\n";
|
|
3913
3598
|
if (typeof document !== "undefined" && document.querySelector("style[data-sp-css=\"PersonaEditor\"]") === null) {
|
|
@@ -4562,7 +4247,7 @@ Instruction-following style:
|
|
|
4562
4247
|
}
|
|
4563
4248
|
//#endregion
|
|
4564
4249
|
//#region \0sp-css:src/client/SettingsSection
|
|
4565
|
-
const css$2 = "/* 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/* ── v1.29 需求②:可展开行(整行点击 → 行内详设)── */\n.ss-expandable {\n flex-wrap: wrap; /* detail 换行占满整行 */\n cursor: default;\n}\n.ss-expandable .ss-rowText {\n cursor: pointer;\n}\n.ss-expandable .ss-rowText:hover .ss-rowName {\n color: var(--dsw-alias-state-success-primary, #22c55e);\n}\n.ss-expanded {\n border-color: var(--dsw-alias-state-success-primary, #22c55e);\n}\n.ss-expandMark {\n display: inline-block;\n margin-left: 6px;\n font-size: 10px;\n color: var(--dsw-alias-label-tertiary);\n transition: transform 0.15s ease;\n}\n.ss-expanded .ss-expandMark {\n transform: rotate(90deg);\n}\n.ss-rowDetail {\n flex-basis: 100%;\n width: 100%;\n border-top: 1px solid var(--dsw-alias-border-l2);\n margin-top: 10px;\n padding-top: 12px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n min-width: 0;\n}\n.ss-detailStack {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n.ss-detailIntro {\n margin: 0;\n font-size: 12px;\n line-height: 19px;\n color: var(--dsw-alias-label-secondary);\n white-space: pre-line;\n word-break: break-word;\n overflow-wrap: anywhere;\n padding: 8px 10px;\n border-radius: 8px;\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.06));\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;v1.27.5 紧凑化:默认单行截断,hover title 看全文) */\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 display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\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-border-l3);\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-foreground);\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-brand-primary);\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/* 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-bg-layer-2);\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/* 自主轨迹「立即唤起」按钮(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-error {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-error-primary, #ef4444);\n background: rgba(239, 68, 68, 0.08);\n border-radius: 8px;\n padding: 8px 10px;\n white-space: pre-line;\n word-break: break-word;\n}\n\n/* ── v1.27.5 紧凑化:折叠组(details/summary)── */\n.ss-collapse {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n overflow: hidden;\n}\n\n.ss-collapseHead {\n display: flex;\n align-items: baseline;\n gap: 10px;\n padding: 10px 14px;\n cursor: pointer;\n list-style: none;\n user-select: none;\n}\n\n.ss-collapseHead::-webkit-details-marker {\n display: none;\n}\n\n.ss-collapseHead::before {\n content: '▸';\n flex: none;\n font-size: 11px;\n color: var(--dsw-alias-label-tertiary);\n transition: transform 0.15s ease;\n}\n\n.ss-collapse[open] > .ss-collapseHead::before {\n transform: rotate(90deg);\n}\n\n.ss-collapseHead:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(128, 128, 128, 0.06));\n}\n\n.ss-collapseTitle {\n font-size: 13px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n.ss-collapseDesc {\n font-size: 12px;\n color: var(--dsw-alias-label-tertiary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n}\n\n.ss-collapseBody {\n padding: 10px 14px 14px;\n border-top: 1px solid var(--dsw-alias-border-l1);\n}\n\n/* ── 开关 + 端口内联行 ── */\n.ss-switchRow {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n/* 同一行放不下时换行(ACP 新增账户那行有四个控件) */\n.ss-switchRowWrap {\n flex-wrap: wrap;\n}\n\n/* 行内字段名(与 .ss-rowName 同一语域,但不吃行高) */\n.ss-fieldLabel {\n flex: none;\n font-size: 12px;\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n}\n\n/* 行内文本输入(与 .ss-portInput 同款外观,宽度随内容) */\n.ss-textInput {\n flex: 1 1 140px;\n min-width: 0;\n padding: 6px 8px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n.ss-textInput::placeholder {\n color: var(--dsw-alias-label-dimmed);\n}\n\n/* 明文 token 展示块(等宽、可整体选中、长串折行) */\n.ss-tokenBox {\n display: block;\n padding: 8px 10px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-family: var(--ds-font-family-code);\n font-size: 12px;\n line-height: 18px;\n word-break: break-all;\n user-select: all;\n}\n\n/* ── ACP 账户台账表(owner 2026-10-17:「面板里只放个开关不放具体的条目吗?」)\n *\n * 用表格而不是卡片列表:台账天生是「一行一条、列对齐可比」的数据\n * (账户 / 角色 / 状态 / token 指纹),卡片会把可比性拆散。\n * 🔴 横向滚动必须挂在外层容器上:给 `<table>` 本身加 `display:block` 会连带丢掉\n * `border-collapse`(表格边框塌陷失效),故表格保持 `display:table`,由 .ss-tableWrap 兜滚动。 */\n.ss-tableWrap {\n max-width: 100%;\n overflow-x: auto;\n}\n\n.ss-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 12px;\n}\n\n.ss-table th,\n.ss-table td {\n padding: 6px 10px;\n text-align: left;\n border-bottom: 1px solid var(--dsw-alias-border-l2);\n white-space: nowrap;\n vertical-align: middle;\n}\n\n.ss-table th {\n color: var(--dsw-alias-label-tertiary);\n font-weight: 600;\n}\n\n.ss-table td code {\n font-size: 11px;\n padding: 1px 4px;\n border-radius: 3px;\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.12));\n}\n\n.ss-table button {\n margin-left: 4px;\n}\n\n.ss-table button:first-child {\n margin-left: 0;\n}\n\n/* ── v1.27.6 「?」帮助浮层(hover/焦点显示三行以上严谨说明)── */\n.ss-help {\n position: relative;\n display: inline-flex;\n align-items: center;\n margin-top: 2px;\n}\n\n.ss-helpMark {\n flex: none;\n width: 16px;\n height: 16px;\n padding: 0;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 50%;\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.12));\n color: var(--dsw-alias-label-tertiary);\n font-size: 10px;\n line-height: 1;\n font-weight: 600;\n cursor: help;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n transition: border-color 0.15s ease, color 0.15s ease;\n}\n\n.ss-helpMark:hover,\n.ss-helpMark:focus-visible {\n border-color: var(--dsw-alias-state-success-primary, #22c55e);\n color: var(--dsw-alias-state-success-primary, #22c55e);\n outline: none;\n}\n\n.ss-helpTip {\n position: absolute;\n left: 0;\n top: calc(100% + 6px);\n z-index: 30;\n width: 300px;\n max-width: 60vw;\n padding: 10px 12px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 10px;\n background: var(--dsw-alias-bg-overlay);\n box-shadow: 0 6px 24px rgba(0, 0, 0, 0.28);\n font-size: 12px;\n line-height: 19px;\n font-weight: 400;\n color: var(--dsw-alias-label-primary);\n white-space: pre-line;\n word-break: break-word;\n opacity: 0;\n pointer-events: none;\n transform: translateY(-4px);\n transition: opacity 0.15s ease, transform 0.15s ease;\n}\n\n.ss-help:hover .ss-helpTip,\n.ss-helpMark:focus-visible + .ss-helpTip {\n opacity: 1;\n pointer-events: auto;\n transform: translateY(0);\n}\n\n/* 折叠组内帮助浮层定位修正(左侧行卡不会溢出面板) */\n.ss-rowCard .ss-helpTip {\n left: 0;\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-bg-layer-2);\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: center;\n}\n\n.ss-qrSvg {\n flex: none;\n width: 120px; /* v1.27.5 紧凑化:160 → 120 */\n height: 120px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: #fff; /* 二维码需要白底才能被微信扫出 */\n padding: 6px;\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-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n font-family: var(--ds-font-family-code);\n resize: vertical;\n}\n\n/* ── 窄屏(面板被塞进窄栏或手机浏览器)────────────────────────────────────\n * 排版问题只有一个根因:`.ss-rowCard` 是「左文本 + 右控件」的两列 flex,\n * 而控件里有端口输入(96px)/开关(40px)/端口+开关(150px)三档。\n * 窄到放不下时,flex 会先压文字(`min-width: 0` 已开)⇒ 标题被挤成一列竖排字。\n * 处理:窄屏把控件落到第二行(左对齐),文字保住整行宽。 */\n@media (max-width: 560px) {\n .ss-rowCard {\n flex-wrap: wrap;\n gap: 10px;\n }\n\n .ss-rowControl {\n flex-basis: 100%;\n justify-content: flex-start;\n }\n\n /* 行内说明在窄屏不必截断:整行宽足够,截断反而藏信息 */\n .ss-rowDesc {\n -webkit-line-clamp: unset;\n display: block;\n }\n\n /* 详情区与折叠头在窄屏收紧内边距(横向像素更值钱) */\n .ss-rowDetail,\n .ss-collapseBody {\n padding-left: 0;\n padding-right: 0;\n }\n\n .ss-switchRowWrap {\n gap: 6px;\n }\n\n .ss-textInput {\n flex-basis: 100%;\n }\n}\n";
|
|
4250
|
+
const css$2 = "/* 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/* ── v1.29 需求②:可展开行(整行点击 → 行内详设)── */\n.ss-expandable {\n flex-wrap: wrap; /* detail 换行占满整行 */\n cursor: default;\n}\n.ss-expandable .ss-rowText {\n cursor: pointer;\n}\n.ss-expandable .ss-rowText:hover .ss-rowName {\n color: var(--dsw-alias-state-success-primary, #22c55e);\n}\n.ss-expanded {\n border-color: var(--dsw-alias-state-success-primary, #22c55e);\n}\n.ss-expandMark {\n display: inline-block;\n margin-left: 6px;\n font-size: 10px;\n color: var(--dsw-alias-label-tertiary);\n transition: transform 0.15s ease;\n}\n.ss-expanded .ss-expandMark {\n transform: rotate(90deg);\n}\n.ss-rowDetail {\n flex-basis: 100%;\n width: 100%;\n border-top: 1px solid var(--dsw-alias-border-l2);\n margin-top: 10px;\n padding-top: 12px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n min-width: 0;\n}\n.ss-detailStack {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n.ss-detailIntro {\n margin: 0;\n font-size: 12px;\n line-height: 19px;\n color: var(--dsw-alias-label-secondary);\n white-space: pre-line;\n word-break: break-word;\n overflow-wrap: anywhere;\n padding: 8px 10px;\n border-radius: 8px;\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.06));\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;v1.27.5 紧凑化:默认单行截断,hover title 看全文) */\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 display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\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-border-l3);\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-foreground);\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-brand-primary);\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/* 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-bg-layer-2);\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/* 自主轨迹「立即唤起」按钮(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-error {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-error-primary, #ef4444);\n background: rgba(239, 68, 68, 0.08);\n border-radius: 8px;\n padding: 8px 10px;\n white-space: pre-line;\n word-break: break-word;\n}\n\n/* ── v1.27.5 紧凑化:折叠组(details/summary)── */\n.ss-collapse {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n overflow: hidden;\n}\n\n.ss-collapseHead {\n display: flex;\n align-items: baseline;\n gap: 10px;\n padding: 10px 14px;\n cursor: pointer;\n list-style: none;\n user-select: none;\n}\n\n.ss-collapseHead::-webkit-details-marker {\n display: none;\n}\n\n.ss-collapseHead::before {\n content: '▸';\n flex: none;\n font-size: 11px;\n color: var(--dsw-alias-label-tertiary);\n transition: transform 0.15s ease;\n}\n\n.ss-collapse[open] > .ss-collapseHead::before {\n transform: rotate(90deg);\n}\n\n.ss-collapseHead:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(128, 128, 128, 0.06));\n}\n\n.ss-collapseTitle {\n font-size: 13px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n.ss-collapseDesc {\n font-size: 12px;\n color: var(--dsw-alias-label-tertiary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n}\n\n.ss-collapseBody {\n padding: 10px 14px 14px;\n border-top: 1px solid var(--dsw-alias-border-l1);\n}\n\n/* ── 开关 + 端口内联行 ── */\n.ss-switchRow {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n/* ── v1.27.6 「?」帮助浮层(hover/焦点显示三行以上严谨说明)── */\n.ss-help {\n position: relative;\n display: inline-flex;\n align-items: center;\n margin-top: 2px;\n}\n\n.ss-helpMark {\n flex: none;\n width: 16px;\n height: 16px;\n padding: 0;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 50%;\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.12));\n color: var(--dsw-alias-label-tertiary);\n font-size: 10px;\n line-height: 1;\n font-weight: 600;\n cursor: help;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n transition: border-color 0.15s ease, color 0.15s ease;\n}\n\n.ss-helpMark:hover,\n.ss-helpMark:focus-visible {\n border-color: var(--dsw-alias-state-success-primary, #22c55e);\n color: var(--dsw-alias-state-success-primary, #22c55e);\n outline: none;\n}\n\n.ss-helpTip {\n position: absolute;\n left: 0;\n top: calc(100% + 6px);\n z-index: 30;\n width: 300px;\n max-width: 60vw;\n padding: 10px 12px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 10px;\n background: var(--dsw-alias-bg-overlay);\n box-shadow: 0 6px 24px rgba(0, 0, 0, 0.28);\n font-size: 12px;\n line-height: 19px;\n font-weight: 400;\n color: var(--dsw-alias-label-primary);\n white-space: pre-line;\n word-break: break-word;\n opacity: 0;\n pointer-events: none;\n transform: translateY(-4px);\n transition: opacity 0.15s ease, transform 0.15s ease;\n}\n\n.ss-help:hover .ss-helpTip,\n.ss-helpMark:focus-visible + .ss-helpTip {\n opacity: 1;\n pointer-events: auto;\n transform: translateY(0);\n}\n\n/* 折叠组内帮助浮层定位修正(左侧行卡不会溢出面板) */\n.ss-rowCard .ss-helpTip {\n left: 0;\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-bg-layer-2);\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: center;\n}\n\n.ss-qrSvg {\n flex: none;\n width: 120px; /* v1.27.5 紧凑化:160 → 120 */\n height: 120px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: #fff; /* 二维码需要白底才能被微信扫出 */\n padding: 6px;\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-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n font-family: var(--ds-font-family-code);\n resize: vertical;\n}\n\n/* ── 窄屏(面板被塞进窄栏或手机浏览器)────────────────────────────────────\n * 排版问题只有一个根因:`.ss-rowCard` 是「左文本 + 右控件」的两列 flex,\n * 而控件里有端口输入(96px)/开关(40px)/端口+开关(150px)三档。\n * 窄到放不下时,flex 会先压文字(`min-width: 0` 已开)⇒ 标题被挤成一列竖排字。\n * 处理:窄屏把控件落到第二行(左对齐),文字保住整行宽。 */\n@media (max-width: 560px) {\n .ss-rowCard {\n flex-wrap: wrap;\n gap: 10px;\n }\n\n .ss-rowControl {\n flex-basis: 100%;\n justify-content: flex-start;\n }\n\n /* 行内说明在窄屏不必截断:整行宽足够,截断反而藏信息 */\n .ss-rowDesc {\n -webkit-line-clamp: unset;\n display: block;\n }\n\n /* 详情区与折叠头在窄屏收紧内边距(横向像素更值钱) */\n .ss-rowDetail,\n .ss-collapseBody {\n padding-left: 0;\n padding-right: 0;\n }\n}\n";
|
|
4566
4251
|
if (typeof document !== "undefined" && document.querySelector("style[data-sp-css=\"SettingsSection\"]") === null) {
|
|
4567
4252
|
const tag = document.createElement("style");
|
|
4568
4253
|
tag.setAttribute("data-sp-css", "SettingsSection");
|
|
@@ -4706,13 +4391,11 @@ Instruction-following style:
|
|
|
4706
4391
|
const skiffPort = value?.skiffDebugPort ?? 3099;
|
|
4707
4392
|
const croOn = value?.croEnabled ?? true;
|
|
4708
4393
|
const diagramOn = value?.diagramEnabled ?? false;
|
|
4709
|
-
const acpFaceOn = value?.acpFaceEnabled ?? false;
|
|
4710
4394
|
const [openGateway, setOpenGateway] = (0, react.useState)(false);
|
|
4711
4395
|
const [openRebuild, setOpenRebuild] = (0, react.useState)(false);
|
|
4712
4396
|
const [openSkiff, setOpenSkiff] = (0, react.useState)(false);
|
|
4713
4397
|
const [openCro, setOpenCro] = (0, react.useState)(false);
|
|
4714
4398
|
const [openDiagram, setOpenDiagram] = (0, react.useState)(false);
|
|
4715
|
-
const [openAcpFace, setOpenAcpFace] = (0, react.useState)(false);
|
|
4716
4399
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4717
4400
|
className: "ss-section",
|
|
4718
4401
|
children: [
|
|
@@ -4823,26 +4506,9 @@ Instruction-following style:
|
|
|
4823
4506
|
})
|
|
4824
4507
|
}) })]
|
|
4825
4508
|
}),
|
|
4826
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
4509
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Group, {
|
|
4827
4510
|
title: "工具",
|
|
4828
|
-
children:
|
|
4829
|
-
title: "ACP 面(官方 ACP,默认 3200)",
|
|
4830
|
-
desc: "让标准 ACP 客户端(如 Agmente)连进本机;每账户一枚 token 把关(默认关)",
|
|
4831
|
-
expandable: true,
|
|
4832
|
-
open: openAcpFace,
|
|
4833
|
-
onToggle: setOpenAcpFace,
|
|
4834
|
-
control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Toggle, {
|
|
4835
|
-
checked: acpFaceOn,
|
|
4836
|
-
onChange: (on) => toggle("acpFaceEnabled", on)
|
|
4837
|
-
}),
|
|
4838
|
-
detail: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4839
|
-
className: "ss-detailStack",
|
|
4840
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4841
|
-
className: "ss-detailIntro",
|
|
4842
|
-
children: "把官方 @deepseek-ai/dsh-acp 挂进本进程,标准 ACP 客户端经 WebSocket 登入本机。\n· 与微信桥的关系:两者是入站通道的两个实现,每个 CCC 二选一(在 CCC 的 .opencode/serenity.json 里配 im.channel)。本开关只管端口开不开\n· 🔴 认证:本面绑 0.0.0.0,而 ACP 协议本身不做认证 ⇒ 由 ACC 在握手前用每账户一枚 token(localstore 键 IM_ACP_TOKEN_<账户ID>)把关;没配账户的 CCC 一律连不上\n· 账户在下面那张表里管(加设备/看指纹/轮换/删除),不必改 JSON 或手敲命令\n· ⚠️ 明文 ws:// ⇒ 局域网内可抓包;上公网必须走 wss + Cloudflare Access"
|
|
4843
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AcpAccountsEditor, {})]
|
|
4844
|
-
})
|
|
4845
|
-
}) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
|
|
4511
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
|
|
4846
4512
|
title: "图(diagram)",
|
|
4847
4513
|
desc: "agent 给一段标签式源码,进程内直接画出 PNG 并贴进对话(不借浏览器;默认关)",
|
|
4848
4514
|
expandable: true,
|
|
@@ -4859,7 +4525,7 @@ Instruction-following style:
|
|
|
4859
4525
|
children: "agent 给一段标签式源码(<diagram> 根 + <rect>/<arrow>/<text>/<color>/<legend>),由 ACC 在进程内画成图并贴进对话 —— 不启浏览器、不截图。\n· 产物:图进对话记录(可回看、可被后续轮次引用、可转微信);另落两份文件在 CCC 的 _tmp/diagram/(.svg 可读可改 / .png 是进对话的那份)\n· 自带体检:重叠块 / 标签溢出 / 悬空端点 / 线压字,四条只告警不拦图;写错的图元被跳过并逐条报错,其余照画\n· 字体随插件内置(约 3.8 MB),因为光栅化引擎看不见系统字体\n· 默认关;关着时工具根本不注册(模型看不到它,不占上下文)\n· 前提:当前模型路由要声明收图像输入。没声明时图照样画、照样落盘,回执里写明原因并给路径"
|
|
4860
4526
|
})
|
|
4861
4527
|
})
|
|
4862
|
-
}) })
|
|
4528
|
+
}) })
|
|
4863
4529
|
}),
|
|
4864
4530
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Collapse, {
|
|
4865
4531
|
title: "彩蛋模式",
|
package/lib/index.d.ts
CHANGED
|
@@ -172,16 +172,6 @@ export interface Config {
|
|
|
172
172
|
croEnabled?: Volatile<boolean | undefined>;
|
|
173
173
|
/** **diagram 工具总闸**(面板层;部署层同义键 = `diagram.enabled`;缺省关;D104) */
|
|
174
174
|
diagramEnabled?: Volatile<boolean | undefined>;
|
|
175
|
-
/**
|
|
176
|
-
* 🔴 **面 E:官方 ACP 总闸**(面板层;部署层同义键 = `acpFace.enabled`;**缺省关**;2026-10-16)。
|
|
177
|
-
*
|
|
178
|
-
* ⚠️ **键名刻意不叫 `acpEnabled`** —— 那是**旧面 E(3100 自造问答面)**的键,
|
|
179
|
-
* 已随 owner「砍掉外部问答」裁决退役、现被**静默忽略**。复用同名会让"当年那份旧配置"
|
|
180
|
-
* 在新面上复活(判据:**退役的是功能,名字仍须留作"无人读"**,否则退役不彻底)。
|
|
181
|
-
*/
|
|
182
|
-
acpFaceEnabled?: Volatile<boolean | undefined>;
|
|
183
|
-
/** 面 E 端口(面板层;部署层同义键 = `acpFace.port`;缺省 3200) */
|
|
184
|
-
acpFacePort?: Volatile<number | undefined>;
|
|
185
175
|
}
|
|
186
176
|
/** schemastery 的 schema 类型(别名只为可读;**名字取自全局命名空间**,见上方 TS2742 说明) */
|
|
187
177
|
type SchemaOf<S, T = S> = Schemastery<S, T>;
|
|
@@ -238,13 +228,6 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
|
238
228
|
}>>, Schemastery.ObjectT<NoInfer<{
|
|
239
229
|
enabled: z<boolean, boolean, "defined">;
|
|
240
230
|
}>>, "plain">;
|
|
241
|
-
acpFace: z<Schemastery.ObjectS<NoInfer<{
|
|
242
|
-
enabled: z<boolean, boolean, "defined">;
|
|
243
|
-
port: z<number, number, "defined">;
|
|
244
|
-
}>>, Schemastery.ObjectT<NoInfer<{
|
|
245
|
-
enabled: z<boolean, boolean, "defined">;
|
|
246
|
-
port: z<number, number, "defined">;
|
|
247
|
-
}>>, "plain">;
|
|
248
231
|
humanChannel: z<Schemastery.ObjectS<NoInfer<{
|
|
249
232
|
accounts: z<HumanChannelAccountConfig[], HumanChannelAccountConfig[], "defined">;
|
|
250
233
|
subscriptions: z<HumanChannelSubscriptionConfig[], HumanChannelSubscriptionConfig[], "defined">;
|
|
@@ -278,8 +261,6 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
|
278
261
|
skiffDebugPort: z<number, number, "volatile">;
|
|
279
262
|
croEnabled: z<boolean, boolean, "volatile">;
|
|
280
263
|
diagramEnabled: z<boolean, boolean, "volatile">;
|
|
281
|
-
acpFaceEnabled: z<boolean, boolean, "volatile">;
|
|
282
|
-
acpFacePort: z<number, number, "volatile">;
|
|
283
264
|
}>>, Schemastery.ObjectT<NoInfer<{
|
|
284
265
|
serenityConfigPaths: z<string[], string[], "defined">;
|
|
285
266
|
tools: z<boolean, boolean, "defined">;
|
|
@@ -329,13 +310,6 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
|
329
310
|
}>>, Schemastery.ObjectT<NoInfer<{
|
|
330
311
|
enabled: z<boolean, boolean, "defined">;
|
|
331
312
|
}>>, "plain">;
|
|
332
|
-
acpFace: z<Schemastery.ObjectS<NoInfer<{
|
|
333
|
-
enabled: z<boolean, boolean, "defined">;
|
|
334
|
-
port: z<number, number, "defined">;
|
|
335
|
-
}>>, Schemastery.ObjectT<NoInfer<{
|
|
336
|
-
enabled: z<boolean, boolean, "defined">;
|
|
337
|
-
port: z<number, number, "defined">;
|
|
338
|
-
}>>, "plain">;
|
|
339
313
|
humanChannel: z<Schemastery.ObjectS<NoInfer<{
|
|
340
314
|
accounts: z<HumanChannelAccountConfig[], HumanChannelAccountConfig[], "defined">;
|
|
341
315
|
subscriptions: z<HumanChannelSubscriptionConfig[], HumanChannelSubscriptionConfig[], "defined">;
|
|
@@ -369,8 +343,6 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
|
369
343
|
skiffDebugPort: z<number, number, "volatile">;
|
|
370
344
|
croEnabled: z<boolean, boolean, "volatile">;
|
|
371
345
|
diagramEnabled: z<boolean, boolean, "volatile">;
|
|
372
|
-
acpFaceEnabled: z<boolean, boolean, "volatile">;
|
|
373
|
-
acpFacePort: z<number, number, "volatile">;
|
|
374
346
|
}>>, "plain">;
|
|
375
347
|
export declare function apply(ctx: Context, config: Config): void;
|
|
376
348
|
export {};
|