# @cnc-tools/cli-kit 中文文档

规范地址：https://npmcn.com/package/%40cnc-tools/cli-kit/

版本：0\.3\.3
npm 元数据更新时间：2026-11-05T15:15:07.864Z
中文译文更新时间：2026-11-10T04:34:10.588Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40cnc-tools/cli-kit
原文对照：https://npmcn.com/package/%40cnc-tools/cli-kit/?lang=original
项目主页：https://github.com/vercel-labs/cnc#readme
源码仓库：https://github.com/vercel-labs/cnc

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：129 kB，50 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=22\.19\.0
- 运行依赖：1 个
- peer 依赖：@vercel/clinkr ^0\.9\.0
- 首次发布：2026-10-08T17:35:03.128Z
- 最新版本发布：2026-11-05T15:15:07.686Z
- 近 30 天下载量：6090（2026-10-10 至 2026-11-08，npm 官方下载统计）
- 已发布版本数：6（近 12 个月 6 个）

## 中文简介

终端外观- feel for Node CLIs: 能力检测,一个小主题,一个活区域流槽,和一个相相运行的渲染器

## 安装

```sh
npm install @cnc-tools/cli-kit
```

也可以使用：`pnpm add @cnc-tools/cli-kit`、`yarn add @cnc-tools/cli-kit`、`bun add @cnc-tools/cli-kit`

## README

# @cnc-tools/cli-kit (英语)

节点CLI的终端外观-feel:能力检测,ANSI剥取,一个小主题,a live-region stream sink,以及用于多步指令的相位运行渲染器.

阶段运行显示在 TTY 上更新的检查表 :

```text
Deploying web
  ✓ Build         bundle ready
      compiling…
  ⠹ Push          Pushing layer 3/5
      uploading…
  • Verify        pending
       sha256:3f2a… done
```

被取代的标签 仍然停留在他们的排 淡的历史。 当输出被管道或捕获时,运行 打印一个简单的固定框架.

