mcpField
C
cvx

cvx

本地服务
github.com/hrtips生产力210 周前更新

关于 cvx

CVX 是本地命令行工具和 MCP 服务,可将 YAML 简历内容转换为设计版或 ATS 友好型 PDF,供个人和编码 Agent 使用。它支持校验数据并在本机完成渲染。

主要功能

  1. 01生成简历 YAML 文件框架
  2. 02校验内容并报告修正项
  3. 03渲染设计版或 ATS 友好型 PDF
  4. 04选择主题和页面布局
  5. 05预览分页而不生成 PDF
  6. 06提供机器可读的命令行输出

适用场景

  1. 01将结构化简历信息生成 PDF
  2. 02渲染前检查 YAML 内容
  3. 03准备 ATS 友好型单栏简历
  4. 04让 Agent 在本地编辑并生成简历

MCP 相关

CVX 为 MCP 客户端提供五种工具:get_schema、init_cv、validate_cv、build_pdf 和 plan_layout。服务完全离线运行,无需 API 密钥。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"hrtips-cvx": {
"command": "npx",
"args": [
"-y",
"@hrtips/cvx"
]
}
}
}
启动命令npx -y @hrtips/cvx

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npm@hrtips/cvx1.8.1

工具

5

收录的工具列表 · 更新于 2 周前

参数类型必填说明
dirstring否包含 cv-content/ 的工作区文件夹的绝对路径。默认为服务端工作目录。
guidesarray否在 `guides` 数组中以内嵌方式返回这些随包提供的指南全文。省略此参数(默认值)仅返回清单 — 仅 ai-guide.md 就约 20 kB,因此需要时再请求,而不要每次调用都请求。

详细介绍

CVX

结构化输入。专业输出。释放 X 的力量。

CI npm 版本 npm 下载量 安装大小 许可证

CVX 可将普通 YAML 转换为设计专业的简历 PDF——只需一条命令,全程本地运行,无需账号;你的数据绝不会离开你的设备。 有两种使用方式:自己编辑 YAML,或者让任意 AI 助手根据你现有的简历代为编写——CVX 会验证文件,并准确告知助手需要修正的内容。

🤖 AI 助手:如果用户要求你使用 CVX 创建简历,请遵循AI 指南中的默认流程(“Default flow (for assistants)”一节)。即使不查看链接,也必须遵守以下要求:绝不编造事实——每条内容都必须符合用户提供的信息;即使公开可见,也无法抓取 linkedin.com 网址——不要据此推断,请用户提供个人资料中的 More → Save to PDF 导出文件或粘贴的文本;首次回复时请索要一张方形照片(无法生成;没有照片,简历也能正常呈现);并且 CVX 是唯一的渲染工具——绝不能替换为其他 PDF 生成器。

**没有终端?没关系。**将以下内容粘贴到任意 AI 聊天工具(Claude、ChatGPT、Gemini,……)中:

Create my CV with https://github.com/hrtips/cvx — open that page and follow its instructions for AI assistants.
Here is my LinkedIn profile: <your profile URL> (or attach your current CV and a photo instead).

CVX 生成的双栏设计简历——青绿色主题、照片侧栏、成就

脚手架生成的示例简历第 1 页——还可通过 --ats 生成 适合 ATS 的单栏版本。自截图以来,分页效果已有改进;你的构建结果可能会以不同方式分页。


两分钟创建简历

npx @hrtips/cvx init     # scaffold cv-content/ with a complete example CV
npx @hrtips/cvx build    # render it to a PDF

init 会为你生成一份完整可用的简历——Bruce Wayne 的,没错,真的是他。打开 bruce-wayne.pdf,你看到的就是一份设计完善的两页简历:照片、侧栏、成就,应有尽有。

现在把它改成你自己的简历。打开 cv-content/ 文件夹,逐个文件将 Bruce 的信息替换为你自己的:

cv-content/
  personal.yaml       ← start here: your name, title, contact details
  summary.yaml        ← the bullet points at the top of page 1
  experience.yaml     ← your work history (the bulk of the CV)
  education.yaml      ← degrees, institutions, years
  competencies.yaml   ← skill pills in the sidebar
  achievements.yaml   ← awards and recognitions
  referees.yaml       ← referees, or [] for "available upon request"
  images/profile.jpg  ← your photo (square, 400×400px or larger)

