@skillfm/local 2.0.4 → 2.0.5

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.
Files changed (49) hide show
  1. package/dist/harness/kernels/deny-pipeline.d.ts +21 -0
  2. package/dist/harness/kernels/deny-pipeline.d.ts.map +1 -0
  3. package/dist/harness/kernels/deny-pipeline.js +225 -0
  4. package/dist/harness/kernels/deny-pipeline.js.map +1 -0
  5. package/dist/harness/kernels/hook-file.d.ts +16 -0
  6. package/dist/harness/kernels/hook-file.d.ts.map +1 -0
  7. package/dist/harness/kernels/hook-file.js +229 -0
  8. package/dist/harness/kernels/hook-file.js.map +1 -0
  9. package/dist/harness/kernels/json-merge.d.ts +45 -0
  10. package/dist/harness/kernels/json-merge.d.ts.map +1 -0
  11. package/dist/harness/kernels/json-merge.js +123 -0
  12. package/dist/harness/kernels/json-merge.js.map +1 -0
  13. package/dist/harness/kernels/mcp-only.d.ts +23 -0
  14. package/dist/harness/kernels/mcp-only.d.ts.map +1 -0
  15. package/dist/harness/kernels/mcp-only.js +215 -0
  16. package/dist/harness/kernels/mcp-only.js.map +1 -0
  17. package/dist/harness/kernels/protocol-reject.d.ts +18 -0
  18. package/dist/harness/kernels/protocol-reject.d.ts.map +1 -0
  19. package/dist/harness/kernels/protocol-reject.js +117 -0
  20. package/dist/harness/kernels/protocol-reject.js.map +1 -0
  21. package/dist/harness/kernels/registry.d.ts +56 -0
  22. package/dist/harness/kernels/registry.d.ts.map +1 -0
  23. package/dist/harness/kernels/registry.js +139 -0
  24. package/dist/harness/kernels/registry.js.map +1 -0
  25. package/dist/harness/kernels/types.d.ts +86 -0
  26. package/dist/harness/kernels/types.d.ts.map +1 -0
  27. package/dist/harness/kernels/types.js +21 -0
  28. package/dist/harness/kernels/types.js.map +1 -0
  29. package/dist/mcp-output/builder.d.ts +24 -0
  30. package/dist/mcp-output/builder.d.ts.map +1 -0
  31. package/dist/mcp-output/builder.js +99 -0
  32. package/dist/mcp-output/builder.js.map +1 -0
  33. package/dist/mcp-output/deny-review.d.ts +64 -0
  34. package/dist/mcp-output/deny-review.d.ts.map +1 -0
  35. package/dist/mcp-output/deny-review.js +212 -0
  36. package/dist/mcp-output/deny-review.js.map +1 -0
  37. package/dist/mcp-output/types.d.ts +64 -0
  38. package/dist/mcp-output/types.d.ts.map +1 -0
  39. package/dist/mcp-output/types.js +21 -0
  40. package/dist/mcp-output/types.js.map +1 -0
  41. package/dist/skill-md/template.d.ts +30 -0
  42. package/dist/skill-md/template.d.ts.map +1 -0
  43. package/dist/skill-md/template.js +194 -0
  44. package/dist/skill-md/template.js.map +1 -0
  45. package/dist/skill-md/writer.d.ts +30 -0
  46. package/dist/skill-md/writer.d.ts.map +1 -0
  47. package/dist/skill-md/writer.js +129 -0
  48. package/dist/skill-md/writer.js.map +1 -0
  49. package/package.json +1 -1
