@shgroup/dsh-serenity-hooks 1.32.0 → 1.34.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/README.md +12 -11
- package/dsh.plugin.json +5 -5
- package/lib/acp-core.d.ts +2 -22
- package/lib/acp-http.d.ts +8 -0
- package/lib/api.d.ts +12 -4
- package/lib/autopilot-chain.d.ts +76 -0
- package/lib/autopilot-core-DCRkiWEe.js +229 -0
- package/lib/autopilot-core.d.ts +132 -0
- package/lib/autopilot-ops.d.ts +48 -0
- package/lib/autopilot-trajectory-D9Znxo75.js +782 -0
- package/lib/autopilot-trajectory.d.ts +79 -83
- package/lib/{ccc-DAsSHsub.js → ccc-NlLr_sxy.js} +18 -2
- package/lib/ccc-roots-Bd_SjEs7.js +152 -0
- package/lib/ccc-roots.d.ts +105 -0
- package/lib/ccc.d.ts +23 -6
- package/lib/client.js +30 -10
- package/lib/clock-runtime.d.ts +197 -0
- package/lib/config-ops.d.ts +9 -14
- package/lib/constants.d.ts +0 -2
- package/lib/container-status.d.ts +183 -0
- package/lib/diag-ops.d.ts +76 -0
- package/lib/face-host.d.ts +110 -0
- package/lib/fs-ops.d.ts +3 -2
- package/lib/gateway-auth.d.ts +2 -5
- package/lib/gateway.d.ts +0 -34
- package/lib/git-ops.d.ts +3 -2
- package/lib/handyman-ops.d.ts +3 -2
- package/lib/handyman-preset-inherit.d.ts +2 -1
- package/lib/host/access.d.ts +8 -7
- package/lib/host/contract.d.ts +17 -6
- package/lib/host/type-contract.d.ts +1 -2
- package/lib/im-bridge.d.ts +6 -5
- package/lib/index.d.ts +1 -1
- package/lib/index.js +11053 -8305
- package/lib/invariant.d.ts +5 -16
- package/lib/invariant.js +8 -4
- package/lib/json.d.ts +1 -1
- package/lib/kit-ops.d.ts +11 -31
- package/lib/localstore-ops.d.ts +3 -17
- package/lib/msm-ops.d.ts +34 -52
- package/lib/opencode-provider.d.ts +4 -5
- package/lib/output-guard-seam.d.ts +1 -4
- package/lib/output-guard.d.ts +12 -3
- package/lib/ports.d.ts +59 -0
- package/lib/rebuild.d.ts +5 -4
- package/lib/seams/bootstrap.d.ts +4 -3
- package/lib/seams/compact.d.ts +2 -1
- package/lib/seams/context.d.ts +2 -4
- package/lib/seams/env.d.ts +2 -1
- package/lib/seams/guards.d.ts +22 -34
- package/lib/seams/keeper.d.ts +4 -4
- package/lib/seams/system-prompt.d.ts +1 -5
- package/lib/session-cleanup.d.ts +3 -2
- package/lib/{settings-section-Bm-xG-NR.js → settings-section-DTYZjwUs.js} +70 -15
- package/lib/settings-section.d.ts +14 -35
- package/lib/skiff-core.d.ts +5 -10
- package/lib/skiff-debug.d.ts +15 -21
- package/lib/skiff-registry-FTjoWQTQ.js +25 -0
- package/lib/skiff-registry.d.ts +2 -1
- package/lib/{skiff-role-BYvNnwv1.js → skiff-role-CEHL5cek.js} +1 -1
- package/lib/skiff-role.d.ts +2 -2
- package/lib/skills/opencode-scan.d.ts +3 -2
- package/lib/skills-discovery.d.ts +15 -2
- package/lib/status.d.ts +2 -1
- package/lib/tools/acc-diag.d.ts +22 -0
- package/lib/tools/cce.d.ts +1 -2
- package/lib/tools/container-admin.d.ts +7 -3
- package/lib/tools/eap.d.ts +2 -3
- package/lib/tools/handyman.d.ts +0 -29
- package/lib/tools/msm.d.ts +0 -4
- package/lib/tools/neat.d.ts +1 -2
- package/lib/tools/praxis.d.ts +0 -1
- package/lib/tools/skiff-admin.d.ts +2 -2
- package/lib/tools/{session.d.ts → trajectory.d.ts} +25 -17
- package/lib/totp.d.ts +0 -4
- package/lib/trajectory-assistant.d.ts +2 -1
- package/lib/trajectory-bound-Cax1p9ut.js +190 -0
- package/lib/{session-bound.d.ts → trajectory-bound.d.ts} +5 -6
- package/lib/trajectory-ops-mrXK0H0I.js +410 -0
- package/lib/{session-ops.d.ts → trajectory-ops.d.ts} +27 -36
- package/lib/trajectory-skills.d.ts +71 -0
- package/lib/wake-registry-CYxIb484.js +257 -0
- package/lib/wake-registry.d.ts +3 -11
- package/lib/wake-scheduler.d.ts +23 -20
- package/lib/web-fetch-provider.d.ts +0 -21
- package/lib/{weixin-api-PjEhmjlZ.js → weixin-api-CtFYm53S.js} +3 -9
- package/lib/weixin-api.d.ts +6 -37
- package/lib/weixin-bridge.d.ts +5 -24
- package/lib/weixin-hook.d.ts +6 -12
- package/lib/weixin-output-guard.d.ts +2 -1
- package/lib/{weixin-route-wWk4AIwV.js → weixin-route-B2ajFypI.js} +4 -5
- package/lib/weixin-route.d.ts +0 -2
- package/lib/weixin-send-api.d.ts +15 -6
- package/package.json +3 -5
- package/experiments/autopilot-trajectory/SKILL.md +0 -115
- package/experiments/autopilot-trajectory/scripts/autopilot-trajectory.ts +0 -522
- package/lib/session-bound-NHozeLFc.js +0 -822
- package/lib/skiff-debug-K2k1JnGj.js +0 -2867
- package/lib/tools/autopilot-trajectory.d.ts +0 -25
- package/lib/{session-cleanup-CMT4mHWt.js → session-cleanup-B6IHZgww.js} +1 -1
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* diag-ops.ts — `acc-diag` 报告装配(v1.33,S142 §32.11)
|
|
3
|
+
*
|
|
4
|
+
* 为什么单独成模块(R↓):工具面(`tools/acc-diag.ts`)只做"取 CCC 根 + 渲染",
|
|
5
|
+
* 装配逻辑放这里 ⇒ 纯函数可单测、不依赖 DSH 工具注册。
|
|
6
|
+
*
|
|
7
|
+
* 为什么**无动作参数**:诊断是低频动作(§32.9 收敛取向),一次调用即出全报告,
|
|
8
|
+
* 不需要子命令面;动作越多,模型选择成本越高。
|
|
9
|
+
*
|
|
10
|
+
* 四段内容(数据来源各自单一真相源,本模块只聚合不复制语义):
|
|
11
|
+
* ① live 运行态 —— 插件进程内 `diagLive(ctx)`(live 会话清单 + 各 autopilot CCC 的
|
|
12
|
+
* 目标命中 / agent 定位诊断)——**独立进程看不到运行时**,这正是本工具存在的理由
|
|
13
|
+
* ② 面板解析 —— `diagLive.panelResolved`(无参面板请求会落到哪个 CCC)
|
|
14
|
+
* ③ 唤醒注册表 —— `wake-registry.json` 全量条目(state / at / target / lastResult)+ 补跑窗口
|
|
15
|
+
* ④ 唤起条件链 —— **进程内** {@link buildWakeChain}(⑥ C6a):逐条件值 + 阻断点 + 修复建议
|
|
16
|
+
* + 只有进程内能看到的三项事实(全局闸 / live 会话 / agent 可解析性)
|
|
17
|
+
*
|
|
18
|
+
* C5「观察面归一」(2026-09-15):①/② 仍走 `diagLive`(那是**live 运行态**的独有取数,
|
|
19
|
+
* 没有第二个来源),但 ①b 时钟与 ③ 注册表改经 `container-status.ts` 取(唯一取数出口)——
|
|
20
|
+
* **投影仍在本文件**(诊断段不含 `message`,面板含;这是渲染差异,不是取数差异)。
|
|
21
|
+
*
|
|
22
|
+
* ⑥ C6a(2026-09-15):④ 段由"spawn 包内脚本"改为**进程内计算**。旧实现是本报告里
|
|
23
|
+
* 唯一一条**跨进程**取数:脚本看不到全局闸/live/agent ⇒ 与本工具 ① 段自相矛盾
|
|
24
|
+
* (① 说"agent 未定位",④ 却印"条件全部满足")。现在 ④ 段与 ① 段读**同一份事实**
|
|
25
|
+
* (`autopilotRuntimeFacts`),且条件链**只有一份实现**(开发面 `dsh-develop diag` import 同一个)。
|
|
26
|
+
*/
|
|
27
|
+
import { type DiagLiveReport } from './autopilot-trajectory.js';
|
|
28
|
+
import { type ClockSnapshot } from './container-status.js';
|
|
29
|
+
import type { Context } from 'cordis';
|
|
30
|
+
/** 进程内时钟状态(唤醒调度器 / autopilot 时钟;判据各自单一真相源) */
|
|
31
|
+
type ClockState = ClockSnapshot;
|
|
32
|
+
interface AccDiagReport {
|
|
33
|
+
/** 调用方会话所属 CCC 根(过程内诊断的目标) */
|
|
34
|
+
ccc: string;
|
|
35
|
+
live: DiagLiveReport;
|
|
36
|
+
/**
|
|
37
|
+
* 进程内两个时钟的武装状态(2026-09-14 F 段缺陷**新暴露面**)。
|
|
38
|
+
* 为什么必须有(R↓):此前"条目为何滞留在 pending"无法从报告回答——④ 段只算**配置**条件,
|
|
39
|
+
* 而真正的原因可能在"时钟根本没在跑"这一层。有了它,同类故障一眼可判。
|
|
40
|
+
*/
|
|
41
|
+
clocks: {
|
|
42
|
+
wake: ClockState;
|
|
43
|
+
autopilot: ClockState;
|
|
44
|
+
};
|
|
45
|
+
wakes: {
|
|
46
|
+
/** 注册表文件路径问题(读不到时非空——不得静默) */
|
|
47
|
+
error: string | null;
|
|
48
|
+
entries: Array<{
|
|
49
|
+
id: string;
|
|
50
|
+
target: string;
|
|
51
|
+
at: string;
|
|
52
|
+
state: string;
|
|
53
|
+
createdBy: string;
|
|
54
|
+
attempts: number;
|
|
55
|
+
lastResult: string | null;
|
|
56
|
+
}>;
|
|
57
|
+
pending: number;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* 唤起条件链(进程内算出的渲染文本,含逐条件值 + 阻断点 + 修复建议)。
|
|
61
|
+
* **不是**子进程输出——判据唯一实现见 `autopilot-chain.ts`。
|
|
62
|
+
*/
|
|
63
|
+
autopilotChain: string;
|
|
64
|
+
/** 条件链判决档(`ready`/`waiting`/`blocked`/`unknown`;供调用方/测试断言,不再解析文本) */
|
|
65
|
+
autopilotVerdict: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* 装配报告(一次调用即全报告)。
|
|
69
|
+
* @param ctx 插件上下文(进程内读 sessions/agents)
|
|
70
|
+
* @param root 调用方 CCC 根(条件链诊断目标)
|
|
71
|
+
* @returns 结构化报告(渲染由 {@link renderAccDiag} 负责)
|
|
72
|
+
*/
|
|
73
|
+
export declare function runAccDiag(ctx: Context, root: string): Promise<AccDiagReport>;
|
|
74
|
+
/** 人读渲染(四段;空段也要显式说明"无",避免"沉默 = 一切正常"的误读) */
|
|
75
|
+
export declare function renderAccDiag(r: AccDiagReport): string;
|
|
76
|
+
export {};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* face-host.ts — **面宿主**:插件自起 HTTP listener 的唯一生命周期处(C4 块 A,S142 2026-09-15)
|
|
3
|
+
*
|
|
4
|
+
* ## 现状 → 本模块要收掉什么(取证:`…/acc-c4c5-current-state.md` §①/§③ 3.1)
|
|
5
|
+
*
|
|
6
|
+
* 插件自己 spawn 了**四个** node:http 监听器(B 3081 网关 / C 3082 微信发送 / D 3099 Skiff 调试
|
|
7
|
+
* / E 3100 ACP+问答)。此前四处各写一份同款样板:`createServer` + `server.once('error')` +
|
|
8
|
+
* `listen(port, host)` + 模块级 `active` 变量 + `close()`;拆卸也分裂成**两套**——
|
|
9
|
+
* `seams/lifecycle.ts` 有一个聚合 disposer,而 `gateway.ts` 与 `weixin-send-api.ts`
|
|
10
|
+
* **各自另注册**一个(D/E 干脆没有自己的 disposer)。
|
|
11
|
+
*
|
|
12
|
+
* 本模块把"listener 生命周期"收成一处:**active 表 + 统一 listen/close + 统一错误与端口占用
|
|
13
|
+
* 处理**。四个面各自只提供 `{ name, port, host, enabled, handler }`。
|
|
14
|
+
*
|
|
15
|
+
* ## 🔴 共享的是「生命周期与样板」,**绝不是**「路由 / 监听器 / 鉴权」
|
|
16
|
+
*
|
|
17
|
+
* 每个面**保留自己的 listener、自己的路由、自己的鉴权**(`handler` 内部原样不动):
|
|
18
|
+
* · **A ↔ C 解耦**(`weixin-send-api.ts:4-7`):3080 会被 3081 原样反代(连请求头),
|
|
19
|
+
* 把 3082 的端点挂到 3080 上 = 已登录的外部家庭账号即可冒充 bot 发消息
|
|
20
|
+
* ⇒ 本模块**不提供**"把面挂到别的面"的能力,也不共享路由表;
|
|
21
|
+
* · **E ↔ D** 共用会话核心(acp-core → skiff-core)但各自独立 listener + 独立路由/HTML;
|
|
22
|
+
* · **B 是 A 的代理宿主**(把请求打到 `127.0.0.1:<主端口>`),不是另一个路由面。
|
|
23
|
+
*
|
|
24
|
+
* ## 面 A(3080)不在本模块之列
|
|
25
|
+
* 它是**宿主 DSH 主 WebUI**,插件只往上挂 `/serenity/*` 路由(`ctx.webServer.register`),
|
|
26
|
+
* **插件不起这个 listener** ⇒ 面宿主只持有 B/C/D/E 四个自起面。
|
|
27
|
+
*
|
|
28
|
+
* ## 两个入口的分工(这是本模块唯一的"抽象决策",别混)
|
|
29
|
+
* · {@link startFace} —— **机械启动**:把一个 handler 绑到 `host:port` 上。同名面若已在监听,
|
|
30
|
+
* **先停后起**(替换);同名面正在启动中则**复用在飞的 Promise**(并发合并——这条替代了
|
|
31
|
+
* `index.ts` 里手搓的 `starting` 在飞标志与随之而来的 `EADDRINUSE` 双绑)。
|
|
32
|
+
* 它**不读** `spec.enabled()`:调用方保证意图(测试/程序化直启也走这里)。
|
|
33
|
+
* · {@link faceEnabled} —— **意图读取**:装配层据此判"该面此刻应否在监听",替代各面 sync 里
|
|
34
|
+
* 手写的 `const want = <配置> && ...` 判据(判据本身只写在面的 {@link FaceSpec} 里一次)。
|
|
35
|
+
*/
|
|
36
|
+
import { type IncomingMessage, type Server, type ServerResponse } from 'node:http';
|
|
37
|
+
/** 面规格:**四个面各自只提供这 5 项**(路由/鉴权/响应体全部归面的 `handler`) */
|
|
38
|
+
export interface FaceSpec {
|
|
39
|
+
/** 面名(日志/拆卸/幂等键;全进程唯一,建议用 `FACE_*` 常量) */
|
|
40
|
+
name: string;
|
|
41
|
+
/** 期望监听端口(0 = 内核分配;实际端口见 {@link FaceHandle.port}) */
|
|
42
|
+
port: number;
|
|
43
|
+
/** 监听地址(各面自定:`127.0.0.1` 或 `0.0.0.0`——**不因归一而改绑**) */
|
|
44
|
+
host: string;
|
|
45
|
+
/** 该面**此刻是否应处于监听状态**(面自己的配置意图;由 {@link faceEnabled} 读取) */
|
|
46
|
+
enabled: () => boolean;
|
|
47
|
+
/** 单请求处理(面自己的路由 / 鉴权 / 响应体,本模块不介入其语义) */
|
|
48
|
+
handler: (req: IncomingMessage, res: ServerResponse) => void | Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* **EADDRINUSE 重试预算**:每次重试前等待的毫秒数序列(长度 = 最多重试次数)。
|
|
51
|
+
* 缺省 = {@link DEFAULT_RETRY_DELAYS}(10 × 1000ms,**生产行为原样不变**)。
|
|
52
|
+
* 传空数组 = 零重试(一次 EADDRINUSE 即 reject);测试用短预算证明"耗尽即 reject"。
|
|
53
|
+
*
|
|
54
|
+
* 🔒 不变量(v1.34.1 修 flake 时显式化):重试预算**可见、可控、有界**——
|
|
55
|
+
* 绑定尝试绝不无声挂满整段预算;耗尽即 **reject**(调用方可见),不静默悬挂。
|
|
56
|
+
* 此前预算是模块内硬写的 10×1s,而 vitest 单测超时 5s ⇒ "快失败"被拉长成"挂死",
|
|
57
|
+
* 调用方无从缩短 ⇒ 预算提到规格面上。
|
|
58
|
+
*/
|
|
59
|
+
retryDelays?: readonly number[];
|
|
60
|
+
/**
|
|
61
|
+
* 绑上后 `server.unref()`(缺省 `false` = server 维持事件循环存活,**其余三面行为不变**)。
|
|
62
|
+
*
|
|
63
|
+
* 面 C(微信发送,`FACE_PORTS.weixinSend.defaultEnabled = true`)必须传 `true`:宿主若以
|
|
64
|
+
* **一次性命令**方式跑(`dsh <cmd>` 用完即退),未 unref 的 listener 会拖着进程不退出。
|
|
65
|
+
* 这是 C4 之前 `weixin-send-api.ts` 的原语义(C4 归一到面宿主时丢失),现逐字恢复。
|
|
66
|
+
*/
|
|
67
|
+
unref?: boolean;
|
|
68
|
+
}
|
|
69
|
+
/** 一个在监听的面 */
|
|
70
|
+
export interface FaceHandle {
|
|
71
|
+
readonly name: string;
|
|
72
|
+
/** **实际**绑定端口(`spec.port=0` 时为内核分配值) */
|
|
73
|
+
readonly port: number;
|
|
74
|
+
readonly host: string;
|
|
75
|
+
/** 原始 http server——面若需挂自己的 server 级事件(gateway 的 `'upgrade'`)在此挂 */
|
|
76
|
+
readonly server: Server;
|
|
77
|
+
/** 停止本面(幂等;只停这一实例,不会误停同名后继实例) */
|
|
78
|
+
dispose: () => void;
|
|
79
|
+
}
|
|
80
|
+
/** 启动被取消(拆卸发生在重试窗口内)——不是失败,调用方按"未启动"处理 */
|
|
81
|
+
export declare class FaceStartCancelled extends Error {
|
|
82
|
+
constructor(name: string);
|
|
83
|
+
}
|
|
84
|
+
/** 面是否在监听 */
|
|
85
|
+
export declare function faceActive(name: string): boolean;
|
|
86
|
+
/** 面的实际监听端口(未在监听 → null) */
|
|
87
|
+
export declare function facePort(name: string): number | null;
|
|
88
|
+
/** 当前在监听的面名(日志/诊断/测试;顺序 = 启动顺序) */
|
|
89
|
+
export declare function activeFaceNames(): string[];
|
|
90
|
+
/**
|
|
91
|
+
* **机械启动**一个面(同名面已在监听 → 先停后起;正在启动中 → 复用同一 Promise)。
|
|
92
|
+
* 绑不上(非端口占用类的错误、或占用重试耗尽)→ **reject**,由调用方决定记日志/放弃。
|
|
93
|
+
*/
|
|
94
|
+
export declare function startFace(spec: FaceSpec): Promise<FaceHandle>;
|
|
95
|
+
/**
|
|
96
|
+
* **意图读取**:该面此刻是否应处于监听状态(`spec.enabled()` 的安全求值——配置源抛错视为"不启用")。
|
|
97
|
+
*
|
|
98
|
+
* 装配层用它替代此前散在各面 sync 里的 `const want = ...` 手写判据;**启动本身不读它**
|
|
99
|
+
* (`startFace` 是机械入口:调用方保证意图,测试/程序化直启即用)。
|
|
100
|
+
* 例:微信发送面的 sync = `faceEnabled(spec) ? startFace(spec) : stopWeixinSendApi()`。
|
|
101
|
+
*/
|
|
102
|
+
export declare function faceEnabled(spec: FaceSpec): boolean;
|
|
103
|
+
/** 停止一个面(幂等)。返回"是否真的停了一个在监听的面"(取消在飞启动不计入)。 */
|
|
104
|
+
export declare function stopFace(name: string): boolean;
|
|
105
|
+
/**
|
|
106
|
+
* 停止**全部**在监听的面 + 取消全部在飞启动。
|
|
107
|
+
* 这是插件卸载/HMR 拆卸自起 listener 的**唯一入口**(`seams/lifecycle.ts` 的聚合 disposer 调用)。
|
|
108
|
+
* @returns 实际停掉的面名(顺序 = 启动顺序)
|
|
109
|
+
*/
|
|
110
|
+
export declare function stopAllFaces(): string[];
|
package/lib/fs-ops.d.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* 保留 dsp 增强:win32 reveal 用 spawn+unref(explorer GUI 进程退出码不可靠,fire-and-forget)。
|
|
11
11
|
*/
|
|
12
12
|
import type { JsonValue } from './json.js';
|
|
13
|
-
|
|
13
|
+
type CcFsAction = 'root' | 'resolve' | 'exists' | 'list' | 'tree' | 'relative' | 'mkdir' | 'rm' | 'mv' | 'cp' | 'touch' | 'append' | 'reveal' | 'info' | 'find';
|
|
14
14
|
export declare const CC_FS_ACTIONS: readonly CcFsAction[];
|
|
15
15
|
export interface CcFsArgs {
|
|
16
16
|
action: CcFsAction;
|
|
@@ -32,5 +32,6 @@ export interface CcFsArgs {
|
|
|
32
32
|
/** 对齐 osp:find 最大递归深度(缺省不限) */
|
|
33
33
|
maxDepth?: number;
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
type CcFsResult = JsonValue;
|
|
36
36
|
export declare function runCcFs(root: string, args: CcFsArgs): CcFsResult;
|
|
37
|
+
export {};
|
package/lib/gateway-auth.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export declare const FAIL_LOCK_THRESHOLD = 5;
|
|
|
37
37
|
export declare const FAIL_LOCK_BASE_MS: number;
|
|
38
38
|
/** 锁定时长指数退避上限 */
|
|
39
39
|
export declare const FAIL_LOCK_MAX_MS: number;
|
|
40
|
-
|
|
40
|
+
interface FailState {
|
|
41
41
|
/** 连续失败计数(成功登录后清零) */
|
|
42
42
|
count: number;
|
|
43
43
|
/** 当前锁定截止时间(0 = 未锁定) */
|
|
@@ -55,10 +55,6 @@ export declare function isAccountLocked(user: string): boolean;
|
|
|
55
55
|
export declare function recordLoginFailure(user: string): number;
|
|
56
56
|
/** 剩余锁定毫秒(0 = 未锁定) */
|
|
57
57
|
export declare function accountLockRemaining(user: string): number;
|
|
58
|
-
/** CSRF token 有效期(毫秒):10 分钟窗口(扫码/多标签场景留足时间) */
|
|
59
|
-
export declare const CSRF_TTL_MS: number;
|
|
60
|
-
/** CSRF token 集合上限(防内存膨胀;超限清理最旧) */
|
|
61
|
-
export declare const CSRF_MAX_TOKENS = 50;
|
|
62
58
|
/** 生成 CSRF token(随机 32B hex)并入集合 */
|
|
63
59
|
export declare function newCsrfToken(): string;
|
|
64
60
|
/** token 是否有效(在集合且未过期;过期自动清理) */
|
|
@@ -87,3 +83,4 @@ export declare function cookieValue(header: string | undefined, name: string): s
|
|
|
87
83
|
* @param csrf - CSRF token(隐藏字段随表单双提交;无 = 旧调用方兼容)
|
|
88
84
|
*/
|
|
89
85
|
export declare function loginPageHtml(extra: string, csrf?: string): string;
|
|
86
|
+
export {};
|
package/lib/gateway.d.ts
CHANGED
|
@@ -26,7 +26,6 @@
|
|
|
26
26
|
* 保持既有 import 面兼容(tests/gateway.test.ts 直接 import 两模块导出)。
|
|
27
27
|
*/
|
|
28
28
|
import type { Context } from 'cordis';
|
|
29
|
-
import { type Server } from 'node:http';
|
|
30
29
|
export { RANDOM_UUID_POLYFILL, injectPolyfillHtml, filterWorkspaceList, workspaceAllowed, workspaceDenyResponse, isWorkspaceCreatePath, parseWorkspaceCreateBody, buildProxyHeaders, transformHtmlForProxy, } from './gateway-proxy.js';
|
|
31
30
|
export { loginPageHtml, verifyGatewayLogin, SESSION_TTL_MS, issueToken, revokeToken, validateToken, FAIL_LOCK_THRESHOLD, FAIL_LOCK_BASE_MS, FAIL_LOCK_MAX_MS, getFailState, resetFailState, isAccountLocked, recordLoginFailure, accountLockRemaining, newCsrfToken, isCsrfValid, csrfFromRequest, safeEqual, originAllowed, cookieValue, } from './gateway-auth.js';
|
|
32
31
|
declare module 'cordis' {
|
|
@@ -37,39 +36,6 @@ declare module 'cordis' {
|
|
|
37
36
|
'serenity/settings-changed'(): void;
|
|
38
37
|
}
|
|
39
38
|
}
|
|
40
|
-
export interface GatewayConfig {
|
|
41
|
-
host: string;
|
|
42
|
-
port: number;
|
|
43
|
-
/** 登录态 cookie 名 */
|
|
44
|
-
cookieName: string;
|
|
45
|
-
/** 主端口(ctx.webServer.port) */
|
|
46
|
-
mainPort: number;
|
|
47
|
-
/** 登录失败后的重定向延迟(秒) */
|
|
48
|
-
loginDelayMs: number;
|
|
49
|
-
/** 外部可访问的工作区路径前缀白名单(v1.22;空 = 全部允许) */
|
|
50
|
-
allowWorkspaces?: string[];
|
|
51
|
-
/** Cookie Secure 属性(v1.22.4;反代 TLS 时开启;明文 HTTP 下必须关,否则 cookie 不落) */
|
|
52
|
-
cookieSecure?: boolean;
|
|
53
|
-
/** 允许外部新建工作区(v1.22.4;false = workspace.create 一律 403 RPC error) */
|
|
54
|
-
allowWorkspaceCreate?: boolean;
|
|
55
|
-
/** 启用 Authenticator 第二因素(v1.22.4;false = TOTP 完全禁用) */
|
|
56
|
-
totpEnabled?: boolean;
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* 启动第二监听器。返回 { server, dispose }——dispose 关 server(**不清 token**:
|
|
60
|
-
* token 模块级,进程重启自然清空;热重建清 token → 已登录用户 WS 断 + 重连 cookie 无效)。
|
|
61
|
-
* @param config - 监听/代理配置。
|
|
62
|
-
* @param getAccounts - 运行时读取账号列表(plugin 全局文件;gateway.enabled 开关在调用方判)。
|
|
63
|
-
*/
|
|
64
|
-
export declare function startGateway(config: GatewayConfig, getAccounts: () => readonly {
|
|
65
|
-
id: string;
|
|
66
|
-
user: string;
|
|
67
|
-
passHash: string;
|
|
68
|
-
totpSecret?: string;
|
|
69
|
-
}[], getDshCookie?: () => string | undefined): {
|
|
70
|
-
server: Server;
|
|
71
|
-
dispose: () => void;
|
|
72
|
-
};
|
|
73
39
|
/** 注册 gateway(index.ts apply 调用)。
|
|
74
40
|
* 归属原则(v1.22):gateway 是 plugin 全局能力——enabled 开关读 DSH settings
|
|
75
41
|
* (readSimpleSettings().gatewayEnabled),host/port/accounts 读 plugin 全局文件
|
package/lib/git-ops.d.ts
CHANGED
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
* 保留 dsp 增强:localstore git 合规联动(S134:deny 且 .gitignore 未覆盖 → status 提示 / commit 拒绝)。
|
|
12
12
|
*/
|
|
13
13
|
import type { JsonValue } from './json.js';
|
|
14
|
-
|
|
14
|
+
type GitAction = 'status' | 'commit' | 'push' | 'log' | 'pull' | 'diff';
|
|
15
15
|
export declare const GIT_ACTIONS: readonly GitAction[];
|
|
16
|
-
|
|
16
|
+
interface GitArgs {
|
|
17
17
|
action: GitAction;
|
|
18
18
|
message?: string;
|
|
19
19
|
/** log 条数(对齐 osp 参数 n,默认 10,max 100) */
|
|
@@ -26,3 +26,4 @@ export interface GitArgs {
|
|
|
26
26
|
path?: string;
|
|
27
27
|
}
|
|
28
28
|
export declare function runGit(root: string, args: GitArgs): JsonValue;
|
|
29
|
+
export {};
|
package/lib/handyman-ops.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* 进度文件(handyman-<label>.md/.json)、续跑、轮次 prompt 结构、stop token。
|
|
6
6
|
* 不兼容旧 loop- 进度文件(用户拍板:仅新 handyman- 前缀)。
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
interface HandymanProgress {
|
|
9
9
|
round: number;
|
|
10
10
|
done: boolean;
|
|
11
11
|
label: string;
|
|
@@ -56,7 +56,7 @@ export declare function buildRoundPrompt(opts: {
|
|
|
56
56
|
*/
|
|
57
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";
|
|
58
58
|
/** handyman 运行状态(进度文件摘要;WebUI 等待界面数据源) */
|
|
59
|
-
|
|
59
|
+
interface HandymanRunInfo {
|
|
60
60
|
label: string;
|
|
61
61
|
round: number;
|
|
62
62
|
done: boolean;
|
|
@@ -66,3 +66,4 @@ export interface HandymanRunInfo {
|
|
|
66
66
|
}
|
|
67
67
|
/** 列出 AGENT_SESSIONS/handyman-*.json 的全部进度(按 updated 倒序;坏文件跳过) */
|
|
68
68
|
export declare function listActiveHandymen(root: string): HandymanRunInfo[];
|
|
69
|
+
export {};
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import type { Context } from 'cordis';
|
|
22
22
|
/** 从父 agent ctx 解析 preset 继承的创建期组合。 */
|
|
23
|
-
|
|
23
|
+
interface HandymanPresetInheritance {
|
|
24
24
|
/** 父 agent 的 preset id(写入子 session meta.agentPreset,供持久化重建);无则不写。 */
|
|
25
25
|
readonly agentPreset?: string;
|
|
26
26
|
/** 创建 setup 钩子:子 scope join 父的 standing preset + deny handyman 工具;无 preset 继承时仅 deny。 */
|
|
@@ -32,3 +32,4 @@ export interface HandymanPresetInheritance {
|
|
|
32
32
|
* @returns 继承结果:meta 用的 agentPreset 与创建 setup 钩子。
|
|
33
33
|
*/
|
|
34
34
|
export declare function handymanPresetInheritance(parentCtx: Context | undefined): HandymanPresetInheritance;
|
|
35
|
+
export {};
|
package/lib/host/access.d.ts
CHANGED
|
@@ -33,7 +33,7 @@ export declare function hostService<T = unknown>(ctx: unknown, name: string): T
|
|
|
33
33
|
* (宿主对插件 apply 抛错 = 整个 dsh 启动失败)。读取失败 = 服务不可用,等价于缺失。
|
|
34
34
|
*/
|
|
35
35
|
export declare function hostInjected<T = unknown>(ctx: unknown, name: string): T | undefined;
|
|
36
|
-
|
|
36
|
+
interface HostSessionLike {
|
|
37
37
|
id?: string;
|
|
38
38
|
header?: {
|
|
39
39
|
cwd?: string;
|
|
@@ -41,25 +41,25 @@ export interface HostSessionLike {
|
|
|
41
41
|
};
|
|
42
42
|
snapshotEvents?: () => unknown[];
|
|
43
43
|
}
|
|
44
|
-
|
|
44
|
+
interface HostSessions {
|
|
45
45
|
list?: () => HostSessionLike[];
|
|
46
46
|
get?: (id: unknown) => HostSessionLike | undefined;
|
|
47
47
|
create?: (...args: unknown[]) => unknown;
|
|
48
48
|
}
|
|
49
|
-
|
|
49
|
+
interface HostAgents {
|
|
50
50
|
create?: (...args: unknown[]) => unknown;
|
|
51
51
|
get?: (id: string) => unknown;
|
|
52
52
|
resume?: (...args: unknown[]) => unknown;
|
|
53
53
|
}
|
|
54
|
-
|
|
54
|
+
interface HostWebServer {
|
|
55
55
|
register?: (registration: unknown) => unknown;
|
|
56
56
|
port?: number;
|
|
57
57
|
}
|
|
58
|
-
|
|
58
|
+
interface HostSettings {
|
|
59
59
|
installSection?: (...args: unknown[]) => unknown;
|
|
60
60
|
}
|
|
61
61
|
/** `ctx.web`(injected;v1.30.12:fetch provider 注册通道) */
|
|
62
|
-
|
|
62
|
+
interface HostWeb {
|
|
63
63
|
registerFetchProvider?: (provider: unknown) => unknown;
|
|
64
64
|
registerSearchProvider?: (provider: unknown) => unknown;
|
|
65
65
|
}
|
|
@@ -82,9 +82,10 @@ export declare function hostWeb(ctx: unknown): HostWeb | undefined;
|
|
|
82
82
|
* 注(v1.31.4):本服务**不在** dsp 的 `inject` 列表内,因此走 `hostInjected` 的
|
|
83
83
|
* 回落分支(`ctx.get`)——见 `hostInjected` 的 v1.31.4 说明与真实 cordis 用例。
|
|
84
84
|
*/
|
|
85
|
-
|
|
85
|
+
interface HostSubagents {
|
|
86
86
|
start?: (name: string, request: unknown) => Promise<unknown>;
|
|
87
87
|
}
|
|
88
88
|
export declare function hostSubagents(ctx: unknown): HostSubagents | undefined;
|
|
89
89
|
/** 会话 cwd 列表(live 会话;形状不符时返回空数组而非抛错) */
|
|
90
90
|
export declare function hostSessionCwds(ctx: unknown): string[];
|
|
91
|
+
export {};
|
package/lib/host/contract.d.ts
CHANGED
|
@@ -19,12 +19,12 @@
|
|
|
19
19
|
* 宿主类型断言),此处只登记清单供文档/测试共用。
|
|
20
20
|
* - **缺失分级**:`required` = 缺失即 ACC 核心能力失效;否则为可降级能力。
|
|
21
21
|
*/
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
type HostAccess = 'injected' | 'lazy';
|
|
23
|
+
interface HostMember {
|
|
24
24
|
name: string;
|
|
25
25
|
kind: 'function' | 'value';
|
|
26
26
|
}
|
|
27
|
-
|
|
27
|
+
interface HostServiceContract {
|
|
28
28
|
/** 稳定标识(报告用) */
|
|
29
29
|
id: string;
|
|
30
30
|
/** 服务名(`ctx.get(name)` 或 `ctx.<name>`) */
|
|
@@ -40,7 +40,7 @@ export interface HostServiceContract {
|
|
|
40
40
|
}
|
|
41
41
|
/** dsp 依赖的宿主服务与成员(对照 `_tmp/host-0.1.5-rc.1/`(`dsh-develop host-fetch` 产物)逐一核对) */
|
|
42
42
|
export declare const HOST_SERVICES: readonly HostServiceContract[];
|
|
43
|
-
|
|
43
|
+
interface HostEventContract {
|
|
44
44
|
name: HostEventName;
|
|
45
45
|
/** 订阅方(文件) */
|
|
46
46
|
site: string;
|
|
@@ -56,14 +56,14 @@ export interface HostEventContract {
|
|
|
56
56
|
* 该 import 为 type-only,编译期擦除,不产生运行时依赖。
|
|
57
57
|
*/
|
|
58
58
|
export declare const HOST_EVENT_NAMES: readonly ["agent/session-start", "agent/pre-step", "agent/turn-stopping", "agent/status", "agent/inbox/inserted", "agent/disposed", "session/event", "session/created", "session/disposed", "settings/updated", "tools/pre-execute", "tools/post-execute", "system-prompt/assemble"];
|
|
59
|
-
|
|
59
|
+
type HostEventName = (typeof HOST_EVENT_NAMES)[number];
|
|
60
60
|
/**
|
|
61
61
|
* dsp 订阅的宿主事件清单(与 HOST_EVENT_NAMES 同源;impact/site 供 health 报告与文档)。
|
|
62
62
|
*/
|
|
63
63
|
export declare const HOST_EVENTS: readonly HostEventContract[];
|
|
64
64
|
/** dsp 被验证过的宿主版本范围(与 package.json peerDependencies 同源,单一真相源) */
|
|
65
65
|
export declare const REQUIRED_HOST_RANGE = "^0.1.5-rc.2";
|
|
66
|
-
|
|
66
|
+
interface HostContractIssue {
|
|
67
67
|
id: string;
|
|
68
68
|
kind: 'service' | 'member' | 'version';
|
|
69
69
|
detail: string;
|
|
@@ -100,5 +100,16 @@ export declare function checkHostVersion(version: string | null): {
|
|
|
100
100
|
* @returns 报告(`ok:false` 时 `issues` 逐条给出缺失项与后果)
|
|
101
101
|
*/
|
|
102
102
|
export declare function probeHostContract(ctx: unknown, hostVersion?: string | null): HostContractReport;
|
|
103
|
+
/**
|
|
104
|
+
* 取宿主契约报告——**进程内唯一来源**。
|
|
105
|
+
*
|
|
106
|
+
* @param ctx 宿主上下文;**仅当快照尚未捕获时**用于跑探针(首见即捕获一次)
|
|
107
|
+
* @param hostVersion 运行中宿主版本(`readDshVersion()`;null = 未知)
|
|
108
|
+
* @returns 契约报告;快照未捕获且未给 `ctx` → `null`(不猜、不重算)
|
|
109
|
+
*/
|
|
110
|
+
export declare function hostContractReport(ctx?: unknown, hostVersion?: string | null): HostContractReport | null;
|
|
111
|
+
/** 测试用:复位进程内快照(避免用例间串味;与 `__resetWakeSchedulerStateForTest` 同规格) */
|
|
112
|
+
export declare function __resetHostContractForTest(): void;
|
|
103
113
|
/** 单行摘要(启动告警用) */
|
|
104
114
|
export declare function summarizeHostContract(report: HostContractReport): string;
|
|
115
|
+
export {};
|
package/lib/im-bridge.d.ts
CHANGED
|
@@ -32,7 +32,7 @@ export type ImUserEntry = {
|
|
|
32
32
|
id: string;
|
|
33
33
|
};
|
|
34
34
|
/** 文本发送输入(通道实现负责凭据解析与记录) */
|
|
35
|
-
|
|
35
|
+
interface ImSendInput {
|
|
36
36
|
root: string;
|
|
37
37
|
/** 通道内用户 id(别名已由本模块解析) */
|
|
38
38
|
userId: string;
|
|
@@ -40,14 +40,14 @@ export interface ImSendInput {
|
|
|
40
40
|
accountId?: string;
|
|
41
41
|
}
|
|
42
42
|
/** 文本发送结果(与既有主动发送返回一致,便于记录/诊断) */
|
|
43
|
-
|
|
43
|
+
interface ImSendResult {
|
|
44
44
|
accountId: string;
|
|
45
45
|
userId: string;
|
|
46
46
|
sessionId: string;
|
|
47
47
|
role: string;
|
|
48
48
|
}
|
|
49
49
|
/** 文件发送输入(`data` 由本模块读盘并校验后传入——通道不碰 CCC 路径) */
|
|
50
|
-
|
|
50
|
+
interface ImSendFileInput {
|
|
51
51
|
root: string;
|
|
52
52
|
userId: string;
|
|
53
53
|
data: Buffer;
|
|
@@ -95,7 +95,7 @@ export type ImJson = null | boolean | number | string | ImJson[] | {
|
|
|
95
95
|
[key: string]: ImJson;
|
|
96
96
|
};
|
|
97
97
|
/** 分发结果(工具面直接渲染;错误码稳定,便于模型与日志消费) */
|
|
98
|
-
|
|
98
|
+
type ImToolResult = {
|
|
99
99
|
ok: true;
|
|
100
100
|
channel: string;
|
|
101
101
|
action: string;
|
|
@@ -106,7 +106,7 @@ export type ImToolResult = {
|
|
|
106
106
|
error: string;
|
|
107
107
|
remediation?: string;
|
|
108
108
|
};
|
|
109
|
-
|
|
109
|
+
interface ImToolRequest {
|
|
110
110
|
channel?: string;
|
|
111
111
|
action?: string;
|
|
112
112
|
user?: string;
|
|
@@ -125,3 +125,4 @@ export interface ImToolRequest {
|
|
|
125
125
|
* @param req 工具参数
|
|
126
126
|
*/
|
|
127
127
|
export declare function runImBridge(root: string, req: ImToolRequest): Promise<ImToolResult>;
|
|
128
|
+
export {};
|
package/lib/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* 形态(DSH 官方 native hook 约定):name / inject / Config / apply,无 default export。
|
|
5
5
|
*
|
|
6
6
|
* 能力:
|
|
7
|
-
* 1. 真实 DSH 工具注册:container_fs(文件系统 15 子命令,含 reveal)、
|
|
7
|
+
* 1. 真实 DSH 工具注册:container_fs(文件系统 15 子命令,含 reveal)、container_trajectory(轨迹生命周期 + 一次性安排,含 rebuild)
|
|
8
8
|
* 2. 拦截缝机械约束:tools/pre-execute + ctx.tools.guard(安全模式/黑名单/路径守卫)
|
|
9
9
|
*
|
|
10
10
|
* 加载:~/.dsh/config.yaml 加 insert 行(免改 DSH 源码),插件包装入 DSH node_modules。
|