This is the source for @htmlbin/cli, the command-line client for htmlbin.dev. The package is open source and published publicly on npm. Treat every file in this repo as if it ships to users.
A single verb (publish) that takes an HTML file and returns a URL. Three backends are pluggable behind the same surface:
cloud(default) — POSTs tohtmlbin.dev. Public previews.gh-pages— commits to agh-pagesbranch via the GitHub Git Data API. Org-internal previews behind GitHub SSO.cloudflare— deploys to Cloudflare Pages with optional Cloudflare Access gating.
The CLI is shipped to be used by humans on the command line, by GitHub Actions in CI, and by coding agents (Claude Code, Cursor, Codex, etc.). It auto-detects coding-agent environments via env vars and switches to JSON output without a flag.
src/bin.ts— CLI entrypoint. Wires commander subcommands to backend methods.src/backend.ts— theBackendinterface every backend implements.src/backends/cloud.ts,src/backends/gh-pages.ts,src/backends/cloudflare.ts— backend impls.src/backends/metadata-guard.ts— shared boundary check; non-cloud backends reject--metadataand--upsert.src/cloud/— htmlbin.dev API client and the metadata parsing module.src/gh/— GitHub Git Data API client and helpers.src/cf/— Cloudflare API client (Pages + Access).src/patterns/— local pattern installer (the agent skill teaches agents to look for these).src/errors.ts—CliErrorclass and the stable exit-code mapping.src/debug.ts— gate for raw upstream response bodies in error details (off by default).test/— vitest unit + e2e tests.examples/— reference GitHub Actions workflows.scripts/build-bundled-patterns.mjs— bakes the official pattern catalog into the build sopatterns initworks offline.
- TypeScript strict, ESM, Node 20+.
- Public surface is the
Backendinterface plus the CLI flags. Code outsidesrc/bin.tsshould not assume CLI specifics. - Error codes are snake_case strings that mirror the htmlbin API's
error.codeshape. The mapping to exit codes lives insrc/errors.ts:exitCodeFor. - Tests use vitest; e2e tests in
test/e2e/spawn the built binary. - No
console.log/console.errorinsrc/. Useprocess.stdout.write/process.stderr.writeso output mode (textvsjson) stays in control. - Token storage is
0o600and the parent.htmlbin/directory is0o700.
Distinct verbs for distinct intents (kubectl / gh / stripe convention):
publish <file>always POSTs (creates).update <slug>mutates an existing drop.--filetriggers PUT (new HTML version), metadata-only flags trigger PATCH (no version bump). Cloud only.publish --upsert --metadata k=vis the agent-idempotent bridge: GETs by metadata, PUTs to the match if found, POSTs otherwise.
--upsert is metadata-keyed only and requires at least one --metadata flag.
- Open a branch for every change. Direct push to
mainis not allowed. - Run
npm run build && npm testbefore opening a PR. - Public-facing copy (README, npm metadata, errors, example workflows) reads as neutral product documentation. No emojis, no em-dash flourishes, no marketing voice.
- Source maps ship with the package. They reference
../src/...paths, never absolute developer paths. - New backend features that touch the cloud API should also be considered for the htmlbin server-side advertised surface:
https://htmlbin.dev/.well-known/agent-skills/htmlbin/SKILL.md,/api/onboard, and/.well-known/agent-card.jsonare the live discovery surfaces; coordinate updates with the htmlbin server.
npm run build # tsup bundles to dist/
npm test # vitest run
npm run typecheck # tsc --noEmit (test helpers have known errors)
npm pack --dry-run # inspect what would ship
npm publish --access public # publish to @htmlbin/cliThe CLI's --version is hard-coded in src/bin.ts and must stay in sync with package.json.