mcpField
J
JevLint-LE

JevLint-LE

本地服务
letools.devAI 与智能体15 天前更新

关于 JevLint-LE

JevLint-LE 可在代码和 JSON 中检查 Jev 与 Luna 决策模型问题,离线规则无需 API 密钥。它面向构建决策请求的开发者和 Agent,并可用用户自己的密钥进行可选模型检查。

主要功能

  1. 01检查 JSON 和六种编程语言
  2. 02应用安全修复并忽略指定发现
  3. 03编辑器、CLI、CI 与 MCP 共用规则
  4. 04提供检查、修复和规则查询的 8 个 MCP 工具
  5. 05可选模型检查与布局探测

适用场景

  1. 01发送请求前发现格式不当的决策问题
  2. 02在编辑器和 CI 中运行一致检查
  3. 03让 Agent 检查并安全修复生成的请求
  4. 04请模型审查问题或测试布局敏感性

MCP 相关

stdio MCP 服务提供 8 个工具,可检查文本或文件、应用安全修复、列出或解释规则,并执行可选的模型检查和探测。调用模型的工具使用用户配置的 API 密钥。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"nolindnaidoo-jevlint-le": {
"command": "npx",
"args": [
"-y",
"jevlint-le-mcp"
]
}
}
}
启动命令npx -y jevlint-le-mcp

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmjevlint-le-mcp0.8.1

工具

8

收录的工具列表 · 更新于 2 周前

参数类型必填说明
textstring是请求 JSON 或源代码。
rulesobject否要覆盖的规则级别,例如 { "JEV004": "off" }。级别:off、hint、info、warning、error。
filenamestring否文件名,其扩展名用于指示文本类型:.json、.ts、.js、.py、.rs 或 .go。默认为 request.jev.json。

详细介绍

DecisionLint 标志

DecisionLint:Jev/Luna Lint

发送前检查 Jev 和 Luna 决策模型问题
支持 JSON、JavaScript、TypeScript、Python、Rust 和 Go,适用于 TypeSafe、OpenAI 及所有提供其中任一平台的服务

从 VS Code Marketplace 安装 Open VSX 下载量 npm 上的 decisionlint-mcp npm 上的 decisionlint LE Tools


DecisionLint 在 VS Code 中:悬停时说明了两条检查结果,然后通过快速修复修复了两条问题

觉得有用? 点赞或评分可以帮助其他开发者找到它 — ★ GitHub · ★ Open VSX · ★ Marketplace

功能

发送 Jev 和 Luna 问题前,先对它们进行 Lint。DecisionLint 会检查你为决策模型编写的问题:TypeSafe 的 Jev、OpenAI 的 Decisions API(gpt-6-luna),以及提供这两种格式的所有平台,从 OpenRouter 和 Vercel AI Gateway,到你自己机器上的 llama.cpp。DecisionLint 会从 JSON 和代码中读取这些问题,并报告那些经评估会导致不佳回答的写法。Lint 不会调用 API,也不需要密钥。有一条可选命令可以让模型自行检查文件,并使用你自己的密钥将请求发送到你选择的平台。

  • 输入时即时 Lint,支持 JSON、JavaScript、TypeScript、Python、Rust 和 Go。
  • 对机械性错误,点击灯泡即可修复;也可以忽略你有异议的检查结果。
  • CI、命令行和 AI Agent 的 MCP 服务使用相同规则。一个设置文件即可覆盖这三种用法。
  • 一个规则集,适用于所有平台。 TypeSafe 的 /v1/systemone 格式和 OpenAI 的 /v1/decisions 格式,以及 predicate、choices 和 levels,都会按照同一套规则进行检查;AI SDK 中针对任一格式的 decide() 调用也一样。请求遵循的限制取决于平台自身,并根据模型 ID 的写法、文件中的 URL 或 target 设置读取:Vercel 限制为 255 个选项,LiteLLM 限制为 128 个问题;平台未公布限制时则不设限制。
  • 两条可选命令,使用你自己的密钥:一条会询问模型,你的问题是否存在文本模式无法发现的问题;另一条会调整问题的布局并重新发送,以检查答案是否稳定。两条命令都会将请求发送到模型 ID 所指的平台,也可以发送到你设置的端点,包括本地 llama.cpp。

像这样的请求看起来没问题,但实际上有三个问题:

{
  "model": "jev-latest",
  "state": "My parcel came three days late and the lid is cracked.",
  "questions": {
    "team": {
      "type": "choice",
      "instructions": "Which team should handle this?",
      "criteria": { "billing": "Charges and refunds", "delivery": "Late or damaged parcels" }
    },
    "late": { "type": "noul", "instructions": "Did more than two parcels arrive late?" }
  }
}
检查结果重要原因
jev-latest 上的 DEC001别名会随每次发布而变,因此即使你这边没有任何改动,答案也可能变化
team 上的 DEC004关于两支队伍都无关的消息,仍会被强行归入其中一支
late 上的 DEC102Jev 计数并不可靠。请分别询问每个包裹,并在代码中计数

安装

适用平台提供功能安装方式
VS Code输入时即时 Lint、点击灯泡即可修复,以及 Ask 和 Probe 命令Marketplace · ext install nolindnaidoo.decisionlint
Cursor、VSCodium、Windsurf相同的扩展Open VSX
终端或 CI 步骤对整个目录树应用相同规则,并提供退出代码、SARIF 和 JUnitnpx decisionlint · npm
任何 MCP Agent,通过 Node 使用通过 stdio 提供 8 个工具npx -y decisionlint-mcp · npm

在 AI Agent 中使用

同一个程序也是 MCP 服务,因此,能够编写 Jev 或 OpenAI Decisions 问题的 Agent 可以检查自己写的内容,并在你看到之前修正问题。工具说明和服务指令列出了这两家供应商以及全部三种请求格式,因此 Agent 知道遇到任何一种情况都应调用它。

