@getkrafter/resume-toolkit 1.0.4 → 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/dist/bin/cli.js CHANGED
@@ -1,4 +1,61 @@
1
1
  #!/usr/bin/env node
2
2
  import { startServer } from '../mcp/server.js';
3
- startServer();
3
+ import { scoreResume } from '../lib/resume-scorer.js';
4
+ import { scoreATS } from '../lib/ats-scorer.js';
5
+ const args = process.argv.slice(2);
6
+ const command = args[0];
7
+ if (command === 'score') {
8
+ const resumeFile = getFlag(args, '--resume');
9
+ const jdFile = getFlag(args, '--jd');
10
+ if (!resumeFile) {
11
+ console.error('Usage: resume-toolkit score --resume <file> [--jd <file>]');
12
+ process.exit(1);
13
+ }
14
+ const fs = await import('node:fs');
15
+ const resumeText = fs.readFileSync(resumeFile, 'utf-8');
16
+ const jdText = jdFile ? fs.readFileSync(jdFile, 'utf-8') : undefined;
17
+ const resumeData = parseRawText(resumeText);
18
+ const result = scoreResume(resumeData, jdText);
19
+ console.log(JSON.stringify(result, null, 2));
20
+ }
21
+ else if (command === 'ats') {
22
+ const resumeFile = getFlag(args, '--resume');
23
+ const jdFile = getFlag(args, '--jd');
24
+ if (!resumeFile || !jdFile) {
25
+ console.error('Usage: resume-toolkit ats --resume <file> --jd <file>');
26
+ process.exit(1);
27
+ }
28
+ const fs = await import('node:fs');
29
+ const resumeText = fs.readFileSync(resumeFile, 'utf-8');
30
+ const jdText = fs.readFileSync(jdFile, 'utf-8');
31
+ const result = scoreATS(resumeText, jdText);
32
+ console.log(JSON.stringify(result, null, 2));
33
+ }
34
+ else {
35
+ // Default: start MCP server
36
+ startServer();
37
+ }
38
+ function getFlag(args, flag) {
39
+ const idx = args.indexOf(flag);
40
+ return idx !== -1 && idx + 1 < args.length ? args[idx + 1] : undefined;
41
+ }
42
+ function parseRawText(text) {
43
+ const lines = text.split('\n');
44
+ const bullets = [];
45
+ const sections = [];
46
+ for (const line of lines) {
47
+ const trimmed = line.trim();
48
+ if (!trimmed)
49
+ continue;
50
+ if (/^\s*[-*•]\s+/.test(line) || /^\s*\d+[.)]\s+/.test(line)) {
51
+ bullets.push(trimmed.replace(/^[-*•]\s+/, '').replace(/^\d+[.)]\s+/, ''));
52
+ }
53
+ else if (trimmed.length < 50 &&
54
+ (trimmed === trimmed.toUpperCase() || /^[A-Z][a-z]/.test(trimmed)) &&
55
+ !/^\s*[-*•]|\d+[.)]/.test(trimmed)) {
56
+ sections.push(trimmed.toLowerCase());
57
+ }
58
+ }
59
+ return { rawText: text, bullets, sections };
60
+ }
4
61
  //# sourceMappingURL=cli.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/bin/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/bin/cli.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getkrafter/resume-toolkit",
3
- "version": "1.0.4",
3
+ "version": "1.1.0",
4
4
  "description": "Deterministic resume scoring, ATS keyword matching, and AI-powered resume tailoring",
5
5
  "type": "module",
