repomix کل یک ریپوی git را در یک فایل متنی جمع می‌کند تا به یک مدل بدهی، و برای این کار هیچ کلید API نمی‌خواهد. در این پست نسخه‌ی 1.18.1 را نصب می‌کنیم و روی یک پروژه‌ی پنج‌فایلی واقعی اجرا می‌کنیم: ۹۶۳ توکن برای کل پروژه، ۶۸۰ توکن وقتی فقط src را می‌گیریم، و ۳۵۷ توکن وقتی --no-files می‌زنیم. دو دام واقعی هم درمی‌آید که در README نوشته نشده: با عوض کردن نام خروجی، فایل قبلی دوباره بسته‌بندی می‌شود و توکن‌ها دو برابر می‌شوند؛ و سقف توکن فایل را می‌نویسد و بعد کد خطا می‌دهد.

repomix چیست و چطور نصبش کنیم

کاری که می‌کند پیش از اینکه به مدل بدهی توصیف کنی: تعداد فایل، توکن هر فایل، و متن کامل هر فایل در یک سند. کاری که نمی‌کند تماس زدن به هیچ مدلی است. تنها راهی که درخواستی به شبکه می‌فرستد خودِ پرچم --remote است، پس می‌شود همین ابزار را در CI بدون هیچ رازی اجرا کرد.

لحظه‌ی خواندن: ۷ اکتبر ۲۰۲۶. آخرین نسخه روی npm همان 1.18.1 است که ۲۱ سپتامبر ۲۰۲۶ منتشر شده، ریپو ۲۸٬۷۳۵ ستاره و ۱٬۵۶۸ فورک دارد، لایسنسش MIT است و engines بسته Node 22 یا بالاتر را لازم دارد. این اعداد زنده‌اند؛ ماه بعد که این پست را می‌خوانی ستاره‌ها بیشتر و نسخه لزوما تازه‌تر است. نسخه را پین می‌کنم چون عددهای این پست به همین نسخه گره خورده‌اند: با نسخه‌ی تازه‌تر ممکن است توکن‌شمار عوض شود و جدول پایین دیگر با اجرای شما نخواند.

# نصب سراسری روی نسخه‌ی پین‌شده
npm install -g repomix@1.18.1

$ repomix --version
1.18.1

# یک پروژه‌ی ۵ فایلی می‌سازیم تا همه‌ی عددها قابل بازتولید باشند
$ mkdir -p shop/src shop/tests && cd shop

# تست‌های خود پروژه قبل از بسته‌بندی سبز است
$ node --test "tests/*.test.js"
ℹ tests 2
ℹ pass 2
ℹ fail 0

$ node src/index.js
{"lines":2,"total":3225000}

الگوی "tests/*.test.js" را داخل گیومه بگذار. با node --test tests/ این پروژه خطای MODULE_NOT_FOUND می‌دهد چون Node مسیر tests را یک ماژول می‌خواند نه یک پوشه‌ی تست. هر تازه‌کاری در این مسیر به همین برخورد می‌کند.

اولین بسته‌بندی و عددهای واقعی

$ repomix . --style markdown -o bundle.md
📦 Repomix v1.18.1
✔ Packing completed successfully!

📈 Top 5 Files by Token Count:
──────────────────────────────
1.  tests/cart.test.js (201 tokens, 558 chars, 20.9%)
2.  src/cart.js (199 tokens, 649 chars, 20.7%)
3.  src/index.js (71 tokens, 222 chars, 7.4%)
4.  package.json (37 tokens, 93 chars, 3.8%)
5.  README.md (27 tokens, 79 chars, 2.8%)

📊 Pack Summary:
  Total Files: 5 files
 Total Tokens: 963 tokens
 Total Chars: 3,551 chars

