npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

cardbuddy

v0.16.0

Published

Local dev service for the CardBuddy card editor — decouples card CRUD (sync/save/validate/render-status/screenshot) from the static public editor, so the editor can be deployed to any static host while each developer runs a local service against their own

Readme

cardbuddy

本地开发服务(Local Dev Service)—— 把「卡片编辑器平台」的前后端彻底解耦。

编辑器前端是纯静态产物(可部署到任意公网静态托管),而卡片的本地增删查改(同步 / 保存 / 校验 / 渲染自检 / 截图 / 远端取卡)由本服务在开发者本机承接。

目标:编辑器平台统一维护、统一部署;每位开发者只在本地启动一个 cardbuddy,在编辑器「设置 → 本地开发服务」里填好地址,即可立即开发自己的卡片代码。

公共 npm 包:cardbuddy —— npm i -g cardbuddy(或 npx cardbuddy)即可安装使用。

改名说明:本包 0.6.0 起由 cardbuddy-dev 改名为 cardbuddy(可执行命令同名)。旧包 cardbuddy-dev 已 deprecated —— 仍可安装但不再更新,请改用 npm i -g cardbuddy。


快速开始

# 任选其一安装(全局或 npx 均可)
npm i -g cardbuddy
# 或
npx cardbuddy

# 在「卡片代码仓库根目录」下启动:
cd /path/to/your/card-repo
cardbuddy
# → 监听 http://127.0.0.1:8787

启动后,在公网编辑器里打开「设置 → 本地开发服务」,填入 http://127.0.0.1:8787,即可跨源调用本机的卡片 CRUD。


初始化一个新工程(cardbuddy init)

没有现成的卡片工程时,一条命令生成「立刻能开发调试」的最小实例:

npx cardbuddy init my-cards     # 目录不存在会自动创建;省略目录名则在当前目录初始化
cd my-cards
npm install
npm run preview                 # 本地服务(8787) + 内置编辑器前端 + 自动开浏览器

生成内容(增量、幂等:已存在的文件一律保留,加 --force 才覆盖):

