Skip to content

Commit 7715b65

Browse files
Merge pull request #24 from SPerekrestova/chore/cleanup
Chore/cleanup
2 parents 4d80a0d + 2754596 commit 7715b65

22 files changed

Lines changed: 391 additions & 531 deletions

package-lock.json

Lines changed: 123 additions & 158 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@
6969
"leetcode-query": "^2.0.0",
7070
"minimist": "^1.2.8",
7171
"pino": "^9.6.0",
72-
"ts-node": "^10.9.2",
7372
"zod": "^3.24.2"
7473
},
7574
"devDependencies": {
@@ -84,7 +83,6 @@
8483
"globals": "^16.0.0",
8584
"husky": "^9.1.7",
8685
"lint-staged": "^15.5.1",
87-
"msw": "^2.12.7",
8886
"pino-pretty": "^13.0.0",
8987
"prettier": "^3.5.3",
9088
"prettier-plugin-organize-imports": "^4.1.0",

src/leetcode/leetcode-global-service.ts

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,27 @@ const LANGUAGE_MAP: Record<string, string> = {
1515
java: "java",
1616
python: "python3",
1717
python3: "python3",
18+
c: "c",
1819
cpp: "cpp",
1920
"c++": "cpp",
21+
csharp: "csharp",
22+
"c#": "csharp",
2023
javascript: "javascript",
2124
js: "javascript",
2225
typescript: "typescript",
23-
ts: "typescript"
26+
ts: "typescript",
27+
php: "php",
28+
swift: "swift",
29+
kotlin: "kotlin",
30+
dart: "dart",
31+
golang: "golang",
32+
go: "golang",
33+
ruby: "ruby",
34+
scala: "scala",
35+
rust: "rust",
36+
racket: "racket",
37+
erlang: "erlang",
38+
elixir: "elixir"
2439
};
2540

2641
/**
@@ -79,25 +94,13 @@ export class LeetCodeGlobalService implements LeetcodeServiceInterface {
7994
return { submissions };
8095
}
8196

82-
/**
83-
* 获取用户最近的提交记录
84-
* @param username
85-
* @param limit
86-
* @returns
87-
*/
8897
async fetchUserRecentSubmissions(
8998
username: string,
9099
limit?: number
91100
): Promise<any> {
92101
return await this.leetCodeApi.recent_submissions(username, limit);
93102
}
94103

95-
/**
96-
* 获取用户最近 AC 的提交记录
97-
* @param username
98-
* @param limit
99-
* @returns
100-
*/
101104
async fetchUserRecentACSubmissions(
102105
username: string,
103106
limit?: number
@@ -149,11 +152,17 @@ export class LeetCodeGlobalService implements LeetcodeServiceInterface {
149152
attended: boolean = true
150153
): Promise<any> {
151154
const contestInfo = await this.leetCodeApi.user_contest_info(username);
152-
if (contestInfo.userContestRankingHistory && attended) {
153-
contestInfo.userContestRankingHistory =
154-
contestInfo.userContestRankingHistory.filter((contest: any) => {
155-
return contest && contest.attended;
156-
});
155+
if (contestInfo.userContestRankingHistory) {
156+
if (attended) {
157+
contestInfo.userContestRankingHistory =
158+
contestInfo.userContestRankingHistory.filter(
159+
(contest: any) => {
160+
return contest && contest.attended;
161+
}
162+
);
163+
}
164+
} else {
165+
contestInfo.userContestRankingHistory = [];
157166
}
158167
return contestInfo;
159168
}
@@ -175,10 +184,7 @@ export class LeetCodeGlobalService implements LeetcodeServiceInterface {
175184
const filteredTopicTags =
176185
problem.topicTags?.map((tag: any) => tag.slug) || [];
177186

178-
const filteredCodeSnippets =
179-
problem.codeSnippets?.filter((snippet: any) =>
180-
["cpp", "python3", "java"].includes(snippet.langSlug)
181-
) || [];
187+
const filteredCodeSnippets = problem.codeSnippets || [];
182188

183189
let parsedSimilarQuestions: any[] = [];
184190
if (problem.similarQuestions) {
@@ -435,7 +441,7 @@ export class LeetCodeGlobalService implements LeetcodeServiceInterface {
435441
return {
436442
accepted: false,
437443
statusMessage: "Error",
438-
errorMessage: `Unexpected submission state: \${result.state}`
444+
errorMessage: `Unexpected submission state: ${result.state}`
439445
};
440446
}
441447

@@ -448,6 +454,10 @@ export class LeetCodeGlobalService implements LeetcodeServiceInterface {
448454
accepted: true,
449455
runtime: result.runtime,
450456
memory: result.memory,
457+
runtimePercentile: result.runtime_percentile,
458+
memoryPercentile: result.memory_percentile,
459+
totalCorrect: result.total_correct,
460+
totalTestcases: result.total_testcases,
451461
statusMessage: "Accepted"
452462
};
453463
} else {
@@ -456,16 +466,27 @@ export class LeetCodeGlobalService implements LeetcodeServiceInterface {
456466
if (result.input) {
457467
failedTestCase = `Input: ${result.input}`;
458468
if (result.expected_answer && result.code_answer) {
459-
failedTestCase += `\\nExpected: ${JSON.stringify(result.expected_answer)}`;
460-
failedTestCase += `\\nGot: ${JSON.stringify(result.code_answer)}`;
469+
failedTestCase += `\nExpected: ${JSON.stringify(result.expected_answer)}`;
470+
failedTestCase += `\nGot: ${JSON.stringify(result.code_answer)}`;
461471
}
462472
}
463473

474+
// Use the most specific error message available
475+
const errorMessage =
476+
result.full_compile_error ||
477+
result.compile_error ||
478+
result.full_runtime_error ||
479+
result.runtime_error ||
480+
result.std_output ||
481+
undefined;
482+
464483
return {
465484
accepted: false,
466485
statusMessage: result.status_msg,
467486
failedTestCase,
468-
errorMessage: result.std_output
487+
errorMessage,
488+
totalCorrect: result.total_correct,
489+
totalTestcases: result.total_testcases
469490
};
470491
}
471492
}
@@ -535,7 +556,7 @@ export class LeetCodeGlobalService implements LeetcodeServiceInterface {
535556
const question = response.data.data?.question;
536557
if (!question) {
537558
throw new Error(
538-
`Problem slug "\${problemSlug}" not found or invalid.`
559+
`Problem slug "${problemSlug}" not found or invalid.`
539560
);
540561
}
541562
return question.questionId;

src/mcp/prompts/auth-prompts.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ Offer browser-specific guidance:
8080
- "LeetCode doesn't provide an official authentication API for third-party tools like this MCP server. Cookie extraction is the standard approach used by LeetCode CLI tools and integrations. Your credentials are stored securely and locally on your machine."
8181
8282
**If user is concerned about security:**
83-
- "Your credentials are encrypted and stored locally in ~/.leetcode-mcp/credentials.json. They're never sent anywhere except directly to LeetCode's API to make requests on your behalf. This is the same method used by official LeetCode CLI tools."
83+
- "Your credentials are stored locally in ~/.leetcode-mcp/credentials.json with restricted file permissions (owner-only access). They're never sent anywhere except directly to LeetCode's API to make requests on your behalf. This is the same method used by official LeetCode CLI tools."
8484
8585
**If user has trouble copying the entire value:**
8686
- "Make sure you're clicking on the value field (not the name), and that you can see the full text is selected before copying. The value is typically quite long (50+ characters)."
@@ -163,7 +163,7 @@ Once you're logged in, I'll walk you through getting two cookie values we need f
163163
- Credentials typically expire after 7-14 days
164164
- LeetCode allows only one active session per account at a time
165165
- The MCP server validates credentials by making a test API call to LeetCode's GraphQL endpoint
166-
- Credentials are stored encrypted in ~/.leetcode-mcp/credentials.json`;
166+
- Credentials are stored locally in ~/.leetcode-mcp/credentials.json with restricted file permissions`;
167167

168168
return {
169169
messages: [

src/mcp/prompts/learning-prompts.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,12 +194,17 @@ Keep the user engaged and learning at each step. Adjust the level of guidance ba
194194
"c#": ".cs",
195195
csharp: ".cs",
196196
go: ".go",
197+
golang: ".go",
197198
rust: ".rs",
198199
ruby: ".rb",
199200
swift: ".swift",
200201
kotlin: ".kt",
201202
scala: ".scala",
202-
php: ".php"
203+
php: ".php",
204+
dart: ".dart",
205+
erlang: ".erl",
206+
elixir: ".ex",
207+
racket: ".rkt"
203208
};
204209

205210
return extensionMap[language.toLowerCase()] || ".txt";

src/mcp/resources/resource-registry.ts

Lines changed: 0 additions & 29 deletions
This file was deleted.

src/mcp/tools/problem-tools.ts

Lines changed: 96 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,35 @@ export class ProblemToolRegistry extends ToolRegistry {
1818
"Retrieves today's LeetCode Daily Challenge problem with complete details, including problem description, constraints, and examples. After fetching, invoke the leetcode_learning_mode and leetcode_problem_workflow prompts before helping the user work on it."
1919
},
2020
async () => {
21-
const data = await this.leetcodeService.fetchDailyChallenge();
22-
return {
23-
content: [
24-
{
25-
type: "text",
26-
text: JSON.stringify({
27-
date: new Date().toISOString().split("T")[0],
28-
problem: data
29-
})
30-
}
31-
]
32-
};
21+
try {
22+
const data =
23+
await this.leetcodeService.fetchDailyChallenge();
24+
return {
25+
content: [
26+
{
27+
type: "text",
28+
text: JSON.stringify({
29+
date:
30+
data?.date ??
31+
new Date().toISOString().split("T")[0],
32+
problem: data
33+
})
34+
}
35+
]
36+
};
37+
} catch (error: any) {
38+
return {
39+
content: [
40+
{
41+
type: "text",
42+
text: JSON.stringify({
43+
error: "Failed to fetch daily challenge",
44+
message: error.message
45+
})
46+
}
47+
]
48+
};
49+
}
3350
}
3451
);
3552

@@ -49,21 +66,35 @@ export class ProblemToolRegistry extends ToolRegistry {
4966
}
5067
},
5168
async ({ titleSlug }) => {
52-
const data =
53-
await this.leetcodeService.fetchProblemSimplified(
54-
titleSlug
55-
);
56-
return {
57-
content: [
58-
{
59-
type: "text",
60-
text: JSON.stringify({
61-
titleSlug,
62-
problem: data
63-
})
64-
}
65-
]
66-
};
69+
try {
70+
const data =
71+
await this.leetcodeService.fetchProblemSimplified(
72+
titleSlug
73+
);
74+
return {
75+
content: [
76+
{
77+
type: "text",
78+
text: JSON.stringify({
79+
titleSlug,
80+
problem: data
81+
})
82+
}
83+
]
84+
};
85+
} catch (error: any) {
86+
return {
87+
content: [
88+
{
89+
type: "text",
90+
text: JSON.stringify({
91+
error: "Failed to fetch problem details",
92+
message: error.message
93+
})
94+
}
95+
]
96+
};
97+
}
6798
}
6899
);
69100

@@ -120,26 +151,44 @@ export class ProblemToolRegistry extends ToolRegistry {
120151
offset,
121152
searchKeywords
122153
}) => {
123-
const data = await this.leetcodeService.searchProblems(
124-
category,
125-
tags,
126-
difficulty,
127-
limit,
128-
offset,
129-
searchKeywords
130-
);
131-
return {
132-
content: [
133-
{
134-
type: "text",
135-
text: JSON.stringify({
136-
filters: { tags, difficulty, searchKeywords },
137-
pagination: { limit, offset },
138-
problems: data
139-
})
140-
}
141-
]
142-
};
154+
try {
155+
const data = await this.leetcodeService.searchProblems(
156+
category,
157+
tags,
158+
difficulty,
159+
limit,
160+
offset,
161+
searchKeywords
162+
);
163+
return {
164+
content: [
165+
{
166+
type: "text",
167+
text: JSON.stringify({
168+
filters: {
169+
tags,
170+
difficulty,
171+
searchKeywords
172+
},
173+
pagination: { limit, offset },
174+
problems: data
175+
})
176+
}
177+
]
178+
};
179+
} catch (error: any) {
180+
return {
181+
content: [
182+
{
183+
type: "text",
184+
text: JSON.stringify({
185+
error: "Failed to search problems",
186+
message: error.message
187+
})
188+
}
189+
]
190+
};
191+
}
143192
}
144193
);
145194
}

0 commit comments

Comments
 (0)