编辑器使用方法
VS Code 1.101+无需安装。扩展会向编辑器提供该服务,Agent 调用工具时,编辑器会启动它
Claude Codeclaude mcp add decisionlint -- npx -y decisionlint-mcp
Cursor、Windsurf 及其他工具指向 npx -y decisionlint-mcp

Claude Code 中的 Agent 通过 MCP 服务检查请求,并列出三项发现

它提供八种工具。lint_text 检查以文本形式传入的请求或源代码,lint_paths 检查磁盘上的文件,每项发现都会附带可修正该问题的编辑内容。fix_text 返回应用安全修复后的文本以及剩余问题的报告,不会写入任何内容。list_rules 列出每条规则及其含义,explain_rule 返回规则自身的页面,其中包含一个会被标记的示例和一个不会被标记的示例。这些工具不会发送任何内容,也不需要密钥。

另外三种工具是供 Agent 使用的编辑器 Ask 命令和 Probe。ask_model 会请求 Jev 或 Luna(使用 model: gpt-6-luna)检查文本或文件中的问题,并返回包含模型发现的 lint 报告。plan_ask 会说明将发送哪些内容,但不会发送任何内容。probe_question 会以不同排版方式发送一个问题,并报告答案是否稳定。会发送内容的两种工具会使用你的密钥并产生费用,其说明会告知 Agent 只有在你提出要求时才能调用。密钥会从客户端启动服务时所处环境中的 TYPESAFE_API_KEY 或 OPENAI_API_KEY 读取,也会从服务启动目录中的 .env.local 或 .env 读取,不会从工具参数中读取,因此密钥不会出现在 Agent 的对话记录中。每种工具都会在文本旁返回结构化内容,而且都不会写入文件。

它在 MCP 注册表中的条目为 io.github.nolindnaidoo/decisionlint,供从该处安装服务的客户端使用。

手动配置:任何使用 MCP 配置文件的宿主

大多数宿主都会读取 JSON 配置。添加一条配置:

{
  "mcpServers": {
    "decisionlint": { "command": "npx", "args": ["-y", "decisionlint-mcp"] }
  }
}

-y 可跳过首次运行时的安装提示。如需每次启动时都跳过 npx,可使用 npm install -g decisionlint-mcp 安装一次,然后将 "command": "decisionlint-mcp" 设为命令。

对于已为 CI 固定 decisionlint 版本的项目,可通过 npx decisionlint --mcp 使用同一个服务。提供给客户端时,应使用不带标志的包,因为直接启动 decisionlint 会运行一个随后退出的 lint 工具,而不是服务。

它能检查哪些问题

Jev 和 Luna 保证的是答案的类型,而不是答案本身。格式不当的问题仍可能得到一个看似笃定的数字。这些规则可以发现那些能从文本中识别出的错误。

CodeNameDefault含义
DEC000unreadablehint问题的一部分是在运行时构建的,因此需要这部分内容的规则未能运行
DEC001unpinned-modelwarningjev-latest 之类的别名会随每次发布而变化,因此即使你这边没有任何更改,答案也可能改变
DEC002choice-option-limiterrorChoice 的选项超过 255 个。API 会拒绝它
DEC003score-level-limiterrorScore 的等级超过 10 个。API 会拒绝它
DEC004no-fallback-optioninfoChoice 没有 other 或 none of the above,因此不符合任何选项的输入会被强行归入某个选项。这是任何地方测得的最大成本,也是最难从文本中判断的一项
DEC005duplicateerror问题 ID、选项或等级重复出现。在对象中,后出现的项会静默覆盖先出现的项
DEC006criteria-shapeerrorChoice 需要选项映射,Score 需要等级数组,而 Noul 接受 true 和 false
DEC007invalid-questionerror类型缺失或未知,或者说明是空字符串
DEC008numeric-levelswarningScore 等级是裸数字。Jev 会根据每个描述将状态与之匹配,而不会看到其位置
DEC009too-few-optionsinfo只有一个选项的 Choice 或只有一个等级的 Score 会对所有输入给出相同答案
DEC010unused-disablewarningdecisionlint-disable 注释没有禁用任何内容,因此它只可能掩盖之后新增的问题
DEC011description-repeats-nameinfo选项的描述只是在重复其名称,或者 Noul 的 criteria 只说了是与否。Jev 会根据描述匹配状态,而这段描述没有提供任何信息
DEC012terse-instructionsinfo说明只有一两个词,因此问题依赖其 ID。Jev 收到的是说明,而不是 ID
DEC013newer-modelinfomodel 指定的 Jev 版本比这些规则所依据的版本更新,因此某个问题在该版本中可能没有任何成本,而该版本中新出现的弱点也未被检查
DEC014question-limiterror请求中的问题数量超过了目标平台单次调用所能接受的数量。平台会拒绝该请求
DEC101double-negativeinfo一个子句中的问题包含双重否定,或者一个否定直接嵌套在另一个否定上
DEC102arithmeticwarning问题要求 Jev 计数或比较数字
DEC103date-comparisoninfo问题要求 Jev 对两个时间进行排序,或测量它们之间的间隔
DEC104compoundoffNoul 用“and”连接两个判断
DEC105generationwarning问题要求给出一个值或撰写一段文本
DEC107negated-nouloff没有 criteria 的 Noul,其措辞使“是”表示某物不存在
DEC108inverted-criteriaoffNoul 的“true” criterion 描述的是否定情况
DEC110degree-levelsoffScore 等级是程度词、裸标签,或同一个词的强弱变化。没有可供 Jev 用来匹配状态的内容
DEC111numeric-encodingoff问题通过十六进制或 RGB 编码指代某个值
DEC112undefined-boundaryoff没有 criteria 的 Noul 由 large、often 或 enough 之类的词触发
DEC301model-countingwarningJev 将问题理解为需要计数或算术运算
DEC302model-undefined-boundaryinfoJev 将 Noul 理解为需要判断未明确界限的程度问题
DEC303model-overlapping-optionsinfoJev 将 Choice 的两个选项理解为涵盖了相同情况
DEC304model-overlapping-levelswarningJev 将 Score 的两个等级理解为描述相同情况
DEC305model-label-mismatchwarningJev 将某个选项理解为名称指向一件事、描述却指向另一件事
DEC306model-criteria-off-topicinfoJev 将 criteria 理解为用于判断说明未要求判断的内容
DEC307model-ordered-optionsinfoJev 将 Choice 的选项理解为同一尺度上的不同步骤,而 Score 才能表示步骤之间的等级
DEC308model-unordered-levelsinfoJev 将 Score 的等级理解为无序类别,而 Choice 才会从中进行选择
DEC309model-depends-on-siblinginfoJev 将问题理解为需要同一请求中另一个问题的答案
DEC310model-overlapping-questionsinfoJev 将同一请求中的两个问题理解为询问相同的判断
DEC311model-answer-not-in-stateinfoJev 将文件中写入的状态理解为不包含问题所询问的内容
DEC312model-orders-in-stateinfoJev 将文件中写入的部分状态理解为在向其读者发出指令
每条发现都链接到自己的页面,其中包含一个会被标记的示例、一个不会被标记的示例、修复方法以及如何忽略它。每个页面还会链接到该规则所依据的 TypeSafe 文档。

