mcpField
D
DecisionLint: Jev/Luna Lint

DecisionLint: Jev/Luna Lint

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

关于 DecisionLint: Jev/Luna Lint

DecisionLint 检查源文件和代码中的 Jev 与 Luna 决策模型问题,静态规则无需 API 调用或密钥。开发者和 Agent 可通过编辑器、命令行、CI 与 MCP 使用它。

主要功能

  1. 01检查 JSON 和六种编程语言
  2. 02编辑器诊断与机械式修复
  3. 03命令行和 CI 多格式报告
  4. 04可选模型审查与布局探测
  5. 05Jev 和 Luna 请求形状共用规则

适用场景

  1. 01编辑时发现问题措辞缺陷
  2. 02在 CI 中检查决策请求
  3. 03让 Agent 检查并安全修复请求文本
  4. 04测试问题答案是否随布局变化

MCP 相关

MCP 服务提供八种工具,可检查和修复文本或文件、列出并解释规则,也可选择模型审查和问题探测。可选模型调用使用服务器环境或本地环境文件中的密钥。

配置

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

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

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

安装包
npmdecisionlint-mcp1.1.0

工具

8

收录的工具列表 · 更新于 4 天前

参数类型必填说明
textstring是请求 JSON 或源代码。
rulesobject否要覆盖的规则级别,例如 { "DEC004": "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 保证的是答案的类型,而不是答案本身。格式不当的问题仍可能得到一个看似笃定的数字。这些规则可以发现那些能从文本中识别出的错误。

代码名称默认级别含义
DEC000unreadablehint问题的部分内容在运行时构建,因此需要这些内容的规则未能运行
DEC001unpinned-modelwarningjev-latest 之类的别名会随每次发布而变动,因此即使你这边没有任何变化,答案也可能改变
DEC002choice-option-limiterror一个 Choice 有超过 255 个选项。API 会拒绝它
DEC003score-level-limiterror一个 Score 有超过 10 个级别。API 会拒绝它
DEC004no-fallback-optioninfo一个 Choice 没有 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 对两个时间排序或测量它们之间的间隔
DEC104compoundoff一个 Noul 用“and”连接了两个判断
DEC105generationwarning问题要求生成一个值或撰写文本
DEC107negated-nouloff一个没有 criteria 的 Noul,其措辞使“是”表示某物不存在
DEC108inverted-criteriaoff某个 Noul 的“true”条件描述的是否定情况
DEC110degree-levelswarningScore 级别是程度词、裸标签,或同一个词的高低变化。没有任何内容可供 Jev 用来匹配状态
DEC111numeric-encodingoff问题通过十六进制或 RGB 编码指代某个值
DEC112undefined-boundaryinfo一个没有 criteria 的 Noul 以“大”“经常”或“足够”等词作为判断条件
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 文档。

检查范围

  • TypeSafe 或 OpenAI 格式的 JSON 和 JSONC 请求正文。
  • 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-16 通过实时 API 在 Luna 上运行。Jev 的阈值能捕获 Luna 上的大多数缺陷,但会漏掉更多缺陷,因此 Luna 保留了这些阈值;所有通过询问 Luna 得出的发现都会说明其阈值是在 Jev 上设定的。措辞规则对 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,用于设定截断值。
  • 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,以及 Vercel AI Gateway,openai/gpt-6-luna-decisions,其回答方式与 OpenAI 相同。
  • Liquid AI,d1。

Luna 和 d1 沿用 Jev 的截断值。它们都能发现大多数缺陷,但发现的缺陷比 Jev 少;它们给出的每条检查结果都会注明截断值的设定位置。docs/cutoffs.md 列出了各个截断值、每个模型捕获的已知缺陷数量和误报的正确问题数量,以及各平台的回答与同一模型在其他平台上的回答相差多远。该文档根据已保存的运行结果编写,因此其中的数字就是这些运行结果本身的统计数据。样本数量较少,应将其视为粗略证据。LiteLLM、Eden AI 和 llama.cpp 尚未运行测试。

询问模型关于某个文件的问题

规则 DEC301 到 DEC312 不属于 linting。只有运行 Ask 命令之一,或在命令行中传入 --ask 时,它们才会运行。每条规则都会将文件中的所有问题发送给决策模型,并询问它一些文本模式无法发现的问题:选项之间存在重叠、选项名称与其描述相矛盾、评判标准针对了错误的对象、某个 Choice 应该是 Score、两个问题询问的是同一件事,或某个问题需要另一个问题的答案。

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

命令发送至默认模型密钥
Ask Jev About This FileTypeSafejev-1.13.0Set TypeSafe API Key,或 TYPESAFE_API_KEY
Ask Luna About This FileOpenAIgpt-6-lunaSet OpenAI API Key,或 OPENAI_API_KEY
Ask via OpenRouter About This FileOpenRoutertypesafe/jev-1.13Set OpenRouter API Key,或 OPENROUTER_API_KEY
Ask via Vercel AI Gateway About This FileVercel AI Gatewaytypesafe-ai/jevSet Vercel AI Gateway API Key,或 AI_GATEWAY_API_KEY
Ask via LLM Gateway About This FileLLM Gatewayjev-1.13.0Set LLM Gateway API Key,或 LLM_GATEWAY_API_KEY
Ask Liquid d1 About This FileLiquid AId1Set Liquid AI API Key,或 LIQUID_API_KEY
Ask the Model at My Endpoint About This Filedecisionlint.ask.endpointdecisionlint.ask.endpointModelSet Endpoint API Key,或无
  1. 通过以下三种方式之一提供平台的密钥。运行该平台的 Set ... API Key 命令并粘贴密钥,密钥会保存在操作系统的密钥链中。或者,在 Settings 中的 decisionlint.ask.keys 下,按平台 ID 输入密钥;该设置只能在用户设置中配置,并且不会纳入 Settings Sync。还可以将密钥放入该平台所命名的环境变量中,并设置在 VS Code 运行的环境里。
  2. 打开包含问题的文件,并运行该平台的 Ask 命令。

每条命令发送的模型由 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 密钥,命令会发送该密钥;否则会发送 TYPESAFE_API_KEY 或 OPENAI_API_KEY 中由该形态对应的 SDK 读取的密钥;如果两者都没有,则不发送密钥,这也是连接本地 llama.cpp 的方式。此端点只能在用户设置中配置,因此代码库无法将你的密钥指向它自行选择的主机。

运行前须知:

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

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

探测问题

将光标放在某个问题中,然后运行 DecisionLint: Probe the Jev Question at the Cursor。它会针对旁边写出的状态发送该问题:先按原样发送三次,然后更改布局后再发送,具体包括反转选项顺序、隐藏选项名称、反转等级顺序以及移除标准。随后会打开报告,显示答案是否发生变化。

如果只改变选项顺序,答案就发生变化,那么这个问题就无法据此作出判断。如果三次相同的请求结果不一致,则输入内容难以判断。

此功能需要文件中写出状态,会发送该状态,并且会消耗五到六个请求。

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

项目设置

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

{
  "rules": { "DEC004": "error", "DEC112": "off" },
  "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 上没有触发错误,因此处于关闭状态。可在 decisionlint.rules 中启用其中任何一条。另外还有 2 条规则因每次触发时都判断错误,已在 0.4.0 中移除。
  • 关于非英文问题的任何信息。
  • 单独一个对象缺少的内容。 questions 映射之外的 { type, instructions } 可能是模板,也可能是构建器的一部分,因此只有在请求中才会报告缺少 criteria。

DEC004 仅提供信息,因为其建议是有条件的:当选项可能无法涵盖所有输入时,添加一个回退选项。它会在 TypeSafe 自身文档的 11 个 Choice 示例中触发 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 键写成了 yes,而 API 要求 true;问题类型拼写错误;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。

未安装时,扩展会使用自身的副本,无需任何设置。

当项目副本无法使用时,扩展也会使用自身的副本;状态栏会显示 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.0.1
  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 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。