سطر اول جدول مهم‌ترین یافته‌ی این پست است: فایل تست با ۲۰۱ توکن از کد اصلی با ۱۹۹ توکن بزرگ‌تر است. روی یک پروژه‌ی کوچک، نیمی از چیزی که به مدل می‌دهی ممکن است تست باشد. اگر هدفت بازبینی کد است، تست‌ها را با --include "src/**" بیرون بگذار و بودجه‌ی context را برای چیزی خرج کن که می‌خواهی خوانده شود.

برای اینکه عددها با اجرای شما بخوانند، -o هر بار نامی متفاوت دارد تا بسته‌ی قبلی وارد بسته‌ی بعدی نشود؛ دلیلش در بخش بعدی است.

پرچمفایلتوکنکاراکتر
پیش‌فرض (XML)۵۹۶۳۳٬۵۵۱
--style markdown۵۹۴۰۳٬۴۱۵
--style json۵۹۷۸۳٬۴۲۲
--style plain۵۹۶۰۴٬۱۰۹
--include "src/**"۲۶۸۰۲٬۸۱۶
--compress۵۷۱۶۲٬۸۲۴
--no-files۵۳۵۷۱٬۶۸۲
--remove-comments۵۸۹۶۳٬۴۸۸

سه سطر این جدول را با هم بخوان. --compress کمترین توکن را در میان حالت‌های محتوا‌دار می‌دهد: کاراکترها از ۳٬۵۵۱ به ۲٬۸۲۴ می‌رسد، یعنی ۷۲۷ تقسیم بر ۳٬۵۵۱ برابر ۰٫۲۰ یعنی ۲۰ درصد کمتر، چون درخت‌سیتتر فقط اسکلت کلاس‌ها و تابع‌ها را نگه می‌دارد و بدنه‌ی تابع‌ها را دور می‌ریزد. --remove-comments برعکس، فقط کامنت‌ها را می‌برد و ۶۷ توکن کم می‌کند؛ برای کدی که کامنتش توضیح است این معمولا بد معامله‌ای است. --no-files تنها حالتی است که محتوای فایل‌ها را حذف می‌کند و فقط فراداده می‌دهد: ۳۵۷ تقسیم بر ۹۶۳ برابر ۰٫۳۷، یعنی ۳۷ درصد اندازه‌ی بسته‌ی کامل، برای وقتی که نقشه‌ی پروژه می‌خواهی نه محتوا.

توکن‌شمار یک عدد خنثی نیست

عدد توکن به این بستگی دارد که با کدام توکن‌نایزر شمرده‌ای. پیش‌فرض o200k_base است، یعنی نایزر مدل‌های GPT-4o. همان پروژه با cl100k_base که نایزر GPT-3.5 و GPT-4 است عدد دیگری می‌دهد.

$ repomix . --token-count-encoding cl100k_base -o bundle.xml
 Total Tokens: 1,068 tokens

$ repomix . --token-count-encoding o200k_base -o bundle.xml
 Total Tokens: 963 tokens

# اختلاف: ۱٬۰۶۸ منهای ۹۶۳ برابر ۱۰۵ توکن
# نسبت: ۱۰۵ تقسیم بر ۹۶۳ برابر ۰٫۱۱ یعنی حدود ۱۱ درصد بیشتر

همان فایل، همان محتوا، ۱۱ درصد بزرگ‌تر شماره می‌شود فقط چون نایزر عوض شده. اگر داری بودجه‌ی context یک نشست را می‌چینی، نایزر همان مدلی را انتخاب کن که واقعا جواب را می‌دهد؛ وگرنه عددی که می‌بینی با عددی که آخر نشست می‌سوزی فرق دارد. این همان منطقی است که در هزینه‌ی واقعی کش پرامپت هم هزینه را با واحدی حساب می‌کند که تعیین‌کننده‌ی نهایی است.

دو دامی که در README نیست

این دو را پیدا کردم چون خودم موقع اندازه‌گیری به عددهای متناقض برخوردم: یک بار ۹۴۰ توکن و بار دیگر ۹۷۱ برای دو فرمان ظاهرا یکسان.