检查范围

  • JSON 和 JSONC 请求正文,支持 TypeSafe 或 OpenAI 的格式。
  • JavaScript 和 TypeScript 中的对象字面量,包括内联传给 client.systemOne(...) 和 client.decisions.create(...) 的请求,以及适用于任一供应商的 Vercel AI SDK 的 decide({ questions });其中 typeSafeAi.decisionModel('...') 内的模型 ID 会被识别为模型。
  • 使用 @typesafe-ai/sdk 的文件中的 noul()、choice() 和 score() 调用。
  • Python:typesafe_sdk 中的字典、Noul(...)、Choice(...) 和 Score(...),LangChain 的 langchain_typesafe 中的 NoulCriteria(...),或封装了上述任一项的库中的相应对象,以及传给 system_one(...) 或 client.decisions.create(...) 的请求。
  • Rust:json! 中的 JSON、以问题类型命名的结构体和枚举变体,以及 ::noul(...) 风格的构造函数。
  • Go:键为字符串的映射、带有 Type 字段的结构体、以问题类型命名的结构体,以及 OpenAI 的 Go SDK 中带有 OfPredicate、OfChoice 和 OfScore 问题的 openai.DecisionNewParams{...}。
  • 在上述任意语言中,以 JSON 形式粘贴到字符串里的请求。
  • 其他任何语言:让程序将它发送的请求写入 .jev.json 文件,然后打开该文件。每项检查都会在该文件上运行,且其中没有任何内容是在运行时构建的,因此不会漏检。
  • oxlint-plugin-jev 配置中的 jev/ask 规则。

OpenAI 的 Decisions API

OpenAI 的 Decisions API 使用模型 gpt-6-luna,提出的问题类型与 Jev 相同,但格式不同。DecisionLint 从 0.5.0 开始读取这类请求。具体覆盖范围如下:

  • 读取。 /v1/decisions 请求正文、TypeScript 和 Python 中的 client.decisions.create(...),以及 Vercel AI SDK 的 decide()。predicate 会被识别为 Noul,choices: [{ value, description }] 会被识别为 Choice 的选项,levels: [{ label, description }] 会被识别为 Score 的等级,并套用相同的规则。
  • 检查。 有证据支持的每条规则:缺少回退选项、描述只是重复名称、指令过于简短、等级程度、重复项、计数、未定义的边界等。发现中会提及 Luna。OpenAI 自己的指南也要求这些内容。
  • 不检查。 DEC002 和 DEC003 检查平台公布的限制,而 OpenAI 没有公布此类限制,因此发往 OpenAI 的请求不会触发这两项检查。发往有此类限制的网关(例如 Vercel)的请求则会触发这两项检查。DEC001 针对的是 Jev 会变动的别名,而 OpenAI 只有一个模型 ID。
  • 格式错误会按 OpenAI 自己的字段名报告:choices 被写成映射或裸名称、Choice 没有 choices、Score 没有 levels。拼错的 predicate 可以通过灯泡修复。重塑格式的修复仅适用于 Jev。
  • 询问 Luna。 运行 Ask Luna About This File,或传入 --ask-platform openai,并提供 OpenAI 密钥。下一节会说明操作方法。
  • 以 Jev 为基准,并为 Luna 单独设定阈值。 所有措辞规则的默认值都是通过衡量缺陷对 jev-1.13.0 的影响而设定的。模型驱动的检查于 2026-10-24 在 Luna 上针对整个校准集运行,并根据 Luna 自己的回答为每项检查设定了适用的阈值,例如十二项中七项。其余五项不会用于检查 Luna,因为没有阈值能区分有缺陷的示例和没有缺陷的示例;docs/cutoffs.md 列出了每项检查无法区分示例的原因。目前尚未测量措辞规则对 Luna 的影响。

每个平台

Jev 和 Luna 是两种模型,TypeSafe 和 OpenAI 则是请求可以发送到的两个平台。Microsoft、Liquid AI 和 Cloudflare 以 TypeSafe 的格式提供各自的模型。OpenRouter、Vercel AI Gateway、LiteLLM 和 LLM Gateway 会以任一种格式转发到其中任意平台。llama.cpp、vLLM 和 Ollaya 可在你自己的机器上运行开源模型。DecisionLint 能读取这两种格式,因此这些平台都适用同一套规则。它们之间的差异集中在一个表格中:src/lint/targets.ts,并附有每项信息的来源页面:

