@shgroup/dsh-serenity-hooks 1.27.14 → 1.28.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-serenity-hooks",
3
- "version": "1.27.14",
3
+ "version": "1.28.1",
4
4
  "main": "lib/index.js",
5
5
  "description": "宁静号 ACC harness(Native Cordis 插件):真实 DSH 工具 cc_fs/session/acc_msm/eap/neat/cce/handyman/session_rebuild/skiff_admin + 拦截缝机械约束(safe-mode/路径守卫)+ 高级设定面板(双端口网关/账号管理)+ Skiff 认知子集角色(实验性)。适配 DSH 公开版(0.1.0-rc,deepseek-ai/deepseek-harness)。",
6
6
  "engines": {
@@ -19,7 +19,8 @@
19
19
  "handyman",
20
20
  "session_rebuild",
21
21
  "localstore",
22
- "skiff_admin"
22
+ "skiff_admin",
23
+ "autopilot-trajectory"
23
24
  ],
24
25
  "skills": []
25
26
  }
@@ -59,6 +59,24 @@ function resolveInside(root, p) {
59
59
  return abs;
60
60
  }
61
61
  /**
62
+ * CCC 名:从 .serenity 标记解析——**跳过 # 注释与空行的首个非空行**。
63
+ * 注册表聚合档路径(.opencode/skills/<cccName>/references/mech-registry.json)以此为准,
64
+ * 是 guards/fs-ops/msm-ops/kit-ops 四处解析的唯一真相源(review P2-2 收口,09-05:
65
+ * 原四处分叉——msm-ops/kit-ops 取严格首行、guards/fs-ops 跳注释——首行为注释/空行时
66
+ * register 目标路径与保护路径分叉,潜在隐患)。
67
+ * @returns CCC 名;无标记/读失败/全注释空行 → null
68
+ */
69
+ function readCccName(root) {
70
+ try {
71
+ const marker = resolve(root, ".serenity");
72
+ if (!existsSync(marker)) return null;
73
+ const line = readFileSync(marker, "utf-8").split("\n").map((l) => l.trim()).find((l) => l !== "" && !l.startsWith("#"));
74
+ return line && line !== "" ? line : null;
75
+ } catch {
76
+ return null;
77
+ }
78
+ }
79
+ /**
62
80
  * 解析 handyman 配置(v1.24.0:取代 loop.defaultModel;不兼容旧 loop 配置——用户拍板)。
63
81
  * @returns 白名单 + 缺省模型 + 上限;models 未配置返回 null(工具应报错要求配置)
64
82
  */
@@ -138,4 +156,4 @@ function matchBlacklist(relPath, rules) {
138
156
  return null;
139
157
  }
140
158
  //#endregion
141
- export { findSerenityRoot as a, matchBlacklist as c, readHandymanConfig as d, readUtf8 as f, findGitRoot as i, pathInside as l, SAFE_MODE_MARKER as n, isSafeModeOn as o, resolveInside as p, classifyPath as r, loadSerenityConfig as s, DEFAULT_SERENITY_CONFIG_PATHS as t, readBlacklist as u };
159
+ export { findSerenityRoot as a, matchBlacklist as c, readCccName as d, readHandymanConfig as f, findGitRoot as i, pathInside as l, resolveInside as m, SAFE_MODE_MARKER as n, isSafeModeOn as o, readUtf8 as p, classifyPath as r, loadSerenityConfig as s, DEFAULT_SERENITY_CONFIG_PATHS as t, readBlacklist as u };
package/lib/ccc.d.ts CHANGED
@@ -22,6 +22,15 @@ export type PathClass = 'inside' | 'outside' | 'same';
22
22
  export declare function pathInside(rootAbs: string, abs: string, caseInsensitive?: boolean): boolean;
23
23
  export declare function classifyPath(p: string, root: string): PathClass;
24
24
  export declare function resolveInside(root: string, p: string): string;
