// TypeScript のコメントを検出・集計・安全に削除する CLI // detect, report and safely remove TypeScript comments
「レビューで直しました」は、
コードに書かない。
Fixes go in code.
Stories go in git.
コーディングエージェントが焼き込む“開発の経緯”コメントを、TypeScript の AST で検出して安全に削除する
CLI。ビルドを支える 78 種類のディレクティブは残したまま、
--diff でエージェントが触ったファイルだけを掃除します。
A CLI that detects and safely removes the narration comments coding agents bake into TypeScript — via the
AST. It keeps all 78 directive kinds your build depends on, and
--diff scopes the sweep to the files the agent just touched.
// なぜ要るのか// why this exists
エージェントは“経緯”をコードに焼き込む Agents bake the meeting minutes into the code
エージェントにレビュー往復をさせると、修正のたびに「指摘に従って直した」という報告文が コメントとして積まれていきます。CLAUDE.md やフックで指示しても止まらないことは公式 issue でも報告されている挙動です。コードの制約を書くコメントは資産ですが、開発の出来事を 引用形式で語るコメントは、半年後の読者には何の情報でもありません。経緯なら git blame と PR スレッドが持っています。 Send an agent through a review loop and every round deposits another “per the review feedback, we now …” into your source. Instructions in CLAUDE.md or hooks don't reliably stop it — there are open issues about exactly this. A comment that states a constraint is an asset; a comment that narrates what happened during development tells a reader six months from now nothing. git blame and the PR thread already keep the story.
// Empty string means "--diff with no value": // fall back to comparing against HEAD. if (input === "") return "HEAD";
// Note: Codex review flagged this case. // Per that feedback, we now guard it. if (input === "") return "HEAD";
// できること// what it does
検出・集計から、壊さない削除まで From detection to deletion that doesn't break
検出と集計Detect & report
.ts / .tsx / .mts / .cts を再帰的にスキャンし、行・ブロックコメントを位置情報つきで text / json / github の 3 形式で出力。 Recursively scans .ts / .tsx / .mts / .cts and reports line and block comments with positions, as text, JSON or GitHub annotations.
安全な削除Safe removal
AST のコメント範囲だけを削除。ディレクティブとライセンスヘッダーはデフォルトで保持し、 削除後は再スキャンで検証。 Splices only AST comment ranges. Directives and license headers are kept by default, and the result is re-scanned to verify.
エージェントの作業範囲だけOnly what the agent touched
git が変更ありと報告するファイルだけに絞り込み。未追跡の新規ファイルも含み、 .gitignore は尊重。 Narrows the sweep to files git reports as changed — untracked files included, .gitignore respected.
ディレクティブを知っているKnows the directives
@ts-expect-error から webpackChunkName: まで、消すと挙動が変わるコメントを 78 本のルールで判定。 From @ts-expect-error to webpackChunkName:, 78 rules identify the comments whose removal would change behaviour.
CI ゲートA gate for CI
コメント検出時に終了コード 1。--format github なら PR の該当行にアノテーションが出ます。 Exit code 1 when comments are reported; with --format github the offending lines are annotated right in the PR.
ライブラリとしてもAlso a library
scanComments / removeComments / changedFiles などを TypeScript API として利用可能。 scanComments, removeComments, changedFiles and friends are available as a typed API.
// 安全装置// the guard rails
「壊れないコメント削除」を、真面目にやる Comment removal that refuses to break your build
正規表現でコメントを消すと、文字列の中の // やテンプレートリテラル、JSX を平気で壊します。削除を真面目にやると意外と深い — このツールが踏んでいる地雷の一部: Regex-based stripping happily corrupts strings, template literals and JSX. Done properly, removal turns out to be deep — a sample of the mines this tool steps around:
a/* x */b はトークンが結合してしまう
a/* x */b would merge two tokens
a b)
a space is inserted where they would join (→ a b)
@ts-expect-error 直下の行が消えると適用先がズレる
deleting the line under @ts-expect-error shifts its target
// この挙動は 415 本のテストと 100% カバレッジ(statements / branches / functions / lines)で固定しています // pinned by 415 tests at 100% coverage — statements, branches, functions and lines
// 78 のディレクティブ// the 78 directives
消すとビルドが壊れるコメントを、知っている It knows which comments your build depends on
判定は「それっぽい文字列を含むか」ではなく、各ツールの実際のパーサー実装(正規表現・文字列比較)に合わせてあります。 Detection is not “contains a similar-looking string” — each rule mirrors the actual parser implementation of the tool it protects.
- webpackChunkName: /** 始まりの docblock では判定しない — webpack はコメント本体をオブジェクトリテラルとして評価するため、JSDoc の * が壊すから。 Not detected in /** docblocks — webpack evaluates the comment body as an object literal, and JSDoc stars break it.
- codeql[...] 単一行コメントのみ — CodeQL の AlertSuppression クエリは // しか読まないため、ブロックコメントは普通のコメント扱い。 Line comments only — CodeQL's AlertSuppression queries never read block comments, so those stay ordinary.
- /*jslint マーカー直後に空白があると無効 — JSLint はコメント開始直後の文字列しか見ないため、空白ありは普通のコメント扱い。 Void if a space follows the marker — JSLint only honours the pragma glued to the comment opener.
// 使い方// how to use it
まず見る、それから消す Look first, then delete
# 何がどこにあるかを見る # see what is where
# エージェントが触ったファイルだけ、まず削除対象を確認 # preview the sweep, scoped to files the agent touched
# 問題なければ削除(ディレクティブとライセンスは保持される) # then delete — directives and license headers survive
# CI で経緯コメントの混入を止める(PR の該当行に注釈が出る) # gate CI — offending lines get annotated in the PR
-
絞るScope
--diff HEADでエージェントが直近触った範囲だけを対象にする。--diff HEADnarrows the target to what the agent just touched. -
確かめるPreview
--dry-runで削除対象を人間が最終確認する。元からあった資産コメントを守るのはここ。--dry-runputs a human in the loop — this is where pre-existing comment assets get protected. - 掃除するSweep 削除して、本当に必要な知見は経緯抜きの Why コメントとして書き直させる。 Delete, and have real insights rewritten as Why comments — without the narration.
終了コード: 0 成功 · 1 --fail-on-comment でコメント検出 · 2 引数・実行時エラー / Node.js ≥ 20 / MIT Exit codes: 0 success · 1 comments found with --fail-on-comment · 2 usage or runtime error / Node.js ≥ 20 / MIT