工具箱唯一的运行时间依赖是 `log-update`,只有 `stream` 财务报告和审定财务报表 `phase-run` 切入点 装上它。 这个 `clinkr` 切入点 [剪辑器](https://github.com/vercel-labs/cnc/tree/main/libs/clinkr) 应用和进口 `@vercel/clinkr`,可选择的对等依赖;没有其他切入点.

## 安装

```sh
npm install @cnc-tools/cli-kit
```

需要节点22.19或更新. 该套装只采用无害环境管理,船舶编译了JavaScript和类型申报.

## 入境点

| 导入 | 它给你什么 |
| --- | --- |
| `@cnc-tools/cli-kit/caps` | `Caps`, (中文(简体) ), `resolveCaps`, (中文(简体) ), `resolveProcessCaps`, (中文(简体) ), `resolveStreamCaps`, (中文(简体) ), `resolveSettledNonInteractiveCaps` |
| `@cnc-tools/cli-kit/ansi` | `stripAnsi` |
| `@cnc-tools/cli-kit/clinkr` | `renderOutcome`, (中文(简体) ), `ui`, (中文(简体) ), `path`, (中文(简体) ), `muted`, (中文(简体) ), `status`, (中文(简体) ), `capsFor`: cli- kit 寻找 Clinkr 应用程序 |
| `@cnc-tools/cli-kit/theme` | `paint`, (中文(简体) ), `dim`, (中文(简体) ), `bold`, (中文(简体) ), `glyph`, (中文(简体) ), `renderTable`, (中文(简体) ), `renderResultBlock`, (中文(简体) ), `statusLine`,文本帮助 |
| `@cnc-tools/cli-kit/stream` | `createStreamSink`, (中文(简体) ), `runStream`:活区及其非TTY合同 |
| `@cnc-tools/cli-kit/phases` | `PhaseEvent`, (中文(简体) ), `PhaseSpec`, (中文(简体) ), `PhaseState`, (中文(简体) ), `createPhaseStateStore` (纯粹,不渲染) |
| `@cnc-tools/cli-kit/phase-run` | `startPhaseRun`, (中文(简体) ), `createPhaseRun`,以及框架、生命周期和尾部构件 |

## Clinkr 应用程序

克林克解决终端,应用颜色优先,选择流,并写出JSON和一个脚本读取的内容. cli-kit画的是人们所看到的。 调用它的 `renderOutcome` 每个结果 `render`数字 :

```ts
import { muted, path, renderOutcome } from "@cnc-tools/cli-kit/clinkr";

// In a command's outcomes:
render: ({ worktreePath, slotName }) =>
  renderOutcome({ done: ["Moved to", path(worktreePath)], rows: [["Slot", slotName ?? muted("—")]] }),
```

传过来 `ui` 改为 `createApplication` 所以每一个错误, 克林克自己的和应用程序的 `canceled` 共享 听着 该布局为cli-kit自有:一双柱地沟,标签/值行取自第18栏的值, `✓` 完成的项目 结果, `!` 警告者, `✗` 用于错误标题,最多5个列表项目,最多2个恢复步骤。 颜色关闭 它打印的布局没有逃生代码; 上面有颜色画出格言、 标签、 值和表格页眉 每一个部分的溪流。 当地语无法渲染出Unicode时,地语会倒回ASCII.

-   `renderOutcome(content)` 使结果的内容带有默认限制。 内容取自克林克 `ResultContent`, (中文(简体) ), 和有字符串的样式值: `done`,行、行和表格单元格。 表格单元格也可能是 Clinker 的 链接, `{ text, url }`: 上面的颜色以口音的 OSC 8 超链接来显示其文本, 链接的颜色, 其 在文字上测量的栏;用彩色去掉,在管子上,它就是一个文字.
-   `path(text)`, (中文(简体) ), `muted(text)`,以及 `status(text, tone)` 是样式值: 文件系统路径, 递归文本 作为占位符, 和状态词在一个基调。 每个人为JSON和剧本读取的 保留了纯文本.
-   `ui` 是应用程序带有默认限制的 UI .
-   `createOutcomeRenderer({ maximumListItems })` 财务报告和审定财务报表 `createUi({ maximumListItems, maximumRecoverySteps })` 让你 拥有其他限制。 每个限值是一个正安全整数;其他任何投出一个 `RangeError`。 。 。 .

## 能力

每个渲染器都需要 `Caps` 明确并返回字符串,因此输出在测试中具有决定性.

```ts
import { resolveCaps, resolveProcessCaps, resolveStreamCaps } from "@cnc-tools/cli-kit/caps";

const caps = resolveProcessCaps(); // reads process.stdout and process.env
const stderrCaps = resolveStreamCaps(process.stderr); // for progress drawn on stderr
const testCaps = resolveCaps({ isTty: false, columns: 100, env: {} });
```

`isTty` 财务报告和审定财务报表 `columns` 描述你所解决的溪流。 保持低调的CLI 可读取的机器和从 stderr 上提取进度应解决顶盖 `process.stderr`。 。 。 .

颜色从正色降解为256和16个颜色,最后变为零. 无空 `NO_COLOR` 转弯 颜色脱落和分数 `FORCE_COLOR`。非 TTY 获得没有颜色,除非 `FORCE_COLOR` 问取来. 胶片 回到ASCII,当地方, `LC_ALL`,则 `LC_CTYPE`,则 `LANG`,不是 UTF-8;是空的 计数为未设置。 使用 `resolveSettledNonInteractiveCaps()` 汇的汇 终端出价未知,如回调和捕获输出等.

## 主题

```ts
import { renderResultBlock, renderTable, cell } from "@cnc-tools/cli-kit/theme";

console.log(renderResultBlock(caps, { kind: "success", headline: "Deployed.", body: "3 services" }));
console.log(
  renderTable({
    caps,
    columns: [
      { header: "SERVICE", width: "auto" },
      { header: "STATUS", width: "fill" },
    ],
    rows: [[cell("web"), cell("ok")]],
  }).join("\n"),
);
```

`statusLine` 使一个相行。 它的名称列垫默认为 13; 通过 `nameWidth` 改为 换一下.

布局测量终端单元格,而不是字符串长度. `terminalWidth` 将CJK和大多数emoji计为两个 单元格和结合标记为零,而截断则不会分出一个石墨. 这是一个近似: 终端对于一些emoji和模糊的width字符仍有分歧.

## 流槽

`createStreamSink(caps, deps)` 使框架被传递。 它不排序工作.

-   **{\\FN黑体\\FS22\\BORD1\\SHAD0\\3AHBE\\4AH00\\FSCX67\\FSCY66\\2CHFFFFFF\\3CH808080}TTY:** 重新绘制 a `log-update` 活区域,隐藏并恢复光标,并旋转所持帧 每90ms (英语). 活地重画会暂停终端自动包装, 这样一个 Stale 宽度不能留下孤行 .
-   **非 TTY 类型 :** 没有动画,没有光标代码,没有重画出逃生. 换行 `onOutput`。 。 。 . 固定的相框写了一次,从ANSI取出. 捕获输出的主机依赖于 这个.

每一个接缝都可以注射: `writer` (默认通过) `log-update`, (中文(简体) ), `clock` (违约) `setTimeout`, (中文(简体) ), `onOutput` (默认写入每条流线通过) `writer`,所以一个作家 指向起伏器,以及 `dwellMs`,每个时间间隔规则 `hold`。默认住有一个 base 勾选; 将您自己的规则传递给慢步 :

```ts
const sink = createStreamSink(caps, {
  dwellMs: (transient, tickMs) => (transient?.startsWith("Uploading") ? tickMs * 3 : tickMs),
});
```

使用 `runStream(caps, deps, body)` 以恢复光标,即使 `body` 掷出.

`sink.emitTransient(line)` 一个非TTY水槽通过它 `onOutput`,而一个 TTY 槽则没有写作,所以现场区域仍然是唯一的作家. 从一个掷出 `onOutput` 到达呼叫者 `emitTransient` 同步; 通过 `hold`,它拒绝 回到承诺.

`sink.finish(finalLines, { persist: false })` 抹去活区域 而不是持续它,a 非 TTY 槽写入未解析帧 。 仅 `finalLines` 已写入。 习惯 `writer` 执行 `clear()` 这条路.

## 阶段运行快速启动

```ts
import { startPhaseRun } from "@cnc-tools/cli-kit/phase-run";

const run = startPhaseRun({
  title: "Deploying web",
  phases: [
    { key: "build", name: "Build", label: "compiling…", detail: "bundle ready" },
    { key: "push", name: "Push", label: "uploading…", detail: "image pushed" },
    { key: "verify", name: "Verify", label: "checking health…", detail: "healthy" },
  ],
});
try {
  run.start("build");
  run.done("build");
  run.start("push");
  run.progress("push", "Pushing layer 3/5");
  run.note("sha256:3f2a… done\n");
  run.done("push");
  await run.finish({ finalLines: ["Deployed web."] });
} finally {
  await run.stop();
}
```

`finish` 解决每个阶段仍然开放。 如果你打电话 `fail()` 首先,失败的行保持红色 以后的阶段仍待处理. `skip(key, detail?)` 财务报告和审定财务报表 `cancel(key, detail?)` 将一行作为跳过 (单位:千美元)`–`)或已取消(`⊖`,用于中断的工作). `note` 将原始子进程输出输入 TTY 上的暗尾线,所以 生活区仍然是唯一的作家. `startPhaseRun` 还接受 `caps`, (中文(简体) ), `writer`, (中文(简体) ), `clock`, (中文(简体) ), `onOutput`, (中文(简体) ), `dwellMs`, (中文(简体) ), `showRuntimeDetails` (排列行显示 `detail` 转至 `done`, (中文(简体) ), `nameWidth`, (中文(简体) ), `sequencing`,以及 `collapse`。 。 。 .

过 `finish({ persist: false })` 当活的检查表是短暂的 和其他的东西,例如 报告Stdout,是永久记录。 活体区域被抹去,没有固定框架 写在TTY或其他地方.

如果 TTY 旋转器在背景中失败( 抛出) `writer.redraw` 或拒绝 `clock.sleep`),运行记录了第一个出错,停止重绘,从不让它作为一个出错 无所取弃. `finish` 仍试图恢复已解决的框架和光标 `stop` 仍然试图恢复,然后用这个自旋器错误拒绝。 通过断裂恢复 写作失败,所以 `finally` 以上事项: `stop` 复试取之.

