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,79 @@
1
+ // ============================================================
2
+ // services/ownership.ts — Ownership verification for data access
3
+ // ============================================================
4
+ // Prevents users from viewing other users' private data (tasks,
5
+ // XP history, evidence) by verifying the caller owns or is
6
+ // associated with the requested entity.
7
+ // ============================================================
8
+ import { supabase } from "./supabase.js";
9
+ import { fail } from "./errors.js";
10
+ import { toMcpResponse } from "./register.js";
11
+ /**
12
+ * Verify that a caller has access to the requested entity's data.
13
+ *
14
+ * Rules:
15
+ * - If target user_id matches caller_user_id → allowed
16
+ * - If target agent_id is owned by caller_user_id → allowed
17
+ * - If target is a task, verify caller owns the task's user_id or agent
18
+ * - Otherwise → denied
19
+ *
20
+ * @returns null if access is allowed, or an MCP error response if denied
21
+ */
22
+ export async function verifyOwnership(params) {
23
+ const { caller_user_id, target_user_id, target_agent_id, target_task_id } = params;
24
+ // Direct user match
25
+ if (target_user_id && target_user_id === caller_user_id) {
26
+ return null; // allowed
27
+ }
28
+ // Check agent ownership
29
+ if (target_agent_id) {
30
+ const { data: agent } = await supabase
31
+ .from("agents")
32
+ .select("owner_user_id")
33
+ .eq("id", target_agent_id)
34
+ .maybeSingle();
35
+ if (agent?.owner_user_id === caller_user_id) {
36
+ return null; // allowed — caller owns this agent
37
+ }
38
+ }
39
+ // Check task ownership (task belongs to caller's user or agent)
40
+ if (target_task_id) {
41
+ const { data: task } = await supabase
42
+ .from("tasks")
43
+ .select("user_id, agent_id")
44
+ .eq("id", target_task_id)
45
+ .maybeSingle();
46
+ if (!task) {
47
+ return toMcpResponse(fail("未找到任务"));
48
+ }
49
+ // Task belongs to caller directly
50
+ if (task.user_id === caller_user_id) {
51
+ return null; // allowed
52
+ }
53
+ // Task belongs to caller's agent
54
+ if (task.agent_id) {
55
+ const { data: agent } = await supabase
56
+ .from("agents")
57
+ .select("owner_user_id")
58
+ .eq("id", task.agent_id)
59
+ .maybeSingle();
60
+ if (agent?.owner_user_id === caller_user_id) {
61
+ return null; // allowed
62
+ }
63
+ }
64
+ }
65
+ // If only user_id was provided and it didn't match, deny
66
+ if (target_user_id && target_user_id !== caller_user_id) {
67
+ return toMcpResponse(fail("拒绝访问:您只能查看自己的数据", "请传入您自己的 user_id 作为 caller_user_id 以证明所有权。"));
68
+ }
69
+ // If only agent_id was provided and ownership check failed
70
+ if (target_agent_id) {
71
+ return toMcpResponse(fail("拒绝访问:您不是此智能体的所有者", "请传入您自己的 user_id 作为 caller_user_id。只有智能体的所有者才能查看其数据。"));
72
+ }
73
+ // Task not owned by caller
74
+ if (target_task_id) {
75
+ return toMcpResponse(fail("拒绝访问:此任务不属于您", "您只能查看属于您或您的智能体的任务。"));
76
+ }
77
+ return toMcpResponse(fail("拒绝访问"));
78
+ }
79
+ //# sourceMappingURL=ownership.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ownership.js","sourceRoot":"","sources":["../../src/services/ownership.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,iEAAiE;AACjE,+DAA+D;AAC/D,gEAAgE;AAChE,2DAA2D;AAC3D,wCAAwC;AACxC,+DAA+D;AAE/D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAKrC;IACC,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,GAAG,MAAM,CAAC;IAEnF,oBAAoB;IACpB,IAAI,cAAc,IAAI,cAAc,KAAK,cAAc,EAAE,CAAC;QACxD,OAAO,IAAI,CAAC,CAAC,UAAU;IACzB,CAAC;IAED,wBAAwB;IACxB,IAAI,eAAe,EAAE,CAAC;QACpB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ;aACnC,IAAI,CAAC,QAAQ,CAAC;aACd,MAAM,CAAC,eAAe,CAAC;aACvB,EAAE,CAAC,IAAI,EAAE,eAAe,CAAC;aACzB,WAAW,EAAE,CAAC;QAEjB,IAAI,KAAK,EAAE,aAAa,KAAK,cAAc,EAAE,CAAC;YAC5C,OAAO,IAAI,CAAC,CAAC,mCAAmC;QAClD,CAAC;IACH,CAAC;IAED,gEAAgE;IAChE,IAAI,cAAc,EAAE,CAAC;QACnB,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,MAAM,QAAQ;aAClC,IAAI,CAAC,OAAO,CAAC;aACb,MAAM,CAAC,mBAAmB,CAAC;aAC3B,EAAE,CAAC,IAAI,EAAE,cAAc,CAAC;aACxB,WAAW,EAAE,CAAC;QAEjB,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QACtC,CAAC;QAED,kCAAkC;QAClC,IAAI,IAAI,CAAC,OAAO,KAAK,cAAc,EAAE,CAAC;YACpC,OAAO,IAAI,CAAC,CAAC,UAAU;QACzB,CAAC;QAED,iCAAiC;QACjC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ;iBACnC,IAAI,CAAC,QAAQ,CAAC;iBACd,MAAM,CAAC,eAAe,CAAC;iBACvB,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC;iBACvB,WAAW,EAAE,CAAC;YAEjB,IAAI,KAAK,EAAE,aAAa,KAAK,cAAc,EAAE,CAAC;gBAC5C,OAAO,IAAI,CAAC,CAAC,UAAU;YACzB,CAAC;QACH,CAAC;IACH,CAAC;IAED,yDAAyD;IACzD,IAAI,cAAc,IAAI,cAAc,KAAK,cAAc,EAAE,CAAC;QACxD,OAAO,aAAa,CAAC,IAAI,CACvB,iBAAiB,EACjB,2CAA2C,CAC5C,CAAC,CAAC;IACL,CAAC;IAED,2DAA2D;IAC3D,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,aAAa,CAAC,IAAI,CACvB,kBAAkB,EAClB,qDAAqD,CACtD,CAAC,CAAC;IACL,CAAC;IAED,2BAA2B;IAC3B,IAAI,cAAc,EAAE,CAAC;QACnB,OAAO,aAAa,CAAC,IAAI,CACvB,cAAc,EACd,oBAAoB,CACrB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AACrC,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Award XP via SECURITY DEFINER RPC (shared helper).
3
+ * Used by skills, quests, and any code that needs to award non-task XP.
4
+ */
5
+ export declare function awardXpViaRpc(entityType: string, entityId: string, xpAmount: number, sourceType: string, description: string, sourceId?: string): Promise<{
6
+ success: boolean;
7
+ running_total?: number;
8
+ }>;
9
+ /**
10
+ * Award class XP via SECURITY DEFINER RPC (shared helper).
11
+ * Updates user_class_progress and records in xp_ledger with class xp_type.
12
+ */
13
+ export declare function awardClassXpViaRpc(userId: string, className: string, xpAmount: number, sourceType: string, description: string, sourceId?: string): Promise<{
14
+ success: boolean;
15
+ new_class_xp?: number;
16
+ }>;
17
+ /**
18
+ * Compute a system template quality score for a task (1-5 scale).
19
+ * Same logic as levelup_request_system_evaluation but runs inline.
20
+ *
21
+ * Timeliness is now tier-aware: tasks completed much faster than the
22
+ * expected pace for their tier score lower on timeliness (2-3/5),
23
+ * while tasks at or above the expected pace score 4-5/5.
24
+ */
25
+ export declare function computeSystemScore(task: {
26
+ completion_pct: number;
27
+ output_type: string | null;
28
+ difficulty: number;
29
+ duration_seconds: number | null;
30
+ xp_tier?: string | null;
31
+ }): {
32
+ score: number;
33
+ breakdown: Record<string, number>;
34
+ };
35
+ /**
36
+ * Get the integrity multiplier for an agent (0.1 to 1.0).
37
+ * Users always get multiplier 1.0.
38
+ */
39
+ export declare function getIntegrityMultiplier(entityType: string, entityId: string): Promise<number>;
40
+ /**
41
+ * Apply quality and integrity multipliers to an XP pool.
42
+ * Returns the adjusted XP amount (never less than 1 if original > 0).
43
+ */
44
+ export declare function applyQualityMultiplier(xpPool: number, qualityScore: number, integrityMultiplier: number): number;
45
+ //# sourceMappingURL=quality-gate.d.ts.map
@@ -0,0 +1,131 @@
1
+ // ============================================================
2
+ // services/quality-gate.ts — Quality-gated XP & shared XP helpers
3
+ // ============================================================
4
+ // Auto-scores a completed task using template-based evaluation,
5
+ // then applies quality and integrity multipliers to XP.
6
+ // Also exports awardXpViaRpc for shared use across tool files.
7
+ // ============================================================
8
+ import { supabase } from "./supabase.js";
9
+ /**
10
+ * Award XP via SECURITY DEFINER RPC (shared helper).
11
+ * Used by skills, quests, and any code that needs to award non-task XP.
12
+ */
13
+ export async function awardXpViaRpc(entityType, entityId, xpAmount, sourceType, description, sourceId) {
14
+ const { data, error } = await supabase.rpc('award_xp_direct', {
15
+ p_entity_type: entityType,
16
+ p_entity_id: entityId,
17
+ p_amount: xpAmount,
18
+ p_source_type: sourceType,
19
+ p_description: description,
20
+ p_source_id: sourceId || null,
21
+ });
22
+ if (error) {
23
+ console.error("award_xp_direct RPC error:", error);
24
+ return { success: false };
25
+ }
26
+ return { success: data?.success ?? false, running_total: data?.running_total };
27
+ }
28
+ /**
29
+ * Award class XP via SECURITY DEFINER RPC (shared helper).
30
+ * Updates user_class_progress and records in xp_ledger with class xp_type.
31
+ */
32
+ export async function awardClassXpViaRpc(userId, className, xpAmount, sourceType, description, sourceId) {
33
+ const { data, error } = await supabase.rpc('award_class_xp', {
34
+ p_user_id: userId,
35
+ p_class_name: className,
36
+ p_amount: xpAmount,
37
+ p_source_type: sourceType,
38
+ p_description: description,
39
+ p_source_id: sourceId || null,
40
+ });
41
+ if (error) {
42
+ console.error("award_class_xp RPC error:", error);
43
+ return { success: false };
44
+ }
45
+ return { success: data?.success ?? false, new_class_xp: data?.new_class_xp };
46
+ }
47
+ // "Good pace" thresholds per tier (seconds). Tasks completed faster than
48
+ // the hard floor pass, but completing well under the expected pace lowers
49
+ // the timeliness score in the quality gate — rewarding thoroughness without
50
+ // hard-blocking fast agents.
51
+ const EXPECTED_PACE_SECONDS = {
52
+ micro: 30, // 30s expected
53
+ light: 120, // 2 min expected
54
+ standard: 300, // 5 min expected
55
+ complex: 600, // 10 min expected
56
+ major: 1800, // 30 min expected
57
+ };
58
+ /**
59
+ * Compute a system template quality score for a task (1-5 scale).
60
+ * Same logic as levelup_request_system_evaluation but runs inline.
61
+ *
62
+ * Timeliness is now tier-aware: tasks completed much faster than the
63
+ * expected pace for their tier score lower on timeliness (2-3/5),
64
+ * while tasks at or above the expected pace score 4-5/5.
65
+ */
66
+ export function computeSystemScore(task) {
67
+ const completionScore = task.completion_pct >= 100 ? 5
68
+ : task.completion_pct >= 75 ? 4
69
+ : task.completion_pct >= 50 ? 3 : 2;
70
+ const hasOutput = task.output_type === "deliverable" || task.output_type === "deployed";
71
+ const outputScore = hasOutput ? 4 : 3;
72
+ const difficultyScore = task.difficulty >= 3 ? 4 : 3;
73
+ // Tier-aware timeliness: compare actual duration against expected pace
74
+ const tier = task.xp_tier || "standard";
75
+ const expectedPace = EXPECTED_PACE_SECONDS[tier] || 300;
76
+ const durationSeconds = task.duration_seconds || 0;
77
+ const paceRatio = durationSeconds / Math.max(1, expectedPace); // 1.0 = on pace
78
+ let timelinessScore;
79
+ if (paceRatio >= 1.0) {
80
+ // At or above expected pace — good
81
+ timelinessScore = paceRatio < 3.0 ? 5 : 4; // very slow = still OK but 4
82
+ }
83
+ else if (paceRatio >= 0.5) {
84
+ // 50-99% of expected pace — slightly fast, decent score
85
+ timelinessScore = 4;
86
+ }
87
+ else if (paceRatio >= 0.3) {
88
+ // 30-49% of expected pace — suspiciously fast
89
+ timelinessScore = 3;
90
+ }
91
+ else {
92
+ // Under 30% of expected pace — rushing
93
+ timelinessScore = 2;
94
+ }
95
+ const breakdown = {
96
+ completeness: completionScore,
97
+ output_quality: outputScore,
98
+ difficulty_appropriate: difficultyScore,
99
+ timeliness: timelinessScore,
100
+ };
101
+ const scores = Object.values(breakdown);
102
+ const score = scores.reduce((s, n) => s + n, 0) / scores.length;
103
+ return { score, breakdown };
104
+ }
105
+ /**
106
+ * Get the integrity multiplier for an agent (0.1 to 1.0).
107
+ * Users always get multiplier 1.0.
108
+ */
109
+ export async function getIntegrityMultiplier(entityType, entityId) {
110
+ if (entityType === "user")
111
+ return 1.0;
112
+ const { data: agent } = await supabase
113
+ .from("agents")
114
+ .select("integrity_score")
115
+ .eq("id", entityId)
116
+ .maybeSingle();
117
+ const integrity = agent?.integrity_score ?? 100;
118
+ return Math.max(0.1, Math.min(1.0, integrity / 100));
119
+ }
120
+ /**
121
+ * Apply quality and integrity multipliers to an XP pool.
122
+ * Returns the adjusted XP amount (never less than 1 if original > 0).
123
+ */
124
+ export function applyQualityMultiplier(xpPool, qualityScore, integrityMultiplier) {
125
+ if (xpPool <= 0)
126
+ return 0;
127
+ const qualityMultiplier = qualityScore / 5.0;
128
+ const adjusted = Math.round(xpPool * qualityMultiplier * integrityMultiplier);
129
+ return Math.max(1, adjusted); // at least 1 XP if pool was > 0
130
+ }
131
+ //# sourceMappingURL=quality-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality-gate.js","sourceRoot":"","sources":["../../src/services/quality-gate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { toMcpResponse } from "./register.js";
2
+ /**
3
+ * Check if an action is within the rate limit.
4
+ *
5
+ * @param entityId - The user or agent ID performing the action
6
+ * @param action - Action name (e.g. "start_task", "complete_task")
7
+ * @param maxCalls - Max calls allowed in the window
8
+ * @param windowMs - Time window in milliseconds
9
+ * @returns null if allowed, or an MCP error response if rate-limited
10
+ */
11
+ export declare function checkRateLimit(entityId: string, action: string, maxCalls: number, windowMs: number): ReturnType<typeof toMcpResponse> | null;
12
+ //# sourceMappingURL=rate-limit.d.ts.map
@@ -0,0 +1,49 @@
1
+ // ============================================================
2
+ // services/rate-limit.ts — In-memory rate limiting
3
+ // ============================================================
4
+ // Simple sliding-window rate limiter to prevent abuse of
5
+ // XP-generating tools (start_task, complete_task, etc.).
6
+ //
7
+ // This is an in-memory solution — limits reset on server restart.
8
+ // For production at scale, replace with Redis-based limiter.
9
+ // ============================================================
10
+ import { fail } from "./errors.js";
11
+ import { toMcpResponse } from "./register.js";
12
+ const buckets = new Map();
13
+ // Clean up stale entries every 10 minutes
14
+ setInterval(() => {
15
+ const cutoff = Date.now() - 3600_000; // 1 hour
16
+ for (const [key, entry] of buckets) {
17
+ entry.timestamps = entry.timestamps.filter((t) => t > cutoff);
18
+ if (entry.timestamps.length === 0)
19
+ buckets.delete(key);
20
+ }
21
+ }, 600_000);
22
+ /**
23
+ * Check if an action is within the rate limit.
24
+ *
25
+ * @param entityId - The user or agent ID performing the action
26
+ * @param action - Action name (e.g. "start_task", "complete_task")
27
+ * @param maxCalls - Max calls allowed in the window
28
+ * @param windowMs - Time window in milliseconds
29
+ * @returns null if allowed, or an MCP error response if rate-limited
30
+ */
31
+ export function checkRateLimit(entityId, action, maxCalls, windowMs) {
32
+ const key = `${action}:${entityId}`;
33
+ const now = Date.now();
34
+ const cutoff = now - windowMs;
35
+ let entry = buckets.get(key);
36
+ if (!entry) {
37
+ entry = { timestamps: [] };
38
+ buckets.set(key, entry);
39
+ }
40
+ // Remove timestamps outside the window
41
+ entry.timestamps = entry.timestamps.filter((t) => t > cutoff);
42
+ if (entry.timestamps.length >= maxCalls) {
43
+ const windowMinutes = Math.round(windowMs / 60_000);
44
+ return toMcpResponse(fail(`超出速率限制:每${windowMinutes}分钟最多${maxCalls}次${action}调用`, "请等待后重试。此限制用于防止滥用。"));
45
+ }
46
+ entry.timestamps.push(now);
47
+ return null;
48
+ }
49
+ //# sourceMappingURL=rate-limit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../../src/services/rate-limit.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,mDAAmD;AACnD,+DAA+D;AAC/D,yDAAyD;AACzD,yDAAyD;AACzD,EAAE;AACF,kEAAkE;AAClE,6DAA6D;AAC7D,+DAA+D;AAE/D,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAM9C,MAAM,OAAO,GAAG,IAAI,GAAG,EAA0B,CAAC;AAElD,0CAA0C;AAC1C,WAAW,CAAC,GAAG,EAAE;IACf,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,CAAC,SAAS;IAC/C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;QACnC,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;QAC9D,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACzD,CAAC;AACH,CAAC,EAAE,OAAO,CAAC,CAAC;AAEZ;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAC5B,QAAgB,EAChB,MAAc,EACd,QAAgB,EAChB,QAAgB;IAEhB,MAAM,GAAG,GAAG,GAAG,MAAM,IAAI,QAAQ,EAAE,CAAC;IACpC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,MAAM,GAAG,GAAG,GAAG,QAAQ,CAAC;IAE9B,IAAI,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,KAAK,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC1B,CAAC;IAED,uCAAuC;IACvC,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;IAE9D,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC;QACxC,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,MAAM,CAAC,CAAC;QACpD,OAAO,aAAa,CAClB,IAAI,CACF,WAAW,aAAa,OAAO,QAAQ,IAAI,MAAM,IAAI,EACrD,mBAAmB,CACpB,CACF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3B,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,49 @@
1
+ import type { ToolResult } from "../types.js";
2
+ /**
3
+ * MCP tool annotations — metadata about what a tool does.
4
+ * These help LLMs decide which tools to call (and which to avoid).
5
+ *
6
+ * readOnlyHint: true = this tool only reads data, never changes anything
7
+ * destructiveHint: true = this tool deletes or irreversibly modifies data
8
+ * idempotentHint: true = calling it twice with same params gives same result
9
+ * openWorldHint: true = the tool talks to external systems (not just our DB)
10
+ */
11
+ export interface ToolAnnotations {
12
+ readOnlyHint: boolean;
13
+ destructiveHint: boolean;
14
+ idempotentHint: boolean;
15
+ openWorldHint: boolean;
16
+ }
17
+ /**
18
+ * Standard annotations for read-only tools (get_*, list_*).
19
+ * Most of our tools are reads, so this is the most common set.
20
+ */
21
+ export declare const READ_ONLY: ToolAnnotations;
22
+ /** For tools that create new records (register_*, start_*, create_*) */
23
+ export declare const CREATES: ToolAnnotations;
24
+ /** For tools that update existing records (update_*, complete_*) */
25
+ export declare const UPDATES: ToolAnnotations;
26
+ /** For tools that delete or irreversibly change data (merge_*, fail with cancel) */
27
+ export declare const DESTRUCTIVE: ToolAnnotations;
28
+ /**
29
+ * Convert a ToolResult into the MCP response format.
30
+ *
31
+ * The MCP protocol expects responses in a specific shape:
32
+ * { content: [{ type: "text", text: "..." }] }
33
+ *
34
+ * If our tool returned an error (success: false), we also set
35
+ * isError: true so the MCP client knows something went wrong.
36
+ */
37
+ export declare function toMcpResponse(result: ToolResult): {
38
+ content: Array<{
39
+ type: "text";
40
+ text: string;
41
+ }>;
42
+ isError?: boolean;
43
+ };
44
+ /**
45
+ * Helper to log tool registration at startup.
46
+ * This helps with debugging — you can see exactly which tools loaded.
47
+ */
48
+ export declare function logRegistered(toolName: string): void;
49
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1,63 @@
1
+ // ============================================================
2
+ // services/register.ts — Tool registration helper
3
+ // ============================================================
4
+ // This file provides a convenience wrapper around the MCP SDK's
5
+ // registerTool method. It standardizes how we register tools
6
+ // and ensures every tool follows the same patterns.
7
+ // ============================================================
8
+ import { formatToolResponse } from "./format.js";
9
+ /**
10
+ * Standard annotations for read-only tools (get_*, list_*).
11
+ * Most of our tools are reads, so this is the most common set.
12
+ */
13
+ export const READ_ONLY = {
14
+ readOnlyHint: true,
15
+ destructiveHint: false,
16
+ idempotentHint: true,
17
+ openWorldHint: false,
18
+ };
19
+ /** For tools that create new records (register_*, start_*, create_*) */
20
+ export const CREATES = {
21
+ readOnlyHint: false,
22
+ destructiveHint: false,
23
+ idempotentHint: false,
24
+ openWorldHint: false,
25
+ };
26
+ /** For tools that update existing records (update_*, complete_*) */
27
+ export const UPDATES = {
28
+ readOnlyHint: false,
29
+ destructiveHint: false,
30
+ idempotentHint: true,
31
+ openWorldHint: false,
32
+ };
33
+ /** For tools that delete or irreversibly change data (merge_*, fail with cancel) */
34
+ export const DESTRUCTIVE = {
35
+ readOnlyHint: false,
36
+ destructiveHint: true,
37
+ idempotentHint: false,
38
+ openWorldHint: false,
39
+ };
40
+ /**
41
+ * Convert a ToolResult into the MCP response format.
42
+ *
43
+ * The MCP protocol expects responses in a specific shape:
44
+ * { content: [{ type: "text", text: "..." }] }
45
+ *
46
+ * If our tool returned an error (success: false), we also set
47
+ * isError: true so the MCP client knows something went wrong.
48
+ */
49
+ export function toMcpResponse(result) {
50
+ const text = formatToolResponse(result);
51
+ return {
52
+ content: [{ type: "text", text }],
53
+ ...(result.success === false ? { isError: true } : {}),
54
+ };
55
+ }
56
+ /**
57
+ * Helper to log tool registration at startup.
58
+ * This helps with debugging — you can see exactly which tools loaded.
59
+ */
60
+ export function logRegistered(toolName) {
61
+ console.error(` ✓ Registered: ${toolName}`);
62
+ }
63
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../../src/services/register.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,kDAAkD;AAClD,+DAA+D;AAC/D,gEAAgE;AAChE,6DAA6D;AAC7D,oDAAoD;AACpD,+DAA+D;AAG/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAmBjD;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAoB;IACxC,YAAY,EAAE,IAAI;IAClB,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,IAAI;IACpB,aAAa,EAAE,KAAK;CACrB,CAAC;AAEF,wEAAwE;AACxE,MAAM,CAAC,MAAM,OAAO,GAAoB;IACtC,YAAY,EAAE,KAAK;IACnB,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,KAAK;IACrB,aAAa,EAAE,KAAK;CACrB,CAAC;AAEF,oEAAoE;AACpE,MAAM,CAAC,MAAM,OAAO,GAAoB;IACtC,YAAY,EAAE,KAAK;IACnB,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,IAAI;IACpB,aAAa,EAAE,KAAK;CACrB,CAAC;AAEF,oFAAoF;AACpF,MAAM,CAAC,MAAM,WAAW,GAAoB;IAC1C,YAAY,EAAE,KAAK;IACnB,eAAe,EAAE,IAAI;IACrB,cAAc,EAAE,KAAK;IACrB,aAAa,EAAE,KAAK;CACrB,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,MAAkB;IAI9C,MAAM,IAAI,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACxC,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC;QAC1C,GAAG,CAAC,MAAM,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACvD,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,OAAO,CAAC,KAAK,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { SupabaseClient } from "@supabase/supabase-js";
2
+ /**
3
+ * Validate that required environment variables are set and
4
+ * initialize the Supabase client. Call this at server startup —
5
+ * if either variable is missing, we crash immediately with a
6
+ * helpful error message rather than failing mysteriously later.
7
+ */
8
+ export declare function validateEnv(): void;
9
+ export declare const supabase: SupabaseClient<any, "public", "public", any, any>;
10
+ //# sourceMappingURL=supabase.d.ts.map
@@ -0,0 +1,79 @@
1
+ // ============================================================
2
+ // services/supabase.ts — Database client setup
3
+ // ============================================================
4
+ // This file creates the Supabase client that ALL tools use to
5
+ // talk to your Postgres database. Think of it as the "phone
6
+ // line" between your MCP server and Supabase.
7
+ //
8
+ // HOW IT WORKS:
9
+ // - Zero-config: Falls back to the public anon key (RLS-protected)
10
+ // - Optional: Set env vars to use your own project or service_role key
11
+ //
12
+ // KEY TYPES:
13
+ // anon key (default): Safe to expose. Respects Row Level Security.
14
+ // All operations go through RLS policies on the database.
15
+ // service_role key (optional): Bypasses RLS. Only set this if you
16
+ // need admin access or are running a private instance.
17
+ // ============================================================
18
+ import { createClient } from "@supabase/supabase-js";
19
+ // Default public project credentials (anon key — safe to expose, RLS-protected)
20
+ const DEFAULT_SUPABASE_URL = "https://pxanrmpwptinbtwigqdt.supabase.co";
21
+ const DEFAULT_SUPABASE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InB4YW5ybXB3cHRpbmJ0d2lncWR0Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzMzMzE0MTUsImV4cCI6MjA4ODkwNzQxNX0.UES9REdFSED5Sl7VT_2tN_96rEgiFFZiXWR5-jflJL0";
22
+ const supabaseUrl = process.env.SUPABASE_URL || DEFAULT_SUPABASE_URL;
23
+ const supabaseKey = process.env.SUPABASE_SERVICE_KEY || DEFAULT_SUPABASE_KEY;
24
+ /**
25
+ * Validate that required environment variables are set and
26
+ * initialize the Supabase client. Call this at server startup —
27
+ * if either variable is missing, we crash immediately with a
28
+ * helpful error message rather than failing mysteriously later.
29
+ */
30
+ export function validateEnv() {
31
+ const usingDefaults = !process.env.SUPABASE_URL && !process.env.SUPABASE_SERVICE_KEY;
32
+ if (usingDefaults) {
33
+ console.error(" ℹ️ Using default public project (anon key, RLS-protected)");
34
+ }
35
+ else {
36
+ // If user set one but not both, warn
37
+ if (!process.env.SUPABASE_URL || !process.env.SUPABASE_SERVICE_KEY) {
38
+ console.error(`\n⚠️ Partial config: set BOTH SUPABASE_URL and SUPABASE_SERVICE_KEY, or neither (for defaults).\n` +
39
+ ` Falling back to defaults for missing values.\n`);
40
+ }
41
+ }
42
+ _supabase = createClient(supabaseUrl, supabaseKey, {
43
+ auth: {
44
+ autoRefreshToken: false,
45
+ persistSession: false,
46
+ },
47
+ });
48
+ }
49
+ /**
50
+ * The Supabase client instance.
51
+ *
52
+ * Usage in tool files:
53
+ * import { supabase } from "../services/supabase.js";
54
+ *
55
+ * const { data, error } = await supabase
56
+ * .from("users")
57
+ * .select("*")
58
+ * .eq("id", userId);
59
+ *
60
+ * Common patterns:
61
+ * .select("*") → get all columns
62
+ * .select("id, name") → get specific columns
63
+ * .eq("id", value) → WHERE id = value
64
+ * .ilike("name", "%pat") → case-insensitive LIKE
65
+ * .order("created_at", { ascending: false }) → ORDER BY
66
+ * .range(0, 19) → LIMIT 20, OFFSET 0
67
+ * .single() → expect exactly one row
68
+ * .maybeSingle() → expect 0 or 1 rows
69
+ */
70
+ let _supabase;
71
+ export const supabase = new Proxy({}, {
72
+ get(_target, prop, receiver) {
73
+ if (!_supabase) {
74
+ throw new Error("Supabase client not initialized. Call validateEnv() first.");
75
+ }
76
+ return Reflect.get(_supabase, prop, receiver);
77
+ },
78
+ });
79
+ //# sourceMappingURL=supabase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supabase.js","sourceRoot":"","sources":["../../src/services/supabase.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+CAA+C;AAC/C,+DAA+D;AAC/D,8DAA8D;AAC9D,4DAA4D;AAC5D,8CAA8C;AAC9C,EAAE;AACF,gBAAgB;AAChB,mEAAmE;AACnE,uEAAuE;AACvE,EAAE;AACF,aAAa;AACb,qEAAqE;AACrE,8DAA8D;AAC9D,oEAAoE;AACpE,2DAA2D;AAC3D,+DAA+D;AAE/D,OAAO,EAAE,YAAY,EAAkB,MAAM,uBAAuB,CAAC;AAErE,gFAAgF;AAChF,MAAM,oBAAoB,GAAG,0CAA0C,CAAC;AACxE,MAAM,oBAAoB,GAAG,kNAAkN,CAAC;AAEhP,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,oBAAoB,CAAC;AACrE,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,oBAAoB,CAAC;AAE7E;;;;;GAKG;AACH,MAAM,UAAU,WAAW;IACzB,MAAM,aAAa,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;IAErF,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAChF,CAAC;SAAM,CAAC;QACN,qCAAqC;QACrC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,CAAC;YACnE,OAAO,CAAC,KAAK,CACX,oGAAoG;gBACpG,kDAAkD,CACnD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,SAAS,GAAG,YAAY,CAAC,WAAW,EAAE,WAAW,EAAE;QACjD,IAAI,EAAE;YACJ,gBAAgB,EAAE,KAAK;YACvB,cAAc,EAAE,KAAK;SACtB;KACF,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,IAAI,SAAyB,CAAC;AAE9B,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,KAAK,CAAC,EAAoB,EAAE;IACtD,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ;QACzB,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;QAChF,CAAC;QACD,OAAO,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IAChD,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ActionHandler } from "../services/dispatcher.js";
3
+ export declare const getAchievementsHandler: ActionHandler;
4
+ export declare const scanAchievementsHandler: ActionHandler;
5
+ export declare function registerAchievementTools(server: McpServer): void;
6
+ //# sourceMappingURL=achievements.d.ts.map