خروجی قبلی را دوباره بسته‌بندی می‌کند

# اجرای اول با نام bundle.xml
$ repomix . -o bundle.xml
  Total Files: 5 files
 Total Tokens: 963 tokens

# اجرای دوم با نام دیگر: فایل قبلی وارد بسته شد
$ repomix . -o bundle2.xml
1.  bundle.xml (961 tokens, 3,550 chars, 49.6%)
  Total Files: 6 files
 Total Tokens: 1,937 tokens

# راه‌حل: خروجی‌های قبلی را صریحا کنار بگذار
$ repomix . -i "bundle*.xml" -o bundle3.xml
  Total Files: 5 files
 Total Tokens: 993 tokens

سطر آخر ۹۹۳ است و از ۹۶۳ بیشتر، چون پیام توضیحی خود repomix هم به بسته اضافه می‌شود. مهم این است که از ۱٬۹۳۷ به ۹۹۳ برگشتیم نه به ۹۶۳. اگر این را در اسکریپتی بگذاری که هر بار یک نام تازه می‌سازد، بسته در هر اجرا از اجرای قبل بزرگ‌تر می‌شود تا به سقف context بخوری. یا خروجی را بیرون از ریپو بنویس، یا با --ignore خودت را از هر خروجی‌ای که ممکن است باقی مانده باشد خلاص کن.

سقف توکن فایل را می‌نویسد و بعد خطا می‌دهد

# روی همان پروژه‌ی ۹۶۳ توکنی
$ repomix . --token-budget 900 -o bundle.xml
✖ Packed output exceeds the token budget: 963 > 900 tokens.
   Reduce the output with --compress, narrow the scope with
   --include/--ignore, or raise --token-budget.
$ echo $?
1

$ repomix . --token-budget 5000 -o bundle.xml
 Total Tokens: 963 tokens
$ echo $?
0

پرچم --token-budget برای گارگارد در CI است: اگر بسته از بودجه بگذرد کد خروجی 1 می‌دهد. راهنما کم روی این نکته مکث می‌کند که فایل خروجی قبل از بررسی بودجه نوشته می‌شود. در اجرای اول فایل bundle.xml با ۳٬۷۷۰ بایت روی دیسک بود در حالی که کد خطا ۱ بود؛ یعنی یک بسته‌ی بیش از بودجه را به‌عنوان خروجی موفق مصرف می‌کردی. برای اینکه این بودجه دروازه‌ی واقعی باشد، اول با --stdout بسنج و بعد فایل را بنویس، یا فایل نوشته‌شده در اجرای ناموفق را پاک کن.

بررسی اسرار کار می‌کند، ولی همه چیز را نمی‌گیرد

هر بسته‌بندی یک اسکن امنیتی هم دارد که در عمل secretlint با پیش‌تنظیم recommend است. هفت الگوی نمونه را روی همین پروژه آزمودم.

الگوی آزمودهنتیجه
توکن ghp_ گیت‌هابگرفته شد، فایل کنار گذاشته شد
توکن xoxb- اسلکگرفته شد، فایل کنار گذاشته شد
توکن npm_گرفته شد، فایل کنار گذاشته شد
کلید AKIA آمازونرد شد
کلید گوگل با پیشوند AIzaرد شد
بلوک کلید خصوصی PEMرد شد
JWT کاملرد شد

دو نکته از این آزمون درمی‌آید. اول اینکه فایل مشکوک کنار گذاشته می‌شود نه اینکه فقط هشدار بدهد: در آزمون توکن گیت‌هاب، شمار فایل از ۶ به ۵ افتاد و آن فایل اصلا داخل بسته نیامد. دوم اینکه پوشش اسکنر کامل نیست. اگر کلید آمازون یا کلید خصوصی داخل ریپویت هست، repomix جلوی نشت آن را نمی‌گیرد. تکیه بر این خط «No suspicious files detected» یعنی امنیت را به یک اسکنر خوش‌بین سپرده‌ای؛ برای ریپویی که به بیرون می‌فرستی، قبل از بسته‌بندی یک git grep روی الگوهای کلید خودت بزن.