如果画第一帧扔, `startPhaseRun` (或 `run.begin`试图恢复光标, 然后抛出油漆出错,即使修复也失败. `startPhaseRun` 返回无会话 然后,所以快速启动 `finally` 从不运行; 失败后 `run.begin`, (中文(简体) ), `run.stop()` 重试 修复。 在TTY外, 扔东西 `onOutput` (或默认) `writer.write`(中文(简体) ) 从助手中同步抛出或 `emit` 相继出现后,就叫它浮出水面 国家进步 `finally` 仍在运行 `stop`。 。 。 .

### 分步骤

一个阶段 `substeps` 宣布一个级别的儿童行。 子步骤不筑巢: `PhaseSpec` 类型 拒绝子步骤 `substeps`,而州商店 扔一个在建筑或一个 `phases-declared` 事件,然后使标题和行保持不变.

### 活动

制作人报告这些进展 `PhaseEvent`编号:

| 活动 | 效果 |
| --- | --- |
| `phases-declared` | 替换标题和行集. |
| `title-changed` | 替换标题. |
| `phase-started` | 标记一行活动,带有可选标签. |
| `phase-progress` | 更改活动行的标签 . `history: "replace"` 放弃旧标签而不是保留它. |
| `phase-notes` | 替换一行的笔记:在其下方显示纯文本,被包而不是被切. |
| `phase-done` | 解决一行. |
| `phase-skipped` | 解决一行跳过: 它从来没有运行. |
| `phase-cancelled` | 解决一行已取消: 它被中断 . |
| `phase-failed` | 解决一行失败, 以事业为标签 . |

使用 `history: "replace"` 用于快速变化状态,例如一步内的一个艺名. 这行的 历史仅保留您想要保存的标签, 并且一个非 TTY 运行日志不会对此进行瞬态行 .

使用 `phase-notes` 对于文本,阅读器需要全部内容,例如为什么一个步骤被重审. 历史和尾巴 线被切到终端宽度; 笔记包, 续行缩入两个单元格。 A 类 排行保存它的笔记 在它和解后, 他们改变不了它的状态.

### 顺序

默认 `sequencing: "implicit"` 适合线性工作流程。 每打开一个行标记 行已完成, 解决父程序会解开子程序, 而失败的子程序会失效 .

继续过去的失败的跑步,例如试跑者,应该通过 `sequencing: "explicit"`。 。 。 . 然后每行只能通过自己的活动解决。 启动子步骤激活待决父程序, 但是 解决不了其他问题。 失败的子步骤让其父母独自一人 `finish` 标记每行 打开作为跳过, 不管失败。 制作人和每家商店 制作它的活动,必须使用 同样的模式.

### 折叠高高的核对表

`collapse: true` 保持长清单短。 固定的行会变成一行 加上任何分步骤 失败或携带笔记。 待决行会隐藏其子步骤直到开始,只有活动行 扩展。 在一个活跃的行中,定居的子步骤会降低历史. 框架比终端高 仍然失去他们的上行 `log-update`剪辑.

如果您的工作流程已经发布 `PhaseEvent`s, 用途 `createPhaseRun({ caps, phases, deps })` 输入 事件改为 `run.emit(event)`。用于自定义显示,例如主机部件,使用 `createPhaseStateStore` 从 `phases` 并表达自己的观点.

## 常见问题

### @cnc-tools/cli-kit 是什么？

终端外观- feel for Node CLIs: 能力检测,一个小主题,一个活区域流槽,和一个相相运行的渲染器

### 如何安装 @cnc-tools/cli-kit？

在项目目录运行 npm install @cnc-tools/cli-kit，或使用 pnpm add / yarn add / bun add。

### @cnc-tools/cli-kit 支持 TypeScript 吗？

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

### @cnc-tools/cli-kit 支持 ESM 还是 CommonJS？

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

### @cnc-tools/cli-kit 需要什么版本的 Node\.js？

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

### @cnc-tools/cli-kit 可以商用吗？

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

### @cnc-tools/cli-kit 的下载量有多少？

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

### @cnc-tools/cli-kit 还在维护吗？

最新版本 0\.3\.3 发布于 2026/11/05（4 天前）；至今共发布 6 个版本，其中过去 12 个月发布了 6 个；首次发布于 2026/10/09。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