平台调用方式密钥变量发布的限制
TypeSafejev-1.13.0、jev-latestTYPESAFE_API_KEY255 个选项、10 个层级
OpenAIgpt-6-lunaOPENAI_API_KEY无
OpenRouter~typesafe/jev-latest、typesafe/jev-1.13OPENROUTER_API_KEY无
Vercel AI Gatewaytypesafe-ai/jev、openai/gpt-6-luna-decisionsAI_GATEWAY_API_KEY255 个选项、10 个层级
LLM Gatewaygpt-6-luna-decisions、microsoft-decision-1LLM_GATEWAY_API_KEY无
Liquid AId1、d1:freeLIQUID_API_KEY无
LiteLLM你设置的端点对应格式的密钥每个请求 128 个问题
Eden AI它自己的路径它自己的密钥255 个选项
llama.cpp你设置的端点无10 个层级

从表格可以得出三点:

  • 请求受到的平台限制约束。 平台信息会从模型 ID 中的平台名称判断,从文件中 URL 所指的平台判断,或从 decisionlint.json 中的 target,或从 decisionlint.target 判断,后者适用于所有请求都发送到同一平台的项目。平台未发布限制时,不会针对该限制报告问题。请求发往何处并不重要:TypeSafe 格式的问题仍遵循 TypeSafe 的限制,其他格式则不受任何限制。
  • 无版本别名的各种写法都会被检测到,并按平台文档中的写法固定版本:jev-latest 固定为 jev-1.13.0,~typesafe/jev-latest 固定为 typesafe/jev-1.13。
  • 使用模型进行的检查会发送到 ID 所指的平台,并使用该平台的密钥变量。像 openai/gpt-6-luna-decisions 这样无法指明托管平台的写法——所有网关都采用这种写法——会被拒绝,而不是猜测目标平台;除非你设置端点。接下来的两个部分会介绍具体方法。

“Open Jev”并不是其中一个平台。至少有九个互不相关的项目使用这个名称来重新实现 /v1/systemone;llama.cpp 提供的那个项目是 ggml-org/OpenJev-GGUF。每个项目都通过你设置的端点调用。

测试过的平台

我们通过每个平台的实时 API 发送了真实请求,并在每个平台上对整个校准集运行了模型检查:

  • TypeSafe,jev-1.13.0,Jev 的阈值在此平台上设定。
  • OpenRouter,typesafe/jev-1.13。它的回答与 TypeSafe 相同,因此其检查结果视为已校准。
  • LLM Gateway,jev-1.13.0,以及 Vercel AI Gateway,typesafe-ai/jev。这两个平台接收 OpenAI 格式的请求,这会让 Jev 的回答略有变化,因此其检查结果会注明阈值是在 TypeSafe 上设定的。
  • OpenAI,gpt-6-luna,Luna 的阈值在此平台上拟合;以及 Vercel AI Gateway,openai/gpt-6-luna-decisions,其回答与 OpenAI 相同。
  • Liquid AI,d1,d1 的阈值在此平台上拟合。

从 1.1.0 起,Luna 和 d1 各自都有专属阈值,这些阈值分别根据对应模型对整个校准集的运行结果拟合:某个阈值不会标记任何正确示例,并且至少能检出十分之六的错误示例。如果某项检查无法达到这个标准,就不会对该模型运行:Luna 有五项检查,d1 有两项。其他模型,或这些模型以其他 ID 或通过其他路由使用时,会按所属系列的阈值,或 Jev 的阈值进行判断,并且其每条检查结果都会注明这一点。docs/cutoffs.md 列出了每个阈值、在每个模型上检出的已知缺陷数量和误标的正确问题数量、未运行的每项检查为何不运行,以及各平台的回答与其他地方相同模型的回答相差多远。该文档根据保存的运行结果编写,因此其中的数字均来自实际运行结果。尚未运行 LiteLLM、Eden AI 和 llama.cpp。

询问模型关于文件的问题

规则 DEC301 至 DEC312 不属于 lint 检查。只有运行某个 询问 命令,或在命令行中传入 --ask 时才会执行。每次运行都会将文件中的每个问题发送给决策模型,并请它检查文本模式无法发现的问题:选项之间有重叠、选项名称与其描述矛盾、标准针对了错误的对象、应该使用 Score 而非 Choice、两个问题询问的是同一件事,或某个问题需要依赖另一个问题的答案。

每个平台各有一个命令,并且各自使用单独的密钥:

命令发送至默认模型密钥
询问 Jev 关于此文件TypeSafejev-1.13.0设置 TypeSafe API 密钥,或 TYPESAFE_API_KEY
询问 Luna 关于此文件OpenAIgpt-6-luna设置 OpenAI API 密钥,或 OPENAI_API_KEY
通过 OpenRouter 询问关于此文件OpenRoutertypesafe/jev-1.13设置 OpenRouter API 密钥,或 OPENROUTER_API_KEY
通过 Vercel AI Gateway 询问关于此文件Vercel AI Gatewaytypesafe-ai/jev设置 Vercel AI Gateway API 密钥,或 AI_GATEWAY_API_KEY
通过 LLM Gateway 询问关于此文件LLM Gatewayjev-1.13.0设置 LLM Gateway API 密钥,或 LLM_GATEWAY_API_KEY
询问 Liquid d1 关于此文件Liquid AId1设置 Liquid AI API 密钥,或 LIQUID_API_KEY
询问关于此文件的自定义端点模型decisionlint.ask.endpointdecisionlint.ask.endpointModel设置端点 API 密钥,或不设置
  1. 通过以下三种方式之一提供该平台的密钥。运行其 设置……API 密钥 命令并粘贴密钥,此操作会将密钥存储在操作系统的密钥链中。或者,在 Settings 中的 decisionlint.ask.keys 下,按平台 ID 输入密钥;该设置只能在用户设置中配置,并且不会包含在 Settings Sync 中。也可以将密钥放入该平台指定的环境变量中,并设置在 VS Code 运行的环境里。
  2. 打开包含问题的文件,并运行该平台的 询问 命令。

