resuml 1.20.1 → 2.0.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/DOCS.md ADDED
@@ -0,0 +1,314 @@
1
+ # resuml: detailed documentation
2
+
3
+ > For the short intro, see [README.md](README.md). For the web app, go to [resuml.app](https://resuml.app).
4
+
5
+ ## Table of contents
6
+
7
+ - [Why YAML](#why-yaml)
8
+ - [Installation](#installation)
9
+ - [CLI commands and options](#cli-commands-and-options)
10
+ - [ATS analysis](#ats-analysis)
11
+ - [Themes](#themes)
12
+ - [Example YAML structure](#example-yaml-structure)
13
+ - [CI/CD integration](#cicd-auto-build-on-push)
14
+ - [AI agent integration (MCP)](#ai-agent-integration-mcp)
15
+ - [Troubleshooting](#troubleshooting)
16
+
17
+ ---
18
+
19
+ ## Why YAML
20
+
21
+ | | YAML | JSON |
22
+ |---|---|---|
23
+ | **Comments** | ✅ `# explain your choices` | ❌ Not supported |
24
+ | **Multi-line strings** | ✅ `summary: >-` block syntax | ❌ Escape everything |
25
+ | **Readability** | ✅ Clean, minimal syntax | ⚠️ Brackets & quotes everywhere |
26
+ | **Diffing** | ✅ Clean git diffs | ⚠️ Noisy diffs |
27
+ | **Compatibility** | ✅ Valid JSON Resume schema | ✅ Native |
28
+
29
+ YAML is a superset of JSON, so your resume stays fully compatible with the [JSON Resume](https://jsonresume.org/) ecosystem.
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ npm install -g resuml
35
+ ```
36
+
37
+ Requires Node.js ≥ 20 and npm ≥ 10.
38
+
39
+ ## CLI commands and options
40
+
41
+ | Command | Description |
42
+ |---------|-------------|
43
+ | `validate` | Validate resume data against the JSON Resume schema |
44
+ | `validate --ats` | Run ATS compatibility analysis |
45
+ | `tojson` | Convert YAML to JSON |
46
+ | `render` | Render the resume to HTML using a theme |
47
+ | `pdf` | Render to PDF |
48
+ | `dev` | Dev server with hot-reload |
49
+ | `mcp` | Start the MCP server for AI agents |
50
+
51
+ ### Options
52
+
53
+ | Option | Alias | Description |
54
+ |--------|-------|-------------|
55
+ | `--resume` | `-r` | Input YAML file(s) or directory |
56
+ | `--output` | `-o` | Output file path |
57
+ | `--theme` | `-t` | Theme name |
58
+ | `--port` | `-p` | Dev server port (default: 3000) |
59
+ | `--language` | | Locale (default: `en`) |
60
+ | `--debug` | | Detailed errors |
61
+ | `--ats` | | Run ATS analysis (with `validate`) |
62
+ | `--jd` | | Path to job description file (with `--ats`) |
63
+ | `--ats-threshold` | | Minimum score (0-100); exits 1 if below |
64
+ | `--format` | | Output format for validate: `text` or `json` |
65
+
66
+ ### Quick start
67
+
68
+ ```bash
69
+ resuml validate --resume resume.yaml
70
+ resuml tojson --resume resume.yaml --output resume.json
71
+ resuml render --resume resume.yaml --theme stackoverflow --output resume.html
72
+ ```
73
+
74
+ ## ATS analysis
75
+
76
+ Deterministic, offline ATS (Applicant Tracking System) checks. No API keys, no LLMs.
77
+
78
+ ```bash
79
+ # Basic ATS score
80
+ resuml validate --resume resume.yaml --ats
81
+
82
+ # Match against a job description
83
+ resuml validate --resume resume.yaml --ats --jd job-description.txt
84
+
85
+ # CI gate: fail if below threshold
86
+ resuml validate --resume resume.yaml --ats --ats-threshold 75
87
+
88
+ # Machine-readable output
89
+ resuml validate --resume resume.yaml --ats --format json
90
+ ```
91
+
92
+ ### What it checks
93
+
94
+ 11 deterministic checks across 3 categories.
95
+
96
+ **Contact information**
97
+ - Complete contact details (name, email, phone, city)
98
+ - LinkedIn profile present
99
+
100
+ **Content quality**
101
+ - Professional summary (length and presence)
102
+ - Work highlights (≥ 2 per entry)
103
+ - Action verbs (highlights start with strong verbs)
104
+ - Quantified impact (numbers / percentages / metrics)
105
+ - No first-person pronouns
106
+
107
+ **Resume structure**
108
+ - Date consistency (no unexplained gaps > 6 months)
109
+ - Skills populated (≥ 3 categories with keywords)
110
+ - Education completeness
111
+ - Essential sections present
112
+
113
+ ### Job description matching
114
+
115
+ Passing `--jd` extracts keywords from the job description using TF-based ranking with stem matching, then compares to your resume. You get:
116
+
117
+ - **Match percentage**: how many JD keywords appear in your resume
118
+ - **Matched keywords**: what you already cover
119
+ - **Missing keywords**: what to consider adding
120
+ - **Extra keywords**: skills in your resume the JD didn't mention
121
+
122
+ ### Scoring
123
+
124
+ | Score | Rating | Meaning |
125
+ |-------|--------|---------|
126
+ | 90-100 | Excellent | Well-optimized for ATS |
127
+ | 75-89 | Good | Minor improvements possible |
128
+ | 60-74 | Needs Work | Several issues to address |
129
+ | 0-59 | Poor | Significant improvements needed |
130
+
131
+ With a JD: final score = 60% generic checks + 40% keyword match.
132
+
133
+ ### Multi-language
134
+
135
+ Supports English and German (language-specific action verbs and pronouns). Use `--language`:
136
+
137
+ ```bash
138
+ resuml validate --resume lebenslauf.yaml --ats --language de
139
+ ```
140
+
141
+ ## Themes
142
+
143
+ resuml supports any `jsonresume-theme-*` package from npm. Install a theme, then pass its name to `--theme`:
144
+
145
+ ```bash
146
+ npm install jsonresume-theme-stackoverflow
147
+ resuml render --resume resume.yaml --theme stackoverflow
148
+ ```
149
+
150
+ | Theme | Install | Style |
151
+ |-------|---------|-------|
152
+ | [stackoverflow](https://github.com/francoislaberge/jsonresume-theme-stackoverflow) | `npm i jsonresume-theme-stackoverflow` | Clean, professional |
153
+ | [elegant](https://github.com/mudassir0909/jsonresume-theme-elegant) | `npm i jsonresume-theme-elegant` | Modern |
154
+ | [kendall](https://github.com/LinuxBozo/jsonresume-theme-kendall) | `npm i jsonresume-theme-kendall` | Minimal |
155
+ | [flat](https://github.com/erming/jsonresume-theme-flat) | `npm i jsonresume-theme-flat` | Flat |
156
+ | [onepage](https://github.com/aonemd/jsonresume-theme-onepage) | `npm i jsonresume-theme-onepage` | Single-page |
157
+
158
+ Browse all at [jsonresume.org/themes](https://jsonresume.org/themes/). The web app at [resuml.app](https://resuml.app) bundles 300+ of them and renders live.
159
+
160
+ ## Example YAML structure
161
+
162
+ ```yaml
163
+ basics:
164
+ name: John Doe
165
+ label: Software Engineer
166
+ email: john@example.com
167
+ summary: Experienced software engineer...
168
+ location:
169
+ city: San Francisco
170
+ countryCode: US
171
+ profiles:
172
+ - network: GitHub
173
+ url: https://github.com/johndoe
174
+
175
+ work:
176
+ - name: Tech Corp
177
+ position: Senior Engineer
178
+ startDate: 2020-01-15
179
+ endDate: 2023-12-31
180
+ summary: Led development of...
181
+ highlights:
182
+ - Reduced latency by 40%
183
+ - Led team of 8 engineers
184
+
185
+ education:
186
+ - institution: University
187
+ area: Computer Science
188
+ studyType: Bachelor
189
+ startDate: 2014-09-01
190
+ endDate: 2018-06-01
191
+
192
+ skills:
193
+ - name: Languages
194
+ level: Expert
195
+ keywords: [TypeScript, Python, Go]
196
+ ```
197
+
198
+ See [examples/](examples/) for more.
199
+
200
+ ## CI/CD: Auto-build on push
201
+
202
+ ```yaml
203
+ # .github/workflows/resume.yml
204
+ name: Build Resume
205
+
206
+ on:
207
+ push:
208
+ paths: ['resume.yaml', 'resume/*.yaml']
209
+
210
+ jobs:
211
+ build:
212
+ runs-on: ubuntu-latest
213
+ steps:
214
+ - uses: actions/checkout@v4
215
+ - uses: actions/setup-node@v4
216
+ with:
217
+ node-version: 20
218
+
219
+ - run: npm install -g resuml
220
+ - run: npm install jsonresume-theme-stackoverflow
221
+
222
+ # Fail the job if ATS score < 75
223
+ - run: resuml validate --resume resume.yaml --ats --ats-threshold 75
224
+
225
+ - run: resuml render --resume resume.yaml --theme stackoverflow --output resume.html
226
+ - run: resuml tojson --resume resume.yaml --output resume.json
227
+
228
+ - uses: actions/upload-artifact@v4
229
+ with:
230
+ name: resume
231
+ path: |
232
+ resume.html
233
+ resume.json
234
+ ```
235
+
236
+ ## AI agent integration (MCP)
237
+
238
+ resuml ships with a [Model Context Protocol](https://modelcontextprotocol.io/) server so Claude Code, Claude Desktop, Cursor, Copilot, or any MCP-compatible client can use it directly.
239
+
240
+ ### Setup
241
+
242
+ Add to your MCP client config:
243
+
244
+ ```json
245
+ {
246
+ "mcpServers": {
247
+ "resuml": {
248
+ "command": "npx",
249
+ "args": ["resuml", "mcp"]
250
+ }
251
+ }
252
+ }
253
+ ```
254
+
255
+ Or run standalone:
256
+
257
+ ```bash
258
+ resuml mcp
259
+ ```
260
+
261
+ ### Using it from Claude Code
262
+
263
+ Once configured, Claude Code can call every resuml capability through natural language. For example:
264
+
265
+ > "I saved the job ad as `jd.txt`. Tailor my resume at `resume.yaml` to match it, iterate until the ATS score is ≥ 80, render with the stackoverflow theme, and export a PDF."
266
+
267
+ Claude Code will:
268
+
269
+ 1. Validate the current YAML.
270
+ 2. Run the ATS check with the JD.
271
+ 3. Edit the YAML to close keyword gaps.
272
+ 4. Re-check until the target score is met.
273
+ 5. Render the HTML and export the PDF.
274
+
275
+ ### Tools
276
+
277
+ | Tool | Purpose |
278
+ |------|---------|
279
+ | `resuml_init_resume` | Generate a starter YAML template |
280
+ | `resuml_validate` | Validate resume YAML against the JSON Resume schema |
281
+ | `resuml_ats_check` | ATS analysis + JD keyword matching |
282
+ | `resuml_render` | Render to HTML using a theme (supports `locale`) |
283
+ | `resuml_list_themes` | List available themes and install status |
284
+ | `resuml_export_pdf` | Export as PDF (supports `margin`, `locale`) |
285
+
286
+ ### Resources
287
+
288
+ | URI | Description |
289
+ |-----|-------------|
290
+ | `resuml://schema/json-resume` | Full JSON Resume schema reference |
291
+ | `resuml://docs/ats-scoring` | ATS scoring rubric, checks, weights, and tips |
292
+ | `resuml://themes/catalog` | Available themes with descriptions |
293
+
294
+ ### Prompts
295
+
296
+ | Prompt | Description |
297
+ |--------|-------------|
298
+ | `tailor-resume-to-jd` | Tailor a resume for a specific job description |
299
+ | `optimize-ats-score` | Analyze and improve an existing resume's ATS score |
300
+ | `review-resume` | Comprehensive review + improvement suggestions |
301
+
302
+ ## Troubleshooting
303
+
304
+ **Validation errors**
305
+ - Check YAML indentation and required fields
306
+ - Run with `--debug` for stack traces
307
+
308
+ **Theme rendering issues**
309
+ - Ensure the theme is installed (`npm install jsonresume-theme-<name>`)
310
+ - Third-party themes may have their own bugs. Try a different theme.
311
+ - The web app at [resuml.app](https://resuml.app) pre-checks themes and flags broken ones
312
+
313
+ **Dev server issues**
314
+ - The default port is 3000. Pass `--port` to override.
package/README.md CHANGED
@@ -66,11 +66,16 @@ Claude will generate the YAML, validate it, iterate until the score clears, and
66
66
  ```bash
67
67
  npm install -g resuml
68
68
 
69
+ # install a theme on demand (any jsonresume-theme-* package)
70
+ npm install -g jsonresume-theme-stackoverflow
71
+
69
72
  resuml validate --resume resume.yaml --ats --jd job.txt
70
73
  resuml render --resume resume.yaml --theme stackoverflow --output resume.html
71
74
  resuml pdf --resume resume.yaml --theme stackoverflow --output resume.pdf
72
75
  ```
73
76
 
77
+ `resuml pdf` and snapshot rendering need Playwright. Install it once with `npm install -g playwright` (it's an optional peer dep so the base install stays slim).
78
+
74
79
  **Minimal `resume.yaml`:**
75
80
 
76
81
  ```yaml
@@ -89,14 +94,14 @@ work:
89
94
  - Led team of 12 engineers
90
95
  ```
91
96
 
92
- Full CLI reference, Node.js API, ATS rubric, CI/CD setup, and every MCP tool live in **[DOCS.md](DOCS.md)**.
97
+ Full CLI reference, ATS rubric, CI/CD setup, and every MCP tool live in **[DOCS.md](DOCS.md)**.
93
98
 
94
99
  ---
95
100
 
96
101
  ## Requirements
97
102
 
98
103
  - Node.js ≥ 20, npm ≥ 10
99
- - Nothing else. Validation, ATS, rendering, and PDF all run locally
104
+ - Optional: `playwright` for `resuml pdf`
100
105
 
101
106
  ## Contributing
102
107
 
@@ -1,3 +1,9 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
1
7
  // src/core.ts
2
8
  import { parse } from "yaml";
3
9
  import merge from "lodash.merge";
@@ -1614,8 +1620,242 @@ function analyzeAts(resume, options = {}) {
1614
1620
  };
1615
1621
  }
1616
1622
 
1623
+ // src/utils/themeLoader.ts
1624
+ import { execFileSync } from "child_process";
1625
+ import { createRequire } from "module";
1626
+ var require2 = createRequire(import.meta.url);
1627
+ function installTheme(packageName) {
1628
+ try {
1629
+ execFileSync("npm", ["install", packageName], {
1630
+ stdio: ["inherit", "pipe", "pipe"],
1631
+ encoding: "utf8"
1632
+ });
1633
+ } catch (error) {
1634
+ throw new Error(`Failed to install ${packageName}: ${error.message}`);
1635
+ }
1636
+ }
1637
+ function loadTheme(themeName, options) {
1638
+ let jsonResumeThemeName;
1639
+ let nativeThemeName;
1640
+ const autoInstall = options?.autoInstall !== false;
1641
+ try {
1642
+ jsonResumeThemeName = themeName.startsWith("jsonresume-theme-") ? themeName : `jsonresume-theme-${themeName}`;
1643
+ try {
1644
+ return require2(jsonResumeThemeName);
1645
+ } catch (_jsonResumeError) {
1646
+ nativeThemeName = `@resuml/theme-${themeName}`;
1647
+ try {
1648
+ return require2(nativeThemeName);
1649
+ } catch (_nativeError) {
1650
+ if (!autoInstall) {
1651
+ throw new Error(
1652
+ `Theme package ${jsonResumeThemeName} or ${nativeThemeName} not found in node_modules.
1653
+ Please install the theme package manually.`
1654
+ );
1655
+ }
1656
+ console.log(`\u{1F4E6} Theme ${jsonResumeThemeName} not found. Installing...`);
1657
+ try {
1658
+ installTheme(jsonResumeThemeName);
1659
+ console.log(`\u2705 Successfully installed ${jsonResumeThemeName}`);
1660
+ return require2(jsonResumeThemeName);
1661
+ } catch (installError) {
1662
+ throw new Error(
1663
+ `Failed to auto-install theme ${jsonResumeThemeName}: ${installError.message}`
1664
+ );
1665
+ }
1666
+ }
1667
+ }
1668
+ } catch (error) {
1669
+ if (error instanceof Error && error.message.includes("Failed to auto-install")) {
1670
+ throw error;
1671
+ }
1672
+ throw new Error(`Theme package ${themeName} not found`);
1673
+ }
1674
+ }
1675
+
1676
+ // src/utils/resumeTemplate.ts
1677
+ function generateResumeYaml(name, email, label) {
1678
+ return `# =============================================================================
1679
+ # Resume - Generated by resuml
1680
+ # Documentation: https://github.com/phoinixi/resuml
1681
+ # Schema: https://jsonresume.org/schema/
1682
+ # =============================================================================
1683
+
1684
+ # --- Basic Information ---
1685
+ basics:
1686
+ name: '${name}'
1687
+ label: '${label}'
1688
+ # image: 'https://example.com/photo.jpg'
1689
+ email: '${email}'
1690
+ # phone: '+1-555-123-4567'
1691
+ # url: 'https://yourwebsite.com'
1692
+ summary: >-
1693
+ Write a short professional summary here.
1694
+ This supports multi-line strings in YAML.
1695
+ location:
1696
+ # address: '123 Main Street'
1697
+ # postalCode: '12345'
1698
+ city: 'Your City'
1699
+ countryCode: 'US'
1700
+ # region: 'Your State'
1701
+ profiles:
1702
+ - network: 'LinkedIn'
1703
+ username: 'your-username'
1704
+ url: 'https://linkedin.com/in/your-username'
1705
+ - network: 'GitHub'
1706
+ username: 'your-username'
1707
+ url: 'https://github.com/your-username'
1708
+
1709
+ # --- Work Experience ---
1710
+ work:
1711
+ - name: 'Company Name'
1712
+ position: 'Job Title'
1713
+ url: 'https://company.com'
1714
+ startDate: '2020-01-01'
1715
+ # endDate: '2023-12-31' # Omit for current position
1716
+ summary: 'Brief description of your role and responsibilities.'
1717
+ highlights:
1718
+ - 'Key achievement or responsibility'
1719
+ - 'Another notable accomplishment'
1720
+
1721
+ # --- Education ---
1722
+ education:
1723
+ - institution: 'University Name'
1724
+ url: 'https://university.edu'
1725
+ area: 'Field of Study'
1726
+ studyType: 'Bachelor of Science'
1727
+ startDate: '2014-09-01'
1728
+ endDate: '2018-06-01'
1729
+ # score: '3.8'
1730
+ courses:
1731
+ - 'Relevant Course 1'
1732
+ - 'Relevant Course 2'
1733
+
1734
+ # --- Skills ---
1735
+ skills:
1736
+ - name: 'Programming Languages'
1737
+ level: 'Expert'
1738
+ keywords:
1739
+ - 'JavaScript'
1740
+ - 'TypeScript'
1741
+ - 'Python'
1742
+ - name: 'Frameworks'
1743
+ level: 'Advanced'
1744
+ keywords:
1745
+ - 'React'
1746
+ - 'Node.js'
1747
+
1748
+ # --- Projects ---
1749
+ # projects:
1750
+ # - name: 'Project Name'
1751
+ # description: 'Brief project description'
1752
+ # highlights:
1753
+ # - 'Key feature or result'
1754
+ # keywords:
1755
+ # - 'Technology Used'
1756
+ # startDate: '2023-01-01'
1757
+ # endDate: '2023-06-30'
1758
+ # url: 'https://github.com/you/project'
1759
+ # roles:
1760
+ # - 'Developer'
1761
+ # type: 'application'
1762
+
1763
+ # --- Languages ---
1764
+ # languages:
1765
+ # - language: 'English'
1766
+ # fluency: 'Native speaker'
1767
+ # - language: 'Spanish'
1768
+ # fluency: 'Professional working proficiency'
1769
+
1770
+ # --- Interests ---
1771
+ # interests:
1772
+ # - name: 'Open Source'
1773
+ # keywords:
1774
+ # - 'Contributing'
1775
+ # - 'Community'
1776
+
1777
+ # --- References ---
1778
+ # references:
1779
+ # - name: 'Jane Smith'
1780
+ # reference: 'It was a pleasure working with...'
1781
+
1782
+ # --- Awards ---
1783
+ # awards:
1784
+ # - title: 'Award Name'
1785
+ # date: '2023-01-01'
1786
+ # awarder: 'Organization'
1787
+ # summary: 'Description of the award'
1788
+
1789
+ # --- Certificates ---
1790
+ # certificates:
1791
+ # - name: 'Certificate Name'
1792
+ # date: '2023-01-01'
1793
+ # issuer: 'Issuing Organization'
1794
+ # url: 'https://example.com/cert'
1795
+
1796
+ # --- Publications ---
1797
+ # publications:
1798
+ # - name: 'Publication Title'
1799
+ # publisher: 'Publisher'
1800
+ # releaseDate: '2023-01-01'
1801
+ # url: 'https://example.com/publication'
1802
+ # summary: 'Brief description'
1803
+
1804
+ # --- Volunteer ---
1805
+ # volunteers:
1806
+ # - organization: 'Organization Name'
1807
+ # position: 'Volunteer Role'
1808
+ # url: 'https://organization.com'
1809
+ # startDate: '2022-01-01'
1810
+ # summary: 'Description of volunteer work'
1811
+ # highlights:
1812
+ # - 'Notable contribution'
1813
+ `;
1814
+ }
1815
+
1816
+ // src/utils/themeInfo.ts
1817
+ import { createRequire as createRequire2 } from "module";
1818
+ var KNOWN_THEMES = [
1819
+ { name: "stackoverflow", pkg: "jsonresume-theme-stackoverflow", description: "Stack Overflow inspired theme" },
1820
+ { name: "elegant", pkg: "jsonresume-theme-elegant", description: "Elegant and professional" },
1821
+ { name: "react", pkg: "jsonresume-theme-react", description: "Built with React components" },
1822
+ { name: "even", pkg: "jsonresume-theme-even", description: "Clean and minimal" },
1823
+ { name: "kendall", pkg: "jsonresume-theme-kendall", description: "Simple and clean layout" },
1824
+ { name: "macchiato", pkg: "jsonresume-theme-macchiato", description: "Beautiful and modern" },
1825
+ { name: "flat", pkg: "jsonresume-theme-flat", description: "Flat design theme" },
1826
+ { name: "class", pkg: "jsonresume-theme-class", description: "Classic professional look" },
1827
+ { name: "short", pkg: "jsonresume-theme-short", description: "Compact single-page resume" },
1828
+ { name: "spartan", pkg: "jsonresume-theme-spartan", description: "Minimalist Spartan design" },
1829
+ { name: "paper", pkg: "jsonresume-theme-paper", description: "Paper-like clean design" },
1830
+ { name: "onepage", pkg: "jsonresume-theme-onepage", description: "One page resume layout" }
1831
+ ];
1832
+ function isThemeInstalled(pkg) {
1833
+ try {
1834
+ const req = createRequire2(process.cwd() + "/");
1835
+ req.resolve(pkg);
1836
+ return true;
1837
+ } catch {
1838
+ return false;
1839
+ }
1840
+ }
1841
+ function getInstalledVersion(pkg) {
1842
+ try {
1843
+ const req = createRequire2(process.cwd() + "/");
1844
+ const pkgJson = req(`${pkg}/package.json`);
1845
+ return pkgJson.version ?? null;
1846
+ } catch {
1847
+ return null;
1848
+ }
1849
+ }
1850
+
1617
1851
  export {
1852
+ __export,
1618
1853
  processResumeData,
1619
- analyzeAts
1854
+ analyzeAts,
1855
+ loadTheme,
1856
+ generateResumeYaml,
1857
+ KNOWN_THEMES,
1858
+ isThemeInstalled,
1859
+ getInstalledVersion
1620
1860
  };
1621
- //# sourceMappingURL=chunk-KRJMZ2RQ.js.map
1861
+ //# sourceMappingURL=chunk-GRIYYG45.js.map