25
+ /**
26
+ * CCC 名:从 .serenity 标记解析——**跳过 # 注释与空行的首个非空行**。
27
+ * 注册表聚合档路径(.opencode/skills/<cccName>/references/mech-registry.json)以此为准,
28
+ * 是 guards/fs-ops/msm-ops/kit-ops 四处解析的唯一真相源(review P2-2 收口,09-05:
29
+ * 原四处分叉——msm-ops/kit-ops 取严格首行、guards/fs-ops 跳注释——首行为注释/空行时
30
+ * register 目标路径与保护路径分叉,潜在隐患)。
31
+ * @returns CCC 名;无标记/读失败/全注释空行 → null
32
+ */
33
+ export declare function readCccName(root: string): string | null;
25
34
  export interface SerenityConfig {
26
35
  /** handyman(杂工)配置:模型白名单(v1.24.0 取代 loop) */
27
36
  handyman?: {
package/lib/client.js CHANGED
@@ -3206,44 +3206,18 @@ window.__ModuleLoader__.load({
3206
3206
  return null;
3207
3207
  }
3208
3208
  const CONFIG_PATH = "/serenity/config";
3209
- /**
3210
- * 获取已有工作区列表(需求 1:白名单从已有工作区选择而非手输)。
3211
- * 走 DSH 原生 RPC `POST /api/workspace.list`(JSON RPC 形态)。
3212
- * 信封必须是完整 ClientRequest:`{ type: 'client-request', rpcId, method, payload }`
3213
- * (api/rpc.ts wire 契约——缺 type/method → clientRequestSchema 校验失败 → bad-request)。
3214
- * 返回 { path, title }[];失败返回空数组(面板显示"暂无可选工作区")。
3215
- */
3216
- async function fetchWorkspaces() {
3217
- try {
3218
- const res = await fetch("/api/workspace.list", {
3219
- method: "POST",
3220
- headers: { "content-type": "application/json" },
3221
- body: JSON.stringify({
3222
- type: "client-request",
3223
- rpcId: `ws-${Date.now().toString(36)}`,
3224
- method: "workspace.list",
3225
- payload: {}
3226
- })
3227
- });
3228
- if (!res.ok) return [];
3229
- const items = (await res.json())?.result?.value?.items;
3230
- if (!Array.isArray(items)) return [];
3231
- return items.filter((i) => typeof i.path === "string" && i.path !== "").map((i) => ({
3232
- path: i.path,
3233
- title: typeof i.title === "string" && i.title !== "" ? i.title : i.path
3234
- }));
3235
- } catch {
3236
- return [];
3237
- }
3238
- }
3239
- /** GET 配置(含账号列表;无 hash) */
3209
+ /** GET 配置(含账号列表 + knownWorkspaces;无 hash) */
3240
3210
  async function fetchConfig() {
3241
3211
  const res = await fetch(CONFIG_PATH, { headers: {
3242
3212
  accept: "application/json",
3243
3213
  "x-serenity-ui": "1"
3244
3214
  } });
3245
3215
  if (!res.ok) return null;
3246
- return (await res.json()).config ?? null;
3216
+ const body = await res.json();
3217
+ return {
3218
+ config: body.config ?? null,
3219
+ knownWorkspaces: body.knownWorkspaces ?? []
3220
+ };
3247
3221
  }
3248
3222
  /** PUT 配置(账号 patch + 工作区白名单 + persona 彩蛋 + 开放容器白名单)→ 返回保存后的 wire */
3249
3223
  async function saveConfig(patch) {
@@ -3303,9 +3277,10 @@ window.__ModuleLoader__.load({
3303
3277
  const [saved, setSaved] = (0, react.useState)(false);
3304
3278
  (0, react.useEffect)(() => {
3305
3279
  let alive = true;
3306
- Promise.all([fetchConfig(), fetchWorkspaces()]).then(([cfg, wss]) => {
3280
+ fetchConfig().then((resp) => {
3307
3281
  if (!alive) return;
3308
- setKnownWorkspaces(wss);
3282
+ const cfg = resp?.config ?? null;
3283
+ setKnownWorkspaces(resp?.knownWorkspaces ?? []);
3309
3284
  if (cfg) {
3310
3285
  setConfig(cfg);
3311
3286
  setHost(cfg.gateway.host);
@@ -3734,8 +3709,8 @@ Instruction-following style:
3734
3709
  let alive = true;
3735
3710
  fetchConfig().then((cfg) => {
3736
3711
  if (!alive || !cfg) return;
3737
- setMode(cfg.persona?.mode ?? "");
3738
- setOverrideText(cfg.persona?.overrideText ?? "");
3712
+ setMode(cfg.config?.persona?.mode ?? "");
3713
+ setOverrideText(cfg.config?.persona?.overrideText ?? "");
3739
3714
  setLoaded(true);
3740
3715
  });
3741
3716
  return () => {
@@ -3893,7 +3868,7 @@ Instruction-following style:
3893
3868
  try {
3894
3869
  const cfg = await fetchConfig();
3895
3870
  if (!alive) return;
3896
- setAllowed(cfg?.publicAsk?.allowed ?? []);
3871
+ setAllowed(cfg?.config?.publicAsk?.allowed ?? []);
3897
3872
  } catch {}
3898
3873
  })();
3899
3874
  return () => {
@@ -4737,7 +4712,7 @@ Instruction-following style:
4737
4712
  scope.set(field, on);
4738
4713
  };
4739
4714
  const setThreshold = (v) => {
4740
- scope.set("rebuildThreshold", Math.min(1, Math.max(.01, v)));
4715
+ scope.set("rebuildThresholdK", Math.min(4e3, Math.max(50, Math.round(v))));
4741
4716
  };
4742
4717
  const setSkiffPort = (v) => {
4743
4718
  scope.set("skiffDebugPort", Math.min(65535, Math.max(1024, Math.round(v))));
@@ -4754,7 +4729,7 @@ Instruction-following style:
4754
4729
  });
4755
4730
  const gatewayOn = value?.gatewayEnabled ?? false;
4756
4731
  const rebuildOn = value?.rebuildEnabled ?? true;
4757
- const threshold = value?.rebuildThreshold ?? .9;
4732
+ const thresholdK = value?.rebuildThresholdK ?? 400;
4758
4733
  const skiffOn = value?.skiffEnabled ?? false;
4759
4734
  const skiffPort = value?.skiffDebugPort ?? 3099;
4760
4735
  const acpOn = value?.acpEnabled ?? false;
@@ -4796,22 +4771,18 @@ Instruction-following style:
4796
4771
  })
4797
4772
  }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowCard, {
4798
4773
  title: "重建阈值",
4799
- desc: "上下文占用达到该比例时提示(0.10 ~ 1.00)",
4800
- help: "重建触发阈值(0.10~1.00,默认 0.90):\n· 含义:上下文占用达到该比例时,轨迹跟踪器开始提醒重建\n· 调低:更早触发(适合长任务,避免上下文耗尽前措手不及)\n· 调高:更晚触发(适合短对话,减少不必要的重建提示)\n· 仅「超限重建」开启时有意义",
4801
- control: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4802
- className: "ss-threshold",
4803
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
4804
- type: "range",
4805
- min: .1,
4806
- max: 1,
4807
- step: .05,
4808
- value: threshold,
4809
- disabled: !rebuildOn,
4810
- onChange: (e) => setThreshold(Number(e.target.value))
4811
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4812
- className: "ss-value",
4813
- children: threshold.toFixed(2)
4814
- })]
4774
+ desc: "上下文占用达到该 K 数值时提示(单位 K token,默认 400)",
4775
+ help: "重建触发阈值(需求①:K 数值,默认 400K,范围 50~4000K):\n· 含义:上下文 projected tokens 达到 thresholdK × 1000 时,轨迹跟踪器开始提醒重建\n· 纯绝对数值(不再依赖窗口比例)——配多大就多大,无窗口上限保护\n· 迁移:旧版 0~1 比例(settings.yaml rebuildThreshold,如 0.9)已废弃并被忽略——\n 请按 K 数值在此重设(如 0.9 → 900);若从未设置则默认 400K 生效\n· 调低:更早触发(适合长任务,避免上下文耗尽前措手不及)\n· 调高:更晚触发(适合短对话,减少不必要的重建提示)\n· 仅「超限重建」开启时有意义",
4776
+ control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
4777
+ className: "ss-portInput",
4778
+ type: "number",
4779
+ min: 50,
4780
+ max: 4e3,
4781
+ step: 50,
4782
+ value: thresholdK,
4783
+ disabled: !rebuildOn,
4784
+ title: "重建阈值(K token,默认 400)",
4785
+ onChange: (e) => setThreshold(Number(e.target.value))
4815
4786
  })
4816
4787
  }) })]