每个命令发送的模型由 decisionlint.ask.models 按平台指定。TypeSafe 的默认模型是设定这些检查阈值时使用的版本;若检查结果来自其他模型,包括 Luna,都会注明这一点。经测量,OpenRouter 的 typesafe/jev-1.13 回答与该版本相同,因此其检查结果不会注明。探测功能会使用 TypeSafe 的密钥和模型,在 TypeSafe 上询问 Jev。 对于你托管的平台,例如 llama.cpp、vLLM、LiteLLM 或 Ollaya,请将 decisionlint.ask.endpoint 设置为其监听的完整 URL, 将 decisionlint.ask.endpointModel 设置为它提供的模型 ID,并且当路径 不以 /systemone 或 /decisions 结尾时,将 decisionlint.ask.endpointShape 设置为 typesafe 或 openai。然后运行 Ask the Model at My Endpoint。如果你设置了 endpoint,它会发送 endpoint 键;否则会发送 TYPESAFE_API_KEY 或 OPENAI_API_KEY 中对应形态的 SDK 会读取的密钥;如果没有密钥,则不发送密钥,这也是连接本地 llama.cpp 的方式。端点只能在你的用户设置中设置,因此存储库无法将你的密钥指向它自行选择的主机。

运行前需要了解:

  • 它会使用你的密钥和额度。 每个问题发送一个请求,每个请求正文再发送一个请求;Jev 每次约 800 个输入 token,Luna 则约为两倍。按 TypeSafe 公布的价格,每个问题只需几千分之一美分;按 OpenAI 的价格,则需百分之一到百分之二美分。发送前显示的数量是向上取整后的估算值,平台实际计费可能有所不同。
  • 只会发送问题内容:类型、说明、标准和 ID。除非启用 decisionlint.ask.sendState,否则不会发送你的 state。启用后,文件中写出的 state 也会发送,并额外运行两项检查:state 是否包含每个问题所询问的内容,以及其中是否包含向阅读者发号施令的文本。
  • 包含运行时构造部分的问题不会发送。 摘要会说明有多少个问题未发送。
  • 每次运行最多发送 decisionlint.ask.maxCalls 个请求,默认为 25 个。
  • 在不受信任的工作区中会禁用此功能。 运行 Workspaces: Manage Workspace Trust 并信任该文件夹即可启用。
  • 编辑文件后,检查结果会消失,因为它们针对的是旧文本。检查期间编辑或关闭文件都会停止检查。
  • 每条检查结果都会显示 Jev 给出的概率。 请将其视为附带数字的论据,而不是裁决。

启用 decisionlint.ask.confirm 后,它会先告知你将发送多少个请求、大约会使用多少个 token 以及费用,然后等待你确认。此选项默认关闭:运行命令即表示决定发送。

探测问题

将光标放在一个问题中,然后运行 DecisionLint: Probe the Jev Question at the Cursor。它会根据旁边写出的 state 对该问题进行检查:先按原样发送三次,然后改变布局再发送:反转选项顺序、隐藏选项名称、反转级别顺序、移除标准。打开的报告会显示答案是否发生变化。

如果仅仅改变选项顺序就导致答案变化,说明这个问题并没有真正做出判断。如果三次相同请求得到不同结果,说明输入难以判断。

文件中必须写出 state;它会发送该 state,且需要五到六个请求。

此扩展中没有其他功能会使用网络。在命令行中,只有 --ask 会使用网络。

项目设置

在项目中放入 decisionlint.json,编辑器和命令行都会读取它,因此你编写时看到的内容就是 CI 报告的内容。

{
  "rules": { "DEC004": "error", "DEC110": "warning" },
  "fallbackOptions": ["other", "none", "unsure"],
  "ignore": ["DEC004:department"],
  "exclude": ["fixtures", "**/*.generated.ts"]
}

exclude 列出无需 lint 的文件和文件夹,路径相对于设置文件。** 可跨越文件夹,* 只匹配当前文件夹,而不含斜杠的名称可匹配任意深度。编辑器和命令行会排除相同的文件。

从被 lint 的文件开始向上查找,最近的设置文件优先,因此文件夹可以有自己的设置文件。适用时,它会替换编辑器中的 rules、fallbackOptions 和 ignore 设置。如果无法读取该文件,则不会 lint 任何内容,状态栏会说明原因。不认识的键会被视为错误,因此拼写错误不会悄悄导致某条规则仍然生效。

要忽略某条检查结果,请使用灯泡菜单:Disable DEC004 for this line 或 for this file 会为你写入注释。严格 JSON 不支持注释,因此要在其中忽略检查结果,请使用 ignore。

它不会告诉你的内容

  • 格式正确的问题在你的数据上是否正确。 这需要带标签的示例和对 Jev 的调用。
  • 关于它无法看到的值的任何信息。 由变量构成的问题会被报告为无法读取,并计入状态栏。文件的部分内容尚未读取时,绝不会显示为干净。
  • 关于措辞的所有信息。 DEC101 到 DEC112 是针对英文文本的启发式规则。只有当措辞不佳的问题在我们的运行或他人的运行中导致 Jev 给出的答案或置信度下降时,才会启用相应规则;而且只有当它在未用于调优的公开代码中,对至少 10 条发现里的 9 条判断正确时,才会继续启用。TypeSafe 文档中描述故障模式的 4 条规则——DEC104、DEC107、DEC108 和 DEC111——在 jev-1.13.0 上没有失效,因此处于关闭状态。DEC110 和 DEC112 会导致答案减少,但在第二个公开样本中未达到 10 条中 9 条的标准,分别为 9 条中 8 条和 3 条中 2 条,因此从 1.1.0 起处于关闭状态。在 decisionlint.rules 中启用其中任意一条。另有两条规则因每次触发都判断错误,已在 0.4.0 中移除。
  • 关于非英文问题的任何信息。
  • 单独一个对象缺少什么。 questions 映射之外的 { type, instructions } 可能是模板,也可能是构造器的一部分,因此只有在请求中才会报告缺少 criteria 的问题。

