feihong-code 0.2.2 → 0.5.1

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 (152) hide show
  1. package/.github/FUNDING.yml +4 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +37 -37
  3. package/.github/ISSUE_TEMPLATE/config.yml +14 -14
  4. package/.github/ISSUE_TEMPLATE/feature_request.md +28 -28
  5. package/.github/PULL_REQUEST_TEMPLATE.md +46 -46
  6. package/.github/SECURITY.md +67 -67
  7. package/.github/dependabot.yml +16 -0
  8. package/.github/workflows/ci.yml +1 -1
  9. package/AGENT-GUIDE.md +382 -237
  10. package/CHANGELOG.md +405 -73
  11. package/CODE_OF_CONDUCT.md +56 -56
  12. package/CONTRIBUTING.md +68 -68
  13. package/LICENSE +22 -22
  14. package/README.md +31 -25
  15. package/README.self-evolve.md +274 -0
  16. package/dist/agent/code-review.js +2 -0
  17. package/dist/agent/code-review.js.map +1 -1
  18. package/dist/agent/code-writer.js +70 -17
  19. package/dist/agent/code-writer.js.map +1 -1
  20. package/dist/agent/context-compactor.js +13 -4
  21. package/dist/agent/context-compactor.js.map +1 -1
  22. package/dist/agent/experience.js +262 -62
  23. package/dist/agent/experience.js.map +1 -1
  24. package/dist/agent/orchestrator.js +148 -68
  25. package/dist/agent/orchestrator.js.map +1 -1
  26. package/dist/agent/quality-gate.js +10 -4
  27. package/dist/agent/quality-gate.js.map +1 -1
  28. package/dist/agent/repo-context.js +181 -0
  29. package/dist/agent/repo-context.js.map +1 -0
  30. package/dist/agent/repo-reader.js +92 -99
  31. package/dist/agent/repo-reader.js.map +1 -1
  32. package/dist/agent/self-heal.js +38 -48
  33. package/dist/agent/self-heal.js.map +1 -1
  34. package/dist/agent/self-improver.js +65 -61
  35. package/dist/agent/self-improver.js.map +1 -1
  36. package/dist/agent/subagent-summary.js +31 -0
  37. package/dist/agent/subagent-summary.js.map +1 -0
  38. package/dist/agent/subagent.js +52 -2
  39. package/dist/agent/subagent.js.map +1 -1
  40. package/dist/agent/symbol-index.js +160 -0
  41. package/dist/agent/symbol-index.js.map +1 -0
  42. package/dist/agent/team.js +193 -0
  43. package/dist/agent/team.js.map +1 -0
  44. package/dist/cli/commands.js +124 -143
  45. package/dist/cli/commands.js.map +1 -1
  46. package/dist/cli/index.js +113 -106
  47. package/dist/cli/index.js.map +1 -1
  48. package/dist/cli/repl.js +82 -7
  49. package/dist/cli/repl.js.map +1 -1
  50. package/dist/cli/run.js +601 -95
  51. package/dist/cli/run.js.map +1 -1
  52. package/dist/cli/tui.js +145 -0
  53. package/dist/cli/tui.js.map +1 -0
  54. package/dist/cli/version.js +1 -1
  55. package/dist/enterprise/audit.js +75 -12
  56. package/dist/enterprise/audit.js.map +1 -1
  57. package/dist/enterprise/index.js +14 -11
  58. package/dist/enterprise/index.js.map +1 -1
  59. package/dist/enterprise/policy.js +22 -10
  60. package/dist/enterprise/policy.js.map +1 -1
  61. package/dist/harness/executor.js +127 -0
  62. package/dist/harness/executor.js.map +1 -0
  63. package/dist/harness/harness.js +87 -0
  64. package/dist/harness/harness.js.map +1 -0
  65. package/dist/harness/index.js +31 -0
  66. package/dist/harness/index.js.map +1 -0
  67. package/dist/harness/loader.js +138 -0
  68. package/dist/harness/loader.js.map +1 -0
  69. package/dist/harness/reporter.js +34 -0
  70. package/dist/harness/reporter.js.map +1 -0
  71. package/dist/harness/types.js +10 -0
  72. package/dist/harness/types.js.map +1 -0
  73. package/dist/harness/verifier.js +48 -0
  74. package/dist/harness/verifier.js.map +1 -0
  75. package/dist/hello.js +14 -0
  76. package/dist/hello.js.map +1 -0
  77. package/dist/memory/auto-summarize.js +208 -0
  78. package/dist/memory/auto-summarize.js.map +1 -0
  79. package/dist/memory/index.js +228 -0
  80. package/dist/memory/index.js.map +1 -0
  81. package/dist/models/model-router.js +23 -10
  82. package/dist/models/model-router.js.map +1 -1
  83. package/dist/plugins/plugin-loader.js +179 -0
  84. package/dist/plugins/plugin-loader.js.map +1 -0
  85. package/dist/runtime/event-log.js.map +1 -1
  86. package/dist/runtime/hooks.js +80 -0
  87. package/dist/runtime/hooks.js.map +1 -0
  88. package/dist/self-evolve/hook.js +60 -0
  89. package/dist/self-evolve/hook.js.map +1 -0
  90. package/dist/shared/config.js +35 -3
  91. package/dist/shared/config.js.map +1 -1
  92. package/dist/shared/i18n.js +535 -0
  93. package/dist/shared/i18n.js.map +1 -0
  94. package/dist/skills/grill.js +2 -1
  95. package/dist/skills/grill.js.map +1 -1
  96. package/dist/skills/self-heal.js +73 -0
  97. package/dist/skills/self-heal.js.map +1 -0
  98. package/dist/skills/skill-loader.js +131 -0
  99. package/dist/skills/skill-loader.js.map +1 -0
  100. package/dist/skills/skill-market.js +195 -0
  101. package/dist/skills/skill-market.js.map +1 -0
  102. package/dist/tools/analysis/code-analyzer.js +45 -18
  103. package/dist/tools/analysis/code-analyzer.js.map +1 -1
  104. package/dist/tools/index.js +5 -0
  105. package/dist/tools/index.js.map +1 -1
  106. package/dist/tools/mcp/index.js +84 -0
  107. package/dist/tools/mcp/index.js.map +1 -0
  108. package/dist/tools/mcp/mcp-client.js +172 -0
  109. package/dist/tools/mcp/mcp-client.js.map +1 -0
  110. package/dist/tools/sandbox.js +126 -0
  111. package/dist/tools/sandbox.js.map +1 -0
  112. package/dist/tools/shell/exec.js +25 -0
  113. package/dist/tools/shell/exec.js.map +1 -1
  114. package/dist/tools/shell/run-shell.tool.js +4 -1
  115. package/dist/tools/shell/run-shell.tool.js.map +1 -1
  116. package/dist/tools/skills/load-skill.tool.js +36 -0
  117. package/dist/tools/skills/load-skill.tool.js.map +1 -0
  118. package/dist/tools/tool.interface.js.map +1 -1
  119. package/dist/tools/tool.registry.js +37 -1
  120. package/dist/tools/tool.registry.js.map +1 -1
  121. package/dist/tools/web/web.tool.js +139 -0
  122. package/dist/tools/web/web.tool.js.map +1 -0
  123. package/dist/web/auth.js +42 -3
  124. package/dist/web/auth.js.map +1 -1
  125. package/dist/web/channels.js +171 -0
  126. package/dist/web/channels.js.map +1 -0
  127. package/dist/web/public/index.html +3253 -39
  128. package/dist/web/public/index.html.tmp +3117 -0
  129. package/dist/web/public/index_new.html +3196 -0
  130. package/dist/web/server.js +790 -11
  131. package/dist/web/server.js.map +1 -1
  132. package/dist/web/task-queue.js +352 -0
  133. package/dist/web/task-queue.js.map +1 -0
  134. package/dist/web/web-config.js +143 -0
  135. package/dist/web/web-config.js.map +1 -0
  136. package/docs/Deployment_Guide_EN.md +288 -0
  137. package/docs/Technical_Manual_EN.md +216 -0
  138. package/docs/User_Manual_EN.md +314 -0
  139. package/docs/self-evolve-implementation.md +165 -0
  140. package/docs/self-evolve.md +166 -0
  141. package/docs//344/272/247/345/223/201/345/274/200/345/217/221/346/226/207/346/241/243.md +614 -614
  142. package/docs//344/274/201/344/270/232/351/203/250/347/275/262/344/270/216/345/220/210/350/247/204.md +267 -267
  143. package/docs//344/275/277/347/224/250/350/257/264/346/230/216/344/271/246.md +318 -358
  144. package/docs//345/270/270/350/247/201/351/227/256/351/242/230/344/270/216/346/225/205/351/232/234/346/216/222/346/237/245.md +130 -130
  145. package/docs//346/212/200/346/234/257/350/257/264/346/230/216/344/271/246.md +216 -303
  146. package/docs//346/236/266/346/236/204/344/270/216API.md +238 -238
  147. package/docs//347/224/250/346/210/267/346/211/213/345/206/214.md +196 -196
  148. package/docs//351/203/250/347/275/262/346/214/207/345/215/227.md +165 -165
  149. package/docs//351/203/250/347/275/262/350/257/264/346/230/216/344/271/246.md +288 -0
  150. package/docs//351/205/215/347/275/256/345/217/202/350/200/203.md +127 -127
  151. package/package.json +114 -109
  152. package/tool-schema.json +127 -127
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.webSearchTool = exports.webFetchTool = void 0;
4
+ /**
5
+ * 飞虹 Code (Muse Code 参照复刻)
6
+ * 晋江市飞虹智科技企业管理有限公司 · 飞扬企源研发中心 · 负责人:吴赐虹
7
+ *
8
+ * P3-2 实时信息检索工具(对齐 Gemini grounding):
9
+ * - web_fetch 抓取指定 URL 的文本内容(HTML 转纯文本)
10
+ * - web_search 关键词搜索(DuckDuckGo HTML 接口,零依赖;可被 FH_SEARCH_ENDPOINT 覆盖)
11
+ *
12
+ * 安全约束(与沙箱网络规则联动):
13
+ * - 执行前用 checkNetworkUrl 校验目标域名(FH_NETWORK_ALLOW/DENY 生效)
14
+ * - 超时(默认 15s)、输出长度截断(默认 6KB),防失控
15
+ * - 全部经 AbortController 实现超时取消
16
+ */
17
+ const zod_1 = require("zod");
18
+ const sandbox_1 = require("../sandbox");
19
+ const logger_1 = require("../../shared/logger");
20
+ const DEFAULT_TIMEOUT = 15000;
21
+ const MAX_OUTPUT = 6000;
22
+ /** 提取网络规则(缺省空规则,不限制) */
23
+ function rulesOf(ctx) {
24
+ return ctx.security.networkRules ?? { networkAllow: [], networkDeny: [] };
25
+ }
26
+ /** 带超时的 fetch:超时/网络错误抛错 */
27
+ async function fetchWithTimeout(url, timeoutMs) {
28
+ const controller = new AbortController();
29
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
30
+ try {
31
+ const res = await fetch(url, { signal: controller.signal, redirect: 'follow', headers: { 'User-Agent': 'fhcode/0.4 (terminal ai agent)' } });
32
+ if (!res.ok)
33
+ throw new Error(`HTTP ${res.status}`);
34
+ return await res.text();
35
+ }
36
+ finally {
37
+ clearTimeout(timer);
38
+ }
39
+ }
40
+ /** HTML → 纯文本(剥离 script/style/标签,压缩空白) */
41
+ function htmlToText(html) {
42
+ return html
43
+ .replace(/<script[\s\S]*?<\/script>/gi, ' ')
44
+ .replace(/<style[\s\S]*?<\/style>/gi, ' ')
45
+ .replace(/<[^>]+>/g, ' ')
46
+ .replace(/&nbsp;/g, ' ')
47
+ .replace(/&amp;/g, '&')
48
+ .replace(/&lt;/g, '<')
49
+ .replace(/&gt;/g, '>')
50
+ .replace(/&quot;/g, '"')
51
+ .replace(/\s+/g, ' ')
52
+ .trim();
53
+ }
54
+ /** 从 DuckDuckGo HTML 结果页提取 (标题, URL) 列表 */
55
+ function parseDuckDuckGoResults(html, max) {
56
+ const out = [];
57
+ // 结果链接形态:<a rel="nofollow" class="result__a" href="...">标题</a>
58
+ const re = /<a[^>]+class="result__a"[^>]+href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/gi;
59
+ let m;
60
+ while ((m = re.exec(html)) !== null && out.length < max) {
61
+ const href = m[1];
62
+ const title = htmlToText(m[2]);
63
+ // DuckDuckGo 结果常为重定向链接,提取真实目标
64
+ let real = href;
65
+ const ddg = /uddg=([^&]+)/.exec(href);
66
+ if (ddg) {
67
+ try {
68
+ real = decodeURIComponent(ddg[1]);
69
+ }
70
+ catch {
71
+ real = href;
72
+ }
73
+ }
74
+ out.push(`${title}\n ${real}`);
75
+ }
76
+ return out;
77
+ }
78
+ exports.webFetchTool = {
79
+ name: 'web_fetch',
80
+ description: '抓取指定 URL 的文本内容(HTML 转纯文本,最多 6KB;目标域名受网络白名单/黑名单约束)',
81
+ jsonSchema: {
82
+ type: 'object',
83
+ properties: { url: { type: 'string', description: '要抓取的 http(s) URL' } },
84
+ required: ['url'],
85
+ },
86
+ schema: zod_1.z.object({ url: zod_1.z.string().url() }),
87
+ async execute(args, ctx) {
88
+ const { url } = args;
89
+ const blocked = (0, sandbox_1.checkNetworkUrl)(rulesOf(ctx), url);
90
+ if (blocked) {
91
+ logger_1.logger.warn('web_fetch blocked by network rules', { url, reason: blocked });
92
+ return { ok: false, output: '', error: `[网络规则拦截] ${blocked}` };
93
+ }
94
+ try {
95
+ const html = await fetchWithTimeout(url, DEFAULT_TIMEOUT);
96
+ const text = htmlToText(html);
97
+ if (!text)
98
+ return { ok: true, output: '(页面无可见文本内容)' };
99
+ return { ok: true, output: text.slice(0, MAX_OUTPUT) };
100
+ }
101
+ catch (e) {
102
+ return { ok: false, output: '', error: `web_fetch 失败: ${e instanceof Error ? e.message : String(e)}` };
103
+ }
104
+ },
105
+ };
106
+ exports.webSearchTool = {
107
+ name: 'web_search',
108
+ description: '实时关键词搜索(默认 DuckDuckGo;FH_SEARCH_ENDPOINT 可指定端点),返回标题与链接',
109
+ jsonSchema: {
110
+ type: 'object',
111
+ properties: {
112
+ query: { type: 'string', description: '搜索关键词' },
113
+ maxResults: { type: 'number', description: '返回条数,默认 5,最多 10' },
114
+ },
115
+ required: ['query'],
116
+ },
117
+ schema: zod_1.z.object({ query: zod_1.z.string().min(1), maxResults: zod_1.z.number().int().min(1).max(10).optional() }),
118
+ async execute(args, ctx) {
119
+ const { query, maxResults = 5 } = args;
120
+ const endpoint = process.env.FH_SEARCH_ENDPOINT || 'https://html.duckduckgo.com/html/';
121
+ const blocked = (0, sandbox_1.checkNetworkUrl)(rulesOf(ctx), endpoint);
122
+ if (blocked) {
123
+ logger_1.logger.warn('web_search blocked by network rules', { endpoint, reason: blocked });
124
+ return { ok: false, output: '', error: `[网络规则拦截] ${blocked}` };
125
+ }
126
+ try {
127
+ const url = `${endpoint}?q=${encodeURIComponent(query)}`;
128
+ const html = await fetchWithTimeout(url, DEFAULT_TIMEOUT);
129
+ const results = parseDuckDuckGoResults(html, maxResults);
130
+ if (results.length === 0)
131
+ return { ok: true, output: '(无搜索结果或页面结构不匹配)' };
132
+ return { ok: true, output: `搜索「${query}」结果:\n` + results.join('\n') };
133
+ }
134
+ catch (e) {
135
+ return { ok: false, output: '', error: `web_search 失败: ${e instanceof Error ? e.message : String(e)}` };
136
+ }
137
+ },
138
+ };
139
+ //# sourceMappingURL=web.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.tool.js","sourceRoot":"","sources":["../../../src/tools/web/web.tool.ts"],"names":[],"mappings":"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"}
package/dist/web/auth.js CHANGED
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SessionStore = void 0;
3
4
  exports.requireToken = requireToken;
