level-up-mcp-server-cn 0.4.0

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 (137) hide show
  1. package/.claude/projects/c--Users-klexi-OneDrive-Desktop-Levelup-level-up-mcp-server/memory/project_testing_service.md +11 -0
  2. package/.claude/settings.local.json +10 -0
  3. package/.env.example +19 -0
  4. package/CLAUDE.md +222 -0
  5. package/CODE_REVIEW.md +282 -0
  6. package/LICENSE +64 -0
  7. package/README.md +198 -0
  8. package/dist/constants.d.ts +33 -0
  9. package/dist/constants.js +78 -0
  10. package/dist/constants.js.map +1 -0
  11. package/dist/data/quest-seeds.d.ts +18 -0
  12. package/dist/data/quest-seeds.js +380 -0
  13. package/dist/data/quest-seeds.js.map +1 -0
  14. package/dist/index.d.ts +3 -0
  15. package/dist/index.js +260 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/schemas/common.d.ts +33 -0
  18. package/dist/schemas/common.js +96 -0
  19. package/dist/schemas/common.js.map +1 -0
  20. package/dist/services/dispatcher.d.ts +27 -0
  21. package/dist/services/dispatcher.js +47 -0
  22. package/dist/services/dispatcher.js.map +1 -0
  23. package/dist/services/errors.d.ts +56 -0
  24. package/dist/services/errors.js +99 -0
  25. package/dist/services/errors.js.map +1 -0
  26. package/dist/services/format.d.ts +74 -0
  27. package/dist/services/format.js +144 -0
  28. package/dist/services/format.js.map +1 -0
  29. package/dist/services/ownership.d.ts +19 -0
  30. package/dist/services/ownership.js +79 -0
  31. package/dist/services/ownership.js.map +1 -0
  32. package/dist/services/quality-gate.d.ts +45 -0
  33. package/dist/services/quality-gate.js +131 -0
  34. package/dist/services/quality-gate.js.map +1 -0
  35. package/dist/services/rate-limit.d.ts +12 -0
  36. package/dist/services/rate-limit.js +49 -0
  37. package/dist/services/rate-limit.js.map +1 -0
  38. package/dist/services/register.d.ts +49 -0
  39. package/dist/services/register.js +63 -0
  40. package/dist/services/register.js.map +1 -0
  41. package/dist/services/supabase.d.ts +10 -0
  42. package/dist/services/supabase.js +79 -0
  43. package/dist/services/supabase.js.map +1 -0
  44. package/dist/tools/achievements.d.ts +6 -0
  45. package/dist/tools/achievements.js +242 -0
  46. package/dist/tools/achievements.js.map +1 -0
  47. package/dist/tools/admin.d.ts +16 -0
  48. package/dist/tools/admin.js +328 -0
  49. package/dist/tools/admin.js.map +1 -0
  50. package/dist/tools/agents.d.ts +3 -0
  51. package/dist/tools/agents.js +400 -0
  52. package/dist/tools/agents.js.map +1 -0
  53. package/dist/tools/bootstrap.d.ts +17 -0
  54. package/dist/tools/bootstrap.js +565 -0
  55. package/dist/tools/bootstrap.js.map +1 -0
  56. package/dist/tools/dispatchers/admin.d.ts +3 -0
  57. package/dist/tools/dispatchers/admin.js +50 -0
  58. package/dist/tools/dispatchers/admin.js.map +1 -0
  59. package/dist/tools/dispatchers/eval.d.ts +3 -0
  60. package/dist/tools/dispatchers/eval.js +40 -0
  61. package/dist/tools/dispatchers/eval.js.map +1 -0
  62. package/dist/tools/dispatchers/quests.d.ts +3 -0
  63. package/dist/tools/dispatchers/quests.js +60 -0
  64. package/dist/tools/dispatchers/quests.js.map +1 -0
  65. package/dist/tools/dispatchers/session.d.ts +3 -0
  66. package/dist/tools/dispatchers/session.js +38 -0
  67. package/dist/tools/dispatchers/session.js.map +1 -0
  68. package/dist/tools/dispatchers/skills.d.ts +3 -0
  69. package/dist/tools/dispatchers/skills.js +49 -0
  70. package/dist/tools/dispatchers/skills.js.map +1 -0
  71. package/dist/tools/dispatchers/tasks.d.ts +3 -0
  72. package/dist/tools/dispatchers/tasks.js +53 -0
  73. package/dist/tools/dispatchers/tasks.js.map +1 -0
  74. package/dist/tools/dispatchers/users.d.ts +3 -0
  75. package/dist/tools/dispatchers/users.js +65 -0
  76. package/dist/tools/dispatchers/users.js.map +1 -0
  77. package/dist/tools/dispatchers/xp.d.ts +3 -0
  78. package/dist/tools/dispatchers/xp.js +51 -0
  79. package/dist/tools/dispatchers/xp.js.map +1 -0
  80. package/dist/tools/growth-plan.d.ts +5 -0
  81. package/dist/tools/growth-plan.js +791 -0
  82. package/dist/tools/growth-plan.js.map +1 -0
  83. package/dist/tools/leaderboards.d.ts +10 -0
  84. package/dist/tools/leaderboards.js +279 -0
  85. package/dist/tools/leaderboards.js.map +1 -0
  86. package/dist/tools/leveling.d.ts +24 -0
  87. package/dist/tools/leveling.js +356 -0
  88. package/dist/tools/leveling.js.map +1 -0
  89. package/dist/tools/metrics.d.ts +3 -0
  90. package/dist/tools/metrics.js +247 -0
  91. package/dist/tools/metrics.js.map +1 -0
  92. package/dist/tools/quests.d.ts +5 -0
  93. package/dist/tools/quests.js +586 -0
  94. package/dist/tools/quests.js.map +1 -0
  95. package/dist/tools/ratings.d.ts +11 -0
  96. package/dist/tools/ratings.js +564 -0
  97. package/dist/tools/ratings.js.map +1 -0
  98. package/dist/tools/skills.d.ts +66 -0
  99. package/dist/tools/skills.js +1112 -0
  100. package/dist/tools/skills.js.map +1 -0
  101. package/dist/tools/system.d.ts +31 -0
  102. package/dist/tools/system.js +605 -0
  103. package/dist/tools/system.js.map +1 -0
  104. package/dist/tools/tasks.d.ts +73 -0
  105. package/dist/tools/tasks.js +1572 -0
  106. package/dist/tools/tasks.js.map +1 -0
  107. package/dist/tools/users.d.ts +97 -0
  108. package/dist/tools/users.js +1306 -0
  109. package/dist/tools/users.js.map +1 -0
  110. package/dist/tools/xp.d.ts +38 -0
  111. package/dist/tools/xp.js +670 -0
  112. package/dist/tools/xp.js.map +1 -0
  113. package/dist/types.d.ts +178 -0
  114. package/dist/types.js +12 -0
  115. package/dist/types.js.map +1 -0
  116. package/docs/recommended-skillsets.md +622 -0
  117. package/docs/skills-and-abilities-review.md +672 -0
  118. package/docs/v0.3-roadmap.md +191 -0
  119. package/package.json +35 -0
  120. package/sql/agent_pending_installs.sql +28 -0
  121. package/sql/award_class_xp.sql +81 -0
  122. package/supabase/.temp/cli-latest +1 -0
  123. package/supabase/.temp/gotrue-version +1 -0
  124. package/supabase/.temp/pooler-url +1 -0
  125. package/supabase/.temp/postgres-version +1 -0
  126. package/supabase/.temp/project-ref +1 -0
  127. package/supabase/.temp/rest-version +1 -0
  128. package/supabase/.temp/storage-migration +1 -0
  129. package/supabase/.temp/storage-version +1 -0
  130. package/supabase/migrations/20260314000000_anon_rls_policies.sql +311 -0
  131. package/supabase/migrations/20260314000001_ownership_rpcs.sql +382 -0
  132. package/supabase/migrations/20260314000002_evidence_and_growth_plan.sql +97 -0
  133. package/supabase/migrations/20260317000000_seed_quests.sql +62 -0
  134. package/supabase/migrations/20260317000001_star_cooldown_and_fixes.sql +16 -0
  135. package/supabase/migrations/20260318000000_restore_rank_names.sql +25 -0
  136. package/supabase/migrations/20260320000000_chinese_rank_names.sql +24 -0
  137. package/vitest.config.ts +11 -0