4817
4788
  }),
@@ -42,12 +42,6 @@ export interface GatewaySettings {
42
42
  /** 是否启用 Authenticator 第二因素(v1.22.4;false = TOTP 完全禁用——登录不要求、绑定入口隐藏) */
43
43
  totpEnabled: boolean;
44
44
  }
45
- /** F2 超限重建配置 */
46
- export interface RebuildSettings {
47
- enabled: boolean;
48
- /** contextPressure 触发比例(0~1) */
49
- thresholdRatio: number;
50
- }
51
45
  /** 彩蛋功能:persona 模式(v1.23.1,S142 用户需求)
52
46
  * 配置后替换 ACC 系统提示词中"输出约束/指令遵循约束"部分(EAP 块 + MSM 原则段);
53
47
  * 未配置(mode 空)→ 完全默认行为,零影响。 */
@@ -66,10 +60,15 @@ export interface PublicAskSettings {
66
60
  /** 开放容器白名单(CCC 目录名,如 home-serenity);空数组 = 全部容器开放 */
67
61
  allowed: string[];
68
62
  }
69
- /** 高级设定全量(localstore.json 持久化形态;passHash 含 hash) */
63
+ /**
64
+ * 高级设定全量(~/.dsh/serenity-hooks.json 持久化形态;passHash 含 hash)。
65
+ * review P2-3:**rebuild 已从高级配置删除**——rebuild 开关/阈值归"简单配置"
66
+ * (settings.yaml 原生面板,见 settings-section.ts),运行时只读 readSimpleSettings();
67
+ * 旧高级 rebuild 字段是死双胞胎(/serenity/config PUT 回显但运行时从不读它)——
68
+ * 删除防误导(用户在高级面板改了却无效)。历史残留字段被 mergeWithDefaults 忽略(幂等安全)。
69
+ */
70
70
  export interface AdvancedSettings {
71
71
  gateway: GatewaySettings;
72
- rebuild: RebuildSettings;
73
72
  persona: PersonaSettings;
74
73
  publicAsk: PublicAskSettings;
75
74
  }