| 产物 | 说明 | | --- | --- | | src/cards/ | 卡片目录骨架(后端与编辑器的约定落点) | | src/cards/helloCard/ | 示例卡(schema.json + data.json,构建期已过校验)——起服务即有卡可看可改 | | skills/ | 随包发布的全量技能库:校验 / 同步 / 保存 / 切图上传 / 建卡管线脚本与工作流文档 | | tools/link-skills.mjs | npm run link:skills:把 skills/ 链到 Codex / Claude / WorkBuddy 等 AI 工具的项目级技能目录 | | .env.cb | 共享配置模板(端口、FinMall 远端基址、AI 网关占位;密钥请写 .env.cb.local) | | package.json | 声明 cardbuddy 依赖 + dev / start / preview / link:skills 脚本 | | .gitignore | 只追加缺失条目:node_modules/、.env.cb.local、.cache/、skills/*/.local/ 等 | | README.md | 上手说明 |

参数:--force 覆盖已存在文件 · --dry-run 只报告不落盘 · --no-skills 不释放技能库(项目已自带)· --no-sample 不生成示例卡。

本命令取代了 dsl-card 仓库里旧的 npm run gen:demo:脚手架随 npm 包发布,无需检出仓库, 且版本天然与所装 cardbuddy 一致(旧方案生成的 demo/ 会随主干漂移)。

⚠️ npx cardbuddy init 卡住不退、目录里只多了个 .cache/? 本机装着 0.12.0 之前的 全局旧版:npx 优先命中全局 bin,而旧版没有 init 子命令,会把 init 当无关参数忽略、 转而启动常驻开发服务(于是既不退、也不脚手架)。用 npm ls -g cardbuddy 核对版本, 再 npm i -g cardbuddy@latest 升级,或 npm uninstall -g cardbuddy 让 npx 每次自行拉取。 0.12.0 起 CLI 对未知子命令会直接报错退出,不再静默起服务。


Preview 模式(本地独立调试)

cardbuddy --preview          # 等价短参 -p

启动后,本地服务在同一个 8787 端口同时托管:

  • 卡片 CRUD / 校验 / 截图等 /__xxx API
  • 打包后的编辑器前端(替代 https://poc-agent.finmall.com/cardBuddy/index.html)
  • 自动注入本地 API 地址并打开默认浏览器

命名说明:--preview 指「本地托管编辑器前端做预览」,与端点 GET /__preview(远端取卡)无关。

前端产物来源优先级:

  1. DSL_PREVIEW_ROOT 显式指定目录
  2. npm 包自带的 dist/preview-editor/(发布包内置;旧包布局 dist/offline-editor/ 自动回退)
  3. 当前目录下的 dist/(仓库内直接运行源码时)

包内已内置打包好的编辑器前端(dist/preview-editor/),因此无需自己构建前端即可使用 --preview。

已废弃别名(仍生效):--offline / -o、DSL_DEV_OFFLINE=1、DSL_OFFLINE_ROOT、注入全局 window.__CARD_DEV_OFFLINE_BASE__。请把手上的脚本 / CI / demo 换成 preview 名,旧名将在后续版本移除; 服务端目前会同时注入新旧两个全局名,因此已构建好的旧 dist/ 前端仍能被新服务托管。


MCP:把 card_* 工具挂给外部 AI agent

cardbuddy --mcp        # stdio JSON-RPC 2.0;不启 HTTP 服务、不占端口

编辑器内置的网页 AI 助手走 POST /__ai/chat;--mcp 把同一套 16 个 card_* 工具 (实现同为 mcp/tools.mjs + mcp/client.mjs,不存在第二份契约逻辑)以 stdio 暴露给 Codex / Claude 这类外部 agent。工具清单与用法见 skills/dsl-card-ai/SKILL.md。

agent 侧配置(cwd 必须是卡片工程根,读写才落在 src/cards/):

{
  "mcpServers": {
    "dsl-card": {
      "command": "<工程绝对路径>/node_modules/.bin/cardbuddy",
      "args": ["--mcp"]
    }
  }
}

stdout 是协议信道。 经 npm run 调用必须加 --silent:npm run mcp 会把 > 包名 脚本名 横幅打到 stdout,多一行客户端就解析失败;直接调 node_modules/.bin/cardbuddy --mcp 无此问题。诊断一律走 stderr 且默认静默, CARDBUDDY_MCP_VERBOSE=1 打开(会打出注入后的 root= / apiBase=)。

cardbuddy init 生成的工程已带 npm run mcp 脚本。回归见 tools/tests/cardbuddy-mcp.test.mjs。

第一次接 agent 的人建议先读 dsl-card 仓库的 docs/CardBuddy MCP 新手教程.md:角色拓扑、 Codex / Claude / Cursor 三种注册配置、实测的完整编辑闭环、四个最常见的坑与排查手册。 (该文件在仓库 docs/ 下,不在本包 files 白名单内,故只给路径不给链接。)

工具对本地服务的依赖分档

--mcp 自己不启服务。启动时自动注入 CARD_ROOT=<工程根> 与 CARD_API_BASE=http(s)://127.0.0.1:<端口>(端口取 CARDBUDDY_CARD_PORT / DSL_DEV_PORT,默认 8787;已有同名环境变量时不覆盖),工具据此决定走 HTTP 还是本地降级:

| 档 | 工具 | | --- | --- | | 纯本地,从不需要服务 | card_route_input card_scaffold card_add_component | | 优先服务,连不上自动降级为直接读写盘(validate 跑 Python 校验器) | card_list card_read card_write card_validate card_history card_rollback | | 优先服务,降级到包内独立离线渲染器 | card_screenshot | | 必须另起一个 cardbuddy | card_render_status card_node_models card_import_meta | | 必须另起服务 且已登录 FinMall | card_sync card_save card_slice_upload |

别直接跑包内 dist/vendored/mcp/server.mjs。 mcp/client.mjs 在模块顶层就 resolve CARD_ROOT / CARD_API_BASE(不是每次调用时读),绕过 CLI 包装层时前者会落到包内快照目录 (card_list 返回 0 张卡)、后者回退 devApiBase() 的 5180(消费者工程没有 Vite 把 /__* 代理到 8787,card_render_status 直接 dev-server-required)。仓库内跑源码时入口回退 <repo>/mcp/server.mjs,无需先 build。


配置(环境变量 / .env)

在仓库根目录的 .env 中配置,或直接用环境变量:

| 变量 | 默认 | 说明 | | --- | --- | --- | | DSL_CARD_ROOT | 当前目录 (cwd) | 卡片代码仓库根(含 src/cards)。可用环境变量二次覆盖。 | | DSL_DEV_PORT | 8787 | 本地服务监听端口。 | | DSL_DEV_PORT_TAKEOVER | auto | 端口被占用时的接管策略:auto 自动结束占用该端口的旧 cardbuddy 实例后启动;force 连无关进程一并结束;off 关闭前置检查(退回原生 EADDRINUSE 报错)。 | | EDITOR_URL | http://127.0.0.1:5180 | 截图自访问的编辑器实例地址(默认指向本地编辑器)。写入 .env 即可持久化。 | | DSL_DEV_TOKEN | (空) | 可选鉴权令牌;开启后请求须带 x-dev-token 头。默认仅靠 127.0.0.1 绑定(不暴露局域网)。 | | DSL_DEV_HTTPS | 0 | 设为 1 启用自签 HTTPS(兜底旧 Safari / 企业策略的混合内容拦截)。 | | DSL_EDITOR_SRC | (空) | 内核开发用:指向本地编辑器 card-editor/ 源码,绕过 vendored 快照调试。 | | DSL_DEV_PREVIEW | 0 | 设为 1 等价于 --preview:同端口托管打包后的编辑器前端并自动打开浏览器。 | | DSL_PREVIEW_ROOT | (空) | 自定义 preview 前端构建产物目录(默认包内 dist/preview-editor/,回退 cwd/dist)。 | | DSL_EDITOR_CMD | (空) | 代码桥外部编辑器命令(如 code / cursor / 带参数整串),按 shell 语义执行并追加临时文件路径;缺省按平台拉起 VSCode(mac open -a、win cmd /s /c "code"、linux code),CLI 缺失再回退 vscode:// 协议。 |


端口被占用时自动接管

启动前先探测 DSL_DEV_PORT:若被上一个 cardbuddy 实例占用(终端直接关掉、Ctrl+C 漏杀、后台残留等), 自动 SIGTERM(宽限 2.5s 后升级 SIGKILL)结束旧进程、等端口真正释放,再继续启动,免去手动 lsof -ti tcp:8787 | xargs kill。

判定「占用者是本服务」有两条依据:HTTP 探测 /__cards 返回 cardbuddy 响应体({ cards: [...] } 或 token 鉴权 403), 或占用进程命令行含 cardbuddy / dsl-card 字样。无关进程占着端口时不会动手,而是直接报错并给出手动处理命令; 确需强制接管设 DSL_DEV_PORT_TAKEOVER=force。

跨平台:macOS / Linux 用 lsof 定位 PID(缺失时回退 ss),Windows 用 netstat -ano + taskkill /T /F。


HTTPS 模式(混合内容兜底)

默认本服务跑在 http://127.0.0.1:8787。当公网编辑器是 HTTPS 时,浏览器可能因「混合内容(Mixed Content)」或「私有网络访问(PNA)」策略拦截对 http://127.0.0.1 的跨源请求。现代 Chrome / Firefox 对回环地址(127.0.0.1 / localhost)豁免混合内容,默认即可用;但 Safari 等更严格的环境会拦截,此时启用 HTTPS 模式:

DSL_DEV_HTTPS=1 cardbuddy
# → 监听 https://127.0.0.1:8787,证书首次自动生成并缓存到 <root>/.local/dsl-dev-tls/

证书为自签(SAN 覆盖 localhost / 127.0.0.1 / ::1),不在系统信任链,首次使用需:

  1. 在浏览器手动打开 https://127.0.0.1:8787/__cards;
  2. 接受「您的连接不是私密连接」警告(一次性,之后该主机被信任);
  3. 回到编辑器「设置 → 本地开发服务」,把 Base URL 改为 https://127.0.0.1:8787 即可。

即便走 HTTP 模式,CORS 层也已回写 Access-Control-Allow-Private-Network: true,向前兼容 Chrome 的 PNA 预检。


端点(与编辑器约定的 /__xxx)

| 端点 | 来源 | 说明 | | --- | --- | --- | | GET /__cards | 自包含 | 卡片列表 | | GET /__card/:id | 自包含 | 单卡 schema/data 读取 | | POST /__sync | 本地服务代理 | 同步远端 FinMall(依赖 finmall-card-sync skill) | | POST /__save | 本地服务代理 | 保存到远端 FinMall(依赖 finmall-card-sync skill) | | GET /__preview | 本地服务代理 | 远端取卡(IDC10015,依赖 finmall-card-sync skill) | | POST /__validate | 本地服务代理 | 契约校验(依赖 dsl-card-generator skill) | | GET /__render-status/:id | 自包含 + 内嵌 Vite SSR | 渲染自检 | | GET /__node-models/:id | 自包含 + 内嵌 Vite SSR | 节点 Property 树模型 | | GET /__import-meta/:id | 自包含 | 导入侧车元数据 | | GET /__history | 自包含 | 编辑历史 | | GET /__screenshot/:id | 自包含(需 Playwright + 系统 Chrome)| 无头截图 | | GET /__events (SSE) | 自包含 | cards-changed 实时推送 | | POST /__code-bridge | 自包含 | 代码桥:代码写临时 js 并拉起外部编辑器,返回 { id, file } | | GET /__code-bridge/:id | 自包含 | 代码桥:拉取外部保存后的最新代码(LF 归一) | | POST /__code-bridge/:id/heartbeat | 自包含 | 代码桥:会话心跳(前端 5s 一次) | | DELETE /__code-bridge/:id | 自包含 | 代码桥:结束会话并删除临时文件 |

FinMall 凭据只在本机:/__sync /__save /__preview 由本地服务代理 FinMall,凭据存于本机 skills/finmall-card-sync 与 .env.cb,公网前端永不接触。

VSCode 代码桥(事件面板代码编辑区)

事件配置面板的代码编辑区底栏右侧有 VSCode 图标:点击后把当前代码片段写到 os.tmpdir()/cardbuddy-code-bridge/<session>.js 并用外部编辑器打开;编辑器内保存即经 文件监听 + SSE(code-bridge-changed)实时回写编辑区(桥接期间 Web 编辑区只读,避免双向冲突)。

  • 清除语义:会话结束 = 再次点击图标断开 / 面板关闭 / 组件卸载(前端 DELETE), 或心跳 TTL 兜底(20s 无心跳即删,覆盖关浏览器 / 崩溃);服务启动时清扫 >24h 残留。 VSCode 标签页关闭事件不装扩展拿不到,故不以「关标签」为清除时机。
  • 回声环防护:服务端写入哈希去重(忽略自写回声);前端回写用 updateCode(code, false) 不触发 onUpdate,不会把收到的内容再写回临时文件。
  • 换编辑器:DSL_EDITOR_CMD=cursor 或任意命令整串(按 shell 语义执行,开发者自配环境变量)。
  • 拉起方式(任一级 spawn 失败或非 0 退出自动降下一级): win code "<file>" → vscode:// 协议;mac open -a "Visual Studio Code" → code CLI → vscode:// 协议; linux code → xdg-open vscode://。文件监听 win/mac/linux 均走 chokidar(原子保存改名覆盖可捕)。

依赖:技能库(skills/)

远端读写与校验类端点(/__sync /__save /__preview /__validate)以及 AI 助手的 skill_read / skill_exec,都通过动态 import / 子进程调用技能脚本:

  • finmall-card-sync(sync / save / preview / 切图上传)
  • dsl-card-generator(validate / autofix / 建卡管线)
  • finmall-session-navigator(FinMall 登录会话;凭据落 skills/finmall-session-navigator/.local/credentials.json)

解析顺序(见 server/core/skillPaths.js,全后端统一):

  1. DSL_SKILLS_ROOT 显式指定;
  2. 项目根 skills/ —— 跑过 cardbuddy init 即有,推荐:可写(凭据、审计、缓存都落在项目内)、随项目走;
  3. 包内快照 dist/vendored/skills/ —— 随 npm 包发布的全量技能库,没跑 init 也能只读兜底。

远端能力(同步 / 保存 / 切图上传)还需要 .env.cb 里的 FINMALL_BASE_URL 等配置, 以及 playwright(本包 optionalDependency,默认会装)与一次 FinMall 登录。 写入类文件(凭据等)永远落项目根,不会写进 node_modules。


安全

  • 仅绑定 127.0.0.1,不暴露局域网。
  • CORS 反射请求 Origin(任意公网域名均可跨源调用,无需配置白名单)。
  • 可选 x-dev-token 鉴权。
  • HTTPS 自签模式(DSL_DEV_HTTPS=1)兜底混合内容拦截(Safari / 严格策略);Chrome / Firefox 默认 HTTP 即可用。

本地开发(编辑器 + 本地服务)

本仓库既是「卡片编辑器平台」的源码,也是 cardbuddy 的源码。下面说明怎么在本地开发编辑器本身(即 card-editor/ 前端与 server/core/ 后端)。

关键区别:同域(dev)vs 跨域(生产)

npm run dev 能"免费"工作,是因为 card-editor/api.js 的 resolveApiBase() 在 import.meta.env.DEV 为真时走同源(第 3 条回退),而这条同源路径在生产里不存在——build 产物的 DEV=false,生产永远依赖「编辑器配好 8787 地址 + 跨源调用本地服务」。

所以本地开发分两条互补的路径:

| 命令 | 编辑器来源 | 后端来源 | 用途 | | --- | --- | --- | --- | | npm run dev | card-editor/ 源码(Vite dev + HMR,5180) | cardbuddy 服务(8787,由 tools/dev.mjs 同起) | 日常改编辑器 / 卡片 | | npm run dev:prod | dist/ 构建产物(vite preview) | cardbuddy 服务(8787) | 部署前权威跨域 smoke test(最贴近生产) | | 部署公网 | dist/ 静态托管(CDN) | 用户本机起 8787 | 生产环境 |

已废弃 dev:full:它用 dev 源码 + 注入 VITE_API_BASE 仿真跨域,但既不贴近生产(非 build 产物),又不如「dev + 设置里启用本地服务」更真实。直接用 dev:prod(build 产物 + 8787)做验证即可。

模式一:纯同域开发(默认,最常用)

npm run dev
# → Vite dev server 端口 5180(由 .env.cb 的 CARDBUDDY_DEV_PORT 控制)
# 浏览器打开 http://localhost:5180

/__cards /__card/:id /__render-status /__node-models 等后端端点全部由 cardbuddy(8787)提供:server/core 的中间件经 mountCoreMiddlewares 挂到它的 connect 实例,Vite 不承载任何后端插件。编辑器前端在 DEV 下经 resolveApiBase() 默认直连 http://127.0.0.1:8787(用非回环地址打开时走 vite.config.mjs 的 cardDevProxy 同源兜底,规避浏览器私有网络访问限制)。

模式二:开发期顺手看跨域(可选)

不想切到 build 产物、又想在开发时验证跨源?不用专门脚本,直接:

npm run dev                            # 编辑器 5180(同域,HMR)
node packages/cardbuddy/src/cli.js # 另起 8787 服务(另开一个终端)

然后在编辑器「设置 → 本地开发服务」里启用并填 http://127.0.0.1:8787。resolveApiBase() 第 2 条(设置启用)优先于 DEV 回退,编辑器立即改走 8787 跨源——这与生产用户操作完全一致,比旧 dev:full 注入还真实。

模式三:部署前生产级验证(npm run dev:prod)

npm run dev:prod
# = npm run build && npm run preview(静态托管 dist/,默认 4173)+ 并行起 8787

打开 http://localhost:4173,在「设置 → 本地开发服务」启用并填 http://127.0.0.1:8787,即可对 build 产物 跑完整的跨源 smoke test(卡片列表 / 画布渲染 / 保存同步 / SSE 实时刷新)。这是部署前最贴近生产的验证;退出 Ctrl+C 同时关闭 preview 与 8787。

dev:prod 不注入 VITE_API_BASE,因此产出的 dist/ 是干净的、可直接用于生产部署——跨源地址完全交由设置(与生产一致)。

改动即时性(哪些要重启)

| 你改的文件 | npm run dev | npm run dev:prod | | --- | --- | --- | | card-editor/**(Vue 组件 / runtime / 样式) | ✅ Vite HMR 即时 | ⚠️ 需重跑 npm run dev:prod(build 产物,无 HMR) | | src/cards/*.json(卡片内容) | ✅ cards-changed watcher 自动重载 | ✅ 8787 SSE 推送自动重载 | | server/core/**(后端中间件) | ⚠️ 需重启 Vite | ⚠️ 需重启 8787 服务 | | vite.config.mjs / 插件配置 | ⚠️ 需重启 Vite | ⚠️ 需重跑 npm run dev:prod(重新 build) |

铁律:改 server/core/** 必须重启对应进程(Node 不会热重载服务端模块),别白等热更新。

前置条件

  • .env.cb 已存在(含 FINMALL_BASE_URL 远端基址、CARDBUDDY_DEV_PORT)。缺它编辑器仍能起,只是远端资源代理会告警。
  • 首次跑前先 npm install(仓库根)。

服务侧单独起(调试 8787 本身)

# 仓库内直接跑源码(无需先 build)
node packages/cardbuddy/src/cli.js
# 或带 HTTPS 兜底
DSL_DEV_HTTPS=1 node packages/cardbuddy/src/cli.js