每修改一个文件后,重新运行 npx @hrtips/cvx build,看着 PDF 更新——将 Bruce 的条目和你的条目并排对照,格式就一目了然。输出文件会自动以你的名字命名(jane-doe.pdf)。

打错字了,或者不确定文件是否正确?npx @hrtips/cvx validate 会一次检查所有内容,并准确告知你需要修正的地方:

cv-content/personal.yaml
  ⚠ unknown key "linkdin"
      ↳ did you mean "linkedin"?

每个脚手架生成的文件都带有 $schema 标头,因此支持 YAML 的编辑器(VS Code + YAML 扩展、JetBrains,……)可以在你输入时自动补全键并标记错误。

通过招聘门户申请工作?也生成适合 ATS 的版本——单栏、无颜色,便于机器读取:

npx @hrtips/cvx build --ats
CLI 参考
命令作用
npx @hrtips/cvx init使用示例简历创建 cv-content/(不会覆盖已有内容)
npx @hrtips/cvx validate检查 cv-content/——一次性列出所有问题,并提供文件和字段路径及修复方法
npx @hrtips/cvx validate --strict警告(未知键)也会导致失败;建议 Agent/CI 使用
npx @hrtips/cvx build将 cv-content/ 渲染为 <your-name>.pdf
npx @hrtips/cvx build --ats渲染 ATS 友好的单栏版本
npx @hrtips/cvx list显示可用主题和布局
npx @hrtips/cvx --help / --version帮助 / 版本

所有命令都接受 --json,用于生成机器可读的输出(stdout 输出一个 JSON 对象,日志输出到 stderr),并使用语义化退出码:0 表示正常,2 表示验证失败,3 表示渲染失败,64 表示用法错误。init 只是为了方便,并非必需——build 可以渲染任何包含有效 YAML 的 cv-content/ 文件夹(内置主题和布局无需额外文件)。

内容架构: 内容文件通过 config.yaml 中的 schemaVersion 标记版本(当前为 1),并根据规范 JSON Schema进行验证。一个架构主版本中可能会新增键。经过验证确认无作用的键也可能会被移除——page1ExperienceCount 和 page1SplitBullets 就在 1.8.0 中被移除——此时构建仍可正常运行,validate 会指出该键已移除,而 validate --strict 会将现在未知的键视为错误。执行移除操作的版本会在 CHANGELOG 中说明。


各文件的内容

以下是脚手架生成的示例片段——构建一次,就能准确看到每个片段在页面上的位置。

personal.yaml — 页眉和联系信息:

name: Bruce Wayne
title: Founder & Field Commander – Gotham Operations
company: Wayne Enterprises
phone: "+1 (201) 555-2283"
phoneHref: "tel:+12015552283"
email: [email protected]
linkedin: linkedin.com/in/brucewayne
linkedinHref: "https://www.linkedin.com/in/brucewayne"

experience.yaml — 每个职位对应一条记录;progression(可选)会在记录中显示职位历史:

- role: Founder & Field Commander – Gotham Operations
  company: The Batman
  period: 2005 – Present
  description: Self-directed vigilante operation safeguarding Gotham City through deterrence, investigation, and crisis response.
  progression:
    - title: Commander, Batman Incorporated
      period: 2011 – Present
    - title: Solo Operative, The Dark Knight
      period: 2005 – 2008
  bullets:
    - Established and scaled a citywide security operation from a solo initiative to a franchised network (Batman Incorporated).
    - Recruited, trained, and led a high-performing field team including Robin, Nightwing, and Batgirl.
    - Reduced organised-crime activity in Gotham by an estimated 60% through data-driven surveillance and rapid incident response.

summary.yaml — 第 1 页顶部的项目符号列表:

- "Strategic operations leader with 20+ years' experience, progressing from solo field operative to Field Commander of a citywide security network."
- "Co-founded the Justice League as a global response coalition, serving as chief strategist and contingency planner for existential-scale threats."

education.yaml

- degree: "Applied Sciences & Criminology (self-directed)"
  institution: League of Shadows
  period: 1998 – 2004

- degree: BSc, Criminology & Chemistry
  institution: Gotham University
  period: 1994 – 1998

competencies.yaml — 在侧边栏中显示为技能标签:

- Strategic Planning
- Criminal Investigation
- Crisis Response
- Surveillance & Intelligence

achievements.yaml

- year: Gotham's Most Influential Citizen
  text: "— 2024, Gotham Gazette"

- year: Key to the City
  text: "— Office of the Mayor, Gotham City"

referees.yaml(使用 [] 可显示“可按要求提供”):

