@skillfm/local 2.0.0 → 2.0.3

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 (55) hide show
  1. package/dist/agent-hints.d.ts +25 -0
  2. package/dist/agent-hints.d.ts.map +1 -0
  3. package/dist/agent-hints.js +87 -0
  4. package/dist/agent-hints.js.map +1 -0
  5. package/dist/doctor.d.ts +30 -0
  6. package/dist/doctor.d.ts.map +1 -0
  7. package/dist/doctor.js +272 -0
  8. package/dist/doctor.js.map +1 -0
  9. package/dist/guard/bin.d.ts +11 -0
  10. package/dist/guard/bin.d.ts.map +1 -0
  11. package/dist/guard/bin.js +16 -0
  12. package/dist/guard/bin.js.map +1 -0
  13. package/dist/guard/cli.d.ts +23 -0
  14. package/dist/guard/cli.d.ts.map +1 -0
  15. package/dist/guard/cli.js +249 -0
  16. package/dist/guard/cli.js.map +1 -0
  17. package/dist/guard/sidecar-client.d.ts +46 -0
  18. package/dist/guard/sidecar-client.d.ts.map +1 -0
  19. package/dist/guard/sidecar-client.js +92 -0
  20. package/dist/guard/sidecar-client.js.map +1 -0
  21. package/dist/guard/state.d.ts +80 -0
  22. package/dist/guard/state.d.ts.map +1 -0
  23. package/dist/guard/state.js +119 -0
  24. package/dist/guard/state.js.map +1 -0
  25. package/dist/harness/detector.d.ts +47 -0
  26. package/dist/harness/detector.d.ts.map +1 -0
  27. package/dist/harness/detector.js +177 -0
  28. package/dist/harness/detector.js.map +1 -0
  29. package/dist/harness/priming.d.ts +42 -0
  30. package/dist/harness/priming.d.ts.map +1 -0
  31. package/dist/harness/priming.js +89 -0
  32. package/dist/harness/priming.js.map +1 -0
  33. package/dist/harness/templates.d.ts +108 -0
  34. package/dist/harness/templates.d.ts.map +1 -0
  35. package/dist/harness/templates.js +171 -0
  36. package/dist/harness/templates.js.map +1 -0
  37. package/dist/harness/writers.d.ts +82 -0
  38. package/dist/harness/writers.d.ts.map +1 -0
  39. package/dist/harness/writers.js +266 -0
  40. package/dist/harness/writers.js.map +1 -0
  41. package/dist/index.js +562 -4
  42. package/dist/index.js.map +1 -1
  43. package/dist/lang.d.ts +21 -0
  44. package/dist/lang.d.ts.map +1 -0
  45. package/dist/lang.js +62 -0
  46. package/dist/lang.js.map +1 -0
  47. package/dist/soul-security.d.ts +76 -0
  48. package/dist/soul-security.d.ts.map +1 -0
  49. package/dist/soul-security.js +197 -0
  50. package/dist/soul-security.js.map +1 -0
  51. package/dist/soul.d.ts +135 -0
  52. package/dist/soul.d.ts.map +1 -0
  53. package/dist/soul.js +439 -0
  54. package/dist/soul.js.map +1 -0
  55. package/package.json +7 -3
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Agent Hint — sidecar → agent 的指令文案 (双语并列)
3
+ *
4
+ * 场景: 用户跑 `npx -y @skillfm/local@latest start` 或 POST /activate/poll
5
+ * 成功后, sidecar 返回的 JSON 里带 `hint_for_agent`, agent 读后决定下一步动作 +
6
+ * 对用户说什么.
7
+ *
8
+ * 设计 (2026-04-19 方案 v2):
9
+ * 首次安装的 hint 文本量不大, 直接**中英并列**. agent 会根据用户发来的消息
10
+ * 语言自动选对应语言回复 — 不需要服务端 detectLang, 更鲁棒
11
+ * (不依赖 env / Intl / locale 判断, 不会踩 macOS LANG=en_US 但系统中文 的坑).
12
+ *
13
+ * 每条 hint 尾部明示: [Reply in the user's language | 请用用户所用的语言回复].
14
+ */
15
+ export type AgentHintKey = 'activation_success' | 'running_activated' | 'running_not_activated';
16
+ interface AgentHintVars {
17
+ /** sidecar 运行地址 (running_* 用) */
18
+ url?: string;
19
+ }
20
+ /**
21
+ * 返回指定 key 的双语并列 hint. Agent 按用户消息语言自动匹配回复.
22
+ */
23
+ export declare function agentHint(key: AgentHintKey, vars?: AgentHintVars): string;
24
+ export {};
25
+ //# sourceMappingURL=agent-hints.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-hints.d.ts","sourceRoot":"","sources":["../src/agent-hints.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,YAAY,GACpB,oBAAoB,GACpB,mBAAmB,GACnB,uBAAuB,CAAC;AAE5B,UAAU,aAAa;IACrB,iCAAiC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAwED;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,GAAE,aAAkB,GAAG,MAAM,CAY7E"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Agent Hint — sidecar → agent 的指令文案 (双语并列)
3
+ *
4
+ * 场景: 用户跑 `npx -y @skillfm/local@latest start` 或 POST /activate/poll
5
+ * 成功后, sidecar 返回的 JSON 里带 `hint_for_agent`, agent 读后决定下一步动作 +
6
+ * 对用户说什么.
7
+ *
8
+ * 设计 (2026-04-19 方案 v2):
9
+ * 首次安装的 hint 文本量不大, 直接**中英并列**. agent 会根据用户发来的消息
10
+ * 语言自动选对应语言回复 — 不需要服务端 detectLang, 更鲁棒
11
+ * (不依赖 env / Intl / locale 判断, 不会踩 macOS LANG=en_US 但系统中文 的坑).
12
+ *
13
+ * 每条 hint 尾部明示: [Reply in the user's language | 请用用户所用的语言回复].
14
+ */
15
+ const LANG_INSTRUCTION = '[Reply in the user\'s language | 请用用户所用的语言回复用户]';
16
+ // ── activation_success ────────────────────────────────────────────────
17
+ const ACTIVATION_SUCCESS_ZH = [
18
+ '[中文] 激活成功!brain_key 已保存到 ~/.skillfm/config.json。停止轮询。',
19
+ '用温暖的语气告诉用户:「SkillFM 激活成功!🎉 配置已保存至 ~/.skillfm/config.json」',
20
+ '然后立即调用 GET /skills 发现可用技能。',
21
+ '以对话的方式介绍技能列表 — 为每个技能用大白话解释它能做什么, ',
22
+ '并基于上下文推荐一个用户可能想先试的。',
23
+ ].join(' ');
24
+ const ACTIVATION_SUCCESS_EN = [
25
+ '[English] Activation successful! brain_key saved to ~/.skillfm/config.json.',
26
+ 'Stop polling. Tell the user warmly:',
27
+ '"SkillFM activated! 🎉 Config saved to ~/.skillfm/config.json"',
28
+ 'then immediately call GET /skills to discover available skills.',
29
+ 'Present the skill list in a friendly, conversational way — for each skill',
30
+ 'explain what it can do in plain language, and suggest one the user might',
31
+ 'want to try first based on context.',
32
+ ].join(' ');
33
+ // ── running_activated ─────────────────────────────────────────────────
34
+ function runningActivatedZh(url) {
35
+ return [
36
+ `[中文] skillfm-local 正在 ${url} 运行。brain key 已加载 — SkillFM 已激活。`,
37
+ '告诉用户「SkillFM 已就绪!」, 然后调用',
38
+ `GET ${url}/skills 发现可用技能。`,
39
+ '以对话的方式介绍 — 用大白话解释每个技能能做什么, 推荐一个可以试试的。',
40
+ ].join(' ');
41
+ }
42
+ function runningActivatedEn(url) {
43
+ return [
44
+ `[English] skillfm-local is running at ${url}. Brain key loaded — SkillFM is already activated.`,
45
+ `Tell the user "SkillFM is ready!" then call GET ${url}/skills to discover`,
46
+ 'available skills. Present them conversationally — explain what each skill does',
47
+ 'in plain language and suggest one to try.',
48
+ ].join(' ');
49
+ }
50
+ // ── running_not_activated ─────────────────────────────────────────────
51
+ function runningNotActivatedZh(url) {
52
+ return [
53
+ `[中文] skillfm-local 正在 ${url} 运行。尚未激活。`,
54
+ `下一步: POST ${url}/activate/start (无请求体) 启动 OAuth 设备流。`,
55
+ '它会返回一个验证链接 — 用友好的语气告诉用户:',
56
+ '「我需要你打开一个链接来完成 SkillFM 激活, 只需要几秒钟:」然后展示链接。',
57
+ `之后每 5 秒轮询 POST ${url}/activate/poll 直到激活。`,
58
+ '不要问用户是否想激活 — 直接做, 这是必需步骤。',
59
+ ].join(' ');
60
+ }
61
+ function runningNotActivatedEn(url) {
62
+ return [
63
+ `[English] skillfm-local is running at ${url}. Not yet activated.`,
64
+ `Next step: POST ${url}/activate/start (no body) to start the OAuth device flow.`,
65
+ 'It returns a verification URL — tell the user in a friendly way:',
66
+ '"I need you to open a link to complete SkillFM activation, just a few seconds:"',
67
+ `then show the URL. After that, poll POST ${url}/activate/poll every 5 seconds`,
68
+ 'until activated. Do NOT ask the user if they want to activate — just do it,',
69
+ 'it is required.',
70
+ ].join(' ');
71
+ }
72
+ // ── public API ────────────────────────────────────────────────────────
73
+ /**
74
+ * 返回指定 key 的双语并列 hint. Agent 按用户消息语言自动匹配回复.
75
+ */
76
+ export function agentHint(key, vars = {}) {
77
+ const url = vars.url ?? '';
78
+ switch (key) {
79
+ case 'activation_success':
80
+ return [ACTIVATION_SUCCESS_ZH, ACTIVATION_SUCCESS_EN, LANG_INSTRUCTION].join('\n\n');
81
+ case 'running_activated':
82
+ return [runningActivatedZh(url), runningActivatedEn(url), LANG_INSTRUCTION].join('\n\n');
83
+ case 'running_not_activated':
84
+ return [runningNotActivatedZh(url), runningNotActivatedEn(url), LANG_INSTRUCTION].join('\n\n');
85
+ }
86
+ }
87
+ //# sourceMappingURL=agent-hints.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-hints.js","sourceRoot":"","sources":["../src/agent-hints.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAYH,MAAM,gBAAgB,GACpB,iDAAiD,CAAC;AAEpD,yEAAyE;AAEzE,MAAM,qBAAqB,GAAG;IAC5B,uDAAuD;IACvD,4DAA4D;IAC5D,4BAA4B;IAC5B,mCAAmC;IACnC,qBAAqB;CACtB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,MAAM,qBAAqB,GAAG;IAC5B,6EAA6E;IAC7E,qCAAqC;IACrC,gEAAgE;IAChE,iEAAiE;IACjE,2EAA2E;IAC3E,0EAA0E;IAC1E,qCAAqC;CACtC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,yEAAyE;AAEzE,SAAS,kBAAkB,CAAC,GAAW;IACrC,OAAO;QACL,yBAAyB,GAAG,kCAAkC;QAC9D,0BAA0B;QAC1B,OAAO,GAAG,iBAAiB;QAC3B,uCAAuC;KACxC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAW;IACrC,OAAO;QACL,yCAAyC,GAAG,oDAAoD;QAChG,mDAAmD,GAAG,qBAAqB;QAC3E,gFAAgF;QAChF,2CAA2C;KAC5C,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAED,yEAAyE;AAEzE,SAAS,qBAAqB,CAAC,GAAW;IACxC,OAAO;QACL,yBAAyB,GAAG,WAAW;QACvC,aAAa,GAAG,sCAAsC;QACtD,0BAA0B;QAC1B,4CAA4C;QAC5C,kBAAkB,GAAG,sBAAsB;QAC3C,2BAA2B;KAC5B,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAED,SAAS,qBAAqB,CAAC,GAAW;IACxC,OAAO;QACL,yCAAyC,GAAG,sBAAsB;QAClE,mBAAmB,GAAG,2DAA2D;QACjF,kEAAkE;QAClE,iFAAiF;QACjF,4CAA4C,GAAG,gCAAgC;QAC/E,6EAA6E;QAC7E,iBAAiB;KAClB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAED,yEAAyE;AAEzE;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,GAAiB,EAAE,OAAsB,EAAE;IACnE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC;IAC3B,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,oBAAoB;YACvB,OAAO,CAAC,qBAAqB,EAAE,qBAAqB,EAAE,gBAAgB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvF,KAAK,mBAAmB;YACtB,OAAO,CAAC,kBAAkB,CAAC,GAAG,CAAC,EAAE,kBAAkB,CAAC,GAAG,CAAC,EAAE,gBAAgB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3F,KAAK,uBAAuB;YAC1B,OAAO,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,EAAE,gBAAgB,CAAC,CAAC,IAAI,CACpF,MAAM,CACP,CAAC;IACN,CAAC;AACH,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * BSO M9-5 — `skillfm doctor` 诊断命令
3
+ *
4
+ * Refs: docs/prd/PRD-BSO-M9-HARNESS-HOOKS.md §3.6
5
+ *
6
+ * 三层自检:
7
+ * L1 LLM 层:priming block 是否已注入到目标文件
8
+ * L2 harness 层:hooks / MCP 配置是否已注册
9
+ * L3 sidecar 层:sidecar 是否在跑、guard 端点是否可达
10
+ *
11
+ * 输出:人类可读(中文),每项 ✅ / ⚠️ / ❌。
12
+ */
13
+ import { type Harness } from './harness/detector.js';
14
+ interface CheckItem {
15
+ layer: 'L1' | 'L2' | 'L3';
16
+ status: 'ok' | 'warn' | 'fail';
17
+ title: string;
18
+ detail: string;
19
+ fix?: string;
20
+ }
21
+ export interface DoctorReport {
22
+ harness: Harness;
23
+ detect_source: string;
24
+ detect_reason: string;
25
+ items: CheckItem[];
26
+ }
27
+ export declare function runDoctor(cwd?: string): Promise<DoctorReport>;
28
+ export declare function renderDoctorReport(r: DoctorReport): string;
29
+ export {};
30
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAiB,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAKpE,UAAU,SAAS;IACjB,KAAK,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAqOD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AAED,wBAAsB,SAAS,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,YAAY,CAAC,CAalF;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,CAqB1D"}
package/dist/doctor.js ADDED
@@ -0,0 +1,272 @@
1
+ /**
2
+ * BSO M9-5 — `skillfm doctor` 诊断命令
3
+ *
4
+ * Refs: docs/prd/PRD-BSO-M9-HARNESS-HOOKS.md §3.6
5
+ *
6
+ * 三层自检:
7
+ * L1 LLM 层:priming block 是否已注入到目标文件
8
+ * L2 harness 层:hooks / MCP 配置是否已注册
9
+ * L3 sidecar 层:sidecar 是否在跑、guard 端点是否可达
10
+ *
11
+ * 输出:人类可读(中文),每项 ✅ / ⚠️ / ❌。
12
+ */
13
+ import { existsSync, readFileSync } from 'node:fs';
14
+ import { detectHarness } from './harness/detector.js';
15
+ import { pathsFor, capabilitiesFor, SKILLFM_GUARD_COMMAND } from './harness/templates.js';
16
+ import { PRIMING_BEGIN } from './harness/priming.js';
17
+ import { readSidecarEndpoint } from './guard/sidecar-client.js';
18
+ function symbol(s) {
19
+ return s === 'ok' ? '✅' : s === 'warn' ? '⚠️ ' : '❌';
20
+ }
21
+ // ============================================================================
22
+ // L1: LLM priming 层
23
+ // ============================================================================
24
+ function checkL1Priming(harness, cwd) {
25
+ const paths = pathsFor(harness, cwd);
26
+ const items = [];
27
+ try {
28
+ if (!existsSync(paths.primingFile)) {
29
+ items.push({
30
+ layer: 'L1',
31
+ status: 'fail',
32
+ title: 'LLM priming 文件不存在',
33
+ detail: paths.primingFile,
34
+ fix: `运行 \`skillfm init --harness=${harness}\``,
35
+ });
36
+ return items;
37
+ }
38
+ const content = readFileSync(paths.primingFile, 'utf-8');
39
+ if (!content.includes(PRIMING_BEGIN)) {
40
+ items.push({
41
+ layer: 'L1',
42
+ status: 'warn',
43
+ title: 'LLM priming 文件存在但未注入 SkillFM block',
44
+ detail: paths.primingFile,
45
+ fix: `运行 \`skillfm init --harness=${harness}\``,
46
+ });
47
+ }
48
+ else {
49
+ items.push({
50
+ layer: 'L1',
51
+ status: 'ok',
52
+ title: 'LLM priming 已注入',
53
+ detail: paths.primingFile,
54
+ });
55
+ }
56
+ }
57
+ catch (err) {
58
+ items.push({
59
+ layer: 'L1',
60
+ status: 'fail',
61
+ title: 'LLM priming 文件检查失败',
62
+ detail: err.message,
63
+ });
64
+ }
65
+ return items;
66
+ }
67
+ // ============================================================================
68
+ // L2: harness 层
69
+ // ============================================================================
70
+ function checkL2Harness(harness, cwd) {
71
+ const paths = pathsFor(harness, cwd);
72
+ const caps = capabilitiesFor(harness);
73
+ const items = [];
74
+ if (harness === 'unknown') {
75
+ items.push({
76
+ layer: 'L2',
77
+ status: 'warn',
78
+ title: 'harness 未识别',
79
+ detail: '无法自动写入 harness 层配置;L1 + L3 仍然可用',
80
+ fix: '运行 `skillfm init --harness=<claude-code|openclaw|cursor|aider|windsurf>`',
81
+ });
82
+ return items;
83
+ }
84
+ if (!caps.preToolUseHook) {
85
+ items.push({
86
+ layer: 'L2',
87
+ status: 'warn',
88
+ title: `${harness}: PreToolUse hook 未支持`,
89
+ detail: caps.fallback || '退化到 MCP description + sidecar 9 红线兜底',
90
+ fix: caps.hookResearched ? undefined : `等待 M9-6 调研结论后升级模板`,
91
+ });
92
+ return items;
93
+ }
94
+ if (!paths.harnessConfigFile) {
95
+ items.push({
96
+ layer: 'L2',
97
+ status: 'fail',
98
+ title: `${harness}: 无 harness 配置文件目标路径`,
99
+ detail: '内部错误,请报 bug',
100
+ });
101
+ return items;
102
+ }
103
+ if (!existsSync(paths.harnessConfigFile)) {
104
+ items.push({
105
+ layer: 'L2',
106
+ status: 'fail',
107
+ title: `${harness}: 配置文件不存在`,
108
+ detail: paths.harnessConfigFile,
109
+ fix: `运行 \`skillfm init --harness=${harness}\``,
110
+ });
111
+ return items;
112
+ }
113
+ try {
114
+ const content = readFileSync(paths.harnessConfigFile, 'utf-8');
115
+ if (!content.includes(SKILLFM_GUARD_COMMAND)) {
116
+ items.push({
117
+ layer: 'L2',
118
+ status: 'warn',
119
+ title: `${harness}: hook 未注册 skillfm-guard`,
120
+ detail: paths.harnessConfigFile,
121
+ fix: `运行 \`skillfm init --harness=${harness}\``,
122
+ });
123
+ }
124
+ else {
125
+ items.push({
126
+ layer: 'L2',
127
+ status: 'ok',
128
+ title: `${harness}: hook 已注册`,
129
+ detail: paths.harnessConfigFile,
130
+ });
131
+ }
132
+ }
133
+ catch (err) {
134
+ items.push({
135
+ layer: 'L2',
136
+ status: 'fail',
137
+ title: `${harness}: 配置文件读取失败`,
138
+ detail: err.message,
139
+ });
140
+ }
141
+ // skillfm-guard 可执行性(简单 existsSync 在 PATH 中不好查;退而求其次检测包内路径)
142
+ // 让 skillfm doctor 读 ~/.skillfm/local.json 的 url 来验证 sidecar 可达即可;
143
+ // guard 可执行由 install 流程保证,此处信息级。
144
+ return items;
145
+ }
146
+ // ============================================================================
147
+ // L3: sidecar + guard endpoint
148
+ // ============================================================================
149
+ async function checkL3Sidecar() {
150
+ const items = [];
151
+ const endpoint = readSidecarEndpoint();
152
+ if (!endpoint) {
153
+ items.push({
154
+ layer: 'L3',
155
+ status: 'fail',
156
+ title: 'sidecar 未运行',
157
+ detail: '找不到 ~/.skillfm/local.json;sidecar 未启动',
158
+ fix: '运行 `skillfm start`',
159
+ });
160
+ return items;
161
+ }
162
+ try {
163
+ const controller = new AbortController();
164
+ const timer = setTimeout(() => controller.abort(), 1000);
165
+ const res = await fetch(`${endpoint.url}/health`, { signal: controller.signal });
166
+ clearTimeout(timer);
167
+ if (res.ok) {
168
+ items.push({
169
+ layer: 'L3',
170
+ status: 'ok',
171
+ title: 'sidecar /health 正常',
172
+ detail: endpoint.url,
173
+ });
174
+ }
175
+ else {
176
+ items.push({
177
+ layer: 'L3',
178
+ status: 'warn',
179
+ title: `sidecar /health 返回 ${res.status}`,
180
+ detail: endpoint.url,
181
+ });
182
+ }
183
+ }
184
+ catch (err) {
185
+ items.push({
186
+ layer: 'L3',
187
+ status: 'fail',
188
+ title: 'sidecar 不可达',
189
+ detail: `${endpoint.url}: ${err.message}`,
190
+ fix: '`skillfm restart`',
191
+ });
192
+ return items;
193
+ }
194
+ try {
195
+ const controller = new AbortController();
196
+ const timer = setTimeout(() => controller.abort(), 1000);
197
+ const res = await fetch(`${endpoint.url}/internal/guard/snapshot`, {
198
+ signal: controller.signal,
199
+ });
200
+ clearTimeout(timer);
201
+ if (res.ok) {
202
+ const body = await res.json().catch(() => ({}));
203
+ const sessCount = body?.snapshot?.sessions?.length ?? 0;
204
+ const lastBrainRunAt = body?.snapshot?.last_brain_run_at ?? null;
205
+ items.push({
206
+ layer: 'L3',
207
+ status: 'ok',
208
+ title: 'guard 端点响应正常',
209
+ detail: `sessions=${sessCount}, last_brain_run_at=${lastBrainRunAt ? new Date(lastBrainRunAt).toISOString() : 'null'}`,
210
+ });
211
+ }
212
+ else {
213
+ items.push({
214
+ layer: 'L3',
215
+ status: 'warn',
216
+ title: `guard 端点返回 ${res.status}`,
217
+ detail: `${endpoint.url}/internal/guard/snapshot`,
218
+ });
219
+ }
220
+ }
221
+ catch (err) {
222
+ items.push({
223
+ layer: 'L3',
224
+ status: 'warn',
225
+ title: 'guard 端点超时',
226
+ detail: err.message,
227
+ });
228
+ }
229
+ return items;
230
+ }
231
+ export async function runDoctor(cwd = process.cwd()) {
232
+ const detected = detectHarness({ cwd });
233
+ const items = [
234
+ ...checkL1Priming(detected.harness, cwd),
235
+ ...checkL2Harness(detected.harness, cwd),
236
+ ...(await checkL3Sidecar()),
237
+ ];
238
+ return {
239
+ harness: detected.harness,
240
+ detect_source: detected.source,
241
+ detect_reason: detected.reason,
242
+ items,
243
+ };
244
+ }
245
+ export function renderDoctorReport(r) {
246
+ const lines = [];
247
+ lines.push(`SkillFM doctor — harness=${r.harness} (detected via ${r.detect_source}: ${r.detect_reason})`);
248
+ lines.push('');
249
+ for (const layer of ['L1', 'L2', 'L3']) {
250
+ const layerItems = r.items.filter((i) => i.layer === layer);
251
+ if (layerItems.length === 0)
252
+ continue;
253
+ lines.push(`${layer === 'L1' ? 'L1 LLM 层' : layer === 'L2' ? 'L2 harness 层' : 'L3 sidecar 层'}`);
254
+ for (const it of layerItems) {
255
+ lines.push(` ${symbol(it.status)} ${it.title}`);
256
+ lines.push(` ${it.detail}`);
257
+ if (it.fix)
258
+ lines.push(` 修复: ${it.fix}`);
259
+ }
260
+ lines.push('');
261
+ }
262
+ const hasFail = r.items.some((i) => i.status === 'fail');
263
+ const hasWarn = r.items.some((i) => i.status === 'warn');
264
+ if (hasFail)
265
+ lines.push('❌ 发现 fail 项,上面列出了修复建议');
266
+ else if (hasWarn)
267
+ lines.push('⚠️ 有 warn 项,查看详情决定是否修复');
268
+ else
269
+ lines.push('✅ 所有检查通过');
270
+ return lines.join('\n');
271
+ }
272
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * BSO M9-4 — skillfm-guard binary entrypoint
4
+ *
5
+ * Installed as `skillfm-guard` via package.json `bin`. Invoked by harness hooks
6
+ * (Claude Code SessionStart/PreToolUse/PostToolUse etc.).
7
+ *
8
+ * Always returns an exit code; never throws. Fail-open behavior lives in cli.ts.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../../src/guard/bin.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG"}
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * BSO M9-4 — skillfm-guard binary entrypoint
4
+ *
5
+ * Installed as `skillfm-guard` via package.json `bin`. Invoked by harness hooks
6
+ * (Claude Code SessionStart/PreToolUse/PostToolUse etc.).
7
+ *
8
+ * Always returns an exit code; never throws. Fail-open behavior lives in cli.ts.
9
+ */
10
+ import { runGuardCli } from './cli.js';
11
+ runGuardCli(process.argv.slice(2)).then((code) => process.exit(code), (err) => {
12
+ process.stderr.write(`[skillfm-guard] fatal: ${err?.message || err}\n`);
13
+ // fail-open: even fatal errors should not lock the user's harness
14
+ process.exit(0);
15
+ });
16
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/guard/bin.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEvC,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CACrC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAC5B,CAAC,GAAG,EAAE,EAAE;IACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,GAAG,EAAE,OAAO,IAAI,GAAG,IAAI,CAAC,CAAC;IACxE,kEAAkE;IAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CACF,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * BSO M9-4 — skillfm-guard CLI 入口
3
+ *
4
+ * Refs: docs/prd/PRD-BSO-M9-HARNESS-HOOKS.md §3.4 + §3.5
5
+ *
6
+ * 子命令(由 harness 的 hook 机制触发):
7
+ * - session-start → SessionStart(warn-only;启 sidecar 记录 session)
8
+ * - pre-tool-use → PreToolUse(阻断性;未 brain_run → exit 2)
9
+ * - post-tool-use → PostToolUse(warn-only;audit 用途)
10
+ * - check-script-loaded → doctor / 旁路用,查询当前 sidecar 状态
11
+ *
12
+ * Claude Code hook payload 约定(Anthropic spec):
13
+ * - SessionStart: stdin JSON { session_id, source?, cwd? }
14
+ * - PreToolUse: stdin JSON { session_id, tool_name, tool_input? }
15
+ * - PostToolUse: stdin JSON { session_id, tool_name, tool_response? }
16
+ *
17
+ * Fail-open 原则:sidecar 不可达 / 超时 / 解析失败一律 exit 0 + stderr warn,
18
+ * 只有 sidecar 明确返回 412 才 exit 2。这样保证 hook 故障不会锁死用户 UX。
19
+ */
20
+ type ExitCode = 0 | 2;
21
+ export declare function runGuardCli(argv: string[]): Promise<ExitCode>;
22
+ export {};
23
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/guard/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAUH,KAAK,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC;AA+MtB,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAyCnE"}