@shgroup/dsh-serenity-hooks 1.34.0 → 1.34.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 +1 -0
- package/dsh.plugin.json +1 -1
- 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 +64 -97
- package/lib/ccc-roots-Bd_SjEs7.js +152 -0
- package/lib/ccc-roots.d.ts +105 -0
- package/lib/ccc.d.ts +3 -6
- package/lib/client.js +2 -2
- 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 +25 -10
- 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 +29 -6
- package/lib/host/type-contract.d.ts +1 -2
- package/lib/im-bridge.d.ts +6 -5
- package/lib/index.js +8336 -5607
- package/lib/invariant.d.ts +0 -15
- package/lib/invariant.js +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 +0 -3
- package/lib/output-guard.d.ts +12 -3
- package/lib/ports.d.ts +59 -0
- package/lib/rebuild.d.ts +1 -1
- 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 +4 -43
- package/lib/seams/keeper.d.ts +1 -1
- package/lib/seams/system-prompt.d.ts +1 -5
- package/lib/session-cleanup.d.ts +3 -2
- package/lib/{settings-section-BuPGQv_H.js → settings-section-DTYZjwUs.js} +65 -9
- package/lib/settings-section.d.ts +3 -31
- package/lib/skiff-core.d.ts +4 -9
- 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-DAfPb6YQ.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/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/trajectory.d.ts +7 -15
- 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/trajectory-bound.d.ts +3 -4
- package/lib/{trajectory-bound-C8DUxi6_.js → trajectory-ops-mrXK0H0I.js} +2 -159
- package/lib/trajectory-ops.d.ts +4 -9
- package/lib/trajectory-skills.d.ts +71 -0
- package/lib/{wake-registry-D0Vj0WXb.js → wake-registry-CYxIb484.js} +7 -20
- package/lib/wake-registry.d.ts +3 -11
- package/lib/wake-scheduler.d.ts +13 -49
- 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-D1ND823E.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 +2 -4
- package/experiments/autopilot-trajectory/SKILL.md +0 -115
- package/experiments/autopilot-trajectory/scripts/autopilot-trajectory.ts +0 -546
- package/lib/autopilot-script.d.ts +0 -40
- package/lib/skiff-debug-D83-Njy7.js +0 -2867
- package/lib/{ccc-eu_IPF94.js → ccc-NlLr_sxy.js} +1 -1
- package/lib/{session-cleanup-CMT4mHWt.js → session-cleanup-B6IHZgww.js} +1 -1
package/lib/invariant.d.ts
CHANGED
|
@@ -5,21 +5,6 @@
|
|
|
5
5
|
* 挂载时 plugin-local 会校验清单;本不变量让仓库内 `verify-package-invariants`
|
|
6
6
|
* 类门禁也可直接调用。
|
|
7
7
|
*/
|
|
8
|
-
export interface PluginManifest {
|
|
9
|
-
id: string;
|
|
10
|
-
version?: string;
|
|
11
|
-
main?: string;
|
|
12
|
-
description?: string;
|
|
13
|
-
engines?: {
|
|
14
|
-
dsh?: string;
|
|
15
|
-
};
|
|
16
|
-
contributes?: {
|
|
17
|
-
tools?: string[];
|
|
18
|
-
skills?: string[];
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
/** 读取插件清单;缺失/非法返回 null */
|
|
22
|
-
export declare function readPluginManifest(manifestPath: string): PluginManifest | null;
|
|
23
8
|
/**
|
|
24
9
|
* 校验清单声明的工具与代码注册的工具一致。
|
|
25
10
|
* 返回不一致项列表(空 = 通过)。
|
package/lib/invariant.js
CHANGED
package/lib/kit-ops.d.ts
CHANGED
|
@@ -10,41 +10,21 @@
|
|
|
10
10
|
* CCC 缺失时返回 degraded 报告而非抛错(对齐 osp 未激活语义)。
|
|
11
11
|
* 保留 dsp 增强:accVersion/dshVersion 版本自省字段。
|
|
12
12
|
* wait 用纯 Node setTimeout——不依赖外部 sleep 可执行文件(Windows 无 GNU coreutils sleep)。
|
|
13
|
+
*
|
|
14
|
+
* C5「观察面归一」(S142 2026-09-15):本文件的 health **不再自己取数**——三原则、注册表结构判据、
|
|
15
|
+
* 配置、宿主契约一律经 `container-status.ts` 取(唯一取数出口),本文件只把事实**渲染**成 osp
|
|
16
|
+
* 既有 wire 形状。故:
|
|
17
|
+
* - `checkRegistryHealth` 已迁入 `container-status.ts`(同一实现,名字不变);
|
|
18
|
+
* - `container-status.ts` 带 @deepseek-ai 值依赖(时钟段)⇒ 这里用 `await import` 保持本模块
|
|
19
|
+
* 静态链**零 DSH 依赖**(与 `api.ts` 的既有约定同规格)。
|
|
20
|
+
* ⚠️ wire 形状**逐字不变**(字段名/取值/出现条件都不许动)——C5 是取数归一,不是文案改版。
|
|
13
21
|
*/
|
|
14
|
-
import { loadSerenityConfig } from './ccc.js';
|
|
15
22
|
import type { JsonValue } from './json.js';
|
|
16
|
-
|
|
23
|
+
type KitAction = 'health' | 'time' | 'wait';
|
|
17
24
|
export declare const KIT_ACTIONS: readonly KitAction[];
|
|
18
|
-
|
|
25
|
+
interface KitArgs {
|
|
19
26
|
action: KitAction;
|
|
20
27
|
seconds?: number;
|
|
21
28
|
}
|
|
22
|
-
/**
|
|
23
|
-
* MSM 注册表完整性检查(需求⑤c S142 用户:"要有ACC层检查方法检查注册表没坏,这东西太核心了")。
|
|
24
|
-
* 注册表坏 → loadMsmEntries JSON.parse 抛 → container_admin/output-guard 全崩 +
|
|
25
|
-
* register 判重也 loadMsmEntries → **自锁无法自救**(R7)——health 必须**不因坏表抛错**,
|
|
26
|
-
* 独立解析(不依赖 loadMsmEntries)逐项检查,坏 = ok:false + issues + 修复指引。
|
|
27
|
-
*
|
|
28
|
-
* 检查项(单级化后唯一聚合档 + root 级遗留):
|
|
29
|
-
* - 文件存在(无注册表 = 空 ok——CCC 尚未注册 MSM 不视为坏)
|
|
30
|
-
* - JSON.parse 合法(剥 BOM;坏 JSON = 结构损坏)
|
|
31
|
-
* - 顶层 v1 wrapper(entries[])或裸数组
|
|
32
|
-
* - 每 entry 字段类型(name/path/skill/category/description)
|
|
33
|
-
* - name 全局唯一(loadMsmEntries byName 去重语义——重复歧义)
|
|
34
|
-
* - path 根内 + 脚本存在(引用完整)
|
|
35
|
-
*
|
|
36
|
-
* 修复指引:register/deregister 每次变更精提交(只 add 注册表文件)→ 坏表可
|
|
37
|
-
* `git checkout -- <registry>` 恢复(bash 可用时 / 用户手动 / container_git 无 checkout
|
|
38
|
-
* 子命令——走 bash git restore,safe-mode 下建议用户介入)。工具只输出指引不代劳(用户拍板)。
|
|
39
|
-
*/
|
|
40
|
-
export interface RegistryHealthReport {
|
|
41
|
-
/** 聚合档路径(相对 CCC 根);无 cccName → null */
|
|
42
|
-
path: string | null;
|
|
43
|
-
ok: boolean;
|
|
44
|
-
/** 该注册表文件是否存在(不存在 = 未注册任何 MSM,非坏) */
|
|
45
|
-
present: boolean;
|
|
46
|
-
issues: string[];
|
|
47
|
-
}
|
|
48
|
-
export declare function checkRegistryHealth(root: string): RegistryHealthReport;
|
|
49
29
|
export declare function runKit(root: string | null, args: KitArgs, hostCtx?: unknown): Promise<JsonValue>;
|
|
50
|
-
export {
|
|
30
|
+
export {};
|
package/lib/localstore-ops.d.ts
CHANGED
|
@@ -18,20 +18,14 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import type { JsonValue } from './json.js';
|
|
20
20
|
/** 命名空间:credential(凭据)| config(配置) */
|
|
21
|
-
|
|
21
|
+
type LocalStoreScope = 'credential' | 'config';
|
|
22
22
|
export declare const LOCALSTORE_SCOPES: readonly LocalStoreScope[];
|
|
23
23
|
/** 存储文件名(CCC 根根目录) */
|
|
24
24
|
export declare const LOCALSTORE_FILENAME = "localstore.json";
|
|
25
|
-
/** 凭据保留节名(JSON 顶层) */
|
|
26
|
-
export declare const CREDENTIALS_SECTION = "credentials";
|
|
27
25
|
/** 凭据 key 规范:大写蛇形,如 HOME_GITLAB_TOKEN */
|
|
28
26
|
export declare const CREDENTIAL_KEY_RE: RegExp;
|
|
29
|
-
/** 配置节名规范:小写字母数字连字符 */
|
|
30
|
-
export declare const CONFIG_SECTION_RE: RegExp;
|
|
31
|
-
/** 配置 key 规范(节内):小驼峰,如 defaultModel */
|
|
32
|
-
export declare const CONFIG_KEY_RE: RegExp;
|
|
33
27
|
/** git 提交策略 */
|
|
34
|
-
|
|
28
|
+
type GitTrack = 'allow' | 'deny';
|
|
35
29
|
/** 存储文件绝对路径(CCC 根根目录) */
|
|
36
30
|
export declare function localstorePath(root: string): string;
|
|
37
31
|
/** git 策略:serenity.json localstore.gitTrack,缺省 deny(不提交) */
|
|
@@ -54,17 +48,8 @@ export declare function checkLocalstoreGitCompliance(root: string): {
|
|
|
54
48
|
ok: boolean;
|
|
55
49
|
reason?: string;
|
|
56
50
|
};
|
|
57
|
-
/** 测试辅助:重置"坏 localstore"告警去重(生产零调用) */
|
|
58
|
-
export declare function __resetBrokenStoreWarningsForTest(): void;
|
|
59
51
|
/** 读取命名空间全部条目:credential → 扁平;config → 分节(剔除 credentials 保留节) */
|
|
60
52
|
export declare function readStore(root: string, scope: LocalStoreScope): Record<string, string> | Record<string, Record<string, string>>;
|
|
61
|
-
/** 校验凭据 key 合法(大写蛇形);不合法抛错 */
|
|
62
|
-
export declare function assertCredentialKey(key: string): void;
|
|
63
|
-
/** 校验 config 路径(节.key);不合法抛错 */
|
|
64
|
-
export declare function assertConfigPath(path: string): {
|
|
65
|
-
section: string;
|
|
66
|
-
key: string;
|
|
67
|
-
};
|
|
68
53
|
/** 写入单个条目(自动建文件;deny 默认时同步确保 .gitignore 物理保证) */
|
|
69
54
|
export declare function writeEntry(root: string, scope: LocalStoreScope, name: string, value: string): void;
|
|
70
55
|
/** 删除单个条目(不存在返回 false);空节自动移除 */
|
|
@@ -85,3 +70,4 @@ export declare function runLocalStore(root: string, args: {
|
|
|
85
70
|
value?: string;
|
|
86
71
|
scope?: string;
|
|
87
72
|
}): JsonValue;
|
|
73
|
+
export {};
|
package/lib/msm-ops.d.ts
CHANGED
|
@@ -5,22 +5,10 @@
|
|
|
5
5
|
* 复用 CCC 的 mech-registry.json(v1 或数组格式)。cwd 钉在 CCC 根。
|
|
6
6
|
*/
|
|
7
7
|
import type { JsonValue } from './json.js';
|
|
8
|
-
|
|
9
|
-
/** CCC 名:从 .serenity 解析(review P2-2 统一收口到 ccc.ts readCccName——跳 # 注释/空行首非空行;此处保留导出名兼容内部调用) */
|
|
10
|
-
export declare function readCccName(root: string): string | null;
|
|
11
|
-
export type MsmAction = 'list' | 'exec' | 'register' | 'deregister' | 'check' | 'guide' | 'ccc-config' | 'catalog';
|
|
8
|
+
type MsmAction = 'list' | 'exec' | 'register' | 'deregister' | 'check' | 'guide' | 'ccc-config' | 'catalog';
|
|
12
9
|
export declare const MSM_ACTIONS: readonly MsmAction[];
|
|
13
|
-
/**
|
|
14
|
-
* ACC 能力目录(需求④ S142 用户拍板:"acc 配置各自做 guide 越来越多,整合成目录式使用指南")。
|
|
15
|
-
* 目录在前、详情各归各——**单一真相源**:本目录只索引"去哪个工具/子命令看详情",不复制详情
|
|
16
|
-
* (避免 container_admin/weixin-doctor 等 guide 全文重复 → 多真相源 → 失同步)。
|
|
17
|
-
* 后续新增功能只需在此加一行(低熵可演进)。
|
|
18
|
-
*/
|
|
19
|
-
export declare const ACC_CATALOG = "\u2550\u2550\u2550 ACC Usage Catalog \u2550\u2550\u2550\nDirectory of ACC capabilities \u2014 each area lists where to go for details (guides live with their feature; this catalog only points).\n\n \u2460 \u8F68\u8FF9\u672C\u4F53 \u2192 container_trajectory\uFF08list/show/create/use + rebuild \u8D85\u9650\u91CD\u5EFA + wake-later \u672A\u6765\u4E00\u6B21\u6027\u5524\u9192\uFF09\n \u539F logbook \u5DF2\u5E76\u5165\uFF08v1.33 \u7528\u6237\u88C1\u51B3\uFF1A\u5E9F\u9664 logbook \u8BCD\uFF09\uFF1Bclose/archive \u5220\uFF08\u5F52\u6863\u8D70 container_fs mv\uFF09\uFF0C\n health/qa/summary \u5206\u522B\u5E76\u5165 use / list\uFF0Chook-develop-guide \u5E76\u8FDB container_admin msm guide\n \u2460b \u5468\u671F\u81EA\u5524\u9192 \u2192 container_admin autopilot\uFF08status/init/generate-bias\u2014\u2014D59 \u5355\u4F8B\uFF1Bstatus \u542B\u5C31\u7EEA\u4E0E\u4E0B\u4E00\u6B65\uFF09\n \u2461 \u8BA4\u77E5\u8D28\u91CF\u6846\u67B6 \u2192 praxis\uFF08eap/neat/cce \u4E09\u5408\u4E00\u2014\u2014\u53EF\u5B9E\u8DF5\u7406\u8BBA\u6CE8\u5165\uFF0Csection \u6E10\u8FDB\u62AB\u9732\uFF0C\u65E0\u53C2\u5373\u76EE\u5F55\uFF09\n \u2462 \u5DE5\u5177\u4E0E\u6267\u884C \u2192 container_fs\uFF08\u5BB9\u5668\u6587\u4EF6\u7CFB\u7EDF 15 \u5B50\u547D\u4EE4\uFF09/ container_git\uFF08git\uFF09/ dashboard\uFF08health \u542B\u6CE8\u518C\u8868\u68C0\u67E5/time/wait\uFF09\n acc_msm \u5DF2\u5E76\u5165 msm\uFF08\u6267\u884C+\u53D1\u73B0\uFF09\u4E0E container_admin\uFF08\u7BA1\u7406\uFF09\u2014\u2014msm(\"<name>\", [\"<args>\"])\uFF1Binspect=true \u67E5\u7528\u6CD5\n handyman\uFF08\u6742\u5DE5 agent \u7F16\u6392\u2014\u2014guide \u5B50\u547D\u4EE4\uFF1Ahandyman guide\uFF09\n \u4E13\u5C5E\u5DE5\u5177\uFF08**\u9ED8\u8BA4\u5BF9\u6240\u6709 CCC \u9690\u85CF**\uFF0C\u53EA\u6709\u5728\u81EA\u5DF1 exclusiveTools \u91CC\u70B9\u540D\u7684 CCC \u53EF\u89C1\uFF09\u2192 acc-diag\uFF08\u8FD0\u884C\u6001\u8BCA\u65AD\uFF09\n \u2463 \u89D2\u8272\u4E0E\u5BF9\u5916\u9762 \u2192 container_admin role\uFF08Skiff \u8BA4\u77E5\u5B50\u96C6\u89D2\u8272\uFF1Aguide/validate/apply/list\u2014\u2014skiff_admin \u5DF2\u5E76\u5165\uFF09\n ACP\uFF08\u7A0B\u5E8F\u5316 JSON-RPC 3100\uFF09/ Skiff \u95EE\u7B54\u9875\uFF08\u516C\u7F51 ask\uFF09\u2014\u2014\u9762\u677F\u300C\u5916\u90E8\u80FD\u529B\u300D\u7EC4\n \u2464 \u81EA\u4E3B\u4E0E\u63A5\u5165 \u2192 container_trajectory wake-later\uFF08\u8DE8\u8F68\u8FF9\u7684\"\u672A\u6765\u65F6\u523B + \u4E00\u6761 message\"\uFF1Bfire-and-forget\uFF0C\u65E0\u56DE\u6267\u65E0\u56DE\u6536\uFF09\n weixin \u5FAE\u4FE1\u6865\uFF08\u914D\u7F6E/\u626B\u7801/\u8DEF\u7531/\u6D88\u606F hook\u2014\u2014CCC \u4FA7 weixin-doctor MSM\uFF1Amsm(\"weixin-doctor\", [\"guide\"])\uFF09\n \u2465 CCC \u914D\u7F6E\u603B\u89C8 \u2192 container_admin msm ccc-config\uFF089 \u6BB5\uFF1Ahandyman/sessionKeeper/localstore/hooks/safeMode/skiff/trajectory/weixin/**exclusiveTools**\uFF09\n \u2466 \u6CE8\u518C\u8868\u4E0E\u5B89\u5168 \u2192 mech-registry.json \u7531 container_admin msm register/deregister \u7BA1\u7406\uFF08\u5199\u4FDD\u62A4\u2014\u2014\u4E0D\u53EF\u76F4\u63A5\u7F16\u8F91\uFF09\n dashboard health \u8F93\u51FA registry \u5B8C\u6574\u6027\u68C0\u67E5\uFF1B\u635F\u574F\u6062\u590D\u6307\u5F15\u89C1 health registry.issues\n CCC \u7EA7\u5F00\u5173\uFF1AexclusiveTools\uFF08\u58F0\u660E\u4E13\u5C5E\u5DE5\u5177\uFF09/ safeMode.blacklist\uFF08\u5199\u8DEF\u5F84\u9ED1\u540D\u5355\uFF09\n\n\u6BCF\u533A\uFF1A\u4E00\u53E5\u8BDD\u5B9A\u4F4D + \u8BE6\u7EC6\u5165\u53E3\uFF08\u5DE5\u5177\u540D / guide \u5B50\u547D\u4EE4\uFF09\u3002\u8BE6\u60C5\u6C38\u8FDC\u4EE5\u5BF9\u5E94\u5DE5\u5177\u7684 guide/ccc-config \u4E3A\u5355\u4E00\u771F\u76F8\u6E90\u3002\n";
|
|
20
10
|
export declare const MSM_GUIDE = "MSM Development Manual (Mech & Semi-Mech framework)\n\n## What it is\nMSM = the executable-unit layer. Mech is pure TS with zero LLM reasoning; Semi-Mech is a TS framework + LLM decision points.\nMSM is ACC's deterministic executable-unit layer \u2014 all shell/exec operations go through MSM and cannot be bypassed.\n\n## Registering a new MSM (container_admin msm register)\n1. Write the script under <skill>/scripts/ (runnable via tsx; must include a main() CLI guard with an import.meta.url check)\n2. container_admin msm register --domain msm --action register <name> --skill <s> --path <script path relative to root> --category <mech|semi-mech> --description <desc>\n3. Auto-writes mech-registry.json (preserving the original format) + git commit (commits only the registry file)\n4. Validation: path must be inside root, script must exist, name must be globally unique\n\n## flag schema (v1)\nflags is a new-style object array for parameter validation and path-escape guarding:\n [{\"name\":\"output\",\"type\":\"string\",\"description\":\"output path\"},\n {\"name\":\"target\",\"type\":\"path\",\"description\":\"operation target (type:path enables in-root validation + symlink defense)\"},\n {\"name\":\"force\",\"type\":\"boolean\",\"description\":\"force mode\",\"default\":false}]\n- {name, type} format \u2014 new style, type:\"path\" enables the path-escape guard\n- {flag, description} format \u2014 old style, CLI flag description string\n- On registration, flags are passed via container_admin msm register --flags '<json>'\n\n## Script conventions\n- Top-of-file documentation: purpose / usage / exit codes\n- Exit codes: 0 success / 1 user / 2 system / 3 operator (per ACC protocol classification)\n- main() CLI guard (DC-M2): the script must start with\n if (import.meta.url === `file://${process.argv[1]}`) { main() }\n or an equivalent isMain / require.main === check \u2014 so vitest imports never trigger top-level code\n- A paired .test.ts or .spec.ts (DC-M1, vitest)\n- Business subprocess environment: SERENITY_ROOT / SERENITY_CCC / SERENITY_VERSION injected\n\n## Interaction & confirmation conventions (no blocking confirmation)\n- MSMs run in **user-less subprocesses** (spawn/execFile, 600s timeout) \u2014 **never** use\n readline / prompt / process.stdin etc. to block waiting for user input (it would hang until killed by the timeout)\n- When a second confirmation is needed: **directly return the confirmation request** (list the operation to perform and its impact + how to retry with the confirmation flag),\n returning a non-zero exit code (or an explicit hint)\n- After the agent confirms, **re-invoke the MSM with the confirmation flag** (e.g. --confirm / --yes / --force) to retry\n- Standard mode (two-phase):\n 1. First call: destructive/confirmation-requiring operation detected and no confirmation flag present \u2192 output the confirmation request (list operation/impact/rollback),\n exit non-zero (e.g. 1 user), **perform no changes**\n 2. After the agent evaluates, re-invoke: with the confirmation flag \u2192 execute and output the result\n- Applies to: delete/overwrite/push/batch operations and other irreversible or wide-impact operations\n- Anti-example (forbidden): readline waiting for user input, process.stdin.on('data') blocking waits\n (MSMs have no stdin interaction channel \u2014 they hang until the 600s timeout)\n\n## Quality checks (container_admin msm check, DC-M1~M4)\nDC-M1 has .test.ts/.spec.ts; DC-M2 has a main() guard (function main( / isMain / require.main === / import.meta.url);\nDC-M3 bidirectional: scripts unregistered + registry references missing scripts; DC-M4 path-type flags marked type:\"path\"\n\n## Self-description (protocol flags, first argument only)\nmsm(\"<name>\", [\"--list\"]) \u2014 list all MSMs\nmsm(\"<name>\", [\"--schema\", \"<n>\"]) \u2014 view a specific MSM's parameter schema\nmsm(\"<name>\", [\"--format=json\"]) \u2014 JSON output mode (remaining args passed through losslessly)\n";
|
|
21
|
-
|
|
22
|
-
export declare const CCC_CONFIG_REFERENCE = "\u2550\u2550\u2550 CCC Configuration Reference \u2550\u2550\u2550\n\nCCC-level features are configured in .opencode/serenity.json.\nBelow are all available configuration sections.\n\n\u2500\u2500 1. handyman.models \u2500\u2500\nhandyman\uFF08\u6742\u5DE5\uFF09\u5DE5\u5177\u53EF\u7528\u6A21\u578B\u767D\u540D\u5355\uFF08provider/model \u5217\u8868\uFF09\uFF1B\u672A\u914D\u7F6E\u65F6 handyman \u62A5\u9519\u8981\u6C42\u914D\u7F6E\u3002\n\u7F3A\u7701\u6A21\u578B = models[0]\uFF08\u53EF\u7528 handyman.defaultModel \u6307\u5B9A\uFF0C\u5FC5\u987B \u2208 models\uFF09\u3002\n**CCC \u5E94\u628A\u8BE5\u767D\u540D\u5355\u6307\u5411\u4F4E\u6210\u672C\u6A21\u578B**\u2014\u2014handyman \u662F\u6279\u91CF\u6267\u884C\u901A\u9053\uFF08v1.31.3 \u53CC\u6A21\u5F0F\u5171\u7528\u540C\u4E00\u767D\u540D\u5355\uFF09\u3002\n\n Modes\uFF08v1.31.3\uFF0C\u7F3A\u7701 foreground\uFF09:\n mode=\"foreground\"\uFF08\u7F3A\u7701\uFF09\uFF1A\u4E00\u6B21\u524D\u53F0\u4E32\u884C\u59D4\u6D3E\uFF08\u5BBF\u4E3B\u59D4\u6D3E\u670D\u52A1 ctx.subagents.start(\"spawn\") +\n agentOptions \u6CE8\u5165\u6A21\u578B\uFF09\u2014\u2014\u4E0D\u5FAA\u73AF\u3001\u4E0D\u6821\u9A8C\u5B8C\u6210\u7801\u3001\u4E0D\u5199\u8FDB\u5EA6\u6587\u4EF6\uFF1B\u8FD4\u56DE\u5B50 agent \u6700\u7EC8\u6587\u672C\u3002\n \u9002\u5408\"\u4E00\u6B21\u8C03\u7528\u4E00\u6B21\u7ED3\u679C\"\uFF08\u9010\u7528\u4F8B\u56DE\u5F52\u3001\u5355\u6B21\u8F6C\u6362\uFF09\u3002\n mode=\"background\"\uFF1A\u65E2\u6709\u5FAA\u73AF\u6821\u9A8C\u5B9E\u73B0\uFF08\u5185\u90E8 while \u786C\u5FAA\u73AF + \u968F\u673A\u5B8C\u6210\u7801\u552F\u4E00\u5224\u636E + \u8F6E\u6B21\u4E0A\u9650\n \u9ED8\u8BA4 100 \u53EF\u7EED\u8DD1 + \u5F02\u5E38\u81EA\u52A8\u91CD\u542F \u2264100 + \u8FDB\u5EA6\u6587\u4EF6 AGENT_SESSIONS/handyman-<label>.md/.json +\n jobs \u5E76\u884C maxParallel \u9ED8\u8BA4 10\uFF09\u3002\u9002\u5408\u957F\u4EFB\u52A1/\u65E0\u4EBA\u503C\u5B88/\u9700\u6297\u63D0\u524D\u6536\u5DE5\u3002\n\n Config:\n { \"handyman\": { \"models\": [\"provider/model-name\"] } }\n\n Example:\n { \"handyman\": { \"models\": [\"minimax-cn-coding-plan/MiniMax-M3\"], \"defaultModel\": \"minimax-cn-coding-plan/MiniMax-M3\", \"maxRounds\": 100, \"maxParallel\": 10 } }\n\n\u2500\u2500 2. sessionKeeper.threshold / sessionKeeper.sessionMdMaxKB \u2500\u2500\ntrajectory-assistant\uFF08TRAJECTORY-ASSISTANT \u00B7 CHECKPOINT\uFF09\u63D0\u9192\u673A\u5236\u7684\u79EF\u5206\u9608\u503C\uFF08\u975E headless \u4E3B agent\uFF09\u3002\n\u6309\u5DE5\u5177\u8C03\u7528\u52A0\u6743 + \u8017\u65F6\u8BA1\u5206\uFF1B\u8FBE\u5230\u9608\u503C\u6CE8\u5165\u63D0\u9192\uFF0C\u8981\u6C42\u6A21\u578B\u56DE\u590D ACK \u7801\u3002\n\n Config:\n { \"sessionKeeper\": { \"threshold\": 150, \"sessionMdMaxKB\": 200 } }\n\n \u8BA1\u5206\uFF1Awrite/edit = 3\uFF0Ctask = 10\uFF0Cread/grep/glob/msm \u7B49 = 1\uFF0C\u65F6\u95F4 = 1/\u5206\u949F\n \u9ED8\u8BA4\uFF1A150\n\n \u25B8 sessionMdMaxKB\uFF08v1.31.1 \u65B0\u589E\uFF0Cv1.31.2 \u7F3A\u7701 100\u2192200\uFF09\uFF1A**\u6D3B\u8DC3 SESSION.md \u4F53\u79EF\u4E0A\u9650\uFF08KB\uFF0C\u7F3A\u7701 200\uFF1B0 = \u5173\u95ED\uFF09**\u3002\n \u8D85\u8FC7 \u2192 \u6CE8\u5165 [TRAJECTORY-ASSISTANT \u00B7 LOGBOOK COMPACTION] \u63D0\u9192\uFF1A\u6682\u505C\u5F53\u524D\u5DE5\u4F5C \u2192\n \u52A0\u8F7D eap\uFF08praxis eap\uFF09\u2192 \u6309 EAP \u5206\u5C42\u9AA8\u67B6\u91CD\u5199 SESSION.md\u3002\u56DB\u6761\u539F\u5219\uFF08ACC \u5185\u5D4C\uFF0C\u968F\u63D0\u9192\u7ED9\u51FA\uFF09\uFF1A\n \u2460 \u4FDD\u7559 EAP \u5206\u5C42\u9AA8\u67B6\uFF08\u4E0D\u538B\u6210\u65F6\u95F4\u6D41\u6C34\u8D26\uFF09\u2461 \u5185\u5BB9\u53EF\u5916\u79FB\u5230 references \u6587\u4EF6\n \uFF08AGENT_SESSIONS/<\u4F1A\u8BDD>/references/*.md\uFF0CSESSION.md \u7559\u94FE\u63A5\uFF09\u2462 \u5141\u8BB8\u6574\u5408/\u5220\u9664\u4E0D\u91CD\u8981\u4E8B\u9879\n \uFF08\u88AB\u53D6\u4EE3\u7684\u51B3\u7B56\u3001\u5DF2\u89E3\u51B3\u95EE\u9898\u3001\u4E2D\u95F4\u6001\uFF09\u2463 \u81EA\u4E3B\u88C1\u91CF\u6743\u5145\u5206\u5141\u8BB8\uFF08\u552F\u4E00\u786C\u8981\u6C42 = \u9AA8\u67B6 +\n \u672A\u51B3\u9879/\u51B3\u7B56\u7406\u7531/\u4E0B\u4E00\u6B65\u4ECD\u53EF\u91CD\u5EFA\uFF09\u3002\u8D85\u9650\u6BCF\u8F6E\u63D0\u9192\uFF1B\u8FDE\u7EED 3 \u8F6E\u672A\u91CD\u5199 \u2192 \u5347\u7EA7\u5F3A\u5236\u8BED\u6C14\uFF1B\n \u6587\u4EF6\u56DE\u5230\u9650\u5185 \u2192 \u81EA\u52A8\u505C\u6B62\uFF08\u81EA\u6108\uFF09\u3002\u8F68\u8FF9\u63D0\u9192**\u4E0D\u673A\u68B0\u963B\u65AD\u5DE5\u4F5C**\uFF08\u4E0E rebuild \u63D0\u9192\u540C\u65CF\uFF09\u3002\n\n\u2500\u2500 3. localstore.gitTrack \u2500\u2500\nlocalstore.json \u7684 git \u7B56\u7565\uFF1Aallow \u53EF\u63D0\u4EA4 / deny \u7981\u63D0\u4EA4\uFF08\u9ED8\u8BA4 deny\uFF09\u3002\ndeny \u65F6\u5199\u5165\u81EA\u52A8\u786E\u4FDD .gitignore \u542B\u8BE5\u6587\u4EF6\uFF08\u7269\u7406\u4FDD\u8BC1\uFF09\uFF0Ccontainer_git commit \u4F1A\u68C0\u67E5\u62D2\u7EDD\u3002\n\n Config:\n { \"localstore\": { \"gitTrack\": \"allow\" } }\n\n\u2500\u2500 4. hooks.autoRestoreSession \u2500\u2500\n\u4F1A\u8BDD\u81EA\u52A8\u6062\u590D\uFF08\u9ED8\u8BA4 true\uFF1B\u53D7 events \u95E8\u63A7\u2014\u2014\u4EC5\u6839\u4F1A\u8BDD + \u5DF2\u6709\u5BF9\u8BDD\u5386\u53F2\u624D\u6062\u590D\uFF09\u3002\n\n Config:\n { \"hooks\": { \"autoRestoreSession\": false } }\n\n\u2500\u2500 5. safeMode / blacklist \u2500\u2500\nsafe-mode \u7531 WebUI \u5F00\u5173\u63A7\u5236\uFF08\u5199 .serenity-safe-on \u6807\u8BB0\uFF09\uFF1B\u9ED1\u540D\u5355\u8DEF\u5F84\u53D7 guards seam \u62E6\u622A\u3002\n\n Config:\n { \"safeMode\": { \"blacklist\": [\".secrets/\"] } }\n\n\u2500\u2500 6. skiff.roles\uFF08F4 \u8BA4\u77E5\u5B50\u96C6\u89D2\u8272\uFF09\u2500\u2500\nSkiff \u89D2\u8272 = \u5168\u77E5\u5168\u80FD trajectory \u7684\u4EFB\u610F\u5B50\u96C6\uFF08CCC \u5B9A\u4E49\uFF09\u3002\u6BCF\u89D2\u8272\u72EC\u7ACB\u6A21\u578B + \u53CC\u767D\u540D\u5355\n\uFF08MSM \u767D\u540D\u5355 msms[] \u4E0E\u975E MSM \u5DE5\u5177\u767D\u540D\u5355 tools[]\uFF0C\u767D\u540D\u5355\u5916\u5168\u9690\u85CF\uFF1Bskill \u52A0\u8F7D\u6052\u53EF\u7528\uFF09\u3002\ntrajectory \u7EAA\u5F8B\u5B50\u96C6\uFF08session/keeper/rebuild \u53C2\u4E0E\u9879\uFF09\u9ED8\u8BA4\u5168\u5173 = \u5B8C\u5168\u72EC\u7ACB\u3002\nsystemPrompt \u5185\u8054 \u6216 systemPromptFile\uFF08.md \u5F15\u7528\uFF0C\u63A8\u8350\uFF09\u2014\u2014\u89D2\u8272\u4F1A\u8BDD\u7684\u5B8C\u6574\u4EBA\u683C/\u8FB9\u754C\u63D0\u793A\u8BCD\u3002\nvalidate \u6821\u9A8C / apply \u751F\u6548 / list \u67E5\u770B\uFF1Acontainer_admin role <guide|validate|apply|list>\uFF08skiff_admin \u5DF2\u5E76\u5165\uFF09\u3002\n\n Config:\n { \"skiff\": { \"roles\": {\n \"qa\": {\n \"model\": \"provider/model\",\n \"msms\": [\"web-search\", \"vlm-describe\"],\n \"tools\": [\"read\", \"grep\", \"glob\"],\n \"systemPromptFile\": \".opencode/skiff/qa.md\"\n } } } }\n\n\u2500\u2500 7. container_trajectory\uFF08\u8F68\u8FF9\uFF1Aautopilot \u81EA\u4E3B\u5DE1\u822A + \u5524\u9192\u6CE8\u518C\u8868\uFF0CD58\uFF09\u2500\u2500\nCCC \u5B9A\u4E49\u7684\u4E00\u6761\u81EA\u4E3B trajectory\u2014\u2014\u65F6\u949F\u5230\u70B9\u81EA\u52A8\u5524\u8D77\uFF08\u524D\u53F0\u6CE8\u5165\uFF0C\u7528\u6237\u53EF\u89C1\u53EF\u4ECB\u5165\uFF09\u3002\n**autopilot \u662F trajectory \u7684\u5B50\u96C6**\uFF1A\u5468\u671F\u81EA\u5524\u9192\u7684\u7279\u4F8B\uFF1Btrajectory \u672C\u8EAB\u662F\u4E00\u7B49\u6982\u5FF5\uFF08\u4E00\u4E2A CCC \u5185\u53EF\u591A\u6761\u5E76\u884C\uFF09\u3002\n\u672A\u914D\u7F6E\u6216 enabled=false \u2192 \u5B8C\u5168\u4E0D\u542F\u52A8\uFF08\u96F6\u8D44\u6E90\u5360\u7528\uFF09\u3002\u591A CCC \u72EC\u7ACB\uFF1A\u6BCF CCC \u81EA\u5DF1\u7684\u914D\u7F6E\u3002\n\u5524\u8D77\u6D88\u606F\u56DB\u6BB5\u5F0F\uFF1A\u8F68\u8FF9\u7126\u70B9 topPrompt\uFF08\u6700\u5148\u6CE8\u5165\uFF0C\u7A33\u5B9A\u951A\uFF09\u2192 \u8EAB\u4EFD\u951A\u5B9A \u2192 \u5148\u9A8C\u504F\u89C1\n\uFF08CCC \u6839\u811A\u672C biasProvider \u8F93\u51FA\uFF09\u2192 \u4EFB\u52A1\u3002\u76EE\u6807\u4F1A\u8BDD session \u5FC5\u586B\uFF08\u76EE\u5F55\u987B\u5E26 --auto \u540E\u7F00\uFF09\u3002\n\u8BCA\u65AD/\u72B6\u6001/\u7ACB\u5373\u5524\u8D77\uFF1Acontainer_admin autopilot\uFF08status/init/generate-bias\uFF09\uFF1BACC \u8D1F\u8D23\u4EBA\u4E13\u7528\u8FD0\u884C\u6001\u8BCA\u65AD\u89C1\u5F00\u53D1\u9762\u3002\n\u5524\u9192\u6CE8\u518C\u8868\uFF08container_trajectory wake-later\uFF09\uFF1A\u5524\u9192 = \u672A\u6765\u65F6\u523B + \u4E00\u6761 message\uFF0C\u53EF\u5524\u9192\u81EA\u5DF1\u6216\u522B\u7684 trajectory\uFF1B\n\u843D\u70B9 AGENT_SESSIONS/wake-registry.json\uFF0C\u4E2D\u5FC3\u8C03\u5EA6\u5668\u5230\u70B9\u6295\u9012\uFF08fire-and-forget\uFF1B\u65E0\u56DE\u6267\u3001\u65E0\u56DE\u6536\uFF09\u3002\n\n Config:\n { \"trajectory\": {\n \"autopilot\": { // \u539F autopilotTrajectory \u6BB5\uFF0C\u5B57\u6BB5\u4E0D\u53D8\uFF08\u65E7\u952E\u4ECD\u56DE\u9000\u8BFB\uFF09\n \"enabled\": true,\n \"intervalHours\": 2,\n \"session\": \"S151\",\n \"biasProvider\": \"autopilot-bias.ts\",\n \"topPrompt\": \"\u672C\u8F68\u8FF9\u6838\u5FC3\u76EE\u6807/\u7EAA\u5F8B/\u8D28\u91CF\u8981\u6C42\uFF08CCC \u81EA\u586B\uFF0C\u9632\u6F02\u79FB\uFF09\",\n \"avoidWakeHours\": { \"start\": 8, \"end\": 18 }\n } } }\n\n\u2500\u2500 8. weixin\uFF08\u5FAE\u4FE1\u6865 F4c-3\uFF0C\u542B\u6D88\u606F\u8BB0\u5F55 hook\uFF09\u2500\u2500\nCCC \u7EA7\u5FAE\u4FE1\u4E2A\u4EBA\u53F7\u63A5\u5165\uFF08iLink \u534F\u8BAE\uFF09\uFF1Adsh \u4E00\u8FDB\u7A0B\u591A CCC\uFF0C\u6BCF CCC \u72EC\u7ACB\u5BF9\u63A5\u5FAE\u4FE1\u6865\u3002\n\u8D26\u53F7/\u8DEF\u7531/\u5F00\u5173\u5728\u6B64\u6587\u4EF6\uFF1B**bot_token \u51ED\u636E\u5728 CCC localstore credential scope**\n\uFF08\u626B\u7801\u7ED1\u5B9A\u540E\u81EA\u52A8\u5199\u5165\uFF0C\u6C38\u4E0D\u8FDB git \u660E\u6587\u9762\uFF09\u3002\n\u8DEF\u7531 user \u2192 role\uFF1Aexact \u4F18\u5148\uFF0C* \u901A\u914D\u515C\u5E95\uFF1Brole \u5FC5\u987B \u2208 \u8BE5 CCC skiff.roles\u3002\n\u9762\u677F\uFF08WebUI \u8BBE\u7F6E \u2192 \u5FAE\u4FE1\u6865\uFF09\u53EF\u626B\u7801\u7ED1\u5B9A/\u79FB\u9664\u8D26\u53F7/\u7F16\u8F91\u8DEF\u7531\uFF1Bmsm(\"weixin-doctor\", [\"status\"|\"diag\"|\"verify\"|\"guide\"]) \u6392\u67E5 + \u5927\u800C\u5168\u6307\u5357\u3002\u51ED\u636E\u4E3B\u52A8\u67E5\u770B\uFF1Alocalstore get WEIXIN_<ACCOUNT>_TOKEN\u3002\n \u25B8 \u4E3B\u52A8\u53D1\u9001\uFF08v1.31.0\uFF1A**ACC \u5DE5\u5177 im-bridge**\uFF09\uFF1A\u8C03\n im-bridge({channel:\"weixin\", action:\"send\", user:\"<\u522B\u540D|id>\", text:\"<\u6587\u672C>\"}) \u7ED9\u7528\u6237\u53D1\u6D88\u606F\u2014\u2014\n **\u5DE5\u5177\u53EA\u80FD\u64CD\u4F5C\u672C\u4F1A\u8BDD CCC**\uFF08\u65E0 ccc \u53C2\u6570\uFF0C\u9632\u8BEF\u53D1\u4ED6\u5BB9\u5668\uFF09\u2192 weixin-bridge.sendProactiveText \u2192\n \u6210\u529F\u540E\u89E6\u53D1 outgoing hook\uFF08source=\"proactive\"\uFF09\u3002\u6587\u4EF6\u7528 action:\"send-file\" + file:\"<CCC \u5185\u8DEF\u5F84>\"\n \uFF08\u9003\u9038/\u7F3A\u5931/\u8D85 20MB \u62D2\u7EDD\uFF09+ \u53EF\u9009 caption\u3002**\u53EF\u89C1\u6027**\uFF1A\u672C CCC \u914D\u7F6E\u4E86 IM \u901A\u9053\n \uFF08weixin.enabled=true\uFF09\u624D\u51FA\u73B0\u5728\u6A21\u578B\u5DE5\u5177\u6E05\u5355\u91CC\uFF1B\u672A\u914D\u7F6E \u2192 \u7531 guards \u9010 agent\n tools.restrict({deny:['im-bridge']}) \u79FB\u9664\uFF08\u4E0D\u662F\"\u770B\u5F97\u5230\u4F46\u88AB\u62D2\"\uFF09\u3002skiff \u89D2\u8272\u53E6\u9700\u5728\n roles.<role>.tools \u767D\u540D\u5355\u5217\u51FA im-bridge\u3002\n \u5386\u53F2\uFF08v1.30.9~v1.30.x\uFF09\uFF1ACCC \u4FA7 MSM weixin-send\uFF08\u8D70 loopback HTTP \u5165\u53E3 3082\uFF09\u2014\u2014\n v1.31.0 \u5DF2\u9000\u5F79\uFF08\u811A\u672C\u5220\u9664 + \u6CE8\u518C\u8868\u6CE8\u9500\uFF09\uFF1B3082 \u5165\u53E3\u4FDD\u7559\u7ED9**\u975E agent \u8C03\u7528\u8005**\u3002\n\n \u25B8 weixin.autoReplyWithLastMessage\uFF08v1.30.10\uFF0C\u5173\u95ED\u6865\u7684\u81EA\u52A8\u8F93\u51FA\uFF09\uFF1A\n \u7F3A\u7701 true = \u73B0\u72B6\uFF1A\u6865\u5728 agent \u4E00\u8F6E\u7ED3\u675F\u540E\u628A**\u6700\u7EC8 assistant \u6587\u672C**\u81EA\u52A8\u56DE\u53D1\u7528\u6237\uFF08source=\"reply\"\uFF09\u3002\n \u663E\u5F0F false = \u5173\u95ED\uFF1A\u6865**\u4E0D\u518D\u8F6C\u53D1\u6700\u7EC8\u6587\u672C**\uFF0C\u8F93\u51FA\u6743\u4EA4\u7ED9 agent\u2014\u2014\u6BCF\u8F6E\u5728\u7528\u6237\u6D88\u606F**\u672B\u5C3E**\u8FFD\u52A0\n **\u673A\u5236\u6807\u8BB0** [serenity:weixin-manual-output] + \u4E00\u884C\u5DF2\u586B\u597D\u53C2\u6570\u7684 im-bridge \u8C03\u7528\n \uFF08\u8D26\u53F7/\u7528\u6237 id\uFF09\uFF0Cagent \u81EA\u5DF1\u51B3\u5B9A\u53D1\u4EC0\u4E48\u3001\u53D1\u51E0\u6761\uFF08\u5168\u90E8\u8BB0 source=\"proactive\"\uFF09\u3002\n **ACC \u53EA\u7ED9\u673A\u5236\u4E0E\u6570\u636E\uFF0C\u7EAA\u5F8B\u63AA\u8F9E\u5F52 CCC**\uFF08v1.30.16\uFF09\uFF1A\u600E\u4E48\u5199/\u5FC5\u987B\u600E\u4E48\u505A/\u540E\u679C\u662F\u4EC0\u4E48\u5199\u5728\n CCC \u89D2\u8272\u63D0\u793A\u8BCD\u6587\u4EF6\u91CC\uFF08\u5982 .opencode/skiff/<role>.md\uFF09\uFF0C\u53EF\u70ED\u6539\uFF08v1.30.15 \u8D77\u89D2\u8272\u63D0\u793A\u8BCD\u70ED\u91CD\u8F7D\uFF09\u3002\n \u673A\u68B0\u95F8\u95E8\uFF08v1.30.16\uFF09\uFF1A\u672C\u8F6E turn \u7ED3\u675F\u4ECD\u672A\u6210\u529F\u8C03\u7528 im-bridge\uFF08send / send-file\uFF1B\u517C\u5BB9\u65E7\n msm(\"weixin-send\") \u5F62\u6001\uFF09\u2192 agent \u88AB\u6253\u56DE\uFF08\u22642 \u6B21\uFF0C\u63D0\u793A = \u6807\u8BB0 + \u4E8B\u5B9E\uFF09\uFF1B\u8FBE\u4E0A\u9650\u653E\u5F03\u5E76\u54CD\u4EAE\u544A\u8B66\u3002\n \u5931\u8D25\u8C03\u7528\u4E0D\u7B97\u5DF2\u9001\u8FBE\u3002\n \u8BED\u4E49\u8FB9\u754C\uFF08\u7528\u6237\u62CD\u677F\uFF09\uFF1A\u53EA\u5173\u6700\u7EC8\u6587\u672C\uFF1B\u7CFB\u7EDF\u7C7B\u6D88\u606F\uFF08\u65B0\u5BF9\u8BDD\u901A\u77E5 / \u8BED\u97F3\u65E0\u6CD5\u89E3\u6790\u63D0\u793A\uFF09\u4FDD\u7559\uFF1B\n typing \u6307\u793A\u4E0E incoming hook \u4E0D\u53D7\u5F71\u54CD\u3002\n\n \u25B8 weixin.fallbackOnNoSend\uFF08v1.30.17\uFF0C\u624B\u52A8\u6A21\u5F0F\u7684**\u515C\u5E95**\uFF1B\u7F3A\u7701 false\uFF09\uFF1A\n \u4EC5\u5728 autoReplyWithLastMessage=false \u65F6\u751F\u6548\u3002true \u2192 \u4E00\u8F6E\u7ED3\u675F\u65F6\u82E5 agent **\u4E00\u6B21\u90FD\u6CA1\u6210\u529F**\n \u8C03\u7528\u8F93\u51FA\u5DE5\u5177\uFF08\u95F8\u95E8\u6253\u56DE\u7528\u5C3D\uFF09\uFF0C\u6865\u628A\u8BE5\u8F6E\u6700\u7EC8\u6587\u672C\u8F6C\u53D1\u7ED9\u7528\u6237\uFF08\u8BB0\u5F55 source=\"reply-fallback\"\uFF0C\n \u65E5\u5FD7\u7559\u54CD\u4EAE\u544A\u8B66\uFF09\u2014\u2014\u4FDD\u8BC1\"\u4E0D\u4E22\u6D88\u606F\"\u3002agent \u81EA\u5DF1\u53D1\u8FC7 \u2192 \u4E0D\u515C\u5E95\uFF08\u8F93\u51FA\u6743\u4ECD\u5728 agent\uFF09\u3002\n \u4E3A\u4EC0\u4E48\u9700\u8981\uFF08\u5B9E\u8BC1\uFF09\uFF1Av1.30.16 \u95F8\u95E8\u4F1A\u6253\u56DE \u22642 \u6B21\uFF0C\u4F46\u5B9E\u6D4B\u67D0\u6A21\u578B\u5728**\u5BD2\u6684\u7C7B\u6D88\u606F**\u4E0A\u8FDE\u7EED 4 \u8F6E\u3001\n \u8DE8 3 \u7248 CCC \u63D0\u793A\u8BCD\u4ECD\u4E0D\u8C03\u5DE5\u5177 \u2192 \u6253\u56DE\u7528\u5C3D\u540E\u7528\u6237\u4EC0\u4E48\u90FD\u6536\u4E0D\u5230\uFF1B\u63D0\u793A\u8BCD\u4E0E\u95F8\u95E8\u5747\u5DF2\u6392\u9664\u3002\n \u4EE3\u4EF7\uFF08\u663E\u5F0F\uFF09\uFF1A\u89D2\u8272\u5931\u53BB\"\u6545\u610F\u9759\u9ED8\"\u80FD\u529B\uFF08\u5B83\u603B\u4F1A\u4EA7\u51FA\u4E00\u6BB5\u6700\u7EC8\u6587\u672C\uFF09\u2192 \u9700\u4E25\u683C\u9759\u9ED8\u7684\u89D2\u8272\u4FDD\u6301\u7F3A\u7701\u3002\n \u4E09\u6001\uFF1A\u2460 autoReplyWithLastMessage=true\uFF08\u7F3A\u7701\uFF09\u6865\u603B\u662F\u56DE\u53D1\uFF1B\u2461 =false + fallbackOnNoSend=true\n = agent \u4F18\u5148\u3001\u6865\u515C\u5E95\uFF08\u63A8\u8350\uFF09\uFF1B\u2462 \u4E24\u8005\u7686 false\uFF08\u7F3A\u7701\uFF09= \u4E25\u683C\u9759\u9ED8\uFF08v1.30.10 \u8BED\u4E49\uFF09\u3002\n \u26A0\uFE0F \u515C\u5E95\u53EA\u5728**\u95F8\u95E8\u88C5\u914D\u6210\u529F**\u65F6\u751F\u6548\uFF08\u672A\u88C5\u914D\u5219\u65E0\u6CD5\u5224\u5B9A\u662F\u5426\u53D1\u9001\u8FC7 \u2192 \u4E0D\u5192\u91CD\u590D\u53D1\u9001\u98CE\u9669\uFF09\u3002\n\n Config:\n { \"weixin\": {\n \"enabled\": true,\n \"hook\": \"scripts/weixin-message-hook.ts\",\n \"autoReplyWithLastMessage\": true,\n \"fallbackOnNoSend\": false,\n \"accounts\": [{ \"accountId\": \"wechat-1\", \"name\": \"\u5BB6\u5EAD\u52A9\u624B\", \"enabled\": true }],\n \"routes\": [{ \"user\": \"*\", \"role\": \"zhaocai\" }]\n } }\n\n \u25B8 weixin.hook\uFF08\u6D88\u606F\u8BB0\u5F55 hook\uFF0Cv1.27.13\uFF09\uFF1A\n \u5FAE\u4FE1\u6865\u6BCF\u6536/\u53D1\u4E00\u6761\u6D88\u606F\u89E6\u53D1\u4E00\u6B21 CCC \u81EA\u5199\u811A\u672C\uFF0C\u7531 CCC \u81EA\u884C\u6301\u4E45\u5316\u4FDD\u5B58\uFF08\u5B58\u54EA/\u5B58\u6210\u4EC0\u4E48\n /\u662F\u5426\u5165\u5E93\u5168\u5F52 CCC\u2014\u2014ACC \u4E0D\u7ED1\u5B9A\u5B58\u50A8\uFF09\u3002\u672A\u914D\u7F6E hook \u2192 \u96F6\u53D8\u5316\uFF08\u4E0D\u89E6\u53D1\uFF09\u3002\n\n \u89E6\u53D1\uFF08\u53CC\u5411\uFF09\uFF1A\n incoming = \u7528\u6237 \u2192 bot\uFF1A\u8DEF\u7531\u547D\u4E2D\u540E\u3001\u5A92\u4F53\u843D\u76D8\u540E\u89E6\u53D1\uFF08\u6587\u672C\u542B\u8BED\u97F3\u8F6C\u5199\uFF1B\u5A92\u4F53\u5E26\u843D\u76D8 relPath\uFF09\n outgoing = bot \u2192 \u7528\u6237\uFF1A\u53D1\u9001\u6210\u529F\u540E\u89E6\u53D1\uFF08reply = \u7528\u6237\u5B9E\u9645\u6536\u5230\u7684\u7EAF\u6587\u672C\uFF0C\u5DF2\u5265\u79BB think\uFF09\n \u00B7 source=\"reply\"\uFF08\u7F3A\u7701\uFF09= \u56DE\u590D\u7528\u6237\u6D88\u606F\uFF1Bsource=\"proactive\"\uFF08v1.30.9\uFF09= bot \u4E3B\u52A8\u53D1\u8D77\n \uFF08CCC \u7ECF im-bridge \u5DE5\u5177\uFF08v1.31.0\uFF1B\u65E7 weixin-send MSM \u5DF2\u9000\u5F79\uFF09\u2192 sendProactiveText\uFF09\uFF1B\n source=\"reply-fallback\"\uFF08v1.30.17\uFF09= \u624B\u52A8\u6A21\u5F0F\u4E0B agent \u672C\u8F6E\u672A\u53D1\u9001 \u2192 \u6865\u515C\u5E95\u8F6C\u53D1\u6700\u7EC8\u6587\u672C\n \u00B7 file\uFF08\u4EC5 send-file \u8865\u8BB0\uFF09\uFF1A{ \"name\": \"\u62A5\u544A.pdf\", \"size\": 12345, \"caption\": \"\u53EF\u9009\" }\n\n \u811A\u672C\u7EA6\u5B9A\uFF08\u4E8B\u4EF6 JSON \u5355\u884C\u7ECF stdin \u4F20\u5165\uFF1Bbun \u4F18\u5148 node \u515C\u5E95\uFF09\uFF1A\n #!/usr/bin/env bun \u6216 node script.js \u2014\u2014 \u8BFB process.stdin \u6574\u6BB5 JSON.parse\n const ev = JSON.parse(await new Response(process.stdin).text())\n ev.event === 'incoming' | 'outgoing'\n\n \u4E8B\u4EF6 schema\uFF08**\u4E0D\u542B\u4EFB\u4F55\u4F1A\u8BDD\u51ED\u636E**\u2014\u2014context_token/bot_token/token/aes_key \u5747\u4E0D\u51FA\u73B0\uFF09\uFF1A\n { \"event\": \"incoming\", \"ts\": 1788359941488, \"cccRoot\": \"/path/ccc\",\n \"accountId\": \"wechat-1\", \"userId\": \"u1@im.wechat\",\n \"sessionId\": \"skiff-weixin-xxx\", \"role\": \"zhaocai\",\n \"message\": { \"text\": \"\u4F60\u597D\", \"media\": [{ \"kind\": \"image\", \"relPath\": \"_tmp/weixin-inbound/<hash>/img_x.jpg\" }] } }\n { \"event\": \"outgoing\", \"ts\": ..., \"cccRoot\": ..., \"accountId\": ...,\n \"userId\": ..., \"sessionId\": ..., \"role\": ...,\n \"reply\": \"\u5DF2\u8BB0\u5F55\uFF08\u7EAF\u6587\u672C\uFF09\", \"source\": \"reply\" | \"proactive\" | \"reply-fallback\" }\n\n \u793A\u4F8B\u811A\u672C\uFF08\u8FFD\u52A0\u5230\u6309\u65E5\u6587\u4EF6\u2014\u2014\u6301\u4E45\u5316\u5F52 CCC \u81EA\u9009\uFF1A\u6587\u4EF6/DB/\u8FDC\u7AEF\u5747\u53EF\uFF09\uFF1A\n const fs = require('node:fs'); const p = '/path/ccc/AGENT_SESSIONS/_weixin-log.jsonl';\n fs.appendFileSync(p, JSON.stringify(ev) + '\\n');\n\n \u6267\u884C\u8BED\u4E49\uFF08\u65C1\u8DEF\u5BB9\u5FCD\uFF09\uFF1A\u5F02\u6B65 fire-and-forget + 15s \u8D85\u65F6 kill + \u5931\u8D25\u4EC5\u65E5\u5FD7\u2014\u2014\n \u5FAE\u4FE1\u6865\u6D88\u606F\u5904\u7406/\u56DE\u590D\u4E0D\u53D7 hook \u5F71\u54CD\uFF1B\u811A\u672C\u987B\u5728 CCC \u6839\u5185\uFF08\u8DEF\u5F84\u9003\u9038\u62D2\u7EDD\uFF09\u3002\n \u5A92\u4F53 relPath \u6307\u5411 _tmp/weixin-inbound/\uFF08\u4E34\u65F6\u76EE\u5F55\uFF09\u2014\u2014\u9700\u6301\u4E45\u4FDD\u5B58\u5A92\u4F53\u6587\u4EF6\u8BF7\u81EA\u884C copy\u3002\n\n\u2500\u2500 9. exclusiveTools\uFF08\u4E13\u5C5E\u5DE5\u5177\u58F0\u660E\uFF0Cv1.33\uFF09\u2500\u2500\n**ACC \u6CE8\u518C\u4F46\u9ED8\u8BA4\u5BF9\u6240\u6709 CCC \u9690\u85CF**\u7684\u5DE5\u5177\uFF0C\u53EA\u6709\u5728\u81EA\u5DF1\u8FD9\u91CC**\u70B9\u540D**\u7684 CCC \u53EF\u89C1\u3002\n\u8FD9\u662F\u901A\u7528\u673A\u5236\uFF08\u4EFB\u4F55\u5DE5\u5177\u540D\u7686\u53EF\uFF09\uFF0C\u5224\u636E\u7531 CCC \u58F0\u660E\u2014\u2014ACC \u4EE3\u7801\u91CC\u4E0D\u51FA\u73B0\u4EFB\u4F55\u5177\u4F53 CCC \u7684\u540D\u5B57\u3002\n\u5F53\u524D\u4E13\u5C5E\u5DE5\u5177\uFF1Aacc-diag\uFF08\u8FD0\u884C\u6001\u8BCA\u65AD\u2014\u2014live \u4F1A\u8BDD / agent \u5B9A\u4F4D / \u5524\u9192\u6CE8\u518C\u8868 / \u5524\u8D77\u6761\u4EF6\u94FE\uFF09\u3002\n\n \u25B8 \u53EF\u89C1\u6027\u8BED\u4E49\uFF1A\u672A\u58F0\u660E \u21D2 \u7531 guards \u9010 agent tools.restrict({deny:[tool]}) \u4ECE**\u6A21\u578B\u5DE5\u5177\u6E05\u5355\u79FB\u9664**\n \uFF08\u4E0D\u662F\"\u770B\u5F97\u5230\u4F46\u88AB\u62D2\"\uFF09\u3002\u914D\u7F6E\u70ED\u66F4\u65B0\uFF1A\u6539\u672C\u6587\u4EF6\u5373\u65F6\u751F\u6548\uFF08\u65E0\u9700\u91CD\u542F\uFF09\u3002\n \u25B8 \u5931\u8D25\u65B9\u5411 **fail-closed**\uFF1A\u672A\u914D\u7F6E / \u5B57\u6BB5\u7F3A\u5931 / \u914D\u7F6E\u635F\u574F\uFF08JSON \u574F\uFF09\u21D2 \u4E00\u5F8B\u6309\"\u672A\u58F0\u660E\"\u5904\u7406\n \uFF08\u4E13\u5C5E\u5DE5\u5177\u4FDD\u6301\u9690\u85CF\uFF1B\u914D\u7F6E\u635F\u574F\u672C\u8EAB\u53E6\u6709\u54CD\u4EAE\u544A\u8B66\uFF09\u3002\u4E0E im-bridge \u76F8\u53CD\u2014\u2014\u9690\u85CF\u4E00\u4E2A**\u5DF2\u5728\u4F7F\u7528**\n \u7684\u901A\u9053\u624D\u4F1A\u9759\u9ED8\u635F\u5BB3\u80FD\u529B\uFF0C\u800C\u4E13\u5C5E\u5DE5\u5177\u7684\u9ED8\u8BA4\u6001\u672C\u5C31\u662F\u9690\u85CF\u3002\n \u25B8 \u914D\u7F6E\u635F\u574F\u7684\u54CD\u4EAE\u544A\u8B66\u53EA\u51FA\u73B0\u4E00\u6B21\uFF08\u6BCF\u8DEF\u5F84\uFF09\uFF0Cdashboard health \u540C\u6837\u80FD\u770B\u5230\u3002\n\n Config:\n { \"exclusiveTools\": [\"acc-diag\"] }\n";
|
|
23
|
-
export interface MsmFlag {
|
|
11
|
+
interface MsmFlag {
|
|
24
12
|
name: string;
|
|
25
13
|
type?: string;
|
|
26
14
|
description?: string;
|
|
@@ -36,7 +24,7 @@ export interface MsmEntry {
|
|
|
36
24
|
usage?: string;
|
|
37
25
|
flags?: MsmFlag[];
|
|
38
26
|
}
|
|
39
|
-
|
|
27
|
+
interface MsmArgs {
|
|
40
28
|
action: MsmAction;
|
|
41
29
|
name?: string;
|
|
42
30
|
args?: string[];
|
|
@@ -49,44 +37,38 @@ export interface MsmArgs {
|
|
|
49
37
|
/** register: 自定义 usage(缺省 'msm <name> [args...]') */
|
|
50
38
|
usage?: string;
|
|
51
39
|
}
|
|
52
|
-
export declare function parseRegistry(raw: string): MsmEntry[];
|
|
53
|
-
/**
|
|
54
|
-
* 注册表单级化(需求⑤a S142 用户拍板:注册表只有一级——对齐 osp cccName 单聚合档):
|
|
55
|
-
* 所有 entry 集中写入 `.opencode/skills/<cccName>/references/mech-registry.json`
|
|
56
|
-
* (cccName = .serenity 首行,即顶层入口 skill 目录),skill 只作 entry 字段。
|
|
57
|
-
* 不再扫描/写入各 skill 目录的分散注册表(历史形态 v1.14~v1.27,register --skill
|
|
58
|
-
* 曾写入各自 skill 目录 —— 多真相源,废弃)。
|
|
59
|
-
*/
|
|
60
|
-
export declare function findRegistries(root: string): string[];
|
|
61
40
|
export declare function loadMsmEntries(root: string): MsmEntry[];
|
|
62
41
|
export declare function findEntry(root: string, name: string): MsmEntry | null;
|
|
63
|
-
/**
|
|
64
|
-
|
|
42
|
+
/**
|
|
43
|
+
* 注册表写入路径(需求⑤a 单级化):永远返回 cccName 聚合档。
|
|
44
|
+
* skill 参数保留签名(兼容调用方)但只进 entry 字段,不决定写入位置。
|
|
45
|
+
*/
|
|
46
|
+
/**
|
|
47
|
+
* 注册表质量契约报告(DC-M1~M4)。**类型别名而非 interface**:`runMsm` 的返回类型是 `JsonValue`,
|
|
48
|
+
* 而 `interface` 不获得隐式索引签名(别名对象类型才有)——用别名可让本报告直接作为 `JsonValue` 返回,
|
|
49
|
+
* 不必在 `case 'check'` 里加类型断言。
|
|
50
|
+
*/
|
|
51
|
+
export type RegistryQualityReport = {
|
|
52
|
+
/** 被检查的注册表条目数 */
|
|
53
|
+
checked: number;
|
|
54
|
+
issues: {
|
|
55
|
+
name: string;
|
|
56
|
+
check: string;
|
|
57
|
+
detail: string;
|
|
58
|
+
}[];
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* **注册表「质量契约」判据(DC-M1~M4)** —— 具名出口(C5 观察面归一,2026-09-15)。
|
|
62
|
+
*
|
|
63
|
+
* 此前这段判据**只存在于 `runMsm` 的 `case 'check'` 分支体内**(没有名字、无法从别处取用),
|
|
64
|
+
* 于是 `dashboard health` 只能另写一份 **不同判据** 的结构检查(`checkRegistryHealth`)。
|
|
65
|
+
* 抽成具名函数后,两条判据**各自有名字、各自可被取用、且仍然完全独立**——合并它们是错的:
|
|
66
|
+
* 本判据的主语是**条目契约**(有没有测试 / main() 守卫 / 双向注册 / path 型 flag),
|
|
67
|
+
* 结构判据的主语是**文件能否安全解析**。同一份注册表在两条判据下可以给出相反结论。
|
|
68
|
+
*
|
|
69
|
+
* 行为与抽取前**逐字一致**(`runMsm` 的 `check` 分支现只做 `return checkRegistryQuality(root)`)。
|
|
70
|
+
*/
|
|
71
|
+
export declare function checkRegistryQuality(root: string): RegistryQualityReport;
|
|
65
72
|
export declare function runMsm(root: string, args: MsmArgs): JsonValue;
|
|
66
|
-
/** 解析并校验 exec 参数:返回可执行条目 + 业务参数(list/schema 协议 flag 已分流) */
|
|
67
|
-
export interface PreparedExec {
|
|
68
|
-
entry: MsmEntry;
|
|
69
|
-
businessArgs: string[];
|
|
70
|
-
fmtJson: boolean;
|
|
71
|
-
/** 业务参数是否含 --help/-h(exit≠0 时不追加 TIP,对齐 osp) */
|
|
72
|
-
hasHelp: boolean;
|
|
73
|
-
/** 协议结果(--list / --schema);非协议执行时为 undefined */
|
|
74
|
-
protocol?: {
|
|
75
|
-
list: {
|
|
76
|
-
name: string;
|
|
77
|
-
category: string | null;
|
|
78
|
-
}[];
|
|
79
|
-
} | {
|
|
80
|
-
schema: {
|
|
81
|
-
name: string;
|
|
82
|
-
path: string;
|
|
83
|
-
flags: {
|
|
84
|
-
name: string;
|
|
85
|
-
type: string | null;
|
|
86
|
-
description: string | null;
|
|
87
|
-
}[];
|
|
88
|
-
};
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
export declare function prepareExec(root: string, args: MsmArgs): PreparedExec;
|
|
92
73
|
export declare function runMsmAsync(root: string, args: MsmArgs): Promise<JsonValue>;
|
|
74
|
+
export {};
|
|
@@ -56,8 +56,6 @@ export declare const LLM_PI_AI_NAMESPACE = "llm-pi-ai";
|
|
|
56
56
|
* 亲和键(缓存永远不命中),反而劣化。常量让"同一安装 → 同一亲和键"成立。
|
|
57
57
|
*/
|
|
58
58
|
export declare const OPENCODE_SESSION_ID = "dsh-serenity";
|
|
59
|
-
/** 视为 opencode 路由的路由名(pi-ai 目录里的两个 id) */
|
|
60
|
-
export declare const OPENCODE_ROUTE_IDS: readonly string[];
|
|
61
59
|
/** 自动配置时创建的路由名(pi-ai 目录的 Go 面;用户选的是付费 `/zen/go`) */
|
|
62
60
|
export declare const OPENCODE_ROUTE_TO_CREATE = "opencode-go";
|
|
63
61
|
/** 触发 L2 建路由的环境变量名(与 pi-ai 目录 provider 的 `envApiKeyAuth` 声明一致) */
|
|
@@ -70,14 +68,14 @@ export declare const OPENCODE_API_KEY_ENV = "OPENCODE_API_KEY";
|
|
|
70
68
|
* 头名大小写不敏感是 HTTP 语义,但**名字不同就是两个头**,故都要。
|
|
71
69
|
*/
|
|
72
70
|
export declare function opencodeRouteHeaders(): Record<string, string>;
|
|
73
|
-
|
|
71
|
+
interface OpencodeAutoConfigInput {
|
|
74
72
|
/** `llm-pi-ai` 命名空间**解析后**的值(`settings.get` 结果;undefined = 命名空间未注册) */
|
|
75
73
|
resolved: unknown;
|
|
76
74
|
/** 进程环境(注入以便测试) */
|
|
77
75
|
env: Readonly<Record<string, string | undefined>>;
|
|
78
76
|
}
|
|
79
77
|
/** 一条动作记录(日志 + 测试断言共用;不返回"秘密"、只返回做了什么) */
|
|
80
|
-
|
|
78
|
+
type OpencodeAutoConfigAction = {
|
|
81
79
|
kind: 'fill-headers';
|
|
82
80
|
route: string;
|
|
83
81
|
keys: readonly string[];
|
|
@@ -92,7 +90,7 @@ export type OpencodeAutoConfigAction = {
|
|
|
92
90
|
kind: 'idle';
|
|
93
91
|
reason: 'namespace-unregistered' | 'no-route';
|
|
94
92
|
};
|
|
95
|
-
|
|
93
|
+
interface OpencodeAutoConfigPlan {
|
|
96
94
|
/** 传给 `settings.update` 的补丁;空对象 = 无事可做(**不写**,避免无谓触发 settings/updated) */
|
|
97
95
|
patch: Record<string, unknown>;
|
|
98
96
|
actions: readonly OpencodeAutoConfigAction[];
|
|
@@ -132,3 +130,4 @@ export declare function applyOpencodeAutoConfigOnce(ctx: Context, env?: Readonly
|
|
|
132
130
|
* 不设"一次性完成"闸门:③ 必须能在之后继续生效(用户随时可能新增 opencode 路由)。
|
|
133
131
|
*/
|
|
134
132
|
export declare function registerOpencodeAutoConfig(ctx: Context): void;
|
|
133
|
+
export {};
|
|
@@ -11,9 +11,6 @@
|
|
|
11
11
|
* (dsh-serenity-hooks/container_trajectory rebuild/mech-registry),打回会瘫痪自身工作。
|
|
12
12
|
*/
|
|
13
13
|
import type { Context } from 'cordis';
|
|
14
|
-
/** 外部面会话判定(v1.26.3 用户拍板:仅外部面检测,本地维护会话豁免):
|
|
15
|
-
* skiff-(F4 问答)/ acp-(F4c 程序化)/ rebuild-(v1.22.4 重建会话)前缀 */
|
|
16
|
-
export declare function isExternalFaceSession(sessionId: string | undefined): boolean;
|
|
17
14
|
/**
|
|
18
15
|
* 注册输出守卫(index.ts apply 调用):
|
|
19
16
|
* turn-stopping 时检测最终输出,命中敏感词 → steer 打回重生成(官方机制,零改 DSH)。
|
package/lib/output-guard.d.ts
CHANGED
|
@@ -16,14 +16,22 @@
|
|
|
16
16
|
* the machine re-reads its inbox: fresh steering runs another step, none closes the
|
|
17
17
|
* turn"——steer 打回是官方支持的"重生成"通道(v1.22.5 rebuild 自动继续同款先例)。
|
|
18
18
|
*/
|
|
19
|
+
/**
|
|
20
|
+
* 内部端口(宁静号服务面)。
|
|
21
|
+
*
|
|
22
|
+
* 🔴 C4 块 B(2026-09-15)**缺陷修复**:此处原为硬写常量 `['3080','3081','3099','3100']`
|
|
23
|
+
* ——**漏了 3082**(微信主动发送面,**默认开**)⇒ 守卫拦不住 agent 在用户可见输出里提及 3082。
|
|
24
|
+
* 现改为**由集中端口表派生**(`ports.ts` 的 `MECHANISM_PORTS`):五面齐全,且新增面时
|
|
25
|
+
* 自动进表——不再存在"另抄一份词表 → 静默漂移"的面。
|
|
26
|
+
*/
|
|
19
27
|
/** 敏感词分类(v1.26.11:打回消息按类给规避指引——裸词不够,模型要知道词是什么/怎么规避) */
|
|
20
|
-
|
|
28
|
+
type SensitiveCategory = 'credential' | 'mechanism' | 'port' | 'msm';
|
|
21
29
|
/** 一次命中(词 + 分类) */
|
|
22
|
-
|
|
30
|
+
interface SensitiveHit {
|
|
23
31
|
word: string;
|
|
24
32
|
category: SensitiveCategory;
|
|
25
33
|
}
|
|
26
|
-
|
|
34
|
+
interface SensitiveWordTable {
|
|
27
35
|
/** 精确匹配词(条目名/值/工具名——命中即敏感) */
|
|
28
36
|
exact: Set<string>;
|
|
29
37
|
/** 子串匹配词(机制词——命中即敏感) */
|
|
@@ -66,3 +74,4 @@ export declare const REBUKE_MAX_ROUNDS = 3;
|
|
|
66
74
|
export declare const rebukeStates: Map<string, {
|
|
67
75
|
consecutive: number;
|
|
68
76
|
}>;
|
|
77
|
+
export {};
|
package/lib/ports.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ports.ts — ACC 对外面的**集中端口表**(C4 块 B,S142 2026-09-15)
|
|
3
|
+
*
|
|
4
|
+
* 为什么存在(现状取证:`AGENT_SESSIONS/…/acc-c4c5-current-state.md` §③ 3.2-8):
|
|
5
|
+
* 端口此前**散在 4 处默认值**(`config-ops.defaultAdvancedSettings` / `settings-section` schema
|
|
6
|
+
* 与 entry / `index.ts` 的 Config 与 `readWebPort` 回退),而 `output-guard.MECHANISM_PORTS`
|
|
7
|
+
* 另抄了一份**词表**——两处真相互不相干、且那份词表**漏了 3082**(微信发送面,**默认开**),
|
|
8
|
+
* 于是"禁止 agent 在用户可见输出里提及内部端口"的守卫对 3082 无效。
|
|
9
|
+
*
|
|
10
|
+
* 本模块是端口语义的**单一真相源**:
|
|
11
|
+
* · 每个面的端口 / 监听地址 / 默认开关 / 语义,只在这里写一次;
|
|
12
|
+
* · 默认值各处(config-ops / settings-section / index)由此派生;
|
|
13
|
+
* · `MECHANISM_PORTS`(output-guard 的"机制端口"词表)**由端口表机械派生**——
|
|
14
|
+
* 新增一个面即自动进词表,不再存在"抄一份词表"的漂移面。
|
|
15
|
+
*
|
|
16
|
+
* 边界(不可混淆,见 §① 表 A):**面 A(3080)不由本插件监听**——它是宿主 DSH 主 WebUI,
|
|
17
|
+
* 插件只往上挂 `/serenity/*` 路由。它入表是为了"端口语义完整 + 进机制词表",
|
|
18
|
+
* **不是**本插件的 listener(`host` 为 `null` 即此意)。
|
|
19
|
+
*
|
|
20
|
+
* 本模块是**零依赖叶模块**(纯常量,无 import)——output-guard(守卫词表)、config-ops
|
|
21
|
+
* (默认值)、settings-section(面板默认)、index(Config 默认)都可安全引用而不引入依赖环。
|
|
22
|
+
*/
|
|
23
|
+
/** 面标识(五个对外面;A 由宿主监听,B/C/D/E 由本插件监听) */
|
|
24
|
+
export type FaceId = 'main' | 'gateway' | 'weixinSend' | 'skiffDebug' | 'acpHttp';
|
|
25
|
+
/** 一个面的端口语义 */
|
|
26
|
+
export interface PortSpec {
|
|
27
|
+
/** 端口号 */
|
|
28
|
+
readonly port: number;
|
|
29
|
+
/** 监听地址;`null` = **不由本插件监听**(宿主 DSH 决定,插件只挂路由) */
|
|
30
|
+
readonly host: string | null;
|
|
31
|
+
/** 默认开关状态(未配置时的值) */
|
|
32
|
+
readonly defaultEnabled: boolean;
|
|
33
|
+
/** 语义:这个面是什么(给人看的一句话) */
|
|
34
|
+
readonly meaning: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 集中端口表。
|
|
38
|
+
* A=宿主主面(插件不监听)/ B=网关(可配,默认关)/ C=微信发送(默认开,仅 loopback)
|
|
39
|
+
* / D=Skiff 调试(默认关)/ E=ACP+问答(默认关)。
|
|
40
|
+
*/
|
|
41
|
+
export declare const FACE_PORTS: Readonly<Record<FaceId, PortSpec>>;
|
|
42
|
+
/** 宿主主 WebUI 端口(面 A:插件**不监听**,只读取;`readWebPort` 的回退值) */
|
|
43
|
+
export declare const MAIN_WEB_PORT: number;
|
|
44
|
+
/** 网关端口默认值(面 B) */
|
|
45
|
+
export declare const GATEWAY_PORT: number;
|
|
46
|
+
/** 微信主动发送端口默认值(面 C) */
|
|
47
|
+
export declare const WEIXIN_SEND_PORT: number;
|
|
48
|
+
/** Skiff 调试页端口默认值(面 D) */
|
|
49
|
+
export declare const SKIFF_DEBUG_PORT: number;
|
|
50
|
+
/** ACP / 对外问答端口默认值(面 E) */
|
|
51
|
+
export declare const ACP_HTTP_PORT: number;
|
|
52
|
+
/**
|
|
53
|
+
* **机制端口**词表(output-guard 用:agent 在**用户可见输出**里提及内部端口即打回)。
|
|
54
|
+
*
|
|
55
|
+
* 由 {@link FACE_PORTS} 机械派生 ⇒ 与面清单**永不漂移**。
|
|
56
|
+
* ⚠️ 修复记录(C4 块 B,2026-09-15):旧常量硬写 `['3080','3081','3099','3100']`
|
|
57
|
+
* ——**漏 3082**(微信发送面,默认开)⇒ 守卫拦不住"3082"这类提及。现由表派生,五面齐全。
|
|
58
|
+
*/
|
|
59
|
+
export declare const MECHANISM_PORTS: readonly string[];
|
package/lib/rebuild.d.ts
CHANGED
|
@@ -61,7 +61,7 @@ export declare function buildRebuildAnchor(root: string, sessionName: string, ac
|
|
|
61
61
|
* ≤200 字截断。空/纯空白 → null(不输出 focus 段)。防 LLM 传多行注入伪造锚点结构。
|
|
62
62
|
*/
|
|
63
63
|
export declare function sanitizeFocusLine(focus: string | null | undefined): string | null;
|
|
64
|
-
|
|
64
|
+
interface RebuildResult {
|
|
65
65
|
/** 是否成功排队(turn 结束时执行清空重建) */
|
|
66
66
|
queued: boolean;
|
|
67
67
|
/** 锚点消息文本(将在 turn 结束时注入) */
|
package/lib/seams/bootstrap.d.ts
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import type { Context } from 'cordis';
|
|
22
22
|
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
23
|
-
|
|
23
|
+
interface BootstrapSettings {
|
|
24
24
|
/** 首请求(bootstrap 阶段)工具集(缺省 dsp 核心;zeroTools 时忽略——0 工具) */
|
|
25
25
|
bootstrapTools: string[];
|
|
26
26
|
/** 晋升信号类型集合 */
|
|
@@ -59,13 +59,13 @@ export declare const DEFAULT_ANCHOR_MESSAGES: string[];
|
|
|
59
59
|
* 统一经 sessionEvents() 读取(snapshotEvents() 优先,.events 兜底)。
|
|
60
60
|
*/
|
|
61
61
|
export declare function hasUserMessageHistory(session: unknown): boolean;
|
|
62
|
-
|
|
62
|
+
interface PromotionStatus {
|
|
63
63
|
/** 最后一次 compaction/end 的 seq(-1 = 未压缩过) */
|
|
64
64
|
boundary: number;
|
|
65
65
|
/** 边界后是否存在持久晋升信号 */
|
|
66
66
|
promoted: boolean;
|
|
67
67
|
}
|
|
68
|
-
|
|
68
|
+
interface PromotionTracker {
|
|
69
69
|
status(agent: Agent | undefined): PromotionStatus;
|
|
70
70
|
observe(session: unknown, event: unknown): void;
|
|
71
71
|
}
|
|
@@ -90,3 +90,4 @@ export declare function createEpochPromotion(promoteEvents: Set<'tool/call' | 'a
|
|
|
90
90
|
* requiredSignals = 锚定轮数(2 条消息 → 2 条回复后晋升)。无参——零配置面。 */
|
|
91
91
|
export declare function resolveBootstrapSettings(): BootstrapSettings;
|
|
92
92
|
export declare function registerBootstrap(ctx: Context): void;
|
|
93
|
+
export {};
|
package/lib/seams/compact.d.ts
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* 成功判定:compaction/end 无 error。
|
|
19
19
|
*/
|
|
20
20
|
import type { Context } from 'cordis';
|
|
21
|
-
|
|
21
|
+
interface CompactRegistration {
|
|
22
22
|
/** CCC 配置相对路径;缺省用 DEFAULT_SERENITY_CONFIG_PATHS */
|
|
23
23
|
configPaths?: string[];
|
|
24
24
|
/** 入口 skill 内容注入上限(与 context.ts 对齐) */
|
|
@@ -29,3 +29,4 @@ export interface CompactRegistration {
|
|
|
29
29
|
* 仅当 agent 工作目录在 CCC 内时生效(激活门控)。
|
|
30
30
|
*/
|
|
31
31
|
export declare function registerCompactRetention(ctx: Context, opts?: CompactRegistration): void;
|
|
32
|
+
export {};
|
package/lib/seams/context.d.ts
CHANGED
|
@@ -12,9 +12,6 @@
|
|
|
12
12
|
import type { Context } from 'cordis';
|
|
13
13
|
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
14
14
|
import type { UserMessage } from '@deepseek-ai/dsh-session';
|
|
15
|
-
export declare const DEFAULT_ENTRY_SKILL_MAX_CHARS = 30000;
|
|
16
|
-
/** 从 dsh 会话日志读标题(latest-wins `session/title` 事件;无返回 null)——供标题 reconcile(U3) */
|
|
17
|
-
export declare function readDshSessionTitle(session: unknown): string | null;
|
|
18
15
|
export declare function accIdentityText(root: string, configPaths?: string[], entrySkillMaxChars?: number): string;
|
|
19
16
|
/**
|
|
20
17
|
* ACC 注入消息(S134 去重):**只含简短身份锚点**([ACC] 已激活 + CCC 根 + 约束 + handyman 模型 + Phase 2)。
|
|
@@ -38,7 +35,7 @@ export declare function shouldAutoRestore(agent: Agent): boolean;
|
|
|
38
35
|
* 避免把过去的 SESSION 上下文注入新任务(跨任务污染)。
|
|
39
36
|
*/
|
|
40
37
|
export declare function shouldRestoreActive(agent: Agent): boolean;
|
|
41
|
-
|
|
38
|
+
interface ContextRegistration {
|
|
42
39
|
configPaths?: string[];
|
|
43
40
|
/** session-start 播种 */
|
|
44
41
|
seedOnStart?: boolean;
|
|
@@ -48,3 +45,4 @@ export interface ContextRegistration {
|
|
|
48
45
|
entrySkillMaxChars?: number;
|
|
49
46
|
}
|
|
50
47
|
export declare function registerContext(ctx: Context, opts?: ContextRegistration): void;
|
|
48
|
+
export {};
|
package/lib/seams/env.d.ts
CHANGED
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import type { Context } from 'cordis';
|
|
12
12
|
import type { DshEnvironmentKey } from '@deepseek-ai/dsh-shell';
|
|
13
|
-
|
|
13
|
+
type SerenityEnvFacts = Partial<Record<DshEnvironmentKey, string>>;
|
|
14
14
|
/** 纯解析:给定 cwd,返回可注入的 DSH_SERENITY_* 事实(非 CCC 返回空) */
|
|
15
15
|
export declare function resolveSerenityEnv(cwd: string): SerenityEnvFacts;
|
|
16
16
|
export declare function registerEnv(ctx: Context): void;
|
|
17
|
+
export {};
|
package/lib/seams/guards.d.ts
CHANGED
|
@@ -21,36 +21,7 @@ export interface GuardInput {
|
|
|
21
21
|
/** 当前 agent 的 dsh 会话 id(Skiff 角色白名单判定;非 skiff 会话不判定) */
|
|
22
22
|
skiffSessionId?: string;
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
* 凭据文件硬名单(数据面守卫,v1.26.3,S142 用户:localstore.json 需要在 read 工具的黑名单里):
|
|
26
|
-
* **任何工具**(含 read/grep/glob/container_fs 只读子命令)命中这些相对 CCC 根的路径 → deny。
|
|
27
|
-
*
|
|
28
|
-
* 与 safeMode.blacklist(写黑名单,v1.18.5 决策只拦写)语义独立:
|
|
29
|
-
* - 黑名单 = 用户可配置的写保护(REPOSITORIES/ 等只读参考源不误伤读)
|
|
30
|
-
* - 凭据硬名单 = **结构性数据面边界**(不依赖 safe-mode 开关,凭据文件任何时候不可读)——
|
|
31
|
-
* 对齐 CCE Bounded Space + wardn "structural guarantee, not policy":localstore.json
|
|
32
|
-
* 含 API keys/tokens/SSH 密码,即使 prompt 纪律失败也无值可吐(机械保证)。
|
|
33
|
-
*/
|
|
34
|
-
export declare const SENSITIVE_CREDENTIAL_FILES: Set<string>;
|
|
35
|
-
/**
|
|
36
|
-
* MSM 注册表写保护(需求⑤b S142 用户拍板:"msm注册的文件需要写保护起来,避免CCC意外写坏搞崩自己"):
|
|
37
|
-
* mech-registry.json 是 CCC 执行层地基(坏 → loadMsmEntries 抛 → container_admin/output-guard 全崩,
|
|
38
|
-
* register 也崩 → 自锁)。**写 deny、读 allow**(与 localstore 读 deny 语义区分 R6——注册表是
|
|
39
|
-
* 结构核心不是秘密,需被 output-guard/skiff-admin 读取建 MSM 词表)。
|
|
40
|
-
*
|
|
41
|
-
* 单级化(需求⑤a)后**唯一合法注册表 = cccName 聚合档**
|
|
42
|
-
* `.opencode/skills/<cccName>/references/mech-registry.json`(cccName = .serenity 首行)。
|
|
43
|
-
* 历史 root 级 `mech-registry.json` 与各 skill 分散注册表已废弃:**不再保护**
|
|
44
|
-
* (review P1:保护一个永不被读的文件 = 死锁——MSM 既不可见又不可删/迁移)。
|
|
45
|
-
* 写工具命中聚合档 → deny(唯一合法写通道 = container_admin msm register/deregister
|
|
46
|
-
* 内部 writeRegistry,走工具实现不经 pre-execute → 天然豁免);读工具放行。
|
|
47
|
-
*/
|
|
48
|
-
export declare function isProtectedRegistryRel(root: string, rel: string): boolean;
|
|
49
|
-
/** 判定工具是否为读类(read/grep/glob + container_fs 只读子命令):凭据文件对读工具同样 deny */
|
|
50
|
-
export declare function isReadTool(toolName: string, action?: string): boolean;
|
|
51
|
-
/** 判定工具是否为写类:普通工具按名;container_fs 复合工具按子命令 action */
|
|
52
|
-
export declare function isWriteTool(toolName: string, action?: string): boolean;
|
|
53
|
-
export interface GuardDecisionResult {
|
|
24
|
+
interface GuardDecisionResult {
|
|
54
25
|
deny?: string;
|
|
55
26
|
kind: 'allow' | 'deny';
|
|
56
27
|
}
|
|
@@ -62,7 +33,7 @@ export interface GuardDecisionResult {
|
|
|
62
33
|
*/
|
|
63
34
|
export declare function decideGuard(input: GuardInput): GuardDecisionResult;
|
|
64
35
|
/** restrict 诊断状态(status API 暴露;排查 restrict 未生效问题) */
|
|
65
|
-
|
|
36
|
+
interface RestrictDiagnostics {
|
|
66
37
|
lastKey: string | null;
|
|
67
38
|
lastAttemptAt: string | null;
|
|
68
39
|
lastSuccess: boolean | null;
|
|
@@ -75,8 +46,6 @@ export declare function getRestrictDiagnostics(): RestrictDiagnostics;
|
|
|
75
46
|
* 标记消失 → 解除。pre-step 每步调用 → 切换实时生效。
|
|
76
47
|
*/
|
|
77
48
|
export declare function syncSafeModeRestriction(agent: Agent, root: string): void;
|
|
78
|
-
/** 条件可见的 IM 工具名(与 tools/im-bridge.ts 的注册名一致) */
|
|
79
|
-
export declare const IM_BRIDGE_TOOL_NAME = "im-bridge";
|
|
80
49
|
/** im-bridge 隐藏诊断(排查"工具为什么不在清单里") */
|
|
81
50
|
export declare function getImBridgeVisibilityDiagnostics(): {
|
|
82
51
|
hiddenKeys: string[];
|
|
@@ -95,15 +64,6 @@ export declare function getImBridgeVisibilityDiagnostics(): {
|
|
|
95
64
|
export declare function syncImBridgeVisibility(agent: Agent, root: string): void;
|
|
96
65
|
/** 会话销毁清理(lifecycle 调用;防 per-会话 Map 无界增长——review F-08 同族) */
|
|
97
66
|
export declare function forgetImBridgeVisibility(sessionId: string): void;
|
|
98
|
-
/**
|
|
99
|
-
* ACC 注册但**默认对所有 CCC 隐藏**的专属工具清单。
|
|
100
|
-
*
|
|
101
|
-
* 语义(通用机制,不绑定任何具体 CCC):只有在 CCC 的 `.opencode/serenity.json`
|
|
102
|
-
* `exclusiveTools` 里**显式声明**过的名字才可见——ACC 侧不出现 CCC 的名字(D23)。
|
|
103
|
-
* 与 im-bridge 的区别:im-bridge 是"配置了通道才可见"(能力由 CCC 配置决定),
|
|
104
|
-
* 本族是"被点名才可见"(能力归属 ACC 负责人)。
|
|
105
|
-
*/
|
|
106
|
-
export declare const EXCLUSIVE_TOOL_NAMES: readonly ["acc-diag"];
|
|
107
67
|
/** 专属工具隐藏诊断(排查"工具为什么不在清单里") */
|
|
108
68
|
export declare function getExclusiveToolsDiagnostics(): {
|
|
109
69
|
hidden: string[];
|
|
@@ -122,7 +82,7 @@ export declare function getExclusiveToolsDiagnostics(): {
|
|
|
122
82
|
export declare function syncExclusiveToolsVisibility(agent: Agent, root: string): void;
|
|
123
83
|
/** 会话销毁清理(lifecycle 调用;本函数按 `${sessionId}::` 前缀回收全部专属工具项) */
|
|
124
84
|
export declare function forgetExclusiveToolsVisibility(sessionId: string): void;
|
|
125
|
-
|
|
85
|
+
interface GuardRegistration {
|
|
126
86
|
/** 配置路径;缺省用 DEFAULT_SERENITY_CONFIG_PATHS */
|
|
127
87
|
configPaths?: string[];
|
|
128
88
|
}
|
|
@@ -131,3 +91,4 @@ export interface GuardRegistration {
|
|
|
131
91
|
* 两者都从 CCC 根实时读取配置(无状态、无缓存)。
|
|
132
92
|
*/
|
|
133
93
|
export declare function registerGuards(ctx: Context, opts?: GuardRegistration): void;
|
|
94
|
+
export {};
|
package/lib/seams/keeper.d.ts
CHANGED
|
@@ -104,7 +104,7 @@ export declare function trajectoryCompactionReminderText(input: {
|
|
|
104
104
|
mdPath: string;
|
|
105
105
|
escalated?: boolean;
|
|
106
106
|
}): string;
|
|
107
|
-
|
|
107
|
+
interface KeeperRegistration {
|
|
108
108
|
/** 缺省阈值(serenity.json sessionKeeper.threshold 优先,其次此值) */
|
|
109
109
|
defaultThreshold?: number;
|
|
110
110
|
/** CCC 配置相对路径 */
|