- name: Diana Prince
  title: Founding Member, Justice League
  company: Themysciran Embassy
  email: [email protected]
  phone: "+1 (202) 555-0177"

删除不需要的内容即可——空文件(或 [])会直接从简历中移除对应部分。放入 cv-content/ 的任何新 .yaml 文件都会自动识别为内容键。

每个文件的完整字段架构说明见 docs/cv-schema.md。

让 AI 为你编写 YAML

这些格式特意设计为便于大模型使用,架构也已发布供机器读取(llms.txt、docs/cv-schema.md)。AI 指南 为各种方式提供了可直接复制粘贴的提示词;简要说明如下:

编码 Agent(Claude Code、Cursor 等)——最省事的方式:运行 npx @hrtips/cvx init,然后让 Agent 用你的信息替换示例内容并构建。脚手架生成的 cv-content/README.md 介绍了架构,因此 Agent 会自行编辑、运行 npx @hrtips/cvx build 并修复错误。

聊天助手(Claude、ChatGPT 等)——粘贴已有简历或 LinkedIn 个人资料文本,并附上以下提示词:

阅读 https://raw.githubusercontent.com/hrtips/cvx/main/docs/cv-schema.md 中的 CVX 内容架构,然后将下面的简历转换为 CVX cv-content/ YAML 文件。每个文件分别放在独立的围栏代码块中,并以文件名作为标题。确保每条事实都忠于我的输入,不要编造任何内容。

将生成的文件保存到 cv-content/,放入你的照片,然后运行 npx @hrtips/cvx build。你的助手无法访问网页?请使用自包含提示词。

将其接入你的 Agent(MCP)

CVX 附带一个 MCP 服务——任何 MCP 客户端(Claude Desktop、Claude Code、Cursor、VS Code,等等)都可以通过五个工具驱动整个流程:get_schema、init_cv、validate_cv、build_pdf 和 plan_layout(一次试运行,用于报告简历的分页情况——页数、每页各栏的填充情况以及内容的分布位置,不会写入 PDF)。无需 API 密钥,完全离线。

CVX 会渲染 YAML 中的 100% 内容,绝不会为了适应页面而丢弃、裁切或隐藏文本——因此,驱动它的助手也无法悄悄删减某个部分来凑页数。如果简历比你期望的更长,它会展示其中的取舍,由你决定删减哪些内容。

npx @hrtips/cvx mcp init --client claude          # Claude Code (.mcp.json, project)
npx @hrtips/cvx mcp init --client claude-desktop  # Claude Desktop (global config)
npx @hrtips/cvx mcp init --client cursor          # Cursor (.cursor/mcp.json)
npx @hrtips/cvx mcp init --client vscode          # VS Code (.vscode/mcp.json)

然后重启客户端,请它制作你的简历——它会获取架构、搭建初始文件、填入你的详细信息、在每次编辑后进行验证,并渲染 PDF。配置写入器会将内容合并到现有文件中,不会覆盖其他服务。另有一个开箱即用的 Agent Skill,为支持 Skill 的 Agent 提供相同的流程。

将其构建到 ChatGPT GPT 中

ChatGPT 的沙盒有 Node 运行时,但通常无法访问 npm 注册表,因此 npx 在其中无法使用。为此,CVX 也以单个独立文件的形式提供——架构、模板、字体等全部包含在内,并以 cvx.bundle.min.js 的形式附在每个发行版中。它除了 Node 20+ 之外不需要任何东西:无需安装、无需 node_modules,也无需额外下载。

大多数 ChatGPT 沙盒都能自行获取该文件,因此你无需上传任何内容——Route D 提示词会原样提供四条设置命令。这一点很重要,因为如果让助手自行摸索,它会先尝试 npx,白白浪费你的轮次。如果下载受阻,请下载 0.92 MB 的 zip 并上传;之后的步骤完全相同。

GPT 可以完成聊天助手通常做不到的事:渲染 PDF、打开 PDF 并查看页面,然后在你看到之前调整布局。

你的照片

将照片放入 cv-content/images/,命名为 profile.<ext>——系统会自动检测 jpg、jpeg、png 或 webp(如果存在多个格式,按此顺序优先)。裁剪为正方形,至少 400×400px。


主题、布局和分页

所有视觉样式都由 cv-content/config.yaml 控制:

theme: teal               # teal | coral | mono
layout: two-column        # two-column | single-column

修改一个值,重新运行 npx @hrtips/cvx build,即可完成。

