lintp · یک خط برای هر ایراد
خروجی لینتر را ایجنت میخواند، نه آدم
خروجی پیشفرض لینترها برای آدمی نوشته شده که یک خطا را میخواند، پس هر ایراد با یک قاب کد و یک فلش اشارهگر و یک بند راهنما میآید. ایجنت برای هر ایراد چهارده خط از همینها میگیرد و کانتکستش را خرج قالببندی میکند. lintp فقط دستور را چاپ میکند و بقیه را میاندازد دور.
$ lintp src/ src/api.py:1 remove unused import `os` src/api.py:14 return str, not int src/ui.tsx:8 add a `key` prop to the list element src/theme.css:1 remove the duplicate CSS property 4 findings, 2 auto-fixable (lintp --fix)
سه ایراد یکسان؛ ۳۱ خط یا ۵ خط
چیزی که ایجنت امروز میخواند
$ ruff check src/api.py I001 [*] Import block is un-sorted or un-formatted --> src/api.py:1:1 | 1 | / import os 2 | | import json | |___________^ help: Organize imports | 1 + import json 2 | import os - import json 3 | | F401 [*] `os` imported but unused --> src/api.py:1:8 | 1 | import os | ^^ 2 | import json | help: Remove unused import: `os` | - import os 1 | import json | Found 2 errors. [*] 2 fixable with the `--fix` option. $ mypy src/api.py src/api.py:11: error: Incompatible return value type (got "str", expected "int") [return-value] Found 1 error in 1 file (checked 1 source file)
چیزی که lintp تحویلش میدهد
$ lintp src/api.py src/api.py:1 sort the import block src/api.py:1 remove unused import `os` src/api.py:11 return int, not str 3 findings, 2 auto-fixable (lintp --fix)
یک فرمان، چهار لینتر
مسیر را به lintp بده. بر اساس پسوند تصمیم میگیرد و هر ایراد را در یک قالب چاپ میکند،
مهم نیست کدام ابزار پیدایش کرده. کدهای خروج هم به کار میآیند: 0 تمیز،
1 ایراد دارد، 2 یکی از لینترها اجرا نشد.
| پسوند | لینتر |
|---|---|
.py .pyi | ruff + mypy |
.js .mjs .cjs .jsx .ts .tsx .mts .cts | oxlint |
.css .scss .json .jsonc | biome |
biome خودش JS و TS را هم لینت میکند، پس آن ایرادها حذف میشوند. صاحبشان oxlint است و پرامپت تکراری از هیچ بدتر است.
فلگها
| فلگ | کارکرد |
|---|---|
--fix | اول اصلاحهای بیخطر را اعمال کن، بعد باقیمانده را گزارش بده |
--codes | نام قاعده را به آخر هر خط اضافه کن |
--strict | قاعدههای pedantic و style از oxlint را هم روشن کن |
--tools | فقط زیرمجموعهای را اجرا کن، مثل --tools ruff,mypy |
کانفیگ خودِ پروژه حرف آخر را میزند
اگر مخزن .oxlintrc.json داشته باشد، lintp همان را با -c پاس
میدهد و هیچ فلگ دستهای از خودش اضافه نمیکند. دستهای که بهزور اعمال شود، قاعدههایی را
برمیگرداند که پروژه عمداً خاموش کرده بود، و از همینجا است که یک wrapper همان توصیهای را
میدهد که پروژه قبلاً ردش کرده.
نصب
سه مرحله، به همین ترتیب. هیچچیز اینجا کامپایل نمیشود.
-
لینترهایی که میخواهی را نصب کن
هیچکدام همراه agent-linters نمیآیند.
$ uv tool install ruff && uv tool install mypy $ npm install -g oxlint @biomejs/biome
-
مخزن را کلون کن و نصبکننده را اجرا کن
$ git clone https://github.com/cocodedk/agent-linters ~/projects/agent-linters $ cd ~/projects/agent-linters && ./install.sh
پوشههای
bin/وshims/وconfig/را به~/.localو~/.configسیملینک میکند و یک خطsourceبه پروفایل شل اضافه میکند. اگر فایل واقعی سرِ راه باشد، اول به<name>.bakمنتقل میشود. -
به Claude Code خبر بده
Claude Code بلوک
envخودش را میخواند، نه پروفایل شل تو. پس دو متغیر را به~/.claude/settings.jsonاضافه کن، یا بگذار./install.sh --claudeباjqاین کار را بکند."env": { "RUFF_OUTPUT_FORMAT": "concise", "RUFF_CACHE_DIR": "/home/YOU/.cache/ruff" }
./install.sh --uninstall همهاش را برمیگرداند و بکاپها را سر جایشان
میگذارد. اجرای دوبارهٔ نصبکننده هم بیخطر است. نیازمندیها: sh از نوع POSIX،
پایتون ۳.۸ یا بالاتر، و خودِ لینترها.
چهار تله که واقعاً وقت دیباگ برد
هر کدام از اینها باعث شد یک لینتر به چیز اشتباهی اشاره کند. به همین دلیل کار lintp به ست کردن یک متغیر محیطی خلاصه نمیشود.
-
هیچوقت یک
MYPY_CACHE_DIRمشترک نگذاردو پروژه که هر کدام یک
utils.pyدارند، در کش مشترک با هم تصادم میکنند و mypy ایراد را به فایلِ آن یکی پروژه نسبت میدهد. ایجنتی که به مسیر اعتماد کند، فایلی را در مخزن اشتباه ویرایش میکند. شیم به هر پوشهٔ کاری کش خودش را میدهد.MYPY_CACHE_DIRارثی هنوز برنده است، چون تنظیم صریح باید برنده باشد، پس اگر یکبار مشترک اکسپورتش کردهای، unset کن. -
ruff هر فایلی را که نام ببری لینت میکند
ruff check app.jsیک صفحه خطای سینتکس پایتونِ خیالی برمیگرداند. قبل از صدا زدن هر ابزاری، مسیرها را با پسوند فیلتر کن. lintp این کار را درselect()میکند. -
مسیرهای mypy نسبت به هدفاند، نه به مسیر جاری
یک
a.pyبدون مسیر در خروجی mypy میتواند به فایل همنامِ دیگری در پوشهٔ جاری برسد. اول مسیرهای گزارششده را نسبت به ریشهٔ هدف حساب کن. -
oxlint کانفیگ را فقط از مسیر جاری میخواند
ruff و mypy و biome همه رو به بالا جستوجو میکنند، oxlint نه. از یک زیرپوشه اجرایش کن و بیصدا همهٔ استثناهایی را از دست میدهی که کانفیگ مخزن برای همانها نوشته شده. lintp خودش بالا میرود و
-cرا پاس میدهد.