feihong-code 8.0.0 → 8.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +193 -193
- package/CHANGELOG.md +140 -117
- package/README.md +656 -636
- package/agent-team/.env.example +13 -0
- package/agent-team/README.md +42 -0
- package/agent-team/agents/__init__.py +0 -0
- package/agent-team/agents/l1_acquisition.py +207 -0
- package/agent-team/agents/l2_content.py +237 -0
- package/agent-team/agents/l3_conversion.py +148 -0
- package/agent-team/agents/l4_analysis.py +118 -0
- package/agent-team/agents/l5_management.py +52 -0
- package/agent-team/agents/registry.py +60 -0
- package/agent-team/config.py +39 -0
- package/agent-team/core/__init__.py +0 -0
- package/agent-team/core/agent.py +73 -0
- package/agent-team/core/models.py +347 -0
- package/agent-team/core/scheduler.py +150 -0
- package/agent-team/core/task.py +121 -0
- package/agent-team/feihongzhi.db +0 -0
- package/agent-team/llm/__init__.py +12 -0
- package/agent-team/llm/base.py +22 -0
- package/agent-team/llm/doubao_llm.py +52 -0
- package/agent-team/llm/mock_llm.py +42 -0
- package/agent-team/main.py +235 -0
- package/agent-team/requirements.txt +2 -0
- package/agent-team/skill_packager.py +248 -0
- package/agent-team/skills/01_AI/350/216/267/345/256/242/347/272/277/347/264/242/351/233/267/350/276/276/SKILL.md +40 -0
- package/agent-team/skills/01_AI/350/216/267/345/256/242/347/272/277/347/264/242/351/233/267/350/276/276/run.py +111 -0
- package/agent-team/skills/02_AI/351/224/200/345/224/256/350/267/237/350/277/233/351/224/200/345/206/240/SKILL.md +38 -0
- package/agent-team/skills/02_AI/351/224/200/345/224/256/350/267/237/350/277/233/351/224/200/345/206/240/run.py +108 -0
- package/agent-team/skills/03_/350/257/204/350/256/272/345/214/272/345/225/206/346/234/272/350/257/206/345/210/253/345/256/230/SKILL.md +38 -0
- package/agent-team/skills/03_/350/257/204/350/256/272/345/214/272/345/225/206/346/234/272/350/257/206/345/210/253/345/256/230/run.py +106 -0
- package/agent-team/skills/04_/345/256/242/346/210/267/350/201/212/345/244/251/346/210/220/344/272/244/345/210/206/346/236/220/345/256/230/SKILL.md +37 -0
- package/agent-team/skills/04_/345/256/242/346/210/267/350/201/212/345/244/251/346/210/220/344/272/244/345/210/206/346/236/220/345/256/230/run.py +107 -0
- package/agent-team/skills/05_/345/220/214/350/241/214/347/210/206/346/254/276/351/233/267/350/276/276/SKILL.md +38 -0
- package/agent-team/skills/05_/345/220/214/350/241/214/347/210/206/346/254/276/351/233/267/350/276/276/run.py +99 -0
- package/agent-team/skills/06_/346/257/217/346/227/245/347/262/276/345/207/206/350/216/267/345/256/242/351/200/211/351/242/230/345/256/230/SKILL.md +39 -0
- package/agent-team/skills/06_/346/257/217/346/227/245/347/262/276/345/207/206/350/216/267/345/256/242/351/200/211/351/242/230/345/256/230/run.py +103 -0
- package/agent-team/skills/07_AI/345/244/226/350/264/270/345/274/200/345/217/221/345/256/242/346/210/267/345/221/230/345/267/245/SKILL.md +39 -0
- package/agent-team/skills/07_AI/345/244/226/350/264/270/345/274/200/345/217/221/345/256/242/346/210/267/345/221/230/345/267/245/run.py +103 -0
- package/agent-team/skills/08_/345/260/217/347/272/242/344/271/246/347/262/276/345/207/206/350/216/267/345/256/242/345/221/230/345/267/245/SKILL.md +40 -0
- package/agent-team/skills/08_/345/260/217/347/272/242/344/271/246/347/262/276/345/207/206/350/216/267/345/256/242/345/221/230/345/267/245/run.py +97 -0
- package/agent-team/skills/09_/347/247/201/345/237/237/345/256/242/346/210/267/345/210/206/345/261/202/350/267/237/350/277/233/345/256/230/SKILL.md +38 -0
- package/agent-team/skills/09_/347/247/201/345/237/237/345/256/242/346/210/267/345/210/206/345/261/202/350/267/237/350/277/233/345/256/230/run.py +106 -0
- package/agent-team/skills/10_GEO/345/225/206/346/234/272/350/257/212/346/226/255/345/256/230/SKILL.md +38 -0
- package/agent-team/skills/10_GEO/345/225/206/346/234/272/350/257/212/346/226/255/345/256/230/run.py +108 -0
- package/agent-team/skills/11_/344/270/200/344/272/272/345/205/254/345/217/270AI/345/221/230/345/267/245/350/260/203/345/272/246/345/256/230/SKILL.md +37 -0
- package/agent-team/skills/11_/344/270/200/344/272/272/345/205/254/345/217/270AI/345/221/230/345/267/245/350/260/203/345/272/246/345/256/230/run.py +111 -0
- package/agent-team/skills/12_/350/200/201/346/235/277/347/237/255/350/247/206/351/242/221/350/216/267/345/256/242/350/204/232/346/234/254/345/256/230/SKILL.md +39 -0
- package/agent-team/skills/12_/350/200/201/346/235/277/347/237/255/350/247/206/351/242/221/350/216/267/345/256/242/350/204/232/346/234/254/345/256/230/run.py +104 -0
- package/agent-team/skills/13_/345/215/232/344/270/273/350/264/246/345/217/267/346/267/261/345/272/246/346/213/206/350/247/243/345/256/230/SKILL.md +37 -0
- package/agent-team/skills/13_/345/215/232/344/270/273/350/264/246/345/217/267/346/267/261/345/272/246/346/213/206/350/247/243/345/256/230/run.py +105 -0
- package/agent-team/skills/14_AI/347/237/255/350/247/206/351/242/221/350/207/252/345/212/250/345/211/252/350/276/221/345/270/210/SKILL.md +39 -0
- package/agent-team/skills/14_AI/347/237/255/350/247/206/351/242/221/350/207/252/345/212/250/345/211/252/350/276/221/345/270/210/run.py +108 -0
- package/agent-team/skills/15_/345/205/254/344/274/227/345/217/267/350/207/252/345/212/250/350/277/220/350/220/245/345/217/221/345/270/203/345/256/230/SKILL.md +38 -0
- package/agent-team/skills/15_/345/205/254/344/274/227/345/217/267/350/207/252/345/212/250/350/277/220/350/220/245/345/217/221/345/270/203/345/256/230/run.py +105 -0
- package/agent-team/skills/16_/350/241/214/344/270/232/346/267/261/345/272/246/345/210/206/346/236/220/345/270/210/SKILL.md +38 -0
- package/agent-team/skills/16_/350/241/214/344/270/232/346/267/261/345/272/246/345/210/206/346/236/220/345/270/210/run.py +108 -0
- package/agent-team/skills/17_/346/212/225/350/265/204/347/240/224/347/251/266/345/222/250/350/257/242/345/256/230/SKILL.md +38 -0
- package/agent-team/skills/17_/346/212/225/350/265/204/347/240/224/347/251/266/345/222/250/350/257/242/345/256/230/run.py +106 -0
- package/agent-team/tests/__init__.py +0 -0
- package/agent-team/tests/test_core.py +156 -0
- package/dist/agent/agent-session.js +103 -0
- package/dist/agent/agent-session.js.map +1 -0
- package/dist/agent/orchestrator.js +8 -0
- package/dist/agent/orchestrator.js.map +1 -1
- package/dist/agent/steer.js +52 -0
- package/dist/agent/steer.js.map +1 -0
- package/dist/cli/index.js +1 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/node-guard.js +17 -0
- package/dist/cli/node-guard.js.map +1 -0
- package/dist/cli/run.js +2 -0
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/version.js +1 -1
- package/dist/enterprise/policy.js +40 -17
- package/dist/enterprise/policy.js.map +1 -1
- package/dist/tools/agents/agents-bridge.js +144 -0
- package/dist/tools/agents/agents-bridge.js.map +1 -0
- package/dist/tools/desktop/desktop-guard.js +81 -0
- package/dist/tools/desktop/desktop-guard.js.map +1 -0
- package/dist/tools/desktop/desktop.tool.js +201 -0
- package/dist/tools/desktop/desktop.tool.js.map +1 -0
- package/dist/tools/desktop/feihong-win.js +163 -0
- package/dist/tools/desktop/feihong-win.js.map +1 -0
- package/dist/tools/desktop/index.js +37 -0
- package/dist/tools/desktop/index.js.map +1 -0
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/mcp/index.js +10 -2
- package/dist/tools/mcp/index.js.map +1 -1
- package/dist/tools/mcp/mcp-client.js +4 -0
- package/dist/tools/mcp/mcp-client.js.map +1 -1
- package/dist/tools/sandbox.js +28 -0
- package/dist/tools/sandbox.js.map +1 -1
- package/dist/web/public/public/css/style.css +1756 -0
- package/dist/web/public/public/favicon.svg +11 -0
- package/dist/web/public/public/index.html +1246 -0
- package/dist/web/public/public/js/api.js +558 -0
- package/dist/web/public/public/js/app.js +2233 -0
- package/dist/web/public/public/js/mock-api.js +259 -0
- package/dist/web/public/public/js/monaco-editor.js +363 -0
- package/dist/web/public/public/js/ui.js +2217 -0
- package/dist/web/public/public/js/utils.js +214 -0
- package/dist/web/public/public/manifest.json +59 -0
- package/dist/web/public/public/robots.txt +14 -0
- package/dist/web/public/public/service-worker.js +149 -0
- package/docs/AI/345/221/230/345/267/245/345/206/233/345/233/242-/346/225/264/345/220/210/350/257/264/346/230/216.md +68 -0
- package/docs/API.md +1 -1
- package/docs/App/346/212/200/346/234/257/350/257/264/346/230/216/344/271/246.md +3 -3
- package/docs/P1.1-P3-P5/345/267/245/347/250/213/345/256/236/346/226/275/346/200/273/347/273/223.md +328 -0
- package/docs/P5-Pi/345/257/271/347/205/247/350/257/204/346/265/213/346/212/245/345/221/212-mock/346/250/241/345/274/217.json +125 -0
- package/docs/P5-Pi/345/257/271/347/205/247/350/257/204/346/265/213/346/212/245/345/221/212-/347/234/237/345/256/236/346/250/241/345/236/213.json +138 -0
- package/docs/P5-pi-compare-real-report.json +138 -0
- package/docs/P5-pi-compare-report.json +125 -0
- package/docs/Pi-Agent/346/216/245/345/205/245/351/243/236/350/231/271Code-MVP/351/233/206/346/210/220/344/272/244/344/273/230/347/211/251.md +355 -0
- package/docs/Pi-Agent/346/216/245/345/205/245/351/243/236/350/231/271Code/344/273/267/345/200/274/345/210/206/346/236/220-/345/274/200/345/217/221/346/226/207/346/241/243.md +291 -0
- package/docs/Pi-Agent/346/216/245/345/205/245/351/243/236/350/231/271Code/344/273/267/345/200/274/351/207/215/344/274/260-/345/217/257/350/247/206/345/214/226.html +84 -0
- package/docs/SWE-bench-300-agnes-2.5-flash-/346/234/200/347/273/210/346/212/245/345/221/212.json +2012 -0
- package/docs/SWE-bench-300-agnes-2.5-flash-/350/267/221/345/210/206/346/212/245/345/221/212.md +74 -0
- package/docs/SWE-bench-Lite-DeepSeek-V4-Flash-/350/267/221/345/210/206/346/212/245/345/221/212.md +102 -0
- package/docs/TECHNICAL-SPECIFICATION.md +66 -0
- package/docs/TECHNICAL-SPECIFICATION.pdf +0 -0
- package/docs/Windows/346/211/213/350/204/232-POC/346/274/224/347/244/272/350/204/232/346/234/254.md +131 -0
- package/docs/Windows/346/211/213/350/204/232/346/216/245/345/205/245/346/214/207/345/215/227.md +181 -0
- package/docs//344/275/277/347/224/250/350/257/264/346/230/216/344/271/246-v8.0.1.md +146 -0
- package/docs//344/275/277/347/224/250/350/257/264/346/230/216/344/271/246.md +1 -1
- package/package.json +6 -3
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 工具函数模块:纯函数,无状态依赖,可被任意模块调用
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
function formatMarkdown(text) {
|
|
6
|
+
// 简单 Markdown 转换
|
|
7
|
+
return text
|
|
8
|
+
.replace(/&/g, '&')
|
|
9
|
+
.replace(/</g, '<')
|
|
10
|
+
.replace(/>/g, '>')
|
|
11
|
+
.replace(/^### (.*$)/gm, '<h3>$1</h3>')
|
|
12
|
+
.replace(/^## (.*$)/gm, '<h2>$1</h2>')
|
|
13
|
+
.replace(/^# (.*$)/gm, '<h1>$1</h1>')
|
|
14
|
+
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
|
|
15
|
+
.replace(/\*(.*?)\*/g, '<em>$1</em>')
|
|
16
|
+
.replace(/`(.*?)`/g, '<code>$1</code>')
|
|
17
|
+
.replace(/\n/g, '<br>');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getDirectoryName(path) {
|
|
21
|
+
if (!path || path === '' || path === '/') return '/';
|
|
22
|
+
if (/^[A-Za-z]:$/.test(path)) return path + '\\';
|
|
23
|
+
if (/^[A-Za-z]:\\$/.test(path)) return path;
|
|
24
|
+
const parts = path.split(/[/\\]/).filter(Boolean);
|
|
25
|
+
if (parts.length <= 1) {
|
|
26
|
+
const driveMatch = parts[0].match(/^([A-Za-z]):$/);
|
|
27
|
+
if (driveMatch) return driveMatch[1] + ':\\';
|
|
28
|
+
return parts[0] || '/';
|
|
29
|
+
}
|
|
30
|
+
const parentParts = parts.slice(0, -1);
|
|
31
|
+
if (/^[A-Za-z]:$/.test(parentParts[0])) {
|
|
32
|
+
return parentParts[0] + '\\' + parentParts.slice(1).join('\\');
|
|
33
|
+
}
|
|
34
|
+
return parentParts.join('\\');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** 渲染空状态提示,减少重复的 innerHTML 赋值代码 */
|
|
38
|
+
function renderEmpty(el, text) {
|
|
39
|
+
if (el) el.innerHTML = '<div class="empty">' + (text || '') + '</div>';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function extractUrl(text) {
|
|
43
|
+
if (!text) return '';
|
|
44
|
+
const m = text.match(/(https?:\/\/[^\s]+)/);
|
|
45
|
+
return m ? m[1] : '';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function linkifyArtifacts(text) {
|
|
49
|
+
let html = escapeHtml(text);
|
|
50
|
+
// 占位符保护:先提取已识别的片段,避免后续正则把已插入的 <span> 标签二次包裹
|
|
51
|
+
const tokens = [];
|
|
52
|
+
const protect = (s) => { const k = '\u0000TOK' + tokens.length + '\u0000'; tokens.push(s); return k; };
|
|
53
|
+
// 1) URL:排除结尾标点与 HTML 实体
|
|
54
|
+
html = html.replace(/(https?:\/\/[^\s<>"'()]+)/g, (m) => protect('<span class="artifact" data-kind="url" data-path="' + m + '">' + m + '</span>'));
|
|
55
|
+
// 2) Windows 绝对路径(支持正/反斜杠、中文、空格,排除结尾标点)
|
|
56
|
+
html = html.replace(/([A-Za-z]:[\\\/][^\s<>"'()]+?)(?=[\s<>"',。;:、))]|$)/g, (m) => protect('<span class="artifact" data-kind="file" data-path="' + m + '">' + m + '</span>'));
|
|
57
|
+
// 3) Unix 风格绝对路径(至少两级目录,避免误匹配 "2023/2024"、"a/b" 等相对写法)
|
|
58
|
+
html = html.replace(/(\/(?:[A-Za-z0-9_\-.]+\/){1,}[A-Za-z0-9_\-.]*)/g, (m) => protect('<span class="artifact" data-kind="file" data-path="' + m + '">' + m + '</span>'));
|
|
59
|
+
tokens.forEach((s, i) => { html = html.split('\u0000TOK' + i + '\u0000').join(s); });
|
|
60
|
+
return html;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function formatSize(n) {
|
|
64
|
+
if (!Number.isFinite(n)) return '';
|
|
65
|
+
if (n < 1024) return n + ' B';
|
|
66
|
+
if (n < 1024 * 1024) return (n / 1024).toFixed(1) + ' KB';
|
|
67
|
+
return (n / 1024 / 1024).toFixed(2) + ' MB';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function estimateDataUrlSize(dataUrl) {
|
|
71
|
+
// base64 长度 × 0.75 估算字节
|
|
72
|
+
const b64 = (dataUrl || '').split(',')[1] || '';
|
|
73
|
+
return Math.round(b64.length * 0.75);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function formatToolArgs(args) {
|
|
77
|
+
if (!args || typeof args !== 'object') return '';
|
|
78
|
+
const keys = Object.keys(args);
|
|
79
|
+
if (!keys.length) return '';
|
|
80
|
+
const rows = keys.map(function (k) {
|
|
81
|
+
let v = args[k];
|
|
82
|
+
if (v == null) v = '';
|
|
83
|
+
else if (typeof v === 'object') v = JSON.stringify(v);
|
|
84
|
+
return '<div><span style="color:var(--ink-2,#6b7280);">' + escapeHtml(k) + ':</span> ' + escapeHtml(String(v)) + '</div>';
|
|
85
|
+
});
|
|
86
|
+
return '<div class="tc-args">' + rows.join('') + '</div>';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function renderMarkdown(text) {
|
|
90
|
+
let html = escapeHtml(text == null ? '' : text);
|
|
91
|
+
const codeBlocks = [];
|
|
92
|
+
html = html.replace(/```(\w*)\n?([\s\S]*?)```/g, function (_, lang, code) {
|
|
93
|
+
const idx = codeBlocks.length;
|
|
94
|
+
codeBlocks.push('<pre style="background:var(--bg,#f5f6fa);padding:10px;border-radius:8px;overflow-x:auto;font-size:12px;margin:6px 0;white-space:pre-wrap;word-break:break-word;"><code>' + code + '</code></pre>');
|
|
95
|
+
return '\x00CB' + idx + '\x00';
|
|
96
|
+
});
|
|
97
|
+
html = html.replace(/`([^`]+)`/g, '<code style="background:var(--bg,#f5f6fa);padding:1px 5px;border-radius:4px;font-size:12px;">$1</code>');
|
|
98
|
+
html = html.replace(/\*\*([^*]+)\*\*/g, '<b>$1</b>');
|
|
99
|
+
html = html.replace(/^### (.*)$/gm, '<div style="font-weight:700;margin:8px 0 4px;">$1</div>');
|
|
100
|
+
html = html.replace(/^## (.*)$/gm, '<div style="font-weight:700;font-size:15px;margin:10px 0 4px;">$1</div>');
|
|
101
|
+
html = html.replace(/^# (.*)$/gm, '<div style="font-weight:700;font-size:16px;margin:10px 0 4px;">$1</div>');
|
|
102
|
+
html = html.replace(/^[-*] (.*)$/gm, '<div style="padding-left:14px;">• $1</div>');
|
|
103
|
+
html = html.replace(/^(\d+)\. (.*)$/gm, '<div style="padding-left:20px;">$1. $2</div>');
|
|
104
|
+
html = html.replace(/(https?:\/\/[^\s<>"'()]+)/g, '<a href="$1" style="color:var(--brand,#4f6ef7);text-decoration:underline;" target="_blank">$1</a>');
|
|
105
|
+
html = html.replace(/\n/g, '<br>');
|
|
106
|
+
html = html.replace(/\x00CB(\d+)\x00/g, function (_, idx) { return codeBlocks[parseInt(idx)]; });
|
|
107
|
+
return html;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 纯文本渲染:只转义HTML、换行和链接,不转标题/列表/加粗/代码块等格式
|
|
111
|
+
// 用于对话流展示,让输出像普通人聊天一样清爽
|
|
112
|
+
function renderPlainText(text) {
|
|
113
|
+
let html = escapeHtml(stripMarkdown(text == null ? '' : text));
|
|
114
|
+
html = html.replace(/(https?:\/\/[^\s<>"'()]+)/g, '<a href="$1" style="color:var(--brand,#4f6ef7);text-decoration:underline;" target="_blank">$1</a>');
|
|
115
|
+
html = html.replace(/\n/g, '<br>');
|
|
116
|
+
return html;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// 把 Markdown 格式符号全部去掉,只保留纯文本内容
|
|
120
|
+
function stripMarkdown(text) {
|
|
121
|
+
let s = String(text);
|
|
122
|
+
// 去掉代码块 ```...``` 里的标记,保留内容
|
|
123
|
+
s = s.replace(/```[\w]*\n?([\s\S]*?)```/g, '$1');
|
|
124
|
+
// 去掉行内代码 `code` 的反引号,保留内容
|
|
125
|
+
s = s.replace(/`([^`]+)`/g, '$1');
|
|
126
|
+
// 去掉加粗 **text** 和 __text__
|
|
127
|
+
s = s.replace(/\*\*([^*]+)\*\*/g, '$1');
|
|
128
|
+
s = s.replace(/__([^_]+)__/g, '$1');
|
|
129
|
+
// 去掉斜体 *text* 和 _text_(注意不要和列表冲突)
|
|
130
|
+
s = s.replace(/\*([^*\n]+)\*/g, '$1');
|
|
131
|
+
s = s.replace(/_([^_\n]+)_/g, '$1');
|
|
132
|
+
// 去掉标题 # ## ### 等,保留标题文字
|
|
133
|
+
s = s.replace(/^#{1,6}\s+/gm, '');
|
|
134
|
+
// 去掉无序列表符号 * - + (行首)
|
|
135
|
+
s = s.replace(/^[\s]*[-*+]\s+/gm, '');
|
|
136
|
+
// 去掉有序列表符号 1. 2. 等(行首)
|
|
137
|
+
s = s.replace(/^[\s]*\d+\.\s+/gm, '');
|
|
138
|
+
// 去掉引用符号 > (行首)
|
|
139
|
+
s = s.replace(/^[\s]*>\s?/gm, '');
|
|
140
|
+
// 去掉链接 [text](url) 只保留 text
|
|
141
|
+
s = s.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1');
|
|
142
|
+
// 去掉图片  只保留 alt
|
|
143
|
+
s = s.replace(/!\[([^\]]*)\]\([^)]+\)/g, '$1');
|
|
144
|
+
// 去掉分割线 --- *** ___
|
|
145
|
+
s = s.replace(/^[-*_]{3,}\s*$/gm, '');
|
|
146
|
+
// 去掉行号引用 L123、ln 456、第789行这种
|
|
147
|
+
s = s.replace(/\b[Ll][nN]?\s*\d+(-\d+)?/g, '');
|
|
148
|
+
s = s.replace(/第\d+行/g, '');
|
|
149
|
+
// 去掉多余的空行(连续3个以上换行变成2个)
|
|
150
|
+
s = s.replace(/\n{3,}/g, '\n\n');
|
|
151
|
+
return s.trim();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function statusBadge(s) { return '<span class="badge ' + s + '">' + s + '</span>'; }
|
|
155
|
+
|
|
156
|
+
function closeModal(id) { document.getElementById(id).classList.remove('show'); }
|
|
157
|
+
|
|
158
|
+
function openModal(id) { document.getElementById(id).classList.add('show'); }
|
|
159
|
+
|
|
160
|
+
function toast(msg) {
|
|
161
|
+
const el = document.getElementById('toast');
|
|
162
|
+
el.textContent = msg; el.classList.add('show');
|
|
163
|
+
clearTimeout(el._t); el._t = setTimeout(() => el.classList.remove('show'), 2200);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function fmtTime(iso) { try { return new Date(iso).toLocaleString(); } catch { return iso || ''; } }
|
|
167
|
+
|
|
168
|
+
function escapeHtml(s) { return String(s ?? '').replace(/[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c])); }
|
|
169
|
+
|
|
170
|
+
function applyI18nToEl(el) {
|
|
171
|
+
const key = el.getAttribute('data-i18n');
|
|
172
|
+
if (!key) return;
|
|
173
|
+
const dict = I18N[currentLang] || I18N.zh;
|
|
174
|
+
const tag = el.tagName;
|
|
175
|
+
|
|
176
|
+
// 1) 输入类控件:只处理 placeholder,用 ph.<id> 专用键;缺失则保留中文原文
|
|
177
|
+
if (tag === 'INPUT' || tag === 'TEXTAREA') {
|
|
178
|
+
if (el._i18nPhZh === undefined) el._i18nPhZh = el.getAttribute('placeholder') || '';
|
|
179
|
+
const phKey = 'ph.' + (el.id || '');
|
|
180
|
+
if (dict[phKey] != null) el.placeholder = dict[phKey];
|
|
181
|
+
else el.placeholder = el._i18nPhZh;
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// 2) <select>:只翻 title,内容交给 renderModelSelect 等渲染函数管理
|
|
186
|
+
if (tag === 'SELECT') {
|
|
187
|
+
if (el._i18nTitleZh === undefined) el._i18nTitleZh = el.getAttribute('title') || '';
|
|
188
|
+
const tiKey = 'title.' + (el.id || '');
|
|
189
|
+
if (dict[tiKey] != null) el.title = dict[tiKey];
|
|
190
|
+
else el.title = el._i18nTitleZh;
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// 3) 含元素子节点:保留子元素,只替换 title 与直接文本节点
|
|
195
|
+
if (el.firstElementChild) {
|
|
196
|
+
if (el.hasAttribute('title')) el.title = t(key);
|
|
197
|
+
let done = false;
|
|
198
|
+
el.childNodes.forEach((node) => {
|
|
199
|
+
if (node.nodeType === 3 && node.nodeValue.trim()) {
|
|
200
|
+
node.nodeValue = done ? '' : t(key);
|
|
201
|
+
done = true;
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// 4) 纯文本元素:直接覆盖
|
|
208
|
+
el.textContent = t(key);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function t(key) {
|
|
212
|
+
const dict = I18N[currentLang] || I18N.zh;
|
|
213
|
+
return dict[key] || key;
|
|
214
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "飞虹 Code",
|
|
3
|
+
"short_name": "飞虹Code",
|
|
4
|
+
"description": "终端 AI 编程智能体,对标 Muse Code / Cursor",
|
|
5
|
+
"start_url": "/",
|
|
6
|
+
"display": "standalone",
|
|
7
|
+
"background_color": "#1a1a2e",
|
|
8
|
+
"theme_color": "#6366f1",
|
|
9
|
+
"orientation": "any",
|
|
10
|
+
"scope": "/",
|
|
11
|
+
"lang": "zh-CN",
|
|
12
|
+
"dir": "ltr",
|
|
13
|
+
"categories": ["developer-tools", "productivity", "utilities"],
|
|
14
|
+
"icons": [
|
|
15
|
+
{
|
|
16
|
+
"src": "/icons/icon-192.png",
|
|
17
|
+
"sizes": "192x192",
|
|
18
|
+
"type": "image/png",
|
|
19
|
+
"purpose": "any maskable"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"src": "/icons/icon-512.png",
|
|
23
|
+
"sizes": "512x512",
|
|
24
|
+
"type": "image/png",
|
|
25
|
+
"purpose": "any maskable"
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"shortcuts": [
|
|
29
|
+
{
|
|
30
|
+
"name": "新建任务",
|
|
31
|
+
"short_name": "新任务",
|
|
32
|
+
"description": "创建新的 AI 编程任务",
|
|
33
|
+
"url": "/?action=new-task",
|
|
34
|
+
"icons": [{ "src": "/icons/icon-192.png", "sizes": "192x192" }]
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "代码补全",
|
|
38
|
+
"short_name": "补全",
|
|
39
|
+
"description": "快速代码补全",
|
|
40
|
+
"url": "/?action=completion",
|
|
41
|
+
"icons": [{ "src": "/icons/icon-192.png", "sizes": "192x192" }]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"name": "代码审查",
|
|
45
|
+
"short_name": "审查",
|
|
46
|
+
"description": "AI 代码审查",
|
|
47
|
+
"url": "/?action=review",
|
|
48
|
+
"icons": [{ "src": "/icons/icon-192.png", "sizes": "192x192" }]
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"prefer_related_applications": false,
|
|
52
|
+
"features": [
|
|
53
|
+
"Cross Platform",
|
|
54
|
+
"AI Code Completion",
|
|
55
|
+
"Multi-agent Collaboration",
|
|
56
|
+
"Voice Programming",
|
|
57
|
+
"Knowledge Library"
|
|
58
|
+
]
|
|
59
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# robots.txt for 飞虹 Code (feihong-code)
|
|
2
|
+
# https://github.com/feihong-code/feihong-code
|
|
3
|
+
|
|
4
|
+
User-agent: *
|
|
5
|
+
Allow: /
|
|
6
|
+
Disallow: /api/
|
|
7
|
+
Disallow: /admin/
|
|
8
|
+
Disallow: /dashboard/
|
|
9
|
+
|
|
10
|
+
# Sitemap
|
|
11
|
+
# Sitemap: https://feihong-code.com/sitemap.xml
|
|
12
|
+
|
|
13
|
+
# Crawl-delay
|
|
14
|
+
Crawl-delay: 1
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 飞虹 Code Service Worker
|
|
3
|
+
* 支持离线缓存、PWA 安装、移动端适配
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const CACHE_NAME = 'feihong-code-v2';
|
|
7
|
+
const STATIC_CACHE = 'feihong-static-v2';
|
|
8
|
+
const RUNTIME_CACHE = 'feihong-runtime-v2';
|
|
9
|
+
|
|
10
|
+
// 静态资源缓存列表
|
|
11
|
+
const STATIC_ASSETS = [
|
|
12
|
+
'/',
|
|
13
|
+
'/index.html',
|
|
14
|
+
'/manifest.json',
|
|
15
|
+
'/css/style.css',
|
|
16
|
+
'/js/app.js',
|
|
17
|
+
'/js/ui.js',
|
|
18
|
+
'/js/api.js',
|
|
19
|
+
'/js/utils.js',
|
|
20
|
+
'/js/monaco-editor.js',
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
// 安装事件:预缓存静态资源
|
|
24
|
+
self.addEventListener('install', (event) => {
|
|
25
|
+
console.log('[SW] Installing...');
|
|
26
|
+
event.waitUntil(
|
|
27
|
+
caches.open(STATIC_CACHE).then((cache) => {
|
|
28
|
+
console.log('[SW] Pre-caching static assets');
|
|
29
|
+
return cache.addAll(STATIC_ASSETS).catch((err) => {
|
|
30
|
+
console.warn('[SW] Pre-cache failed:', err);
|
|
31
|
+
});
|
|
32
|
+
}).then(() => self.skipWaiting())
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// 激活事件:清理旧缓存
|
|
37
|
+
self.addEventListener('activate', (event) => {
|
|
38
|
+
console.log('[SW] Activating...');
|
|
39
|
+
event.waitUntil(
|
|
40
|
+
caches.keys().then((cacheNames) => {
|
|
41
|
+
return Promise.all(
|
|
42
|
+
cacheNames
|
|
43
|
+
.filter((name) => name !== STATIC_CACHE && name !== RUNTIME_CACHE)
|
|
44
|
+
.map((name) => {
|
|
45
|
+
console.log('[SW] Deleting old cache:', name);
|
|
46
|
+
return caches.delete(name);
|
|
47
|
+
})
|
|
48
|
+
);
|
|
49
|
+
}).then(() => self.clients.claim())
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// fetch 事件:缓存策略
|
|
54
|
+
self.addEventListener('fetch', (event) => {
|
|
55
|
+
const { request } = event;
|
|
56
|
+
const url = new URL(request.url);
|
|
57
|
+
|
|
58
|
+
// 只缓存同源请求
|
|
59
|
+
if (url.origin !== self.location.origin) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// API 请求:直接透传,不缓存(API 响应是动态的,缓存会导致公钥/认证/模型配置等数据过期)
|
|
64
|
+
if (url.pathname.startsWith('/api/')) {
|
|
65
|
+
// 安全相关 API 强制不缓存,直接走网络
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 静态资源:缓存优先,失败时回退到网络
|
|
70
|
+
if (request.method === 'GET') {
|
|
71
|
+
event.respondWith(
|
|
72
|
+
caches.match(request).then((cached) => {
|
|
73
|
+
if (cached) return cached;
|
|
74
|
+
return fetch(request).then((response) => {
|
|
75
|
+
if (response.status === 200) {
|
|
76
|
+
const clone = response.clone();
|
|
77
|
+
caches.open(RUNTIME_CACHE).then((cache) => cache.put(request, clone));
|
|
78
|
+
}
|
|
79
|
+
return response;
|
|
80
|
+
}).catch(() => {
|
|
81
|
+
// 对于 HTML 请求,返回离线页面
|
|
82
|
+
if (request.headers.get('accept')?.includes('text/html')) {
|
|
83
|
+
return caches.match('/index.html');
|
|
84
|
+
}
|
|
85
|
+
return new Response('Offline', { status: 503 });
|
|
86
|
+
});
|
|
87
|
+
})
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// 消息事件:支持手动更新缓存
|
|
93
|
+
self.addEventListener('message', (event) => {
|
|
94
|
+
const { type } = event.data || {};
|
|
95
|
+
|
|
96
|
+
if (type === 'SKIP_WAITING') {
|
|
97
|
+
self.skipWaiting();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (type === 'CLEAR_CACHE') {
|
|
101
|
+
caches.keys().then((names) => {
|
|
102
|
+
names.forEach((name) => caches.delete(name));
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (type === 'GET_VERSION') {
|
|
107
|
+
event.source.postMessage({
|
|
108
|
+
type: 'VERSION',
|
|
109
|
+
version: CACHE_NAME,
|
|
110
|
+
staticCache: STATIC_CACHE,
|
|
111
|
+
runtimeCache: RUNTIME_CACHE,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// 推送通知(预留)
|
|
117
|
+
self.addEventListener('push', (event) => {
|
|
118
|
+
if (event.data) {
|
|
119
|
+
const data = event.data.json();
|
|
120
|
+
const title = data.title || '飞虹 Code';
|
|
121
|
+
const options = {
|
|
122
|
+
body: data.body || '',
|
|
123
|
+
icon: '/icons/icon-192.png',
|
|
124
|
+
badge: '/icons/icon-192.png',
|
|
125
|
+
data: data.data || {},
|
|
126
|
+
};
|
|
127
|
+
event.waitUntil(self.registration.showNotification(title, options));
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// 通知点击
|
|
132
|
+
self.addEventListener('notificationclick', (event) => {
|
|
133
|
+
event.notification.close();
|
|
134
|
+
const url = event.notification.data?.url || '/';
|
|
135
|
+
event.waitUntil(
|
|
136
|
+
clients.openWindow(url).catch(() => {
|
|
137
|
+
return clients.matchAll({ type: 'window' }).then((clientList) => {
|
|
138
|
+
for (const client of clientList) {
|
|
139
|
+
if (client.url === url && 'focus' in client) {
|
|
140
|
+
return client.focus();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (clients.openWindow) return clients.openWindow(url);
|
|
144
|
+
});
|
|
145
|
+
})
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
console.log('[SW] Service Worker loaded');
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# AI 员工军团 · 飞虹整合说明
|
|
2
|
+
|
|
3
|
+
> 晋江市飞虹智科技企业管理有限公司 · 飞扬企源研发中心 · 负责人:吴赐虹
|
|
4
|
+
> 对应飞虹 Code v8.0.0 主线:「企业 AI 底座」的指挥中心层
|
|
5
|
+
|
|
6
|
+
## 一、这是什么
|
|
7
|
+
|
|
8
|
+
把 `feihongzhi_agents`(AI 员工军团系统,Python 实现,17 个业务 AI 员工)作为**产品资产**整合进飞虹 Code,
|
|
9
|
+
并通过飞虹原生工具桥接 + **复用飞虹模型路由**,让两个体系共用一套模型配置、一套安全策略。
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
飞虹 Code(指挥中心)
|
|
13
|
+
├─ feihong_agents_list 只读:员工清单 / 任务统计
|
|
14
|
+
├─ feihong_agents_submit 写(需审批):提交任务 + 立即执行
|
|
15
|
+
└─ 模型路由 ──→ LLM_PROVIDER=doubao(DOUBAO_API_KEY/MODEL/BASE_URL 透传,apiKey 不回显)
|
|
16
|
+
│
|
|
17
|
+
▼
|
|
18
|
+
agent-team/(本仓库根目录,Python 框架本体)
|
|
19
|
+
├─ main.py CLI:init-db / list-agents / submit / run-once / run-loop / approve / stats
|
|
20
|
+
├─ core/ 数据模型(SQLite)+ 调度器(重试 3 次 / 人工闸门)
|
|
21
|
+
├─ agents/ L1-L5 五层 17 员工模块(registry.py 注册)
|
|
22
|
+
├─ llm/ doubao_llm(OpenAI 兼容,零第三方依赖)+ mock_llm
|
|
23
|
+
├─ skills/ 17 个技能包(SKILL.md + run.py)
|
|
24
|
+
└─ feihongzhi.db 任务/线索/客户/内容资产库(首次调用自动 init-db,幂等)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## 二、安装与配置
|
|
28
|
+
|
|
29
|
+
1. **框架**:已复制到仓库根 `agent-team/`(随飞虹分发;`I:\skills\feihongzhi_agents` 为源)。
|
|
30
|
+
2. **技能**:17 个技能已安装到用户级技能目录 `%USERPROFILE%\.feihong-code\skills\`(`discoverSkills` 48 个技能中 17 个为 AI 员工)。
|
|
31
|
+
3. **模型**:无需单独配置。桥接自动读取飞虹 `models.providers` 中**第一个 openai-compatible 且带 apiKey 的 provider**,
|
|
32
|
+
映射为 `DOUBAO_API_KEY / DOUBAO_MODEL / DOUBAO_BASE_URL` + `LLM_PROVIDER=doubao`;无可用 provider 时回退
|
|
33
|
+
`LLM_PROVIDER=mock`(本地确定性,跑通全链路)。可用环境变量覆盖:
|
|
34
|
+
- `FEIHONG_AGENT_TEAM_DIR`:agent-team 目录(缺省 `<仓库根>/agent-team`)
|
|
35
|
+
- `FEIHONG_PYTHON`:Python 解释器(缺省 `python`,本机 Python 3.14.7 已验证)
|
|
36
|
+
|
|
37
|
+
## 三、工具契约
|
|
38
|
+
|
|
39
|
+
| 工具 | 权限 | 入参 | 出参 |
|
|
40
|
+
|---|---|---|---|
|
|
41
|
+
| `feihong_agents_list` | 只读(any) | `scope: agents(默认)\|stats` | 员工清单表格 / 任务统计 JSON |
|
|
42
|
+
| `feihong_agents_submit` | 写(operator/admin 需审批) | `agentId: 1-17(兼容"01")`、`input: JSON 字符串`、`executeNow: 默认 true` | 任务 JSON + 执行结果 |
|
|
43
|
+
|
|
44
|
+
- `agentId` 对应员工编号(01-17),清单用 `feihong_agents_list` 查询。
|
|
45
|
+
- `input` 字段按对应技能 SKILL.md 声明(如 01 获客:`channels`/`keywords`)。
|
|
46
|
+
- 写操作一律走飞虹审批(`approvalTools` 含 `feihong_agents_submit`);只读沙箱拦截同款名单。
|
|
47
|
+
- 安全:apiKey 仅作为子进程环境变量传递,不回显、不落盘、不进审计。
|
|
48
|
+
|
|
49
|
+
## 四、已验证(2026-09-08)
|
|
50
|
+
|
|
51
|
+
- 全量单测 **269/269 通过**(含新增 `tests/unit/agents.test.ts` 3 例:无 provider 回退 mock / 键名安全 / 不误填 key);typecheck 0 错误。
|
|
52
|
+
- 真实链路(dist 产品路径):`list` → 17 员工清单 ✅;`stats` → 任务状态分布 ✅;
|
|
53
|
+
`submit`(mock)→ task_id `T82d867202e43` pending→success,线索入库 3 条 ✅。
|
|
54
|
+
- dist 重建:`npx tsc` 成功 + copy-web 手动等价(本机 Node 环境已知问题,见交接记录)。
|
|
55
|
+
|
|
56
|
+
## 五、使用示例
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
用户:让 01 获客线索雷达找一批客户
|
|
60
|
+
飞虹:feihong_agents_submit agentId=1 input={"channels":"[朋友圈,抖音]","keywords":"企业AI"}
|
|
61
|
+
→ 审批 → 任务成功 → 线索入库 → feihong_agents_list scope=stats 查看结果
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 六、后续可选(未做)
|
|
65
|
+
|
|
66
|
+
- `run-loop`(持续执行)包装为飞虹后台任务/定时任务。
|
|
67
|
+
- `approve`(人工闸门)接入飞虹审批流,替代 Python 侧确认。
|
|
68
|
+
- 员工任务结果回写飞虹记忆(memory/),形成「AI 员工 → 指挥中心」闭环复盘。
|
package/docs/API.md
CHANGED
|
@@ -334,15 +334,15 @@ public class MainActivity extends Activity {
|
|
|
334
334
|
|------|------|------|
|
|
335
335
|
| JDK | 17(Microsoft Build) | JAVA_HOME 指向 |
|
|
336
336
|
| Android SDK | platform 34 + build-tools 34 | ANDROID_HOME 指向 |
|
|
337
|
-
| Gradle | 8.7 | 已解压至
|
|
337
|
+
| Gradle | 8.7 | 已解压至 %USERPROFILE%/.workbuddy/tools/gradle-8.7 |
|
|
338
338
|
|
|
339
339
|
### 7.2 构建命令
|
|
340
340
|
|
|
341
341
|
```bash
|
|
342
342
|
cd fhcode-android
|
|
343
343
|
export JAVA_HOME="C:/Program Files/Microsoft/jdk-17.0.12.7-hotspot"
|
|
344
|
-
export ANDROID_HOME="
|
|
345
|
-
"
|
|
344
|
+
export ANDROID_HOME="%USERPROFILE%/AppData/Local/Android/Sdk"
|
|
345
|
+
"%USERPROFILE%/.workbuddy/tools/gradle-8.7/bin/gradle.bat" assembleDebug --no-daemon
|
|
346
346
|
```
|
|
347
347
|
|
|
348
348
|
产物:`app/build/outputs/apk/debug/app-debug.apk`
|