@phuthuycoding/markcv 0.1.0 → 0.1.2

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/CHANGELOG.md ADDED
@@ -0,0 +1,66 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.2] - 2026-09-06
11
+
12
+ ### Fixed
13
+
14
+ - `markcv --version` reported the version that was hardcoded in the source rather
15
+ than the one actually installed: 0.1.1 shipped while `--version` still said
16
+ 0.1.0. Both the CLI and the MCP server now read it from `package.json`, and a
17
+ test fails if the two ever disagree.
18
+
19
+ ## [0.1.1] - 2026-09-06
20
+
21
+ ### Added
22
+
23
+ - `markcv mcp` subcommand, so MCP clients can use the shape everyone else uses:
24
+ `npx -y @phuthuycoding/markcv mcp`. With two binaries in the package, the bare
25
+ `npx` form would otherwise need `--package=…`, which nobody writes from memory.
26
+
27
+ ### Changed
28
+
29
+ - README now leads with installing from npm, and no longer asks the reader to
30
+ clone and build. Development setup moved to `CONTRIBUTING.md`.
31
+ - MCP documentation defaults to the `npx` form; the global `markcv-mcp` binary is
32
+ presented as the faster alternative rather than the only way.
33
+ - `render --no-photo` reports `photo disabled` instead of
34
+ `photo none (placeholder box)` — not embedding a photo and not finding one are
35
+ different things.
36
+
37
+ ## [0.1.0] - 2026-09-06
38
+
39
+ First release.
40
+
41
+ ### Added
42
+
43
+ - `fit` — explains *why* a CV does not fit a page target, separating content that
44
+ is genuinely too long from content pushed onto a new page by a bad break, and
45
+ naming the block responsible with the pixels it wasted.
46
+ - `lint` — audits content rather than formatting: overselling (`spearheaded`,
47
+ `comprehensive`), **underselling** (`advised on` next to work of real scale),
48
+ present-tense bullets on finished jobs, skills claimed with no supporting
49
+ experience, duplicate bullets, IC/manager role mismatch, bullets without a
50
+ single number, emoji in headings, and over-long bullets.
51
+ - `tailor` — compares a CV against a job description: requirements with no
52
+ evidence, keywords that appear only under SKILLS, and bullets unrelated to the
53
+ role.
54
+ - `render` — Markdown to A4 PDF via a system Chrome, with portrait photo
55
+ auto-detection and a warning when the photo will bloat the PDF.
56
+ - `new`, `list`, `diff`, `build` — master/variant workflow for keeping one content
57
+ store and cutting tailored copies from it.
58
+ - MCP server exposing seven tools that return structured JSON, so an agent can
59
+ iterate: edit → `check_fit` → read `culprits` → edit again.
60
+ - Two ATS-safe themes: `classic` and `compact`.
61
+ - Example CVs in `examples/`, with and without a portrait photo.
62
+
63
+ [Unreleased]: https://github.com/phuthuycoding/markcv/compare/v0.1.2...HEAD
64
+ [0.1.2]: https://github.com/phuthuycoding/markcv/compare/v0.1.1...v0.1.2
65
+ [0.1.1]: https://github.com/phuthuycoding/markcv/compare/v0.1.0...v0.1.1
66
+ [0.1.0]: https://github.com/phuthuycoding/markcv/releases/tag/v0.1.0
package/README.md CHANGED
@@ -19,20 +19,17 @@ Two things set it apart from ordinary markdown→PDF tools:
19
19
  ## Install
20
20
 
21
21
  ```bash
22
- git clone https://github.com/phuthuycoding/markcv.git
23
- cd markcv
24
- npm install # builds dist/ via the prepare script
25
- npm link # puts `markcv` and `markcv-mcp` on your PATH
22
+ npm install -g @phuthuycoding/markcv
26
23
  ```
27
24
 
28
- Or from npm:
25
+ The package is scoped; the commands are not. You type `markcv` and `markcv-mcp`.
26
+
27
+ Or run it without installing:
29
28
 
30
29
  ```bash
31
- npm install -g @phuthuycoding/markcv
30
+ npx @phuthuycoding/markcv fit cv.md --pages 2
32
31
  ```
