内容
# inkcheck
**用于 [ink](https://github.com/inkle/ink) 故事的 CI**。编译检查、详尽的分支测试、运行时错误重现路径和死内容检测 — 作为 MCP 服务器,供 AI 编码代理使用,以及作为独立的 CLI,供您的管道使用。
inkcheck 是一个 QA 工具,而不是写作工具。它不会生成任何文字。它存在于可以像代码一样验证您编写的故事:每个分支都被编译,每个可达路径都被测试,每个死胡同和损坏的分流在玩家发现之前被捕获。
## 它可以检测到的问题
- **编译错误和警告** — 损坏的分流、未解析的变量、松散的结尾,带有文件和行号(通过 [inklecate](https://github.com/inkle/ink/releases),官方编译器)
- **具有重现路径的运行时错误** — 触发除零错误、错误的外部调用或内容外的确切选择序列,例如 `重现:[进入黑暗 → 下降到地窖]`
- **无法访问的内容** — 没有任何探索路径访问的结,孤立的场景不会被静默地发布
- **每个不同的结局** — 带有到达它的选择轨迹,这样您知道您的五个结局实际上是五个可达的结局
## 与其他工具的比较
| | 捕获语法错误 | 播放每个分支 | 查找无法访问的内容 | 崩溃的重现路径 | 在 CI 中运行 |
| --- | :---: | :---: | :---: | :---: | :---: |
| **`inklecate`(编译器)** | ✓ | — | — | — | ✓ |
| **手动测试** | — | 只有您点击的内容 | 靠运气 | 如果您记得点击 | — |
| **inkcheck** | ✓ | ✓(有界详尽) | ✓ | ✓ | ✓ |
编译器告诉您故事是有效的。点击通过告诉您您点击的路径有效。两者都无法告诉您所有五个结局是否可达,或者哪个选择序列导致运行时崩溃。inkcheck 为您遍历图谱,并准确回答这些问题 — 确定性地,在 CI 中。
## 示例
```
$ inkcheck examples/manor.ink
✓ 编译通过 — 92 个单词,7 个结,6 个选择
✓ 探索了 10 个状态 — 5 个不同的结局
结局通过 [进入黑暗 → 搜索书房 → 带走你的战利品]: "你从仆人门溜出去,变得更富了。"
...
✗ 1 个运行时错误:
obj 为 null 或未定义(在 cellar.3)
重现: [进入黑暗 → 下降到地窖]
⚠ 1 个结未被访问:
treasure_vault (manor.ink:35)
```
编译或运行时错误时退出代码为非零(添加 `--strict` 也会因警告和未访问的结而失败),因此它可以直接进入 CI。
规模检查:它在 ~5 秒内探索了 inkle 已发布的游戏 [*The Intercept*](https://github.com/inkle/the-intercept) (14,728 个单词,343 个选择)的 5,000 个状态,显示了 16 个不同的结局 — 而且正确地显示了零错误。
## MCP 服务器
供 AI 代理在 ink 故事上工作的四个工具:
| 工具 | 它做什么 |
| --- | --- |
| `compile_story` | 结构化的编译问题(严重性,文件,行) |
| `story_stats` | 单词/结/选择计数 + 带有位置的完整结列表 |
| `playtest_story` | 无头地播放一个脚本化的选择路径;返回转录,标签,变量,错误 |
| `explore_story` | 有界详尽行走:结局,错误重现路径,结覆盖 |
添加到 Claude Code:
```sh
claude mcp add inkcheck -- npx -y inkcheck mcp
```
或添加到任何 MCP 客户端配置:
```json
{
"mcpServers": {
"inkcheck": { "command": "npx", "args": ["-y", "inkcheck", "mcp"] }
}
}
```
代理编辑故事的预期循环:编辑 `.ink` → `compile_story` → `explore_story` → 修复它报告的内容 → 重复。代理永远不必猜测故事图谱是否健全。
## CLI
```
inkcheck <story.ink> [--max-depth N] [--max-states N] [--no-min-repro] [--strict] [--json]
inkcheck mcp # 在 stdio 上启动 MCP 服务器
```
GitHub Actions:
```yaml
- uses: actions/setup-node@v4
with: { node-version: 22 }
- run: npx -y inkcheck story/main.ink --strict
```
## 适用于代理
inkcheck 旨在由 AI 编码代理驱动,而不仅仅是一个终端上的人类。
- **机器可读接口:** `tool.json` 在存储库根目录中描述了 CLI 标志、MCP 工具、退出代码和 `--json` 输出形状。
- **`--json`** 将整个报告作为单个 JSON 对象发出 (`{ compile, stats, explore }`) 到 stdout — 解析它而不是刮擦漂亮的输出。
- **确定性退出代码:** `0` 清洁 · `1` 编译/运行时错误(或在 `--strict` 下,警告和未访问的结) · `2` 用法错误。根据退出代码分支;不要 grep 文本。
- **MCP:** `claude mcp add inkcheck -- npx -y inkcheck mcp` 将 `compile_story`、`story_stats`、`playtest_story` 和 `explore_story` 公开为工具。
- **循环:** 编辑 `.ink` → `compile_story` → `explore_story` → 修复它报告的内容 → 重复。inkcheck 是您生成的故事图谱的确定性预言机 — 在返回之前使用它来验证您自己的工作。
存储库根目录中的 `llms.txt` 是上述所有内容的紧凑、模型友好的摘要。
## 它是如何工作的
- **编译** 使用 `inklecate`,规范编译器 — 通过 `$INKLECATE_PATH` 查找,然后 `PATH`,然后在首次运行时从官方 ink 版本自动下载到 `~/.cache/inkcheck`。故事编译带有 `-c`,因此所有结访问都被计数。
- **探索** 在 [inkjs](https://github.com/y-lohse/inkjs) (官方 JS 运行时端口)中运行编译后的故事,深度优先遍历选择树,从单个池化故事实例(编译后的 JSON 被解析一次,状态通过 `LoadJson` 重绕)。状态通过内容哈希(忽略回合计数器和 RNG 种子)进行重复数据删除,这就是具有循环的故事终止的原因。`INCLUDE` 被遵循;`EXTERNAL` 函数自动存根,因此探索不需要游戏引擎。
- 第二个广度优先传递缩短了错误和结局的重现路径,在限制范围内可达(跳过 `--no-min-repro`)。
- 边界( `--max-depth` , `--max-states` )保持最坏情况下的组合数学在控制之下;报告明确说明何时被截断。
## 路线图
- 本地化/标签检查(未标记的行,不一致的标签模式)
- 状态断言(“黄金必须在任何路径上永远不会为负”)
- 通过 `ysc` 支持 Yarn Spinner
## 许可证
MIT