@shgroup/dsh-serenity-hooks 1.72.0 → 1.74.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/README.md +12 -11
- package/dsh.plugin.json +2 -2
- package/lib/accounts-BHQbakUh.js +33 -0
- package/lib/{ccc-Dkoa2oW3.js → ccc-CyYJL4F2.js} +9 -9
- package/lib/{ccc-roots-jZYR2GVE.js → ccc-roots-B2t_aM8L.js} +5 -5
- package/lib/client.js +165 -58
- package/lib/{wake/cro.d.ts → cro/core.d.ts} +3 -3
- package/lib/{wake/cro-guide.d.ts → cro/guide.d.ts} +3 -3
- package/lib/{wake/cro-log.d.ts → cro/log.d.ts} +2 -2
- package/lib/{wake/cro-turns.d.ts → cro/turns.d.ts} +2 -2
- package/lib/guard/seam.d.ts +4 -4
- package/lib/host/effect.d.ts +1 -1
- package/lib/{ilink-DEpmE3yi.js → ilink-BMk2w2KY.js} +1 -1
- package/lib/im/bridge.d.ts +36 -65
- package/lib/im/endpoint.d.ts +3 -3
- package/lib/im/feishu-account.d.ts +92 -0
- package/lib/im/guard.d.ts +1 -1
- package/lib/im/hook.d.ts +1 -1
- package/lib/im/inbound-event.d.ts +162 -0
- package/lib/im/route.d.ts +38 -3
- package/lib/index.d.ts +5 -27
- package/lib/index.js +1089 -1208
- package/lib/kernel/ccc-roots.d.ts +4 -4
- package/lib/kernel/ccc.d.ts +19 -19
- package/lib/kernel/ports.d.ts +3 -5
- package/lib/lib-TxscFKeo.js +119355 -0
- package/lib/{message-source-kVoNK0C5.js → message-source-DCpoRHP3.js} +2 -2
- package/lib/patches/opencode-provider.d.ts +1 -1
- package/lib/{profile-DyMJ_bfr.js → profile-BVt84mbi.js} +68 -65
- package/lib/rolldown-runtime-B4iAMlE-.js +35 -0
- package/lib/{route-f7JlinIt.js → route-COOFLTpU.js} +61 -8
- package/lib/seams/guards.d.ts +14 -14
- package/lib/seams/keeper.d.ts +1 -1
- package/lib/seams/lifecycle.d.ts +2 -2
- package/lib/{settings-lt1i3OZv.js → settings-D8hlqxua.js} +49 -84
- package/lib/skills/resource-index.d.ts +1 -1
- package/lib/surface/faces.d.ts +1 -1
- package/lib/surface/http.d.ts +1 -1
- package/lib/surface/settings.d.ts +7 -13
- package/lib/surface/text.d.ts +72 -0
- package/lib/surface/usage.d.ts +2 -2
- package/lib/tools/config-docs.d.ts +53 -0
- package/lib/tools/container-admin.d.ts +19 -12
- package/lib/tools/msm/service.d.ts +7 -0
- package/lib/tools/trajectory-constraint-admin.d.ts +30 -0
- package/lib/{role/worker/idle.d.ts → trajectory/carrier.d.ts} +12 -2
- package/lib/trajectory/core.d.ts +1 -1
- package/lib/{role/worker → trajectory/delegate}/core.d.ts +7 -1
- package/lib/{role/worker → trajectory/delegate}/preset.d.ts +9 -2
- package/lib/trajectory/policy/profile.d.ts +122 -0
- package/lib/trajectory/policy/rules.d.ts +98 -0
- package/lib/{role/skiff/registry.d.ts → trajectory/policy/window.d.ts} +19 -13
- package/lib/trajectory/prompt.d.ts +12 -12
- package/lib/trajectory/rebuild.d.ts +2 -2
- package/lib/{role/skiff/core.d.ts → trajectory/session.d.ts} +58 -49
- package/package.json +3 -2
- package/lib/role/skiff/config.d.ts +0 -79
- package/lib/role/skiff/debug.d.ts +0 -88
- package/lib/role/skiff/profile.d.ts +0 -115
- package/lib/rolldown-runtime-8H4AJuhK.js +0 -14
- package/lib/tools/skiff-admin.d.ts +0 -30
package/README.md
CHANGED
|
@@ -80,7 +80,7 @@ dsh plugin --profile web add link:$(pwd)/hooks/dsh-serenity-hooks
|
|
|
80
80
|
| `serenity-skill-creator` | 增强型技能标准(serenity-skill)的创建器:`guide` 编写方法 / `create` 生成骨架(基础链路径由它算)/ `check` 结构检查(三态可分辨:已建模通过 · 普通技能 · 建模了但检查未执行)/ `review` 逐条合规问题清单 / `index` 预览**模型实际会看到**的参考件清单 / `status` 全容器一览 | 新建或改造技能、为技能建本体、需要确认"模型究竟能否看到指定参考件"时 |
|
|
81
81
|
| `cheap-worker` | 杂工:委派一个低成本模型的助手执行任务,取回其最终文本。一次调用一个串行子代理;`jobs` 可一次扇出多个并行(上限 10)。**不循环、不校验完成码、不写进度文件** | 大批量、重复性的工作(扫描数十个技能、逐用例回归) |
|
|
82
82
|
| `localstore` | 存储密钥与配置(凭据、偏好两个命名空间) | API key、密码集中放一处,不进 git |
|
|
83
|
-
| `container_admin` |
|
|
83
|
+
| `container_admin` | 机务舱:`config` 域(说明目录/按章详情 + 轨迹约束的 guide/validate/apply/list + 看当前配置)/`msm` 域(小工具注册表 + 手册) | 定义轨迹约束、注册新小工具、查配置怎么填时 |
|
|
84
84
|
| `im-bridge` | 向 IM 联系人发消息(目前为微信):发文本、发文件、查已配置联系人、查通道状态。每次成功发送自动写入工作区的消息记录 | 需要 AI 主动给家人/同事发消息时(见 §6.2)。**条件出现**:仅在工作区配置了微信桥时可见 |
|
|
85
85
|
| `acc-diag` | ACC 运行态诊断:一次调用输出全报告——当前活跃会话数、各自所属工作区、唤醒时钟的武装态与 tick 次数、唤醒登记表的每一条 | **ACC 维护者专用**。**条件出现**:默认对所有工作区隐藏,仅在工作区配置中点名(`exclusiveTools`)时出现 |
|
|
86
86
|
| `diagram` | 绘图:AI 给出一段**标签式源码**,插件**在进程内**将其绘制为 PNG 并**贴入对话**——不启动浏览器、不截图、正常路径不落文件。坐标 = 画布像素、y 向下;写错的图元逐条报错并跳过,其余照常绘制;自带四项检查(块重叠 / 标签溢出 / 悬空端点 / 线压字),**只告警不拦图** | 需要把关系图/示意图直接放进对话时。**条件出现**:实验性 demo,**默认关**(关闭时该工具**根本不注册**,AI 看不到它、不占上下文);开关在设置面板「工具」组,拨动即时生效。中英文与常用符号均可绘制,因字体随插件内置(约 5 MB) |
|
|
@@ -112,10 +112,11 @@ dsh plugin --profile web add link:$(pwd)/hooks/dsh-serenity-hooks
|
|
|
112
112
|
| DSH 主界面 | 3080 | 本机自用(插件不碰这个端口,也不起这个监听器) |
|
|
113
113
|
| **网页登录入口** | 3081 | 外部/手机访问完整界面:登录后反向代理到 3080,可配工作区白名单 |
|
|
114
114
|
| **微信主动发送入口** | 3082(只绑 127.0.0.1) | 工作区外的脚本/集成用它给微信发消息(公网不可达,所以不需要密钥)。工作区内的 AI 不走这个端口,直接使用 `im-bridge` 工具 |
|
|
115
|
-
| **受限轨迹调试页** | 3099(只绑 127.0.0.1) | 调试 skiff 时使用,可切换工作区、查看对话轨迹 |
|
|
116
115
|
| **微信桥** | 无需端口(出站长轮询) | 家人在微信里直接和 AI 说话 |
|
|
117
116
|
|
|
118
|
-
> 3081
|
|
117
|
+
> 3081 **默认关**(须自行开启);3082 **默认开**(微信桥启用时才有意义)。默认只监听 127.0.0.1 的入口,如需暴露到公网,由使用者自行决定方式(隧道 / 反代 / 端口映射都行),插件不绑定任何特定做法。
|
|
118
|
+
>
|
|
119
|
+
> 原 3099「受限轨迹调试页」已随 v1.73.0 整条退役 —— 轨迹约束的配置现由 `container_admin config` 直接读写。
|
|
119
120
|
|
|
120
121
|
> 🔴 **已退役:原「ACP + 对外问答页」(3100)**。该面是本插件早期自造的一套私有 HTTP+HTML 协议外壳
|
|
121
122
|
> (无客户端生态),已于 2026-10-15 **整体移除**(连同 `acp-core` / `acp-http` 与相关开关、问答页 key)。
|
|
@@ -251,28 +252,28 @@ my-workspace/ ← 工作区根目录(放一个 .serenity
|
|
|
251
252
|
`source: "reply-fallback"` 表示"AI 没发、插件兜底发的"。
|
|
252
253
|
- **排障**:`msm("weixin-doctor", ["status"|"diag"|"verify"|"guide"])`
|
|
253
254
|
|
|
254
|
-
### 6.3
|
|
255
|
+
### 6.3 轨迹约束(trajectory constraint)
|
|
255
256
|
|
|
256
|
-
|
|
257
|
-
|
|
257
|
+
**轨迹约束就是一条「目录里放了 `trajectory-constraint.json` 的认知轨迹」** —— 没有别的定义。
|
|
258
|
+
放进去,这条轨迹立刻受约束;删掉它,当场恢复成普通轨迹。
|
|
258
259
|
|
|
259
260
|
```jsonc
|
|
260
261
|
// AGENT_SESSIONS/2026-10-19--qa--问答/ ← 轨迹目录(编码 = 目录名固定位置那一段)
|
|
261
|
-
// ├─ SESSION.md
|
|
262
|
-
// ├─
|
|
262
|
+
// ├─ SESSION.md ← 它自己的身体(工作台就是它,不另建)
|
|
263
|
+
// ├─ PROMPT.md ← 它的章程(推荐;所有轨迹都适用,不限于轨迹约束)
|
|
264
|
+
// ├─ trajectory-constraint.json ← 约束面(这个文件的存在,就是"它是轨迹约束"的判据)
|
|
263
265
|
{
|
|
264
266
|
"model": "provider/model", // 这条轨迹单独用哪个模型
|
|
265
267
|
"msms": ["web-search", "vlm-describe"], // 它能调哪些小工具(MSM)
|
|
266
268
|
"tools": ["read", "grep", "glob"], // 它能用哪些平台工具
|
|
267
|
-
"systemPromptFile": "roles/qa.md", // 它的人格与边界(也可以直接内联 systemPrompt)
|
|
268
269
|
"cognitiveTrajectory": { "session": true, "keeper": true, "rebuild": true } // 缺省即全 true
|
|
269
270
|
}
|
|
270
271
|
```
|
|
271
272
|
|
|
272
273
|
- 两份白名单分开配(小工具 / 平台工具),**没列出来的一律从工具清单里移除**(不是"看得见调不动")
|
|
273
274
|
- **`cognitiveTrajectory` 缺省全 `true`**:工作台就是它自己的 `SESSION.md`,关掉等于把它的身体摘了
|
|
274
|
-
-
|
|
275
|
-
- `container_admin
|
|
275
|
+
- 章程写在轨迹目录的 **`PROMPT.md`** 里(跟着轨迹走,归档时一起搬);旧的 `systemPromptFile` 仍被读取,但 `PROMPT.md` 优先
|
|
276
|
+
- `container_admin config validate` 校验,`apply` 才真正生效;两者都**实时读盘**,改完下一轮即生效
|
|
276
277
|
- 微信路由也指向它:`routes: [{ "user": "*", "trajectory": "qa" }]`(**user → 轨迹编码**)
|
|
277
278
|
|
|
278
279
|
### 6.4 对外接入(官方 ACP)
|
package/dsh.plugin.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-serenity-hooks",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.74.0",
|
|
4
4
|
"main": "lib/index.js",
|
|
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 按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 认知轨迹日志与原地重建 +
|
|
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 按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 认知轨迹日志与原地重建 + 网页登录入口/IM 桥/认知轨迹唤醒注册表。轨迹约束 = 目录下有 trajectory-constraint.json 的认知轨迹(约束面住在轨迹里);轨迹提示词 = 轨迹目录下的 PROMPT.md(一条轨迹「是谁、按什么章程工作」,所有轨迹通用,追加在容器层与质量层之后,不替换它们)。适配 DSH 0.1.7-rc.1 / 0.2.0-rc.1 / 0.2.1-rc.1(三档,deepseek-ai/deepseek-harness)。",
|
|
6
6
|
"engines": {
|
|
7
7
|
"dsh": ">=0.1.7-rc.1"
|
|
8
8
|
},
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { n as __exportAll } from "./rolldown-runtime-B4iAMlE-.js";
|
|
2
|
+
//#region src/im/accounts.ts
|
|
3
|
+
var accounts_exports = /* @__PURE__ */ __exportAll({
|
|
4
|
+
getImAccountImpl: () => getImAccountImpl,
|
|
5
|
+
imAccountChannels: () => imAccountChannels,
|
|
6
|
+
normalizeAccountChannel: () => normalizeAccountChannel,
|
|
7
|
+
registerImAccountImpl: () => registerImAccountImpl
|
|
8
|
+
});
|
|
9
|
+
const impls = /* @__PURE__ */ new Map();
|
|
10
|
+
/** 注册账号实现(`index.ts` 装配时调用;重复 channel 覆盖——测试与热重载友好) */
|
|
11
|
+
function registerImAccountImpl(impl) {
|
|
12
|
+
impls.set(impl.channel, impl);
|
|
13
|
+
}
|
|
14
|
+
/** 取实现(未注册 ⇒ `null`,由调用方**响亮出声**,不要静默跳过) */
|
|
15
|
+
function getImAccountImpl(channel) {
|
|
16
|
+
return impls.get(channel) ?? null;
|
|
17
|
+
}
|
|
18
|
+
/** 已注册的实现名(诊断与错误文案用;顺序 = 注册顺序) */
|
|
19
|
+
function imAccountChannels() {
|
|
20
|
+
return [...impls.keys()];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 账号行的渠道归一(**单一处**)。
|
|
24
|
+
*
|
|
25
|
+
* 缺省 `weixin`:老配置平移到 `im` 段时不必补这个字段——owner 的"统一配置"
|
|
26
|
+
* 要能直接吃旧数据(与 `route.ts` 的 `normalizeImSection` 保持同一口径)。
|
|
27
|
+
*/
|
|
28
|
+
function normalizeAccountChannel(channel) {
|
|
29
|
+
const v = (channel ?? "").trim();
|
|
30
|
+
return v === "" ? "weixin" : v;
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
export { registerImAccountImpl as a, normalizeAccountChannel as i, getImAccountImpl as n, imAccountChannels as r, accounts_exports as t };
|
|
@@ -77,18 +77,18 @@ function readCccName(root) {
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
/**
|
|
80
|
-
* 🔴 **`
|
|
80
|
+
* 🔴 **`TrajectoryConstraintConfig` 已于 2026-10-19 退役**(owner 重做令)。
|
|
81
81
|
*
|
|
82
|
-
* 它的语义整体搬进**轨迹目录下的 `
|
|
83
|
-
* `
|
|
82
|
+
* 它的语义整体搬进**轨迹目录下的 `trajectory-constraint.json`**,类型现在是
|
|
83
|
+
* `trajectory/policy/profile.ts` 的 `TrajectoryConstraint`(在那里还多了 `code`/`dirName`/`path`
|
|
84
84
|
* 三个与轨迹身份相关的字段)。
|
|
85
85
|
*
|
|
86
|
-
*
|
|
87
|
-
* 放进 `serenity.json` 会让"这条轨迹是不是
|
|
88
|
-
* 一条判据(「目录下拥有 `
|
|
86
|
+
* 退役理由(一句话):轨迹约束的约束面是**某一条轨迹的属性**,不是容器级配置表里的一个 entry。
|
|
87
|
+
* 放进 `serenity.json` 会让"这条轨迹是不是 轨迹约束"分散在**两个文件**里,而 owner 要的是
|
|
88
|
+
* 一条判据(「目录下拥有 `trajectory-constraint.json` 的认知轨迹自动是一个 轨迹约束」)。
|
|
89
89
|
*
|
|
90
90
|
* ⚠️ 旧字段里 `kind: temporary|persistent` **整件无对应物**:它区分"有没有工作台",
|
|
91
|
-
* 而新模型里
|
|
91
|
+
* 而新模型里 轨迹约束恒等于一条轨迹 ⇒ 恒有 SESSION.md ⇒ 该区分没有指称对象(静默忽略)。
|
|
92
92
|
*/
|
|
93
93
|
/**
|
|
94
94
|
* 解析 cheap-worker 配置。
|
|
@@ -139,7 +139,7 @@ function readUtf8(path) {
|
|
|
139
139
|
}
|
|
140
140
|
/**
|
|
141
141
|
* 已告警过的损坏配置路径(进程级去重:同一坏文件不刷屏,但绝不静默)。
|
|
142
|
-
* S142 review F-07:此前损坏 → 静默返回 `{}`——安全模式黑名单/cheap-worker
|
|
142
|
+
* S142 review F-07:此前损坏 → 静默返回 `{}`——安全模式黑名单/cheap-worker 白名单/轨迹约束角色
|
|
143
143
|
* 全部**无声失效**(用户以为配了,实际没配)。守卫的输入失败必须响亮。
|
|
144
144
|
*/
|
|
145
145
|
const warnedBrokenConfigs = /* @__PURE__ */ new Set();
|
|
@@ -163,7 +163,7 @@ function loadSerenityConfig(root, paths = DEFAULT_SERENITY_CONFIG_PATHS) {
|
|
|
163
163
|
} catch (err) {
|
|
164
164
|
if (!warnedBrokenConfigs.has(p)) {
|
|
165
165
|
warnedBrokenConfigs.add(p);
|
|
166
|
-
console.warn(`[serenity-hooks] ✗ CCC 配置解析失败,已按空配置继续(该 CCC 的安全模式黑名单/cheap-worker
|
|
166
|
+
console.warn(`[serenity-hooks] ✗ CCC 配置解析失败,已按空配置继续(该 CCC 的安全模式黑名单/cheap-worker 白名单/轨迹约束角色等全部失效,请修 JSON): ${p} — ${String(err?.message ?? err)}`);
|
|
167
167
|
}
|
|
168
168
|
return {};
|
|
169
169
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as findSerenityRoot } from "./ccc-
|
|
1
|
+
import { n as __exportAll } from "./rolldown-runtime-B4iAMlE-.js";
|
|
2
|
+
import { a as findSerenityRoot } from "./ccc-CyYJL4F2.js";
|
|
3
3
|
import { basename } from "node:path";
|
|
4
4
|
//#region src/host/access.ts
|
|
5
5
|
/**
|
|
@@ -215,7 +215,7 @@ function liveSessionPaths(ctx) {
|
|
|
215
215
|
* **整个列表都不含后者**("名单不全")。并集修正它,且**不改**任何消费方的输入契约。
|
|
216
216
|
*
|
|
217
217
|
* @param ctx 插件上下文
|
|
218
|
-
* @param opts.defaultRoot 默认根(不在列表 → 置首);opts.withRoles 是否读
|
|
218
|
+
* @param opts.defaultRoot 默认根(不在列表 → 置首);opts.withRoles 是否读 `轨迹约束.roles`
|
|
219
219
|
* @returns 按上述顺序去重的 CCC 条目(无任何来源 → 空数组 + 可选默认根)
|
|
220
220
|
*/
|
|
221
221
|
async function listCccs(ctx, opts = {}) {
|
|
@@ -227,10 +227,10 @@ 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 {
|
|
230
|
+
const { listTrajectoryConstraints } = await import("./profile-BVt84mbi.js").then((n) => n.i);
|
|
231
231
|
rolesOf = (root) => {
|
|
232
232
|
try {
|
|
233
|
-
return
|
|
233
|
+
return listTrajectoryConstraints(root).map((p) => p.code);
|
|
234
234
|
} catch {
|
|
235
235
|
return [];
|
|
236
236
|
}
|
package/lib/client.js
CHANGED
|
@@ -3751,16 +3751,26 @@ Instruction-following style:
|
|
|
3751
3751
|
});
|
|
3752
3752
|
}
|
|
3753
3753
|
//#endregion
|
|
3754
|
-
//#region src/client/
|
|
3754
|
+
//#region src/client/ImBridgeEditor.tsx
|
|
3755
3755
|
/**
|
|
3756
|
-
*
|
|
3756
|
+
* ImBridgeEditor.tsx — 「IM 桥」配置区块(原 `WeixinBridgeEditor`,2026-10-19 泛化)
|
|
3757
3757
|
*
|
|
3758
|
-
*
|
|
3758
|
+
* ## 为什么改名 + 泛化(R↓,这不是"改个标题")
|
|
3759
|
+
*
|
|
3760
|
+
* P2 起「微信」与「飞书」是**并列的账号实现**:装配处只认 `account.channel`
|
|
3761
|
+
* (`im/accounts.ts` 的派发表),而账号、路由、会话**全部与渠道无关**。
|
|
3762
|
+
* ⇒ 面板属于"设定账号"这一层,标题若仍叫「微信桥」,第二家 IM 一接上就开始说谎
|
|
3763
|
+
* (**正是 D151 记过的那类失效:引用与口径随别的功能演进失效,且零机械信号**)。
|
|
3764
|
+
*
|
|
3765
|
+
* ⚠️ **扫码绑定是微信独有形态**;飞书走**凭据表单**(appId/appSecret)。
|
|
3766
|
+
* 二者在同一个「IM 桥」块里按账号行的 `channel` 分列。
|
|
3767
|
+
* 判据:**面板不是判据**(施工图 P4 原文),它只负责把统一配置显示出来并可写。
|
|
3768
|
+
*
|
|
3769
|
+
* **CCC 级配置**(S142 用户拍板:dsh 一个进程含多个 CCC,每个 CCC 独立对接 IM 桥):
|
|
3759
3770
|
* - 顶部 **CCC 选择器**(数据源 /serenity/cccs——listCccs 复用)——显式选择配置目标,
|
|
3760
|
-
* 不隐式依赖"当前活跃会话"(WebUI
|
|
3761
|
-
* - 选中 CCC 后:总开关 /
|
|
3762
|
-
* -
|
|
3763
|
-
* → 轮询 /serenity/weixin/login → confirmed 自动写凭据 + 账号元信息
|
|
3771
|
+
* 不隐式依赖"当前活跃会话"(WebUI 顶层全局,IM 桥是配置写入必须显式)
|
|
3772
|
+
* - 选中 CCC 后:总开关 / 账号列表 / 路由表(user → 轨迹编码)
|
|
3773
|
+
* - 扫码绑定(**微信专用**):POST login-start → qrcode-generator 生成二维码 SVG
|
|
3764
3774
|
*
|
|
3765
3775
|
* 全部端点带显式 ccc 参数 + x-serenity-ui 头(服务端校验)。
|
|
3766
3776
|
*/
|
|
@@ -3775,9 +3785,16 @@ Instruction-following style:
|
|
|
3775
3785
|
scalable: true
|
|
3776
3786
|
});
|
|
3777
3787
|
}
|
|
3788
|
+
/** 账号渠道的显示名(未登记的新渠道原样显示,不猜) */
|
|
3789
|
+
function channelLabel(channel) {
|
|
3790
|
+
const c = (channel ?? "weixin").trim() || "weixin";
|
|
3791
|
+
if (c === "weixin") return "微信";
|
|
3792
|
+
if (c === "feishu") return "飞书";
|
|
3793
|
+
return c;
|
|
3794
|
+
}
|
|
3778
3795
|
/** 当前工作区 CCC(默认选择器初值:settings 面板无 workspace 参数——服务端 /serenity/weixin 显式 ccc;
|
|
3779
3796
|
* 选择器默认选第一个;用户手选) */
|
|
3780
|
-
function
|
|
3797
|
+
function ImBridgeEditor() {
|
|
3781
3798
|
const [cccs, setCccs] = (0, react.useState)([]);
|
|
3782
3799
|
const [selectedRoot, setSelectedRoot] = (0, react.useState)("");
|
|
3783
3800
|
const [status, setStatus] = (0, react.useState)(null);
|
|
@@ -3788,6 +3805,11 @@ Instruction-following style:
|
|
|
3788
3805
|
const [loginError, setLoginError] = (0, react.useState)(null);
|
|
3789
3806
|
const [loginNotice, setLoginNotice] = (0, react.useState)(null);
|
|
3790
3807
|
const [routesDraft, setRoutesDraft] = (0, react.useState)("");
|
|
3808
|
+
const [feishuAppId, setFeishuAppId] = (0, react.useState)("");
|
|
3809
|
+
const [feishuAppSecret, setFeishuAppSecret] = (0, react.useState)("");
|
|
3810
|
+
const [feishuName, setFeishuName] = (0, react.useState)("");
|
|
3811
|
+
const [feishuBusy, setFeishuBusy] = (0, react.useState)(false);
|
|
3812
|
+
const [feishuNotice, setFeishuNotice] = (0, react.useState)(null);
|
|
3791
3813
|
(0, react.useEffect)(() => {
|
|
3792
3814
|
let alive = true;
|
|
3793
3815
|
(async () => {
|
|
@@ -4004,6 +4026,54 @@ Instruction-following style:
|
|
|
4004
4026
|
if (b.lastPollAt > 0) return `轮询中(${new Date(b.lastPollAt).toLocaleTimeString()})`;
|
|
4005
4027
|
return "启动中";
|
|
4006
4028
|
};
|
|
4029
|
+
/**
|
|
4030
|
+
* 添加飞书账号(P4)。
|
|
4031
|
+
*
|
|
4032
|
+
* 🔴 为什么飞书是表单而微信用二维码:**扫码是微信独有形态**。飞书的身份是
|
|
4033
|
+
* 「企业自建应用」的 appId + appSecret ⇒ 只能由人从飞书开放平台后台抄过来。
|
|
4034
|
+
* 在此之前面板没有任何入口 ⇒ owner 只能手写 localstore,那不算"能配"。
|
|
4035
|
+
*
|
|
4036
|
+
* 成功后**清空表单**:这是"可反复添加"的判据(同一份凭据连点两次会建出两个账号)。
|
|
4037
|
+
*/
|
|
4038
|
+
const addFeishuAccount = async () => {
|
|
4039
|
+
if (!selectedRoot || feishuBusy) return;
|
|
4040
|
+
setFeishuBusy(true);
|
|
4041
|
+
setFeishuNotice(null);
|
|
4042
|
+
try {
|
|
4043
|
+
const res = await fetch("/serenity/weixin", {
|
|
4044
|
+
method: "POST",
|
|
4045
|
+
headers: {
|
|
4046
|
+
"content-type": "application/json",
|
|
4047
|
+
"x-serenity-ui": "1"
|
|
4048
|
+
},
|
|
4049
|
+
body: JSON.stringify({
|
|
4050
|
+
action: "add-feishu-account",
|
|
4051
|
+
ccc: selectedRoot,
|
|
4052
|
+
appId: feishuAppId.trim(),
|
|
4053
|
+
appSecret: feishuAppSecret.trim(),
|
|
4054
|
+
name: feishuName.trim()
|
|
4055
|
+
})
|
|
4056
|
+
});
|
|
4057
|
+
const body = await res.json().catch(() => null);
|
|
4058
|
+
if (!res.ok) {
|
|
4059
|
+
setFeishuNotice(body?.error ?? `HTTP ${res.status}`);
|
|
4060
|
+
return;
|
|
4061
|
+
}
|
|
4062
|
+
setFeishuNotice(`账号 ${body?.accountId ?? ""} 已添加 ✓(凭据已写入 localstore)`);
|
|
4063
|
+
setFeishuAppId("");
|
|
4064
|
+
setFeishuAppSecret("");
|
|
4065
|
+
setFeishuName("");
|
|
4066
|
+
const sbody = await (await fetch(`/serenity/weixin?ccc=${encodeURIComponent(selectedRoot)}`, { headers: {
|
|
4067
|
+
accept: "application/json",
|
|
4068
|
+
"x-serenity-ui": "1"
|
|
4069
|
+
} })).json().catch(() => null);
|
|
4070
|
+
if (sbody) setStatus(sbody);
|
|
4071
|
+
} catch (err) {
|
|
4072
|
+
setFeishuNotice(err instanceof Error ? err.message : String(err));
|
|
4073
|
+
} finally {
|
|
4074
|
+
setFeishuBusy(false);
|
|
4075
|
+
}
|
|
4076
|
+
};
|
|
4007
4077
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
|
|
4008
4078
|
className: "ss-rows",
|
|
4009
4079
|
children: [
|
|
@@ -4018,7 +4088,7 @@ Instruction-following style:
|
|
|
4018
4088
|
}),
|
|
4019
4089
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4020
4090
|
className: "ss-rowDesc",
|
|
4021
|
-
children: "
|
|
4091
|
+
children: "选择要配置 IM 桥的认知容器"
|
|
4022
4092
|
}),
|
|
4023
4093
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4024
4094
|
className: "ss-help",
|
|
@@ -4029,7 +4099,7 @@ Instruction-following style:
|
|
|
4029
4099
|
children: "?"
|
|
4030
4100
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4031
4101
|
className: "ss-helpTip",
|
|
4032
|
-
children: "
|
|
4102
|
+
children: "IM 桥是 CCC 级配置。\n· 一个 dsh 进程可挂多个 CCC,各自独立对接 IM\n· 在这里显式选择目标,不跟随当前会话\n· 各 CCC 的账号、路由、开关互不影响\n· 切换后自动加载该 CCC 的配置"
|
|
4033
4103
|
})]
|
|
4034
4104
|
})
|
|
4035
4105
|
]
|
|
@@ -4078,18 +4148,18 @@ Instruction-following style:
|
|
|
4078
4148
|
}),
|
|
4079
4149
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4080
4150
|
className: "ss-rowDesc",
|
|
4081
|
-
children: status.accounts.length === 0 ? "
|
|
4151
|
+
children: status.accounts.length === 0 ? "未绑定账号——微信可扫码绑定,飞书填凭据" : status.accounts.map((a) => `${channelLabel(a.channel)}·${a.accountId}${a.bound ? "✓" : "✗"}`).join(" ")
|
|
4082
4152
|
}),
|
|
4083
4153
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4084
4154
|
className: "ss-help",
|
|
4085
4155
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4086
4156
|
type: "button",
|
|
4087
4157
|
className: "ss-helpMark",
|
|
4088
|
-
"aria-label": "
|
|
4158
|
+
"aria-label": "IM 桥总开关帮助",
|
|
4089
4159
|
children: "?"
|
|
4090
4160
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4091
4161
|
className: "ss-helpTip",
|
|
4092
|
-
children: "
|
|
4162
|
+
children: "IM 桥总开关。\n· 开启后该 CCC 开始收消息(每个账号各自一条连接)\n· 前置:至少一个已绑定凭据的账号\n· 每账号独立连接;✓ = 已绑定凭据,✗ = 未绑定\n· 关闭 = 停止全部连接,零资源占用"
|
|
4093
4163
|
})]
|
|
4094
4164
|
})
|
|
4095
4165
|
]
|
|
@@ -4111,7 +4181,14 @@ Instruction-following style:
|
|
|
4111
4181
|
className: "ss-rowText",
|
|
4112
4182
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4113
4183
|
className: "ss-rowName",
|
|
4114
|
-
children: [
|
|
4184
|
+
children: [
|
|
4185
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4186
|
+
className: "ss-channelTag",
|
|
4187
|
+
children: channelLabel(a.channel)
|
|
4188
|
+
}),
|
|
4189
|
+
a.accountId,
|
|
4190
|
+
a.name ? ` · ${a.name}` : ""
|
|
4191
|
+
]
|
|
4115
4192
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4116
4193
|
className: "ss-rowDesc",
|
|
4117
4194
|
children: [
|
|
@@ -4187,6 +4264,68 @@ Instruction-following style:
|
|
|
4187
4264
|
})
|
|
4188
4265
|
})]
|
|
4189
4266
|
}) }),
|
|
4267
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4268
|
+
className: "ss-rowCard",
|
|
4269
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4270
|
+
className: "ss-rowText",
|
|
4271
|
+
children: [
|
|
4272
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4273
|
+
className: "ss-rowName",
|
|
4274
|
+
children: "添加飞书账号"
|
|
4275
|
+
}),
|
|
4276
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4277
|
+
className: "ss-rowDesc",
|
|
4278
|
+
children: feishuNotice ?? "填企业自建应用的 App ID 与 App Secret——每提交一次新增一个账号"
|
|
4279
|
+
}),
|
|
4280
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4281
|
+
className: "ss-help",
|
|
4282
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4283
|
+
type: "button",
|
|
4284
|
+
className: "ss-helpMark",
|
|
4285
|
+
"aria-label": "飞书绑定帮助",
|
|
4286
|
+
children: "?"
|
|
4287
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4288
|
+
className: "ss-helpTip",
|
|
4289
|
+
children: "添加飞书账号(企业自建应用)。\n· 飞书开放平台 → 开发者后台 → 你的应用 → 「凭证与基础信息」\n· 复制 App ID 与 App Secret 填在下面\n· 事件订阅选「长连接」并订阅 im.message.receive_v1\n· 每提交一次新增一个账号,各自独立连接\n· 与微信并列:账号、路由、开关互不影响"
|
|
4290
|
+
})]
|
|
4291
|
+
})
|
|
4292
|
+
]
|
|
4293
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4294
|
+
className: "ss-rowControl",
|
|
4295
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4296
|
+
type: "button",
|
|
4297
|
+
className: "ss-loginBtn",
|
|
4298
|
+
disabled: feishuBusy || feishuAppId.trim() === "" || feishuAppSecret.trim() === "",
|
|
4299
|
+
onClick: () => void addFeishuAccount(),
|
|
4300
|
+
children: feishuBusy ? "添加中…" : "添加飞书账号"
|
|
4301
|
+
})
|
|
4302
|
+
})]
|
|
4303
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4304
|
+
className: "ss-feishuForm",
|
|
4305
|
+
children: [
|
|
4306
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4307
|
+
className: "ss-input",
|
|
4308
|
+
type: "text",
|
|
4309
|
+
placeholder: "App ID(cli_xxx)",
|
|
4310
|
+
value: feishuAppId,
|
|
4311
|
+
onChange: (e) => setFeishuAppId(e.target.value)
|
|
4312
|
+
}),
|
|
4313
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4314
|
+
className: "ss-input",
|
|
4315
|
+
type: "password",
|
|
4316
|
+
placeholder: "App Secret",
|
|
4317
|
+
value: feishuAppSecret,
|
|
4318
|
+
onChange: (e) => setFeishuAppSecret(e.target.value)
|
|
4319
|
+
}),
|
|
4320
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4321
|
+
className: "ss-input",
|
|
4322
|
+
type: "text",
|
|
4323
|
+
placeholder: "账号名(可选,如「家庭群机器人」)",
|
|
4324
|
+
value: feishuName,
|
|
4325
|
+
onChange: (e) => setFeishuName(e.target.value)
|
|
4326
|
+
})
|
|
4327
|
+
]
|
|
4328
|
+
})] }),
|
|
4190
4329
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4191
4330
|
className: "ss-rowCard",
|
|
4192
4331
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -4198,7 +4337,7 @@ Instruction-following style:
|
|
|
4198
4337
|
}),
|
|
4199
4338
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4200
4339
|
className: "ss-rowDesc",
|
|
4201
|
-
children: "
|
|
4340
|
+
children: "IM 用户 → 认知轨迹编码(`*` 通配兜底)"
|
|
4202
4341
|
}),
|
|
4203
4342
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4204
4343
|
className: "ss-help",
|
|
@@ -4209,7 +4348,7 @@ Instruction-following style:
|
|
|
4209
4348
|
children: "?"
|
|
4210
4349
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4211
4350
|
className: "ss-helpTip",
|
|
4212
|
-
children: "
|
|
4351
|
+
children: "路由表:IM 用户 → 认知轨迹编码映射。\n· 格式:[{\"user\": \"xxx@im.wechat\", \"trajectory\": \"my-code\"}, ...]\n· user = 该渠道的用户 ID(微信 from_user_id / 飞书 open_id);`*` = 通配兜底\n· trajectory = 该 CCC 里某条认知轨迹的**编码**(目录名里 `YYYY-MM-DD--<编码>` 那一段)\n· 未命中路由的用户不回复(不暴露机器人)"
|
|
4213
4352
|
})]
|
|
4214
4353
|
})
|
|
4215
4354
|
]
|
|
@@ -4238,7 +4377,7 @@ Instruction-following style:
|
|
|
4238
4377
|
children: "加载中…"
|
|
4239
4378
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4240
4379
|
className: "ss-rowDesc",
|
|
4241
|
-
children: "读取所选 CCC
|
|
4380
|
+
children: "读取所选 CCC 的 IM 桥配置"
|
|
4242
4381
|
})]
|
|
4243
4382
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "ss-rowControl" })]
|
|
4244
4383
|
}) })
|
|
@@ -4247,7 +4386,7 @@ Instruction-following style:
|
|
|
4247
4386
|
}
|
|
4248
4387
|
//#endregion
|
|
4249
4388
|
//#region \0sp-css:src/client/SettingsSection
|
|
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";
|
|
4389
|
+
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/* IM 桥:账号行的**渠道标签**(2026-10-19 泛化后新增)。\n 为什么是标签而不是\"把渠道拼进 id\":渠道是账号的属性,不是名字的一部分;\n 拼进去会让「同一个账号换了渠道」看起来像另一个账号。\n 🔴 不得定宽(v1.72.0 那次 `sp-label` 写死 76px 压住数值的教训)⇒ inline-block + 自适应。 */\n.ss-channelTag {\n display: inline-block;\n padding: 0 6px;\n margin-right: 6px;\n border-radius: 4px;\n font-size: 11px;\n line-height: 18px;\n font-weight: 600;\n vertical-align: 1px;\n background: rgba(11, 168, 117, .12);\n color: #0ba875;\n white-space: nowrap;\n}\n\n@media (prefers-color-scheme: dark) {\n .ss-channelTag { color: #3ddc9a; }\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/* 飞书凭据表单(P4):三格竖排——appId / appSecret / 账号名。\n * 🔴 不做成一行三格:App Secret 通常 32 位,窄屏下会被压到看不见自己输了什么\n * (本文件 D152 记过同族:定宽 + 无断点会把值压到标签上)。竖排在小屏也保持可读。 */\n.ss-feishuForm {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin-top: 6px;\n}\n\n.ss-feishuForm .ss-input {\n width: 100%;\n box-sizing: border-box;\n padding: 7px 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}\n\n.ss-feishuForm .ss-input::placeholder {\n color: var(--dsw-alias-label-secondary);\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";
|
|
4251
4390
|
if (typeof document !== "undefined" && document.querySelector("style[data-sp-css=\"SettingsSection\"]") === null) {
|
|
4252
4391
|
const tag = document.createElement("style");
|
|
4253
4392
|
tag.setAttribute("data-sp-css", "SettingsSection");
|
|
@@ -4382,18 +4521,12 @@ Instruction-following style:
|
|
|
4382
4521
|
const setThreshold = (v) => {
|
|
4383
4522
|
set("rebuildThresholdK", Math.min(4e3, Math.max(50, Math.round(v))));
|
|
4384
4523
|
};
|
|
4385
|
-
const setSkiffPort = (v) => {
|
|
4386
|
-
set("skiffDebugPort", Math.min(65535, Math.max(1024, Math.round(v))));
|
|
4387
|
-
};
|
|
4388
4524
|
const gatewayOn = value?.gatewayEnabled ?? false;
|
|
4389
4525
|
const thresholdK = value?.rebuildThresholdK ?? 400;
|
|
4390
|
-
const skiffOn = value?.skiffEnabled ?? false;
|
|
4391
|
-
const skiffPort = value?.skiffDebugPort ?? 3099;
|
|
4392
4526
|
const croOn = value?.croEnabled ?? true;
|
|
4393
4527
|
const diagramOn = value?.diagramEnabled ?? false;
|
|
4394
4528
|
const [openGateway, setOpenGateway] = (0, react.useState)(false);
|
|
4395
4529
|
const [openRebuild, setOpenRebuild] = (0, react.useState)(false);
|
|
4396
|
-
const [openSkiff, setOpenSkiff] = (0, react.useState)(false);
|
|
4397
4530
|
const [openCro, setOpenCro] = (0, react.useState)(false);
|
|
4398
4531
|
const [openDiagram, setOpenDiagram] = (0, react.useState)(false);
|
|
4399
4532
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -4432,7 +4565,7 @@ Instruction-following style:
|
|
|
4432
4565
|
title: "上下文",
|
|
4433
4566
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
|
|
4434
4567
|
title: "超限重建",
|
|
4435
|
-
desc: "上下文接近上限时提示调用
|
|
4568
|
+
desc: "上下文接近上限时提示调用 cognitive_trajectory rebuild 清空重建",
|
|
4436
4569
|
expandable: true,
|
|
4437
4570
|
open: openRebuild,
|
|
4438
4571
|
onToggle: setOpenRebuild,
|
|
@@ -4440,7 +4573,7 @@ Instruction-following style:
|
|
|
4440
4573
|
className: "ss-detailStack",
|
|
4441
4574
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4442
4575
|
className: "ss-detailIntro",
|
|
4443
|
-
children: "上下文占用到阈值时,由模型调用
|
|
4576
|
+
children: "上下文占用到阈值时,由模型调用 cognitive_trajectory rebuild 原地清空重建。\n· 语义:丢弃当前会话 → 新建 → 注入「继续原 SESSION 的工作」\n· SESSION.md 原位不动,轨迹延续,上下文归零\n· 恒开、无总闸;要调敏感度只改下面的阈值"
|
|
4444
4577
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
|
|
4445
4578
|
title: "重建阈值",
|
|
4446
4579
|
desc: "上下文占用到该值(K token,默认 400)时提示重建",
|
|
@@ -4459,35 +4592,9 @@ Instruction-following style:
|
|
|
4459
4592
|
})
|
|
4460
4593
|
}) })
|
|
4461
4594
|
}),
|
|
4462
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
4595
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Group, {
|
|
4463
4596
|
title: "外部能力",
|
|
4464
|
-
children:
|
|
4465
|
-
title: "Skiff 调试",
|
|
4466
|
-
desc: "Skiff 认知子集问答页(默认 3099,仅本机,实验性)",
|
|
4467
|
-
expandable: true,
|
|
4468
|
-
open: openSkiff,
|
|
4469
|
-
onToggle: setOpenSkiff,
|
|
4470
|
-
control: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4471
|
-
className: "ss-switchRow",
|
|
4472
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Toggle, {
|
|
4473
|
-
checked: skiffOn,
|
|
4474
|
-
onChange: (on) => toggle("skiffEnabled", on)
|
|
4475
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4476
|
-
className: "ss-portInput",
|
|
4477
|
-
type: "number",
|
|
4478
|
-
min: 1024,
|
|
4479
|
-
max: 65535,
|
|
4480
|
-
value: skiffPort,
|
|
4481
|
-
disabled: !skiffOn,
|
|
4482
|
-
title: "Skiff 调试端口(默认 3099)",
|
|
4483
|
-
onChange: (e) => setSkiffPort(Number(e.target.value))
|
|
4484
|
-
})]
|
|
4485
|
-
}),
|
|
4486
|
-
detail: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4487
|
-
className: "ss-detailIntro",
|
|
4488
|
-
children: "Skiff 认知子集角色的问答页,仅监听 127.0.0.1。\n· Skiff = 完整轨迹的任意子集(认知子集角色)\n· 先在 CCC 的 skiff.roles 里配角色,再用此页以角色身份问答\n· 实验性,人工启停,默认关"
|
|
4489
|
-
})
|
|
4490
|
-
}) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
|
|
4597
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
|
|
4491
4598
|
title: "CRO(轨迹自编程唤起)",
|
|
4492
4599
|
desc: "让轨迹用自己的一段程序决定何时唤起(全局开关,默认开)",
|
|
4493
4600
|
expandable: true,
|
|
@@ -4504,7 +4611,7 @@ Instruction-following style:
|
|
|
4504
4611
|
children: "轨迹目录下放一个 continuous-re-occurrence.ts,调度器每 5 分钟跑它一次,由这段程序决定要不要唤、何时唤、唤的时候说什么。\n· 程序文件在即启用,不必在此配置;本开关只是总闸\n· 关掉只停 CRO 阶段:定时唤醒(send-later)、即时投递(send-now)与唤醒表投递照常\n· 没有程序文件的轨迹本来就不参与"
|
|
4505
4612
|
})
|
|
4506
4613
|
})
|
|
4507
|
-
}) })
|
|
4614
|
+
}) })
|
|
4508
4615
|
}),
|
|
4509
4616
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Group, {
|
|
4510
4617
|
title: "工具",
|
|
@@ -4533,9 +4640,9 @@ Instruction-following style:
|
|
|
4533
4640
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PersonaEditor, {})
|
|
4534
4641
|
}),
|
|
4535
4642
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Collapse, {
|
|
4536
|
-
title: "
|
|
4537
|
-
desc: "
|
|
4538
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
4643
|
+
title: "IM 桥",
|
|
4644
|
+
desc: "绑定即时通讯账号 · 路由到认知轨迹(CCC 级配置)",
|
|
4645
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImBridgeEditor, {})
|
|
4539
4646
|
}),
|
|
4540
4647
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Collapse, {
|
|
4541
4648
|
title: "会话清理",
|