33
32
 
34
- The package is scoped, but the commands are not — you still type `markcv` and `markcv-mcp`.
35
-
36
33
  Requires a Chromium-based browser already on your machine (Chrome, Chromium, Edge, Brave). markcv deliberately does **not** download its own Chromium — it uses `puppeteer-core`, so the install stays small. If your browser lives somewhere unusual, point at it with `MARKCV_CHROME=/path/to/chrome`.
37
34
 
38
35
  ## Usage
@@ -129,61 +126,49 @@ Note what the bullets in those samples have in common: a number, or a before and
129
126
 
130
127
  Lets an AI agent (Claude Code, Claude Desktop, Cursor…) build and audit CVs on its own.
131
128
 
132
- Install it first (see [Install](#install) above), then point a client at `markcv-mcp`.
133
-
134
- Check the server starts (it waits for JSON-RPC on stdin and prints nothing — that is
135
- correct; Ctrl+C to quit):
136
-
137
- ```bash
138
- markcv-mcp
139
- ```
129
+ Nothing to install: `npx` fetches the package on first use and caches it.
140
130
 
141
131
  ### Register it with a client
142
132
 
143
- After `npm link` the command is simply `markcv-mcp`. Without it, use an **absolute path**
144
- to `dist/mcp/server.js`. The repo ships `.mcp.json.example` to copy from.
145
-
146
- **Claude Code** — add to `.mcp.json` in your project (shared with the team), or `~/.claude.json` (just you):
133
+ **Claude Code** add to `.mcp.json` in your project (shared with the team), or
134
+ `~/.claude.json` (just you):
147
135
 
148
136
  ```json
149
137
  {
150
138
  "mcpServers": {
151
139
  "markcv": {
152
- "command": "markcv-mcp",
140
+ "command": "npx",
141
+ "args": ["-y", "@phuthuycoding/markcv", "mcp"],
153
142
  "cwd": "/path/to/your/cv/folder"
154
143
  }
155
144
  }
156
145
  }
157
146
  ```
158
147
 
159
- Or add it from the command line:
148
+ Or from the command line:
160
149
 
161
150
  ```bash
162
- claude mcp add markcv -- markcv-mcp
151
+ claude mcp add markcv -- npx -y @phuthuycoding/markcv mcp
163
152
  claude mcp list # confirm it connected
164
153
  ```
165
154
 
166
155
  Restart the client afterwards so it picks the server up.
167
156
 
168
- **Claude Desktop** `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows), same `mcpServers` shape, then restart the app.
157
+ If you installed the package globally, `"command": "markcv-mcp"` with no `args`
158
+ works too and starts marginally faster. The repo ships `.mcp.json.example` with
159
+ both shapes.
160
+
161
+ **Claude Desktop** — `~/Library/Application Support/Claude/claude_desktop_config.json`
162
+ (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows), same shape,
163
+ then restart the app.
169
164
 
170
165
  **Cursor** — `.cursor/mcp.json` in the project, same shape.
171
166
 
172
167
  ### File paths in tool arguments
173
168
 
174
- Every tool takes a file path. Relative paths resolve against the **server process's working directory**, so either pass absolute paths or give the server a `cwd`:
175
-
176
- ```json
177
- {
178
- "mcpServers": {
179
- "markcv": {
180
- "command": "node",
181
- "args": ["/path/to/markcv/dist/mcp/server.js"],
182
- "cwd": "/path/to/your/cv/folder"
183
- }
184
- }
185
- }
186
- ```
169
+ Every tool takes a file path, and relative paths resolve against the **server
170
+ process's working directory** — hence the `cwd` above. Without it, pass absolute
171
+ paths instead.
187
172
 
188
173
  ### Tools
189
174
 
@@ -201,7 +186,8 @@ Every tool returns **structured JSON**, not prose — so an agent can loop on it
201
186
 
202
187
  ### Requirements
203
188
 
204
- Node >= 18 and a Chromium-based browser. If it is in a non-standard location:
189
+ Node >= 18 and a Chromium-based browser (only `render` and `check_fit` need it).
190
+ If it is in a non-standard location:
205
191
 
206
192
  ```json
207
193
  { "mcpServers": { "markcv": { "command": "node", "args": ["..."],
package/dist/cli.js CHANGED
@@ -8,8 +8,9 @@ import { lint } from "./core/lint.js";
8
8
  import { tailor } from "./core/tailor.js";
9
9
  import { newVariant, listVariants, diffVariants } from "./core/variants.js";
10
10
  import { c, ok, bad, warn, info } from "./ui.js";
11
+ import { VERSION } from "./version.js";
11
12
  const program = new Command();
12
- program.name("markcv").description("Build, fit and audit a CV written in Markdown").version("0.1.0");
13
+ program.name("markcv").description("Build, fit and audit a CV written in Markdown").version(VERSION);
13
14
  const pdfNameFor = (md) => md.replace(/\.md$/, ".pdf");
14
15
  function printFit(r) {
15
16
  const head = r.fits ? ok(`${r.pages} page(s)`) : bad(`${r.pages} pages (target ${r.targetPages})`);
@@ -185,4 +186,13 @@ program
185
186
  console.log(`${mark} ${f.padEnd(34)} ${fit.pages} page(s) ${c.dim(fit.fits ? "" : fit.suggestions[0] ?? "")}`);
186
187
  }
187
188
  });
189
+ program
190
+ .command("mcp")
191
+ .description("Start the MCP server on stdio (for AI agent clients)")
192
+ .action(async () => {
193
+ // Importing the server starts it: it connects to stdio and stays there.
194
+ // Having it as a subcommand is what lets `npx @scope/pkg mcp` work without
195
+ // the --package dance a second binary would need.
196
+ await import("./mcp/server.js");
197
+ });
188
198
  program.parseAsync(process.argv);
@@ -10,7 +10,8 @@ import { analyseFit } from "../core/fit.js";
10
10
  import { lint } from "../core/lint.js";
11
11
  import { tailor } from "../core/tailor.js";
12
12
  import { newVariant, listVariants, diffVariants } from "../core/variants.js";
13
- const server = new McpServer({ name: "markcv", version: "0.1.0" });
13
+ import { VERSION } from "../version.js";
14
+ const server = new McpServer({ name: "markcv", version: VERSION });
14
15
  /** Every tool returns JSON so an agent can loop on the result, rather than prose for a human. */
15
16
  const json = (data) => ({
16
17
  content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
@@ -0,0 +1 @@
1
+ export declare const VERSION: string;
@@ -0,0 +1,21 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ /**
5
+ * Read the version from package.json instead of hardcoding it.
6
+ * A hardcoded copy silently goes stale the moment a release is cut, and then
7
+ * `--version` reports one thing while the installed code is another.
8
+ */
9
+ function readVersion() {
10
+ const here = dirname(fileURLToPath(import.meta.url));
11
+ for (const rel of ["../package.json", "../../package.json"]) {
12
+ try {
13
+ return JSON.parse(readFileSync(join(here, rel), "utf8")).version;
14
+ }
15
+ catch {
16
+ // try the next candidate: dist/ is one level deeper than src/
17
+ }
18
+ }
19
+ return "0.0.0";
20
+ }
21
+ export const VERSION = readVersion();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phuthuycoding/markcv",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Fit, lint and build a CV from Markdown - CLI + MCP server for AI agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -15,7 +15,8 @@
15
15
  "dist",
16
16
  "themes",
17
17
  "README.md",
18
- "LICENSE"
18
+ "LICENSE",
19
+ "CHANGELOG.md"
19
20
  ],
20
21
  "engines": {
21
22
  "node": ">=18"
@@ -26,7 +27,8 @@
26
27
  "mcp": "node dist/mcp/server.js",
27
28
  "test": "node --test test/*.test.js",
28
29
  "prepublishOnly": "npm run build",
29
- "prepare": "npm run build"
30
+ "prepare": "npm run build",
31
+ "changelog": "node scripts/changelog.mjs"
30
32
  },
31
33
  "keywords": [
32
34
  "cv",