@centient/cli-utils

中文文档
0.2.0发布于 2026/09/13MITTypeScriptES Module零依赖近 30 天下载 3143

Dependency-free CLI primitives: terminal capability detection, ANSI color helpers, and semver-lite (parse/compare/satisfies)

原始使用文档
文档目录9 节
  1. Installation
  2. Terminal capabilities & color
  3. Color precedence order
  4. Live-process convenience wrappers
  5. Structured errors
  6. Semver-lite
  7. Supported range forms
  8. API
  9. License

@centient/cli-utils

Dependency-free CLI primitives shared across Centient command-line tools:

  • Terminal capability detection — NO_COLOR / FORCE_COLOR / TERM precedence with an injectable env record, so detection is unit-testable.
  • ANSI color helpers — degrade to identity (empty-string) codes when color is unsupported.
  • Semver-lite — parse / compare / satisfies for major.minor.patch[-prerelease], no external semver dependency.

Zero runtime dependencies. ESM-only.

Installation

npm install @centient/cli-utils

Or as a workspace dependency in the monorepo:

pnpm add @centient/cli-utils --workspace

Terminal capabilities & color

Detection is split into a pure core (takes an injectable env record and a stream descriptor — read no globals) and thin live-process wrappers for ergonomic CLI call sites.

Color precedence order

resolveColorSupport(env, isTTY) resolves color support by this exact precedence (highest wins):

  1. FORCE_COLOR present (any value, including "") → color ON
  2. NO_COLOR present (any value, including "") → color OFF
  3. TERM === "dumb" → color OFF, isDumb = true
  4. stream is a TTY → color ON
  5. otherwise → color OFF

Presence is tested by key presence (the NO_COLOR convention): the variable's mere presence is the signal, regardless of value. A key whose value is undefined counts as absent.

import {
  detectCapabilities,
  makeAnsiColors,
  colorize,
} from "@centient/cli-utils";

// Pure / testable: pass an env record and a stream descriptor.
const caps = detectCapabilities(process.env, process.stdout);
// caps -> { isTTY, hasColor, isDumb, width }

const colors = makeAnsiColors(caps.hasColor);
console.log(colorize(colors, "green", "ok"));
// "ok" is wrapped in ANSI green when color is enabled, returned unchanged when not.

Live-process convenience wrappers

import { detectTerminalCapabilities, createAnsiColors } from "@centient/cli-utils";

const caps = detectTerminalCapabilities("stdout"); // reads process.env + process.stdout
const colors = createAnsiColors();                 // colors for the live stdout

Structured errors

import { writeError } from "@centient/cli-utils";

writeError("config not found", "a path to engram.json", "pass --config <path>");
// [ERROR] config not found
//   Expected: a path to engram.json
//   Recovery: pass --config <path>

The sink is injectable (writeError(what, expected, recovery, write?)), defaulting to process.stderr. Returns void; exit-code handling is the caller's responsibility.

Semver-lite

Parses major.minor.patch with optional pre-release identifiers and build metadata. Build metadata is parsed off and ignored for ordering (SemVer 2.0 §10). Pre-releases are ordered per SemVer 2.0 §11 — a pre-release sorts below its release.

import {
  parseSemver,
  tryParseSemver,
  formatSemver,
  compareSemver,
  compareVersions,
  satisfies,
} from "@centient/cli-utils";

parseSemver("1.2.3-rc.1");
// { major: 1, minor: 2, patch: 3, prerelease: ["rc", 1] }

tryParseSemver("v1.2.3"); // parsed tuple
tryParseSemver("not-a-version"); // null (diagnostic/fail-open paths)

const actual = tryParseSemver("v1.5.0");
const minimum = tryParseSemver("1.2.0");
const meetsMinimum =
  actual === null || minimum === null
    ? null // caller chooses whether to warn, skip, or fail open
    : compareSemver(actual, minimum) >= 0;

formatSemver(parseSemver("1.2.3-rc.1")); // "1.2.3-rc.1" (round-trips)

compareVersions("1.0.0-rc.1", "1.0.0"); // -1 (pre-release < release)

satisfies("1.5.3", "^1.2.0"); // true

Supported range forms

No compound ranges, no ||, no hyphen ranges.

RangeMeaning
1.2.3exact match
>=1.2.3inclusive lower bound
>1.2.3exclusive lower bound
<=1.2.3inclusive upper bound
<1.2.3exclusive upper bound
^1.2.3caret: same major, at or above (>=1.2.3 <2.0.0)
~1.2.3tilde: same major.minor, at or above (>=1.2.3 <1.3.0)
* / ""any version

parseSemver, compareVersions, and satisfies remain strict: malformed versions or ranges throw SemverError (carrying expected and input fields) rather than degrading silently. tryParseSemver is the explicit non-throwing boundary for externally reported versions; it returns null on invalid input and accepts one conventional lowercase v immediately before the numeric core.

API

ExportDescription
resolveColorSupport(env, isTTY)Pure color-support resolver (the precedence core).
detectCapabilities(env, stream)Pure capability detection from an env record + stream descriptor.
detectTerminalCapabilities(stream?)Live-process wrapper over detectCapabilities.
makeAnsiColors(enabled)Pure ANSI color set; empty strings when disabled.
createAnsiColors()Live-process wrapper; colors for stdout.
colorize(colors, code, text)Wrap text in a code + reset, or identity when disabled.
writeError(what, expected, recovery, write?)Three-part structured error to an injectable sink.
parseSemver(input)Parse to SemverTuple; throws SemverError.
tryParseSemver(input)Parse an external version without throwing; accepts a leading v and returns null on invalid input.
formatSemver(v)Format back to a string (round-trips parseSemver).
compareSemver(a, b) / compareVersions(a, b)Total-order compare (-1 / 0 / 1).
satisfies(version, range)Test a version against a range.

License

MIT

版本与发布记录

@centient/cli-utils 共发布 2 个版本,首次发布于 2026/06/16;过去 12 个月发布了 2 个版本。

版本发布日期距今
0.2.0latest2026/09/131 个月前
0.1.02026/06/164 个月前

关于 @centient/cli-utils 的常见问题

@centient/cli-utils 是什么?

Dependency-free CLI primitives: terminal capability detection, ANSI color helpers, and semver-lite (parse/compare/satisfies)

如何安装 @centient/cli-utils?

在项目目录运行 npm install @centient/cli-utils,或使用 pnpm add / yarn add / bun add。

@centient/cli-utils 支持 TypeScript 吗?

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

@centient/cli-utils 支持 ESM 还是 CommonJS?

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

@centient/cli-utils 需要什么版本的 Node.js?

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

@centient/cli-utils 可以商用吗?

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

@centient/cli-utils 的下载量有多少?

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

@centient/cli-utils 还在维护吗?

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