@webskill/sdk 0.6.0 → 0.8.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/dist/agent.d.ts +2 -2
- package/dist/agent.js +218 -28
- package/dist/browser.d.ts +177 -4
- package/dist/browser.js +444 -35
- package/dist/{catalogComponents-Dr5dFMAb-Dacibl1e.js → catalogComponents-DfxxfUvn-D55Gbb2l.js} +4016 -1226
- package/dist/{dist-8oQRa8Xz.js → dist-59XlqDuv.js} +93 -6
- package/dist/{dist-DnYG2-eY.js → dist-CJqQsIm9.js} +498 -118
- package/dist/{dist-DusANsrn.js → dist-DmI5SBBF.js} +437 -55
- package/dist/eventTypes-g1BXL6x5-CibcOftR.js +37 -0
- package/dist/governance.d.ts +91 -11
- package/dist/governance.js +194 -52
- package/dist/{index-C-KFAZoF.d.ts → index-K-eewlGL.d.ts} +176 -75
- package/dist/{index-BMocOEi0.d.ts → index-P9J2LTfU.d.ts} +163 -6
- package/dist/{index-BuTpBMzr.d.ts → index-fLskQfAS.d.ts} +156 -5
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -4
- package/dist/mcp.d.ts +129 -6
- package/dist/mcp.js +235 -28
- package/dist/{memoryArtifactStore-52Zn9npI-BMPYwvoy.js → memoryArtifactStore-52Zn9npI-upv5OWYf.js} +1 -1
- package/dist/node.d.ts +3 -3
- package/dist/node.js +4 -3
- package/dist/{openUiLibrary-Bdrji9qK-DzAxRlTY.js → openUiLibrary-DURlAxjk-CU6AzfSW.js} +3 -3
- package/dist/{skillVersionStore-BzLbzFOL-CxdAFWO2.d.ts → skillVersionStore-Bl-ElD45-gRfSaAby.d.ts} +8 -2
- package/dist/{testing-CYTFqkDm.js → testing-BCUO5gZR.js} +2 -2
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +2 -2
- package/dist/{types-4pg-qp_I-Gq63X8Oa.d.ts → types-B3n0cMZu-BdcqQ35O.d.ts} +74 -7
- package/dist/ui-react.d.ts +16 -7
- package/dist/ui-react.js +159 -108
- package/dist/ui-vue.d.ts +1 -1
- package/dist/ui-vue.js +2 -2
- package/dist/ui.d.ts +4 -4
- package/dist/ui.js +3 -3
- package/dist/{webskillLitCatalog-_mugzRHx-B_54vxum.js → webskillLitCatalog-DwTwSBFt-DiXXpNZA.js} +22 -3
- package/package.json +2 -2
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//#region ../governance/dist/eventTypes-g1BXL6x5.js
|
|
2
|
+
/**
|
|
3
|
+
* 审计事件类型常量(FR-13.4)。
|
|
4
|
+
*
|
|
5
|
+
* 存在的理由是**消灭调用点的字面量**:写入点分散在 governance 与 console 的十来个文件里,
|
|
6
|
+
* 字面量拼错不会有任何编译期反馈,只会在审计里留下一条永远查不到的记录。
|
|
7
|
+
*
|
|
8
|
+
* `AuditEvent.type` 刻意**保持 `string`**、不收窄为 `AuditEventType`——
|
|
9
|
+
* 收窄会让外部写入方(插件、其它宿主)无法追加自定义类型,且会立刻产生快照差异。
|
|
10
|
+
*/
|
|
11
|
+
const AUDIT_EVENT_TYPES = {
|
|
12
|
+
skillEdited: "skill.edited",
|
|
13
|
+
skillRolledBack: "skill.rolled_back",
|
|
14
|
+
skillPublished: "skill.published",
|
|
15
|
+
skillRepairApplied: "skill.repair_applied",
|
|
16
|
+
skillQuarantined: "skill.quarantined",
|
|
17
|
+
skillPolicyDenied: "skill.policy_denied",
|
|
18
|
+
skillUninstalled: "skill.uninstalled",
|
|
19
|
+
skillInstalled: "skill.installed",
|
|
20
|
+
trustKeyAdded: "trust.key_added",
|
|
21
|
+
trustKeyRemoved: "trust.key_removed",
|
|
22
|
+
policyNetworkChanged: "policy.network_changed",
|
|
23
|
+
policyPrivacyChanged: "policy.privacy_changed",
|
|
24
|
+
policySecurityChanged: "policy.security_changed",
|
|
25
|
+
policySandboxChanged: "policy.sandbox_changed",
|
|
26
|
+
policyAgentCapabilitiesChanged: "policy.agent_capabilities_changed",
|
|
27
|
+
profileChanged: "profile.changed",
|
|
28
|
+
mcpEndpointChanged: "mcp.endpoint_changed",
|
|
29
|
+
mcpPolicyRelaxed: "mcp.policy_relaxed",
|
|
30
|
+
providerChanged: "provider.changed",
|
|
31
|
+
candidateGenerated: "candidate.generated"
|
|
32
|
+
};
|
|
33
|
+
/** 稳定展示序:筛选下拉与文档表格都从这里取,不各自维护一份顺序 */
|
|
34
|
+
const AUDIT_EVENT_TYPE_LIST = Object.values(AUDIT_EVENT_TYPES);
|
|
35
|
+
|
|
36
|
+
//#endregion
|
|
37
|
+
export { AUDIT_EVENT_TYPE_LIST as n, AUDIT_EVENT_TYPES as t };
|
package/dist/governance.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { _ as SkillVersion, a as AuditLog, c as CandidateFile, d as CandidateSource, f as CandidateStatus, g as SkillState, h as SKILL_VERSION_PAGE_SIZE, i as AuditEvent, l as CandidateRisk, m as CompositeApprovalPolicy, n as ApprovalDecision, o as AuditQueryFilter, p as CandidateStore, r as ApprovalPolicy, s as CANDIDATE_PAGE_SIZE, t as AlwaysHumanApprovalPolicy, u as CandidateSkill, v as SkillVersionStore, y as candidateToCatalogEntry } from "./skillVersionStore-
|
|
1
|
+
import { H as PageQuery, I as FileSystemProvider, V as Page, ct as SkillManagerPort, f as LlmMessage, it as SkillDocument, l as LlmClient, nt as SkillCatalogEntry, x as UiBridge } from "./types-B3n0cMZu-BdcqQ35O.js";
|
|
2
|
+
import { H as IntegrityVerdict, It as SkillIntegrityGuard, Lt as SkillOutcomeReporter, Vt as SkillStateGuard, bt as RuntimeRun, pn as WebSkillRuntime } from "./index-K-eewlGL.js";
|
|
3
|
+
import { _ as SkillVersion, a as AuditLog, c as CandidateFile, d as CandidateSource, f as CandidateStatus, g as SkillState, h as SKILL_VERSION_PAGE_SIZE, i as AuditEvent, l as CandidateRisk, m as CompositeApprovalPolicy, n as ApprovalDecision, o as AuditQueryFilter, p as CandidateStore, r as ApprovalPolicy, s as CANDIDATE_PAGE_SIZE, t as AlwaysHumanApprovalPolicy, u as CandidateSkill, v as SkillVersionStore, y as candidateToCatalogEntry } from "./skillVersionStore-Bl-ElD45-gRfSaAby.js";
|
|
4
4
|
//#region ../governance/dist/index.d.ts
|
|
5
5
|
//#region src/candidate/candidateNormalizer.d.ts
|
|
6
6
|
/** 剥 markdown fence 与 <think> 块、截取首尾 {};非对象 → CANDIDATE_INVALID */
|
|
@@ -99,12 +99,37 @@ interface AuditChainVerification {
|
|
|
99
99
|
/** 首个断链位置(行号,0 起;ok 时 undefined) */
|
|
100
100
|
brokenAt?: number;
|
|
101
101
|
reason?: string;
|
|
102
|
+
/** 已扫描的记录总数(无论成败都给,便于判断断点在全链中的位置) */
|
|
103
|
+
total?: number;
|
|
104
|
+
/** 断点前一条的 ts(断点在首行时缺失) */
|
|
105
|
+
brokenBeforeTs?: string;
|
|
106
|
+
/** 断点所在记录的 ts(该行不可解析时缺失) */
|
|
107
|
+
brokenAfterTs?: string;
|
|
108
|
+
}
|
|
109
|
+
/** 带断链报告的分页结果(`tolerateBrokenChain` 打开时才可能带上后两个字段) */
|
|
110
|
+
interface AuditPage extends Page<AuditEvent> {
|
|
111
|
+
chainBrokenAt?: number;
|
|
112
|
+
chainReason?: string;
|
|
113
|
+
/**
|
|
114
|
+
* 解析失败的行。长度 > 0 即「读不动」,但已解析的记录仍在 `items` 里——
|
|
115
|
+
* 不给这个字段的话,坏行被吞掉后的返回值与「真的没有事件」完全一样(FR-18.3)。
|
|
116
|
+
*/
|
|
117
|
+
malformed?: {
|
|
118
|
+
count: number;
|
|
119
|
+
firstLine: number;
|
|
120
|
+
};
|
|
102
121
|
}
|
|
103
122
|
/**
|
|
104
123
|
* JSONL 追加式审计日志(<managedRoot>/.webskill/audit.jsonl):
|
|
105
|
-
* 真追加(fs.appendText,不整读改写)+ lastHash
|
|
124
|
+
* 真追加(fs.appendText,不整读改写)+ lastHash 缓存(仅当文件字节数未变时可用)。
|
|
106
125
|
* 语义:**tamper-evident, not tamper-proof**——verifyChain 能检出篡改/删除/换序,
|
|
107
126
|
* 但不阻止有写权限者直接改写文件;更强保证需要签名信任体系(未排期)。
|
|
127
|
+
*
|
|
128
|
+
* **并发边界**:追加的串行化只在**同一进程内**成立(模块级 mutex)。
|
|
129
|
+
* 跨进程 / 跨标签页靠的是「写前用 `stat().size` 重新确认链尾」:
|
|
130
|
+
* 外部写入会改变字节数,后写者因此会重读链尾而不会分叉——
|
|
131
|
+
* 除非两个进程落在同一个 stat/append 窗口内。真正的跨进程互斥需要文件锁,
|
|
132
|
+
* `FileSystemProvider` 不提供,不在本版承诺范围。
|
|
108
133
|
*/
|
|
109
134
|
declare class FsAuditLog implements AuditLog {
|
|
110
135
|
#private;
|
|
@@ -126,11 +151,47 @@ declare class FsAuditLog implements AuditLog {
|
|
|
126
151
|
* 任一处对不上以 `GOVERNANCE_FAILED` 报错。范围之外的断链不在本方法职责内——
|
|
127
152
|
* 那是 `verifyChain()` 的事(全量 O(N) 校验不该压在每次翻页上)。
|
|
128
153
|
*/
|
|
129
|
-
query(filter?: AuditQueryFilter & PageQuery): Promise<
|
|
130
|
-
/** hash 链完整性校验:逐行重算 hash 并核对 prevHash
|
|
154
|
+
query(filter?: AuditQueryFilter & PageQuery): Promise<AuditPage>;
|
|
155
|
+
/** hash 链完整性校验:逐行重算 hash 并核对 prevHash 链接。**只读**,绝不改写历史 */
|
|
131
156
|
verifyChain(): Promise<AuditChainVerification>;
|
|
132
157
|
}
|
|
133
158
|
//#endregion
|
|
159
|
+
//#region src/audit/eventTypes.d.ts
|
|
160
|
+
/**
|
|
161
|
+
* 审计事件类型常量(FR-13.4)。
|
|
162
|
+
*
|
|
163
|
+
* 存在的理由是**消灭调用点的字面量**:写入点分散在 governance 与 console 的十来个文件里,
|
|
164
|
+
* 字面量拼错不会有任何编译期反馈,只会在审计里留下一条永远查不到的记录。
|
|
165
|
+
*
|
|
166
|
+
* `AuditEvent.type` 刻意**保持 `string`**、不收窄为 `AuditEventType`——
|
|
167
|
+
* 收窄会让外部写入方(插件、其它宿主)无法追加自定义类型,且会立刻产生快照差异。
|
|
168
|
+
*/
|
|
169
|
+
declare const AUDIT_EVENT_TYPES: {
|
|
170
|
+
readonly skillEdited: "skill.edited";
|
|
171
|
+
readonly skillRolledBack: "skill.rolled_back";
|
|
172
|
+
readonly skillPublished: "skill.published";
|
|
173
|
+
readonly skillRepairApplied: "skill.repair_applied";
|
|
174
|
+
readonly skillQuarantined: "skill.quarantined";
|
|
175
|
+
readonly skillPolicyDenied: "skill.policy_denied";
|
|
176
|
+
readonly skillUninstalled: "skill.uninstalled";
|
|
177
|
+
readonly skillInstalled: "skill.installed";
|
|
178
|
+
readonly trustKeyAdded: "trust.key_added";
|
|
179
|
+
readonly trustKeyRemoved: "trust.key_removed";
|
|
180
|
+
readonly policyNetworkChanged: "policy.network_changed";
|
|
181
|
+
readonly policyPrivacyChanged: "policy.privacy_changed";
|
|
182
|
+
readonly policySecurityChanged: "policy.security_changed";
|
|
183
|
+
readonly policySandboxChanged: "policy.sandbox_changed";
|
|
184
|
+
readonly policyAgentCapabilitiesChanged: "policy.agent_capabilities_changed";
|
|
185
|
+
readonly profileChanged: "profile.changed";
|
|
186
|
+
readonly mcpEndpointChanged: "mcp.endpoint_changed";
|
|
187
|
+
readonly mcpPolicyRelaxed: "mcp.policy_relaxed";
|
|
188
|
+
readonly providerChanged: "provider.changed";
|
|
189
|
+
readonly candidateGenerated: "candidate.generated";
|
|
190
|
+
};
|
|
191
|
+
type AuditEventType = (typeof AUDIT_EVENT_TYPES)[keyof typeof AUDIT_EVENT_TYPES];
|
|
192
|
+
/** 稳定展示序:筛选下拉与文档表格都从这里取,不各自维护一份顺序 */
|
|
193
|
+
declare const AUDIT_EVENT_TYPE_LIST: readonly AuditEventType[];
|
|
194
|
+
//#endregion
|
|
134
195
|
//#region src/repair/failureAnalyzer.d.ts
|
|
135
196
|
interface FailureDiagnosis {
|
|
136
197
|
cause: string;
|
|
@@ -173,6 +234,17 @@ declare class RepairPlanner {
|
|
|
173
234
|
}
|
|
174
235
|
//#endregion
|
|
175
236
|
//#region src/state/skillStatePolicy.d.ts
|
|
237
|
+
/**
|
|
238
|
+
* 用户策略主动拒绝的错误码(FR-12.4):这是配置生效的证据,不是技能有问题,不计入隔离阈值。
|
|
239
|
+
*
|
|
240
|
+
* 集中在这一份常量里而不散在条件判断里,是为了让「哪些码不计数」只有一个事实源。
|
|
241
|
+
*/
|
|
242
|
+
declare const POLICY_DENIAL_CODES: ReadonlySet<string>;
|
|
243
|
+
/** 自动隔离的原因判别式(FR-12.6);人工隔离仍写自由文本 */
|
|
244
|
+
declare const QUARANTINE_REASONS: {
|
|
245
|
+
readonly integrity: "integrity";
|
|
246
|
+
readonly failures: "failures";
|
|
247
|
+
};
|
|
176
248
|
/**
|
|
177
249
|
* 降级治理:states.json 持久化;失败达阈值 → quarantined;
|
|
178
250
|
* canRoute 仅 active;canExecute active|deprecated;disabled 执行抛 SKILL_DISABLED;
|
|
@@ -191,15 +263,22 @@ declare class SkillStatePolicy {
|
|
|
191
263
|
setState(skillName: string, state: SkillState, input: {
|
|
192
264
|
actor?: string;
|
|
193
265
|
reason?: string;
|
|
266
|
+
detail?: string;
|
|
194
267
|
}): Promise<void>;
|
|
195
268
|
/**
|
|
196
269
|
* 失败计数;达阈值(默认 3)→ quarantined + 审计。
|
|
197
270
|
*
|
|
198
|
-
*
|
|
271
|
+
* 计数是**连续**而非累计(0.7.0 FR-12.5):一次成功执行经 `clearFailures` 归零,
|
|
272
|
+
* `setState(name, 'active')` 同样清零。
|
|
199
273
|
*/
|
|
200
274
|
recordFailure(skillName: string, input?: {
|
|
201
275
|
actor?: string;
|
|
202
276
|
}): Promise<SkillState>;
|
|
277
|
+
/**
|
|
278
|
+
* 成功清零(FR-12.5)。不写审计(成功是常态,写了会把审计流淹掉),
|
|
279
|
+
* 也**不改变 state**——已隔离的技能不会因一次成功自动解除。
|
|
280
|
+
*/
|
|
281
|
+
clearFailures(skillName: string): Promise<void>;
|
|
203
282
|
canRoute(state: SkillState): boolean;
|
|
204
283
|
canExecute(state: SkillState): boolean;
|
|
205
284
|
/**
|
|
@@ -221,17 +300,18 @@ declare class SkillStatePolicy {
|
|
|
221
300
|
toSkillIntegrityGuard(verify: (skillName: string) => Promise<IntegrityVerdict>): SkillIntegrityGuard;
|
|
222
301
|
/**
|
|
223
302
|
* runtime `SkillOutcomeReporter` 适配(F1):一次真实的技能脚本执行失败 → `recordFailure`,
|
|
224
|
-
* 达阈值即自动 `quarantined` +
|
|
303
|
+
* 达阈值即自动 `quarantined` + 写审计;一次成功 → `clearFailures`。
|
|
225
304
|
*
|
|
226
305
|
* 0.4.0 之前 `recordFailure` 没有任何生产调用方——`states.json` 的失败计数只在单测里增长,
|
|
227
306
|
* 于是「失败达阈值自动隔离」在真实部署里从不触发,Console 上那个计数恒为 0。
|
|
228
307
|
* 这个适配器就是把那一段接上:runtime 不能反向依赖治理,装配点只能在宿主。
|
|
229
308
|
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
309
|
+
* 策略拒绝的分流放在这里而不是 `recordFailure`:后者是**治理动作**(管理员也可手工调用),
|
|
310
|
+
* 它不该知道运行时错误码;判定“这次失败算不算技能的错”是**上报侧**的语义。
|
|
232
311
|
*/
|
|
233
312
|
toSkillOutcomeReporter(input?: {
|
|
234
313
|
actor?: string;
|
|
314
|
+
policyDenialCodes?: ReadonlySet<string>;
|
|
235
315
|
}): SkillOutcomeReporter;
|
|
236
316
|
/** disabled → SKILL_DISABLED;quarantined → SKILL_QUARANTINED */
|
|
237
317
|
assertExecutable(skillName: string): Promise<void>;
|
|
@@ -405,4 +485,4 @@ declare function createMissHook(deps: {
|
|
|
405
485
|
*/
|
|
406
486
|
declare function completeText(llm: LlmClient, messages: LlmMessage[]): Promise<string>;
|
|
407
487
|
//#endregion
|
|
408
|
-
export { AUDIT_PAGE_SIZE, AlwaysHumanApprovalPolicy, type ApprovalDecision, type ApprovalPolicy, type AuditEvent, type AuditLog, type AuditQueryFilter, CANDIDATE_PAGE_SIZE, type CandidateFile, type CandidateRisk, type CandidateSink, type CandidateSinkOptions, type CandidateSkill, type CandidateSource, type CandidateStatus, CandidateStore, CompositeApprovalPolicy, DependencyGraph, DocumentSkillExtractor, type EvaluationReport, type EvaluationResult, EvaluationRunner, type EvaluationTask, FailureAnalyzer, type FailureDiagnosis, FsAuditLog, type GeneratedSkillSubmission, LlmCandidateGenerator, type RepairOption, RepairPlanner, SCORING_WEIGHTS, SKILL_VERSION_PAGE_SIZE, type ScoreInput, SimilarityDetector, SkillScorer, type SkillState, SkillStatePolicy, type SkillVersion, SkillVersionStore, type SourceDocument, candidateToCatalogEntry, completeText, createCandidateSink, createMissHook, jaccardSimilarity, normalizeCandidate, normalizeCandidateFiles, normalizeRisk, parseJsonObject, readDocument, sanitizeCandidateName, suggestFromFailedRun, validateCandidate };
|
|
488
|
+
export { AUDIT_EVENT_TYPES, AUDIT_EVENT_TYPE_LIST, AUDIT_PAGE_SIZE, AlwaysHumanApprovalPolicy, type ApprovalDecision, type ApprovalPolicy, type AuditChainVerification, type AuditEvent, type AuditEventType, type AuditLog, type AuditPage, type AuditQueryFilter, CANDIDATE_PAGE_SIZE, type CandidateFile, type CandidateRisk, type CandidateSink, type CandidateSinkOptions, type CandidateSkill, type CandidateSource, type CandidateStatus, CandidateStore, CompositeApprovalPolicy, DependencyGraph, DocumentSkillExtractor, type EvaluationReport, type EvaluationResult, EvaluationRunner, type EvaluationTask, FailureAnalyzer, type FailureDiagnosis, FsAuditLog, type GeneratedSkillSubmission, LlmCandidateGenerator, POLICY_DENIAL_CODES, QUARANTINE_REASONS, type RepairOption, RepairPlanner, SCORING_WEIGHTS, SKILL_VERSION_PAGE_SIZE, type ScoreInput, SimilarityDetector, SkillScorer, type SkillState, SkillStatePolicy, type SkillVersion, SkillVersionStore, type SourceDocument, candidateToCatalogEntry, completeText, createCandidateSink, createMissHook, jaccardSimilarity, normalizeCandidate, normalizeCandidateFiles, normalizeRisk, parseJsonObject, readDocument, sanitizeCandidateName, suggestFromFailedRun, validateCandidate };
|
package/dist/governance.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as textParts, n as partsToText } from "./memoryArtifactStore-52Zn9npI-
|
|
1
|
+
import { A as messageOf, D as isValidSkillName, g as assertSafePathSegment, m as WebSkillError } from "./dist-59XlqDuv.js";
|
|
2
|
+
import { a as textParts, n as partsToText } from "./memoryArtifactStore-52Zn9npI-upv5OWYf.js";
|
|
3
|
+
import { n as AUDIT_EVENT_TYPE_LIST, t as AUDIT_EVENT_TYPES } from "./eventTypes-g1BXL6x5-CibcOftR.js";
|
|
3
4
|
|
|
4
5
|
//#region ../governance/dist/index.js
|
|
5
6
|
const invalid = (message, details) => {
|
|
@@ -331,19 +332,32 @@ function canonical(event) {
|
|
|
331
332
|
});
|
|
332
333
|
}
|
|
333
334
|
/**
|
|
335
|
+
* 同一进程内按审计文件路径共享的链式 mutex。
|
|
336
|
+
* 跟着实例走不行:本类允许多实例指向同一个 root,而交错追加正是分叉的来源。
|
|
337
|
+
*/
|
|
338
|
+
const APPEND_LOCKS = /* @__PURE__ */ new Map();
|
|
339
|
+
/**
|
|
334
340
|
* JSONL 追加式审计日志(<managedRoot>/.webskill/audit.jsonl):
|
|
335
|
-
* 真追加(fs.appendText,不整读改写)+ lastHash
|
|
341
|
+
* 真追加(fs.appendText,不整读改写)+ lastHash 缓存(仅当文件字节数未变时可用)。
|
|
336
342
|
* 语义:**tamper-evident, not tamper-proof**——verifyChain 能检出篡改/删除/换序,
|
|
337
343
|
* 但不阻止有写权限者直接改写文件;更强保证需要签名信任体系(未排期)。
|
|
344
|
+
*
|
|
345
|
+
* **并发边界**:追加的串行化只在**同一进程内**成立(模块级 mutex)。
|
|
346
|
+
* 跨进程 / 跨标签页靠的是「写前用 `stat().size` 重新确认链尾」:
|
|
347
|
+
* 外部写入会改变字节数,后写者因此会重读链尾而不会分叉——
|
|
348
|
+
* 除非两个进程落在同一个 stat/append 窗口内。真正的跨进程互斥需要文件锁,
|
|
349
|
+
* `FileSystemProvider` 不提供,不在本版承诺范围。
|
|
338
350
|
*/
|
|
339
351
|
var FsAuditLog = class {
|
|
340
352
|
#root;
|
|
341
353
|
#fs;
|
|
342
354
|
#now;
|
|
343
355
|
#createId;
|
|
344
|
-
/** lastHash
|
|
356
|
+
/** lastHash 内存缓存(仅当 #lastKnownSize 与当前文件字节数相等时才作数) */
|
|
345
357
|
#lastHash;
|
|
346
358
|
#lastHashSeeded = false;
|
|
359
|
+
/** 本实例最后一次写入后观察到的文件字节数 */
|
|
360
|
+
#lastKnownSize;
|
|
347
361
|
constructor(deps) {
|
|
348
362
|
this.#root = deps.root.replace(/\/+$/, "");
|
|
349
363
|
this.#fs = deps.fs;
|
|
@@ -354,8 +368,13 @@ var FsAuditLog = class {
|
|
|
354
368
|
async #seedLastHash() {
|
|
355
369
|
this.#lastHashSeeded = true;
|
|
356
370
|
const path = fileOf$1(this.#root);
|
|
357
|
-
if (!await this.#fs.exists(path))
|
|
358
|
-
|
|
371
|
+
if (!await this.#fs.exists(path)) {
|
|
372
|
+
this.#lastKnownSize = void 0;
|
|
373
|
+
return "GENESIS";
|
|
374
|
+
}
|
|
375
|
+
const text = await this.#fs.readText(path);
|
|
376
|
+
this.#lastKnownSize = await this.#fileSize();
|
|
377
|
+
const lines = text.split("\n").filter((l) => l.trim() !== "");
|
|
359
378
|
if (lines.length === 0) return "GENESIS";
|
|
360
379
|
try {
|
|
361
380
|
const last = JSON.parse(lines.at(-1));
|
|
@@ -364,21 +383,50 @@ var FsAuditLog = class {
|
|
|
364
383
|
throw new WebSkillError("GOVERNANCE_FAILED", `Audit log tail line at ${path} is corrupted; refusing to append (the chain must not silently restart)`, e);
|
|
365
384
|
}
|
|
366
385
|
}
|
|
386
|
+
/** 当前字节数;文件不存在、提供方不报 size 或 stat 抛错时统一返回 undefined */
|
|
387
|
+
async #fileSize() {
|
|
388
|
+
try {
|
|
389
|
+
return (await this.#fs.stat(fileOf$1(this.#root))).size;
|
|
390
|
+
} catch {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* 追加前解析链尾(FR-13.1)。
|
|
396
|
+
* 缓存只在「文件字节数与本实例上次写后一致」时才作数;
|
|
397
|
+
* 拿不到 size 就无条件重读——不把「大概没变」当正确性依据。
|
|
398
|
+
*/
|
|
399
|
+
async #resolvePrevHash() {
|
|
400
|
+
if (!this.#lastHashSeeded) return this.#seedLastHash();
|
|
401
|
+
const size = await this.#fileSize();
|
|
402
|
+
if (size === void 0 || size !== this.#lastKnownSize) return this.#seedLastHash();
|
|
403
|
+
return this.#lastHash;
|
|
404
|
+
}
|
|
405
|
+
/** 同一审计文件上的追加串行化(前一个失败也要继续排队) */
|
|
406
|
+
async #withAppendLock(work) {
|
|
407
|
+
const path = fileOf$1(this.#root);
|
|
408
|
+
const next = (APPEND_LOCKS.get(path) ?? Promise.resolve()).then(work, work);
|
|
409
|
+
APPEND_LOCKS.set(path, next.catch(() => void 0));
|
|
410
|
+
return next;
|
|
411
|
+
}
|
|
367
412
|
async append(event) {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
413
|
+
return this.#withAppendLock(async () => {
|
|
414
|
+
const prevHash = await this.#resolvePrevHash();
|
|
415
|
+
const full = {
|
|
416
|
+
id: event.id ?? this.#createId?.() ?? `audit-${Math.random().toString(36).slice(2, 10)}`,
|
|
417
|
+
ts: event.ts ?? this.#now?.() ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
418
|
+
type: event.type,
|
|
419
|
+
target: event.target,
|
|
420
|
+
...event.actor !== void 0 ? { actor: event.actor } : {},
|
|
421
|
+
...event.data !== void 0 ? { data: event.data } : {},
|
|
422
|
+
prevHash
|
|
423
|
+
};
|
|
424
|
+
full.hash = await sha256Hex$1(canonical(full));
|
|
425
|
+
await this.#fs.appendText(fileOf$1(this.#root), `${JSON.stringify(full)}\n`);
|
|
426
|
+
this.#lastHash = full.hash;
|
|
427
|
+
this.#lastKnownSize = await this.#fileSize();
|
|
428
|
+
return full;
|
|
429
|
+
});
|
|
382
430
|
}
|
|
383
431
|
/**
|
|
384
432
|
* 分页 + 筛选下推。整文件读仍在(JSONL 布局未改,备案 D25),
|
|
@@ -395,15 +443,21 @@ var FsAuditLog = class {
|
|
|
395
443
|
/** 按文件行序保留(含解析失败的洞):链校验必须在文件行序上做,不能在筛选结果上做 */
|
|
396
444
|
const records = [];
|
|
397
445
|
let skippedLines = 0;
|
|
446
|
+
let firstMalformedLine = -1;
|
|
398
447
|
for (const line of raw.split("\n")) {
|
|
399
448
|
if (line.trim() === "") continue;
|
|
400
449
|
try {
|
|
401
450
|
records.push(JSON.parse(line));
|
|
402
451
|
} catch {
|
|
452
|
+
if (firstMalformedLine < 0) firstMalformedLine = records.length;
|
|
403
453
|
skippedLines += 1;
|
|
404
454
|
records.push(void 0);
|
|
405
455
|
}
|
|
406
456
|
}
|
|
457
|
+
const malformed = skippedLines > 0 ? {
|
|
458
|
+
count: skippedLines,
|
|
459
|
+
firstLine: firstMalformedLine
|
|
460
|
+
} : void 0;
|
|
407
461
|
if (skippedLines > 0) console.warn(`[webskill] Audit log at ${path} contains ${skippedLines} unparsable line(s) skipped by query; run verifyChain() to check integrity`);
|
|
408
462
|
const matched = [];
|
|
409
463
|
for (let i = 0; i < records.length; i++) {
|
|
@@ -425,29 +479,48 @@ var FsAuditLog = class {
|
|
|
425
479
|
}
|
|
426
480
|
const start = Math.max(0, end - limit);
|
|
427
481
|
const items = [];
|
|
482
|
+
let broken;
|
|
428
483
|
for (const line of matched.slice(start, end)) {
|
|
429
484
|
const event = records[line];
|
|
430
|
-
await this.#
|
|
485
|
+
const failure = await this.#chainFailureAt(records, line);
|
|
486
|
+
if (failure !== void 0) {
|
|
487
|
+
if (filter.tolerateBrokenChain !== true) throw new WebSkillError("GOVERNANCE_FAILED", `Audit chain is broken at line ${line} of ${path}: ${failure}`);
|
|
488
|
+
broken ??= {
|
|
489
|
+
at: line,
|
|
490
|
+
reason: failure
|
|
491
|
+
};
|
|
492
|
+
break;
|
|
493
|
+
}
|
|
431
494
|
items.push(event);
|
|
432
495
|
}
|
|
433
496
|
return {
|
|
434
497
|
items,
|
|
435
|
-
...start > 0 ? { nextCursor: String(start) } : {}
|
|
498
|
+
...start > 0 ? { nextCursor: String(start) } : {},
|
|
499
|
+
...broken !== void 0 ? {
|
|
500
|
+
chainBrokenAt: broken.at,
|
|
501
|
+
chainReason: broken.reason
|
|
502
|
+
} : {},
|
|
503
|
+
...malformed !== void 0 ? { malformed } : {}
|
|
436
504
|
};
|
|
437
505
|
}
|
|
438
|
-
/** 单行的链自洽:本行 hash 重算相符,且 prevHash 指向前一行的 hash */
|
|
439
|
-
async #
|
|
506
|
+
/** 单行的链自洽:本行 hash 重算相符,且 prevHash 指向前一行的 hash。自洽时返回 undefined */
|
|
507
|
+
async #chainFailureAt(records, index) {
|
|
440
508
|
const event = records[index];
|
|
441
509
|
const expectedPrev = index === 0 ? "GENESIS" : records[index - 1]?.hash;
|
|
442
|
-
if (expectedPrev === void 0 || event.prevHash !== expectedPrev)
|
|
443
|
-
if (event.hash !== await sha256Hex$1(canonical(event)))
|
|
510
|
+
if (expectedPrev === void 0 || event.prevHash !== expectedPrev) return "prevHash link mismatch (events may have been removed, reordered or corrupted)";
|
|
511
|
+
if (event.hash !== await sha256Hex$1(canonical(event))) return "event hash mismatch (event content was tampered)";
|
|
444
512
|
}
|
|
445
|
-
/** hash 链完整性校验:逐行重算 hash 并核对 prevHash
|
|
513
|
+
/** hash 链完整性校验:逐行重算 hash 并核对 prevHash 链接。**只读**,绝不改写历史 */
|
|
446
514
|
async verifyChain() {
|
|
447
515
|
const path = fileOf$1(this.#root);
|
|
448
|
-
if (!await this.#fs.exists(path)) return {
|
|
516
|
+
if (!await this.#fs.exists(path)) return {
|
|
517
|
+
ok: true,
|
|
518
|
+
total: 0
|
|
519
|
+
};
|
|
449
520
|
const lines = (await this.#fs.readText(path)).split("\n").filter((l) => l.trim() !== "");
|
|
521
|
+
const total = lines.length;
|
|
450
522
|
let expectedPrev = "GENESIS";
|
|
523
|
+
let prevTs;
|
|
451
524
|
for (let i = 0; i < lines.length; i++) {
|
|
452
525
|
let event;
|
|
453
526
|
try {
|
|
@@ -456,23 +529,29 @@ var FsAuditLog = class {
|
|
|
456
529
|
return {
|
|
457
530
|
ok: false,
|
|
458
531
|
brokenAt: i,
|
|
459
|
-
reason: "line is not valid JSON"
|
|
532
|
+
reason: "line is not valid JSON",
|
|
533
|
+
total,
|
|
534
|
+
...prevTs !== void 0 ? { brokenBeforeTs: prevTs } : {}
|
|
460
535
|
};
|
|
461
536
|
}
|
|
462
|
-
|
|
537
|
+
const broken = (reason) => ({
|
|
463
538
|
ok: false,
|
|
464
539
|
brokenAt: i,
|
|
465
|
-
reason
|
|
466
|
-
|
|
540
|
+
reason,
|
|
541
|
+
total,
|
|
542
|
+
...prevTs !== void 0 ? { brokenBeforeTs: prevTs } : {},
|
|
543
|
+
...typeof event.ts === "string" ? { brokenAfterTs: event.ts } : {}
|
|
544
|
+
});
|
|
545
|
+
if (event.prevHash !== expectedPrev) return broken("prevHash link mismatch (events may have been removed or reordered)");
|
|
467
546
|
const expectedHash = await sha256Hex$1(canonical(event));
|
|
468
|
-
if (event.hash !== expectedHash) return
|
|
469
|
-
ok: false,
|
|
470
|
-
brokenAt: i,
|
|
471
|
-
reason: "event hash mismatch (event content was tampered)"
|
|
472
|
-
};
|
|
547
|
+
if (event.hash !== expectedHash) return broken("event hash mismatch (event content was tampered)");
|
|
473
548
|
expectedPrev = event.hash;
|
|
549
|
+
prevTs = event.ts;
|
|
474
550
|
}
|
|
475
|
-
return {
|
|
551
|
+
return {
|
|
552
|
+
ok: true,
|
|
553
|
+
total
|
|
554
|
+
};
|
|
476
555
|
}
|
|
477
556
|
};
|
|
478
557
|
const dirOf = (root, skillName) => {
|
|
@@ -560,7 +639,7 @@ var SkillVersionStore = class {
|
|
|
560
639
|
async rollback(skillName, targetVersionId, input) {
|
|
561
640
|
const target = await this.get(skillName, targetVersionId);
|
|
562
641
|
const auditEvent = await this.#audit?.append({
|
|
563
|
-
type:
|
|
642
|
+
type: AUDIT_EVENT_TYPES.skillRolledBack,
|
|
564
643
|
target: skillName,
|
|
565
644
|
...input.actor !== void 0 ? { actor: input.actor } : {},
|
|
566
645
|
data: { targetVersionId }
|
|
@@ -653,6 +732,21 @@ var RepairPlanner = class {
|
|
|
653
732
|
};
|
|
654
733
|
const fileOf = (root) => `${root}/.webskill/states.json`;
|
|
655
734
|
/**
|
|
735
|
+
* 用户策略主动拒绝的错误码(FR-12.4):这是配置生效的证据,不是技能有问题,不计入隔离阈值。
|
|
736
|
+
*
|
|
737
|
+
* 集中在这一份常量里而不散在条件判断里,是为了让「哪些码不计数」只有一个事实源。
|
|
738
|
+
*/
|
|
739
|
+
const POLICY_DENIAL_CODES = /* @__PURE__ */ new Set([
|
|
740
|
+
"NETWORK_BLOCKED",
|
|
741
|
+
"TOOL_NOT_ALLOWED",
|
|
742
|
+
"FS_PERMISSION_DENIED"
|
|
743
|
+
]);
|
|
744
|
+
/** 自动隔离的原因判别式(FR-12.6);人工隔离仍写自由文本 */
|
|
745
|
+
const QUARANTINE_REASONS = {
|
|
746
|
+
integrity: "integrity",
|
|
747
|
+
failures: "failures"
|
|
748
|
+
};
|
|
749
|
+
/**
|
|
656
750
|
* 降级治理:states.json 持久化;失败达阈值 → quarantined;
|
|
657
751
|
* canRoute 仅 active;canExecute active|deprecated;disabled 执行抛 SKILL_DISABLED;
|
|
658
752
|
* 卸载/状态变更经 UiBridge confirm 审批。
|
|
@@ -713,17 +807,22 @@ var SkillStatePolicy = class {
|
|
|
713
807
|
data.states[skillName] = state;
|
|
714
808
|
if (state === "active") delete data.failures[skillName];
|
|
715
809
|
await this.#persist();
|
|
810
|
+
const auditData = {
|
|
811
|
+
...input.reason !== void 0 ? { reason: input.reason } : {},
|
|
812
|
+
...input.detail !== void 0 ? { detail: input.detail } : {}
|
|
813
|
+
};
|
|
716
814
|
await this.#audit?.append({
|
|
717
815
|
type: `skill.${state === "active" ? "reactivated" : state === "quarantined" ? "quarantined" : state === "deprecated" ? "deprecated" : "disabled"}`,
|
|
718
816
|
target: skillName,
|
|
719
817
|
...input.actor !== void 0 ? { actor: input.actor } : {},
|
|
720
|
-
...
|
|
818
|
+
...Object.keys(auditData).length > 0 ? { data: auditData } : {}
|
|
721
819
|
});
|
|
722
820
|
}
|
|
723
821
|
/**
|
|
724
822
|
* 失败计数;达阈值(默认 3)→ quarantined + 审计。
|
|
725
823
|
*
|
|
726
|
-
*
|
|
824
|
+
* 计数是**连续**而非累计(0.7.0 FR-12.5):一次成功执行经 `clearFailures` 归零,
|
|
825
|
+
* `setState(name, 'active')` 同样清零。
|
|
727
826
|
*/
|
|
728
827
|
async recordFailure(skillName, input = {}) {
|
|
729
828
|
assertSafePathSegment(skillName, "skill name");
|
|
@@ -735,10 +834,11 @@ var SkillStatePolicy = class {
|
|
|
735
834
|
state = "quarantined";
|
|
736
835
|
data.states[skillName] = "quarantined";
|
|
737
836
|
await this.#audit?.append({
|
|
738
|
-
type:
|
|
837
|
+
type: AUDIT_EVENT_TYPES.skillQuarantined,
|
|
739
838
|
target: skillName,
|
|
740
839
|
...input.actor !== void 0 ? { actor: input.actor } : {},
|
|
741
840
|
data: {
|
|
841
|
+
reason: QUARANTINE_REASONS.failures,
|
|
742
842
|
failures: count,
|
|
743
843
|
threshold: this.#failureThreshold
|
|
744
844
|
}
|
|
@@ -747,6 +847,17 @@ var SkillStatePolicy = class {
|
|
|
747
847
|
await this.#persist();
|
|
748
848
|
return state;
|
|
749
849
|
}
|
|
850
|
+
/**
|
|
851
|
+
* 成功清零(FR-12.5)。不写审计(成功是常态,写了会把审计流淹掉),
|
|
852
|
+
* 也**不改变 state**——已隔离的技能不会因一次成功自动解除。
|
|
853
|
+
*/
|
|
854
|
+
async clearFailures(skillName) {
|
|
855
|
+
assertSafePathSegment(skillName, "skill name");
|
|
856
|
+
const data = await this.#load();
|
|
857
|
+
if (data.failures[skillName] === void 0) return;
|
|
858
|
+
delete data.failures[skillName];
|
|
859
|
+
await this.#persist();
|
|
860
|
+
}
|
|
750
861
|
canRoute(state) {
|
|
751
862
|
return state === "active";
|
|
752
863
|
}
|
|
@@ -790,25 +901,44 @@ var SkillStatePolicy = class {
|
|
|
790
901
|
reason: `integrity check failed: ${e instanceof Error ? e.message : String(e)}`
|
|
791
902
|
};
|
|
792
903
|
}
|
|
793
|
-
if (!verdict.ok) await this.setState(skillName, "quarantined", {
|
|
904
|
+
if (!verdict.ok) await this.setState(skillName, "quarantined", {
|
|
905
|
+
reason: QUARANTINE_REASONS.integrity,
|
|
906
|
+
detail: verdict.reason ?? "integrity verification failed on activation"
|
|
907
|
+
});
|
|
794
908
|
return verdict;
|
|
795
909
|
} };
|
|
796
910
|
}
|
|
797
911
|
/**
|
|
798
912
|
* runtime `SkillOutcomeReporter` 适配(F1):一次真实的技能脚本执行失败 → `recordFailure`,
|
|
799
|
-
* 达阈值即自动 `quarantined` +
|
|
913
|
+
* 达阈值即自动 `quarantined` + 写审计;一次成功 → `clearFailures`。
|
|
800
914
|
*
|
|
801
915
|
* 0.4.0 之前 `recordFailure` 没有任何生产调用方——`states.json` 的失败计数只在单测里增长,
|
|
802
916
|
* 于是「失败达阈值自动隔离」在真实部署里从不触发,Console 上那个计数恒为 0。
|
|
803
917
|
* 这个适配器就是把那一段接上:runtime 不能反向依赖治理,装配点只能在宿主。
|
|
804
918
|
*
|
|
805
|
-
*
|
|
806
|
-
*
|
|
919
|
+
* 策略拒绝的分流放在这里而不是 `recordFailure`:后者是**治理动作**(管理员也可手工调用),
|
|
920
|
+
* 它不该知道运行时错误码;判定“这次失败算不算技能的错”是**上报侧**的语义。
|
|
807
921
|
*/
|
|
808
922
|
toSkillOutcomeReporter(input = {}) {
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
923
|
+
const denied = input.policyDenialCodes ?? POLICY_DENIAL_CODES;
|
|
924
|
+
const actor = input.actor !== void 0 ? { actor: input.actor } : {};
|
|
925
|
+
return {
|
|
926
|
+
onSkillFailed: async (report) => {
|
|
927
|
+
if (denied.has(report.code)) {
|
|
928
|
+
await this.#audit?.append({
|
|
929
|
+
type: AUDIT_EVENT_TYPES.skillPolicyDenied,
|
|
930
|
+
target: report.skillName,
|
|
931
|
+
...actor,
|
|
932
|
+
data: { code: report.code }
|
|
933
|
+
});
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
936
|
+
await this.recordFailure(report.skillName, actor);
|
|
937
|
+
},
|
|
938
|
+
onSkillSucceeded: async (report) => {
|
|
939
|
+
await this.clearFailures(report.skillName);
|
|
940
|
+
}
|
|
941
|
+
};
|
|
812
942
|
}
|
|
813
943
|
/** disabled → SKILL_DISABLED;quarantined → SKILL_QUARANTINED */
|
|
814
944
|
async assertExecutable(skillName) {
|
|
@@ -839,7 +969,7 @@ var SkillStatePolicy = class {
|
|
|
839
969
|
delete data.failures[skillName];
|
|
840
970
|
await this.#persist();
|
|
841
971
|
await this.#audit?.append({
|
|
842
|
-
type:
|
|
972
|
+
type: AUDIT_EVENT_TYPES.skillUninstalled,
|
|
843
973
|
target: skillName,
|
|
844
974
|
actor: input.actor
|
|
845
975
|
});
|
|
@@ -902,14 +1032,17 @@ var EvaluationRunner = class {
|
|
|
902
1032
|
/** 失败 trace → 回归评估任务建议(prompt 复现 + expected 错误模式) */
|
|
903
1033
|
function suggestFromFailedRun(run) {
|
|
904
1034
|
const errorPatterns = run.trace.filter((e) => e.type === "tool.failed" || e.type === "run.failed").map((e) => String(e.data?.["code"] ?? e.message ?? "")).filter(Boolean);
|
|
1035
|
+
const failedSkills = [...new Set(run.trace.filter((e) => e.type === "tool.failed").map((e) => e.data?.["skillName"]).filter((name) => typeof name === "string" && name !== ""))];
|
|
905
1036
|
return {
|
|
906
1037
|
id: `regression-${run.id}`,
|
|
907
1038
|
prompt: run.userPrompt,
|
|
1039
|
+
...run.activeSkillNames.length > 0 ? { skillNames: [...run.activeSkillNames] } : {},
|
|
908
1040
|
expected: (output, rerun) => rerun.status === "completed" && !rerun.trace.some((e) => (e.type === "tool.failed" || e.type === "run.failed") && errorPatterns.includes(String(e.data?.["code"] ?? ""))),
|
|
909
1041
|
metadata: {
|
|
910
1042
|
source: "test-suggestion",
|
|
911
1043
|
failureReason: run.terminationReason ?? "unknown",
|
|
912
|
-
errorPatterns
|
|
1044
|
+
errorPatterns,
|
|
1045
|
+
failedSkills
|
|
913
1046
|
}
|
|
914
1047
|
};
|
|
915
1048
|
}
|
|
@@ -1085,8 +1218,17 @@ function createMissHook(deps) {
|
|
|
1085
1218
|
source: "runtime-miss"
|
|
1086
1219
|
});
|
|
1087
1220
|
await deps.store.save(candidate);
|
|
1221
|
+
await deps.audit?.append({
|
|
1222
|
+
type: AUDIT_EVENT_TYPES.candidateGenerated,
|
|
1223
|
+
actor: "system",
|
|
1224
|
+
target: candidate.name,
|
|
1225
|
+
data: {
|
|
1226
|
+
source: "runtime-miss",
|
|
1227
|
+
candidateId: candidate.id
|
|
1228
|
+
}
|
|
1229
|
+
});
|
|
1088
1230
|
};
|
|
1089
1231
|
}
|
|
1090
1232
|
|
|
1091
1233
|
//#endregion
|
|
1092
|
-
export { AUDIT_PAGE_SIZE, AlwaysHumanApprovalPolicy, CANDIDATE_PAGE_SIZE, CandidateStore, CompositeApprovalPolicy, DependencyGraph, DocumentSkillExtractor, EvaluationRunner, FailureAnalyzer, FsAuditLog, LlmCandidateGenerator, RepairPlanner, SCORING_WEIGHTS, SKILL_VERSION_PAGE_SIZE, SimilarityDetector, SkillScorer, SkillStatePolicy, SkillVersionStore, candidateToCatalogEntry, completeText, createCandidateSink, createMissHook, jaccardSimilarity, normalizeCandidate, normalizeCandidateFiles, normalizeRisk, parseJsonObject, readDocument, sanitizeCandidateName, suggestFromFailedRun, validateCandidate };
|
|
1234
|
+
export { AUDIT_EVENT_TYPES, AUDIT_EVENT_TYPE_LIST, AUDIT_PAGE_SIZE, AlwaysHumanApprovalPolicy, CANDIDATE_PAGE_SIZE, CandidateStore, CompositeApprovalPolicy, DependencyGraph, DocumentSkillExtractor, EvaluationRunner, FailureAnalyzer, FsAuditLog, LlmCandidateGenerator, POLICY_DENIAL_CODES, QUARANTINE_REASONS, RepairPlanner, SCORING_WEIGHTS, SKILL_VERSION_PAGE_SIZE, SimilarityDetector, SkillScorer, SkillStatePolicy, SkillVersionStore, candidateToCatalogEntry, completeText, createCandidateSink, createMissHook, jaccardSimilarity, normalizeCandidate, normalizeCandidateFiles, normalizeRisk, parseJsonObject, readDocument, sanitizeCandidateName, suggestFromFailedRun, validateCandidate };
|