主题控制颜色和样式:

主题强调色说明
teal#1a6070专业青绿色(默认)
coral#c0534a温暖的珊瑚红
mono#000000黑白配色,为 ATS 优化

布局控制页面结构:

布局结构说明
two-column侧栏 + 主栏设计精美的简历,带有照片、个人信息区块和成就
single-column全宽适用于 ATS,无侧栏、无装饰元素

分页——系统会自动将工作经历条目分配到各页(采用贪心装箱算法),确保内容不会溢出页面;如果某个条目太长,无法放入剩余空间,系统会在项目符号边界处拆分,并在下一页续排。没有分页设置:布局会随内容自动调整。(旧的 page1ExperienceCount / page1SplitBullets 键已移除——经测试,它们从未减少页数,强制使用反而会将内容推到一张未编号的额外页面上。仍包含这些键的配置会收到一条验证消息,明确说明这一点。)

脚本支持

CV 渲染仅支持英语/西欧拉丁文字。 CVX 打包了 Lato,且不注册备用字体,因此 Lato 不支持的文字——西里尔文、希腊文、越南语、土耳其语中的 ş/ğ、捷克语/罗马尼亚语变音符号,以及所有非拉丁文字(天城文、泰米尔文、僧伽罗文、CJK、阿拉伯文等)——都会无法显示。cvx validate 和 cvx build 会在内容包含打包字体无法绘制的字符时发出醒目警告,因此问题会清楚地显现,而不会悄无声息地发生。

这是有意为之的范围决策,并非疏忽:为这些文字提供备用字体会让软件包体积超出预算许多倍。(项目网站支持多语言;渲染器不支持——两者相互独立。)

自定义布局

你可以定义自己的页面结构——将 .yaml 文件放入 cv-content/layouts/,然后通过文件名引用:

# cv-content/layouts/compact.yaml
template: two-column

pages:
  first:
    sidebar:
      - identity-photo
      - contact
    main:
      - summary
      - spacer: 27
      - experience

  continuation:
    sidebar:
      - identity-compact
      - education
      - competencies
      - achievements
    main:
      - experience:continued

  last:
    sidebar:
      - identity-compact
      - referees
    main:
      - experience:continued

然后在 config.yaml 中设置 layout: compact。

侧栏的三个列表属于同一条有序流,而非分别分配给三个页面。 first.sidebar + continuation.sidebar + last.sidebar 会按此顺序拼接,CVX 会测量拼接后的内容,以确定每个部分落在哪一页。因此,last.sidebar: [referees] 的意思是 “referees 在侧栏中排在最后”,而不是 “referees 显示在最后一页”。用这些分组表达顺序;分页由测量结果决定。(identity-photo/identity-compact 是例外——它们会注入每一页侧栏的顶部,而不是参与排版。)主栏列表仍按页面类型区分:first.main 用于第 1 页,last.main 用于最后一页,continuation.main 用于中间页面。

可用的部分键:

键渲染内容
identity-photo姓名、头衔、公司 + 个人资料照片(侧栏)
identity-compact姓名、头衔、公司,不含照片(侧栏)
contact电话、电子邮件、LinkedIn、带图标的所在地(侧栏)
achievements年份 + 描述列表(侧栏)
education学位、院校、时间段(侧栏)
competencies药丸样式的技能标签(侧栏)
referees推荐人联系方式(侧栏)
summary项目符号列表(主栏)
experience第 1 页的工作经历条目(主栏)
experience:continued后续页面的工作经历条目(主栏)
header-ats全宽姓名/头衔/联系方式页眉(单栏)
spacer: N高度为 N 点的垂直间隔

ATS 和 AI 解析器关键词

两份 PDF 都会将关键词列表嵌入标准的 Keywords 元数据字段——某些申请人跟踪系统(ATS)和 AI 简历解析器会读取此字段。关键词位于元数据中,不会作为隐藏文本出现在页面上。

现实情况:大多数主流 ATS 根据从简历正文提取的文本进行排名,而对 PDF Keywords/XMP 字段的支持并不一致。请将其视为对关键词丰富的正文的尽力补充,而非替代品,也不要指望它单独成为可靠的排名手段。确保每个关键词都真实;填入虚假或无关词语会导致元数据与正文不符,进而使简历被自动拒绝。