@@ -131,7 +130,7 @@ export interface GatewayAccountWire {
131
130
  /** 该账号是否已绑定 TOTP(v1.22.4) */
132
131
  hasTotp: boolean;
133
132
  }
134
- /** 设定 wire 形态(GET /serenity/config 返回;rebuild 同持久化,gateway 去 hash) */
133
+ /** 设定 wire 形态(GET /serenity/config 返回;gateway 去 hash) */
135
134
  export interface AdvancedSettingsWire {
136
135
  gateway: {
137
136
  enabled: boolean;
@@ -143,7 +142,6 @@ export interface AdvancedSettingsWire {
143
142
  allowWorkspaceCreate: boolean;
144
143
  totpEnabled: boolean;
145
144
  };
146
- rebuild: RebuildSettings;
147
145
  persona: PersonaSettings;
148
146
  publicAsk: {
149
147
  /** 开放容器白名单(v1.26.2:容器名数组;空 = 全部开放) */
@@ -152,6 +150,19 @@ export interface AdvancedSettingsWire {
152
150
  }
153
151
  /** 持久化 → wire(剥离 passHash/totpSecret;只留布尔) */
154
152
  export declare function toWire(settings: AdvancedSettings): AdvancedSettingsWire;
153
+ /**
154
+ * 已知工作区投影(v1.28.0 适配 0.1.2-rc.1 A2 方案 A′):
155
+ * rc.1 workspace.list unary 删除 → AccountsEditor 白名单下拉的数据源改走 gateway 自有
156
+ * /serenity/config 的 knownWorkspaces(host workspaceRegistry.list() 投影,白名单过滤)。
157
+ * 纯函数可单测。allowPrefixes 空 = 全部放行(向后兼容默认)。
158
+ */
159
+ export declare function projectKnownWorkspaces(workspaces: Array<{
160
+ path?: string;
161
+ title?: string;
162
+ }>, allowPrefixes: readonly string[]): Array<{
163
+ path: string;
164
+ title: string;
165
+ }>;
155
166
  /**
156
167
  * wire → 持久化(面板 PUT 用):
157
168
  * accounts 元素可选带 `pass`:非空 → 重新 hash;空/缺省 → 保留现有 hash(按 id 匹配)。
package/lib/index.d.ts CHANGED
@@ -14,7 +14,8 @@
14
14
  import type { Context } from 'cordis';
15
15
  import z from '@deepseek-ai/schemastery';
16
16
  export declare const name = "dsh-serenity-hooks";
17
- /** 主动调用的服务;其余(agent 事件)随 harness 装配必然存在 */
17
+ /** 主动调用的服务;其余(agent 事件)随 harness 装配必然存在
18
+ * (v1.28.0 适配 0.1.2-rc.1:+ 'settings'——B4 settings 服务由 provider 插件加载后才有) */
18
19
  export declare const inject: string[];
19
20
  /** 插件配置(cordis.yml 提供;进程级) */
20
21
  export interface Config {
@@ -47,7 +48,7 @@ export interface Config {
47
48
  /** F2 超限重建(entry 默认值,运行时经 DSH settings) */
48
49
  rebuild?: {
49
50
  enabled?: boolean;
50
- thresholdRatio?: number;
51
+ thresholdK?: number;
51
52
  };
52
53
  /** F4 Skiff(实验性):调试服务启停(entry 默认值,运行时经 DSH settings) */
53
54
  skiff?: {