بسته‌بندی راه دور، و کِی به چه چیزی دست بزنی

پرچم --remote ریپو را خودش دانلود و بسته‌بندی می‌کند بدون اینکه در سیستم کلون کنی. همین را روی خود repomix اجرا کردم: ۱٬۱۴۰ فایل، ۱٬۴۲۱٬۸۷۴ توکن و ۵٬۳۵۸٬۸۳۷ کاراکتر در یک فایل ۵٫۹ مگابایتی. یک میلیون و چهارصد هزار توکن در هیچ context جا نمی‌شود، پس گرفتنش کار بی‌فایده‌ای است. برای همین بودجه‌ی توکن یک پرچم تزئینی نیست؛ تنها چیزی است که جلوی یک اشتباه گران را می‌گیرد. پیش از بسته‌بندی یک ریپوی بزرگ اول با --no-files --token-count-tree نقشه‌ی توکن‌ها را ببین و با --include تصمیم بگیر کدام پوشه‌ها را برداری.

کارفرمانچه می‌گیری
بازبینی کد توسط مدل بیرونی--include "src/**" --compressفقط اسکلت کد، کمترین توکن
پاسخ به پرسش درباره‌ی پروژه--include "src/**"محتوای کامل کد
اندازه‌گیری پروژه--no-files --token-count-treeدرخت پوشه با توکن هر شاخه
پر کردن context یک نشست--remote به‌تنهاییبسته‌ای که به‌احتمال زیاد جا نمی‌شود

خط آخر جدول را جدی بگیر. در ایجنت بعد از یک فراخوانی ابزار خالی برمی‌گردد دیدم که وقتی خروجی یک ابزار بزرگ‌تر از انتظار بود، همان یک پاسخ خراب می‌شد. یک بسته‌ی یک‌میلیون‌توکنی دقیقا همان دسته خطاست. اگر در نشست کلاد کد به چنین فایلی اشاره می‌کنی، اول اندازه‌اش کن، بعد کوچکش کن، و تازه بعد بدهش به مدل.

آنچه در این پست واقعا اجرا شد: نصب repomix@1.18.1، بسته‌بندی یک پروژه‌ی پنج‌فایلی در هشت حالت پرچم، آزمون بودجه در سه سطح، آزمون هفت الگوی کلید، و بسته‌بندی راه دور خود repomix. هر عددی در این متن از یکی از همین اجراها می‌آید. آمار گیت‌هاب و npm را مستقیم از API خواندم، نه از صفحه‌ی ریپو؛ یعنی دقیق‌اند ولی یک لحظه بعد از لحظه‌ی خواندن‌اند.

منابع

  1. مخزن yamadashy/repomix — لایسنس، ستاره و فورک در لحظه‌ی ۷ اکتبر ۲۰۲۶
  2. صفحه‌ی انتشارها — نسخه‌ی 1.18.1 و تاریخچه‌ی انتشار
  3. فراداده‌ی بسته در رجیستری npm — زمان انتشار 1.18.1 و شرط engines
  4. README پروژه — معرفی ابزار و قالب‌های خروجی
  5. package.json پروژه — نام بسته و نسخه
  6. راهنمای Repomix — شرح پرچم‌های خط فرمان و بودجه‌ی توکن
  7. مسئله‌های باز پروژه — شمار مسائل باز در لحظه‌ی خواندن
  8. صفحه‌ی دانلود Node.js — نسخه‌های پشتیبانی‌شده
  9. پرونده‌ی لایسنس — متن لایسنس MIT
  10. Changelog کلاد کد — نسخه‌ی 2.1.292 در ۶ اکتبر ۲۰۲۶