4
5
  const crypto_1 = require("crypto");
5
6
  /** 计时安全的字符串比较,避免令牌逐字节泄露的计时攻击面 */
@@ -10,16 +11,54 @@ function safeEqual(a, b) {
10
11
  return false;
11
12
  return (0, crypto_1.timingSafeEqual)(ab, bb);
12
13
  }
14
+ /**
15
+ * 内存会话存储(进程内)。
16
+ * Web 控制台当前为本地单用户/小团队使用,会话不落盘;
17
+ * 若后续需要跨进程共享,可迁移到 Redis/数据库。
18
+ */
19
+ class SessionStore {
20
+ sessions = new Map();
21
+ create(phone) {
22
+ const token = (0, crypto_1.randomBytes)(32).toString('hex');
23
+ const session = { phone, token, createdAt: new Date().toISOString() };
24
+ this.sessions.set(token, session);
25
+ return token;
26
+ }
27
+ has(token) {
28
+ return this.sessions.has(token);
29
+ }
30
+ get(token) {
31
+ return this.sessions.get(token);
32
+ }
33
+ revoke(token) {
34
+ return this.sessions.delete(token);
35
+ }
36
+ }
37
+ exports.SessionStore = SessionStore;
13
38
  /** 返回 Express 中间件:校验 Authorization: Bearer <token> */
