@shgroup/dsh-serenity-hooks 1.79.0 → 1.79.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.79.0",
3
+ "version": "1.79.1",
4
4
  "main": "lib/index.js",
5
5
  "description": "宁静号 ACC harness(Native Cordis 插件):给 DSH 装一个「AI 工作区」——14 个工具(container_fs/cognitive_trajectory/dashboard/container_git/msm/praxis/ontology/serenity-skill-creator/cheap-worker/localstore/container_admin;另三个 im-bridge/acc-diag/diagram 按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 认知轨迹日志与原地重建 + 网页登录入口/IM 桥/认知轨迹唤醒注册表。轨迹声明 = 轨迹目录下的 trajectory.json(约束面 + 旧标识 uid + CRO 机器绑定 cro.host;旧名 trajectory-constraint.json / skiff.json 仍在读取族里);轨迹提示词 = 轨迹目录下的 PROMPT.md(一条轨迹「是谁、按什么章程工作」,所有轨迹通用,追加在容器层与质量层之后,不替换它们)。适配 DSH 0.1.7-rc.1 / 0.2.0-rc.1 / 0.2.1-rc.1(三档,deepseek-ai/deepseek-harness)。",
6
6
  "engines": {
@@ -64,6 +64,16 @@ export interface ImChannel {
64
64
  id: string;
65
65
  /** 该 CCC 是否启用了本通道(缺省实现:读该通道的 CCC 配置) */
66
66
  isEnabled(root: string): boolean;
67
+ /**
68
+ * `isEnabled` 为假时**给人看的原因与怎么改**(可选)。
69
+ *
70
+ * 🔴 为什么它归通道自己而不归工具面(2026-10-20 Q4 真机验收踩到):
71
+ * 工具面先前统一印「enable it in … (weixin.enabled)」,而**只有通道自己知道
72
+ * "怎样才能启用我"** —— 飞书能否用不取决于 `weixin.enabled`,而取决于有没有
73
+ * 一条启用中的飞书账号。⇒ 统一文案在第二个渠道上就成了**教一个不生效的改法**。
74
+ * 缺省(不给)⇒ 用通用文案,说"查该渠道自己的开关/账号表",不点名任何具体字段。
75
+ */
76
+ notEnabledReason?(root: string): string | undefined;
67
77
  /** 别名/裸 id → 通道用户;无法解析返回 null */
68
78
  resolveUser(root: string, input: string): ImUserEntry | null;
69
79
  /** 已配置别名列表(`users` 动作) */
package/lib/index.js CHANGED
@@ -11168,11 +11168,19 @@ function hasEnabledImChannel(root) {
11168
11168
  } catch {}
11169
11169
  return false;
11170
11170
  }
11171
- /** 错误码 → 可行动提示(模型视角:说清怎么改) */
11172
- function remediationFor(code) {
11171
+ /**
11172
+ * 错误码 → 可行动提示(模型视角:说清怎么改)。
11173
+ *
11174
+ * 🔴 `CHANNEL_NOT_CONFIGURED` 的提示**不能写死某一个渠道的字段名**(2026-10-20 Q4 真机验收踩到):
11175
+ * 首版逐字写「enable it in … (weixin.enabled)」,而接第二个渠道后,**飞书能不能用不取决于
11176
+ * 这个开关**(它取决于有没有一条启用中的飞书账号)⇒ 按那句提示去改 `weixin.enabled`
11177
+ * **不会生效**,而错误码又指向"没配置" ⇒ 用户据此改完还是同一句报错。
11178
+ * ⇒ 提示按**渠道是否带自己的启用判据**分岔:带 `channelHint` 的就用它自己的说法。
11179
+ */
11180
+ function remediationFor(code, channelHint) {
11173
11181
  switch (code) {
11174
11182
  case "CHANNEL_UNKNOWN": return "Use a registered channel id (see the tool description)";
11175
- case "CHANNEL_NOT_CONFIGURED": return "This CCC has not configured that channel — enable it in .opencode/serenity.json (weixin.enabled) or the settings panel";
11183
+ case "CHANNEL_NOT_CONFIGURED": return channelHint ?? "This CCC has not configured that channel — check .opencode/serenity.json (the channel's own enabled flag / accounts) or the settings panel";
11176
11184
  case "ACTION_UNKNOWN": return "Use send / send-file / users / status";
11177
11185
  case "ACTION_UNSUPPORTED": return "This channel does not support that action";
11178
11186
  case "ALIAS_UNKNOWN": return "Use a configured alias (see action=users) or a raw channel user id";
@@ -11252,7 +11260,7 @@ async function runImBridge(root, req) {
11252
11260
  if (channelId === "") return fail("CHANNEL_REQUIRED", "channel is required", "Provide channel (e.g. \"weixin\")");
11253
11261
  const channel = channels.get(channelId);
11254
11262
  if (!channel) return fail("CHANNEL_UNKNOWN", `unknown channel "${channelId}" (registered: ${imChannelIds().join(", ") || "(none)"})`);
11255
- if (!channel.isEnabled(root)) return fail("CHANNEL_NOT_CONFIGURED", `channel "${channelId}" is not configured for this CCC (${root})`);
11263
+ if (!channel.isEnabled(root)) return fail("CHANNEL_NOT_CONFIGURED", `channel "${channelId}" is not configured for this CCC (${root})`, channel.notEnabledReason?.(root));
11256
11264
  if (action === "users") return {
11257
11265
  ok: true,
11258
11266
  channel: channelId,
@@ -21359,6 +21367,13 @@ const weixinChannel = {
21359
21367
  isEnabled(root) {
21360
21368
  return readWeixinSettings(root).enabled === true;
21361
21369
  },
21370
+ /**
21371
+ * 微信的启用判据**只有总开关这一半**(有 token 的账号是可选的:条数不限、0 条也能开)。
21372
+ * ⇒ 它的提示可以只提这个开关 —— 这与飞书的**两半**不同,别把两家的提示合成一句。
21373
+ */
21374
+ notEnabledReason() {
21375
+ return "This CCC has no IM bridge enabled — turn on the IM switch in .opencode/serenity.json (im.enabled, or the legacy weixin.enabled) or in the settings panel";
21376
+ },
21362
21377
  resolveUser(root, input) {
21363
21378
  const raw = input.trim();
21364
21379
  if (raw === "") return null;
@@ -21605,6 +21620,16 @@ const feishuChannel = {
21605
21620
  if (settings.enabled !== true) return false;
21606
21621
  return (settings.accounts ?? []).some((a) => a.enabled !== false && isFeishuAccount(a));
21607
21622
  },
21623
+ /**
21624
+ * 启用判据不成立时**说清是哪一半不成立**。
21625
+ *
21626
+ * 🔴 两半的改法完全不同(总开关 vs 加一条账号),合并成一句会让人改错那一半
21627
+ * —— 这正是本轮真机验收暴露出来的形态(旧文案只提 `weixin.enabled`)。
21628
+ */
21629
+ notEnabledReason(root) {
21630
+ if (readWeixinSettings(root).enabled !== true) return "This CCC has no IM bridge enabled — turn on the IM switch in .opencode/serenity.json (im.enabled, or the legacy weixin.enabled) or in the settings panel";
21631
+ return "The IM bridge is on, but this CCC has no enabled feishu account — add one (App ID + App Secret) in the settings panel, or add a row with channel:\"feishu\" to im.accounts";
21632
+ },
21608
21633
  resolveUser(root, input) {
21609
21634
  const raw = input.trim();
21610
21635
  if (raw === "") return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shgroup/dsh-serenity-hooks",
3
- "version": "1.79.0",
3
+ "version": "1.79.1",
4
4
  "description": "宁静号 ACC harness(Native Cordis 插件)——给 DeepSeek Harness 装一个「AI 工作区」:14 个工具(container_fs/cognitive_trajectory/dashboard/container_git/msm/praxis/ontology/serenity-skill-creator/cheap-worker/localstore/container_admin;另三个 im-bridge/acc-diag/diagram 按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫/对外输出守卫)+ 认知轨迹日志与原地重建 + 网页登录入口/IM 桥/认知轨迹唤醒注册表。轨迹声明 = 轨迹目录下的 trajectory.json(约束面 + 旧标识 uid + CRO 机器绑定 cro.host;旧名 trajectory-constraint.json / skiff.json 仍在读取族里);轨迹提示词 = 轨迹目录下的 PROMPT.md(一条轨迹「是谁、按什么章程工作」,所有轨迹通用,追加在容器层与质量层之后,不替换它们)。适配 DSH 0.1.7-rc.1 / 0.2.0-rc.1 / 0.2.1-rc.1(三档)。",
5
5
  "license": "MIT",
6
6
  "repository": {