Skip to content

核心概念

返回总览

真正影响理解速度的,不是字段多不多,而是几个概念有没有分清

这一页只讲五件事

  • workflow 是什么
  • step 在哪里起作用
  • values、results、events 分别放什么
  • initialValues 和 defaultValue 有什么区别
  • history、checkpoint、logs 该怎么选

workflow 是一条声明式执行链

clack-kit 的主线可以压成一句话

定义 workflow,按顺序执行 steps,把输入写进 values,把步骤产物写进 results,把运行过程记进 events

ts
import { defineStep, defineWorkflow } from 'clack-kit';

const workflow = defineWorkflow({
  id: 'release',
  steps: [
    defineStep.text({
      id: 'version',
      message: '版本号',
      required: true,
    }),
    defineStep.confirm({
      id: 'dryRun',
      message: '先 dry run 吗',
    }),
  ],
});

这段定义本身不会执行任何命令,也不会立刻产生交互

直到 kit.run 或 runWorkflow 被调用,workflow 才进入运行阶段

step 是执行单元,不是纯展示配置

每个 step 都有三个基础维度

  • id 决定写入 values 或 results 时的 key
  • kind 或 type 决定使用哪类处理器
  • 配置字段决定展示方式、校验规则和运行行为

当前内置 step 可以分成三组

分组类型
输入类text、password、path、date、select、selectKey、autocomplete、multiselect、autocompleteMultiselect、groupMultiselect、confirm
展示类note、box、log
执行类command

输入类步骤通常写入 values,command 步骤通常把返回值写入 results,展示类步骤主要产生事件和终端输出

values、results、events 分别存什么

这三个容器一定要分清

容器主要内容最常见用途
values输入值、最终配置、快照字段条件判断、摘要、历史复用
results步骤显式返回的业务结果读命令步骤产物、后续业务判断
events运行过程中的结构化事件日志、分析、排障

values

适合放会影响后续步骤选择的内容

ts
if (result.values.environment === 'production') {
  // ...
}

results

适合放命令步骤或自定义步骤产生的结构化结果

ts
const image = result.results.buildImage;

events

适合排查“这次运行到底发生了什么”

ts
const failed = result.events.find((event) => event.type === 'workflow-failed');

initialValues 和 defaultValue 不是一回事

这两个名字很像,职责完全不同

字段放置位置作用
initialValuesrun 的入参用外部值预填本次运行,常常直接跳过交互
defaultValue单个 step 定义给交互控件一个默认建议值,通常仍然进入交互

一个判断方法就够用

  • 值来自 CLI、配置文件、环境变量,用 initialValues
  • 值只是表单初始建议,用 defaultValue

history、checkpoint、logs 解决的是三类不同问题

能力解决的问题典型场景
history下次能不能复用上一次输入重复执行同类工作流
checkpoint中断后能不能从现场继续长流程、半自动流程
logs运行完能不能回看过程审计、排障、归档

history

保存的是一份输入快照,重点在 values

checkpoint

保存的是中断现场,除了 values 还会包含 results 和已完成步骤信息

logs

保存的是运行事件、输出、分析摘要和元数据

when 是条件流入口,同名步骤必须互斥

clack-kit 推荐把步骤平铺开,再用 when 控制命中

ts
defineStep.command({
  id: 'prepareReact',
  title: '准备 React 模板',
  when: (context) => context.values.framework === 'react',
  async run(_, io) {
    io.stdout('prepare react\n');
  },
});

如果多条步骤使用相同 id,when 必须互斥

原因很直接,先命中的步骤会把这个 id 标记为已完成,后续同名步骤要么被跳过,要么覆盖结果

一张图看完整数据流

Loading diagram…

下一步建议