@debuffjp/cli

中文文档
0.33.0发布于 2026/11/11MITTypeScriptES Module构建来源已验证近 30 天下载 1万

The debuff CLI: dev server, builds with size reports, assets, logic tests, scenarios and fuzzing

原始使用文档
文档目录7 节
  1. Exit codes and errors
  2. Agent hook
  3. Scenarios
  4. Programmatic use
  5. Assets and plugins
  6. Aseprite
  7. tenten

@debuffjp/cli

The debuff command: dev server, production builds with size reports, asset manifests, browser scenarios, fuzz playtesting and project inspection. Built on Vite.

npm install -D @debuffjp/cli
npx debuff --help
CommandWhat it does
debuff create [dir]Scaffold a game (same as npm create debuff)
debuff dev [--port] [--host]Dev server with hot reload; regenerates the asset manifest on change
debuff build [--sourcemap]Production build, then a raw/gzip/brotli report. Fails if dev-only code leaks
debuff reportSize report for an existing dist/
debuff assetsRun the asset pipeline: list every asset, its importer and size, plus unused and generated files
debuff test [files] [-t text] [--changed] [--queue name] [--accept-saves] [--json]Run logic tests (tests/**/*.test.ts) with keiko: the real game in Node, no browser, in milliseconds. From 0.32, every run records what each test used, and --changed runs only the tests whose code or files changed since they last passed, plus new and failed ones; --queue push keeps a separate record for a pre-push hook or CI (how it decides). From 0.29.3 it also compares the saves in src/ with saves.json and prints what changed, the same check as debuff build, and --accept-saves updates saves.json. It only reports: debuff build still fails on a save error. Before 0.29.3 only debuff build checked saves, and debuff test --accept-saves failed with "Unknown option"
debuff scenario [files] [--update] [--strict]Run scenarios/*.json in headless Chrome/Edge
debuff fuzz [--seconds] [--runs] [--seed] [--keys] [--ignore]Play headless with random but plausible input. Reports explained errors, stuck states and loops (the scene, or two state fields, flipping between the same two values), each saved as a scenario in .debuff/fuzz/ that reproduces it. --keys takes key codes, PointerRight / PointerMiddle, and the gestures Wheel (a scroll) and Touch (a finger tap or drag), e.g. --keys Touch,Wheel,Space for a touch game. --ignore state.shots skips noisy fields. Exits 1 on errors
debuff telemetry [on|off|status]Anonymous build registration: after a successful build, debuff build sends a random project id, the package name and the debuff version to debuff.jp, so we can find games made with debuff. Off in CI, or with debuff telemetry off / DEBUFF_TELEMETRY=0. What's sent
debuff papercut <title> [--minutes] [--repo] [--area] [--kind] [--workaround] [--hit <id>] [--force]Report tooling friction (a slow or flaky tool, a missing API, confusing docs) to the public board at papercuts.debuff.jp. It lists close matches instead of filing a duplicate: rerun with --hit <id> to add your minutes to one, or --force. With --hit, the title or --body is the note and --workaround fills the papercut's workaround when it has none (from 0.24.1; 0.24.0 dropped it). Sends only what you typed and debuff-cli <version>. DEBUFF_PAPERCUTS_TOKEN makes new entries show at once; without it they wait for review. Added in 0.24
debuff papercuts [on|off|status]Automatic papercuts: the CLI and MCP server report a setup failure seen twice in a week, or a command far slower than it should be, to papercuts.debuff.jp. They send a fixed title, an error code, minutes and the version, never messages, paths or project details. From 0.26.2 also the OS, CPU count, memory, Node version and what was checked (which browsers were missing). Once a day per fingerprint at most; off in CI or with DEBUFF_PAPERCUTS=0. What's sent. Added in 0.24
debuff inspectJSON summary of the project
debuff upgrade [--to] [--dry-run]Move every debuff package to the latest release (or --to <version>) together, keeping each range's ^, ~ or exact style, install with the project's package manager, then run the new version's doctor --fix, which also rewrites the agent skills. Never downgrades without --to. If an earlier run updated package.json but its install failed or was interrupted, running it again installs and runs doctor (before 0.31.1 it said "already on" and stopped; --json lists the packages as stale). Added in 0.21
debuff doctor [--live] [--fix]Check the setup in one pass: Node version, debuff package versions, node_modules, debuff.config.ts, assets, saves.json, agent files and the browser scenarios use. Each problem comes with a fix. --fix applies the safe ones (install, dedupe, add @debuffjp/dev, write a missing .mcp.json, rewrite the agent skills for the installed version, and from 0.23 write the agent hook files that are missing) in the project's package manager, then checks again. --live also starts the dev server and checks the game exposes its dev hooks. From 0.21 it also says when a newer debuff is out. Exits 2 when a required check fails (1 before 0.20). Other commands that fail on setup point here

Add --json for machine-readable output and --root <dir> to target another project.

From 0.29.1, size reports use Brotli quality 11 for code and HTML, and quality 4 for assets, source maps and other files. This avoids spending minutes recompressing large assets just to report their size. Before 0.29.1, every file used quality 11. This applies to debuff build, debuff report, debuff inspect, the MCP build tool and buildReport(). Raw and gzip measurements keep their previous settings. Reports measure compressed sizes without writing compressed files; your host chooses how to compress downloads.

Once a day, at the end of a command, the CLI prints one line on stderr when a newer debuff is out (from 0.21). From 0.24, debuff dev prints it under its banner instead, since it never exits. The hint is never printed in --json mode, and it's off in CI and with DEBUFF_UPDATE_CHECK=0. Agents get the same news from the agent hook at session start (below).

Exit codes and errors

From 0.20. Before that, every failure exited 1, doctor exited 1 when a required check failed, unknown options were ignored, and --json errors were printed as text.

The exit code says what to do next, so scripts and agents can act without reading the output:

ExitMeaningWhat to do
0SuccessCarry on
1The run reported a failure (a test, scenario, fuzz finding or leak), or something unexpected brokeRead the report or the error
2The project or machine needs fixing first (no browser, invalid config, missing dev hooks, a busy port, a failing doctor)Run npx debuff doctor and apply its fixes. A retry won't help
3Bad input: an unknown command or option, or a folder that isn't thereFix the command line

With --json (and always for inspect), stdout carries exactly one JSON document: the result, or this when the command can't run:

{ "error": { "code": "browser_not_found", "message": "…", "fix": "Install Chrome or Edge, or set DEBUFF_BROWSER…", "transient": false } }

code is one of unknown_command, bad_option, not_a_project, nothing_to_run (from 0.21: no scenarios, or no build to report on), config_invalid, browser_not_found, dev_hooks_missing, game_hung (from 0.28: one call into the game took over 60 s), port_in_use, network and unexpected, and keeps its meaning between releases. transient: true means the same command may work if run again (a network blip). Logs go to stderr. The MCP server's tools add the same code and fix to their errors.

Agent hook

From 0.23. New projects ship .claude/hooks/debuff.mjs, wired into Claude Code by .claude/settings.json and into Codex by .codex/hooks.json. Around each edit and shell command, it:

  • asks the human before screenshot baselines or saves change;
  • refuses edits to .debuff/, dist/ and node_modules/, a foreground dev server, and hand-changed @debuffjp/* versions;
  • warns about new Math.random, Date.now and real-timer lines in src/;
  • once per stop, asks for debuff test when src/ changed since the last run;
  • from 0.24, at session start and at most once a day, tells the agent when a newer debuff is out, so it can ask the human about npx debuff upgrade.

The shim imports @debuffjp/cli/hook, so the rules come from the installed CLI. It does nothing before npm install, and DEBUFF_HOOK=0 turns it off. // debuff-hook-ignore <rule> at the end of a line skips that line. Rules and details: Working with AI agents.

Scenarios

{
  "$schema": "../node_modules/@debuffjp/cli/schema/scenario.schema.json",
  "steps": [
    { "press": "ArrowRight" },
    { "wait": 30 },
    { "expect": { "state.player.x": { "gt": 200 } } },
    { "set": { "player.speed": 400 } },
    { "capture": "after-move" }
  ]
}

Time advances only through wait and until steps, so runs are deterministic. Every step renders in a real browser, so long waits are slow (a minute of game time can take a few minutes): check timers and other long timings with logic tests, and keep scenarios short. until steps one tick at a time until its conditions hold, and fails if they don't within that many steps (default 600), so a scenario says "until the player lands" instead of guessing a wait. Paths read the dev state: scene, tick, state.* (your inspect()), and events.<name>, the number of times the game called game.emit("<name>") (0 until the first). For example { "until": { "events.coin": { "gte": 1 } }, "within": 60 }. Replays saved from the dev panel (or the MCP game_replay tool) are scenarios too. From 0.31 they hold a checkpoint step every 60 ticks, a hash of each part of the game's state; when one stops matching, the report warns once with the tick and the parts that differ (state.player, events), and the scenario still passes. ### Accessibility checks

Scenarios can screen what the game actually draws:

  • { "flashes": 240 } plays 240 steps and fails on flashing that could trigger photosensitive seizures: more than three flashes a second over a quarter of a 10° field. It approximates WCAG 2.3.1's general flash threshold, taking the 10° field as a third of the screen each way.
  • { "contrast": [x, y, w, h], "min": 4.5 } fails if the light and dark parts of a region (say, your HUD text) contrast less than min (default 4.5:1, WCAG AA for text).
  • "stepTimeout": 120 at the top of a scenario changes how many seconds one step may take before the game counts as hung. Default 60, from 0.28.
  • "reducedMotion": true at the top of a scenario runs it with the browser asking for reduced motion, so you can check that mode too.

These are screening checks on one run, not a certification: a pass means nothing obviously unsafe happened in the steps you played. Red flashes aren't checked yet.

Captures are compared against per-platform baselines in scenarios/__baselines__/. A missing baseline is recorded unless you pass --strict. Set DEBUFF_BROWSER to use a specific Chromium build.

Programmatic use

import { buildReport, compileAssets, runScenarios } from "@debuffjp/cli";

Assets and plugins

Put source assets in assets/. The pipeline builds an in-memory manifest (/assets/manifest.json). Only files the manifest references are served in dev and emitted in builds, and sources are never modified.

The pipeline warns about a PNG wider or taller than 4096 pixels, because a GPU with a smaller texture limit draws it black. Split a long sprite strip into several sheets. Before 0.29.3, there was no warning.

Add tooling plugins in debuff.config.ts:

import { defineConfig } from "@debuffjp/cli";

export default defineConfig({
  plugins: [
    {
      name: "maps",
      apiVersion: 1,
      // Any language: SourceFile JSON on stdin, ImportResult JSON on stdout.
      assets: [{ name: "maps", extensions: [".map"], command: ["python", "tools/import_map.py"] }],
    },
  ],
});

Aseprite

The first-party aseprite() plugin runs Aseprite for you, so .aseprite and .ase files in assets/ load like PNGs with no export step:

import { aseprite, defineConfig } from "@debuffjp/cli";

export default defineConfig({ plugins: [aseprite()] });
  • hero.aseprite with several frames becomes a sprite sheet: assets.frames("hero") returns the frames in order.
  • [email protected] flattens to one image with a 6x9 grid, ready for BitmapFont.
  • Hidden layers are left out, so guide layers stay in the source.

It looks for Aseprite in $ASEPRITE, then on PATH, then in the usual install folders (including Steam). You can also pass aseprite({ binary }). If it can't find Aseprite, the build warns and skips those files. Results are cached by file contents, so Aseprite only runs when a file changes.

aseprite/new-font.lua creates a blank font sheet with the grid set up:

aseprite -b --script-param w=6 --script-param h=9 --script-param out=assets/[email protected] --script node_modules/@debuffjp/cli/aseprite/new-font.lua

tenten

tenten is a headless pixel-art tool for coding agents: an MCP server draws sprites and animations and saves them as .tt, a JSON file with the pixels as text grids that diffs in git. .tt files in assets/ become PNGs and sprite sheets with no configuration, the same way aseprite() does for .aseprite. Add the tenten() plugin only to change how tenten is run:

import { defineConfig, tenten } from "@debuffjp/cli";

export default defineConfig({ plugins: [tenten({ command: ["node", "../tenten/bin/tenten.js"] })] });
  • slime.tt with several frames becomes a sprite sheet: assets.frames("slime") returns the frames in order.
  • [email protected] flattens to one image with a 6x9 grid.

debuff runs tenten from $TENTEN (its bin/tenten.js), then the copy installed in the project, and otherwise fetches it with npx -y -p @debuffjp/tenten tenten the first time a .tt file is seen. tenten needs Node 24. Results are cached by file contents.

版本与发布记录

@debuffjp/cli 共发布 56 个版本,首次发布于 2026/10/16;过去 12 个月发布了 56 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.33.0latest2026/11/11今天
0.32.02026/11/074 天前
0.31.12026/11/065 天前
0.31.02026/11/065 天前
0.30.02026/11/056 天前
0.29.22026/11/056 天前

关于 @debuffjp/cli 的常见问题

@debuffjp/cli 是什么?

The debuff CLI: dev server, builds with size reports, assets, logic tests, scenarios and fuzzing

如何安装 @debuffjp/cli?

在项目目录运行 npm install @debuffjp/cli,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 debuff,可以用 npx debuff 直接运行。

@debuffjp/cli 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@debuffjp/cli 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@debuffjp/cli 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@debuffjp/cli 可以商用吗?

@debuffjp/cli 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@debuffjp/cli 的下载量有多少?

根据 npm 官方下载统计,@debuffjp/cli 在 2026/10/12 – 2026/11/10 这 30 天内被下载 10,167 次,日均约 339 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@debuffjp/cli 还在维护吗?

最新版本 0.33.0 发布于 2026/11/11(今天);至今共发布 56 个版本,其中过去 12 个月发布了 56 个;首次发布于 2026/10/16。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。