DEC004 仅提供信息,因为它背后的建议有条件:当选项可能无法涵盖所有输入时,添加回退选项。TypeSafe 自身文档中的 Choice 示例有 11 个,其中 9 个会触发此规则。如果你的选项已穷尽所有情况,可针对该问题关闭此规则。

忽略发现

在代码中:

// decisionlint-disable-next-line DEC004
const side = { type: 'choice', instructions: 'Heads or tails?', criteria: { heads: null, tails: null } };

decisionlint-disable-line 会忽略同一行,decisionlint-disable 会忽略整个文件。 不指定代码即可关闭所有规则。

不会忽略任何内容的注释会被报告为 DEC010,因此修复发现后遗留的注释无法隐藏之后的新发现。

为 JevLint-LE 编写的内容仍然有效:jevlint-le-disable 注释,以及注释、rules 或 ignore 中的 JEV 代码,都会被永久读取。每条发现都会附带 DEC 代码。

修复

有些发现无需你做决定即可修复:Noul 的 criteria 键写成了 API 要求 true 的 yes、问题类型拼写错误、criteria 格式不正确。npx decisionlint --fix 会写入这些修复内容,每次运行的摘要也会说明可以修复多少项。

在编辑器中,保存时修复会执行相同操作:

{ "editor.codeActionsOnSave": { "source.fixAll.decisionlint": "explicit" } }

添加回退选项和固定模型会改变正常请求的行为,因此绝不会替你写入。这些操作会保留在灯泡菜单中。

JSON 不支持注释,因此请使用此设置:

{ "decisionlint.ignore": ["DEC004:side"] }

CLI

相同的 lint 检查也可在编辑器之外运行,供 CI 和 VS Code 以外的任何编辑器使用。

命令行报告一个小型请求中的三条发现

编辑器和 CI 使用同一版本

像安装其他 linter 一样,将它安装到项目中:

npm install --save-dev decisionlint

之后,编辑器会使用该副本进行 lint,而不是扩展自带的副本,因此你在输入时看到的结果,就是 npx decisionlint 在 CI 中报告的结果。版本会随 package.json 一起变更,并同时对所有人生效。使用项目副本时,状态栏会显示 project 0.5.2。

未安装时,扩展会使用自带副本进行 lint,无需任何设置。

当项目副本无法使用时,扩展也会改用自带副本;状态栏会显示 project has 0.2.0,并在工具提示中说明原因:

  • 工作区不受信任,因为加载该副本会运行其中的代码
  • 该副本早于 0.3.0,这是编辑器能够加载的首个版本
  • 该副本加载失败,或无法读取这类文件

如果无法读取副本的 package.json,则没有版本可显示,因此状态栏会显示 project copy unreadable,并同样在工具提示中说明原因。

无论项目安装了什么,Ask 命令和探测功能始终运行扩展自带的代码。

npx decisionlint src/                 # a directory, searched for files it reads
npx decisionlint request.jev.json     # one file
npx decisionlint --format github .    # annotations on a pull request

运行通过时,它会以 0 退出;发现的问题导致运行失败时,以 1 退出;无法完成所要求的操作时,以 2 退出,例如遇到未知选项、缺少路径或没有可读取的内容。错误总会导致运行失败。只有警告数量超过 --max-warnings 时,警告才会导致运行失败。

选项作用
--format <stylish|compact|json|github|sarif|junit>指定发现的问题的打印方式。stylish 按文件分组,是默认格式。compact 每行显示一项,格式为 path:line:column。sarif 用于代码扫描,junit 用于测试报告工具。也可使用 -f
--rule <CODE=level>将一条规则设为 off、hint、info、warning 或 error。也可以用规则名称代替代码,warn 表示 warning
--config <file>使用此设置文件,并且不在文件附近查找 decisionlint.json。也可使用 -c
--max-warnings <n>报告的警告超过 n 条时,运行失败
--stdin-filename <path>将标准输入作为该文件进行检查
--fix写入仅修复 API 会拒绝内容的修复
--quiet仅打印错误
--ask还会就每个问题询问模型。请求会发送到模型 ID 所指的平台:默认使用 TYPESAFE_API_KEY 发送到 TypeSafe;使用 --ask-model gpt-6-luna 时,使用 OPENAI_API_KEY 发送到 OpenAI;也可以按各平台的名称指定 OpenRouter、Vercel AI Gateway、LLM Gateway 或 Liquid AI,或者发送到 --ask-endpoint 指定的位置
--ask-plan显示 --ask 将发送的内容,但不发送任何内容
--ask-platform <id>指定 --ask 的发送平台:typesafe、openai、openrouter、vercel、llmgateway 或 liquid。每个平台都有自己的密钥变量和对应名称格式的默认模型。不指定时,模型 ID 会将请求发送到其名称所指的平台
--ask-model <id>指定 --ask 使用的模型:Jev 版本、OpenAI Decisions API 的 gpt-6-luna,或其他平台名称格式的模型 ID。默认值为 jev-1.13.0
--ask-endpoint <url>指定 --ask 发送请求的完整 URL,适用于你托管的平台,或模型名称未指定主机的网关。也可从 DECISIONLINT_ASK_ENDPOINT 读取。如果工具不识别该主机,请求会发送对应格式的密钥,或不发送密钥
--ask-shape <shape>当 --ask-endpoint 的路径不以 /systemone 或 /decisions 结尾时,指定发送到该地址的请求格式:typesafe 或 openai。也可从 DECISIONLINT_ASK_SHAPE 读取
--ask-max-calls <n>指定一次运行中 --ask 最多可发送的请求数。默认值为 25
--ask-send-state使用 --ask 时,也发送写入文件的状态
--color、--no-color为默认格式启用或关闭颜色。不指定任一选项时,终端中会启用颜色,除非设置了 NO_COLOR
--no-error-on-unmatched-pattern路径中没有可检查的文件时,运行仍通过
--mcp以 MCP 服务模式运行

