@shgroup/dsh-serenity-hooks 1.57.0 → 1.57.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -9
- package/assets/eap-paper-LICENSE.txt +21 -0
- package/assets/eap-paper.md +492 -0
- package/dsh.plugin.json +1 -1
- package/lib/{ccc-roots-BC8mn8iM.js → ccc-roots-GIJ3A_tw.js} +79 -2
- package/lib/ccc-roots.d.ts +2 -1
- package/lib/client.js +43 -379
- package/lib/config-ops.d.ts +3 -34
- package/lib/face-host.d.ts +7 -5
- package/lib/index.d.ts +0 -31
- package/lib/index.js +197 -1079
- package/lib/{message-source-BcCRsEOh.js → message-source-B4P3Uw6D.js} +1 -1
- package/lib/output-guard-seam.d.ts +9 -2
- package/lib/ports.d.ts +6 -6
- package/lib/seams/lifecycle.d.ts +3 -3
- package/lib/{settings-section-xHABl8nk.js → settings-section-DQIVsTqE.js} +45 -30
- package/lib/settings-section.d.ts +3 -16
- package/lib/skiff-core.d.ts +6 -5
- package/lib/skiff-debug.d.ts +5 -4
- package/lib/skiff-role.d.ts +1 -1
- package/lib/tools/eap.d.ts +33 -3
- package/lib/tools/praxis.d.ts +4 -2
- package/lib/tools/skiff-admin.d.ts +1 -1
- package/lib/unattended-ops.d.ts +3 -1
- package/lib/weixin-bridge.d.ts +9 -2
- package/lib/weixin-output-guard.d.ts +1 -1
- package/package.json +3 -1
- package/lib/access-CNccNtgf.js +0 -79
- package/lib/acp-core.d.ts +0 -80
- package/lib/acp-http.d.ts +0 -37
- package/lib/skiff-registry-BjIX_KD1.js +0 -43
|
@@ -1,7 +1,84 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
|
|
2
|
-
import { a as hostSessions, i as hostService } from "./access-CNccNtgf.js";
|
|
3
2
|
import { a as findSerenityRoot } from "./ccc-B0ZGL9lx.js";
|
|
4
3
|
import { basename } from "node:path";
|
|
4
|
+
//#region src/host/access.ts
|
|
5
|
+
/**
|
|
6
|
+
* host/access.ts — 宿主访问收口(S142 review F-06)
|
|
7
|
+
*
|
|
8
|
+
* 为什么存在:dsp 此前在 30+ 个文件里各自用 `(ctx as unknown as {…})` 断言读取宿主
|
|
9
|
+
* 服务——契约表达分散、失败模式各异(多数静默 undefined)。本模块是**唯一**读取宿主
|
|
10
|
+
* 的入口:所有 `ctx.get` / `ctx.<service>` 的形状断言集中在此,调用点只拿类型化结果。
|
|
11
|
+
*
|
|
12
|
+
* 约定:
|
|
13
|
+
* - 只读、无副作用;服务缺失一律返回 `undefined`(调用方决定降级策略),**不抛错**
|
|
14
|
+
* (宿主对插件 apply 抛错 = 整个 dsh 启动失败,访问层不能成为单点)。
|
|
15
|
+
* - 形状以 `AI_LAB/dsh-harness-public` @ 0.1.2-rc.1 为准;成员缺失由
|
|
16
|
+
* `host/contract.ts` 的探针在装载时与 `dashboard health` 中报告。
|
|
17
|
+
* - 迁移是渐进的:新代码必须走本模块;旧调用点逐轮收敛(F-06 轮次记录见 CHANGELOG)。
|
|
18
|
+
*/
|
|
19
|
+
/** 通用读取:`ctx.get(name)`(含异常吞掉——服务 getter 抛错视为不可用) */
|
|
20
|
+
function hostService(ctx, name) {
|
|
21
|
+
const c = ctx;
|
|
22
|
+
if (typeof c?.get !== "function") return void 0;
|
|
23
|
+
try {
|
|
24
|
+
return c.get(name);
|
|
25
|
+
} catch {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 直接属性读取(injected 服务:`ctx.<name>`),属性缺失**或读取抛错**时回落 `ctx.get`。
|
|
31
|
+
*
|
|
32
|
+
* v1.31.4 修复(R↓,实证 v1.31.3 真机首测):cordis 的 Context 是 Proxy,
|
|
33
|
+
* `ReflectService.handler.get`(`vendor/cordis/src/reflect.ts`)对**未经 `inject` 声明**
|
|
34
|
+
* 的服务名会沿 fiber 链查找,找不到时**抛错**而非返回 undefined:
|
|
35
|
+
*
|
|
36
|
+
* cannot get property "<name>" without inject
|
|
37
|
+
*
|
|
38
|
+
* 于是"先直接属性读、失败回落 ctx.get"的写法在**真实 cordis** 下永远走不到回落分支——
|
|
39
|
+
* 异常直接逃逸(`hostService` 的 try/catch 被绕过)。v1.31.3 的 `hostSubagents`
|
|
40
|
+
* 正是这样炸的:`subagents` 是 lazy 服务(不在插件 `inject` 列表内)。
|
|
41
|
+
* 现有 fake ctx 单测(普通对象无 getter)复现不了 → 真 cordis 用例见
|
|
42
|
+
* `tests/host/cordis-access.test.ts`。
|
|
43
|
+
*
|
|
44
|
+
* 为什么吞掉异常而不是让它冒泡:本模块的契约是"服务缺失一律返回 undefined,**不抛错**"
|
|
45
|
+
* (宿主对插件 apply 抛错 = 整个 dsh 启动失败)。读取失败 = 服务不可用,等价于缺失。
|
|
46
|
+
*/
|
|
47
|
+
function hostInjected(ctx, name) {
|
|
48
|
+
const c = ctx;
|
|
49
|
+
try {
|
|
50
|
+
const direct = c?.[name];
|
|
51
|
+
if (direct !== void 0) return direct;
|
|
52
|
+
} catch {}
|
|
53
|
+
return hostService(ctx, name);
|
|
54
|
+
}
|
|
55
|
+
/** `ctx.sessions`(injected) */
|
|
56
|
+
function hostSessions(ctx) {
|
|
57
|
+
return hostInjected(ctx, "sessions");
|
|
58
|
+
}
|
|
59
|
+
/** `ctx.agents`(injected) */
|
|
60
|
+
function hostAgents(ctx) {
|
|
61
|
+
return hostInjected(ctx, "agents");
|
|
62
|
+
}
|
|
63
|
+
/** `ctx.webServer`(injected) */
|
|
64
|
+
function hostWebServer(ctx) {
|
|
65
|
+
return hostInjected(ctx, "webServer");
|
|
66
|
+
}
|
|
67
|
+
/** `ctx.settings`(injected;提供 settings 面板装配通道) */
|
|
68
|
+
function hostSettings(ctx) {
|
|
69
|
+
return hostInjected(ctx, "settings");
|
|
70
|
+
}
|
|
71
|
+
/** `ctx.web`(injected;v1.30.12 web_fetch provider 注册通道) */
|
|
72
|
+
function hostWeb(ctx) {
|
|
73
|
+
return hostInjected(ctx, "web");
|
|
74
|
+
}
|
|
75
|
+
function hostSubagents(ctx) {
|
|
76
|
+
return hostInjected(ctx, "subagents");
|
|
77
|
+
}
|
|
78
|
+
function hostLlm(ctx) {
|
|
79
|
+
return hostInjected(ctx, "llm");
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
5
82
|
//#region src/ccc-roots.ts
|
|
6
83
|
/**
|
|
7
84
|
* ccc-roots.ts — CCC 根解析的**唯一判断层**(L1 单根解析 + L2 全量枚举)
|
|
@@ -160,4 +237,4 @@ async function listCccs(ctx, opts = {}) {
|
|
|
160
237
|
}));
|
|
161
238
|
}
|
|
162
239
|
//#endregion
|
|
163
|
-
export { ccc_roots_exports as a, cccRootForExec as i, agentCwdFor as n, listCccs as o, cccRootForCwd as r, NO_CCC_FROM_AGENT_CWD as t };
|
|
240
|
+
export { ccc_roots_exports as a, hostInjected as c, hostSessions as d, hostSettings as f, hostWebServer as h, cccRootForExec as i, hostLlm as l, hostWeb as m, agentCwdFor as n, listCccs as o, hostSubagents as p, cccRootForCwd as r, hostAgents as s, NO_CCC_FROM_AGENT_CWD as t, hostService as u };
|
package/lib/ccc-roots.d.ts
CHANGED
|
@@ -75,7 +75,8 @@ export declare function cccRootForExec(execOrAgent: ExecOrAgent): string | null;
|
|
|
75
75
|
* **文案逐字不变**(外在行为不变)。
|
|
76
76
|
*/
|
|
77
77
|
export declare const NO_CCC_FROM_AGENT_CWD = "No CCC found: no .serenity file from agent cwd";
|
|
78
|
-
/** 候选 CCC 条目(调试页 CCC 切换器 / 微信桥 /
|
|
78
|
+
/** 候选 CCC 条目(调试页 CCC 切换器 / 微信桥 / `/serenity/cccs` 共用数据形状)
|
|
79
|
+
* ⚠️ 2026-10-15:原同批还有「ACP 问答页」,其面已退役 ⇒ 消费方少一个(形状不变)。 */
|
|
79
80
|
export interface CccEntry {
|
|
80
81
|
/** CCC 根(绝对路径) */
|
|
81
82
|
root: string;
|
package/lib/client.js
CHANGED
|
@@ -3207,7 +3207,7 @@ window.__ModuleLoader__.load({
|
|
|
3207
3207
|
knownWorkspaces: body.knownWorkspaces ?? []
|
|
3208
3208
|
};
|
|
3209
3209
|
}
|
|
3210
|
-
/** PUT 配置(账号 patch + 工作区白名单 + persona
|
|
3210
|
+
/** PUT 配置(账号 patch + 工作区白名单 + persona 彩蛋)→ 返回保存后的 wire */
|
|
3211
3211
|
async function saveConfig(patch) {
|
|
3212
3212
|
const res = await fetch(CONFIG_PATH, {
|
|
3213
3213
|
method: "PUT",
|
|
@@ -3799,286 +3799,6 @@ Instruction-following style:
|
|
|
3799
3799
|
});
|
|
3800
3800
|
}
|
|
3801
3801
|
//#endregion
|
|
3802
|
-
//#region src/client/PublicAskEditor.tsx
|
|
3803
|
-
/**
|
|
3804
|
-
* PublicAskEditor.tsx — 建议问答页配置(v1.26.2,S142 用户需求)
|
|
3805
|
-
*
|
|
3806
|
-
* 功能:
|
|
3807
|
-
* - **开放容器白名单**:从 /serenity/cccs 拉取候选容器,chips 选择哪些开放;
|
|
3808
|
-
* 空白名单 = 全部容器开放(向后兼容 v1.26.1 全局开放语义)。
|
|
3809
|
-
* - **key + 地址展示**:经 /serenity/public-ask 获取访问 key 与各开放容器 URL
|
|
3810
|
-
* (用户:配置处需能获取 key 和地址——管理员复制分享给使用者)。
|
|
3811
|
-
*
|
|
3812
|
-
* 数据通道(plugin 全局):
|
|
3813
|
-
* - GET /serenity/cccs 候选容器(node half listCccs)
|
|
3814
|
-
* - GET /serenity/public-ask key + 地址(x-serenity-ui 头)
|
|
3815
|
-
* - PUT /serenity/config publicAsk.allowed 白名单保存(accounts-api saveConfig)
|
|
3816
|
-
*/
|
|
3817
|
-
function PublicAskEditor(props) {
|
|
3818
|
-
const { publicAskOn } = props;
|
|
3819
|
-
const [candidates, setCandidates] = (0, react.useState)([]);
|
|
3820
|
-
const [allowed, setAllowed] = (0, react.useState)(null);
|
|
3821
|
-
const [info, setInfo] = (0, react.useState)(null);
|
|
3822
|
-
const [busy, setBusy] = (0, react.useState)(false);
|
|
3823
|
-
const [error, setError] = (0, react.useState)(null);
|
|
3824
|
-
const [saved, setSaved] = (0, react.useState)(false);
|
|
3825
|
-
const [rotating, setRotating] = (0, react.useState)(false);
|
|
3826
|
-
const rotateKey = async () => {
|
|
3827
|
-
if (!window.confirm("重新生成访问 Key?旧 Key 将立即失效,需要重新分享给使用者。")) return;
|
|
3828
|
-
setRotating(true);
|
|
3829
|
-
setError(null);
|
|
3830
|
-
try {
|
|
3831
|
-
const res = await fetch("/serenity/public-ask", {
|
|
3832
|
-
method: "PUT",
|
|
3833
|
-
headers: {
|
|
3834
|
-
"content-type": "application/json",
|
|
3835
|
-
"x-serenity-ui": "1"
|
|
3836
|
-
},
|
|
3837
|
-
body: JSON.stringify({ action: "rotate" })
|
|
3838
|
-
});
|
|
3839
|
-
if (!res.ok) throw new Error(`轮换失败(${res.status})`);
|
|
3840
|
-
const body = await res.json();
|
|
3841
|
-
setInfo((cur) => cur ? {
|
|
3842
|
-
...cur,
|
|
3843
|
-
key: body.key
|
|
3844
|
-
} : cur);
|
|
3845
|
-
setSaved(true);
|
|
3846
|
-
setTimeout(() => setSaved(false), 2500);
|
|
3847
|
-
} catch (err) {
|
|
3848
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
3849
|
-
} finally {
|
|
3850
|
-
setRotating(false);
|
|
3851
|
-
}
|
|
3852
|
-
};
|
|
3853
|
-
(0, react.useEffect)(() => {
|
|
3854
|
-
let alive = true;
|
|
3855
|
-
(async () => {
|
|
3856
|
-
try {
|
|
3857
|
-
const cfg = await fetchConfig();
|
|
3858
|
-
if (!alive) return;
|
|
3859
|
-
setAllowed(cfg?.config?.publicAsk?.allowed ?? []);
|
|
3860
|
-
} catch {}
|
|
3861
|
-
})();
|
|
3862
|
-
return () => {
|
|
3863
|
-
alive = false;
|
|
3864
|
-
};
|
|
3865
|
-
}, []);
|
|
3866
|
-
(0, react.useEffect)(() => {
|
|
3867
|
-
let alive = true;
|
|
3868
|
-
(async () => {
|
|
3869
|
-
try {
|
|
3870
|
-
const res = await fetch("/serenity/cccs", { headers: { accept: "application/json" } });
|
|
3871
|
-
if (!res.ok) return;
|
|
3872
|
-
const body = await res.json();
|
|
3873
|
-
if (alive) setCandidates(body?.cccs ?? []);
|
|
3874
|
-
} catch {}
|
|
3875
|
-
})();
|
|
3876
|
-
return () => {
|
|
3877
|
-
alive = false;
|
|
3878
|
-
};
|
|
3879
|
-
}, []);
|
|
3880
|
-
(0, react.useEffect)(() => {
|
|
3881
|
-
if (!publicAskOn) return;
|
|
3882
|
-
let alive = true;
|
|
3883
|
-
(async () => {
|
|
3884
|
-
try {
|
|
3885
|
-
const res = await fetch("/serenity/public-ask", { headers: {
|
|
3886
|
-
accept: "application/json",
|
|
3887
|
-
"x-serenity-ui": "1"
|
|
3888
|
-
} });
|
|
3889
|
-
if (!res.ok) return;
|
|
3890
|
-
const body = await res.json();
|
|
3891
|
-
if (alive) setInfo(body);
|
|
3892
|
-
} catch {}
|
|
3893
|
-
})();
|
|
3894
|
-
return () => {
|
|
3895
|
-
alive = false;
|
|
3896
|
-
};
|
|
3897
|
-
}, [publicAskOn]);
|
|
3898
|
-
const toggleAllowed = (name) => {
|
|
3899
|
-
setAllowed((cur) => {
|
|
3900
|
-
const base = cur ?? [];
|
|
3901
|
-
return base.includes(name) ? base.filter((n) => n !== name) : [...base, name];
|
|
3902
|
-
});
|
|
3903
|
-
};
|
|
3904
|
-
const save = async () => {
|
|
3905
|
-
if (allowed === null) return;
|
|
3906
|
-
setBusy(true);
|
|
3907
|
-
setError(null);
|
|
3908
|
-
setSaved(false);
|
|
3909
|
-
try {
|
|
3910
|
-
const cfg = await saveConfig({ publicAsk: { allowed } });
|
|
3911
|
-
if (cfg) {
|
|
3912
|
-
setAllowed(cfg.publicAsk.allowed ?? []);
|
|
3913
|
-
setSaved(true);
|
|
3914
|
-
setTimeout(() => setSaved(false), 2e3);
|
|
3915
|
-
}
|
|
3916
|
-
} catch (err) {
|
|
3917
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
3918
|
-
} finally {
|
|
3919
|
-
setBusy(false);
|
|
3920
|
-
}
|
|
3921
|
-
};
|
|
3922
|
-
const allOpen = (allowed ?? []).length === 0;
|
|
3923
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3924
|
-
className: "ae-root",
|
|
3925
|
-
children: [
|
|
3926
|
-
!publicAskOn && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3927
|
-
className: "ae-warn",
|
|
3928
|
-
children: "⚠️ Skiff 问答页当前关闭——先开启上方「Skiff 问答页」开关,外部访问才生效。"
|
|
3929
|
-
}),
|
|
3930
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3931
|
-
className: "ae-block",
|
|
3932
|
-
children: [
|
|
3933
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
3934
|
-
className: "ae-title",
|
|
3935
|
-
children: "开放容器"
|
|
3936
|
-
}),
|
|
3937
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
3938
|
-
className: "ae-desc",
|
|
3939
|
-
children: [
|
|
3940
|
-
"允许外部问答的认知容器(URL:/c/<容器名>)。",
|
|
3941
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: "未选择 = 全部容器开放" }),
|
|
3942
|
-
"; 选择后仅白名单内容器可访问。"
|
|
3943
|
-
]
|
|
3944
|
-
}),
|
|
3945
|
-
candidates.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3946
|
-
className: "ae-note",
|
|
3947
|
-
children: "暂无可选容器(/serenity/cccs 未返回条目——先在工作区打开一个 CCC)"
|
|
3948
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3949
|
-
className: "ae-chips",
|
|
3950
|
-
children: candidates.map((c) => {
|
|
3951
|
-
const on = (allowed ?? []).includes(c.name);
|
|
3952
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3953
|
-
type: "button",
|
|
3954
|
-
className: `ae-chip${on ? " ae-chipOn" : ""}`,
|
|
3955
|
-
onClick: () => toggleAllowed(c.name),
|
|
3956
|
-
title: `${c.root}(${c.roles.length} 角色)`,
|
|
3957
|
-
children: [c.name, on ? " ✓" : ""]
|
|
3958
|
-
}, c.name);
|
|
3959
|
-
})
|
|
3960
|
-
}),
|
|
3961
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3962
|
-
className: "ae-actions",
|
|
3963
|
-
children: [
|
|
3964
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3965
|
-
type: "button",
|
|
3966
|
-
className: "ae-save",
|
|
3967
|
-
disabled: busy || allowed === null,
|
|
3968
|
-
onClick: () => void save(),
|
|
3969
|
-
children: busy ? "保存中…" : "保存白名单"
|
|
3970
|
-
}),
|
|
3971
|
-
saved && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3972
|
-
className: "ae-saved",
|
|
3973
|
-
children: "✓ 已保存"
|
|
3974
|
-
}),
|
|
3975
|
-
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3976
|
-
className: "ae-err",
|
|
3977
|
-
children: error
|
|
3978
|
-
})
|
|
3979
|
-
]
|
|
3980
|
-
}),
|
|
3981
|
-
allOpen && allowed !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3982
|
-
className: "ae-note",
|
|
3983
|
-
children: "当前为「全部开放」——所有发现到的认知容器都可问答。"
|
|
3984
|
-
})
|
|
3985
|
-
]
|
|
3986
|
-
}),
|
|
3987
|
-
publicAskOn && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3988
|
-
className: "ae-block",
|
|
3989
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
3990
|
-
className: "ae-title",
|
|
3991
|
-
children: "访问 Key 与地址"
|
|
3992
|
-
}), info ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
3993
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3994
|
-
className: "ae-desc",
|
|
3995
|
-
children: "把下面的 key 与地址分享给使用者;key 已自动保存在其浏览器(localStorage)。"
|
|
3996
|
-
}),
|
|
3997
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3998
|
-
className: "ae-row",
|
|
3999
|
-
children: [
|
|
4000
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4001
|
-
className: "ae-label",
|
|
4002
|
-
children: "访问 Key"
|
|
4003
|
-
}),
|
|
4004
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
4005
|
-
className: "ae-key",
|
|
4006
|
-
children: info.key
|
|
4007
|
-
}),
|
|
4008
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4009
|
-
type: "button",
|
|
4010
|
-
className: "ae-copy",
|
|
4011
|
-
onClick: () => {
|
|
4012
|
-
navigator.clipboard?.writeText(info.key);
|
|
4013
|
-
},
|
|
4014
|
-
children: "复制"
|
|
4015
|
-
}),
|
|
4016
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4017
|
-
type: "button",
|
|
4018
|
-
className: "ae-copy ae-rotate",
|
|
4019
|
-
disabled: rotating,
|
|
4020
|
-
onClick: () => void rotateKey(),
|
|
4021
|
-
children: rotating ? "生成中…" : "重新生成"
|
|
4022
|
-
})
|
|
4023
|
-
]
|
|
4024
|
-
}),
|
|
4025
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4026
|
-
className: "ae-row",
|
|
4027
|
-
children: [
|
|
4028
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4029
|
-
className: "ae-label",
|
|
4030
|
-
children: "容器列表页"
|
|
4031
|
-
}),
|
|
4032
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
4033
|
-
className: "ae-key",
|
|
4034
|
-
children: info.listUrl
|
|
4035
|
-
}),
|
|
4036
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4037
|
-
type: "button",
|
|
4038
|
-
className: "ae-copy",
|
|
4039
|
-
onClick: () => {
|
|
4040
|
-
navigator.clipboard?.writeText(info.listUrl);
|
|
4041
|
-
},
|
|
4042
|
-
children: "复制"
|
|
4043
|
-
})
|
|
4044
|
-
]
|
|
4045
|
-
}),
|
|
4046
|
-
info.urls.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4047
|
-
className: "ae-rows",
|
|
4048
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4049
|
-
className: "ae-label",
|
|
4050
|
-
children: "各容器地址"
|
|
4051
|
-
}), info.urls.map((u) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4052
|
-
className: "ae-row",
|
|
4053
|
-
children: [
|
|
4054
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4055
|
-
className: "ae-label ae-labelDim",
|
|
4056
|
-
children: u.name
|
|
4057
|
-
}),
|
|
4058
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
4059
|
-
className: "ae-key",
|
|
4060
|
-
children: u.url
|
|
4061
|
-
}),
|
|
4062
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4063
|
-
type: "button",
|
|
4064
|
-
className: "ae-copy",
|
|
4065
|
-
onClick: () => {
|
|
4066
|
-
navigator.clipboard?.writeText(u.url);
|
|
4067
|
-
},
|
|
4068
|
-
children: "复制"
|
|
4069
|
-
})
|
|
4070
|
-
]
|
|
4071
|
-
}, u.name))]
|
|
4072
|
-
})
|
|
4073
|
-
] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4074
|
-
className: "ae-note",
|
|
4075
|
-
children: "开启后此处显示访问 key 与地址…"
|
|
4076
|
-
})]
|
|
4077
|
-
})
|
|
4078
|
-
]
|
|
4079
|
-
});
|
|
4080
|
-
}
|
|
4081
|
-
//#endregion
|
|
4082
3802
|
//#region src/client/WeixinBridgeEditor.tsx
|
|
4083
3803
|
/**
|
|
4084
3804
|
* WeixinBridgeEditor.tsx — 「微信桥」配置区块(F4c-3,v1.27.0 实验性)
|
|
@@ -4712,24 +4432,16 @@ Instruction-following style:
|
|
|
4712
4432
|
const setSkiffPort = (v) => {
|
|
4713
4433
|
set("skiffDebugPort", Math.min(65535, Math.max(1024, Math.round(v))));
|
|
4714
4434
|
};
|
|
4715
|
-
const setAcpPort = (v) => {
|
|
4716
|
-
set("acpHttpPort", Math.min(65535, Math.max(1024, Math.round(v))));
|
|
4717
|
-
};
|
|
4718
4435
|
const gatewayOn = value?.gatewayEnabled ?? false;
|
|
4719
4436
|
const thresholdK = value?.rebuildThresholdK ?? 400;
|
|
4720
4437
|
const skiffOn = value?.skiffEnabled ?? false;
|
|
4721
4438
|
const skiffPort = value?.skiffDebugPort ?? 3099;
|
|
4722
|
-
const acpOn = value?.acpEnabled ?? false;
|
|
4723
|
-
const acpPort = value?.acpHttpPort ?? 3100;
|
|
4724
|
-
const publicAskOn = value?.publicAskEnabled ?? false;
|
|
4725
4439
|
const croOn = value?.croEnabled ?? true;
|
|
4726
4440
|
const unattendedOn = value?.unattendedEnabled ?? false;
|
|
4727
4441
|
const diagramOn = value?.diagramEnabled ?? false;
|
|
4728
4442
|
const [openGateway, setOpenGateway] = (0, react.useState)(false);
|
|
4729
4443
|
const [openRebuild, setOpenRebuild] = (0, react.useState)(false);
|
|
4730
4444
|
const [openSkiff, setOpenSkiff] = (0, react.useState)(false);
|
|
4731
|
-
const [openAcp, setOpenAcp] = (0, react.useState)(false);
|
|
4732
|
-
const [openPublicAsk, setOpenPublicAsk] = (0, react.useState)(false);
|
|
4733
4445
|
const [openCro, setOpenCro] = (0, react.useState)(false);
|
|
4734
4446
|
const [openUnattended, setOpenUnattended] = (0, react.useState)(false);
|
|
4735
4447
|
const [openDiagram, setOpenDiagram] = (0, react.useState)(false);
|
|
@@ -4821,98 +4533,50 @@ Instruction-following style:
|
|
|
4821
4533
|
}),
|
|
4822
4534
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Group, {
|
|
4823
4535
|
title: "外部能力",
|
|
4824
|
-
children: [
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4864
|
-
className: "ss-portInput",
|
|
4865
|
-
type: "number",
|
|
4866
|
-
min: 1024,
|
|
4867
|
-
max: 65535,
|
|
4868
|
-
value: acpPort,
|
|
4869
|
-
disabled: !acpOn && !publicAskOn,
|
|
4870
|
-
title: "ACP + Skiff 问答共用端口(默认 3100)",
|
|
4871
|
-
onChange: (e) => setAcpPort(Number(e.target.value))
|
|
4872
|
-
})]
|
|
4873
|
-
}),
|
|
4874
|
-
detail: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4536
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
|
|
4537
|
+
title: "Skiff 调试",
|
|
4538
|
+
desc: "Skiff 认知子集问答页(端口 3099,实验性,127.0.0.1)",
|
|
4539
|
+
expandable: true,
|
|
4540
|
+
open: openSkiff,
|
|
4541
|
+
onToggle: setOpenSkiff,
|
|
4542
|
+
control: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4543
|
+
className: "ss-switchRow",
|
|
4544
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Toggle, {
|
|
4545
|
+
checked: skiffOn,
|
|
4546
|
+
onChange: (on) => toggle("skiffEnabled", on)
|
|
4547
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4548
|
+
className: "ss-portInput",
|
|
4549
|
+
type: "number",
|
|
4550
|
+
min: 1024,
|
|
4551
|
+
max: 65535,
|
|
4552
|
+
value: skiffPort,
|
|
4553
|
+
disabled: !skiffOn,
|
|
4554
|
+
title: "Skiff 调试端口(默认 3099)",
|
|
4555
|
+
onChange: (e) => setSkiffPort(Number(e.target.value))
|
|
4556
|
+
})]
|
|
4557
|
+
}),
|
|
4558
|
+
detail: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4559
|
+
className: "ss-detailIntro",
|
|
4560
|
+
children: "Skiff 认知子集角色调试服务(端口 3099):\n· 概念:Skiff = 完整宁静号 trajectory 的任意子集(认知子集角色)\n· 服务:角色问答页(调试用),仅监听 127.0.0.1(本地)\n· 使用:配置 CCC 的 skiff.roles 角色后,可经此页以角色身份问答\n· 实验性:人工启停,默认关闭;对外问答请用「Skiff 问答页」"
|
|
4561
|
+
})
|
|
4562
|
+
}) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
|
|
4563
|
+
title: "CRO(轨迹自编程唤起)",
|
|
4564
|
+
desc: "让轨迹用自己的一段程序决定何时唤起(全局开关,默认开)",
|
|
4565
|
+
expandable: true,
|
|
4566
|
+
open: openCro,
|
|
4567
|
+
onToggle: setOpenCro,
|
|
4568
|
+
control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Toggle, {
|
|
4569
|
+
checked: croOn,
|
|
4570
|
+
onChange: (on) => toggle("croEnabled", on)
|
|
4571
|
+
}),
|
|
4572
|
+
detail: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4573
|
+
className: "ss-detailStack",
|
|
4574
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4875
4575
|
className: "ss-detailIntro",
|
|
4876
|
-
children: "
|
|
4877
|
-
})
|
|
4878
|
-
}) }),
|
|
4879
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
|
|
4880
|
-
title: "Skiff 问答页",
|
|
4881
|
-
desc: "按认知容器暴露问答页(端口 3100,需 key)",
|
|
4882
|
-
expandable: true,
|
|
4883
|
-
open: openPublicAsk,
|
|
4884
|
-
onToggle: setOpenPublicAsk,
|
|
4885
|
-
control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Toggle, {
|
|
4886
|
-
checked: publicAskOn,
|
|
4887
|
-
onChange: (on) => toggle("publicAskEnabled", on)
|
|
4888
|
-
}),
|
|
4889
|
-
detail: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4890
|
-
className: "ss-detailStack",
|
|
4891
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4892
|
-
className: "ss-detailIntro",
|
|
4893
|
-
children: "Skiff 问答页(对外问答,端口 3100,key 认证):\n· 作用:让外部用户在浏览器中与指定 CCC 的 Skiff 角色对话\n· 认证:访问 key(首次开启自动生成)\n· 授权:开放容器白名单(未选 = 全部开放)\n· 外部接入:需经部署方自选方案暴露(隧道/反代/端口映射)\n· 安全:key 可轮换(旧 key 立即失效)"
|
|
4894
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PublicAskEditor, { publicAskOn })]
|
|
4576
|
+
children: "CRO = Continuous Re-Occurrence(轨迹自编程唤起)。\n· 作用:轨迹目录下放一个 continuous-re-occurrence.ts,ACC 的 5min tick 会 spawn 它,\n 由这段程序自己决定“要不要唤、何时唤、唤起时说什么”\n· 怎么启用:程序文件在即启用(无需在此配置);本开关是**总闸**\n· 关掉它的后果:**只有 CRO 阶段停跑** —— 定时唤醒(send-later)、即时投递(send-now)\n 与唤醒表投递**照常工作**\n· 默认开:已在生产稳定运行,且“没有程序文件的轨迹”本来就不参与(默认存在感为零)\n· 与它同时废止的开关:原“唤醒调度器”闸(2026-09-21 所有者令砍掉)——\n 唤醒调度器现**恒开**,不再有可被误关的开关"
|
|
4895
4577
|
})
|
|
4896
|
-
})
|
|
4897
|
-
|
|
4898
|
-
title: "CRO(轨迹自编程唤起)",
|
|
4899
|
-
desc: "让轨迹用自己的一段程序决定何时唤起(全局开关,默认开)",
|
|
4900
|
-
expandable: true,
|
|
4901
|
-
open: openCro,
|
|
4902
|
-
onToggle: setOpenCro,
|
|
4903
|
-
control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Toggle, {
|
|
4904
|
-
checked: croOn,
|
|
4905
|
-
onChange: (on) => toggle("croEnabled", on)
|
|
4906
|
-
}),
|
|
4907
|
-
detail: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4908
|
-
className: "ss-detailStack",
|
|
4909
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4910
|
-
className: "ss-detailIntro",
|
|
4911
|
-
children: "CRO = Continuous Re-Occurrence(轨迹自编程唤起)。\n· 作用:轨迹目录下放一个 continuous-re-occurrence.ts,ACC 的 5min tick 会 spawn 它,\n 由这段程序自己决定“要不要唤、何时唤、唤起时说什么”\n· 怎么启用:程序文件在即启用(无需在此配置);本开关是**总闸**\n· 关掉它的后果:**只有 CRO 阶段停跑** —— 定时唤醒(send-later)、即时投递(send-now)\n 与唤醒表投递**照常工作**\n· 默认开:已在生产稳定运行,且“没有程序文件的轨迹”本来就不参与(默认存在感为零)\n· 与它同时废止的开关:原“唤醒调度器”闸(2026-09-21 所有者令砍掉)——\n 唤醒调度器现**恒开**,不再有可被误关的开关"
|
|
4912
|
-
})
|
|
4913
|
-
})
|
|
4914
|
-
}) })
|
|
4915
|
-
]
|
|
4578
|
+
})
|
|
4579
|
+
}) })]
|
|
4916
4580
|
}),
|
|
4917
4581
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Group, {
|
|
4918
4582
|
title: "工具",
|
package/lib/config-ops.d.ts
CHANGED
|
@@ -51,15 +51,9 @@ interface PersonaSettings {
|
|
|
51
51
|
/** 用户替换文本(替代 EAP 块 + MSM 原则段的原文) */
|
|
52
52
|
overrideText: string;
|
|
53
53
|
}
|
|
54
|
-
/** F4d 建议问答页(v1.26.1
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
interface PublicAskSettings {
|
|
58
|
-
/** 访问 key(空 = 未生成;首次启用时 ensurePublicAskKey 自动生成随机 key 写回固定) */
|
|
59
|
-
key: string;
|
|
60
|
-
/** 开放容器白名单(CCC 目录名,如 home-serenity);空数组 = 全部容器开放 */
|
|
61
|
-
allowed: string[];
|
|
62
|
-
}
|
|
54
|
+
/** F4d 建议问答页(v1.26.1)**已于 2026-10-15 整面退役**(owner 裁「砍掉外部问答」)
|
|
55
|
+
* ⇒ 原 `PublicAskSettings`(key + 容器白名单)连同 `AdvancedSettings.publicAsk` 一并删除。
|
|
56
|
+
* 旧配置文件残留 `publicAsk` 节 ⇒ **静默忽略**(`mergeWithDefaults` 不再读它,幂等安全)。 */
|
|
63
57
|
/**
|
|
64
58
|
* 高级设定全量(~/.dsh/serenity-hooks.json 持久化形态;passHash 含 hash)。
|
|
65
59
|
* review P2-3:**rebuild 已从高级配置删除**——rebuild 开关/阈值归"简单配置"
|
|
@@ -70,7 +64,6 @@ interface PublicAskSettings {
|
|
|
70
64
|
interface AdvancedSettings {
|
|
71
65
|
gateway: GatewaySettings;
|
|
72
66
|
persona: PersonaSettings;
|
|
73
|
-
publicAsk: PublicAskSettings;
|
|
74
67
|
/** 主动发送入口(v1.30.9):**只绑 127.0.0.1** 的独立监听器——CCC 的 MSM 用它发消息给指定用户 */
|
|
75
68
|
weixinApi: WeixinApiSettings;
|
|
76
69
|
}
|
|
@@ -99,26 +92,6 @@ export declare function writeAdvancedSettings(settings: AdvancedSettings): void;
|
|
|
99
92
|
* accounts 传入数组 → 整体替换;accounts 未传 → 保留现有。
|
|
100
93
|
*/
|
|
101
94
|
export declare function updateAdvancedSettings(patch: Partial<AdvancedSettings>): AdvancedSettings;
|
|
102
|
-
/**
|
|
103
|
-
* 确保问答页访问 key 存在(首次启用自动生成 + 写回固定,用户拍板"配置时生成"):
|
|
104
|
-
* 读取全局配置 publicAsk.key;为空 → 生成 32 字节随机 hex(64 字符)→ 写回持久化。
|
|
105
|
-
* @returns 当前固定 key(已生成则返回既有值——**幂等**,不会覆盖用户手改的 key)
|
|
106
|
-
*/
|
|
107
|
-
export declare function ensurePublicAskKey(): string;
|
|
108
|
-
/** 校验问答页访问 key(timing-safe;key 未生成 → 恒 false——没有 key 不工作) */
|
|
109
|
-
export declare function verifyPublicAskKey(provided: string | undefined): boolean;
|
|
110
|
-
/**
|
|
111
|
-
* 轮换问答页访问 key(v1.26.5,S142 用户:公网开放 + 不好说要换 key 呢):
|
|
112
|
-
* 生成新 32 字节随机 hex(64 字符)→ 覆盖写回(**强制替换**——旧 key 立即失效)。
|
|
113
|
-
* @returns 新 key(面板展示给管理员,重新分享给使用者)
|
|
114
|
-
*/
|
|
115
|
-
export declare function rotatePublicAskKey(): string;
|
|
116
|
-
/** 重置 IP 失败状态(测试/管理员解封) */
|
|
117
|
-
export declare function resetPublicAskIpFail(ip: string): void;
|
|
118
|
-
/** IP 当前是否锁定(到期自动解锁) */
|
|
119
|
-
export declare function isPublicAskIpLocked(ip: string): boolean;
|
|
120
|
-
/** 记录一次 key 校验失败;达到阈值 → 锁定(指数退避)。返回锁定剩余毫秒(0 = 未锁定) */
|
|
121
|
-
export declare function recordPublicAskFail(ip: string): number;
|
|
122
95
|
/**
|
|
123
96
|
* 一次性迁移(v1.21.x → v1.22):旧版把 `serenityAdvanced` 存在 CCC localstore.json;
|
|
124
97
|
* 新版归 plugin 全局文件。全局文件已存在 → 跳过(幂等);localstore 无旧节 → 跳过。
|
|
@@ -147,10 +120,6 @@ interface AdvancedSettingsWire {
|
|
|
147
120
|
totpEnabled: boolean;
|
|
148
121
|
};
|
|
149
122
|
persona: PersonaSettings;
|
|
150
|
-
publicAsk: {
|
|
151
|
-
/** 开放容器白名单(v1.26.2:容器名数组;空 = 全部开放) */
|
|
152
|
-
allowed: string[];
|
|
153
|
-
};
|
|
154
123
|
}
|
|
155
124
|
/** 持久化 → wire(剥离 passHash/totpSecret;只留布尔) */
|
|
156
125
|
export declare function toWire(settings: AdvancedSettings): AdvancedSettingsWire;
|