@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,212 @@
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
+ function decisionToMcpAction(d) {
21
+ if (d === 'approved')
22
+ return 'accept';
23
+ if (d === 'modified')
24
+ return 'decline'; // 用户改 ScriptCard = 拒绝原 tool call
25
+ if (d === 'cancelled')
26
+ return 'cancel';
27
+ return 'cancel'; // pending 不该出现,保守 cancel
28
+ }
29
+ export function buildElicitationCompletePayload(rec) {
30
+ if (!rec.elicitation_id || rec.decision === 'pending')
31
+ return null;
32
+ return {
33
+ jsonrpc: '2.0',
34
+ method: 'notifications/elicitation/complete',
35
+ params: {
36
+ elicitationId: rec.elicitation_id,
37
+ action: decisionToMcpAction(rec.decision),
38
+ skillfm_decision: rec.decision,
39
+ decided_at: rec.decided_at ?? Date.now(),
40
+ },
41
+ };
42
+ }
43
+ class ReviewStore extends EventEmitter {
44
+ store = new Map();
45
+ /** elicitation_id → task_id 反向索引(订阅按 elicitationId 走,broadcast 按 elicitationId)*/
46
+ elicitationIndex = new Map();
47
+ open(input, elicitation_id) {
48
+ const existing = this.store.get(input.task_id);
49
+ if (existing && existing.decision === 'pending') {
50
+ // upgrade elicitation_id 如果新调用带了 — 避免老 envelope 失活
51
+ if (elicitation_id && elicitation_id !== existing.elicitation_id) {
52
+ if (existing.elicitation_id)
53
+ this.elicitationIndex.delete(existing.elicitation_id);
54
+ existing.elicitation_id = elicitation_id;
55
+ this.elicitationIndex.set(elicitation_id, input.task_id);
56
+ }
57
+ return existing;
58
+ }
59
+ const rec = {
60
+ task_id: input.task_id,
61
+ decision: 'pending',
62
+ created_at: Date.now(),
63
+ reject: input,
64
+ elicitation_id,
65
+ };
66
+ this.store.set(input.task_id, rec);
67
+ if (elicitation_id)
68
+ this.elicitationIndex.set(elicitation_id, input.task_id);
69
+ return rec;
70
+ }
71
+ decide(task_id, decision) {
72
+ const rec = this.store.get(task_id);
73
+ if (!rec)
74
+ return null;
75
+ rec.decision = decision;
76
+ rec.decided_at = Date.now();
77
+ // 广播 — 订阅者按 elicitation_id 收
78
+ if (rec.elicitation_id) {
79
+ const payload = buildElicitationCompletePayload(rec);
80
+ if (payload) {
81
+ this.emit('elicitation:complete', { elicitationId: rec.elicitation_id, payload, record: rec });
82
+ this.emit(`elicitation:${rec.elicitation_id}`, { payload, record: rec });
83
+ }
84
+ }
85
+ return rec;
86
+ }
87
+ get(task_id) {
88
+ return this.store.get(task_id) ?? null;
89
+ }
90
+ getByElicitationId(elicitation_id) {
91
+ const tid = this.elicitationIndex.get(elicitation_id);
92
+ return tid ? this.get(tid) : null;
93
+ }
94
+ list() {
95
+ return Array.from(this.store.values());
96
+ }
97
+ /** 测试用:清空 */
98
+ reset() {
99
+ this.store.clear();
100
+ this.elicitationIndex.clear();
101
+ this.removeAllListeners();
102
+ }
103
+ }
104
+ export const reviewStore = new ReviewStore();
105
+ // ============================================================================
106
+ // HTML 渲染(极简内联 CSS,无外部资源)
107
+ // ============================================================================
108
+ function escapeHtml(s) {
109
+ return s
110
+ .replace(/&/g, '&amp;')
111
+ .replace(/</g, '&lt;')
112
+ .replace(/>/g, '&gt;')
113
+ .replace(/"/g, '&quot;')
114
+ .replace(/'/g, '&#39;');
115
+ }
116
+ export function renderReviewPage(rec) {
117
+ const r = rec.reject;
118
+ const decided = rec.decision !== 'pending';
119
+ return `<!doctype html>
120
+ <html lang="zh-CN">
121
+ <head>
122
+ <meta charset="utf-8" />
123
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
124
+ <title>SkillFM 风险任务审阅 · ${escapeHtml(r.task_id)}</title>
125
+ <style>
126
+ body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", sans-serif;
127
+ margin: 0; padding: 2rem; max-width: 720px; margin-left: auto; margin-right: auto;
128
+ color: #1a1a1a; background: #f7f7f8; line-height: 1.6; }
129
+ h1 { font-size: 1.4rem; margin: 0 0 .5rem; }
130
+ .badge { display: inline-block; padding: 2px 10px; border-radius: 12px; font-size: .8rem; font-weight: 600; }
131
+ .badge-A { background: #fee2e2; color: #991b1b; }
132
+ .badge-B { background: #fef3c7; color: #92400e; }
133
+ .badge-C { background: #dcfce7; color: #166534; }
134
+ .card { background: #fff; padding: 1.5rem; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,.05); margin-top: 1rem; }
135
+ .meta { color: #666; font-size: .85rem; }
136
+ pre { background: #f1f1f3; padding: 1rem; border-radius: 8px; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word; font-size: .9rem; }
137
+ .actions { margin-top: 1.5rem; display: flex; gap: .75rem; flex-wrap: wrap; }
138
+ button { padding: .6rem 1.2rem; font-size: .95rem; border: none; border-radius: 8px; cursor: pointer; font-weight: 500; }
139
+ .btn-approve { background: #16a34a; color: #fff; }
140
+ .btn-cancel { background: #dc2626; color: #fff; }
141
+ .btn-modify { background: #2563eb; color: #fff; }
142
+ .btn-disabled { background: #d1d5db; color: #6b7280; cursor: not-allowed; }
143
+ .status { margin-top: 1rem; padding: 1rem; border-radius: 8px; font-weight: 500; }
144
+ .status-approved { background: #dcfce7; color: #166534; }
145
+ .status-cancelled { background: #fee2e2; color: #991b1b; }
146
+ .status-modified { background: #dbeafe; color: #1e40af; }
147
+ </style>
148
+ </head>
149
+ <body>
150
+ <h1>⛔ SkillFM 风险任务审阅</h1>
151
+ <div class="meta">
152
+ Task ID: <code>${escapeHtml(r.task_id)}</code>
153
+ ${r.tier ? ` · <span class="badge badge-${r.tier}">Tier-${r.tier}</span>` : ''}
154
+ ${r.redline ? ` · 触发 ${escapeHtml(r.redline)}` : ''}
155
+ </div>
156
+
157
+ <div class="card">
158
+ <h2 style="margin-top:0;font-size:1rem;">原因</h2>
159
+ <p>${escapeHtml(r.reason)}</p>
160
+ ${r.hint ? `<h2 style="font-size:1rem;">建议</h2><p>${escapeHtml(r.hint)}</p>` : ''}
161
+ ${r.tool ? `<div class="meta">触发 tool: <code>${escapeHtml(r.tool)}</code></div>` : ''}
162
+ </div>
163
+
164
+ ${decided
165
+ ? `<div class="status status-${rec.decision}">
166
+ 已${decisionLabel(rec.decision)}(${new Date(rec.decided_at).toLocaleString('zh-CN')})
167
+ </div>`
168
+ : `<div class="actions">
169
+ <button class="btn-approve" onclick="decide('approve')">同意(让 agent 继续)</button>
170
+ <button class="btn-modify" onclick="decide('modify')">修改 ScriptCard</button>
171
+ <button class="btn-cancel" onclick="decide('cancel')">撤销(abort 任务)</button>
172
+ </div>
173
+ <script>
174
+ async function decide(action) {
175
+ const r = await fetch('/deny-review/${encodeURIComponent(r.task_id)}/' + action, { method: 'POST' });
176
+ if (r.ok) location.reload(); else alert('操作失败:' + r.status);
177
+ }
178
+ </script>`}
179
+
180
+ <p class="meta" style="margin-top:2rem;">
181
+ 本页由 SkillFM sidecar 本地服务渲染(loopback only)。
182
+ 决策后 SkillFM 会通过 MCP <code>notifications/elicitation/complete</code> 通知 agent。
183
+ </p>
184
+ </body>
185
+ </html>`;
186
+ }
187
+ function decisionLabel(d) {
188
+ switch (d) {
189
+ case 'approved':
190
+ return '同意';
191
+ case 'cancelled':
192
+ return '撤销';
193
+ case 'modified':
194
+ return '改走 ScriptCard 修改流程';
195
+ default:
196
+ return '处理';
197
+ }
198
+ }
199
+ export function renderNotFoundPage(taskId) {
200
+ return `<!doctype html>
201
+ <html lang="zh-CN"><meta charset="utf-8"><title>SkillFM · 未找到</title>
202
+ <body style="font-family:sans-serif;padding:2rem;max-width:640px;margin:auto;">
203
+ <h1>404 — Task <code>${escapeHtml(taskId)}</code> 未找到</h1>
204
+ <p>该 task_id 没有 pending 审阅记录。可能:</p>
205
+ <ul>
206
+ <li>该任务已经被审阅过(决策已记录)</li>
207
+ <li>sidecar 重启后内存状态已清空</li>
208
+ <li>URL 拼写错误</li>
209
+ </ul>
210
+ </body></html>`;
211
+ }
212
+ //# sourceMappingURL=deny-review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deny-review.js","sourceRoot":"","sources":["../../src/mcp-output/deny-review.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * BSO M9.5 — MCP Protocol-Reject 输出层类型
3
+ *
4
+ * Refs:
5
+ * - docs/prd/PRD-BSO-M9-HARNESS-HOOKS.md §3.3
6
+ * - docs/research/EMERGING-AGENT-PRODUCTS-2026-04-19.md §3
7
+ * - MCP spec 2025-11-25
8
+ * · tools/call response with isError
9
+ * · elicitation/create
10
+ * · URLElicitationRequiredError (-32042)
11
+ */
12
+ export declare const MCP_OUTPUT_VERSION = "v2";
13
+ export declare const MCP_OUTPUT_FEATURES: readonly ["isError", "elicitation", "url-elicitation-required-error"];
14
+ export type McpOutputFeature = (typeof MCP_OUTPUT_FEATURES)[number];
15
+ export interface RejectInput {
16
+ /** 任务 id(生命周期内唯一,用于 elicitation 配对) */
17
+ task_id: string;
18
+ /** 触发的 9 红线 ID(S1-S9) */
19
+ redline?: string;
20
+ /** 风险等级 */
21
+ tier?: 'A' | 'B' | 'C';
22
+ /** 失败原因(中文,给用户看) */
23
+ reason: string;
24
+ /** 操作建议(中文,给用户看) */
25
+ hint?: string;
26
+ /** 触发的 tool 名 */
27
+ tool?: string;
28
+ /** sidecar 自身 base URL(构造 /deny-review/:task_id 用) */
29
+ sidecarBaseUrl: string;
30
+ /** request id (jsonrpc) — 镜像回 MCP error response */
31
+ requestId?: string | number | null;
32
+ }
33
+ export interface McpRejectEnvelope {
34
+ /** RFC 8259: 协议层错误(机制 A)*/
35
+ error?: {
36
+ jsonrpc: '2.0';
37
+ id: string | number | null;
38
+ error: {
39
+ code: -32042;
40
+ message: string;
41
+ data: {
42
+ elicitations: Array<{
43
+ mode: 'url';
44
+ elicitationId: string;
45
+ url: string;
46
+ message: string;
47
+ }>;
48
+ };
49
+ };
50
+ };
51
+ /** result + isError(机制 B,最广兼容)*/
52
+ result: {
53
+ jsonrpc: '2.0';
54
+ id: string | number | null;
55
+ result: {
56
+ content: Array<{
57
+ type: 'text';
58
+ text: string;
59
+ }>;
60
+ isError: true;
61
+ };
62
+ };
63
+ }
64
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/mcp-output/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,eAAO,MAAM,kBAAkB,OAAO,CAAC;AAEvC,eAAO,MAAM,mBAAmB,uEAItB,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAMpE,MAAM,WAAW,WAAW;IAC1B,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW;IACX,IAAI,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IACvB,oBAAoB;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iBAAiB;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,cAAc,EAAE,MAAM,CAAC;IACvB,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CACpC;AAMD,MAAM,WAAW,iBAAiB;IAChC,2BAA2B;IAC3B,KAAK,CAAC,EAAE;QACN,OAAO,EAAE,KAAK,CAAC;QACf,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;QAC3B,KAAK,EAAE;YACL,IAAI,EAAE,CAAC,KAAK,CAAC;YACb,OAAO,EAAE,MAAM,CAAC;YAChB,IAAI,EAAE;gBACJ,YAAY,EAAE,KAAK,CAAC;oBAClB,IAAI,EAAE,KAAK,CAAC;oBACZ,aAAa,EAAE,MAAM,CAAC;oBACtB,GAAG,EAAE,MAAM,CAAC;oBACZ,OAAO,EAAE,MAAM,CAAC;iBACjB,CAAC,CAAC;aACJ,CAAC;SACH,CAAC;KACH,CAAC;IACF,iCAAiC;IACjC,MAAM,EAAE;QACN,OAAO,EAAE,KAAK,CAAC;QACf,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;QAC3B,MAAM,EAAE;YACN,OAAO,EAAE,KAAK,CAAC;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,IAAI,EAAE,MAAM,CAAA;aAAE,CAAC,CAAC;YAC/C,OAAO,EAAE,IAAI,CAAC;SACf,CAAC;KACH,CAAC;CACH"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * BSO M9.5 — MCP Protocol-Reject 输出层类型
3
+ *
4
+ * Refs:
5
+ * - docs/prd/PRD-BSO-M9-HARNESS-HOOKS.md §3.3
6
+ * - docs/research/EMERGING-AGENT-PRODUCTS-2026-04-19.md §3
7
+ * - MCP spec 2025-11-25
8
+ * · tools/call response with isError
9
+ * · elicitation/create
10
+ * · URLElicitationRequiredError (-32042)
11
+ */
12
+ // ============================================================================
13
+ // 输出层版本(doctor probe 用)
14
+ // ============================================================================
15
+ export const MCP_OUTPUT_VERSION = 'v2';
16
+ export const MCP_OUTPUT_FEATURES = [
17
+ 'isError',
18
+ 'elicitation',
19
+ 'url-elicitation-required-error',
20
+ ];
21
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/mcp-output/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,+EAA+E;AAC/E,wBAAwB;AACxB,+EAA+E;AAE/E,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEvC,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,SAAS;IACT,aAAa;IACb,gCAAgC;CACxB,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * BSO M9 v0.3 — Layer 1: SKILL.md 模板(兼容 Anthropic Skills 格式)
3
+ *
4
+ * Refs:
5
+ * - docs/prd/PRD-BSO-M9-HARNESS-HOOKS.md §3.2
6
+ * - 主公决策 Q2=B': Layer 1 文件格式 100% 对齐 Anthropic Skills 标准;
7
+ * Layer 2/3 拦截协议保持 SkillFM 差异化。
8
+ *
9
+ * 文件格式:YAML frontmatter + Markdown body
10
+ * frontmatter 字段(Anthropic Skills 标准):
11
+ * - name: 唯一 slug
12
+ * - description: 何时触发本 skill 的描述(写给 LLM 看)
13
+ * - license: 默认 Apache-2.0
14
+ * - allowed-tools: skill 调用的 tool 白名单
15
+ * - metadata: 自定义字段(嵌套,不污染顶层)
16
+ *
17
+ * 写入位置(由 writer.ts 决定):
18
+ * - 项目级:./SKILL.md
19
+ * - Anthropic Claude Code 用户级(可选):~/.claude/skills/skillfm-bso/SKILL.md
20
+ */
21
+ export type SkillLang = 'zh' | 'en' | 'auto';
22
+ export declare const SKILL_MD_BEGIN = "<!-- SKILLFM-SKILL-BEGIN: do not edit, managed by @skillfm/local -->";
23
+ export declare const SKILL_MD_END = "<!-- SKILLFM-SKILL-END -->";
24
+ export interface BuildSkillMdOptions {
25
+ lang?: SkillLang;
26
+ /** 是否包含 SKILLFM-BEGIN/END 边界(写到现有文件时建议 true)*/
27
+ withBoundaryMarkers?: boolean;
28
+ }
29
+ export declare function buildSkillMd(opts?: BuildSkillMdOptions): string;
30
+ //# sourceMappingURL=template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../src/skill-md/template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AA+CH,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;AAwI7C,eAAO,MAAM,cAAc,yEAAyE,CAAC;AACrG,eAAO,MAAM,YAAY,+BAA+B,CAAC;AAMzD,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,+CAA+C;IAC/C,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,wBAAgB,YAAY,CAAC,IAAI,GAAE,mBAAwB,GAAG,MAAM,CASnE"}
@@ -0,0 +1,194 @@
1
+ /**
2
+ * BSO M9 v0.3 — Layer 1: SKILL.md 模板(兼容 Anthropic Skills 格式)
3
+ *
4
+ * Refs:
5
+ * - docs/prd/PRD-BSO-M9-HARNESS-HOOKS.md §3.2
6
+ * - 主公决策 Q2=B': Layer 1 文件格式 100% 对齐 Anthropic Skills 标准;
7
+ * Layer 2/3 拦截协议保持 SkillFM 差异化。
8
+ *
9
+ * 文件格式:YAML frontmatter + Markdown body
10
+ * frontmatter 字段(Anthropic Skills 标准):
11
+ * - name: 唯一 slug
12
+ * - description: 何时触发本 skill 的描述(写给 LLM 看)
13
+ * - license: 默认 Apache-2.0
14
+ * - allowed-tools: skill 调用的 tool 白名单
15
+ * - metadata: 自定义字段(嵌套,不污染顶层)
16
+ *
17
+ * 写入位置(由 writer.ts 决定):
18
+ * - 项目级:./SKILL.md
19
+ * - Anthropic Claude Code 用户级(可选):~/.claude/skills/skillfm-bso/SKILL.md
20
+ */
21
+ import { readFileSync } from 'node:fs';
22
+ import { join } from 'node:path';
23
+ import { fileURLToPath } from 'node:url';
24
+ // ============================================================================
25
+ // 元信息(运行时读包 version,避免硬编码漂移)
26
+ // ============================================================================
27
+ function loadPackageVersion() {
28
+ const here = __dirnameSafe();
29
+ // 候选路径(覆盖 dist/skill-md/, src/skill-md/, 以及 npm install 安装路径)
30
+ const candidates = [
31
+ join(here, '..', '..', 'package.json'), // dist/skill-md/template.js → ../../package.json
32
+ join(here, '..', 'package.json'),
33
+ join(here, '..', '..', '..', 'package.json'),
34
+ ];
35
+ for (const p of candidates) {
36
+ try {
37
+ const raw = readFileSync(p, 'utf-8');
38
+ const pkg = JSON.parse(raw);
39
+ if (pkg?.name === '@skillfm/local' && typeof pkg.version === 'string') {
40
+ return pkg.version;
41
+ }
42
+ }
43
+ catch {
44
+ // continue
45
+ }
46
+ }
47
+ return 'unknown';
48
+ }
49
+ function __dirnameSafe() {
50
+ try {
51
+ if (typeof import.meta !== 'undefined' && import.meta.url) {
52
+ return fileURLToPath(new URL('.', import.meta.url));
53
+ }
54
+ }
55
+ catch {
56
+ // fall through
57
+ }
58
+ return process.cwd();
59
+ }
60
+ const DEFAULT_FRONTMATTER = () => ({
61
+ name: 'skillfm-bso-priming',
62
+ description: 'SkillFM BSO 协议 priming — 触发条件:当前 workspace 装了 @skillfm/local 且任务涉及破坏性操作(写文件 / 改代码 / 跑命令 / 调外部 API / 涉及支付)时自动加载',
63
+ license: 'Apache-2.0',
64
+ 'allowed-tools': [
65
+ 'mcp__skillfm__brain_run',
66
+ 'mcp__skillfm__list_skills',
67
+ 'mcp__skillfm__my_status',
68
+ 'mcp__skillfm__guard_status',
69
+ ],
70
+ metadata: {
71
+ skillfm_version: loadPackageVersion(),
72
+ bso_version: 'v1.1',
73
+ layer: 1,
74
+ homepage: 'https://skillfm.ai',
75
+ },
76
+ });
77
+ function renderFrontmatterYaml(fm) {
78
+ // 手写极简 YAML(避免引入 yaml 依赖;@skillfm/local zero-dep 原则)
79
+ const lines = [
80
+ '---',
81
+ `name: ${fm.name}`,
82
+ `description: ${quoteIfNeeded(fm.description)}`,
83
+ `license: ${fm.license}`,
84
+ 'allowed-tools:',
85
+ ...fm['allowed-tools'].map((t) => ` - ${t}`),
86
+ 'metadata:',
87
+ ` skillfm_version: "${fm.metadata.skillfm_version}"`,
88
+ ` bso_version: "${fm.metadata.bso_version}"`,
89
+ ` layer: ${fm.metadata.layer}`,
90
+ ` homepage: ${fm.metadata.homepage}`,
91
+ '---',
92
+ ];
93
+ return lines.join('\n');
94
+ }
95
+ function quoteIfNeeded(s) {
96
+ // 含特殊字符(含 ":"、换行、单/双引号、#)→ 加双引号 + escape
97
+ if (/[:"\n#]/.test(s) || /^[ \t]/.test(s)) {
98
+ return `"${s.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
99
+ }
100
+ return s;
101
+ }
102
+ // ============================================================================
103
+ // body 模板(zh / en)
104
+ // ============================================================================
105
+ const BODY_ZH = `# SkillFM BSO 协议 priming
106
+
107
+ ## 你必须知道
108
+
109
+ 本 workspace 启用了 SkillFM BSO(Behavioral Soul Override)协议。
110
+ 任何破坏性操作(写文件 / 改代码 / 跑命令 / 调外部 API / 涉及支付)开始前,
111
+ 必须先调用 \`mcp__skillfm__brain_run\`,拿到 ScriptCard 后按 \`must_do\` 顺序执行。
112
+
113
+ 未先 call brain_run 直接执行破坏性操作 → harness 层 hook 会 \`exit 2\` 阻断;
114
+ 若 hook 失效 → MCP 协议层会以 \`URLElicitationRequiredError\` 要求用户在
115
+ SkillFM 控制台审阅;若两者都被绕过 → sidecar 9 红线在协议契约层兜底拒绝。
116
+
117
+ ## 三层防御一览(仅供你理解,不必复述)
118
+
119
+ - L1 你的 priming(本文件) · 跟随率 70-95%
120
+ - L2 sidecar 协议 + MCP reject · 协议级强制
121
+ - L3 brain 仲裁 + harness hook · 机械级强制
122
+
123
+ ## 何时该 call brain_run
124
+
125
+ - 涉及业务流程编排(多步骤 + 风险评级)
126
+ - 用户首次发出某类请求(无历史 ScriptCard 缓存)
127
+ - 检测到 \`mode=strict\` / Tier ≥ B 的任务
128
+ - 用户要赚钱 / 出交付物 / 走对外发布场景
129
+
130
+ ## 边界
131
+
132
+ - 不要编造价格、收入、市场数据 — 引用 pipeline 返回的数字
133
+ - 用户要交付物且你能帮忙 → 走 \`brain_run\`,不要凭记忆手搓
134
+ - 移除:\`skillfm uninstall\` 或直接删本块(含 \`<!-- SKILLFM-BEGIN -->\` 边界)
135
+ `;
136
+ const BODY_EN = `# SkillFM BSO Protocol priming
137
+
138
+ ## You must know
139
+
140
+ This workspace has the SkillFM BSO (Behavioral Soul Override) protocol enabled.
141
+ Before ANY destructive operation (file write / code edit / shell command /
142
+ external API call / payment), you MUST first call \`mcp__skillfm__brain_run\`
143
+ and follow the returned ScriptCard's \`must_do\` order.
144
+
145
+ Skipping brain_run and going straight to destructive ops → the harness-layer
146
+ hook will \`exit 2\` to block you; if the hook is disabled → the MCP protocol
147
+ layer will return \`URLElicitationRequiredError\` forcing the user to review in
148
+ SkillFM console; if both are bypassed → the sidecar 9 redlines reject at the
149
+ contract layer.
150
+
151
+ ## Three-layer defense (for your understanding; do not narrate)
152
+
153
+ - L1 your priming (this file) · 70-95% follow rate
154
+ - L2 sidecar + MCP reject · protocol-level enforcement
155
+ - L3 brain arbitration + harness hook · mechanical enforcement
156
+
157
+ ## When to call brain_run
158
+
159
+ - Multi-step business orchestration with risk tiers
160
+ - First time the user makes this kind of request (no prior ScriptCard cache)
161
+ - Detected \`mode=strict\` or Tier ≥ B tasks
162
+ - User wants to earn money / produce deliverables / publish externally
163
+
164
+ ## Boundary
165
+
166
+ - Never fabricate pricing / earnings / market data — quote pipeline output
167
+ - If the user wants a deliverable you could help with → route through \`brain_run\`
168
+ - To remove: \`skillfm uninstall\` or delete this block (incl. SKILLFM-BEGIN markers)
169
+ `;
170
+ // ============================================================================
171
+ // 边界标记(与 priming.ts 一致,复用 uninstall 命令)
172
+ // ============================================================================
173
+ export const SKILL_MD_BEGIN = '<!-- SKILLFM-SKILL-BEGIN: do not edit, managed by @skillfm/local -->';
174
+ export const SKILL_MD_END = '<!-- SKILLFM-SKILL-END -->';
175
+ export function buildSkillMd(opts = {}) {
176
+ const lang = resolveLang(opts.lang);
177
+ const fm = renderFrontmatterYaml(DEFAULT_FRONTMATTER());
178
+ const body = lang === 'zh' ? BODY_ZH : BODY_EN;
179
+ const content = `${fm}\n\n${body}`;
180
+ if (opts.withBoundaryMarkers) {
181
+ return `${SKILL_MD_BEGIN}\n${content}${SKILL_MD_END}\n`;
182
+ }
183
+ return content;
184
+ }
185
+ function resolveLang(lang) {
186
+ if (lang === 'zh')
187
+ return 'zh';
188
+ if (lang === 'en')
189
+ return 'en';
190
+ // auto
191
+ const lc = (process.env.LANG || process.env.LC_ALL || process.env.LC_MESSAGES || '').toLowerCase();
192
+ return lc.includes('zh') ? 'zh' : 'en';
193
+ }
194
+ //# sourceMappingURL=template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../../src/skill-md/template.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * BSO M9 v0.3 — Layer 1: SKILL.md 写入器
3
+ *
4
+ * Refs:
5
+ * - docs/prd/PRD-BSO-M9-HARNESS-HOOKS.md §3.2.2
6
+ *
7
+ * 写入策略:
8
+ * - 项目级 ./SKILL.md:必写(所有 host 都拿到 priming)
9
+ * - Anthropic Claude Code 用户级 ~/.claude/skills/skillfm-bso/SKILL.md:可选
10
+ * (由 init flag --copy-to-user 触发,本里程碑只提供 hint)
11
+ *
12
+ * 已存在 ./SKILL.md:
13
+ * - 内含 SKILLFM-SKILL-BEGIN/END → upgrade-safe replace
14
+ * - 不含我们的标记 → backup 后 append(不覆盖用户已有 skill)
15
+ */
16
+ import { type SkillLang } from './template.js';
17
+ export interface SkillMdWriteResult {
18
+ path: string;
19
+ action: 'created' | 'appended' | 'replaced' | 'already-present';
20
+ bytesWritten: number;
21
+ backupPath?: string;
22
+ }
23
+ export interface WriteSkillMdOptions {
24
+ cwd: string;
25
+ lang?: SkillLang;
26
+ }
27
+ export declare function writeProjectSkillMd(opts: WriteSkillMdOptions): SkillMdWriteResult;
28
+ export declare function userScopeSkillMdPath(): string;
29
+ export declare function writeUserScopeSkillMd(lang?: SkillLang): SkillMdWriteResult;
30
+ //# sourceMappingURL=writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../src/skill-md/writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAWH,OAAO,EAIL,KAAK,SAAS,EACf,MAAM,eAAe,CAAC;AAMvB,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,iBAAiB,CAAC;IAChE,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAMD,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,mBAAmB,GAAG,kBAAkB,CAqEjF;AAMD,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAgB,qBAAqB,CAAC,IAAI,CAAC,EAAE,SAAS,GAAG,kBAAkB,CAqC1E"}