mcpField
D
deslop

deslop

github.com/overextended开发209 次安装2 周前更新
代码仓库

关于 deslop

deslop 是用于清理分支中 AI 生成代码的编码技能,要求保持行为不变。它仅处理差异引入的代码,并保留针对不可信输入的安全检查。

主要功能

  1. 01清理变更代码而不重构
  2. 02对比分支与默认分支
  3. 03纳入未提交的变更
  4. 04保留安全与权限检查
  5. 05遵循文件现有风格

适用场景

  1. 01清除分支中的调试日志和未使用导入
  2. 02简化新改代码中的嵌套守卫
  3. 03整理变更引入的紧凑代码行

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/overextended/skills --skill deslop

安装后在 Claude Code 中输入/deslop确认已加载。

附带文件agents/openai.yamlCREDITS.md

详细介绍

移除 AI 生成的冗余代码

找出此分支中更改的代码,并移除其中引入的 AI 生成冗余内容。保持行为不变:这是一次清理,不是重构。

范围

  • Git 仓库:与默认分支的合并基点比较(git merge-base HEAD origin/HEAD,否则使用 main 或 master),并包含未提交的更改。
  • 没有 git(服务器文件夹中很常见):使用本次会话中更改的文件。如果没有更改,请询问要清理哪个资源或哪些文件。

仅修改差异中引入的行。周围的代码体现了项目风格,但不是清理目标。

重点检查

根据文件及其所属资源的其他内容来判断候选项:在某个资源中属于冗余内容的代码,在另一个资源中可能是项目惯例。

所有代码

  • 叙述代码的注释(-- 遍历玩家)、重复函数名含义的注释,或与文件注释风格不符的注释。
  • 遗留调试代码:多余的 print 或 console.log、已注释掉的代码。
  • 可通过提前 return 简化的深层嵌套。
  • 代码过于紧凑。参见排版。
  • 分支新增但未使用的局部变量、导入或参数。
  • 与文件风格不一致的命名(在 snake_case 文件中使用 camelCase,反之亦然)。

Lua

  • 对可信路径中不可能为 nil 的值进行 pcall 包装或 nil 检查:例如,资源清单声明为依赖项的资源导出,或同一函数刚刚设置的值。
  • 与 true 或 false 比较(if isOpen == true then),但文件中没有这样的写法。
  • 文件声明使用 local 时却新增全局变量。将变量改为局部变量前,先搜索整个资源中的其他用法:资源中的每个 Lua 文件在同一侧共享一个全局作用域,因此其他文件可能会读取它。
  • 同一文件中混用 Citizen.CreateThread / Citizen.Wait 和 CreateThread / Wait。它们是相同的函数:遵循文件中已有的写法。
  • 资源依赖 ox_lib 时,手写了资源已能从 ox_lib 获取的辅助函数:例如,在使用 lib.table.contains 的代码旁写了 contains 循环;或在资源其他位置使用 lib.requestModel 时,写了 RequestModel / HasModelLoaded 等待循环。仅当 ox_lib 函数的行为相同时才替换;先阅读其源码,确认超时、返回值和错误处理方面的差异。

TypeScript / JavaScript

  • 仅用于压制类型错误的 any 强制类型转换、as unknown as,以及 @ts-ignore / @ts-expect-error。
  • 对可信调用使用 try / catch,但只记录日志后继续执行。

排版

Agent 会把代码挤在一起:一行写多个语句;多个守卫之间不留空行;把条件拆成多行以便塞进同一个 if。判断排版时,应参照默认分支中的文件或分支未修改的文件,而不要参照分支自身的代码:如果分支编写了文件的大部分内容,那么其中的排版本身就是冗余代码的一部分。

  • 每行一条语句。
  • 不同步骤之间留空行:守卫、查找、处理、返回。
  • 仅当守卫很短且其主体只是一个 return 或 return false 时,才将守卫写在一行。
  • 守卫返回表格或执行更多操作时,应拆分为多行。
  • 条件过长而无法写在一行时,应拆成多个守卫,不能将一个 if 拆成多行。
  • 调用或表构造超过约 120 个字符时,每个参数或字段单独占一行。较短的则保留在一行。

之前:

if type(data) ~= 'table' or type(data.slot) ~= 'number' or type(data.count) ~= 'number'
    or data.count < 1 then return false end
local player = GetPlayer(source)
if not player or not player.shop then return false end
local item = player.shop.items[data.slot]
if not item then return false end
if item.license and not HasLicense(player, item.license) then return false, { type = 'error', description = 'missing_license' } end

之后:

if type(data) ~= 'table' then return false end

if type(data.slot) ~= 'number' or type(data.count) ~= 'number' or data.count < 1 then
    return false
end

local player = GetPlayer(source)

if not player or not player.shop then return false end

local item = player.shop.items[data.slot]

if not item then return false end

if item.license and not HasLicense(player, item.license) then
    return false, { type = 'error', description = 'missing_license' }
end

绝不删除

接收客户端任何内容的服务端代码都不是可信路径。请保留以下所有检查:

  • 服务端网络事件处理器(RegisterNetEvent、针对网络事件的 AddEventHandler)的参数检查,以及服务端 lib.callback.register 回调的参数检查;
  • 基于 source 的查找:玩家是否存在、是否拥有物品、是否靠近目标、是否拥有相应职业或组别;
  • 频率限制、距离检查和权限检查(IsPlayerAceAllowed、框架的职业或组别检查)。

通用清理会把这些检查当作多余的防御性代码,而它们正是防止漏洞利用的关键。如果某项检查确实看起来多余,也请保留,并在摘要中说明。可以将检查拆分为独立的 guard 或单独一行:每项检查都必须保留。

此外,还要保留对数据库数据和 NUI 回调(RegisterNUICallback)数据的检查,以及对可选资源的保护检查(GetResourceState(name) == 'started')。

护栏

  • 除非是修复明确的 bug,否则保持行为不变,并在摘要中注明任何 bug 修复。
  • 优先进行最小范围的针对性修改,避免大规模重写。布局是例外:修复此分支新增的所有挤在一行的代码,而不是只修复示例。不要重新格式化未修改的代码。
  • 最终摘要保持简洁(1-3 句话)。

评论

支持 Markdown