@@ -0,0 +1,139 @@
1
+ /**
2
+ * BSO M9 v0.3 — Layer 3 KernelAdapter 注册表 + 装配
3
+ *
4
+ * Refs:
5
+ * - docs/prd/PRD-BSO-M9-HARNESS-HOOKS.md §3.4.3
6
+ *
7
+ * `installAll(host)`:根据 host 命中所有匹配的 adapter,并行 install。
8
+ * 多内核共存策略:M9 P0 取强制力最强的一类(hook-file > deny-pipeline > mcp-only)。
9
+ *
10
+ * 用法:
11
+ * ```ts
12
+ * const host = detectHostInfo();
13
+ * const report = await installAll({ host, cwd: process.cwd(), apply: true });
14
+ * ```
15
+ */
16
+ import { detectHarness } from '../detector.js';
17
+ import { hookFileAdapter } from './hook-file.js';
18
+ import { denyPipelineAdapter } from './deny-pipeline.js';
19
+ import { mcpOnlyAdapter, scanMcpOnlyHosts } from './mcp-only.js';
20
+ import { protocolRejectAdapter } from './protocol-reject.js';
21
+ // ============================================================================
22
+ // 注册表(顺序 = 强制力降序)
23
+ // ============================================================================
24
+ export const REGISTRY = [
25
+ hookFileAdapter,
26
+ denyPipelineAdapter,
27
+ mcpOnlyAdapter,
28
+ // protocolRejectAdapter 不参与 installAll(matches=false),仅 diagnoseAll 引用
29
+ ];
30
+ export const ALL_ADAPTERS = [
31
+ ...REGISTRY,
32
+ protocolRejectAdapter,
33
+ ];
34
+ export function getAdapter(kind) {
35
+ return ALL_ADAPTERS.find((a) => a.kind === kind);
36
+ }
37
+ // ============================================================================
38
+ // 检测 → host info
39
+ // ============================================================================
40
+ /**
41
+ * detectHarness 只识别 v0.2 的 5 个 IDE/CLI host;v0.3 新增的 mcp-only host
42
+ * (Claude Desktop / 5ire / Tome / Witsy)需要走配置文件扫描。
43
+ *
44
+ * 策略:
45
+ * 1. detector 命中 → 返回该 host
46
+ * 2. detector unknown → 扫 mcp-only 候选;若有命中且唯一 → 返回该 host
47
+ * 3. 多个候选或无候选 → 返回 unknown
48
+ */
49
+ export function detectPrimaryHost() {
50
+ const det = detectHarness();
51
+ if (det.harness !== 'unknown') {
52
+ return {
53
+ host: det.harness,
54
+ source: 'detected',
55
+ reason: det.reason,
56
+ };
57
+ }
58
+ const scanned = scanMcpOnlyHosts();
59
+ if (scanned.length === 1) {
60
+ return scanned[0];
61
+ }
62
+ if (scanned.length > 1) {
63
+ return {
64
+ host: 'unknown',
65
+ source: 'scanned',
66
+ reason: `multiple mcp-only hosts found: ${scanned.map((s) => s.host).join(', ')}; use --host=<name> to disambiguate`,
67
+ };
68
+ }
69
+ return {
70
+ host: 'unknown',
71
+ source: 'detected',
72
+ reason: det.reason,
73
+ };
74
+ }
75
+ export async function installAll(opts) {
76
+ const ctx = {
77
+ host: opts.host,
78
+ cwd: opts.cwd,
79
+ apply: opts.apply,
80
+ };
81
+ const matched = opts.forceKernel
82
+ ? ALL_ADAPTERS.filter((a) => a.kind === opts.forceKernel)
83
+ : REGISTRY.filter((a) => a.matches(opts.host));
84
+ const results = [];
85
+ const warnings = [];
86
+ if (matched.length === 0) {
87
+ warnings.push(`host ${opts.host.host} 未命中任何 Layer 3 内核;仅 Layer 1 SKILL.md priming 生效`);
88
+ }
89
+ else {
90
+ // 顺序执行(避免 backup 时戳冲突)
91
+ for (const adapter of matched) {
92
+ try {
93
+ const r = await adapter.install(ctx);
94
+ results.push(r);
95
+ warnings.push(...r.warnings);
96
+ }
97
+ catch (err) {
98
+ warnings.push(`${adapter.kind} install 失败: ${err.message}`);
99
+ }
100
+ }
101
+ }
102
+ // mcp-only 额外 host
103
+ if (opts.alsoInstallMcpHosts && opts.alsoInstallMcpHosts.length > 0) {
104
+ for (const h of opts.alsoInstallMcpHosts) {
105
+ const subCtx = {
106
+ host: { host: h, source: 'forced' },
107
+ cwd: opts.cwd,
108
+ apply: opts.apply,
109
+ };
110
+ try {
111
+ const r = await mcpOnlyAdapter.install(subCtx);
112
+ results.push(r);
113
+ warnings.push(...r.warnings);
114
+ }
115
+ catch (err) {
116
+ warnings.push(`mcp-only ${h} install 失败: ${err.message}`);
117
+ }
118
+ }
119
+ }
120
+ return {
121
+ host: opts.host,
122
+ matched: matched.map((a) => a.kind),
123
+ results,
124
+ warnings,
125
+ };
126
+ }
127
+ export async function diagnoseAll(host, cwd) {
128
+ const ctx = { host, cwd, apply: false };
129
+ const layer3 = await Promise.all(REGISTRY.filter((a) => a.matches(host)).map((a) => a.diagnose(ctx)));
130
+ const layer2 = await protocolRejectAdapter.diagnose(ctx);
131
+ return { host, layer3, layer2 };
132
+ }
133
+ // ============================================================================
134
+ // 兼容映射:把 detector.Harness 映射到 HostId
135
+ // ============================================================================
136
+ export function harnessToHostId(h) {
137
+ return h;
138
+ }
139
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/harness/kernels/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * BSO M9 v0.3 — KernelAdapter 抽象(Layer 3)
3
+ *
4
+ * Refs:
5
+ * - docs/prd/PRD-BSO-M9-HARNESS-HOOKS.md §3.4
6
+ *
7
+ * 哲学转向:v0.2 是 "N harness × N adapter" 扁平设计;v0.3 改为
8
+ * "K 类机制内核 × N host 模板" 抽象 — 一类内核覆盖 N 个 host,
9
+ * 新 host 95% 归入已有内核类别零额外开发。
10
+ *
11
+ * P0 内核(M9):
12
+ * - hook-file (Claude Code / Cursor 1.7+ / Windsurf)
13
+ * - deny-pipeline (OpenClaw)
14
+ * - mcp-only (Claude Desktop / 5ire / Tome / Witsy)
15
+ * - protocol-reject (Layer 2 联动占位,无独立 install/uninstall)
16
+ *
17
+ * P1+ 内核(M9 之后):hook-executable / lifecycle-decorator /
18
+ * filter-pipeline / memory-block / ...(详见 PRD §8)。
19
+ */
20
+ import type { Harness } from '../detector.js';
21
+ export type KernelType = 'hook-file' | 'deny-pipeline' | 'mcp-only' | 'protocol-reject';
22
+ /**
23
+ * 候选 host 标识。注:不复用 Harness 类型 — 因为 mcp-only 内核覆盖了
24
+ * detector.ts 之前没有的 host(Claude Desktop / 5ire / Tome / Witsy)。
25
+ */
26
+ export type HostId = Harness | 'claude-desktop' | '5ire' | 'tome' | 'witsy';
27
+ export interface HostInfo {
28
+ /** 命中的 host 名 */
29
+ host: HostId;
30
+ /** 命中来源(detector / 用户 --host=... / mcp-only 全候选扫描)*/
31
+ source: 'detected' | 'forced' | 'scanned';
32
+ /** 可读提示(doctor 用) */
33
+ reason?: string;
34
+ /** harness 版本,未知则 undefined */
35
+ version?: string;
36
+ }
37
+ export interface InstallContext {
38
+ host: HostInfo;
39
+ cwd: string;
40
+ /** 写入是否真正落盘;false 时只 dry-run(doctor 用) */
41
+ apply: boolean;
42
+ }
43
+ export interface InstalledFile {
44
+ /** 文件绝对路径 */
45
+ path: string;
46
+ /** 操作类型 */
47
+ action: 'created' | 'merged' | 'already-registered' | 'replaced' | 'noop';
48
+ /** 备份路径(若有) */
49
+ backup?: string;
50
+ /** 备注 */
51
+ details?: string;
52
+ }
53
+ export interface InstallResult {
54
+ kernel: KernelType;
55
+ host: HostId;
56
+ /** 写入的文件清单 */
57
+ files: InstalledFile[];
58
+ /** 警告(不阻断 init) */
59
+ warnings: string[];
60
+ }
61
+ export interface DiagnoseResult {
62
+ kernel: KernelType;
63
+ host: HostId;
64
+ /** 该内核当前的强制力等级 */
65
+ level: 'strong' | 'protocol-fallback' | 'soft' | 'absent';
66
+ /** 子检查项(每条独立) */
67
+ checks: Array<{
68
+ name: string;
69
+ ok: boolean;
70
+ detail?: string;
71
+ }>;
72
+ }
73
+ export interface KernelAdapter {
74
+ kind: KernelType;
75
+ /** 该 adapter 覆盖的所有 host */
76
+ supportedHosts: readonly HostId[];
77
+ /** 当前 host 是否归入该内核类别 */
78
+ matches(host: HostInfo): boolean;
79
+ /** 安装:写入配置文件 + 注册 hooks/MCP/deny */
80
+ install(ctx: InstallContext): Promise<InstallResult>;
81
+ /** 卸载:恢复 .bak / 移除注册项 */
82
+ uninstall(ctx: InstallContext): Promise<InstallResult>;
83
+ /** 诊断:检查该 host 当前 install 状态 */
84
+ diagnose(ctx: InstallContext): Promise<DiagnoseResult>;
85
+ }
86
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/harness/kernels/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAM9C,MAAM,MAAM,UAAU,GAClB,WAAW,GACX,eAAe,GACf,UAAU,GACV,iBAAiB,CAAC;AAMtB;;;GAGG;AACH,MAAM,MAAM,MAAM,GACd,OAAO,GACP,gBAAgB,GAChB,MAAM,GACN,MAAM,GACN,OAAO,CAAC;AAEZ,MAAM,WAAW,QAAQ;IACvB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,MAAM,EAAE,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC1C,qBAAqB;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAMD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,0CAA0C;IAC1C,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,aAAa;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW;IACX,MAAM,EACF,SAAS,GACT,QAAQ,GACR,oBAAoB,GACpB,UAAU,GACV,MAAM,CAAC;IACX,eAAe;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS;IACT,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc;IACd,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,mBAAmB;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,KAAK,EAAE,QAAQ,GAAG,mBAAmB,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC1D,iBAAiB;IACjB,MAAM,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,EAAE,EAAE,OAAO,CAAC;QACZ,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;CACJ;AAMD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,UAAU,CAAC;IAEjB,2BAA2B;IAC3B,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAElC,wBAAwB;IACxB,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;IAEjC,oCAAoC;IACpC,OAAO,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAErD,yBAAyB;IACzB,SAAS,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAEvD,gCAAgC;IAChC,QAAQ,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACxD"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * BSO M9 v0.3 — KernelAdapter 抽象(Layer 3)
3
+ *
4
+ * Refs:
5
+ * - docs/prd/PRD-BSO-M9-HARNESS-HOOKS.md §3.4
6
+ *
7
+ * 哲学转向:v0.2 是 "N harness × N adapter" 扁平设计;v0.3 改为
8
+ * "K 类机制内核 × N host 模板" 抽象 — 一类内核覆盖 N 个 host,
9
+ * 新 host 95% 归入已有内核类别零额外开发。
10
+ *
11
+ * P0 内核(M9):
12
+ * - hook-file (Claude Code / Cursor 1.7+ / Windsurf)
13
+ * - deny-pipeline (OpenClaw)
14
+ * - mcp-only (Claude Desktop / 5ire / Tome / Witsy)
15
+ * - protocol-reject (Layer 2 联动占位,无独立 install/uninstall)
16
+ *
17
+ * P1+ 内核(M9 之后):hook-executable / lifecycle-decorator /
18
+ * filter-pipeline / memory-block / ...(详见 PRD §8)。
19
+ */
20
+ export {};
21
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/harness/kernels/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * BSO M9.5 — MCP Protocol-Reject 输出 builder
3
+ *
4
+ * Refs: docs/prd/PRD-BSO-M9-HARNESS-HOOKS.md §3.3.2
5
+ *
6
+ * 双发策略(机制 C):
7
+ * - 机制 A:URLElicitationRequiredError(-32042) → 强 client(MCP 2025-11-25)
8
+ * - 机制 B:result + isError:true → 全 client 兜底
9
+ *
10
+ * 调用方按需选取(HTTP 端点根据 query format= 输出哪个)。
11
+ */
12
+ import type { McpRejectEnvelope, RejectInput } from './types.js';
13
+ export declare function buildElicitationId(taskId: string): string;
14
+ export declare function buildElicitationError(input: RejectInput, elicitationIdOverride?: string): NonNullable<McpRejectEnvelope['error']>;
15
+ export declare function buildIsErrorResult(input: RejectInput): McpRejectEnvelope['result'];
16
+ /**
17
+ * 双发:返回 envelope,HTTP 层按 query/header 选择。
18
+ * 默认 envelope 中两个字段都 populate。
19
+ *
20
+ * 可选传 elicitationIdOverride —— 让 sidecar 提前生成 id 注册到 reviewStore,
21
+ * 保证 envelope.error.data.elicitations[0].elicitationId 与 reviewStore index 对得上。
22
+ */
23
+ export declare function buildRejectEnvelope(input: RejectInput, elicitationIdOverride?: string): McpRejectEnvelope;
24
+ //# sourceMappingURL=builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../src/mcp-output/builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,WAAW,EACZ,MAAM,YAAY,CAAC;AAMpB,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAIzD;AAiCD,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,WAAW,EAClB,qBAAqB,CAAC,EAAE,MAAM,GAC7B,WAAW,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAqBzC;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAclF;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,WAAW,EAClB,qBAAqB,CAAC,EAAE,MAAM,GAC7B,iBAAiB,CAKnB"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * BSO M9.5 — MCP Protocol-Reject 输出 builder
3
+ *
4
+ * Refs: docs/prd/PRD-BSO-M9-HARNESS-HOOKS.md §3.3.2
5
+ *
6
+ * 双发策略(机制 C):
7
+ * - 机制 A:URLElicitationRequiredError(-32042) → 强 client(MCP 2025-11-25)
8
+ * - 机制 B:result + isError:true → 全 client 兜底
9
+ *
10
+ * 调用方按需选取(HTTP 端点根据 query format= 输出哪个)。
11
+ */
12
+ // ============================================================================
13
+ // elicitation id 生成
14
+ // ============================================================================
15
+ export function buildElicitationId(taskId) {
16
+ // 不引入 crypto;用时间戳 + taskId hash 做唯一 id(生命周期内可识别即可)
17
+ const ts = Date.now().toString(36);
18
+ return `skillfm-deny-${taskId}-${ts}`;
19
+ }
20
+ function buildDenyReviewUrl(sidecarBaseUrl, taskId) {
21
+ return `${sidecarBaseUrl.replace(/\/$/, '')}/deny-review/${encodeURIComponent(taskId)}`;
22
+ }
23
+ // ============================================================================
24
+ // 文案
25
+ // ============================================================================
26
+ function buildShortMessage(input) {
27
+ const parts = [`SkillFM 9 红线拦截`];
28
+ if (input.redline)
29
+ parts.push(`(${input.redline})`);
30
+ parts.push('— 需用户审阅');
31
+ return parts.join(' ');
32
+ }
33
+ function buildLongText(input) {
34
+ const lines = [];
35
+ lines.push(`SkillFM 拦截:本任务${input.tool ? `调用 \`${input.tool}\` 时` : ''}触发 9 红线${input.redline ? ` ${input.redline}` : ''}。`);
36
+ if (input.tier)
37
+ lines.push(`风险等级:Tier-${input.tier}。`);
38
+ lines.push(`原因:${input.reason}`);
39
+ if (input.hint)
40
+ lines.push(`建议:${input.hint}`);
41
+ lines.push('');
42
+ lines.push(`审阅入口:${buildDenyReviewUrl(input.sidecarBaseUrl, input.task_id)}`);
43
+ lines.push('用户在审阅页同意后,SkillFM 会发 notifications/elicitation/complete,client 自动 retry。');
44
+ return lines.join('\n');
45
+ }
46
+ // ============================================================================
47
+ // builders
48
+ // ============================================================================
49
+ export function buildElicitationError(input, elicitationIdOverride) {
50
+ const elicitationId = elicitationIdOverride ?? buildElicitationId(input.task_id);
51
+ const url = buildDenyReviewUrl(input.sidecarBaseUrl, input.task_id);
52
+ return {
53
+ jsonrpc: '2.0',
54
+ id: input.requestId ?? null,
55
+ error: {
56
+ code: -32042,
57
+ message: buildShortMessage(input),
58
+ data: {
59
+ elicitations: [
60
+ {
61
+ mode: 'url',
62
+ elicitationId,
63
+ url,
64
+ message: buildLongText(input),
65
+ },
66
+ ],
67
+ },
68
+ },
69
+ };
70
+ }
71
+ export function buildIsErrorResult(input) {
72
+ return {
73
+ jsonrpc: '2.0',
74
+ id: input.requestId ?? null,
75
+ result: {
76
+ content: [
77
+ {
78
+ type: 'text',
79
+ text: buildLongText(input),
80
+ },
81
+ ],
82
+ isError: true,
83
+ },
84
+ };
85
+ }
86
+ /**
87
+ * 双发:返回 envelope,HTTP 层按 query/header 选择。
88
+ * 默认 envelope 中两个字段都 populate。
89
+ *
90
+ * 可选传 elicitationIdOverride —— 让 sidecar 提前生成 id 注册到 reviewStore,
91
+ * 保证 envelope.error.data.elicitations[0].elicitationId 与 reviewStore index 对得上。
92
+ */
93
+ export function buildRejectEnvelope(input, elicitationIdOverride) {
94
+ return {
95
+ error: buildElicitationError(input, elicitationIdOverride),
96
+ result: buildIsErrorResult(input),
97
+ };
98
+ }
99
+ //# sourceMappingURL=builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.js","sourceRoot":"","sources":["../../src/mcp-output/builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,+EAA+E;AAC/E,oBAAoB;AACpB,+EAA+E;AAE/E,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,mDAAmD;IACnD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACnC,OAAO,gBAAgB,MAAM,IAAI,EAAE,EAAE,CAAC;AACxC,CAAC;AAED,SAAS,kBAAkB,CAAC,cAAsB,EAAE,MAAc;IAChE,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,gBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC;AAC1F,CAAC;AAED,+EAA+E;AAC/E,KAAK;AACL,+EAA+E;AAE/E,SAAS,iBAAiB,CAAC,KAAkB;IAC3C,MAAM,KAAK,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACjC,IAAI,KAAK,CAAC,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC;IACpD,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtB,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,SAAS,aAAa,CAAC,KAAkB;IACvC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,iBAAiB,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,KAAK,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,UAAU,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC7H,IAAI,KAAK,CAAC,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,aAAa,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC;IACvD,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACjC,IAAI,KAAK,CAAC,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAC/C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,QAAQ,kBAAkB,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC9E,KAAK,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;IACvF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,+EAA+E;AAC/E,WAAW;AACX,+EAA+E;AAE/E,MAAM,UAAU,qBAAqB,CACnC,KAAkB,EAClB,qBAA8B;IAE9B,MAAM,aAAa,GAAG,qBAAqB,IAAI,kBAAkB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjF,MAAM,GAAG,GAAG,kBAAkB,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACpE,OAAO;QACL,OAAO,EAAE,KAAK;QACd,EAAE,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI;QAC3B,KAAK,EAAE;YACL,IAAI,EAAE,CAAC,KAAK;YACZ,OAAO,EAAE,iBAAiB,CAAC,KAAK,CAAC;YACjC,IAAI,EAAE;gBACJ,YAAY,EAAE;oBACZ;wBACE,IAAI,EAAE,KAAK;wBACX,aAAa;wBACb,GAAG;wBACH,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC;qBAC9B;iBACF;aACF;SACF;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAkB;IACnD,OAAO;QACL,OAAO,EAAE,KAAK;QACd,EAAE,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI;QAC3B,MAAM,EAAE;YACN,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,aAAa,CAAC,KAAK,CAAC;iBAC3B;aACF;YACD,OAAO,EAAE,IAAI;SACd;KACF,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CACjC,KAAkB,EAClB,qBAA8B;IAE9B,OAAO;QACL,KAAK,EAAE,qBAAqB,CAAC,KAAK,EAAE,qBAAqB,CAAC;QAC1D,MAAM,EAAE,kBAAkB,CAAC,KAAK,CAAC;KAClC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * BSO M9.5 — /deny-review/:task_id HTML 审阅页 + elicitation/complete 事件流
3
+ *
4
+ * Refs: docs/prd/PRD-BSO-M9-HARNESS-HOOKS.md §3.3.4
5
+ *
6
+ * 用户在浏览器里看到这个页面后:
7
+ * - "同意" → POST /deny-review/:task_id/approve → reviewStore.decide → 广播 complete 事件
8
+ * - "修改" → POST /deny-review/:task_id/modify → 同上 (decision='modified')
9
+ * - "撤销" → POST /deny-review/:task_id/cancel → 同上 (decision='cancelled')
10
+ *
11
+ * 事件订阅(M9.5 L2-4):
12
+ * - SSE: GET /internal/mcp/elicitation/stream?elicitationId=<id>
13
+ * - Polling: GET /internal/mcp/elicitation/poll?elicitationId=<id>
14
+ *
15
+ * 注:MCP host 的"自动 retry"由 SkillFM MCP bridge(P1+ 独立进程)拿到 complete 事件
16
+ * 后通过 MCP transport 转发 notifications/elicitation/complete 给 client。本文件
17
+ * 只负责 sidecar 侧事件源 + 订阅接口。
18
+ */
19
+ import { EventEmitter } from 'node:events';
20
+ import type { RejectInput } from './types.js';
21
+ export type ReviewDecision = 'pending' | 'approved' | 'cancelled' | 'modified';
22
+ export interface ReviewRecord {
23
+ task_id: string;
24
+ decision: ReviewDecision;
25
+ created_at: number;
26
+ decided_at?: number;
27
+ reject: RejectInput;
28
+ /** 与 MCP -32042 envelope 内 elicitations[].elicitationId 配对 */
29
+ elicitation_id?: string;
30
+ }
31
+ /**
32
+ * MCP 标准 notifications/elicitation/complete payload。
33
+ * client 拿到后会自动 retry 原 tool call。
34
+ */
35
+ export interface ElicitationCompletePayload {
36
+ jsonrpc: '2.0';
37
+ method: 'notifications/elicitation/complete';
38
+ params: {
39
+ elicitationId: string;
40
+ /** MCP spec 三态 */
41
+ action: 'accept' | 'decline' | 'cancel';
42
+ /** SkillFM 自定义补充字段 */
43
+ skillfm_decision: ReviewDecision;
44
+ decided_at: number;
45
+ };
46
+ }
47
+ export declare function buildElicitationCompletePayload(rec: ReviewRecord): ElicitationCompletePayload | null;
48
+ declare class ReviewStore extends EventEmitter {
49
+ private store;
50
+ /** elicitation_id → task_id 反向索引(订阅按 elicitationId 走,broadcast 按 elicitationId)*/
51
+ private elicitationIndex;
52
+ open(input: RejectInput, elicitation_id?: string): ReviewRecord;
53
+ decide(task_id: string, decision: Exclude<ReviewDecision, 'pending'>): ReviewRecord | null;
54
+ get(task_id: string): ReviewRecord | null;
55
+ getByElicitationId(elicitation_id: string): ReviewRecord | null;
56
+ list(): ReviewRecord[];
57
+ /** 测试用:清空 */
58
+ reset(): void;
59
+ }
60
+ export declare const reviewStore: ReviewStore;
61
+ export declare function renderReviewPage(rec: ReviewRecord): string;
62
+ export declare function renderNotFoundPage(taskId: string): string;
63
+ export {};
64
+ //# sourceMappingURL=deny-review.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deny-review.d.ts","sourceRoot":"","sources":["../../src/mcp-output/deny-review.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAM9C,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,CAAC;AAE/E,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,cAAc,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,WAAW,CAAC;IACpB,8DAA8D;IAC9D,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,KAAK,CAAC;IACf,MAAM,EAAE,oCAAoC,CAAC;IAC7C,MAAM,EAAE;QACN,aAAa,EAAE,MAAM,CAAC;QACtB,kBAAkB;QAClB,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;QACxC,sBAAsB;QACtB,gBAAgB,EAAE,cAAc,CAAC;QACjC,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AASD,wBAAgB,+BAA+B,CAC7C,GAAG,EAAE,YAAY,GAChB,0BAA0B,GAAG,IAAI,CAYnC;AAED,cAAM,WAAY,SAAQ,YAAY;IACpC,OAAO,CAAC,KAAK,CAAmC;IAChD,kFAAkF;IAClF,OAAO,CAAC,gBAAgB,CAA6B;IAErD,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,YAAY;IAuB/D,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,cAAc,EAAE,SAAS,CAAC,GAAG,YAAY,GAAG,IAAI;IAgB1F,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAIzC,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAK/D,IAAI,IAAI,YAAY,EAAE;IAItB,aAAa;IACb,KAAK,IAAI,IAAI;CAKd;AAED,eAAO,MAAM,WAAW,aAAoB,CAAC;AAe7C,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAwE1D;AAeD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAYzD"}