关键词来自两个来源,合并后去重(正文提取的词语排在前面):

  1. 自动提取自你的 competencies.yaml 和职位名称(公司名称信号较弱,因此会有意排除)。
  2. 在 cv-content/keywords.yaml 中手动整理——可以使用扁平列表,也可以按标题分组:
# cv-content/keywords.yaml
- Operations Management
- Risk Management
# …or grouped:
Leadership: [Executive Leadership, Team Building]

在 config.yaml 中配置:

atsKeywords:
  enabled: true       # master switch                                  (default: true)
  autoDerive: true    # also derive from competencies + job titles      (default: true)
  max: 40             # optional cap; body-derived terms are kept first (default: all)


面向开发者

以下内容均与开发 CVX 本身有关——自定义主题、渲染流程以及贡献代码。创建简历时不需要了解这些内容。

基于克隆版本开发

git clone [email protected]:hrtips/cvx.git
cd cvx
npm install
npm run dev        # live browser preview at http://localhost:5173
npm run pdf        # generate PDF (same pipeline as `cvx build`)
npm run pdf:ats    # generate the ATS variant
npm test           # unit tests
npm run build:lib  # build the publishable lib/ (what the CLI runs)

仓库中的 cv-content/ 带有相同的 Bruce Wayne 示例,因此克隆后即可直接构建。项目还包含照片裁剪辅助脚本:python3 scripts/crop-profile.py path/to/photo.jpg。

自定义主题

主题随软件包一同发布,因此目前要使用自定义主题,需要基于克隆的仓库进行操作 — npx CLI 提供了三个内置主题。

在 src/pdf/themes/ 中放入一个 .js 文件 — 系统会自动发现,无需注册:

// src/pdf/themes/navy.js
import { tealTheme } from './teal.js'

export const navyTheme = {
  ...tealTheme,
  name: 'navy',
  palette: {
    ...tealTheme.palette,
    accent:    '#1e3a5f',
    sidebarBg: '#eef1f5',
    tagBg:     '#d0d8e8',
    tagText:   '#1e3a5f',
    divider:   '#b8c4d4',
  },
}

在 config.yaml 中设置 theme: navy。主题对象包含五个可覆盖的命名空间:

命名空间控制内容
palette所有颜色 — 强调色、背景、文本、标签、分隔线、语义透明度颜色
typography各元素的字号、字重、字间距、行高
spacing所有组件使用的间距、外边距、内边距值
chrome装饰尺寸 — 圆角半径、分隔线宽度、照片尺寸、角标
geometry页面尺寸、列宽比例、内边距对象

自动发现

约定优于注册 — 将文件放入正确的文件夹即可自动识别:

