@shgroup/dsh-serenity-hooks 1.56.9 → 1.56.10
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/assets/README.md +4 -4
- package/assets/serenity-voyage.html +3 -4
- package/dsh.plugin.json +1 -1
- package/lib/{ccc-roots-Bo0HKLlM.js → ccc-roots-CDW2dO0n.js} +1 -1
- package/lib/ccc.d.ts +11 -2
- package/lib/client.js +7 -7
- package/lib/cro-guide.d.ts +3 -1
- package/lib/git-ops.d.ts +1 -1
- package/lib/im-weixin.d.ts +10 -3
- package/lib/index.js +53 -47
- package/lib/{message-source-BExngUPX.js → message-source-CQNfQaTx.js} +3 -3
- package/lib/rebuild.d.ts +1 -1
- package/lib/skiff-core.d.ts +1 -1
- package/lib/{skiff-role-BSg6Qu9k.js → skiff-role-Det66X16.js} +1 -1
- package/lib/skiff-role.d.ts +1 -1
- package/lib/skills-discovery.d.ts +2 -3
- package/lib/voyage-page.d.ts +3 -4
- package/lib/{weixin-route-BNyH5ghC.js → weixin-route-CxCciqQl.js} +17 -1
- package/lib/weixin-send-api.d.ts +1 -1
- package/package.json +1 -1
package/assets/README.md
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
│ three.core.min.js + three.module.min.js(构建输入)· build.ts(构建脚本)
|
|
28
28
|
├── serenity-voyage.html ← 与本目录同物(改源后重建,再拷过来)
|
|
29
29
|
├── preview.png · preview-card.png 两种形态的真实渲染帧
|
|
30
|
-
└── provenance/S132-ORIGIN-SESSION.md
|
|
30
|
+
└── provenance/S132-ORIGIN-SESSION.md 赠予方的原始会话记录
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
**重建**:在该目录下 `bun build/build.ts`(脚本自定位,目录挪动不会断),产物写出后
|
|
@@ -35,15 +35,15 @@
|
|
|
35
35
|
|
|
36
36
|
### 来历与内容口径
|
|
37
37
|
|
|
38
|
-
-
|
|
38
|
+
- **来历**:作品由**另一个 Serenity CCC 实例**赠予,属跨容器赠品。
|
|
39
39
|
它的三维建模、运镜与渲染质量是原作者的功劳;本仓库承载的是**内容重播 + 卡片模式**。
|
|
40
40
|
- **内容重播(S142 §12.42/§12.43)**:星空词元已从赠予方的名字换成**宁静号自己的**
|
|
41
41
|
技能 / 公理 / MSM / 本体文件名(102 条,全部有出处、无自造);事实面板六个数
|
|
42
42
|
(仓库 19 / 技能 35 / 工具 84 / 本体 12 / 公理 56 / 会话 190)为实测快照,口径写在
|
|
43
43
|
`app.js` 的注释里。
|
|
44
|
-
-
|
|
44
|
+
- **外来内容已归零**:赠予方的技能名前缀、公理名前缀、铭牌字样等**全部替换**。
|
|
45
45
|
该判据已被 `tests/voyage-page.test.ts` 自动化(**大小写不敏感**——上一轮正因人工
|
|
46
|
-
grep
|
|
46
|
+
grep 用了小写而漏掉全大写的铭牌字样),改动资产若带回外来内容,测试即红。
|
|
47
47
|
|
|
48
48
|
### 版本口径
|
|
49
49
|
|
|
@@ -1098,10 +1098,9 @@ function makeCodeSlabTex(name) {
|
|
|
1098
1098
|
g.x.fillRect(24, 72, W2 - 48, 3);
|
|
1099
1099
|
return mkTex(g.c, true);
|
|
1100
1100
|
}
|
|
1101
|
-
// 🔴
|
|
1102
|
-
//
|
|
1103
|
-
//
|
|
1104
|
-
// (同 §12.25 那次"漏相对导入形态"的教训)。已改为我们自己的容器名,验收改用 `grep -i`。
|
|
1101
|
+
// 🔴 内容扫尾留档:原铭牌词表里有一项是**赠予方的容器名**,属"他们的内容"。
|
|
1102
|
+
// 上一轮残留验收漏过它(grep 用了小写而此处是全大写 ⇒ 判据覆盖面失守)。
|
|
1103
|
+
// 已改为我们自己的容器名,验收改用 `grep -i`(大小写不敏感,判据才成立)。
|
|
1105
1104
|
var SLAB_NAMES = ['SERENITY', '03-K64', 'HOME-SERENITY', '认知星空', '宁静号'];
|
|
1106
1105
|
var slabTexes = SLAB_NAMES.map(makeCodeSlabTex);
|
|
1107
1106
|
|
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-serenity-hooks",
|
|
3
|
-
"version": "1.56.
|
|
3
|
+
"version": "1.56.10",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"description": "宁静号 ACC harness(Native Cordis 插件):给 DSH 装一个「AI 工作区」——14 个工具(container_fs/container_trajectory/dashboard/container_git/msm/praxis/ontology/serenity-skill-creator/handyman/localstore/container_admin;另三个 im-bridge/acc-diag/diagram 按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 轨迹日志与原地重建 + 网页登录入口/微信桥/子角色/对外问答页/trajectory 唤醒注册表。适配 DSH 0.1.7-rc.1 与 0.2.0-rc.1(双档,deepseek-ai/deepseek-harness)。",
|
|
6
6
|
"engines": {
|
|
@@ -150,7 +150,7 @@ async function listCccs(ctx, opts = {}) {
|
|
|
150
150
|
if (typeof defaultRoot === "string" && defaultRoot !== "" && !c.roots.includes(defaultRoot)) c.roots.unshift(defaultRoot);
|
|
151
151
|
let rolesOf = null;
|
|
152
152
|
if (opts.withRoles === true) {
|
|
153
|
-
const { readSkiffRoles } = await import("./skiff-role-
|
|
153
|
+
const { readSkiffRoles } = await import("./skiff-role-Det66X16.js").then((n) => n.u);
|
|
154
154
|
rolesOf = (root) => [...readSkiffRoles(root).keys()];
|
|
155
155
|
}
|
|
156
156
|
return c.roots.map((root) => ({
|
package/lib/ccc.d.ts
CHANGED
|
@@ -91,7 +91,7 @@ interface SerenityConfig {
|
|
|
91
91
|
* 多 CCC 独立(v1.27.4):每 CCC 自己的配置,时钟遍历所有 live+enabled CCC 各自唤起。
|
|
92
92
|
*/
|
|
93
93
|
autopilotTrajectory?: AutopilotTrajectorySettings;
|
|
94
|
-
/** 旧键兼容(正式化前存量 CCC
|
|
94
|
+
/** 旧键兼容(正式化前存量 CCC——新键 autopilotTrajectory 优先,旧键回退) */
|
|
95
95
|
autotrajectory?: AutopilotTrajectorySettings;
|
|
96
96
|
/**
|
|
97
97
|
* trajectory 族配置(D58,S142 2026-09-13):`trajectory` 是一等概念,
|
|
@@ -187,6 +187,15 @@ export interface WeixinSettings {
|
|
|
187
187
|
accounts?: WeixinAccountConfig[];
|
|
188
188
|
/** 消息路由:微信用户 → 该 CCC 的 skiff role(不绑定具体 role——用户自选) */
|
|
189
189
|
routes?: WeixinRouteConfig[];
|
|
190
|
+
/**
|
|
191
|
+
* 用户别名表(v1.56.10):`{ "<别名>": "<localstore 凭据键>" }`。
|
|
192
|
+
*
|
|
193
|
+
* 🔴 **为什么搬到这里**(2026-10-14 隐私核查):别名(家人称呼)**是 CCC 的数据,不是 ACC 的机制**
|
|
194
|
+
* ——按 D23 归属判据「改它要不要发版」:加一个家人别名**不该**要动插件源码并发版。
|
|
195
|
+
* 此前别名硬编码在 ACC 源码里,导致**家人称呼随 npm 包公开发布**。
|
|
196
|
+
* 归位后 ACC 不认识任何具体人名;别名由各 CCC 自配(留空 = 只用裸 iLink 用户 id)。
|
|
197
|
+
*/
|
|
198
|
+
aliases?: Record<string, string>;
|
|
190
199
|
/**
|
|
191
200
|
* 消息记录 hook(v1.27.13,用户"微信桥所有消息记录,支持 hook,CCC 自写持久性保存"):
|
|
192
201
|
* 相对 CCC 根的脚本路径——微信桥每收/发一条消息触发一次(事件 JSON 经 stdin 传入,
|
|
@@ -229,7 +238,7 @@ export interface WeixinSettings {
|
|
|
229
238
|
export interface WeixinAccountConfig {
|
|
230
239
|
/** 本地唯一键(如 wechat-1;localstore 凭据键 weixin.accounts.<accountId>.*) */
|
|
231
240
|
accountId: string;
|
|
232
|
-
/** 展示名(可选;如"
|
|
241
|
+
/** 展示名(可选;如"家庭助手") */
|
|
233
242
|
name?: string;
|
|
234
243
|
/** 该账号轮询开关(缺省 true) */
|
|
235
244
|
enabled?: boolean;
|
package/lib/client.js
CHANGED
|
@@ -7,7 +7,7 @@ window.__ModuleLoader__.load({
|
|
|
7
7
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
8
8
|
let react = require("react");
|
|
9
9
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
10
|
-
//#region \0sp-css
|
|
10
|
+
//#region \0sp-css:src/client/SafeModePanel
|
|
11
11
|
const css$5 = "/* SafeModePanel — 会话头部 Serenity 状态胶囊(v1.24.10 胶囊改版,对齐 OcgoDockEntry pill)\n * 胶囊 999px 全圆 → 点击 → 自绘 popover(340px 右上角卡片,外点/Escape 关闭)\n * popover 内:分组(groupTitle 标题 + rowCard 行卡)——看齐官方 settings 设计语言\n * 遵循 web-styling.md:颜色只用 --dsw-alias-* 语义 token(明暗自适应)+ --sp-safe-green 统一绿家族;\n * 前缀 sp- 防冲突。 */\n\n/* ── 统一绿色变量家族(一处改全改;emerald 500~600 区间保证深色对比度) ── */\n\n.sp-root {\n --sp-safe-green: #0ba875; /* emerald-550:SAFE ON 主色 */\n --sp-safe-green-deep: #059669; /* emerald-600:渐变深端 */\n}\n\n/* ── 头部状态胶囊(可点击) ── */\n\n.sp-card {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 9px; /* 无固定 height:由内容撑高(胶囊) */\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-2);\n color: inherit;\n font-size: 12px;\n line-height: 1;\n cursor: pointer;\n transition: background var(--ds-transition-duration-fast, 0.1s) var(--ds-ease-in-out, ease),\n border-color var(--ds-transition-duration-fast, 0.1s) var(--ds-ease-in-out, ease);\n}\n\n.sp-card:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n border-color: var(--dsw-alias-border-l2);\n}\n\n.sp-card:focus-visible {\n outline: 2px solid var(--dsw-alias-button-ghost-active-border);\n outline-offset: 1px;\n}\n\n.sp-card:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n/* 绿点 = Serenity 在线(恒亮绿,不随 SAFE 变);离线/未激活 → 灰 */\n.sp-dot {\n flex: none;\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--dsw-alias-state-success-primary);\n}\n\n.sp-dotOff {\n background: var(--dsw-alias-label-dimmed);\n}\n\n.sp-cardInactive {\n opacity: 0.85;\n}\n\n.sp-cardInactive .sp-brand {\n color: var(--dsw-alias-label-secondary);\n font-weight: 500;\n}\n\n.sp-brand {\n color: var(--dsw-alias-label-primary);\n font-weight: 500;\n}\n\n/* 版本号:monospace + translateY(1px) 下沉对齐(与文字基线齐平) */\n.sp-ver {\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n font-family: var(--ds-font-family-code, monospace);\n transform: translateY(1px);\n}\n\n/* 1px 深灰分隔线(两侧紧凑) */\n.sp-sep {\n flex: none;\n width: 1px;\n height: 12px;\n margin: 0 2px;\n background: var(--dsw-alias-label-tertiary);\n}\n\n.sp-shield {\n display: inline-flex;\n width: 14px;\n height: 14px;\n flex: none;\n}\n\n.sp-shield svg {\n width: 14px;\n height: 14px;\n}\n\n.sp-statusWord {\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0;\n white-space: nowrap;\n}\n\n/* SAFE OFF(未保护):灰——低姿态提醒,非错误(用户自己的开关选择) */\n.sp-cardUnprotected .sp-shield {\n color: var(--dsw-alias-label-secondary);\n}\n\n.sp-cardUnprotected .sp-statusWord {\n color: var(--dsw-alias-label-secondary);\n}\n\n/* SAFE ON(保护中):emerald 绿——安心(盾牌实色 + SAFE 文字渐变质感) */\n.sp-cardProtected .sp-shield {\n color: var(--sp-safe-green);\n}\n\n.sp-cardProtected .sp-statusWord {\n color: var(--sp-safe-green);\n background: linear-gradient(135deg, var(--sp-safe-green) 0%, var(--sp-safe-green-deep) 100%);\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n}\n\n/* ── Mac 风格滑块(v1.24.10:轨道 24×13 / thumb 11px 灰白 #f2f4f6 无图标 / cubic-bezier 平滑) ── */\n\n.sp-switch {\n display: inline-block;\n width: 24px;\n height: 13px;\n border-radius: 999px;\n position: relative;\n flex: none;\n cursor: pointer;\n transition: background 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.sp-switchOff {\n background: var(--dsw-alias-border-l2);\n}\n\n.sp-switchOn {\n background: var(--sp-safe-green);\n}\n\n.sp-switchThumb {\n position: absolute;\n top: 1px;\n width: 11px;\n height: 11px;\n border-radius: 50%;\n background: #f2f4f6; /* Mac 灰白 thumb(明暗通用) */\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);\n transition: left 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.sp-switchOff .sp-switchThumb {\n left: 1px;\n}\n\n.sp-switchOn .sp-switchThumb {\n left: 12px; /* 24 - 11 - 1 */\n}\n\n/* CSS 特异性坑(S013 指南):.sp-switch:hover (0,2,0) 会覆盖 .sp-switchOn (0,1,0)\n * → ON 态 hover 绿底消失。必须同特异性且后定义补回。 */\n.sp-switch:hover {\n filter: brightness(1.08);\n}\n\n.sp-switchOn:hover {\n background: var(--sp-safe-green);\n}\n\n.sp-switchBusy {\n opacity: 0.6;\n cursor: default;\n pointer-events: none;\n}\n\n.sp-chev {\n color: var(--dsw-alias-label-dimmed);\n flex: none;\n}\n\n/* ── 自绘 popover(340px 右上角小卡片,替代官方 Modal) ── */\n\n.sp-root {\n position: relative;\n display: inline-flex;\n}\n\n/* ── 自绘 popover(卡片,替代官方 Modal)\n v1.36.1(所有者:「卡片做成双倍宽,左侧是信息,右侧是动画」):340 → **680px**(双倍)。\n v1.39.1(所有者:「下拉 dialog / 弹窗内容过宽后,会被左侧元素遮挡」):\n 🔴 根因 = **祖先 `overflow:hidden` 裁切**,不是 z-index 也不是宽度不够。\n 真机取证(CDP hit-test,1280/1600/1920 三档一致):\n · 胶囊右端 x=954.2、卡片 680 宽 ⇒ 左边界 274.2\n · 而会话中列 `pI_x6G_centerCol` / `wSkVaW_root` 都 `overflow:hidden` 且左边界 = **280**\n ⇒ 左边缘 **5.8px** 被裁掉(左边框线与圆角消失)。\n 加宽前(340px)左边界 614.2 远在 280 右侧 ⇒ **这正是 v1.36.1 加宽引入的回归**。\n 修法:**改为 `position: fixed`** —— fixed 子元素**不受祖先 overflow 裁切**;\n 坐标由 SafeModePanel 用 `getBoundingClientRect()` 算出并夹取进视口(见 .tsx 的 useLayoutEffect)。\n (本仓 client 侧**无 `react-dom` 依赖** ⇒ `createPortal` 不可用;fixed 是等效且更轻的出路。\n 已在真机验证祖先链**无** transform/filter/contain/will-change ⇒ fixed 不会被降级为相对某祖先。)\n 宽度仍走 `min(680px, 100vw-24px)`(窄视口兜底),窄屏退回单栏见文末 @media。 */\n.sp-pop {\n position: fixed; /* 不受祖先 overflow:hidden 裁切;left/top 由 JS 计算 */\n top: 0; /* ← 声明默认值,JS 会覆写(未落位时组件给 -9999 屏外值,不会闪到右下角) */\n left: 0;\n width: min(680px, calc(100vw - 24px));\n z-index: 2000;\n box-sizing: border-box;\n padding: 14px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 14px;\n background: var(--dsw-alias-bg-overlay);\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);\n}\n\n/* ── 航行动画栏:宁静号心智模型(ACC 层资产 /serenity/voyage,S142 §12.44 → v1.36.1 改右栏)\n v1.36.1 改版(所有者:「卡片做成双倍宽,左侧是信息,右侧是动画」):\n 动画从**背景层**改为**右栏**。这一改动解开了 v1.36.0 的取舍死结——\n 旧布局里动画垫在正文底下,必须靠 0.75 的卡片底色把它压住才读得清字;\n 分段之后两者不再争同一片像素 ⇒ 动画可以亮、正文可以干净,不必再互相妥协。\n ⚠️ 动画本身仍是「卡片模式」(词元压到 22%、铭牌层关闭),本栏只负责**给位置**,不改作品。 */\n.sp-popVoyage {\n overflow: hidden; /* 裁掉 iframe 在 14px 圆角外的溢出 */\n /* 分段后不再需要 0.75 的重压暗:压到 0.9 只压整体观感,不与正文争对比度。\n 若所有者觉得动画太亮/太暗,这仍是主旋钮(次旋钮 = iframe 的 blur)。 */\n background: rgba(6, 11, 14, 0.9);\n display: flex;\n flex-direction: row;\n /* 两栏都从**同一行高**分配(row 轴 cross = 高度):左栏按内容、右栏吃满行高。\n 行高 = 左栏内容高度,且被 max-height 封顶 ⇒ 信息长时内部滚动,动画不把行撑破。 */\n align-items: stretch;\n gap: 12px;\n padding: 12px;\n max-height: calc(100vh - 120px);\n}\n/* 左栏:信息(正文)——固定 340px,与旧卡片同宽,保证原有排印不变 */\n.sp-popVoyage > .sp-popBody {\n position: relative;\n z-index: 1;\n order: 1;\n flex: none;\n width: 340px;\n min-width: 0;\n}\n/* 右栏:动画——吃掉剩余宽度,并吃满左栏高度 */\n.sp-voyage {\n order: 2;\n flex: 1 1 auto;\n min-width: 0;\n position: relative;\n pointer-events: none; /* 纯展示:不挡点击、不抢焦点 */\n overflow: hidden;\n border-radius: 10px;\n min-height: 260px; /* 动画的下限:信息很少时也不塌成一条 */\n}\n.sp-voyage iframe {\n display: block;\n width: 100%;\n height: 100%;\n border: 0;\n /* ⚠️ 用 iframe 自身的 filter 而**不是** backdrop-filter:iframe 内容不参与本文档的\n backdrop(跨文档不采样)⇒ backdrop-filter 对它无效,只有 filter 才是可靠的杠杆。\n v1.36.1:动画移入独立右栏后不再压在文字后面 ⇒ 磨砂可以收得很轻(1.2 → 0.6px),\n 既保留柔化,又让飞船细节(舷窗/引擎环)比旧版清楚。 */\n filter: blur(0.6px);\n}\n\n/* 窄屏(放不下两栏)⇒ 退回单栏:信息在上、动画在下(DOM 顺序即如此,无需改结构) */\n@media (max-width: 860px) {\n .sp-pop {\n /* 两栏放不下时,卡片回到\"不超过视口\"的旧行为 */\n width: min(420px, calc(100vw - 24px));\n }\n .sp-popVoyage {\n flex-direction: column;\n align-items: stretch;\n }\n .sp-popVoyage > .sp-popBody {\n width: auto; /* 单栏下不再固定 340px,跟随卡片宽度 */\n flex: none; /* 按内容高(仍受自身 max-height 约束) */\n }\n .sp-voyage {\n flex: none;\n height: 200px; /* 单栏时给动画明确高度,避免被 flex 压扁 */\n min-height: 0;\n }\n}\n\n.sp-popBody {\n display: flex;\n flex-direction: column;\n gap: 14px;\n max-height: calc(100vh - 140px);\n overflow-y: auto;\n}\n\n/* ── 分组(官方 settings 语言:groupTitle + rows) ── */\n\n.sp-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.sp-groupHead {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.sp-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.sp-rows {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n/* 行卡(rowCard:border + radius + padding;值与 label 分离、长内容可换行) */\n.sp-row {\n display: flex;\n align-items: baseline;\n gap: 12px;\n min-width: 0;\n padding: 8px 12px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.sp-label {\n flex: none;\n width: 76px;\n font-size: 12px;\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n}\n\n.sp-value {\n flex: 1;\n min-width: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-primary);\n font-family: var(--ds-font-family-code, monospace);\n word-break: break-all;\n overflow-wrap: anywhere;\n}\n\n/* 安全模式动作区 */\n.sp-actions {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 8px 12px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.sp-toggle {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n height: 24px;\n padding: 0 10px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 6px;\n font-size: 12px;\n cursor: pointer;\n transition: background var(--ds-transition-duration-fast, 0.1s) var(--ds-ease-in-out, ease);\n}\n\n.sp-toggleLg {\n height: 30px;\n padding: 0 16px;\n font-size: 13px;\n}\n\n.sp-toggleOn {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 14%, transparent);\n color: var(--dsw-alias-state-error-primary);\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, transparent);\n}\n\n.sp-toggleOff {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n\n.sp-toggleIcon {\n flex: none;\n}\n\n.sp-toggleDesc {\n flex: 1;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n}\n\n/* handyman 运行状态区块 */\n\n.sp-handymenToggle {\n flex: none;\n padding: 2px 10px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n cursor: pointer;\n}\n\n.sp-handymenToggle:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.sp-handymenList {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin-top: 2px;\n}\n\n.sp-handymanItem {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 8px 12px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 8px;\n min-width: 0;\n}\n\n.sp-handymanHead {\n display: flex;\n align-items: baseline;\n gap: 8px;\n min-width: 0;\n}\n\n.sp-handymanLabel {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n.sp-handymanRound {\n flex: none;\n font-size: 11px;\n color: var(--dsw-alias-label-dimmed);\n}\n\n.sp-handymanTime {\n flex: none;\n font-size: 11px;\n color: var(--dsw-alias-label-dimmed);\n}\n\n.sp-handymanResp {\n font-size: 11px;\n line-height: 16px;\n color: var(--dsw-alias-label-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.sp-handymenMore {\n font-size: 11px;\n color: var(--dsw-alias-label-dimmed);\n padding: 4px 12px;\n}\n\n/* 底部提示(配置入口引导) */\n.sp-hint {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n padding: 8px 12px;\n border: 1px dashed var(--dsw-alias-border-l2);\n border-radius: 10px;\n}\n";
|
|
12
12
|
if (typeof document !== "undefined" && document.querySelector("style[data-sp-css=\"SafeModePanel\"]") === null) {
|
|
13
13
|
const tag = document.createElement("style");
|
|
@@ -3312,7 +3312,7 @@ window.__ModuleLoader__.load({
|
|
|
3312
3312
|
return (await res.json()).config ?? null;
|
|
3313
3313
|
}
|
|
3314
3314
|
//#endregion
|
|
3315
|
-
//#region \0sp-css
|
|
3315
|
+
//#region \0sp-css:src/client/AccountsEditor
|
|
3316
3316
|
const css$4 = "/* AccountsEditor — DSH 设置面板「外部访问」区块(v1.22)\n * 与 SettingsSection ss-* 同设计语言:--dsw-alias-* 语义 token,明暗自适应。 */\n\n.ae-root {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n font-size: 13px;\n}\n\n/* ── v1.27.5 紧凑化:折叠块(details/summary)── */\n.ae-collapse {\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 8px;\n overflow: hidden;\n}\n\n.ae-collapseHead {\n display: flex;\n align-items: baseline;\n gap: 8px;\n padding: 8px 12px;\n cursor: pointer;\n list-style: none;\n user-select: none;\n}\n\n.ae-collapseHead::-webkit-details-marker {\n display: none;\n}\n\n.ae-collapseHead::before {\n content: '▸';\n flex: none;\n font-size: 11px;\n color: var(--dsw-alias-label-dimmed);\n transition: transform 0.15s ease;\n}\n\n.ae-collapse[open] > .ae-collapseHead::before {\n transform: rotate(90deg);\n}\n\n.ae-collapseHead:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(128, 128, 128, 0.06));\n}\n\n.ae-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.ae-collapseBody {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 8px 12px 10px;\n border-top: 1px solid var(--dsw-alias-border-l1);\n}\n\n.ae-warn {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-warn-label);\n word-break: break-word;\n}\n\n.ae-block {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.ae-title {\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.ae-desc {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n.ae-note {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n}\n\n/* ── 监听设置 / 白名单输入行 ── */\n\n.ae-row {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.ae-label {\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.ae-input {\n flex: 1;\n min-width: 0;\n padding: 6px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n outline: none;\n}\n\n.ae-input:focus {\n border-color: var(--dsw-alias-button-ghost-active-border);\n}\n\n.ae-input::placeholder {\n color: var(--dsw-alias-label-dimmed);\n}\n\n.ae-input.ae-port {\n flex: none;\n width: 76px;\n}\n\n/* ── 账号列表 ── */\n\n.ae-list {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.ae-head {\n display: flex;\n gap: 8px;\n font-size: 11px;\n font-weight: 500;\n color: var(--dsw-alias-label-dimmed);\n padding: 0 2px;\n text-transform: uppercase;\n letter-spacing: 0.02em;\n}\n\n.ae-item {\n display: flex;\n gap: 8px;\n align-items: center;\n padding: 6px 2px;\n}\n\n.ae-colUser { flex: 1.2; }\n.ae-colPass { flex: 1.6; }\n.ae-colTotp { flex: 2.2; min-width: 0; }\n.ae-colOp { flex: none; width: 48px; }\n\n/* ── v1.22.4 TOTP 第二因素 ── */\n\n.ae-totpBtn {\n flex: none;\n padding: 4px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n cursor: pointer;\n white-space: nowrap;\n}\n\n.ae-totpBtn:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.ae-totpPending {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n align-items: center;\n min-width: 0;\n}\n\n/* v1.24.6:TOTP 绑定二维码(扫码即录入;scalable SVG,白底保证扫码识别) */\n.ae-totpQr {\n flex-basis: 100%;\n display: inline-flex;\n justify-content: center;\n padding: 8px;\n background: #fff;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 8px;\n}\n\n.ae-totpQr svg {\n width: 132px;\n height: 132px;\n display: block;\n}\n\n.ae-totpSecret {\n font-family: var(--ds-font-family-code);\n font-size: 11px;\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 4px;\n padding: 2px 6px;\n color: var(--dsw-alias-label-secondary);\n word-break: break-all;\n}\n\n.ae-totpUri {\n font-size: 11px;\n color: var(--dsw-alias-button-info-fill);\n text-decoration: none;\n}\n\n.ae-totpUri:hover {\n text-decoration: underline;\n}\n\n/* v1.24.7:绑定提示(去确认码后——扫码或手动录入,保存即绑定) */\n.ae-totpHint {\n flex-basis: 100%;\n font-size: 11px;\n color: var(--dsw-alias-label-tertiary);\n}\n\n.ae-totpBadge {\n font-size: 12px;\n color: var(--dsw-alias-state-warn-label);\n}\n\n.ae-totpClear {\n display: flex;\n gap: 6px;\n align-items: center;\n}\n\n.ae-check {\n display: flex;\n gap: 8px;\n align-items: center;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n margin-top: 10px;\n cursor: pointer;\n}\n\n.ae-check input {\n accent-color: var(--dsw-alias-button-info-fill);\n}\n\n.ae-del {\n flex: none;\n padding: 4px 10px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-state-error-primary);\n font-size: 12px;\n cursor: pointer;\n}\n\n.ae-del:hover {\n background: var(--dsw-alias-interactive-bg-hover-danger);\n}\n\n.ae-add {\n align-self: flex-start;\n padding: 5px 12px;\n border: 1px dashed var(--dsw-alias-border-l2);\n border-radius: 8px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n cursor: pointer;\n}\n\n.ae-add:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.ae-wsSelect {\n margin-top: 8px;\n max-width: 100%;\n cursor: pointer;\n}\n\n/* ── 工作区白名单 chips ── */\n\n.ae-wsList {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n.ae-wsChip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 3px 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.14));\n}\n\n.ae-wsPath {\n font-size: 12px;\n color: var(--dsw-alias-label-primary);\n font-family: var(--ds-font-family-code, monospace);\n word-break: break-all;\n}\n\n.ae-wsDel {\n flex: none;\n width: 18px;\n height: 18px;\n border: none;\n border-radius: 50%;\n background: transparent;\n color: var(--dsw-alias-label-dimmed);\n font-size: 13px;\n line-height: 1;\n cursor: pointer;\n}\n\n.ae-wsDel:hover {\n background: var(--dsw-alias-interactive-bg-hover-danger);\n color: var(--dsw-alias-state-error-primary);\n}\n\n/* ── 错误 / 操作区 ── */\n\n.ae-error {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-error-primary);\n word-break: break-word;\n}\n\n.ae-actions {\n display: flex;\n justify-content: flex-end;\n padding-top: 4px;\n border-top: 1px solid var(--dsw-alias-border-l1);\n}\n\n.ae-save {\n padding: 7px 24px;\n border: 0;\n border-radius: 8px;\n background: var(--dsw-alias-button-primary-fill);\n color: var(--dsw-alias-label-primary-foreground);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n}\n\n.ae-save:hover:not(:disabled) {\n filter: brightness(1.08);\n}\n\n.ae-save:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n/* ── v1.26.2 建议问答页配置(PublicAskEditor:开放容器白名单 chips + key/地址展示)── */\n\n.ae-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin: 8px 0 4px;\n}\n\n.ae-chip {\n padding: 4px 12px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 999px;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n cursor: pointer;\n transition: background 0.15s ease, border-color 0.15s ease;\n}\n\n.ae-chip:hover {\n border-color: var(--dsw-alias-button-ghost-active-border);\n}\n\n.ae-chipOn {\n background: var(--dsw-alias-button-primary-fill);\n border-color: var(--dsw-alias-button-primary-fill);\n color: var(--dsw-alias-label-primary-foreground);\n}\n\n.ae-saved {\n margin-left: 10px;\n font-size: 12px;\n color: var(--dsw-alias-state-success-primary);\n}\n\n.ae-err {\n margin-left: 10px;\n font-size: 12px;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.ae-key {\n font-family: var(--ds-font-family-code);\n font-size: 12px;\n padding: 2px 8px;\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n word-break: break-all;\n user-select: all;\n}\n\n.ae-copy {\n flex: none;\n margin-left: 8px;\n padding: 3px 10px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n cursor: pointer;\n}\n\n.ae-copy:hover {\n border-color: var(--dsw-alias-button-ghost-active-border);\n color: var(--dsw-alias-label-primary);\n}\n\n/* v1.26.5 轮换 key(警示色:旧 key 立即失效) */\n.ae-rotate {\n color: var(--dsw-alias-state-error-primary);\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 35%, transparent);\n}\n\n.ae-rotate:hover {\n border-color: var(--dsw-alias-state-error-primary);\n color: var(--dsw-alias-state-error-primary);\n}\n\n.ae-rotate:disabled {\n opacity: 0.6;\n cursor: wait;\n}\n\n.ae-rows {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin-top: 8px;\n}\n\n.ae-labelDim {\n opacity: 0.65;\n min-width: 96px;\n}\n";
|
|
3317
3317
|
if (typeof document !== "undefined" && document.querySelector("style[data-sp-css=\"AccountsEditor\"]") === null) {
|
|
3318
3318
|
const tag = document.createElement("style");
|
|
@@ -3729,7 +3729,7 @@ window.__ModuleLoader__.load({
|
|
|
3729
3729
|
});
|
|
3730
3730
|
}
|
|
3731
3731
|
//#endregion
|
|
3732
|
-
//#region \0sp-css
|
|
3732
|
+
//#region \0sp-css:src/client/PersonaEditor
|
|
3733
3733
|
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";
|
|
3734
3734
|
if (typeof document !== "undefined" && document.querySelector("style[data-sp-css=\"PersonaEditor\"]") === null) {
|
|
3735
3735
|
const tag = document.createElement("style");
|
|
@@ -4625,7 +4625,7 @@ Instruction-following style:
|
|
|
4625
4625
|
children: "?"
|
|
4626
4626
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4627
4627
|
className: "ss-helpTip",
|
|
4628
|
-
children: "路由表:微信用户 → skiff 角色映射\n· 格式:[{\"user\": \"xxx@im.wechat\", \"role\": \"
|
|
4628
|
+
children: "路由表:微信用户 → skiff 角色映射\n· 格式:[{\"user\": \"xxx@im.wechat\", \"role\": \"my-role\"}, ...]\n· user = 微信用户 ID(from_user_id);`*` = 通配兜底\n· role = 该 CCC 已定义的 skiff.roles 角色名\n· 未命中路由的用户不回复(不暴露机器人)"
|
|
4629
4629
|
})]
|
|
4630
4630
|
})
|
|
4631
4631
|
]
|
|
@@ -4662,7 +4662,7 @@ Instruction-following style:
|
|
|
4662
4662
|
});
|
|
4663
4663
|
}
|
|
4664
4664
|
//#endregion
|
|
4665
|
-
//#region \0sp-css
|
|
4665
|
+
//#region \0sp-css:src/client/SettingsSection
|
|
4666
4666
|
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/* 阈值行(滑块 + 值) */\n.ss-threshold {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.ss-threshold input[type='range'] {\n width: 160px;\n}\n\n/* Skiff 调试端口输入(number;关闭时跟随 disabled 半透明) */\n.ss-portInput {\n width: 96px;\n padding: 6px 8px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-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.ss-value {\n min-width: 40px;\n font-variant-numeric: tabular-nums;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n text-align: right;\n}\n\n/* 自主轨迹「立即唤起」按钮(v1.26.14 调试语义;官方 button 语言:primary 弱化) */\n.ss-wakeBtn {\n flex: none;\n padding: 5px 12px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-interactive-bg-active, rgba(128, 128, 128, 0.12));\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n cursor: pointer;\n transition: opacity var(--ds-transition-duration-fast, 0.15s) ease;\n}\n\n.ss-wakeBtn:hover:not(:disabled) {\n border-color: var(--dsw-alias-state-success-primary, #22c55e);\n color: var(--dsw-alias-state-success-primary, #22c55e);\n}\n\n.ss-wakeBtn:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n/* 底部帮助行 */\n.ss-hint {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 降级提示 */\n.ss-degrade {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-warn-label);\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n/* 错误提示(v1.29 会话清理等) */\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/* ── v1.27.5 紧凑化:只读定义列表(dl/dt/dd 2 列网格)── */\n.ss-defList {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 6px 20px;\n margin: 0;\n width: 100%;\n min-width: 0;\n}\n\n.ss-defItem {\n display: flex;\n flex-direction: column;\n gap: 1px;\n min-width: 0;\n}\n\n.ss-defTerm {\n font-size: 11px;\n line-height: 16px;\n font-weight: 500;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n color: var(--dsw-alias-label-tertiary);\n}\n\n.ss-defValue {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-primary);\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/* ── v1.27.5 紧凑化:开关 + 端口内联行 ── */\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";
|
|
4667
4667
|
if (typeof document !== "undefined" && document.querySelector("style[data-sp-css=\"SettingsSection\"]") === null) {
|
|
4668
4668
|
const tag = document.createElement("style");
|
|
@@ -5257,7 +5257,7 @@ Instruction-following style:
|
|
|
5257
5257
|
};
|
|
5258
5258
|
}
|
|
5259
5259
|
//#endregion
|
|
5260
|
-
//#region \0sp-css
|
|
5260
|
+
//#region \0sp-css:src/client/DiagramToolView
|
|
5261
5261
|
const css$1 = "/*\n * DiagramToolView.css — `diagram` 工具行(Chat 视图)\n *\n * 🔴 只用 design-platform 的**官方** token(`--dsw-alias-*`)。\n * 自造 token(如 --sp-color / --text-primary)在浅色主题下 var() 永不解析 ⇒ 永远走深色 fallback\n * ⇒ 黑块 / 黑字(2026-09-04 S142 用户反馈的成因)。`tests/client-css-tokens.test.ts` 机械守卫此约束。\n * 本文件用到的 5 个 token 均在官方词汇表内:bg-layer-1 / border-l1 /\n * label-primary / label-secondary / state-error-primary。\n */\n\n.sp-dgRow {\n display: flex;\n flex-direction: column;\n gap: 6px;\n min-width: 0;\n}\n\n.sp-dgTitle {\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n word-break: break-word;\n}\n\n.sp-dgHint {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* 图自身有像素尺寸;这里只兜住容器宽度(窄屏不溢出)与圆角/描边 */\n.sp-dgImage {\n display: block;\n max-width: 100%;\n height: auto;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-1);\n}\n\n/* 信封文字:结果原文里的换行是有意排版的(一行一个图元/lint 项)⇒ 保留换行 */\n.sp-dgText {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.sp-dgError {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-error-primary);\n}\n";
|
|
5262
5262
|
if (typeof document !== "undefined" && document.querySelector("style[data-sp-css=\"DiagramToolView\"]") === null) {
|
|
5263
5263
|
const tag = document.createElement("style");
|
|
@@ -5437,7 +5437,7 @@ Instruction-following style:
|
|
|
5437
5437
|
return out;
|
|
5438
5438
|
}
|
|
5439
5439
|
//#endregion
|
|
5440
|
-
//#region \0sp-css
|
|
5440
|
+
//#region \0sp-css:src/client/DiagramImageTail
|
|
5441
5441
|
const css = "/**\n * DiagramImageTail.css — 轮尾图行的样式(v1.51.3)\n *\n * 与 `DiagramToolView.css` 同规矩:**只用官方 `--dsw-alias-*` 词汇表里的令牌**,\n * 圆角/尺寸用字面量(`--dsw-radius-*` **不在**官方 alias 词汇表里,`client-css-tokens.test.ts`\n * 会把它当自造 token 拦下 —— 浅色主题下会变成黑块)。\n */\n.sp-dtRoot {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n margin-top: 12px;\n}\n\n.sp-dtImage {\n max-width: 100%;\n height: auto;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-1);\n}\n\n/* 字节还在读(或读数被拒)时的占位 —— 与图的左边缘对齐,避免行高跳动 */\n.sp-dtPending {\n width: 160px;\n height: 100px;\n border-radius: 6px;\n background: var(--dsw-alias-interactive-bg-hover);\n}\n";
|
|
5442
5442
|
if (typeof document !== "undefined" && document.querySelector("style[data-sp-css=\"DiagramImageTail\"]") === null) {
|
|
5443
5443
|
const tag = document.createElement("style");
|
package/lib/cro-guide.d.ts
CHANGED
|
@@ -23,7 +23,9 @@ import { type CroSnapshotInput } from './cro.js';
|
|
|
23
23
|
/**
|
|
24
24
|
* 样例快照输入 —— **代表性数据**(不是真实某条轨迹的现状)。
|
|
25
25
|
*
|
|
26
|
-
* 取值刻意让它能演示所有者举的
|
|
26
|
+
* 取值刻意让它能演示所有者举的"天亮/有人/非高峰 + 已在干活 + 日志过大"场景。
|
|
27
|
+
* 🔒 **路径与轨迹名一律用中性占位**(`/home/user/workspace`、`<S###>` 式示例),
|
|
28
|
+
* 不写任何真实机器路径或私有会话名 —— 本文件随 npm 包发布(2026-10-14 隐私核查)。
|
|
27
29
|
*/
|
|
28
30
|
export declare const CRO_SAMPLE_SNAPSHOT_INPUT: CroSnapshotInput;
|
|
29
31
|
/**
|
package/lib/git-ops.d.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* - diff:git diff [--cached] [<ref>] [-- <path>]
|
|
12
12
|
* 保留 dsp 增强:localstore git 合规联动(S134:deny 且 .gitignore 未覆盖 → status 提示 / commit 拒绝)。
|
|
13
13
|
*
|
|
14
|
-
* 🔴 2026-09-26
|
|
14
|
+
* 🔴 2026-09-26 修(由另一个 CCC 实例报障):**push 曾把"超时被杀"报成成功**。
|
|
15
15
|
* 机制(**实测**,非推断):`spawnSync` 超时**不设 `err.killed`**(实测 `code=ETIMEDOUT` /
|
|
16
16
|
* `signal=SIGTERM` / `status=null` / `stderr` 长度 0),而 `execFileSync` **成功时丢弃 stderr**;
|
|
17
17
|
* 于是"超时被杀"与"真成功"都交出 `{stdout:'', stderr:''}` —— 旧判据 `if (!stderr) → 成功`
|
package/lib/im-weixin.d.ts
CHANGED
|
@@ -12,8 +12,15 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import type { ImChannel } from './im-bridge.js';
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* 解析该 CCC 的别名表(v1.56.10)。
|
|
16
|
+
*
|
|
17
|
+
* 🔴 **为什么不再硬编码**(2026-10-14 隐私核查):别名是**使用者自己的称呼**,属 CCC 的数据
|
|
18
|
+
* (D23:加一个别名不该要发版)。此前硬编码在 ACC 源码 ⇒ **这些称呼随 npm 包公开发布**。
|
|
19
|
+
* 现在别名**只**来自该 CCC 的 `.opencode/serenity.json` → `weixin.aliases`;
|
|
20
|
+
* ACC 不认识任何具体名字。未配置 ⇒ `{}`(此时只能用裸 iLink 用户 id)。
|
|
21
|
+
*
|
|
22
|
+
* ⚠️ **迁移**:升级前用过别名的部署,需把原表补进自己的 CCC 配置,否则别名解析不到
|
|
23
|
+
* (见 CHANGELOG v1.56.10 的迁移段;裸 `xxx@im.wechat` 形式始终可用)。
|
|
17
24
|
*/
|
|
18
|
-
export declare
|
|
25
|
+
export declare function weixinAliasMap(root: string): Record<string, string>;
|
|
19
26
|
export declare const weixinChannel: ImChannel;
|
package/lib/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
|
|
2
2
|
import { a as hostSessions, c as hostWeb, i as hostService, l as hostWebServer, n as hostInjected, o as hostSettings, r as hostLlm, s as hostSubagents, t as hostAgents } from "./access-CNccNtgf.js";
|
|
3
3
|
import { _ as resolveInside, a as findSerenityRoot$1, c as matchBlacklist, d as readCccName$1, f as readExclusiveTools, h as readTrajectorySkills, i as findGitRoot, l as pathInside, m as readSafeModeHiddenTools, n as SAFE_MODE_MARKER, o as isSafeModeOn, p as readHandymanConfig, r as classifyPath, s as loadSerenityConfig, t as DEFAULT_SERENITY_CONFIG_PATHS, u as readBlacklist } from "./ccc-DXky9UZu.js";
|
|
4
|
-
import { i as cccRootForExec, n as agentCwdFor, o as listCccs, r as cccRootForCwd, t as NO_CCC_FROM_AGENT_CWD } from "./ccc-roots-
|
|
5
|
-
import { A as localIdStamp, C as setActiveSessionInfo, D as isoLocal, E as useSession, O as localFileStamp, S as sessionsRoot, T as summarize, _ as namingTitleFor, a as pruneMissingBindings, b as resolveSessionByTitle, c as setBindingStore, d as clearActiveSessionInfo, f as createSession, g as listSessions, h as getActiveSessionInfo, i as listBoundSessionIds, k as localHuman, l as DEFAULT_SESSION_SCOPE, m as findSession, n as PLUGIN_SOURCE, o as readLastBound, p as extractSessionMdPathFromText, r as appendBound, s as resolveSessionTrajectoryLabel, t as ACC_MESSAGE_KIND, u as TRAJECTORY_ACTIONS, v as parseSessionContextFromEvents, w as showSession, x as sessionEvents$1, y as readActiveSessionMd } from "./message-source-
|
|
6
|
-
import { a as readWeixinCredential, c as weixinInboundDir, d as LOCALSTORE_SCOPES, f as checkLocalstoreGitCompliance, g as runLocalStore, h as readStore, i as matchWeixinRoute, l as weixinSessionIdFor, m as readGitTrack, n as extractWeixinText, o as readWeixinSettings, p as localstorePath, r as hasVoiceItem, s as sanitizeFileName$1, t as extractWeixinMedia } from "./weixin-route-
|
|
4
|
+
import { i as cccRootForExec, n as agentCwdFor, o as listCccs, r as cccRootForCwd, t as NO_CCC_FROM_AGENT_CWD } from "./ccc-roots-CDW2dO0n.js";
|
|
5
|
+
import { A as localIdStamp, C as setActiveSessionInfo, D as isoLocal, E as useSession, O as localFileStamp, S as sessionsRoot, T as summarize, _ as namingTitleFor, a as pruneMissingBindings, b as resolveSessionByTitle, c as setBindingStore, d as clearActiveSessionInfo, f as createSession, g as listSessions, h as getActiveSessionInfo, i as listBoundSessionIds, k as localHuman, l as DEFAULT_SESSION_SCOPE, m as findSession, n as PLUGIN_SOURCE, o as readLastBound, p as extractSessionMdPathFromText, r as appendBound, s as resolveSessionTrajectoryLabel, t as ACC_MESSAGE_KIND, u as TRAJECTORY_ACTIONS, v as parseSessionContextFromEvents, w as showSession, x as sessionEvents$1, y as readActiveSessionMd } from "./message-source-CQNfQaTx.js";
|
|
6
|
+
import { a as readWeixinCredential, c as weixinInboundDir, d as LOCALSTORE_SCOPES, f as checkLocalstoreGitCompliance, g as runLocalStore, h as readStore, i as matchWeixinRoute, l as weixinSessionIdFor, m as readGitTrack, n as extractWeixinText, o as readWeixinSettings, p as localstorePath, r as hasVoiceItem, s as sanitizeFileName$1, t as extractWeixinMedia } from "./weixin-route-CxCciqQl.js";
|
|
7
7
|
import { a as unregisterSkiffSession$1, i as skiffSessionSnapshot$1, n as skiffRoleFor$1, o as ACC_VERSION, r as skiffSessionInfo$1, t as registerSkiffSession$1 } from "./skiff-registry-BjIX_KD1.js";
|
|
8
|
-
import { a as readSkiffRoles, c as roleMsmWhitelist, d as systemPromptSource, f as trajectorySubset, i as isSkiffSessionId, l as roleToolWhitelist, n as buildSkiffBasePrompt, o as resolveRoleSystemPrompt, r as createRolePromptReader, s as resolveSkiffKind } from "./skiff-role-
|
|
8
|
+
import { a as readSkiffRoles, c as roleMsmWhitelist, d as systemPromptSource, f as trajectorySubset, i as isSkiffSessionId, l as roleToolWhitelist, n as buildSkiffBasePrompt, o as resolveRoleSystemPrompt, r as createRolePromptReader, s as resolveSkiffKind } from "./skiff-role-Det66X16.js";
|
|
9
9
|
import { a as ACP_HTTP_PORT, c as MAIN_WEB_PORT, d as WEIXIN_SEND_PORT, l as MECHANISM_PORTS, n as readSimpleSettings, o as FACE_PORTS, r as registerSettingsSection, s as GATEWAY_PORT, u as SKIFF_DEBUG_PORT } from "./settings-section-xHABl8nk.js";
|
|
10
10
|
import { REGISTERED_TOOLS } from "./invariant.js";
|
|
11
11
|
import { a as markdownToPlainText, c as sendTyping, i as getUpdates, l as sniffImageExt, n as downloadMedia, o as sendFileMessage, r as getConfig, s as sendTextMessage, t as TypingStatus } from "./weixin-api-BrRcPiQs.js";
|
|
@@ -623,7 +623,7 @@ function createKitTool(ctx) {
|
|
|
623
623
|
* - diff:git diff [--cached] [<ref>] [-- <path>]
|
|
624
624
|
* 保留 dsp 增强:localstore git 合规联动(S134:deny 且 .gitignore 未覆盖 → status 提示 / commit 拒绝)。
|
|
625
625
|
*
|
|
626
|
-
* 🔴 2026-09-26
|
|
626
|
+
* 🔴 2026-09-26 修(由另一个 CCC 实例报障):**push 曾把"超时被杀"报成成功**。
|
|
627
627
|
* 机制(**实测**,非推断):`spawnSync` 超时**不设 `err.killed`**(实测 `code=ETIMEDOUT` /
|
|
628
628
|
* `signal=SIGTERM` / `status=null` / `stderr` 长度 0),而 `execFileSync` **成功时丢弃 stderr**;
|
|
629
629
|
* 于是"超时被杀"与"真成功"都交出 `{stdout:'', stderr:''}` —— 旧判据 `if (!stderr) → 成功`
|
|
@@ -642,7 +642,7 @@ const GIT_ACTIONS = [
|
|
|
642
642
|
];
|
|
643
643
|
/** 本地动作超时(ms) */
|
|
644
644
|
const DEFAULT_LOCAL_TIMEOUT_MS = 3e4;
|
|
645
|
-
/** 网络动作(fetch/push/pull)超时(ms)——大体量推送可能远超 30s
|
|
645
|
+
/** 网络动作(fetch/push/pull)超时(ms)——大体量推送可能远超 30s(实测某实例 >60s) */
|
|
646
646
|
const DEFAULT_NET_TIMEOUT_MS = 18e4;
|
|
647
647
|
/**
|
|
648
648
|
* 超时可覆盖(`DSH_localTimeout()` / `DSH_netTimeout()`)。
|
|
@@ -1324,7 +1324,7 @@ CCC 级微信个人号接入(iLink 协议):dsh 一进程多 CCC,每 CCC
|
|
|
1324
1324
|
"autoReplyWithLastMessage": true,
|
|
1325
1325
|
"fallbackOnNoSend": false,
|
|
1326
1326
|
"accounts": [{ "accountId": "wechat-1", "name": "家庭助手", "enabled": true }],
|
|
1327
|
-
"routes": [{ "user": "*", "role": "
|
|
1327
|
+
"routes": [{ "user": "*", "role": "my-role" }]
|
|
1328
1328
|
} }
|
|
1329
1329
|
|
|
1330
1330
|
▸ weixin.hook(消息记录 hook,v1.27.13):
|
|
@@ -1347,7 +1347,7 @@ CCC 级微信个人号接入(iLink 协议):dsh 一进程多 CCC,每 CCC
|
|
|
1347
1347
|
事件 schema(**不含任何会话凭据**——context_token/bot_token/token/aes_key 均不出现):
|
|
1348
1348
|
{ "event": "incoming", "ts": 1788359941488, "cccRoot": "/path/ccc",
|
|
1349
1349
|
"accountId": "wechat-1", "userId": "u1@im.wechat",
|
|
1350
|
-
"sessionId": "skiff-weixin-xxx", "role": "
|
|
1350
|
+
"sessionId": "skiff-weixin-xxx", "role": "my-role",
|
|
1351
1351
|
"message": { "text": "你好", "media": [{ "kind": "image", "relPath": "_tmp/weixin-inbound/<hash>/img_x.jpg" }] } }
|
|
1352
1352
|
{ "event": "outgoing", "ts": ..., "cccRoot": ..., "accountId": ...,
|
|
1353
1353
|
"userId": ..., "sessionId": ..., "role": ...,
|
|
@@ -2132,11 +2132,10 @@ function waitAgentIdle(ctx, agent) {
|
|
|
2132
2132
|
* skills-discovery.ts — CCC 入口 skill 自动发现(纯逻辑,零 DSH 依赖)
|
|
2133
2133
|
*
|
|
2134
2134
|
* 发现全部入口技能(原文全量,不截断)—— **现行三个来源**(原为四个,**来源 3 已于 2026-09-21 删除**):
|
|
2135
|
-
* 0. **`.serenity` 记号文件内容 = 顶层入口 skill 名**(CCC
|
|
2136
|
-
* tiangong-serenity 的 .serenity 内容为 `tg-serenity`)—— 最高优先
|
|
2135
|
+
* 0. **`.serenity` 记号文件内容 = 顶层入口 skill 名**(CCC 记号文件的权威语义)—— 最高优先
|
|
2137
2136
|
* 1. `.dsh/entry-skill` 指针文件(内容 = skill 名)—— 兼容旧约定
|
|
2138
2137
|
* 2. `.opencode/skills/*-serenity/SKILL.md` —— 自动扫描该 CCC 的顶层入口
|
|
2139
|
-
*
|
|
2138
|
+
* (命名模式 `*-serenity`)
|
|
2140
2139
|
* ~~3. `.dsh/skills/*-serenity/SKILL.md`(扫 ACC 装进 CCC 的技能副本)~~ —— 🔴 **已删**:
|
|
2141
2140
|
* owner 2026-09-21 令「连模板和安装命令一起删」(B 案)。**判据、实测证据与日期逐字记在
|
|
2142
2141
|
* `findEntrySkills()` 体内那一段注释里**——本头部只留结论,**不复述判据**(避免两处会漂的真相源)。
|
|
@@ -4017,7 +4016,7 @@ const AUTO_BOUND_NOTE_PREFIX = "auto-created for skiff role";
|
|
|
4017
4016
|
* 注入 agent 系统提示词(用户对话面不可见)。
|
|
4018
4017
|
*
|
|
4019
4018
|
* v1.30.13(S142 诊断 D5):写入纪律**不点名具体工具**。旧文案写死 "with write/edit",
|
|
4020
|
-
*
|
|
4019
|
+
* 而某角色的工具白名单已移除 write/edit(写能力收归 CCC 的 session-write MSM)
|
|
4021
4020
|
* → 指令指向它根本没有的工具(注入纪律与能力面矛盾,模型只能猜)。
|
|
4022
4021
|
* 现文案改为「用本角色被授权的写入通道」——ACC 只声明义务(写进工作台),
|
|
4023
4022
|
* 具体通道由 CCC 的角色配置与角色提示词决定(ACC/CCC 归属二分;也不把某个 CCC 的
|
|
@@ -7391,7 +7390,7 @@ function cmdCompliance(args) {
|
|
|
7391
7390
|
*
|
|
7392
7391
|
* 2026-09-14 S188 修(缺陷④):旧实现把 `skillDependsOn(A, B)` 的两端都收进 targets,
|
|
7393
7392
|
* 于是按生成指引逐 target 审会得到一半**方向错误的伪 Fail**(如"home-memory 未声明
|
|
7394
|
-
* 依赖
|
|
7393
|
+
* 依赖 `roleX-memory`"——B 端根本不欠任何声明)。同时修缺陷⑤:合取式
|
|
7395
7394
|
* (`dependsOn(X,A) and dependsOn(X,B)`)里 X 出现两次,旧实现不去重。
|
|
7396
7395
|
*/
|
|
7397
7396
|
function findDependsOnDeclarers(node) {
|
|
@@ -11985,13 +11984,15 @@ function registerWakeScheduler(ctx) {
|
|
|
11985
11984
|
/**
|
|
11986
11985
|
* 样例快照输入 —— **代表性数据**(不是真实某条轨迹的现状)。
|
|
11987
11986
|
*
|
|
11988
|
-
* 取值刻意让它能演示所有者举的
|
|
11987
|
+
* 取值刻意让它能演示所有者举的"天亮/有人/非高峰 + 已在干活 + 日志过大"场景。
|
|
11988
|
+
* 🔒 **路径与轨迹名一律用中性占位**(`/home/user/workspace`、`<S###>` 式示例),
|
|
11989
|
+
* 不写任何真实机器路径或私有会话名 —— 本文件随 npm 包发布(2026-10-14 隐私核查)。
|
|
11989
11990
|
*/
|
|
11990
11991
|
const CRO_SAMPLE_SNAPSHOT_INPUT = {
|
|
11991
|
-
dirName: "2026-
|
|
11992
|
-
cccRoot: "/home/
|
|
11992
|
+
dirName: "2026-01-01--S001--example-trajectory",
|
|
11993
|
+
cccRoot: "/home/user/workspace",
|
|
11993
11994
|
nowMs: 17898e8,
|
|
11994
|
-
sessionMdPath: "/home/
|
|
11995
|
+
sessionMdPath: "/home/user/workspace/AGENT_SESSIONS/2026-01-01--S001--example-trajectory/SESSION.md",
|
|
11995
11996
|
sessionMdBytes: 182e3,
|
|
11996
11997
|
sessionMdMtimeMs: 1789799e6,
|
|
11997
11998
|
references: [{
|
|
@@ -12007,10 +12008,10 @@ const CRO_SAMPLE_SNAPSHOT_INPUT = {
|
|
|
12007
12008
|
liveSessionIds: ["session-adccc461-9f32-4d9a-a688-9da81fa1ca35"],
|
|
12008
12009
|
runningSessionIds: [],
|
|
12009
12010
|
pendingWakes: [{
|
|
12010
|
-
id: "w-
|
|
12011
|
-
at: "2026-
|
|
12012
|
-
createdAt: "2026-
|
|
12013
|
-
createdBy: "
|
|
12011
|
+
id: "w-20260101-0900-aaaa",
|
|
12012
|
+
at: "2026-01-01T09:30:00+08:00",
|
|
12013
|
+
createdAt: "2026-01-01T07:00:00+08:00",
|
|
12014
|
+
createdBy: "S001"
|
|
12014
12015
|
}],
|
|
12015
12016
|
scheduler: {
|
|
12016
12017
|
armed: true,
|
|
@@ -15482,11 +15483,11 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
15482
15483
|
sendJson$4(res, 400, { error: chk.error });
|
|
15483
15484
|
return;
|
|
15484
15485
|
}
|
|
15485
|
-
const { readWeixinSettings } = await import("./weixin-route-
|
|
15486
|
+
const { readWeixinSettings } = await import("./weixin-route-CxCciqQl.js").then((n) => n.u);
|
|
15486
15487
|
const { weixinBridgeStatus } = await Promise.resolve().then(() => weixin_bridge_exports);
|
|
15487
15488
|
const settings = readWeixinSettings(chk.root);
|
|
15488
15489
|
const bridge = weixinBridgeStatus().find((b) => b.ccc === chk.root);
|
|
15489
|
-
const { readWeixinCredential } = await import("./weixin-route-
|
|
15490
|
+
const { readWeixinCredential } = await import("./weixin-route-CxCciqQl.js").then((n) => n.u);
|
|
15490
15491
|
const accounts = (settings.accounts ?? []).map((a) => ({
|
|
15491
15492
|
accountId: a.accountId,
|
|
15492
15493
|
name: a.name ?? void 0,
|
|
@@ -15518,7 +15519,7 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
15518
15519
|
const { fetchQRCode } = await import("./weixin-api-BrRcPiQs.js").then((n) => n.u);
|
|
15519
15520
|
const { randomUUID } = await import("node:crypto");
|
|
15520
15521
|
for (const [key, v] of weixinLogins) if (Date.now() - v.startedAt > WEIXIN_LOGIN_TTL_MS) weixinLogins.delete(key);
|
|
15521
|
-
const { readWeixinSettings } = await import("./weixin-route-
|
|
15522
|
+
const { readWeixinSettings } = await import("./weixin-route-CxCciqQl.js").then((n) => n.u);
|
|
15522
15523
|
const qr = await fetchQRCode({ botType: readWeixinSettings(root).botType ?? void 0 });
|
|
15523
15524
|
const loginKey = randomUUID();
|
|
15524
15525
|
weixinLogins.set(loginKey, {
|
|
@@ -15539,7 +15540,7 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
15539
15540
|
sendJson$4(res, 400, { error: "missing accountId" });
|
|
15540
15541
|
return;
|
|
15541
15542
|
}
|
|
15542
|
-
const { removeWeixinAccount } = await import("./weixin-route-
|
|
15543
|
+
const { removeWeixinAccount } = await import("./weixin-route-CxCciqQl.js").then((n) => n.u);
|
|
15543
15544
|
const { syncCccBridge } = await Promise.resolve().then(() => weixin_bridge_exports);
|
|
15544
15545
|
removeWeixinAccount(root, body.accountId);
|
|
15545
15546
|
syncCccBridge(ctx, root);
|
|
@@ -15552,8 +15553,8 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
15552
15553
|
sendJson$4(res, 400, { error: "invalid routes (expected [{user, role}, ...])" });
|
|
15553
15554
|
return;
|
|
15554
15555
|
}
|
|
15555
|
-
const { saveWeixinRoutes } = await import("./weixin-route-
|
|
15556
|
-
const { readSkiffRoles } = await import("./skiff-role-
|
|
15556
|
+
const { saveWeixinRoutes } = await import("./weixin-route-CxCciqQl.js").then((n) => n.u);
|
|
15557
|
+
const { readSkiffRoles } = await import("./skiff-role-Det66X16.js").then((n) => n.u);
|
|
15557
15558
|
const roles = readSkiffRoles(root);
|
|
15558
15559
|
for (const r of routes) if (!roles.has(r.role)) {
|
|
15559
15560
|
sendJson$4(res, 400, { error: `unknown role: ${r.role} (not in ${root} skiff.roles)` });
|
|
@@ -15565,7 +15566,7 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
15565
15566
|
}
|
|
15566
15567
|
if (body.action === "set-enabled") {
|
|
15567
15568
|
const enabled = body.enabled === true;
|
|
15568
|
-
const { readWeixinSettings, setWeixinEnabled } = await import("./weixin-route-
|
|
15569
|
+
const { readWeixinSettings, setWeixinEnabled } = await import("./weixin-route-CxCciqQl.js").then((n) => n.u);
|
|
15569
15570
|
const { syncCccBridge } = await Promise.resolve().then(() => weixin_bridge_exports);
|
|
15570
15571
|
const settings = readWeixinSettings(root);
|
|
15571
15572
|
if (enabled && (settings.accounts ?? []).length === 0) {
|
|
@@ -15609,7 +15610,7 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
15609
15610
|
return;
|
|
15610
15611
|
}
|
|
15611
15612
|
const { pollQRStatus } = await import("./weixin-api-BrRcPiQs.js").then((n) => n.u);
|
|
15612
|
-
const { readWeixinSettings } = await import("./weixin-route-
|
|
15613
|
+
const { readWeixinSettings } = await import("./weixin-route-CxCciqQl.js").then((n) => n.u);
|
|
15613
15614
|
const settings = readWeixinSettings(login.root);
|
|
15614
15615
|
const status = await pollQRStatus({
|
|
15615
15616
|
baseUrl: void 0,
|
|
@@ -15624,7 +15625,7 @@ function registerStatusApi(ctx, opts = {}) {
|
|
|
15624
15625
|
});
|
|
15625
15626
|
return;
|
|
15626
15627
|
}
|
|
15627
|
-
const { upsertWeixinAccount, writeWeixinCredential, nextWeixinAccountId } = await import("./weixin-route-
|
|
15628
|
+
const { upsertWeixinAccount, writeWeixinCredential, nextWeixinAccountId } = await import("./weixin-route-CxCciqQl.js").then((n) => n.u);
|
|
15628
15629
|
const { syncCccBridge } = await Promise.resolve().then(() => weixin_bridge_exports);
|
|
15629
15630
|
const accountId = nextWeixinAccountId(settings);
|
|
15630
15631
|
upsertWeixinAccount(login.root, {
|
|
@@ -17551,7 +17552,7 @@ function sessionNameFromMdPath(mdPath) {
|
|
|
17551
17552
|
* v1.30.13(S142 用户"微信桥 + skiff 会话锚定要准确",诊断 D4):**移除**原 ④「全局最新未完成
|
|
17552
17553
|
* 会话」(`findLatestActiveSessionMd`)。理由(R↓):④ 是**跨轨迹**猜测——候选①②③全空时,
|
|
17553
17554
|
* 它会把 rebuild 静默接到 AGENT_SESSIONS 里最新的另一个会话(临时 skiff 会话 persistent=false、
|
|
17554
|
-
*
|
|
17555
|
+
* 重启后首条消息前、新会话首条消息都命中该形态),而"接错轨迹"比重建失败危险得多
|
|
17555
17556
|
* (错误轨迹被继续写入 + 正确轨迹静默丢失)。现在全部候选失败 → 返回 null → 调用方
|
|
17556
17557
|
* 报错引导用户显式 `container_trajectory use`(响亮失败优于静默接错)。
|
|
17557
17558
|
* 备选:④ 仅在"同 scope 确无绑定"时兜底——同样会接错轨迹,故不采纳。
|
|
@@ -21742,7 +21743,7 @@ async function runAccountLoop(ctx, root, accountId, cred, loop, machine = false)
|
|
|
21742
21743
|
*
|
|
21743
21744
|
* 边界(R↓):ACC 只提供**机制与数据**——"桥不转发最终文本"这个事实 + 三个已填好的参数值
|
|
21744
21745
|
* (CCC 根 / 账号 / 用户 id)。**纪律措辞归 CCC**:怎么写、必须怎么做、后果是什么,全部写在
|
|
21745
|
-
* CCC 的角色提示词文件里(如 `.opencode/skiff
|
|
21746
|
+
* CCC 的角色提示词文件里(如 `.opencode/skiff/<role>.md` 的「输出通道」节),CCC 可随时改,
|
|
21746
21747
|
* 且 v1.30.15 起角色提示词热重载——改完立即生效,无需 ACC 发版。
|
|
21747
21748
|
*
|
|
21748
21749
|
* 为什么不用 ACC 写措辞(历史教训):v1.30.10~v1.30.15 由 ACC 内嵌一段纪律文案,用户实测
|
|
@@ -21780,7 +21781,7 @@ function manualOutputFallbackNeeded(input) {
|
|
|
21780
21781
|
*/
|
|
21781
21782
|
async function resolveCccRootByAlias(ctx, alias) {
|
|
21782
21783
|
try {
|
|
21783
|
-
const { listCccs } = await import("./ccc-roots-
|
|
21784
|
+
const { listCccs } = await import("./ccc-roots-CDW2dO0n.js").then((n) => n.a);
|
|
21784
21785
|
const entries = await listCccs(ctx);
|
|
21785
21786
|
const byName = entries.find((e) => e.name === alias);
|
|
21786
21787
|
if (byName) return byName.root;
|
|
@@ -22279,7 +22280,7 @@ function syncHumanChannel(ctx) {
|
|
|
22279
22280
|
(async () => {
|
|
22280
22281
|
try {
|
|
22281
22282
|
stopMachineLoops();
|
|
22282
|
-
const { listCccs } = await import("./ccc-roots-
|
|
22283
|
+
const { listCccs } = await import("./ccc-roots-CDW2dO0n.js").then((n) => n.a);
|
|
22283
22284
|
for (const entry of await listCccs(ctx)) syncCccBridge(ctx, entry.root);
|
|
22284
22285
|
} catch {}
|
|
22285
22286
|
})();
|
|
@@ -22447,7 +22448,7 @@ function parseSendRequest(body) {
|
|
|
22447
22448
|
if (!user.includes("@")) return {
|
|
22448
22449
|
ok: false,
|
|
22449
22450
|
error: `invalid "user": ${user}`,
|
|
22450
|
-
remediation: "需为 iLink from_user_id(含
|
|
22451
|
+
remediation: "需为 iLink from_user_id(含 @);别名请在调用方解析"
|
|
22451
22452
|
};
|
|
22452
22453
|
const text = typeof o.text === "string" ? o.text.trim() : "";
|
|
22453
22454
|
if (text === "") return {
|
|
@@ -22515,7 +22516,7 @@ function matchCcc(input, candidates) {
|
|
|
22515
22516
|
}
|
|
22516
22517
|
/** 组装候选列表(`ccc-roots.listCccs` 投影 + `.serenity` 名;动态 import 保持本模块静态依赖轻量) */
|
|
22517
22518
|
async function collectCandidates(ctx) {
|
|
22518
|
-
const { listCccs } = await import("./ccc-roots-
|
|
22519
|
+
const { listCccs } = await import("./ccc-roots-CDW2dO0n.js").then((n) => n.a);
|
|
22519
22520
|
const entries = await listCccs(ctx, { defaultRoot: process.cwd() });
|
|
22520
22521
|
const seen = /* @__PURE__ */ new Set();
|
|
22521
22522
|
const out = [];
|
|
@@ -23698,14 +23699,19 @@ function registerDeepseekVisionPatch(ctx, enabled) {
|
|
|
23698
23699
|
* - `sendFile` 走 iLink 上传(`weixin-api.sendFileMessage`)+ 同一 outgoing hook(带 `file` 元数据)
|
|
23699
23700
|
*/
|
|
23700
23701
|
/**
|
|
23701
|
-
*
|
|
23702
|
-
*
|
|
23702
|
+
* 解析该 CCC 的别名表(v1.56.10)。
|
|
23703
|
+
*
|
|
23704
|
+
* 🔴 **为什么不再硬编码**(2026-10-14 隐私核查):别名是**使用者自己的称呼**,属 CCC 的数据
|
|
23705
|
+
* (D23:加一个别名不该要发版)。此前硬编码在 ACC 源码 ⇒ **这些称呼随 npm 包公开发布**。
|
|
23706
|
+
* 现在别名**只**来自该 CCC 的 `.opencode/serenity.json` → `weixin.aliases`;
|
|
23707
|
+
* ACC 不认识任何具体名字。未配置 ⇒ `{}`(此时只能用裸 iLink 用户 id)。
|
|
23708
|
+
*
|
|
23709
|
+
* ⚠️ **迁移**:升级前用过别名的部署,需把原表补进自己的 CCC 配置,否则别名解析不到
|
|
23710
|
+
* (见 CHANGELOG v1.56.10 的迁移段;裸 `xxx@im.wechat` 形式始终可用)。
|
|
23703
23711
|
*/
|
|
23704
|
-
|
|
23705
|
-
|
|
23706
|
-
|
|
23707
|
-
xiaowang: "WEIXIN_USER_DANICA"
|
|
23708
|
-
};
|
|
23712
|
+
function weixinAliasMap(root) {
|
|
23713
|
+
return readWeixinSettings(root).aliases ?? {};
|
|
23714
|
+
}
|
|
23709
23715
|
/** 读该 CCC 的一个凭据值(空/缺失 → null) */
|
|
23710
23716
|
function credentialValue(root, key) {
|
|
23711
23717
|
try {
|
|
@@ -23728,7 +23734,7 @@ const weixinChannel = {
|
|
|
23728
23734
|
const raw = input.trim();
|
|
23729
23735
|
if (raw === "") return null;
|
|
23730
23736
|
const alias = raw.toLowerCase();
|
|
23731
|
-
const key =
|
|
23737
|
+
const key = weixinAliasMap(root)[alias];
|
|
23732
23738
|
if (key) {
|
|
23733
23739
|
const id = credentialValue(root, key);
|
|
23734
23740
|
return id ? {
|
|
@@ -23744,7 +23750,7 @@ const weixinChannel = {
|
|
|
23744
23750
|
},
|
|
23745
23751
|
listUsers(root) {
|
|
23746
23752
|
const out = [];
|
|
23747
|
-
for (const [alias, key] of Object.entries(
|
|
23753
|
+
for (const [alias, key] of Object.entries(weixinAliasMap(root))) {
|
|
23748
23754
|
const id = credentialValue(root, key);
|
|
23749
23755
|
if (id) out.push({
|
|
23750
23756
|
alias,
|
|
@@ -23868,7 +23874,7 @@ function renderText(value) {
|
|
|
23868
23874
|
function createImBridgeTool() {
|
|
23869
23875
|
return defineTool({
|
|
23870
23876
|
name: "im-bridge",
|
|
23871
|
-
description: `Send messages to family members through an IM channel configured for THIS container (currently: weixin / 微信). Every successful send is recorded in the container log automatically; this tool only acts on the current container (no target container parameter). It is hidden entirely when this container has no IM channel configured. Channels: ${imChannelIds().join(", ") || "(none registered)"}. Actions: send (text) / send-file (a file inside this container) / users (list configured recipients) / status (channel health). user accepts a configured alias (e.g.
|
|
23877
|
+
description: `Send messages to family members through an IM channel configured for THIS container (currently: weixin / 微信). Every successful send is recorded in the container log automatically; this tool only acts on the current container (no target container parameter). It is hidden entirely when this container has no IM channel configured. Channels: ${imChannelIds().join(", ") || "(none registered)"}. Actions: send (text) / send-file (a file inside this container) / users (list configured recipients) / status (channel health). user accepts a configured alias (e.g. user-a, user-b) or a raw channel user id. Failures return a stable code plus a remediation hint.`,
|
|
23872
23878
|
parameters: {
|
|
23873
23879
|
channel: {
|
|
23874
23880
|
type: "string",
|
|
@@ -23883,7 +23889,7 @@ function createImBridgeTool() {
|
|
|
23883
23889
|
},
|
|
23884
23890
|
user: {
|
|
23885
23891
|
type: "string",
|
|
23886
|
-
description: "Recipient: configured alias (
|
|
23892
|
+
description: "Recipient: configured alias (user-a, user-b) or raw channel user id (send / send-file)"
|
|
23887
23893
|
},
|
|
23888
23894
|
text: {
|
|
23889
23895
|
type: "string",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as cccRootForCwd } from "./ccc-roots-
|
|
1
|
+
import { r as cccRootForCwd } from "./ccc-roots-CDW2dO0n.js";
|
|
2
2
|
import { basename, dirname, join } from "node:path";
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
4
4
|
//#region src/time.ts
|
|
@@ -650,8 +650,8 @@ const migratedRoots = /* @__PURE__ */ new Set();
|
|
|
650
650
|
* **按 CCC 惰性补迁移**(§0L 修正,S142 2026-09-19)。
|
|
651
651
|
*
|
|
652
652
|
* 🔴 为什么需要它(实测缺陷,R↓):
|
|
653
|
-
* 装载期那次迁移用的是 `process.cwd()` —— 而 dsh **服务进程的 cwd
|
|
654
|
-
* **不是 CCC 根**(实测 `acc-diag`:`进程 cwd:
|
|
653
|
+
* 装载期那次迁移用的是 `process.cwd()` —— 而 dsh **服务进程的 cwd 是用户家目录**,
|
|
654
|
+
* **不是 CCC 根**(实测 `acc-diag`:`进程 cwd: <家目录> | 进程 CCC: (无)`)。
|
|
655
655
|
* ⇒ 迁移读的是一个**不存在的文件**,静默迁移 0 条
|
|
656
656
|
* (症状:发布后 `~/.dsh/storages/serenity_bindings.json` **没出现**)。
|
|
657
657
|
*
|
package/lib/rebuild.d.ts
CHANGED
|
@@ -78,7 +78,7 @@ interface RebuildResult {
|
|
|
78
78
|
* v1.30.13(S142 用户"微信桥 + skiff 会话锚定要准确",诊断 D4):**移除**原 ④「全局最新未完成
|
|
79
79
|
* 会话」(`findLatestActiveSessionMd`)。理由(R↓):④ 是**跨轨迹**猜测——候选①②③全空时,
|
|
80
80
|
* 它会把 rebuild 静默接到 AGENT_SESSIONS 里最新的另一个会话(临时 skiff 会话 persistent=false、
|
|
81
|
-
*
|
|
81
|
+
* 重启后首条消息前、新会话首条消息都命中该形态),而"接错轨迹"比重建失败危险得多
|
|
82
82
|
* (错误轨迹被继续写入 + 正确轨迹静默丢失)。现在全部候选失败 → 返回 null → 调用方
|
|
83
83
|
* 报错引导用户显式 `container_trajectory use`(响亮失败优于静默接错)。
|
|
84
84
|
* 备选:④ 仅在"同 scope 确无绑定"时兜底——同样会接错轨迹,故不采纳。
|
package/lib/skiff-core.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ export declare function skiffSessionSnapshot(): ReadonlyMap<string, {
|
|
|
35
35
|
* 注入 agent 系统提示词(用户对话面不可见)。
|
|
36
36
|
*
|
|
37
37
|
* v1.30.13(S142 诊断 D5):写入纪律**不点名具体工具**。旧文案写死 "with write/edit",
|
|
38
|
-
*
|
|
38
|
+
* 而某角色的工具白名单已移除 write/edit(写能力收归 CCC 的 session-write MSM)
|
|
39
39
|
* → 指令指向它根本没有的工具(注入纪律与能力面矛盾,模型只能猜)。
|
|
40
40
|
* 现文案改为「用本角色被授权的写入通道」——ACC 只声明义务(写进工作台),
|
|
41
41
|
* 具体通道由 CCC 的角色配置与角色提示词决定(ACC/CCC 归属二分;也不把某个 CCC 的
|
|
@@ -116,7 +116,7 @@ function resolveSkiffKind(role, hasStableId) {
|
|
|
116
116
|
*
|
|
117
117
|
* 为什么是函数而不是字符串(R↓):旧实现 `createSkiffAgent` 在创建时把
|
|
118
118
|
* `resolveRoleSystemPrompt(...)` 的结果**快照**进系统提示词段闭包 → CCC 改了
|
|
119
|
-
*
|
|
119
|
+
* `<role>.md` 必须重启 dsh web 才生效(本轮实证:改完 18KB 提示词,live agent 仍用旧文本)。
|
|
120
120
|
* 现形态返回一个读取函数,由系统提示词段的 `text()` **每轮调用**:
|
|
121
121
|
* - `systemPromptFile`:按 **mtime + size** 缓存重读(命中缓存零 IO;未变不解析)
|
|
122
122
|
* → 改文件即生效,**无需重启**;变更时打一行 info 日志(可观测,便于确认热更生效)
|
package/lib/skiff-role.d.ts
CHANGED
|
@@ -56,7 +56,7 @@ export declare function resolveSkiffKind(role: SkiffRoleConfig | undefined, hasS
|
|
|
56
56
|
*
|
|
57
57
|
* 为什么是函数而不是字符串(R↓):旧实现 `createSkiffAgent` 在创建时把
|
|
58
58
|
* `resolveRoleSystemPrompt(...)` 的结果**快照**进系统提示词段闭包 → CCC 改了
|
|
59
|
-
*
|
|
59
|
+
* `<role>.md` 必须重启 dsh web 才生效(本轮实证:改完 18KB 提示词,live agent 仍用旧文本)。
|
|
60
60
|
* 现形态返回一个读取函数,由系统提示词段的 `text()` **每轮调用**:
|
|
61
61
|
* - `systemPromptFile`:按 **mtime + size** 缓存重读(命中缓存零 IO;未变不解析)
|
|
62
62
|
* → 改文件即生效,**无需重启**;变更时打一行 info 日志(可观测,便于确认热更生效)
|
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
* skills-discovery.ts — CCC 入口 skill 自动发现(纯逻辑,零 DSH 依赖)
|
|
3
3
|
*
|
|
4
4
|
* 发现全部入口技能(原文全量,不截断)—— **现行三个来源**(原为四个,**来源 3 已于 2026-09-21 删除**):
|
|
5
|
-
* 0. **`.serenity` 记号文件内容 = 顶层入口 skill 名**(CCC
|
|
6
|
-
* tiangong-serenity 的 .serenity 内容为 `tg-serenity`)—— 最高优先
|
|
5
|
+
* 0. **`.serenity` 记号文件内容 = 顶层入口 skill 名**(CCC 记号文件的权威语义)—— 最高优先
|
|
7
6
|
* 1. `.dsh/entry-skill` 指针文件(内容 = skill 名)—— 兼容旧约定
|
|
8
7
|
* 2. `.opencode/skills/*-serenity/SKILL.md` —— 自动扫描该 CCC 的顶层入口
|
|
9
|
-
*
|
|
8
|
+
* (命名模式 `*-serenity`)
|
|
10
9
|
* ~~3. `.dsh/skills/*-serenity/SKILL.md`(扫 ACC 装进 CCC 的技能副本)~~ —— 🔴 **已删**:
|
|
11
10
|
* owner 2026-09-21 令「连模板和安装命令一起删」(B 案)。**判据、实测证据与日期逐字记在
|
|
12
11
|
* `findEntrySkills()` 体内那一段注释里**——本头部只留结论,**不复述判据**(避免两处会漂的真相源)。
|
package/lib/voyage-page.d.ts
CHANGED
|
@@ -16,10 +16,9 @@
|
|
|
16
16
|
* ③ 独立路由 ⇒ **惰性加载**(只在卡片展开时请求一次)+ 可长缓存,关闭 iframe 即卸载,
|
|
17
17
|
* WebGL 上下文随之释放。
|
|
18
18
|
*
|
|
19
|
-
* 来历(R
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* 与实测容器规模数字。
|
|
19
|
+
* 来历(R↓):作品由**另一个 Serenity CCC 实例**赠予;**本仓库只携带
|
|
20
|
+
* 构建产物**,源与构建脚本住在该实例侧(详见 `assets/README.md`)。内容已重播为宁静号自己的
|
|
21
|
+
* 技能/公理/MSM/本体词元与实测容器规模数字。
|
|
23
22
|
*/
|
|
24
23
|
import type { Context } from 'cordis';
|
|
25
24
|
export declare const VOYAGE_PATH = "/serenity/voyage";
|
|
@@ -353,7 +353,8 @@ function readWeixinSettings(root, paths = DEFAULT_SERENITY_CONFIG_PATHS) {
|
|
|
353
353
|
name: typeof a.name === "string" ? a.name : void 0,
|
|
354
354
|
enabled: a.enabled !== false
|
|
355
355
|
})) : [],
|
|
356
|
-
routes: Array.isArray(w.routes) ? w.routes.filter((r) => typeof r === "object" && r !== null && typeof r.user === "string" && r.user !== "" && typeof r.role === "string" && r.role !== "") : []
|
|
356
|
+
routes: Array.isArray(w.routes) ? w.routes.filter((r) => typeof r === "object" && r !== null && typeof r.user === "string" && r.user !== "" && typeof r.role === "string" && r.role !== "") : [],
|
|
357
|
+
aliases: readAliases(w)
|
|
357
358
|
};
|
|
358
359
|
} catch {
|
|
359
360
|
return {
|
|
@@ -363,6 +364,21 @@ function readWeixinSettings(root, paths = DEFAULT_SERENITY_CONFIG_PATHS) {
|
|
|
363
364
|
};
|
|
364
365
|
}
|
|
365
366
|
}
|
|
367
|
+
/**
|
|
368
|
+
* 别名表清洗(v1.56.10):键归一为小写、值必须是非空字符串;非法项静默丢弃。
|
|
369
|
+
* 空/缺省 → `{}`(此时别名解析不可用,只能用裸 iLink 用户 id)。
|
|
370
|
+
*/
|
|
371
|
+
function readAliases(w) {
|
|
372
|
+
const raw = w.aliases;
|
|
373
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return {};
|
|
374
|
+
const out = {};
|
|
375
|
+
for (const [k, v] of Object.entries(raw)) {
|
|
376
|
+
const alias = k.trim().toLowerCase();
|
|
377
|
+
if (alias === "" || typeof v !== "string" || v.trim() === "") continue;
|
|
378
|
+
out[alias] = v.trim();
|
|
379
|
+
}
|
|
380
|
+
return out;
|
|
381
|
+
}
|
|
366
382
|
/** localstore 凭据键(credential scope: WEIXIN_<ACCOUNT_ID>_<FIELD>) */
|
|
367
383
|
function lsKey(accountId, field) {
|
|
368
384
|
return `${LS_PREFIX}${accountKeyPart(accountId)}_${field}`;
|
package/lib/weixin-send-api.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 形态(用户拍板 A2):**独立监听器,只绑 127.0.0.1**(默认 3082,plugin 全局配置 weixinApi)。
|
|
5
5
|
* 为什么不挂在主 webServer(3080) 上:3080 会被 3081 公网网关原样反代(含全部请求头),
|
|
6
|
-
* 而 3081 的登录态属于"
|
|
6
|
+
* 而 3081 的登录态属于"对外账号"——一旦挂上去,任何已登录的外部用户都能冒充 bot 发消息。
|
|
7
7
|
* 独立 loopback 监听器则**不经网关、公网不可达**,因此不做共享密钥;仍校验来源地址。
|
|
8
8
|
*
|
|
9
9
|
* 调用者 = **非 agent 的调用者**(外部脚本/集成/运维)。**agent 侧已不走这里**:v1.31.0 起
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shgroup/dsh-serenity-hooks",
|
|
3
|
-
"version": "1.56.
|
|
3
|
+
"version": "1.56.10",
|
|
4
4
|
"description": "宁静号 ACC harness(Native Cordis 插件)——给 DeepSeek Harness 装一个「AI 工作区」:14 个工具(container_fs/container_trajectory/dashboard/container_git/msm/praxis/ontology/serenity-skill-creator/handyman/localstore/container_admin;另三个 im-bridge/acc-diag/diagram 按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫/对外输出守卫)+ 工作日志与原地重建 + 网页登录入口/微信桥/子角色/对外问答页/trajectory 唤醒注册表。适配 DSH 0.1.7-rc.1 与 0.2.0-rc.1(双档)。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|