toolflow 3.1.4
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 +31 -0
- package/README.md +106 -0
- package/README_zh.md +109 -0
- package/docs/reports/ADVANCED_EVOLUTION_REPORT.md +44 -0
- package/docs/reports/AUDIT_AND_OPTIMIZATION_REPORT.md +645 -0
- package/docs/reports/COLD_START_REVIEW_EVOLUTION.md +51 -0
- package/docs/reports/DEEP_ECOSYSTEM_EVOLUTION.md +43 -0
- package/docs/reports/MEMORY.md +18 -0
- package/docs/reports/MICHAEL_DISPATCH_RESULT.md +36 -0
- package/docs/reports/OPENSOURCE_INTEGRATION_REPORT.md +43 -0
- package/docs/reports/PHASE_1_OPTIMIZATION_REPORT.md +87 -0
- package/docs/reports/PHASE_2_OPTIMIZATION_REPORT.md +50 -0
- package/docs/reports/PHASE_3_OPTIMIZATION_REPORT.md +24 -0
- package/docs/reports/PHASE_4_OPTIMIZATION_REPORT.md +28 -0
- package/docs/reports/REPORT_TO_MICHAEL.md +101 -0
- package/docs/reports/SIGNOFF_AND_RELEASE_REPORT.md +85 -0
- package/docs/reports/STAFF_ASSIGNMENTS.md +26 -0
- package/docs/reports/TASK_ASSIGNMENTS.md +59 -0
- package/docs/reports/V1_6_0_EVOLUTION_REPORT.md +48 -0
- package/docs/reports/V1_9_0_HOTFIX_REPORT.md +30 -0
- package/docs/reports/V2_0_0_RELEASE_REPORT.md +18 -0
- package/docs/reports/V2_2_0_ZERO_SPECIALIZATION_REPORT.md +24 -0
- package/docs/reports/V2_3_0_EVOLUTION_REPORT.md +12 -0
- package/ecosystem_taxonomy.json +798 -0
- package/package.json +46 -0
- package/src/blast_radius.ts +302 -0
- package/src/deep_ecosystem.ts +523 -0
- package/src/degradation_matrix.ts +180 -0
- package/src/dehydrator.ts +532 -0
- package/src/ecosystem_taxonomy.json +803 -0
- package/src/engine.ts +1510 -0
- package/src/i18n.ts +89 -0
- package/src/index.ts +983 -0
- package/src/json_extractor.ts +57 -0
- package/src/memory.ts +151 -0
- package/src/prompts_manager.ts +262 -0
- package/src/review_isolation.ts +188 -0
- package/src/state.ts +810 -0
- package/src/taxonomy.ts +580 -0
- package/src/types.ts +341 -0
- package/src/ui.ts +1036 -0
- package/src/worker_orchestrator.ts +60 -0
- package/tests/challenger_stress_harness.ts +265 -0
- package/tests/monorepo_multilang_stress.ts +404 -0
- package/tests/sandbox_e2e.ts +167 -0
- package/tests/test_json_extractor.ts +44 -0
- package/tests/test_modules_1_to_4.ts +106 -0
- package/tests/test_suite.ts +1689 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ToolFlow Deep Ecosystem Engine (v1.8.0)
|
|
3
|
+
* 深度生态装配系统:
|
|
4
|
+
* 1. Deep Skills Distiller: 物理读取并结构化提炼 SKILL.md 规则、SOP 与门禁检查点
|
|
5
|
+
* 2. Deep MCP Registry: 方法级探测与精准参数调用模板合成 (无幻觉直达)
|
|
6
|
+
* 3. Deep Contract Binder: 将方法级调用模板与高压 Skill 契约注入蓝图各阶段
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import * as fs from "fs";
|
|
10
|
+
import * as path from "path";
|
|
11
|
+
import { exec } from "child_process";
|
|
12
|
+
import { promisify } from "util";
|
|
13
|
+
import { DistilledSkillContract, McpToolBinding, BlueprintStage, EcosystemBundlePlan, RecommendedPackageItem } from "./types.js";
|
|
14
|
+
|
|
15
|
+
const execAsync = promisify(exec);
|
|
16
|
+
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// 1. Deep Skills Distiller (Skill 深度解析与 SOP 规则蒸馏器)
|
|
19
|
+
// ============================================================================
|
|
20
|
+
|
|
21
|
+
export class SkillDistiller {
|
|
22
|
+
/**
|
|
23
|
+
* 从给定的 SKILL.md 文件物理内容中蒸馏提炼紧凑规则契约
|
|
24
|
+
*/
|
|
25
|
+
public static distillFromContent(skillName: string, content: string, filePath?: string): DistilledSkillContract {
|
|
26
|
+
const lines = content.split(/\r?\n/);
|
|
27
|
+
const directives: string[] = [];
|
|
28
|
+
const sopSteps: string[] = [];
|
|
29
|
+
const rules: string[] = [];
|
|
30
|
+
const checkpoints: string[] = [];
|
|
31
|
+
|
|
32
|
+
let currentSection: "unknown" | "sop" | "rules" | "checklist" | "directives" = "unknown";
|
|
33
|
+
|
|
34
|
+
for (const rawLine of lines) {
|
|
35
|
+
const line = rawLine.trim();
|
|
36
|
+
if (!line) continue;
|
|
37
|
+
|
|
38
|
+
// 标题探测
|
|
39
|
+
const lower = line.toLowerCase();
|
|
40
|
+
if (line.startsWith("#")) {
|
|
41
|
+
if (lower.includes("step") || lower.includes("workflow") || lower.includes("sop") || lower.includes("流程") || lower.includes("步骤")) {
|
|
42
|
+
currentSection = "sop";
|
|
43
|
+
} else if (lower.includes("rule") || lower.includes("guideline") || lower.includes("constraint") || lower.includes("规范") || lower.includes("原则")) {
|
|
44
|
+
currentSection = "rules";
|
|
45
|
+
} else if (lower.includes("check") || lower.includes("audit") || lower.includes("verify") || lower.includes("清单") || lower.includes("验收")) {
|
|
46
|
+
currentSection = "checklist";
|
|
47
|
+
} else if (lower.includes("command") || lower.includes("usage") || lower.includes("directive") || lower.includes("指令")) {
|
|
48
|
+
currentSection = "directives";
|
|
49
|
+
} else {
|
|
50
|
+
currentSection = "unknown";
|
|
51
|
+
}
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 提取核心指令 (如 /plan, /review, 或者带有反引号的命令)
|
|
56
|
+
if (currentSection === "directives" || line.startsWith("`/") || line.includes("`plannotator") || line.includes("`workflow")) {
|
|
57
|
+
if ((line.startsWith("-") || line.startsWith("*") || line.startsWith("•") || line.match(/^\d+\./)) && line.length < 180) {
|
|
58
|
+
directives.push(line.replace(/^[-*•\d.]\s*/, ""));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 提取 SOP 步骤
|
|
63
|
+
if (currentSection === "sop" || line.match(/^\d+\.\s/)) {
|
|
64
|
+
if (line.length < 200 && (line.match(/^\d+\./) || line.startsWith("-") || line.startsWith("*"))) {
|
|
65
|
+
sopSteps.push(line.replace(/^[-*•\d.]\s*/, ""));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 提取硬性约束规则 (含 Never, Always, 严禁, 必须, 绝不)
|
|
70
|
+
if (currentSection === "rules" || lower.includes("never") || lower.includes("always") || line.includes("严禁") || line.includes("必须") || line.includes("禁止")) {
|
|
71
|
+
if ((line.startsWith("-") || line.startsWith("*") || line.startsWith("•")) && line.length < 200) {
|
|
72
|
+
rules.push(line.replace(/^[-*•]\s*/, ""));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 提取验收检查清单 (Checkpoints)
|
|
77
|
+
if (currentSection === "checklist" || line.includes("[ ]") || line.includes("[x]")) {
|
|
78
|
+
if (line.length < 180) {
|
|
79
|
+
checkpoints.push(line.replace(/^[-*•]\s*(\[[ x]\]\s*)?/, ""));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// 兜底保障:若未按规整 Markdown 排版,从全局嗅探高价值指令
|
|
85
|
+
if (directives.length === 0) {
|
|
86
|
+
const slashMatches = content.match(/\/[a-zA-Z0-9_-]+/g);
|
|
87
|
+
if (slashMatches) {
|
|
88
|
+
directives.push(...Array.from(new Set(slashMatches)).slice(0, 3));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (rules.length === 0) {
|
|
92
|
+
rules.push(`严格遵守「${skillName}」技能的操作标准,确保工作流程专业可溯。`);
|
|
93
|
+
}
|
|
94
|
+
if (checkpoints.length === 0) {
|
|
95
|
+
checkpoints.push(`验证「${skillName}」所规定的产物输出完整性。`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
skillName,
|
|
100
|
+
filePath,
|
|
101
|
+
directives: directives.slice(0, 4),
|
|
102
|
+
sopSteps: sopSteps.slice(0, 5),
|
|
103
|
+
rules: rules.slice(0, 5),
|
|
104
|
+
checkpoints: checkpoints.slice(0, 5)
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* 物理读取本地 SKILL.md 并蒸馏
|
|
110
|
+
*/
|
|
111
|
+
public static distillFromFile(filePath: string, skillName: string): DistilledSkillContract {
|
|
112
|
+
try {
|
|
113
|
+
if (fs.existsSync(filePath)) {
|
|
114
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
115
|
+
return this.distillFromContent(skillName, content, filePath);
|
|
116
|
+
}
|
|
117
|
+
} catch (_) {}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
skillName,
|
|
121
|
+
filePath,
|
|
122
|
+
directives: [`/skill:${skillName}`],
|
|
123
|
+
sopSteps: [`激活并遵循 ${skillName} 流程`],
|
|
124
|
+
rules: [`执行本阶段时强制应用 ${skillName} 的规范`],
|
|
125
|
+
checkpoints: [`检查 ${skillName} 规约是否满足`]
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* 将蒸馏契约格式化为可直接物理注入 System Prompt 的高压契约块
|
|
131
|
+
*/
|
|
132
|
+
public static formatAsSystemContract(contract: DistilledSkillContract): string {
|
|
133
|
+
const lines: string[] = [];
|
|
134
|
+
lines.push(`\n<skill_contract skill="${contract.skillName}">`);
|
|
135
|
+
lines.push(` [SOP 核心规范与操作约束]`);
|
|
136
|
+
for (const rule of contract.rules) {
|
|
137
|
+
lines.push(` • ${rule}`);
|
|
138
|
+
}
|
|
139
|
+
if (contract.sopSteps.length > 0) {
|
|
140
|
+
lines.push(` [执行 SOP 步骤]`);
|
|
141
|
+
contract.sopSteps.forEach((s, idx) => lines.push(` ${idx + 1}. ${s}`));
|
|
142
|
+
}
|
|
143
|
+
if (contract.checkpoints.length > 0) {
|
|
144
|
+
lines.push(` [完工核对门禁 (Checkpoints)]`);
|
|
145
|
+
for (const cp of contract.checkpoints) {
|
|
146
|
+
lines.push(` [ ] ${cp}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
lines.push(`</skill_contract>\n`);
|
|
150
|
+
return lines.join("\n");
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ============================================================================
|
|
155
|
+
// 2. Deep MCP Registry (MCP 方法级字典与调用模板合成器)
|
|
156
|
+
// ============================================================================
|
|
157
|
+
|
|
158
|
+
export interface KnownMcpMethodProfile {
|
|
159
|
+
server: string;
|
|
160
|
+
tool: string;
|
|
161
|
+
category: "browser" | "database" | "git" | "filesystem" | "api" | "general";
|
|
162
|
+
description: string;
|
|
163
|
+
sampleTemplate: string;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// 内置常见高频 MCP Server 深度方法知识库 (开箱即用无幻觉)
|
|
167
|
+
export const KNOWN_MCP_METHODS: KnownMcpMethodProfile[] = [
|
|
168
|
+
// Playwright / Puppeteer 浏览器自动化
|
|
169
|
+
{
|
|
170
|
+
server: "playwright",
|
|
171
|
+
tool: "playwright_navigate",
|
|
172
|
+
category: "browser",
|
|
173
|
+
description: "导航到指定页面进行测试或渲染",
|
|
174
|
+
sampleTemplate: `mcp({ server: "playwright", tool: "playwright_navigate", args: { url: "http://localhost:3000" } })`
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
server: "playwright",
|
|
178
|
+
tool: "playwright_screenshot",
|
|
179
|
+
category: "browser",
|
|
180
|
+
description: "截取网页渲染画面进行视觉走查",
|
|
181
|
+
sampleTemplate: `mcp({ server: "playwright", tool: "playwright_screenshot", args: { path: "preview.png" } })`
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
server: "puppeteer",
|
|
185
|
+
tool: "puppeteer_navigate",
|
|
186
|
+
category: "browser",
|
|
187
|
+
description: "控制 Headless 浏览器打开本地/远程页面",
|
|
188
|
+
sampleTemplate: `mcp({ server: "puppeteer", tool: "puppeteer_navigate", args: { url: "http://localhost:8080" } })`
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
server: "puppeteer",
|
|
192
|
+
tool: "puppeteer_screenshot",
|
|
193
|
+
category: "browser",
|
|
194
|
+
description: "对当前前端页面进行快照走查",
|
|
195
|
+
sampleTemplate: `mcp({ server: "puppeteer", tool: "puppeteer_screenshot", args: { name: "page_check" } })`
|
|
196
|
+
},
|
|
197
|
+
// 数据库相关 (Postgres / MySQL / SQLite)
|
|
198
|
+
{
|
|
199
|
+
server: "postgres",
|
|
200
|
+
tool: "query",
|
|
201
|
+
category: "database",
|
|
202
|
+
description: "执行 SQL 查询以校验数据表结构与真实数据",
|
|
203
|
+
sampleTemplate: `mcp({ server: "postgres", tool: "query", args: { sql: "SELECT * FROM users LIMIT 5;" } })`
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
server: "sqlite",
|
|
207
|
+
tool: "read_query",
|
|
208
|
+
category: "database",
|
|
209
|
+
description: "查询 SQLite 数据库表或 Schema",
|
|
210
|
+
sampleTemplate: `mcp({ server: "sqlite", tool: "read_query", args: { query: "SELECT name FROM sqlite_master WHERE type='table';" } })`
|
|
211
|
+
},
|
|
212
|
+
// GitHub / 协作
|
|
213
|
+
{
|
|
214
|
+
server: "github",
|
|
215
|
+
tool: "create_pull_request",
|
|
216
|
+
category: "git",
|
|
217
|
+
description: "基于当前交付成果自动创建 PR",
|
|
218
|
+
sampleTemplate: `mcp({ server: "github", tool: "create_pull_request", args: { title: "feat: deliver task", branch: "feat/task" } })`
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
server: "github",
|
|
222
|
+
tool: "get_file_contents",
|
|
223
|
+
category: "git",
|
|
224
|
+
description: "检索远端仓库关键参照代码",
|
|
225
|
+
sampleTemplate: `mcp({ server: "github", tool: "get_file_contents", args: { path: "README.md" } })`
|
|
226
|
+
},
|
|
227
|
+
// 通用 Fetch / API
|
|
228
|
+
{
|
|
229
|
+
server: "fetch",
|
|
230
|
+
tool: "fetch",
|
|
231
|
+
category: "api",
|
|
232
|
+
description: "抓取外部 API 规范或文档",
|
|
233
|
+
sampleTemplate: `mcp({ server: "fetch", tool: "fetch", args: { url: "https://api.example.com/v1/health" } })`
|
|
234
|
+
}
|
|
235
|
+
];
|
|
236
|
+
|
|
237
|
+
export class McpMethodRegistry {
|
|
238
|
+
/**
|
|
239
|
+
* 根据检测到的 MCP Server 列表,智能生成阶段适用的方法级精准绑定
|
|
240
|
+
*/
|
|
241
|
+
public static resolveBindingsForStage(
|
|
242
|
+
serverNames: string[],
|
|
243
|
+
stageObjective: string,
|
|
244
|
+
isReviewStage: boolean = false
|
|
245
|
+
): McpToolBinding[] {
|
|
246
|
+
const bindings: McpToolBinding[] = [];
|
|
247
|
+
const lowerObj = stageObjective.toLowerCase();
|
|
248
|
+
|
|
249
|
+
for (const sName of serverNames) {
|
|
250
|
+
const lowerServer = sName.toLowerCase();
|
|
251
|
+
// 匹配已知方法
|
|
252
|
+
const matched = KNOWN_MCP_METHODS.filter(m => m.server.toLowerCase() === lowerServer);
|
|
253
|
+
|
|
254
|
+
if (matched.length > 0) {
|
|
255
|
+
for (const item of matched) {
|
|
256
|
+
// 如果是测试/走查阶段,优先绑定截图和测试
|
|
257
|
+
if (isReviewStage && (item.category === "browser" || item.tool.includes("screenshot") || item.tool.includes("query"))) {
|
|
258
|
+
bindings.push({
|
|
259
|
+
server: item.server,
|
|
260
|
+
tool: item.tool,
|
|
261
|
+
reason: item.description,
|
|
262
|
+
template: item.sampleTemplate
|
|
263
|
+
});
|
|
264
|
+
} else if (!isReviewStage && item.category !== "browser") {
|
|
265
|
+
// 普通阶段绑定非浏览器走查工具
|
|
266
|
+
bindings.push({
|
|
267
|
+
server: item.server,
|
|
268
|
+
tool: item.tool,
|
|
269
|
+
reason: item.description,
|
|
270
|
+
template: item.sampleTemplate
|
|
271
|
+
});
|
|
272
|
+
} else if (lowerObj.includes("page") || lowerObj.includes("web") || lowerObj.includes("ui") || lowerObj.includes("页面")) {
|
|
273
|
+
// 明确指明 UI 的阶段,直接挂载浏览器操作
|
|
274
|
+
bindings.push({
|
|
275
|
+
server: item.server,
|
|
276
|
+
tool: item.tool,
|
|
277
|
+
reason: item.description,
|
|
278
|
+
template: item.sampleTemplate
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
} else {
|
|
283
|
+
// 未知但配置了的通用 MCP Server:生成规范的标准动态调用模板
|
|
284
|
+
bindings.push({
|
|
285
|
+
server: sName,
|
|
286
|
+
tool: `${sName}_action`,
|
|
287
|
+
reason: `调用客户配置的「${sName}」专用服务`,
|
|
288
|
+
template: `mcp({ server: "${sName}", tool: "<tool_name>", args: { ... } })`
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return bindings.slice(0, 3); // 每个阶段精准绑定最相关的 1-3 个方法,杜绝过载
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// ============================================================================
|
|
298
|
+
// 3. Deep Contract Binder (生态深度灌注与阶段装备)
|
|
299
|
+
// ============================================================================
|
|
300
|
+
|
|
301
|
+
export function bindDeepEcosystemToStage(
|
|
302
|
+
stage: BlueprintStage,
|
|
303
|
+
availableMcpServers: string[],
|
|
304
|
+
discoveredSkills: Array<{ name: string; filePath?: string }>
|
|
305
|
+
): void {
|
|
306
|
+
// 1. 绑定 MCP 方法级模板
|
|
307
|
+
if (availableMcpServers && availableMcpServers.length > 0) {
|
|
308
|
+
const mcpBindings = McpMethodRegistry.resolveBindingsForStage(
|
|
309
|
+
availableMcpServers,
|
|
310
|
+
stage.coreObjective,
|
|
311
|
+
stage.isReviewStage
|
|
312
|
+
);
|
|
313
|
+
if (mcpBindings.length > 0) {
|
|
314
|
+
stage.mcpToolBindings = mcpBindings;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// 2. 蒸馏并绑定匹配到的 Skill
|
|
319
|
+
if (stage.boundCapabilities?.skills && stage.boundCapabilities.skills.length > 0) {
|
|
320
|
+
const targetSkillName = stage.boundCapabilities.skills[0];
|
|
321
|
+
const skillItem = discoveredSkills.find(s => s.name.toLowerCase() === targetSkillName.toLowerCase());
|
|
322
|
+
|
|
323
|
+
if (skillItem && skillItem.filePath) {
|
|
324
|
+
stage.skillContract = SkillDistiller.distillFromFile(skillItem.filePath, skillItem.name);
|
|
325
|
+
} else {
|
|
326
|
+
stage.skillContract = {
|
|
327
|
+
skillName: targetSkillName,
|
|
328
|
+
directives: [`/skill:${targetSkillName}`],
|
|
329
|
+
sopSteps: [`遵循 ${targetSkillName} 标准规范执行业务设计与代码构建`],
|
|
330
|
+
rules: [`禁止偏离 ${targetSkillName} 的指引要求`],
|
|
331
|
+
checkpoints: [`核对 ${targetSkillName} 成果指标`]
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// ============================================================================
|
|
338
|
+
// 4. Ecosystem Catalog Radar & Installer (全网生态索引雷达与一键装配管线)
|
|
339
|
+
// ============================================================================
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* 官方通用基础设施工具底册 (仅收录官方权威通用的底层编排与基础审查框架)
|
|
343
|
+
*/
|
|
344
|
+
export const CURATED_ECOSYSTEM_CATALOG: Array<{
|
|
345
|
+
name: string;
|
|
346
|
+
source: string;
|
|
347
|
+
keywords: string[];
|
|
348
|
+
description: string;
|
|
349
|
+
leverageReason: string;
|
|
350
|
+
official?: boolean;
|
|
351
|
+
}> = [
|
|
352
|
+
{
|
|
353
|
+
name: "@earendil-works/pi-subagents",
|
|
354
|
+
source: "npm:pi-subagents",
|
|
355
|
+
keywords: ["subagent", "agent", "worker", "parallel", "council", "多代理", "子代理", "并行", "审查会"],
|
|
356
|
+
description: "Pi 官方多代理隔离并发编排核心",
|
|
357
|
+
leverageReason: "实现子任务隔离沙盒与并发分发,避免主会话日志爆炸",
|
|
358
|
+
official: true
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
name: "@quintinshaw/pi-dynamic-workflows",
|
|
362
|
+
source: "npm:@quintinshaw/pi-dynamic-workflows",
|
|
363
|
+
keywords: ["workflow", "pipeline", "dag", "flow", "工作流", "流水线"],
|
|
364
|
+
description: "Pi 官方原生动态有向无环工作流调度引擎",
|
|
365
|
+
leverageReason: "提供工业级状态机流转与任务管道拓扑",
|
|
366
|
+
official: true
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
name: "@plannotator/pi-extension",
|
|
370
|
+
source: "npm:@plannotator/pi-extension",
|
|
371
|
+
keywords: ["review", "annotation", "diff", "audit", "走查", "批注", "审查", "代码评审"],
|
|
372
|
+
description: "专业可视化代码与架构走查审查套件",
|
|
373
|
+
leverageReason: "提供交互式 Diff 批注与无记忆冷启动质检",
|
|
374
|
+
official: true
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
name: "@modelcontextprotocol/server-playwright",
|
|
378
|
+
source: "npm:@modelcontextprotocol/server-playwright",
|
|
379
|
+
keywords: ["browser", "web", "crawl", "scrape", "ui test", "e2e", "页面走查", "浏览器", "网页自动化", "截图"],
|
|
380
|
+
description: "无头浏览器控制与自动化截图/端到端测试 MCP 服务",
|
|
381
|
+
leverageReason: "免去从零编写 Selenium/Puppeteer 脚本,直接通过标准 MCP 调用浏览器",
|
|
382
|
+
official: true
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
name: "@modelcontextprotocol/server-postgres",
|
|
386
|
+
source: "npm:@modelcontextprotocol/server-postgres",
|
|
387
|
+
keywords: ["postgres", "pgsql", "database", "sql", "数据库", "表结构"],
|
|
388
|
+
description: "PostgreSQL 数据库元数据探测与查询 MCP 服务",
|
|
389
|
+
leverageReason: "直接读取库表结构与执行 SQL 巡检,免去手写数据库驱动"
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
name: "@modelcontextprotocol/server-github",
|
|
393
|
+
source: "npm:@modelcontextprotocol/server-github",
|
|
394
|
+
keywords: ["github", "pr", "issue", "repo", "commit", "代码库"],
|
|
395
|
+
description: "GitHub 仓库/PR/Issue 官方 MCP 读写网关",
|
|
396
|
+
leverageReason: "一键集成 Pull Request 自动化走查与提交"
|
|
397
|
+
}
|
|
398
|
+
];
|
|
399
|
+
|
|
400
|
+
export class EcosystemRadar {
|
|
401
|
+
/**
|
|
402
|
+
* 针对任务推导全网公认优秀的生态工具套餐 (Batch Recommendation)
|
|
403
|
+
* 遵循建议 1:绝不逐个询问,而是打包成一揽子方案!
|
|
404
|
+
*/
|
|
405
|
+
public static async searchEcosystemCatalog(
|
|
406
|
+
task: string,
|
|
407
|
+
installedNames: string[] = []
|
|
408
|
+
): Promise<EcosystemBundlePlan[]> {
|
|
409
|
+
const lowerTask = task.toLowerCase();
|
|
410
|
+
const recommendedPackages: RecommendedPackageItem[] = [];
|
|
411
|
+
|
|
412
|
+
const installedSet = new Set(installedNames.map(n => n.toLowerCase().replace(/^@[\w-]+\//, "")));
|
|
413
|
+
|
|
414
|
+
// 1. 优先扫描精选底册
|
|
415
|
+
for (const item of CURATED_ECOSYSTEM_CATALOG) {
|
|
416
|
+
// 若本地已安装则跳过
|
|
417
|
+
const cleanName = item.name.toLowerCase().replace(/^@[\w-]+\//, "");
|
|
418
|
+
if (installedSet.has(cleanName) || installedSet.has(item.name.toLowerCase())) {
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// 关键词匹配
|
|
423
|
+
const hit = item.keywords.some(kw => lowerTask.includes(kw.toLowerCase()));
|
|
424
|
+
if (hit) {
|
|
425
|
+
recommendedPackages.push({
|
|
426
|
+
name: item.name,
|
|
427
|
+
source: item.source,
|
|
428
|
+
description: item.description,
|
|
429
|
+
leverageReason: item.leverageReason,
|
|
430
|
+
official: item.official
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// 2. 组装套餐方案 (若有推荐,返回套餐 A 与纯净方案 B)
|
|
436
|
+
if (recommendedPackages.length > 0) {
|
|
437
|
+
const bundleA: EcosystemBundlePlan = {
|
|
438
|
+
id: "bundle_recommended",
|
|
439
|
+
title: `[一键装配] 自动引入 ${recommendedPackages.length} 个社区/官方公认神装套件 (强烈推荐)`,
|
|
440
|
+
description: recommendedPackages.map(p => `• @${p.name}: ${p.leverageReason}`).join("\n"),
|
|
441
|
+
packages: recommendedPackages,
|
|
442
|
+
isRecommended: true
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
const bundleB: EcosystemBundlePlan = {
|
|
446
|
+
id: "bundle_vanilla",
|
|
447
|
+
title: "[直接从零手写] 不引入外部新插件,仅用本地环境与标准库实现",
|
|
448
|
+
description: "适合网络受限或纯净项目环境,将从零手写核心业务逻辑与通信通道",
|
|
449
|
+
packages: [],
|
|
450
|
+
isRecommended: false
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
return [bundleA, bundleB];
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
return [];
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* 解析当前宿主系统上可执行的 `pi` 命令前缀(对 Windows 批处理/环境 PATH 进行跨平台加固)
|
|
461
|
+
*/
|
|
462
|
+
public static resolvePiCliCommand(): string {
|
|
463
|
+
if (process.platform !== "win32") {
|
|
464
|
+
return "pi";
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Windows 平台加固解析策略:
|
|
468
|
+
// 1. 优先尝试直接 `pi` (若全局 PATH 关联正常)
|
|
469
|
+
// 2. 备选尝试 `pi.cmd` (避免某些 cmd.exe/子进程缺少 PATHEXT 解析)
|
|
470
|
+
// 3. 备选尝试 `npx pi` (npm 环境原生兜底)
|
|
471
|
+
// 4. 备选尝试 `npx.cmd pi`
|
|
472
|
+
const candidates = ["pi", "pi.cmd", "npx pi", "npx.cmd pi"];
|
|
473
|
+
for (const candidate of candidates) {
|
|
474
|
+
try {
|
|
475
|
+
const testCmd = `${candidate} --version`;
|
|
476
|
+
const { execSync } = require("child_process");
|
|
477
|
+
execSync(testCmd, { stdio: "ignore", timeout: 4000 });
|
|
478
|
+
return candidate;
|
|
479
|
+
} catch {
|
|
480
|
+
// 继续探测下一个候选
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// 默认 fallback
|
|
485
|
+
return "npx pi";
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* 在项目本地安全安装生态包 (`pi install -l <source>`)
|
|
490
|
+
*/
|
|
491
|
+
public static async installPackagesLocally(
|
|
492
|
+
packages: RecommendedPackageItem[],
|
|
493
|
+
cwd: string = process.cwd()
|
|
494
|
+
): Promise<{ success: boolean; installed: string[]; failed: string[]; log: string }> {
|
|
495
|
+
const installed: string[] = [];
|
|
496
|
+
const failed: string[] = [];
|
|
497
|
+
const logs: string[] = [];
|
|
498
|
+
const cliPrefix = EcosystemRadar.resolvePiCliCommand();
|
|
499
|
+
|
|
500
|
+
for (const pkg of packages) {
|
|
501
|
+
try {
|
|
502
|
+
logs.push(`[ToolFlow] 正在为本地项目安装: ${pkg.source} ...`);
|
|
503
|
+
// 安全参数校验:避免异常字符注入,并添加 --approve 标志规避无 TTY 交互死锁挂起
|
|
504
|
+
const safeSource = pkg.source.replace(/["'`$\\]/g, "");
|
|
505
|
+
const cmd = `${cliPrefix} install -l ${safeSource} --approve`;
|
|
506
|
+
const { stdout, stderr } = await execAsync(cmd, { cwd, timeout: 60000 });
|
|
507
|
+
installed.push(pkg.name);
|
|
508
|
+
logs.push(`[ToolFlow] ${pkg.name} 安装成功:\n${stdout}`);
|
|
509
|
+
} catch (err: any) {
|
|
510
|
+
failed.push(pkg.name);
|
|
511
|
+
logs.push(`[ToolFlow] ${pkg.name} 安装失败: ${err.message}`);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
return {
|
|
516
|
+
success: failed.length === 0,
|
|
517
|
+
installed,
|
|
518
|
+
failed,
|
|
519
|
+
log: logs.join("\n")
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|