@@ -0,0 +1,791 @@
1
+ // ============================================================
2
+ // tools/growth-plan.ts — Growth Plan (Tool 70)
3
+ // ============================================================
4
+ // Generates a prioritised action list for an agent to reach
5
+ // a target rank, skill proficiency, or next level.
6
+ //
7
+ // Reads the agent's current state against requirements and
8
+ // produces concrete steps ordered by XP efficiency.
9
+ // Results are cached in growth_plan_cache.
10
+ // ============================================================
11
+ import { z } from "zod";
12
+ import { supabase } from "../services/supabase.js";
13
+ import { ok, fail, handleSupabaseError } from "../services/errors.js";
14
+ import { toMcpResponse, logRegistered } from "../services/register.js";
15
+ import { uuidSchema } from "../schemas/common.js";
16
+ import * as crypto from "crypto";
17
+ // Handler registry — populated by registerGrowthPlanTools(), accessed by dispatchers
18
+ export const growthPlanHandlers = {};
19
+ // ---- Helpers ----
20
+ function hashTarget(target) {
21
+ const sorted = JSON.stringify(target, Object.keys(target).sort());
22
+ return crypto.createHash("sha256").update(sorted).digest("hex").slice(0, 16);
23
+ }
24
+ export function registerGrowthPlanTools(server) {
25
+ console.error("\n📋 Section 14: Growth Plan");
26
+ // ================================================================
27
+ // Tool 70: levelup_get_growth_plan
28
+ // ================================================================
29
+ server.registerTool("levelup_get_growth_plan", {
30
+ title: "获取成长计划",
31
+ description: `生成一个优先排序的行动列表,用于达到目标段位、技能等级或下一等级。
32
+
33
+ 当用户询问如何升级、应该做什么、或如何达到某个段位时调用。
34
+ 返回有序步骤:安装工具、完成任务、获取技能——每步附带
35
+ 经验值估算和冷却时间说明。按顺序执行步骤。
36
+
37
+ 参数:
38
+ - agent_id (uuid): 目标智能体。
39
+ - target (object): 以下之一:
40
+ - { type: "next_level" } — 达到下一等级
41
+ - { type: "next_rank" } — 达到下一段位
42
+ - { type: "rank", rank: "D" } — 达到指定段位
43
+ - { type: "skill_proficiency", skill_id: uuid, target_proficiency: 5 } — 达到技能等级
44
+ - horizon_days (integer, 可选): 规划周期(默认7天)。
45
+ - include_xp_estimates (boolean, 可选): 默认 true。
46
+
47
+ 返回:
48
+ 当前状态、经验值差距、有序步骤、受阻步骤、警告。`,
49
+ inputSchema: {
50
+ agent_id: uuidSchema.describe("目标智能体"),
51
+ target: z.object({
52
+ type: z.enum(["next_level", "next_rank", "rank", "skill_proficiency"]).describe("目标类型"),
53
+ rank: z.string().optional().describe("目标段位字母(如 'D'、'C')"),
54
+ skill_id: uuidSchema.optional().describe("用于 skill_proficiency 目标"),
55
+ target_proficiency: z.number().int().min(1).max(10).optional().describe("目标熟练度等级"),
56
+ }).describe("目标方向"),
57
+ horizon_days: z.number().int().min(1).max(30).default(7).describe("规划周期(天)"),
58
+ include_xp_estimates: z.boolean().default(true).describe("每步包含经验值估算"),
59
+ },
60
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
61
+ }, (growthPlanHandlers.gp = async (params) => {
62
+ // --- Check cache first ---
63
+ const targetHash = hashTarget(params.target);
64
+ const { data: cached } = await supabase
65
+ .from("growth_plan_cache")
66
+ .select("plan, generated_at, expires_at")
67
+ .eq("agent_id", params.agent_id)
68
+ .eq("target_hash", targetHash)
69
+ .eq("invalidated", false)
70
+ .gt("expires_at", new Date().toISOString())
71
+ .order("generated_at", { ascending: false })
72
+ .limit(1)
73
+ .maybeSingle();
74
+ if (cached) {
75
+ return toMcpResponse(ok({
76
+ ...cached.plan,
77
+ from_cache: true,
78
+ cached_at: cached.generated_at,
79
+ expires_at: cached.expires_at,
80
+ }));
81
+ }
82
+ // --- Fetch agent state ---
83
+ const { data: agent, error: agentError } = await supabase
84
+ .from("agents").select("id, name, level, xp, integrity_score, owner_user_id")
85
+ .eq("id", params.agent_id).single();
86
+ if (agentError)
87
+ return toMcpResponse(handleSupabaseError(agentError, "get_growth_plan"));
88
+ // Get agent's current skills
89
+ const { data: agentSkills } = await supabase
90
+ .from("agent_skills")
91
+ .select("skill_id, proficiency_level, usage_count")
92
+ .eq("agent_id", params.agent_id);
93
+ const skillMap = new Map((agentSkills || []).map((s) => [s.skill_id, s]));
94
+ // Get installed tools
95
+ const { data: installations } = await supabase
96
+ .from("agent_tool_installations")
97
+ .select("tool_name, tool_type")
98
+ .eq("agent_id", params.agent_id);
99
+ const installedTools = new Set((installations || []).map((i) => i.tool_name));
100
+ // Get current rank
101
+ const { data: currentRank } = await supabase
102
+ .from("rank_definitions")
103
+ .select("rank_letter, rank_name, min_level, max_level")
104
+ .eq("entity_type", "agent")
105
+ .lte("min_level", agent.level)
106
+ .gte("max_level", agent.level)
107
+ .maybeSingle();
108
+ // --- Determine target ---
109
+ let targetLevel;
110
+ let targetDescription;
111
+ let targetXp;
112
+ if (params.target.type === "next_level") {
113
+ targetLevel = agent.level + 1;
114
+ targetDescription = `等级 ${targetLevel}`;
115
+ }
116
+ else if (params.target.type === "next_rank" || params.target.type === "rank") {
117
+ // Get rank definitions
118
+ const { data: ranks } = await supabase
119
+ .from("rank_definitions")
120
+ .select("rank_letter, rank_name, min_level, max_level")
121
+ .eq("entity_type", "agent")
122
+ .order("min_level", { ascending: true });
123
+ if (params.target.type === "rank" && params.target.rank) {
124
+ const targetRank = (ranks || []).find((r) => r.rank_letter === params.target.rank);
125
+ if (!targetRank)
126
+ return toMcpResponse(fail(`未找到段位 "${params.target.rank}"`));
127
+ targetLevel = targetRank.min_level;
128
+ targetDescription = `段位 ${targetRank.rank_letter} — ${targetRank.rank_name}`;
129
+ }
130
+ else {
131
+ // next_rank: find rank after current
132
+ const currentIdx = (ranks || []).findIndex((r) => r.rank_letter === currentRank?.rank_letter);
133
+ const nextRank = (ranks || [])[currentIdx + 1];
134
+ if (!nextRank)
135
+ return toMcpResponse(fail("已达最高段位"));
136
+ targetLevel = nextRank.min_level;
137
+ targetDescription = `段位 ${nextRank.rank_letter} — ${nextRank.rank_name}`;
138
+ }
139
+ }
140
+ else {
141
+ // skill_proficiency — different flow
142
+ targetLevel = agent.level; // no level target for skill goals
143
+ targetDescription = `技能熟练度 ${params.target.target_proficiency || 5}`;
144
+ }
145
+ // Get XP needed from level curve
146
+ const { data: levelCurve } = await supabase
147
+ .from("level_curves")
148
+ .select("level, cumulative_xp")
149
+ .eq("entity_type", "agent")
150
+ .lte("level", targetLevel)
151
+ .order("level", { ascending: true });
152
+ const targetCurveEntry = (levelCurve || []).find((c) => c.level === targetLevel);
153
+ targetXp = targetCurveEntry?.cumulative_xp || 0;
154
+ const xpGap = Math.max(0, targetXp - agent.xp);
155
+ // --- Compute skill discount ---
156
+ let skillDiscountPct = 0;
157
+ const { data: levelReq } = await supabase
158
+ .from("level_requirements").select("id")
159
+ .eq("level", agent.level + 1).maybeSingle();
160
+ if (levelReq) {
161
+ const { data: skillDiscounts } = await supabase
162
+ .from("level_req_skills")
163
+ .select("skill_id, min_proficiency, xp_discount_pct")
164
+ .eq("level_requirement_id", levelReq.id);
165
+ for (const sd of skillDiscounts || []) {
166
+ const agentSkill = skillMap.get(sd.skill_id);
167
+ if (agentSkill && agentSkill.proficiency_level >= sd.min_proficiency) {
168
+ skillDiscountPct += sd.xp_discount_pct;
169
+ }
170
+ }
171
+ }
172
+ // --- Build steps ---
173
+ const steps = [];
174
+ const blockedSteps = [];
175
+ const alreadyCompleted = [];
176
+ let stepNumber = 0;
177
+ // Step type 1: Tool installations that grant skill proficiency
178
+ const { data: toolMappings } = await supabase
179
+ .from("skill_tool_mappings")
180
+ .select("skill_id, tool_name, setup_credit");
181
+ // Get skill names for display
182
+ const allSkillIds = [...new Set([
183
+ ...(agentSkills || []).map((s) => s.skill_id),
184
+ ...(toolMappings || []).map((m) => m.skill_id),
185
+ ])];
186
+ const { data: skillDetails } = allSkillIds.length > 0
187
+ ? await supabase.from("skills").select("id, name, category_id").in("id", allSkillIds)
188
+ : { data: [] };
189
+ const skillNameMap = new Map((skillDetails || []).map((s) => [s.id, s.name]));
190
+ // Deduplicate: group skills per MCP tool
191
+ const mcpSkillGroups = new Map();
192
+ for (const mapping of toolMappings || []) {
193
+ const skillName = skillNameMap.get(mapping.skill_id) || mapping.tool_name;
194
+ const existing = mcpSkillGroups.get(mapping.tool_name) || { skills: [], totalCredit: 0 };
195
+ existing.skills.push(skillName);
196
+ existing.totalCredit += mapping.setup_credit || 1;
197
+ mcpSkillGroups.set(mapping.tool_name, existing);
198
+ }
199
+ const installSteps = [];
200
+ for (const [toolName, group] of mcpSkillGroups) {
201
+ if (installedTools.has(toolName)) {
202
+ alreadyCompleted.push({
203
+ description: `已安装工具: ${toolName} (${group.skills.join(", ")})`,
204
+ xp_earned: 20,
205
+ });
206
+ continue;
207
+ }
208
+ // Check if any of this tool's skills are at proficiency 0
209
+ const hasFoundationSkill = group.skills.some((name) => {
210
+ const skill = (skillDetails || []).find((s) => s.name === name);
211
+ return skill && !skillMap.has(skill.id);
212
+ });
213
+ const priority = hasFoundationSkill ? "high" : "medium";
214
+ installSteps.push({
215
+ step_number: 0, // renumbered later
216
+ priority,
217
+ action_type: "install_tool",
218
+ title: `安装 ${toolName}`,
219
+ description: `解锁 ${group.skills.join(" + ")}(${group.skills.length} 项技能)。奖励 20 经验值。`,
220
+ skills_affected: group.skills,
221
+ xp_estimate: 20,
222
+ cooldown_note: "每天最多 3 次工具安装可获得经验值。",
223
+ evidence_required: "api_response 或截图",
224
+ mcp_name: toolName,
225
+ });
226
+ }
227
+ // Cap install suggestions at 5 (spread across days)
228
+ installSteps.sort((a, b) => (a.priority === "high" ? 0 : 1) - (b.priority === "high" ? 0 : 1));
229
+ const cappedInstalls = installSteps.slice(0, 5);
230
+ // Step type 2: Task completions for XP
231
+ const { data: taskTypes } = await supabase
232
+ .from("task_types")
233
+ .select("id, name, base_xp, xp_tier, category")
234
+ .eq("status", "active")
235
+ .order("base_xp", { ascending: false });
236
+ // Get cooldown config for notes
237
+ const { data: cooldownConfig } = await supabase
238
+ .from("xp_config").select("config_value")
239
+ .eq("config_key", "task_cooldown_base_minutes").maybeSingle();
240
+ const cooldowns = (cooldownConfig?.config_value || {});
241
+ // Check what task types the agent has already completed
242
+ const { data: completedTasks } = await supabase
243
+ .from("tasks")
244
+ .select("task_type_id")
245
+ .eq("agent_id", params.agent_id)
246
+ .eq("status", "completed");
247
+ const completedTypeIds = new Set((completedTasks || []).map((t) => t.task_type_id));
248
+ const completedTypeCounts = new Map();
249
+ for (const t of completedTasks || []) {
250
+ completedTypeCounts.set(t.task_type_id, (completedTypeCounts.get(t.task_type_id) || 0) + 1);
251
+ }
252
+ // Level-gated tier access: new agents should start small and build up
253
+ const TIER_LEVEL_GATES = {
254
+ micro: 1, // Available from level 1
255
+ light: 1, // Available from level 1
256
+ standard: 1, // Available from level 1
257
+ complex: 5, // Unlocks at level 5 (Rank E, 5 stars)
258
+ major: 10, // Unlocks at level 10 (Rank D)
259
+ };
260
+ // Sort task types by XP efficiency and diversity
261
+ for (const tt of taskTypes || []) {
262
+ const cooldownMinutes = cooldowns[tt.xp_tier] || 0;
263
+ const xpEstimate = tt.base_xp;
264
+ const alreadyDone = completedTypeCounts.get(tt.id) || 0;
265
+ // Gate large tasks behind level requirements
266
+ const requiredLevel = TIER_LEVEL_GATES[tt.xp_tier] || 1;
267
+ if (agent.level < requiredLevel) {
268
+ blockedSteps.push({
269
+ title: `${tt.name} (${tt.xp_tier} tier)`,
270
+ blocked_reason: `需要等级 ${requiredLevel}+(当前等级 ${agent.level})`,
271
+ unblock_action: `先完成${tt.xp_tier === "major" ? "complex" : "standard"}级任务以达到等级 ${requiredLevel}。`,
272
+ });
273
+ continue;
274
+ }
275
+ // Prioritize by agent level:
276
+ // Low-level agents: tool installs and micro/light/standard tasks first
277
+ // Higher-level agents: complex/major tasks get higher priority
278
+ let priority;
279
+ if (alreadyDone === 0) {
280
+ // Never-done types get diversity bonus, but tier-appropriate
281
+ if (tt.xp_tier === "micro" || tt.xp_tier === "light") {
282
+ priority = agent.level <= 3 ? "high" : "low";
283
+ }
284
+ else if (tt.xp_tier === "standard") {
285
+ priority = "high";
286
+ }
287
+ else {
288
+ priority = agent.level >= requiredLevel ? "medium" : "low";
289
+ }
290
+ }
291
+ else {
292
+ priority = xpEstimate >= 25 ? "medium" : "low";
293
+ }
294
+ // Calculate repetitions needed based on XP gap
295
+ const effectiveXpPerTask = Math.round(xpEstimate * 0.8); // assume ~80% quality multiplier
296
+ const repsNeeded = xpGap > 0 ? Math.min(10, Math.ceil(xpGap / Math.max(1, effectiveXpPerTask * 3))) : 1;
297
+ let cooldownNote = null;
298
+ if (cooldownMinutes > 0) {
299
+ cooldownNote = `${tt.xp_tier} 级别:任务间冷却 ${cooldownMinutes} 分钟。`;
300
+ }
301
+ stepNumber++;
302
+ steps.push({
303
+ step_number: stepNumber,
304
+ priority,
305
+ action_type: "complete_task",
306
+ title: alreadyDone === 0
307
+ ? `完成一个 ${tt.name} 任务(新类型——多样性加成)`
308
+ : `完成 ${repsNeeded} 个 ${tt.name} 任务`,
309
+ description: `${tt.category || "综合"}类任务。基础经验值:${xpEstimate}。${alreadyDone === 0 ? "首次完成此类型——有助于多样性加成。" : `已完成 ${alreadyDone} 次。`}`,
310
+ skills_affected: [],
311
+ xp_estimate: effectiveXpPerTask * repsNeeded,
312
+ cooldown_note: cooldownNote,
313
+ evidence_required: "deliverable_url 或 platform_reference",
314
+ task_type: tt.name,
315
+ task_type_id: tt.id,
316
+ repetitions_needed: repsNeeded,
317
+ repetitions_completed: Math.min(alreadyDone, repsNeeded),
318
+ });
319
+ }
320
+ // --- Interleave installs and tasks (max 3 installs then a task) ---
321
+ // Sort task steps by priority then XP
322
+ const priorityOrder = { high: 0, medium: 1, low: 2 };
323
+ steps.sort((a, b) => {
324
+ const pDiff = priorityOrder[a.priority] - priorityOrder[b.priority];
325
+ if (pDiff !== 0)
326
+ return pDiff;
327
+ return b.xp_estimate - a.xp_estimate;
328
+ });
329
+ // Interleave: for new agents, start with installs but mix in tasks
330
+ const interleaved = [];
331
+ let installIdx = 0;
332
+ let taskIdx = 0;
333
+ const taskSteps = steps; // all steps are tasks at this point
334
+ let installStreak = 0;
335
+ if (agent.level <= 3 && cappedInstalls.length > 0) {
336
+ // New agents: max 3 installs, then a task, repeat
337
+ while (installIdx < cappedInstalls.length || taskIdx < taskSteps.length) {
338
+ if (installIdx < cappedInstalls.length && installStreak < 3) {
339
+ interleaved.push(cappedInstalls[installIdx++]);
340
+ installStreak++;
341
+ }
342
+ else if (taskIdx < taskSteps.length) {
343
+ interleaved.push(taskSteps[taskIdx++]);
344
+ installStreak = 0;
345
+ }
346
+ else {
347
+ break;
348
+ }
349
+ }
350
+ }
351
+ else {
352
+ // Experienced agents: tasks first, installs mixed in
353
+ interleaved.push(...taskSteps);
354
+ interleaved.push(...cappedInstalls);
355
+ }
356
+ // Re-number and differentiate priorities
357
+ interleaved.forEach((s, i) => {
358
+ s.step_number = i + 1;
359
+ if (i < 3)
360
+ s.priority = "high";
361
+ else if (i < 6)
362
+ s.priority = "medium";
363
+ else
364
+ s.priority = "low";
365
+ });
366
+ // --- Timegate warnings ---
367
+ const warnings = [];
368
+ const { data: starCooldown } = await supabase
369
+ .from("xp_config").select("config_value")
370
+ .eq("config_key", "agent_star_cooldown_hours").maybeSingle();
371
+ if (starCooldown?.config_value && currentRank) {
372
+ const cooldownHours = starCooldown.config_value[currentRank.rank_letter];
373
+ if (cooldownHours && cooldownHours > 0) {
374
+ warnings.push(`时间门控:段位 ${currentRank.rank_letter} 每颗星之间有 ${cooldownHours} 小时冷却。`);
375
+ }
376
+ }
377
+ if (xpGap <= 0) {
378
+ warnings.push("你已拥有足够的经验值达成目标。调用 levelup_check_level_up 来执行升级。");
379
+ }
380
+ // --- Recommended skillsets from ability categories ---
381
+ // Find which categories the agent is weakest in and recommend MCPs + skills
382
+ const { data: allCategories } = await supabase
383
+ .from("skill_categories").select("id, name, description");
384
+ const recommendations = [];
385
+ if (allCategories && agentSkills) {
386
+ // Group agent skills by category
387
+ const catProficiency = new Map();
388
+ for (const as of agentSkills) {
389
+ const skill = (skillDetails || []).find((s) => s.id === as.skill_id);
390
+ if (skill) {
391
+ const profs = catProficiency.get(skill.category_id) || [];
392
+ profs.push(as.proficiency_level);
393
+ catProficiency.set(skill.category_id, profs);
394
+ }
395
+ }
396
+ // Recommended MCPs per category (top picks from verified sources)
397
+ const categoryMcps = {
398
+ "Software Engineering": ["Filesystem MCP", "Git MCP", "GitHub MCP"],
399
+ "Web Development": ["Playwright MCP", "Fetch MCP", "Firecrawl MCP"],
400
+ "Data Analysis": ["Memory MCP", "Brave Search MCP", "Chroma MCP"],
401
+ "DevOps & Infrastructure": ["GitHub MCP", "Terraform MCP", "AWS MCP", "Docker MCP"],
402
+ "Security & Testing": ["Snyk Agent Scan", "Playwright MCP"],
403
+ "Design & Visual": ["Playwright MCP"],
404
+ "Research & Knowledge": ["Brave Search MCP", "Fetch MCP", "arXiv MCP", "Memory MCP"],
405
+ "Writing & Content": ["Notion MCP", "ElevenLabs MCP"],
406
+ "Communication": ["Notion MCP", "Atlassian MCP"],
407
+ "Project Management": ["GitHub MCP", "Notion MCP", "Atlassian MCP"],
408
+ "Database & Backend": ["MongoDB MCP", "Chroma MCP"],
409
+ "Cloud & Platform": ["AWS MCP", "Cloudflare MCP", "Terraform MCP"],
410
+ "AI & Machine Learning": ["Sequential Thinking MCP", "Memory MCP", "Chroma MCP"],
411
+ };
412
+ const categorySkills = {
413
+ "Software Engineering": ["refactor", "conventional-commit", "architecture-blueprint-generator"],
414
+ "Web Development": ["frontend-design", "webapp-testing", "playwright-generate-test"],
415
+ "Data Analysis": ["xlsx", "sql-optimization", "sql-code-review"],
416
+ "DevOps & Infrastructure": ["devops-rollout-plan", "multi-stage-dockerfile", "cloud-design-patterns"],
417
+ "Security & Testing": ["agent-governance", "ai-prompt-engineering-safety-review"],
418
+ "Design & Visual": ["canvas-design", "brand-guidelines", "excalidraw-diagram-generator"],
419
+ "Research & Knowledge": ["remember", "create-technical-spike", "context-map"],
420
+ "Writing & Content": ["documentation-writer", "create-readme", "create-specification"],
421
+ "Project Management": ["breakdown-epic-pm", "prd", "create-architectural-decision-record"],
422
+ "AI & Machine Learning": ["claude-api", "mcp-builder", "prompt-builder", "agentic-eval"],
423
+ };
424
+ // Find weakest categories (avg proficiency < 3 or no skills)
425
+ for (const cat of allCategories) {
426
+ const profs = catProficiency.get(cat.id) || [];
427
+ const avgProf = profs.length > 0 ? profs.reduce((a, b) => a + b, 0) / profs.length : 0;
428
+ if (avgProf < 3 && recommendations.length < 5) {
429
+ recommendations.push({
430
+ ability: cat.name,
431
+ current_proficiency: Math.round(avgProf * 10) / 10,
432
+ suggested_mcps: categoryMcps[cat.name] || [],
433
+ suggested_skills: categorySkills[cat.name] || [],
434
+ tip: avgProf === 0
435
+ ? `先安装 ${cat.name} 推荐的 MCP 来获取工具安装经验值。`
436
+ : `完成更多 ${cat.name} 任务来提升熟练度。当前平均:${avgProf.toFixed(1)}/10。`,
437
+ });
438
+ }
439
+ }
440
+ }
441
+ // --- Build response ---
442
+ const effectiveXpGap = Math.round(xpGap * (1 - skillDiscountPct / 100));
443
+ const plan = {
444
+ agent_id: agent.id,
445
+ agent_name: agent.name,
446
+ current_level: agent.level,
447
+ current_rank: currentRank ? `${currentRank.rank_letter} — ${currentRank.rank_name}` : "未定段",
448
+ current_xp: agent.xp,
449
+ target_description: targetDescription,
450
+ xp_to_target: xpGap,
451
+ skill_discount_pct: skillDiscountPct,
452
+ effective_xp_to_target: effectiveXpGap,
453
+ steps: interleaved.slice(0, 20), // Cap at 20 steps
454
+ recommended_skillsets: recommendations.length > 0 ? recommendations : undefined,
455
+ blocked_steps: blockedSteps,
456
+ already_completed: alreadyCompleted,
457
+ warnings,
458
+ generated_at: new Date().toISOString(),
459
+ expires_at: new Date(Date.now() + params.horizon_days * 86400_000).toISOString(),
460
+ };
461
+ // --- Cache the plan ---
462
+ await supabase.from("growth_plan_cache").insert({
463
+ agent_id: params.agent_id,
464
+ target_hash: targetHash,
465
+ plan,
466
+ expires_at: plan.expires_at,
467
+ });
468
+ return toMcpResponse(ok({ ...plan, from_cache: false }));
469
+ }));
470
+ logRegistered("levelup_get_growth_plan");
471
+ // ================================================================
472
+ // Tool 71: levelup_browse_skillsets
473
+ // ================================================================
474
+ // Recommended MCPs per ability (only official/org-owned repos)
475
+ const SKILLSET_DATA = {
476
+ "Software Engineering": {
477
+ description: "代码编写、调试、重构、架构设计",
478
+ mcps: [
479
+ { name: "Filesystem MCP", purpose: "读写和编辑项目文件", repo: "modelcontextprotocol/servers/src/filesystem", trust: "Reference", best_practice: "仅限项目目录——绝不允许访问根目录或用户主目录" },
480
+ { name: "Git MCP", purpose: "分支、提交、差异比较、合并", repo: "modelcontextprotocol/servers/src/git", trust: "Reference", best_practice: "提交前务必检查差异;避免强制推送" },
481
+ { name: "GitHub MCP", purpose: "PR、Issue、代码审查、CI", repo: "github/github-mcp-server", trust: "Official (28K stars)", best_practice: "使用最小权限的细粒度 PAT;绝不提交 token" },
482
+ { name: "Sequential Thinking", purpose: "架构设计的多步推理", repo: "modelcontextprotocol/servers/src/sequentialthinking", trust: "Reference", best_practice: "用于复杂的多步问题,而非简单查询" },
483
+ ],
484
+ skills: [
485
+ { name: "refactor", what_it_teaches: "安全重构模式、方法提取、降低复杂度", source: "GitHub", best_practice: "逐步应用;每步后运行测试" },
486
+ { name: "conventional-commit", what_it_teaches: "结构化提交信息(feat/fix/chore)", source: "GitHub", best_practice: "遵循项目现有的提交约定" },
487
+ { name: "architecture-blueprint-generator", what_it_teaches: "从代码库生成架构文档", source: "GitHub", best_practice: "架构变更时同步更新蓝图" },
488
+ { name: "mcp-builder", what_it_teaches: "从零开始构建 MCP 服务器", source: "Anthropic", best_practice: "遵循 MCP 规范;使用 MCP inspector 测试" },
489
+ ],
490
+ progression: "Filesystem + Git → GitHub → Sequential Thinking",
491
+ notes: null,
492
+ },
493
+ "Web Development": {
494
+ description: "前端/后端、HTML/CSS/JS、框架、API",
495
+ mcps: [
496
+ { name: "Filesystem MCP", purpose: "项目文件管理", repo: "modelcontextprotocol/servers/src/filesystem", trust: "Reference", best_practice: "仅限项目目录" },
497
+ { name: "Playwright MCP", purpose: "浏览器自动化、端到端测试", repo: "microsoft/playwright-mcp", trust: "Official (29K stars)", best_practice: "优先使用无障碍快照而非截图以提高速度" },
498
+ { name: "Fetch MCP", purpose: "HTTP 请求、API 测试", repo: "modelcontextprotocol/servers/src/fetch", trust: "Reference", best_practice: "设置合理的超时时间;不要请求不可信的 URL" },
499
+ { name: "Firecrawl MCP", purpose: "深度网站爬取和抓取", repo: "firecrawl/firecrawl-mcp-server", trust: "Official (5.8K stars)", best_practice: "遵守 robots.txt;仅用于自有或已授权的网站" },
500
+ ],
501
+ skills: [
502
+ { name: "frontend-design", what_it_teaches: "前端 UI 设计模式", source: "Anthropic", best_practice: "匹配设计系统;测试响应式断点" },
503
+ { name: "webapp-testing", what_it_teaches: "Web 应用测试策略", source: "Anthropic", best_practice: "测试用户流程,而非实现细节" },
504
+ { name: "playwright-generate-test", what_it_teaches: "生成 Playwright 端到端测试", source: "GitHub", best_practice: "使用 data-testid 选择器;避免脆弱的 CSS 选择器" },
505
+ ],
506
+ progression: "Filesystem + Fetch → Playwright → Firecrawl",
507
+ notes: null,
508
+ },
509
+ "Data Analysis": {
510
+ description: "SQL、数据处理、统计分析、可视化",
511
+ mcps: [
512
+ { name: "Filesystem MCP", purpose: "读写 CSV、JSON 等数据文件", repo: "modelcontextprotocol/servers/src/filesystem", trust: "Reference", best_practice: "写入前验证数据;转换前做好备份" },
513
+ { name: "Memory MCP", purpose: "跨会话跟踪分析上下文", repo: "modelcontextprotocol/servers/src/memory", trust: "Reference", best_practice: "用于持久化上下文,而非主数据存储" },
514
+ { name: "Chroma MCP", purpose: "向量数据库,用于嵌入", repo: "chroma-core/chroma-mcp", trust: "Official (515 stars)", best_practice: "用于语义搜索;保持集合范围明确" },
515
+ ],
516
+ skills: [
517
+ { name: "xlsx", what_it_teaches: "Excel 电子表格创建、公式、图表", source: "Anthropic", best_practice: "验证公式;使用命名范围" },
518
+ { name: "sql-optimization", what_it_teaches: "SQL 查询性能优化", source: "GitHub", best_practice: "优化前先用 EXPLAIN 分析查询" },
519
+ ],
520
+ progression: "Filesystem → Memory → Chroma",
521
+ notes: null,
522
+ },
523
+ "DevOps & Infrastructure": {
524
+ description: "CI/CD、部署、监控、基础设施即代码",
525
+ mcps: [
526
+ { name: "GitHub MCP", purpose: "通过 GitHub Actions 实现 CI/CD", repo: "github/github-mcp-server", trust: "Official (28K stars)", best_practice: "合并前审查工作流变更" },
527
+ { name: "Terraform MCP", purpose: "基础设施即代码", repo: "hashicorp/terraform-mcp-server", trust: "Official (1.3K stars)", best_practice: "apply 前务必先运行 plan" },
528
+ { name: "AWS MCP", purpose: "Lambda、S3、云服务", repo: "awslabs/mcp", trust: "Official (8.5K stars)", best_practice: "使用最小权限 IAM 角色" },
529
+ { name: "Cloudflare MCP", purpose: "Workers、边缘计算、CDN、DNS", repo: "cloudflare/mcp-server-cloudflare", trust: "Official (3.5K stars)", best_practice: "部署前先在本地测试 Workers" },
530
+ { name: "Grafana MCP", purpose: "可观测性仪表板", repo: "grafana/mcp-grafana", trust: "Official (2.5K stars)", best_practice: "建议智能体使用只读权限" },
531
+ { name: "Docker MCP", purpose: "容器管理", repo: "docker/mcp-gateway", trust: "Official (1.3K stars)", best_practice: "不要将 Docker socket 暴露给不可信的智能体" },
532
+ ],
533
+ skills: [
534
+ { name: "devops-rollout-plan", what_it_teaches: "规划安全的生产环境发布", source: "GitHub", best_practice: "包含回滚步骤;使用金丝雀部署" },
535
+ { name: "multi-stage-dockerfile", what_it_teaches: "优化 Docker 镜像", source: "GitHub", best_practice: "最小化镜像体积;排除开发依赖" },
536
+ { name: "cloud-design-patterns", what_it_teaches: "云架构模式(重试、熔断器)", source: "GitHub", best_practice: "根据需求选择合适的模式" },
537
+ ],
538
+ progression: "GitHub → AWS/Cloudflare → Terraform → Grafana → Docker",
539
+ notes: null,
540
+ },
541
+ "Security & Testing": {
542
+ description: "漏洞扫描、代码审查、质量保证",
543
+ mcps: [
544
+ { name: "Snyk Agent Scan", purpose: "AI 智能体和 MCP 的安全扫描器", repo: "snyk/agent-scan", trust: "Official (1.9K stars)", best_practice: "使用前扫描所有新安装的 MCP" },
545
+ { name: "Playwright MCP", purpose: "端到端安全测试", repo: "microsoft/playwright-mcp", trust: "Official (29K stars)", best_practice: "测试认证流程、输入验证、XSS 向量" },
546
+ { name: "GitHub MCP", purpose: "PR 安全审查", repo: "github/github-mcp-server", trust: "Official (28K stars)", best_practice: "启用分支保护;要求代码审查" },
547
+ ],
548
+ skills: [
549
+ { name: "agent-governance", what_it_teaches: "AI 智能体的治理策略", source: "GitHub", best_practice: "授予自主权之前先定义边界" },
550
+ { name: "ai-prompt-engineering-safety-review", what_it_teaches: "审查提示词的注入风险", source: "GitHub", best_practice: "部署前检查所有面向用户的提示词" },
551
+ ],
552
+ progression: "Filesystem → Snyk → GitHub PR review → Playwright E2E",
553
+ notes: null,
554
+ },
555
+ "Design & Visual": {
556
+ description: "UI/UX、图表、视觉资源",
557
+ mcps: [
558
+ { name: "Playwright MCP", purpose: "视觉测试、截图对比", repo: "microsoft/playwright-mcp", trust: "Official (29K stars)", best_practice: "用于 UI 测试和视觉回归测试" },
559
+ ],
560
+ skills: [
561
+ { name: "canvas-design", what_it_teaches: "使用 canvas 进行视觉设计", source: "Anthropic", best_practice: "遵循品牌规范;保持一致性" },
562
+ { name: "brand-guidelines", what_it_teaches: "创建并遵循品牌标识", source: "Anthropic", best_practice: "先定义颜色、字体、间距" },
563
+ { name: "theme-factory", what_it_teaches: "生成一致的 UI 主题", source: "Anthropic", best_practice: "支持明暗模式;使用 CSS 变量" },
564
+ ],
565
+ progression: "Playwright → canvas-design → brand-guidelines → theme-factory",
566
+ notes: "Canva、Excalidraw、Blender 和 Mermaid 尚无官方 MCP 服务器。",
567
+ },
568
+ "Research & Knowledge": {
569
+ description: "文献综述、事实核查、来源评估、信息综合",
570
+ mcps: [
571
+ { name: "Brave Search MCP", purpose: "隐私优先的网络搜索", repo: "brave/brave-search-mcp-server", trust: "Official (775 stars)", best_practice: "始终标注来源;交叉验证信息" },
572
+ { name: "Fetch MCP", purpose: "读取网页、提取内容", repo: "modelcontextprotocol/servers/src/fetch", trust: "Reference", best_practice: "将 HTML 转为 markdown 以获得更干净的内容" },
573
+ { name: "Memory MCP", purpose: "持久化知识图谱", repo: "modelcontextprotocol/servers/src/memory", trust: "Reference", best_practice: "结构化实体和关系" },
574
+ ],
575
+ skills: [
576
+ { name: "remember", what_it_teaches: "智能体的持久记忆模式", source: "GitHub", best_practice: "存储结构化发现,而非原始数据" },
577
+ { name: "create-technical-spike", what_it_teaches: "限时技术调研", source: "GitHub", best_practice: "预先定义成功标准" },
578
+ { name: "context-map", what_it_teaches: "在复杂领域中映射上下文关系", source: "GitHub", best_practice: "深入研究前先识别有界上下文" },
579
+ ],
580
+ progression: "Brave Search + Fetch → Memory",
581
+ notes: null,
582
+ },
583
+ "Writing & Content": {
584
+ description: "技术写作、文案、文档、编辑",
585
+ mcps: [
586
+ { name: "Filesystem MCP", purpose: "读写文档", repo: "modelcontextprotocol/servers/src/filesystem", trust: "Reference", best_practice: "使用统一的文件命名;为重要文档做版本管理" },
587
+ { name: "Notion MCP", purpose: "知识库、文档、Wiki", repo: "makenotion/notion-mcp-server", trust: "Official (4K stars)", best_practice: "使用限定特定页面范围的 API token" },
588
+ { name: "ElevenLabs MCP", purpose: "内容文本转语音", repo: "elevenlabs/elevenlabs-mcp", trust: "Official (1.3K stars)", best_practice: "选择合适的语音;发布前审听音频" },
589
+ ],
590
+ skills: [
591
+ { name: "doc-coauthoring", what_it_teaches: "协作文档编写", source: "Anthropic", best_practice: "保持一致的语气;跟踪修改" },
592
+ { name: "docx", what_it_teaches: "带格式的 Word 文档创建", source: "Anthropic", best_practice: "统一使用样式" },
593
+ { name: "documentation-writer", what_it_teaches: "技术文档编写最佳实践", source: "GitHub", best_practice: "根据读者水平写作;包含代码示例" },
594
+ { name: "create-readme", what_it_teaches: "生成全面的 README 文档", source: "GitHub", best_practice: "包含安装、用法和贡献指南" },
595
+ ],
596
+ progression: "Filesystem + Notion → ElevenLabs",
597
+ notes: null,
598
+ },
599
+ "Communication & Collaboration": {
600
+ description: "团队协调、状态更新、异步沟通",
601
+ mcps: [
602
+ { name: "Notion MCP", purpose: "共享文档", repo: "makenotion/notion-mcp-server", trust: "Official (4K stars)", best_practice: "仅将集成范围限定在团队工作空间" },
603
+ { name: "Atlassian MCP", purpose: "Jira 问题、Confluence 文档", repo: "atlassian/atlassian-mcp-server", trust: "Official (436 stars)", best_practice: "以只读为主;状态变更需经审批" },
604
+ ],
605
+ skills: [
606
+ { name: "internal-comms", what_it_teaches: "内部沟通写作", source: "Anthropic", best_practice: "语气匹配受众;简明扼要" },
607
+ { name: "meeting-minutes", what_it_teaches: "记录和整理会议纪要", source: "GitHub", best_practice: "包含责任人和截止日期的待办事项" },
608
+ ],
609
+ progression: "Notion → Atlassian",
610
+ notes: "Gmail、Slack、Discord 尚无其官方公司发布的 MCP 服务器。",
611
+ },
612
+ "Project Management": {
613
+ description: "规划、任务跟踪、路线图",
614
+ mcps: [
615
+ { name: "GitHub MCP", purpose: "Issue、里程碑、项目看板", repo: "github/github-mcp-server", trust: "Official (28K stars)", best_practice: "统一使用标签和里程碑" },
616
+ { name: "Notion MCP", purpose: "项目 Wiki、数据库", repo: "makenotion/notion-mcp-server", trust: "Official (4K stars)", best_practice: "使用一致的 schema 结构化数据库" },
617
+ { name: "Atlassian MCP", purpose: "Jira 冲刺、看板", repo: "atlassian/atlassian-mcp-server", trust: "Official (436 stars)", best_practice: "遵循团队现有的工作流" },
618
+ { name: "Memory MCP", purpose: "跨会话跟踪决策", repo: "modelcontextprotocol/servers/src/memory", trust: "Reference", best_practice: "记录关键决策的理由和日期" },
619
+ ],
620
+ skills: [
621
+ { name: "breakdown-epic-pm", what_it_teaches: "将 Epic 拆解为可管理的用户故事", source: "GitHub", best_practice: "每个故事应可独立交付" },
622
+ { name: "prd", what_it_teaches: "编写产品需求文档", source: "GitHub", best_practice: "定义用户故事、验收标准和范围" },
623
+ { name: "create-architectural-decision-record", what_it_teaches: "记录架构决策(ADR)", source: "GitHub", best_practice: "记录上下文、决策和影响" },
624
+ ],
625
+ progression: "GitHub issues + Notion → Atlassian → Memory",
626
+ notes: null,
627
+ },
628
+ "Database & Backend": {
629
+ description: "Schema 设计、查询优化、数据迁移",
630
+ mcps: [
631
+ { name: "MongoDB MCP", purpose: "文档数据库操作", repo: "mongodb-js/mongodb-mcp-server", trust: "Official (959 stars)", best_practice: "从环境变量读取连接字符串;绝不硬编码凭证" },
632
+ { name: "Chroma MCP", purpose: "向量数据库,用于嵌入", repo: "chroma-core/chroma-mcp", trust: "Official (515 stars)", best_practice: "按项目划分集合范围" },
633
+ { name: "Stripe MCP", purpose: "支付集成和数据", repo: "stripe/ai", trust: "Official (1.4K stars)", best_practice: "开发时使用测试密钥;绝不记录支付数据" },
634
+ ],
635
+ skills: [
636
+ { name: "postgresql-optimization", what_it_teaches: "PostgreSQL 查询和 schema 优化", source: "GitHub", best_practice: "使用 EXPLAIN ANALYZE;根据查询模式添加索引" },
637
+ { name: "cosmosdb-datamodeling", what_it_teaches: "NoSQL 数据建模模式", source: "GitHub", best_practice: "面向访问模式设计,而非范式化" },
638
+ ],
639
+ progression: "MongoDB → Chroma → Stripe",
640
+ notes: "Supabase 和 PostgreSQL 尚无官方 MCP 服务器。",
641
+ },
642
+ "Cloud & Platform": {
643
+ description: "云服务、无服务器、边缘计算、弹性扩展",
644
+ mcps: [
645
+ { name: "AWS MCP", purpose: "Lambda、S3、EC2,完整 AWS 套件", repo: "awslabs/mcp", trust: "Official (8.5K stars)", best_practice: "使用最小权限 IAM 角色;定期轮换凭证" },
646
+ { name: "Cloudflare MCP", purpose: "Workers、边缘计算、CDN、DNS", repo: "cloudflare/mcp-server-cloudflare", trust: "Official (3.5K stars)", best_practice: "部署前使用 wrangler 本地测试 Workers" },
647
+ { name: "Terraform MCP", purpose: "多云基础设施即代码", repo: "hashicorp/terraform-mcp-server", trust: "Official (1.3K stars)", best_practice: "使用远程状态;操作时锁定状态" },
648
+ { name: "Docker MCP", purpose: "容器编排", repo: "docker/mcp-gateway", trust: "Official (1.3K stars)", best_practice: "多容器用 Docker Compose;不要以 root 运行" },
649
+ ],
650
+ skills: [
651
+ { name: "azure-static-web-apps", what_it_teaches: "将静态 Web 应用部署到云端", source: "GitHub", best_practice: "使用预发布环境;配置自定义域名" },
652
+ { name: "containerize-aspnetcore", what_it_teaches: "将应用容器化部署到云端", source: "GitHub", best_practice: "使用多阶段构建;最小化镜像体积" },
653
+ ],
654
+ progression: "Docker → AWS/Cloudflare → Terraform",
655
+ notes: null,
656
+ },
657
+ "AI & Machine Learning": {
658
+ description: "模型训练、提示词工程、智能体编排",
659
+ mcps: [
660
+ { name: "Sequential Thinking MCP", purpose: "复杂的多步推理", repo: "modelcontextprotocol/servers/src/sequentialthinking", trust: "Reference", best_practice: "用于规划和分解,而非简单查询" },
661
+ { name: "Memory MCP", purpose: "跨会话持久化知识", repo: "modelcontextprotocol/servers/src/memory", trust: "Reference", best_practice: "以知识图谱形式结构化;清理过期条目" },
662
+ { name: "Chroma MCP", purpose: "向量数据库,用于嵌入", repo: "chroma-core/chroma-mcp", trust: "Official (515 stars)", best_practice: "使用合适的嵌入模型;监控集合大小" },
663
+ ],
664
+ skills: [
665
+ { name: "claude-api", what_it_teaches: "使用 Claude API 构建应用", source: "Anthropic", best_practice: "长响应使用流式传输;处理速率限制" },
666
+ { name: "mcp-builder", what_it_teaches: "从零开始构建 MCP 服务器", source: "Anthropic", best_practice: "遵循规范;使用 MCP inspector 验证" },
667
+ { name: "prompt-builder", what_it_teaches: "编写高效的提示词", source: "GitHub", best_practice: "具体明确;提供示例;约束输出格式" },
668
+ { name: "agentic-eval", what_it_teaches: "评估智能体 AI 系统", source: "GitHub", best_practice: "定义明确的成功指标;测试对抗性输入" },
669
+ ],
670
+ progression: "Sequential Thinking + Memory → Chroma",
671
+ notes: null,
672
+ },
673
+ "Marketing & SEO": {
674
+ description: "SEO、竞品分析、内容策略",
675
+ mcps: [
676
+ { name: "Firecrawl MCP", purpose: "SEO 审计、竞品网站爬取", repo: "firecrawl/firecrawl-mcp-server", trust: "Official (5.8K stars)", best_practice: "遵守速率限制;仅爬取自有或已授权的网站" },
677
+ { name: "Brave Search MCP", purpose: "市场调研、趋势分析", repo: "brave/brave-search-mcp-server", trust: "Official (775 stars)", best_practice: "使用日期过滤器进行趋势研究" },
678
+ { name: "Notion MCP", purpose: "内容日历、策略文档", repo: "makenotion/notion-mcp-server", trust: "Official (4K stars)", best_practice: "为周期性内容工作流创建模板" },
679
+ ],
680
+ skills: [],
681
+ progression: "Brave Search → Firecrawl → Notion",
682
+ notes: null,
683
+ },
684
+ "Finance & Commerce": {
685
+ description: "金融数据、支付、定价、市场分析",
686
+ mcps: [
687
+ { name: "Stripe MCP", purpose: "支付集成和计费", repo: "stripe/ai", trust: "Official (1.4K stars)", best_practice: "开发时始终使用测试密钥;不记录 PCI 数据" },
688
+ { name: "Brave Search MCP", purpose: "市场调研、财经新闻", repo: "brave/brave-search-mcp-server", trust: "Official (775 stars)", best_practice: "从多个来源交叉验证金融数据" },
689
+ ],
690
+ skills: [],
691
+ progression: "Fetch (financial APIs) → Brave Search → Stripe",
692
+ notes: null,
693
+ },
694
+ "Science & Life Sciences": {
695
+ description: "科研、数据分析、文献综述、生物信息学",
696
+ mcps: [
697
+ { name: "Fetch MCP", purpose: "访问 PubMed、NCBI 等 API", repo: "modelcontextprotocol/servers/src/fetch", trust: "Reference", best_practice: "使用结构化 API 端点(PubMed E-utilities)" },
698
+ { name: "Memory MCP", purpose: "跨会话跟踪研究发现", repo: "modelcontextprotocol/servers/src/memory", trust: "Reference", best_practice: "将引用元数据与研究发现一同存储" },
699
+ ],
700
+ skills: [],
701
+ progression: "Fetch (PubMed API) → Memory",
702
+ notes: "文献综述工作流请参考 Research & Knowledge 技能(第 7 类)。",
703
+ },
704
+ "Culture & Creative": {
705
+ description: "艺术策展、文化知识、娱乐、创意项目",
706
+ mcps: [
707
+ { name: "Fetch MCP", purpose: "访问博物馆 API(Met、Smithsonian)", repo: "modelcontextprotocol/servers/src/fetch", trust: "Reference", best_practice: "使用官方 REST API" },
708
+ { name: "ElevenLabs MCP", purpose: "创意项目音频", repo: "elevenlabs/elevenlabs-mcp", trust: "Official (1.3K stars)", best_practice: "语音风格匹配项目基调" },
709
+ ],
710
+ skills: [
711
+ { name: "algorithmic-art", what_it_teaches: "通过代码和算法生成艺术作品", source: "Anthropic", best_practice: "尝试不同参数;记录有趣的种子值" },
712
+ { name: "game-engine", what_it_teaches: "游戏开发模式", source: "GitHub", best_practice: "从原型开始;迭代优化玩法" },
713
+ ],
714
+ progression: "Fetch (museum APIs) → ElevenLabs",
715
+ notes: null,
716
+ },
717
+ };
718
+ server.registerTool("levelup_browse_skillsets", {
719
+ title: "浏览推荐技能集",
720
+ description: `浏览任意能力类别的推荐 MCP(工具)和技能(知识)。
721
+
722
+ 返回某个能力的官方推荐配置——需要安装哪些 MCP、
723
+ 学习哪些技能、进阶路径以及每项的最佳实践。
724
+
725
+ 用途:
726
+ - 了解特定领域需要哪些工具
727
+ - 获取推荐的学习路径
728
+ - 查找每个 MCP 的最佳实践
729
+
730
+ 使用 ability="all" 查看所有类别,或指定如 "Software Engineering"。
731
+
732
+ 参数:
733
+ - ability (string): 能力名称(如 "Software Engineering"、"Web Development")或 "all" 查看总览。
734
+
735
+ 返回:
736
+ MCP 及其仓库、信任等级和最佳实践。
737
+ 技能及其来源和最佳实践。
738
+ 进阶路径和备注。`,
739
+ inputSchema: {
740
+ ability: z.string().describe('能力类别名称(如 "Software Engineering"、"DevOps & Infrastructure")或 "all" 查看总览'),
741
+ },
742
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
743
+ }, (growthPlanHandlers.bs = async (params) => {
744
+ const query = params.ability.toLowerCase().trim();
745
+ if (query === "all" || query === "list" || query === "overview") {
746
+ const overview = Object.entries(SKILLSET_DATA).map(([name, data]) => ({
747
+ ability: name,
748
+ description: data.description,
749
+ mcp_count: data.mcps.length,
750
+ skill_count: data.skills.length,
751
+ progression: data.progression,
752
+ }));
753
+ return toMcpResponse(ok({
754
+ total_abilities: overview.length,
755
+ abilities: overview,
756
+ skill_sources: [
757
+ { name: "anthropics/skills", publisher: "Anthropic", url: "https://github.com/anthropics/skills", description: "官方 SKILL.md 格式——17 个生产级技能" },
758
+ { name: "github/awesome-copilot", publisher: "GitHub", url: "https://github.com/github/awesome-copilot/tree/main/skills", description: "222 个 Copilot 社区技能(兼容任何智能体)" },
759
+ ],
760
+ tip: "使用具体的能力名称再次调用,查看完整的 MCP + 技能推荐。",
761
+ }));
762
+ }
763
+ // Fuzzy match on ability name
764
+ const match = Object.entries(SKILLSET_DATA).find(([name]) => name.toLowerCase().includes(query) || query.includes(name.toLowerCase()));
765
+ if (!match) {
766
+ const available = Object.keys(SKILLSET_DATA).join(", ");
767
+ return toMcpResponse(fail(`未找到匹配 "${params.ability}" 的能力`, `可用能力:${available}`));
768
+ }
769
+ const [abilityName, data] = match;
770
+ return toMcpResponse(ok({
771
+ ability: abilityName,
772
+ description: data.description,
773
+ mcps: data.mcps.map((m) => ({
774
+ ...m,
775
+ install_url: `https://github.com/${m.repo}`,
776
+ })),
777
+ skills: data.skills.map((s) => ({
778
+ ...s,
779
+ install_url: s.source === "Anthropic"
780
+ ? `https://github.com/anthropics/skills/tree/main/skills/${s.name}`
781
+ : `https://github.com/github/awesome-copilot/tree/main/skills/${s.name}`,
782
+ })),
783
+ progression: data.progression,
784
+ notes: data.notes,
785
+ how_to_install: "安装 MCP 或技能后,使用 levelup_install_agent_skill 进行注册。",
786
+ }));
787
+ }));
788
+ logRegistered("levelup_browse_skillsets");
789
+ console.error(` → 2 of 2 growth plan tools registered ✅`);
790
+ }
791
+ //# sourceMappingURL=growth-plan.js.map