code-cleanup

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Code Cleanup

代码清理

Post-implementation cleanup of code that is already correct. Prunes the comment noise an AI tends to add, applies the project's conventions, and simplifies what is needlessly complicated.
Correctness is not this skill's job. It does not hunt for bugs, and it must not "fix" behavior it thinks is wrong — that is
/changes-review
. Everything here preserves behavior.
对已正确实现的代码进行事后清理。精简AI通常会添加的冗余注释,应用项目规范,并简化不必要的复杂实现。
正确性并非本技能的职责。它不会寻找Bug,也绝不能“修复”它认为错误的行为——那是
/changes-review
的工作。本技能的所有操作都将保留代码原有行为。

Core Principle

核心原则

A comment stays only if the code cannot carry it and no other artifact can either. The default for every comment in scope is delete. One survives by earning its line, not by being defensible.
Ask where the sentence belongs before asking whether it is true. A comment competes with the code itself and with three other artifacts, and it loses to all four:
What the sentence saysWhere it belongs
What the code doesThe code. Delete the comment.
Why it is built this way — the decision, the alternative rejected, the historyThe commit message
What changed and what a reviewer should look atThe PR body
Work still owed, or context that outlives this changeAn issue
What a reader of this file would get wrong without itHere. Keep it, at one or two lines.
Only the last row survives contact with the source. The rows above it are usually real content filed in the wrong place — surface the text in the report under the destination it belongs to, then take it out of the code.
Two further removals are not about placement:
  • A missing name. A comment that exists because a symbol is vaguely named is a rename, not a comment.
  • A fact already stated nearby. Once one comment carries a mechanism, a second comment on another part of that mechanism is duplication — see Phase 2.5.
Be aggressive, and know what aggression means here. It means deleting what does not earn its place. It does not mean shortening to save space: a surviving comment must still read well and still be correct, and a compaction that drops a fact or leaves a half-sentence is a worse outcome than the verbose original it replaced.
只有当代码无法承载信息且其他文档也无法替代时,注释才可以保留。所有范围内的注释默认都要被删除。注释只有证明自己存在的价值才能留存,而非仅仅合理即可。
先判断语句应归属的位置,再判断其是否正确。注释会与代码本身及另外三类文档竞争,且在这四类场景中都会落败:
语句描述的内容应存放的位置
代码的功能代码本身。删除该注释。
为何采用这种实现方式——决策过程、被否决的方案、历史背景commit message
变更内容及评审重点PR正文
待完成工作或超出本次变更范围的上下文Issue
阅读当前文件的用户若没有该注释会产生误解的信息此处。保留1-2行注释。
只有最后一行的内容可以留在源代码中。上方几行的内容通常是放错位置的有效信息——在报告中指明其应归属的位置,然后从代码中移除。
还有两类移除操作与位置无关:
  • 命名缺失。因符号命名模糊而存在的注释应通过重命名符号来解决,而非保留注释。
  • 重复信息。若已有一处注释解释了某个机制,另一处针对同一机制不同部分的注释属于重复内容——详见阶段2.5。
要主动精简,但需明确此处“主动”的含义。它指的是删除那些没有存在价值的内容,而非单纯为了节省空间而缩短内容:留存的注释仍需易于阅读且准确,若精简后遗漏了信息或语句不完整,效果反而比冗长的原文更差。

Read Intent First

优先识别意图

  • A request about comments ("clean up the comments") → comment work is the whole job. Code changes are allowed only where a cheap rename removes the need for a comment.
  • A general "clean this up" → run the full pass: comments, artifacts, conventions, simplify.
  • --comments-only
    forces the comment-focused mode regardless of phrasing, and never touches code. It disables, without exception: convention loading and fixes, the simplifier pass, rename-to-kill, and quick wins. Comments and docs only. It may still report what it would otherwise have done.
  • --no-simplify
    runs everything except the simplifier pass.
  • 针对注释的请求(如“清理注释”)→ 仅处理注释。仅当简单重命名符号即可消除注释需求时,才允许修改代码。
  • 一般性的“清理代码”请求→ 执行完整流程:注释处理、文档归档、规范应用、代码简化。
  • --comments-only
    参数强制开启仅聚焦注释的模式,绝不修改代码。它会无条件禁用:规范加载与修复、代码简化流程、重命名消除注释操作,以及快速修复。仅处理注释和文档。它仍会报告原本会执行的操作。
  • --no-simplify
    参数会执行除代码简化之外的所有操作。

Asking the User

询问用户

Every question in this skill is written as
AskUserQuestion
options. Use that tool where the host offers it, or the host's nearest structured-choice equivalent. Where the host has neither, ask the same question in normal chat as a numbered list of 2–5 options — recommended first, one short line of description each — and wait for the user to reply with a number.
本技能中的所有问题均以
AskUserQuestion
选项形式呈现。若宿主提供该工具则使用它,或使用宿主最接近的结构化选择替代方案。若宿主两者都不支持,则以普通聊天形式提出相同问题,列出2-5个带编号的选项——推荐优先选项,每个选项配一行简短描述——等待用户回复编号。

Workflow

工作流程

Phase 1: Scope

阶段1:范围确定