内容放置位置发现方式
内容cv-content/*.yaml除 config.yaml 外,任何 .yaml 文件都会成为与其文件名对应的内容键
主题src/pdf/themes/*.js任何导出带有 name 属性对象的 .js 文件
布局cv-content/layouts/*.yaml任何包含 template 和 pages 结构的 .yaml 文件
个人资料照片cv-content/images/profile.*首个匹配 .jpg、.jpeg、.png、.webp 的文件

要添加一个全新的内容板块(例如出版物):创建 cv-content/publications.yaml(自动提供为 content.publications),在 src/pdf/sections/ 中构建板块组件,在 registry.js 中注册,然后在布局中引用它。

架构

三个可独立替换的关注点:

Content (YAML)  ×  Theme (JS)  ×  Layout (YAML)
     ↓                ↓               ↓
  what to say    how it looks    where it goes

渲染流水线:

config.yaml → resolves theme + layout
    ↓
cv-content/*.yaml → auto-loaded into data bag
    ↓
layout.js → packs experience entries across pages (using theme metrics)
    ↓
CVDocument → picks template (TwoColumn or SingleColumn)
    ↓
template → renders slots from layout config via section registry
    ↓
sections → read theme from React context, render content
    ↓
@react-pdf/renderer → PDF buffer → file

项目结构

cv-content/                      ← content (the repo carries the example CV)
  *.yaml                         ← auto-discovered content files
  config.yaml                    ← theme, layout, pagination
  layouts/                       ← auto-discovered layout definitions
  images/profile.<ext>           ← photo (jpg/jpeg/png/webp)

src/pdf/                         ← framework
  CVDocument.jsx                 ← unified config-driven document
  ATSDocument.jsx                ← standalone ATS document
  ThemeContext.jsx               ← React context + useStyles hook
  render.js                      ← shared render pipeline (CLI + scripts)
  layout.js                      ← theme-aware page-packing + sidebar resolution
  keywords.js                    ← ATS/AI-parser keyword metadata
  reproducible.js                ← SOURCE_DATE_EPOCH support (see below)
  profilePhoto.js                ← shared profile-image extension precedence
  loadContent.js                 ← auto-discovers cv-content/*.yaml
  loadLayout.js                  ← normalizes layout YAML → slot config
  fonts.js                       ← Lato font registration
  *.test.js                      ← Vitest unit tests (co-located)
  themes/                        ← auto-discovered themes (teal, coral, mono)
  templates/                     ← page shells (TwoColumn, SingleColumn)
  sections/                      ← content sections + registry
  components/                    ← shared leaf components

scripts/
  export-pdf.js                  ← npm run pdf
  export-pdf-ats.js              ← npm run pdf:ats
  build-lib.js                   ← npm run build:lib (publishing build)
  crop-profile.py                ← photo crop helper

bin/cvx.js                    ← npx CLI (init / build)
template/cv-content/             ← starter content scaffolded by `cvx init`
lib/                             ← generated: published transform of src/pdf (gitignored)

测试

npm test

单元测试覆盖纯逻辑模块 — 关键词构建、页面排版、侧边栏解析、可复现性辅助工具以及个人资料照片选择器。测试与其覆盖的代码放在一起(src/pdf/*.test.js),另有用于跨模块检查的 test/。CI 会在 Linux 和 macOS 上使用 Node 20/22/24 运行测试套件(此外,还会在 Windows 上使用 Node 22 运行),然后打包 tarball 并对已安装的 CLI 进行端到端测试,包括字节完全一致的可复现性检查。

质量门禁

构建流程有意设置得很严格 — 只有通过以下所有门禁且零警告的更改才能合并。运行 npm run check(lint + 类型检查 + 覆盖率 + 死代码检查)可在本地一次性执行所有检查;CI 会在 quality 和 security 作业中强制执行这些检查。

门禁命令检查内容
Lint + 格式npm run lintOxlint(快速检查正确性/suspicious,包括 rules-of-hooks、no-focused-tests)+ Biome(格式、导入、更深入的 lint)— 零警告
类型npm run typecheck使用 checkJs + 对 JS/JSX 源码全面启用 strict 的 tsc --noEmit(通过 JSDoc + src/pdf/types.d.ts 提供类型,后者由 JSON Schema 派生)
覆盖率npm run test:covVitest v8,每个文件的行/函数/语句覆盖率均 ≥ 90%,分支覆盖率 ≥ 85% — 不进行全局平均,不允许按文件豁免
死代码npm run knip不存在未使用的文件、导出项或依赖项
软件包npm run publint · npm run attwpublint 软件包检查 + arethetypeswrong 解析检查
供应链security CI 作业actionlint · zizmor(固定到 SHA 的操作、最小权限)· gitleaks · osv-scanner

格式化/lint 自动修复:npm run lint:fix。GitHub Actions 均固定到提交 SHA,并由 Dependabot 保持更新。

可复现构建

设置 SOURCE_DATE_EPOCH(自 Unix 纪元起的秒数),即可确保每次运行生成的 PDF 输出字节级一致——这有助于进行 CI 检查,并验证内容变更是否是唯一的变更:

SOURCE_DATE_EPOCH=$(git log -1 --format=%ct) npx @hrtips/cvx build   # or npm run pdf

这会固定 PDF 的 CreationDate(以及与之关联的尾部文件 ID)、字体子集名称和对象写入顺序——这些内容通常会因运行而异。不设置该变量时,构建行为正常,并会使用当前时间戳。

在相同平台和 Node 版本下,可保证输出字节级一致。在不同操作系统或 Node 主版本上构建时,输出在视觉上相同,但字节级不一致(字体子集的嵌入顺序取决于平台,zlib 输出则会因 Node 版本而异)。

技术栈

  • @react-pdf/renderer — 将 React 渲染为 PDF(无需无头浏览器)
  • Vite + React — 实时浏览器预览
  • js-yaml — YAML 解析(固定使用 4.x 版本,以匹配 @rollup/plugin-yaml)
  • esbuild — 对 lib/ 进行仅转换构建,以便发布
  • tsx — 运行仓库导出脚本
  • Vitest — 单元测试
  • Lato — 嵌入字体(Light 300、Regular 400、Bold 700)

许可证

Apache-2.0 © ramith。

捆绑的 Lato 字体单独采用 SIL Open Font License 1.1 许可。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。