@shgroup/dsh-serenity-hooks 1.47.2 → 1.47.4

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.47.2",
3
+ "version": "1.47.4",
4
4
  "main": "lib/index.js",
5
5
  "description": "宁静号 ACC harness(Native Cordis 插件):给 DSH 装一个「AI 工作区」——11 个工具(container_fs/container_trajectory/dashboard/container_git/msm/praxis/handyman/localstore/container_admin/im-bridge/acc-diag;后两个按配置条件出现)+ 机械约束(安全模式/工作区围墙/密钥守卫)+ 轨迹日志与原地重建 + 网页登录入口/微信桥/子角色/对外问答页/trajectory 唤醒注册表。适配 DSH 0.1.5-rc.2(deepseek-ai/deepseek-harness)。",
6
6
  "engines": {
@@ -72,5 +72,8 @@ function hostWeb(ctx) {
72
72
  function hostSubagents(ctx) {
73
73
  return hostInjected(ctx, "subagents");
74
74
  }
75
+ function hostLlm(ctx) {
76
+ return hostInjected(ctx, "llm");
77
+ }
75
78
  //#endregion
76
- export { hostSettings as a, hostWebServer as c, hostSessions as i, hostInjected as n, hostSubagents as o, hostService as r, hostWeb as s, hostAgents as t };
79
+ export { hostSessions as a, hostWeb as c, hostService as i, hostWebServer as l, hostInjected as n, hostSettings as o, hostLlm as r, hostSubagents as s, hostAgents as t };
package/lib/api.d.ts CHANGED
@@ -10,7 +10,6 @@
10
10
  * 经 ctx.webServer(webserver 服务,公开版由 httpServer 改名)注册;客户端与服务器同源,调用无信任围栏问题。
11
11
  */
12
12
  import type { Context } from 'cordis';
13
- import type { IncomingMessage } from 'node:http';
14
13
  /** 图片落盘目录(CCC 根相对;S142 图片自动识别基础设施——粘贴图片落盘供 agent 经 CCC vlm MSM 自主处理) */
15
14
  export declare const IMAGE_UPLOAD_DIR = "_tmp/images_from_user";
16
15
  /** 文件落盘目录(CCC 根相对;v1.24.1 粘贴任意文件自动落盘——agent 经 CCC 既有 MSM(pdf-extract/archive-extract 等)自主处理) */
@@ -32,15 +31,6 @@ export declare function sanitizeFileName(name: string): string;
32
31
  * 校验失败抛 Error(handler 转 400)。
33
32
  */
34
33
  export declare function saveFileToTmp(root: string, fileName: string, data: string): string;
35
- /**
36
- * WebUI 专属动作的来源判别(C4 块 C:此前 **9 处内联** `req.headers['x-serenity-ui'] !== '1'`)。
37
- *
38
- * ⚠️ 语义边界(勿误读为认证):这是**客户端判别头**——任何本机能发 HTTP 的进程都可自带它
39
- * (无密钥、无签名、不校验来源,见现状取证 §② 面 A "认证与守卫")。它区分的是
40
- * "WebUI 触发的动作"与"agent/curl 触发的动作"(如 safe-mode 不可由 agent 自行开关)。
41
- * 本 helper 只做**同一判据的归一**,不放宽也不收紧:判据、状态码、文案均由调用方给出。
42
- */
43
- export declare function senderIsWebUi(req: IncomingMessage): boolean;
44
34
  interface StatusApiRegistration {
45
35
  configPaths?: string[];
46
36
  }
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { i as hostSessions, r as hostService } from "./access-fiehjxV6.js";
2
+ import { a as hostSessions, i as hostService } from "./access-CNccNtgf.js";
3
3
  import { a as findSerenityRoot } from "./ccc-DG4Oc7I1.js";
4
4
  import { basename } from "node:path";
5
5
  //#region src/ccc-roots.ts
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * clock-runtime.ts — **时钟运行时工厂**(S142 §38 复审候选 C6b,路径 **P2**)
3
3
  *
4
- * 本仓有**两条各自独立运行**的 5min 时钟:
5
- * · 唤醒调度器(`wake-scheduler.ts`,一次性唤醒,D58)
6
- * · autopilot 时钟(`autopilot-trajectory.ts`,周期自唤醒,D59)
4
+ * 🔴 2026-09-25(S142 分批清死代码·第 1 批)**更正**:本文件当初是为**两条**独立 5min 时钟抽出的公共引擎:
5
+ * · 唤醒调度器(`wake-scheduler.ts`,一次性唤醒,D58)—— **现存**
6
+ * · autopilot 时钟(`autopilot-trajectory.ts`,周期自唤醒,D59)—— 🔴 **已随 v1.35.0 整段退场**
7
7
  * 二者的**业务判据完全不同**(谁来扫 / 扫什么 / 投递给谁 / 按什么周期),但**引擎骨架逐字同形**
8
8
  * ——进程态 + 快照 + 复位 + `startTimer` + tick 外壳 + 事件接线 + disposer + `timer.unref()`。
9
- * 本条把**引擎**抽到本工厂,**各钟仍各持自己的定时器与自己的串行链**。
9
+ * 本条把**引擎**抽到本工厂,**各钟仍各持自己的定时器与自己的串行链**(现存的那一钟 = 唤醒调度器)。
10
10
  *
11
11
  * ───────────────────────────────────────────────────────────────────────────
12
12
  * 🔴 硬约束一:**两条时钟绝不可共用"排队执行"的链**(这是 P2 与 P1 的分界判据)
@@ -26,7 +26,9 @@
26
26
  *
27
27
  * 🔴 硬约束三:**闸是可选能力,工厂不得替调用方假设"必须有闸"**(v1.34 S-1 解耦 → 2026-09-21 收窄)
28
28
  *
29
- * 现只余 **autopilot `autopilotWakeEnabled`**(**缺省关**)一条;**唤醒调度器已无闸**
29
+ * 🔴 2026-09-25(S142 分批清死代码·第 1 批)**更正:当前零条闸在用** —— 现存唯一那一钟
30
+ * (唤醒调度器)本已无闸,而"曾只余的那一条" `autopilotWakeEnabled` 已随 **v1.35.0 autopilot
31
+ * 整段退场**一并消失 ⇒ `gate` **缺省即常态,不是特例**。**唤醒调度器已无闸**
30
32
  * (原 `wakeSchedulerEnabled` 于 2026-09-21 所有者令砍掉 ⇒ 调用方**不传** `gate`
31
33
  * = 恒武装、永不因闸跳过、`enabled` 恒 `true`)。工厂取 `gate` **回调**(每次现读),
32
34
  * **不做**任何合并或缓存;**缺省无闸是合法形态,不是漏配**。
@@ -49,7 +49,6 @@
49
49
  * ⚠️ 这也天然处理了「同一轨迹多载体」(S142 曾挂 4 条)的情形。
50
50
  */
51
51
  import type { Context } from 'cordis';
52
- import type { Agent } from '@deepseek-ai/dsh-agent';
53
52
  /** 一次「在跑」记录的 TTL(见文件头的方向性判据) */
54
53
  export declare const TURN_TTL_MS: number;
55
54
  /** 标记「在跑」(`agent/created` + `agent/status=running` 调用) */
@@ -91,5 +90,3 @@ export declare function __resetCroTurnsForTest(): void;
91
90
  * @param ctx 插件上下文
92
91
  */
93
92
  export declare function registerCroTurnTracking(ctx: Context): void;
94
- /** 类型再导出(调用方少一处 import) */
95
- export type { Agent as CroAgent };
package/lib/cro.d.ts CHANGED
@@ -256,8 +256,6 @@ export declare function listCroTrajectories(root: string): string[];
256
256
  * @returns 执行结果(含输出的解析交由 `parseCroOutput`)
257
257
  */
258
258
  export declare function runCroProcess(scriptAbs: string, stdinJson: string, timeoutMs?: number): Promise<CroRunResult>;
259
- /** 读 SESSION.md 体积(供看门狗判据等复用;读不到 ⇒ null) */
260
- export declare function readSessionMdBytes(mdPath: string): number | null;
261
259
  /** 读取快照所需的 fs 侧数据(**纯读取,不抛**) */
262
260
  export declare function readCroSnapshotInput(root: string, dirName: string, nowMs: number, extras: {
263
261
  liveSessionIds: string[];
@@ -39,6 +39,34 @@ export declare function splitModel(model: string): {
39
39
  };
40
40
  /** 校验模型在白名单内;不在 → 抛错(用户拍板:只能使用 CCC 配置的模型) */
41
41
  export declare function requireWhitelistedModel(model: string, models: string[]): void;
42
+ /**
43
+ * providerAvailabilityError — 判定「**本机有没有该 provider 的 adapter**」,并产出**可执行**的错误文本。
44
+ * 返回 `null` = 全部可用(调用方照常继续)。
45
+ *
46
+ * 🔴 为什么需要它(S142 2026-09-25,owner 在 **Mac** 上实测):`handyman` 的模型白名单写在
47
+ * **CCC**(`.opencode/serenity.json`,**随 git 走**),而 provider adapter 由**每台机器的宿主**
48
+ * 注册(profile 配置 / settings 命名空间)⇒ 同一份白名单在一台机器可用、在另一台必失败。
49
+ * 实测症状:宿主抛 `no adapter registered for provider "<p>"`(`dsh-llm`,code `NO_ADAPTER`),
50
+ * 而**前台路径的 `diagnostic` 是空的** ⇒ 调用方(LLM)拿到 `stopReason:"error"` 却**不知道为什么**,
51
+ * 也就无法修正自己的配置 —— 本条把「沉默的失败」变成「可执行的错误」。
52
+ *
53
+ * 数据来源(宿主 `LlmRuntime`):`listProviders()` = **有 adapter 的路由**;
54
+ * `listConfigurableProviders()` = **已声明但未必激活**的路由(含激活用的 settings 命名空间)。
55
+ *
56
+ * 判据边界:`model` 串里**没有 `/`** 时取不到 provider(沿用 agent 默认路由)⇒ **不判定**(跳过)。
57
+ */
58
+ export declare function providerAvailabilityError(models: readonly string[], facts: {
59
+ registered: readonly {
60
+ id: string;
61
+ name?: string;
62
+ }[];
63
+ declared?: readonly {
64
+ provider: string;
65
+ displayName?: string;
66
+ settingsNs?: string;
67
+ }[];
68
+ configPath?: string;
69
+ }): string | null;
42
70
  /** 轮次 prompt(对齐老 loop 结构:回顾进度 → 自由工作 → 汇报;S134 EAP 化:固定详尽) */
43
71
  export declare function buildRoundPrompt(opts: {
44
72
  root: string;
@@ -54,7 +82,7 @@ export declare function buildRoundPrompt(opts: {
54
82
  * 使用 handyman 前必须先加载 eap 设计方案;并行策略(jobs 编排);提示词规范(详尽固定 EAP);
55
83
  * 阅读/文字编写类 handyman 内部也加载 eap。
56
84
  */
57
- export declare const HANDYMAN_GUIDE = "# handyman \u2014 Scale-Up Usage Guide (guide)\n\n## Two modes (v1.31.3; default = foreground)\n| | foreground (default) | background |\n|---|---|---|\n| What | one serial child agent runs the task ONCE and returns its final text | loop-validated worker: hard while-loop + random completion code |\n| Use when | you need exactly one result back now (per-case testers, single conversions) | long/unattended work needing anti-early-finish, resumability, or parallel jobs |\n| Loop / validation | none | stop-token is the ONLY completion condition; round cap (default 100); auto-restart (\u2264100) |\n| Progress file | none | AGENT_SESSIONS/handyman-<label>.md/.json (same label resumes) |\n| Parallel jobs | no (call once per task) | yes (jobs=[...], handyman.maxParallel default 10) |\n| Mechanism | host delegation service ctx.subagents.start(\"spawn\") + agentOptions | ctx.agents.create + internal while-loop |\n| Model source | CCC handyman.models whitelist (same for both) | same |\n\n## \u26A0\uFE0F Before using: load eap and design the plan\nBefore calling handyman, load eap (acc-eap skill) and design the \"scale-up handyman plan\" based on the EAP framework.\n\n### 1. Task decomposition (E\u2191 Explicit)\n- Split large tasks into explicit subtasks: each subtask defines goal / input / boundaries (what to do, what not to do) / acceptance criteria\n- Make dependencies explicit: dependent tasks run serially, independent ones can run in parallel (background mode)\n\n### 2. Prompt design (handyman's task parameter)\n- task must be detailed, fixed, and EAP-compliant: clear goal, drawn boundaries, decidable acceptance criteria\n- foreground mode: the child does NOT share your conversation \u2014 restate everything it needs in task\n- Anti-example \"handle this file\" \u2014 ambiguous; good example \"read <path>, extract all rows of the\u300C\u5173\u952E\u51B3\u7B56\u300Dtable,\n output a JSON array (fields id/conclusion/evidence), do not modify the original file\"\n- Reading/curating or text-writing work (extracting from files, summarizing, writing docs, generating text, etc.):\n the handyman-internal agent is also required to load eap and organize output per the EAP standard\n\n### 3. Model whitelist (CCC-configured, mandatory)\n- handyman only uses models listed in .opencode/serenity.json \"handyman.models\" \u2014 never arbitrary models\n- The CCC is expected to point this whitelist at LOW-COST models: handyman is the bulk-execution channel\n- background mode: recursive subagents inside a worker inherit the worker's model automatically (DSH native)\n- foreground mode: the child is started through the host delegation service with the resolved model\n\n### 4. Parallel strategy (background mode only)\n- Independent subtasks can run in parallel via handyman(mode=\"background\", jobs=[...]): each job gets its own label + task + stop token + progress file\n- Concurrency safety guaranteed: unique sessionId (handyman-<label>-<uuid>), progress files isolated per label\n (AGENT_SESSIONS/handyman-<label>.json) \u2014 same label resumes, different labels never interfere\n- Parallel cap: handyman.maxParallel (default 10 \u2014 cheap models are cheap)\n- Aggregation: after each parallel job produces progress, the main agent merges (or spawns one aggregation handyman)\n- For programmable pipeline/phase orchestration at scale, use the platform's workflow tool instead\n\n## Completion criteria\n- foreground: the child's run settles; done=true only when stopReason=\"completed\" (otherwise read diagnostic)\n- background (osp loop standard): the only completion condition = the worker echoes this round's random verification\n code (stop token); dialogue round cap (default 100, osp fail-safe, forced stop beyond the cap, resumable);\n automatic restart on abnormal agent stop (\u2264100 restarts, anti-infinite-loop)\n\n## Waiting UI\n- The WebUI session-header Serenity detail card shows running background handymen's progress\n (label / round / last response), one line per parallel job, ~3s refresh (foreground mode writes no progress)\n";
85
+ export declare const HANDYMAN_GUIDE = "# handyman \u2014 Scale-Up Usage Guide (guide)\n\n## Two modes (v1.31.3; default = foreground)\n| | foreground (default) | background |\n|---|---|---|\n| What | one serial child agent runs the task ONCE and returns its final text | loop-validated worker: hard while-loop + random completion code |\n| Use when | you need exactly one result back now (per-case testers, single conversions) | long/unattended work needing anti-early-finish, resumability, or parallel jobs |\n| Loop / validation | none | stop-token is the ONLY completion condition; round cap (default 100); auto-restart (\u2264100) |\n| Progress file | none | AGENT_SESSIONS/handyman-<label>.md/.json (same label resumes) |\n| Parallel jobs | no (call once per task) | yes (jobs=[...], handyman.maxParallel default 10) |\n| Mechanism | host delegation service ctx.subagents.start(\"spawn\") + agentOptions | ctx.agents.create + internal while-loop |\n| Model source | CCC handyman.models whitelist (same for both) | same |\n\n## \u26A0\uFE0F Before using: load eap and design the plan\nBefore calling handyman, load eap (acc-eap skill) and design the \"scale-up handyman plan\" based on the EAP framework.\n\n### 1. Task decomposition (E\u2191 Explicit)\n- Split large tasks into explicit subtasks: each subtask defines goal / input / boundaries (what to do, what not to do) / acceptance criteria\n- Make dependencies explicit: dependent tasks run serially, independent ones can run in parallel (background mode)\n\n### 2. Prompt design (handyman's task parameter)\n- task must be detailed, fixed, and EAP-compliant: clear goal, drawn boundaries, decidable acceptance criteria\n- foreground mode: the child does NOT share your conversation \u2014 restate everything it needs in task\n- Anti-example \"handle this file\" \u2014 ambiguous; good example \"read <path>, extract all rows of the\u300C\u5173\u952E\u51B3\u7B56\u300Dtable,\n output a JSON array (fields id/conclusion/evidence), do not modify the original file\"\n- Reading/curating or text-writing work (extracting from files, summarizing, writing docs, generating text, etc.):\n the handyman-internal agent is also required to load eap and organize output per the EAP standard\n\n### 3. Model whitelist (CCC-configured, mandatory)\n- handyman only uses models listed in .opencode/serenity.json \"handyman.models\" \u2014 never arbitrary models\n- The CCC is expected to point this whitelist at LOW-COST models: handyman is the bulk-execution channel\n- background mode: recursive subagents inside a worker inherit the worker's model automatically (DSH native)\n- foreground mode: the child is started through the host delegation service with the resolved model\n\n### 3b. \uD83D\uDD34 Provider availability (per-machine \u2014 the whitelist is NOT enough)\n- The whitelist lives in the **CCC** (\"serenity.json\", it **travels with the repository**), but provider\n **adapters are registered per machine by the host** (profile config / settings namespace). An entry that\n works on one machine can fail on another with: \"no adapter registered for provider <p>\".\n- Before spawning, handyman verifies the provider of the resolved model against the adapters registered\n **on this machine**; if it is missing it reports the requested model, where it is configured, **the\n providers that ARE available here**, any declared-but-dormant route (with its settings namespace), and the\n exact fix \u2014 foreground puts this in \"diagnostic\", background throws it.\n- \u21D2 If you see \"has no adapter registered on this machine\": edit \".opencode/serenity.json\" \"handyman.models\"\n (and \"handyman.defaultModel\") to a provider listed as available, or activate/register the provider on this\n machine. **Do not retry the same call unchanged** \u2014 it fails identically.\n\n### 4. Parallel strategy (background mode only)\n- Independent subtasks can run in parallel via handyman(mode=\"background\", jobs=[...]): each job gets its own label + task + stop token + progress file\n- Concurrency safety guaranteed: unique sessionId (handyman-<label>-<uuid>), progress files isolated per label\n (AGENT_SESSIONS/handyman-<label>.json) \u2014 same label resumes, different labels never interfere\n- Parallel cap: handyman.maxParallel (default 10 \u2014 cheap models are cheap)\n- Aggregation: after each parallel job produces progress, the main agent merges (or spawns one aggregation handyman)\n- For programmable pipeline/phase orchestration at scale, use the platform's workflow tool instead\n\n## Completion criteria\n- foreground: the child's run settles; done=true only when stopReason=\"completed\" (otherwise read diagnostic)\n- background (osp loop standard): the only completion condition = the worker echoes this round's random verification\n code (stop token); dialogue round cap (default 100, osp fail-safe, forced stop beyond the cap, resumable);\n automatic restart on abnormal agent stop (\u2264100 restarts, anti-infinite-loop)\n\n## Waiting UI\n- The WebUI session-header Serenity detail card shows running background handymen's progress\n (label / round / last response), one line per parallel job, ~3s refresh (foreground mode writes no progress)\n";
58
86
  /** handyman 运行状态(进度文件摘要;WebUI 等待界面数据源) */
59
87
  interface HandymanRunInfo {
60
88
  label: string;
@@ -96,6 +96,27 @@ interface HostSubagents {
96
96
  start?: (name: string, request: unknown) => Promise<unknown>;
97
97
  }
98
98
  export declare function hostSubagents(ctx: unknown): HostSubagents | undefined;
99
+ /**
100
+ * `ctx.llm`(`LlmRuntime`;v1.48:handyman 的 **provider 预检**取证面)。
101
+ *
102
+ * 形状对照宿主 rc.2(`@deepseek-ai/dsh-llm`):
103
+ * · `listProviders()` → `{ id, name }[]` —— **有 adapter** 的路由("本机真能用")
104
+ * · `listConfigurableProviders()` → `{ provider, displayName, settingsNs, … }[]` ——
105
+ * **已声明但未必激活**的路由("可以激活")
106
+ *
107
+ * 🔴 为什么走 `hostInjected` 而不是直接属性读:`llm` **不在** dsp 的 `inject` 列表内
108
+ * (见 `src/index.ts` 的 `inject`)⇒ 真实 cordis 下直接属性读对未声明服务**会抛**
109
+ * (`cannot get property "llm" without inject`),必须回落 `ctx.get`。
110
+ *
111
+ * 🔴 为什么**刻意不把 `llm` 加进 `inject`**:预检是**尽力而为**的增强,不是运行前提。
112
+ * 加进 `inject` 会让"没有 llm 服务的 profile"**整块不激活插件** —— 为了一条诊断信息
113
+ * 换来插件不上线,代价与收益倒挂。缺失一律 `undefined`,调用方**不得**因此抛错。
114
+ */
115
+ interface HostLlm {
116
+ listProviders?: () => unknown;
117
+ listConfigurableProviders?: () => unknown;
118
+ }
119
+ export declare function hostLlm(ctx: unknown): HostLlm | undefined;
99
120
  /** 会话 cwd 列表(live 会话;形状不符时返回空数组而非抛错) */
100
121
  export declare function hostSessionCwds(ctx: unknown): string[];
101
122
  export {};