摘要行始终会说明有多少问题未能完整读取,并列出因大小而跳过的文件,以及无法读取的文件或文件夹。它不会跟随链接文件夹。除非传入 --ask,否则不会运行需要询问 Jev 的检查,也不会使用网络。

在 CI 中及提交前

在 GitHub 上,此 action 会为拉取请求添加注释:

- uses: nolindnaidoo/[email protected]
  with:
    paths: src

对于 GitHub 代码扫描,请生成 SARIF 并上传:

- run: npx decisionlint --format sarif src > decisionlint.sarif
  continue-on-error: true
- uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: decisionlint.sarif

--format junit 会写入 Jenkins、GitLab 和大多数测试报告工具可读取的 XML。只有错误会被视为失败用例,因为只有错误会导致运行失败。

搭配 pre-commit 使用:

- repo: https://github.com/nolindnaidoo/decisionlint
  rev: v1.1.0
  hooks:
    - id: decisionlint
询问模型

--ask 会在 lint 后运行向决策模型提问的检查项 DEC301 至 DEC312。这是唯一会使用网络的选项,且无法通过设置文件启用。

npx decisionlint --ask-plan src/                    # what it would send. No key, nothing sent
TYPESAFE_API_KEY=... npx decisionlint --ask src/    # send it
  • --ask-platform 用于指定请求发送到哪里:typesafe、openai、openrouter、vercel、llmgateway 或 liquid。每个平台都有以自身拼写命名的默认模型,以及各自的密钥变量:TYPESAFE_API_KEY、OPENAI_API_KEY、OPENROUTER_API_KEY、AI_GATEWAY_API_KEY、LLM_GATEWAY_API_KEY 或 LIQUID_API_KEY。未指定该选项时,若 --ask-model 使用平台对应的拼写,或使用适用于 OpenRouter 的 ~typesafe/jev-latest,请求就会发送到该平台;裸 ID 则发送到其厂商。密钥只会从相应变量中读取,不会从其他地方读取,也绝不会打印出来。
  • --ask-endpoint 或 DECISIONLINT_ASK_ENDPOINT 会将请求发送到你托管的平台;如果路径未说明其采用哪种格式,可通过 --ask-shape 指定。若名称未指向任何主机,例如 openai/gpt-6-luna-decisions,则在未指定该选项时会拒绝请求,不会发送任何内容。
  • 问题中包含运行时构建的部分时,绝不会发送该问题。摘要会统计被拦截的问题数。
  • 除非添加 --ask-send-state,否则不会发送状态信息。
  • --ask-max-calls 限制整个运行过程中的调用次数。若运行所需调用次数超出限制,将以状态码 2 退出,因此作业不会在只检查项目部分内容后通过。
  • 密钥被拒绝、请求失败或运行被你中止时,也会以状态码 2 退出,并说明已收到答复的请求数和计划请求总数。
  • 默认情况下,这些发现项的级别为警告或更低,因此只有在通过 --rule 提高级别,或指定 --max-warnings 时才会导致运行失败。

命令

每个命令都可以设置快捷键。打开 键盘快捷方式,搜索 DecisionLint,然后为列表中的任意命令按下你想使用的按键。默认情况下没有绑定任何快捷键,因此不会与现有快捷键冲突。

也可以将它们写入 keybindings.json。以下按键仅为示例:

[
  { "key": "ctrl+alt+j", "command": "decisionlint.lintFile", "when": "editorTextFocus" },
  { "key": "ctrl+alt+k", "command": "decisionlint.askJev", "when": "editorTextFocus" }
]
命令ID
检查此文件中的问题decisionlint.lintFile
检查工作区中的问题decisionlint.lintWorkspace
打开设置decisionlint.openSettings
就此文件询问 Jevdecisionlint.askJev
就此文件询问 Lunadecisionlint.askLuna
通过 OpenRouter 就此文件提问decisionlint.askOpenRouter
通过 Vercel AI Gateway 就此文件提问decisionlint.askVercel
通过 LLM Gateway 就此文件提问decisionlint.askLlmGateway
通过 Liquid d1 就此文件提问decisionlint.askLiquid
就此文件询问我端点上的模型decisionlint.askEndpoint
设置 TypeSafe API 密钥decisionlint.setTypeSafeApiKey
设置 OpenAI API 密钥decisionlint.setOpenAIApiKey
设置 OpenRouter API 密钥decisionlint.setOpenRouterApiKey
设置 Vercel AI Gateway API 密钥decisionlint.setVercelApiKey
设置 LLM Gateway API 密钥decisionlint.setLlmGatewayApiKey
设置 Liquid AI API 密钥decisionlint.setLiquidApiKey
设置端点 API 密钥decisionlint.setEndpointApiKey
清除 API 密钥decisionlint.clearApiKeys
检查光标处的问题decisionlint.probeQuestion

Ask 命令和探测命令会使用你的密钥发送请求,因此请为它们选择不容易误触的快捷键。

设置

