@dommaker/harness 1.8.0 → 1.9.0
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/CHANGELOG.md +18 -1
- package/README.md +1 -1
- package/dist/cli/commands/check.d.ts +8 -0
- package/dist/cli/commands/check.d.ts.map +1 -1
- package/dist/cli/commands/check.js +10 -11
- package/dist/cli/commands/check.js.map +1 -1
- package/dist/cli/commands/status.d.ts +8 -0
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +5 -7
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/sync-docs/capabilities-syncer.d.ts +22 -0
- package/dist/cli/commands/sync-docs/capabilities-syncer.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/capabilities-syncer.js +113 -8
- package/dist/cli/commands/sync-docs/capabilities-syncer.js.map +1 -1
- package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/index.js +36 -4
- package/dist/cli/commands/sync-docs/index.js.map +1 -1
- package/dist/cli/state-io.d.ts +34 -0
- package/dist/cli/state-io.d.ts.map +1 -0
- package/dist/cli/state-io.js +71 -0
- package/dist/cli/state-io.js.map +1 -0
- package/dist/hooks/bootstrap.d.ts +9 -12
- package/dist/hooks/bootstrap.d.ts.map +1 -1
- package/dist/hooks/bootstrap.js +9 -31
- package/dist/hooks/bootstrap.js.map +1 -1
- package/dist/hooks/index.d.ts +5 -7
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +4 -10
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/CONTEXT.md +2 -2
- package/src/__tests__/public-exports.test.ts +30 -4
- package/src/__tests__/public-type-surface.test.ts +0 -8
- package/src/cli/__tests__/state-io.test.ts +50 -0
- package/src/cli/commands/CONTEXT.md +4 -0
- package/src/cli/commands/__tests__/check-read-count.test.ts +3 -0
- package/src/cli/commands/__tests__/check.test.ts +20 -8
- package/src/cli/commands/__tests__/registry.test.ts +39 -3
- package/src/cli/commands/__tests__/status-extra.test.ts +25 -8
- package/src/cli/commands/__tests__/status.test.ts +46 -18
- package/src/cli/commands/__tests__/sync-docs-table-layout.test.ts +259 -0
- package/src/cli/commands/check.ts +20 -18
- package/src/cli/commands/status.ts +12 -7
- package/src/cli/commands/sync-docs/capabilities-syncer.ts +139 -9
- package/src/cli/commands/sync-docs/index.ts +41 -4
- package/src/cli/state-io.ts +53 -0
- package/src/hooks/CONTEXT.md +12 -22
- package/src/hooks/__tests__/bootstrap.test.ts +21 -70
- package/src/hooks/bootstrap.ts +9 -48
- package/src/hooks/index.ts +5 -20
- package/src/index.ts +1 -13
- package/dist/hooks/config.d.ts +0 -30
- package/dist/hooks/config.d.ts.map +0 -1
- package/dist/hooks/config.js +0 -34
- package/dist/hooks/config.js.map +0 -1
- package/dist/hooks/pipeline.d.ts +0 -36
- package/dist/hooks/pipeline.d.ts.map +0 -1
- package/dist/hooks/pipeline.js +0 -133
- package/dist/hooks/pipeline.js.map +0 -1
- package/dist/hooks/registry.d.ts +0 -70
- package/dist/hooks/registry.d.ts.map +0 -1
- package/dist/hooks/registry.js +0 -141
- package/dist/hooks/registry.js.map +0 -1
- package/dist/hooks/types.d.ts +0 -111
- package/dist/hooks/types.d.ts.map +0 -1
- package/dist/hooks/types.js +0 -9
- package/dist/hooks/types.js.map +0 -1
- package/src/__tests__/hooks-pipeline.test.ts +0 -201
- package/src/hooks/__tests__/config.test.ts +0 -19
- package/src/hooks/__tests__/pipeline.test.ts +0 -90
- package/src/hooks/__tests__/registry.test.ts +0 -115
- package/src/hooks/config.ts +0 -33
- package/src/hooks/pipeline.ts +0 -155
- package/src/hooks/registry.ts +0 -166
- package/src/hooks/types.ts +0 -118
package/src/hooks/registry.ts
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HookRegistry — hook 注册/注销/查询
|
|
3
|
-
*
|
|
4
|
-
* 纯簿记,无执行逻辑。线程不安全(Node.js 单线程)。
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { EffectiveHook, HookConfig, HookDefinition, HookPhase } from './types';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* 注册表闭环双向校验(H5,复制 checker 闭环模式)
|
|
11
|
-
*
|
|
12
|
-
* 声明(HookConfig,consumer 的 per-hook 配置表)↔ 实现(注册的
|
|
13
|
-
* HookDefinition)加载期双向校验,任一不满足即抛错,拒绝静默缺失:
|
|
14
|
-
* - 引用未注册 → 抛错(声明了配置但没有注册实现 = 死配置)
|
|
15
|
-
* - 注册无定义 → 抛错(注册了实现但没有配置声明 = 死代码)
|
|
16
|
-
* - 重复声明 / 重复注册 → 抛错
|
|
17
|
-
*
|
|
18
|
-
* 断言限构建/测试期调用(harness 无内置 hook 定义,加载期闭环由
|
|
19
|
-
* consumer 在其注册点/测试中调用本函数),不进入运行时热路径,
|
|
20
|
-
* 不破坏 --help/--version 懒加载。消灭「hook 定义不注册 = 死代码」
|
|
21
|
-
* 类 prompt 规矩(studio 侧随动)。
|
|
22
|
-
*
|
|
23
|
-
* @throws 任一方向不满足时抛错
|
|
24
|
-
*/
|
|
25
|
-
export function assertHookRegistryClosed<C = unknown, R = unknown>(
|
|
26
|
-
configs: readonly HookConfig[],
|
|
27
|
-
hooks: readonly HookDefinition<C, R>[]
|
|
28
|
-
): void {
|
|
29
|
-
const configNames = new Set<string>();
|
|
30
|
-
for (const config of configs) {
|
|
31
|
-
if (configNames.has(config.name)) {
|
|
32
|
-
throw new Error(
|
|
33
|
-
`[harness] hook 注册表闭环校验失败:hook 配置 "${config.name}" 重复声明。`
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
configNames.add(config.name);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const hookNames = new Set<string>();
|
|
40
|
-
for (const hook of hooks) {
|
|
41
|
-
if (hookNames.has(hook.name)) {
|
|
42
|
-
throw new Error(
|
|
43
|
-
`[harness] hook 注册表闭环校验失败:hook "${hook.name}" 重复注册。`
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
hookNames.add(hook.name);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
for (const config of configs) {
|
|
50
|
-
if (!hookNames.has(config.name)) {
|
|
51
|
-
throw new Error(
|
|
52
|
-
`[harness] hook 注册表闭环校验失败:hook 配置 "${config.name}" 引用的实现未注册。` +
|
|
53
|
-
`请注册同名 HookDefinition,或删除该配置声明。`
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
for (const hook of hooks) {
|
|
59
|
-
if (!configNames.has(hook.name)) {
|
|
60
|
-
throw new Error(
|
|
61
|
-
`[harness] hook 注册表闭环校验失败:hook "${hook.name}" 注册了实现但没有对应配置声明。` +
|
|
62
|
-
`请补齐 HookConfig 声明,或移除该实现。`
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export class HookRegistry<C = unknown, R = unknown> {
|
|
69
|
-
private hooks: Map<string, EffectiveHook<C, R>> = new Map();
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* 注册 hook(同名覆盖)
|
|
73
|
-
*
|
|
74
|
-
* 有效 `enabled` / `errorStrategy` 由 HookConfig 填充——配置表是这两个
|
|
75
|
-
* 语义的唯一声明点(#159),定义与配置名称不一致即抛错。
|
|
76
|
-
*/
|
|
77
|
-
register(hook: HookDefinition<C, R>, config: HookConfig): void {
|
|
78
|
-
if (hook.name !== config.name) {
|
|
79
|
-
throw new Error(
|
|
80
|
-
`[harness] hook 注册失败:定义 "${hook.name}" 与配置 "${config.name}" 名称不一致。`
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
this.hooks.set(hook.name, {
|
|
84
|
-
...hook,
|
|
85
|
-
enabled: config.enabled,
|
|
86
|
-
errorStrategy: config.errorStrategy,
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* 批量注册(按 name 配对配置;有实现缺配置声明即抛错)
|
|
92
|
-
*/
|
|
93
|
-
registerAll(hooks: HookDefinition<C, R>[], configs: readonly HookConfig[]): void {
|
|
94
|
-
const configByName = new Map(configs.map(c => [c.name, c]));
|
|
95
|
-
for (const hook of hooks) {
|
|
96
|
-
const config = configByName.get(hook.name);
|
|
97
|
-
if (!config) {
|
|
98
|
-
throw new Error(
|
|
99
|
-
`[harness] hook 注册失败:hook "${hook.name}" 没有对应的 HookConfig 声明。`
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
this.register(hook, config);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* 注销 hook
|
|
108
|
-
*/
|
|
109
|
-
unregister(name: string): boolean {
|
|
110
|
-
return this.hooks.delete(name);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* 获取单个 hook(含有效 enabled / errorStrategy)
|
|
115
|
-
*/
|
|
116
|
-
get(name: string): EffectiveHook<C, R> | undefined {
|
|
117
|
-
return this.hooks.get(name);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* 获取指定时机、已启用的 hook,按优先级排序
|
|
122
|
-
*/
|
|
123
|
-
getEnabled(phase: HookPhase): EffectiveHook<C, R>[] {
|
|
124
|
-
return Array.from(this.hooks.values())
|
|
125
|
-
.filter(h => h.phase === phase && h.enabled)
|
|
126
|
-
.sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* 列出所有 hook 名称
|
|
131
|
-
*/
|
|
132
|
-
listNames(): string[] {
|
|
133
|
-
return Array.from(this.hooks.keys());
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* 列出所有 hook(含禁用)
|
|
138
|
-
*/
|
|
139
|
-
listAll(): EffectiveHook<C, R>[] {
|
|
140
|
-
return Array.from(this.hooks.values());
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* 启用/禁用 hook
|
|
145
|
-
*/
|
|
146
|
-
setEnabled(name: string, enabled: boolean): boolean {
|
|
147
|
-
const hook = this.hooks.get(name);
|
|
148
|
-
if (!hook) return false;
|
|
149
|
-
hook.enabled = enabled;
|
|
150
|
-
return true;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* 清空所有 hook
|
|
155
|
-
*/
|
|
156
|
-
clear(): void {
|
|
157
|
-
this.hooks.clear();
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Hook 数量
|
|
162
|
-
*/
|
|
163
|
-
get size(): number {
|
|
164
|
-
return this.hooks.size;
|
|
165
|
-
}
|
|
166
|
-
}
|
package/src/hooks/types.ts
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hooks 类型定义
|
|
3
|
-
*
|
|
4
|
-
* 通用 hook 管线:注册、排序、错误隔离、采样。
|
|
5
|
-
* 无业务逻辑,consumer 自行定义 hook 名称和语义。
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Hook 执行时机
|
|
10
|
-
*/
|
|
11
|
-
export type HookPhase = 'before' | 'after' | 'around';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Hook 错误处理策略(有效集合:'block' | 'warn')
|
|
15
|
-
*
|
|
16
|
-
* #159 起原 'ignore' 退出有效面:策略的唯一声明点是 HookConfig(必填),
|
|
17
|
-
* 不存在「未声明 strategy」的运行时形态。
|
|
18
|
-
*/
|
|
19
|
-
export type HookErrorStrategy = 'block' | 'warn';
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Hook 配置(G7 归一后形状:consumer 侧的 per-hook 声明表)
|
|
23
|
-
*
|
|
24
|
-
* 声明与实现构成注册表闭环(assertHookRegistryClosed 双向校验):
|
|
25
|
-
* - 声明(HookConfig)是「定义」侧:引用未注册实现 → 抛错
|
|
26
|
-
* - 注册(HookDefinition)是「实现」侧:注册无对应声明 → 抛错
|
|
27
|
-
*
|
|
28
|
-
* #159 起本表是 `enabled` / `errorStrategy` 的**唯一声明点**:
|
|
29
|
-
* HookDefinition 不再携带这两个字段,有效值在注册环节由本表填充
|
|
30
|
-
* (见 EffectiveHook),声明与实现两处值矛盾在构造上不可能出现。
|
|
31
|
-
*
|
|
32
|
-
* 对应 studio 侧 per-hook 运行时配置(hooks/config.ts 的 DEFAULTS)语义:
|
|
33
|
-
* blocking:true ↔ errorStrategy 'block'(失败阻断管线),
|
|
34
|
-
* blocking:false ↔ errorStrategy 'warn'(记录警告继续)——无损映射见
|
|
35
|
-
* config.ts 的 toErrorStrategy。
|
|
36
|
-
*/
|
|
37
|
-
export interface HookConfig {
|
|
38
|
-
/** Hook 唯一名称(须与注册的 HookDefinition.name 一致) */
|
|
39
|
-
name: string;
|
|
40
|
-
/** 是否启用(false 时不进入管线) */
|
|
41
|
-
enabled: boolean;
|
|
42
|
-
/** 错误策略:block=失败阻断管线,warn=记录警告继续 */
|
|
43
|
-
errorStrategy: HookErrorStrategy;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Hook 定义
|
|
48
|
-
*
|
|
49
|
-
* Consumer 自行选择 name(如 'beforeAgentExecute'),harness 只提供管线。
|
|
50
|
-
* `enabled` / `errorStrategy` 不在此处声明——唯一声明点是 HookConfig(#159)。
|
|
51
|
-
*/
|
|
52
|
-
export interface HookDefinition<C = unknown, R = unknown> {
|
|
53
|
-
/** Hook 唯一名称(consumer 定义语义) */
|
|
54
|
-
name: string;
|
|
55
|
-
/** 执行时机 */
|
|
56
|
-
phase: HookPhase;
|
|
57
|
-
/** 优先级(越小越先执行,默认 100) */
|
|
58
|
-
priority?: number;
|
|
59
|
-
/** 采样率 0-1(1=100% 执行,0.1=10% 采样) */
|
|
60
|
-
sampleRate?: number;
|
|
61
|
-
/** Hook 执行函数 */
|
|
62
|
-
execute: (context: C) => Promise<HookResult<R>>;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* 有效 hook = HookDefinition + 注册环节由 HookConfig 填充的有效值
|
|
67
|
-
*
|
|
68
|
-
* 管线与注册表的判定(启用过滤、block/warn 分派)只读本类型,
|
|
69
|
-
* 值来源单一(HookConfig),不存在第二声明点。
|
|
70
|
-
*/
|
|
71
|
-
export interface EffectiveHook<C = unknown, R = unknown> extends HookDefinition<C, R> {
|
|
72
|
-
/** 是否启用(来自 HookConfig.enabled) */
|
|
73
|
-
enabled: boolean;
|
|
74
|
-
/** 错误策略(来自 HookConfig.errorStrategy) */
|
|
75
|
-
errorStrategy: HookErrorStrategy;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Hook 执行结果
|
|
80
|
-
*/
|
|
81
|
-
export interface HookResult<R = unknown> {
|
|
82
|
-
/** 是否通过(blocking hook 必须返回 false 才阻断) */
|
|
83
|
-
passed: boolean;
|
|
84
|
-
/** 结果数据 */
|
|
85
|
-
data?: R;
|
|
86
|
-
/** 错误信息 */
|
|
87
|
-
error?: string;
|
|
88
|
-
/** 元数据(consumer 自行定义) */
|
|
89
|
-
metadata?: Record<string, unknown>;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Hook 执行记录
|
|
94
|
-
*/
|
|
95
|
-
export interface HookExecutionRecord {
|
|
96
|
-
hookName: string;
|
|
97
|
-
phase: HookPhase;
|
|
98
|
-
startedAt: number;
|
|
99
|
-
completedAt: number;
|
|
100
|
-
durationMs: number;
|
|
101
|
-
passed: boolean;
|
|
102
|
-
error?: string;
|
|
103
|
-
sampled?: boolean;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* 管线执行结果
|
|
108
|
-
*/
|
|
109
|
-
export interface PipelineResult {
|
|
110
|
-
/** 是否全部通过(blocking hook 任一失败 = false) */
|
|
111
|
-
passed: boolean;
|
|
112
|
-
/** 各 hook 执行记录 */
|
|
113
|
-
records: HookExecutionRecord[];
|
|
114
|
-
/** 失败的 blocking hook 名称列表 */
|
|
115
|
-
blockedBy: string[];
|
|
116
|
-
/** 警告 hook 名称列表 */
|
|
117
|
-
warnings: string[];
|
|
118
|
-
}
|