6
6
  "exports": {
@@ -69,9 +69,11 @@ You do NOT need to do this manually. The `score_resume` MCP tool handles parsing
69
69
 
70
70
  ---
71
71
 
72
- ## Step 5 — Call the Scoring Tool
72
+ ## Step 5 — Score the Resume
73
73
 
74
- **Standard path** (pasted text or file):
74
+ Choose the method that matches your environment:
75
+
76
+ **Option A — MCP tools available** (user has the MCP server configured):
75
77
 
76
78
  Call the `score_resume` MCP tool:
77
79
  ```json
@@ -81,9 +83,7 @@ Call the `score_resume` MCP tool:
81
83
  }
82
84
  ```
83
85
 
84
- **Krafter path** (user selected a Krafter resume):
85
-
86
- Call the `score_krafter_resume` MCP tool:
86
+ Or for Krafter resumes, call `score_krafter_resume`:
87
87
  ```json
88
88
  {
89
89
  "id": "<the resume ID from list_resumes>",
@@ -91,6 +91,22 @@ Call the `score_krafter_resume` MCP tool:
91
91
  }
92
92
  ```
93
93
 
94
+ **Option B — CLI** (no MCP server needed):
95
+
96
+ 1. Write the resume text to a temp file (e.g., `/tmp/resume.txt`).
97
+ 2. If a JD was provided, write it to another temp file (e.g., `/tmp/jd.txt`).
98
+ 3. Run:
99
+
100
+ ```bash
101
+ # Without JD:
102
+ npx @getkrafter/resume-toolkit score --resume /tmp/resume.txt
103
+
104
+ # With JD:
105
+ npx @getkrafter/resume-toolkit score --resume /tmp/resume.txt --jd /tmp/jd.txt
106
+ ```
107
+
108
+ The output is a JSON `ResumeScore` object. Parse it and present results per Step 6.
109
+
94
110
  ---
95
111
 
96
112
  ## Step 6 — Present the Results
@@ -56,27 +56,31 @@ transformation internally via `toResumeData`.
56
56
 
57
57
  ### Step 4 -- Run Scoring Tools
58
58
 
59
- Run **both** scoring tools to get the full picture:
59
+ Run **both** scoring tools to get the full picture. Choose the method that matches your environment:
60
60
 
61
- **For pasted/file resumes:**
61
+ **Option A — MCP tools available** (user has the MCP server configured):
62
62
 
63
- 1. `score_ats` with `{ resumeText, jdText }` -- returns `ATSResult` with:
64
- - `score` (0-100)
65
- - `matched` keywords (array)
66
- - `missing` keywords (array)
67
- - `details.bigramsMatched`, `details.unigramsMatched`, `details.bigramsMissing`, `details.unigramsMissing`
63
+ For pasted/file resumes:
64
+ 1. `score_ats` with `{ resumeText, jdText }` -- returns `ATSResult` with `score`, `matched`, `missing`, and `details` breakdown.
65
+ 2. `score_resume` with `{ resumeText, jdText }` -- returns `ResumeScore` with `total`, `mode`, `breakdown`, `ats`, and `flags`.
68
66
 
69
- 2. `score_resume` with `{ resumeText, jdText }` -- returns `ResumeScore` with:
70
- - `total` (0-100)
71
- - `mode` ("with-jd")
72
- - `breakdown` per dimension (quantification, verbStrength, ats, bulletStructure, sectionCompleteness)
73
- - `ats` (embedded ATSResult)
74
- - `flags` (diagnostic messages)
67
+ For Krafter resumes:
68
+ 1. `score_krafter_resume` with `{ id, jdText }` -- returns the full `ResumeScore` including the embedded `ATSResult`.
75
69
 
76
- **For Krafter resumes:**
70
+ **Option B — CLI** (no MCP server needed):
77
71
 
78
- 1. `score_krafter_resume` with `{ id, jdText }` -- returns the full `ResumeScore` including the embedded `ATSResult`.
79
- 2. Optionally also call `score_ats` directly if you need the standalone ATS breakdown.
72
+ 1. Write the resume text to `/tmp/resume.txt` and the JD to `/tmp/jd.txt`.
73
+ 2. Run both commands:
74
+
75
+ ```bash
76
+ # Full score with ATS:
77
+ npx @getkrafter/resume-toolkit score --resume /tmp/resume.txt --jd /tmp/jd.txt
78
+
79
+ # Standalone ATS analysis:
80
+ npx @getkrafter/resume-toolkit ats --resume /tmp/resume.txt --jd /tmp/jd.txt
81
+ ```
82
+
83
+ Parse the JSON output from each command and continue to Step 5.
80
84
 
81
85
  ### Step 5 -- Gap Analysis
82
86