设置项默认值含义
decisionlint.rules{}按规则代码或名称设置严重级别:off、hint、info、warning、error。如果条目指定了不存在的规则或级别,检查会停止并说明原因,与 decisionlint.json 中的行为一致
decisionlint.fallbackOptionsother、none、unknown、unclear、uncertain、unsure、ambiguous、undetermined、neither、not stated、not applicable、insufficient evidence、cannot tell、n/a,以及另外五种语言中的“other”使选项成为 DEC004 后备选项的词。选项名称中只要包含其中一个词,就会被视为符合条件,因此 none_implied 和 other_or_unclear 也符合条件
decisionlint.ignore[]要忽略的 CODE:questionId 条目
decisionlint.target""所有请求发送到的平台,用于确定其限制。留空时,会根据每个模型 ID 读取平台
decisionlint.ask.modelstypesafe 对应 jev-1.13.0,其余平台使用各自的默认值各个平台的 Ask 命令发送的模型 ID。TypeSafe 的默认值是校准检查时使用的版本
decisionlint.ask.keys空各个平台的 API 密钥,以及你指定的主机对应的 endpoint。如果不想使用钥匙串,可以在此输入密钥。仅限用户设置,不会同步
decisionlint.ask.endpoint""Ask the Model at My Endpoint 要向其发送请求的平台托管 URL。仅限用户设置
decisionlint.ask.endpointShape""发送到该端点的数据格式:typesafe 或 openai。当路径未表明格式时使用
decisionlint.ask.endpointModel""发送到该端点的模型 ID
decisionlint.ask.maxCalls25单个 Ask 命令最多可发送的请求数
decisionlint.ask.sendStatefalse同时发送文件中写入的状态,以便模型进行检查
decisionlint.ask.confirmfalse付费命令发送任何内容前,显示将要发送的内容及费用,并等待确认
decisionlint.includeJSON、JavaScript、TypeScript、Python、Rust 和 Go 文件工作区命令要检查的文件
decisionlint.excludenode_modules 和构建输出工作区命令要跳过的文件
decisionlint.maxFileSizeBytes1000000超过此大小的文件会被报告为已跳过
decisionlint.notificationsLevelimportant通知中显示的信息量。all 会在每条命令后添加摘要,silent 仅在命令无法运行时显示消息。检查结果始终会显示在编辑器中

隐私与安全

  • 检查绝不会使用网络。 扩展、命令行和 MCP 服务无需密钥即可进行检查,也不会发送任何内容。不会收集遥测数据。
  • 只有 Ask 命令、探测命令、--ask 和两个会发送数据的 MCP 工具 会连接到平台,并使用你的密钥;且只有在你运行它们时才会连接。它们会发送 问题,不会发送你的 state,除非你启用 decisionlint.ask.sendState 或 --ask-send-state。探测命令会发送问题旁边写入的状态。
  • 密钥不会留在代码库中。 Set ... API Key 命令会将 密钥存储在操作系统钥匙串中。decisionlint.ask.keys 和 decisionlint.ask.endpoint 只能在用户设置中配置;这些设置不会纳入设置同步, 因此代码库无法将你的密钥发送到任意主机。命令行只会从环境变量 读取密钥,且绝不会打印密钥。
  • 不受信任的工作区无法发送数据。 其中的 Ask 命令会被禁用,也不会加载 项目自带的检查器,因为加载它会运行工作区中的代码。
  • MCP 服务不会写入任何内容,并且只会从客户端启动它时提供的环境、 或其目录中的 .env.local 或 .env 读取密钥,绝不会从工具参数中读取, 因此密钥不会进入 Agent 的对话记录。

文档

内容位置
产品是什么,以及计划中的内容SPEC.md
产品如何构建和维系:架构、不变量、发布AGENTS.md
每条规则,以及一个会触发标记的示例和一个不会触发的示例docs/rules
每个阈值,以及它在每种模型和平台上捕获的内容docs/cutoffs.md
更改内容CHANGELOG.md
工具页面及其余同系列工具letools.dev/tools/decisionlint

开发

bun install
bun run typecheck && bun run lint && bun run test
bun run build
bun run test:integration   # real VS Code against samples/
bun run package            # release/decisionlint-<version>.vsix
bun run test:e2e-vsix      # the packaged VSIX in a clean profile

AGENTS.md 是工程标准。SPEC.md 说明了产品是什么,以及计划中的内容。samples/ 是一个放有预设错误的工作区,供 bun run test:integration 使用;该命令会驱动一个真实的 VS Code。

更多 LE 系列工具

面向每个模型日常工作的 16 款单一用途工具。每款都提供 Rust CLI 和 MCP 服务。详情请访问:letools.dev

提取

  • String-LE — 提取代码库中的所有字符串,方便人们阅读
  • Numbers-LE — 提取代码库中的所有硬编码数字,方便人们检查
  • Units-LE — 提取所有带单位的量并进行规范化,遇到含义不明确的量时按名称拒绝处理
  • Dates-LE — 提取所有日期和时间戳,并给出每个值解析出的确切时刻
  • IDs-LE — 提取所有 UUID、ULID、NanoID、ObjectId 和 Snowflake,并解码其中的时间信息
  • IPs-LE — 提取所有 IP 地址、CIDR 网段和 MAC 地址,进行规范化并按作用域分类
  • URLs-LE — 提取代码库中的所有 URL,并给出其协议和确切位置
  • Paths-LE — 提取代码库中的所有文件路径,并指出它们是否仍然指向有效目标
  • Colors-LE — 提取代码库中的所有颜色,并指出哪些颜色不在你的调色板中

检查

  • Regex-LE — 查找代码库中的所有正则表达式,并报告哪些可能导致灾难性回溯
  • Versions-LE — 查找仓库各清单文件中对同一依赖的约束不一致之处
  • i18n-LE — 识别项目使用的 i18n 库,再依据该库的规则审计其语言目录
  • Scrape-LE — 在编写抓取器之前检查页面是否可抓取,并说明何时无法判断

防护

  • Secrets-LE — 查找代码库中的硬编码凭据,并且绝不在报告中打印凭据
  • EnvSync-LE — 比较目录树中的 dotenv 文件,并指出哪些文件缺少哪些键
  • Unicode-LE — 查找隐藏含义的 Unicode 字符——双向控制符、不可见字符、同形异义字符、混合文字脚本

每款工具都独立运行:没有共享 crate,也没有发布的核心库。若其中两款工具给出相同结论,那是因为同一个答案恰好都正确。

联系 — nolindnaidoo.com · GitHub · LinkedIn

nolindnaidoo 的其他项目

Rust — pixelcoords 和 pixelactions 构成一个循环:pixelcoords 负责回答在哪里,pixelactions 则在该位置执行操作。它们各有自己的工具和风格,并不属于 LE 系列。

许可证

MIT © nolindnaidoo

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。