resuml 3.0.0 → 3.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/bin/resuml +3 -2
- package/dist/ats/index.d.ts +83 -0
- package/dist/ats/index.js +8 -0
- package/dist/ats/index.js.map +1 -0
- package/dist/chunk-G4AN2EMI.js +461 -0
- package/dist/chunk-G4AN2EMI.js.map +1 -0
- package/dist/chunk-M6JY5UDJ.js +778 -0
- package/dist/chunk-M6JY5UDJ.js.map +1 -0
- package/dist/chunk-N55EPZ2N.js +1836 -0
- package/dist/chunk-N55EPZ2N.js.map +1 -0
- package/dist/{chunk-R4MD5YMV.js → chunk-QR77BRMN.js} +154 -2434
- package/dist/chunk-QR77BRMN.js.map +1 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +24 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +4 -424
- package/dist/index.js +10 -775
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +6 -3
- package/dist/mcp/server.js.map +1 -1
- package/dist/skills/index.d.ts +67 -0
- package/dist/skills/index.js +13 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/types/index.d.ts +343 -0
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +28 -3
- package/dist/chunk-R4MD5YMV.js.map +0 -1
- package/src/types/resume.ts +0 -344
- package/src/types/schema.d.ts +0 -6
package/bin/resuml
CHANGED
|
@@ -6,13 +6,14 @@ import { dirname, join } from 'path';
|
|
|
6
6
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
7
7
|
|
|
8
8
|
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
9
|
-
const distPath = join(currentDir, '../dist/
|
|
9
|
+
const distPath = join(currentDir, '../dist/cli.js');
|
|
10
10
|
|
|
11
11
|
try {
|
|
12
12
|
if (!existsSync(distPath)) {
|
|
13
13
|
throw new Error('CLI not built. Please run "npm run build" first.');
|
|
14
14
|
}
|
|
15
|
-
await import(pathToFileURL(distPath).href);
|
|
15
|
+
const { main } = await import(pathToFileURL(distPath).href);
|
|
16
|
+
await main();
|
|
16
17
|
} catch (err) {
|
|
17
18
|
console.error('Error starting resuml CLI:', err);
|
|
18
19
|
process.exit(1);
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Resume as ResumeSchema } from '../types/index.js';
|
|
2
|
+
|
|
3
|
+
type Tier = 'parsing' | 'match' | 'recruiter';
|
|
4
|
+
type AtsCheckWeight = 'high' | 'medium' | 'low';
|
|
5
|
+
type AtsRating = 'excellent' | 'good' | 'needs-work' | 'poor';
|
|
6
|
+
type CheckStatus = 'pass' | 'warn' | 'fail' | 'skipped';
|
|
7
|
+
type Grade = 'A' | 'B' | 'C' | 'D' | 'F';
|
|
8
|
+
interface CheckResult {
|
|
9
|
+
id: string;
|
|
10
|
+
tier: Tier;
|
|
11
|
+
status: CheckStatus;
|
|
12
|
+
score: number;
|
|
13
|
+
weight: AtsCheckWeight;
|
|
14
|
+
message: string;
|
|
15
|
+
hints: string[];
|
|
16
|
+
}
|
|
17
|
+
interface TierResult {
|
|
18
|
+
score: number;
|
|
19
|
+
grade: Grade;
|
|
20
|
+
checks: CheckResult[];
|
|
21
|
+
}
|
|
22
|
+
interface KnockoutSignal {
|
|
23
|
+
signal: string;
|
|
24
|
+
evidence: string;
|
|
25
|
+
recommendation: string;
|
|
26
|
+
}
|
|
27
|
+
interface TieredAtsResult {
|
|
28
|
+
score: number;
|
|
29
|
+
rating: AtsRating;
|
|
30
|
+
tiers: {
|
|
31
|
+
parsing: TierResult;
|
|
32
|
+
match?: TierResult;
|
|
33
|
+
recruiter: TierResult;
|
|
34
|
+
};
|
|
35
|
+
knockouts: KnockoutSignal[];
|
|
36
|
+
summary: string;
|
|
37
|
+
}
|
|
38
|
+
interface AtsOptions {
|
|
39
|
+
language?: string;
|
|
40
|
+
jobDescription?: string;
|
|
41
|
+
threshold?: number;
|
|
42
|
+
config?: AtsConfig;
|
|
43
|
+
}
|
|
44
|
+
interface AtsConfig {
|
|
45
|
+
weights: {
|
|
46
|
+
tiers: {
|
|
47
|
+
parsing: number;
|
|
48
|
+
match: number;
|
|
49
|
+
recruiter: number;
|
|
50
|
+
};
|
|
51
|
+
checks: Record<string, AtsCheckWeight>;
|
|
52
|
+
};
|
|
53
|
+
thresholds: {
|
|
54
|
+
rating: {
|
|
55
|
+
excellent: number;
|
|
56
|
+
good: number;
|
|
57
|
+
needsWork: number;
|
|
58
|
+
};
|
|
59
|
+
grade: {
|
|
60
|
+
A: number;
|
|
61
|
+
B: number;
|
|
62
|
+
C: number;
|
|
63
|
+
D: number;
|
|
64
|
+
};
|
|
65
|
+
seniorYoeCutoff: number;
|
|
66
|
+
wordCount: {
|
|
67
|
+
min: number;
|
|
68
|
+
max: number;
|
|
69
|
+
seniorMax: number;
|
|
70
|
+
};
|
|
71
|
+
bulletsPerRole: {
|
|
72
|
+
min: number;
|
|
73
|
+
max: number;
|
|
74
|
+
seniorMax: number;
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
disable: string[];
|
|
78
|
+
locale: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
declare function analyzeAts(resume: ResumeSchema, options?: AtsOptions): TieredAtsResult;
|
|
82
|
+
|
|
83
|
+
export { type AtsOptions, type CheckResult, type KnockoutSignal, type TierResult, type TieredAtsResult, analyzeAts };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
// src/core.ts
|
|
2
|
+
import { parse } from "yaml";
|
|
3
|
+
import merge from "lodash.merge";
|
|
4
|
+
import { validate } from "@jsonresume/schema";
|
|
5
|
+
async function processResumeData(yamlContents) {
|
|
6
|
+
if (yamlContents.length === 0) {
|
|
7
|
+
throw new Error("No YAML content provided for processing.");
|
|
8
|
+
}
|
|
9
|
+
const dataObjects = yamlContents.map((content) => {
|
|
10
|
+
try {
|
|
11
|
+
return parse(content);
|
|
12
|
+
} catch (error) {
|
|
13
|
+
console.warn("Failed to parse YAML content:", error);
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}).filter((data) => typeof data === "object" && data !== null);
|
|
17
|
+
if (dataObjects.length === 0) {
|
|
18
|
+
throw new Error("No valid YAML content found after parsing.");
|
|
19
|
+
}
|
|
20
|
+
const customizer = (objValue, srcValue) => {
|
|
21
|
+
if (Array.isArray(objValue)) {
|
|
22
|
+
return objValue.concat(srcValue);
|
|
23
|
+
}
|
|
24
|
+
return void 0;
|
|
25
|
+
};
|
|
26
|
+
const mergedData = dataObjects.reduce((acc, data) => merge(acc, data, customizer), {});
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
validate(mergedData, (errors, isValid) => {
|
|
29
|
+
if (!isValid) {
|
|
30
|
+
reject(
|
|
31
|
+
new Error(`Resume data failed schema validation: ${JSON.stringify(errors, null, 2)}`)
|
|
32
|
+
);
|
|
33
|
+
} else {
|
|
34
|
+
resolve(mergedData);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// src/utils/themeLoader.ts
|
|
41
|
+
import { execFileSync } from "child_process";
|
|
42
|
+
import { createRequire } from "module";
|
|
43
|
+
var require2 = createRequire(import.meta.url);
|
|
44
|
+
function installTheme(packageName) {
|
|
45
|
+
try {
|
|
46
|
+
execFileSync("npm", ["install", packageName], {
|
|
47
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
48
|
+
encoding: "utf8"
|
|
49
|
+
});
|
|
50
|
+
} catch (error) {
|
|
51
|
+
throw new Error(`Failed to install ${packageName}: ${error.message}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function loadTheme(themeName, options) {
|
|
55
|
+
let jsonResumeThemeName;
|
|
56
|
+
let nativeThemeName;
|
|
57
|
+
const autoInstall = options?.autoInstall !== false;
|
|
58
|
+
try {
|
|
59
|
+
jsonResumeThemeName = themeName.startsWith("jsonresume-theme-") ? themeName : `jsonresume-theme-${themeName}`;
|
|
60
|
+
try {
|
|
61
|
+
return require2(jsonResumeThemeName);
|
|
62
|
+
} catch (_jsonResumeError) {
|
|
63
|
+
nativeThemeName = `@resuml/theme-${themeName}`;
|
|
64
|
+
try {
|
|
65
|
+
return require2(nativeThemeName);
|
|
66
|
+
} catch (_nativeError) {
|
|
67
|
+
if (!autoInstall) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`Theme package ${jsonResumeThemeName} or ${nativeThemeName} not found in node_modules.
|
|
70
|
+
Please install the theme package manually.`
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
console.log(`\u{1F4E6} Theme ${jsonResumeThemeName} not found. Installing...`);
|
|
74
|
+
try {
|
|
75
|
+
installTheme(jsonResumeThemeName);
|
|
76
|
+
console.log(`\u2705 Successfully installed ${jsonResumeThemeName}`);
|
|
77
|
+
return require2(jsonResumeThemeName);
|
|
78
|
+
} catch (installError) {
|
|
79
|
+
throw new Error(
|
|
80
|
+
`Failed to auto-install theme ${jsonResumeThemeName}: ${installError.message}`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
} catch (error) {
|
|
86
|
+
if (error instanceof Error && error.message.includes("Failed to auto-install")) {
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
throw new Error(`Theme package ${themeName} not found`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/utils/resumeTemplate.ts
|
|
94
|
+
function generateResumeYaml(name, email, label) {
|
|
95
|
+
return `# =============================================================================
|
|
96
|
+
# Resume - Generated by resuml
|
|
97
|
+
# Documentation: https://github.com/phoinixi/resuml
|
|
98
|
+
# Schema: https://jsonresume.org/schema/
|
|
99
|
+
# =============================================================================
|
|
100
|
+
|
|
101
|
+
# --- Basic Information ---
|
|
102
|
+
basics:
|
|
103
|
+
name: '${name}'
|
|
104
|
+
label: '${label}'
|
|
105
|
+
# image: 'https://example.com/photo.jpg'
|
|
106
|
+
email: '${email}'
|
|
107
|
+
# phone: '+1-555-123-4567'
|
|
108
|
+
# url: 'https://yourwebsite.com'
|
|
109
|
+
summary: >-
|
|
110
|
+
Write a short professional summary here.
|
|
111
|
+
This supports multi-line strings in YAML.
|
|
112
|
+
location:
|
|
113
|
+
# address: '123 Main Street'
|
|
114
|
+
# postalCode: '12345'
|
|
115
|
+
city: 'Your City'
|
|
116
|
+
countryCode: 'US'
|
|
117
|
+
# region: 'Your State'
|
|
118
|
+
profiles:
|
|
119
|
+
- network: 'LinkedIn'
|
|
120
|
+
username: 'your-username'
|
|
121
|
+
url: 'https://linkedin.com/in/your-username'
|
|
122
|
+
- network: 'GitHub'
|
|
123
|
+
username: 'your-username'
|
|
124
|
+
url: 'https://github.com/your-username'
|
|
125
|
+
|
|
126
|
+
# --- Work Experience ---
|
|
127
|
+
work:
|
|
128
|
+
- name: 'Company Name'
|
|
129
|
+
position: 'Job Title'
|
|
130
|
+
url: 'https://company.com'
|
|
131
|
+
startDate: '2020-01-01'
|
|
132
|
+
# endDate: '2023-12-31' # Omit for current position
|
|
133
|
+
summary: 'Brief description of your role and responsibilities.'
|
|
134
|
+
highlights:
|
|
135
|
+
- 'Key achievement or responsibility'
|
|
136
|
+
- 'Another notable accomplishment'
|
|
137
|
+
|
|
138
|
+
# --- Education ---
|
|
139
|
+
education:
|
|
140
|
+
- institution: 'University Name'
|
|
141
|
+
url: 'https://university.edu'
|
|
142
|
+
area: 'Field of Study'
|
|
143
|
+
studyType: 'Bachelor of Science'
|
|
144
|
+
startDate: '2014-09-01'
|
|
145
|
+
endDate: '2018-06-01'
|
|
146
|
+
# score: '3.8'
|
|
147
|
+
courses:
|
|
148
|
+
- 'Relevant Course 1'
|
|
149
|
+
- 'Relevant Course 2'
|
|
150
|
+
|
|
151
|
+
# --- Skills ---
|
|
152
|
+
skills:
|
|
153
|
+
- name: 'Programming Languages'
|
|
154
|
+
level: 'Expert'
|
|
155
|
+
keywords:
|
|
156
|
+
- 'JavaScript'
|
|
157
|
+
- 'TypeScript'
|
|
158
|
+
- 'Python'
|
|
159
|
+
- name: 'Frameworks'
|
|
160
|
+
level: 'Advanced'
|
|
161
|
+
keywords:
|
|
162
|
+
- 'React'
|
|
163
|
+
- 'Node.js'
|
|
164
|
+
|
|
165
|
+
# --- Projects ---
|
|
166
|
+
# projects:
|
|
167
|
+
# - name: 'Project Name'
|
|
168
|
+
# description: 'Brief project description'
|
|
169
|
+
# highlights:
|
|
170
|
+
# - 'Key feature or result'
|
|
171
|
+
# keywords:
|
|
172
|
+
# - 'Technology Used'
|
|
173
|
+
# startDate: '2023-01-01'
|
|
174
|
+
# endDate: '2023-06-30'
|
|
175
|
+
# url: 'https://github.com/you/project'
|
|
176
|
+
# roles:
|
|
177
|
+
# - 'Developer'
|
|
178
|
+
# type: 'application'
|
|
179
|
+
|
|
180
|
+
# --- Languages ---
|
|
181
|
+
# languages:
|
|
182
|
+
# - language: 'English'
|
|
183
|
+
# fluency: 'Native speaker'
|
|
184
|
+
# - language: 'Spanish'
|
|
185
|
+
# fluency: 'Professional working proficiency'
|
|
186
|
+
|
|
187
|
+
# --- Interests ---
|
|
188
|
+
# interests:
|
|
189
|
+
# - name: 'Open Source'
|
|
190
|
+
# keywords:
|
|
191
|
+
# - 'Contributing'
|
|
192
|
+
# - 'Community'
|
|
193
|
+
|
|
194
|
+
# --- References ---
|
|
195
|
+
# references:
|
|
196
|
+
# - name: 'Jane Smith'
|
|
197
|
+
# reference: 'It was a pleasure working with...'
|
|
198
|
+
|
|
199
|
+
# --- Awards ---
|
|
200
|
+
# awards:
|
|
201
|
+
# - title: 'Award Name'
|
|
202
|
+
# date: '2023-01-01'
|
|
203
|
+
# awarder: 'Organization'
|
|
204
|
+
# summary: 'Description of the award'
|
|
205
|
+
|
|
206
|
+
# --- Certificates ---
|
|
207
|
+
# certificates:
|
|
208
|
+
# - name: 'Certificate Name'
|
|
209
|
+
# date: '2023-01-01'
|
|
210
|
+
# issuer: 'Issuing Organization'
|
|
211
|
+
# url: 'https://example.com/cert'
|
|
212
|
+
|
|
213
|
+
# --- Publications ---
|
|
214
|
+
# publications:
|
|
215
|
+
# - name: 'Publication Title'
|
|
216
|
+
# publisher: 'Publisher'
|
|
217
|
+
# releaseDate: '2023-01-01'
|
|
218
|
+
# url: 'https://example.com/publication'
|
|
219
|
+
# summary: 'Brief description'
|
|
220
|
+
|
|
221
|
+
# --- Volunteer ---
|
|
222
|
+
# volunteers:
|
|
223
|
+
# - organization: 'Organization Name'
|
|
224
|
+
# position: 'Volunteer Role'
|
|
225
|
+
# url: 'https://organization.com'
|
|
226
|
+
# startDate: '2022-01-01'
|
|
227
|
+
# summary: 'Description of volunteer work'
|
|
228
|
+
# highlights:
|
|
229
|
+
# - 'Notable contribution'
|
|
230
|
+
`;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// src/utils/themeInfo.ts
|
|
234
|
+
import { createRequire as createRequire2 } from "module";
|
|
235
|
+
var KNOWN_THEMES = [
|
|
236
|
+
{
|
|
237
|
+
name: "stackoverflow",
|
|
238
|
+
pkg: "jsonresume-theme-stackoverflow",
|
|
239
|
+
description: "Stack Overflow inspired theme"
|
|
240
|
+
},
|
|
241
|
+
{ name: "elegant", pkg: "jsonresume-theme-elegant", description: "Elegant and professional" },
|
|
242
|
+
{ name: "react", pkg: "jsonresume-theme-react", description: "Built with React components" },
|
|
243
|
+
{ name: "even", pkg: "jsonresume-theme-even", description: "Clean and minimal" },
|
|
244
|
+
{ name: "kendall", pkg: "jsonresume-theme-kendall", description: "Simple and clean layout" },
|
|
245
|
+
{ name: "macchiato", pkg: "jsonresume-theme-macchiato", description: "Beautiful and modern" },
|
|
246
|
+
{ name: "flat", pkg: "jsonresume-theme-flat", description: "Flat design theme" },
|
|
247
|
+
{ name: "class", pkg: "jsonresume-theme-class", description: "Classic professional look" },
|
|
248
|
+
{ name: "short", pkg: "jsonresume-theme-short", description: "Compact single-page resume" },
|
|
249
|
+
{ name: "spartan", pkg: "jsonresume-theme-spartan", description: "Minimalist Spartan design" },
|
|
250
|
+
{ name: "paper", pkg: "jsonresume-theme-paper", description: "Paper-like clean design" },
|
|
251
|
+
{ name: "onepage", pkg: "jsonresume-theme-onepage", description: "One page resume layout" }
|
|
252
|
+
];
|
|
253
|
+
function isThemeInstalled(pkg) {
|
|
254
|
+
try {
|
|
255
|
+
const req = createRequire2(process.cwd() + "/");
|
|
256
|
+
req.resolve(pkg);
|
|
257
|
+
return true;
|
|
258
|
+
} catch {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function getInstalledVersion(pkg) {
|
|
263
|
+
try {
|
|
264
|
+
const req = createRequire2(process.cwd() + "/");
|
|
265
|
+
const pkgJson = req(`${pkg}/package.json`);
|
|
266
|
+
return pkgJson.version ?? null;
|
|
267
|
+
} catch {
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// src/ats/rubric.ts
|
|
273
|
+
var rubric = [
|
|
274
|
+
// Parsing tier - Greenhouse-doc-grounded
|
|
275
|
+
{
|
|
276
|
+
id: "conventional-sections",
|
|
277
|
+
tier: "parsing",
|
|
278
|
+
weight: "high",
|
|
279
|
+
evidenceLevel: "evidence",
|
|
280
|
+
description: "Required JSON Resume sections (basics, work, education) are present.",
|
|
281
|
+
source: "https://support.greenhouse.io/hc/en-us/articles/200989175-Unsuccessful-resume-parse"
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
id: "date-format-consistency",
|
|
285
|
+
tier: "parsing",
|
|
286
|
+
weight: "medium",
|
|
287
|
+
evidenceLevel: "evidence",
|
|
288
|
+
description: "Dates use ISO-8601 (YYYY-MM-DD or YYYY-MM); no mixed formats; no >6mo gaps.",
|
|
289
|
+
source: "https://hireflow.net/blog/taleo-resume-parsing-problems-explained"
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
id: "contact-in-body",
|
|
293
|
+
tier: "parsing",
|
|
294
|
+
weight: "high",
|
|
295
|
+
evidenceLevel: "evidence",
|
|
296
|
+
description: "Email and phone present in basics block (parseable by Textkernel/Sovren).",
|
|
297
|
+
source: "https://developer.textkernel.com/tx-platform/v10/faq/"
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
id: "reverse-chron-order",
|
|
301
|
+
tier: "parsing",
|
|
302
|
+
weight: "medium",
|
|
303
|
+
evidenceLevel: "evidence",
|
|
304
|
+
description: "work[] and education[] sorted descending by startDate."
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
id: "education-complete",
|
|
308
|
+
tier: "parsing",
|
|
309
|
+
weight: "low",
|
|
310
|
+
evidenceLevel: "evidence",
|
|
311
|
+
description: "Each education entry has institution, area, and studyType."
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
id: "pdf-text-extractable",
|
|
315
|
+
tier: "parsing",
|
|
316
|
+
weight: "high",
|
|
317
|
+
evidenceLevel: "evidence",
|
|
318
|
+
description: "Rendered PDF body text is selectable (>=70% of resume word count extractable).",
|
|
319
|
+
source: "https://www.ashbyhq.com/product-updates/ai-assisted-application-review"
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
id: "pdf-size-under-2.5mb",
|
|
323
|
+
tier: "parsing",
|
|
324
|
+
weight: "medium",
|
|
325
|
+
evidenceLevel: "evidence",
|
|
326
|
+
description: "Rendered PDF is under 2.5 MB (Greenhouse documented limit).",
|
|
327
|
+
source: "https://support.greenhouse.io/hc/en-us/articles/200989175-Unsuccessful-resume-parse"
|
|
328
|
+
},
|
|
329
|
+
// Match tier - JD-aware
|
|
330
|
+
{
|
|
331
|
+
id: "hard-skill-overlap",
|
|
332
|
+
tier: "match",
|
|
333
|
+
weight: "high",
|
|
334
|
+
evidenceLevel: "evidence",
|
|
335
|
+
description: "Hard skill overlap with JD using bundled O*NET-trie skill index. ESCO migration tracked separately."
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
id: "title-alignment",
|
|
339
|
+
tier: "match",
|
|
340
|
+
weight: "high",
|
|
341
|
+
evidenceLevel: "evidence",
|
|
342
|
+
description: "Most-recent work[].position aligns with JD title via token Jaccard after stripping seniority modifiers."
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
id: "education-level",
|
|
346
|
+
tier: "match",
|
|
347
|
+
weight: "medium",
|
|
348
|
+
evidenceLevel: "evidence",
|
|
349
|
+
description: "Max studyType meets/exceeds JD education requirement (Bachelor/Master/PhD detection)."
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
id: "yoe-match",
|
|
353
|
+
tier: "match",
|
|
354
|
+
weight: "high",
|
|
355
|
+
evidenceLevel: "evidence",
|
|
356
|
+
description: "Total years of experience (overlap-merged from work[]) meets JD years requirement."
|
|
357
|
+
},
|
|
358
|
+
// Recruiter tier - Rezi/Teal/Enhancv-grounded numbers
|
|
359
|
+
{
|
|
360
|
+
id: "summary-length",
|
|
361
|
+
tier: "recruiter",
|
|
362
|
+
weight: "medium",
|
|
363
|
+
evidenceLevel: "convention",
|
|
364
|
+
description: "Professional summary 20-50 words / 2-4 sentences.",
|
|
365
|
+
source: "https://www.rezi.ai/rezi-docs/the-rezi-score-explained"
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
id: "action-verb-start",
|
|
369
|
+
tier: "recruiter",
|
|
370
|
+
weight: "medium",
|
|
371
|
+
evidenceLevel: "convention",
|
|
372
|
+
description: "Highlights start with an action verb."
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
id: "quantification-density",
|
|
376
|
+
tier: "recruiter",
|
|
377
|
+
weight: "high",
|
|
378
|
+
evidenceLevel: "convention",
|
|
379
|
+
description: "At least 50% of highlights include numbers/metrics."
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
id: "pronoun-leakage",
|
|
383
|
+
tier: "recruiter",
|
|
384
|
+
weight: "low",
|
|
385
|
+
evidenceLevel: "convention",
|
|
386
|
+
description: "Convention, not ATS: ATS does not filter on pronouns; this is recruiter style.",
|
|
387
|
+
source: "https://resume.io/blog/first-person-resume"
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
id: "bullets-per-role",
|
|
391
|
+
tier: "recruiter",
|
|
392
|
+
weight: "medium",
|
|
393
|
+
evidenceLevel: "convention",
|
|
394
|
+
description: "Each work entry has 3-6 highlights (10 for senior).",
|
|
395
|
+
source: "https://www.rezi.ai/rezi-docs/the-rezi-score-explained"
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
id: "word-count-total",
|
|
399
|
+
tier: "recruiter",
|
|
400
|
+
weight: "low",
|
|
401
|
+
evidenceLevel: "convention",
|
|
402
|
+
description: "Total resume body 400-800 words (1600 senior).",
|
|
403
|
+
source: "https://www.rezi.ai/rezi-docs/the-rezi-score-explained"
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
id: "highlight-length",
|
|
407
|
+
tier: "recruiter",
|
|
408
|
+
weight: "low",
|
|
409
|
+
evidenceLevel: "convention",
|
|
410
|
+
description: "Each highlight fits within two visual lines (~30 words)."
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
id: "has-linkedin",
|
|
414
|
+
tier: "recruiter",
|
|
415
|
+
weight: "low",
|
|
416
|
+
evidenceLevel: "convention",
|
|
417
|
+
description: "LinkedIn profile present in basics.profiles."
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
id: "skills-populated",
|
|
421
|
+
tier: "recruiter",
|
|
422
|
+
weight: "medium",
|
|
423
|
+
evidenceLevel: "convention",
|
|
424
|
+
description: "At least 3 skill categories with keywords."
|
|
425
|
+
}
|
|
426
|
+
];
|
|
427
|
+
var byId = new Map(rubric.map((r) => [r.id, r]));
|
|
428
|
+
function getRubricEntry(id, opts = {}) {
|
|
429
|
+
const entry = byId.get(id);
|
|
430
|
+
if (!entry && opts.strict) throw new Error(`Unknown rubric id: ${id}`);
|
|
431
|
+
return entry;
|
|
432
|
+
}
|
|
433
|
+
function rubricByTier(tier) {
|
|
434
|
+
return rubric.filter((r) => r.tier === tier);
|
|
435
|
+
}
|
|
436
|
+
function listRubricMarkdown() {
|
|
437
|
+
const tiers = ["parsing", "match", "recruiter"];
|
|
438
|
+
const sections = tiers.map((t) => {
|
|
439
|
+
const entries = rubricByTier(t);
|
|
440
|
+
const lines = entries.map(
|
|
441
|
+
(e) => `- **${e.id}** (${e.weight}, ${e.evidenceLevel}): ${e.description}${e.source ? `
|
|
442
|
+
Source: ${e.source}` : ""}`
|
|
443
|
+
).join("\n");
|
|
444
|
+
return `## Tier: ${t}
|
|
445
|
+
|
|
446
|
+
${lines}`;
|
|
447
|
+
});
|
|
448
|
+
return ["# resuml ATS Rubric", "", ...sections].join("\n\n");
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
export {
|
|
452
|
+
processResumeData,
|
|
453
|
+
loadTheme,
|
|
454
|
+
generateResumeYaml,
|
|
455
|
+
KNOWN_THEMES,
|
|
456
|
+
isThemeInstalled,
|
|
457
|
+
getInstalledVersion,
|
|
458
|
+
getRubricEntry,
|
|
459
|
+
listRubricMarkdown
|
|
460
|
+
};
|
|
461
|
+
//# sourceMappingURL=chunk-G4AN2EMI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core.ts","../src/utils/themeLoader.ts","../src/utils/resumeTemplate.ts","../src/utils/themeInfo.ts","../src/ats/rubric.ts"],"sourcesContent":["// Placeholder for core logic\n\nimport { parse } from 'yaml';\nimport merge from 'lodash.merge';\nimport { validate } from '@jsonresume/schema';\nimport type { ResumeSchema as Resume } from './types/resume';\n\nexport type { Resume };\n\n/**\n * Merges and validates resume data objects against the JSON Resume schema.\n * @param yamlContents - An array of YAML strings containing resume data.\n * @returns The merged and validated resume data.\n * @throws Error if validation fails.\n */\nexport async function processResumeData(yamlContents: string[]): Promise<Resume> {\n if (yamlContents.length === 0) {\n throw new Error('No YAML content provided for processing.');\n }\n\n // Parse YAML content and filter out invalid objects\n const dataObjects = yamlContents\n .map((content) => {\n try {\n return parse(content) as Partial<Resume>;\n } catch (error) {\n console.warn('Failed to parse YAML content:', error);\n return null;\n }\n })\n .filter((data): data is Partial<Resume> => typeof data === 'object' && data !== null);\n\n if (dataObjects.length === 0) {\n throw new Error('No valid YAML content found after parsing.');\n }\n\n // Custom array merge to ensure arrays are concatenated\n const customizer = (objValue: unknown, srcValue: unknown) => {\n if (Array.isArray(objValue)) {\n return (objValue as unknown[]).concat(srcValue as unknown[]);\n }\n return undefined; // Let lodash handle it\n };\n\n // Merge data: Concatenate arrays, deep merge objects\n const mergedData = dataObjects.reduce((acc, data) => merge(acc, data, customizer), {});\n\n // Validate using the official JSON Resume validator\n return new Promise((resolve, reject) => {\n validate(mergedData, (errors, isValid) => {\n if (!isValid) {\n reject(\n new Error(`Resume data failed schema validation: ${JSON.stringify(errors, null, 2)}`)\n );\n } else {\n resolve(mergedData);\n }\n });\n });\n}\n","import { execFileSync } from 'child_process';\nimport { createRequire } from 'module';\n\nconst require = createRequire(import.meta.url);\n\nexport interface ThemeModule {\n render: (\n resume: Record<string, unknown>,\n options?: Record<string, unknown>\n ) => string | Promise<string>;\n}\n\n/**\n * Install a theme package using npm\n * @param packageName The npm package name to install\n */\nfunction installTheme(packageName: string): void {\n try {\n execFileSync('npm', ['install', packageName], {\n stdio: ['inherit', 'pipe', 'pipe'],\n encoding: 'utf8',\n });\n } catch (error) {\n throw new Error(`Failed to install ${packageName}: ${(error as Error).message}`);\n }\n}\n\n/**\n * Load a theme module by name\n * @param themeName The name of the theme to load\n * @param options Optional settings (autoInstall: boolean)\n * @returns The loaded theme module\n */\nexport function loadTheme(themeName: string, options?: { autoInstall?: boolean }): ThemeModule {\n let jsonResumeThemeName: string;\n let nativeThemeName: string;\n const autoInstall = options?.autoInstall !== false;\n\n try {\n // Try loading as a JSON Resume theme\n jsonResumeThemeName = themeName.startsWith('jsonresume-theme-')\n ? themeName\n : `jsonresume-theme-${themeName}`;\n\n try {\n // Use require for CommonJS modules\n return require(jsonResumeThemeName) as ThemeModule;\n } catch (_jsonResumeError) {\n // If not found as JSON Resume theme, try as native theme\n nativeThemeName = `@resuml/theme-${themeName}`;\n try {\n return require(nativeThemeName) as ThemeModule;\n } catch (_nativeError) {\n if (!autoInstall) {\n throw new Error(\n `Theme package ${jsonResumeThemeName} or ${nativeThemeName} not found in node_modules.\\n` +\n `Please install the theme package manually.`\n );\n }\n // Both attempts failed - auto-install the theme\n console.log(`📦 Theme ${jsonResumeThemeName} not found. Installing...`);\n try {\n installTheme(jsonResumeThemeName);\n console.log(`✅ Successfully installed ${jsonResumeThemeName}`);\n // Try requiring again after installation\n return require(jsonResumeThemeName) as ThemeModule;\n } catch (installError) {\n throw new Error(\n `Failed to auto-install theme ${jsonResumeThemeName}: ${\n (installError as Error).message\n }`\n );\n }\n }\n }\n } catch (error) {\n // Re-throw if it's already our custom error\n if (error instanceof Error && error.message.includes('Failed to auto-install')) {\n throw error;\n }\n throw new Error(`Theme package ${themeName} not found`);\n }\n}\n","export function generateResumeYaml(name: string, email: string, label: string): string {\n return `# =============================================================================\n# Resume - Generated by resuml\n# Documentation: https://github.com/phoinixi/resuml\n# Schema: https://jsonresume.org/schema/\n# =============================================================================\n\n# --- Basic Information ---\nbasics:\n name: '${name}'\n label: '${label}'\n # image: 'https://example.com/photo.jpg'\n email: '${email}'\n # phone: '+1-555-123-4567'\n # url: 'https://yourwebsite.com'\n summary: >-\n Write a short professional summary here.\n This supports multi-line strings in YAML.\n location:\n # address: '123 Main Street'\n # postalCode: '12345'\n city: 'Your City'\n countryCode: 'US'\n # region: 'Your State'\n profiles:\n - network: 'LinkedIn'\n username: 'your-username'\n url: 'https://linkedin.com/in/your-username'\n - network: 'GitHub'\n username: 'your-username'\n url: 'https://github.com/your-username'\n\n# --- Work Experience ---\nwork:\n - name: 'Company Name'\n position: 'Job Title'\n url: 'https://company.com'\n startDate: '2020-01-01'\n # endDate: '2023-12-31' # Omit for current position\n summary: 'Brief description of your role and responsibilities.'\n highlights:\n - 'Key achievement or responsibility'\n - 'Another notable accomplishment'\n\n# --- Education ---\neducation:\n - institution: 'University Name'\n url: 'https://university.edu'\n area: 'Field of Study'\n studyType: 'Bachelor of Science'\n startDate: '2014-09-01'\n endDate: '2018-06-01'\n # score: '3.8'\n courses:\n - 'Relevant Course 1'\n - 'Relevant Course 2'\n\n# --- Skills ---\nskills:\n - name: 'Programming Languages'\n level: 'Expert'\n keywords:\n - 'JavaScript'\n - 'TypeScript'\n - 'Python'\n - name: 'Frameworks'\n level: 'Advanced'\n keywords:\n - 'React'\n - 'Node.js'\n\n# --- Projects ---\n# projects:\n# - name: 'Project Name'\n# description: 'Brief project description'\n# highlights:\n# - 'Key feature or result'\n# keywords:\n# - 'Technology Used'\n# startDate: '2023-01-01'\n# endDate: '2023-06-30'\n# url: 'https://github.com/you/project'\n# roles:\n# - 'Developer'\n# type: 'application'\n\n# --- Languages ---\n# languages:\n# - language: 'English'\n# fluency: 'Native speaker'\n# - language: 'Spanish'\n# fluency: 'Professional working proficiency'\n\n# --- Interests ---\n# interests:\n# - name: 'Open Source'\n# keywords:\n# - 'Contributing'\n# - 'Community'\n\n# --- References ---\n# references:\n# - name: 'Jane Smith'\n# reference: 'It was a pleasure working with...'\n\n# --- Awards ---\n# awards:\n# - title: 'Award Name'\n# date: '2023-01-01'\n# awarder: 'Organization'\n# summary: 'Description of the award'\n\n# --- Certificates ---\n# certificates:\n# - name: 'Certificate Name'\n# date: '2023-01-01'\n# issuer: 'Issuing Organization'\n# url: 'https://example.com/cert'\n\n# --- Publications ---\n# publications:\n# - name: 'Publication Title'\n# publisher: 'Publisher'\n# releaseDate: '2023-01-01'\n# url: 'https://example.com/publication'\n# summary: 'Brief description'\n\n# --- Volunteer ---\n# volunteers:\n# - organization: 'Organization Name'\n# position: 'Volunteer Role'\n# url: 'https://organization.com'\n# startDate: '2022-01-01'\n# summary: 'Description of volunteer work'\n# highlights:\n# - 'Notable contribution'\n`;\n}\n","import { createRequire } from 'module';\n\nexport interface ThemeInfo {\n name: string;\n pkg: string;\n description: string;\n}\n\nexport const KNOWN_THEMES: ThemeInfo[] = [\n {\n name: 'stackoverflow',\n pkg: 'jsonresume-theme-stackoverflow',\n description: 'Stack Overflow inspired theme',\n },\n { name: 'elegant', pkg: 'jsonresume-theme-elegant', description: 'Elegant and professional' },\n { name: 'react', pkg: 'jsonresume-theme-react', description: 'Built with React components' },\n { name: 'even', pkg: 'jsonresume-theme-even', description: 'Clean and minimal' },\n { name: 'kendall', pkg: 'jsonresume-theme-kendall', description: 'Simple and clean layout' },\n { name: 'macchiato', pkg: 'jsonresume-theme-macchiato', description: 'Beautiful and modern' },\n { name: 'flat', pkg: 'jsonresume-theme-flat', description: 'Flat design theme' },\n { name: 'class', pkg: 'jsonresume-theme-class', description: 'Classic professional look' },\n { name: 'short', pkg: 'jsonresume-theme-short', description: 'Compact single-page resume' },\n { name: 'spartan', pkg: 'jsonresume-theme-spartan', description: 'Minimalist Spartan design' },\n { name: 'paper', pkg: 'jsonresume-theme-paper', description: 'Paper-like clean design' },\n { name: 'onepage', pkg: 'jsonresume-theme-onepage', description: 'One page resume layout' },\n];\n\nexport function isThemeInstalled(pkg: string): boolean {\n try {\n const req = createRequire(process.cwd() + '/');\n req.resolve(pkg);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function getInstalledVersion(pkg: string): string | null {\n try {\n const req = createRequire(process.cwd() + '/');\n const pkgJson = req(`${pkg}/package.json`) as { version?: string };\n return pkgJson.version ?? null;\n } catch {\n return null;\n }\n}\n","import type { RubricEntry, Tier } from './types';\n\nexport const rubric: RubricEntry[] = [\n // Parsing tier - Greenhouse-doc-grounded\n {\n id: 'conventional-sections',\n tier: 'parsing',\n weight: 'high',\n evidenceLevel: 'evidence',\n description: 'Required JSON Resume sections (basics, work, education) are present.',\n source: 'https://support.greenhouse.io/hc/en-us/articles/200989175-Unsuccessful-resume-parse',\n },\n {\n id: 'date-format-consistency',\n tier: 'parsing',\n weight: 'medium',\n evidenceLevel: 'evidence',\n description: 'Dates use ISO-8601 (YYYY-MM-DD or YYYY-MM); no mixed formats; no >6mo gaps.',\n source: 'https://hireflow.net/blog/taleo-resume-parsing-problems-explained',\n },\n {\n id: 'contact-in-body',\n tier: 'parsing',\n weight: 'high',\n evidenceLevel: 'evidence',\n description: 'Email and phone present in basics block (parseable by Textkernel/Sovren).',\n source: 'https://developer.textkernel.com/tx-platform/v10/faq/',\n },\n {\n id: 'reverse-chron-order',\n tier: 'parsing',\n weight: 'medium',\n evidenceLevel: 'evidence',\n description: 'work[] and education[] sorted descending by startDate.',\n },\n {\n id: 'education-complete',\n tier: 'parsing',\n weight: 'low',\n evidenceLevel: 'evidence',\n description: 'Each education entry has institution, area, and studyType.',\n },\n {\n id: 'pdf-text-extractable',\n tier: 'parsing',\n weight: 'high',\n evidenceLevel: 'evidence',\n description: 'Rendered PDF body text is selectable (>=70% of resume word count extractable).',\n source: 'https://www.ashbyhq.com/product-updates/ai-assisted-application-review',\n },\n {\n id: 'pdf-size-under-2.5mb',\n tier: 'parsing',\n weight: 'medium',\n evidenceLevel: 'evidence',\n description: 'Rendered PDF is under 2.5 MB (Greenhouse documented limit).',\n source: 'https://support.greenhouse.io/hc/en-us/articles/200989175-Unsuccessful-resume-parse',\n },\n\n // Match tier - JD-aware\n {\n id: 'hard-skill-overlap',\n tier: 'match',\n weight: 'high',\n evidenceLevel: 'evidence',\n description:\n 'Hard skill overlap with JD using bundled O*NET-trie skill index. ESCO migration tracked separately.',\n },\n {\n id: 'title-alignment',\n tier: 'match',\n weight: 'high',\n evidenceLevel: 'evidence',\n description:\n 'Most-recent work[].position aligns with JD title via token Jaccard after stripping seniority modifiers.',\n },\n {\n id: 'education-level',\n tier: 'match',\n weight: 'medium',\n evidenceLevel: 'evidence',\n description:\n 'Max studyType meets/exceeds JD education requirement (Bachelor/Master/PhD detection).',\n },\n {\n id: 'yoe-match',\n tier: 'match',\n weight: 'high',\n evidenceLevel: 'evidence',\n description:\n 'Total years of experience (overlap-merged from work[]) meets JD years requirement.',\n },\n\n // Recruiter tier - Rezi/Teal/Enhancv-grounded numbers\n {\n id: 'summary-length',\n tier: 'recruiter',\n weight: 'medium',\n evidenceLevel: 'convention',\n description: 'Professional summary 20-50 words / 2-4 sentences.',\n source: 'https://www.rezi.ai/rezi-docs/the-rezi-score-explained',\n },\n {\n id: 'action-verb-start',\n tier: 'recruiter',\n weight: 'medium',\n evidenceLevel: 'convention',\n description: 'Highlights start with an action verb.',\n },\n {\n id: 'quantification-density',\n tier: 'recruiter',\n weight: 'high',\n evidenceLevel: 'convention',\n description: 'At least 50% of highlights include numbers/metrics.',\n },\n {\n id: 'pronoun-leakage',\n tier: 'recruiter',\n weight: 'low',\n evidenceLevel: 'convention',\n description: 'Convention, not ATS: ATS does not filter on pronouns; this is recruiter style.',\n source: 'https://resume.io/blog/first-person-resume',\n },\n {\n id: 'bullets-per-role',\n tier: 'recruiter',\n weight: 'medium',\n evidenceLevel: 'convention',\n description: 'Each work entry has 3-6 highlights (10 for senior).',\n source: 'https://www.rezi.ai/rezi-docs/the-rezi-score-explained',\n },\n {\n id: 'word-count-total',\n tier: 'recruiter',\n weight: 'low',\n evidenceLevel: 'convention',\n description: 'Total resume body 400-800 words (1600 senior).',\n source: 'https://www.rezi.ai/rezi-docs/the-rezi-score-explained',\n },\n {\n id: 'highlight-length',\n tier: 'recruiter',\n weight: 'low',\n evidenceLevel: 'convention',\n description: 'Each highlight fits within two visual lines (~30 words).',\n },\n {\n id: 'has-linkedin',\n tier: 'recruiter',\n weight: 'low',\n evidenceLevel: 'convention',\n description: 'LinkedIn profile present in basics.profiles.',\n },\n {\n id: 'skills-populated',\n tier: 'recruiter',\n weight: 'medium',\n evidenceLevel: 'convention',\n description: 'At least 3 skill categories with keywords.',\n },\n];\n\nconst byId: Map<string, RubricEntry> = new Map(rubric.map((r) => [r.id, r]));\n\nexport function getRubricEntry(\n id: string,\n opts: { strict?: boolean } = {}\n): RubricEntry | undefined {\n const entry = byId.get(id);\n if (!entry && opts.strict) throw new Error(`Unknown rubric id: ${id}`);\n return entry;\n}\n\nexport function rubricByTier(tier: Tier): RubricEntry[] {\n return rubric.filter((r) => r.tier === tier);\n}\n\nexport function listRubricMarkdown(): string {\n const tiers: Tier[] = ['parsing', 'match', 'recruiter'];\n const sections = tiers.map((t) => {\n const entries = rubricByTier(t);\n const lines = entries\n .map(\n (e) =>\n `- **${e.id}** (${e.weight}, ${e.evidenceLevel}): ${e.description}${e.source ? `\\n Source: ${e.source}` : ''}`\n )\n .join('\\n');\n return `## Tier: ${t}\\n\\n${lines}`;\n });\n return ['# resuml ATS Rubric', '', ...sections].join('\\n\\n');\n}\n"],"mappings":"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","names":["require","createRequire"]}
|