14
- function requireToken(token) {
39
+ function requireToken(masterToken, sessions) {
15
40
  return (req, res, next) => {
16
41
  const header = req.header('authorization') || '';
17
42
  const m = /^Bearer\s+(.+)$/i.exec(header);
18
- if (!m || !safeEqual(m[1], token)) {
43
+ if (!m) {
19
44
  res.status(401).json({ ok: false, error: 'unauthorized' });
20
45
  return;
21
46
  }
22
- next();
47
+ const token = m[1];
48
+ if (safeEqual(token, masterToken)) {
49
+ next();
50
+ return;
51
+ }
52
+ if (sessions?.has(token)) {
53
+ const session = sessions.get(token);
54
+ if (session) {
55
+ // 通过索引签名附加用户信息,供 /api/auth/me 等后续接口读取
56
+ req.user = session;
57
+ }
58
+ next();
59
+ return;
60
+ }
61
+ res.status(401).json({ ok: false, error: 'unauthorized' });
23
62
  };
24
63
  }
25
64
  //# sourceMappingURL=auth.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/web/auth.ts"],"names":[],"mappings":";;AAmBA,oCAUC;AArBD,mCAAyC;AAEzC,iCAAiC;AACjC,SAAS,SAAS,CAAC,CAAS,EAAE,CAAS;IACrC,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1B,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1B,IAAI,EAAE,CAAC,MAAM,KAAK,EAAE,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1C,OAAO,IAAA,wBAAe,EAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AACjC,CAAC;AAED,sDAAsD;AACtD,SAAgB,YAAY,CAAC,KAAa;IACxC,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;QAC/D,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;QACjD,MAAM,CAAC,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC;YAClC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;YAC3D,OAAO;QACT,CAAC;QACD,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/web/auth.ts"],"names":[],"mappings":";;;AAwDA,oCAwBC;AAtED,mCAAsD;AAEtD,iCAAiC;AACjC,SAAS,SAAS,CAAC,CAAS,EAAE,CAAS;IACrC,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1B,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1B,IAAI,EAAE,CAAC,MAAM,KAAK,EAAE,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1C,OAAO,IAAA,wBAAe,EAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AACjC,CAAC;AASD;;;;GAIG;AACH,MAAa,YAAY;IACN,QAAQ,GAAG,IAAI,GAAG,EAAmB,CAAC;IAEvD,MAAM,CAAC,KAAa;QAClB,MAAM,KAAK,GAAG,IAAA,oBAAW,EAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAY,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;QAC/E,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAClC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,GAAG,CAAC,KAAa;QACf,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,GAAG,CAAC,KAAa;QACf,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,MAAM,CAAC,KAAa;QAClB,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC;CACF;AArBD,oCAqBC;AAED,sDAAsD;AACtD,SAAgB,YAAY,CAAC,WAAmB,EAAE,QAAuB;IACvE,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;QAC/D,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;QACjD,MAAM,CAAC,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;YAC3D,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACnB,IAAI,SAAS,CAAC,KAAK,EAAE,WAAW,CAAC,EAAE,CAAC;YAClC,IAAI,EAAE,CAAC;YACP,OAAO;QACT,CAAC;QACD,IAAI,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACpC,IAAI,OAAO,EAAE,CAAC;gBACZ,sCAAsC;gBACrC,GAAoC,CAAC,IAAI,GAAG,OAAO,CAAC;YACvD,CAAC;YACD,IAAI,EAAE,CAAC;YACP,OAAO;QACT,CAAC;QACD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MessageChannels = void 0;
4
+ exports.telegramConfig = telegramConfig;
5
+ exports.wecomKeys = wecomKeys;
6
+ exports.allowedChannels = allowedChannels;
7
+ exports.isChannelAllowed = isChannelAllowed;
8
+ exports.verifyHmacSignature = verifyHmacSignature;
9
+ exports.verifyWecomSignature = verifyWecomSignature;
10
+ exports.formatTaskMessage = formatTaskMessage;
11
+ /**
12
+ * 飞虹 Code (Muse Code 参照复刻)
13
+ * 晋江市飞虹智科技企业管理有限公司 · 飞扬企源研发中心 · 负责人:吴赐虹
14
+ *
15
+ * P5-6/P6-O6 消息渠道(对齐 OpenClaw 的"多渠道消息接入",此处作为调度通知出口):
16
+ * - Telegram 机器人:FH_CHANNEL_TELEGRAM_BOT_TOKEN + FH_CHANNEL_TELEGRAM_CHAT_ID
17
+ * - 企业微信群机器人:FH_CHANNEL_WECOM_KEY(逗号分隔可多个)
18
+ * - 任务状态变化时把紧凑消息推送到已启用渠道
19
+ * O6 安全前置:
20
+ * - 出站白名单 FH_CHANNEL_ALLOW(逗号分隔,缺省全部放行;显式配置后仅白名单渠道可发)
21
+ * - 入站签名校验工具(供 M3 入站 webhook 复用):verifyHmacSignature(HMAC-SHA256)、
22
+ * verifyWecomSignature(企微回调 SHA1 排序校验)
23
+ *
24
+ * 设计:
25
+ * - 零依赖(全局 fetch + AbortController 超时),fire-and-forget 容错
26
+ * - 未配置渠道 = 无操作(保持离线/内网无感)
27
+ * - 文本消息统一由 formatTaskMessage 生成,渠道只负责投递
28
+ */
29
+ const crypto_1 = require("crypto");
30
+ const logger_1 = require("../shared/logger");
31
+ /** 环境变量开关 */
32
+ function telegramConfig() {
33
+ const token = process.env.FH_CHANNEL_TELEGRAM_BOT_TOKEN?.trim() || '';
34
+ const chatId = process.env.FH_CHANNEL_TELEGRAM_CHAT_ID?.trim() || '';
35
+ return token && chatId ? { token, chatId } : null;
36
+ }
37
+ function wecomKeys() {
38
+ return (process.env.FH_CHANNEL_WECOM_KEY || '')
39
+ .split(',')
40
+ .map((s) => s.trim())
41
+ .filter(Boolean);
42
+ }
43
+ /** O6:出站渠道白名单(FH_CHANNEL_ALLOW 逗号分隔;空 = 全部放行) */
44
+ function allowedChannels() {
45
+ return (process.env.FH_CHANNEL_ALLOW || '')
46
+ .split(',')
47
+ .map((s) => s.trim().toLowerCase())
48
+ .filter(Boolean);
49
+ }
50
+ function isChannelAllowed(channel) {
51
+ const allow = allowedChannels();
52
+ if (allow.length === 0)
53
+ return true;
54
+ return allow.includes(channel.toLowerCase());
55
+ }
56
+ /**
57
+ * O6:HMAC-SHA256 签名校验(入站 webhook 防伪造)。
58
+ * 调用方约定签名头格式,如 `X-Fhcode-Signature: sha256=<hex>`。
59
+ */
60
+ function verifyHmacSignature(secret, payload, signatureHex) {
61
+ if (!secret || !signatureHex)
62
+ return false;
63
+ const expected = (0, crypto_1.createHmac)('sha256', secret).update(payload).digest('hex');
64
+ const got = signatureHex.replace(/^sha256=/i, '').toLowerCase();
65
+ if (expected.length !== got.length)
66
+ return false;
67
+ try {
68
+ return (0, crypto_1.timingSafeEqual)(Buffer.from(expected, 'hex'), Buffer.from(got, 'hex'));
69
+ }
70
+ catch {
71
+ return false;
72
+ }
73
+ }
74
+ /**
75
+ * O6:企业微信回调签名校验(SHA1 排序拼接 token/timestamp/nonce/echoStr)。
76
+ * 按企微规范:signature = sha1(sort([token, timestamp, nonce, echoStr]).join(''))。
77
+ */
78
+ function verifyWecomSignature(token, timestamp, nonce, echoStr, signature) {
79
+ if (!token || !signature)
80
+ return false;
81
+ const sorted = [token, timestamp, nonce, echoStr].sort().join('');
82
+ const expected = (0, crypto_1.createHash)('sha1').update(sorted).digest('hex');
83
+ if (expected.length !== signature.length)
84
+ return false;
85
+ try {
86
+ return (0, crypto_1.timingSafeEqual)(Buffer.from(expected, 'hex'), Buffer.from(signature.toLowerCase(), 'hex'));
87
+ }
88
+ catch {
89
+ return false;
90
+ }
91
+ }
92
+ /** 生成任务状态通知文本(渠道无关) */
93
+ function formatTaskMessage(record, status) {
94
+ const emoji = { queued: '🕐', running: '⚙️', done: '✅', failed: '❌' };
95
+ const r = record.result;
96
+ const lines = [
97
+ `${emoji[status] ?? 'ℹ️'} [fhcode] 任务状态: ${status}`,
98
+ `📋 目标: ${record.goal.slice(0, 120)}`,
99
+ `🆔 任务: ${record.id.slice(0, 8)}`,
100
+ ];
101
+ if (r) {
102
+ lines.push(`⚙️ 迭代: ${r.iterations} · 成本: $${r.costUsd.toFixed(6)}`);
103
+ }
104
+ if (record.error)
105
+ lines.push(`⚠️ 错误: ${record.error.slice(0, 200)}`);
106
+ return lines.join('\n');
107
+ }
108
+ async function postJson(url, body, timeoutMs = 10000) {
109
+ const controller = new AbortController();
110
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
111
+ try {
112
+ const res = await fetch(url, {
113
+ method: 'POST',
114
+ headers: { 'Content-Type': 'application/json' },
115
+ body: JSON.stringify(body),
116
+ signal: controller.signal,
117
+ });
118
+ if (!res.ok)
119
+ throw new Error(`HTTP ${res.status}`);
120
+ }
121
+ finally {
122
+ clearTimeout(timer);
123
+ }
124
+ }
125
+ /** 消息渠道聚合器:按环境变量启用 Telegram / 企业微信,投递失败仅告警 */
126
+ class MessageChannels {
127
+ /** 是否配置了任何渠道 */
128
+ get enabled() {
129
+ return !!telegramConfig() || wecomKeys().length > 0;
130
+ }
131
+ /** 向所有已启用渠道推送任务状态(受 FH_CHANNEL_ALLOW 白名单约束) */
132
+ async notify(record, status) {
133
+ if (!this.enabled)
134
+ return;
135
+ const text = formatTaskMessage(record, status);
136
+ const tg = telegramConfig();
137
+ if (tg && isChannelAllowed('telegram')) {
138
+ await this.safe('telegram', async () => {
139
+ await postJson(`https://api.telegram.org/bot${tg.token}/sendMessage`, {
140
+ chat_id: tg.chatId,
141
+ text,
142
+ });
143
+ });
144
+ }
145
+ const keys = wecomKeys();
146
+ for (const key of keys) {
147
+ if (!isChannelAllowed('wecom'))
148
+ break;
149
+ await this.safe('wecom', async () => {
150
+ await postJson(`https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${key}`, {
151
+ msgtype: 'text',
152
+ text: { content: text },
153
+ });
154
+ });
155
+ }
156
+ }
157
+ /** 单渠道投递容错 */
158
+ async safe(name, fn) {
159
+ try {
160
+ await fn();
161
+ }
162
+ catch (e) {
163
+ logger_1.logger.warn('message channel delivery failed', {
164
+ channel: name,
165
+ error: e instanceof Error ? e.message : String(e),
166
+ });
167
+ }
168
+ }
169
+ }
170
+ exports.MessageChannels = MessageChannels;
171
+ //# sourceMappingURL=channels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channels.js","sourceRoot":"","sources":["../../src/web/channels.ts"],"names":[],"mappings":"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"}