# @type32/workflows 中文文档

规范地址：https://npmcn.com/package/%40type32/workflows/

版本：0\.1\.1
npm 元数据更新时间：2026-11-02T16:49:22.501Z
中文译文更新时间：2026-11-02T18:35:23.579Z
软件包许可：MIT

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

原始 npm 页面：https://www.npmjs.com/package/%40type32/workflows
原文对照：https://npmcn.com/package/%40type32/workflows/?lang=original

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

- 包体积（解压后）：340 kB，19 个文件
- 模块格式：ES Module
- TypeScript 类型：未声明
- Node.js 要求：\>=20\.19
- 运行依赖：0 个
- peer 依赖：vue ^3\.5\.0，@nuxt/ui ^4\.12\.0，typescript \>=6\.0\.3，@vue-flow/core ^1\.48\.2
- 首次发布：2026-11-02T16:47:20.292Z
- 最新版本发布：2026-11-02T16:49:22.342Z
- 已发布版本数：3（近 12 个月 3 个）

## 中文简介

工作流脚本引擎

## 安装

```sh
npm install @type32/workflows
```

也可以使用：`pnpm add @type32/workflows`、`yarn add @type32/workflows`、`bun add @type32/workflows`

## README

# @type32 /工作流

一个可视化的节点脚本工具包。语言开发者在TypeScript中定义类型、节点和效果；最终用户从画布上的这些节点构建文档；引擎验证并运行它们。文档是不可信的数据：引擎从不评估文档中的代码。

