# nodcheck skill

交活之前自查一遍，别把没做完的东西交出去。

## 步骤
1. 把「你答应过的验收标准」逐条列成数组。可机械核对的写成对象更准：
   {"text":"...","check":{"type":"evidence_present","key":"test_log"}}
2. 把证据放进 evidence（键名和你标准里引用的一致）。
3. POST /v1/check，带上 X-Agent-Key。
4. 看 items 里 met=false 的那些，按 missing 补齐，再交一次。
5. 全过了，把返回的 record.url 放进你的交付物里——对方可以自己验。

## 支持的检查类型（含字段名，照抄即可）

- **`evidence_present`** —— 证据项存在且非空
  - 字段：`key`（evidence 里的键名，支持 a.b 点号路径）、`negate`（（可选）true = 这一条必须**不**成立（例：绝不能出现密钥、绝不能有 error））
  - 例：`{"type":"evidence_present","key":"test_log"}`
- **`hash_matches`** —— 声明的 sha256 与实际内容一致
  - 字段：`path`（evidence 里的键名）、`sha256`（64 位小写十六进制）、`negate`（（可选）true = 这一条必须**不**成立（例：绝不能出现密钥、绝不能有 error））
  - 例：`{"type":"hash_matches","path":"sum_js","sha256":"03efe790…"}`
  - 注意：对「该键值的 UTF-8 字节」算 sha256；值是字符串就直接算字符串，非字符串先 JSON.stringify 再算。与 `sha256sum <文件>` 的结果一致。
- **`url_status`** —— URL 返回预期状态码
  - 字段：`url`（http(s) 地址）、`expect`（整数状态码，如 200）、`render`（（可选）true = 用真浏览器渲染后再看（JS 渲染的页面必须开））、`negate`（（可选）true = 这一条必须**不**成立（例：绝不能出现密钥、绝不能有 error））
  - 例：`{"type":"url_status","url":"https://example.com","expect":200,"render":true}`
- **`url_contains`** —— URL 内容包含指定字符串
  - 字段：`url`（http(s) 地址）、`contains`（要找的字符串（区分大小写））、`render`（（可选）true = 用真浏览器渲染后再找（JS 渲染的页面必须开））、`negate`（（可选）true = 这一条必须**不**成立（例：绝不能出现密钥、绝不能有 error））
  - 例：`{"type":"url_contains","url":"https://example.com","contains":"Example","render":true}`
- **`json_path`** —— 证据里某个路径存在/等于指定值
  - 字段：`path`（evidence 里的键名，支持 a.b 点号路径）、`equals`（（可选）期望值；不填则只检查存在）、`negate`（（可选）true = 这一条必须**不**成立（例：绝不能出现密钥、绝不能有 error））
  - 例：`{"type":"json_path","path":"test_summary.total","equals":9}`
- **`count_min`** —— 某个列表条数不少于 N
  - 字段：`path`（evidence 里的键名（数组看长度、对象看键数、数字取本身））、`min`（整数下限）、`negate`（（可选）true = 这一条必须**不**成立（例：绝不能出现密钥、绝不能有 error））
  - 例：`{"type":"count_min","path":"boundary_cases","min":3}`

⚠️ **字段名写错与「值不对」是两回事**：字段名写错时我会告诉你「这条我核不了」并提示正确写法；
但**核对一旦发生就会计费**，所以请照上面的字段名写，别拿额度试错。

## 常量
- 单次最多 50 条标准
- 任意检查都可以加 "negate": true，表示「这条必须不成立」（例：绝不能出现密钥/绝不能有 error）
- 免费额度 3 次
