@webskill/sdk 0.2.7 → 0.3.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/README.md +42 -0
- package/dist/browser.d.ts +13 -4
- package/dist/browser.js +19 -10
- package/dist/{catalogComponents-C_V39rbF-B94i0fW7.js → catalogComponents-C_V39rbF-BOHveMWa.js} +254 -9090
- package/dist/client-BCM6Z3yq-qUQNkKrK.js +7787 -0
- package/dist/{dist-BQzncxXg.js → dist-8oQRa8Xz.js} +212 -13
- package/dist/{dist-CtBLBbEz.js → dist-ZKaM8j06.js} +2 -2
- package/dist/{dist-BdOW8N4V.js → dist-rorEJsNi.js} +596 -59
- package/dist/governance.d.ts +30 -197
- package/dist/governance.js +38 -199
- package/dist/{index-BpIK7tJM.d.ts → index-8d-oEDww.d.ts} +215 -2
- package/dist/{index-BNQNSDKg.d.ts → index-wiV5X8Rz.d.ts} +21 -4
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/{jsonRenderRegistry-9GrWP_hE-CMkryt1H.js → jsonRenderRegistry-9GrWP_hE-U6Do3Kid.js} +2 -2
- package/dist/mcp.d.ts +5 -3
- package/dist/mcp.js +10 -5
- package/dist/node.d.ts +338 -4
- package/dist/node.js +2338 -4
- package/dist/{openUiLibrary-B8-Cvou9-Cu1QZqoT.js → openUiLibrary-B8-Cvou9-BbpNTXS3.js} +2 -2
- package/dist/sandboxWorkerEntry.js +12 -3
- package/dist/skillVersionStore-DOEI9ptb-BxbYL70B.d.ts +127 -0
- package/dist/stdio-CFMoANJJ-BxrTeXh7.js +31 -0
- package/dist/{testing-BUoXvm1u.js → testing-CsrG3XLz.js} +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/dist/{types-7fnqDVrf-BnRQjVU3.d.ts → types-AmKCKJn_-VGabeXK4.d.ts} +140 -3
- package/dist/types-WovEf4ED-CZSDiiBU.js +6215 -0
- package/dist/ui-react.d.ts +2 -2
- package/dist/ui-react.js +6 -6
- package/dist/ui-vue.d.ts +1 -1
- package/dist/ui-vue.js +1 -1
- package/dist/ui.d.ts +3 -3
- package/dist/ui.js +2 -2
- package/dist/{webskillLitCatalog-CNaUpasU-CfSRvqCZ.js → webskillLitCatalog-CNaUpasU-BslMcxRZ.js} +1 -1
- package/package.json +4 -7
- package/dist/dist-CcMIUXeZ.js +0 -1896
- package/dist/index-BHL5FWGw.d.ts +0 -240
package/dist/governance.d.ts
CHANGED
|
@@ -1,85 +1,37 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { d as
|
|
4
|
-
//#region ../governance/dist/
|
|
5
|
-
//#region src/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import { P as FileSystemProvider, Q as SkillDocument, X as SkillCatalogEntry, c as LlmClient, nt as SkillManagerPort, u as LlmMessage, v as UiBridge } from "./types-AmKCKJn_-VGabeXK4.js";
|
|
2
|
+
import { mt as SkillStateGuard, nt as RuntimeRun, wt as WebSkillRuntime } from "./index-8d-oEDww.js";
|
|
3
|
+
import { a as AuditLog, c as CandidateSkill, d as CandidateStore, f as CompositeApprovalPolicy, g as candidateToCatalogEntry, h as SkillVersionStore, i as AuditEvent, l as CandidateSource, m as SkillVersion, n as ApprovalDecision, o as CandidateFile, p as SkillState, r as ApprovalPolicy, s as CandidateRisk, t as AlwaysHumanApprovalPolicy, u as CandidateStatus } from "./skillVersionStore-DOEI9ptb-BxbYL70B.js";
|
|
4
|
+
//#region ../governance/dist/index.d.ts
|
|
5
|
+
//#region src/candidate/candidateNormalizer.d.ts
|
|
6
|
+
/** 剥 markdown fence 与 <think> 块、截取首尾 {};非对象 → CANDIDATE_INVALID */
|
|
7
|
+
declare function parseJsonObject(raw: string): Record<string, unknown>;
|
|
8
|
+
/** 小写连字符化、≤64、过 isValidSkillName */
|
|
9
|
+
declare function sanitizeCandidateName(raw: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* 文件归一:补 SKILL.md;路径含 `..` / 以 `/` 开头 / 含 `\` → CANDIDATE_INVALID;
|
|
12
|
+
* scripts/ 下必须是 .ts/.js。
|
|
13
|
+
*/
|
|
14
|
+
declare function normalizeCandidateFiles(files: Array<{
|
|
10
15
|
path: string;
|
|
11
|
-
kind: 'skill-md' | 'script' | 'reference' | 'asset';
|
|
12
16
|
content: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
name: string;
|
|
17
|
-
description: string;
|
|
18
|
-
status: CandidateStatus;
|
|
19
|
-
source: CandidateSource;
|
|
17
|
+
}>, name: string, description: string): CandidateFile[];
|
|
18
|
+
/** 含脚本且 LLM 自报 low → 强制 medium 并追加"必须人工审批"原因 */
|
|
19
|
+
declare function normalizeRisk(declared: unknown, files: CandidateFile[], reasons: string[]): {
|
|
20
20
|
risk: CandidateRisk;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
type: string;
|
|
31
|
-
target: string;
|
|
32
|
-
actor?: string;
|
|
33
|
-
ts: string;
|
|
34
|
-
data?: Record<string, unknown>;
|
|
35
|
-
/** hash 链:上一条事件的 hash(首条为 GENESIS) */
|
|
36
|
-
prevHash?: string;
|
|
37
|
-
/** 本事件规范化载荷 + prevHash 的 sha256 */
|
|
38
|
-
hash?: string;
|
|
39
|
-
}
|
|
40
|
-
interface AuditLog {
|
|
41
|
-
append(event: Omit<AuditEvent, 'id' | 'ts'> & {
|
|
42
|
-
id?: string;
|
|
43
|
-
ts?: string;
|
|
44
|
-
}): Promise<AuditEvent>;
|
|
45
|
-
query(filter: {
|
|
46
|
-
target?: string;
|
|
47
|
-
type?: string;
|
|
48
|
-
since?: string;
|
|
49
|
-
}): Promise<AuditEvent[]>;
|
|
50
|
-
}
|
|
51
|
-
interface SkillVersion {
|
|
52
|
-
versionId: string;
|
|
53
|
-
parentVersionId?: string;
|
|
54
|
-
createdAt: string;
|
|
55
|
-
reason: string;
|
|
56
|
-
manifest: SkillManifest;
|
|
57
|
-
auditEventId?: string;
|
|
58
|
-
/** 发布时捕获的技能归档(zip 相对路径,applyRollback 恢复用;0.2.0 起记录) */
|
|
59
|
-
archivePath?: string;
|
|
60
|
-
}
|
|
61
|
-
type SkillState = 'active' | 'quarantined' | 'deprecated' | 'disabled';
|
|
21
|
+
reasons: string[];
|
|
22
|
+
};
|
|
23
|
+
/** 不信任归一化管线全链路;状态恒为 draft */
|
|
24
|
+
declare function normalizeCandidate(input: {
|
|
25
|
+
raw: Record<string, unknown>;
|
|
26
|
+
source: CandidateSource;
|
|
27
|
+
now?: () => string;
|
|
28
|
+
createId?: () => string;
|
|
29
|
+
}): CandidateSkill;
|
|
62
30
|
//#endregion
|
|
63
31
|
//#region src/candidate/candidateValidator.d.ts
|
|
64
32
|
/** 候选校验:缺 SKILL.md / 非法扩展名 → CANDIDATE_INVALID */
|
|
65
33
|
declare function validateCandidate(candidate: CandidateSkill): void;
|
|
66
34
|
//#endregion
|
|
67
|
-
//#region src/candidate/candidateStore.d.ts
|
|
68
|
-
/** 逐文件持久化的候选存储:<managedRoot>/.webskill/candidates/<id>.json */
|
|
69
|
-
declare class CandidateStore {
|
|
70
|
-
#private;
|
|
71
|
-
constructor(deps: {
|
|
72
|
-
root: string;
|
|
73
|
-
fs: FileSystemProvider;
|
|
74
|
-
});
|
|
75
|
-
save(candidate: CandidateSkill): Promise<void>;
|
|
76
|
-
get(id: string): Promise<CandidateSkill>;
|
|
77
|
-
list(): Promise<CandidateSkill[]>;
|
|
78
|
-
updateStatus(id: string, status: CandidateStatus, now?: string): Promise<CandidateSkill>;
|
|
79
|
-
}
|
|
80
|
-
/** 硬门禁:仅 published 可转换为 Catalog 条目,否则 APPROVAL_REQUIRED */
|
|
81
|
-
declare function candidateToCatalogEntry(candidate: CandidateSkill): SkillCatalogEntry;
|
|
82
|
-
//#endregion
|
|
83
35
|
//#region src/candidate/llmCandidateGenerator.d.ts
|
|
84
36
|
/** LLM 候选生成器:prompt 强制约束 + 不信任归一化管线 + candidate.created 审计 */
|
|
85
37
|
declare class LlmCandidateGenerator {
|
|
@@ -97,37 +49,6 @@ declare class LlmCandidateGenerator {
|
|
|
97
49
|
}): Promise<CandidateSkill>;
|
|
98
50
|
}
|
|
99
51
|
//#endregion
|
|
100
|
-
//#region src/versioning/skillVersionStore.d.ts
|
|
101
|
-
/** 版本存储:manifest 快照 + parentVersionId 链;回滚 = 追加新版本(谱系不断)。
|
|
102
|
-
* 保留策略:maxArchivesPerSkill(默认 5)超出时清理最旧版本(json + zip 归档一并删除)。 */
|
|
103
|
-
declare class SkillVersionStore {
|
|
104
|
-
#private;
|
|
105
|
-
constructor(deps: {
|
|
106
|
-
root: string;
|
|
107
|
-
fs: FileSystemProvider;
|
|
108
|
-
now?: () => string;
|
|
109
|
-
createId?: () => string;
|
|
110
|
-
audit?: AuditLog;
|
|
111
|
-
/** 每技能保留的版本/归档上限(默认 5,超出清理最旧) */
|
|
112
|
-
maxArchivesPerSkill?: number;
|
|
113
|
-
});
|
|
114
|
-
add(skillName: string, input: {
|
|
115
|
-
reason: string;
|
|
116
|
-
manifest: SkillManifest;
|
|
117
|
-
parentVersionId?: string;
|
|
118
|
-
archive?: Uint8Array;
|
|
119
|
-
}): Promise<SkillVersion>;
|
|
120
|
-
/** 读取版本归档字节(applyRollback 用;未捕获归档的旧版本 → GOVERNANCE_FAILED) */
|
|
121
|
-
readArchive(skillName: string, versionId: string): Promise<Uint8Array>;
|
|
122
|
-
list(skillName: string): Promise<SkillVersion[]>;
|
|
123
|
-
get(skillName: string, versionId: string): Promise<SkillVersion>;
|
|
124
|
-
/** 回滚:基于旧 manifest 追加新版本 + skill.rolled_back 审计 */
|
|
125
|
-
rollback(skillName: string, targetVersionId: string, input: {
|
|
126
|
-
actor?: string;
|
|
127
|
-
reason?: string;
|
|
128
|
-
}): Promise<SkillVersion>;
|
|
129
|
-
}
|
|
130
|
-
//#endregion
|
|
131
52
|
//#region src/audit/fsAuditLog.d.ts
|
|
132
53
|
interface AuditChainVerification {
|
|
133
54
|
ok: boolean;
|
|
@@ -167,6 +88,8 @@ interface FailureDiagnosis {
|
|
|
167
88
|
cause: string;
|
|
168
89
|
suggestedFix: string;
|
|
169
90
|
errorCode?: string;
|
|
91
|
+
/** 诊断来源:'llm' 为模型输出,'rules' 为错误码归类兑底 */
|
|
92
|
+
source: 'llm' | 'rules';
|
|
170
93
|
}
|
|
171
94
|
/** 失败诊断:trace 摘要 → LLM 诊断(JSON);无 LLM 时规则版(错误码归类) */
|
|
172
95
|
declare class FailureAnalyzer {
|
|
@@ -241,7 +164,7 @@ declare class SkillStatePolicy {
|
|
|
241
164
|
uninstall(skillName: string, input: {
|
|
242
165
|
actor: string;
|
|
243
166
|
uiBridge: UiBridge;
|
|
244
|
-
skillManager:
|
|
167
|
+
skillManager: SkillManagerPort;
|
|
245
168
|
}): Promise<void>;
|
|
246
169
|
}
|
|
247
170
|
//#endregion
|
|
@@ -359,96 +282,6 @@ interface SourceDocument {
|
|
|
359
282
|
/** 读文档 + sha256 hash(变更检测用) */
|
|
360
283
|
declare function readDocument(fs: FileSystemProvider, path: string): Promise<SourceDocument>;
|
|
361
284
|
//#endregion
|
|
362
|
-
//#region ../governance/dist/index.d.ts
|
|
363
|
-
//#region src/candidate/candidateNormalizer.d.ts
|
|
364
|
-
/** 剥 markdown fence 与 <think> 块、截取首尾 {};非对象 → CANDIDATE_INVALID */
|
|
365
|
-
declare function parseJsonObject(raw: string): Record<string, unknown>;
|
|
366
|
-
/** 小写连字符化、≤64、过 isValidSkillName */
|
|
367
|
-
declare function sanitizeCandidateName(raw: string): string;
|
|
368
|
-
/**
|
|
369
|
-
* 文件归一:补 SKILL.md;路径含 `..` / 以 `/` 开头 / 含 `\` → CANDIDATE_INVALID;
|
|
370
|
-
* scripts/ 下必须是 .ts/.js。
|
|
371
|
-
*/
|
|
372
|
-
declare function normalizeCandidateFiles(files: Array<{
|
|
373
|
-
path: string;
|
|
374
|
-
content: string;
|
|
375
|
-
}>, name: string, description: string): CandidateFile[];
|
|
376
|
-
/** 含脚本且 LLM 自报 low → 强制 medium 并追加"必须人工审批"原因 */
|
|
377
|
-
declare function normalizeRisk(declared: unknown, files: CandidateFile[], reasons: string[]): {
|
|
378
|
-
risk: CandidateRisk;
|
|
379
|
-
reasons: string[];
|
|
380
|
-
};
|
|
381
|
-
/** 不信任归一化管线全链路;状态恒为 draft */
|
|
382
|
-
declare function normalizeCandidate(input: {
|
|
383
|
-
raw: Record<string, unknown>;
|
|
384
|
-
source: CandidateSource;
|
|
385
|
-
now?: () => string;
|
|
386
|
-
createId?: () => string;
|
|
387
|
-
}): CandidateSkill;
|
|
388
|
-
//#endregion
|
|
389
|
-
//#region src/approval/policies.d.ts
|
|
390
|
-
interface ApprovalDecision {
|
|
391
|
-
needsHuman: boolean;
|
|
392
|
-
reason: string;
|
|
393
|
-
}
|
|
394
|
-
interface ApprovalPolicy {
|
|
395
|
-
evaluate(candidate: CandidateSkill): ApprovalDecision;
|
|
396
|
-
}
|
|
397
|
-
/** 默认策略:任何候选都必须人工审批 */
|
|
398
|
-
declare class AlwaysHumanApprovalPolicy implements ApprovalPolicy {
|
|
399
|
-
evaluate(candidate: CandidateSkill): ApprovalDecision;
|
|
400
|
-
}
|
|
401
|
-
/** 规则组合策略:首个命中的规则胜出,全部未命中走 fallback(默认 AlwaysHuman) */
|
|
402
|
-
declare class CompositeApprovalPolicy implements ApprovalPolicy {
|
|
403
|
-
#private;
|
|
404
|
-
constructor(rules: Array<(candidate: CandidateSkill) => ApprovalDecision | undefined>, fallback?: ApprovalPolicy);
|
|
405
|
-
evaluate(candidate: CandidateSkill): ApprovalDecision;
|
|
406
|
-
}
|
|
407
|
-
//#endregion
|
|
408
|
-
//#region src/approval/approvalWorkflow.d.ts
|
|
409
|
-
/** 审批工作流:review(UiBridge confirm 真实接线)/ publish(校验→安装→版本→审计) */
|
|
410
|
-
declare class ApprovalWorkflow {
|
|
411
|
-
#private;
|
|
412
|
-
constructor(deps: {
|
|
413
|
-
policy: ApprovalPolicy;
|
|
414
|
-
audit: AuditLog;
|
|
415
|
-
store: CandidateStore;
|
|
416
|
-
skillManager: SkillManager;
|
|
417
|
-
versions: SkillVersionStore;
|
|
418
|
-
fs?: FileSystemProvider;
|
|
419
|
-
});
|
|
420
|
-
/** 策略评估;needs-human 时经 UiBridge confirm 真实询问,按应答迁移状态 */
|
|
421
|
-
review(candidateId: string, input: {
|
|
422
|
-
actor: string;
|
|
423
|
-
uiBridge?: UiBridge;
|
|
424
|
-
}): Promise<CandidateSkill>;
|
|
425
|
-
/** publish 全链路:approved 前置 → 写出 staging → validateSkills → install → 版本 → 审计 */
|
|
426
|
-
publish(candidateId: string, input: {
|
|
427
|
-
actor: string;
|
|
428
|
-
}): Promise<SkillManifest>;
|
|
429
|
-
/**
|
|
430
|
-
* 真实回滚(受审批保护:仅经显式 actor 调用并全程审计):
|
|
431
|
-
* 版本归档解包 → staging 校验 → 原子安装(复用安装管线 swap)→ 追加新版本 + 审计。
|
|
432
|
-
* RepairPlanner 的 rollback 选项(targetVersionId)经本方法执行。
|
|
433
|
-
*/
|
|
434
|
-
applyRollback(skillName: string, versionId: string, input: {
|
|
435
|
-
actor: string;
|
|
436
|
-
reason?: string;
|
|
437
|
-
}): Promise<SkillManifest>;
|
|
438
|
-
}
|
|
439
|
-
//#endregion
|
|
440
|
-
//#region src/evaluation/evaluationRuntime.d.ts
|
|
441
|
-
/**
|
|
442
|
-
* 治理评估专用 runtime 装配(不可信技能试用路径):
|
|
443
|
-
* 默认注入 ProcessSandboxExecutor(fork + --permission 真实进程隔离;子进程
|
|
444
|
-
* env 默认清空防密钥泄露,需透传时经 ProcessSandboxOptions.envWhitelist 显式放行)。
|
|
445
|
-
* 可配置 executor 切回 SandboxedScriptExecutor(worker_threads 能力面收敛形态,
|
|
446
|
-
* 非安全边界;envWhitelist 同样适用于该执行器)。
|
|
447
|
-
*/
|
|
448
|
-
declare function createEvaluationRuntime(deps: WebSkillRuntimeDeps & {
|
|
449
|
-
executor?: ScriptExecutor;
|
|
450
|
-
}): WebSkillRuntime;
|
|
451
|
-
//#endregion
|
|
452
285
|
//#region src/documents/documentSkillExtractor.d.ts
|
|
453
286
|
/** 文档 → LLM 抽取 → 完整防御管线 → draft 候选(source: document) */
|
|
454
287
|
declare class DocumentSkillExtractor {
|
|
@@ -495,4 +328,4 @@ declare function createMissHook(deps: {
|
|
|
495
328
|
*/
|
|
496
329
|
declare function completeText(llm: LlmClient, messages: LlmMessage[]): Promise<string>;
|
|
497
330
|
//#endregion
|
|
498
|
-
export { AlwaysHumanApprovalPolicy, type ApprovalDecision, type ApprovalPolicy,
|
|
331
|
+
export { AlwaysHumanApprovalPolicy, type ApprovalDecision, type ApprovalPolicy, type AuditEvent, type AuditLog, type CandidateFile, type CandidateRisk, type CandidateSkill, type CandidateSource, type CandidateStatus, CandidateStore, CompositeApprovalPolicy, DependencyGraph, DocumentSkillExtractor, type EvaluationReport, type EvaluationResult, EvaluationRunner, type EvaluationTask, FailureAnalyzer, type FailureDiagnosis, FsAuditLog, LlmCandidateGenerator, type RepairOption, RepairPlanner, SCORING_WEIGHTS, type ScoreInput, SimilarityDetector, SkillScorer, type SkillState, SkillStatePolicy, type SkillVersion, SkillVersionStore, type SourceDocument, candidateToCatalogEntry, completeText, createMissHook, jaccardSimilarity, normalizeCandidate, normalizeCandidateFiles, normalizeRisk, parseJsonObject, readDocument, sanitizeCandidateName, suggestFromFailedRun, validateCandidate };
|
package/dist/governance.js
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { S as WebSkillRuntime } from "./dist-BdOW8N4V.js";
|
|
3
|
-
import { i as NodeFS, s as ProcessSandboxExecutor, u as exportArchive } from "./dist-CcMIUXeZ.js";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { tmpdir } from "node:os";
|
|
6
|
-
import { mkdtemp } from "node:fs/promises";
|
|
1
|
+
import { O as messageOf, T as isValidSkillName, g as assertSafePathSegment, m as WebSkillError } from "./dist-8oQRa8Xz.js";
|
|
7
2
|
|
|
8
|
-
//#region ../governance/dist/
|
|
3
|
+
//#region ../governance/dist/index.js
|
|
9
4
|
const invalid = (message, details) => {
|
|
10
5
|
throw new WebSkillError("CANDIDATE_INVALID", message, details);
|
|
11
6
|
};
|
|
@@ -216,6 +211,31 @@ var LlmCandidateGenerator = class {
|
|
|
216
211
|
return candidate;
|
|
217
212
|
}
|
|
218
213
|
};
|
|
214
|
+
/** 默认策略:任何候选都必须人工审批 */
|
|
215
|
+
var AlwaysHumanApprovalPolicy = class {
|
|
216
|
+
evaluate(candidate) {
|
|
217
|
+
return {
|
|
218
|
+
needsHuman: true,
|
|
219
|
+
reason: `Candidate "${candidate.name}" requires human approval (risk: ${candidate.risk})`
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
/** 规则组合策略:首个命中的规则胜出,全部未命中走 fallback(默认 AlwaysHuman) */
|
|
224
|
+
var CompositeApprovalPolicy = class {
|
|
225
|
+
#rules;
|
|
226
|
+
#fallback;
|
|
227
|
+
constructor(rules, fallback) {
|
|
228
|
+
this.#rules = rules;
|
|
229
|
+
this.#fallback = fallback ?? new AlwaysHumanApprovalPolicy();
|
|
230
|
+
}
|
|
231
|
+
evaluate(candidate) {
|
|
232
|
+
for (const rule of this.#rules) {
|
|
233
|
+
const decision = rule(candidate);
|
|
234
|
+
if (decision) return decision;
|
|
235
|
+
}
|
|
236
|
+
return this.#fallback.evaluate(candidate);
|
|
237
|
+
}
|
|
238
|
+
};
|
|
219
239
|
const fileOf$1 = (root) => `${root}/.webskill/audit.jsonl`;
|
|
220
240
|
/** 环境无关 sha256(WebCrypto;Node ≥17 与浏览器均有 globalThis.crypto.subtle) */
|
|
221
241
|
const sha256Hex$1 = async (text) => {
|
|
@@ -289,12 +309,14 @@ var FsAuditLog = class {
|
|
|
289
309
|
if (!await this.#fs.exists(path)) return [];
|
|
290
310
|
const raw = await this.#fs.readText(path);
|
|
291
311
|
const events = [];
|
|
312
|
+
let skippedLines = 0;
|
|
292
313
|
for (const line of raw.split("\n")) {
|
|
293
314
|
if (line.trim() === "") continue;
|
|
294
315
|
let event;
|
|
295
316
|
try {
|
|
296
317
|
event = JSON.parse(line);
|
|
297
318
|
} catch {
|
|
319
|
+
skippedLines += 1;
|
|
298
320
|
continue;
|
|
299
321
|
}
|
|
300
322
|
if (filter.target !== void 0 && event.target !== filter.target) continue;
|
|
@@ -302,6 +324,7 @@ var FsAuditLog = class {
|
|
|
302
324
|
if (filter.since !== void 0 && event.ts < filter.since) continue;
|
|
303
325
|
events.push(event);
|
|
304
326
|
}
|
|
327
|
+
if (skippedLines > 0) console.warn(`[webskill] Audit log at ${path} contains ${skippedLines} unparsable line(s) skipped by query; run verifyChain() to check integrity`);
|
|
305
328
|
return events;
|
|
306
329
|
}
|
|
307
330
|
/** hash 链完整性校验:逐行重算 hash 并核对 prevHash 链接 */
|
|
@@ -461,14 +484,18 @@ var FailureAnalyzer = class {
|
|
|
461
484
|
return {
|
|
462
485
|
cause: String(parsed["cause"] ?? "Unknown cause"),
|
|
463
486
|
suggestedFix: String(parsed["suggestedFix"] ?? "Manual inspection required"),
|
|
464
|
-
...typeof parsed["errorCode"] === "string" ? { errorCode: parsed["errorCode"] } : firstCode ? { errorCode: firstCode } : {}
|
|
487
|
+
...typeof parsed["errorCode"] === "string" ? { errorCode: parsed["errorCode"] } : firstCode ? { errorCode: firstCode } : {},
|
|
488
|
+
source: "llm"
|
|
465
489
|
};
|
|
466
|
-
} catch {
|
|
490
|
+
} catch (e) {
|
|
491
|
+
console.warn(`[webskill] LLM diagnosis output was not valid JSON, falling back to rule-based diagnosis: ${e instanceof Error ? e.message : String(e)}`);
|
|
492
|
+
}
|
|
467
493
|
}
|
|
468
494
|
return {
|
|
469
495
|
cause: firstCode ? ERROR_CAUSES[firstCode] ?? `Failure with code ${firstCode}` : "Unknown failure (no error code in trace)",
|
|
470
496
|
suggestedFix: firstCode ? `Inspect the component responsible for ${firstCode}` : "Inspect the run trace manually",
|
|
471
|
-
...firstCode ? { errorCode: firstCode } : {}
|
|
497
|
+
...firstCode ? { errorCode: firstCode } : {},
|
|
498
|
+
source: "rules"
|
|
472
499
|
};
|
|
473
500
|
}
|
|
474
501
|
};
|
|
@@ -809,194 +836,6 @@ async function readDocument(fs, path) {
|
|
|
809
836
|
hash: await sha256Hex(content)
|
|
810
837
|
};
|
|
811
838
|
}
|
|
812
|
-
|
|
813
|
-
//#endregion
|
|
814
|
-
//#region ../governance/dist/index.js
|
|
815
|
-
/** 默认策略:任何候选都必须人工审批 */
|
|
816
|
-
var AlwaysHumanApprovalPolicy = class {
|
|
817
|
-
evaluate(candidate) {
|
|
818
|
-
return {
|
|
819
|
-
needsHuman: true,
|
|
820
|
-
reason: `Candidate "${candidate.name}" requires human approval (risk: ${candidate.risk})`
|
|
821
|
-
};
|
|
822
|
-
}
|
|
823
|
-
};
|
|
824
|
-
/** 规则组合策略:首个命中的规则胜出,全部未命中走 fallback(默认 AlwaysHuman) */
|
|
825
|
-
var CompositeApprovalPolicy = class {
|
|
826
|
-
#rules;
|
|
827
|
-
#fallback;
|
|
828
|
-
constructor(rules, fallback) {
|
|
829
|
-
this.#rules = rules;
|
|
830
|
-
this.#fallback = fallback ?? new AlwaysHumanApprovalPolicy();
|
|
831
|
-
}
|
|
832
|
-
evaluate(candidate) {
|
|
833
|
-
for (const rule of this.#rules) {
|
|
834
|
-
const decision = rule(candidate);
|
|
835
|
-
if (decision) return decision;
|
|
836
|
-
}
|
|
837
|
-
return this.#fallback.evaluate(candidate);
|
|
838
|
-
}
|
|
839
|
-
};
|
|
840
|
-
/** 审批工作流:review(UiBridge confirm 真实接线)/ publish(校验→安装→版本→审计) */
|
|
841
|
-
var ApprovalWorkflow = class {
|
|
842
|
-
#policy;
|
|
843
|
-
#audit;
|
|
844
|
-
#store;
|
|
845
|
-
#skillManager;
|
|
846
|
-
#versions;
|
|
847
|
-
#fs;
|
|
848
|
-
constructor(deps) {
|
|
849
|
-
this.#policy = deps.policy;
|
|
850
|
-
this.#audit = deps.audit;
|
|
851
|
-
this.#store = deps.store;
|
|
852
|
-
this.#skillManager = deps.skillManager;
|
|
853
|
-
this.#versions = deps.versions;
|
|
854
|
-
this.#fs = deps.fs ?? new NodeFS();
|
|
855
|
-
}
|
|
856
|
-
/** 策略评估;needs-human 时经 UiBridge confirm 真实询问,按应答迁移状态 */
|
|
857
|
-
async review(candidateId, input) {
|
|
858
|
-
const candidate = await this.#store.get(candidateId);
|
|
859
|
-
if (candidate.status !== "draft" && candidate.status !== "pending-review") throw new WebSkillError("GOVERNANCE_FAILED", `Candidate "${candidateId}" cannot be reviewed from status "${candidate.status}"`);
|
|
860
|
-
const decision = this.#policy.evaluate(candidate);
|
|
861
|
-
let approved;
|
|
862
|
-
if (decision.needsHuman) {
|
|
863
|
-
if (!input.uiBridge) {
|
|
864
|
-
await this.#store.updateStatus(candidateId, "pending-review");
|
|
865
|
-
throw new WebSkillError("APPROVAL_REQUIRED", `Candidate "${candidate.name}" requires human approval: ${decision.reason}`);
|
|
866
|
-
}
|
|
867
|
-
await this.#store.updateStatus(candidateId, "pending-review");
|
|
868
|
-
const response = await input.uiBridge.request({
|
|
869
|
-
type: "confirm",
|
|
870
|
-
id: `approval-${candidateId}`,
|
|
871
|
-
message: `Approve candidate "${candidate.name}" (risk: ${candidate.risk})? ${decision.reason}`,
|
|
872
|
-
defaultValue: false
|
|
873
|
-
});
|
|
874
|
-
approved = response.cancelled !== true && response.value === true;
|
|
875
|
-
} else approved = true;
|
|
876
|
-
const updated = await this.#store.updateStatus(candidateId, approved ? "approved" : "rejected");
|
|
877
|
-
await this.#audit.append({
|
|
878
|
-
type: "candidate.reviewed",
|
|
879
|
-
target: candidateId,
|
|
880
|
-
actor: input.actor,
|
|
881
|
-
data: {
|
|
882
|
-
approved,
|
|
883
|
-
reason: decision.reason
|
|
884
|
-
}
|
|
885
|
-
});
|
|
886
|
-
return updated;
|
|
887
|
-
}
|
|
888
|
-
/** publish 全链路:approved 前置 → 写出 staging → validateSkills → install → 版本 → 审计 */
|
|
889
|
-
async publish(candidateId, input) {
|
|
890
|
-
const candidate = await this.#store.get(candidateId);
|
|
891
|
-
if (candidate.status !== "approved") throw new WebSkillError("APPROVAL_REQUIRED", `Candidate "${candidate.name}" must be approved before publishing (status: ${candidate.status})`);
|
|
892
|
-
const stagingRoot = (await mkdtemp(path.join(tmpdir(), "webskill-candidate-"))).split(path.sep).join("/");
|
|
893
|
-
try {
|
|
894
|
-
const skillDir = `${stagingRoot}/${candidate.name}`;
|
|
895
|
-
for (const file of candidate.files) await this.#fs.writeText(resolveInsideRoot(skillDir, file.path), file.content);
|
|
896
|
-
const report = await validateSkills(this.#fs, [stagingRoot]);
|
|
897
|
-
if (!report.ok) {
|
|
898
|
-
const errors = report.issues.filter((i) => i.severity === "error");
|
|
899
|
-
throw new WebSkillError("GOVERNANCE_FAILED", `Candidate "${candidate.name}" failed validation: ${errors.map((i) => i.message).join("; ")}`, errors);
|
|
900
|
-
}
|
|
901
|
-
const manifest = await this.#skillManager.install({
|
|
902
|
-
type: "local",
|
|
903
|
-
path: skillDir
|
|
904
|
-
});
|
|
905
|
-
const archiveOut = `${stagingRoot}/version-archive.zip`;
|
|
906
|
-
await exportArchive(this.#fs, `${this.#skillManager.managedRoot}/${candidate.name}`, {
|
|
907
|
-
format: "zip",
|
|
908
|
-
outPath: archiveOut
|
|
909
|
-
});
|
|
910
|
-
await this.#versions.add(candidate.name, {
|
|
911
|
-
reason: `Publish candidate ${candidateId}`,
|
|
912
|
-
manifest,
|
|
913
|
-
archive: await this.#fs.readBinary(archiveOut)
|
|
914
|
-
});
|
|
915
|
-
await this.#store.updateStatus(candidateId, "published");
|
|
916
|
-
await this.#audit.append({
|
|
917
|
-
type: "skill.published",
|
|
918
|
-
target: candidate.name,
|
|
919
|
-
actor: input.actor,
|
|
920
|
-
data: {
|
|
921
|
-
candidateId,
|
|
922
|
-
digest: manifest.integrity.digest
|
|
923
|
-
}
|
|
924
|
-
});
|
|
925
|
-
return manifest;
|
|
926
|
-
} catch (e) {
|
|
927
|
-
if (e instanceof WebSkillError) throw e;
|
|
928
|
-
throw new WebSkillError("GOVERNANCE_FAILED", `Failed to publish candidate "${candidateId}": ${messageOf(e)}`, e);
|
|
929
|
-
} finally {
|
|
930
|
-
try {
|
|
931
|
-
await this.#fs.remove(stagingRoot, { recursive: true });
|
|
932
|
-
} catch {}
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
/**
|
|
936
|
-
* 真实回滚(受审批保护:仅经显式 actor 调用并全程审计):
|
|
937
|
-
* 版本归档解包 → staging 校验 → 原子安装(复用安装管线 swap)→ 追加新版本 + 审计。
|
|
938
|
-
* RepairPlanner 的 rollback 选项(targetVersionId)经本方法执行。
|
|
939
|
-
*/
|
|
940
|
-
async applyRollback(skillName, versionId, input) {
|
|
941
|
-
assertSafePathSegment(skillName, "skill name");
|
|
942
|
-
assertSafePathSegment(versionId, "version id");
|
|
943
|
-
const version = await this.#versions.get(skillName, versionId);
|
|
944
|
-
const archive = await this.#versions.readArchive(skillName, versionId);
|
|
945
|
-
const stagingRoot = (await mkdtemp(path.join(tmpdir(), "webskill-rollback-"))).split(path.sep).join("/");
|
|
946
|
-
try {
|
|
947
|
-
const skillDir = `${stagingRoot}/${skillName}`;
|
|
948
|
-
for (const [rel, content] of await unzipWithLimits(archive)) {
|
|
949
|
-
if (rel.endsWith("/")) continue;
|
|
950
|
-
await this.#fs.writeBinary(resolveInsideRoot(skillDir, rel), content);
|
|
951
|
-
}
|
|
952
|
-
const report = await validateSkills(this.#fs, [stagingRoot]);
|
|
953
|
-
if (!report.ok) {
|
|
954
|
-
const errors = report.issues.filter((i) => i.severity === "error");
|
|
955
|
-
throw new WebSkillError("GOVERNANCE_FAILED", `Rollback archive of "${skillName}" failed validation: ${errors.map((i) => i.message).join("; ")}`, errors);
|
|
956
|
-
}
|
|
957
|
-
const manifest = await this.#skillManager.install({
|
|
958
|
-
type: "local",
|
|
959
|
-
path: skillDir
|
|
960
|
-
});
|
|
961
|
-
if (manifest.integrity.digest !== version.manifest.integrity.digest) throw new WebSkillError("GOVERNANCE_FAILED", `Rollback of "${skillName}" to version "${versionId}" produced a digest mismatch: expected ${version.manifest.integrity.digest}, got ${manifest.integrity.digest}`);
|
|
962
|
-
await this.#versions.add(skillName, {
|
|
963
|
-
reason: input.reason ?? `Rollback to version ${versionId}`,
|
|
964
|
-
manifest,
|
|
965
|
-
archive
|
|
966
|
-
});
|
|
967
|
-
await this.#audit.append({
|
|
968
|
-
type: "skill.rolled_back",
|
|
969
|
-
target: skillName,
|
|
970
|
-
actor: input.actor,
|
|
971
|
-
data: {
|
|
972
|
-
targetVersionId: versionId,
|
|
973
|
-
reason: input.reason
|
|
974
|
-
}
|
|
975
|
-
});
|
|
976
|
-
return manifest;
|
|
977
|
-
} catch (e) {
|
|
978
|
-
if (e instanceof WebSkillError) throw e;
|
|
979
|
-
throw new WebSkillError("GOVERNANCE_FAILED", `Failed to roll back "${skillName}" to version "${versionId}": ${messageOf(e)}`, e);
|
|
980
|
-
} finally {
|
|
981
|
-
try {
|
|
982
|
-
await this.#fs.remove(stagingRoot, { recursive: true });
|
|
983
|
-
} catch {}
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
};
|
|
987
|
-
/**
|
|
988
|
-
* 治理评估专用 runtime 装配(不可信技能试用路径):
|
|
989
|
-
* 默认注入 ProcessSandboxExecutor(fork + --permission 真实进程隔离;子进程
|
|
990
|
-
* env 默认清空防密钥泄露,需透传时经 ProcessSandboxOptions.envWhitelist 显式放行)。
|
|
991
|
-
* 可配置 executor 切回 SandboxedScriptExecutor(worker_threads 能力面收敛形态,
|
|
992
|
-
* 非安全边界;envWhitelist 同样适用于该执行器)。
|
|
993
|
-
*/
|
|
994
|
-
function createEvaluationRuntime(deps) {
|
|
995
|
-
return new WebSkillRuntime({
|
|
996
|
-
...deps,
|
|
997
|
-
executor: deps.executor ?? new ProcessSandboxExecutor(deps.fs)
|
|
998
|
-
});
|
|
999
|
-
}
|
|
1000
839
|
const EXTRACT_PROMPT = (doc, nameHint) => [
|
|
1001
840
|
"Extract an executable skill from the following document as STRICT JSON only.",
|
|
1002
841
|
"Schema: {\"name\": string, \"description\": string, \"risk\": \"low\"|\"medium\"|\"high\",",
|
|
@@ -1080,4 +919,4 @@ function createMissHook(deps) {
|
|
|
1080
919
|
}
|
|
1081
920
|
|
|
1082
921
|
//#endregion
|
|
1083
|
-
export { AlwaysHumanApprovalPolicy,
|
|
922
|
+
export { AlwaysHumanApprovalPolicy, CandidateStore, CompositeApprovalPolicy, DependencyGraph, DocumentSkillExtractor, EvaluationRunner, FailureAnalyzer, FsAuditLog, LlmCandidateGenerator, RepairPlanner, SCORING_WEIGHTS, SimilarityDetector, SkillScorer, SkillStatePolicy, SkillVersionStore, candidateToCatalogEntry, completeText, createMissHook, jaccardSimilarity, normalizeCandidate, normalizeCandidateFiles, normalizeRisk, parseJsonObject, readDocument, sanitizeCandidateName, suggestFromFailedRun, validateCandidate };
|