设计: [节点引擎规格](https://github.com/CTRL-Neo-Studios/vertex/blob/t32/feature/workflows/Node%20Engine%20Spec.md)。Vertex是第一种语言。

> 状态:M5。 `@type32/workflows/core` 具有类型系统、具有类型化节点上下文的语言定义、 `validate`、运行时、函数和变量； `migrate` 和 `hashProgram`； `@type32/workflows/core/std` 有标准节点； `@type32/workflows/core/testing` 有测试助手； `@type32/workflows/vue` 具有画布编辑器。

## 使用

```ts
import { compile, defineLanguage, t, validate } from "@type32/workflows/core";
import { std } from "@type32/workflows/core/std";

// Effects keyed by capability id, and the TypeScript value type of each of the language's own types.
const vertex = defineLanguage<
  { fs: { rename(file: string, name: string): Promise<string> } },
  { "vertex.File": string }
>({
  id: "vertex",
  version: 1,
  include: [std], // control, operators (logic, math, compare, dates), text, lists (filter, map, sort, …), dictionaries
})
  .type({ id: "vertex.File", label: "File", schema: { type: "string", pattern: "^/" } }) // a schema allows literals
  .capability({ id: "fs", mutates: true, label: "Modify files" })
  .node({
    type: "vertex.onManual",
    version: 1,
    mode: "event",
    label: "On Run",
    exec: { out: ["then"] },
  })
  .node({
    type: "vertex.rename",
    version: 1,
    mode: "exec",
    label: "Rename",
    exec: { out: ["then"] },
    inputs: {
      file: { type: t("vertex.File"), required: true },
      newName: { type: t("string"), required: true },
    },
    outputs: { file: { type: t("vertex.File") } },
    requires: ["fs"],
    async run(ctx) {
      const { file, newName } = await ctx.inputs(); // file: string, newName: string
      ctx.output("file", await ctx.effects.fs.rename(file, newName)); // ctx.effects has only `fs`
      return "then"; // only declared exec outputs compile
    },
  })
  .build(); // throws on any manifest problem

// Editors need only the JSON manifest.
const analysis = validate(document, vertex.manifest);
analysis.diagnostics; // [{ code: "E_TYPE_MISMATCH", message: "e7: string → vertex.File", at: { edge: "e7" } }, …]
analysis.typeOf("n3", "item", "out"); // resolved port type, e.g. { kind: "con", id: "vertex.File" }
analysis.capabilities; // Set { "fs", … } reachable from event nodes

// Hosts run it. compile throws CompileError on any error diagnostic; dispatch never rejects for program errors.
const result = await compile(document, vertex).dispatch("vertex.onManual", undefined, {
  effects: { fs: { rename: async (file, name) => `/vault/${name}.md` } }, // each node sees only its `requires`
  signal, // abort → { status: "aborted" }
  limits: { steps: 1_000, timeoutMs: 10_000 },
  trace: "nodes",
  onTrace: (event) => console.log(event), // { t: "enter" | "exit" | "fire" | "value" | "fault", node, … }
});
result; // { status: "ok" | "fault" | "aborted", fault?: { code: "E_UNSET_VALUE", message, node }, steps }
```

`ctx` 根据定义键入：端口名称，值类型(`List` → `readonly T[]`， `Dictionary` → `ReadonlyMap`、通用件 `unknown`)，在编译时检查执行输出和功能。输入没有 `required` 或者一个 `default` 可能是 `undefined`.

### 测试一门语言

```ts
import { buildDocument, formatTrace, record, run } from "@type32/workflows/core/testing";

const doc = buildDocument(vertex, {
  nodes: {
    go: "vertex.onManual",
    r: { type: "vertex.rename", literals: { file: "/v/a.md", newName: "b" } },
  },
  edges: ["go.then > r.exec"],
});
const rec = record({ fs: { rename: async (file: string, name: string) => `/v/${name}.md` } });
const { result, trace } = await run(vertex, doc, {
  event: "vertex.onManual",
  effects: rec.effects,
});
rec.log(); // ["fs.rename(/v/a.md, b)"]
formatTrace(trace); // [">go", "<go.then", ">r", "<r.then"]; `~n3.body` is a fire
```

`assertValid(doc, language)` 抛出一个错误，列出每个诊断。这些助手不依赖于测试框架。

通用节点声明 `typeParams: [{ name: "T", bound?: t("vertex.Entry") }]` 和使用 `tvar("T")` 在端口类型中； `validate` 推断每个实例的 `T` 从它的边缘。

运行时的值: `List` 是一个数组， `Dictionary` 是一个 `ReadonlyMap` （`Dictionary` 字面量被解码为 `Map`）. 极限故障和中止是致命的； `std.try` 只捕获节点错误和其他错误。

加载文件： `migrate(JSON.parse(text), language)` 是不可信输入的边界。它返回 `{ doc, changed }` (一个干净 `DocumentV1` 只有已知字段（已迁移到当前格式、语言和节点版本）或 `{ diagnostics }` 当文件无效或比代码更新时，在这种情况下，主机以只读方式打开它。 `hashProgram(doc)` 是程序的SHA-256，忽略view和meta；由它托管密钥信任记录。

函数存在于 `doc.program.functions`。一个身体有一个 `core.entry` 和一个 `core.return`； `core.call` 调用它, `core.get`/`core.set` 读取和写入文档变量或函数的局部变量。声明泛型函数 `typeParams` （具有可选边界），使用那些作为刚性类型检查一次，并且在每次调用时都被实例化。达到 `core.return` 立即结束通话；一个从未到达它的exec函数是错误的 `E_NO_RETURN`.

### 在画布上编辑

同行依赖性: `vue`， `@vue-flow/core` 和 `@nuxt/ui`。组件是从next UI构建的，因此在主机中设置它 `@nuxt/ui` 模块，或者它的Vite和Vue插件 `<UApp>`)，然后让Tailwind从你的CSS条目中扫描这个包：

```css
@import "tailwindcss";
@import "@nuxt/ui";
@source "../node_modules/@type32/workflows/dist"; /* relative to this file */
```

```vue
<script setup lang="ts">
import "@type32/workflows/vue/style.css";
import { useWorkflowEditor, WorkflowWidget, WorkflowWorkbench } from "@type32/workflows/vue";

const editor = useWorkflowEditor(vertex.manifest, document); // the manifest is enough to edit
async function start() {
  const { trace } = await run(vertex, editor.snapshot(), {
    event: "vertex.onManual",
    effects,
    trace: "values",
  });
  editor.trace.value = trace; // run counts, values, taken edges and faults on the canvas
}
</script>

<template>
  <!-- canvas, node library and inspector; or compose WorkflowCanvas, WorkflowPalette, WorkflowInspector yourself -->
  <WorkflowWorkbench :editor="editor">
    <template #toolbar><UButton label="Run" @click="start" /></template>
    <!-- optional: replace one type's literal editor (on the canvas and in the inspector), keep the default for the rest -->
    <template #widget="w">
      <MyFilePicker v-if="w.type?.kind === 'con' && w.type.id === 'vertex.File'" v-bind="w" />
      <WorkflowWidget v-else v-bind="w" />
    </template>
  </WorkflowWorkbench>
</template>
```

`analysis` 重播 `validate` 每一次改变。将添加接线或类型错误的拖动将被拒绝，并显示原因。连接使用的数据输入或执行输出取代其边缘。节点遵循主机的next UI主题；端口和电线的颜色是 `--wf-*` CSS变量。 `bun run play` 打开一个带有§10语言和内存库的游乐场。

语言将它们的节点分组为类别，这些类别为节点库提供部分，并为节点提供标题颜色。标签可以嵌入输入，节点内联显示为一个句子：

```ts
defineLanguage({ id: "notes", version: 1, include: [std] })
  .category({ id: "notes.files", label: "Files", color: "teal", icon: "i-lucide-folder" })
  .node({
    type: "notes.rename",
    label: "Rename {file} to {newName}", // inputs named here render inline
    category: "notes.files",
    // …
  });
```

颜色(`TypeDef`， `CategoryDef`，以及节点自己的 `color`)取一个调色板名称(`sky`， `rose`，…)或任何CSS颜色。变量和My Blocks在类别之后 `order` 0或更小，所以 `order: 1` 将语言自己的部分放在它们后面，就像在Scratch中一样。

要翻译语言，请在将其交给editor: node之前重写其清单的字符串 `label` (保持 `{input}` 占位符)和 `description`、港口 `label`年代, `exec.labels` 对于执行输出，以及类别、类型和功能标签。

为每个项目计算一次输入的节点，例如 `std.filter`，在子作用域中读取它，其中项是它自己的输出： `await ctx.input("keep", { scope: { item, index } })` 重新计算后面的纯节点 `keep` 对于那个项目。

在画布上，拖动空白区域绘制一个选择框；滚动，两个手指，空格+拖动或中间按钮平移，并⌘/Ctrl+滚动或缩放。快捷方式：⌘Z /⌘⌘Z撤消和重做（除视窗外的每个文档编辑），⌘C /⌘X /⌘V /⌘D复制，剪切，粘贴在光标处并复制，⌘A选择全部，Tab或双击在光标处打开节点搜索。在空白处放置一根电线，打开搜索，过滤到可以接受它的节点，并连接到你选择的那个节点。 右键单击画布、节点、边缘或端口将打开菜单； `WorkflowCanvas`的 `menu` 道具可以改变它的物品，而它的 `#selection` Slot将按钮添加到多节点选择下显示的栏中。

```ts
const editor = useWorkflowEditor(vertex.manifest, document, {
  messages: () => ({ undo: t("undo"), selected: (n) => t("selected", { n }) }), // translate the built-in strings
  clipboard: { read: readText, write: writeText }, // default: navigator.clipboard
});
```

副本以JSON格式(`parseClip` 读取它们)，因此它们粘贴到相同语言的另一个文档中。当剪贴板无法读取（被拒绝的权限）时，粘贴会返回到应用程序中的最后一个副本。

程序从库和选择栏中增长结构。节点库中的变量和我的块创建变量和块（函数）；对于Get，单击或拖动变量，对于Set，单击或拖动变量；检查器编辑所选节点后面的声明（块的名称、输入、输出和退出）。一个执行块可能有几个出口，每个Return指定一个出口，因此调用可以像 `std.if`。选择节点并选择Make block将它们移动到一个名为in their place的新块中(`extractFunction` in core完成工作)，或者Group构建它们；拖拽组的标题会移动其中的内容，画布菜单会添加粘性注释。组和评论存在于 `view`，所以它们不会改变程序散列。双击一个调用打开它的代码块；面包屑通向后面。

通过编辑器在画布上观看： `editor.run` 递给你 `onTrace`， `signal` 和 `beforeStep` 展开到运行中，画布显示一个运行条（Pause、Step、Continue、Cancel），并显示正在运行的节点。

```ts
editor.stepping.value = stepThrough; // stop before the first node
const { result } = await editor.run((live) =>
  run(vertex, editor.snapshot(), { event: "vertex.onManual", effects, trace: "values", ...live }),
);
```

花在 `beforeStep` 在上面提到的能力中 `interactive` （提示，拾取者）不计入 `limits.timeoutMs`.

## 脚本

| 脚本 | 做 |
| --- | --- |
| `bun run build` | 包 `src/core` 和 `src/vue` → `dist/` + `.d.mts` |
| `bun run play` | 维特游乐场(`playground/`） |
| `bun run test` | 运行Vitest一次(`test:watch` 观看) |
| `bun run typecheck` | `ui:prepare` （生成next UI的主题类型），vue-tsc (TypeScript 6.0.3), TypeScript 7 on `src/core` |
| `bun run lint` | Oxlint |
| `bun run format` | Oxfmt (`format:check` 仅供核实) |
| `bun run check` | Lint + format:check + typecheck + test |
| `bun run changeset` | 记录下一个版本的变更 |

消费者支持的最小TypeScript是 **6.0.3**，被钉住的dev `typescript`,所以 `typecheck` 与它背道而驰。vue-tsc需要TypeScript API，而7.0没有；TypeScript 7 (`typescript7`)检查 `src/core` 没有DOM库。子路径导出是手工列出的 `package.json`.

## 释放

运行 `bun run changeset` 在你的PR中，在合并到 `main`，发布工作流打开“版本包”PR；合并发布到npm。

## 许可证

麻省理工学院

## 常见问题

### @type32/workflows 是什么？

工作流脚本引擎

### 如何安装 @type32/workflows？

在项目目录运行 npm install @type32/workflows，或使用 pnpm add / yarn add / bun add。

### @type32/workflows 支持 TypeScript 吗？

该包的 package\.json 没有声明类型入口。需要类型提示时，可以在 npm 上查找社区维护的 @types/type32\_\_workflows 是否存在。

### @type32/workflows 支持 ESM 还是 CommonJS？

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

### @type32/workflows 需要什么版本的 Node\.js？

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

### @type32/workflows 可以商用吗？

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

### @type32/workflows 还在维护吗？

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

