resume-parser-ats 1.1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Dhanush Kandhan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,294 @@
1
+ # šŸ“„ Resume Parser
2
+
3
+ <p align="center">
4
+ <strong>Deep resume parsing • ATS compatibility scoring • Actionable improvement insights</strong>
5
+ </p>
6
+
7
+ <p align="center">
8
+ Made with ā¤ļø by <strong>Dhanush Kandhan</strong>
9
+ </p>
10
+
11
+ ---
12
+
13
+ A powerful agent skill that deeply parses resumes using the **OpenResume 4-step algorithm**, extracts structured information (Name, Email, Phone, Education, Work Experience, Skills, Projects), evaluates ATS (Applicant Tracking System) compatibility, and provides prioritized, actionable suggestions to improve your resume.
14
+
15
+ ## ✨ Features
16
+
17
+ - **šŸ” Deep Parsing** — Extracts 10+ fields from raw text or PDF using a feature-scoring engine
18
+ - **šŸ“Š ATS Scoring** — Grades your resume A+ through F with detailed per-field confidence ratings
19
+ - **šŸ’” Smart Suggestions** — Prioritized, categorized fixes (critical → low) with before/after examples
20
+ - **šŸ› ļø CLI & MCP Server** — Use interactively from the command line or as an MCP tool
21
+ - **āš™ļø Configurable Strictness** — Lenient, moderate, or strict ATS evaluation modes
22
+ - **šŸ”’ Zero Dependencies on Proprietary APIs** — Runs entirely locally with no external calls
23
+
24
+ ## šŸ“¦ Installation
25
+
26
+ ```bash
27
+ # Clone the repo
28
+ git clone https://github.com/dhanushk-offl/resume-parser-skill.git
29
+ cd resume-parser-skill
30
+
31
+ # Install dependencies
32
+ npm install
33
+
34
+ # Build
35
+ npm run build
36
+ ```
37
+
38
+ ## šŸš€ Usage
39
+
40
+ ### As a CLI Tool
41
+
42
+ ```bash
43
+ # Parse a resume and output structured data
44
+ npx resume-parser parse resume.pdf
45
+
46
+ # Parse + analyze ATS compatibility
47
+ npx resume-parser analyze resume.pdf
48
+
49
+ # Full pipeline: parse + analyze + actionable suggestions
50
+ npx resume-parser insights resume.pdf
51
+
52
+ # Parse from raw text
53
+ npx resume-parser parse "John Doe\njohn@email.com\nSoftware Engineer"
54
+
55
+ # Adjust ATS strictness
56
+ npx resume-parser analyze resume.pdf --strictness strict
57
+
58
+ # Focus on specific areas
59
+ npx resume-parser insights resume.pdf --focus ats,formatting --json
60
+ ```
61
+
62
+ ### As a Library
63
+
64
+ ```typescript
65
+ import { parseResume, analyzeResume, suggestImprovements } from "resume-parser-ats";
66
+
67
+ // Step 1: Parse
68
+ const parsed = parseResume({ rawText: "..." });
69
+ console.log(parsed.data.profile.name); // "Jane Doe"
70
+ console.log(parsed.data.profile.email); // "jane@example.com"
71
+ console.log(parsed.data.education[0]?.school); // "MIT"
72
+
73
+ // Step 2: Analyze ATS compatibility
74
+ const analysis = analyzeResume({
75
+ rawText: "...",
76
+ parsedResume: parsed.data,
77
+ strictness: "moderate",
78
+ });
79
+ console.log(analysis.data.atsScore); // 72
80
+ console.log(analysis.data.atsGrade); // "B-"
81
+
82
+ // Step 3: Get improvement suggestions
83
+ const suggestions = suggestImprovements({
84
+ rawText: "...",
85
+ parsedResume: parsed.data,
86
+ analysisResult: analysis.data,
87
+ focusAreas: ["ats", "content", "formatting", "structure"],
88
+ });
89
+ console.log(suggestions.data.quickWins); // ["Fix your name format...", ...]
90
+ console.log(suggestions.data.suggestions[0].title); // "Name is not parseable by ATS"
91
+ ```
92
+
93
+ ### As an MCP Server
94
+
95
+ ```bash
96
+ npm run mcp
97
+ ```
98
+
99
+ Starts a Model Context Protocol server exposing three tools:
100
+
101
+ | Tool | Description |
102
+ |------|-------------|
103
+ | `parse_resume` | Parse a resume PDF or raw text and return structured data |
104
+ | `analyze_resume` | Parse + compute ATS compatibility score with per-field confidence |
105
+ | `suggest_improvements` | Parse + analyze + generate prioritized improvement suggestions |
106
+
107
+ ## 🧠 How It Works: The 4-Step Algorithm
108
+
109
+ The parser follows the **OpenResume algorithm**, a proven methodology used by real ATS systems:
110
+
111
+ ### Step 1 — Read Text Items
112
+
113
+ Extracts all text items from the resume, including:
114
+ - Text content
115
+ - X/Y positions (relative to bottom-left origin)
116
+ - Bold metadata
117
+ - Newline markers
118
+
119
+ ### Step 2 — Group Into Lines
120
+
121
+ Merges adjacent text items on the same Y-coordinate when their horizontal distance is less than the average character width. Groups by Y-coordinate to reconstruct the line-by-line reading order.
122
+
123
+ ### Step 3 — Group Into Sections
124
+
125
+ Detects section titles using two heuristics:
126
+ 1. **Primary**: Only text item in line + bold + ALL UPPERCASE
127
+ 2. **Fallback**: Keyword match against known headers (EDUCATION, EXPERIENCE, SKILLS, etc.)
128
+
129
+ ### Step 4 — Extract Attributes via Feature Scoring
130
+
131
+ Each attribute (Name, Email, Phone, etc.) has **feature sets** — matching functions with positive/negative scores. The text item with the highest total score wins. This is how real ATS systems rank candidates:
132
+
133
+ | Feature (Name) | Score | Feature (Email) | Score |
134
+ |---|---|---|---|
135
+ | Contains only letters/spaces/periods | +3 | Matches email regex | +4 |
136
+ | Is bolded | +2 | Contains @ symbol | +4 |
137
+ | Is ALL UPPERCASE | +2 | Looks like a name (no @) | -1 |
138
+ | Contains @ (probably email) | -4 | Contains digits (no @) | -2 |
139
+ | Contains numbers (probably phone) | -4 | — | — |
140
+
141
+ ## šŸ“Š Use Cases
142
+
143
+ ### 1. šŸŽÆ Job Seeker — ATS Optimization
144
+
145
+ > *Before applying to jobs, run your resume through the parser to see what an ATS actually extracts.*
146
+
147
+ ```bash
148
+ npx resume-parser insights my-resume.pdf --strictness strict --json
149
+ ```
150
+
151
+ Identify critical issues like a missing email, unparseable name, or sections an ATS can't detect — and fix them *before* you apply.
152
+
153
+ ### 2. šŸ¢ Recruiter — Bulk Resume Screening
154
+
155
+ > *Programmatically parse and score hundreds of resumes to rank candidates by ATS readability.*
156
+
157
+ ```typescript
158
+ import { parseResume, analyzeResume } from "resume-parser-ats";
159
+ import fs from "fs";
160
+
161
+ const files = fs.readdirSync("resumes/");
162
+ for (const file of files) {
163
+ const parsed = parseResume({ filePath: `resumes/${file}` });
164
+ const analysis = analyzeResume({
165
+ filePath: `resumes/${file}`,
166
+ parsedResume: parsed.data,
167
+ strictness: "moderate",
168
+ });
169
+ console.log(`${file}: ATS Score ${analysis.data.atsScore}/100 (${analysis.data.atsGrade})`);
170
+ }
171
+ ```
172
+
173
+ ### 3. šŸ¤– Agent Integration — AI-Powered Resume Coach
174
+
175
+ > *Embed the skill into an AI agent that reviews resumes and gives personalized coaching.*
176
+
177
+ ```typescript
178
+ import { fullPipeline } from "resume-parser-ats";
179
+
180
+ const result = fullPipeline({ rawText: resumeText, strictness: "strict" });
181
+
182
+ // result.parsed — structured data
183
+ // result.analyzed — ATS score + field analysis
184
+ // result.suggestions — prioritized actions
185
+
186
+ // Feed to an LLM for natural-language coaching
187
+ const prompt = `You are a resume coach. Here is the analysis:
188
+ ${JSON.stringify(result.analyzed.data)}
189
+ Suggest improvements in a friendly, encouraging tone.`;
190
+ ```
191
+
192
+ ### 4. šŸ“ˆ Career Platform — Resume Health Dashboard
193
+
194
+ > *Show users a "resume health score" on your career platform dashboard.*
195
+
196
+ - Parse on upload → store `atsScore`, `atsGrade`, and `fieldAnalyses`
197
+ - Display a visual dashboard with color-coded field ratings
198
+ - Surface `quickWins` as a checklist
199
+ - Track score improvements over time as users update their resumes
200
+
201
+ ### 5. šŸŽ“ University Career Center — Student Resume Reviews
202
+
203
+ > *Automate initial resume screening for career centers at scale.*
204
+
205
+ - Batch-parse student resumes and generate summary reports
206
+ - Flag common issues (missing dates, non-standard section headers)
207
+ - Provide standardized improvement templates
208
+
209
+ ### 6. šŸ”„ Resume Migration Tool
210
+
211
+ > *Convert resumes from one format to structured JSON for database ingestion.*
212
+
213
+ ```typescript
214
+ import { parseResume } from "resume-parser-ats";
215
+
216
+ const result = parseResume({ filePath: "legacy-resume.pdf" });
217
+ // result.data is a clean, typed JSON object ready for your database
218
+ ```
219
+
220
+ ## šŸ—ļø Architecture
221
+
222
+ ```
223
+ resume-parser/
224
+ ā”œā”€ā”€ package.json # Project metadata & scripts
225
+ ā”œā”€ā”€ README.md # This file
226
+ ā”œā”€ā”€ LICENSE # MIT License — Dhanush Kandhan
227
+ ā”œā”€ā”€ AGENTS.md # Agent-facing configuration
228
+ ā”œā”€ā”€ SKILL.md # Skill definition for agent consumption
229
+ ā”œā”€ā”€ src/
230
+ │ ā”œā”€ā”€ index.ts # Main entry point + fullPipeline()
231
+ │ ā”œā”€ā”€ tools/
232
+ │ │ ā”œā”€ā”€ parse-resume.ts # Step 1-4 parsing engine
233
+ │ │ ā”œā”€ā”€ analyze-resume.ts # ATS scoring & analysis
234
+ │ │ └── suggest-improvements.ts # Fix suggestions generator
235
+ │ └── prompts/
236
+ │ ā”œā”€ā”€ parser-prompt.ts # Prompt templates for parsing
237
+ │ └── insights-prompt.ts # Prompt templates for insights
238
+ ā”œā”€ā”€ mcp-server/
239
+ │ └── server.ts # MCP server implementation
240
+ ā”œā”€ā”€ bin/
241
+ │ └── cli.js # CLI entry point
242
+ └── test/
243
+ └── evals/ # Evaluation test suites
244
+ ā”œā”€ā”€ parse-resume.test.js
245
+ ā”œā”€ā”€ analyze-resume.test.js
246
+ └── suggest-improvements.test.js
247
+ ```
248
+
249
+ ## 🧪 Testing
250
+
251
+ ```bash
252
+ # Run all tests
253
+ npm test
254
+
255
+ # Run evaluation suites
256
+ node --test test/evals/parse-resume.test.js
257
+ node --test test/evals/analyze-resume.test.js
258
+ node --test test/evals/suggest-improvements.test.js
259
+ ```
260
+
261
+ ## šŸ¤ Contributing
262
+
263
+ 1. Fork the repository
264
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
265
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
266
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
267
+ 5. Open a Pull Request
268
+
269
+ ## ā˜ļø CI/CD
270
+
271
+ This project uses GitHub Actions for continuous integration and npm publishing:
272
+
273
+ | Workflow | Trigger | What it does |
274
+ |----------|---------|-------------|
275
+ | **Build & Test** | Push/PR to `master` | Lint, build, and test across Node 18/20/22 |
276
+ | **Publish to npm** | Tag push `v*` (e.g. `v1.0.0`) | Builds and publishes to npmjs with provenance |
277
+
278
+ To publish a new version:
279
+
280
+ ```bash
281
+ npm version patch # or minor, major
282
+ git push --follow-tags
283
+ ```
284
+
285
+ ## šŸ“„ License
286
+
287
+ MIT License — Copyright (c) 2025 **Dhanush Kandhan**. See [LICENSE](./LICENSE) for details.
288
+
289
+ ---
290
+
291
+ <p align="center">
292
+ Made with ā¤ļø by <strong>Dhanush Kandhan</strong><br>
293
+ <em>If this project helped you, consider giving it a ⭐ on GitHub!</em>
294
+ </p>
package/bin/cli.js ADDED
@@ -0,0 +1,368 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Resume Parser — CLI Entry Point
5
+ *
6
+ * Usage:
7
+ * resume-parser parse <file|text> Parse a resume and output structured data
8
+ * resume-parser analyze <file|text> Parse + analyze ATS compatibility
9
+ * resume-parser insights <file|text> Full pipeline: parse + analyze + suggestions
10
+ */
11
+
12
+ const path = require("path");
13
+ const fs = require("fs");
14
+ const { parseResume } = require("../dist/src/tools/parse-resume");
15
+ const { analyzeResume } = require("../dist/src/tools/analyze-resume");
16
+ const { suggestImprovements } = require("../dist/src/tools/suggest-improvements");
17
+
18
+ // ---------------------------------------------------------------------------
19
+ // CLI argument parsing
20
+ // ---------------------------------------------------------------------------
21
+
22
+ function printUsage() {
23
+ console.log(`
24
+ Resume Parser CLI — Deep resume parsing with ATS insights
25
+
26
+ Usage:
27
+ resume-parser <command> <input> [options]
28
+
29
+ Commands:
30
+ parse <file|text> Parse a resume and output structured data
31
+ analyze <file|text> Parse + analyze ATS compatibility
32
+ insights <file|text> Full pipeline: parse + analyze + suggestions
33
+
34
+ Options:
35
+ --strictness <level> ATS strictness: lenient, moderate, strict (default: moderate)
36
+ --focus <areas> Focus areas: ats,content,formatting,structure (default: all)
37
+ --json Output raw JSON instead of formatted report
38
+ --help Show this help message
39
+
40
+ Examples:
41
+ resume-parser parse resume.pdf
42
+ resume-parser analyze resume.pdf --strictness strict
43
+ resume-parser insights resume.pdf --focus ats,formatting --json
44
+ resume-parser parse "John Doe\\njohn@email.com\\nSoftware Engineer"
45
+ `);
46
+ }
47
+
48
+ function main() {
49
+ const args = process.argv.slice(2);
50
+
51
+ if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
52
+ printUsage();
53
+ process.exit(0);
54
+ }
55
+
56
+ const command = args[0];
57
+ const inputArg = args[1];
58
+
59
+ if (!inputArg) {
60
+ console.error("Error: Please provide a file path or text input.");
61
+ printUsage();
62
+ process.exit(1);
63
+ }
64
+
65
+ // Parse options
66
+ const strictnessIdx = args.indexOf("--strictness");
67
+ const strictness = strictnessIdx >= 0 ? args[strictnessIdx + 1] : "moderate";
68
+
69
+ const focusIdx = args.indexOf("--focus");
70
+ const focusAreas = focusIdx >= 0
71
+ ? args[focusIdx + 1].split(",")
72
+ : ["ats", "content", "formatting", "structure"];
73
+
74
+ const jsonOutput = args.includes("--json");
75
+
76
+ // Determine input type: file path or raw text
77
+ let filePath;
78
+ let rawText;
79
+
80
+ if (fs.existsSync(inputArg)) {
81
+ filePath = path.resolve(inputArg);
82
+ } else {
83
+ rawText = inputArg.replace(/\\n/g, "\n");
84
+ }
85
+
86
+ // Execute command
87
+ switch (command) {
88
+ case "parse": {
89
+ const result = parseResume({ filePath, rawText });
90
+ if (jsonOutput) {
91
+ console.log(JSON.stringify(result, null, 2));
92
+ } else {
93
+ printParseResult(result);
94
+ }
95
+ break;
96
+ }
97
+
98
+ case "analyze": {
99
+ const parsed = parseResume({ filePath, rawText });
100
+ const analyzed = analyzeResume({
101
+ filePath,
102
+ rawText,
103
+ parsedResume: parsed.data,
104
+ strictness,
105
+ });
106
+ if (jsonOutput) {
107
+ console.log(JSON.stringify(analyzed, null, 2));
108
+ } else {
109
+ printAnalysisResult(analyzed);
110
+ }
111
+ break;
112
+ }
113
+
114
+ case "insights": {
115
+ const parsed = parseResume({ filePath, rawText });
116
+ const analyzed = analyzeResume({
117
+ filePath,
118
+ rawText,
119
+ parsedResume: parsed.data,
120
+ strictness,
121
+ });
122
+ const suggestions = suggestImprovements({
123
+ filePath,
124
+ rawText,
125
+ parsedResume: parsed.data,
126
+ analysisResult: analyzed.data,
127
+ focusAreas,
128
+ });
129
+ if (jsonOutput) {
130
+ console.log(JSON.stringify(suggestions, null, 2));
131
+ } else {
132
+ printInsightsResult(suggestions);
133
+ }
134
+ break;
135
+ }
136
+
137
+ default:
138
+ console.error("Unknown command: " + command);
139
+ printUsage();
140
+ process.exit(1);
141
+ }
142
+ }
143
+
144
+ // ---------------------------------------------------------------------------
145
+ // Formatted output helpers
146
+ // ---------------------------------------------------------------------------
147
+
148
+ function printParseResult(result) {
149
+ if (!result.success) {
150
+ console.log("āŒ Failed to parse resume");
151
+ console.log("Warnings:", result.metadata.warnings.join(", "));
152
+ return;
153
+ }
154
+
155
+ const { profile, education, experience, skills, projects } = result.data;
156
+
157
+ console.log("\nšŸ“„ Resume Parsing Results\n");
158
+ console.log("━".repeat(50));
159
+
160
+ // Profile
161
+ console.log("\n✨ Profile");
162
+ console.log("─".repeat(30));
163
+ console.log(" Name: " + (profile.name || "Not parsed"));
164
+ console.log(" Email: " + (profile.email || "Not parsed"));
165
+ console.log(" Phone: " + (profile.phone || "Not parsed"));
166
+ console.log(" Location: " + (profile.location || "Not parsed"));
167
+ console.log(" Link: " + (profile.url || "Not parsed"));
168
+
169
+ if (profile.summary) {
170
+ console.log(" Summary: " + profile.summary);
171
+ }
172
+
173
+ // Education
174
+ if (education.length > 0) {
175
+ console.log("\nšŸŽ“ Education");
176
+ console.log("─".repeat(30));
177
+ for (const edu of education) {
178
+ console.log(" School: " + (edu.school || "Not parsed"));
179
+ console.log(" Degree: " + (edu.degree || "Not parsed"));
180
+ console.log(" GPA: " + (edu.gpa || "Not parsed"));
181
+ console.log(" Date: " + (edu.date || "Not parsed"));
182
+ if (edu.descriptions.length > 0) {
183
+ console.log(" Descriptions: " + edu.descriptions.join("; "));
184
+ }
185
+ console.log();
186
+ }
187
+ }
188
+
189
+ // Work Experience
190
+ if (experience.length > 0) {
191
+ console.log("šŸ’¼ Work Experience");
192
+ console.log("─".repeat(30));
193
+ for (const exp of experience) {
194
+ console.log(" Company: " + (exp.company || "Not parsed"));
195
+ console.log(" Job Title: " + (exp.jobTitle || "Not parsed"));
196
+ console.log(" Date: " + (exp.date || "Not parsed"));
197
+ if (exp.descriptions.length > 0) {
198
+ console.log(" Descriptions:");
199
+ for (const d of exp.descriptions) {
200
+ console.log(" • " + d);
201
+ }
202
+ }
203
+ console.log();
204
+ }
205
+ }
206
+
207
+ // Skills
208
+ if (skills.length > 0) {
209
+ console.log("šŸ› ļø Skills");
210
+ console.log("─".repeat(30));
211
+ for (const skill of skills) {
212
+ for (const d of skill.descriptions) {
213
+ console.log(" • " + d);
214
+ }
215
+ }
216
+ }
217
+
218
+ // Projects
219
+ if (projects.length > 0) {
220
+ console.log("\nšŸš€ Projects");
221
+ console.log("─".repeat(30));
222
+ for (const proj of projects) {
223
+ console.log(" Name: " + (proj.name || "Not parsed"));
224
+ console.log(" Date: " + (proj.date || "Not parsed"));
225
+ if (proj.descriptions.length > 0) {
226
+ console.log(" Descriptions:");
227
+ for (const d of proj.descriptions) {
228
+ console.log(" • " + d);
229
+ }
230
+ }
231
+ console.log();
232
+ }
233
+ }
234
+
235
+ // Metadata
236
+ console.log("\n" + "━".repeat(50));
237
+ console.log("Steps completed: " + result.metadata.stepsCompleted.join(" → "));
238
+ if (result.metadata.warnings.length > 0) {
239
+ console.log("Warnings: " + result.metadata.warnings.join(", "));
240
+ }
241
+ }
242
+
243
+ function printAnalysisResult(result) {
244
+ if (!result.success) {
245
+ console.log("āŒ Failed to analyze resume");
246
+ return;
247
+ }
248
+
249
+ const { atsScore, atsGrade, fieldAnalyses, sectionAnalyses, overallNotes, formatIssues } = result.data;
250
+
251
+ console.log("\nšŸ“Š Resume Analysis Report\n");
252
+ console.log("━".repeat(50));
253
+ console.log("\nšŸŽÆ ATS Compatibility Score: " + atsScore + "/100 (Grade: " + atsGrade + ")\n");
254
+
255
+ // Field analyses
256
+ console.log("šŸ“‹ Field Extraction Analysis");
257
+ console.log("─".repeat(40));
258
+ for (const field of fieldAnalyses) {
259
+ let icon = "āŒ";
260
+ if (field.confidence === "high") icon = "āœ…";
261
+ else if (field.confidence === "medium") icon = "āš ļø";
262
+ else if (field.confidence === "low") icon = "šŸ”¶";
263
+ const val = field.value || "Not parsed";
264
+ console.log(" " + icon + " " + field.field.padEnd(12) + " | " + val.padEnd(30) + " | " + field.confidence);
265
+ }
266
+
267
+ // Section analyses
268
+ console.log("\nšŸ“‘ Section Detection");
269
+ console.log("─".repeat(40));
270
+ for (const section of sectionAnalyses) {
271
+ const icon = section.detected ? "āœ…" : "āŒ";
272
+ const issues = section.issues.length > 0 ? section.issues.join(", ") : "OK";
273
+ console.log(" " + icon + " " + section.section.padEnd(25) + " | Lines: " + section.lineCount + " | " + issues);
274
+ }
275
+
276
+ // Format issues
277
+ if (formatIssues.length > 0) {
278
+ console.log("\nāš ļø Format Issues");
279
+ console.log("─".repeat(40));
280
+ for (const issue of formatIssues) {
281
+ let severityIcon = "🟢";
282
+ if (issue.severity === "critical") severityIcon = "šŸ”“";
283
+ else if (issue.severity === "high") severityIcon = "🟠";
284
+ else if (issue.severity === "medium") severityIcon = "🟔";
285
+ console.log(" " + severityIcon + " [" + issue.severity.toUpperCase() + "] " + issue.description);
286
+ console.log(" Affected: " + issue.affectedFields.join(", "));
287
+ console.log(" Fix: " + issue.suggestion);
288
+ }
289
+ }
290
+
291
+ // Overall notes
292
+ console.log("\nšŸ“ Overall Notes");
293
+ console.log("─".repeat(40));
294
+ for (const note of overallNotes) {
295
+ console.log(" • " + note);
296
+ }
297
+
298
+ console.log("\n" + "━".repeat(50));
299
+ }
300
+
301
+ function printInsightsResult(result) {
302
+ const { overallScore, overallGrade, criticalFixes, totalSuggestions, suggestions, sectionSuggestions, quickWins, longTermAdvice } = result.data;
303
+
304
+ console.log("\nšŸ” Resume Insights Report\n");
305
+ console.log("━".repeat(50));
306
+ console.log("\nšŸŽÆ ATS Compatibility Score: " + overallScore + "/100 (Grade: " + overallGrade + ")");
307
+ console.log("šŸ”“ Critical fixes needed: " + criticalFixes);
308
+ console.log("šŸ“ Total suggestions: " + totalSuggestions + "\n");
309
+
310
+ // Quick wins
311
+ if (quickWins.length > 0) {
312
+ console.log("⚔ Quick Wins (fix these first):");
313
+ console.log("─".repeat(40));
314
+ for (let i = 0; i < quickWins.length; i++) {
315
+ console.log(" " + (i + 1) + ". " + quickWins[i]);
316
+ }
317
+ console.log();
318
+ }
319
+
320
+ // All suggestions
321
+ if (suggestions.length > 0) {
322
+ console.log("šŸ“‹ All Suggestions (sorted by priority):");
323
+ console.log("─".repeat(40));
324
+ for (const sug of suggestions) {
325
+ let icon = "🟢";
326
+ if (sug.priority === "critical") icon = "šŸ”“";
327
+ else if (sug.priority === "high") icon = "🟠";
328
+ else if (sug.priority === "medium") icon = "🟔";
329
+ console.log("\n " + icon + " [" + sug.priority.toUpperCase() + "] " + sug.title);
330
+ console.log(" Field: " + sug.field);
331
+ console.log(" Issue: " + sug.description);
332
+ console.log(" Current: " + (sug.currentValue || "Not parsed"));
333
+ console.log(" Suggested: " + sug.suggestedValue);
334
+ console.log(" Why: " + sug.rationale);
335
+ }
336
+ console.log();
337
+ }
338
+
339
+ // Section suggestions
340
+ console.log("šŸ“‘ Section Status:");
341
+ console.log("─".repeat(40));
342
+ for (const section of sectionSuggestions) {
343
+ const icon = section.present ? "āœ…" : "āŒ";
344
+ console.log(" " + icon + " " + section.section);
345
+ if (section.issues.length > 0) {
346
+ for (const issue of section.issues) {
347
+ console.log(" āš ļø " + issue);
348
+ }
349
+ }
350
+ if (section.recommendations.length > 0) {
351
+ for (const rec of section.recommendations) {
352
+ console.log(" šŸ’” " + rec);
353
+ }
354
+ }
355
+ }
356
+
357
+ // Long-term advice
358
+ console.log("\n🌟 Long-term Improvement Advice:");
359
+ console.log("─".repeat(40));
360
+ for (const advice of longTermAdvice) {
361
+ console.log(" • " + advice);
362
+ }
363
+
364
+ console.log("\n" + "━".repeat(50));
365
+ }
366
+
367
+ // Run
368
+ main();
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Resume Parser — MCP Server
3
+ *
4
+ * Exposes the resume parsing, analysis, and suggestion tools
5
+ * via the Model Context Protocol (MCP).
6
+ *
7
+ * Tools:
8
+ * - parse_resume: Parse a resume PDF/text and return structured data
9
+ * - analyze_resume: Parse + compute ATS compatibility score
10
+ * - suggest_improvements: Generate actionable fix suggestions
11
+ *
12
+ * Usage:
13
+ * npm run mcp
14
+ *
15
+ * The server communicates via stdio using the MCP protocol.
16
+ */
17
+ export {};
18
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../mcp-server/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG"}