Step 1: Find project guidelines. Check for comment/doc conventions in:
CLAUDE.md   AGENTS.md   .cursor/rules/*.md(c)   docs/CONTRIBUTING.md   docs/STYLE_GUIDE.md   .github/CONTRIBUTING.md
Honor anything they say about comment style, JSDoc requirements, or section markers.
Step 2: Resolve the target. In priority order:
  1. Explicit argument — files, a directory, or a commit ref passed in → use exactly that.
  2. Uncommitted changes (default) — staged + unstaged:
    bash
    git diff --name-only HEAD                    # tracked modifications (staged + unstaged)
    git ls-files --others --exclude-standard     # new untracked files
  3. Last commit — fall back here only when the working tree is clean:
    bash
    git diff --name-only HEAD~1..HEAD
Announce which scope resolved (e.g. "Cleaning uncommitted changes: 4 files" or "Tree clean — cleaning last commit
0cccf9d
: 3 files").
Filter to code files (exclude
*.md
,
*.json
,
*.lock
,
*.yaml
,
*.yml
,
dist/
,
build/
,
*.min.js
,
*.map
).
Step 3: Decide which comments are in scope. For diff/commit modes, pull the actual hunks (
git diff HEAD
/
git show
) and consider:
  • every comment added or modified by the change, plus
  • pre-existing comments in changed files that relate to the changed code (e.g. a doc comment on a function whose body you just edited).
Leave unrelated pre-existing comments elsewhere in the file alone — surgical. For an explicitly named file, the whole file is in scope.
Step 4: Load the conventions that apply. Skip entirely under
--comments-only
.
Always load
references/conventions.md
.
It is the repo-adaptive half of the pass: read what the project itself documents, detect the stack, and audit against both. It is what makes this work on a repo the stack files below do not describe.
The eight stack files carry fixed conventions for one specific frontend stack. Each is gated on two conditions, and both must hold:
ReferencePathsOnly when
references/react.md
*.tsx
react
in deps and React 19+
references/typescript.md
*.ts
,
*.tsx
typescript
in deps, or
tsconfig.json
exists
references/tailwind.md
*.tsx
tailwindcss
or
@tailwindcss/*
in deps
references/radix.md
*.tsx
radix-ui
or
@radix-ui/*
in deps
references/storybook.md
*.stories.tsx
,
.storybook/**
@storybook/*
in deps, or
.storybook/
exists
references/frontend-structure.md
src/**
(JS/TS only — never
src/main/kotlin/**
)
react
or
preact
in deps
references/kotlin.md
*.kt
.kt
files present, or a
kotlin(...)
plugin in
build.gradle.kts
The dependency gate is not optional. A path glob alone would load
tailwind.md
for any
.tsx
file and rewrite
h-4 w-4
to
size-4
in a project with no Tailwind, or convert a variant lookup to
cva
without the package installed. Check
package.json
before loading a stack file; if the dependency is absent, the file does not apply and its rules are not violations.
react.md
additionally requires React 19 —
forwardRef
is correct on 18 and its ref-as-prop rule would break the build.
The project's own instructions outrank all of this. If
CLAUDE.md
,
AGENTS.md
, or a rules file found in Step 1 contradicts a reference, follow the project. These are defaults for repos that have not said otherwise — not a house style to write into someone else's codebase.
步骤1:查找项目规范。在以下位置检查注释/文档规范:
CLAUDE.md   AGENTS.md   .cursor/rules/*.md(c)   docs/CONTRIBUTING.md   docs/STYLE_GUIDE.md   .github/CONTRIBUTING.md
严格遵循其中关于注释风格、JSDoc要求或章节标记的规定。
步骤2:确定目标范围。按优先级排序:
  1. 显式参数——传入的文件、目录或提交引用→ 严格使用该范围。
  2. 未提交变更(默认)——暂存+未暂存:
    bash
    git diff --name-only HEAD                    # 已跟踪文件的修改(暂存+未暂存)
    git ls-files --others --exclude-standard     # 新增的未跟踪文件
  3. 最后一次提交——仅当工作区干净时才回退到此处:
    bash
    git diff --name-only HEAD~1..HEAD
告知用户确定的范围(例如:“清理未提交变更:4个文件”或“工作区干净——清理最后一次提交
0cccf9d
:3个文件”)。
筛选出代码文件(排除
*.md
、
*.json
、
*.lock
、
*.yaml
、
*.yml
、
dist/
、
build/
、
*.min.js
、
*.map
)。
步骤3:确定范围内的注释。对于差异/提交模式,提取实际代码块(
git diff HEAD
/
git show
)并考虑:
  • 本次变更新增或修改的所有注释,以及
  • 变更文件中与修改代码相关的原有注释(例如:刚编辑过的函数的文档注释)。
忽略文件中其他无关的原有注释——精准操作。对于显式指定的文件,整个文件都在范围内。
步骤4:加载适用的规范。在
--comments-only
模式下完全跳过此步骤。
始终加载
references/conventions.md
。它是适配仓库的核心部分:读取项目自身的文档,检测技术栈,并对照两者进行检查。这是本技能能在未被技术栈文件描述的仓库中正常工作的关键。
八个技术栈文件针对特定前端栈提供固定规范。每个文件的加载需满足两个条件,且必须同时成立:
参考文件路径仅当满足以下条件时加载
references/react.md
*.tsx
依赖中包含
react
且 React版本为19+
references/typescript.md
*.ts
,
*.tsx
依赖中包含
typescript
,或存在
tsconfig.json
references/tailwind.md
*.tsx
依赖中包含
tailwindcss
或
@tailwindcss/*
references/radix.md
*.tsx
依赖中包含
radix-ui
或
@radix-ui/*
references/storybook.md
*.stories.tsx
,
.storybook/**
依赖中包含
@storybook/*
,或存在
.storybook/
目录
references/frontend-structure.md
src/**
(仅JS/TS文件——绝不包含
src/main/kotlin/**
)
依赖中包含
react
或
preact
references/kotlin.md
*.kt
存在
.kt
文件,或
build.gradle.kts
中包含
kotlin(...)
插件
依赖检查不可省略。仅通过路径通配符会导致在没有Tailwind的项目中加载
tailwind.md
,并将
h-4 w-4
重写为
size-4
,或在未安装包的情况下将变量查找转换为
cva
。加载技术栈文件前先检查
package.json
;若依赖不存在,则该文件不适用,其规则也不视为违规。
react.md
额外要求React 19版本——
forwardRef
在React 18中是正确的,而其“ref作为属性”的规则会导致构建失败。
项目自身的说明优先级最高。若步骤1中找到的
CLAUDE.md
、
AGENTS.md
或规则文件与参考文件冲突,遵循项目自身的规定。这些参考文件是未明确说明的仓库的默认规范——并非要写入他人代码库的固定风格。

Phase 2: Classify Each Comment

阶段2:分类每个注释

Run every in-scope comment through this table. The first five classes are the AI-noise the skill exists to remove; a comment that matches none of them still has to earn its line under the Core Principle before it stays.
ClassWhat it looks likeAction
Restates the codeOne-liner narration (
// increment counter
) or a multi-line block describing how the mechanism works, step by step, that a reader gets from the code itself
Remove
Design rationale / history"We do it this way because…", "Captured here because by the time X runs…", "chose this over Y", the story of the decision aimed at a PR readerRemove from code; surface the text for the commit message
Wider contextDescribes the change rather than the file: what a reviewer should check, what the surrounding refactor is for, what is deliberately out of scopeRemove from code; surface it for the PR body
DuplicateRestates a mechanism a nearby comment already carries, from a second angleRemove — keep the one authoritative statement (Phase 2.5)
External-context reference
// see #123
,
// added for PR #45
,
// per the linked issue
,
// fixes JIRA-88
,
// see STAGE3.md
Strip the reference. If the fact matters, state it inline so the file reads on its own; if it does not, delete the comment. Keep a link only where the context is genuinely unreachable otherwise — an upstream bug tracker for a workaround, a spec section, an RFC
Non-obvious behavior / gotcha / hackTiming dependency, surprising side effect, workaround for an external bug, a constraint you cannot infer from the codeKeep — compact to 1–2 lines, drop the narration
Comment compensating for a bad nameThe comment exists mainly to explain what a vague symbol meansRename the symbol (see Phase 3); delete the comment. Under
--comments-only
, leave both and report the rename as a suggestion
Documentation (JSDoc / docstring / public API)API-level doc humans rely onGentle, not exempt: correct inaccuracies and tighten — cut prose that re-spells the signature or the parameter names. Never gut what a caller cannot get from the type: what it does, what it throws, what it returns
AI implementation artifacts
// TODO: implement
on done code,
// Claude:
/
// AI:
,
// Add your code here
, leftover
console.log('DEBUG…')
, commented-out alternatives with AI reasoning
Remove
Misleading / staleDescribes behavior the code no longer has, wrong names, outdated referencesFix if obvious, else flag
Markers
HACK
FIXME
XXX
BUG
TODO
@ts-expect-error
eslint-disable
// region
, license headers
Preserve (flag
FIXME
/
HACK
/
TODO
for review, don't delete)
The test for the top two classes: read the code without the comment. If you still understand what it does, the comment was restating — remove it. If what you lose is why a decision was made rather than what the code does, that belongs in the commit message, not the source.
Prefix markers —
// !
warning,
// ?
open question,
// *
divider — belong to the human, never to you.
Never author one; the user places them by hand. What to do with one that already exists turns on whose line it is:
  • In pre-existing code — preserve the prefix. The comment text is still judged like any other, but the marker is not yours to remove.
  • On a line this change added — drop the prefix and judge the bare comment on its merits. Exception: keep and match it where the project genuinely uses the convention —
    CLAUDE.md
    ,
    AGENTS.md
    , or a rules file documents it, or the surrounding untouched code is visibly written that way.
A
// TODO:
left on work this change just finished is an AI implementation artifact, and goes. One the project or the user placed is a marker, and stays.
Test files: a step-label comment that just narrates the next call (
// focus the field
) is restatement — remove it. Keep one only where it conveys intent the calls don't (e.g. "most recent, not stale"). The test name and assertions should carry the rest.
将所有范围内的注释对照下表进行分类。前五类是本技能要清除的AI冗余内容;若注释不属于其中任何一类,仍需符合核心原则才能留存。
类别特征操作
重复代码含义单行叙述(如
// 递增计数器
)或逐步骤描述机制的多行块,而读者可直接从代码中理解这些内容
移除
设计依据/历史背景“我们这样做是因为……”、“在此处捕获是因为当X运行时……”、“选择此方案而非Y”、面向PR读者的决策过程描述从代码中移除;将内容提取到commit message中
更广泛的上下文描述变更而非文件本身:评审重点、周边重构的目的、故意排除在范围外的内容从代码中移除;将内容提取到PR正文中
重复内容从另一个角度重复描述已有注释解释的机制移除——保留唯一权威说明(阶段2.5)
外部上下文引用
// 参见#123
、
// 为PR #45添加
、
// 根据链接的Issue
、
// 修复JIRA-88
、
// 参见STAGE3.md
移除引用。若信息重要,则内联说明以确保文件可独立阅读;若不重要,则删除注释。仅当上下文确实无法通过其他方式获取时才保留链接——例如上游Bug跟踪器的 workaround、规范章节、RFC
非直观行为/陷阱/临时方案时序依赖、意外副作用、针对外部Bug的 workaround、无法从代码中推断的约束保留——精简为1-2行,删除冗余叙述
因命名不佳而存在的注释注释主要用于解释模糊符号的含义重命名符号(见阶段3);删除注释。在
--comments-only
模式下,保留两者并将重命名作为建议报告
文档(JSDoc / 文档字符串 / 公共API)开发者依赖的API级文档温和精简,而非豁免:修正不准确内容并精简——删除重复签名或参数名称的文字。绝不要删除调用者无法从类型中获取的内容:功能、抛出异常、返回值
AI实现残留内容已完成代码上的
// TODO: implement
、
// Claude:
/
// AI:
、
// Add your code here
、遗留的
console.log('DEBUG…')
、带AI推理的注释掉的替代方案
移除
误导性/过时内容描述的行为与当前代码不符、名称错误、过时引用若明显则修正,否则标记
标记
HACK
FIXME
XXX
BUG
TODO
@ts-expect-error
eslint-disable
// region
、许可证头部
保留(标记
FIXME
/
HACK
/
TODO
以供评审,不删除)
前两类的判断标准:不看注释直接阅读代码。若仍能理解代码功能,则该注释属于重复内容——移除。若缺失的是决策原因而非代码功能,则应放在commit message中,而非源代码中。
前缀标记——
// !
警告、
// ?
待解决问题、
// *
分隔符——属于用户,而非本技能
。绝不要添加此类标记;由用户手动添加。对于已存在的标记,处理方式取决于其归属:
  • 在原有代码中——保留前缀。注释内容仍需像其他注释一样判断,但标记不可移除。
  • 在本次变更添加的行上——移除前缀,仅判断注释本身的价值。例外:若项目确实使用该规范——
    CLAUDE.md
    、
    AGENTS.md
    或规则文件中有说明,或周边未修改的代码明显采用该风格——则保留并匹配前缀。
已完成工作上遗留的
// TODO:
属于AI实现残留内容,应移除。项目或用户添加的
// TODO:
属于标记,应保留。
测试文件:仅叙述下一个调用的步骤标签注释(如
// 聚焦输入框
)属于重复内容——移除。仅当注释传达了调用无法体现的意图时才保留(例如“最新的,而非过时的”)。测试名称和断言应承载其余信息。

Phase 2.5: Read the survivors together

阶段2.5:整体审阅留存的注释

Phase 2 judges one comment at a time, which is exactly how three individually defensible comments end up telling one story between them. Before applying anything, read the surviving set as a whole.
  • One mechanism, one home. Where two or three comments each explain a part of the same mechanism, keep the explanation once — on the thing all of them exist to serve, usually the field or the declaration rather than any of the functions touching it — and delete the others. The remaining one may grow a line to absorb what was real in them.
  • Contradiction. The same rule stated in opposite directions in two places means at least one is stale. Resolve it against the code; never keep both.
  • Density is a signal, not a quota. Count added comment lines against added code lines. Past roughly a fifth, look again — not to hit a number, but because in practice that ratio has meant duplication rather than thoroughness. Report both counts either way.
This phase exists because wording-level trimming cannot reach the problem it solves. A pass that shortens three comments and leaves all three still leaves the reader three places to look and three places to update, and it is the failure this skill is most often called back to fix.
阶段2逐个判断注释,这正是三个单独合理的注释最终共同讲述一个故事的原因。在应用任何修改前,整体阅读留存的注释集合。
  • 一个机制,一个归属地。若两三个注释分别解释同一机制的不同部分,则仅保留一次解释——放在所有注释服务的对象上,通常是字段或声明,而非任何调用它的函数——并删除其他注释。留存的注释可增加一行以吸收其他注释中的有效内容。
  • 矛盾内容。同一规则在两处表述相反,意味着至少一处已过时。根据代码内容解决矛盾;绝不要同时保留两者。
  • 密度是信号,而非配额。统计添加的注释行数与添加的代码行数之比。超过约五分之一时,需重新审视——并非为了达到某个数值,而是实际上该比例通常意味着重复内容而非全面性。无论如何都要报告这两个计数。
此阶段的存在是因为逐字精简无法解决其针对的问题。若精简三个注释但仍保留全部三个,读者仍需查看三处并更新三处,这正是本技能常被召回修复的问题。

Phase 3: Apply

阶段3:应用修改

Auto-apply. Edit directly — uncommitted changes are the review surface, and
git diff
shows exactly what changed. With
--dry-run
, produce the Phase 4 report and stop without editing.
Order: remove restatement → pull rationale and wider context out (collect for the report by destination) → strip external references → de-duplicate per Phase 2.5 → compact gotchas → rename-to-kill → docs polish → AI artifacts & dead code → quick wins → conventions → flag the rest. The simplifier runs after all of it, in Phase 3.5.
Convention fixes. Apply only the references that passed both gates in Step 4. Fix what is mechanical, local, and behavior-preserving —
h-4 w-4
that should be
size-4
, an
interface X extends Y
that should be an intersection type, a flat story name missing its group prefix, a
forwardRef
that should be ref-as-prop if the project is on React 19.
Two things are never auto-applied:
  • Anything that ripples past the files in scope — a rename with external callers, a file move to satisfy the structure rules, a dependency swap like
    @radix-ui/react-tabs
    →
    radix-ui
    .
  • Anything a reference marks report-only, and anything that changes behavior. Some rules in
    references/conventions.md
    and
    references/kotlin.md
    are correctness or security checks; they produce findings, never edits.
Skipped entirely under
--comments-only
.
Renaming to kill a comment. Skipped under
--comments-only
— a rename is a code change. When a cheap, local rename makes a comment unnecessary, do it and remove the comment. "Cheap" = a single symbol whose every reference you can update in the in-scope files (a local variable, a private function). Anything heavier — splitting a function into utilities, reshaping control flow, renaming an exported symbol with external callers — is not applied; record it as a suggestion in the report instead.
Quick wins (auto-fix if truly trivial). Skipped under
--comments-only
. An obvious missing return type TS already infers, or an unused import your comment removal orphaned. Leave an
eslint-disable
alone unless you can actually run the linter and confirm the rule passes — guessing that a suppression is stale is how a suppression becomes a build failure.
Safety rules:
  • Never remove
    @ts-ignore
    /
    @ts-expect-error
    without understanding why it's there.
  • Never remove
    eslint-disable
    without running the linter and confirming the rule passes.
    allowed-tools
    grants only
    Bash(git:*)
    , so on most invocations you cannot — leave it and report it.
  • Never delete
    HACK
    /
    FIXME
    /
    XXX
    /
    BUG
    comments — flag them.
  • Never remove license headers or copyright notices.
  • Preserve
    // region
    /
    // endregion
    and any project-specific markers.
自动应用。直接编辑代码——未提交变更是评审依据,
git diff
可准确显示变更内容。使用
--dry-run
参数时,生成阶段4的报告但不进行编辑。
顺序:移除重复内容→ 提取设计依据和更广泛的上下文(按归属地收集到报告中)→ 移除外部引用→ 按阶段2.5去重→ 精简陷阱注释→ 重命名消除注释→ 优化文档→ 移除AI残留内容和死代码→ 快速修复→ 应用规范→ 标记剩余内容。代码简化在阶段3.5中最后执行。
规范修复。仅应用步骤4中通过两个检查的参考文件规则。修复机械性、局部性且保留行为的内容——将应改为
size-4
的
h-4 w-4
修复,将应改为交叉类型的
interface X extends Y
修复,将缺失组前缀的扁平故事名称修复,若项目使用React 19则将
forwardRef
改为ref作为属性。
两类内容绝不自动应用:
  • 影响范围超出当前文件的内容——涉及外部调用者的重命名、为满足结构规则的文件移动、依赖替换(如
    @radix-ui/react-tabs
    →
    radix-ui
    )。
  • 参考文件标记为仅报告的内容,以及任何改变行为的内容。
    references/conventions.md
    和
    references/kotlin.md
    中的部分规则是正确性或安全检查;它们仅生成发现,绝不进行编辑。
在
--comments-only
模式下完全跳过此步骤。
重命名消除注释。在
--comments-only
模式下跳过——重命名属于代码修改。当简单的局部重命名可消除注释需求时,执行重命名并删除注释。“简单”指单个符号,且其所有引用都可在范围内的文件中更新(局部变量、私有函数)。任何更复杂的操作——将函数拆分为工具类、重构控制流、重命名带有外部调用者的导出符号——绝不应用;而是作为建议记录在报告中。
快速修复(若确实 trivial则自动修复)。在
--comments-only
模式下跳过。TS已推断出的明显缺失的返回类型,或因注释删除而孤立的未使用导入。除非能运行linter确认规则通过,否则不要修改
eslint-disable
——猜测抑制规则已过时会导致构建失败。
安全规则:
  • 若不理解
    @ts-ignore
    /
    @ts-expect-error
    存在的原因,绝不要移除它们。
  • 若不运行linter确认规则通过,绝不要移除
    eslint-disable
    。
    allowed-tools
    仅授权
    Bash(git:*)
    ,因此大多数情况下无法运行linter——保留并报告它。
  • 绝不要删除
    HACK
    /
    FIXME
    /
    XXX
    /
    BUG
    注释——标记它们。
  • 绝不要删除许可证头部或版权声明。
  • 保留
    // region
    /
    // endregion
    以及任何项目特定的标记。

Phase 3.5: Simplifier pass

阶段3.5:代码简化流程

Skipped entirely under
--comments-only
,
--no-simplify
, or
--dry-run
. Under
--dry-run
the analysis still runs — the suggestions go in the report and nothing is written.
Simplify code that is more complicated than it needs to be, preserving behavior exactly: collapse a nested conditional into a guard clause, replace a hand-rolled loop with the obvious built-in, drop an indirection with one caller, delete a branch that cannot be reached, unwrap a wrapper that only forwards. Small, local, provable.
Not in scope: anything that changes behavior, anything that needs a test to prove it is safe, and anything the code is doing deliberately for a reason you cannot see. When in doubt, it is a suggestion, not an edit.
Whether to ask first turns on one observable signal: did the invocation carry anything beyond the bare skill name?
  • Any argument, flag, or instruction — apply without asking. A scope, a flag, "simplify the parser", "clean this up and tidy the helpers". The caller already said what they want, and a skill invoking this one always passes at least a scope or a flag.
  • Nothing at all — ask before applying. A bare
    /code-cleanup
    , or a bare "clean up the changes" with no further direction.
That rule is deliberately mechanical, because "did a human or a skill call me" is not something you can read at runtime. A skill calling this one must pass at least one argument — a scope, or
--no-simplify
if it wants the pass off. A caller that passes nothing gets treated as a user who typed the bare command, which means it may block on a prompt.
If the host cannot prompt interactively at all, do not ask — apply nothing, and report the simplifications as suggestions.
Ask per Asking the User:
  1. Apply the simplifications
    (Recommended) — N refactors, all behavior-preserving
  2. Report them only
    — list them under Suggested refactors, change nothing
Declined, or the host cannot prompt → fall back to the existing Suggested refactors (not applied) section. Under
--no-simplify
and
--dry-run
the analysis still runs and populates that section; under
--comments-only
the pass does not run at all and the section carries only the renames and convention fixes it would otherwise have applied.
在
--comments-only
、
--no-simplify
或
--dry-run
模式下完全跳过。在
--dry-run
模式下仍会执行分析——建议会放入报告但不进行修改。
简化过于复杂的代码,严格保留原有行为:将嵌套条件转换为守卫子句,用内置方法替换手动实现的循环,删除仅有一个调用者的间接层,删除无法到达的分支,移除仅转发调用的包装器。操作应小而局部,且可证明安全。
不属于范围的内容:任何改变行为的操作、需要测试证明安全的操作、以及代码故意为你无法看到的原因而执行的操作。若有疑问,作为建议而非编辑。
是否先询问用户取决于一个可观察的信号:调用时是否包含技能名称之外的内容?
  • 任何参数、标记或指令——直接应用无需询问。例如指定范围、标记、“简化解析器”、“清理代码并整理工具类”。调用者已明确需求,且调用本技能的其他技能至少会传递范围或标记。
  • 无任何额外内容——应用前先询问。例如仅输入
    /code-cleanup
    ,或仅输入“清理变更”无进一步说明。
该规则是刻意机械化的,因为无法在运行时判断调用者是人类还是其他技能。调用本技能的其他技能必须至少传递一个参数——范围,或若要关闭简化流程则传递
--no-simplify
。无参数的调用者会被视为输入裸命令的用户,这意味着可能会因提示而阻塞。
若宿主完全无法交互式提示,则不要询问——不应用任何修改,将简化建议放入报告。
按照询问用户的规则提问:
  1. 应用简化修改
    (推荐)——N个重构,均保留原有行为
  2. 仅报告建议
    ——在“建议重构(未应用)”部分列出,不做任何修改
若用户拒绝,或宿主无法提示→ 回退到现有的**建议重构(未应用)**部分。在
--no-simplify
和
--dry-run
模式下仍会执行分析并填充该部分;在
--comments-only
模式下完全不执行该流程,该部分仅包含原本会应用的重命名和规范修复建议。

Phase 4: Report

阶段4:生成报告

undefined
undefined

Cleanup: [N files, M comments touched]

清理结果:[N个文件,M个注释被处理]

Scope: uncommitted changes (4 files) Comment lines: 64 → 28 · added code lines: 201
范围:未提交变更(4个文件) 注释行数:64 → 28 · 新增代码行数:201

Removed

已移除内容

  • [count] restated / how-it-works comments
  • [count] duplicate explanations, folded into the one that stays
  • [count] external references (issue / PR / doc numbers) stripped
  • [count] AI artifacts
  • [count] dead commented code
  • [数量] 重复代码含义/机制说明注释
  • [数量] 重复解释,已合并到留存的注释中
  • [数量] 外部引用(Issue/PR/文档编号)已移除
  • [数量] AI残留内容
  • [数量] 已注释的死代码

Compacted

已精简内容

  • [count] gotcha comments shortened
  • [数量] 陷阱注释已缩短

Renamed (to remove a comment)

重命名(以消除注释)

  • activeDataContext
    →
    focusedDataContext
    (file.ts)
  • activeDataContext
    →
    focusedDataContext
    (file.ts)

Docs

文档优化

  • [count] doc comments corrected / tightened
  • [数量] 文档注释已修正/精简

Conventions applied

已应用的规范

  • Button.tsx:12
    forwardRef → ref-as-prop (react.md)
  • Card.tsx:30
    h-4 w-4
    →
    size-4
    (tailwind.md)
  • Button.tsx:12
    forwardRef → ref作为属性 (react.md)
  • Card.tsx:30
    h-4 w-4
    →
    size-4
    (tailwind.md)

Simplified

已简化的代码

  • parse.ts:44
    nested conditional → guard clause
  • index.ts:8
    removed a wrapper that only forwarded to
    format()
  • parse.ts:44
    嵌套条件 → 守卫子句
  • index.ts:8
    移除仅转发到
    format()
    的包装器

Belongs in the commit message

应放入commit message的内容

The seed is captured at the toggle's pointer-down because the click blurs the field before the open handler runs. Clearing context on close is the plugin's job.
在切换按钮的pointer-down事件时捕获种子,因为点击会在打开处理程序运行前失去输入框焦点。关闭时清除上下文是插件的职责。

Belongs in the PR body

应放入PR正文的内容

  • The change is scoped to the
    Map
    branch of the converter; the surrounding conversion path is deliberately untouched.
  • 变更范围限于转换器的
    Map
    分支;周边转换路径故意未修改。

Belongs in an issue

应放入Issue的内容

  • parse.ts
    still handles the legacy
    v1
    envelope and nothing in this change needs it — worth an issue, not a comment.
  • parse.ts
    仍处理旧版
    v1
    信封,本次变更无需此功能——值得创建一个Issue,而非保留注释。

Quick wins

快速修复

  • util.ts:3
    removed an import orphaned by a comment deletion
  • util.ts:3
    移除因注释删除而孤立的导入

Suggested refactors (not applied)

建议重构(未应用)

Everything analysed but not edited lands here: declined simplifications, renames with callers outside scope, convention fixes that ripple past the files in scope, and file moves the structure rules imply.
  • file.ts:120
    handleDataActivePath does two things — consider splitting focus-tracking from context-push
  • Card.tsx
    structure rules put this in
    components/card/
    — a move, so not applied
所有已分析但未编辑的内容都放在此处:被拒绝的简化、影响范围外调用者的重命名、影响范围外文件的规范修复、结构规则建议的文件移动。
  • file.ts:120
    handleDataActivePath承担两项职责——考虑将焦点跟踪与上下文推送拆分
  • Card.tsx
    结构规则建议将其放在
    components/card/
    ——属于文件移动,未应用

Flagged for review

标记需评审的内容

  • file.ts:456
    FIXME left in place — needs attention
  • file.ts:88
    comment claims X but code does Y

The three **Belongs in** sections carry the text taken out of the source, filed where it should have
gone. They are *inputs* to those artifacts, not blocks to be pasted at the end of one.

**Commit message** is the important one: it answers why the code is built the way it is, which is
the first thing a body has to establish, so the commit writer folds it into that opening paragraph.
Write it as prose that can carry that weight — the reason, not a label for it.

**PR body** and **an issue** are handed to whoever writes them. This skill files nothing itself: it
opens no issue and edits no PR. Omit a section that has nothing in it rather than printing an empty
heading.
  • file.ts:456
    FIXME已保留——需关注
  • file.ts:88
    注释声称X但代码实际执行Y

三个**应放入**部分包含从源代码中提取的内容,并归档到正确位置。它们是这些文档的**输入**,而非要粘贴到末尾的块。

**commit message**是最重要的:它解释了代码为何采用这种实现方式,这是commit message首先要说明的内容,因此提交者应将其融入开头段落。将其写成能承载该重要性的散文——说明原因,而非仅贴标签。

**PR正文**和**Issue**的内容会交给负责编写它们的人。本技能本身不会创建任何内容:不会打开Issue也不会编辑PR。若某部分无内容则省略该标题,而非打印空标题。

Examples

示例

Restated mechanism → remove

重复机制说明 → 移除

The function name already says everything the comment does.
typescript
// Before
// Opens the Content Operator dialog and seeds it with the field captured by
// `captureOperatorSeed` (if any), then clears the pending seed.
export function openOperatorWithSeed(): void { ... }

// After
export function openOperatorWithSeed(): void { ... }
函数名称已包含注释的所有信息。
typescript
// 之前
// 打开内容操作器对话框,并使用`captureOperatorSeed`捕获的输入框(若有)填充种子,然后清除待处理的种子。
export function openOperatorWithSeed(): void { ... }

// 之后
export function openOperatorWithSeed(): void { ... }

Design rationale → commit message

设计依据 → 放入commit message

typescript
// Before
// CS pushes the focused data field to the operator as its mention target — but
// only while the dialog is open. While closed the field is remembered so the
// toolbar can seed the dialog on open. The seed is captured at pointer-down
// because clicking the toggle blurs the field before the open handler runs.
// Clearing context on close is the plugin's responsibility.

// After  (a short orienting note stays; the decision story goes to the commit)
// Focused field is pushed as context only while the dialog is open;
// while closed it is remembered as a seed for the next open.
Report → Belongs in the commit message: "Seed captured at pointer-down because the click blurs the field before the open handler runs; clearing on close is the plugin's job."
typescript
// 之前
// CS将聚焦的数据字段作为提及目标推送给操作器——但仅在对话框打开时有效。关闭时会记住该字段,以便工具栏在打开对话框时填充种子。在pointer-down事件时捕获种子,因为点击切换按钮会在打开处理程序运行前失去输入框焦点。关闭时清除上下文是插件的职责。

// 之后 (保留简短的定位说明;决策过程放入commit message)
// 聚焦字段仅在对话框打开时作为上下文推送;关闭时会被记住作为下次打开的种子。
报告 → 应放入commit message的内容:“在pointer-down事件时捕获种子,因为点击会在打开处理程序运行前失去输入框焦点;关闭时清除上下文是插件的职责。”

Gotcha → keep, compacted

陷阱注释 → 保留并精简

typescript
// Before
// Field snapshotted when the user initiates opening the operator dialog (toolbar
// toggle pointer-down), consumed by `openOperatorWithSeed`. Captured before the
// click blurs the field, because by the time the dialog opens focus is gone.
let pendingOperatorSeed: string | null = null;

// After
// Captured at toggle pointer-down, before the click blurs the focused field.
let pendingOperatorSeed: string | null = null;
typescript
// 之前
// 用户启动打开操作器对话框(工具栏切换按钮pointer-down)时快照输入框,供`openOperatorWithSeed`使用。在点击失去输入框焦点前捕获,因为对话框打开时焦点已消失。
let pendingOperatorSeed: string | null = null;

// 之后
// 在切换按钮pointer-down事件时捕获,早于点击导致的输入框失焦。
let pendingOperatorSeed: string | null = null;

Rename to kill the comment

重命名以消除注释

typescript
// Before
// Live focused data field as a context path, or null. Reflects the field
// focused right now (set on focus, cleared on blur).
let activeDataContext: string | null = null;

// After
let focusedDataContext: string | null = null;
typescript
// 之前
// 当前聚焦的数据字段的上下文路径,或null。反映当前聚焦的字段(聚焦时设置,失焦时清除)。
let activeDataContext: string | null = null;

// 之后
let focusedDataContext: string | null = null;

Useful transformation → keep, carried by the concrete example

有用的转换 → 保留,通过具体示例体现

typescript
// Before: "Strip the leading dot from the absolute data path (e.g. …)."
// After
// Drop the leading dot: ".itemSet[1].field" -> "itemSet[1].field".
typescript
// 之前:“从绝对数据路径中移除前导点(例如……)。”
// 之后
// 移除前导点:".itemSet[1].field" -> "itemSet[1].field"。

One mechanism in three places → one home

同一机制在三处出现 → 合并到一处

Each of these is defensible alone, which is why a per-comment pass keeps all three. Together they are one story told in fragments, and the reader has three places to look and three to update.
typescript
// Before — three adjacent declarations, three angles on the same mechanism
// Set when a modifier rebuilds its own output, so the target's render is dead work.
suppressRender: boolean;
// A modifier rebuilds from `expression` plus its own `renderDice`, so rendering
// the target first produces a string nobody reads.
function createDiscardedRenderContext() { ... }
// Every pool render routes through here, including the suppressed ones, which is
// why the guard lives at the call site rather than in each wrapper.
function renderedPool() { ... }

// After — the whole mechanism sits once, on the field both functions serve
// Set when a modifier rebuilds its own output; the target's render is then dead work.
// Every pool render routes through `renderedPool`, including suppressed ones.
suppressRender: boolean;
单独看每一处都合理,这也是逐注释流程会保留全部三处的原因。但它们共同讲述一个碎片化的故事,读者需要查看三处并更新三处。
typescript
// 之前——三个相邻的声明,从三个角度描述同一机制
// 当修改器重建自身输出时设置,因此目标的渲染是无效工作。
suppressRender: boolean;
// 修改器从`expression`加上自身的`renderDice`重建,因此先渲染目标会生成无人读取的字符串。
function createDiscardedRenderContext() { ... }
// 所有池渲染都通过此处路由,包括被抑制的渲染,因此守卫逻辑位于调用点而非每个包装器中。
function renderedPool() { ... }

// 之后——整个机制仅保留一次,放在两个函数都服务的字段上
// 当修改器重建自身输出时设置;此时目标的渲染是无效工作。
// 所有池渲染都通过`renderedPool`路由,包括被抑制的渲染。
suppressRender: boolean;

External reference → self-contained, or gone

外部引用 → 改为自包含内容或移除

typescript
// Before
// Workaround for the case described in #412.

// After — the fact is in the file; the issue number bought the reader nothing
// Chrome reports a zero-height box until the font loads, so measure after `ready`.
typescript
// 之前
// 针对#412中描述的情况的workaround。

// 之后——信息已包含在文件中;Issue编号对读者无意义
// Chrome在字体加载前会报告零高度盒子,因此在`ready`事件后再测量。

Common Mistakes

常见错误

  • Deleting a gotcha as if it were restatement. "Captured before the click blurs the field" is why, not what — compact it, don't drop it.
  • Keeping rationale "to be safe". If it's the decision story, the commit message is its home; surface it and remove it from the source.
  • Over-trimming docs. Public API docs are for humans reading the signature — correct and tighten, never gut.
  • Renaming exported symbols with outside callers. That's a refactor, not a rename-to-kill — flag it, don't apply it.
  • Trimming a duplicate's wording instead of deleting it. Three shorter comments still telling one story is the same defect, one round later. Phase 2.5 is not optional.
  • Keeping a comment because it is true. True is not the bar — being unobtainable from the code, and belonging in this file rather than the commit, the PR, or an issue, is.
  • Authoring a
    // !
    warning, a
    // ?
    or a
    // *
    prefix.
    Those are the user's to place.
  • Touching unrelated comments. Stay within the changed code; surgical.
  • Drifting into correctness. A simplification that changes behavior is a bug you introduced, not a cleanup. If the code looks wrong rather than untidy, say so in the report and leave it —
    /changes-review
    owns correctness.
  • Imposing the references on a project that disagrees.
    CLAUDE.md
    and the repo's own rules files win. The references are defaults, not a house style to export.
  • 将陷阱注释当作重复内容删除。“在点击失焦前捕获”是原因,而非功能——应精简,而非删除。
  • 为了“安全”保留设计依据。若属于决策过程,其归属地是commit message;提取内容并从源代码中移除。
  • 过度精简文档。公共API文档供阅读签名的开发者使用——修正并精简,绝不要删除核心内容。
  • 重命名带有外部调用者的导出符号。这属于重构,而非重命名消除注释——标记它,不要应用。
  • 精简重复内容的措辞而非删除。三个较短的注释仍讲述同一个故事,属于同一缺陷。阶段2.5是必须执行的步骤。
  • 因注释正确而保留。正确并非标准——标准是无法从代码中获取,且属于当前文件而非commit message、PR或Issue。
  • 添加
    // !
    警告、
    // ?
    或
    // *
    前缀
    。这些由用户添加。
  • 修改无关注释。仅处理修改的代码;精准操作。
  • 偏离到正确性检查。改变行为的简化是你引入的Bug,而非清理。若代码看起来错误而非混乱,在报告中说明并保留——
    /changes-review
    负责正确性检查。
  • 将参考规范强加给有不同规定的项目。
    CLAUDE.md
    和仓库自身的规则文件优先级更高。参考规范是默认值,而非要输出的固定风格。

Arguments

参数

ArgumentDescription
(none)Clean uncommitted changes; fall back to the last commit if the tree is clean
<file>
/
<dir>/
Clean the named file(s) or directory — whole file in scope
<commit-ref>
Clean the files changed in that commit
--comments-only
Comment work only; never touch code — no conventions, no simplification
--no-simplify
Everything except the simplifier pass
--dry-run
Report what would change without editing
参数描述
无清理未提交变更;若工作区干净则回退到最后一次提交
<file>
/
<dir>/
清理指定文件或目录——整个文件都在范围内
<commit-ref>
清理该提交中修改的文件
--comments-only
仅处理注释;绝不修改代码——不应用规范,不进行简化
--no-simplify
执行除代码简化之外的所有操作
--dry-run
报告会进行的修改但不执行编辑
",